Actual source code: tri2d.c
1: #ifdef PETSC_RCS_HEADER
2: static char vcid[] = "$Id: tri2d.c,v 1.38 2000/10/17 13:48:55 knepley Exp $";
3: #endif
5: /* Implements 2d triangular grids */
6: #include "src/mesh/impls/triangular/2d/2dimpl.h" /*I "mesh.h" I*/
7: #include "tri2dView.h"
8: #include "tri2dCSR.h"
9: #ifdef PETSC_HAVE_TRIANGLE
10: #include "tri2d_Triangle.h"
11: #endif
13: extern int PartitionGhostNodeIndex_Private(Partition, int, int *);
14: EXTERN_C_BEGIN
15: int MeshSerialize_Triangular_2D(MPI_Comm, Mesh *, PetscViewer, PetscTruth);
16: EXTERN_C_END
18: /*--------------------------------------------- Public Functions ----------------------------------------------------*/
19: /*@C
20: MeshTriangular2DCalcAreas - Calculate and store the area of each element
22: Collective on Mesh
24: Input Parameters:
25: + mesh - The mesh
26: - create - The flag which creates the storage if it does not already exist
28: Note:
29: If areas have not been calculated before, and 'create' is PETSC_FALSE,
30: then no action taken.
32: Level: beginner
34: .keywords: mesh, element, area
35: .seealso: MeshTriangular2DCalcAspectRatios()
36: @*/
37: int MeshTriangular2DCalcAreas(Mesh mesh, PetscTruth create)
38: {
39: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
40: int numFaces = mesh->numFaces;
41: int numCorners = mesh->numCorners;
42: int *faces = tri->faces;
43: double *nodes = tri->nodes;
44: double x21, x31, y21, y31;
45: int elem;
46: int ierr;
49: if (tri->areas || create == PETSC_TRUE)
50: {
51: if (tri->areas) {
52: PetscFree(tri->areas);
53: }
54: PetscMalloc(numFaces * sizeof(double), &tri->areas);
55: for(elem = 0; elem < numFaces; elem++)
56: {
57: if (mesh->isPeriodic == PETSC_TRUE) {
58: x21 = MeshPeriodicDiffX(mesh, nodes[faces[elem*numCorners+1]*2] - nodes[faces[elem*numCorners]*2]);
59: y21 = MeshPeriodicDiffY(mesh, nodes[faces[elem*numCorners+1]*2+1] - nodes[faces[elem*numCorners]*2+1]);
60: x31 = MeshPeriodicDiffX(mesh, nodes[faces[elem*numCorners+2]*2] - nodes[faces[elem*numCorners]*2]);
61: y31 = MeshPeriodicDiffY(mesh, nodes[faces[elem*numCorners+2]*2+1] - nodes[faces[elem*numCorners]*2+1]);
62: } else {
63: x21 = nodes[faces[elem*numCorners+1]*2] - nodes[faces[elem*numCorners]*2];
64: y21 = nodes[faces[elem*numCorners+1]*2+1] - nodes[faces[elem*numCorners]*2+1];
65: x31 = nodes[faces[elem*numCorners+2]*2] - nodes[faces[elem*numCorners]*2];
66: y31 = nodes[faces[elem*numCorners+2]*2+1] - nodes[faces[elem*numCorners]*2+1];
67: }
68: tri->areas[elem] = PetscAbsReal(x21*y31 - x31*y21)/2.0;
69: }
70: PetscLogFlops(numFaces*8);
71: }
72: return(0);
73: }
75: /*@C
76: MeshTriangular2DCalcAspectRatios - Calculate and store the aspect ratio of each element
78: Collective on Mesh
80: Input Parameters:
81: + mesh - The mesh
82: - create - The flag which creates the storage if it does not already exist
84: Note:
85: If aspect ratios have not been calculated before, and 'create' is PETSC_FALSE,
86: then no action taken.
88: Level: beginner
90: .keywords: mesh, element, aspect ratio
91: .seealso: MeshTriangular2DCalcAreas()
92: @*/
93: int MeshTriangular2DCalcAspectRatios(Mesh mesh, PetscTruth create)
94: {
95: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
96: int numFaces = mesh->numFaces;
97: int numCorners = mesh->numCorners;
98: int *faces = tri->faces;
99: double *nodes = tri->nodes;
100: double x21, x31, x32, y21, y31, y32;
101: double area;
102: int elem;
103: int ierr;
106: if (tri->aspectRatios || create == PETSC_TRUE)
107: {
108: if (tri->aspectRatios) {
109: PetscFree(tri->aspectRatios);
110: }
111: PetscMalloc(numFaces * sizeof(double), &tri->aspectRatios);
112: for(elem = 0; elem < numFaces; elem++)
113: {
114: if (mesh->isPeriodic == PETSC_TRUE) {
115: x21 = MeshPeriodicDiffX(mesh, nodes[faces[elem*numCorners+1]*2] - nodes[faces[elem*numCorners]*2]);
116: y21 = MeshPeriodicDiffY(mesh, nodes[faces[elem*numCorners+1]*2+1] - nodes[faces[elem*numCorners]*2+1]);
117: x31 = MeshPeriodicDiffX(mesh, nodes[faces[elem*numCorners+2]*2] - nodes[faces[elem*numCorners]*2]);
118: y31 = MeshPeriodicDiffY(mesh, nodes[faces[elem*numCorners+2]*2+1] - nodes[faces[elem*numCorners]*2+1]);
119: x32 = MeshPeriodicDiffX(mesh, nodes[faces[elem*numCorners+2]*2] - nodes[faces[elem*numCorners+1]*2]);
120: y32 = MeshPeriodicDiffY(mesh, nodes[faces[elem*numCorners+2]*2+1] - nodes[faces[elem*numCorners+1]*2+1]);
121: } else {
122: x21 = nodes[faces[elem*numCorners+1]*2] - nodes[faces[elem*numCorners]*2];
123: y21 = nodes[faces[elem*numCorners+1]*2+1] - nodes[faces[elem*numCorners]*2+1];
124: x31 = nodes[faces[elem*numCorners+2]*2] - nodes[faces[elem*numCorners]*2];
125: y31 = nodes[faces[elem*numCorners+2]*2+1] - nodes[faces[elem*numCorners]*2+1];
126: x32 = nodes[faces[elem*numCorners+2]*2] - nodes[faces[elem*numCorners+1]*2];
127: y32 = nodes[faces[elem*numCorners+2]*2+1] - nodes[faces[elem*numCorners+1]*2+1];
128: }
129: area = PetscAbsReal(x21*y31 - x31*y21);
130: tri->aspectRatios[elem] = PetscMax(x32*x32 + y32*y32, PetscMax(x21*x21 + y21*y21, x31*x31 + y31*y31)) / area;
131: }
132: PetscLogFlops(numFaces*19);
133: }
134: return(0);
135: }
137: /*--------------------------------------------- Private Functions ---------------------------------------------------*/
138: static int MeshDestroy_Triangular_2D(Mesh mesh)
139: {
140: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
141: int ierr;
144: if (tri->nodes != PETSC_NULL) {
145: PetscFree(tri->nodes);
146: PetscFree(tri->markers);
147: PetscFree(tri->degrees);
148: }
149: if (tri->nodesOld != PETSC_NULL) {
150: PetscFree(tri->nodesOld);
151: }
152: if (tri->edges != PETSC_NULL) {
153: PetscFree(tri->edges);
154: PetscFree(tri->edgemarkers);
155: }
156: if (tri->faces != PETSC_NULL) {
157: PetscFree(tri->faces);
158: }
159: if (tri->neighbors != PETSC_NULL) {
160: PetscFree(tri->neighbors);
161: }
162: if (tri->bdNodes != PETSC_NULL) {
163: PetscFree(tri->bdNodes);
164: PetscFree(tri->bdEdges);
165: PetscFree(tri->bdMarkers);
166: PetscFree(tri->bdBegin);
167: PetscFree(tri->bdEdgeBegin);
168: }
169: #if 0
170: if (tri->bdCtx != PETSC_NULL) {
171: MeshBoundaryDestroy(tri->bdCtx);
172: }
173: if (tri->bdCtxNew != PETSC_NULL) {
174: MeshBoundaryDestroy(tri->bdCtxNew);
175: }
176: #endif
177: if (tri->areas != PETSC_NULL) {
178: PetscFree(tri->areas);
179: }
180: if (tri->aspectRatios != PETSC_NULL) {
181: PetscFree(tri->aspectRatios);
182: }
183: PetscFree(tri);
184: if (mesh->support != PETSC_NULL) {
185: PetscFree(mesh->support);
186: }
187: PartitionDestroy(mesh->part);
188: if (mesh->nodeOrdering != PETSC_NULL) {
189: AODestroy(mesh->nodeOrdering);
190: }
191: if (mesh->coarseMap != PETSC_NULL) {
192: AODestroy(mesh->coarseMap);
193: }
195: return(0);
196: }
198: int MeshDebug_Triangular_2D(Mesh mesh, PetscTruth distributed)
199: {
200: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
201: Partition p = mesh->part;
202: Partition_Triangular_2D *q = PETSC_NULL;
203: int numBd = mesh->numBd;
204: int numElements = mesh->numFaces;
205: int numCorners = mesh->numCorners;
206: int numNodes = mesh->numNodes;
207: int *elements = tri->faces;
208: int *markers = tri->markers;
209: int *bdMarkers = tri->bdMarkers;
210: int degree;
211: int *support;
212: int *degrees;
213: int *supports;
214: int *sizes;
215: int numProcs, rank;
216: PetscTruth isMidnode;
217: int proc, bd, elem, nElem, sElem, sElem2, corner, node, newNode, size;
218: int ierr;
221: MPI_Comm_size(mesh->comm, &numProcs);
222: MPI_Comm_rank(mesh->comm, &rank);
223: if (p != PETSC_NULL) {
224: q = (Partition_Triangular_2D *) p->data;
225: }
227: /* Check basic sizes */
228: PetscMalloc(numProcs * sizeof(int), &sizes);
229: MPI_Allgather(&mesh->numBd, 1, MPI_INT, sizes, 1, MPI_INT, mesh->comm);
230: for(proc = 0, 0; proc < numProcs-1; proc++) {
231: if (sizes[proc] != sizes[proc+1]) {
232: PetscPrintf(mesh->comm, "The number of boundaries is different on proc %d(%d) and proc %d(%d)n",
233: proc, sizes[proc], proc+1, sizes[proc+1]);
234: 1;
235: }
236: }
237:
238: #if 0
239: /* I made vertices distributed in linear meshes */
240: MPI_Allgather(&tri->numVertices, 1, MPI_INT, sizes, 1, MPI_INT, mesh->comm);
241: for(proc = 0, 0; proc < numProcs-1; proc++) {
242: if (sizes[proc] != sizes[proc+1]) {
243: PetscPrintf(mesh->comm, "The number of vertices is different on proc %d(%d) and proc %d(%d)n",
244: proc, sizes[proc], proc+1, sizes[proc+1]);
245: 1;
246: }
247: }
248:
249: #endif
250: MPI_Allgather(&mesh->numCorners, 1, MPI_INT, sizes, 1, MPI_INT, mesh->comm);
251: for(proc = 0, 0; proc < numProcs-1; proc++) {
252: if (sizes[proc] != sizes[proc+1]) {
253: PetscPrintf(mesh->comm, "The number of face corners is different on proc %d(%d) and proc %d(%d)n",
254: proc, sizes[proc], proc+1, sizes[proc+1]);
255: 1;
256: }
257: }
258:
259: MPI_Allgather(&mesh->numBdEdges, 1, MPI_INT, sizes, 1, MPI_INT, mesh->comm);
260: for(proc = 0, 0; proc < numProcs-1; proc++) {
261: if (sizes[proc] != sizes[proc+1]) {
262: PetscPrintf(mesh->comm, "The number of boundary edges is different on proc %d(%d) and proc %d(%d)n",
263: proc, sizes[proc], proc+1, sizes[proc+1]);
264: 1;
265: }
266: }
267:
268: if (distributed == PETSC_FALSE) {
269: MPI_Allgather(&mesh->numNodes, 1, MPI_INT, sizes, 1, MPI_INT, mesh->comm);
270: for(proc = 0, 0; proc < numProcs-1; proc++) {
271: if (sizes[proc] != sizes[proc+1]) {
272: PetscPrintf(mesh->comm, "The number of nodes is different on proc %d(%d) and proc %d(%d)n",
273: proc, sizes[proc], proc+1, sizes[proc+1]);
274: 1;
275: }
276: }
277:
278: MPI_Allgather(&mesh->numBdNodes, 1, MPI_INT, sizes, 1, MPI_INT, mesh->comm);
279: for(proc = 0, 0; proc < numProcs-1; proc++) {
280: if (sizes[proc] != sizes[proc+1]) {
281: PetscPrintf(mesh->comm, "The number of boundary nodes is different on proc %d(%d) and proc %d(%d)n",
282: proc, sizes[proc], proc+1, sizes[proc+1]);
283: 1;
284: }
285: }
286:
287: MPI_Allgather(&mesh->numEdges, 1, MPI_INT, sizes, 1, MPI_INT, mesh->comm);
288: for(proc = 0, 0; proc < numProcs-1; proc++) {
289: if (sizes[proc] != sizes[proc+1]) {
290: PetscPrintf(mesh->comm, "The number of edges is different on proc %d(%d) and proc %d(%d)n",
291: proc, sizes[proc], proc+1, sizes[proc+1]);
292: 1;
293: }
294: }
295:
296: MPI_Allgather(&mesh->numFaces, 1, MPI_INT, sizes, 1, MPI_INT, mesh->comm);
297: for(proc = 0, 0; proc < numProcs-1; proc++) {
298: if (sizes[proc] != sizes[proc+1]) {
299: PetscPrintf(mesh->comm, "The number of faces is different on proc %d(%d) and proc %d(%d)n",
300: proc, sizes[proc], proc+1, sizes[proc+1]);
301: 1;
302: }
303: }
304:
305: } else {
306: MPI_Allreduce(&mesh->numNodes, &size, 1, MPI_INT, MPI_SUM, mesh->comm);
307: if (size != q->numNodes) {
308: SETERRQ2(PETSC_ERR_PLIB, "The total number of nodes %d should be %dn", size, q->numNodes);
309: }
310: #if 0
311: MPI_Allreduce(&tri->numBdNodes, &size, 1, MPI_INT, MPI_SUM, mesh->comm);
312: #else
313: size = mesh->numBdNodes;
314: #endif
315: if (size != q->numBdNodes) {
316: SETERRQ2(PETSC_ERR_PLIB, "The total number of boundary nodes %d should be %dn", size, q->numBdNodes);
317: }
318: MPI_Allreduce(&mesh->numEdges, &size, 1, MPI_INT, MPI_SUM, mesh->comm);
319: if (size != q->numEdges) {
320: SETERRQ2(PETSC_ERR_PLIB, "The total number of edges %d should be %dn", size, q->numEdges);
321: }
322: MPI_Allreduce(&mesh->numFaces, &size, 1, MPI_INT, MPI_SUM, mesh->comm);
323: if (size != mesh->part->numElements) {
324: SETERRQ2(PETSC_ERR_PLIB, "The total number of faces %d should be %dn", size, mesh->part->numElements);
325: }
326: }
327: PetscFree(sizes);
329: if (distributed == PETSC_FALSE) {
330: /* Check markers */
331: for(node = 0; node < numNodes; node++) {
332: if (!markers[node]) continue;
334: for(bd = 0; bd < numBd; bd++)
335: if(bdMarkers[bd] == markers[node])
336: break;
337: if (bd == numBd) {
338: SETERRQ2(PETSC_ERR_PLIB, "The marker %d for node %d is invalidn", markers[node], node);
339: }
340: }
341: /* Check mesh connectivity */
342: for(node = 0; node < numNodes; node++) {
343: MeshGetNodeSupport(mesh, node, 0, °ree, &support);
345: /* Check node degree */
346: PetscMalloc(numProcs * sizeof(int), °rees);
347: MPI_Allgather(°ree, 1, MPI_INT, degrees, 1, MPI_INT, mesh->comm);
348: for(proc = 0, 0; proc < numProcs-1; proc++)
349: if (degrees[proc] != degrees[proc+1]) {
350: PetscPrintf(mesh->comm, "Degree of node %d is different on proc %d(%d) and proc %d(%d)n",
351: node, proc, degrees[proc], proc+1, degrees[proc+1]);
352: PetscPrintf(mesh->comm, "Node Information:n");
353: PetscSequentialPhaseBegin(mesh->comm, 1);
354: PetscPrintf(PETSC_COMM_SELF, " Processor %dn", rank);
355: if ((rank == proc) || (rank == proc+1))
356: for(sElem = 0; sElem < degree; sElem++)
357: PetscPrintf(PETSC_COMM_SELF, " Support : %dn", support[sElem]);
358: PetscPrintf(PETSC_COMM_SELF, " Marker : %dn", tri->markers[node]);
359: PetscPrintf(PETSC_COMM_SELF, " Location : (%g,%g)n", tri->nodes[node*2], tri->nodes[node*2+1]);
360: PetscPrintf(PETSC_COMM_SELF, " In Elements:");
361: for(elem = 0, isMidnode = PETSC_FALSE; elem < numElements; elem++)
362: for(corner = 0; corner < numCorners; corner++)
363: if (elements[elem*numCorners+corner] == node) {
364: PetscPrintf(PETSC_COMM_SELF, " %d", elem);
365: if (corner >= 3)
366: isMidnode = PETSC_TRUE;
367: }
368: PetscPrintf(PETSC_COMM_SELF, "n");
369: if (isMidnode == PETSC_TRUE)
370: PetscPrintf(PETSC_COMM_SELF, " Midnoden");
371: else
372: PetscPrintf(PETSC_COMM_SELF, " Vertexn");
373: PetscSequentialPhaseEnd(mesh->comm, 1);
374: 1;
375: }
376:
377: PetscFree(degrees);
379: /* Check support elements */
380: PetscMalloc(degree*numProcs * sizeof(int), &supports);
381: MPI_Allgather(support, degree, MPI_INT, supports, degree, MPI_INT, mesh->comm);
382: for(sElem = 0, 0; sElem < degree; sElem++) {
383: nElem = supports[sElem];
384: for(proc = 1; proc < numProcs; proc++) {
385: for(sElem2 = 0; sElem2 < degree; sElem2++)
386: if (supports[proc*degree+sElem2] == nElem)
387: break;
388: if (sElem2 == degree) {
389: PetscPrintf(mesh->comm, "Support element %d of node %d on proc %d(%d) is not present on proc %dn",
390: sElem, node, 0, supports[sElem], proc);
391: PetscPrintf(mesh->comm, " Support of node %d on proc %d:n ", node, proc);
392: for(sElem2 = 0; sElem2 < degree; sElem2++)
393: PetscPrintf(mesh->comm, " %d", supports[proc*degree+sElem2]);
394: PetscPrintf(mesh->comm, "n");
395: 1;
396: }
397: }
398: }
399:
400: PetscFree(supports);
402: /* Check that node only appears inside elements in the support */
403: for(elem = 0, 0; elem < numElements; elem++)
404: for(corner = 0; corner < numCorners; corner++) {
405: newNode = elements[elem*numCorners+corner];
406: if (node == newNode) {
407: for(sElem = 0; sElem < degree; sElem++)
408: if (support[sElem] == elem)
409: break;
410: if (sElem == degree) {
411: PetscPrintf(mesh->comm, "Node %d found in element %d which is not present in the supportn",
412: node, elem);
413: 1;
414: }
415: }
416: }
417:
419: MeshRestoreNodeSupport(mesh, node, 0, °ree, &support);
420: }
421: } else {
422: /* Check markers */
423: for(node = 0; node < q->numOverlapNodes; node++) {
424: if (!markers[node]) continue;
426: for(bd = 0; bd < numBd; bd++)
427: if(bdMarkers[bd] == markers[node])
428: break;
429: if (bd == numBd) {
430: SETERRQ2(PETSC_ERR_PLIB, "The marker %d for node %d is invalidn", markers[node], node);
431: }
432: }
433: /* Check mesh connectivity */
434: for(node = 0; node < q->numLocNodes; node++) {
435: MeshGetNodeSupport(mesh, node, 0, °ree, &support);
437: /* Check that node only appears inside elements in the support */
438: for(elem = 0, 0; elem < p->numOverlapElements; elem++) {
439: for(corner = 0; corner < numCorners; corner++) {
440: newNode = elements[elem*numCorners+corner];
441: if (node == newNode) {
442: for(sElem = 0; sElem < degree; sElem++) {
443: if (support[sElem] == elem) break;
444: }
445: if (sElem == degree) {
446: PetscPrintf(PETSC_COMM_SELF, "[%d]Node %d found in element %d which is not present in the supportn",
447: p->rank, node, elem);
448: 1;
449: }
450: }
451: }
452: }
453:
455: MeshRestoreNodeSupport(mesh, node, 0, °ree, &support);
456: }
457: }
458: return(0);
459: }
461: int MeshSetupSupport_Triangular_2D(Mesh mesh)
462: {
463: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
464: int edge, node;
465: int ierr;
468: /* Calculate maximum degree of vertices */
469: if (mesh->numNodes > 0) {
470: PetscMalloc(mesh->numNodes * sizeof(int), &tri->degrees);
471: }
472: PetscMemzero(tri->degrees, mesh->numNodes * sizeof(int));
473: for(edge = 0; edge < mesh->numEdges*2; edge++) {
474: tri->degrees[tri->edges[edge]]++;
475: }
476: for(node = 0, mesh->maxDegree = 0; node < mesh->numNodes; node++) {
477: mesh->maxDegree = PetscMax(mesh->maxDegree, tri->degrees[node]);
478: }
479: if (mesh->maxDegree > 0) {
480: PetscMalloc(mesh->maxDegree * sizeof(int), &mesh->support);
481: }
482: mesh->supportTaken = PETSC_FALSE;
483: return(0);
484: }
486: int MeshCheckBoundary_Triangular_2D(Mesh mesh) {
487: MeshBoundary2D *bdCtx = mesh->bdCtx;
488: int *markers = bdCtx->markers;
489: int *segments = bdCtx->segments;
490: int *segMarkers = bdCtx->segMarkers;
491: int numBd = 0;
492: int numBdVertices = 0;
493: int numBdSegments = 0;
494: int *bdMarkers;
495: int *bdBegin;
496: int *bdSegmentBegin;
497: int bd, vertex, segment, marker, rank;
498: int ierr;
502: MPI_Comm_rank(mesh->comm, &rank);
503: if (rank != 0) return(0);
504: PetscMalloc(bdCtx->numBd * sizeof(int), &bdMarkers);
505: PetscMalloc((bdCtx->numBd+1) * sizeof(int), &bdBegin);
506: PetscMalloc((bdCtx->numBd+1) * sizeof(int), &bdSegmentBegin);
507: PetscMemzero(bdBegin, (bdCtx->numBd+1) * sizeof(int));
508: PetscMemzero(bdSegmentBegin, (bdCtx->numBd+1) * sizeof(int));
509: for(vertex = 0; vertex < bdCtx->numVertices; vertex++) {
510: if (markers[vertex] == 0) continue;
511: numBdVertices++;
512: /* Check for new marker */
513: for(bd = 0; bd < numBd; bd++) {
514: if (markers[vertex] == bdMarkers[bd]) break;
515: }
516: if (bd == numBd) {
517: if (numBd >= bdCtx->numBd) SETERRQ1(PETSC_ERR_ARG_CORRUPT, "More markers present than declared: %d", bdCtx->numBd);
518: /* Insert new marker */
519: for(bd = 0; bd < numBd; bd++) {
520: if (markers[vertex] < bdMarkers[bd]) break;
521: }
522: if (bd < numBd) {
523: PetscMemmove(&bdMarkers[bd+1], &bdMarkers[bd], (numBd-bd) * sizeof(int));
524: PetscMemmove(&bdBegin[bd+2], &bdBegin[bd+1], (numBd-bd) * sizeof(int));
525: bdBegin[bd+1] = 0;
526: bdSegmentBegin[bd+1] = 0;
527: }
528: bdMarkers[bd] = markers[vertex];
529: numBd++;
530: bdBegin[bd+1]++;
531: } else {
532: bdBegin[bd+1]++;
533: }
534: }
535: for(segment = 0; segment < bdCtx->numSegments; segment++) {
536: if (segMarkers[segment] == 0) continue;
537: marker = segMarkers[segment];
538: for(bd = 0; bd < numBd; bd++) {
539: if (marker == bdMarkers[bd]) break;
540: }
541: if (bd == numBd) SETERRQ2(PETSC_ERR_ARG_CORRUPT, "Invalid segment marker %d on segment %d", marker, segment);
542: numBdSegments++;
543: bdSegmentBegin[bd+1]++;
544: if (markers[segments[segment*2]] != marker) {
545: SETERRQ4(PETSC_ERR_PLIB, "Marker %d on left vertex %d does not match marker %d on its segment %d",
546: markers[segments[segment*2]], segments[segment*2], marker, segment);
547: }
548: if (markers[segments[segment*2+1]] != marker) {
549: SETERRQ4(PETSC_ERR_PLIB, "Marker %d on right vertex %d does not match marker %d on its segment %d",
550: markers[segments[segment*2+1]], segments[segment*2+1], marker, segment);
551: }
552: }
554: /* Do prefix sums to get position offsets */
555: for(bd = 2; bd <= numBd; bd++) {
556: bdBegin[bd] = bdBegin[bd-1] + bdBegin[bd];
557: bdSegmentBegin[bd] = bdSegmentBegin[bd-1] + bdSegmentBegin[bd];
558: }
560: if (numBd != bdCtx->numBd) {
561: SETERRQ2(PETSC_ERR_PLIB, "Invalid number of boundaries %d should be %d", numBd, bdCtx->numBd);
562: }
563: if (bdBegin[numBd] != numBdVertices) {
564: SETERRQ2(PETSC_ERR_PLIB, "Invalid number of boundary vertices %d should be %d", bdBegin[numBd], numBdVertices);
565: }
566: if (bdSegmentBegin[numBd] != numBdSegments) {
567: SETERRQ2(PETSC_ERR_PLIB, "Invalid number of boundary segments %d should be %d", bdSegmentBegin[numBd], numBdSegments);
568: }
569: PetscFree(bdMarkers);
570: PetscFree(bdBegin);
571: PetscFree(bdSegmentBegin);
572: return(0);
573: }
575: int MeshSetupBoundary_Triangular_2D(Mesh mesh)
576: {
577: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
578: int numBd = mesh->numBd;
579: int numNodes = mesh->numNodes;
580: int *markers = tri->markers;
581: int numEdges = mesh->numEdges;
582: int *edges = tri->edges;
583: int *edgemarkers = tri->edgemarkers;
584: int numFaces = mesh->numFaces;
585: int numCorners = mesh->numCorners;
586: int *faces = tri->faces;
587: int newNumBd; /* Current number of different boundary markers */
588: int numBdEdges; /* Current offset into bdEdges[] */
589: int *bdNodes; /* Node numbers for boundary nodes ordered by boundary */
590: int *bdEdges; /* Node numbers for boundary edges ordered by boundary */
591: int *bdBeginOff; /* Current offset into the bdNodes or bdEdges array */
592: int *bdSeen; /* Flags for boundaries already processed */
593: PetscTruth closed; /* Indicates whether a boundary has been closed */
594: int degree;
595: int *support;
596: int rank, bd, marker, node, nextNode, midnode, bdNode, nextBdNode, midBdNode, edge, bdEdge;
597: int elem, cElem, supElem, corner, supCorner, tmp;
598: int ierr;
601: MPI_Comm_rank(mesh->comm, &rank);
602: PetscLogEventBegin(MESH_SetupBoundary, mesh, 0, 0, 0);
603: tri->areas = PETSC_NULL;
604: tri->aspectRatios = PETSC_NULL;
605: mesh->numBdNodes = 0;
606: mesh->numBdEdges = 0;
607: if (numBd == 0) {
608: tri->bdMarkers = PETSC_NULL;
609: tri->bdBegin = PETSC_NULL;
610: tri->bdEdgeBegin = PETSC_NULL;
611: tri->bdNodes = PETSC_NULL;
612: tri->bdEdges = PETSC_NULL;
613: return(0);
614: }
615: PetscMalloc(numBd * sizeof(int), &tri->bdMarkers);
616: PetscMalloc((numBd+1) * sizeof(int), &tri->bdBegin);
617: PetscMalloc((numBd+1) * sizeof(int), &tri->bdEdgeBegin);
618: PetscMalloc((numBd+1) * sizeof(int), &bdBeginOff);
619: PetscLogObjectMemory(mesh, (numBd + (numBd+1)*2) * sizeof(int));
620: PetscMemzero(tri->bdMarkers, numBd * sizeof(int));
621: PetscMemzero(tri->bdBegin, (numBd+1) * sizeof(int));
622: PetscMemzero(tri->bdEdgeBegin, (numBd+1) * sizeof(int));
623: PetscMemzero(bdBeginOff, (numBd+1) * sizeof(int));
625: for(node = 0, newNumBd = 0; node < numNodes; node++) {
626: /* Get number of boundary nodes and markers */
627: if (markers[node]) {
628: mesh->numBdNodes++;
629: /* Check for new marker */
630: for(bd = 0; bd < newNumBd; bd++) {
631: if (markers[node] == tri->bdMarkers[bd]) break;
632: }
633: if (bd == newNumBd) {
634: /* Insert new marker */
635: for(bd = 0; bd < newNumBd; bd++) {
636: if (markers[node] < tri->bdMarkers[bd]) break;
637: }
638: if (bd < newNumBd) {
639: PetscMemmove(&tri->bdMarkers[bd+1], &tri->bdMarkers[bd], (newNumBd-bd) * sizeof(int));
640: PetscMemmove(&tri->bdBegin[bd+2], &tri->bdBegin[bd+1], (newNumBd-bd) * sizeof(int));
641: tri->bdBegin[bd+1] = 0;
642: }
643: tri->bdMarkers[bd] = markers[node];
644: newNumBd++;
645: tri->bdBegin[bd+1]++;
646: } else {
647: tri->bdBegin[bd+1]++;
648: }
649: }
650: }
652: /* Do prefix sums to get position offsets */
653: for(bd = 2; bd <= numBd; bd++) {
654: tri->bdBegin[bd] = tri->bdBegin[bd-1] + tri->bdBegin[bd];
655: }
657: /* This is shameful -- I will write the code to look over edges soon */
658: if (numCorners == 3) {
659: PetscMemcpy(tri->bdEdgeBegin, tri->bdBegin, (numBd+1) * sizeof(int));
660: } else if (numCorners == 6) {
661: /* We know that there are an even number of nodes in every boundary */
662: for(bd = 0; bd <= numBd; bd++) {
663: if (tri->bdBegin[bd]%2) {
664: SETERRQ2(PETSC_ERR_PLIB, "There are %d nodes on boundary %d (not divisible by two)",
665: tri->bdBegin[bd]-tri->bdBegin[bd-1], tri->bdMarkers[bd]);
666: } else {
667: tri->bdEdgeBegin[bd] = tri->bdBegin[bd]/2;
668: }
669: }
670: } else {
671: SETERRQ1(PETSC_ERR_SUP, "Number of local nodes %d not supported", numCorners);
672: }
674: /* Get number of boundary edges */
675: for(edge = 0; edge < numEdges; edge++) {
676: marker = edgemarkers[edge];
677: if (marker) {
678: mesh->numBdEdges++;
679: MeshGetMidnodeFromEdge(mesh, edge, &midnode);
680: if (markers[edges[edge*2]] != marker) {
681: if ((markers[edges[edge*2+1]] == marker) &&
682: ((markers[midnode] == markers[edges[edge*2]]) || (markers[midnode] == markers[edges[edge*2+1]]))) {
683: /* I assume here that the generator mistakenly included an edge between two boundaries */
684: PetscPrintf(PETSC_COMM_SELF, "[%d]Removing edge %d between boundaries %d and %d from boundaryn",
685: rank, edge, markers[edges[edge*2]], markers[edges[edge*2+1]]);
686: edgemarkers[edge] = 0;
687: markers[midnode] = 0;
688: continue;
689: } else {
690: SETERRQ5(PETSC_ERR_PLIB, "Marker %d on left node %d does not match marker %d on its edge %d, right marker is %d",
691: markers[edges[edge*2]], edges[edge*2], marker, edge, markers[edges[edge*2+1]]);
692: }
693: }
694: if (markers[edges[edge*2+1]] != marker) {
695: if ((markers[edges[edge*2]] == marker) &&
696: ((markers[midnode] == markers[edges[edge*2]]) || (markers[midnode] == markers[edges[edge*2+1]]))) {
697: /* I assume here that the generator mistakenly included an edge between two boundaries */
698: PetscPrintf(PETSC_COMM_SELF, "[%d]Removing edge %d between boundaries %d and %d from boundaryn",
699: rank, edge, markers[edges[edge*2]], markers[edges[edge*2+1]]);
700: edgemarkers[edge] = 0;
701: markers[midnode] = 0;
702: continue;
703: } else {
704: SETERRQ5(PETSC_ERR_PLIB, "Marker %d on right node %d does not match marker %d on its edge %d, left marker is %d",
705: markers[edges[edge*2+1]], edges[edge*2+1], marker, edge, markers[edges[edge*2]]);
706: }
707: }
708: if (markers[midnode] != marker) {
709: SETERRQ5(PETSC_ERR_PLIB, "Marker %d on midnode %d does not match marker %d on its edge %d, left marker is %d",
710: markers[midnode], midnode, marker, edge, markers[edges[edge*2]]);
711: }
712: }
713: }
715: /* Check boundary information consistency */
716: if (newNumBd != numBd) {
717: SETERRQ2(PETSC_ERR_PLIB, "Invalid number of boundaries %d should be %d", newNumBd, numBd);
718: }
719: if (tri->bdBegin[numBd] != mesh->numBdNodes) {
720: SETERRQ2(PETSC_ERR_PLIB, "Invalid number of boundary nodes %d should be %d", tri->bdBegin[numBd], mesh->numBdNodes);
721: }
722: if (tri->bdEdgeBegin[numBd] != mesh->numBdEdges) {
723: SETERRQ2(PETSC_ERR_PLIB, "Invalid number of boundary edges %d should be %d", tri->bdEdgeBegin[numBd], mesh->numBdEdges);
724: }
726: PetscMalloc(mesh->numBdNodes * sizeof(int), &bdNodes);
727: PetscMalloc(mesh->numBdEdges * sizeof(int), &bdEdges);
728: PetscLogObjectMemory(mesh, (mesh->numBdNodes + mesh->numBdEdges) * sizeof(int));
730: /* Split nodes by marker */
731: PetscMemcpy(bdBeginOff, tri->bdBegin, (numBd+1) * sizeof(int));
732: for(node = 0; node < numNodes; node++) {
733: for(bd = 0; bd < numBd; bd++) {
734: if (markers[node] == tri->bdMarkers[bd]) {
735: #ifdef MESH_TRACE_BOUNDARY_CREATE
736: PetscPrintf(PETSC_COMM_WORLD, "bd: %d bdNode[%d] = %dn", bd, bdBeginOff[bd], node);
737: #endif
738: bdNodes[bdBeginOff[bd]++] = node;
739: }
740: }
741: }
742: for(bd = 0; bd < numBd; bd++) {
743: if (tri->bdBegin[bd+1] != bdBeginOff[bd])
744: SETERRQ(PETSC_ERR_PLIB, "Invalid boundary node marker information");
745: }
747: /* Split edges by marker */
748: PetscMemcpy(bdBeginOff, tri->bdEdgeBegin, (numBd+1) * sizeof(int));
749: for(edge = 0; edge < numEdges; edge++) {
750: for(bd = 0; bd < numBd; bd++) {
751: if (edgemarkers[edge] == tri->bdMarkers[bd]) {
752: #ifdef MESH_TRACE_BOUNDARY_CREATE
753: PetscPrintf(PETSC_COMM_WORLD, "bd: %d bdEdge[%d] = %dn", bd, bdBeginOff[bd], edge);
754: #endif
755: bdEdges[bdBeginOff[bd]++] = edge;
756: }
757: }
758: }
759: for(bd = 0; bd < numBd; bd++) {
760: if (tri->bdEdgeBegin[bd+1] != bdBeginOff[bd])
761: SETERRQ(PETSC_ERR_PLIB, "Invalid boundary edge marker information");
762: }
763: PetscFree(bdBeginOff);
765: /* Order boundary counter-clockwise */
766: PetscMalloc(numBd * sizeof(int), &bdSeen);
767: PetscMemzero(bdSeen, numBd * sizeof(int));
768: /* Loop over elements */
769: for(elem = 0; elem < numFaces; elem++) {
770: /* Find an element with a node on the boundary */
771: for(corner = 0; corner < 3; corner++) {
772: if (markers[faces[elem*numCorners+corner]]) {
773: /* Find boundary index */
774: cElem = elem;
775: node = faces[elem*numCorners+corner];
776: for(bd = 0; bd < numBd; bd++)
777: if (markers[node] == tri->bdMarkers[bd])
778: break;
779: if (bd == numBd) SETERRQ(PETSC_ERR_PLIB, "Invalid boundary marker");
780: /* Check for processed boundaries */
781: if (bdSeen[bd])
782: continue;
783: numBdEdges = tri->bdEdgeBegin[bd];
785: /* Start building this boundary */
786: #ifdef MESH_TRACE_BOUNDARY_CREATE
787: PetscPrintf(mesh->comm, "Starting boundary %d beginning at %d ending before %dn",
788: bd, tri->bdBegin[bd], tri->bdBegin[bd+1]);
789: #endif
790: /* Find initial node */
791: for(bdNode = tri->bdBegin[bd]; bdNode < tri->bdBegin[bd+1]; bdNode++) {
792: if (bdNodes[bdNode] == node) {
793: /* Move this node to the head of the list */
794: #ifdef MESH_TRACE_BOUNDARY_CREATE
795: PetscPrintf(mesh->comm, " moving node %d from %d to %dn", bdNodes[bdNode], bdNode, tri->bdBegin[bd]);
796: #endif
797: tmp = bdNodes[tri->bdBegin[bd]];
798: bdNodes[tri->bdBegin[bd]] = bdNodes[bdNode];
799: bdNodes[bdNode] = tmp;
800: break;
801: }
802: }
804: /* Order edges counterclockwise around a boundary */
805: /* I do not currently check the orientation of the constructed boundary */
806: for(bdNode = tri->bdBegin[bd], closed = PETSC_FALSE; bdNode < tri->bdBegin[bd+1]; bdNode++) {
807: #ifdef MESH_TRACE_BOUNDARY_CREATE
808: PetscPrintf(mesh->comm, "n At boundary node %d x:%lf y: %lfn",
809: bdNode, tri->nodes[bdNodes[bdNode]*2], tri->nodes[bdNodes[bdNode]*2+1]);
810: #ifdef MESH_TRACE_BOUNDARY_CREATE_DETAIL
811: for(node = tri->bdBegin[bd]; node < tri->bdBegin[bd+1]; node++)
812: PetscPrintf(mesh->comm, " bdNode[%d]: %dn", node, bdNodes[node]);
813: #endif
814: #endif
816: /* Find a neighbor of the point -- Could maybe do better than linear search */
817: for(bdEdge = numBdEdges; bdEdge < tri->bdEdgeBegin[bd+1]; bdEdge++) {
818: edge = bdEdges[bdEdge];
819: if ((edgemarkers[edge] == tri->bdMarkers[bd]) &&
820: (((edges[edge*2] == bdNodes[bdNode]) && (markers[edges[edge*2+1]] == tri->bdMarkers[bd])) ||
821: ((edges[edge*2+1] == bdNodes[bdNode]) && (markers[edges[edge*2]] == tri->bdMarkers[bd]))))
822: {
823: /* Get neighboring node number */
824: if (edges[edge*2] == bdNodes[bdNode]) {
825: node = edges[edge*2+1];
826: } else {
827: node = edges[edge*2];
828: }
830: /* Find neighboring node in bdNodes[] */
831: for(nextBdNode = tri->bdBegin[bd]; nextBdNode < tri->bdBegin[bd+1]; nextBdNode++)
832: if (bdNodes[nextBdNode] == node) break;
833: #ifdef MESH_TRACE_BOUNDARY_CREATE
834: PetscPrintf(mesh->comm, " found connection along edge %d to bd node %d = node %dn",
835: edge, nextBdNode, node);
836: #endif
838: if (nextBdNode > bdNode) {
839: /* Insert midnode */
840: if (numCorners == 6) {
841: /* Move this node next to the connected one */
842: #ifdef MESH_TRACE_BOUNDARY_CREATE
843: PetscPrintf(mesh->comm, " moving node %d from %d to %dn", bdNodes[nextBdNode], nextBdNode, bdNode+2);
844: #endif
845: tmp = bdNodes[bdNode+2];
846: bdNodes[bdNode+2] = bdNodes[nextBdNode];
847: bdNodes[nextBdNode] = tmp;
848: nextBdNode = bdNode+2;
850: /* Walk around the node looking for a boundary edge and reset containing element */
851: node = bdNodes[bdNode];
852: nextNode = bdNodes[nextBdNode];
853: ierr = MeshGetNodeSupport(mesh, node, cElem, °ree, &support);
854: for(supElem = 0, midnode = -1; supElem < degree; supElem++) {
855: for(supCorner = 0; supCorner < 3; supCorner++) {
856: cElem = support[supElem];
857: if ((faces[cElem*numCorners+supCorner] == node) &&
858: (faces[cElem*numCorners+((supCorner+1)%3)] == nextNode))
859: {
860: midnode = faces[cElem*numCorners+((((supCorner*2+1)%3)*2)%3 + 3)];
861: supElem = degree;
862: break;
863: }
864: else if ((faces[cElem*numCorners+supCorner] == node) &&
865: (faces[cElem*numCorners+((supCorner+2)%3)] == nextNode))
866: {
867: midnode = faces[cElem*numCorners+((((supCorner*2+2)%3)*2)%3 + 3)];
868: supElem = degree;
869: break;
870: }
871: }
872: }
873: ierr = MeshRestoreNodeSupport(mesh, node, cElem, °ree, &support);
874: /* Find midnode in bdNodes[] */
875: for(midBdNode = tri->bdBegin[bd]; midBdNode < tri->bdBegin[bd+1]; midBdNode++)
876: if (bdNodes[midBdNode] == midnode)
877: break;
878: if (midBdNode == tri->bdBegin[bd+1]) SETERRQ(PETSC_ERR_PLIB, "Unable to locate midnode on boundary");
879: #ifdef MESH_TRACE_BOUNDARY_CREATE
880: PetscPrintf(mesh->comm, " moving midnode %d in elem %d from %d to %dn",
881: midnode, cElem, midBdNode, bdNode+1);
882: #endif
883: tmp = bdNodes[bdNode+1];
884: bdNodes[bdNode+1] = bdNodes[midBdNode];
885: bdNodes[midBdNode] = tmp;
886: bdNode++;
887: } else {
888: /* numCorners == 3 */
889: /* Move this node next to the connected one */
890: #ifdef MESH_TRACE_BOUNDARY_CREATE
891: PetscPrintf(mesh->comm, " moving node %d from %d to %dn", bdNodes[nextBdNode], nextBdNode, bdNode+1);
892: #endif
893: tmp = bdNodes[bdNode+1];
894: bdNodes[bdNode+1] = bdNodes[nextBdNode];
895: bdNodes[nextBdNode] = tmp;
896: }
898: /* Reorder bdEdges[] */
899: #ifdef MESH_TRACE_BOUNDARY_CREATE
900: PetscPrintf(mesh->comm, " moving edge %d from %d to %dn", edge, bdEdge, numBdEdges);
901: #endif
902: tmp = bdEdges[numBdEdges];
903: bdEdges[numBdEdges] = bdEdges[bdEdge];
904: bdEdges[bdEdge] = tmp;
905: numBdEdges++;
906: break;
907: }
908: /* Check that first and last nodes are connected (closed boundary) */
909: else if ((nextBdNode == tri->bdBegin[bd]) && (bdNode != (numCorners == 6 ? nextBdNode+2 : nextBdNode+1)))
910: {
911: if (bdEdges[numBdEdges++] != edge) SETERRQ(PETSC_ERR_PLIB, "Invalid closing edge");
912: closed = PETSC_TRUE;
913: /* End the loop since only a midnode is left */
914: bdNode = tri->bdBegin[bd+1];
915: #ifdef MESH_TRACE_BOUNDARY_CREATE
916: PetscPrintf(mesh->comm, " adding edge %d total: %dn", edge, numBdEdges);
917: #endif
918: break;
919: }
920: }
921: }
922: if (bdEdge == tri->bdEdgeBegin[bd+1]) SETERRQ(PETSC_ERR_PLIB, "No connection");
923: }
925: /* Check for closed boundary */
926: if (closed == PETSC_FALSE) {
927: PetscPrintf(PETSC_COMM_SELF, "Boundary %d with marker %d is not closedn", bd, tri->bdMarkers[bd]);
928: }
930: /* Check size of boundary */
931: if (tri->bdBegin[bd+1] != numBdEdges*(numCorners == 3 ? 1 : 2)) {
932: PetscPrintf(PETSC_COMM_SELF, "On boundary %d with marker %d, edge count %d x %d should equal %d (was %d)n",
933: bd, tri->bdMarkers[bd], numBdEdges, (numCorners == 3 ? 1 : 2), tri->bdBegin[bd+1], tri->bdBegin[bd]);
934: SETERRQ(PETSC_ERR_PLIB, "Invalid boundary edge marker information");
935: }
936: #ifdef MESH_TRACE_BOUNDARY_CREATE
937: /* Check boundary nodes */
938: for(bdNode = tri->bdBegin[bd]; bdNode < tri->bdBegin[bd+1]; bdNode++)
939: PetscPrintf(mesh->comm, "bd: %4d bdNode: %4d node: %5dn",
940: bd, bdNode, bdNodes[bdNode], bdEdges[bdNode], edges[bdEdges[bdNode]*2], edges[bdEdges[bdNode]*2+1]);
941: /* Check boundary edges */
942: for(bdEdge = tri->bdEdgeBegin[bd]; bdEdge < tri->bdEdgeBegin[bd+1]; bdEdge++)
943: PetscPrintf(mesh->comm, "bd: %4d bdEdge: %4d edge: %5d start: %5d end: %5dn",
944: bd, bdEdge, bdEdges[bdEdge], edges[bdEdges[bdEdge]*2], edges[bdEdges[bdEdge]*2+1]);
945: #endif
946: bdSeen[bd] = 1;
947: }
948: }
949: }
950: PetscFree(bdSeen);
952: /* Set fields */
953: tri->bdNodes = bdNodes;
954: tri->bdEdges = bdEdges;
955: /* Diagnostics */
956: #ifdef MESH_TRACE_BOUNDARY_REORDER
957: int minNode, minBdNode, minEdge, minBdEdge, dir, nextBdEdge;
959: PetscMalloc(mesh->numBdNodes * sizeof(int), &bdNodes);
960: PetscMalloc(mesh->numBdEdges * sizeof(int), &bdEdges);
961: for(bd = 0; bd < numBd; bd++) {
962: /* Find smallest node */
963: for(bdNode = tri->bdBegin[bd], minNode = tri->numNodes, minBdNode = -1; bdNode < tri->bdBegin[bd+1]; bdNode++)
964: if (tri->bdNodes[bdNode] < minNode) {
965: minNode = tri->bdNodes[bdNode];
966: minBdNode = bdNode;
967: }
968: /* Proceed in the direction of the smaller node */
969: if (minBdNode == tri->bdBegin[bd]) {
970: if (tri->bdNodes[minBdNode+1] < tri->bdNodes[tri->bdBegin[bd+1]-1])
971: dir = 1;
972: else
973: dir = 0;
974: } else if (minBdNode == tri->bdBegin[bd+1]-1) {
975: if (tri->bdNodes[tri->bdBegin[bd]] < tri->bdNodes[minBdNode-1])
976: dir = 0;
977: else
978: dir = 1;
979: } else if (tri->bdNodes[minBdNode+1] < tri->bdNodes[minBdNode-1]) {
980: dir = 1;
981: } else {
982: dir = 0;
983: }
984: if (dir)
985: {
986: for(nextBdNode = tri->bdBegin[bd], bdNode = minBdNode; bdNode < tri->bdBegin[bd+1]; nextBdNode++, bdNode++)
987: bdNodes[nextBdNode] = tri->bdNodes[bdNode];
988: for(bdNode = tri->bdBegin[bd]; bdNode < minBdNode; nextBdNode++, bdNode++)
989: bdNodes[nextBdNode] = tri->bdNodes[bdNode];
990: }
991: else
992: {
993: for(nextBdNode = tri->bdBegin[bd], bdNode = minBdNode; bdNode >= tri->bdBegin[bd]; nextBdNode++, bdNode--)
994: bdNodes[nextBdNode] = tri->bdNodes[bdNode];
995: for(bdNode = tri->bdBegin[bd+1]-1; bdNode > minBdNode; nextBdNode++, bdNode--)
996: bdNodes[nextBdNode] = tri->bdNodes[bdNode];
997: }
998: }
999: for(bd = 0; bd < numBd; bd++) {
1000: /* Find smallest edge */
1001: for(bdEdge = tri->bdEdgeBegin[bd], minEdge = tri->numEdges, minBdEdge = -1; bdEdge < tri->bdEdgeBegin[bd+1]; bdEdge++)
1002: if (tri->bdEdges[bdEdge] < minEdge) {
1003: minEdge = tri->bdEdges[bdEdge];
1004: minBdEdge = bdEdge;
1005: }
1006: /* Proceed in the direction of the smaller edge */
1007: if (minBdEdge == tri->bdEdgeBegin[bd]) {
1008: if (tri->bdEdges[minBdEdge+1] < tri->bdEdges[tri->bdEdgeBegin[bd+1]-1])
1009: dir = 1;
1010: else
1011: dir = 0;
1012: } else if (minBdEdge == tri->bdEdgeBegin[bd+1]-1) {
1013: if (tri->bdEdges[tri->bdEdgeBegin[bd]] < tri->bdEdges[minBdEdge-1])
1014: dir = 0;
1015: else
1016: dir = 1;
1017: } else if (tri->bdEdges[minBdEdge+1] < tri->bdEdges[minBdEdge-1]) {
1018: dir = 1;
1019: } else {
1020: dir = 0;
1021: }
1022: if (dir)
1023: {
1024: for(nextBdEdge = tri->bdEdgeBegin[bd], bdEdge = minBdEdge; bdEdge < tri->bdEdgeBegin[bd+1]; nextBdEdge++, bdEdge++)
1025: bdEdges[nextBdEdge] = tri->bdEdges[bdEdge];
1026: for(bdEdge = tri->bdEdgeBegin[bd]; bdEdge < minBdEdge; nextBdEdge++, bdEdge++)
1027: bdEdges[nextBdEdge] = tri->bdEdges[bdEdge];
1028: }
1029: else
1030: {
1031: for(nextBdEdge = tri->bdEdgeBegin[bd], bdEdge = minBdEdge; bdEdge >= tri->bdEdgeBegin[bd]; nextBdEdge++, bdEdge--)
1032: bdEdges[nextBdEdge] = tri->bdEdges[bdEdge];
1033: for(bdEdge = tri->bdEdgeBegin[bd+1]-1; bdEdge > minBdEdge; nextBdEdge++, bdEdge--)
1034: bdEdges[nextBdEdge] = tri->bdEdges[bdEdge];
1035: }
1036: }
1037: PetscMemcpy(tri->bdNodes, bdNodes, mesh->numBdNodes * sizeof(int));
1038: PetscMemcpy(tri->bdEdges, bdEdges, mesh->numBdEdges * sizeof(int));
1039: PetscFree(bdNodes);
1040: PetscFree(bdEdges);
1041: #endif
1042: #ifdef MESH_TRACE_BOUNDARY
1043: int minNode, minBdNode, minEdge, minBdEdge, dir;
1045: for(bd = 0; bd < numBd; bd++) {
1046: /* Find smallest node */
1047: for(bdNode = tri->bdBegin[bd], minNode = tri->numNodes, minBdNode = -1; bdNode < tri->bdBegin[bd+1]; bdNode++)
1048: if (tri->bdNodes[bdNode] < minNode) {
1049: minNode = tri->bdNodes[bdNode];
1050: minBdNode = bdNode;
1051: }
1052: /* Proceed in the direction of the smaller node */
1053: if (minBdNode == tri->bdBegin[bd]) {
1054: if (tri->bdNodes[minBdNode+1] < tri->bdNodes[tri->bdBegin[bd+1]-1])
1055: dir = 1;
1056: else
1057: dir = 0;
1058: } else if (minBdNode == tri->bdBegin[bd+1]-1) {
1059: if (tri->bdNodes[tri->bdBegin[bd]] < tri->bdNodes[minBdNode-1])
1060: dir = 0;
1061: else
1062: dir = 1;
1063: } else if (tri->bdNodes[minBdNode+1] < tri->bdNodes[minBdNode-1]) {
1064: dir = 1;
1065: } else {
1066: dir = 0;
1067: }
1068: if (dir)
1069: {
1070: for(bdNode = minBdNode; bdNode < tri->bdBegin[bd+1]; bdNode++)
1071: PetscPrintf(mesh->comm, "bd: %4d node: %5dn", bd, tri->bdNodes[bdNode]);
1072: for(bdNode = tri->bdBegin[bd]; bdNode < minBdNode; bdNode++)
1073: PetscPrintf(mesh->comm, "bd: %4d node: %5dn", bd, tri->bdNodes[bdNode]);
1074: }
1075: else
1076: {
1077: for(bdNode = minBdNode; bdNode >= tri->bdBegin[bd]; bdNode--)
1078: PetscPrintf(mesh->comm, "bd: %4d node: %5dn", bd, tri->bdNodes[bdNode]);
1079: for(bdNode = tri->bdBegin[bd+1]-1; bdNode > minBdNode; bdNode--)
1080: PetscPrintf(mesh->comm, "bd: %4d node: %5dn", bd, tri->bdNodes[bdNode]);
1081: }
1082: }
1083: for(bd = 0; bd < numBd; bd++) {
1084: /* Find smallest edge */
1085: for(bdEdge = tri->bdEdgeBegin[bd], minEdge = tri->numEdges, minBdEdge = -1; bdEdge < tri->bdEdgeBegin[bd+1]; bdEdge++)
1086: if (tri->bdEdges[bdEdge] < minEdge) {
1087: minEdge = tri->bdEdges[bdEdge];
1088: minBdEdge = bdEdge;
1089: }
1090: /* Proceed in the direction of the smaller edge */
1091: if (minBdEdge == tri->bdEdgeBegin[bd]) {
1092: if (tri->bdEdges[minBdEdge+1] < tri->bdEdges[tri->bdEdgeBegin[bd+1]-1])
1093: dir = 1;
1094: else
1095: dir = 0;
1096: } else if (minBdEdge == tri->bdEdgeBegin[bd+1]-1) {
1097: if (tri->bdEdges[tri->bdEdgeBegin[bd]] < tri->bdEdges[minBdEdge-1])
1098: dir = 0;
1099: else
1100: dir = 1;
1101: } else if (tri->bdEdges[minBdEdge+1] < tri->bdEdges[minBdEdge-1]) {
1102: dir = 1;
1103: } else {
1104: dir = 0;
1105: }
1106: if (dir)
1107: {
1108: for(bdEdge = minBdEdge; bdEdge < tri->bdEdgeBegin[bd+1]; bdEdge++)
1109: PetscPrintf(mesh->comm, "bd: %4d edge: %5d start: %5d end: %5dn",
1110: bd, tri->bdEdges[bdEdge], edges[tri->bdEdges[bdEdge]*2], edges[tri->bdEdges[bdEdge]*2+1]);
1111: for(bdEdge = tri->bdEdgeBegin[bd]; bdEdge < minBdEdge; bdEdge++)
1112: PetscPrintf(mesh->comm, "bd: %4d edge: %5d start: %5d end: %5dn",
1113: bd, tri->bdEdges[bdEdge], edges[tri->bdEdges[bdEdge]*2], edges[tri->bdEdges[bdEdge]*2+1]);
1114: }
1115: else
1116: {
1117: for(bdEdge = minBdEdge; bdEdge >= tri->bdEdgeBegin[bd]; bdEdge--)
1118: PetscPrintf(mesh->comm, "bd: %4d edge: %5d start: %5d end: %5dn",
1119: bd, tri->bdEdges[bdEdge], edges[tri->bdEdges[bdEdge]*2], edges[tri->bdEdges[bdEdge]*2+1]);
1120: for(bdEdge = tri->bdEdgeBegin[bd+1]-1; bdEdge > minBdEdge; bdEdge--)
1121: PetscPrintf(mesh->comm, "bd: %4d edge: %5d start: %5d end: %5dn",
1122: bd, tri->bdEdges[bdEdge], edges[tri->bdEdges[bdEdge]*2], edges[tri->bdEdges[bdEdge]*2+1]);
1123: }
1124: }
1125: #endif
1127: PetscLogEventEnd(MESH_SetupBoundary, mesh, 0, 0, 0);
1128: return(0);
1129: }
1131: /*
1132: MeshAssemble_Private - This function assembles the mesh entirely on the first processor.
1134: Collective on Mesh
1136: Input Parameters:
1137: . mesh - The mesh being refined
1139: Output Parameter:
1140: + nodes - The node coordinates
1141: . markers - The node markers
1142: . faces - The nodes for each element
1143: - edges - The nodes for each edge
1145: Level: developer
1147: .keywords mesh, assemble
1148: .seealso MeshInitRefineInput_Triangle()
1149: */
1150: int MeshAssemble_Private(Mesh mesh, double **nodes, int **markers, int **faces, int **edges)
1151: {
1152: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1153: Partition p = mesh->part;
1154: Partition_Triangular_2D *q = (Partition_Triangular_2D *) p->data;
1155: int numNodes = q->numNodes;
1156: int numFaces = p->numElements;
1157: int numEdges = q->numEdges;
1158: int numCorners = mesh->numCorners;
1159: int numProcs = p->numProcs;
1160: int rank = p->rank;
1161: int *locFaces = PETSC_NULL;
1162: int *locEdges = PETSC_NULL;
1163: int *numRecvNodes, *numRecvMarkers, *numRecvFaces, *numRecvEdges;
1164: int *nodeOffsets, *markerOffsets, *faceOffsets, *edgeOffsets;
1165: int proc, elem, edge, size;
1166: int ierr;
1169: /* Allocate global arrays */
1170: if (rank == 0) {
1171: PetscMalloc(numNodes*2 * sizeof(double), nodes);
1172: PetscMalloc(numNodes * sizeof(int), markers);
1173: PetscMalloc(numFaces*numCorners * sizeof(int), faces);
1174: PetscMalloc(numEdges*2 * sizeof(int), edges);
1175: }
1177: if (numProcs > 1) {
1178: if (mesh->numFaces > 0) {
1179: PetscMalloc(mesh->numFaces*numCorners * sizeof(int), &locFaces);
1180: }
1181: if (mesh->numEdges > 0) {
1182: PetscMalloc(mesh->numEdges*2 * sizeof(int), &locEdges);
1183: }
1185: /* Calculate offsets */
1186: PetscMalloc(numProcs * sizeof(int), &numRecvNodes);
1187: PetscMalloc(numProcs * sizeof(int), &numRecvMarkers);
1188: PetscMalloc(numProcs * sizeof(int), &numRecvEdges);
1189: PetscMalloc(numProcs * sizeof(int), &numRecvFaces);
1190: PetscMalloc(numProcs * sizeof(int), &nodeOffsets);
1191: PetscMalloc(numProcs * sizeof(int), &markerOffsets);
1192: PetscMalloc(numProcs * sizeof(int), &edgeOffsets);
1193: PetscMalloc(numProcs * sizeof(int), &faceOffsets);
1194: for(proc = 0; proc < numProcs; proc++) {
1195: numRecvNodes[proc] = (q->firstNode[proc+1] - q->firstNode[proc])*2;
1196: numRecvMarkers[proc] = (q->firstNode[proc+1] - q->firstNode[proc]);
1197: numRecvEdges[proc] = (q->firstEdge[proc+1] - q->firstEdge[proc])*2;
1198: numRecvFaces[proc] = (p->firstElement[proc+1] - p->firstElement[proc])*numCorners;
1199: }
1200: nodeOffsets[0] = 0;
1201: markerOffsets[0] = 0;
1202: edgeOffsets[0] = 0;
1203: faceOffsets[0] = 0;
1204: for(proc = 1; proc < numProcs; proc++) {
1205: nodeOffsets[proc] = numRecvNodes[proc-1] + nodeOffsets[proc-1];
1206: markerOffsets[proc] = numRecvMarkers[proc-1] + markerOffsets[proc-1];
1207: edgeOffsets[proc] = numRecvEdges[proc-1] + edgeOffsets[proc-1];
1208: faceOffsets[proc] = numRecvFaces[proc-1] + faceOffsets[proc-1];
1209: }
1211: /* Local to global node number conversion */
1212: for(elem = 0; elem < mesh->numFaces*numCorners; elem++) {
1213: PartitionLocalToGlobalNodeIndex(p, tri->faces[elem], &locFaces[elem]);
1214: }
1215: for(edge = 0; edge < mesh->numEdges*2; edge++) {
1216: PartitionLocalToGlobalNodeIndex(p, tri->edges[edge], &locEdges[edge]);
1217: }
1219: /* Collect global arrays */
1220: size = mesh->numNodes*2;
1221: MPI_Gatherv(tri->nodes, size, MPI_DOUBLE, *nodes, numRecvNodes, nodeOffsets, MPI_DOUBLE, 0, p->comm);
1222:
1223: size = mesh->numNodes;
1224: MPI_Gatherv(tri->markers, size, MPI_INT, *markers, numRecvMarkers, markerOffsets, MPI_INT, 0, p->comm);
1225:
1226: size = mesh->numEdges*2;
1227: MPI_Gatherv(locEdges, size, MPI_INT, *edges, numRecvEdges, edgeOffsets, MPI_INT, 0, p->comm);
1228:
1229: size = mesh->numFaces*numCorners;
1230: MPI_Gatherv(locFaces, size, MPI_INT, *faces, numRecvFaces, faceOffsets, MPI_INT, 0, p->comm);
1231:
1233: /* Cleanup */
1234: if (locFaces != PETSC_NULL) {
1235: PetscFree(locFaces);
1236: }
1237: if (locEdges != PETSC_NULL) {
1238: PetscFree(locEdges);
1239: }
1240: PetscFree(numRecvNodes);
1241: PetscFree(numRecvMarkers);
1242: PetscFree(numRecvEdges);
1243: PetscFree(numRecvFaces);
1244: PetscFree(nodeOffsets);
1245: PetscFree(markerOffsets);
1246: PetscFree(edgeOffsets);
1247: PetscFree(faceOffsets);
1248: } else {
1249: /* Uniprocessor case */
1250: PetscMemcpy(*nodes, tri->nodes, numNodes*2 * sizeof(double));
1251: PetscMemcpy(*markers, tri->markers, numNodes * sizeof(int));
1252: PetscMemcpy(*faces, tri->faces, numFaces*numCorners * sizeof(int));
1253: PetscMemcpy(*edges, tri->edges, numEdges*2 * sizeof(int));
1254: }
1255: return(0);
1256: }
1258: /*
1259: MeshCoarsen_Triangular_2D - Coarsens a two dimensional unstructured mesh using area constraints
1261: Collective on Mesh
1263: Input Parameters:
1264: + mesh - The mesh begin coarsened
1265: - area - A function which gives an area constraint when evaluated inside an element
1267: Output Parameters:
1268: . newmesh - The coarse mesh
1270: Note:
1271: If PETSC_NULL is given as the 'area' argument, the mesh consisting only of vertices is returned.
1273: Level: developer
1275: .keywords unstructured grid
1276: .seealso GridCoarsen(), MeshRefine(), MeshReform()
1277: */
1278: static int MeshCoarsen_Triangular_2D(Mesh mesh, PointFunction area, Mesh *newmesh)
1279: {
1280: ParameterDict dict;
1281: Mesh m;
1282: Mesh_Triangular *tri;
1283: Partition p;
1284: Partition_Triangular_2D *q;
1285: Mesh_Triangular *triOld = (Mesh_Triangular *) mesh->data;
1286: Partition pOld = mesh->part;
1287: Partition_Triangular_2D *qOld = (Partition_Triangular_2D *) pOld->data;
1288: int (*refine)(Mesh, PointFunction, Mesh);
1289: int *newNodes; /* newNodes[fine node #] = coarse node # or -1 */
1290: int *FineMapping; /* FineMapping[n] = node n in the fine mesh numbering */
1291: int *CoarseMapping; /* CoarseMapping[n] = node n in the coarse mesh numbering */
1292: PetscTruth hasIndex;
1293: int *nodePerm, *temp;
1294: int numGhostElements, numGhostNodes;
1295: int proc, bd, elem, edge, corner, node, newNode, gNode, ghostNode, bdNode, count;
1296: int ierr;
1299: if (area == PETSC_NULL) {
1300: if (mesh->numCorners == 3) {
1301: /* Return the mesh and increment the reference count instead of copying */
1302: PetscObjectReference((PetscObject) mesh);
1303: *newmesh = mesh;
1304: return(0);
1305: } else if (mesh->numCorners != 6) {
1306: SETERRQ1(PETSC_ERR_SUP, "Number of local nodes %d not supported", mesh->numCorners);
1307: }
1309: /* We would like to preserve the partition of vertices, although it may be somewhat
1310: unbalanced, since this makes mapping from the coarse mesh back to the original
1311: much easier.
1312: */
1313: MeshCreate(mesh->comm, &m);
1314: ParameterDictCreate(mesh->comm, &dict);
1315: ParameterDictSetObject(dict, "bdCtx", mesh->bdCtx);
1316: ParameterDictSetInteger(dict, "dim", 2);
1317: ParameterDictSetInteger(dict, "numLocNodes", mesh->numCorners);
1318: PetscObjectSetParameterDict((PetscObject) m, dict);
1319: ParameterDictDestroy(dict);
1320: PetscNew(Mesh_Triangular, &tri);
1321: PetscLogObjectMemory(m, sizeof(Mesh_Triangular));
1322: PetscMemcpy(m->ops, mesh->ops, sizeof(struct _MeshOps));
1323: PetscStrallocpy(mesh->type_name, &m->type_name);
1324: PetscStrallocpy(mesh->serialize_name, &m->serialize_name);
1325: m->data = (void *) tri;
1326: m->dim = 2;
1327: m->startX = mesh->startX;
1328: m->endX = mesh->endX;
1329: m->sizeX = mesh->sizeX;
1330: m->startY = mesh->startY;
1331: m->endY = mesh->endY;
1332: m->sizeY = mesh->sizeY;
1333: m->isPeriodic = mesh->isPeriodic;
1334: m->isPeriodicDim[0] = mesh->isPeriodicDim[0];
1335: m->isPeriodicDim[1] = mesh->isPeriodicDim[1];
1336: m->isPeriodicDim[2] = mesh->isPeriodicDim[2];
1337: m->nodeOrdering = PETSC_NULL;
1338: m->partitioned = 1;
1339: m->highlightElement = mesh->highlightElement;
1340: m->usr = mesh->usr;
1342: /* Copy function list */
1343: PetscObjectQueryFunction((PetscObject) mesh, "MeshTriangular2D_Refine_C", (void (**)(void)) &refine);
1344: if (refine != PETSC_NULL) {
1345: #ifdef PETSC_HAVE_TRIANGLE
1346: PetscObjectComposeFunction((PetscObject) m, "MeshTriangular2D_Refine_C", "MeshRefine_Triangle",
1347: (void (*)(void)) MeshRefine_Triangle);
1348: #else
1349: /* The query needs to return the name also */
1350: PetscObjectComposeFunction((PetscObject) m, "MeshTriangular2D_Refine_C", "", (void (*)(void)) refine);
1351: #endif
1352:
1353: }
1355: /* Create the partition object */
1356: PartitionCreate(m, &p);
1357: PetscNew(Partition_Triangular_2D, &q);
1358: PetscLogObjectMemory(p, sizeof(Partition_Triangular_2D));
1359: PetscMemcpy(p->ops, pOld->ops, sizeof(struct _PartitionOps));
1360: PetscObjectChangeTypeName((PetscObject) p, pOld->type_name);
1361: PetscObjectChangeSerializeName((PetscObject) p, pOld->serialize_name);
1362: p->data = (void *) q;
1363: m->part = p;
1364: PetscLogObjectParent(m, p);
1366: /* Construct element partition */
1367: p->numProcs = pOld->numProcs;
1368: p->rank = pOld->rank;
1369: p->ordering = PETSC_NULL;
1370: p->numLocElements = pOld->numLocElements;
1371: p->numElements = pOld->numElements;
1372: p->numOverlapElements = pOld->numOverlapElements;
1373: PetscMalloc((p->numProcs+1) * sizeof(int), &p->firstElement);
1374: PetscMemcpy(p->firstElement, pOld->firstElement, (p->numProcs+1) * sizeof(int));
1375: p->ghostElements = PETSC_NULL;
1376: p->ghostElementProcs = PETSC_NULL;
1377: numGhostElements = pOld->numOverlapElements - pOld->numLocElements;
1378: if (numGhostElements > 0) {
1379: PetscMalloc(numGhostElements * sizeof(int), &p->ghostElements);
1380: PetscMalloc(numGhostElements * sizeof(int), &p->ghostElementProcs);
1381: PetscLogObjectMemory(p, numGhostElements*2 * sizeof(int));
1382: PetscMemcpy(p->ghostElements, pOld->ghostElements, numGhostElements * sizeof(int));
1383: PetscMemcpy(p->ghostElementProcs, pOld->ghostElementProcs, numGhostElements * sizeof(int));
1384: }
1385: q->nodeOrdering = PETSC_NULL;
1386: q->edgeOrdering = PETSC_NULL;
1387: q->numLocEdges = qOld->numLocEdges;
1388: q->numEdges = qOld->numEdges;
1389: PetscMalloc((p->numProcs+1) * sizeof(int), &q->firstEdge);
1390: PetscMemcpy(q->firstEdge, qOld->firstEdge, (p->numProcs+1) * sizeof(int));
1391: PetscLogObjectMemory(p, (p->numProcs+1)*2 * sizeof(int));
1393: /* We must handle ghost members since we manually construct the partition */
1394: m->numBd = mesh->numBd;
1395: m->numFaces = mesh->numFaces;
1396: m->numCorners = 3;
1397: m->numEdges = mesh->numEdges;
1398: PetscMalloc(p->numOverlapElements*m->numCorners * sizeof(int), &tri->faces);
1399: PetscMalloc(p->numOverlapElements*3 * sizeof(int), &tri->neighbors);
1400: PetscMalloc(m->numEdges*2 * sizeof(int), &tri->edges);
1401: PetscMalloc(m->numEdges * sizeof(int), &tri->edgemarkers);
1402: PetscMalloc(qOld->numOverlapNodes * sizeof(int), &newNodes);
1403: PetscLogObjectMemory(m, (p->numOverlapElements*(m->numCorners + 3) + m->numEdges*3) * sizeof(int));
1404: for(node = 0; node < qOld->numOverlapNodes; node++)
1405: newNodes[node] = -1;
1406: /* Renumber the vertices and construct the face list */
1407: for(elem = 0, newNode = 0, numGhostNodes = 0; elem < p->numOverlapElements; elem++) {
1408: for(corner = 0; corner < 3; corner++) {
1409: node = triOld->faces[elem*mesh->numCorners+corner];
1410: if (newNodes[node] == -1) {
1411: if (node >= mesh->numNodes) {
1412: /* Mark them as ghost nodes */
1413: numGhostNodes++;
1414: newNodes[node] = -2;
1415: } else {
1416: newNodes[node] = newNode++;
1417: }
1418: }
1419: tri->faces[elem*m->numCorners+corner] = node;
1420: }
1421: }
1422: PetscMemcpy(tri->neighbors, triOld->neighbors, p->numOverlapElements*3 * sizeof(int));
1423: PetscMemcpy(tri->edges, triOld->edges, m->numEdges*2 * sizeof(int));
1424: PetscMemcpy(tri->edgemarkers, triOld->edgemarkers, m->numEdges * sizeof(int));
1426: /* We may have extra ghost nodes from the edges */
1427: for(edge = 0; edge < q->numLocEdges; edge++) {
1428: for(corner = 0; corner < 2; corner++) {
1429: node = tri->edges[edge*2+corner];
1430: if (newNodes[node] == -1) {
1431: if (node >= mesh->numNodes) {
1432: /* Mark them as ghost nodes */
1433: numGhostNodes++;
1434: newNodes[node] = -2;
1435: }
1436: }
1437: }
1438: }
1440: /* Compute vertex sizes */
1441: m->numNodes = newNode;
1442: m->numVertices = m->numNodes;
1443: MPI_Allreduce(&m->numNodes, &q->numNodes, 1, MPI_INT, MPI_SUM, m->comm);
1444: q->numLocNodes = newNode;
1445: q->numOverlapNodes = newNode + numGhostNodes;
1447: /* Compute vertex partition */
1448: PetscMalloc((p->numProcs+1) * sizeof(int), &q->firstNode);
1449: PetscLogObjectMemory(p, (p->numProcs+1) * sizeof(int));
1450: MPI_Allgather(&q->numLocNodes, 1, MPI_INT, &q->firstNode[1], 1, MPI_INT, p->comm);
1451: for(proc = 1, q->firstNode[0] = 0; proc <= p->numProcs; proc++) {
1452: q->firstNode[proc] += q->firstNode[proc-1];
1453: }
1454: q->ghostNodes = PETSC_NULL;
1455: q->ghostNodeProcs = PETSC_NULL;
1456: if (numGhostNodes > 0) {
1457: PetscMalloc(numGhostNodes * sizeof(int), &q->ghostNodes);
1458: PetscMalloc(numGhostNodes * sizeof(int), &q->ghostNodeProcs);
1459: PetscLogObjectMemory(p, numGhostNodes*2 * sizeof(int));
1460: }
1462: /* Create the mapping from coarse nodes to vertices in the original mesh */
1463: PetscMalloc(m->numNodes * sizeof(int), &FineMapping);
1464: PetscMalloc(m->numNodes * sizeof(int), &CoarseMapping);
1465: for(node = 0, count = 0; node < mesh->numNodes; node++) {
1466: newNode = newNodes[node];
1467: if (newNode >= 0) {
1468: /* These are all interior nodes */
1469: PartitionLocalToGlobalNodeIndex(pOld, node, &FineMapping[count]);
1470: PartitionLocalToGlobalNodeIndex(p, newNode, &CoarseMapping[count]);
1471: count++;
1472: }
1473: }
1474: if (count != m->numNodes) SETERRQ2(PETSC_ERR_PLIB, "Invalid coarse map size %d should be %d", count, m->numNodes);
1475: AOCreateMapping(m->comm, m->numNodes, FineMapping, CoarseMapping, &m->coarseMap);
1476: PetscFree(FineMapping);
1477: PetscFree(CoarseMapping);
1479: /* Setup ghost nodes */
1480: for(ghostNode = mesh->numNodes, count = 0; ghostNode < qOld->numOverlapNodes; ghostNode++) {
1481: if (newNodes[ghostNode] == -2) {
1482: PartitionLocalToGlobalNodeIndex(pOld, ghostNode, &gNode);
1483: AOApplicationToPetsc(m->coarseMap, 1, &gNode);
1484: q->ghostNodes[count] = gNode;
1485: q->ghostNodeProcs[count] = qOld->ghostNodeProcs[ghostNode-mesh->numNodes];
1486: count++;
1487: }
1488: }
1489: if (count != numGhostNodes) SETERRQ2(PETSC_ERR_PLIB, "Invalid number of ghost nodes %d should be %d", count, numGhostNodes);
1490: /* Cleanup */
1491: PetscFree(newNodes);
1493: /* Resort ghost nodes */
1494: if (numGhostNodes > 0) {
1495: PetscMalloc(numGhostNodes*2 * sizeof(int), &nodePerm);
1496: temp = nodePerm + numGhostNodes;
1497: for(node = 0; node < numGhostNodes; node++)
1498: nodePerm[node] = node;
1499: PetscSortIntWithPermutation(numGhostNodes, q->ghostNodes, nodePerm);
1500: for(node = 0; node < numGhostNodes; node++)
1501: temp[node] = q->ghostNodes[nodePerm[node]];
1502: for(node = 0; node < numGhostNodes; node++)
1503: q->ghostNodes[node] = temp[node];
1504: for(node = 0; node < numGhostNodes; node++)
1505: temp[node] = q->ghostNodeProcs[nodePerm[node]];
1506: for(node = 0; node < numGhostNodes; node++)
1507: q->ghostNodeProcs[node] = temp[node];
1508: PetscFree(nodePerm);
1509: }
1511: /* Copy vertex information */
1512: PetscMalloc(q->numOverlapNodes*2 * sizeof(double), &tri->nodes);
1513: PetscMalloc(q->numOverlapNodes * sizeof(int), &tri->markers);
1514: PetscLogObjectMemory(m, q->numOverlapNodes*2 * sizeof(double));
1515: PetscLogObjectMemory(m, q->numOverlapNodes * sizeof(int));
1516: for(newNode = 0; newNode < q->numOverlapNodes; newNode++) {
1517: PartitionLocalToGlobalNodeIndex(p, newNode, &gNode);
1518: AOPetscToApplication(m->coarseMap, 1, &gNode);
1519: PartitionGlobalToLocalNodeIndex(pOld, gNode, &node);
1520: tri->nodes[newNode*2] = triOld->nodes[node*2];
1521: tri->nodes[newNode*2+1] = triOld->nodes[node*2+1];
1522: tri->markers[newNode] = triOld->markers[node];
1523: }
1525: /* Renumber nodes */
1526: for(elem = 0; elem < p->numOverlapElements*m->numCorners; elem++) {
1527: PartitionLocalToGlobalNodeIndex(pOld, tri->faces[elem], &tri->faces[elem]);
1528: }
1529: for(edge = 0; edge < m->numEdges*2; edge++) {
1530: PartitionLocalToGlobalNodeIndex(pOld, tri->edges[edge], &tri->edges[edge]);
1531: }
1532: AOApplicationToPetsc(m->coarseMap, p->numOverlapElements*m->numCorners, tri->faces);
1533: AOApplicationToPetsc(m->coarseMap, m->numEdges*2, tri->edges);
1534: for(elem = 0; elem < p->numOverlapElements*m->numCorners; elem++) {
1535: PartitionGlobalToLocalNodeIndex(p, tri->faces[elem], &tri->faces[elem]);
1536: }
1537: for(edge = 0; edge < m->numEdges*2; edge++) {
1538: PartitionGlobalToLocalNodeIndex(p, tri->edges[edge], &tri->edges[edge]);
1539: }
1541: /* Construct derived and boundary information */
1542: tri->areas = PETSC_NULL;
1543: tri->aspectRatios = PETSC_NULL;
1544: m->numBdEdges = mesh->numBdEdges;
1545: PetscMalloc(m->numBd * sizeof(int), &tri->bdMarkers);
1546: PetscMalloc((m->numBd+1) * sizeof(int), &tri->bdBegin);
1547: PetscMalloc((m->numBd+1) * sizeof(int), &tri->bdEdgeBegin);
1548: PetscMalloc(m->numBdEdges * sizeof(int), &tri->bdEdges);
1549: PetscLogObjectMemory(m, (m->numBd + (m->numBd+1)*2 + m->numBdEdges) * sizeof(int));
1550: PetscMemcpy(tri->bdMarkers, triOld->bdMarkers, m->numBd * sizeof(int));
1551: PetscMemcpy(tri->bdEdgeBegin, triOld->bdEdgeBegin, (m->numBd+1) * sizeof(int));
1552: PetscMemcpy(tri->bdEdges, triOld->bdEdges, m->numBdEdges * sizeof(int));
1553: tri->bdBegin[0] = 0;
1554: for(bd = 0; bd < m->numBd; bd++) {
1555: tri->bdBegin[bd+1] = tri->bdBegin[bd];
1556: for(bdNode = triOld->bdBegin[bd]; bdNode < triOld->bdBegin[bd+1]; bdNode++) {
1557: node = triOld->bdNodes[bdNode];
1558: AOMappingHasApplicationIndex(m->coarseMap, node, &hasIndex);
1559: if (hasIndex == PETSC_TRUE)
1560: tri->bdBegin[bd+1]++;
1561: }
1562: }
1563: m->numBdNodes = tri->bdBegin[m->numBd];
1564: /* Assume closed boundaries */
1565: if (m->numBdNodes != m->numBdEdges) SETERRQ(PETSC_ERR_PLIB, "Invalid mesh boundary");
1566: #ifdef PETSC_USE_BOPT_g
1567: MPI_Scan(&m->numBdNodes, &node, 1, MPI_INT, MPI_SUM, m->comm);
1568: if (node != m->numBdNodes*(p->rank+1)) SETERRQ(PETSC_ERR_PLIB, "Invalid mesh boundary");
1569: #endif
1570: PetscMalloc(m->numBdNodes * sizeof(int), &tri->bdNodes);
1571: PetscLogObjectMemory(m, m->numBdNodes * sizeof(int));
1572: for(bd = 0, count = 0; bd < m->numBd; bd++) {
1573: for(bdNode = triOld->bdBegin[bd]; bdNode < triOld->bdBegin[bd+1]; bdNode++) {
1574: node = triOld->bdNodes[bdNode];
1575: AOMappingHasApplicationIndex(m->coarseMap, node, &hasIndex);
1576: if (hasIndex == PETSC_TRUE) {
1577: AOApplicationToPetsc(m->coarseMap, 1, &node);
1578: tri->bdNodes[count++] = node;
1579: }
1580: }
1581: }
1582: if (count != m->numBdNodes) SETERRQ(PETSC_ERR_PLIB, "Invalid boundary node partition");
1584: /* Partition boundary nodes */
1585: PetscMalloc((p->numProcs+1) * sizeof(int), &q->firstBdNode);
1586: PetscLogObjectMemory(p, (p->numProcs+1) * sizeof(int));
1587: q->numLocBdNodes = 0;
1588: for(bdNode = 0; bdNode < m->numBdNodes; bdNode++) {
1589: newNode = tri->bdNodes[bdNode];
1590: if ((newNode >= q->firstNode[p->rank]) && (newNode < q->firstNode[p->rank+1]))
1591: q->numLocBdNodes++;
1592: }
1593: MPI_Allgather(&q->numLocBdNodes, 1, MPI_INT, &q->firstBdNode[1], 1, MPI_INT, p->comm);
1594: for(proc = 1, q->firstBdNode[0] = 0; proc <= p->numProcs; proc++) {
1595: q->firstBdNode[proc] += q->firstBdNode[proc-1];
1596: }
1597: q->numBdNodes = q->firstBdNode[p->numProcs];
1599: /* Process ghost boundary nodes */
1600: q->numOverlapBdNodes = q->numLocBdNodes;
1601: for(node = 0; node < numGhostNodes; node++) {
1602: if (tri->markers[m->numNodes+node] != 0)
1603: q->numOverlapBdNodes++;
1604: }
1605: q->ghostBdNodes = PETSC_NULL;
1606: if (q->numOverlapBdNodes > q->numLocBdNodes) {
1607: PetscMalloc((q->numOverlapBdNodes - q->numLocBdNodes) * sizeof(int), &q->ghostBdNodes);
1608: for(node = 0, bdNode = 0; node < numGhostNodes; node++) {
1609: if (tri->markers[m->numNodes+node] != 0)
1610: q->ghostBdNodes[bdNode++] = node;
1611: }
1612: if (bdNode != q->numOverlapBdNodes - q->numLocBdNodes) SETERRQ(PETSC_ERR_PLIB, "Invalid boundary node partition");
1613: }
1615: /* Copy holes from previous mesh */
1616: m->numHoles = mesh->numHoles;
1617: m->holes = PETSC_NULL;
1618: if (m->numHoles > 0) {
1619: PetscMalloc(m->numHoles*2 * sizeof(double), &m->holes);
1620: PetscMemcpy(m->holes, mesh->holes, m->numHoles*2 * sizeof(double));
1621: PetscLogObjectMemory(m, m->numHoles*2 * sizeof(double));
1622: }
1624: /* Calculate maximum degree of vertices */
1625: m->maxDegree = mesh->maxDegree;
1626: PetscMalloc(m->numNodes * sizeof(int), &tri->degrees);
1627: PetscMalloc(m->maxDegree * sizeof(int), &m->support);
1628: for(newNode = 0; newNode < m->numNodes; newNode++) {
1629: PartitionLocalToGlobalNodeIndex(p, newNode, &gNode);
1630: AOPetscToApplication(m->coarseMap, 1, &gNode);
1631: PartitionGlobalToLocalNodeIndex(pOld, gNode, &node);
1632: tri->degrees[newNode] = triOld->degrees[node];
1633: }
1634: m->supportTaken = PETSC_FALSE;
1636: #ifdef PETSC_USE_BOPT_g
1637: /* Check mesh integrity */
1638: MeshDebug_Triangular_2D(m, PETSC_TRUE);
1639: #endif
1641: /* Initialize save space */
1642: tri->nodesOld = PETSC_NULL;
1644: } else {
1645: SETERRQ(PETSC_ERR_SUP, "No coarsening strategies currently supported");
1646: }
1648: PetscObjectSetName((PetscObject) m, "Coarse Mesh");
1649: *newmesh = m;
1650: return(0);
1651: }
1653: /*
1654: MeshRefine_Triangular_2D - Refines a two dimensional unstructured mesh using area constraints
1656: Collective on Mesh
1658: Input Parameters:
1659: + mesh - The mesh begin refined
1660: - area - A function which gives an area constraint when evaluated inside an element
1662: Output Parameter:
1663: . newmesh - The refined mesh
1665: Level: developer
1667: .keywords unstructured grid
1668: .seealso GridRefine(), MeshCoarsen(), MeshReform()
1669: */
1670: static int MeshRefine_Triangular_2D(Mesh mesh, PointFunction area, Mesh *newmesh)
1671: {
1672: ParameterDict dict;
1673: Mesh m;
1674: int (*f)(Mesh, PointFunction, Mesh);
1675: int ierr;
1678: MeshCreate(mesh->comm, &m);
1679: ParameterDictCreate(mesh->comm, &dict);
1680: ParameterDictSetObject(dict, "bdCtx", mesh->bdCtx);
1681: ParameterDictSetInteger(dict, "dim", 2);
1682: ParameterDictSetInteger(dict, "numLocNodes", mesh->numCorners);
1683: PetscObjectSetParameterDict((PetscObject) m, dict);
1684: ParameterDictDestroy(dict);
1686: PetscObjectQueryFunction((PetscObject) mesh, "MeshTriangular2D_Refine_C", (void (**)(void)) &f);
1687: if (f == PETSC_NULL) SETERRQ(PETSC_ERR_SUP, "Mesh has no refinement function");
1688: (*f)(mesh, area, m);
1689: PetscObjectSetName((PetscObject) m, "Refined Mesh");
1690: *newmesh = m;
1691: return(0);
1692: }
1694: static int MeshResetNodes_Triangular_2D(Mesh mesh, PetscTruth resetBd)
1695: {
1696: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1697: int *elements = tri->faces;
1698: int *markers = tri->markers;
1699: double *nodes = tri->nodes;
1700: int numCorners = mesh->numCorners;
1701: int elem, corner, node1, node2, midNode, midCorner;
1704: if (numCorners == 3)
1705: return(0);
1707: if (mesh->isPeriodic == PETSC_TRUE) {
1708: for(elem = 0; elem < mesh->part->numOverlapElements; elem++) {
1709: for(corner = 0; corner < 3; corner++) {
1710: node1 = elements[elem*numCorners+corner];
1711: node2 = elements[elem*numCorners+((corner+1)%3)];
1712: if ((markers[node1] != markers[node2]) || (markers[node1] == 0) || (resetBd == PETSC_TRUE)) {
1713: midCorner = (corner+2)%3 + 3;
1714: midNode = elements[elem*numCorners+midCorner];
1715: nodes[midNode*2] = MeshPeriodicX(mesh, 0.5*(nodes[node1*2] +
1716: MeshPeriodicRelativeX(mesh, nodes[node2*2], nodes[node1*2])));
1717: nodes[midNode*2+1] = MeshPeriodicY(mesh, 0.5*(nodes[node1*2+1] +
1718: MeshPeriodicRelativeY(mesh, nodes[node2*2+1], nodes[node1*2+1])));
1719: }
1720: }
1721: }
1722: } else {
1723: for(elem = 0; elem < mesh->part->numOverlapElements; elem++) {
1724: for(corner = 0; corner < 3; corner++) {
1725: node1 = elements[elem*numCorners+corner];
1726: node2 = elements[elem*numCorners+((corner+1)%3)];
1727: if ((markers[node1] != markers[node2]) || (markers[node1] == 0) || (resetBd == PETSC_TRUE)) {
1728: midCorner = (corner+2)%3 + 3;
1729: midNode = elements[elem*numCorners+midCorner];
1730: nodes[midNode*2] = 0.5*(nodes[node1*2] + nodes[node2*2]);
1731: nodes[midNode*2+1] = 0.5*(nodes[node1*2+1] + nodes[node2*2+1]);
1732: }
1733: }
1734: }
1735: }
1736: return(0);
1737: }
1739: int MeshPartition_Triangular_2D(Mesh mesh)
1740: {
1744: PartitionCreateTriangular2D(mesh, &mesh->part);
1745: mesh->partitioned = 1;
1746: PetscFunctionReturn(ierr);
1747: }
1749: int MeshUpdateBoundingBox_Triangular_2D(Mesh mesh)
1750: {
1751: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1752: double *nodes = tri->nodes;
1753: Partition part;
1754: int dim, numOverlapNodes;
1755: int node;
1756: int ierr;
1758: /* Calculate the local bounding box */
1760: MeshGetPartition(mesh, &part);
1761: MeshGetDimension(mesh, &dim);
1762: PartitionGetNumOverlapNodes(part, &numOverlapNodes);
1763: if (numOverlapNodes > 0) {
1764: mesh->locStartX = mesh->locEndX = nodes[0];
1765: mesh->locStartY = mesh->locEndY = nodes[1];
1766: } else {
1767: mesh->locStartX = mesh->locEndX = 0.0;
1768: mesh->locStartY = mesh->locEndY = 0.0;
1769: }
1770: for(node = 0; node < numOverlapNodes; node++) {
1771: if (nodes[node*dim] < mesh->locStartX) mesh->locStartX = nodes[node*dim];
1772: if (nodes[node*dim] > mesh->locEndX) mesh->locEndX = nodes[node*dim];
1773: if (nodes[node*dim+1] < mesh->locStartY) mesh->locStartY = nodes[node*dim+1];
1774: if (nodes[node*dim+1] > mesh->locEndY) mesh->locEndY = nodes[node*dim+1];
1775: }
1776: mesh->locSizeX = mesh->locEndX - mesh->locStartX;
1777: mesh->locSizeY = mesh->locEndY - mesh->locStartY;
1778: return(0);
1779: }
1781: int MeshGetElemNeighbor_Triangular_2D(Mesh mesh, int elem, int corner, int *neighbor)
1782: {
1783: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1784: #ifdef PETSC_USE_BOPT_g
1785: int numOverlapElements;
1786: int ierr;
1787: #endif
1790: #ifdef PETSC_USE_BOPT_g
1791: PartitionGetNumOverlapElements(mesh->part, &numOverlapElements);
1792: if ((elem < 0) || (elem >= numOverlapElements)) {
1793: SETERRQ2(PETSC_ERR_ARG_WRONG, "Invalid element %d should be in [0,%d)", elem, numOverlapElements);
1794: }
1795: if ((corner < 0) || (corner >= mesh->numCorners)) {
1796: SETERRQ2(PETSC_ERR_ARG_WRONG, "Invalid corner %d should be in [0,%d)", corner, mesh->numCorners);
1797: }
1798: #endif
1799: *neighbor = tri->neighbors[elem*3+corner];
1800: return(0);
1801: }
1803: int MeshGetNodeCoords_Triangular_2D(Mesh mesh, int node, double *x, double *y, double *z)
1804: {
1805: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1806: int dim = mesh->dim;
1807: #ifdef PETSC_USE_BOPT_g
1808: int numOverlapNodes;
1809: int ierr;
1810: #endif
1813: #ifdef PETSC_USE_BOPT_g
1814: ierr = PartitionGetNumOverlapNodes(mesh->part, &numOverlapNodes);
1815: if ((node < 0) || (node >= numOverlapNodes)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE, "Invalid node specified");
1816: #endif
1817: if (x != PETSC_NULL) *x = tri->nodes[node*dim];
1818: if (y != PETSC_NULL) *y = tri->nodes[node*dim+1];
1819: if (z != PETSC_NULL) *z = 0.0;
1820: return(0);
1821: }
1823: int MeshSetNodeCoords_Triangular_2D(Mesh mesh, int node, double x, double y, double z)
1824: {
1825: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1826: int dim = mesh->dim;
1827: #ifdef PETSC_USE_BOPT_g
1828: int numOverlapNodes;
1829: int ierr;
1830: #endif
1833: #ifdef PETSC_USE_BOPT_g
1834: ierr = PartitionGetNumOverlapNodes(mesh->part, &numOverlapNodes);
1835: if ((node < 0) || (node >= numOverlapNodes)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE, "Invalid node specified");
1836: #endif
1837: tri->nodes[node*dim] = MeshPeriodicX(mesh, x);
1838: tri->nodes[node*dim+1] = MeshPeriodicY(mesh, y);
1839: return(0);
1840: }
1842: int MeshGetNodeCoordsSaved_Triangular_2D(Mesh mesh, int node, double *x, double *y, double *z)
1843: {
1844: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1845: int dim = mesh->dim;
1846: #ifdef PETSC_USE_BOPT_g
1847: int numOverlapNodes;
1848: int ierr;
1849: #endif
1852: #ifdef PETSC_USE_BOPT_g
1853: ierr = PartitionGetNumOverlapNodes(mesh->part, &numOverlapNodes);
1854: if ((node < 0) || (node >= numOverlapNodes)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE, "Invalid node specified");
1855: #endif
1856: if (tri->nodesOld != PETSC_NULL) {
1857: if (x != PETSC_NULL) *x = tri->nodesOld[node*dim];
1858: if (y != PETSC_NULL) *y = tri->nodesOld[node*dim+1];
1859: if (z != PETSC_NULL) *z = 0.0;
1860: } else {
1861: if (x != PETSC_NULL) *x = tri->nodes[node*dim];
1862: if (y != PETSC_NULL) *y = tri->nodes[node*dim+1];
1863: if (z != PETSC_NULL) *z = 0.0;
1864: }
1865: return(0);
1866: }
1868: int MeshGetNodeBoundary_Triangular_2D(Mesh mesh, int node, int *bd)
1869: {
1870: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1871: #ifdef PETSC_USE_BOPT_g
1872: int numOverlapNodes;
1873: int ierr;
1874: #endif
1877: #ifdef PETSC_USE_BOPT_g
1878: ierr = PartitionGetNumOverlapNodes(mesh->part, &numOverlapNodes);
1879: if ((node < 0) || (node >= numOverlapNodes)) {
1880: SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE, "Invalid node %d should be in [0,%d)", node, numOverlapNodes);
1881: }
1882: #endif
1883: *bd = tri->markers[node];
1884: return(0);
1885: }
1887: int MeshGetNodeFromElement_Triangular_2D(Mesh mesh, int elem, int corner, int *node)
1888: {
1889: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1890: int numCorners = mesh->numCorners;
1893: *node = tri->faces[elem*numCorners+corner];
1894: return(0);
1895: }
1897: int MeshGetNodeFromEdge_Triangular_2D(Mesh mesh, int edge, int corner, int *node)
1898: {
1899: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1902: *node = tri->edges[edge*2+corner];
1903: return(0);
1904: }
1906: int MeshNodeIsVertex_Triangular_2D(Mesh mesh, int node, PetscTruth *isVertex)
1907: {
1908: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1909: #ifdef PETSC_USE_BOPT_g
1910: int numOverlapNodes;
1911: int ierr;
1912: #endif
1915: #ifdef PETSC_USE_BOPT_g
1916: ierr = PartitionGetNumOverlapNodes(mesh->part, &numOverlapNodes);
1917: if ((node < 0) || (node >= numOverlapNodes)) {
1918: SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE, "Invalid node %d should be in [0,%d)", node, numOverlapNodes);
1919: }
1920: #endif
1921: if (tri->degrees[node] == 0)
1922: *isVertex = PETSC_FALSE;
1923: else
1924: *isVertex = PETSC_TRUE;
1925: return(0);
1926: }
1928: int MeshGetBoundarySize_Triangular_2D(Mesh mesh, int boundary, int *size)
1929: {
1930: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1931: int b; /* Canonical boundary number */
1932: int ierr;
1935: /* Find canonical boundary number */
1936: MeshGetBoundaryIndex(mesh, boundary, &b);
1937: *size = tri->bdBegin[b+1] - tri->bdBegin[b];
1938: return(0);
1939: }
1941: int MeshGetBoundaryIndex_Triangular_2D(Mesh mesh, int boundary, int *index)
1942: {
1943: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1944: int b; /* Canonical boundary number */
1947: /* Find canonical boundary number */
1948: for(b = 0; b < mesh->numBd; b++)
1949: if (tri->bdMarkers[b] == boundary) break;
1950: if (b == mesh->numBd) SETERRQ1(PETSC_ERR_ARG_WRONG, "Invalid boundary marker %d", boundary);
1951: *index = b;
1952: return(0);
1953: }
1955: int MeshGetBoundaryStart_Triangular_2D(Mesh mesh, int boundary, PetscTruth ghost, int *node)
1956: {
1957: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1958: int b; /* Canonical boundary number */
1959: int ierr;
1962: /* Find canonical boundary number */
1963: MeshGetBoundaryIndex(mesh, boundary, &b);
1964: if (mesh->activeBd != -1) SETERRQ1(PETSC_ERR_ARG_WRONGSTATE, "Already iterating over boundary %d", mesh->activeBd);
1965: /* Find first boundary node */
1966: mesh->activeBd = b;
1967: mesh->activeBdOld = b;
1968: mesh->activeBdNode = tri->bdBegin[b] - 1;
1969: MeshGetBoundaryNext(mesh, boundary, ghost, node);
1970: return(0);
1971: }
1973: int MeshGetBoundaryNext_Triangular_2D(Mesh mesh, int boundary, PetscTruth ghost, int *node)
1974: {
1975: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
1976: Partition p = mesh->part;
1977: Partition_Triangular_2D *q = (Partition_Triangular_2D *) p->data;
1978: int numNodes = mesh->numNodes;
1979: int b; /* Canonical boundary number */
1980: int tempNode; /* Canonical local node number */
1981: int ierr;
1984: /* Find canonical boundary number */
1985: MeshGetBoundaryIndex(mesh, boundary, &b);
1986: /* Find next boundary node */
1987: if (mesh->activeBd != b) SETERRQ1(PETSC_ERR_ARG_WRONG, "Boundary %d not active", boundary);
1988: do {
1989: mesh->activeBdNode++;
1990: if (mesh->activeBdNode == tri->bdBegin[b+1]) {
1991: mesh->activeBd = mesh->activeBdNode = -1;
1992: *node = -1;
1993: return(0);
1994: }
1995: tempNode = tri->bdNodes[mesh->activeBdNode] - q->firstNode[p->rank];
1996: /* Translate ghost nodes */
1997: if (ghost == PETSC_TRUE) {
1998: if ((tempNode < 0) || (tempNode >= numNodes)) {
1999: PartitionGhostNodeIndex_Private(p, tri->bdNodes[mesh->activeBdNode], &tempNode);
2000: if (ierr == 0) {
2001: tempNode += numNodes;
2002: break;
2003: }
2004: }
2005: }
2006: }
2007: while((tempNode < 0) || (tempNode >= numNodes));
2008: *node = tempNode;
2009: return(0);
2010: }
2012: int MeshGetActiveBoundary_Triangular_2D(Mesh mesh, int *boundary)
2013: {
2014: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
2017: if (mesh->activeBdOld >= 0) {
2018: *boundary = tri->bdMarkers[mesh->activeBdOld];
2019: } else {
2020: *boundary = 0;
2021: }
2022: return(0);
2023: }
2025: int MeshGetNodeSupport_Triangular_2D(Mesh mesh, int node, int startElem, int *degree, int **support)
2026: {
2027: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
2028: int numOverlapElements = mesh->numFaces;
2029: int numCorners = mesh->numCorners;
2030: int *elements = tri->faces;
2031: int *neighbors = tri->neighbors;
2032: int deg = -1;
2033: PetscTruth found;
2034: int firstElem;
2035: int prevElem, nextElem;
2036: int elem, neighbor, corner;
2039: /* First check suggested element */
2040: firstElem = -1;
2041: for(corner = 0; corner < numCorners; corner++) {
2042: if (elements[startElem*numCorners+corner] == node) {
2043: firstElem = startElem;
2044: if (corner >= 3) {
2045: deg = 1;
2046: } else {
2047: deg = 0;
2048: }
2049: break;
2050: }
2051: }
2053: /* Locate an element containing the node */
2054: if (mesh->part != PETSC_NULL) {
2055: numOverlapElements = mesh->part->numOverlapElements;
2056: }
2057: for(elem = 0; (elem < numOverlapElements) && (firstElem < 0); elem++) {
2058: for(corner = 0; corner < numCorners; corner++) {
2059: if (elements[elem*numCorners+corner] == node) {
2060: firstElem = elem;
2061: if (corner >= 3) {
2062: deg = 1;
2063: } else {
2064: deg = 0;
2065: }
2066: break;
2067: }
2068: }
2069: }
2070: if (firstElem < 0) {
2071: SETERRQ1(PETSC_ERR_ARG_WRONG, "Node %d not found in mesh", node);
2072: }
2074: /* Check for midnode */
2075: if (deg != 0) {
2076: mesh->support[0] = firstElem;
2077: mesh->support[1] = -1;
2078: /* Find other element containing node */
2079: for(neighbor = 0; neighbor < 3; neighbor++) {
2080: elem = neighbors[firstElem*3+neighbor];
2081: if (elem < 0)
2082: continue;
2084: for(corner = 3; corner < numCorners; corner++) {
2085: if (elements[elem*numCorners+corner] == node) {
2086: mesh->support[1] = elem;
2087: deg++;
2088: break;
2089: }
2090: }
2091: if (corner < numCorners) break;
2092: }
2093: #ifdef PETSC_USE_BOPT_g
2094: if (mesh->support[1] == -1) {
2095: if (tri->markers[node] == 0) SETERRQ1(PETSC_ERR_PLIB, "Interior node %d with incomplete support", node);
2096: }
2097: #endif
2098: *support = mesh->support;
2099: *degree = deg;
2100: return(0);
2101: }
2103: /* Walk around node */
2104: prevElem = -1;
2105: nextElem = -1;
2106: found = PETSC_TRUE;
2107: while((nextElem != firstElem) && (found == PETSC_TRUE)) {
2108: /* First time through */
2109: if (prevElem == -1)
2110: nextElem = firstElem;
2112: /* Add element to the list */
2113: mesh->support[deg++] = nextElem;
2115: /* Look for a neighbor containing the node */
2116: found = PETSC_FALSE;
2117: for(neighbor = 0; neighbor < 3; neighbor++) {
2118: /* Reject the element we just came from (we could reject the opposite face also) */
2119: elem = neighbors[nextElem*3+neighbor];
2120: if ((elem == prevElem) || (elem < 0)) continue;
2122: for(corner = 0; corner < 3; corner++) {
2123: if (elements[elem*numCorners+corner] == node) {
2124: prevElem = nextElem;
2125: nextElem = elem;
2126: found = PETSC_TRUE;
2127: break;
2128: }
2129: }
2130: if (corner < 3) break;
2131: }
2133: if (found == PETSC_FALSE) {
2134: #ifdef PETSC_USE_BOPT_g
2135: /* Make sure that this is a boundary node */
2136: if (tri->markers[node] == 0) SETERRQ(PETSC_ERR_PLIB, "Interior node with incomplete support");
2137: #endif
2139: /* Also walk the other way for a boundary node --
2140: We could be nice and reorder the elements afterwards to all be adjacent */
2141: if (deg > 1) {
2142: prevElem = mesh->support[1];
2143: nextElem = mesh->support[0];
2144: found = PETSC_TRUE;
2145: while(found == PETSC_TRUE) {
2146: /* Look for a neighbor containing the node */
2147: found = PETSC_FALSE;
2148: for(neighbor = 0; neighbor < 3; neighbor++) {
2149: /* Reject the element we just came from (we could reject the opposite face also) */
2150: elem = neighbors[nextElem*3+neighbor];
2151: if ((elem == prevElem) || (elem < 0)) continue;
2153: for(corner = 0; corner < 3; corner++) {
2154: if (elements[elem*numCorners+corner] == node) {
2155: prevElem = nextElem;
2156: nextElem = elem;
2157: found = PETSC_TRUE;
2159: /* Add element to the list */
2160: mesh->support[deg++] = nextElem;
2161: break;
2162: }
2163: }
2164: if (corner < 3) break;
2165: }
2166: }
2167: }
2168: }
2170: #ifdef PETSC_USE_BOPT_g
2171: /* Check for overflow */
2172: if (deg > mesh->maxDegree) SETERRQ1(PETSC_ERR_MEM, "Maximum degree %d exceeded", mesh->maxDegree);
2173: #endif
2174: }
2176: *support = mesh->support;
2177: *degree = deg;
2178: return(0);
2179: }
2181: #if 0
2182: int MeshLocatePoint_Triangular_2D_Directed(Mesh mesh, double xx, double yy, double zz, int *containingElem)
2183: {
2184: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
2185: double start_x, start_y; /* Coordinates of a vertex */
2186: double v_x, v_y; /* Coordinates of an edge vector */
2187: double p_x, p_y; /* Coordinates of the vector from a vertex (start) to a point */
2188: double cross; /* The magnitude of the cross product of two vectors */
2189: PetscTruth inside[3]; /* Are we in the correct halfplane? */
2190: PetscTruth found; /* We have found the element containing a point */
2191: int nextElem; /* The next element to search */
2192: int prevElem; /* The last element searched */
2193: int numCorners = mesh->numCorners;
2194: int numElements = mesh->numFaces;
2195: double *nodes = tri->nodes;
2196: int *elements = tri->faces;
2197: int *neighbors = tri->neighbors;
2198: double x = xx;
2199: double y = yy;
2200: double coords[6];
2201: int neighbor;
2202: int elem, edge;
2205: *containingElem = -1;
2206: /* Quick bounding rectangle check */
2207: if ((mesh->isPeriodic == PETSC_FALSE) &&
2208: ((mesh->locStartX > x) || (mesh->locEndX < x) || (mesh->locStartY > y) || (mesh->locEndY < y)))
2209: return(0);
2210: /* Simple search */
2211: for(elem = 0, found = PETSC_FALSE; elem < numElements; elem++) {
2212: /* A point lies within a triangle is it is on the inner side of every edge --
2213: We take the cross product of the edge oriented counterclockwise with
2214: the vector from the edge start to the point:
2216: 2
2217: |
2218: |
2219: |
2220: 0---1----> v_0
2221:
2222: theta
2223:
2224: P
2226: If
2228: |v_i cross P| equiv |v_i| |P| sintheta > 0
2230: then the point lies in the correct half-plane. This has the advantage of
2231: only using elementary arithmetic. Robust predicates could be used to catch
2232: points near a boundary.
2233: */
2234: if (mesh->isPeriodic == PETSC_TRUE) {
2235: coords[0] = nodes[elements[elem*numCorners]*2];
2236: coords[1] = nodes[elements[elem*numCorners]*2+1];
2237: coords[2] = MeshPeriodicRelativeX(mesh, nodes[elements[elem*numCorners+1]*2], nodes[elements[elem*numCorners]*2]);
2238: coords[3] = MeshPeriodicRelativeY(mesh, nodes[elements[elem*numCorners+1]*2+1], nodes[elements[elem*numCorners]*2+1]);
2239: coords[4] = MeshPeriodicRelativeX(mesh, nodes[elements[elem*numCorners+2]*2], nodes[elements[elem*numCorners]*2]);
2240: coords[5] = MeshPeriodicRelativeY(mesh, nodes[elements[elem*numCorners+2]*2+1], nodes[elements[elem*numCorners]*2+1]);
2241: x = MeshPeriodicRelativeX(mesh, xx, nodes[elements[elem*numCorners]*2]);
2242: y = MeshPeriodicRelativeY(mesh, yy, nodes[elements[elem*numCorners]*2+1]);
2243: }
2244: for(edge = 0; edge < 3; edge++) {
2245: /* First edge 0--1 */
2246: if (mesh->isPeriodic == PETSC_TRUE) {
2247: start_x = coords[edge*2];
2248: start_y = coords[edge*2+1];
2249: v_x = coords[((edge+1)%3)*2] - start_x;
2250: v_y = coords[((edge+1)%3)*2+1] - start_y;
2251: } else {
2252: start_x = nodes[elements[elem*numCorners+edge]*2];
2253: start_y = nodes[elements[elem*numCorners+edge]*2+1];
2254: v_x = nodes[elements[elem*numCorners+((edge+1)%3)]*2] - start_x;
2255: v_y = nodes[elements[elem*numCorners+((edge+1)%3)]*2+1] - start_y;
2256: }
2257: p_x = x - start_x;
2258: p_y = y - start_y;
2259: cross = v_x*p_y - v_y*p_x;
2261: /* We will use this routine to find integration points which lie on the
2262: boundary so we must give a little slack to the test. I do not think
2263: this will bias our results. */
2264: if ((cross >= 0) || (PetscAbsScalar(cross) < PETSC_MACHINE_EPSILON)) {
2265: inside[edge] = PETSC_TRUE;
2266: } else {
2267: inside[edge] = PETSC_FALSE;
2268: }
2269: }
2271: /* This information could be used for a directed search --
2273: 4 T|
2274: F|
2275: F|
2276: |
2277: |
2278: 2
2279: T | T
2280: 5 T | F 3
2281: F |T T
2282: ----0---1------
2283: F | F F
2284: 6 T | T 1 F 2
2285: F | T T
2287: and clearly all F's means that the area of the triangle is 0.
2288: The regions are ordered so that all the Hamming distances are
2289: 1 (Gray code).
2290: */
2291: if (inside[2] == PETSC_TRUE) {
2292: if (inside[1] == PETSC_TRUE) {
2293: if (inside[0] == PETSC_TRUE) {
2294: /* Region 0 -- TTT */
2295: found = PETSC_TRUE;
2296: } else {
2297: /* Region 1 -- FTT */
2298: nextElem = neighbors[elem*3+2];
2299: }
2300: } else {
2301: if (inside[0] == PETSC_TRUE) {
2302: /* Region 3 -- TFT */
2303: nextElem = neighbors[elem*3];
2304: } else {
2305: /* Region 2 -- FFT */
2306: if (neighbors[elem*3] >= 0) {
2307: nextElem = neighbors[elem*3];
2308: } else {
2309: nextElem = neighbors[elem*3+2];
2310: }
2311: }
2312: }
2313: } else {
2314: if (inside[1] == PETSC_TRUE) {
2315: if (inside[0] == PETSC_TRUE) {
2316: /* Region 5 -- TTF */
2317: nextElem = neighbors[elem*3+1];
2318: } else {
2319: /* Region 6 -- FTF */
2320: if (neighbors[elem*3+1] >= 0) {
2321: nextElem = neighbors[elem*3+1];
2322: } else {
2323: nextElem = neighbors[elem*3+2];
2324: }
2325: }
2326: } else {
2327: if (inside[0] == PETSC_TRUE) {
2328: /* Region 4 -- TFF */
2329: if (neighbors[elem*3] >= 0) {
2330: nextElem = neighbors[elem*3];
2331: } else {
2332: nextElem = neighbors[elem*3+1];
2333: }
2334: } else {
2335: /* Region 7 -- FFF */
2336: PetscPrintf(PETSC_COMM_SELF, "Element %d: (%g, %g)-(%g, %g)-(%g, %g) and (%g, %g)n", elem,
2337: nodes[elements[elem*numCorners]*2], nodes[elements[elem*numCorners]*2+1],
2338: nodes[elements[elem*numCorners+1]*2], nodes[elements[elem*numCorners+1]*2+1],
2339: nodes[elements[elem*numCorners+2]*2], nodes[elements[elem*numCorners+2]*2+1], x, y);
2340: SETERRQ1(PETSC_ERR_MESH_NULL_ELEM, "Element %d has no area", elem);
2341: }
2342: }
2343: }
2345: /* We found the point */
2346: if (found) {
2347: *containingElem = elem;
2348: break;
2349: }
2351: /* Choose next direction */
2352: if (nextElem < 0) {
2353: /* Choose randomly */
2354: for(neighbor = 0; neighbor < 3; neighbor++) {
2355: tempElem = neighbors[elem*3+neighbor];
2356: if ((tempElem >= 0) && (tempElem != prevElem)) {
2357: nextElem = tempElem;
2358: break;
2359: }
2360: }
2361: if (nextElem < 0) {
2362: SETERRQ1(PETSC_ERR_MAX_ITER, "Element search hit dead end in element %d", elem);
2363: }
2364: }
2366: prevElem = elem;
2367: }
2369: return(0);
2370: }
2371: #endif
2373: int MeshLocatePoint_Triangular_2D(Mesh mesh, double xx, double yy, double zz, int *containingElem) {
2374: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
2375: double start_x, start_y; /* Coordinates of a vertex */
2376: double v_x, v_y; /* Coordinates of an edge vector */
2377: double p_x, p_y; /* Coordinates of the vector from a vertex (start) to a point */
2378: double cross; /* The magnitude of the cross product of two vectors */
2379: PetscTruth inside[3]; /* Are we in the correct halfplane? */
2380: PetscTruth found; /* We have found the element containing a point */
2381: int numCorners = mesh->numCorners;
2382: int numElements = mesh->numFaces;
2383: double *nodes = tri->nodes;
2384: int *markers = tri->markers;
2385: int *elements = tri->faces;
2386: int *neighbors = tri->neighbors;
2387: double x = xx;
2388: double y = yy;
2389: double coords[6];
2390: double pNormSq;
2391: int elem, edge;
2394: *containingElem = -1;
2395: /* Quick bounding rectangle check */
2396: if ((mesh->isPeriodic == PETSC_FALSE) &&
2397: ((mesh->locStartX > x) || (mesh->locEndX < x) || (mesh->locStartY > y) || (mesh->locEndY < y)))
2398: return(0);
2399: /* Simple search */
2400: for(elem = 0, found = PETSC_FALSE; elem < numElements; elem++) {
2401: /* A point lies within a triangle is it is on the inner side of every edge --
2402: We take the cross product of the edge oriented counterclockwise with
2403: the vector from the edge start to the point:
2405: 2
2406: |
2407: |
2408: |
2409: 0---1----> v_0
2410:
2411: theta
2412:
2413: P
2415: If
2417: |v_i cross P| equiv |v_i| |P| sintheta > 0
2419: then the point lies in the correct half-plane. This has the advantage of
2420: only using elementary arithmetic. Robust predicates could be used to catch
2421: points near a boundary.
2422: */
2423: if (mesh->isPeriodic == PETSC_TRUE) {
2424: coords[0] = nodes[elements[elem*numCorners]*2];
2425: coords[1] = nodes[elements[elem*numCorners]*2+1];
2426: coords[2] = MeshPeriodicRelativeX(mesh, nodes[elements[elem*numCorners+1]*2], nodes[elements[elem*numCorners]*2]);
2427: coords[3] = MeshPeriodicRelativeY(mesh, nodes[elements[elem*numCorners+1]*2+1], nodes[elements[elem*numCorners]*2+1]);
2428: coords[4] = MeshPeriodicRelativeX(mesh, nodes[elements[elem*numCorners+2]*2], nodes[elements[elem*numCorners]*2]);
2429: coords[5] = MeshPeriodicRelativeY(mesh, nodes[elements[elem*numCorners+2]*2+1], nodes[elements[elem*numCorners]*2+1]);
2430: x = MeshPeriodicRelativeX(mesh, xx, nodes[elements[elem*numCorners]*2]);
2431: y = MeshPeriodicRelativeY(mesh, yy, nodes[elements[elem*numCorners]*2+1]);
2432: }
2433: for(edge = 0; edge < 3; edge++) {
2434: /* First edge 0--1 */
2435: if (mesh->isPeriodic == PETSC_TRUE) {
2436: start_x = coords[edge*2];
2437: start_y = coords[edge*2+1];
2438: v_x = coords[((edge+1)%3)*2] - start_x;
2439: v_y = coords[((edge+1)%3)*2+1] - start_y;
2440: } else {
2441: start_x = nodes[elements[elem*numCorners+edge]*2];
2442: start_y = nodes[elements[elem*numCorners+edge]*2+1];
2443: v_x = nodes[elements[elem*numCorners+((edge+1)%3)]*2] - start_x;
2444: v_y = nodes[elements[elem*numCorners+((edge+1)%3)]*2+1] - start_y;
2445: }
2446: p_x = x - start_x;
2447: p_y = y - start_y;
2448: cross = v_x*p_y - v_y*p_x;
2449: pNormSq = p_x*p_x+p_y*p_y;
2451: /* Check for identical points, being looser at the boundary */
2452: if (pNormSq < PETSC_MACHINE_EPSILON) {
2453: *containingElem = elem;
2454: return(0);
2455: } else if (markers[elements[elem*numCorners+edge]] != 0) {
2456: if (pNormSq < 0.001*PetscMax(v_x*v_x, v_y*v_y)) {
2457: *containingElem = elem;
2458: return(0);
2459: }
2460: }
2462: if (cross >= 0) {
2463: inside[edge] = PETSC_TRUE;
2464: } else if ((neighbors[elem*3+((edge+2)%3)] < 0) && (cross*cross < 0.087155743*(v_x*v_x+v_y*v_y)*pNormSq)) {
2465: /* We are losing precision here (I think) for large problems (since points are turning up inside particles)
2466: and therefore I am putting a 5 degree limit on this check (sin 5 = 0.087155743), which is only active for
2467: boundary edges. */
2468: inside[edge] = PETSC_TRUE;
2469: } else {
2470: inside[edge] = PETSC_FALSE;
2471: }
2472: }
2474: /* This information could be used for a directed search --
2476: 4 T|
2477: F|
2478: F|
2479: |
2480: |
2481: 2
2482: T | T
2483: 5 T | F 3
2484: F |T T
2485: ----0---1------
2486: F | F F
2487: 6 T | T 1 F 2
2488: F | T T
2490: and clearly all F's means that the area of the triangle is 0.
2491: The regions are ordered so that all the Hamming distances are
2492: 1 (Gray code).
2493: */
2494: if ((inside[2] == PETSC_TRUE) && (inside[1] == PETSC_TRUE) && (inside[0] == PETSC_TRUE)) {
2495: double minX = coords[0];
2496: double maxX = coords[0];
2497: double minY = coords[1];
2498: double maxY = coords[1];
2499: double offX, offY;
2501: if (coords[2] < minX) minX = coords[2];
2502: if (coords[2] > maxX) maxX = coords[2];
2503: if (coords[3] < minY) minY = coords[3];
2504: if (coords[3] > maxY) maxY = coords[3];
2505: if (coords[4] < minX) minX = coords[4];
2506: if (coords[4] > maxX) maxX = coords[4];
2507: if (coords[5] < minY) minY = coords[5];
2508: if (coords[5] > maxY) maxY = coords[5];
2509: offX = 0.01*(maxX - minX);
2510: offY = 0.01*(maxY - minY);
2512: if ((x >= minX-offX) && (x <= maxX+offX) && (y >= minY-offY) && (y <= maxY+offY)) {
2513: /* Region 0 -- TTT */
2514: found = PETSC_TRUE;
2515: }
2516: } else if ((inside[2] == PETSC_FALSE) && (inside[1] == PETSC_FALSE) && (inside[0] == PETSC_FALSE)) {
2517: /* Region 7 -- FFF */
2518: PetscPrintf(PETSC_COMM_SELF, "Element %d: (%g, %g)-(%g, %g)-(%g, %g) and (%g, %g)n", elem, coords[0], coords[1], coords[2],
2519: coords[3], coords[4], coords[5], x, y);
2520: SETERRQ1(PETSC_ERR_MESH_NULL_ELEM, "Element %d has no area or is inverted", elem);
2521: }
2523: /* We found the point */
2524: if (found) {
2525: *containingElem = elem;
2526: break;
2527: }
2528: }
2530: return(0);
2531: }
2533: int MeshNearestNode_Triangular_2D(Mesh mesh, double x, double y, double z, PetscTruth outsideDomain, int *node)
2534: {
2535: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
2536: Partition p = mesh->part;
2537: Partition_Triangular_2D *q = (Partition_Triangular_2D *) p->data;
2538: int numCorners = mesh->numCorners;
2539: int *elements = tri->faces;
2540: int numNodes = mesh->numNodes;
2541: double *nodes = tri->nodes;
2542: int *firstNode = q->firstNode;
2543: int rank = p->rank;
2544: int elem;
2545: double minDist, dist, allMinDist;
2546: int minNode, globalMinNode, allMinNode;
2547: int corner, n;
2548: int ierr;
2551: if (outsideDomain == PETSC_FALSE) {
2552: MeshLocatePoint(mesh, x, y, z, &elem);
2553: if (elem >= 0) {
2554: minDist = PetscSqr(MeshPeriodicDiffX(mesh, nodes[elements[elem*numCorners]*2] - x)) +
2555: PetscSqr(MeshPeriodicDiffY(mesh, nodes[elements[elem*numCorners]*2+1] - y));
2556: minNode = elements[elem*numCorners];
2557: for(corner = 1; corner < numCorners; corner++) {
2558: dist = PetscSqr(MeshPeriodicDiffX(mesh, nodes[elements[elem*numCorners+corner]*2] - x)) +
2559: PetscSqr(MeshPeriodicDiffY(mesh, nodes[elements[elem*numCorners+corner]*2+1] - y));
2560: if (dist < minDist) {
2561: minDist = dist;
2562: minNode = elements[elem*numCorners+corner];
2563: }
2564: }
2565: PartitionLocalToGlobalNodeIndex(p, minNode, &globalMinNode);
2566: } else {
2567: minNode = -1;
2568: globalMinNode = -1;
2569: }
2571: /* The minimum node might still be a ghost node */
2572: MPI_Allreduce(&globalMinNode, &allMinNode, 1, MPI_INT, MPI_MAX, p->comm);
2573: if ((allMinNode >= firstNode[rank]) && (allMinNode < firstNode[rank+1])) {
2574: *node = allMinNode - firstNode[rank];
2575: } else {
2576: *node = -1;
2577: }
2578: if (allMinNode < 0)
2579: PetscFunctionReturn(1);
2580: } else {
2581: /* Brute force check */
2582: minNode = 0;
2583: minDist = PetscSqr(MeshPeriodicDiffX(mesh, nodes[0*2] - x)) +
2584: PetscSqr(MeshPeriodicDiffY(mesh, nodes[0*2+1] - y));
2585: for(n = 1; n < numNodes; n++) {
2586: dist = PetscSqr(MeshPeriodicDiffX(mesh, nodes[n*2] - x)) +
2587: PetscSqr(MeshPeriodicDiffY(mesh, nodes[n*2+1] - y));
2588: if (dist < minDist) {
2589: minDist = dist;
2590: minNode = n;
2591: }
2592: }
2594: /* Find the minimum distance */
2595: MPI_Allreduce(&minDist, &allMinDist, 1, MPI_DOUBLE, MPI_MIN, p->comm);
2596: if (minDist == allMinDist) {
2597: PartitionLocalToGlobalNodeIndex(p, minNode, &globalMinNode);
2598: } else {
2599: globalMinNode = -1;
2600: }
2602: /* We might still have ties */
2603: MPI_Allreduce(&globalMinNode, &allMinNode, 1, MPI_INT, MPI_MAX, p->comm);
2604: if ((allMinNode >= firstNode[rank]) && (allMinNode < firstNode[rank+1])) {
2605: *node = allMinNode - firstNode[rank];
2606: } else {
2607: *node = -1;
2608: }
2609: if (allMinNode < 0)
2610: PetscFunctionReturn(1);
2611: }
2613: return(0);
2614: }
2616: int MeshSaveMesh_Triangular_2D(Mesh mesh) {
2617: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
2618: int dim = mesh->dim;
2619: int numOverlapNodes;
2620: int ierr;
2623: ierr = PartitionGetNumOverlapNodes(mesh->part, &numOverlapNodes);
2624: if (tri->nodesOld == PETSC_NULL) {
2625: PetscMalloc(numOverlapNodes*dim * sizeof(double), &tri->nodesOld);
2626: PetscLogObjectMemory(mesh, numOverlapNodes*dim * sizeof(double));
2627: }
2628: PetscMemcpy(tri->nodesOld, tri->nodes, numOverlapNodes*dim * sizeof(double));
2629: return(0);
2630: }
2632: int MeshRestoreMesh_Triangular_2D(Mesh mesh) {
2633: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
2634: int dim = mesh->dim;
2635: int numOverlapNodes;
2636: int ierr;
2639: ierr = PartitionGetNumOverlapNodes(mesh->part, &numOverlapNodes);
2640: if (tri->nodesOld != PETSC_NULL) {
2641: PetscMemcpy(tri->nodes, tri->nodesOld, numOverlapNodes*dim * sizeof(double));
2642: }
2643: return(0);
2644: }
2646: int MeshIsDistorted_Triangular_2D(Mesh mesh, PetscTruth *flag) {
2647: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
2648: double *nodes = tri->nodes;
2649: int *faces = tri->faces;
2650: int numCorners = mesh->numCorners;
2651: int numElements = mesh->numFaces;
2652: double maxAspectRatio = mesh->maxAspectRatio;
2653: double area; /* Twice the area of the triangle */
2654: double aspectRatio; /* (Longest edge)^2/(Twice the area of the triangle) */
2655: double max;
2656: PetscTruth locFlag;
2657: double x21, y21, x31, y31, x32, y32;
2658: int elem;
2659: int locRetVal;
2660: int retVal;
2661: int ierr;
2664: for(elem = 0, locFlag = PETSC_FALSE, locRetVal = 0, max = 0.0; elem < numElements; elem++) {
2665: /* Find the area */
2666: if (mesh->isPeriodic == PETSC_TRUE) {
2667: x21 = MeshPeriodicDiffX(mesh, nodes[faces[elem*numCorners+1]*2] - nodes[faces[elem*numCorners]*2]);
2668: y21 = MeshPeriodicDiffY(mesh, nodes[faces[elem*numCorners+1]*2+1] - nodes[faces[elem*numCorners]*2+1]);
2669: x31 = MeshPeriodicDiffX(mesh, nodes[faces[elem*numCorners+2]*2] - nodes[faces[elem*numCorners]*2]);
2670: y31 = MeshPeriodicDiffY(mesh, nodes[faces[elem*numCorners+2]*2+1] - nodes[faces[elem*numCorners]*2+1]);
2671: x32 = MeshPeriodicDiffX(mesh, nodes[faces[elem*numCorners+2]*2] - nodes[faces[elem*numCorners+1]*2]);
2672: y32 = MeshPeriodicDiffY(mesh, nodes[faces[elem*numCorners+2]*2+1] - nodes[faces[elem*numCorners+1]*2+1]);
2673: } else {
2674: x21 = nodes[faces[elem*numCorners+1]*2] - nodes[faces[elem*numCorners]*2];
2675: y21 = nodes[faces[elem*numCorners+1]*2+1] - nodes[faces[elem*numCorners]*2+1];
2676: x31 = nodes[faces[elem*numCorners+2]*2] - nodes[faces[elem*numCorners]*2];
2677: y31 = nodes[faces[elem*numCorners+2]*2+1] - nodes[faces[elem*numCorners]*2+1];
2678: x32 = nodes[faces[elem*numCorners+2]*2] - nodes[faces[elem*numCorners+1]*2];
2679: y32 = nodes[faces[elem*numCorners+2]*2+1] - nodes[faces[elem*numCorners+1]*2+1];
2680: }
2681: area = x21*y31 - x31*y21;
2682: /* Check for inverted elements */
2683: if (area < 0.0) {
2684: locFlag = PETSC_TRUE;
2685: locRetVal = 1;
2686: break;
2687: } else if (area == 0.0) {
2688: SETERRQ1(PETSC_ERR_ARG_CORRUPT, "Element %d has no area", elem);
2689: }
2691: /* Find the aspect ratio = (longest edge length)^2 / (2 area) */
2692: aspectRatio = PetscMax(x21*x21 + y21*y21, x31*x31 + y31*y31);
2693: aspectRatio = PetscMax(x32*x32 + y32*y32, aspectRatio);
2694: aspectRatio /= area;
2695: /* We cannot bail here since we must check for inverted elements */
2696: max = PetscMax(max, aspectRatio);
2697: }
2698: if (max > maxAspectRatio) {
2699: PetscLogInfo(mesh, "Aspect ratio too large in element %d: %g > %gn", elem, max, maxAspectRatio);
2700: locFlag = PETSC_TRUE;
2701: } else {
2702: PetscLogInfo(mesh, "Maximum aspect ratio in element %d: %gn", elem, max);
2703: }
2704: PetscLogFlops(elem*19);
2705: MPI_Allreduce(&locFlag, flag, 1, MPI_INT, MPI_LOR, mesh->comm);
2706: MPI_Allreduce(&locRetVal, &retVal, 1, MPI_INT, MPI_LOR, mesh->comm);
2707: PetscFunctionReturn(retVal);
2708: }
2710: static struct _MeshOps MeshOps = {/* Generic Operations */
2711: PETSC_NULL/* MeshSetup */,
2712: PETSC_NULL/* MeshSetFromOptions */,
2713: MeshView_Triangular_2D,
2714: PETSC_NULL/* MeshCopy */,
2715: PETSC_NULL/* MeshDuplicate */,
2716: MeshDestroy_Triangular_2D,
2717: /* Mesh-Specific Operations */
2718: MeshPartition_Triangular_2D,
2719: MeshCoarsen_Triangular_2D,
2720: MeshRefine_Triangular_2D,
2721: MeshResetNodes_Triangular_2D,
2722: MeshSaveMesh_Triangular_2D,
2723: MeshRestoreMesh_Triangular_2D,
2724: /* Mesh Query Functions */
2725: MeshUpdateBoundingBox_Triangular_2D,
2726: MeshIsDistorted_Triangular_2D,
2727: /* Mesh Boundary Query Functions */
2728: MeshGetBoundarySize_Triangular_2D,
2729: MeshGetBoundaryIndex_Triangular_2D,
2730: MeshGetBoundaryStart_Triangular_2D,
2731: MeshGetBoundaryNext_Triangular_2D,
2732: MeshGetActiveBoundary_Triangular_2D,
2733: /* Mesh Node Query Functions */
2734: MeshGetNodeBoundary_Triangular_2D,
2735: MeshNodeIsVertex_Triangular_2D,
2736: MeshGetNodeCoords_Triangular_2D,
2737: MeshSetNodeCoords_Triangular_2D,
2738: MeshGetNodeCoordsSaved_Triangular_2D,
2739: MeshNearestNode_Triangular_2D,
2740: MeshGetNodeSupport_Triangular_2D,
2741: /* Mesh Element Query Functions */
2742: MeshGetElemNeighbor_Triangular_2D,
2743: MeshLocatePoint_Triangular_2D,
2744: /* Mesh Embedding Query Functions */
2745: MeshGetNodeFromElement_Triangular_2D,
2746: MeshGetNodeFromEdge_Triangular_2D,
2747: /* CSR Support Functions */
2748: MeshCreateLocalCSR_Triangular_2D,
2749: MeshCreateFullCSR_Triangular_2D,
2750: MeshCreateDualCSR_Triangular_2D};
2752: /*@
2753: MeshCreateTriangular2DCSR - Creates a basic two dimensional unstructured grid from an existing CSR representation.
2755: Collective on MPI_Comm
2757: Input Parameters:
2758: + comm - The communicator that shares the grid
2759: . numNodes - The number of mesh nodes, here identical to vertices
2760: . numFaces - The number of elements in the mesh
2761: . nodes - The coordinates for each node
2762: . offsets - The offset of each node's adjacency list
2763: . adj - The adjacency list for the mesh
2764: - faces - The list of nodes for each element
2766: Output Parameter:
2767: . mesh - The mesh
2769: Level: beginner
2771: .keywords unstructured mesh
2772: .seealso MeshCreateTriangular2D(), MeshCreateTriangular2DPeriodic()
2773: @*/
2774: int MeshCreateTriangular2DCSR(MPI_Comm comm, int numNodes, int numFaces, double *nodes, int *offsets, int *adj, int *faces, Mesh *mesh)
2775: {
2776: ParameterDict dict;
2777: MeshBoundary2D *bdCtx;
2778: int ierr;
2781: /* REWORK: We are really stretching this interface, but I need this yesterday */
2782: PetscMalloc(sizeof(MeshBoundary2D), &bdCtx);
2783: bdCtx->numBd = 0;
2784: bdCtx->numVertices = numNodes;
2785: bdCtx->vertices = nodes;
2786: bdCtx->markers = offsets;
2787: bdCtx->segMarkers = adj;
2788: bdCtx->numSegments = numFaces;
2789: bdCtx->segments = faces;
2790: bdCtx->numHoles = 0;
2791: bdCtx->holes = PETSC_NULL;
2792: MeshCreate(comm, mesh);
2793: ParameterDictCreate(comm, &dict);
2794: ParameterDictSetObject(dict, "bdCtx", bdCtx);
2795: ParameterDictSetInteger(dict, "numLocNodes", 3);
2796: PetscObjectSetParameterDict((PetscObject) *mesh, dict);
2797: ParameterDictDestroy(dict);
2798: MeshSetDimension(*mesh, 2);
2799: /* Setup special mechanisms */
2800: PetscObjectComposeFunction((PetscObject) *mesh, "MeshTriangular2D_Create_C", "MeshCreate_CSR",
2801: (void (*)(void)) MeshCreate_CSR);
2802:
2803: PetscObjectComposeFunction((PetscObject) *mesh, "MeshTriangular2D_Refine_C", "MeshRefine_CSR",
2804: (void (*)(void)) MeshRefine_CSR);
2805:
2806: MeshSetType(*mesh, MESH_TRIANGULAR_2D);
2808: PetscObjectSetName((PetscObject) *mesh, "Constructed Mesh");
2809: PetscFree(bdCtx);
2810: return(0);
2811: }
2813: EXTERN_C_BEGIN
2814: int MeshSerialize_Triangular_2D(MPI_Comm comm, Mesh *mesh, PetscViewer viewer, PetscTruth store)
2815: {
2816: Mesh m;
2817: Mesh_Triangular *tri;
2818: int fd;
2819: int zero = 0;
2820: int one = 1;
2821: int numNodes, numEdges, numFaces, numCorners, numBd, numBdNodes, numBdEdges, old;
2822: int ierr;
2825: PetscViewerBinaryGetDescriptor(viewer, &fd);
2826: if (store) {
2827: m = *mesh;
2828: PetscBinaryWrite(fd, &m->highlightElement, 1, PETSC_INT, 0);
2829: PetscBinaryWrite(fd, &m->maxDegree, 1, PETSC_INT, 0);
2830: PetscBinaryWrite(fd, &m->startX, 1, PETSC_DOUBLE, 0);
2831: PetscBinaryWrite(fd, &m->endX, 1, PETSC_DOUBLE, 0);
2832: PetscBinaryWrite(fd, &m->sizeX, 1, PETSC_DOUBLE, 0);
2833: PetscBinaryWrite(fd, &m->startY, 1, PETSC_DOUBLE, 0);
2834: PetscBinaryWrite(fd, &m->endY, 1, PETSC_DOUBLE, 0);
2835: PetscBinaryWrite(fd, &m->sizeY, 1, PETSC_DOUBLE, 0);
2836: PetscBinaryWrite(fd, &m->startZ, 1, PETSC_DOUBLE, 0);
2837: PetscBinaryWrite(fd, &m->endZ, 1, PETSC_DOUBLE, 0);
2838: PetscBinaryWrite(fd, &m->sizeZ, 1, PETSC_DOUBLE, 0);
2839: PetscBinaryWrite(fd, &m->locStartX, 1, PETSC_DOUBLE, 0);
2840: PetscBinaryWrite(fd, &m->locEndX, 1, PETSC_DOUBLE, 0);
2841: PetscBinaryWrite(fd, &m->locSizeX, 1, PETSC_DOUBLE, 0);
2842: PetscBinaryWrite(fd, &m->locStartY, 1, PETSC_DOUBLE, 0);
2843: PetscBinaryWrite(fd, &m->locEndY, 1, PETSC_DOUBLE, 0);
2844: PetscBinaryWrite(fd, &m->locSizeY, 1, PETSC_DOUBLE, 0);
2845: PetscBinaryWrite(fd, &m->locStartZ, 1, PETSC_DOUBLE, 0);
2846: PetscBinaryWrite(fd, &m->locEndZ, 1, PETSC_DOUBLE, 0);
2847: PetscBinaryWrite(fd, &m->locSizeZ, 1, PETSC_DOUBLE, 0);
2848: PetscBinaryWrite(fd, &m->isPeriodic, 1, PETSC_INT, 0);
2849: PetscBinaryWrite(fd, &m->isPeriodicDim, 3, PETSC_INT, 0);
2851: PetscBinaryWrite(fd, &m->numBd, 1, PETSC_INT, 0);
2852: PetscBinaryWrite(fd, &m->numVertices, 1, PETSC_INT, 0);
2853: PetscBinaryWrite(fd, &m->numNodes, 1, PETSC_INT, 0);
2854: PetscBinaryWrite(fd, &m->numBdNodes, 1, PETSC_INT, 0);
2855: PetscBinaryWrite(fd, &m->numEdges, 1, PETSC_INT, 0);
2856: PetscBinaryWrite(fd, &m->numBdEdges, 1, PETSC_INT, 0);
2857: PetscBinaryWrite(fd, &m->numFaces, 1, PETSC_INT, 0);
2858: PetscBinaryWrite(fd, &m->numBdFaces, 1, PETSC_INT, 0);
2859: PetscBinaryWrite(fd, &m->numCells, 1, PETSC_INT, 0);
2860: PetscBinaryWrite(fd, &m->numCorners, 1, PETSC_INT, 0);
2861: PetscBinaryWrite(fd, &m->numCellCorners, 1, PETSC_INT, 0);
2862: PetscBinaryWrite(fd, &m->numHoles, 1, PETSC_INT, 0);
2864: PartitionSerialize(m, &m->part, viewer, store);
2866: PartitionGetNumOverlapElements(m->part, &numFaces);
2867: PartitionGetNumOverlapNodes(m->part, &numNodes);
2868: numEdges = m->numEdges;
2869: numCorners = m->numCorners;
2870: numBd = m->numBd;
2871: numBdNodes = m->numBdNodes;
2872: numBdEdges = m->numBdEdges;
2874: tri = (Mesh_Triangular *) (*mesh)->data;
2875: PetscBinaryWrite(fd, tri->nodes, numNodes*2, PETSC_DOUBLE, 0);
2876: if (tri->nodesOld == PETSC_NULL) {
2877: PetscBinaryWrite(fd, &zero, 1, PETSC_INT, 0);
2878: } else {
2879: PetscBinaryWrite(fd, &one, 1, PETSC_INT, 0);
2880: PetscBinaryWrite(fd, tri->nodesOld, numNodes*2, PETSC_DOUBLE, 0);
2881: }
2882: PetscBinaryWrite(fd, tri->markers, numNodes, PETSC_INT, 0);
2883: PetscBinaryWrite(fd, tri->degrees, numNodes, PETSC_INT, 0);
2884: PetscBinaryWrite(fd, tri->edges, numEdges*2, PETSC_INT, 0);
2885: PetscBinaryWrite(fd, tri->edgemarkers, numEdges, PETSC_INT, 0);
2886: PetscBinaryWrite(fd, tri->faces, numFaces*numCorners, PETSC_INT, 0);
2887: PetscBinaryWrite(fd, tri->neighbors, numFaces*3, PETSC_INT, 0);
2888: PetscBinaryWrite(fd, tri->bdNodes, numBdNodes, PETSC_INT, 0);
2889: PetscBinaryWrite(fd, tri->bdEdges, numBdEdges, PETSC_INT, 0);
2890: PetscBinaryWrite(fd, tri->bdMarkers, numBd, PETSC_INT, 0);
2891: PetscBinaryWrite(fd, tri->bdBegin, numBd+1, PETSC_INT, 0);
2892: PetscBinaryWrite(fd, tri->bdEdgeBegin, numBd+1, PETSC_INT, 0);
2893: PetscBinaryWrite(fd, m->holes, m->numHoles*2, PETSC_DOUBLE, 0);
2895: PetscBinaryWrite(fd, &m->maxAspectRatio, 1, PETSC_DOUBLE, 0);
2896: } else {
2897: /* Create the mesh context */
2898: MeshCreate(comm, &m);
2899: PetscNew(Mesh_Triangular, &tri);
2900: PetscLogObjectMemory(m, sizeof(Mesh_Triangular));
2901: PetscMemcpy(m->ops, &MeshOps, sizeof(struct _MeshOps));
2902: PetscStrallocpy(MESH_TRIANGULAR_2D, &m->type_name);
2903: m->data = (void *) tri;
2904: m->dim = 2;
2906: PetscBinaryRead(fd, &m->highlightElement, 1, PETSC_INT);
2907: PetscBinaryRead(fd, &m->maxDegree, 1, PETSC_INT);
2908: PetscMalloc(m->maxDegree * sizeof(int), &m->support);
2910: PetscBinaryRead(fd, &m->startX, 1, PETSC_DOUBLE);
2911: PetscBinaryRead(fd, &m->endX, 1, PETSC_DOUBLE);
2912: PetscBinaryRead(fd, &m->sizeX, 1, PETSC_DOUBLE);
2913: PetscBinaryRead(fd, &m->startY, 1, PETSC_DOUBLE);
2914: PetscBinaryRead(fd, &m->endY, 1, PETSC_DOUBLE);
2915: PetscBinaryRead(fd, &m->sizeY, 1, PETSC_DOUBLE);
2916: PetscBinaryRead(fd, &m->startZ, 1, PETSC_DOUBLE);
2917: PetscBinaryRead(fd, &m->endZ, 1, PETSC_DOUBLE);
2918: PetscBinaryRead(fd, &m->sizeZ, 1, PETSC_DOUBLE);
2919: PetscBinaryRead(fd, &m->locStartX, 1, PETSC_DOUBLE);
2920: PetscBinaryRead(fd, &m->locEndX, 1, PETSC_DOUBLE);
2921: PetscBinaryRead(fd, &m->locSizeX, 1, PETSC_DOUBLE);
2922: PetscBinaryRead(fd, &m->locStartY, 1, PETSC_DOUBLE);
2923: PetscBinaryRead(fd, &m->locEndY, 1, PETSC_DOUBLE);
2924: PetscBinaryRead(fd, &m->locSizeY, 1, PETSC_DOUBLE);
2925: PetscBinaryRead(fd, &m->locStartZ, 1, PETSC_DOUBLE);
2926: PetscBinaryRead(fd, &m->locEndZ, 1, PETSC_DOUBLE);
2927: PetscBinaryRead(fd, &m->locSizeZ, 1, PETSC_DOUBLE);
2928: PetscBinaryRead(fd, &m->isPeriodic, 1, PETSC_INT);
2929: PetscBinaryRead(fd, &m->isPeriodicDim, 3, PETSC_INT);
2931: m->activeBd = -1;
2932: m->activeBdOld = -1;
2933: m->activeBdNode = -1;
2934: tri->areas = PETSC_NULL;
2935: tri->aspectRatios = PETSC_NULL;
2937: PetscBinaryRead(fd, &m->numBd, 1, PETSC_INT);
2938: PetscBinaryRead(fd, &m->numVertices, 1, PETSC_INT);
2939: PetscBinaryRead(fd, &m->numNodes, 1, PETSC_INT);
2940: PetscBinaryRead(fd, &m->numBdNodes, 1, PETSC_INT);
2941: PetscBinaryRead(fd, &m->numEdges, 1, PETSC_INT);
2942: PetscBinaryRead(fd, &m->numBdEdges, 1, PETSC_INT);
2943: PetscBinaryRead(fd, &m->numFaces, 1, PETSC_INT);
2944: PetscBinaryRead(fd, &m->numBdFaces, 1, PETSC_INT);
2945: PetscBinaryRead(fd, &m->numCells, 1, PETSC_INT);
2946: PetscBinaryRead(fd, &m->numCorners, 1, PETSC_INT);
2947: PetscBinaryRead(fd, &m->numCellCorners, 1, PETSC_INT);
2948: PetscBinaryRead(fd, &m->numHoles, 1, PETSC_INT);
2950: PartitionSerialize(m, &m->part, viewer, store);
2951: PetscLogObjectParent(m, m->part);
2953: PartitionGetNumOverlapElements(m->part, &numFaces);
2954: PartitionGetNumOverlapNodes(m->part, &numNodes);
2955: numEdges = m->numEdges;
2956: numCorners = m->numCorners;
2957: numBd = m->numBd;
2958: numBdNodes = m->numBdNodes;
2959: numBdEdges = m->numBdEdges;
2960: PetscMalloc(numNodes*2 * sizeof(double), &tri->nodes);
2961: PetscMalloc(numNodes * sizeof(int), &tri->markers);
2962: PetscMalloc(numNodes * sizeof(int), &tri->degrees);
2963: PetscMalloc(numEdges*2 * sizeof(int), &tri->edges);
2964: PetscMalloc(numEdges * sizeof(int), &tri->edgemarkers);
2965: PetscMalloc(numFaces*numCorners * sizeof(int), &tri->faces);
2966: PetscMalloc(numFaces*3 * sizeof(int), &tri->neighbors);
2967: PetscMalloc(numBdNodes * sizeof(int), &tri->bdNodes);
2968: PetscMalloc(numBdEdges * sizeof(int), &tri->bdEdges);
2969: PetscMalloc(numBd * sizeof(int), &tri->bdMarkers);
2970: PetscMalloc((numBd+1) * sizeof(int), &tri->bdBegin);
2971: PetscMalloc((numBd+1) * sizeof(int), &tri->bdEdgeBegin);
2972: if (m->numHoles > 0) {
2973: PetscMalloc(m->numHoles*2 * sizeof(double), &m->holes);
2974: } else {
2975: m->holes = PETSC_NULL;
2976: }
2977: PetscLogObjectMemory(m, (numNodes*2 + m->numHoles*2) * sizeof(double) +
2978: (numNodes*2 + numEdges*3 + numFaces*(numCorners+1) + numBdNodes + numBdEdges + numBd*3+2)*sizeof(int));
2979: PetscBinaryRead(fd, tri->nodes, numNodes*2, PETSC_DOUBLE);
2980: PetscBinaryRead(fd, &old, 1, PETSC_INT);
2981: if (old) {
2982: PetscMalloc(numNodes*2 * sizeof(double), &tri->nodesOld);
2983: PetscLogObjectMemory(m, numNodes*2 * sizeof(double));
2984: PetscBinaryRead(fd, tri->nodesOld, numNodes*2, PETSC_DOUBLE);
2985: } else {
2986: tri->nodesOld = PETSC_NULL;
2987: }
2988: PetscBinaryRead(fd, tri->markers, numNodes, PETSC_INT);
2989: PetscBinaryRead(fd, tri->degrees, numNodes, PETSC_INT);
2990: PetscBinaryRead(fd, tri->edges, numEdges*2, PETSC_INT);
2991: PetscBinaryRead(fd, tri->edgemarkers, numEdges, PETSC_INT);
2992: PetscBinaryRead(fd, tri->faces, numFaces*numCorners, PETSC_INT);
2993: PetscBinaryRead(fd, tri->neighbors, numFaces*3, PETSC_INT);
2994: PetscBinaryRead(fd, tri->bdNodes, numBdNodes, PETSC_INT);
2995: PetscBinaryRead(fd, tri->bdEdges, numBdEdges, PETSC_INT);
2996: PetscBinaryRead(fd, tri->bdMarkers, numBd, PETSC_INT);
2997: PetscBinaryRead(fd, tri->bdBegin, numBd+1, PETSC_INT);
2998: PetscBinaryRead(fd, tri->bdEdgeBegin, numBd+1, PETSC_INT);
2999: PetscBinaryRead(fd, m->holes, m->numHoles*m->dim, PETSC_DOUBLE);
3001: PetscBinaryRead(fd, &m->maxAspectRatio, 1, PETSC_DOUBLE);
3003: #ifdef PETSC_USE_BOPT_g
3004: /* Check mesh integrity */
3005: MeshDebug_Triangular_2D(m, PETSC_TRUE);
3006: #endif
3007: *mesh = m;
3008: }
3010: return(0);
3011: }
3012: EXTERN_C_END
3014: EXTERN_C_BEGIN
3015: int MeshCreate_Triangular_2D(Mesh mesh) {
3016: Mesh_Triangular *tri;
3017: int (*f)(MeshBoundary2D *, int, Mesh);
3018: MPI_Comm comm;
3019: PetscTruth opt;
3020: int ierr;
3023: PetscNew(Mesh_Triangular, &tri);
3024: PetscMemcpy(mesh->ops, &MeshOps, sizeof(struct _MeshOps));
3025: mesh->data = (void *) tri;
3026: PetscStrallocpy(MESH_SER_TRIANGULAR_2D_BINARY, &mesh->serialize_name);
3027: mesh->dim = 2;
3029: /* Setup the periodic domain */
3030: if (mesh->isPeriodic == PETSC_TRUE) {
3031: MeshBoundary2DSetBoundingBox(mesh, mesh->bdCtx);
3032: }
3034: /* Setup default mechanisms */
3035: PetscObjectQueryFunction((PetscObject) mesh, "MeshTriangular2D_Create_C", (PetscVoidFunction) &f);
3036: if (f == PETSC_NULL) {
3037: #ifdef PETSC_HAVE_TRIANGLE
3038: if (mesh->isPeriodic == PETSC_TRUE) {
3039: PetscObjectComposeFunction((PetscObject) mesh, "MeshTriangular2D_Create_C", "MeshCreate_Periodic",
3040: (void (*)(void)) MeshCreate_Periodic);
3041:
3042: PetscObjectComposeFunction((PetscObject) mesh, "MeshTriangular2D_Refine_C", "MeshRefine_Periodic",
3043: (void (*)(void)) MeshRefine_Periodic);
3044:
3045: } else {
3046: PetscObjectComposeFunction((PetscObject) mesh, "MeshTriangular2D_Create_C", "MeshCreate_Triangle",
3047: (void (*)(void)) MeshCreate_Triangle);
3048:
3049: PetscObjectComposeFunction((PetscObject) mesh, "MeshTriangular2D_Refine_C", "MeshRefine_Triangle",
3050: (void (*)(void)) MeshRefine_Triangle);
3051: }
3052: #endif
3053: }
3055: MeshCheckBoundary_Triangular_2D(mesh);
3057: PetscObjectQueryFunction((PetscObject) mesh, "MeshTriangular2D_Create_C", (PetscVoidFunction) &f);
3058: if (!f) SETERRQ(1,"Unable to find mesh generation function");
3059: (*f)(mesh->bdCtx, mesh->numCorners, mesh);
3061: /* Calculate maximum degree of vertices */
3062: MeshSetupSupport_Triangular_2D(mesh);
3064: /* Construct derived and boundary information */
3065: MeshSetupBoundary_Triangular_2D(mesh);
3067: /* Reorder nodes before distributing mesh */
3068: PetscOptionsHasName(mesh->prefix, "-mesh_reorder", &opt);
3069: if (opt == PETSC_TRUE) {
3070: /* MUST FIX: Since we have duplicated the whole mesh, we may impersonate a serial mesh */
3071: comm = mesh->comm;
3072: mesh->comm = PETSC_COMM_SELF;
3073: MeshGetOrdering(mesh, MESH_ORDER_TRIANGULAR_2D_RCM, &mesh->nodeOrdering);
3074: mesh->comm = comm;
3076: /* Permute arrays implicitly numbered by node numbers */
3077: AOApplicationToPetscPermuteReal(mesh->nodeOrdering, mesh->dim, tri->nodes);
3078: AOApplicationToPetscPermuteInt(mesh->nodeOrdering, 1, tri->markers);
3079: AOApplicationToPetscPermuteInt(mesh->nodeOrdering, 1, tri->degrees);
3080: /* Renumber arrays dependent on the canonical node numbering */
3081: AOApplicationToPetsc(mesh->nodeOrdering, mesh->numEdges*2, tri->edges);
3082: AOApplicationToPetsc(mesh->nodeOrdering, mesh->numFaces*mesh->numCorners, tri->faces);
3083: AOApplicationToPetsc(mesh->nodeOrdering, mesh->numBdNodes, tri->bdNodes);
3084: }
3086: /* Initialize partition */
3087: MeshPartition(mesh);
3089: /* Initialize save space */
3090: tri->nodesOld = PETSC_NULL;
3092: /* Reset the midnodes */
3093: if (mesh->isPeriodic == PETSC_TRUE) {
3094: MeshResetNodes(mesh, PETSC_TRUE);
3095: }
3097: return(0);
3098: }
3099: EXTERN_C_END