xref: /petsc/share/petsc/saws/js/treeInterface.js (revision 3aa2d9e3a17455108487be9a174c0f069d9014ad)
1//this file contains all the code for the input interface through the tree diagram
2
3//global variables to keep track of where the input box is on the page
4var boxPresent = false;
5var boxEndtag = "";
6var box_x = 0;
7var box_y = 0;
8var box_size = new Object();
9
10function removeBox(){
11    $("#tempInput").remove();
12}
13
14//this method submits the options and generates the children (if any) with appropriate defaults
15//returns 1 on success and 0 on fail
16function submitOptions(){
17
18    var endtag = boxEndtag;
19    var parentEndtag = getParent(endtag);
20
21    var selectedPc = $("#temp_pc_type").val();
22
23    var symm;
24    var posdef;
25    var logstruc;
26
27    if($("#temp_symm").length == 0) { //if the checkbox options were not displayed
28        symm = matInfo[endtag].symm;
29        posdef = matInfo[endtag].posdef;
30        logstruc = matInfo[endtag].logstruc;
31    }
32
33    else {
34        symm     = $("#temp_symm").prop("checked");
35        posdef   = $("#temp_posdef").prop("checked");
36        logstruc = $("#temp_logstruc").prop("checked");
37    }
38
39    //check if matrix properties are valid
40    if(!symm && posdef) {
41        alert("Error: Cannot be non-symmetric yet positive definite");
42        return 0;
43    }
44
45    if(endtag != "0") { //check for discrepancies with parent
46        var parentSymm = matInfo[parentEndtag].symm;
47        var parentPosdef = matInfo[parentEndtag].posdef;
48        var parentLogstruc = matInfo[parentEndtag].logstruc;
49        if(parentSymm && !symm) {
50            alert("Error: Cannot have symmetric parent yet be non-symmetric");
51            return 0;
52        }
53        if(parentPosdef && !posdef) {
54            alert("Error: Cannot have positive definite parent yet be non-positive definite");
55            return 0;
56        }
57    }
58
59    //check for more invalid setups
60    if(selectedPc == "fieldsplit") {
61        var blocks = $("#temp_pc_fieldsplit_blocks").val();
62        if(blocks.match(/[^0-9]/) || blocks < 1) {
63            alert("Error: Must have at least 1 block for fieldsplit");
64            return 0;
65        }
66        /*if(!logstruc) {
67            alert("Error: Cannot use fieldsplit on non-logically block structured matrix");
68            return 0;
69        }*/
70    }
71    else if(selectedPc == "mg") { //extra options for mg
72        var levels = $("#temp_pc_mg_levels").val();
73        if(levels.match(/[^0-9]/) || levels < 1) {
74            alert("Error: Must have at least 1 level for multigrid");
75            return 0;
76        }
77    }
78    else if(selectedPc == "gamg") {
79        var levels = $("#temp_pc_gamg_levels").val();
80        if(levels.match(/[^0-9]/) || levels < 1) {
81            alert("Error: Must have at least 1 level for geometric algebraic multigrid");
82            return 0;
83        }
84    }
85    else if(selectedPc == "bjacobi") {
86        var blocks = $("#temp_pc_bjacobi_blocks").val();
87        if(blocks.match(/[^0-9]/) || blocks < 1) {
88            alert("Error: Must have at least 1 block for bjacobi");
89            return 0;
90        }
91    }
92    else if(selectedPc == "redundant") {
93        var number = $("#temp_pc_redundant_number").val();
94        if(number.match(/[^0-9]/) || number < 1) {
95            alert("Error: Redundant Number must be at least 1");
96            return 0;
97        }
98    }
99    else if(selectedPc == "asm") {
100        var blocks = $("#temp_pc_asm_blocks").val();
101        if(blocks.match(/[^0-9]/) || blocks < 1) {
102            alert("Error: Must have at least 1 block for Additive Schwarz Method");
103            return 0;
104        }
105        var overlap = $("#temp_pc_asm_overlap").val();
106        if(overlap.match(/[^0-9]/) || overlap < 1) {
107            alert("Error: Must have overlap of at least 1 for Additive Schwarz Method");
108            return 0;
109        }
110    }
111
112
113    //only preserve some options if the pc_type didn't change
114    var oldPc = matInfo[endtag].pc_type;
115    var newPc = $("#temp_pc_type").val();
116    var changedPc = (oldPc != newPc);
117    if(changedPc)
118        deleteAllChildren(endtag);
119
120    //write options to matInfo
121    matInfo[endtag].symm = symm;
122    matInfo[endtag].posdef = posdef;
123    matInfo[endtag].logstruc = logstruc;
124
125    matInfo[endtag].pc_type = $("#temp_pc_type").val();
126    matInfo[endtag].ksp_type = $("#temp_ksp_type").val();
127
128    //update dropdown list interface
129    $("#symm" + endtag).prop("checked",symm);
130    $("#posdef" + endtag).prop("checked",posdef);
131    $("#logstruc" + endtag).prop("checked",logstruc);
132
133    if(!symm)
134        $("#posdef" + endtag).attr("disabled", true);
135    if(symm)
136        $("#posdef" + endtag).attr("disabled", false);
137
138    $("#pc_type" + endtag).val(matInfo[endtag].pc_type);
139    $("#ksp_type" + endtag).val(matInfo[endtag].ksp_type);
140
141    var pc_type = matInfo[endtag].pc_type;
142
143    if(pc_type == "fieldsplit") { //extra options for fieldsplit
144        var blocks = $("#temp_pc_fieldsplit_blocks").val();
145        var type   = $("#temp_pc_fieldsplit_type").val();
146
147        if(changedPc)
148            $("#pc_type" + endtag).trigger("change");
149
150        //set the appropriate option and then trigger the change in the field (this writes to matInfo)
151        $("#pc_fieldsplit_type" + endtag).val(type);
152        $("#pc_fieldsplit_type" + endtag).trigger("change");
153        $("#pc_fieldsplit_blocks" + endtag).val(blocks);
154        $("#pc_fieldsplit_blocks" + endtag).trigger("keyup");
155    }
156    else if(pc_type == "mg") { //extra options for mg
157        var levels = $("#temp_pc_mg_levels").val();
158        var type   = $("#temp_pc_mg_type").val();
159
160        if(changedPc)
161            $("#pc_type" + endtag).trigger("change");
162
163        //set the appropriate option and then trigger the change in the field (this writes to matInfo)
164        $("#pc_mg_type" + endtag).val(type);
165        $("#pc_mg_type" + endtag).trigger("change");
166        $("#pc_mg_levels" + endtag).val(levels);
167        $("#pc_mg_levels" + endtag).trigger("keyup");
168    }
169    else if(pc_type == "gamg") {
170        var levels = $("#temp_pc_gamg_levels").val();
171        var type   = $("#temp_pc_gamg_type").val();
172
173        if(changedPc)
174            $("#pc_type" + endtag).trigger("change");
175
176        //set the appropriate option and then trigger the change in the field (this writes to matInfo)
177        $("#pc_gamg_type" + endtag).val(type);
178        $("#pc_gamg_type" + endtag).trigger("change");
179        $("#pc_gamg_levels" + endtag).val(levels);
180        $("#pc_gamg_levels" + endtag).trigger("keyup");
181    }
182    else if(pc_type == "bjacobi") {
183        var blocks = $("#temp_pc_bjacobi_blocks").val();
184        if(changedPc)
185            $("#pc_type" + endtag).trigger("change");
186        $("#pc_bjacobi_blocks" + endtag).val(blocks);
187        $("#pc_bjacobi_blocks" + endtag).trigger("keyup");
188    }
189    else if(pc_type == "redundant") {
190        var number = $("#temp_pc_redundant_number").val();
191        if(changedPc)
192            $("#pc_type" + endtag).trigger("change");
193        $("#pc_redundant_number" + endtag).val(number);
194        $("#pc_redundant_number" + endtag).trigger("keyup");
195    }
196    else if(pc_type == "asm") {
197        var blocks  = $("#temp_pc_asm_blocks").val();
198        var overlap = $("#temp_pc_asm_overlap").val();
199        if(changedPc)
200            $("#pc_type" + endtag).trigger("change");
201        $("#pc_asm_blocks" + endtag).val(blocks);
202        $("#pc_asm_blocks" + endtag).trigger("keyup");
203        $("#pc_asm_overlap" + endtag).val(overlap);
204        $("#pc_asm_overlap" + endtag).trigger("keyup");
205    }
206    else if(pc_type == "ksp") {
207        //ksp doesn't have any additional options, but it has one child
208        if(changedPc)
209            $("#pc_type" + endtag).trigger("change");
210    }
211
212    enforceProperties(endtag);
213
214    return 1;
215}
216
217// this function enforces the logical properties of the matrix
218function enforceProperties(endtag) {
219
220    var symm  = matInfo[endtag].symm;
221    var posdef = matInfo[endtag].posdef;
222
223    if(symm) { //if symm, then all children must be symm
224        for (var key in matInfo) {
225            if (matInfo.hasOwnProperty(key)) {
226                if(key.indexOf(endtag) == 0) { //if it is indeed a child
227                    matInfo[key].symm = true;
228                }
229            }
230        }
231    }
232
233    if(posdef) { //if posdef, then all children must be posdef
234        for (var key in matInfo) {
235            if (matInfo.hasOwnProperty(key)) {
236                if(key.indexOf(endtag) == 0) { //if it is indeed a child
237                    matInfo[key].posdef = true;
238                }
239            }
240        }
241    }
242
243}
244
245//this function ensures that all children are properly generated and initialized
246function generateChildren(endtag) {
247
248    var pc_type = matInfo[endtag].pc_type;
249
250    if(pc_type == "bjacobi") { //needs 1 child
251        //check if that 1 child already exists. if so, then stop. otherwise, generate that child, select the defaults, and recursively ensure that the new child also has the appropriate children
252        var childEndtag = endtag + "_0";
253        if(matInfo[childEndtag] == undefined) { //generate child
254            var defaults = getDefaults("bjacobi",matInfo[endtag].symm,matInfo[endtag].posdef,matInfo[endtag].logstruc);
255
256            matInfo[childEndtag] = {
257                pc_type:  defaults.sub_pc_type,
258                ksp_type: defaults.sub_ksp_type,
259                symm:     matInfo[endtag].symm, //inherit !!
260                posdef:   matInfo[endtag].posdef,
261                logstruc: matInfo[endtag].logstruc
262            };
263            generateChildren(childEndtag);
264        }
265    }
266    else if(pc_type == "fieldsplit") {
267        for(var i=0; i<matInfo[endtag].pc_fieldsplit_blocks; i++) {
268            var childEndtag = endtag + "_" + i;
269            if(matInfo[childEndtag] == undefined) { //generate child
270                var defaults = getDefaults("fieldsplit",matInfo[endtag].symm,matInfo[endtag].posdef,matInfo[endtag].logstruc);
271
272                matInfo[childEndtag] = {
273                    pc_type:  defaults.sub_pc_type,
274                    ksp_type: defaults.sub_ksp_type,
275                    symm:     matInfo[endtag].symm, //inherit !!
276                    posdef:   matInfo[endtag].posdef,
277                    logstruc: false //to prevent infinite recursion
278                };
279                generateChildren(childEndtag);
280            }
281        }
282    }
283    else if(pc_type == "mg") {
284        for(var i=0; i<matInfo[endtag].pc_mg_levels; i++) {
285            var childEndtag = endtag + "_" + i;
286            if(matInfo[childEndtag] == undefined) { //generate child
287                var defaults = getDefaults("mg",matInfo[endtag].symm,matInfo[endtag].posdef,matInfo[endtag].logstruc);
288
289                matInfo[childEndtag] = {
290                    pc_type:  defaults.sub_pc_type,
291                    ksp_type: defaults.sub_ksp_type,
292                    symm:     matInfo[endtag].symm, //inherit !!
293                    posdef:   matInfo[endtag].posdef,
294                    logstruc: matInfo[endtag].logstruc
295                };
296                generateChildren(childEndtag);
297            }
298        }
299    }
300    else if(pc_type == "gamg") {
301        for(var i=0; i<matInfo[endtag].pc_gamg_levels; i++) {
302            var childEndtag = endtag + "_" + i;
303            if(matInfo[childEndtag] == undefined) { //generate child
304                var defaults = getDefaults("gamg",matInfo[endtag].symm,matInfo[endtag].posdef,matInfo[endtag].logstruc);
305
306                matInfo[childEndtag] = {
307                    pc_type:  defaults.sub_pc_type,
308                    ksp_type: defaults.sub_ksp_type,
309                    symm:     matInfo[endtag].symm, //inherit !!
310                    posdef:   matInfo[endtag].posdef,
311                    logstruc: matInfo[endtag].logstruc
312                };
313                generateChildren(childEndtag);
314            }
315        }
316    }
317    else if(pc_type == "ksp") {
318        var childEndtag = endtag + "_0";
319        if(matInfo[childEndtag] == undefined) { //generate child
320            var defaults = getDefaults("ksp",matInfo[endtag].symm,matInfo[endtag].posdef,matInfo[endtag].logstruc);
321
322            matInfo[childEndtag] = {
323                pc_type:  defaults.sub_pc_type,
324                ksp_type: defaults.sub_ksp_type,
325                symm:     matInfo[endtag].symm, //inherit !!
326                posdef:   matInfo[endtag].posdef,
327                logstruc: matInfo[endtag].logstruc
328            };
329            generateChildren(childEndtag);
330        }
331    }
332
333}
334
335$(document).on("click","input[id='setOptions']",function(){
336
337    var result = submitOptions(); //submitOptions() returns 0 on fail and 1 on success
338    if(result == 1) {
339        removeBox();
340        boxPresent = false;
341        refresh();
342    }
343});
344
345$(document).on("change","input[id='temp_symm']",function(){
346    setDefaults2();
347});
348
349$(document).on("change","input[id='temp_posdef']",function(){
350    setDefaults2();
351});
352
353$(document).on("change","input[id='temp_logstruc']",function(){
354    setDefaults2();
355});
356
357//this function sets default ksp/pc when the properties of the matrix are changed
358function setDefaults2() {
359    var symm     = $("#temp_symm").prop("checked");
360    var posdef   = $("#temp_posdef").prop("checked");
361    var logstruc = $("#temp_logstruc").prop("checked");
362
363    var endtag = boxEndtag;
364
365    var defaults;
366    if(endtag == "0") { //has no parent
367        defaults = getDefaults("",symm,posdef,logstruc);
368    }
369    else { //otherwise, we should generate a more appropriate default
370        var parentEndtag    = getParent(endtag);
371        var parent_pc_type  = matInfo[parentEndtag].pc_type;
372        var parent_symm     = matInfo[parentEndtag].symm;
373        var parent_posdef   = matInfo[parentEndtag].posdef;
374        var parent_logstruc = matInfo[parentEndtag].logstruc;
375        defaults            = getDefaults(parent_pc_type,parent_symm,parent_posdef,parent_logstruc,symm,posdef,logstruc); //if this current solver is a sub-solver, then we should set defaults according to its parent. this suggestion will be better.
376        defaults = {
377            pc_type: defaults.sub_pc_type,
378            ksp_type: defaults.sub_ksp_type
379        };
380    }
381
382    $("#temp_pc_type").val(defaults.pc_type);
383    $("#temp_ksp_type").val(defaults.ksp_type);
384
385    $("#temp_pc_type").trigger("change"); //display the correct options
386}
387
388//this function displays the appropriate options for each pc_type when pc_type dropdown is changed (for example, bjacobi blocks, fieldsplit type, etc)
389$(document).on("change","select[id='temp_pc_type']", function(){
390
391    var endtag = boxEndtag;
392    var pc_type = $(this).val();
393
394    //first, remove all the existing suboptions
395    $("#temp_pc_type").nextAll().remove();//remove the options in the same level solver
396
397    if(pc_type == "fieldsplit") { //add the extra options that fieldsplit requires
398        appendExtraOptions("fieldsplit");
399        var defaults = getDefaults("fieldsplit",matInfo[endtag].symm,matInfo[endtag].posdef,matInfo[endtag].logstruc);
400        $("#temp_pc_fieldsplit_type").val(defaults.pc_fieldsplit_type);
401        $("#temp_pc_fieldsplit_blocks").val(defaults.pc_fieldsplit_blocks);
402    }
403    else if(pc_type == "mg") {
404        appendExtraOptions("mg");
405        var defaults = getDefaults("mg",matInfo[endtag].symm,matInfo[endtag].posdef,matInfo[endtag].logstruc);
406        $("#temp_pc_mg_type").val(defaults.pc_mg_type);
407        $("#temp_pc_mg_levels").val(defaults.pc_mg_levels);
408    }
409    else if(pc_type == "bjacobi") {
410        appendExtraOptions("bjacobi");
411        var defaults = getDefaults("bjacobi",matInfo[endtag].symm,matInfo[endtag].posdef,matInfo[endtag].logstruc);
412        $("#temp_pc_bjacobi_blocks").val(defaults.pc_bjacobi_blocks);
413    }
414    else if(pc_type == "gamg") {
415        appendExtraOptions("gamg");
416        var defaults = getDefaults("gamg",matInfo[endtag].symm,matInfo[endtag].posdef,matInfo[endtag].logstruc);
417        $("#temp_pc_gamg_type").val(defaults.pc_gamg_type);
418        $("#temp_pc_gamg_levels").val(defaults.pc_gamg_levels);
419    }
420    else if(pc_type == "redundant") {
421        appendExtraOptions("redundant");
422        var defaults = getDefaults("redundant",matInfo[endtag].symm,matInfo[endtag].posdef,matInfo[endtag].logstruc);
423        $("#temp_pc_redundant_number").val(defaults.pc_redundant_number);
424    }
425    else if(pc_type == "asm") {
426        appendExtraOptions("asm");
427        var defaults = getDefaults("asm",matInfo[endtag].symm,matInfo[endtag].posdef,matInfo[endtag].logstruc);
428        $("#temp_pc_asm_blocks").val(defaults.pc_asm_blocks);
429        $("#temp_pc_asm_overlap").val(defaults.pc_asm_overlap);
430    }
431
432    $("#tempInput").append("<br><input type=\"button\" value=\"Set Options\" id=\"setOptions\">"); //put the button back because we still want that (was removed in the nextAll().remove())
433});
434
435//remove the box when the user clicks sufficiently outside of it (still needs major debugging)
436/*$(document).on("click", function(e) {
437
438    if(e.pageX < (box_x-node_radius-5) || e.pageX > (box_x + box_size.width) || e.pageY < (box_y-node_radius-5)) {
439        //note: the reason we dont have the 'greater than y' term is because the dropdown menu goes below the box
440        removeBox();
441        //alert('removed');
442        //alert(e.pageX < (box_x-node_radius-5));
443        //alert(e.pageX > (box_x + box_size.width));
444        //alert(e.pageY < (box_y-node_radius-5));
445        console.log(e.pageX);
446        console.log(e.pageY);
447        boxPresent = false;
448    }
449});*/
450
451//upon a user click, present the user with the currently selected options that the user can change
452$(document).on("click","circle[id^='node']",function() {
453
454    var id     = $(this).attr("id");//really should not be used in this method. there are better ways of getting information
455    var endtag = id.substring(id.indexOf("0"),id.length);
456    var parentEndtag = getParent(endtag);
457    //scrollTo("solver"+endtag);
458    var x = $(this).attr("cx");
459    var y = $(this).attr("cy");
460
461    if(boxPresent && boxEndtag == endtag) { //user clicked the same node again
462        removeBox();
463        boxPresent = false;
464        return;
465    }
466    else if(boxPresent && boxEndtag != endtag) { //user clicked a different node
467        removeBox();
468        boxPresent = true;
469        boxEndtag = endtag;
470    }
471    else {
472        boxPresent = true;
473        boxEndtag = endtag;
474    }
475
476    //append an absolute-positioned div to display options for that node
477    var svgCanvas = $(this).parent().get(0);
478    var parent    = $(svgCanvas).parent().get(0);
479    var parent_x = parseFloat($(svgCanvas).offset().left) + parseFloat(x) + node_radius;
480    var parent_y = parseFloat($(svgCanvas).offset().top) + parseFloat(y) + node_radius;
481    $(parent).append("<div id=\"tempInput\" style=\"z-index:1;position:absolute;left:" + (parent_x) + "px;top:" + (parent_y) + "px;font-size:14px;opacity:1;border:2px solid lightblue;border-radius:" + node_radius + "px;\"></div>");
482    $("#tempInput").css("background", "#dddddd");
483
484    box_x = parent_x;
485    box_y = parent_y;
486
487    var childNum = endtag.substring(endtag.lastIndexOf("_")+1, endtag.length);
488
489    var solverText = "";
490    if(endtag == "0")
491        solverText = "<b>Root Solver Options (Matrix is <input type=\"checkbox\" id=\"temp_symm" + "\">symmetric,  <input type=\"checkbox\" id=\"temp_posdef" + "\">positive definite, <input type=\"checkbox\" id=\"temp_logstruc" + "\">block structured)</b>";
492    else if(matInfo[parentEndtag].pc_type == "bjacobi")
493        solverText = "<b>" + "Bjacobi Solver Options" + "</b>";
494    else if(matInfo[parentEndtag].pc_type == "fieldsplit")
495        solverText = "<b>Fieldsplit " + childNum + " Options (Matrix is <input type=\"checkbox\" id=\"temp_symm" + "\">symmetric,  <input type=\"checkbox\" id=\"temp_posdef" + "\">positive definite, <input type=\"checkbox\" id=\"temp_logstruc" + "\">block structured)</b>";
496    else if(matInfo[parentEndtag].pc_type == "redundant")
497        solverText = "<b>" + "Redundant Solver Options" + "</b>";
498    else if(matInfo[parentEndtag].pc_type == "asm")
499        solverText = "<b>" + "ASM Solver Options" + "</b>";
500    else if(matInfo[parentEndtag].pc_type == "ksp")
501        solverText = "<b>" + "KSP Solver Options" + "</b>";
502    else if(matInfo[parentEndtag].pc_type == "mg" || matInfo[parentEndtag].pc_type == "gamg") {
503        if(childNum == 0) //coarse grid solver (level 0)
504            solverText = "<b> Coarse Grid Solver (Level 0)  </b>";
505        else
506            solverText = "<b>Smoothing (Level " + childNum + ")  </b>";
507    }
508
509    $("#tempInput").append(solverText);
510    $("#tempInput").append("<br><b>KSP &nbsp;&nbsp;&nbsp;&nbsp;</b><select id=\"temp_ksp_type" + "\"></select>");
511    $("#tempInput").append("<br><b>PC  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</b><select id=\"temp_pc_type" + "\"></select>");
512
513    populateList("pc",endtag,"#temp_pc_type"); //this is kind of stupid right now. I'll fix this later
514    populateList("ksp",endtag,"#temp_ksp_type");
515    $("#temp_pc_type").val(matInfo[endtag].pc_type);
516    $("#temp_ksp_type").val(matInfo[endtag].ksp_type);
517
518    //fill in the currently selected properties
519    if(matInfo[endtag].symm)
520        $("#temp_symm").attr("checked", true);
521    if(matInfo[endtag].posdef)
522        $("#temp_posdef").attr("checked", true);
523    if(matInfo[endtag].logstruc)
524        $("#temp_logstruc").attr("checked", true);
525
526    if(matInfo[endtag].pc_type == "fieldsplit") { //append extra options for fieldsplit
527        appendExtraOptions("fieldsplit");
528        $("#temp_pc_fieldsplit_type").val(matInfo[endtag].pc_fieldsplit_type);
529        $("#temp_pc_fieldsplit_blocks").val(matInfo[endtag].pc_fieldsplit_blocks);
530    }
531    else if(matInfo[endtag].pc_type == "bjacobi") { //append extra options for bjacobi
532        appendExtraOptions("bjacobi");
533        $("#temp_pc_bjacobi_blocks").val(matInfo[endtag].pc_bjacobi_blocks);
534    }
535    else if(matInfo[endtag].pc_type == "redundant") {
536        appendExtraOptions("redundant");
537        $("#temp_pc_redundant_number").val(matInfo[endtag].pc_redundant_number);
538    }
539    else if(matInfo[endtag].pc_type == "asm") {
540        appendExtraOptions("asm");
541        $("#temp_pc_asm_blocks").val(matInfo[endtag].pc_asm_blocks);
542        $("#temp_pc_asm_overlap").val(matInfo[endtag].pc_asm_overlap);
543    }
544    else if(matInfo[endtag].pc_type == "mg") {
545        appendExtraOptions("mg");
546        $("#temp_pc_mg_type").val(matInfo[endtag].pc_mg_type);
547        $("#temp_pc_mg_levels").val(matInfo[endtag].pc_mg_levels);
548    }
549    else if(matInfo[endtag].pc_type == "gamg") {
550        appendExtraOptions("gamg");
551        $("#temp_pc_gamg_type").val(matInfo[endtag].pc_gamg_type);
552        $("#temp_pc_gamg_levels").val(matInfo[endtag].pc_gamg_levels);
553    }
554
555    //append the submit button
556    $("#tempInput").append("<br><input type=\"button\" value=\"Set Options\" id=\"setOptions\">");
557
558    box_size = {
559        height: $("#tempInput").height(),
560        width: $("#tempInput").width()
561    };
562
563});
564
565//this function only appends the appropriate html. it does NOT select the appropriate defaults
566function appendExtraOptions(pc_type) {
567
568    if(pc_type == "fieldsplit") { //append extra options for fieldsplit
569        $("#tempInput").append("<br><b>Fieldsplit Type &nbsp;&nbsp;</b><select id=\"temp_pc_fieldsplit_type" + "\"></select>");
570        $("#tempInput").append("<br><b>Fieldsplit Blocks </b><input type='text' id=\"temp_pc_fieldsplit_blocks" + "\" maxlength='4'>");
571        populateList("fieldsplit","", "#temp_pc_fieldsplit_type");
572    }
573    else if(pc_type == "bjacobi") { //append extra options for bjacobi
574        $("#tempInput").append("<br><b>Bjacobi Blocks </b><input type='text' id=\'temp_pc_bjacobi_blocks" + "\' maxlength='4'>");
575    }
576    else if(pc_type == "redundant") {
577        $("#tempInput").append("<br><b>Redundant Number </b><input type='text' id=\'temp_pc_redundant_number" + "\' maxlength='4'>");
578    }
579    else if(pc_type == "asm") {
580        $("#tempInput").append("<br><b>ASM blocks   &nbsp;&nbsp;</b><input type='text' id=\"temp_pc_asm_blocks" + "\" maxlength='4'>");
581	$("#tempInput").append("<br><b>ASM overlap   </b><input type='text' id=\"temp_pc_asm_overlap" + "\" maxlength='4'>");
582    }
583    else if(pc_type == "mg") {
584        $("#tempInput").append("<br><b>MG Type &nbsp;&nbsp;</b><select id=\"temp_pc_mg_type" + "\"></select>");
585        $("#tempInput").append("<br><b>MG Levels </b><input type='text' id=\'temp_pc_mg_levels" + "\' maxlength='4'>");
586        populateList("mg","","#temp_pc_mg_type");
587    }
588    else if(pc_type == "gamg") {
589        $("#tempInput").append("<br><b>GAMG Type &nbsp;&nbsp;</b><select id=\"temp_pc_gamg_type" + "\"></select>");
590        $("#tempInput").append("<br><b>GAMG Levels </b><input type='text' id=\'temp_pc_gamg_levels" + "\' maxlength='4'>");
591        populateList("gamg","","#temp_pc_gamg_type");
592    }
593}
594
595//deletes all children from matInfo
596function deleteAllChildren(endtag) {
597
598    var numChildren = getNumChildren(matInfo, endtag);
599
600    for(var i=0; i<numChildren; i++) {
601        var childEndtag = endtag + "_" + i;
602
603        if(getNumChildren(matInfo, childEndtag) > 0)//this child has more children
604        {
605            removeAllChildren(childEndtag);//recursive call to remove all children of that child
606        }
607        delete matInfo[childEndtag];
608        $("#solver" + childEndtag).remove();
609    }
610
611    //adjust variables in matInfo (shouldn't really be needed)
612    if(matInfo[endtag].pc_type == "mg") {
613        matInfo[endtag].pc_mg_levels = 0;
614    }
615    else if(matInfo[endtag].pc_type == "gamg") {
616        matInfo[endtag].pc_gamg_levels = 0;
617    }
618    else if(matInfo[endtag].pc_type == "fieldsplit") {
619        matInfo[endtag].pc_fieldsplit_blocks = 0;
620    }
621}
622