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, &degree, &support);

345:       /* Check node degree */
346:       PetscMalloc(numProcs * sizeof(int), &degrees);
347:       MPI_Allgather(&degree, 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, &degree, &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, &degree, &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, &degree, &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, &degree, &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, &degree, &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