xref: /petsc/share/petsc/saws/js/drawDiagrams.js (revision 37d05b0256c1e9ba4bc423c4eccb3df226931ef0)
1//this recursive function should always be called on the root solver (endtag = "0").
2//targetEndtag is the endtag of the solver option that is currently being asked. the reason we have this as a parameter is because there is simply not enough space to display a diagram of the ENTIRE solver. so, we only display a path to the current solver option
3//x,y are the x and y coordinates of the upper lefthand corner of the svg (should initially be called with 0,0)
4//this function returns a string that needs to be put into an svg in the html page
5function drawDiagrams(data,endtag,targetEndtag,x,y) {
6
7    if(data["0"].x_extreme == undefined)
8        data["0"].x_extreme = 0;
9    if(data["0"].y_extreme == undefined)
10        data["0"].y_extreme = 0;
11
12    var numChildren = getNumChildren(data,endtag);
13
14    if(numChildren == 0) //base case. no children.
15        return "";
16    if(targetEndtag.indexOf(endtag) != 0) //base case. endtag is not on the path to targetEndtag.
17        return "";
18
19    var ret   = "";
20
21    if(data[endtag].pc_type == "fieldsplit") {
22        if(x+400 > data["0"].x_extreme)
23            data["0"].x_extreme = x+400;
24        if(y+400 > data["0"].y_extreme)
25            data["0"].y_extreme = y+400;
26    }
27    else if(data[endtag].pc_type == "mg") {
28        var mg_levels = data[endtag].mg_levels;
29        var global_downshift = 141*mg_levels + 68*mg_levels;
30        if(x+465 > data["0"].x_extreme)
31            data["0"].x_extreme = x+465;
32        if(y+global_downshift > data["0"].y_extreme)
33            data["0"].y_extreme = y+global_downshift;
34    }
35
36    if(data[endtag].pc_type == "fieldsplit") { //draw fieldsplit diagram
37        var colors = ["green","blue","red"];
38        var layer = 0;
39        ret += "<polygon points=\""+x+","+y+" "+(x+400)+","+y+" "+(x+400)+","+(y+400)+" "+x+","+(y+400)+"\" style=\"fill:khaki;stroke:black;stroke-width:1\"></polygon>";
40        layer = 1;
41
42        function drawFieldsplit(data,endtag,level,targetEndtag,x,y,size) { //(x,y) is the upper lefthand corner. size is the size of one side of the parent square (in pixels)
43            //work = draw the children of the fieldsplit then call draw on each child
44            if(targetEndtag.indexOf(endtag) != 0)
45                return ""; //endtag is not on the path to the targetEndtag
46
47            var ret = "";
48
49            var numChildren = getNumChildren(data,endtag);
50            if(numChildren == 0)
51                return;
52            var colorNum = level;//the depth of the fieldsplit within other fieldsplits
53
54            for(var i=0; i<numChildren; i++) {
55                var side   = size/(numChildren+1);//leave one extra block of space
56                var curr_x = x + i*side;
57                var curr_y = y + i*side;
58
59                ret += "<polygon points=\""+curr_x+","+curr_y+" "+(curr_x+side)+","+curr_y+" "+(curr_x+side)+","+(curr_y+side)+" "+curr_x+","+(curr_y+side)+"\" style=\"fill:"+colors[colorNum]+";stroke:black;stroke-width:1\"></polygon>";
60
61                var childEndtag = endtag + "_" + i;
62                //only draw if child is indeed a fieldsplit
63
64                if(data[childEndtag] != undefined && data[childEndtag].pc_type == "fieldsplit")
65                    ret += drawFieldsplit(data,childEndtag, level+1, targetEndtag, curr_x, curr_y, size/numChildren);
66
67                //if child is mg, then it is time to switch drawing methods
68                else if(data[childEndtag] != undefined && data[childEndtag].pc_type == "mg") {
69                    var possible = drawDiagrams(data,childEndtag,targetEndtag,x+size+20+146,y+i*side);
70                    if(possible != "") {//don't draw the arrow if there is no diagram following
71                        ret += "<image x=\""+(x+size+20)+"\" y=\""+(y+i*side+side/2-13)+"\" width=\"146\" height=\"26\" xlink:href=\"images/arrow.png\"></image>";
72                        ret += possible;
73                    }
74                }
75            }
76            var side = size/(numChildren+1);//side of the blank square
77            var blank_x = x + numChildren*side;
78            var blank_y = y + numChildren*side;
79
80            var inc = side/4;//the increment
81            for(var i=1; i<4; i++) { //add diagonal ellipsis
82                var x_coord = blank_x + i*inc;
83                var y_coord = blank_y + i*inc;
84                ret += "<circle cx=\""+x_coord+"\" cy=\"" + y_coord + "\" r=\"2\" stroke=\"black\" stroke-width=\"2\" fill=\"black\"></circle>";
85            }
86
87            return ret;
88        }
89        ret += drawFieldsplit(data,endtag,0,targetEndtag,x,y,400);
90    }
91
92    else if(data[endtag].pc_type == "mg") { //draw multigrid diagram. multigrid diagram doesn't use an inner recursive function because it's not that complex to draw.
93
94        var selectedChild = "";
95
96        //generate a parallelogram for each layer
97        for(var i=0; i<numChildren; i++) { //i represents the multigrid level (i=0 would be coarse)
98            var dim = 3+2*i;//dimxdim grid
99            var global_downshift = 141*i + 68*i;
100
101            ret += "<polygon points=\""+x+","+(y+141+global_downshift)+" "+ (x+141)+","+(y+global_downshift)+" "+(x+465)+","+(y+global_downshift)+" "+(x+324)+","+(y+141+global_downshift)+"\" style=\"fill:khaki;stroke:black;stroke-width:1\"> </polygon>";
102
103            for(var j=1; j<dim; j++) {//draw 'vertical' lines
104                var inc = 324/dim;//parallogram is 324 wide and 200 on the slant side (1.6x)
105                var shift = j*inc;
106                var top_shift = shift + 141;
107                ret += "<line x1=\""+(x+shift)+"\" y1=\""+(y+141+global_downshift)+"\" x2=\""+(x+top_shift)+"\" y2=\""+(y+global_downshift)+"\" style='stroke:black;stroke-width:1'></line>";
108            }
109            for(var j=1; j<dim; j++) {//draw horizontal lines
110                var inc = 141/dim;//parallelogram is 141 tall
111                var horiz_shift = (141/dim) * j;
112                var horiz_shift_end = horiz_shift + 324;
113
114                var shift = 141 - inc * j;
115                ret += "<line x1=\""+(x+horiz_shift)+"\" y1=\""+(y+shift+global_downshift) +"\" x2=\""+(x+horiz_shift_end)+"\" y2=\""+(y+shift+global_downshift)+"\" style='stroke:black;stroke-width:1'></line>";
116            }
117
118            if(i != numChildren-1)//add transition arrows image if there are more grids left
119                ret += "<image x=\""+x+"\" y=\""+(y+141+global_downshift)+"\" width=\"349\" height=\"68\" xlink:href=\"/images/transition.bmp\"/>"; //images in svg are handled differently. can't simply use <img>
120
121            //if the current child is the one that is on the path to the target, then record it
122            var childEndtag = endtag + "_" + i;
123
124            if(targetEndtag.indexOf(childEndtag) == 0) { //this can only happen with 1 child (the one that is on the path to the target)
125                selectedChild = i;
126            }
127        }
128
129        var new_x = x + 465;
130        var new_y = y + (selectedChild) * (141+68);//manipulate based on selectedChild
131
132        //recursively draw the rest of the path to targetEndtag
133
134        var possible  = drawDiagrams(data,endtag+"_"+selectedChild,targetEndtag,new_x+146,new_y);
135        if(possible != "") {//only add the arrow if something was actually drawn
136            ret += "<image x=\""+(new_x-45)+"\" y=\""+(new_y+70)+"\" width=\"146\" height=\"26\" xlink:href=\"images/arrow.png\"></image>";
137            ret += possible;
138        }
139    }
140
141    return ret;
142}
143