1 | ######################################################### |
---|
2 | # |
---|
3 | # |
---|
4 | # Read in a data file stored in the mg_cell data format. |
---|
5 | # |
---|
6 | # mg_cell is a code written by Linda Stals for parallel |
---|
7 | # mulitgrid solver based on adaptive finite elements. The |
---|
8 | # reason this code is used is because it gives a grid |
---|
9 | # partition. |
---|
10 | # |
---|
11 | # This is only intended as a temporary file, once an |
---|
12 | # automatic grid partitioner has been incorporated this |
---|
13 | # file will become redundant. |
---|
14 | # |
---|
15 | # Authors: Linda Stals and Matthew Hardy, June 2005 |
---|
16 | # |
---|
17 | # |
---|
18 | ######################################################### |
---|
19 | |
---|
20 | from string import atoi |
---|
21 | from string import atof |
---|
22 | from string import split |
---|
23 | |
---|
24 | |
---|
25 | ######################################################### |
---|
26 | # Read in a mg_cell file. It is assumed that the file |
---|
27 | # has a very specific format. An example file is given in |
---|
28 | # test_3l_2c.out. |
---|
29 | # |
---|
30 | # *) The mg_cell data-structure is a node-based |
---|
31 | # data-structure, consequently the same triangle will |
---|
32 | # appear three times (mg_cell outputs all of the triangles |
---|
33 | # connected to a given node). |
---|
34 | # |
---|
35 | # *) The node labels are given in terms of the global ID, |
---|
36 | # which may be thought of as a string (e.g. 12_2), this |
---|
37 | # needs to be converted into an integer format for the GA |
---|
38 | # data structure. |
---|
39 | # |
---|
40 | # *) It is necessary to specify the boundary conditions, |
---|
41 | # which has been done in mg_cel by outputing the edges |
---|
42 | # with a tag. If the tag is negative the edge is an |
---|
43 | # interior edge, if the tag is positive it is a boundary |
---|
44 | # edge. Different boundary conditions will be given |
---|
45 | # different tags. |
---|
46 | # |
---|
47 | # ------------------------------------------------------- |
---|
48 | # |
---|
49 | # *) The information returned by this routine is the |
---|
50 | # nodes, triangles, boundary edges and the number of |
---|
51 | # triangles to be assigned to each processor. All of the |
---|
52 | # node labels are still stored by the global ID. |
---|
53 | # |
---|
54 | ######################################################### |
---|
55 | def readmg(f): |
---|
56 | |
---|
57 | # read the nuber of processors |
---|
58 | |
---|
59 | f.readline() |
---|
60 | no_proc = atoi(f.readline().split()[0]) |
---|
61 | |
---|
62 | # skip over additional information not needed |
---|
63 | |
---|
64 | for i in range(5): |
---|
65 | f.readline(); |
---|
66 | |
---|
67 | # nodes list |
---|
68 | |
---|
69 | nodes = [] |
---|
70 | |
---|
71 | # boundary edge list |
---|
72 | |
---|
73 | edges = [] |
---|
74 | |
---|
75 | # triangle list |
---|
76 | |
---|
77 | triangles = [] |
---|
78 | |
---|
79 | # know first nodes_per_proc[0] belong to cell 0, next |
---|
80 | # nodes_per_proc[1] belong to cell 1 etc. |
---|
81 | |
---|
82 | nodes_per_proc = [] |
---|
83 | triangles_per_proc = [] |
---|
84 | |
---|
85 | # loop over the processors |
---|
86 | |
---|
87 | for q in range(no_proc): |
---|
88 | |
---|
89 | # read the nodes |
---|
90 | |
---|
91 | no_nodes = atoi(f.readline().split()[1]) |
---|
92 | nodes_per_proc.append(no_nodes) |
---|
93 | f.readline() |
---|
94 | |
---|
95 | for i in range(no_nodes): |
---|
96 | line = f.readline().split() |
---|
97 | line[1:3] = map(atof, line[1:3]) |
---|
98 | nodes.append(line[0:3]) |
---|
99 | |
---|
100 | # read the edges |
---|
101 | |
---|
102 | f.readline() |
---|
103 | no_edges = atoi(f.readline().split()[1]) |
---|
104 | f.readline() |
---|
105 | |
---|
106 | for i in range(no_edges): |
---|
107 | line = f.readline().split() |
---|
108 | if (atoi(line[2]) >= 0): |
---|
109 | edges.append(line) |
---|
110 | |
---|
111 | # read the triangles |
---|
112 | |
---|
113 | f.readline(), f.readline(), f.readline() |
---|
114 | no_triangles = atoi(f.readline().split()[1]) |
---|
115 | f.readline() |
---|
116 | |
---|
117 | # remove any triangles that have been repeated |
---|
118 | |
---|
119 | for i in range(no_triangles): |
---|
120 | line = f.readline().split() |
---|
121 | line.sort() |
---|
122 | if (len(triangles)==0): |
---|
123 | triangles.append(line) |
---|
124 | continue |
---|
125 | |
---|
126 | for t in range(len(triangles)): |
---|
127 | if (triangles[t]==line): |
---|
128 | break |
---|
129 | if (triangles[t]!=line): |
---|
130 | triangles.append(line) |
---|
131 | |
---|
132 | # keep a record of how many triangles belong to each processor |
---|
133 | |
---|
134 | no_triangles=len(triangles)-sum(triangles_per_proc) |
---|
135 | triangles_per_proc.append(no_triangles) |
---|
136 | |
---|
137 | # skip extra space |
---|
138 | |
---|
139 | f.readline() |
---|
140 | f.readline() |
---|
141 | f.readline() |
---|
142 | f.readline() |
---|
143 | |
---|
144 | # return the nodes, triangles, boundary edges and the number of triangles |
---|
145 | # to be assigned to each processor |
---|
146 | |
---|
147 | return nodes, triangles, edges, triangles_per_proc |
---|
148 | |
---|
149 | |
---|
150 | ######################################################### |
---|
151 | # Convert the format of the data to that used by |
---|
152 | # pyvolution |
---|
153 | # |
---|
154 | # |
---|
155 | # *) Change the nodes global ID's to an integer value, |
---|
156 | #starting from 0. |
---|
157 | # |
---|
158 | # *) The triangles and boundary edges must also be |
---|
159 | # updated accordingly. |
---|
160 | # |
---|
161 | # ------------------------------------------------------- |
---|
162 | # |
---|
163 | # *) The nodes, triangles and boundary edges defined by |
---|
164 | # the new numbering scheme are returned |
---|
165 | # |
---|
166 | ######################################################### |
---|
167 | |
---|
168 | def restructure(nodes, triangles, edges): |
---|
169 | Nnodes =len(nodes) |
---|
170 | Ntriangles = len(triangles) |
---|
171 | |
---|
172 | index={} #a dictionary mapping existing node ids to the new ids 0,1,2,... |
---|
173 | |
---|
174 | GAnodes = [] |
---|
175 | |
---|
176 | for node_idnew in range(Nnodes): #move through the list of nodes, renumbering to 0,1,2, ... |
---|
177 | index[nodes[node_idnew][0]]=node_idnew #make the dictionary entry, for later use by triangles |
---|
178 | GAnodes.append(nodes[node_idnew][1:3]) |
---|
179 | # nodes[node_idnew][0]=node_idnew #renumber the node |
---|
180 | |
---|
181 | GAedges = {} |
---|
182 | for e in edges: |
---|
183 | GAedges[index[e[0]]]=[] |
---|
184 | for e in edges: |
---|
185 | GAedges[index[e[0]]].append([index[e[1]],e[2]]) |
---|
186 | |
---|
187 | #Now loop over the triangles, changing the node ids and orientation. |
---|
188 | for t in range(Ntriangles): |
---|
189 | for i in range(3): |
---|
190 | n=index[triangles[t][i]] #use the dictionary to get the new node id |
---|
191 | triangles[t][i]=n #relabel the node |
---|
192 | |
---|
193 | |
---|
194 | del(index) #delete the dictionary |
---|
195 | |
---|
196 | return GAnodes, triangles, GAedges |
---|
197 | |
---|
198 | |
---|
199 | ######################################################### |
---|
200 | # |
---|
201 | # Reorientate the triangles |
---|
202 | # |
---|
203 | # |
---|
204 | # *) The ordering of the nodes in the triangles may need |
---|
205 | # be changed to ensure the correct orientation. |
---|
206 | # |
---|
207 | # ------------------------------------------------------- |
---|
208 | # |
---|
209 | # *) The modified list of triangles is returned |
---|
210 | # |
---|
211 | ######################################################### |
---|
212 | def reorient(nodes, triangles): |
---|
213 | |
---|
214 | |
---|
215 | Nnodes =len(nodes) |
---|
216 | Ntriangles = len(triangles) |
---|
217 | |
---|
218 | #Now loop over the triangles, changing the node ids and orientation. |
---|
219 | for t in range(Ntriangles): |
---|
220 | x=[] #x-coordinates of the three nodes (vertices) |
---|
221 | y=[] #y-coordinates of the three nodes (vertices) |
---|
222 | for i in range(3): |
---|
223 | n=triangles[t][i] #use the dictionary to get the new node id |
---|
224 | x.append(nodes[n][0]) |
---|
225 | y.append(nodes[n][1]) |
---|
226 | if ((x[1]-x[0])*(y[2]-y[0])-(x[2]-x[0])*(y[1]-y[0])<0): #need to change the orientation |
---|
227 | triangles[t][2]=triangles[t][0]#swap the 0th and 2nd nodes |
---|
228 | triangles[t][0]=n |
---|
229 | |
---|
230 | del(x) |
---|
231 | del(y) |
---|
232 | |
---|
233 | return triangles |
---|
234 | |
---|
235 | |
---|
236 | ######################################################### |
---|
237 | # |
---|
238 | # Put the boundary edge information into a form compatible |
---|
239 | # with the GA datastructure |
---|
240 | # |
---|
241 | # *) The GA datastructure assumes that the boundary edge |
---|
242 | # information is stored in a dictionary. The dictionary |
---|
243 | # key is a list [ti, ei], where ti is the triangle number |
---|
244 | # and ei (0 <= ei < 2) is the edge number for the triangle |
---|
245 | # ti. The value assigned to the given key is the boundary |
---|
246 | # tag. |
---|
247 | # |
---|
248 | # ------------------------------------------------------- |
---|
249 | # |
---|
250 | # *) The boundary edge information is returned. |
---|
251 | ######################################################### |
---|
252 | def mesh_boundary(triangles, edges): |
---|
253 | |
---|
254 | # intialise the boundary dictionary |
---|
255 | |
---|
256 | boundary = {} |
---|
257 | |
---|
258 | # loop over all of the triangles |
---|
259 | |
---|
260 | for i in range(len(triangles)): |
---|
261 | |
---|
262 | # given a particular triangle |
---|
263 | |
---|
264 | t = triangles[i] |
---|
265 | |
---|
266 | # is the first vertex a boundary node? |
---|
267 | |
---|
268 | if (edges.has_key(t[0])): |
---|
269 | |
---|
270 | # check to see if the triangles has a boundary |
---|
271 | # edge |
---|
272 | |
---|
273 | for b in edges[t[0]]: |
---|
274 | if (b[0] == t[1]): |
---|
275 | boundary[i, 2] = b[1] |
---|
276 | elif (b[0] == t[2]): |
---|
277 | boundary[i, 1] = b[1] |
---|
278 | |
---|
279 | # is the second vertex a boundary node? |
---|
280 | |
---|
281 | if (edges.has_key(t[1])): |
---|
282 | |
---|
283 | # check to see if the triangles has a boundary |
---|
284 | # edge |
---|
285 | |
---|
286 | for b in edges[t[1]]: |
---|
287 | if (b[0] == t[0]): |
---|
288 | boundary[i, 2] = b[1] |
---|
289 | elif (b[0] == t[2]): |
---|
290 | boundary[i, 0] = b[1] |
---|
291 | |
---|
292 | # is the third vertex a boundary node? |
---|
293 | |
---|
294 | if (edges.has_key(t[2])): |
---|
295 | |
---|
296 | # check to see if the triangles has a boundary |
---|
297 | # edge |
---|
298 | |
---|
299 | for b in edges[t[2]]: |
---|
300 | if (b[0] == t[0]): |
---|
301 | boundary[i, 1] = b[1] |
---|
302 | elif (b[0] == t[1]): |
---|
303 | boundary[i, 0] = b[1] |
---|
304 | |
---|
305 | # return the boundary information |
---|
306 | |
---|
307 | return boundary |
---|
308 | |
---|
309 | |
---|
310 | ######################################################### |
---|
311 | # |
---|
312 | # Read the nodes, triangles and boundary information from |
---|
313 | # given file |
---|
314 | # |
---|
315 | # *) The information in the file is stored using the |
---|
316 | # mg_cell format. |
---|
317 | # |
---|
318 | # *) See the documentation of the previous functions. |
---|
319 | # |
---|
320 | # ------------------------------------------------------- |
---|
321 | # |
---|
322 | # *The information returned by this routine includes the |
---|
323 | # nodes, triangles, boundary edges and the number of |
---|
324 | # triangles to be assigned to each processor. |
---|
325 | # |
---|
326 | ######################################################### |
---|
327 | |
---|
328 | def mg2ga(f): |
---|
329 | |
---|
330 | # read in the information from the file |
---|
331 | |
---|
332 | [nodes, triangles, edges, triangles_per_proc] = readmg(f) |
---|
333 | |
---|
334 | # change the node numbering scheme to be compatible |
---|
335 | # with the GA datastructure |
---|
336 | |
---|
337 | [nodes, triangles, edges] = restructure(nodes, triangles, edges) |
---|
338 | |
---|
339 | # makesure the triangles are orientated in the correct |
---|
340 | # way |
---|
341 | triangles = reorient(nodes, triangles) |
---|
342 | |
---|
343 | # collect the boundary edge information |
---|
344 | |
---|
345 | boundary = mesh_boundary(triangles, edges) |
---|
346 | |
---|
347 | # return the information |
---|
348 | |
---|
349 | return nodes, triangles, boundary, triangles_per_proc |
---|