Actual source code: meshpylith.c

  1: #include <petscmesh_formats.hh>   /*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: #ifdef PETSC_OPT_SIEVE
268:     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[]) {
269:       throw ALE::Exception("Not implemented for optimized sieves");
270:     };
271:     void Builder::buildTractions(const Obj<real_section_type>& tractionField, const Obj<Mesh>& boundaryMesh, int numCells, int numTractions, int vertsPerFace, int tractionVertices[], double tractionValues[]) {
272:       throw ALE::Exception("Not implemented for optimized sieves");
273:     };
274:     void Builder::buildMaterials(const Obj<Mesh>& mesh, const Obj<int_section_type>& matField, const int materials[]) {
275:       throw ALE::Exception("Not implemented for optimized sieves");
276:     };
277:     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) {
278:       throw ALE::Exception("Not implemented for optimized sieves");
279:     };
280:     Obj<Builder::Mesh> Builder::createTraction(const Obj<Mesh>& mesh, const std::string& basename, const bool useZeroBase = false) {
281:       throw ALE::Exception("Not implemented for optimized sieves");
282:     };
283:     void Builder::createCohesiveElements(const Obj<Mesh>& mesh, const std::set<Mesh::point_type>& faultVertices) {
284:       throw ALE::Exception("Not implemented for optimized sieves");
285:     };
286:     PetscErrorCode Viewer::writeVertices(const Obj<Mesh>& mesh, PetscViewer viewer) {
287:       throw ALE::Exception("Not implemented for optimized sieves");
288:     };
289:     PetscErrorCode Viewer::writeElements(const Obj<Mesh>& mesh, const Obj<Builder::int_section_type>& materialField, PetscViewer viewer) {
290:       throw ALE::Exception("Not implemented for optimized sieves");
291:     };
292:     PetscErrorCode Viewer::writeVerticesLocal(const Obj<Mesh>& mesh, PetscViewer viewer) {
293:       throw ALE::Exception("Not implemented for optimized sieves");
294:     };
295:     PetscErrorCode Viewer::writeElementsLocal(const Obj<Mesh>& mesh, const Obj<Builder::int_section_type>& materialField, PetscViewer viewer) {
296:       throw ALE::Exception("Not implemented for optimized sieves");
297:     };
298:     PetscErrorCode Viewer::writeTractionsLocal(const Obj<Mesh>& mesh, const Obj<Mesh>& tractionMesh, const Obj<Builder::real_section_type>& tractionField, PetscViewer viewer) {
299:       throw ALE::Exception("Not implemented for optimized sieves");
300:     };
301: #else
302:     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[]) {
303:       PetscViewer    viewer;
304:       FILE          *f;
305:       PetscInt       maxTractions = 1024, tractionCount = 0;
306:       PetscInt      *tractionVerts;
307:       PetscScalar   *tractionVals;
308:       double         scaleFactor = 1.0;
309:       char           buf[2048];
310:       PetscInt       c;
311:       PetscInt       commRank;

314:       MPI_Comm_rank(comm, &commRank);
315:       if (dim != 3) {
316:         throw ALE::Exception("PyLith only works in 3D");
317:       }
318:       if (commRank != 0) return;
319:       PetscViewerCreate(PETSC_COMM_SELF, &viewer);
320:       PetscViewerSetType(viewer, PETSC_VIEWER_ASCII);
321:       PetscViewerFileSetMode(viewer, FILE_MODE_READ);
322:       PetscExceptionTry1(PetscViewerFileSetName(viewer, filename.c_str()), PETSC_ERR_FILE_OPEN);
323:       if (PetscExceptionValue(ierr)) {
324:         // this means that a caller above me has also tryed this exception so I don't handle it here, pass it up
325:       } else if (PetscExceptionCaught(ierr,PETSC_ERR_FILE_OPEN)) {
326:         // File does not exist
327:         return;
328:       }
329:       /* Logic right now is only good for linear tets and hexes, and should be fixed in the future. */
330:       if (corners == 4) {
331:         vertsPerFace = 3;
332:       } else if (corners == 8) {
333:         vertsPerFace = 4;
334:       } else {
335:         throw ALE::Exception("Unrecognized element type");
336:       }

338:       PetscViewerASCIIGetPointer(viewer, &f);
339:       /* Ignore comments */
340:       ignoreComments(buf, 2048, f);
341:       /* Read units */
342:       const char *units = strtok(buf, " ");
343:       if (strcmp(units, "traction_units")) {
344:         throw ALE::Exception("Invalid traction units line");
345:       }
346:       units = strtok(NULL, " ");
347:       if (strcmp(units, "=")) {
348:         throw ALE::Exception("Invalid traction units line");
349:       }
350:       units = strtok(NULL, " ");
351:       if (!strcmp(units, "MPa")) {
352:         /* Should use Pythia to do units conversion */
353:         scaleFactor = 1.0e6;
354:       }
355:       /* Ignore comments */
356:       ignoreComments(buf, 2048, f);
357:       // Allocate memory.
358:       PetscMalloc2(maxTractions*vertsPerFace,PetscInt,&tractionVerts,maxTractions*dim,PetscScalar,&tractionVals);
359:       do {
360:         const char *s = strtok(buf, " ");

362:         if (tractionCount == maxTractions) {
363:           PetscInt    *titmp;
364:           PetscScalar *tvtmp;

366:           titmp = tractionVerts;
367:           tvtmp = tractionVals;
368:           PetscMalloc2(maxTractions*vertsPerFace*2,PetscInt,&tractionVerts,maxTractions*dim*2,PetscScalar,&tractionVals);
369:           PetscMemcpy(tractionVerts,  titmp, maxTractions*vertsPerFace   * sizeof(PetscInt));
370:           PetscMemcpy(tractionVals, tvtmp, maxTractions*dim * sizeof(PetscScalar));
371:           PetscFree2(titmp,tvtmp);
372:           maxTractions *= 2;
373:         }
374:         /* Get vertices */
375:         int v1 = atoi(s);
376:         if (!useZeroBase) v1 -= 1;
377:         tractionVerts[tractionCount*vertsPerFace+0] = v1;
378:         s = strtok(NULL, " ");
379:         int v2 = atoi(s);
380:         if (!useZeroBase) v2 -= 1;
381:         tractionVerts[tractionCount*vertsPerFace+1] = v2;
382:         s = strtok(NULL, " ");
383:         int v3 = atoi(s);
384:         if (!useZeroBase) v3 -= 1;
385:         tractionVerts[tractionCount*vertsPerFace+2] = v3;
386:         s = strtok(NULL, " ");
387:         if (vertsPerFace > 3) {
388:           int v4 = atoi(s);
389:           if (!useZeroBase) v4 -= 1;
390:           tractionVerts[tractionCount*vertsPerFace+3] = v4;
391:           s = strtok(NULL, " ");
392:         }
393:         /* Get traction values */
394:         for(c = 0; c < dim; c++) {
395:           tractionVals[tractionCount*dim+c] = atof(s);
396:           s = strtok(NULL, " ");
397:         }
398:         tractionCount++;
399:       } while(fgets(buf, 2048, f) != NULL);
400:       PetscViewerDestroy(viewer);
401:       numTractions      = tractionCount;
402:       *tractionVertices = tractionVerts;
403:       *tractionValues   = tractionVals;
404:     };
405:     void Builder::buildTractions(const Obj<real_section_type>& tractionField, const Obj<Mesh>& boundaryMesh, int numCells, int numTractions, int vertsPerFace, int tractionVertices[], double tractionValues[]) {
406:       real_section_type::value_type values[3];
407:       // Make boundary topology
408:       Obj<sieve_type> boundarySieve = new sieve_type(tractionField->comm(), tractionField->debug());

410:       ALE::SieveBuilder<Mesh>::buildTopology(boundarySieve, 2, numTractions, tractionVertices, 0, false, vertsPerFace, numCells);
411:       boundaryMesh->setSieve(boundarySieve);
412:       boundaryMesh->stratify();
413:       // Make traction field
414:       tractionField->setName("traction");
415:       tractionField->setFiberDimension(boundaryMesh->heightStratum(0), 3);
416:       boundaryMesh->allocate(tractionField);
417:       const Obj<Mesh::label_sequence>& faces = boundaryMesh->heightStratum(0);
418:       int k = 0;

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

423:         values[0] = tractionValues[k*3+0];
424:         values[1] = tractionValues[k*3+1];
425:         values[2] = tractionValues[k*3+2];
426:         k++;
427:         tractionField->updatePoint(face, values);
428:       }
429:     };
430:     void Builder::buildMaterials(const Obj<Mesh>& mesh, const Obj<int_section_type>& matField, const int materials[]) {
431:       const Obj<Mesh::label_sequence>& elements = mesh->heightStratum(0);

433:       matField->setName("material");
434:       matField->setFiberDimension(elements, 1);
435:       mesh->allocate(matField);
436:       for(Mesh::label_sequence::iterator e_iter = elements->begin(); e_iter != elements->end(); ++e_iter) {
437:         matField->updatePoint(*e_iter, &materials[*e_iter]);
438:       }
439:     };
440:     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) {
441:       Obj<Mesh>       mesh  = new Mesh(comm, dim, debug);
442:       Obj<sieve_type> sieve = new sieve_type(comm, debug);
443:       int    *cells, *materials;
444:       double *coordinates;
445:       int     numCells = 0, numVertices = 0, numCorners = dim+1;

447:       ALE::PyLith::Builder::readConnectivity(comm, basename+".connect", numCorners, useZeroBase, numCells, &cells, &materials);
448:       ALE::PyLith::Builder::readCoordinates(comm, basename+".coord", dim, numVertices, &coordinates);
449:       ALE::SieveBuilder<Mesh>::buildTopology(sieve, dim, numCells, cells, numVertices, interpolate, numCorners);
450:       mesh->setSieve(sieve);
451:       mesh->stratify();
452:       ALE::SieveBuilder<Mesh>::buildCoordinates(mesh, dim, coordinates);
453:       Obj<int_section_type> material = mesh->getIntSection("material");
454:       buildMaterials(mesh, material, materials);
455:       Obj<PETSC_MESH_TYPE> tractionMesh = createTraction(mesh, basename, useZeroBase);
456:       if (!tractionMesh.isNull()) {/* Have to carry tractions around somehow */}
457:       return mesh;
458:     };
459:     Obj<Builder::Mesh> Builder::createTraction(const Obj<Mesh>& mesh, const std::string& basename, const bool useZeroBase = false) {
460:       Obj<Mesh> tractionMesh = NULL;
461:       MPI_Comm comm       = mesh->comm();
462:       int      debug      = mesh->debug();
463:       int      dim        = mesh->getDimension();
464:       int      numCells   = mesh->heightStratum(0)->size();
465:       int      numCorners = mesh->getSieve()->cone(*mesh->heightStratum(0)->begin())->size();
466:       int     *tractionVertices;
467:       double  *tractionValues;
468:       int      numTractions = 0, vertsPerFace = 0, hasTractions;

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

475:         const Obj<Mesh::real_section_type>& traction = tractionMesh->getRealSection("traction");
476:         buildTractions(traction, tractionMesh, numCells, numTractions, vertsPerFace, tractionVertices, tractionValues);
477:       }
478:       return tractionMesh;
479:     };
480:     void Builder::createCohesiveElements(const Obj<Mesh>& mesh, const std::set<Mesh::point_type>& faultVertices) {
481:       typedef std::vector<Mesh::point_type> PointArray;
482:       const Obj<Mesh::sieve_type>               sieve      = mesh->getSieve();
483:       const Obj<Mesh>                           fault      = new Mesh(mesh->comm(), mesh->debug());
484:       const Obj<Mesh::sieve_type>               faultSieve = new Mesh::sieve_type(sieve->comm(), sieve->debug());
485:       const std::set<Mesh::point_type>::const_iterator fvBegin = faultVertices.begin();
486:       const std::set<Mesh::point_type>::const_iterator fvEnd   = faultVertices.end();
487:       // There should be logic here to determine this
488:       const unsigned int                        faceSize   = 3;
489:       int                                       f          = 0;
490:       int                                       debug      = mesh->debug();
491:       Obj<PointArray>                           face       = new PointArray();
492:       std::set<Mesh::point_type>                faultCells;

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

500:         if (debug) {std::cout << "Checking fault vertex " << *fv_iter << std::endl;}
501:         for(Mesh::sieve_type::traits::supportSequence::iterator c_iter = cBegin; c_iter != cEnd; ++c_iter) {
502:           if (debug) {std::cout << "  Checking cell " << *c_iter << std::endl;}
503:           if (faultCells.find(*c_iter) != faultCells.end()) continue;
504:           const Obj<Mesh::sieve_type::traits::coneSequence>& cone   = sieve->cone(*c_iter);
505:           const Mesh::sieve_type::traits::coneSequence::iterator  vBegin = cone->begin();
506:           const Mesh::sieve_type::traits::coneSequence::iterator  vEnd   = cone->end();

508:           face->clear();
509:           for(Mesh::sieve_type::traits::coneSequence::iterator v_iter = vBegin; v_iter != vEnd; ++v_iter) {
510:             if (faultVertices.find(*v_iter) != fvEnd) {
511:               if (debug) {std::cout << "    contains fault vertex " << *v_iter << std::endl;}
512:               face->insert(face->end(), *v_iter);
513:             }
514:           }
515:           if (face->size() > faceSize) throw ALE::Exception("Invalid fault mesh: Too many vertices of an element on the fault");
516:           if (face->size() == faceSize) {
517:             if (debug) {std::cout << "  Contains a face on the fault" << std::endl;}
518:             const Obj<sieve_type::supportSet> preFace = faultSieve->nJoin1(face);

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

548:       for(Mesh::label_sequence::iterator v_iter = fVertices->begin(); v_iter != fVertices->end(); ++v_iter) {
549:         if (debug) {std::cout << "Duplicating " << *v_iter << " to " << vertexRenumber[*v_iter] << std::endl;}
550:         vertexRenumber[*v_iter] = newVertex++;
551:       }
552:       // Split the mesh along the fault sieve and create cohesive elements
553:       const Obj<Mesh::label_sequence>& faces = fault->depthStratum(1);
554:       PointArray                       newVertices;

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

562:         if (debug) {std::cout << "  Replacing cell " << cell << std::endl;}
563:         newVertices.clear();
564:         for(PETSC_MESH_TYPE::sieve_type::traits::coneSequence::iterator v_iter = cone->begin(); v_iter != cone->end(); ++v_iter) {
565:           if (vertexRenumber.find(*v_iter) != vertexRenumber.end()) {
566:             if (debug) {std::cout << "    vertex " << vertexRenumber[*v_iter] << std::endl;}
567:             newVertices.insert(newVertices.end(), vertexRenumber[*v_iter]);
568:           } else {
569:             if (debug) {std::cout << "    vertex " << *v_iter << std::endl;}
570:             newVertices.insert(newVertices.end(), *v_iter);
571:           }
572:         }
573:         sieve->clearCone(cell);
574:         int color = 0;
575:         for(PointArray::const_iterator v_iter = newVertices.begin(); v_iter != newVertices.end(); ++v_iter) {
576:           sieve->addArrow(*v_iter, cell, color++);
577:         }
578:       }
579:       // Fix coordinates
580:       const Obj<Mesh::real_section_type>& coordinates = mesh->getRealSection("coordinates");
581:       const Obj<Mesh::label_sequence>&    fVertices2  = fault->depthStratum(0);

583:       for(Mesh::label_sequence::iterator v_iter = fVertices2->begin(); v_iter != fVertices2->end(); ++v_iter) {
584:         coordinates->addPoint(vertexRenumber[*v_iter], coordinates->getFiberDimension(*v_iter));
585:       }
586:       mesh->reallocate(coordinates);
587:       for(Mesh::label_sequence::iterator v_iter = fVertices2->begin(); v_iter != fVertices2->end(); ++v_iter) {
588:         coordinates->updatePoint(vertexRenumber[*v_iter], coordinates->restrictPoint(*v_iter));
589:       }
590:     };
591:     //
592:     // Viewer methods
593:     //
596:     PetscErrorCode Viewer::writeVertices(const Obj<Mesh>& mesh, PetscViewer viewer) {
597:       Obj<Builder::real_section_type> coordinates  = mesh->getRealSection("coordinates");
598:       //Mesh::section_type::patch_type patch;
599:       //const double  *array = coordinates->restrict(Mesh::section_type::patch_type());
600:       //int            dim = mesh->getDimension();
601:       //int            numVertices;

605: #if 0
606:       //FIX:
607:       if (vertexBundle->getGlobalOffsets()) {
608:         numVertices = vertexBundle->getGlobalOffsets()[mesh->commSize()];
609:       } else {
610:         numVertices = mesh->getTopology()->depthStratum(0)->size();
611:       }
612:       PetscViewerASCIIPrintf(viewer,"#\n");
613:       PetscViewerASCIIPrintf(viewer,"coord_units = m\n");
614:       PetscViewerASCIIPrintf(viewer,"#\n");
615:       PetscViewerASCIIPrintf(viewer,"#\n");
616:       PetscViewerASCIIPrintf(viewer,"#  Node      X-coord           Y-coord           Z-coord\n");
617:       PetscViewerASCIIPrintf(viewer,"#\n");
618:       if (mesh->commRank() == 0) {
619:         int numLocalVertices = mesh->getTopology()->depthStratum(0)->size();
620:         int vertexCount = 1;

622:         for(int v = 0; v < numLocalVertices; v++) {
623:           PetscViewerASCIIPrintf(viewer,"%7D ", vertexCount++);
624:           for(int d = 0; d < dim; d++) {
625:             if (d > 0) {
626:               PetscViewerASCIIPrintf(viewer," ");
627:             }
628:             PetscViewerASCIIPrintf(viewer,"% 16.8E", array[v*dim+d]);
629:           }
630:           PetscViewerASCIIPrintf(viewer,"\n");
631:         }
632:         for(int p = 1; p < mesh->commSize(); p++) {
633:           double    *remoteCoords;
634:           MPI_Status status;

636:           MPI_Recv(&numLocalVertices, 1, MPI_INT, p, 1, mesh->comm(), &status);
637:           PetscMalloc(numLocalVertices*dim * sizeof(double), &remoteCoords);
638:           MPI_Recv(remoteCoords, numLocalVertices*dim, MPI_DOUBLE, p, 1, mesh->comm(), &status);
639:           for(int v = 0; v < numLocalVertices; v++) {
640:             PetscViewerASCIIPrintf(viewer,"%7D   ", vertexCount++);
641:             for(int d = 0; d < dim; d++) {
642:               if (d > 0) {
643:                 PetscViewerASCIIPrintf(viewer, " ");
644:               }
645:               PetscViewerASCIIPrintf(viewer, "% 16.8E", remoteCoords[v*dim+d]);
646:             }
647:             PetscViewerASCIIPrintf(viewer, "\n");
648:           }
649:         }
650:       } else {
651:         Obj<Mesh::bundle_type> globalOrder = coordinates->getGlobalOrder();
652:         Obj<Mesh::field_type::order_type::coneSequence> cone = globalOrder->getPatch(patch);
653:         const int *offsets = coordinates->getGlobalOffsets();
654:         int        numLocalVertices = (offsets[mesh->commRank()+1] - offsets[mesh->commRank()])/dim;
655:         double    *localCoords;
656:         int        k = 0;

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

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

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

698:       if (dim != 3) {
699:         SETERRQ(PETSC_ERR_SUP, "PyLith only supports 3D meshes.");
700:       }
701:       if (corners == 4) {
702:         // Linear tetrahedron
703:         elementType = 5;
704:       } else if (corners == 8) {
705:         // Linear hexahedron
706:         elementType = 1;
707:       } else {
708:         SETERRQ1(PETSC_ERR_SUP, "PyLith Error: Unsupported number of elements vertices: %d", corners);
709:       }
710:       PetscViewerASCIIPrintf(viewer,"#\n");
711:       PetscViewerASCIIPrintf(viewer,"#     N ETP MAT INF     N1     N2     N3     N4     N5     N6     N7     N8\n");
712:       PetscViewerASCIIPrintf(viewer,"#\n");
713:       if (mesh->commRank() == 0) {
714:         int elementCount = 1;

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

719:           PetscViewerASCIIPrintf(viewer, "%7d %3d", elementCount++, elementType);
720:           if (hasMaterial) {
721:             // No infinite elements
722:             PetscViewerASCIIPrintf(viewer, " %3d %3d", (int) materialField->restrict(patch, *e_itor)[0], 0);
723:           } else {
724:             // No infinite elements
725:             PetscViewerASCIIPrintf(viewer, " %3d %3d", 1, 0);
726:           }
727:           for(Mesh::bundle_type::order_type::coneSequence::iterator c_itor = cone->begin(); c_itor != cone->end(); ++c_itor) {
728:             PetscViewerASCIIPrintf(viewer, " %6d", globalVertex->getIndex(patch, *c_itor).prefix+1);
729:           }
730:           PetscViewerASCIIPrintf(viewer, "\n");
731:         }
732:         for(int p = 1; p < mesh->commSize(); p++) {
733:           int         numLocalElements;
734:           int        *remoteVertices;
735:           MPI_Status  status;

737:           MPI_Recv(&numLocalElements, 1, MPI_INT, p, 1, mesh->comm(), &status);
738:           PetscMalloc(numLocalElements*(corners+1) * sizeof(int), &remoteVertices);
739:           MPI_Recv(remoteVertices, numLocalElements*(corners+1), MPI_INT, p, 1, mesh->comm(), &status);
740:           for(int e = 0; e < numLocalElements; e++) {
741:             // Only linear tetrahedra, material, no infinite elements
742:             int mat = remoteVertices[e*(corners+1)+corners];

744:             PetscViewerASCIIPrintf(viewer, "%7d %3d %3d %3d", elementCount++, elementType, mat, 0);
745:             for(int c = 0; c < corners; c++) {
746:               PetscViewerASCIIPrintf(viewer, " %6d", remoteVertices[e*(corners+1)+c]);
747:             }
748:             PetscViewerASCIIPrintf(viewer, "\n");
749:           }
750:           PetscFree(remoteVertices);
751:         }
752:       } else {
753:         const int *offsets = elementBundle->getGlobalOffsets();
754:         int        numLocalElements = offsets[mesh->commRank()+1] - offsets[mesh->commRank()];
755:         int       *localVertices;
756:         int        k = 0;

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

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

793:       PetscViewerASCIIPrintf(viewer,"#\n");
794:       PetscViewerASCIIPrintf(viewer,"coord_units = m\n");
795:       PetscViewerASCIIPrintf(viewer,"#\n");
796:       PetscViewerASCIIPrintf(viewer,"#\n");
797:       PetscViewerASCIIPrintf(viewer,"#  Node      X-coord           Y-coord           Z-coord\n");
798:       PetscViewerASCIIPrintf(viewer,"#\n");

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

803:         PetscViewerASCIIPrintf(viewer, "%7D ", vNumbering->getIndex(*v_iter)+1);
804:         for(int d = 0; d < embedDim; d++) {
805:           if (d > 0) {
806:             PetscViewerASCIIPrintf(viewer, " ");
807:           }
808:           PetscViewerASCIIPrintf(viewer, "% 16.8E", array[d]);
809:         }
810:         PetscViewerASCIIPrintf(viewer, "\n");
811:       }
812:       return(0);
813:     };
816:     PetscErrorCode Viewer::writeElementsLocal(const Obj<Mesh>& mesh, const Obj<Builder::int_section_type>& materialField, PetscViewer viewer) {
817:       const Obj<Mesh::sieve_type>&     sieve      = mesh->getSieve();
818:       const Obj<Mesh::label_sequence>& elements   = mesh->heightStratum(0);
819:       const Obj<Mesh::numbering_type>& eNumbering = mesh->getFactory()->getLocalNumbering(mesh, mesh->depth());
820:       const Obj<Mesh::numbering_type>& vNumbering = mesh->getFactory()->getLocalNumbering(mesh, 0);
821:       int            dim          = mesh->getDimension();
822:       //int            corners      = sieve->nCone(*elements->begin(), topology->depth())->size();
823:       int            corners      = sieve->cone(*elements->begin())->size();
824:       bool           hasMaterial  = !materialField.isNull();
825:       int            elementType  = -1;

829:       if (dim != 3) {
830:         SETERRQ(PETSC_ERR_SUP, "PyLith only supports 3D meshes.");
831:       }
832:       if (corners == 4) {
833:         // Linear tetrahedron
834:         elementType = 5;
835:       } else if (corners == 8) {
836:         // Linear hexahedron
837:         elementType = 1;
838:       } else {
839:         SETERRQ1(PETSC_ERR_SUP, "PyLith Error: Unsupported number of elements vertices: %d", corners);
840:       }
841:       PetscViewerASCIIPrintf(viewer,"#\n");
842:       PetscViewerASCIIPrintf(viewer,"#     N ETP MAT INF     N1     N2     N3     N4     N5     N6     N7     N8\n");
843:       PetscViewerASCIIPrintf(viewer,"#\n");
844:       for(Mesh::label_sequence::iterator e_iter = elements->begin(); e_iter != elements->end(); ++e_iter) {
845:         const Obj<Mesh::sieve_type::traits::coneSequence> cone  = sieve->cone(*e_iter);
846:         Mesh::sieve_type::traits::coneSequence::iterator  begin = cone->begin();
847:         Mesh::sieve_type::traits::coneSequence::iterator  end   = cone->end();

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

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

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

885:         for(int i = 0; i < size; i++) {
886:           const Builder::pair_section_type::point_type& v     = values[i].first;
887:           const PETSC_MESH_TYPE::base_type::split_value&      split = values[i].second;

889:           // No time history
890:           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);
891:         }
892:       }
893:       return(0);
894:     };
895: #endif
898:     PetscErrorCode Viewer::writeTractionsLocal(const Obj<Mesh>& mesh, const Obj<Mesh>& tractionMesh, const Obj<Builder::real_section_type>& tractionField, PetscViewer viewer) {
899:       const Obj<Mesh::sieve_type>&     sieve = tractionMesh->getSieve();
900:       const Obj<Mesh::label_sequence>& faces = tractionMesh->heightStratum(0);
901:       const Obj<Mesh::numbering_type>& vNumbering = mesh->getFactory()->getLocalNumbering(mesh, 0);

905:       PetscViewerASCIIPrintf(viewer,"#\n");
906:       PetscViewerASCIIPrintf(viewer,"traction_units = Pa\n");
907:       PetscViewerASCIIPrintf(viewer,"#\n");
908:       PetscViewerASCIIPrintf(viewer,"#\n");
909:       for(Mesh::label_sequence::iterator f_iter = faces->begin(); f_iter != faces->end(); ++f_iter) {
910:         const Mesh::point_type& face = *f_iter;
911:         const Obj<Mesh::sieve_type::traits::coneSequence>& cone = sieve->cone(face);

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

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

921:         for(int i = 0; i < mesh->getDimension(); ++i) {
922:           if (i > 0) {
923:             PetscViewerASCIIPrintf(viewer, " ");
924:             std::cout << " ";
925:           }
926:           PetscViewerASCIIPrintf(viewer, "%15.9g", values[i]);
927:           std::cout << values[i];
928:         }
929:         PetscViewerASCIIPrintf(viewer,"\n");
930:         std::cout << std::endl;
931:       }
932:       return(0);
933:     };
934: #endif
935:   };
936: };