Actual source code: meshpylith.c

  1: #include "src/dm/mesh/meshpylith.h"   /*I      "petscmesh.h"   I*/

  3: #include<list>
  4: #include<map>

  6: namespace ALE {
  7:   namespace PyLith {
  8:     //
  9:     // Builder methods
 10:     //
 11:     inline void Builder::ignoreComments(char *buf, PetscInt bufSize, FILE *f) {
 12:       while((fgets(buf, bufSize, f) != NULL) && ((buf[0] == '#') || (buf[0] == '\0'))) {}
 13:     };
 14:     void Builder::readConnectivity(MPI_Comm comm, const std::string& filename, int& corners, const bool useZeroBase, int& numElements, int *vertices[], int *materials[]) {
 15:       PetscViewer    viewer;
 16:       FILE          *f;
 17:       PetscInt       maxCells = 1024, cellCount = 0;
 18:       PetscInt      *verts;
 19:       PetscInt      *mats;
 20:       char           buf[2048];
 21:       PetscInt       c;
 22:       PetscInt       commRank;

 25:       MPI_Comm_rank(comm, &commRank);
 26:       if (commRank != 0) return;
 27:       PetscViewerCreate(PETSC_COMM_SELF, &viewer);
 28:       PetscViewerSetType(viewer, PETSC_VIEWER_ASCII);
 29:       PetscViewerFileSetMode(viewer, FILE_MODE_READ);
 30:       PetscViewerFileSetName(viewer, filename.c_str());
 31:       PetscViewerASCIIGetPointer(viewer, &f);
 32:       /* Ignore comments */
 33:       ignoreComments(buf, 2048, f);
 34:       do {
 35:         const char *v = strtok(buf, " ");
 36:         int         elementType;

 38:         if (cellCount == maxCells) {
 39:           PetscInt *vtmp, *mtmp;

 41:           vtmp = verts;
 42:           mtmp = mats;
 43:           PetscMalloc2(maxCells*2*corners,PetscInt,&verts,maxCells*2,PetscInt,&mats);
 44:           PetscMemcpy(verts, vtmp, maxCells*corners * sizeof(PetscInt));
 45:           PetscMemcpy(mats,  mtmp, maxCells         * sizeof(PetscInt));
 46:           PetscFree2(vtmp,mtmp);
 47:           maxCells *= 2;
 48:         }
 49:         /* Ignore cell number */
 50:         v = strtok(NULL, " ");
 51:         /* Get element type */
 52:         elementType = atoi(v);
 53:         if (elementType == 1) {
 54:           corners = 8;
 55:         } else if (elementType == 5) {
 56:           corners = 4;
 57:         } else {
 58:           ostringstream msg;

 60:           msg << "We do not accept element type " << elementType << " right now";
 61:           throw ALE::Exception(msg.str().c_str());
 62:         }
 63:         if (cellCount == 0) {
 64:           PetscMalloc2(maxCells*corners,PetscInt,&verts,maxCells,PetscInt,&mats);
 65:         }
 66:         v = strtok(NULL, " ");
 67:         /* Store material type */
 68:         mats[cellCount] = atoi(v);
 69:         v = strtok(NULL, " ");
 70:         /* Ignore infinite domain element code */
 71:         v = strtok(NULL, " ");
 72:         for(c = 0; c < corners; c++) {
 73:           int vertex = atoi(v);
 74: 
 75:           if (!useZeroBase) vertex -= 1;
 76:           verts[cellCount*corners+c] = vertex;
 77:           v = strtok(NULL, " ");
 78:         }
 79:         cellCount++;
 80:       } while(fgets(buf, 2048, f) != NULL);
 81:       PetscViewerDestroy(viewer);
 82:       numElements = cellCount;
 83:       *vertices   = verts;
 84:       *materials  = mats;
 85:     };
 86:     void Builder::readCoordinates(MPI_Comm comm, const std::string& filename, const int dim, int& numVertices, double *coordinates[]) {
 87:       PetscViewer    viewer;
 88:       FILE          *f;
 89:       PetscInt       maxVerts = 1024, vertexCount = 0;
 90:       PetscScalar   *coords;
 91:       double         scaleFactor = 1.0;
 92:       char           buf[2048];
 93:       PetscInt       c;
 94:       PetscInt       commRank;

 97:       MPI_Comm_rank(comm, &commRank);
 98:       if (commRank == 0) {
 99:         PetscViewerCreate(PETSC_COMM_SELF, &viewer);
100:         PetscViewerSetType(viewer, PETSC_VIEWER_ASCII);
101:         PetscViewerFileSetMode(viewer, FILE_MODE_READ);
102:         PetscViewerFileSetName(viewer, filename.c_str());
103:         PetscViewerASCIIGetPointer(viewer, &f);
104:         /* Ignore comments */
105:         ignoreComments(buf, 2048, f);
106:         PetscMalloc(maxVerts*dim * sizeof(PetscScalar), &coords);
107:         /* Read units */
108:         const char *units = strtok(buf, " ");
109:         if (strcmp(units, "coord_units")) {
110:           throw ALE::Exception("Invalid coordinate units line");
111:         }
112:         units = strtok(NULL, " ");
113:         if (strcmp(units, "=")) {
114:           throw ALE::Exception("Invalid coordinate units line");
115:         }
116:         units = strtok(NULL, " ");
117:         if (!strcmp(units, "km")) {
118:           /* Should use Pythia to do units conversion */
119:           scaleFactor = 1000.0;
120:         }
121:         /* Ignore comments */
122:         ignoreComments(buf, 2048, f);
123:         do {
124:           const char *x = strtok(buf, " ");

126:           if (vertexCount == maxVerts) {
127:             PetscScalar *ctmp;

129:             ctmp = coords;
130:             PetscMalloc(maxVerts*2*dim * sizeof(PetscScalar), &coords);
131:             PetscMemcpy(coords, ctmp, maxVerts*dim * sizeof(PetscScalar));
132:             PetscFree(ctmp);
133:             maxVerts *= 2;
134:           }
135:           /* Ignore vertex number */
136:           x = strtok(NULL, " ");
137:           for(c = 0; c < dim; c++) {
138:             coords[vertexCount*dim+c] = atof(x)*scaleFactor;
139:             x = strtok(NULL, " ");
140:           }
141:           vertexCount++;
142:         } while(fgets(buf, 2048, f) != NULL);
143:         PetscViewerDestroy(viewer);
144:         numVertices = vertexCount;
145:         *coordinates = coords;
146:       }
147:     };
148:     // numSplit is the number of split node entries (lines in the file)
149:     // splitInd[] is an array of numSplit pairs, <element, vertex>
150:     // splitValues[] is an array of numSplit*dim displacements
151:     void Builder::readSplit(MPI_Comm comm, const std::string& filename, const int dim, const bool useZeroBase, int& numSplit, int *splitInd[], int *loadHistory[], double *splitValues[]) {
152:       PetscViewer    viewer;
153:       FILE          *f;
154:       PetscInt       maxSplit = 1024, splitCount = 0;
155:       PetscInt      *splitId;
156:       PetscInt      *loadHist;
157:       PetscScalar   *splitVal;
158:       char           buf[2048];
159:       PetscInt       c;
160:       PetscInt       commRank;

163:       MPI_Comm_rank(comm, &commRank);
164:       if (dim != 3) {
165:         throw ALE::Exception("PyLith only works in 3D");
166:       }
167:       if (commRank != 0) return;
168:       PetscViewerCreate(PETSC_COMM_SELF, &viewer);
169:       PetscViewerSetType(viewer, PETSC_VIEWER_ASCII);
170:       PetscViewerFileSetMode(viewer, FILE_MODE_READ);
171:       PetscExceptionTry1(PetscViewerFileSetName(viewer, filename.c_str()), PETSC_ERR_FILE_OPEN);
172:       if (PetscExceptionValue(ierr)) {
173:         // this means that a caller above me has also tryed this exception so I don't handle it here, pass it up
174:       } else if (PetscExceptionCaught(ierr,PETSC_ERR_FILE_OPEN)) {
175:         // File does not exist
176:         return;
177:       }
178:       PetscViewerASCIIGetPointer(viewer, &f);
179:       /* Ignore comments */
180:       ignoreComments(buf, 2048, f);
181:       PetscMalloc3(maxSplit*2,PetscInt,&splitId,maxSplit,PetscInt,&loadHist,maxSplit*dim,PetscScalar,&splitVal);
182:       do {
183:         const char *s = strtok(buf, " ");

185:         if (splitCount == maxSplit) {
186:           PetscInt    *sitmp;
187:           PetscInt    *lhtmp;
188:           PetscScalar *svtmp;

190:           sitmp = splitId;
191:           lhtmp = loadHist;
192:           svtmp = splitVal;
193:           PetscMalloc3(maxSplit*2*2,PetscInt,&splitId,maxSplit*2,PetscInt,&loadHist,maxSplit*dim*2,PetscScalar,&splitVal);
194:           PetscMemcpy(splitId,  sitmp, maxSplit*2   * sizeof(PetscInt));
195:           PetscMemcpy(loadHist, lhtmp, maxSplit     * sizeof(PetscInt));
196:           PetscMemcpy(splitVal, svtmp, maxSplit*dim * sizeof(PetscScalar));
197:           PetscFree3(sitmp,lhtmp,svtmp);
198:           maxSplit *= 2;
199:         }
200:         /* Get element number */
201:         int elem = atoi(s);
202:         if (!useZeroBase) elem -= 1;
203:         splitId[splitCount*2+0] = elem;
204:         s = strtok(NULL, " ");
205:         /* Get node number */
206:         int node = atoi(s);
207:         if (!useZeroBase) node -= 1;
208:         splitId[splitCount*2+1] = node;
209:         s = strtok(NULL, " ");
210:         /* Ignore load history number */
211:         loadHist[splitCount] = atoi(s);
212:         s = strtok(NULL, " ");
213:         /* Get split values */
214:         for(c = 0; c < dim; c++) {
215:           splitVal[splitCount*dim+c] = atof(s);
216:           s = strtok(NULL, " ");
217:         }
218:         splitCount++;
219:       } while(fgets(buf, 2048, f) != NULL);
220:       PetscViewerDestroy(viewer);
221:       numSplit     = splitCount;
222:       *splitInd    = splitId;
223:       *loadHistory = loadHist;
224:       *splitValues = splitVal;
225:     };
226: #if 0
227:     void Builder::buildSplit(const Obj<pair_section_type>& splitField, const Obj<int_section_type>& loadField, int numCells, int numSplit, int splitInd[], int loadHistory[], double splitVals[]) {
228:       const pair_section_type::patch_type                     patch = 0;
229:       pair_section_type::value_type                          *values;
230:       int_section_type::value_type                           *history;
231:       std::map<pair_section_type::point_type, std::set<int> > elem2index;
232:       int                                                     numValues = 0;

234:       splitField->setName("split");
235:       for(int e = 0; e < numSplit; e++) {
236:         splitField->addFiberDimension(patch, splitInd[e*2+0], 1);
237:         loadField->addFiberDimension(patch, splitInd[e*2+0], 1);
238:         elem2index[splitInd[e*2+0]].insert(e);
239:       }
240:       splitField->allocate();
241:       loadField->allocate();
242:       for(std::map<pair_section_type::point_type, std::set<int> >::const_iterator e_iter = elem2index.begin(); e_iter != elem2index.end(); ++e_iter) {
243:         numValues = std::max(numValues, (int) e_iter->second.size());
244:       }
245:       values  = new pair_section_type::value_type[numValues];
246:       history = new int_section_type::value_type[numValues];
247:       for(std::map<pair_section_type::point_type, std::set<int> >::const_iterator e_iter = elem2index.begin(); e_iter != elem2index.end(); ++e_iter) {
248:         const pair_section_type::point_type& e = e_iter->first;
249:         int                                  k = 0;

251:         for(std::set<int>::const_iterator i_iter = e_iter->second.begin(); i_iter != e_iter->second.end(); ++i_iter, ++k) {
252:           const int& i = *i_iter;

254:           if (k >= numValues) {throw ALE::Exception("Invalid split node input");}
255:           values[k].first    = splitInd[i*2+1] + numCells;
256:           values[k].second.x = splitVals[i*3+0];
257:           values[k].second.y = splitVals[i*3+1];
258:           values[k].second.z = splitVals[i*3+2];
259:           history[k]         = loadHistory[i];
260:         }
261:         splitField->updatePoint(patch, e, values);
262:         loadField->updatePoint(patch, e, history);
263:       }
264:       delete [] values;
265:     };
266: #endif
267:     void Builder::readTractions(MPI_Comm comm, const std::string& filename, const int dim, const int& corners, const bool useZeroBase, int& numTractions, int& vertsPerFace, int *tractionVertices[], double *tractionValues[]) {
268:       PetscViewer    viewer;
269:       FILE          *f;
270:       PetscInt       maxTractions = 1024, tractionCount = 0;
271:       PetscInt      *tractionVerts;
272:       PetscScalar   *tractionVals;
273:       double         scaleFactor = 1.0;
274:       char           buf[2048];
275:       PetscInt       c;
276:       PetscInt       commRank;

279:       MPI_Comm_rank(comm, &commRank);
280:       if (dim != 3) {
281:         throw ALE::Exception("PyLith only works in 3D");
282:       }
283:       if (commRank != 0) return;
284:       PetscViewerCreate(PETSC_COMM_SELF, &viewer);
285:       PetscViewerSetType(viewer, PETSC_VIEWER_ASCII);
286:       PetscViewerFileSetMode(viewer, FILE_MODE_READ);
287:       PetscExceptionTry1(PetscViewerFileSetName(viewer, filename.c_str()), PETSC_ERR_FILE_OPEN);
288:       if (PetscExceptionValue(ierr)) {
289:         // this means that a caller above me has also tryed this exception so I don't handle it here, pass it up
290:       } else if (PetscExceptionCaught(ierr,PETSC_ERR_FILE_OPEN)) {
291:         // File does not exist
292:         return;
293:       }
294:       /* Logic right now is only good for linear tets and hexes, and should be fixed in the future. */
295:       if (corners == 4) {
296:         vertsPerFace = 3;
297:       } else if (corners == 8) {
298:         vertsPerFace = 4;
299:       } else {
300:         throw ALE::Exception("Unrecognized element type");
301:       }

303:       PetscViewerASCIIGetPointer(viewer, &f);
304:       /* Ignore comments */
305:       ignoreComments(buf, 2048, f);
306:       /* Read units */
307:       const char *units = strtok(buf, " ");
308:       if (strcmp(units, "traction_units")) {
309:         throw ALE::Exception("Invalid traction units line");
310:       }
311:       units = strtok(NULL, " ");
312:       if (strcmp(units, "=")) {
313:         throw ALE::Exception("Invalid traction units line");
314:       }
315:       units = strtok(NULL, " ");
316:       if (!strcmp(units, "MPa")) {
317:         /* Should use Pythia to do units conversion */
318:         scaleFactor = 1.0e6;
319:       }
320:       /* Ignore comments */
321:       ignoreComments(buf, 2048, f);
322:       // Allocate memory.
323:       PetscMalloc2(maxTractions*vertsPerFace,PetscInt,&tractionVerts,maxTractions*dim,PetscScalar,&tractionVals);
324:       do {
325:         const char *s = strtok(buf, " ");

327:         if (tractionCount == maxTractions) {
328:           PetscInt    *titmp;
329:           PetscScalar *tvtmp;

331:           titmp = tractionVerts;
332:           tvtmp = tractionVals;
333:           PetscMalloc2(maxTractions*vertsPerFace*2,PetscInt,&tractionVerts,maxTractions*dim*2,PetscScalar,&tractionVals);
334:           PetscMemcpy(tractionVerts,  titmp, maxTractions*vertsPerFace   * sizeof(PetscInt));
335:           PetscMemcpy(tractionVals, tvtmp, maxTractions*dim * sizeof(PetscScalar));
336:           PetscFree2(titmp,tvtmp);
337:           maxTractions *= 2;
338:         }
339:         /* Get vertices */
340:         int v1 = atoi(s);
341:         if (!useZeroBase) v1 -= 1;
342:         tractionVerts[tractionCount*vertsPerFace+0] = v1;
343:         s = strtok(NULL, " ");
344:         int v2 = atoi(s);
345:         if (!useZeroBase) v2 -= 1;
346:         tractionVerts[tractionCount*vertsPerFace+1] = v2;
347:         s = strtok(NULL, " ");
348:         int v3 = atoi(s);
349:         if (!useZeroBase) v3 -= 1;
350:         tractionVerts[tractionCount*vertsPerFace+2] = v3;
351:         s = strtok(NULL, " ");
352:         if (vertsPerFace > 3) {
353:           int v4 = atoi(s);
354:           if (!useZeroBase) v4 -= 1;
355:           tractionVerts[tractionCount*vertsPerFace+3] = v4;
356:           s = strtok(NULL, " ");
357:         }
358:         /* Get traction values */
359:         for(c = 0; c < dim; c++) {
360:           tractionVals[tractionCount*dim+c] = atof(s);
361:           s = strtok(NULL, " ");
362:         }
363:         tractionCount++;
364:       } while(fgets(buf, 2048, f) != NULL);
365:       PetscViewerDestroy(viewer);
366:       numTractions      = tractionCount;
367:       *tractionVertices = tractionVerts;
368:       *tractionValues   = tractionVals;
369:     };
370:     void Builder::buildTractions(const Obj<real_section_type>& tractionField, const Obj<Mesh>& boundaryMesh, int numCells, int numTractions, int vertsPerFace, int tractionVertices[], double tractionValues[]) {
371:       real_section_type::value_type values[3];
372:       // Make boundary topology
373:       Obj<sieve_type> boundarySieve = new sieve_type(tractionField->comm(), tractionField->debug());

375:       ALE::SieveBuilder<Mesh>::buildTopology(boundarySieve, 2, numTractions, tractionVertices, 0, false, vertsPerFace, numCells);
376:       boundaryMesh->setSieve(boundarySieve);
377:       boundaryMesh->stratify();
378:       // Make traction field
379:       tractionField->setName("traction");
380:       tractionField->setFiberDimension(boundaryMesh->heightStratum(0), 3);
381:       boundaryMesh->allocate(tractionField);
382:       const Obj<Mesh::label_sequence>& faces = boundaryMesh->heightStratum(0);
383:       int k = 0;

385:       for(Mesh::label_sequence::iterator f_iter = faces->begin(); f_iter != faces->end(); ++f_iter) {
386:         const Mesh::point_type& face = *f_iter;

388:         values[0] = tractionValues[k*3+0];
389:         values[1] = tractionValues[k*3+1];
390:         values[2] = tractionValues[k*3+2];
391:         k++;
392:         tractionField->updatePoint(face, values);
393:       }
394:     };
395:     void Builder::buildMaterials(const Obj<Mesh>& mesh, const Obj<int_section_type>& matField, const int materials[]) {
396:       const Obj<Mesh::label_sequence>& elements = mesh->heightStratum(0);

398:       matField->setName("material");
399:       matField->setFiberDimension(elements, 1);
400:       mesh->allocate(matField);
401:       for(Mesh::label_sequence::iterator e_iter = elements->begin(); e_iter != elements->end(); ++e_iter) {
402:         matField->updatePoint(*e_iter, &materials[*e_iter]);
403:       }
404:     };
405:     Obj<Builder::Mesh> Builder::readMesh(MPI_Comm comm, const int dim, const std::string& basename, const bool useZeroBase = false, const bool interpolate = false, const int debug = 0) {
406:       Obj<Mesh>       mesh  = new Mesh(comm, dim, debug);
407:       Obj<sieve_type> sieve = new sieve_type(comm, debug);
408:       int    *cells, *materials;
409:       double *coordinates;
410:       int     numCells = 0, numVertices = 0, numCorners = dim+1;

412:       ALE::PyLith::Builder::readConnectivity(comm, basename+".connect", numCorners, useZeroBase, numCells, &cells, &materials);
413:       ALE::PyLith::Builder::readCoordinates(comm, basename+".coord", dim, numVertices, &coordinates);
414:       ALE::SieveBuilder<Mesh>::buildTopology(sieve, dim, numCells, cells, numVertices, interpolate, numCorners);
415:       mesh->setSieve(sieve);
416:       mesh->stratify();
417:       ALE::SieveBuilder<Mesh>::buildCoordinates(mesh, dim, coordinates);
418:       Obj<int_section_type> material = mesh->getIntSection("material");
419:       buildMaterials(mesh, material, materials);
420: #if 0
421:       Obj<ALE::Mesh::pair_section_type> split = createSplit(mesh, basename, useZeroBase);
422:       if (!split.isNull()) {mesh->setPairSection("split", split);}
423: #endif
424:       Obj<ALE::Mesh> tractionMesh = createTraction(mesh, basename, useZeroBase);
425:       if (!tractionMesh.isNull()) {/* Have to carry tractions around somehow */}
426:       return mesh;
427:     };
428: #if 0
429:     Obj<Builder::pair_section_type> Builder::createSplit(const Obj<Mesh>& mesh, const std::string& basename, const bool useZeroBase = false) {
430:       Obj<pair_section_type> split = NULL;
431:       MPI_Comm comm     = mesh->comm();
432:       int      dim      = mesh->getDimension();
433:       int      numCells = mesh->getTopology()->heightStratum(0, 0)->size();
434:       int     *splitInd, *loadHistory;
435:       double  *splitValues;
436:       int      numSplit = 0, hasSplit;

438:       ALE::PyLith::Builder::readSplit(comm, basename+".split", dim, useZeroBase, numSplit, &splitInd, &loadHistory, &splitValues);
439:       MPI_Allreduce(&numSplit, &hasSplit, 1, MPI_INT, MPI_MAX, comm);
440:       if (hasSplit) {
441:         split = new pair_section_type(mesh->getTopology());
442:         Obj<int_section_type> loadField = mesh->getIntSection("loadHistory");
443:         buildSplit(split, loadField, numCells, numSplit, splitInd, loadHistory, splitValues);
444:       }
445:       return split;
446:     };
447: #endif
448:     Obj<Builder::Mesh> Builder::createTraction(const Obj<Mesh>& mesh, const std::string& basename, const bool useZeroBase = false) {
449:       Obj<Mesh> tractionMesh = NULL;
450:       MPI_Comm comm       = mesh->comm();
451:       int      debug      = mesh->debug();
452:       int      dim        = mesh->getDimension();
453:       int      numCells   = mesh->heightStratum(0)->size();
454:       int      numCorners = mesh->getSieve()->cone(*mesh->heightStratum(0)->begin())->size();
455:       int     *tractionVertices;
456:       double  *tractionValues;
457:       int      numTractions = 0, vertsPerFace = 0, hasTractions;

459:       ALE::PyLith::Builder::readTractions(comm, basename+".traction", dim, numCorners, useZeroBase, numTractions, vertsPerFace, &tractionVertices, &tractionValues);
460:       MPI_Allreduce(&numTractions, &hasTractions, 1, MPI_INT, MPI_MAX, comm);
461:       if (hasTractions) {
462:         tractionMesh = new Mesh(comm, debug);

464:         const Obj<Mesh::real_section_type>& traction = tractionMesh->getRealSection("traction");
465:         buildTractions(traction, tractionMesh, numCells, numTractions, vertsPerFace, tractionVertices, tractionValues);
466:       }
467:       return tractionMesh;
468:     };
469:     void Builder::createCohesiveElements(const Obj<Mesh>& mesh, const std::set<Mesh::point_type>& faultVertices) {
470:       typedef std::vector<Mesh::point_type> PointArray;
471:       const Obj<Mesh::sieve_type>               sieve      = mesh->getSieve();
472:       const Obj<Mesh>                           fault      = new Mesh(mesh->comm(), mesh->debug());
473:       const Obj<Mesh::sieve_type>               faultSieve = new Mesh::sieve_type(sieve->comm(), sieve->debug());
474:       const std::set<Mesh::point_type>::const_iterator fvBegin = faultVertices.begin();
475:       const std::set<Mesh::point_type>::const_iterator fvEnd   = faultVertices.end();
476:       // There should be logic here to determine this
477:       const unsigned int                        faceSize   = 3;
478:       int                                       f          = 0;
479:       int                                       debug      = mesh->debug();
480:       Obj<PointArray>                           face       = new PointArray();
481:       std::set<Mesh::point_type>                faultCells;

483:       // Create a sieve which captures the fault
484:       for(std::set<int>::const_iterator fv_iter = fvBegin; fv_iter != fvEnd; ++fv_iter) {
485:         const Obj<Mesh::sieve_type::traits::supportSequence>&     cells  = sieve->support(*fv_iter);
486:         const Mesh::sieve_type::traits::supportSequence::iterator cBegin = cells->begin();
487:         const Mesh::sieve_type::traits::supportSequence::iterator cEnd   = cells->end();

489:         if (debug) {std::cout << "Checking fault vertex " << *fv_iter << std::endl;}
490:         for(Mesh::sieve_type::traits::supportSequence::iterator c_iter = cBegin; c_iter != cEnd; ++c_iter) {
491:           if (debug) {std::cout << "  Checking cell " << *c_iter << std::endl;}
492:           if (faultCells.find(*c_iter) != faultCells.end()) continue;
493:           const Obj<Mesh::sieve_type::traits::coneSequence>& cone   = sieve->cone(*c_iter);
494:           const Mesh::sieve_type::traits::coneSequence::iterator  vBegin = cone->begin();
495:           const Mesh::sieve_type::traits::coneSequence::iterator  vEnd   = cone->end();

497:           face->clear();
498:           for(Mesh::sieve_type::traits::coneSequence::iterator v_iter = vBegin; v_iter != vEnd; ++v_iter) {
499:             if (faultVertices.find(*v_iter) != fvEnd) {
500:               if (debug) {std::cout << "    contains fault vertex " << *v_iter << std::endl;}
501:               face->insert(face->end(), *v_iter);
502:             }
503:           }
504:           if (face->size() > faceSize) throw ALE::Exception("Invalid fault mesh: Too many vertices of an element on the fault");
505:           if (face->size() == faceSize) {
506:             if (debug) {std::cout << "  Contains a face on the fault" << std::endl;}
507:             const Obj<sieve_type::supportSet> preFace = faultSieve->nJoin1(face);

509:             if (preFace->size() > 1) {
510:               throw ALE::Exception("Invalid fault sieve: Multiple faces from vertex set");
511:             } else if (preFace->size() == 1) {
512:               faultSieve->addArrow(*preFace->begin(), *c_iter);
513:             } else if (preFace->size() == 0) {
514:               if (debug) {std::cout << "  Adding face " << f << std::endl;}
515:               int color = 0;
516:               for(PointArray::const_iterator f_iter = face->begin(); f_iter != face->end(); ++f_iter) {
517:                 if (debug) {std::cout << "    vertex " << *f_iter << std::endl;}
518:                 faultSieve->addArrow(*f_iter, f, color++);
519:               }
520:               faultSieve->addArrow(f, *c_iter);
521:               f++;
522:             }
523:             faultCells.insert(*c_iter);
524:           }
525:         }
526:       }
527:       fault->setSieve(faultSieve);
528:       fault->stratify();
529:       faultCells.clear();
530:       if (debug) {fault->view("Fault mesh");}
531:       // Add new shadow vertices
532:       const Obj<Mesh::label_sequence>& fVertices = fault->depthStratum(0);
533:       const Obj<Mesh::label_sequence>& vertices  = mesh->depthStratum(0);
534:       Mesh::point_type                 newVertex = *vertices->begin() + vertices->size();
535:       std::map<int,int>                vertexRenumber;

537:       for(Mesh::label_sequence::iterator v_iter = fVertices->begin(); v_iter != fVertices->end(); ++v_iter) {
538:         if (debug) {std::cout << "Duplicating " << *v_iter << " to " << vertexRenumber[*v_iter] << std::endl;}
539:         vertexRenumber[*v_iter] = newVertex++;
540:       }
541:       // Split the mesh along the fault sieve and create cohesive elements
542:       const Obj<Mesh::label_sequence>& faces = fault->depthStratum(1);
543:       PointArray                       newVertices;

545:       for(Mesh::label_sequence::iterator f_iter = faces->begin(); f_iter != faces->end(); ++f_iter) {
546:         if (debug) {std::cout << "Considering fault face " << *f_iter << std::endl;}
547:         const Obj<Mesh::sieve_type::traits::supportSequence>& cells = faultSieve->support(*f_iter);
548:         Mesh::point_type                                      cell  = std::max(*cells->begin(), *(++cells->begin()));
549:         const Obj<Mesh::sieve_type::traits::coneSequence>&    cone  = sieve->cone(cell);

551:         if (debug) {std::cout << "  Replacing cell " << cell << std::endl;}
552:         newVertices.clear();
553:         for(ALE::Mesh::sieve_type::traits::coneSequence::iterator v_iter = cone->begin(); v_iter != cone->end(); ++v_iter) {
554:           if (vertexRenumber.find(*v_iter) != vertexRenumber.end()) {
555:             if (debug) {std::cout << "    vertex " << vertexRenumber[*v_iter] << std::endl;}
556:             newVertices.insert(newVertices.end(), vertexRenumber[*v_iter]);
557:           } else {
558:             if (debug) {std::cout << "    vertex " << *v_iter << std::endl;}
559:             newVertices.insert(newVertices.end(), *v_iter);
560:           }
561:         }
562:         sieve->clearCone(cell);
563:         int color = 0;
564:         for(PointArray::const_iterator v_iter = newVertices.begin(); v_iter != newVertices.end(); ++v_iter) {
565:           sieve->addArrow(*v_iter, cell, color++);
566:         }
567:       }
568:       // Fix coordinates
569:       const Obj<Mesh::real_section_type>& coordinates = mesh->getRealSection("coordinates");
570:       const Obj<Mesh::label_sequence>&    fVertices2  = fault->depthStratum(0);

572:       for(Mesh::label_sequence::iterator v_iter = fVertices2->begin(); v_iter != fVertices2->end(); ++v_iter) {
573:         coordinates->addPoint(vertexRenumber[*v_iter], coordinates->getFiberDimension(*v_iter));
574:       }
575:       mesh->reallocate(coordinates);
576:       for(Mesh::label_sequence::iterator v_iter = fVertices2->begin(); v_iter != fVertices2->end(); ++v_iter) {
577:         coordinates->updatePoint(vertexRenumber[*v_iter], coordinates->restrictPoint(*v_iter));
578:       }
579:     };
580:     //
581:     // Viewer methods
582:     //
585:     PetscErrorCode Viewer::writeVertices(const Obj<Mesh>& mesh, PetscViewer viewer) {
586:       Obj<Builder::real_section_type> coordinates  = mesh->getRealSection("coordinates");
587:       //Mesh::section_type::patch_type patch;
588:       //const double  *array = coordinates->restrict(Mesh::section_type::patch_type());
589:       //int            dim = mesh->getDimension();
590:       //int            numVertices;

594: #if 0
595:       //FIX:
596:       if (vertexBundle->getGlobalOffsets()) {
597:         numVertices = vertexBundle->getGlobalOffsets()[mesh->commSize()];
598:       } else {
599:         numVertices = mesh->getTopology()->depthStratum(0)->size();
600:       }
601:       PetscViewerASCIIPrintf(viewer,"#\n");
602:       PetscViewerASCIIPrintf(viewer,"coord_units = m\n");
603:       PetscViewerASCIIPrintf(viewer,"#\n");
604:       PetscViewerASCIIPrintf(viewer,"#\n");
605:       PetscViewerASCIIPrintf(viewer,"#  Node      X-coord           Y-coord           Z-coord\n");
606:       PetscViewerASCIIPrintf(viewer,"#\n");
607:       if (mesh->commRank() == 0) {
608:         int numLocalVertices = mesh->getTopology()->depthStratum(0)->size();
609:         int vertexCount = 1;

611:         for(int v = 0; v < numLocalVertices; v++) {
612:           PetscViewerASCIIPrintf(viewer,"%7D ", vertexCount++);
613:           for(int d = 0; d < dim; d++) {
614:             if (d > 0) {
615:               PetscViewerASCIIPrintf(viewer," ");
616:             }
617:             PetscViewerASCIIPrintf(viewer,"% 16.8E", array[v*dim+d]);
618:           }
619:           PetscViewerASCIIPrintf(viewer,"\n");
620:         }
621:         for(int p = 1; p < mesh->commSize(); p++) {
622:           double    *remoteCoords;
623:           MPI_Status status;

625:           MPI_Recv(&numLocalVertices, 1, MPI_INT, p, 1, mesh->comm(), &status);
626:           PetscMalloc(numLocalVertices*dim * sizeof(double), &remoteCoords);
627:           MPI_Recv(remoteCoords, numLocalVertices*dim, MPI_DOUBLE, p, 1, mesh->comm(), &status);
628:           for(int v = 0; v < numLocalVertices; v++) {
629:             PetscViewerASCIIPrintf(viewer,"%7D   ", vertexCount++);
630:             for(int d = 0; d < dim; d++) {
631:               if (d > 0) {
632:                 PetscViewerASCIIPrintf(viewer, " ");
633:               }
634:               PetscViewerASCIIPrintf(viewer, "% 16.8E", remoteCoords[v*dim+d]);
635:             }
636:             PetscViewerASCIIPrintf(viewer, "\n");
637:           }
638:         }
639:       } else {
640:         Obj<Mesh::bundle_type> globalOrder = coordinates->getGlobalOrder();
641:         Obj<Mesh::field_type::order_type::coneSequence> cone = globalOrder->getPatch(patch);
642:         const int *offsets = coordinates->getGlobalOffsets();
643:         int        numLocalVertices = (offsets[mesh->commRank()+1] - offsets[mesh->commRank()])/dim;
644:         double    *localCoords;
645:         int        k = 0;

647:         PetscMalloc(numLocalVertices*dim * sizeof(double), &localCoords);
648:         for(Mesh::field_type::order_type::coneSequence::iterator p_iter = cone->begin(); p_iter != cone->end(); ++p_iter) {
649:           int dim = globalOrder->getFiberDimension(patch, *p_iter);

651:           if (dim > 0) {
652:             int offset = coordinates->getFiberOffset(patch, *p_iter);

654:             for(int i = offset; i < offset+dim; ++i) {
655:               localCoords[k++] = array[i];
656:             }
657:           }
658:         }
659:         if (k != numLocalVertices*dim) {
660:           SETERRQ2(PETSC_ERR_PLIB, "Invalid number of coordinates to send %d should be %d", k, numLocalVertices*dim);
661:         }
662:         MPI_Send(&numLocalVertices, 1, MPI_INT, 0, 1, mesh->comm());
663:         MPI_Send(localCoords, numLocalVertices*dim, MPI_DOUBLE, 0, 1, mesh->comm());
664:         PetscFree(localCoords);
665:       }
666: #endif
667:       return(0);
668:     };
671:     PetscErrorCode Viewer::writeElements(const Obj<Mesh>& mesh, const Obj<Builder::int_section_type>& materialField, PetscViewer viewer) {
672: #if 0
673:       Obj<Mesh::sieve_type::traits::heightSequence> elements = topology->heightStratum(0);
674:       Obj<Mesh::bundle_type> elementBundle = mesh->getBundle(topology->depth());
675:       Obj<Mesh::bundle_type> vertexBundle = mesh->getBundle(0);
676:       Obj<Mesh::bundle_type> globalVertex = vertexBundle->getGlobalOrder();
677:       Obj<Mesh::bundle_type> globalElement = elementBundle->getGlobalOrder();
678:       Mesh::bundle_type::patch_type patch;
679:       std::string    orderName("element");
680:       bool           hasMaterial  = !materialField.isNull();
681:       int            dim  = mesh->getDimension();
682:       int            corners = topology->nCone(*elements->begin(), topology->depth())->size();
683:       int            elementType = -1;

687:       if (dim != 3) {
688:         SETERRQ(PETSC_ERR_SUP, "PyLith only supports 3D meshes.");
689:       }
690:       if (corners == 4) {
691:         // Linear tetrahedron
692:         elementType = 5;
693:       } else if (corners == 8) {
694:         // Linear hexahedron
695:         elementType = 1;
696:       } else {
697:         SETERRQ1(PETSC_ERR_SUP, "PyLith Error: Unsupported number of elements vertices: %d", corners);
698:       }
699:       PetscViewerASCIIPrintf(viewer,"#\n");
700:       PetscViewerASCIIPrintf(viewer,"#     N ETP MAT INF     N1     N2     N3     N4     N5     N6     N7     N8\n");
701:       PetscViewerASCIIPrintf(viewer,"#\n");
702:       if (mesh->commRank() == 0) {
703:         int elementCount = 1;

705:         for(Mesh::sieve_type::traits::heightSequence::iterator e_itor = elements->begin(); e_itor != elements->end(); ++e_itor) {
706:           Obj<Mesh::bundle_type::order_type::coneSequence> cone = vertexBundle->getPatch(orderName, *e_itor);

708:           PetscViewerASCIIPrintf(viewer, "%7d %3d", elementCount++, elementType);
709:           if (hasMaterial) {
710:             // No infinite elements
711:             PetscViewerASCIIPrintf(viewer, " %3d %3d", (int) materialField->restrict(patch, *e_itor)[0], 0);
712:           } else {
713:             // No infinite elements
714:             PetscViewerASCIIPrintf(viewer, " %3d %3d", 1, 0);
715:           }
716:           for(Mesh::bundle_type::order_type::coneSequence::iterator c_itor = cone->begin(); c_itor != cone->end(); ++c_itor) {
717:             PetscViewerASCIIPrintf(viewer, " %6d", globalVertex->getIndex(patch, *c_itor).prefix+1);
718:           }
719:           PetscViewerASCIIPrintf(viewer, "\n");
720:         }
721:         for(int p = 1; p < mesh->commSize(); p++) {
722:           int         numLocalElements;
723:           int        *remoteVertices;
724:           MPI_Status  status;

726:           MPI_Recv(&numLocalElements, 1, MPI_INT, p, 1, mesh->comm(), &status);
727:           PetscMalloc(numLocalElements*(corners+1) * sizeof(int), &remoteVertices);
728:           MPI_Recv(remoteVertices, numLocalElements*(corners+1), MPI_INT, p, 1, mesh->comm(), &status);
729:           for(int e = 0; e < numLocalElements; e++) {
730:             // Only linear tetrahedra, material, no infinite elements
731:             int mat = remoteVertices[e*(corners+1)+corners];

733:             PetscViewerASCIIPrintf(viewer, "%7d %3d %3d %3d", elementCount++, elementType, mat, 0);
734:             for(int c = 0; c < corners; c++) {
735:               PetscViewerASCIIPrintf(viewer, " %6d", remoteVertices[e*(corners+1)+c]);
736:             }
737:             PetscViewerASCIIPrintf(viewer, "\n");
738:           }
739:           PetscFree(remoteVertices);
740:         }
741:       } else {
742:         const int *offsets = elementBundle->getGlobalOffsets();
743:         int        numLocalElements = offsets[mesh->commRank()+1] - offsets[mesh->commRank()];
744:         int       *localVertices;
745:         int        k = 0;

747:         PetscMalloc(numLocalElements*(corners+1) * sizeof(int), &localVertices);
748:         for(Mesh::sieve_type::traits::heightSequence::iterator e_itor = elements->begin(); e_itor != elements->end(); ++e_itor) {
749:           Obj<Mesh::bundle_type::order_type::coneSequence> cone = vertexBundle->getPatch(orderName, *e_itor);

751:           if (globalElement->getFiberDimension(patch, *e_itor) > 0) {
752:             for(Mesh::bundle_type::order_type::coneSequence::iterator c_itor = cone->begin(); c_itor != cone->end(); ++c_itor) {
753:               localVertices[k++] = globalVertex->getIndex(patch, *c_itor).prefix;
754:             }
755:             if (hasMaterial) {
756:               localVertices[k++] = (int) materialField->restrict(patch, *e_itor)[0];
757:             } else {
758:               localVertices[k++] = 1;
759:             }
760:           }
761:         }
762:         if (k != numLocalElements*corners) {
763:           SETERRQ2(PETSC_ERR_PLIB, "Invalid number of vertices to send %d should be %d", k, numLocalElements*corners);
764:         }
765:         MPI_Send(&numLocalElements, 1, MPI_INT, 0, 1, mesh->comm());
766:         MPI_Send(localVertices, numLocalElements*(corners+1), MPI_INT, 0, 1, mesh->comm());
767:         PetscFree(localVertices);
768:       }
769: #endif
770:       return(0);
771:     };
774:     PetscErrorCode Viewer::writeVerticesLocal(const Obj<Mesh>& mesh, PetscViewer viewer) {
775:       const Obj<Mesh::real_section_type>& coordinates = mesh->getRealSection("coordinates");
776:       const Obj<Mesh::label_sequence>&    vertices    = mesh->depthStratum(0);
777:       const Obj<Mesh::numbering_type>&    vNumbering  = mesh->getFactory()->getLocalNumbering(mesh, 0);
778:       int            embedDim = coordinates->getFiberDimension(*vertices->begin());

782:       PetscViewerASCIIPrintf(viewer,"#\n");
783:       PetscViewerASCIIPrintf(viewer,"coord_units = m\n");
784:       PetscViewerASCIIPrintf(viewer,"#\n");
785:       PetscViewerASCIIPrintf(viewer,"#\n");
786:       PetscViewerASCIIPrintf(viewer,"#  Node      X-coord           Y-coord           Z-coord\n");
787:       PetscViewerASCIIPrintf(viewer,"#\n");

789:       for(Mesh::label_sequence::iterator v_iter = vertices->begin(); v_iter != vertices->end(); ++v_iter) {
790:         const Mesh::real_section_type::value_type *array = coordinates->restrictPoint(*v_iter);

792:         PetscViewerASCIIPrintf(viewer, "%7D ", vNumbering->getIndex(*v_iter)+1);
793:         for(int d = 0; d < embedDim; d++) {
794:           if (d > 0) {
795:             PetscViewerASCIIPrintf(viewer, " ");
796:           }
797:           PetscViewerASCIIPrintf(viewer, "% 16.8E", array[d]);
798:         }
799:         PetscViewerASCIIPrintf(viewer, "\n");
800:       }
801:       return(0);
802:     };
805:     PetscErrorCode Viewer::writeElementsLocal(const Obj<Mesh>& mesh, const Obj<Builder::int_section_type>& materialField, PetscViewer viewer) {
806:       const Obj<Mesh::sieve_type>&     sieve      = mesh->getSieve();
807:       const Obj<Mesh::label_sequence>& elements   = mesh->heightStratum(0);
808:       const Obj<Mesh::numbering_type>& eNumbering = mesh->getFactory()->getLocalNumbering(mesh, mesh->depth());
809:       const Obj<Mesh::numbering_type>& vNumbering = mesh->getFactory()->getLocalNumbering(mesh, 0);
810:       int            dim          = mesh->getDimension();
811:       //int            corners      = sieve->nCone(*elements->begin(), topology->depth())->size();
812:       int            corners      = sieve->cone(*elements->begin())->size();
813:       bool           hasMaterial  = !materialField.isNull();
814:       int            elementType  = -1;

818:       if (dim != 3) {
819:         SETERRQ(PETSC_ERR_SUP, "PyLith only supports 3D meshes.");
820:       }
821:       if (corners == 4) {
822:         // Linear tetrahedron
823:         elementType = 5;
824:       } else if (corners == 8) {
825:         // Linear hexahedron
826:         elementType = 1;
827:       } else {
828:         SETERRQ1(PETSC_ERR_SUP, "PyLith Error: Unsupported number of elements vertices: %d", corners);
829:       }
830:       PetscViewerASCIIPrintf(viewer,"#\n");
831:       PetscViewerASCIIPrintf(viewer,"#     N ETP MAT INF     N1     N2     N3     N4     N5     N6     N7     N8\n");
832:       PetscViewerASCIIPrintf(viewer,"#\n");
833:       for(Mesh::label_sequence::iterator e_iter = elements->begin(); e_iter != elements->end(); ++e_iter) {
834:         const Obj<Mesh::sieve_type::traits::coneSequence> cone  = sieve->cone(*e_iter);
835:         Mesh::sieve_type::traits::coneSequence::iterator  begin = cone->begin();
836:         Mesh::sieve_type::traits::coneSequence::iterator  end   = cone->end();

838:         PetscViewerASCIIPrintf(viewer, "%7d %3d", eNumbering->getIndex(*e_iter)+1, elementType);
839:         if (hasMaterial) {
840:           // No infinite elements
841:           PetscViewerASCIIPrintf(viewer, " %3d %3d", (int) materialField->restrictPoint(*e_iter)[0], 0);
842:         } else {
843:           // No infinite elements
844:           PetscViewerASCIIPrintf(viewer, " %3d %3d", 1, 0);
845:         }
846:         for(Mesh::sieve_type::traits::coneSequence::iterator c_iter = begin; c_iter != end; ++c_iter) {
847:           //FIX: Need a global ordering here
848:           PetscViewerASCIIPrintf(viewer, " %6d", vNumbering->getIndex(*c_iter)+1);
849:         }
850:         PetscViewerASCIIPrintf(viewer, "\n");
851:       }
852:       return(0);
853:     };
854: #if 0
857:     // The elements seem to be implicitly numbered by appearance, which makes it impossible to
858:     //   number here by bundle, but we can fix it by traversing the elements like the vertices
859:     PetscErrorCode Viewer::writeSplitLocal(const Obj<Mesh>& mesh, const Obj<Builder::pair_section_type>& splitField, PetscViewer viewer) {
860:       const Obj<Mesh::topology_type>&        topology   = mesh->getTopology();
861:       Builder::pair_section_type::patch_type patch      = 0;
862:       const Obj<Mesh::numbering_type>&       eNumbering = mesh->getFactory()->getLocalNumbering(topology, patch, topology->depth());
863:       const Obj<Mesh::numbering_type>&       vNumbering = mesh->getFactory()->getLocalNumbering(topology, patch, 0);

867:       const Builder::pair_section_type::atlas_type::chart_type& chart = splitField->getPatch(patch);

869:       for(Builder::pair_section_type::atlas_type::chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
870:         const Builder::pair_section_type::point_type& e      = *c_iter;
871:         const Builder::pair_section_type::value_type *values = splitField->restrict(patch, e);
872:         const int                                     size   = splitField->getFiberDimension(patch, e);

874:         for(int i = 0; i < size; i++) {
875:           const Builder::pair_section_type::point_type& v     = values[i].first;
876:           const ALE::Mesh::base_type::split_value&      split = values[i].second;

878:           // No time history
879:           PetscViewerASCIIPrintf(viewer, "%6d %6d 0 %15.9g %15.9g %15.9g\n", eNumbering->getIndex(e)+1, vNumbering->getIndex(v)+1, split.x, split.y, split.z);
880:         }
881:       }
882:       return(0);
883:     };
884: #endif
887:     PetscErrorCode Viewer::writeTractionsLocal(const Obj<Mesh>& mesh, const Obj<Mesh>& tractionMesh, const Obj<Builder::real_section_type>& tractionField, PetscViewer viewer) {
888:       const Obj<Mesh::sieve_type>&     sieve = tractionMesh->getSieve();
889:       const Obj<Mesh::label_sequence>& faces = tractionMesh->heightStratum(0);
890:       const Obj<Mesh::numbering_type>& vNumbering = mesh->getFactory()->getLocalNumbering(mesh, 0);

894:       PetscViewerASCIIPrintf(viewer,"#\n");
895:       PetscViewerASCIIPrintf(viewer,"traction_units = Pa\n");
896:       PetscViewerASCIIPrintf(viewer,"#\n");
897:       PetscViewerASCIIPrintf(viewer,"#\n");
898:       for(Mesh::label_sequence::iterator f_iter = faces->begin(); f_iter != faces->end(); ++f_iter) {
899:         const Mesh::point_type& face = *f_iter;
900:         const Obj<Mesh::sieve_type::traits::coneSequence>& cone = sieve->cone(face);

902:         for(Mesh::sieve_type::traits::coneSequence::iterator c_iter = cone->begin(); c_iter != cone->end(); ++c_iter) {
903:           const Mesh::point_type& vertex = *c_iter;

905:           PetscViewerASCIIPrintf(viewer, "%6d", vNumbering->getIndex(vertex)+1);
906:           std::cout << vNumbering->getIndex(vertex) << " ("<<vertex<<") ";
907:         }
908:         const Mesh::real_section_type::value_type *values = tractionField->restrictPoint(face);

910:         for(int i = 0; i < mesh->getDimension(); ++i) {
911:           if (i > 0) {
912:             PetscViewerASCIIPrintf(viewer, " ");
913:             std::cout << " ";
914:           }
915:           PetscViewerASCIIPrintf(viewer, "%15.9g", values[i]);
916:           std::cout << values[i];
917:         }
918:         PetscViewerASCIIPrintf(viewer,"\n");
919:         std::cout << std::endl;
920:       }
921:       return(0);
922:     };
923:   };
924: };

926: namespace ALECompat {
927:   namespace PyLith {
928:     using ALECompat::Mesh;
929:     //
930:     // Builder methods
931:     //
932:     char *Builder::coord_units = NULL;
933:     char *Builder::traction_units = NULL;
934:     void Builder::broadcastString(const MPI_Comm comm, const int rank, const char *input, char **output) {
935:       int len;

937:       if (rank == 0) {
938:         len = strlen(input);
939:       }
940:       MPI_Bcast(&len, 1, MPI_INT, 0, comm);
941:       *output = new char[len+1];
942:       if (rank == 0) {
943:         strcpy(*output, input);
944:       }
945:       MPI_Bcast(*output, len+1, MPI_CHAR, 0, comm);
946:     };
947:     inline void Builder::ignoreComments(char *buf, PetscInt bufSize, FILE *f) {
948:       while((fgets(buf, bufSize, f) != NULL) && ((buf[0] == '#') || (buf[0] == '\0'))) {}
949:     };
950:     void Builder::readConnectivity(MPI_Comm comm, const std::string& filename, int& corners, const bool useZeroBase, int& numElements, int *vertices[], int *materials[]) {
951:       PetscViewer    viewer;
952:       FILE          *f;
953:       PetscInt       maxCells = 1024, cellCount = 0;
954:       PetscInt      *verts;
955:       PetscInt      *mats;
956:       char           buf[2048];
957:       PetscInt       c;
958:       PetscInt       commRank;

961:       MPI_Comm_rank(comm, &commRank);
962:       if (commRank != 0) return;
963:       PetscViewerCreate(PETSC_COMM_SELF, &viewer);
964:       PetscViewerSetType(viewer, PETSC_VIEWER_ASCII);
965:       PetscViewerFileSetMode(viewer, FILE_MODE_READ);
966:       PetscViewerFileSetName(viewer, filename.c_str());
967:       PetscViewerASCIIGetPointer(viewer, &f);
968:       /* Ignore comments */
969:       ignoreComments(buf, 2048, f);
970:       do {
971:         const char *v = strtok(buf, " ");
972:         int         elementType;

974:         if (cellCount == maxCells) {
975:           PetscInt *vtmp, *mtmp;

977:           vtmp = verts;
978:           mtmp = mats;
979:           PetscMalloc2(maxCells*2*corners,PetscInt,&verts,maxCells*2,PetscInt,&mats);
980:           PetscMemcpy(verts, vtmp, maxCells*corners * sizeof(PetscInt));
981:           PetscMemcpy(mats,  mtmp, maxCells         * sizeof(PetscInt));
982:           PetscFree2(vtmp,mtmp);
983:           maxCells *= 2;
984:         }
985:         /* Ignore cell number */
986:         v = strtok(NULL, " ");
987:         /* Get element type */
988:         elementType = atoi(v);
989:         if (elementType == 1) {
990:           corners = 8;
991:         } else if (elementType == 5) {
992:           corners = 4;
993:         } else {
994:           ostringstream msg;

996:           msg << "We do not accept element type " << elementType << " right now";
997:           throw ALE::Exception(msg.str().c_str());
998:         }
999:         if (cellCount == 0) {
1000:           PetscMalloc2(maxCells*corners,PetscInt,&verts,maxCells,PetscInt,&mats);
1001:         }
1002:         v = strtok(NULL, " ");
1003:         /* Store material type */
1004:         mats[cellCount] = atoi(v);
1005:         v = strtok(NULL, " ");
1006:         /* Ignore infinite domain element code */
1007:         v = strtok(NULL, " ");
1008:         for(c = 0; c < corners; c++) {
1009:           int vertex = atoi(v);
1010: 
1011:           if (!useZeroBase) vertex -= 1;
1012:           verts[cellCount*corners+c] = vertex;
1013:           v = strtok(NULL, " ");
1014:         }
1015:         cellCount++;
1016:       } while(fgets(buf, 2048, f) != NULL);
1017:       PetscViewerDestroy(viewer);
1018:       numElements = cellCount;
1019:       *vertices   = verts;
1020:       *materials  = mats;
1021:     };
1022:     void Builder::readCoordinates(MPI_Comm comm, const std::string& filename, const int dim, int& numVertices, double *coordinates[]) {
1023:       PetscViewer    viewer;
1024:       FILE          *f;
1025:       PetscInt       maxVerts = 1024, vertexCount = 0;
1026:       PetscScalar   *coords;
1027:       const char    *units = NULL;
1028:       double         scaleFactor = 1.0;
1029:       char           buf[2048];
1030:       PetscInt       c;
1031:       PetscInt       commRank;

1034:       MPI_Comm_rank(comm, &commRank);
1035:       if (commRank == 0) {
1036:         PetscViewerCreate(PETSC_COMM_SELF, &viewer);
1037:         PetscViewerSetType(viewer, PETSC_VIEWER_ASCII);
1038:         PetscViewerFileSetMode(viewer, FILE_MODE_READ);
1039:         PetscViewerFileSetName(viewer, filename.c_str());
1040:         PetscViewerASCIIGetPointer(viewer, &f);
1041:         /* Ignore comments */
1042:         ignoreComments(buf, 2048, f);
1043:         PetscMalloc(maxVerts*dim * sizeof(PetscScalar), &coords);
1044:         /* Read units */
1045:         units = strtok(buf, " ");
1046:         if (strcmp(units, "coord_units")) {
1047:           throw ALE::Exception("Invalid coordinate units line");
1048:         }
1049:         units = strtok(NULL, " ");
1050:         if (strcmp(units, "=")) {
1051:           throw ALE::Exception("Invalid coordinate units line");
1052:         }
1053:         units = strtok(NULL, " ");
1054:       }
1055:       /* Should use Pythia to do units conversion */
1056:       Builder::broadcastString(comm, commRank, units, &Builder::coord_units);
1057:       if (commRank == 0) {
1058:         /* Ignore comments */
1059:         ignoreComments(buf, 2048, f);
1060:         do {
1061:           const char *x = strtok(buf, " ");

1063:           if (vertexCount == maxVerts) {
1064:             PetscScalar *ctmp;

1066:             ctmp = coords;
1067:             PetscMalloc(maxVerts*2*dim * sizeof(PetscScalar), &coords);
1068:             PetscMemcpy(coords, ctmp, maxVerts*dim * sizeof(PetscScalar));
1069:             PetscFree(ctmp);
1070:             maxVerts *= 2;
1071:           }
1072:           /* Ignore vertex number */
1073:           x = strtok(NULL, " ");
1074:           for(c = 0; c < dim; c++) {
1075:             coords[vertexCount*dim+c] = atof(x)*scaleFactor;
1076:             x = strtok(NULL, " ");
1077:           }
1078:           vertexCount++;
1079:         } while(fgets(buf, 2048, f) != NULL);
1080:         PetscViewerDestroy(viewer);
1081:         numVertices = vertexCount;
1082:         *coordinates = coords;
1083:       }
1084:     };
1085:     // numSplit is the number of split node entries (lines in the file)
1086:     // splitInd[] is an array of numSplit pairs, <element, vertex>
1087:     // splitValues[] is an array of numSplit*dim displacements
1088:     void Builder::readSplit(MPI_Comm comm, const std::string& filename, const int dim, const bool useZeroBase, int& numSplit, int *splitInd[], int *loadHistory[], double *splitValues[]) {
1089:       PetscViewer    viewer;
1090:       FILE          *f;
1091:       PetscInt       maxSplit = 1024, splitCount = 0;
1092:       PetscInt      *splitId;
1093:       PetscInt      *loadHist;
1094:       PetscScalar   *splitVal;
1095:       char           buf[2048];
1096:       PetscInt       c;
1097:       PetscInt       commRank;

1100:       MPI_Comm_rank(comm, &commRank);
1101:       if (dim != 3) {
1102:         throw ALE::Exception("PyLith only works in 3D");
1103:       }
1104:       if (commRank != 0) return;
1105:       PetscViewerCreate(PETSC_COMM_SELF, &viewer);
1106:       PetscViewerSetType(viewer, PETSC_VIEWER_ASCII);
1107:       PetscViewerFileSetMode(viewer, FILE_MODE_READ);
1108:       PetscExceptionTry1(PetscViewerFileSetName(viewer, filename.c_str()), PETSC_ERR_FILE_OPEN);
1109:       if (PetscExceptionValue(ierr)) {
1110:         // this means that a caller above me has also tryed this exception so I don't handle it here, pass it up
1111:       } else if (PetscExceptionCaught(ierr,PETSC_ERR_FILE_OPEN)) {
1112:         // File does not exist
1113:         return;
1114:       }
1115:       PetscViewerASCIIGetPointer(viewer, &f);
1116:       /* Ignore comments */
1117:       ignoreComments(buf, 2048, f);
1118:       PetscMalloc3(maxSplit*2,PetscInt,&splitId,maxSplit,PetscInt,&loadHist,maxSplit*dim,PetscScalar,&splitVal);
1119:       do {
1120:         const char *s = strtok(buf, " ");

1122:         if (splitCount == maxSplit) {
1123:           PetscInt    *sitmp;
1124:           PetscInt    *lhtmp;
1125:           PetscScalar *svtmp;

1127:           sitmp = splitId;
1128:           lhtmp = loadHist;
1129:           svtmp = splitVal;
1130:           PetscMalloc3(maxSplit*2*2,PetscInt,&splitId,maxSplit*2,PetscInt,&loadHist,maxSplit*dim*2,PetscScalar,&splitVal);
1131:           PetscMemcpy(splitId,  sitmp, maxSplit*2   * sizeof(PetscInt));
1132:           PetscMemcpy(loadHist, lhtmp, maxSplit     * sizeof(PetscInt));
1133:           PetscMemcpy(splitVal, svtmp, maxSplit*dim * sizeof(PetscScalar));
1134:           PetscFree3(sitmp,lhtmp,svtmp);
1135:           maxSplit *= 2;
1136:         }
1137:         /* Get element number */
1138:         int elem = atoi(s);
1139:         if (!useZeroBase) elem -= 1;
1140:         splitId[splitCount*2+0] = elem;
1141:         s = strtok(NULL, " ");
1142:         /* Get node number */
1143:         int node = atoi(s);
1144:         if (!useZeroBase) node -= 1;
1145:         splitId[splitCount*2+1] = node;
1146:         s = strtok(NULL, " ");
1147:         /* Ignore load history number */
1148:         loadHist[splitCount] = atoi(s);
1149:         s = strtok(NULL, " ");
1150:         /* Get split values */
1151:         for(c = 0; c < dim; c++) {
1152:           splitVal[splitCount*dim+c] = atof(s);
1153:           s = strtok(NULL, " ");
1154:         }
1155:         splitCount++;
1156:       } while(fgets(buf, 2048, f) != NULL);
1157:       PetscViewerDestroy(viewer);
1158:       numSplit     = splitCount;
1159:       *splitInd    = splitId;
1160:       *loadHistory = loadHist;
1161:       *splitValues = splitVal;
1162:     };
1163:     void Builder::buildSplit(const Obj<pair_section_type>& splitField, const Obj<int_section_type>& loadField, int numCells, int numSplit, int splitInd[], int loadHistory[], double splitVals[]) {
1164:       const pair_section_type::patch_type                     patch = 0;
1165:       pair_section_type::value_type                          *values;
1166:       int_section_type::value_type                           *history;
1167:       std::map<pair_section_type::point_type, std::set<int> > elem2index;
1168:       int                                                     numValues = 0;

1170:       splitField->setName("split");
1171:       for(int e = 0; e < numSplit; e++) {
1172:         splitField->addFiberDimension(patch, splitInd[e*2+0], 1);
1173:         loadField->addFiberDimension(patch, splitInd[e*2+0], 1);
1174:         elem2index[splitInd[e*2+0]].insert(e);
1175:       }
1176:       splitField->allocate();
1177:       loadField->allocate();
1178:       for(std::map<pair_section_type::point_type, std::set<int> >::const_iterator e_iter = elem2index.begin(); e_iter != elem2index.end(); ++e_iter) {
1179:         numValues = std::max(numValues, (int) e_iter->second.size());
1180:       }
1181:       values  = new pair_section_type::value_type[numValues];
1182:       history = new int_section_type::value_type[numValues];
1183:       for(std::map<pair_section_type::point_type, std::set<int> >::const_iterator e_iter = elem2index.begin(); e_iter != elem2index.end(); ++e_iter) {
1184:         const pair_section_type::point_type& e = e_iter->first;
1185:         int                                  k = 0;

1187:         for(std::set<int>::const_iterator i_iter = e_iter->second.begin(); i_iter != e_iter->second.end(); ++i_iter, ++k) {
1188:           const int& i = *i_iter;

1190:           if (k >= numValues) {throw ALE::Exception("Invalid split node input");}
1191:           values[k].first    = splitInd[i*2+1] + numCells;
1192:           values[k].second.x = splitVals[i*3+0];
1193:           values[k].second.y = splitVals[i*3+1];
1194:           values[k].second.z = splitVals[i*3+2];
1195:           history[k]         = loadHistory[i];
1196:         }
1197:         splitField->updatePoint(patch, e, values);
1198:         loadField->updatePoint(patch, e, history);
1199:       }
1200:       delete [] values;
1201:     };
1202:     void Builder::readTractions(MPI_Comm comm, const std::string& filename, const int dim, const int& corners, const bool useZeroBase, int& numTractions, int& vertsPerFace, int *tractionVertices[], double *tractionValues[]) {
1203:       PetscViewer    viewer;
1204:       FILE          *f;
1205:       PetscInt       maxTractions = 1024, tractionCount = 0;
1206:       PetscInt      *tractionVerts;
1207:       PetscScalar   *tractionVals;
1208:       const char    *units = NULL;
1209:       char           buf[2048];
1210:       PetscInt       c;
1211:       PetscInt       commRank;
1212:       PetscTruth     found = PETSC_TRUE;

1215:       MPI_Comm_rank(comm, &commRank);
1216:       if (dim != 3) {
1217:         throw ALE::Exception("PyLith only works in 3D");
1218:       }
1219:       if (commRank == 0) {
1220:         PetscViewerCreate(PETSC_COMM_SELF, &viewer);
1221:         PetscViewerSetType(viewer, PETSC_VIEWER_ASCII);
1222:         PetscViewerFileSetMode(viewer, FILE_MODE_READ);
1223:         PetscExceptionTry1(PetscViewerFileSetName(viewer, filename.c_str()), PETSC_ERR_FILE_OPEN);
1224:         if (PetscExceptionValue(ierr)) {
1225:           // this means that a caller above me has also tryed this exception so I don't handle it here, pass it up
1226:         } else if (PetscExceptionCaught(ierr,PETSC_ERR_FILE_OPEN)) {
1227:           // File does not exist
1228:           found = PETSC_FALSE;
1229:         }
1230:         /* Logic right now is only good for linear tets and hexes, and should be fixed in the future. */
1231:         if (corners == 4) {
1232:           vertsPerFace = 3;
1233:         } else if (corners == 8) {
1234:           vertsPerFace = 4;
1235:         } else {
1236:           throw ALE::Exception("Unrecognized element type");
1237:         }
1238:       }
1239:       MPI_Bcast(&found, 1, MPI_INT, 0, comm);
1240:       if (!found) return;
1241:       if (commRank == 0) {
1242:         PetscViewerASCIIGetPointer(viewer, &f);
1243:         /* Ignore comments */
1244:         ignoreComments(buf, 2048, f);
1245:         /* Read units */
1246:         units = strtok(buf, " ");
1247:         if (strcmp(units, "traction_units")) {
1248:           throw ALE::Exception("Invalid traction units line");
1249:         }
1250:         units = strtok(NULL, " ");
1251:         if (strcmp(units, "=")) {
1252:           throw ALE::Exception("Invalid traction units line");
1253:         }
1254:         units = strtok(NULL, " ");
1255:       }
1256:       /* Should use Pythia to do units conversion */
1257:       Builder::broadcastString(comm, commRank, units, &Builder::traction_units);
1258:       if (commRank == 0) {
1259:         /* Ignore comments */
1260:         ignoreComments(buf, 2048, f);
1261:         // Allocate memory.
1262:         PetscMalloc2(maxTractions*vertsPerFace,PetscInt,&tractionVerts,maxTractions*dim,PetscScalar,&tractionVals);
1263:         do {
1264:           const char *s = strtok(buf, " ");

1266:           if (tractionCount == maxTractions) {
1267:             PetscInt    *titmp;
1268:             PetscScalar *tvtmp;

1270:             titmp = tractionVerts;
1271:             tvtmp = tractionVals;
1272:             PetscMalloc2(maxTractions*vertsPerFace*2,PetscInt,&tractionVerts,maxTractions*dim*2,PetscScalar,&tractionVals);
1273:             PetscMemcpy(tractionVerts,  titmp, maxTractions*vertsPerFace   * sizeof(PetscInt));
1274:             PetscMemcpy(tractionVals, tvtmp, maxTractions*dim * sizeof(PetscScalar));
1275:             PetscFree2(titmp,tvtmp);
1276:             maxTractions *= 2;
1277:           }
1278:           /* Get vertices */
1279:           int v1 = atoi(s);
1280:           if (!useZeroBase) v1 -= 1;
1281:           tractionVerts[tractionCount*vertsPerFace+0] = v1;
1282:           s = strtok(NULL, " ");
1283:           int v2 = atoi(s);
1284:           if (!useZeroBase) v2 -= 1;
1285:           tractionVerts[tractionCount*vertsPerFace+1] = v2;
1286:           s = strtok(NULL, " ");
1287:           int v3 = atoi(s);
1288:           if (!useZeroBase) v3 -= 1;
1289:           tractionVerts[tractionCount*vertsPerFace+2] = v3;
1290:           s = strtok(NULL, " ");
1291:           if (vertsPerFace > 3) {
1292:             int v4 = atoi(s);
1293:             if (!useZeroBase) v4 -= 1;
1294:             tractionVerts[tractionCount*vertsPerFace+3] = v4;
1295:             s = strtok(NULL, " ");
1296:           }
1297:           /* Get traction values */
1298:           for(c = 0; c < dim; c++) {
1299:             tractionVals[tractionCount*dim+c] = atof(s);
1300:             s = strtok(NULL, " ");
1301:           }
1302:           tractionCount++;
1303:         } while(fgets(buf, 2048, f) != NULL);
1304:         PetscViewerDestroy(viewer);
1305:         numTractions      = tractionCount;
1306:         *tractionVertices = tractionVerts;
1307:         *tractionValues   = tractionVals;
1308:       }
1309:     };
1310:     void Builder::buildTractions(const Obj<real_section_type>& tractionField, const Obj<topology_type>& boundaryTopology, int numCells, int numTractions, int vertsPerFace, int tractionVertices[], double tractionValues[]) {
1311:       const real_section_type::patch_type                  patch = 0;
1312:       real_section_type::value_type                        values[3];
1313:       // Make boundary topology
1314:       Obj<sieve_type> boundarySieve = new sieve_type(tractionField->comm(), tractionField->debug());

1316:       ALECompat::New::SieveBuilder<Mesh>::buildTopology(boundarySieve, 2, numTractions, tractionVertices, 0, false, vertsPerFace, numCells);
1317:       boundaryTopology->setPatch(patch, boundarySieve);
1318:       boundaryTopology->stratify();
1319:       // Make traction field
1320:       tractionField->setName("traction");
1321:       tractionField->setTopology(boundaryTopology);
1322:       tractionField->setFiberDimensionByHeight(patch, 0, 3);
1323:       tractionField->allocate();
1324:       const Obj<topology_type::label_sequence>& faces = boundaryTopology->heightStratum(patch, 0);
1325:       int k = 0;

1327:       for(topology_type::label_sequence::iterator f_iter = faces->begin(); f_iter != faces->end(); ++f_iter) {
1328:         const topology_type::point_type& face = *f_iter;

1330:         values[0] = tractionValues[k*3+0];
1331:         values[1] = tractionValues[k*3+1];
1332:         values[2] = tractionValues[k*3+2];
1333:         k++;
1334:         tractionField->updatePoint(patch, face, values);
1335:       }
1336:     };
1337:     void Builder::buildMaterials(const Obj<int_section_type>& matField, const int materials[]) {
1338:       const int_section_type::patch_type        patch    = 0;
1339:       const Obj<topology_type::label_sequence>& elements = matField->getTopology()->heightStratum(patch, 0);

1341:       matField->setName("material");
1342:       matField->setFiberDimensionByHeight(patch, 0, 1);
1343:       matField->allocate();
1344:       for(topology_type::label_sequence::iterator e_iter = elements->begin(); e_iter != elements->end(); ++e_iter) {
1345:         matField->updatePoint(patch, *e_iter, &materials[*e_iter]);
1346:       }
1347:     };
1348:     Obj<Mesh> Builder::readMesh(MPI_Comm comm, const int dim, const std::string& basename, const bool useZeroBase = false, const bool interpolate = false, const int debug = 0) {
1349:       Obj<Mesh>             mesh     = new Mesh(comm, dim, debug);
1350:       Obj<sieve_type>       sieve    = new sieve_type(comm, debug);
1351:       Obj<topology_type>    topology = new topology_type(comm, debug);
1352:       int    *cells, *materials;
1353:       double *coordinates;
1354:       int     numCells = 0, numVertices = 0, numCorners = dim+1;

1356:       ALECompat::PyLith::Builder::readConnectivity(comm, basename+".connect", numCorners, useZeroBase, numCells, &cells, &materials);
1357:       ALECompat::PyLith::Builder::readCoordinates(comm, basename+".coord", dim, numVertices, &coordinates);
1358:       ALECompat::New::SieveBuilder<Mesh>::buildTopology(sieve, dim, numCells, cells, numVertices, interpolate, numCorners);
1359:       sieve->stratify();
1360:       topology->setPatch(0, sieve);
1361:       topology->stratify();
1362:       mesh->setTopology(topology);
1363:       ALECompat::New::SieveBuilder<Mesh>::buildCoordinates(mesh->getRealSection("coordinates"), dim, coordinates);
1364:       Obj<int_section_type> material = mesh->getIntSection("material");
1365:       buildMaterials(material, materials);
1366:       Obj<ALECompat::Mesh::pair_section_type> split = createSplit(mesh, basename, useZeroBase);
1367:       if (!split.isNull()) {mesh->setPairSection("split", split);}
1368:       Obj<ALECompat::Mesh::real_section_type> traction = createTraction(mesh, basename, useZeroBase);
1369:       if (!traction.isNull()) {mesh->setRealSection("traction", traction);}
1370:       return mesh;
1371:     };
1372:     Obj<Builder::pair_section_type> Builder::createSplit(const Obj<Mesh>& mesh, const std::string& basename, const bool useZeroBase = false) {
1373:       Obj<pair_section_type> split = NULL;
1374:       MPI_Comm comm     = mesh->comm();
1375:       int      dim      = mesh->getDimension();
1376:       int      numCells = mesh->getTopology()->heightStratum(0, 0)->size();
1377:       int     *splitInd, *loadHistory;
1378:       double  *splitValues;
1379:       int      numSplit = 0, hasSplit;

1381:       ALECompat::PyLith::Builder::readSplit(comm, basename+".split", dim, useZeroBase, numSplit, &splitInd, &loadHistory, &splitValues);
1382:       MPI_Allreduce(&numSplit, &hasSplit, 1, MPI_INT, MPI_MAX, comm);
1383:       if (hasSplit) {
1384:         split = new pair_section_type(mesh->getTopology());
1385:         Obj<int_section_type> loadField = mesh->getIntSection("loadHistory");
1386:         buildSplit(split, loadField, numCells, numSplit, splitInd, loadHistory, splitValues);
1387:       }
1388:       return split;
1389:     };
1390:     Obj<Mesh::real_section_type> Builder::createTraction(const Obj<Mesh>& mesh, const std::string& basename, const bool useZeroBase = false) {
1391:       Obj<real_section_type> traction = NULL;
1392:       MPI_Comm comm       = mesh->comm();
1393:       int      debug      = mesh->debug();
1394:       int      dim        = mesh->getDimension();
1395:       int      numCells   = mesh->getTopology()->heightStratum(0, 0)->size();
1396:       int      numCorners = mesh->getTopology()->getPatch(0)->cone(*mesh->getTopology()->heightStratum(0, 0)->begin())->size();
1397:       int     *tractionVertices;
1398:       double  *tractionValues;
1399:       int      numTractions = 0, vertsPerFace = 0, hasTractions;

1401:       ALECompat::PyLith::Builder::readTractions(comm, basename+".traction", dim, numCorners, useZeroBase, numTractions, vertsPerFace, &tractionVertices, &tractionValues);
1402:       MPI_Allreduce(&numTractions, &hasTractions, 1, MPI_INT, MPI_MAX, comm);
1403:       if (hasTractions) {
1404:         Obj<topology_type> boundaryTopology = new topology_type(mesh->comm(), debug);

1406:         traction = new real_section_type(boundaryTopology);
1407:         buildTractions(traction, boundaryTopology, numCells, numTractions, vertsPerFace, tractionVertices, tractionValues);
1408:       }
1409:       return traction;
1410:     };
1411:     void Builder::createCohesiveElements(const Obj<Mesh>& mesh, const std::set<Mesh::point_type>& faultVertices) {
1412:       typedef std::vector<Mesh::point_type> PointArray;
1413:       const Mesh::real_section_type::patch_type patch      = 0;
1414:       const Obj<Mesh::sieve_type>               sieve      = mesh->getTopology()->getPatch(patch);
1415:       const Obj<Mesh::topology_type>            fault      = new Mesh::topology_type(sieve->comm(), sieve->debug());
1416:       const Obj<Mesh::sieve_type>               faultSieve = new Mesh::sieve_type(sieve->comm(), sieve->debug());
1417:       const std::set<Mesh::point_type>::const_iterator fvBegin = faultVertices.begin();
1418:       const std::set<Mesh::point_type>::const_iterator fvEnd   = faultVertices.end();
1419:       // There should be logic here to determine this
1420:       const unsigned int                        faceSize   = 3;
1421:       int                                       f          = 0;
1422:       int                                       debug      = mesh->debug();
1423:       Obj<PointArray>                           face       = new PointArray();
1424:       std::set<Mesh::point_type>                faultCells;

1426:       // Create a sieve which captures the fault
1427:       for(std::set<int>::const_iterator fv_iter = fvBegin; fv_iter != fvEnd; ++fv_iter) {
1428:         const Obj<Mesh::sieve_type::traits::supportSequence>&     cells  = sieve->support(*fv_iter);
1429:         const Mesh::sieve_type::traits::supportSequence::iterator cBegin = cells->begin();
1430:         const Mesh::sieve_type::traits::supportSequence::iterator cEnd   = cells->end();

1432:         if (debug) {std::cout << "Checking fault vertex " << *fv_iter << std::endl;}
1433:         for(ALECompat::Mesh::sieve_type::traits::supportSequence::iterator c_iter = cBegin; c_iter != cEnd; ++c_iter) {
1434:           if (debug) {std::cout << "  Checking cell " << *c_iter << std::endl;}
1435:           if (faultCells.find(*c_iter) != faultCells.end()) continue;
1436:           const Obj<ALECompat::Mesh::sieve_type::traits::coneSequence>& cone   = sieve->cone(*c_iter);
1437:           const Mesh::sieve_type::traits::coneSequence::iterator  vBegin = cone->begin();
1438:           const Mesh::sieve_type::traits::coneSequence::iterator  vEnd   = cone->end();

1440:           face->clear();
1441:           for(ALECompat::Mesh::sieve_type::traits::coneSequence::iterator v_iter = vBegin; v_iter != vEnd; ++v_iter) {
1442:             if (faultVertices.find(*v_iter) != fvEnd) {
1443:               if (debug) {std::cout << "    contains fault vertex " << *v_iter << std::endl;}
1444:               face->insert(face->end(), *v_iter);
1445:             }
1446:           }
1447:           if (face->size() > faceSize) throw ALE::Exception("Invalid fault mesh: Too many vertices of an element on the fault");
1448:           if (face->size() == faceSize) {
1449:             if (debug) {std::cout << "  Contains a face on the fault" << std::endl;}
1450:             const Obj<sieve_type::supportSet> preFace = faultSieve->nJoin1(face);

1452:             if (preFace->size() > 1) {
1453:               throw ALE::Exception("Invalid fault sieve: Multiple faces from vertex set");
1454:             } else if (preFace->size() == 1) {
1455:               faultSieve->addArrow(*preFace->begin(), *c_iter);
1456:             } else if (preFace->size() == 0) {
1457:               if (debug) {std::cout << "  Adding face " << f << std::endl;}
1458:               int color = 0;
1459:               for(PointArray::const_iterator f_iter = face->begin(); f_iter != face->end(); ++f_iter) {
1460:                 if (debug) {std::cout << "    vertex " << *f_iter << std::endl;}
1461:                 faultSieve->addArrow(*f_iter, f, color++);
1462:               }
1463:               faultSieve->addArrow(f, *c_iter);
1464:               f++;
1465:             }
1466:             faultCells.insert(*c_iter);
1467:           }
1468:         }
1469:       }
1470:       fault->setPatch(patch, faultSieve);
1471:       fault->stratify();
1472:       faultCells.clear();
1473:       if (debug) {fault->view("Fault sieve");}
1474:       // Add new shadow vertices
1475:       const Obj<Mesh::topology_type::label_sequence>& fVertices = fault->depthStratum(patch, 0);
1476:       const Obj<Mesh::topology_type::label_sequence>& vertices  = mesh->getTopology()->depthStratum(patch, 0);
1477:       Mesh::topology_type::point_type                 newVertex = *vertices->begin() + vertices->size();
1478:       std::map<int,int>                               vertexRenumber;

1480:       for(Mesh::topology_type::label_sequence::iterator v_iter = fVertices->begin(); v_iter != fVertices->end(); ++v_iter) {
1481:         if (debug) {std::cout << "Duplicating " << *v_iter << " to " << vertexRenumber[*v_iter] << std::endl;}
1482:         vertexRenumber[*v_iter] = newVertex++;
1483:       }
1484:       // Split the mesh along the fault sieve and create cohesive elements
1485:       const Obj<Mesh::topology_type::label_sequence>& faces     = fault->depthStratum(patch, 1);
1486:       PointArray                                      newVertices;

1488:       for(Mesh::topology_type::label_sequence::iterator f_iter = faces->begin(); f_iter != faces->end(); ++f_iter) {
1489:         if (debug) {std::cout << "Considering fault face " << *f_iter << std::endl;}
1490:         const Obj<Mesh::sieve_type::traits::supportSequence>& cells = faultSieve->support(*f_iter);
1491:         Mesh::topology_type::point_type                       cell  = std::max(*cells->begin(), *(++cells->begin()));
1492:         const Obj<Mesh::sieve_type::traits::coneSequence>&    cone  = sieve->cone(cell);

1494:         if (debug) {std::cout << "  Replacing cell " << cell << std::endl;}
1495:         newVertices.clear();
1496:         for(ALECompat::Mesh::sieve_type::traits::coneSequence::iterator v_iter = cone->begin(); v_iter != cone->end(); ++v_iter) {
1497:           if (vertexRenumber.find(*v_iter) != vertexRenumber.end()) {
1498:             if (debug) {std::cout << "    vertex " << vertexRenumber[*v_iter] << std::endl;}
1499:             newVertices.insert(newVertices.end(), vertexRenumber[*v_iter]);
1500:           } else {
1501:             if (debug) {std::cout << "    vertex " << *v_iter << std::endl;}
1502:             newVertices.insert(newVertices.end(), *v_iter);
1503:           }
1504:         }
1505:         sieve->clearCone(cell);
1506:         int color = 0;
1507:         for(PointArray::const_iterator v_iter = newVertices.begin(); v_iter != newVertices.end(); ++v_iter) {
1508:           sieve->addArrow(*v_iter, cell, color++);
1509:         }
1510:       }
1511:       // Fix coordinates
1512:       const Obj<Mesh::real_section_type>&             coordinates = mesh->getRealSection("coordinates");
1513:       const Obj<Mesh::topology_type::label_sequence>& fVertices2  = fault->depthStratum(patch, 0);

1515:       for(Mesh::topology_type::label_sequence::iterator v_iter = fVertices2->begin(); v_iter != fVertices2->end(); ++v_iter) {
1516:         coordinates->addPoint(patch, vertexRenumber[*v_iter], coordinates->getFiberDimension(patch, *v_iter));
1517:       }
1518:       coordinates->reallocate();
1519:       for(Mesh::topology_type::label_sequence::iterator v_iter = fVertices2->begin(); v_iter != fVertices2->end(); ++v_iter) {
1520:         coordinates->updatePoint(patch, vertexRenumber[*v_iter], coordinates->restrictPoint(patch, *v_iter));
1521:       }
1522:     };
1523:     //
1524:     // Viewer methods
1525:     //
1528:     PetscErrorCode Viewer::writeVertices(const Obj<Mesh>& mesh, PetscViewer viewer) {
1529:       Obj<Builder::real_section_type> coordinates  = mesh->getRealSection("coordinates");
1530:       //Mesh::section_type::patch_type patch;
1531:       //const double  *array = coordinates->restrict(Mesh::section_type::patch_type());
1532:       //int            dim = mesh->getDimension();
1533:       //int            numVertices;

1537: #if 0
1538:       //FIX:
1539:       if (vertexBundle->getGlobalOffsets()) {
1540:         numVertices = vertexBundle->getGlobalOffsets()[mesh->commSize()];
1541:       } else {
1542:         numVertices = mesh->getTopology()->depthStratum(0)->size();
1543:       }
1544:       PetscViewerASCIIPrintf(viewer,"#\n");
1545:       PetscViewerASCIIPrintf(viewer,"coord_units = %s\n", Builder::coord_units);
1546:       PetscViewerASCIIPrintf(viewer,"#\n");
1547:       PetscViewerASCIIPrintf(viewer,"#\n");
1548:       PetscViewerASCIIPrintf(viewer,"#  Node      X-coord           Y-coord           Z-coord\n");
1549:       PetscViewerASCIIPrintf(viewer,"#\n");
1550:       if (mesh->commRank() == 0) {
1551:         int numLocalVertices = mesh->getTopology()->depthStratum(0)->size();
1552:         int vertexCount = 1;

1554:         for(int v = 0; v < numLocalVertices; v++) {
1555:           PetscViewerASCIIPrintf(viewer,"%7D ", vertexCount++);
1556:           for(int d = 0; d < dim; d++) {
1557:             if (d > 0) {
1558:               PetscViewerASCIIPrintf(viewer," ");
1559:             }
1560:             PetscViewerASCIIPrintf(viewer,"% 16.8E", array[v*dim+d]);
1561:           }
1562:           PetscViewerASCIIPrintf(viewer,"\n");
1563:         }
1564:         for(int p = 1; p < mesh->commSize(); p++) {
1565:           double    *remoteCoords;
1566:           MPI_Status status;

1568:           MPI_Recv(&numLocalVertices, 1, MPI_INT, p, 1, mesh->comm(), &status);
1569:           PetscMalloc(numLocalVertices*dim * sizeof(double), &remoteCoords);
1570:           MPI_Recv(remoteCoords, numLocalVertices*dim, MPI_DOUBLE, p, 1, mesh->comm(), &status);
1571:           for(int v = 0; v < numLocalVertices; v++) {
1572:             PetscViewerASCIIPrintf(viewer,"%7D   ", vertexCount++);
1573:             for(int d = 0; d < dim; d++) {
1574:               if (d > 0) {
1575:                 PetscViewerASCIIPrintf(viewer, " ");
1576:               }
1577:               PetscViewerASCIIPrintf(viewer, "% 16.8E", remoteCoords[v*dim+d]);
1578:             }
1579:             PetscViewerASCIIPrintf(viewer, "\n");
1580:           }
1581:         }
1582:       } else {
1583:         Obj<Mesh::bundle_type> globalOrder = coordinates->getGlobalOrder();
1584:         Obj<Mesh::field_type::order_type::coneSequence> cone = globalOrder->getPatch(patch);
1585:         const int *offsets = coordinates->getGlobalOffsets();
1586:         int        numLocalVertices = (offsets[mesh->commRank()+1] - offsets[mesh->commRank()])/dim;
1587:         double    *localCoords;
1588:         int        k = 0;

1590:         PetscMalloc(numLocalVertices*dim * sizeof(double), &localCoords);
1591:         for(Mesh::field_type::order_type::coneSequence::iterator p_iter = cone->begin(); p_iter != cone->end(); ++p_iter) {
1592:           int dim = globalOrder->getFiberDimension(patch, *p_iter);

1594:           if (dim > 0) {
1595:             int offset = coordinates->getFiberOffset(patch, *p_iter);

1597:             for(int i = offset; i < offset+dim; ++i) {
1598:               localCoords[k++] = array[i];
1599:             }
1600:           }
1601:         }
1602:         if (k != numLocalVertices*dim) {
1603:           SETERRQ2(PETSC_ERR_PLIB, "Invalid number of coordinates to send %d should be %d", k, numLocalVertices*dim);
1604:         }
1605:         MPI_Send(&numLocalVertices, 1, MPI_INT, 0, 1, mesh->comm());
1606:         MPI_Send(localCoords, numLocalVertices*dim, MPI_DOUBLE, 0, 1, mesh->comm());
1607:         PetscFree(localCoords);
1608:       }
1609: #endif
1610:       return(0);
1611:     };
1614:     PetscErrorCode Viewer::writeElements(const Obj<Mesh>& mesh, const Obj<Builder::int_section_type>& materialField, PetscViewer viewer) {
1615:       Obj<Mesh::topology_type> topology = mesh->getTopology();
1616: #if 0
1617:       Obj<Mesh::sieve_type::traits::heightSequence> elements = topology->heightStratum(0);
1618:       Obj<Mesh::bundle_type> elementBundle = mesh->getBundle(topology->depth());
1619:       Obj<Mesh::bundle_type> vertexBundle = mesh->getBundle(0);
1620:       Obj<Mesh::bundle_type> globalVertex = vertexBundle->getGlobalOrder();
1621:       Obj<Mesh::bundle_type> globalElement = elementBundle->getGlobalOrder();
1622:       Mesh::bundle_type::patch_type patch;
1623:       std::string    orderName("element");
1624:       bool           hasMaterial  = !materialField.isNull();
1625:       int            dim  = mesh->getDimension();
1626:       int            corners = topology->nCone(*elements->begin(), topology->depth())->size();
1627:       int            elementType = -1;

1631:       if (dim != 3) {
1632:         SETERRQ(PETSC_ERR_SUP, "PyLith only supports 3D meshes.");
1633:       }
1634:       if (corners == 4) {
1635:         // Linear tetrahedron
1636:         elementType = 5;
1637:       } else if (corners == 8) {
1638:         // Linear hexahedron
1639:         elementType = 1;
1640:       } else {
1641:         SETERRQ1(PETSC_ERR_SUP, "PyLith Error: Unsupported number of elements vertices: %d", corners);
1642:       }
1643:       PetscViewerASCIIPrintf(viewer,"#\n");
1644:       PetscViewerASCIIPrintf(viewer,"#     N ETP MAT INF     N1     N2     N3     N4     N5     N6     N7     N8\n");
1645:       PetscViewerASCIIPrintf(viewer,"#\n");
1646:       if (mesh->commRank() == 0) {
1647:         int elementCount = 1;

1649:         for(Mesh::sieve_type::traits::heightSequence::iterator e_itor = elements->begin(); e_itor != elements->end(); ++e_itor) {
1650:           Obj<Mesh::bundle_type::order_type::coneSequence> cone = vertexBundle->getPatch(orderName, *e_itor);

1652:           PetscViewerASCIIPrintf(viewer, "%7d %3d", elementCount++, elementType);
1653:           if (hasMaterial) {
1654:             // No infinite elements
1655:             PetscViewerASCIIPrintf(viewer, " %3d %3d", (int) materialField->restrict(patch, *e_itor)[0], 0);
1656:           } else {
1657:             // No infinite elements
1658:             PetscViewerASCIIPrintf(viewer, " %3d %3d", 1, 0);
1659:           }
1660:           for(Mesh::bundle_type::order_type::coneSequence::iterator c_itor = cone->begin(); c_itor != cone->end(); ++c_itor) {
1661:             PetscViewerASCIIPrintf(viewer, " %6d", globalVertex->getIndex(patch, *c_itor).prefix+1);
1662:           }
1663:           PetscViewerASCIIPrintf(viewer, "\n");
1664:         }
1665:         for(int p = 1; p < mesh->commSize(); p++) {
1666:           int         numLocalElements;
1667:           int        *remoteVertices;
1668:           MPI_Status  status;

1670:           MPI_Recv(&numLocalElements, 1, MPI_INT, p, 1, mesh->comm(), &status);
1671:           PetscMalloc(numLocalElements*(corners+1) * sizeof(int), &remoteVertices);
1672:           MPI_Recv(remoteVertices, numLocalElements*(corners+1), MPI_INT, p, 1, mesh->comm(), &status);
1673:           for(int e = 0; e < numLocalElements; e++) {
1674:             // Only linear tetrahedra, material, no infinite elements
1675:             int mat = remoteVertices[e*(corners+1)+corners];

1677:             PetscViewerASCIIPrintf(viewer, "%7d %3d %3d %3d", elementCount++, elementType, mat, 0);
1678:             for(int c = 0; c < corners; c++) {
1679:               PetscViewerASCIIPrintf(viewer, " %6d", remoteVertices[e*(corners+1)+c]);
1680:             }
1681:             PetscViewerASCIIPrintf(viewer, "\n");
1682:           }
1683:           PetscFree(remoteVertices);
1684:         }
1685:       } else {
1686:         const int *offsets = elementBundle->getGlobalOffsets();
1687:         int        numLocalElements = offsets[mesh->commRank()+1] - offsets[mesh->commRank()];
1688:         int       *localVertices;
1689:         int        k = 0;

1691:         PetscMalloc(numLocalElements*(corners+1) * sizeof(int), &localVertices);
1692:         for(Mesh::sieve_type::traits::heightSequence::iterator e_itor = elements->begin(); e_itor != elements->end(); ++e_itor) {
1693:           Obj<Mesh::bundle_type::order_type::coneSequence> cone = vertexBundle->getPatch(orderName, *e_itor);

1695:           if (globalElement->getFiberDimension(patch, *e_itor) > 0) {
1696:             for(Mesh::bundle_type::order_type::coneSequence::iterator c_itor = cone->begin(); c_itor != cone->end(); ++c_itor) {
1697:               localVertices[k++] = globalVertex->getIndex(patch, *c_itor).prefix;
1698:             }
1699:             if (hasMaterial) {
1700:               localVertices[k++] = (int) materialField->restrict(patch, *e_itor)[0];
1701:             } else {
1702:               localVertices[k++] = 1;
1703:             }
1704:           }
1705:         }
1706:         if (k != numLocalElements*corners) {
1707:           SETERRQ2(PETSC_ERR_PLIB, "Invalid number of vertices to send %d should be %d", k, numLocalElements*corners);
1708:         }
1709:         MPI_Send(&numLocalElements, 1, MPI_INT, 0, 1, mesh->comm());
1710:         MPI_Send(localVertices, numLocalElements*(corners+1), MPI_INT, 0, 1, mesh->comm());
1711:         PetscFree(localVertices);
1712:       }
1713: #endif
1714:       return(0);
1715:     };
1718:     PetscErrorCode Viewer::writeVerticesLocal(const Obj<Mesh>& mesh, PetscViewer viewer) {
1719:       const Builder::real_section_type::patch_type       patch       = 0;
1720:       const Obj<Builder::real_section_type>&             coordinates = mesh->getRealSection("coordinates");
1721:       const Obj<Builder::topology_type>&                 topology    = mesh->getTopology();
1722:       const Obj<Builder::topology_type::label_sequence>& vertices    = topology->depthStratum(patch, 0);
1723:       const Obj<Mesh::numbering_type>&                   vNumbering  = mesh->getFactory()->getLocalNumbering(topology, patch, 0);
1724:       int            embedDim = coordinates->getFiberDimension(patch, *vertices->begin());

1728:       PetscViewerASCIIPrintf(viewer,"#\n");
1729:       PetscViewerASCIIPrintf(viewer,"coord_units = %s\n", Builder::coord_units);
1730:       PetscViewerASCIIPrintf(viewer,"#\n");
1731:       PetscViewerASCIIPrintf(viewer,"#\n");
1732:       PetscViewerASCIIPrintf(viewer,"#  Node      X-coord           Y-coord           Z-coord\n");
1733:       PetscViewerASCIIPrintf(viewer,"#\n");

1735:       for(Mesh::topology_type::label_sequence::iterator v_iter = vertices->begin(); v_iter != vertices->end(); ++v_iter) {
1736:         const Builder::real_section_type::value_type *array = coordinates->restrict(patch, *v_iter);

1738:         PetscViewerASCIIPrintf(viewer, "%7D ", vNumbering->getIndex(*v_iter)+1);
1739:         for(int d = 0; d < embedDim; d++) {
1740:           if (d > 0) {
1741:             PetscViewerASCIIPrintf(viewer, " ");
1742:           }
1743:           PetscViewerASCIIPrintf(viewer, "% 16.8E", array[d]);
1744:         }
1745:         PetscViewerASCIIPrintf(viewer, "\n");
1746:       }
1747:       return(0);
1748:     };
1751:     PetscErrorCode Viewer::writeElementsLocal(const Obj<Mesh>& mesh, const Obj<Builder::int_section_type>& materialField, PetscViewer viewer) {
1752:       const Mesh::topology_type::patch_type           patch      = 0;
1753:       const Obj<Mesh::topology_type>&                 topology   = mesh->getTopology();
1754:       const Obj<Mesh::sieve_type>&                    sieve      = topology->getPatch(patch);
1755:       const Obj<Mesh::topology_type::label_sequence>& elements   = topology->heightStratum(patch, 0);
1756:       const Obj<Mesh::numbering_type>&                eNumbering = mesh->getFactory()->getLocalNumbering(topology, patch, topology->depth());
1757:       const Obj<Mesh::numbering_type>&                vNumbering = mesh->getFactory()->getLocalNumbering(topology, patch, 0);
1758:       int            dim          = mesh->getDimension();
1759:       //int            corners      = sieve->nCone(*elements->begin(), topology->depth())->size();
1760:       int            corners      = sieve->cone(*elements->begin())->size();
1761:       bool           hasMaterial  = !materialField.isNull();
1762:       int            elementType  = -1;

1766:       if (dim != 3) {
1767:         SETERRQ(PETSC_ERR_SUP, "PyLith only supports 3D meshes.");
1768:       }
1769:       if (corners == 4) {
1770:         // Linear tetrahedron
1771:         elementType = 5;
1772:       } else if (corners == 8) {
1773:         // Linear hexahedron
1774:         elementType = 1;
1775:       } else {
1776:         SETERRQ1(PETSC_ERR_SUP, "PyLith Error: Unsupported number of elements vertices: %d", corners);
1777:       }
1778:       PetscViewerASCIIPrintf(viewer,"#\n");
1779:       PetscViewerASCIIPrintf(viewer,"#     N ETP MAT INF     N1     N2     N3     N4     N5     N6     N7     N8\n");
1780:       PetscViewerASCIIPrintf(viewer,"#\n");
1781:       for(Mesh::topology_type::label_sequence::iterator e_iter = elements->begin(); e_iter != elements->end(); ++e_iter) {
1782:         const Obj<Mesh::sieve_type::traits::coneSequence> cone  = sieve->cone(*e_iter);
1783:         Mesh::sieve_type::traits::coneSequence::iterator  begin = cone->begin();
1784:         Mesh::sieve_type::traits::coneSequence::iterator  end   = cone->end();

1786:         PetscViewerASCIIPrintf(viewer, "%7d %3d", eNumbering->getIndex(*e_iter)+1, elementType);
1787:         if (hasMaterial) {
1788:           // No infinite elements
1789:           PetscViewerASCIIPrintf(viewer, " %3d %3d", (int) materialField->restrict(patch, *e_iter)[0], 0);
1790:         } else {
1791:           // No infinite elements
1792:           PetscViewerASCIIPrintf(viewer, " %3d %3d", 1, 0);
1793:         }
1794:         for(Mesh::sieve_type::traits::coneSequence::iterator c_iter = begin; c_iter != end; ++c_iter) {
1795:           //FIX: Need a global ordering here
1796:           PetscViewerASCIIPrintf(viewer, " %6d", vNumbering->getIndex(*c_iter)+1);
1797:         }
1798:         PetscViewerASCIIPrintf(viewer, "\n");
1799:       }
1800:       return(0);
1801:     };
1804:     // The elements seem to be implicitly numbered by appearance, which makes it impossible to
1805:     //   number here by bundle, but we can fix it by traversing the elements like the vertices
1806:     PetscErrorCode Viewer::writeSplitLocal(const Obj<Mesh>& mesh, const Obj<Builder::pair_section_type>& splitField, PetscViewer viewer) {
1807:       const Obj<Mesh::topology_type>&        topology   = mesh->getTopology();
1808:       Builder::pair_section_type::patch_type patch      = 0;
1809:       const Obj<Mesh::numbering_type>&       eNumbering = mesh->getFactory()->getLocalNumbering(topology, patch, topology->depth());
1810:       const Obj<Mesh::numbering_type>&       vNumbering = mesh->getFactory()->getLocalNumbering(topology, patch, 0);

1814:       const Builder::pair_section_type::atlas_type::chart_type& chart = splitField->getPatch(patch);

1816:       for(Builder::pair_section_type::atlas_type::chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
1817:         const Builder::pair_section_type::point_type& e      = *c_iter;
1818:         const Builder::pair_section_type::value_type *values = splitField->restrict(patch, e);
1819:         const int                                     size   = splitField->getFiberDimension(patch, e);

1821:         for(int i = 0; i < size; i++) {
1822:           const Builder::pair_section_type::point_type& v     = values[i].first;
1823:           const ALECompat::Mesh::base_type::split_value&      split = values[i].second;

1825:           // No time history
1826:           PetscViewerASCIIPrintf(viewer, "%6d %6d 0 %15.9g %15.9g %15.9g\n", eNumbering->getIndex(e)+1, vNumbering->getIndex(v)+1, split.x, split.y, split.z);
1827:         }
1828:       }
1829:       return(0);
1830:     };
1833:     PetscErrorCode Viewer::writeTractionsLocal(const Obj<Mesh>& mesh, const Obj<Builder::real_section_type>& tractionField, PetscViewer viewer) {
1834:       typedef Builder::topology_type     topology_type;
1835:       typedef Builder::real_section_type section_type;
1836:       const section_type::patch_type            patch      = 0;
1837:       const Obj<topology_type>&         boundaryTopology   = tractionField->getTopology();
1838:       const Obj<topology_type::sieve_type>&     sieve      = boundaryTopology->getPatch(patch);
1839:       const Obj<topology_type::label_sequence>& faces      = boundaryTopology->heightStratum(patch, 0);
1840:       const Obj<Mesh::topology_type>&           topology   = mesh->getTopology();
1841:       const Obj<Mesh::numbering_type>&          vNumbering = mesh->getFactory()->getLocalNumbering(topology, patch, 0);

1845:       PetscViewerASCIIPrintf(viewer,"#\n");
1846:       PetscViewerASCIIPrintf(viewer,"traction_units = %s\n", Builder::traction_units);
1847:       PetscViewerASCIIPrintf(viewer,"#\n");
1848:       PetscViewerASCIIPrintf(viewer,"#\n");
1849:       for(topology_type::label_sequence::iterator f_iter = faces->begin(); f_iter != faces->end(); ++f_iter) {
1850:         const topology_type::point_type& face = *f_iter;
1851:         const Obj<topology_type::sieve_type::traits::coneSequence>& cone = sieve->cone(face);

1853:         for(topology_type::sieve_type::traits::coneSequence::iterator c_iter = cone->begin(); c_iter != cone->end(); ++c_iter) {
1854:           const topology_type::point_type& vertex = *c_iter;

1856:           PetscViewerASCIIPrintf(viewer, "%6d", vNumbering->getIndex(vertex)+1);
1857:           std::cout << vNumbering->getIndex(vertex) << " ("<<vertex<<") ";
1858:         }
1859:         const section_type::value_type *values = tractionField->restrict(patch, face);

1861:         for(int i = 0; i < mesh->getDimension(); ++i) {
1862:           if (i > 0) {
1863:             PetscViewerASCIIPrintf(viewer, " ");
1864:             std::cout << " ";
1865:           }
1866:           PetscViewerASCIIPrintf(viewer, "%15.9g", values[i]);
1867:           std::cout << values[i];
1868:         }
1869:         PetscViewerASCIIPrintf(viewer,"\n");
1870:         std::cout << std::endl;
1871:       }
1872:       return(0);
1873:     };
1874:   };
1875: };