Actual source code: Field.hh

  1: #ifndef included_ALE_Field_hh
  2: #define included_ALE_Field_hh

  4: #ifndef  included_ALE_SieveAlgorithms_hh
  5: #include <SieveAlgorithms.hh>
  6: #endif


 10: // Sieve need point_type
 11: // Section need point_type and value_type
 12: //   size(), restrict(), update() need orientation which is a Bundle (circular)
 13: // Bundle is Sieve+Section

 15: // An AbstractSection is a mapping from Sieve points to sets of values
 16: //   This is our presentation of a section of a fibre bundle,
 17: //     in which the Topology is the base space, and
 18: //     the value sets are vectors in the fiber spaces
 19: //   The main interface to values is through restrict() and update()
 20: //     This retrieval uses Sieve closure()
 21: //     We should call these rawRestrict/rawUpdate
 22: //   The Section must also be able to set/report the dimension of each fiber
 23: //     for which we use another section we call an \emph{Atlas}
 24: //     For some storage schemes, we also want offsets to go with these dimensions
 25: //   We must have some way of limiting the points associated with values
 26: //     so each section must support a getPatch() call returning the points with associated fibers
 27: //     I was using the Chart for this
 28: //   The Section must be able to participate in \emph{completion}
 29: //     This means restrict to a provided overlap, and exchange in the restricted sections
 30: //     Completion does not use hierarchy, so we see the Topology as a DiscreteTopology
 31: namespace ALE {
 32:   template<typename Point_>
 33:   class DiscreteSieve {
 34:   public:
 35:     typedef Point_                  point_type;
 36:     typedef std::vector<point_type> coneSequence;
 37:     typedef std::vector<point_type> coneSet;
 38:     typedef std::vector<point_type> coneArray;
 39:     typedef std::vector<point_type> supportSequence;
 40:     typedef std::vector<point_type> supportSet;
 41:     typedef std::vector<point_type> supportArray;
 42:     typedef std::set<point_type>    points_type;
 43:     typedef points_type             baseSequence;
 44:     typedef points_type             capSequence;
 45:   protected:
 46:     Obj<points_type>  _points;
 47:     Obj<coneSequence> _empty;
 48:     Obj<coneSequence> _return;
 49:     void _init() {
 50:       this->_points = new points_type();
 51:       this->_empty  = new coneSequence();
 52:       this->_return = new coneSequence();
 53:     };
 54:   public:
 55:     DiscreteSieve() {
 56:       this->_init();
 57:     };
 58:     template<typename Input>
 59:     DiscreteSieve(const Obj<Input>& points) {
 60:       this->_init();
 61:       this->_points->insert(points->begin(), points->end());
 62:     };
 63:     virtual ~DiscreteSieve() {};
 64:   public:
 65:     void addPoint(const point_type& point) {
 66:       this->_points->insert(point);
 67:     };
 68:     template<typename Input>
 69:     void addPoints(const Obj<Input>& points) {
 70:       this->_points->insert(points->begin(), points->end());
 71:     };
 72:     const Obj<coneSequence>& cone(const point_type& p) {return this->_empty;};
 73:     template<typename Input>
 74:     const Obj<coneSequence>& cone(const Input& p) {return this->_empty;};
 75:     const Obj<coneSet>& nCone(const point_type& p, const int level) {
 76:       if (level == 0) {
 77:         return this->closure(p);
 78:       } else {
 79:         return this->_empty;
 80:       }
 81:     };
 82:     const Obj<coneArray>& closure(const point_type& p) {
 83:       this->_return->clear();
 84:       this->_return->push_back(p);
 85:       return this->_return;
 86:     };
 87:     const Obj<supportSequence>& support(const point_type& p) {return this->_empty;};
 88:     template<typename Input>
 89:     const Obj<supportSequence>& support(const Input& p) {return this->_empty;};
 90:     const Obj<supportSet>& nSupport(const point_type& p, const int level) {
 91:       if (level == 0) {
 92:         return this->star(p);
 93:       } else {
 94:         return this->_empty;
 95:       }
 96:     };
 97:     const Obj<supportArray>& star(const point_type& p) {
 98:       this->_return->clear();
 99:       this->_return->push_back(p);
100:       return this->_return;
101:     };
102:     const Obj<capSequence>& roots() {return this->_points;};
103:     const Obj<capSequence>& cap() {return this->_points;};
104:     const Obj<baseSequence>& leaves() {return this->_points;};
105:     const Obj<baseSequence>& base() {return this->_points;};
106:     template<typename Color>
107:     void addArrow(const point_type& p, const point_type& q, const Color& color) {
108:       throw ALE::Exception("Cannot add an arrow to a DiscreteSieve");
109:     };
110:     void stratify() {};
111:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
112:       ostringstream txt;
113:       int rank;

115:       if (comm == MPI_COMM_NULL) {
116:         comm = MPI_COMM_SELF;
117:         rank = 0;
118:       } else {
119:         MPI_Comm_rank(comm, &rank);
120:       }
121:       if (name == "") {
122:         if(rank == 0) {
123:           txt << "viewing a DiscreteSieve" << std::endl;
124:         }
125:       } else {
126:         if(rank == 0) {
127:           txt << "viewing DiscreteSieve '" << name << "'" << std::endl;
128:         }
129:       }
130:       for(typename points_type::const_iterator p_iter = this->_points->begin(); p_iter != this->_points->end(); ++p_iter) {
131:         txt << "  Point " << *p_iter << std::endl;
132:       }
133:       PetscSynchronizedPrintf(comm, txt.str().c_str());
134:       PetscSynchronizedFlush(comm);
135:     };
136:   };
137:   // A ConstantSection is the simplest Section
138:   //   All fibers are dimension 1
139:   //   All values are equal to a constant
140:   //     We need no value storage and no communication for completion
141:   template<typename Point_, typename Value_>
142:   class ConstantSection : public ALE::ParallelObject {
143:   public:
144:     typedef Point_               point_type;
145:     typedef std::set<point_type> chart_type;
146:     typedef Value_               value_type;
147:   protected:
148:     chart_type _chart;
149:     value_type _value;
150:     value_type _defaultValue;
151:   public:
152:     ConstantSection(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug), _defaultValue(0) {};
153:     ConstantSection(MPI_Comm comm, const value_type& value, const int debug) : ParallelObject(comm, debug), _value(value), _defaultValue(value) {};
154:     ConstantSection(MPI_Comm comm, const value_type& value, const value_type& defaultValue, const int debug) : ParallelObject(comm, debug), _value(value), _defaultValue(defaultValue) {};
155:   public: // Verifiers
156:     void checkPoint(const point_type& point) const {
157:       if (this->_chart.find(point) == this->_chart.end()) {
158:         ostringstream msg;
159:         msg << "Invalid section point " << point << std::endl;
160:         throw ALE::Exception(msg.str().c_str());
161:       }
162:     };
163:     void checkDimension(const int& dim) {
164:       if (dim != 1) {
165:         ostringstream msg;
166:         msg << "Invalid fiber dimension " << dim << " must be 1" << std::endl;
167:         throw ALE::Exception(msg.str().c_str());
168:       }
169:     };
170:     bool hasPoint(const point_type& point) const {
171:       return this->_chart.count(point) > 0;
172:     };
173:   public: // Accessors
174:     const chart_type& getChart() {return this->_chart;};
175:     void addPoint(const point_type& point) {
176:       this->_chart.insert(point);
177:     };
178:     template<typename Points>
179:     void addPoint(const Obj<Points>& points) {
180:       this->_chart.insert(points->begin(), points->end());
181:     };
182:     void addPoint(const std::set<point_type>& points) {
183:       this->_chart.insert(points.begin(), points.end());
184:     };
185:     value_type getDefaultValue() {return this->_defaultValue;};
186:     void setDefaultValue(const value_type value) {this->_defaultValue = value;};
187:     void copy(const Obj<ConstantSection>& section) {
188:       const chart_type& chart = section->getChart();

190:       this->addPoint(chart);
191:       this->_value = section->restrict(*chart.begin())[0];
192:     };
193:   public: // Sizes
194:     void clear() {
195:       this->_chart.clear();
196:     };
197:     int getFiberDimension(const point_type& p) const {
198:       if (this->hasPoint(p)) return 1;
199:       return 0;
200:     };
201:     void setFiberDimension(const point_type& p, int dim) {
202:       this->checkDimension(dim);
203:       this->addPoint(p);
204:     };
205:     template<typename Sequence>
206:     void setFiberDimension(const Obj<Sequence>& points, int dim) {
207:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
208:         this->setFiberDimension(*p_iter, dim);
209:       }
210:     };
211:     void addFiberDimension(const point_type& p, int dim) {
212:       if (this->_chart.find(p) != this->_chart.end()) {
213:         ostringstream msg;
214:         msg << "Invalid addition to fiber dimension " << dim << " cannot exceed 1" << std::endl;
215:         throw ALE::Exception(msg.str().c_str());
216:       } else {
217:         this->setFiberDimension(p, dim);
218:       }
219:     };
220:     int size() {return this->_sheaf.size();};
221:     int size(const point_type& p) {return this->getFiberDimension(p);};
222:   public: // Restriction
223:     const value_type *restrict(const point_type& p) const {
224:       if (this->hasPoint(p)) {
225:         return &this->_value;
226:       }
227:       return &this->_defaultValue;
228:     };
229:     const value_type *restrictPoint(const point_type& p) const {return this->restrict(p);};
230:     void update(const point_type& p, const value_type v[]) {
231:       this->_value = v[0];
232:     };
233:     void updatePoint(const point_type& p, const value_type v[]) {return this->update(p, v);};
234:     void updateAdd(const point_type& p, const value_type v[]) {
235:       this->_value += v[0];
236:     };
237:     void updateAddPoint(const point_type& p, const value_type v[]) {return this->updateAdd(p, v);};
238:   public:
239:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
240:       ostringstream txt;
241:       int rank;

243:       if (comm == MPI_COMM_NULL) {
244:         comm = this->comm();
245:         rank = this->commRank();
246:       } else {
247:         MPI_Comm_rank(comm, &rank);
248:       }
249:       if (name == "") {
250:         if(rank == 0) {
251:           txt << "viewing a ConstantSection" << std::endl;
252:         }
253:       } else {
254:         if(rank == 0) {
255:           txt << "viewing ConstantSection '" << name << "'" << std::endl;
256:         }
257:       }
258:       txt <<"["<<this->commRank()<<"]: Value " << this->_value << std::endl;
259:       PetscSynchronizedPrintf(comm, txt.str().c_str());
260:       PetscSynchronizedFlush(comm);
261:     };
262:   };

264:   // A UniformSection often acts as an Atlas
265:   //   All fibers are the same dimension
266:   //     Note we can use a ConstantSection for this Atlas
267:   //   Each point may have a different vector
268:   //     Thus we need storage for values, and hence must implement completion
269:   template<typename Point_, typename Value_, int fiberDim = 1>
270:   class UniformSection : public ALE::ParallelObject {
271:   public:
272:     typedef Point_                           point_type;
273:     typedef ConstantSection<point_type, int> atlas_type;
274:     typedef typename atlas_type::chart_type  chart_type;
275:     typedef Value_                           value_type;
276:     typedef struct {value_type v[fiberDim];} fiber_type;
277:     typedef std::map<point_type, fiber_type> values_type;
278:   protected:
279:     Obj<atlas_type> _atlas;
280:     values_type     _array;
281:     fiber_type      _emptyValue;
282:   public:
283:     UniformSection(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {
284:       this->_atlas = new atlas_type(comm, fiberDim, 0, debug);
285:       for(int i = 0; i < fiberDim; ++i) this->_emptyValue.v[i] = value_type();
286:     };
287:     UniformSection(const Obj<atlas_type>& atlas) : ParallelObject(atlas->comm(), atlas->debug()), _atlas(atlas) {
288:       int dim = fiberDim;
289:       this->_atlas->update(*this->_atlas->getChart().begin(), &dim);
290:       for(int i = 0; i < fiberDim; ++i) this->_emptyValue.v[i] = value_type();
291:     };
292:     virtual ~UniformSection() {
293:       this->_atlas = NULL;
294:     };
295:   public:
296:     value_type *getRawArray(const int size) {
297:       static value_type *array   = NULL;
298:       static int         maxSize = 0;

300:       if (size > maxSize) {
301:         maxSize = size;
302:         if (array) delete [] array;
303:         array = new value_type[maxSize];
304:       };
305:       return array;
306:     };
307:   public: // Verifiers
308:     bool hasPoint(const point_type& point) {
309:       return this->_atlas->hasPoint(point);
310:     };
311:     void checkDimension(const int& dim) {
312:       if (dim != fiberDim) {
313:         ostringstream msg;
314:         msg << "Invalid fiber dimension " << dim << " must be " << fiberDim << std::endl;
315:         throw ALE::Exception(msg.str().c_str());
316:       }
317:     };
318:   public: // Accessors
319:     const chart_type& getChart() {return this->_atlas->getChart();};
320:     const Obj<atlas_type>& getAtlas() {return this->_atlas;};
321:     void setAtlas(const Obj<atlas_type>& atlas) {this->_atlas = atlas;};
322:     void addPoint(const point_type& point) {
323:       this->setFiberDimension(point, fiberDim);
324:     };
325:     template<typename Points>
326:     void addPoint(const Obj<Points>& points) {
327:       for(typename Points::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
328:         this->setFiberDimension(*p_iter, fiberDim);
329:       }
330:     };
331:     void copy(const Obj<UniformSection>& section) {
332:       this->getAtlas()->copy(section->getAtlas());
333:       const chart_type& chart = section->getChart();

335:       for(typename chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
336:         this->updatePoint(*c_iter, section->restrictPoint(*c_iter));
337:       }
338:     };
339:   public: // Sizes
340:     void clear() {
341:       this->_atlas->clear();
342:       this->_array.clear();
343:     };
344:     int getFiberDimension(const point_type& p) const {
345:       return this->_atlas->restrictPoint(p)[0];
346:     };
347:     void setFiberDimension(const point_type& p, int dim) {
348:       this->checkDimension(dim);
349:       this->_atlas->addPoint(p);
350:       this->_atlas->updatePoint(p, &dim);
351:     };
352:     template<typename Sequence>
353:     void setFiberDimension(const Obj<Sequence>& points, int dim) {
354:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
355:         this->setFiberDimension(*p_iter, dim);
356:       }
357:     };
358:     void setFiberDimension(const std::set<point_type>& points, int dim) {
359:       for(typename std::set<point_type>::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
360:         this->setFiberDimension(*p_iter, dim);
361:       }
362:     };
363:     void addFiberDimension(const point_type& p, int dim) {
364:       if (this->hasPoint(p)) {
365:         ostringstream msg;
366:         msg << "Invalid addition to fiber dimension " << dim << " cannot exceed " << fiberDim << std::endl;
367:         throw ALE::Exception(msg.str().c_str());
368:       } else {
369:         this->setFiberDimension(p, dim);
370:       }
371:     };
372:     int size() const {
373:       const chart_type& points = this->_atlas->getChart();
374:       int               size   = 0;

376:       for(typename chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
377:         size += this->getFiberDimension(*p_iter);
378:       }
379:       return size;
380:     };
381:     int sizeWithBC() const {
382:       return this->size();
383:     };
384:   public: // Restriction
385:     // Return a pointer to the entire contiguous storage array
386:     const values_type& restrict() {
387:       return this->_array;
388:     };
389:     // Return only the values associated to this point, not its closure
390:     const value_type *restrictPoint(const point_type& p) {
391:       if (this->_array.find(p) == this->_array.end()) return this->_emptyValue.v;
392:       return this->_array[p].v;
393:     };
394:     // Update only the values associated to this point, not its closure
395:     void updatePoint(const point_type& p, const value_type v[]) {
396:       for(int i = 0; i < fiberDim; ++i) {
397:         this->_array[p].v[i] = v[i];
398:       }
399:     };
400:     // Update only the values associated to this point, not its closure
401:     void updateAddPoint(const point_type& p, const value_type v[]) {
402:       for(int i = 0; i < fiberDim; ++i) {
403:         this->_array[p].v[i] += v[i];
404:       }
405:     };
406:     void updatePointAll(const point_type& p, const value_type v[]) {
407:       this->updatePoint(p, v);
408:     };
409:   public:
410:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) {
411:       ostringstream txt;
412:       int rank;

414:       if (comm == MPI_COMM_NULL) {
415:         comm = this->comm();
416:         rank = this->commRank();
417:       } else {
418:         MPI_Comm_rank(comm, &rank);
419:       }
420:       if (name == "") {
421:         if(rank == 0) {
422:           txt << "viewing a UniformSection" << std::endl;
423:         }
424:       } else {
425:         if(rank == 0) {
426:           txt << "viewing UniformSection '" << name << "'" << std::endl;
427:         }
428:       }
429:       const typename atlas_type::chart_type& chart = this->_atlas->getChart();
430:       values_type&                           array = this->_array;

432:       for(typename atlas_type::chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
433:         const point_type&                     point = *p_iter;
434:         const typename atlas_type::value_type dim   = this->_atlas->restrict(point)[0];

436:         if (dim != 0) {
437:           txt << "[" << this->commRank() << "]:   " << point << " dim " << dim << "  ";
438:           for(int i = 0; i < dim; i++) {
439:             txt << " " << array[point].v[i];
440:           }
441:           txt << std::endl;
442:         }
443:       }
444:       if (chart.size() == 0) {
445:         txt << "[" << this->commRank() << "]: empty" << std::endl;
446:       }
447:       PetscSynchronizedPrintf(comm, txt.str().c_str());
448:       PetscSynchronizedFlush(comm);
449:     };
450:   };
451:   // A Section is our most general construct (more general ones could be envisioned)
452:   //   The Atlas is a UniformSection of dimension 1 and value type Point
453:   //     to hold each fiber dimension and offsets into a contiguous patch array
454:   template<typename Point_, typename Value_>
455:   class Section : public ALE::ParallelObject {
456:   public:
457:     typedef Point_                                 point_type;
458:     typedef ALE::Point                             index_type;
459:     typedef UniformSection<point_type, index_type> atlas_type;
460:     typedef typename atlas_type::chart_type        chart_type;
461:     typedef Value_                                 value_type;
462:     typedef value_type *                           values_type;
463:   protected:
464:     Obj<atlas_type> _atlas;
465:     Obj<atlas_type> _atlasNew;
466:     values_type     _array;
467:   public:
468:     Section(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {
469:       this->_atlas    = new atlas_type(comm, debug);
470:       this->_atlasNew = NULL;
471:       this->_array    = NULL;
472:     };
473:     Section(const Obj<atlas_type>& atlas) : ParallelObject(atlas->comm(), atlas->debug()), _atlas(atlas), _atlasNew(NULL), _array(NULL) {};
474:     virtual ~Section() {
475:       if (this->_array) {
476:         delete [] this->_array;
477:         this->_array = NULL;
478:       }
479:     };
480:   public:
481:     value_type *getRawArray(const int size) {
482:       static value_type *array   = NULL;
483:       static int         maxSize = 0;

485:       if (size > maxSize) {
486:         maxSize = size;
487:         if (array) delete [] array;
488:         array = new value_type[maxSize];
489:       };
490:       return array;
491:     };
492:     int getStorageSize() const {
493:       return this->sizeWithBC();
494:     };
495:   public: // Verifiers
496:     bool hasPoint(const point_type& point) {
497:       return this->_atlas->hasPoint(point);
498:     };
499:   public: // Accessors
500:     const Obj<atlas_type>& getAtlas() {return this->_atlas;};
501:     void setAtlas(const Obj<atlas_type>& atlas) {this->_atlas = atlas;};
502:     const Obj<atlas_type>& getNewAtlas() {return this->_atlasNew;};
503:     void setNewAtlas(const Obj<atlas_type>& atlas) {this->_atlasNew = atlas;};
504:     const chart_type& getChart() const {return this->_atlas->getChart();};
505:   public: // BC
506:     // Returns the number of constraints on a point
507:     const int getConstraintDimension(const point_type& p) const {
508:       return std::max(0, -this->_atlas->restrictPoint(p)->prefix);
509:     };
510:     // Set the number of constraints on a point
511:     //   We only allow the entire point to be constrained, so these will be the
512:     //   only dofs on the point
513:     void setConstraintDimension(const point_type& p, const int numConstraints) {
514:       this->setFiberDimension(p, -numConstraints);
515:     };
516:     void addConstraintDimension(const point_type& p, const int numConstraints) {
517:       throw ALE::Exception("Variable constraint dimensions not available for this Section type");
518:     };
519:     void copyBC(const Obj<Section>& section) {
520:       const chart_type& chart = this->getChart();

522:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
523:         if (this->getConstraintDimension(*p_iter)) {
524:           this->updatePointBC(*p_iter, section->restrictPoint(*p_iter));
525:         }
526:       }
527:     };
528:     void defaultConstraintDof() {};
529:   public: // Sizes
530:     void clear() {
531:       this->_atlas->clear();
532:       delete [] this->_array;
533:       this->_array = NULL;
534:     };
535:     // Return the total number of dofs on the point (free and constrained)
536:     int getFiberDimension(const point_type& p) const {
537:       return std::abs(this->_atlas->restrictPoint(p)->prefix);
538:     };
539:     int getFiberDimension(const Obj<atlas_type>& atlas, const point_type& p) const {
540:       return std::abs(atlas->restrictPoint(p)->prefix);
541:     };
542:     // Set the total number of dofs on the point (free and constrained)
543:     void setFiberDimension(const point_type& p, int dim) {
544:       const index_type idx(dim, -1);
545:       this->_atlas->addPoint(p);
546:       this->_atlas->updatePoint(p, &idx);
547:     };
548:     template<typename Sequence>
549:     void setFiberDimension(const Obj<Sequence>& points, int dim) {
550:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
551:         this->setFiberDimension(*p_iter, dim);
552:       }
553:     };
554:     void addFiberDimension(const point_type& p, int dim) {
555:       if (this->_atlas->hasPoint(p)) {
556:         const index_type values(dim, 0);
557:         this->_atlas->updateAddPoint(p, &values);
558:       } else {
559:         this->setFiberDimension(p, dim);
560:       }
561:     };
562:     // Return the number of constrained dofs on this point
563:     //   If constrained, this is equal to the fiber dimension
564:     //   Otherwise, 0
565:     int getConstrainedFiberDimension(const point_type& p) const {
566:       return std::max(0, this->_atlas->restrictPoint(p)->prefix);
567:     };
568:     // Return the total number of free dofs
569:     int size() const {
570:       const chart_type& points = this->getChart();
571:       int size = 0;

573:       for(typename chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
574:         size += this->getConstrainedFiberDimension(*p_iter);
575:       }
576:       return size;
577:     };
578:     // Return the total number of dofs (free and constrained)
579:     int sizeWithBC() const {
580:       const chart_type& points = this->getChart();
581:       int size = 0;

583:       for(typename chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
584:         size += this->getFiberDimension(*p_iter);
585:       }
586:       return size;
587:     };
588:   public: // Index retrieval
589:     const typename index_type::index_type& getIndex(const point_type& p) {
590:       return this->_atlas->restrictPoint(p)->index;
591:     };
592:     void setIndex(const point_type& p, const typename index_type::index_type& index) {
593:       ((typename atlas_type::value_type *) this->_atlas->restrictPoint(p))->index = index;
594:     };
595:     void setIndexBC(const point_type& p, const typename index_type::index_type& index) {
596:       this->setIndex(p, index);
597:     };
598:     void getIndices(const point_type& p, PetscInt indices[], PetscInt *indx, const int orientation = 1, const bool freeOnly = false, const bool skipConstraints = false) {
599:       this->getIndices(p, this->getIndex(p), indices, indx, orientation, freeOnly, skipConstraints);
600:     };
601:     template<typename Order_>
602:     void getIndices(const point_type& p, const Obj<Order_>& order, PetscInt indices[], PetscInt *indx, const int orientation = 1, const bool freeOnly = false, const bool skipConstraints = false) {
603:       this->getIndices(p, order->getIndex(p), indices, indx, orientation, freeOnly, skipConstraints);
604:     };
605:     void getIndices(const point_type& p, const int start, PetscInt indices[], PetscInt *indx, const int orientation = 1, const bool freeOnly = false, const bool skipConstraints = false) {
606:       const int& dim   = this->getFiberDimension(p);
607:       const int& cDim  = this->getConstraintDimension(p);
608:       const int  end   = start + dim;

610:       if (!cDim) {
611:         if (orientation >= 0) {
612:           for(int i = start; i < end; ++i) {
613:             indices[(*indx)++] = i;
614:           }
615:         } else {
616:           for(int i = end-1; i >= start; --i) {
617:             indices[(*indx)++] = i;
618:           }
619:         }
620:       } else {
621:         if (!freeOnly) {
622:           for(int i = start; i < end; ++i) {
623:             indices[(*indx)++] = -1;
624:           }
625:         }
626:       }
627:     };
628:   public: // Allocation
629:     void allocateStorage() {
630:       const int totalSize = this->sizeWithBC();

632:       this->_array = new value_type[totalSize];
633:       PetscMemzero(this->_array, totalSize * sizeof(value_type));
634:     };
635:     void replaceStorage(value_type *newArray) {
636:       delete [] this->_array;
637:       this->_array    = newArray;
638:       this->_atlasNew = NULL;
639:     };
640:     void addPoint(const point_type& point, const int dim) {
641:       if (dim == 0) return;
642:       if (this->_atlasNew.isNull()) {
643:         this->_atlasNew = new atlas_type(this->comm(), this->debug());
644:         this->_atlasNew->copy(this->_atlas);
645:       }
646:       const index_type idx(dim, -1);
647:       this->_atlasNew->addPoint(point);
648:       this->_atlasNew->updatePoint(point, &idx);
649:     };
650:     template<typename Sequence>
651:     void addPoints(const Obj<Sequence>& points, const int dim) {
652:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
653:         this->addPoint(*p_iter, dim);
654:       }
655:     };
656:     void orderPoints(const Obj<atlas_type>& atlas){
657:       const chart_type& chart    = this->getChart();
658:       int               offset   = 0;
659:       int               bcOffset = this->size();

661:       for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
662:         typename atlas_type::value_type idx  = atlas->restrictPoint(*c_iter)[0];
663:         const int&                      dim  = idx.prefix;

665:         if (dim >= 0) {
666:           idx.index = offset;
667:           atlas->updatePoint(*c_iter, &idx);
668:           offset += dim;
669:         } else {
670:           idx.index = bcOffset;
671:           atlas->updatePoint(*c_iter, &idx);
672:           bcOffset -= dim;
673:         }
674:       }
675:     };
676:     void allocatePoint() {
677:       this->orderPoints(this->_atlas);
678:       this->allocateStorage();
679:     };
680:   public: // Restriction and Update
681:     // Zero entries
682:     void zero() {
683:       memset(this->_array, 0, this->size()* sizeof(value_type));
684:     };
685:     // Return a pointer to the entire contiguous storage array
686:     const value_type *restrict() {
687:       return this->_array;
688:     };
689:     // Update the entire contiguous storage array
690:     void update(const value_type v[]) {
691:       const value_type *array = this->_array;
692:       const int         size  = this->size();

694:       for(int i = 0; i < size; i++) {
695:         array[i] = v[i];
696:       }
697:     };
698:     // Return the free values on a point
699:     const value_type *restrictPoint(const point_type& p) {
700:       return &(this->_array[this->_atlas->restrictPoint(p)[0].index]);
701:     };
702:     // Update the free values on a point
703:     void updatePoint(const point_type& p, const value_type v[], const int orientation = 1) {
704:       const index_type& idx = this->_atlas->restrictPoint(p)[0];
705:       value_type       *a   = &(this->_array[idx.index]);

707:       if (orientation >= 0) {
708:         for(int i = 0; i < idx.prefix; ++i) {
709:           a[i] = v[i];
710:         }
711:       } else {
712:         const int last = idx.prefix-1;

714:         for(int i = 0; i < idx.prefix; ++i) {
715:           a[i] = v[last-i];
716:         }
717:       }
718:     };
719:     // Update the free values on a point
720:     void updateAddPoint(const point_type& p, const value_type v[], const int orientation = 1) {
721:       const index_type& idx = this->_atlas->restrictPoint(p)[0];
722:       value_type       *a   = &(this->_array[idx.index]);

724:       if (orientation >= 0) {
725:         for(int i = 0; i < idx.prefix; ++i) {
726:           a[i] += v[i];
727:         }
728:       } else {
729:         const int last = idx.prefix-1;

731:         for(int i = 0; i < idx.prefix; ++i) {
732:           a[i] += v[last-i];
733:         }
734:       }
735:     };
736:     // Update only the constrained dofs on a point
737:     void updatePointBC(const point_type& p, const value_type v[], const int orientation = 1) {
738:       const index_type& idx = this->_atlas->restrictPoint(p)[0];
739:       const int         dim = -idx.prefix;
740:       value_type       *a   = &(this->_array[idx.index]);

742:       if (orientation >= 0) {
743:         for(int i = 0; i < dim; ++i) {
744:           a[i] = v[i];
745:         }
746:       } else {
747:         const int last = dim-1;

749:         for(int i = 0; i < dim; ++i) {
750:           a[i] = v[last-i];
751:         }
752:       }
753:     };
754:     // Update all dofs on a point (free and constrained)
755:     void updatePointAll(const point_type& p, const value_type v[], const int orientation = 1) {
756:       const index_type& idx = this->_atlas->restrictPoint(p)[0];
757:       const int         dim = std::abs(idx.prefix);
758:       value_type       *a   = &(this->_array[idx.index]);

760:       if (orientation >= 0) {
761:         for(int i = 0; i < dim; ++i) {
762:           a[i] = v[i];
763:         }
764:       } else {
765:         const int last = dim-1;

767:         for(int i = 0; i < dim; ++i) {
768:           a[i] = v[last-i];
769:         }
770:       }
771:     };
772:   public:
773:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
774:       ostringstream txt;
775:       int rank;

777:       if (comm == MPI_COMM_NULL) {
778:         comm = this->comm();
779:         rank = this->commRank();
780:       } else {
781:         MPI_Comm_rank(comm, &rank);
782:       }
783:       if(rank == 0) {
784:         txt << "viewing Section " << this->getName() << std::endl;
785:         if (name != "") {
786:           txt << ": " << name << "'";
787:         }
788:         txt << std::endl;
789:       }
790:       const typename atlas_type::chart_type& chart = this->_atlas->getChart();
791:       const value_type                      *array = this->_array;

793:       for(typename atlas_type::chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
794:         const point_type& point = *p_iter;
795:         const index_type& idx   = this->_atlas->restrictPoint(point)[0];
796:         const int         dim   = this->getFiberDimension(point);

798:         if (idx.prefix != 0) {
799:           txt << "[" << this->commRank() << "]:   " << point << " dim " << idx.prefix << " offset " << idx.index << "  ";
800:           for(int i = 0; i < dim; i++) {
801:             txt << " " << array[idx.index+i];
802:           }
803:           txt << std::endl;
804:         }
805:       }
806:       if (chart.size() == 0) {
807:         txt << "[" << this->commRank() << "]: empty" << std::endl;
808:       }
809:       PetscSynchronizedPrintf(comm, txt.str().c_str());
810:       PetscSynchronizedFlush(comm);
811:     };
812:   public: // Fibrations
813:     void setConstraintDof(const point_type& p, const int dofs[]) {};
814:     int getNumSpaces() const {return 1;};
815:     void addSpace() {};
816:     int getFiberDimension(const point_type& p, const int space) {return this->getFiberDimension(p);};
817:     void setFiberDimension(const point_type& p, int dim, const int space) {this->setFiberDimension(p, dim);};
818:     template<typename Sequence>
819:     void setFiberDimension(const Obj<Sequence>& points, int dim, const int space) {
820:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
821:         this->setFiberDimension(*p_iter, dim, space);
822:       }
823:     };
824:     void setConstraintDimension(const point_type& p, const int numConstraints, const int space) {
825:       this->setConstraintDimension(p, numConstraints);
826:     };
827:   };
828:   // GeneralSection will support BC on a subset of unknowns on a point
829:   //   We make a separate constraint Atlas to mark constrained dofs on a point
830:   //   Storage will be contiguous by node, just as in Section
831:   //     This allows fast restrict(p)
832:   //     Then update() is accomplished by skipping constrained unknowns
833:   //     We must eliminate restrict() since it does not correspond to the constrained system
834:   //   Numbering will have to be rewritten to calculate correct mappings
835:   //     I think we can just generate multiple tuples per point
836:   template<typename Point_, typename Value_>
837:   class GeneralSection : public ALE::ParallelObject {
838:   public:
839:     typedef Point_                                 point_type;
840:     typedef ALE::Point                             index_type;
841:     typedef UniformSection<point_type, index_type> atlas_type;
842:     typedef Section<point_type, int>               bc_type;
843:     typedef typename atlas_type::chart_type        chart_type;
844:     typedef Value_                                 value_type;
845:     typedef value_type *                           values_type;
846:     typedef std::pair<const int *, const int *>    customAtlasInd_type;
847:     typedef std::pair<customAtlasInd_type, bool>   customAtlas_type;
848:   protected:
849:     Obj<atlas_type> _atlas;
850:     Obj<atlas_type> _atlasNew;
851:     values_type     _array;
852:     bool            _sharedStorage;
853:     int             _sharedStorageSize;
854:     Obj<bc_type>    _bc;
855:     std::vector<Obj<atlas_type> > _spaces;
856:     std::vector<Obj<bc_type> >    _bcs;
857:     // Optimization
858:     std::vector<customAtlas_type> _customRestrictAtlas;
859:     std::vector<customAtlas_type> _customUpdateAtlas;
860:   public:
861:     GeneralSection(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {
862:       this->_atlas         = new atlas_type(comm, debug);
863:       this->_atlasNew      = NULL;
864:       this->_array         = NULL;
865:       this->_sharedStorage = false;
866:       this->_bc            = new bc_type(comm, debug);
867:     };
868:     GeneralSection(const Obj<atlas_type>& atlas) : ParallelObject(atlas->comm(), atlas->debug()), _atlas(atlas), _atlasNew(NULL), _array(NULL), _sharedStorage(false), _sharedStorageSize(0) {
869:       this->_bc       = new bc_type(comm, debug);
870:     };
871:     virtual ~GeneralSection() {
872:       if (this->_array && !this->_sharedStorage) {
873:         delete [] this->_array;
874:         this->_array = NULL;
875:       }
876:       for(std::vector<customAtlas_type>::iterator a_iter = this->_customRestrictAtlas.begin(); a_iter != this->_customRestrictAtlas.end(); ++a_iter) {
877:         if (a_iter->second) {
878:           delete [] a_iter->first.first;
879:           delete [] a_iter->first.second;
880:         }
881:       }
882:       for(std::vector<customAtlas_type>::iterator a_iter = this->_customUpdateAtlas.begin(); a_iter != this->_customUpdateAtlas.end(); ++a_iter) {
883:         if (a_iter->second) {
884:           delete [] a_iter->first.first;
885:           delete [] a_iter->first.second;
886:         }
887:       }
888:     };
889:   public:
890:     value_type *getRawArray(const int size) {
891:       // Put in a sentinel value that deallocates the array
892:       static value_type *array   = NULL;
893:       static int         maxSize = 0;

895:       if (size > maxSize) {
896:         maxSize = size;
897:         if (array) delete [] array;
898:         array = new value_type[maxSize];
899:       };
900:       return array;
901:     };
902:     int getStorageSize() const {
903:       if (this->_sharedStorage) {
904:         return this->_sharedStorageSize;
905:       }
906:       return this->sizeWithBC();
907:     };
908:   public: // Verifiers
909:     bool hasPoint(const point_type& point) {
910:       return this->_atlas->hasPoint(point);
911:     };
912:   public: // Accessors
913:     const Obj<atlas_type>& getAtlas() const {return this->_atlas;};
914:     void setAtlas(const Obj<atlas_type>& atlas) {this->_atlas = atlas;};
915:     const Obj<atlas_type>& getNewAtlas() const {return this->_atlasNew;};
916:     void setNewAtlas(const Obj<atlas_type>& atlas) {this->_atlasNew = atlas;};
917:     const Obj<bc_type>& getBC() const {return this->_bc;};
918:     void setBC(const Obj<bc_type>& bc) {this->_bc = bc;};
919:     const chart_type& getChart() const {return this->_atlas->getChart();};
920:   public: // BC
921:     // Returns the number of constraints on a point
922:     const int getConstraintDimension(const point_type& p) const {
923:       if (!this->_bc->hasPoint(p)) return 0;
924:       return this->_bc->getFiberDimension(p);
925:     };
926:     // Set the number of constraints on a point
927:     void setConstraintDimension(const point_type& p, const int numConstraints) {
928:       this->_bc->setFiberDimension(p, numConstraints);
929:     };
930:     // Increment the number of constraints on a point
931:     void addConstraintDimension(const point_type& p, const int numConstraints) {
932:       this->_bc->addFiberDimension(p, numConstraints);
933:     };
934:     // Return the local dofs which are constrained on a point
935:     const int *getConstraintDof(const point_type& p) {
936:       return this->_bc->restrictPoint(p);
937:     };
938:     // Set the local dofs which are constrained on a point
939:     void setConstraintDof(const point_type& p, const int dofs[]) {
940:       this->_bc->updatePoint(p, dofs);
941:     };
942:     void copyBC(const Obj<GeneralSection>& section) {
943:       this->setBC(section->getBC());
944:       const chart_type& chart = this->getChart();

946:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
947:         if (this->getConstraintDimension(*p_iter)) {
948:           this->updatePointBCFull(*p_iter, section->restrictPoint(*p_iter));
949:         }
950:       }
951:       this->copyFibration(section);
952:     };
953:     void defaultConstraintDof() {
954:       const chart_type& chart = this->getChart();
955:       int size = 0;

957:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
958:         size = std::max(size, this->getConstraintDimension(*p_iter));
959:       }
960:       int *dofs = new int[size];
961:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
962:         const int cDim = this->getConstraintDimension(*p_iter);

964:         if (cDim) {
965:           for(int d = 0; d < cDim; ++d) {
966:             dofs[d] = d;
967:           }
968:           this->_bc->updatePoint(*p_iter, dofs);
969:         }
970:       }
971:     };
972:   public: // Sizes
973:     void clear() {
974:       this->_atlas->clear();
975:       if (!this->_sharedStorage) delete [] this->_array;
976:       this->_array = NULL;
977:       this->_bc->clear();
978:     };
979:     // Return the total number of dofs on the point (free and constrained)
980:     int getFiberDimension(const point_type& p) const {
981:       return this->_atlas->restrictPoint(p)->prefix;
982:     };
983:     int getFiberDimension(const Obj<atlas_type>& atlas, const point_type& p) const {
984:       return atlas->restrictPoint(p)->prefix;
985:     };
986:     // Set the total number of dofs on the point (free and constrained)
987:     void setFiberDimension(const point_type& p, int dim) {
988:       const index_type idx(dim, -1);
989:       this->_atlas->addPoint(p);
990:       this->_atlas->updatePoint(p, &idx);
991:     };
992:     template<typename Sequence>
993:     void setFiberDimension(const Obj<Sequence>& points, int dim) {
994:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
995:         this->setFiberDimension(*p_iter, dim);
996:       }
997:     };
998:     void addFiberDimension(const point_type& p, int dim) {
999:       if (this->_atlas->hasPoint(p)) {
1000:         const index_type values(dim, 0);
1001:         this->_atlas->updateAddPoint(p, &values);
1002:       } else {
1003:         this->setFiberDimension(p, dim);
1004:       }
1005:     };
1006:     // Return the number of constrained dofs on this point
1007:     int getConstrainedFiberDimension(const point_type& p) const {
1008:       return this->getFiberDimension(p) - this->getConstraintDimension(p);
1009:     };
1010:     // Return the total number of free dofs
1011:     int size() const {
1012:       const chart_type& points = this->getChart();
1013:       int               size   = 0;

1015:       for(typename chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
1016:         size += this->getConstrainedFiberDimension(*p_iter);
1017:       }
1018:       return size;
1019:     };
1020:     // Return the total number of dofs (free and constrained)
1021:     int sizeWithBC() const {
1022:       const chart_type& points = this->getChart();
1023:       int               size   = 0;

1025:       for(typename chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
1026:         size += this->getFiberDimension(*p_iter);
1027:       }
1028:       return size;
1029:     };
1030:   public: // Index retrieval
1031:     const typename index_type::index_type& getIndex(const point_type& p) {
1032:       return this->_atlas->restrictPoint(p)->index;
1033:     };
1034:     void setIndex(const point_type& p, const typename index_type::index_type& index) {
1035:       ((typename atlas_type::value_type *) this->_atlas->restrictPoint(p))->index = index;
1036:     };
1037:     void setIndexBC(const point_type& p, const typename index_type::index_type& index) {};
1038:     void getIndices(const point_type& p, PetscInt indices[], PetscInt *indx, const int orientation = 1, const bool freeOnly = false, const bool skipConstraints = false) {
1039:       this->getIndices(p, this->getIndex(p), indices, indx, orientation, freeOnly, skipConstraints);
1040:     };
1041:     template<typename Order_>
1042:     void getIndices(const point_type& p, const Obj<Order_>& order, PetscInt indices[], PetscInt *indx, const int orientation = 1, const bool freeOnly = false, const bool skipConstraints = false) {
1043:       this->getIndices(p, order->getIndex(p), indices, indx, orientation, freeOnly, skipConstraints);
1044:     };
1045:     void getIndicesRaw(const point_type& p, const int start, PetscInt indices[], PetscInt *indx, const int orientation) {
1046:       if (orientation >= 0) {
1047:         const int& dim = this->getFiberDimension(p);
1048:         const int  end = start + dim;

1050:         for(int i = start; i < end; ++i) {
1051:           indices[(*indx)++] = i;
1052:         }
1053:       } else {
1054:         const int numSpaces = this->getNumSpaces();
1055:         int offset = start;

1057:         for(int space = 0; space < numSpaces; ++space) {
1058:           const int& dim = this->getFiberDimension(p, space);

1060:           for(int i = offset+dim-1; i >= offset; --i) {
1061:             indices[(*indx)++] = i;
1062:           }
1063:           offset += dim;
1064:         }
1065:         if (!numSpaces) {
1066:           const int& dim = this->getFiberDimension(p);

1068:           for(int i = offset+dim-1; i >= offset; --i) {
1069:             indices[(*indx)++] = i;
1070:           }
1071:           offset += dim;
1072:         }
1073:       }
1074:     }
1075:     void getIndices(const point_type& p, const int start, PetscInt indices[], PetscInt *indx, const int orientation = 1, const bool freeOnly = false, const bool skipConstraints = false) {
1076:       const int& cDim = this->getConstraintDimension(p);

1078:       if (!cDim) {
1079:         this->getIndicesRaw(p, start, indices, indx, orientation);
1080:       } else {
1081:         if (orientation >= 0) {
1082:           const int&                          dim  = this->getFiberDimension(p);
1083:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
1084:           int                                 cInd = 0;

1086:           for(int i = start, k = 0; k < dim; ++k) {
1087:             if ((cInd < cDim) && (k == cDof[cInd])) {
1088:               if (!freeOnly) indices[(*indx)++] = -(k+1);
1089:               if (skipConstraints) ++i;
1090:               ++cInd;
1091:             } else {
1092:               indices[(*indx)++] = i++;
1093:             }
1094:           }
1095:         } else {
1096:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
1097:           int                                 offset  = 0;
1098:           int                                 cOffset = 0;
1099:           int                                 j       = -1;

1101:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1102:             const int  dim = this->getFiberDimension(p, space);
1103:             const int tDim = this->getConstrainedFiberDimension(p, space);
1104:             int       cInd = (dim - tDim)-1;

1106:             j += dim;
1107:             for(int i = 0, k = start+tDim+offset; i < dim; ++i, --j) {
1108:               if ((cInd >= 0) && (j == cDof[cInd+cOffset])) {
1109:                 if (!freeOnly) indices[(*indx)++] = -(offset+i+1);
1110:                 if (skipConstraints) --k;
1111:                 --cInd;
1112:               } else {
1113:                 indices[(*indx)++] = --k;
1114:               }
1115:             }
1116:             j       += dim;
1117:             offset  += dim;
1118:             cOffset += dim - tDim;
1119:           }
1120:         }
1121:       }
1122:     };
1123:   public: // Allocation
1124:     void allocateStorage() {
1125:       const int totalSize = this->sizeWithBC();

1127:       this->_array             = new value_type[totalSize];
1128:       this->_sharedStorage     = false;
1129:       this->_sharedStorageSize = 0;
1130:       PetscMemzero(this->_array, totalSize * sizeof(value_type));
1131:       this->_bc->allocatePoint();
1132:     };
1133:     void replaceStorage(value_type *newArray, const bool sharedStorage = false, const int sharedStorageSize = 0) {
1134:       if (this->_array && !this->_sharedStorage) {delete [] this->_array;}
1135:       this->_array             = newArray;
1136:       this->_sharedStorage     = sharedStorage;
1137:       this->_sharedStorageSize = sharedStorageSize;
1138:       this->_atlas             = this->_atlasNew;
1139:       this->_atlasNew          = NULL;
1140:     };
1141:     void addPoint(const point_type& point, const int dim) {
1142:       if (dim == 0) return;
1143:       if (this->_atlasNew.isNull()) {
1144:         this->_atlasNew = new atlas_type(this->comm(), this->debug());
1145:         this->_atlasNew->copy(this->_atlas);
1146:       }
1147:       const index_type idx(dim, -1);
1148:       this->_atlasNew->addPoint(point);
1149:       this->_atlasNew->updatePoint(point, &idx);
1150:     };
1151:     void orderPoints(const Obj<atlas_type>& atlas){
1152:       const chart_type& chart  = this->getChart();
1153:       int               offset = 0;

1155:       for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
1156:         typename atlas_type::value_type idx = atlas->restrictPoint(*c_iter)[0];
1157:         const int&                      dim = idx.prefix;

1159:         idx.index = offset;
1160:         atlas->updatePoint(*c_iter, &idx);
1161:         offset += dim;
1162:       }
1163:     };
1164:     void allocatePoint() {
1165:       this->orderPoints(this->_atlas);
1166:       this->allocateStorage();
1167:     };
1168:   public: // Restriction and Update
1169:     // Zero entries
1170:     void zero() {
1171:       this->set(0.0);
1172:     };
1173:     void set(const value_type value) {
1174:       //memset(this->_array, 0, this->sizeWithBC()* sizeof(value_type));
1175:       const chart_type& chart = this->getChart();

1177:       for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
1178:         value_type *array = (value_type *) this->restrictPoint(*c_iter);
1179:         const int&  dim   = this->getFiberDimension(*c_iter);
1180:         const int&  cDim  = this->getConstraintDimension(*c_iter);

1182:         if (!cDim) {
1183:           for(int i = 0; i < dim; ++i) {
1184:             array[i] = value;
1185:           }
1186:         } else {
1187:           const typename bc_type::value_type *cDof = this->getConstraintDof(*c_iter);
1188:           int                                 cInd = 0;

1190:           for(int i = 0; i < dim; ++i) {
1191:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
1192:             array[i] = value;
1193:           }
1194:         }
1195:       }
1196:     };
1197:     // Add two sections and put the result in a third
1198:     void add(const Obj<GeneralSection>& x, const Obj<GeneralSection>& y) {
1199:       // Check atlases
1200:       const chart_type& chart = this->getChart();

1202:       for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
1203:         value_type       *array  = (value_type *) this->restrictPoint(*c_iter);
1204:         const value_type *xArray = x->restrictPoint(*c_iter);
1205:         const value_type *yArray = y->restrictPoint(*c_iter);
1206:         const int&        dim    = this->getFiberDimension(*c_iter);
1207:         const int&        cDim   = this->getConstraintDimension(*c_iter);

1209:         if (!cDim) {
1210:           for(int i = 0; i < dim; ++i) {
1211:             array[i] = xArray[i] + yArray[i];
1212:           }
1213:         } else {
1214:           const typename bc_type::value_type *cDof = this->getConstraintDof(*c_iter);
1215:           int                                 cInd = 0;

1217:           for(int i = 0; i < dim; ++i) {
1218:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
1219:             array[i] = xArray[i] + yArray[i];
1220:           }
1221:         }
1222:       }
1223:     };
1224:     // this = this + alpha * x
1225:     void axpy(const value_type alpha, const Obj<GeneralSection>& x) {
1226:       // Check atlases
1227:       const chart_type& chart = this->getChart();

1229:       for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
1230:         value_type       *array  = (value_type *) this->restrictPoint(*c_iter);
1231:         const value_type *xArray = x->restrictPoint(*c_iter);
1232:         const int&        dim    = this->getFiberDimension(*c_iter);
1233:         const int&        cDim   = this->getConstraintDimension(*c_iter);

1235:         if (!cDim) {
1236:           for(int i = 0; i < dim; ++i) {
1237:             array[i] += alpha*xArray[i];
1238:           }
1239:         } else {
1240:           const typename bc_type::value_type *cDof = this->getConstraintDof(*c_iter);
1241:           int                                 cInd = 0;

1243:           for(int i = 0; i < dim; ++i) {
1244:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
1245:             array[i] += alpha*xArray[i];
1246:           }
1247:         }
1248:       }
1249:     };
1250:     // Return the free values on a point
1251:     const value_type *restrict() const {
1252:       return this->_array;
1253:     };
1254:     // Return the free values on a point
1255:     const value_type *restrictPoint(const point_type& p) const {
1256:       return &(this->_array[this->_atlas->restrictPoint(p)[0].index]);
1257:     };
1258:     // Update the free values on a point
1259:     //   Takes a full array and ignores constrained values
1260:     void updatePoint(const point_type& p, const value_type v[], const int orientation = 1) {
1261:       value_type *array = (value_type *) this->restrictPoint(p);
1262:       const int&  cDim  = this->getConstraintDimension(p);

1264:       if (!cDim) {
1265:         if (orientation >= 0) {
1266:           const int& dim = this->getFiberDimension(p);

1268:           for(int i = 0; i < dim; ++i) {
1269:             array[i] = v[i];
1270:           }
1271:         } else {
1272:           int offset = 0;
1273:           int j      = -1;

1275:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1276:             const int& dim = this->getFiberDimension(p, space);

1278:             for(int i = dim-1; i >= 0; --i) {
1279:               array[++j] = v[i+offset];
1280:             }
1281:             offset += dim;
1282:           }
1283:         }
1284:       } else {
1285:         if (orientation >= 0) {
1286:           const int&                          dim  = this->getFiberDimension(p);
1287:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
1288:           int                                 cInd = 0;

1290:           for(int i = 0; i < dim; ++i) {
1291:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
1292:             array[i] = v[i];
1293:           }
1294:         } else {
1295:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
1296:           int                                 offset  = 0;
1297:           int                                 cOffset = 0;
1298:           int                                 j       = 0;

1300:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1301:             const int  dim = this->getFiberDimension(p, space);
1302:             const int tDim = this->getConstrainedFiberDimension(p, space);
1303:             const int sDim = dim - tDim;
1304:             int       cInd = 0;

1306:             for(int i = 0, k = dim+offset-1; i < dim; ++i, ++j, --k) {
1307:               if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
1308:               array[j] = v[k];
1309:             }
1310:             offset  += dim;
1311:             cOffset += dim - tDim;
1312:           }
1313:         }
1314:       }
1315:     };
1316:     // Update the free values on a point
1317:     //   Takes a full array and ignores constrained values
1318:     void updateAddPoint(const point_type& p, const value_type v[], const int orientation = 1) {
1319:       value_type *array = (value_type *) this->restrictPoint(p);
1320:       const int&  cDim  = this->getConstraintDimension(p);

1322:       if (!cDim) {
1323:         if (orientation >= 0) {
1324:           const int& dim = this->getFiberDimension(p);

1326:           for(int i = 0; i < dim; ++i) {
1327:             array[i] += v[i];
1328:           }
1329:         } else {
1330:           int offset = 0;
1331:           int j      = -1;

1333:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1334:             const int& dim = this->getFiberDimension(p, space);

1336:             for(int i = dim-1; i >= 0; --i) {
1337:               array[++j] += v[i+offset];
1338:             }
1339:             offset += dim;
1340:           }
1341:         }
1342:       } else {
1343:         if (orientation >= 0) {
1344:           const int&                          dim  = this->getFiberDimension(p);
1345:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
1346:           int                                 cInd = 0;

1348:           for(int i = 0; i < dim; ++i) {
1349:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
1350:             array[i] += v[i];
1351:           }
1352:         } else {
1353:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
1354:           int                                 offset  = 0;
1355:           int                                 cOffset = 0;
1356:           int                                 j       = 0;

1358:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1359:             const int  dim = this->getFiberDimension(p, space);
1360:             const int tDim = this->getConstrainedFiberDimension(p, space);
1361:             const int sDim = dim - tDim;
1362:             int       cInd = 0;

1364:             for(int i = 0, k = dim+offset-1; i < dim; ++i, ++j, --k) {
1365:               if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
1366:               array[j] += v[k];
1367:             }
1368:             offset  += dim;
1369:             cOffset += dim - tDim;
1370:           }
1371:         }
1372:       }
1373:     };
1374:     // Update the free values on a point
1375:     //   Takes ONLY unconstrained values
1376:     void updateFreePoint(const point_type& p, const value_type v[], const int orientation = 1) {
1377:       value_type *array = (value_type *) this->restrictPoint(p);
1378:       const int&  cDim  = this->getConstraintDimension(p);

1380:       if (!cDim) {
1381:         if (orientation >= 0) {
1382:           const int& dim = this->getFiberDimension(p);

1384:           for(int i = 0; i < dim; ++i) {
1385:             array[i] = v[i];
1386:           }
1387:         } else {
1388:           int offset = 0;
1389:           int j      = -1;

1391:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1392:             const int& dim = this->getFiberDimension(p, space);

1394:             for(int i = dim-1; i >= 0; --i) {
1395:               array[++j] = v[i+offset];
1396:             }
1397:             offset += dim;
1398:           }
1399:         }
1400:       } else {
1401:         if (orientation >= 0) {
1402:           const int&                          dim  = this->getFiberDimension(p);
1403:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
1404:           int                                 cInd = 0;

1406:           for(int i = 0, k = -1; i < dim; ++i) {
1407:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
1408:             array[i] = v[++k];
1409:           }
1410:         } else {
1411:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
1412:           int                                 offset  = 0;
1413:           int                                 cOffset = 0;
1414:           int                                 j       = 0;

1416:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1417:             const int  dim = this->getFiberDimension(p, space);
1418:             const int tDim = this->getConstrainedFiberDimension(p, space);
1419:             const int sDim = dim - tDim;
1420:             int       cInd = 0;

1422:             for(int i = 0, k = tDim+offset-1; i < dim; ++i, ++j) {
1423:               if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
1424:               array[j] = v[--k];
1425:             }
1426:             offset  += dim;
1427:             cOffset += dim - tDim;
1428:           }
1429:         }
1430:       }
1431:     };
1432:     // Update the free values on a point
1433:     //   Takes ONLY unconstrained values
1434:     void updateFreeAddPoint(const point_type& p, const value_type v[], const int orientation = 1) {
1435:       value_type *array = (value_type *) this->restrictPoint(p);
1436:       const int&  cDim  = this->getConstraintDimension(p);

1438:       if (!cDim) {
1439:         if (orientation >= 0) {
1440:           const int& dim = this->getFiberDimension(p);

1442:           for(int i = 0; i < dim; ++i) {
1443:             array[i] += v[i];
1444:           }
1445:         } else {
1446:           int offset = 0;
1447:           int j      = -1;

1449:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1450:             const int& dim = this->getFiberDimension(p, space);

1452:             for(int i = dim-1; i >= 0; --i) {
1453:               array[++j] += v[i+offset];
1454:             }
1455:             offset += dim;
1456:           }
1457:         }
1458:       } else {
1459:         if (orientation >= 0) {
1460:           const int&                          dim  = this->getFiberDimension(p);
1461:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
1462:           int                                 cInd = 0;

1464:           for(int i = 0, k = -1; i < dim; ++i) {
1465:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
1466:             array[i] += v[++k];
1467:           }
1468:         } else {
1469:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
1470:           int                                 offset  = 0;
1471:           int                                 cOffset = 0;
1472:           int                                 j       = 0;

1474:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1475:             const int  dim = this->getFiberDimension(p, space);
1476:             const int tDim = this->getConstrainedFiberDimension(p, space);
1477:             const int sDim = dim - tDim;
1478:             int       cInd = 0;

1480:             for(int i = 0, k = tDim+offset-1; i < dim; ++i, ++j) {
1481:               if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
1482:               array[j] += v[--k];
1483:             }
1484:             offset  += dim;
1485:             cOffset += dim - tDim;
1486:           }
1487:         }
1488:       }
1489:     };
1490:     // Update only the constrained dofs on a point
1491:     //   This takes an array with ONLY bc values
1492:     void updatePointBC(const point_type& p, const value_type v[], const int orientation = 1) {
1493:       value_type *array = (value_type *) this->restrictPoint(p);
1494:       const int&  cDim  = this->getConstraintDimension(p);

1496:       if (cDim) {
1497:         if (orientation >= 0) {
1498:           const int&                          dim  = this->getFiberDimension(p);
1499:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
1500:           int                                 cInd = 0;

1502:           for(int i = 0; i < dim; ++i) {
1503:             if (cInd == cDim) break;
1504:             if (i == cDof[cInd]) {
1505:               array[i] = v[cInd];
1506:               ++cInd;
1507:             }
1508:           }
1509:         } else {
1510:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
1511:           int                                 cOffset = 0;
1512:           int                                 j       = 0;

1514:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1515:             const int  dim = this->getFiberDimension(p, space);
1516:             const int tDim = this->getConstrainedFiberDimension(p, space);
1517:             int       cInd = 0;

1519:             for(int i = 0; i < dim; ++i, ++j) {
1520:               if (cInd < 0) break;
1521:               if (j == cDof[cInd+cOffset]) {
1522:                 array[j] = v[cInd+cOffset];
1523:                 ++cInd;
1524:               }
1525:             }
1526:             cOffset += dim - tDim;
1527:           }
1528:         }
1529:       }
1530:     };
1531:     // Update only the constrained dofs on a point
1532:     //   This takes an array with ALL values, not just BC
1533:     void updatePointBCFull(const point_type& p, const value_type v[], const int orientation = 1) {
1534:       value_type *array = (value_type *) this->restrictPoint(p);
1535:       const int&  cDim  = this->getConstraintDimension(p);

1537:       if (cDim) {
1538:         if (orientation >= 0) {
1539:           const int&                          dim  = this->getFiberDimension(p);
1540:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
1541:           int                                 cInd = 0;

1543:           for(int i = 0; i < dim; ++i) {
1544:             if (cInd == cDim) break;
1545:             if (i == cDof[cInd]) {
1546:               array[i] = v[i];
1547:               ++cInd;
1548:             }
1549:           }
1550:         } else {
1551:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
1552:           int                                 offset  = 0;
1553:           int                                 cOffset = 0;
1554:           int                                 j       = 0;

1556:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1557:             const int  dim = this->getFiberDimension(p, space);
1558:             const int tDim = this->getConstrainedFiberDimension(p, space);
1559:             int       cInd = 0;

1561:             for(int i = 0, k = dim+offset-1; i < dim; ++i, ++j, --k) {
1562:               if (cInd < 0) break;
1563:               if (j == cDof[cInd+cOffset]) {
1564:                 array[j] = v[k];
1565:                 ++cInd;
1566:               }
1567:             }
1568:             offset  += dim;
1569:             cOffset += dim - tDim;
1570:           }
1571:         }
1572:       }
1573:     };
1574:     // Update all dofs on a point (free and constrained)
1575:     void updatePointAll(const point_type& p, const value_type v[], const int orientation = 1) {
1576:       value_type *array = (value_type *) this->restrictPoint(p);

1578:       if (orientation >= 0) {
1579:         const int& dim = this->getFiberDimension(p);

1581:         for(int i = 0; i < dim; ++i) {
1582:           array[i] = v[i];
1583:         }
1584:       } else {
1585:         int offset = 0;
1586:         int j      = -1;

1588:         for(int space = 0; space < this->getNumSpaces(); ++space) {
1589:           const int& dim = this->getFiberDimension(p, space);

1591:           for(int i = dim-1; i >= 0; --i) {
1592:             array[++j] = v[i+offset];
1593:           }
1594:           offset += dim;
1595:         }
1596:       }
1597:     };
1598:     // Update all dofs on a point (free and constrained)
1599:     void updatePointAllAdd(const point_type& p, const value_type v[], const int orientation = 1) {
1600:       value_type *array = (value_type *) this->restrictPoint(p);

1602:       if (orientation >= 0) {
1603:         const int& dim = this->getFiberDimension(p);

1605:         for(int i = 0; i < dim; ++i) {
1606:           array[i] += v[i];
1607:         }
1608:       } else {
1609:         int offset = 0;
1610:         int j      = -1;

1612:         for(int space = 0; space < this->getNumSpaces(); ++space) {
1613:           const int& dim = this->getFiberDimension(p, space);

1615:           for(int i = dim-1; i >= 0; --i) {
1616:             array[++j] += v[i+offset];
1617:           }
1618:           offset += dim;
1619:         }
1620:       }
1621:     };
1622:   public: // Fibrations
1623:     int getNumSpaces() const {return this->_spaces.size();};
1624:     const std::vector<Obj<atlas_type> >& getSpaces() {return this->_spaces;};
1625:     const std::vector<Obj<bc_type> >& getBCs() {return this->_bcs;};
1626:     void addSpace() {
1627:       Obj<atlas_type> space = new atlas_type(this->comm(), this->debug());
1628:       Obj<bc_type>    bc    = new bc_type(this->comm(), this->debug());
1629:       this->_spaces.push_back(space);
1630:       this->_bcs.push_back(bc);
1631:     };
1632:     int getFiberDimension(const point_type& p, const int space) const {
1633:       return this->_spaces[space]->restrictPoint(p)->prefix;
1634:     };
1635:     void setFiberDimension(const point_type& p, int dim, const int space) {
1636:       const index_type idx(dim, -1);
1637:       this->_spaces[space]->addPoint(p);
1638:       this->_spaces[space]->updatePoint(p, &idx);
1639:     };
1640:     template<typename Sequence>
1641:     void setFiberDimension(const Obj<Sequence>& points, int dim, const int space) {
1642:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
1643:         this->setFiberDimension(*p_iter, dim, space);
1644:       }
1645:     };
1646:     const int getConstraintDimension(const point_type& p, const int space) const {
1647:       if (!this->_bcs[space]->hasPoint(p)) return 0;
1648:       return this->_bcs[space]->getFiberDimension(p);
1649:     };
1650:     void setConstraintDimension(const point_type& p, const int numConstraints, const int space) {
1651:       this->_bcs[space]->setFiberDimension(p, numConstraints);
1652:     };
1653:     int getConstrainedFiberDimension(const point_type& p, const int space) const {
1654:       return this->getFiberDimension(p, space) - this->getConstraintDimension(p, space);
1655:     };
1656:     void copyFibration(const Obj<GeneralSection>& section) {
1657:       const std::vector<Obj<atlas_type> >& spaces = section->getSpaces();
1658:       const std::vector<Obj<bc_type> >&    bcs    = section->getBCs();

1660:       this->_spaces.clear();
1661:       for(typename std::vector<Obj<atlas_type> >::const_iterator s_iter = spaces.begin(); s_iter != spaces.end(); ++s_iter) {
1662:         this->_spaces.push_back(*s_iter);
1663:       }
1664:       this->_bcs.clear();
1665:       for(typename std::vector<Obj<bc_type> >::const_iterator b_iter = bcs.begin(); b_iter != bcs.end(); ++b_iter) {
1666:         this->_bcs.push_back(*b_iter);
1667:       }
1668:     };
1669:     Obj<GeneralSection> getFibration(const int space) const {
1670:       Obj<GeneralSection> field = new GeneralSection(this->comm(), this->debug());
1671: //     Obj<atlas_type> _atlas;
1672: //     std::vector<Obj<atlas_type> > _spaces;
1673: //     Obj<bc_type>    _bc;
1674: //     std::vector<Obj<bc_type> >    _bcs;
1675:       field->addSpace();
1676:       const chart_type& chart = this->getChart();

1678:       // Copy sizes
1679:       for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
1680:         const int fDim = this->getFiberDimension(*c_iter, space);
1681:         const int cDim = this->getConstraintDimension(*c_iter, space);

1683:         if (fDim) {
1684:           field->setFiberDimension(*c_iter, fDim);
1685:           field->setFiberDimension(*c_iter, fDim, 0);
1686:         }
1687:         if (cDim) {
1688:           field->setConstraintDimension(*c_iter, cDim);
1689:           field->setConstraintDimension(*c_iter, cDim, 0);
1690:         }
1691:       }
1692:       field->allocateStorage();
1693:       Obj<atlas_type>   newAtlas = new atlas_type(this->comm(), this->debug());
1694:       const chart_type& newChart = field->getChart();

1696:       for(typename chart_type::iterator c_iter = newChart.begin(); c_iter != newChart.end(); ++c_iter) {
1697:         const int cDim   = field->getConstraintDimension(*c_iter);
1698:         const int dof[1] = {0};

1700:         if (cDim) {
1701:           field->setConstraintDof(*c_iter, dof);
1702:         }
1703:       }
1704:       // Copy offsets
1705:       for(typename chart_type::iterator c_iter = newChart.begin(); c_iter != newChart.end(); ++c_iter) {
1706:         index_type idx;

1708:         idx.prefix = field->getFiberDimension(*c_iter);
1709:         idx.index  = this->_atlas->restrictPoint(*c_iter)[0].index;
1710:         for(int s = 0; s < space; ++s) {
1711:           idx.index += this->getFiberDimension(*c_iter, s);
1712:         }
1713:         newAtlas->addPoint(*c_iter);
1714:         newAtlas->updatePoint(*c_iter, &idx);
1715:       }
1716:       field->replaceStorage(this->_array, true, this->getStorageSize());
1717:       field->setAtlas(newAtlas);
1718:       return field;
1719:     };
1720:   public: // Optimization
1721:     void getCustomRestrictAtlas(const int tag, const int *offsets[], const int *indices[]) {
1722:       *offsets = this->_customRestrictAtlas[tag].first.first;
1723:       *indices = this->_customRestrictAtlas[tag].first.second;
1724:     };
1725:     void getCustomUpdateAtlas(const int tag, const int *offsets[], const int *indices[]) {
1726:       *offsets = this->_customUpdateAtlas[tag].first.first;
1727:       *indices = this->_customUpdateAtlas[tag].first.second;
1728:     };
1729:     // This returns the tag assigned to the atlas
1730:     int setCustomAtlas(const int restrictOffsets[], const int restrictIndices[], const int updateOffsets[], const int updateIndices[], bool autoFree = true) {
1731:       this->_customRestrictAtlas.push_back(customAtlas_type(customAtlasInd_type(restrictOffsets, restrictIndices), autoFree));
1732:       this->_customUpdateAtlas.push_back(customAtlas_type(customAtlasInd_type(updateOffsets, updateIndices), autoFree));
1733:       return this->_customUpdateAtlas.size()-1;
1734:     };
1735:     int copyCustomAtlas(const Obj<GeneralSection>& section, const int tag) {
1736:       const int *rOffsets, *rIndices, *uOffsets, *uIndices;

1738:       section->getCustomRestrictAtlas(tag, &rOffsets, &rIndices);
1739:       section->getCustomUpdateAtlas(tag, &uOffsets, &uIndices);
1740:       return this->setCustomAtlas(rOffsets, rIndices, uOffsets, uIndices, false);
1741:     };
1742:   public:
1743:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
1744:       ostringstream txt;
1745:       int rank;

1747:       if (comm == MPI_COMM_NULL) {
1748:         comm = this->comm();
1749:         rank = this->commRank();
1750:       } else {
1751:         MPI_Comm_rank(comm, &rank);
1752:       }
1753:       if (name == "") {
1754:         if(rank == 0) {
1755:           txt << "viewing a GeneralSection" << std::endl;
1756:         }
1757:       } else {
1758:         if (rank == 0) {
1759:           txt << "viewing GeneralSection '" << name << "'" << std::endl;
1760:         }
1761:       }
1762:       if (rank == 0) {
1763:         txt << "  Fields: " << this->getNumSpaces() << std::endl;
1764:       }
1765:       const chart_type& chart = this->getChart();

1767:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
1768:         const value_type *array = this->restrictPoint(*p_iter);
1769:         const int&        dim   = this->getFiberDimension(*p_iter);

1771:         if (dim != 0) {
1772:           txt << "[" << this->commRank() << "]:   " << *p_iter << " dim " << dim << " offset " << this->_atlas->restrictPoint(*p_iter)->index << "  ";
1773:           for(int i = 0; i < dim; i++) {
1774:             txt << " " << array[i];
1775:           }
1776:           const int& dim = this->getConstraintDimension(*p_iter);

1778:           if (dim) {
1779:             const typename bc_type::value_type *bcArray = this->_bc->restrictPoint(*p_iter);

1781:             txt << " constrained";
1782:             for(int i = 0; i < dim; ++i) {
1783:               txt << " " << bcArray[i];
1784:             }
1785:           }
1786:           txt << std::endl;
1787:         }
1788:       }
1789:       if (chart.size() == 0) {
1790:         txt << "[" << this->commRank() << "]: empty" << std::endl;
1791:       }
1792:       PetscSynchronizedPrintf(comm, txt.str().c_str());
1793:       PetscSynchronizedFlush(comm);
1794:     };
1795:   };
1796:   // A Field combines several sections
1797:   template<typename Overlap_, typename Patch_, typename Section_>
1798:   class Field : public ALE::ParallelObject {
1799:   public:
1800:     typedef Overlap_                                 overlap_type;
1801:     typedef Patch_                                   patch_type;
1802:     typedef Section_                                 section_type;
1803:     typedef typename section_type::point_type        point_type;
1804:     typedef typename section_type::chart_type        chart_type;
1805:     typedef typename section_type::value_type        value_type;
1806:     typedef std::map<patch_type, Obj<section_type> > sheaf_type;
1807:     typedef enum {SEND, RECEIVE}                     request_type;
1808:     typedef std::map<patch_type, MPI_Request>        requests_type;
1809:   protected:
1810:     sheaf_type    _sheaf;
1811:     int           _tag;
1812:     MPI_Datatype  _datatype;
1813:     requests_type _requests;
1814:   public:
1815:     Field(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {
1816:       this->_tag      = this->getNewTag();
1817:       this->_datatype = this->getMPIDatatype();
1818:     };
1819:     Field(MPI_Comm comm, const int tag, const int debug) : ParallelObject(comm, debug), _tag(tag) {
1820:       this->_datatype = this->getMPIDatatype();
1821:     };
1822:     virtual ~Field() {};
1823:   protected:
1824:     MPI_Datatype getMPIDatatype() {
1825:       if (sizeof(value_type) == 4) {
1826:         return MPI_INT;
1827:       } else if (sizeof(value_type) == 8) {
1828:         return MPI_DOUBLE;
1829:       } else if (sizeof(value_type) == 28) {
1830:         int          blen[2];
1831:         MPI_Aint     indices[2];
1832:         MPI_Datatype oldtypes[2], newtype;
1833:         blen[0] = 1; indices[0] = 0;           oldtypes[0] = MPI_INT;
1834:         blen[1] = 3; indices[1] = sizeof(int); oldtypes[1] = MPI_DOUBLE;
1835:         MPI_Type_struct(2, blen, indices, oldtypes, &newtype);
1836:         MPI_Type_commit(&newtype);
1837:         return newtype;
1838:       } else if (sizeof(value_type) == 32) {
1839:         int          blen[2];
1840:         MPI_Aint     indices[2];
1841:         MPI_Datatype oldtypes[2], newtype;
1842:         blen[0] = 1; indices[0] = 0;           oldtypes[0] = MPI_DOUBLE;
1843:         blen[1] = 3; indices[1] = sizeof(int); oldtypes[1] = MPI_DOUBLE;
1844:         MPI_Type_struct(2, blen, indices, oldtypes, &newtype);
1845:         MPI_Type_commit(&newtype);
1846:         return newtype;
1847:       }
1848:       throw ALE::Exception("Cannot determine MPI type for value type");
1849:     };
1850:     int getNewTag() {
1851:       static int tagKeyval = MPI_KEYVAL_INVALID;
1852:       int *tagvalp = NULL, *maxval, flg;

1854:       if (tagKeyval == MPI_KEYVAL_INVALID) {
1855:         tagvalp = (int *) malloc(sizeof(int));
1856:         MPI_Keyval_create(MPI_NULL_COPY_FN, Mesh_DelTag, &tagKeyval, (void *) NULL);
1857:         MPI_Attr_put(this->_comm, tagKeyval, tagvalp);
1858:         tagvalp[0] = 0;
1859:       }
1860:       MPI_Attr_get(this->_comm, tagKeyval, (void **) &tagvalp, &flg);
1861:       if (tagvalp[0] < 1) {
1862:         MPI_Attr_get(MPI_COMM_WORLD, MPI_TAG_UB, (void **) &maxval, &flg);
1863:         tagvalp[0] = *maxval - 128; // hope that any still active tags were issued right at the beginning of the run
1864:       }
1865:       if (this->debug()) {
1866:         std::cout << "[" << this->commRank() << "]Got new tag " << tagvalp[0] << std::endl;
1867:       }
1868:       return tagvalp[0]--;
1869:     };
1870:   public: // Verifiers
1871:     void checkPatch(const patch_type& patch) const {
1872:       if (this->_sheaf.find(patch) == this->_sheaf.end()) {
1873:         ostringstream msg;
1874:         msg << "Invalid field patch " << patch << std::endl;
1875:         throw ALE::Exception(msg.str().c_str());
1876:       }
1877:     };
1878:     bool hasPatch(const patch_type& patch) {
1879:       if (this->_sheaf.find(patch) == this->_sheaf.end()) {
1880:         return false;
1881:       }
1882:       return true;
1883:     };
1884:   public: // Accessors
1885:     int getTag() const {return this->_tag;};
1886:     void setTag(const int tag) {this->_tag = tag;};
1887:     Obj<section_type>& getSection(const patch_type& patch) {
1888:       if (this->_sheaf.find(patch) == this->_sheaf.end()) {
1889:         this->_sheaf[patch] = new section_type(this->comm(), this->debug());
1890:       }
1891:       return this->_sheaf[patch];
1892:     };
1893:     void setSection(const patch_type& patch, const Obj<section_type>& section) {this->_sheaf[patch] = section;};
1894:     const sheaf_type& getPatches() {
1895:       return this->_sheaf;
1896:     };
1897:     void clear() {
1898:       for(typename sheaf_type::const_iterator p_iter = this->_sheaf.begin(); p_iter != this->_sheaf.end(); ++p_iter) {
1899:         p_iter->second->clear();
1900:       }
1901:     };
1902:   public: //  Adapter
1903:     template<typename Topology_>
1904:     void setTopology(const Obj<Topology_>& topology) {
1905:       const typename Topology_::sheaf_type& patches = topology->getPatches();

1907:       for(typename Topology_::sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
1908:         int                      rank    = p_iter->first;
1909:         const Obj<section_type>& section = this->getSection(rank);
1910:         const Obj<typename Topology_::sieve_type::baseSequence>& base = p_iter->second->base();

1912:         for(typename Topology_::sieve_type::baseSequence::iterator b_iter = base->begin(); b_iter != base->end(); ++b_iter) {
1913:           section->setFiberDimension(*b_iter, 1);
1914:         }
1915:       }
1916:     };
1917:     void allocate() {
1918:       for(typename sheaf_type::const_iterator p_iter = this->_sheaf.begin(); p_iter != this->_sheaf.end(); ++p_iter) {
1919:         p_iter->second->allocatePoint();
1920:       }
1921:     };
1922:   public: // Communication
1923:     void construct(const int size) {
1924:       const sheaf_type& patches = this->getPatches();

1926:       for(typename sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
1927:         const patch_type         rank    = p_iter->first;
1928:         const Obj<section_type>& section = this->getSection(rank);
1929:         const chart_type&        chart   = section->getChart();

1931:         for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
1932:           section->setFiberDimension(*c_iter, size);
1933:         }
1934:       }
1935:     };
1936:     template<typename Sizer>
1937:     void construct(const Obj<Sizer>& sizer) {
1938:       const sheaf_type& patches = this->getPatches();

1940:       for(typename sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
1941:         const patch_type         rank    = p_iter->first;
1942:         const Obj<section_type>& section = this->getSection(rank);
1943:         const chart_type&        chart   = section->getChart();
1944: 
1945:         for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
1946:           section->setFiberDimension(*c_iter, *(sizer->getSection(rank)->restrictPoint(*c_iter)));
1947:         }
1948:       }
1949:     };
1950:     void constructCommunication(const request_type& requestType) {
1951:       const sheaf_type& patches = this->getPatches();

1953:       for(typename sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
1954:         const patch_type         patch   = p_iter->first;
1955:         const Obj<section_type>& section = this->getSection(patch);
1956:         MPI_Request              request;

1958:         if (requestType == RECEIVE) {
1959:           if (this->_debug) {std::cout <<"["<<this->commRank()<<"] Receiving data(" << section->size() << ") from " << patch << " tag " << this->_tag << std::endl;}
1960:           MPI_Recv_init((void *) section->restrict(), section->size(), this->_datatype, patch, this->_tag, this->comm(), &request);
1961:         } else {
1962:           if (this->_debug) {std::cout <<"["<<this->commRank()<<"] Sending data (" << section->size() << ") to " << patch << " tag " << this->_tag << std::endl;}
1963:           MPI_Send_init((void *) section->restrict(), section->size(), this->_datatype, patch, this->_tag, this->comm(), &request);
1964:         }
1965:         this->_requests[patch] = request;
1966:       }
1967:     };
1968:     void startCommunication() {
1969:       const sheaf_type& patches = this->getPatches();

1971:       for(typename sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
1972:         MPI_Request request = this->_requests[p_iter->first];

1974:         MPI_Start(&request);
1975:       }
1976:     };
1977:     void endCommunication() {
1978:       const sheaf_type& patches = this->getPatches();
1979:       MPI_Status status;

1981:       for(typename sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
1982:         MPI_Request request = this->_requests[p_iter->first];

1984:         MPI_Wait(&request, &status);
1985:       }
1986:     };
1987:   public:
1988:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
1989:       ostringstream txt;
1990:       int rank;

1992:       if (comm == MPI_COMM_NULL) {
1993:         comm = this->comm();
1994:         rank = this->commRank();
1995:       } else {
1996:         MPI_Comm_rank(comm, &rank);
1997:       }
1998:       if (name == "") {
1999:         if(rank == 0) {
2000:           txt << "viewing a Field" << std::endl;
2001:         }
2002:       } else {
2003:         if(rank == 0) {
2004:           txt << "viewing Field '" << name << "'" << std::endl;
2005:         }
2006:       }
2007:       PetscSynchronizedPrintf(comm, txt.str().c_str());
2008:       PetscSynchronizedFlush(comm);
2009:       for(typename sheaf_type::const_iterator p_iter = this->_sheaf.begin(); p_iter != this->_sheaf.end(); ++p_iter) {
2010:         ostringstream txt1;

2012:         txt1 << "[" << this->commRank() << "]: Patch " << p_iter->first << std::endl;
2013:         PetscSynchronizedPrintf(comm, txt1.str().c_str());
2014:         PetscSynchronizedFlush(comm);
2015:         p_iter->second->view("field section", comm);
2016:       }
2017:     };
2018:   };
2019: }

2021: namespace ALECompat {
2022:   namespace New {
2023:     using ALE::Obj;
2024:   // A ConstantSection is the simplest Section
2025:   //   All fibers are dimension 1
2026:   //   All values are equal to a constant
2027:   //     We need no value storage and no communication for completion
2028:   template<typename Topology_, typename Value_>
2029:   class NewConstantSection : public ALE::ParallelObject {
2030:   public:
2031:     typedef Topology_                          topology_type;
2032:     typedef typename topology_type::patch_type patch_type;
2033:     typedef typename topology_type::sieve_type sieve_type;
2034:     typedef typename topology_type::point_type point_type;
2035:     typedef std::set<point_type>               chart_type;
2036:     typedef std::map<patch_type, chart_type>   atlas_type;
2037:     typedef Value_                             value_type;
2038:   protected:
2039:     Obj<topology_type> _topology;
2040:     atlas_type         _atlas;
2041:     chart_type         _emptyChart;
2042:     value_type         _value;
2043:     value_type         _defaultValue;
2044:   public:
2045:     NewConstantSection(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug), _defaultValue(0) {
2046:       this->_topology = new topology_type(comm, debug);
2047:     };
2048:     NewConstantSection(const Obj<topology_type>& topology) : ParallelObject(topology->comm(), topology->debug()), _topology(topology) {};
2049:     NewConstantSection(const Obj<topology_type>& topology, const value_type& value) : ParallelObject(topology->comm(), topology->debug()), _topology(topology), _value(value), _defaultValue(value) {};
2050:     NewConstantSection(const Obj<topology_type>& topology, const value_type& value, const value_type& defaultValue) : ParallelObject(topology->comm(), topology->debug()), _topology(topology), _value(value), _defaultValue(defaultValue) {};
2051:   public: // Verifiers
2052:     void checkPatch(const patch_type& patch) const {
2053:       this->_topology->checkPatch(patch);
2054:       if (this->_atlas.find(patch) == this->_atlas.end()) {
2055:         ostringstream msg;
2056:         msg << "Invalid atlas patch " << patch << std::endl;
2057:         throw ALE::Exception(msg.str().c_str());
2058:       }
2059:     };
2060:     void checkPoint(const patch_type& patch, const point_type& point) const {
2061:       this->checkPatch(patch);
2062:       if (this->_atlas.find(patch)->second.find(point) == this->_atlas.find(patch)->second.end()) {
2063:         ostringstream msg;
2064:         msg << "Invalid section point " << point << std::endl;
2065:         throw ALE::Exception(msg.str().c_str());
2066:       }
2067:     };
2068:     void checkDimension(const int& dim) {
2069:       if (dim != 1) {
2070:         ostringstream msg;
2071:         msg << "Invalid fiber dimension " << dim << " must be 1" << std::endl;
2072:         throw ALE::Exception(msg.str().c_str());
2073:       }
2074:     };
2075:     bool hasPatch(const patch_type& patch) {
2076:       if (this->_atlas.find(patch) == this->_atlas.end()) {
2077:         return false;
2078:       }
2079:       return true;
2080:     };
2081:     bool hasPoint(const patch_type& patch, const point_type& point) const {
2082:       this->checkPatch(patch);
2083:       return this->_atlas.find(patch)->second.count(point) > 0;
2084:     };
2085:     bool hasPoint(const point_type& point) const {
2086:       this->checkPatch(0);
2087:       return this->_atlas.find(0)->second.count(point) > 0;
2088:     };
2089:   public: // Accessors
2090:     const Obj<topology_type>& getTopology() const {return this->_topology;};
2091:     void setTopology(const Obj<topology_type>& topology) {this->_topology = topology;};
2092:     const chart_type& getPatch(const patch_type& patch) {
2093:       if (this->hasPatch(patch)) {
2094:         return this->_atlas[patch];
2095:       }
2096:       return this->_emptyChart;
2097:     };
2098:     void updatePatch(const patch_type& patch, const point_type& point) {
2099:       this->_atlas[patch].insert(point);
2100:     };
2101:     template<typename Points>
2102:     void updatePatch(const patch_type& patch, const Obj<Points>& points) {
2103:       this->_atlas[patch].insert(points->begin(), points->end());
2104:     };
2105:     value_type getDefaultValue() {return this->_defaultValue;};
2106:     void setDefaultValue(const value_type value) {this->_defaultValue = value;};
2107:   public: // Sizes
2108:     void clear() {
2109:       this->_atlas.clear();
2110:     };
2111:     int getFiberDimension(const patch_type& patch, const point_type& p) const {
2112:       if (this->hasPoint(patch, p)) return 1;
2113:       return 0;
2114:     };
2115:     void setFiberDimension(const patch_type& patch, const point_type& p, int dim) {
2116:       this->checkDimension(dim);
2117:       this->updatePatch(patch, p);
2118:     };
2119:     template<typename Sequence>
2120:     void setFiberDimension(const patch_type& patch, const Obj<Sequence>& points, int dim) {
2121:       for(typename topology_type::label_sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
2122:         this->setFiberDimension(patch, *p_iter, dim);
2123:       }
2124:     };
2125:     void addFiberDimension(const patch_type& patch, const point_type& p, int dim) {
2126:       if (this->hasPatch(patch) && (this->_atlas[patch].find(p) != this->_atlas[patch].end())) {
2127:         ostringstream msg;
2128:         msg << "Invalid addition to fiber dimension " << dim << " cannot exceed 1" << std::endl;
2129:         throw ALE::Exception(msg.str().c_str());
2130:       } else {
2131:         this->setFiberDimension(patch, p, dim);
2132:       }
2133:     };
2134:     void setFiberDimensionByDepth(const patch_type& patch, int depth, int dim) {
2135:       this->setFiberDimension(patch, this->_topology->getLabelStratum(patch, "depth", depth), dim);
2136:     };
2137:     void setFiberDimensionByHeight(const patch_type& patch, int height, int dim) {
2138:       this->setFiberDimension(patch, this->_topology->getLabelStratum(patch, "height", height), dim);
2139:     };
2140:     int size(const patch_type& patch) {return this->_atlas[patch].size();};
2141:     int size(const patch_type& patch, const point_type& p) {return this->getFiberDimension(patch, p);};
2142:   public: // Restriction
2143:     const value_type *restrict(const patch_type& patch, const point_type& p) const {
2144:       //std::cout <<"["<<this->commRank()<<"]: Constant restrict ("<<patch<<","<<p<<") from " << std::endl;
2145:       //for(typename chart_type::iterator c_iter = this->_atlas.find(patch)->second.begin(); c_iter != this->_atlas.find(patch)->second.end(); ++c_iter) {
2146:       //  std::cout <<"["<<this->commRank()<<"]:   point " << *c_iter << std::endl;
2147:       //}
2148:       if (this->hasPoint(patch, p)) {
2149:         return &this->_value;
2150:       }
2151:       return &this->_defaultValue;
2152:     };
2153:     const value_type *restrictPoint(const patch_type& patch, const point_type& p) const {return this->restrict(patch, p);};
2154:     const value_type *restrictPoint(const point_type& p) const {return this->restrict(0, p);};
2155:     void update(const patch_type& patch, const point_type& p, const value_type v[]) {
2156:       this->checkPatch(patch);
2157:       this->_value = v[0];
2158:     };
2159:     void updatePoint(const patch_type& patch, const point_type& p, const value_type v[]) {return this->update(patch, p, v);};
2160:     void updateAdd(const patch_type& patch, const point_type& p, const value_type v[]) {
2161:       this->checkPatch(patch);
2162:       this->_value += v[0];
2163:     };
2164:     void updateAddPoint(const patch_type& patch, const point_type& p, const value_type v[]) {return this->updateAdd(patch, p, v);};
2165:   public:
2166:     void copy(const Obj<NewConstantSection>& section) {
2167:       const typename topology_type::sheaf_type& patches = this->_topology->getPatches();

2169:       for(typename topology_type::sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
2170:         const patch_type& patch = p_iter->first;
2171:         if (!section->hasPatch(patch)) continue;
2172:         const chart_type& chart = section->getPatch(patch);

2174:         for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
2175:           this->updatePatch(patch, *c_iter);
2176:         }
2177:         this->_value = section->restrict(patch, *chart.begin())[0];
2178:       }
2179:     };
2180:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
2181:       ostringstream txt;
2182:       int rank;

2184:       if (comm == MPI_COMM_NULL) {
2185:         comm = this->comm();
2186:         rank = this->commRank();
2187:       } else {
2188:         MPI_Comm_rank(comm, &rank);
2189:       }
2190:       if (name == "") {
2191:         if(rank == 0) {
2192:           txt << "viewing a NewConstantSection" << std::endl;
2193:         }
2194:       } else {
2195:         if(rank == 0) {
2196:           txt << "viewing NewConstantSection '" << name << "'" << std::endl;
2197:         }
2198:       }
2199:       const typename topology_type::sheaf_type& sheaf = this->_topology->getPatches();

2201:       for(typename topology_type::sheaf_type::const_iterator p_iter = sheaf.begin(); p_iter != sheaf.end(); ++p_iter) {
2202:         txt <<"["<<this->commRank()<<"]: Patch " << p_iter->first << std::endl;
2203:         txt <<"["<<this->commRank()<<"]:   Value " << this->_value << std::endl;
2204:       }
2205:       PetscSynchronizedPrintf(comm, txt.str().c_str());
2206:       PetscSynchronizedFlush(comm);
2207:     };
2208:   };

2210:   // A UniformSection often acts as an Atlas
2211:   //   All fibers are the same dimension
2212:   //     Note we can use a ConstantSection for this Atlas
2213:   //   Each point may have a different vector
2214:   //     Thus we need storage for values, and hence must implement completion
2215:   template<typename Topology_, typename Value_, int fiberDim = 1>
2216:   class UniformSection : public ALE::ParallelObject {
2217:   public:
2218:     typedef Topology_                              topology_type;
2219:     typedef typename topology_type::patch_type     patch_type;
2220:     typedef typename topology_type::sieve_type     sieve_type;
2221:     typedef typename topology_type::point_type     point_type;
2222:     typedef NewConstantSection<topology_type, int> atlas_type;
2223:     typedef typename atlas_type::chart_type        chart_type;
2224:     typedef Value_                                 value_type;
2225:     typedef struct {value_type v[fiberDim];}       fiber_type;
2226:     typedef std::map<point_type, fiber_type>       array_type;
2227:     typedef std::map<patch_type, array_type>       values_type;
2228:   protected:
2229:     Obj<atlas_type> _atlas;
2230:     values_type     _arrays;
2231:   public:
2232:     UniformSection(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {
2233:       this->_atlas = new atlas_type(comm, debug);
2234:     };
2235:     UniformSection(const Obj<topology_type>& topology) : ParallelObject(topology->comm(), topology->debug()) {
2236:       this->_atlas = new atlas_type(topology, fiberDim, 0);
2237:     };
2238:     UniformSection(const Obj<atlas_type>& atlas) : ParallelObject(atlas->comm(), atlas->debug()), _atlas(atlas) {};
2239:   protected:
2240:     value_type *getRawArray(const int size) {
2241:       static value_type *array   = NULL;
2242:       static int         maxSize = 0;

2244:       if (size > maxSize) {
2245:         maxSize = size;
2246:         if (array) delete [] array;
2247:         array = new value_type[maxSize];
2248:       };
2249:       return array;
2250:     };
2251:   public: // Verifiers
2252:     void checkPatch(const patch_type& patch) {
2253:       this->_atlas->checkPatch(patch);
2254:       if (this->_arrays.find(patch) == this->_arrays.end()) {
2255:         ostringstream msg;
2256:         msg << "Invalid section patch: " << patch << std::endl;
2257:         throw ALE::Exception(msg.str().c_str());
2258:       }
2259:     };
2260:     bool hasPatch(const patch_type& patch) {
2261:       return this->_atlas->hasPatch(patch);
2262:     };
2263:     bool hasPoint(const patch_type& patch, const point_type& point) {
2264:       return this->_atlas->hasPoint(patch, point);
2265:     };
2266:     bool hasPoint(const point_type& point) {
2267:       return this->_atlas->hasPoint(0, point);
2268:     };
2269:     void checkDimension(const int& dim) {
2270:       if (dim != fiberDim) {
2271:         ostringstream msg;
2272:         msg << "Invalid fiber dimension " << dim << " must be " << fiberDim << std::endl;
2273:         throw ALE::Exception(msg.str().c_str());
2274:       }
2275:     };
2276:   public: // Accessors
2277:     const Obj<atlas_type>& getAtlas() {return this->_atlas;};
2278:     void setAtlas(const Obj<atlas_type>& atlas) {this->_atlas = atlas;};
2279:     const Obj<topology_type>& getTopology() {return this->_atlas->getTopology();};
2280:     void setTopology(const Obj<topology_type>& topology) {this->_atlas->setTopology(topology);};
2281:     const chart_type& getPatch(const patch_type& patch) {
2282:       return this->_atlas->getPatch(patch);
2283:     };
2284:     void updatePatch(const patch_type& patch, const point_type& point) {
2285:       this->setFiberDimension(patch, point, 1);
2286:     };
2287:     template<typename Points>
2288:     void updatePatch(const patch_type& patch, const Obj<Points>& points) {
2289:       for(typename Points::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
2290:         this->setFiberDimension(patch, *p_iter, 1);
2291:       }
2292:     };
2293:     void copy(const Obj<UniformSection<Topology_, Value_, fiberDim> >& section) {
2294:       this->getAtlas()->copy(section->getAtlas());
2295:       const typename topology_type::sheaf_type& sheaf = section->getTopology()->getPatches();

2297:       for(typename topology_type::sheaf_type::const_iterator s_iter = sheaf.begin(); s_iter != sheaf.end(); ++s_iter) {
2298:         const patch_type& patch = s_iter->first;
2299:         if (!section->hasPatch(patch)) continue;
2300:         const chart_type& chart = section->getPatch(patch);

2302:         for(typename chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
2303:           this->updatePoint(s_iter->first, *c_iter, section->restrictPoint(s_iter->first, *c_iter));
2304:         }
2305:       }
2306:     };
2307:   public: // Sizes
2308:     void clear() {
2309:       this->_atlas->clear();
2310:       this->_arrays.clear();
2311:     };
2312:     int getFiberDimension(const patch_type& patch, const point_type& p) const {
2313:       // Could check for non-existence here
2314:       return this->_atlas->restrictPoint(patch, p)[0];
2315:     };
2316:     void setFiberDimension(const patch_type& patch, const point_type& p, int dim) {
2317:       this->checkDimension(dim);
2318:       this->_atlas->updatePatch(patch, p);
2319:       this->_atlas->updatePoint(patch, p, &dim);
2320:     };
2321:     template<typename Sequence>
2322:     void setFiberDimension(const patch_type& patch, const Obj<Sequence>& points, int dim) {
2323:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
2324:         this->setFiberDimension(patch, *p_iter, dim);
2325:       }
2326:     };
2327:     void setFiberDimension(const patch_type& patch, const std::set<point_type>& points, int dim) {
2328:       for(typename std::set<point_type>::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
2329:         this->setFiberDimension(patch, *p_iter, dim);
2330:       }
2331:     };
2332:     void addFiberDimension(const patch_type& patch, const point_type& p, int dim) {
2333:       if (this->hasPatch(patch) && (this->_atlas[patch].find(p) != this->_atlas[patch].end())) {
2334:         ostringstream msg;
2335:         msg << "Invalid addition to fiber dimension " << dim << " cannot exceed " << fiberDim << std::endl;
2336:         throw ALE::Exception(msg.str().c_str());
2337:       } else {
2338:         this->setFiberDimension(patch, p, dim);
2339:       }
2340:     };
2341:     void setFiberDimensionByDepth(const patch_type& patch, int depth, int dim) {
2342:       this->setFiberDimension(patch, this->getTopology()->getLabelStratum(patch, "depth", depth), dim);
2343:     };
2344:     void setFiberDimensionByHeight(const patch_type& patch, int height, int dim) {
2345:       this->setFiberDimension(patch, this->getTopology()->getLabelStratum(patch, "height", height), dim);
2346:     };
2347:     int size(const patch_type& patch) {
2348:       const typename atlas_type::chart_type& points = this->_atlas->getPatch(patch);
2349:       int size = 0;

2351:       for(typename atlas_type::chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
2352:         size += this->getFiberDimension(patch, *p_iter);
2353:       }
2354:       return size;
2355:     };
2356:     int size(const patch_type& patch, const point_type& p) {
2357:       const typename atlas_type::chart_type&  points  = this->_atlas->getPatch(patch);
2358:       const Obj<typename sieve_type::coneSet> closure = this->getTopology()->getPatch(patch)->closure(p);
2359:       typename sieve_type::coneSet::iterator  end     = closure->end();
2360:       int size = 0;

2362:       for(typename sieve_type::coneSet::iterator c_iter = closure->begin(); c_iter != end; ++c_iter) {
2363:         if (points.count(*c_iter)) {
2364:           size += this->getFiberDimension(patch, *c_iter);
2365:         }
2366:       }
2367:       return size;
2368:     };
2369:     void orderPatches() {};
2370:   public: // Restriction
2371:     // Return a pointer to the entire contiguous storage array
2372:     const array_type& restrict(const patch_type& patch) {
2373:       this->checkPatch(patch);
2374:       return this->_arrays[patch];
2375:     };
2376:     // Return the values for the closure of this point
2377:     //   use a smart pointer?
2378:     const value_type *restrict(const patch_type& patch, const point_type& p) {
2379:       this->checkPatch(patch);
2380:       const chart_type& chart = this->getPatch(patch);
2381:       array_type& array  = this->_arrays[patch];
2382:       const int   size   = this->size(patch, p);
2383:       value_type *values = this->getRawArray(size);
2384:       int         j      = -1;

2386:       // We could actually ask for the height of the individual point
2387:       if (this->getTopology()->height(patch) < 2) {
2388:         // Avoids only the copy of closure()
2389:         const int& dim = this->_atlas->restrictPoint(patch, p)[0];

2391:         if (chart.count(p)) {
2392:           for(int i = 0; i < dim; ++i) {
2393:             values[++j] = array[p].v[i];
2394:           }
2395:         }
2396:         // Need only the cone
2397:         const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
2398:         typename sieve_type::coneSequence::iterator   end  = cone->end();

2400:         for(typename sieve_type::coneSequence::iterator p_iter = cone->begin(); p_iter != end; ++p_iter) {
2401:           if (chart.count(*p_iter)) {
2402:             const int& dim = this->_atlas->restrictPoint(patch, *p_iter)[0];

2404:             for(int i = 0; i < dim; ++i) {
2405:               values[++j] = array[*p_iter].v[i];
2406:             }
2407:           }
2408:         }
2409:       } else {
2410:         // Right now, we have no way of consistently ordering the closure()
2411:         const Obj<typename sieve_type::coneSet>& closure = this->getTopology()->getPatch(patch)->closure(p);
2412:         typename sieve_type::coneSet::iterator   end     = closure->end();

2414:         for(typename sieve_type::coneSet::iterator p_iter = closure->begin(); p_iter != end; ++p_iter) {
2415:           if (chart.count(*p_iter)) {
2416:             const int& dim = this->_atlas->restrictPoint(patch, *p_iter)[0];

2418:             for(int i = 0; i < dim; ++i) {
2419:               values[++j] = array[*p_iter].v[i];
2420:             }
2421:           }
2422:         }
2423:       }
2424:       if (j != size-1) {
2425:         ostringstream txt;

2427:         txt << "Invalid restrict to point " << p << std::endl;
2428:         txt << "  j " << j << " should be " << (size-1) << std::endl;
2429:         std::cout << txt.str();
2430:         throw ALE::Exception(txt.str().c_str());
2431:       }
2432:       return values;
2433:     };
2434:     void update(const patch_type& patch, const point_type& p, const value_type v[]) {
2435:       this->_atlas->checkPatch(patch);
2436:       const chart_type& chart = this->getPatch(patch);
2437:       array_type& array = this->_arrays[patch];
2438:       int         j     = -1;

2440:       if (this->getTopology()->height(patch) < 2) {
2441:         // Only avoids the copy of closure()
2442:         const int& dim = this->_atlas->restrict(patch, p)[0];

2444:         if (chart.count(p)) {
2445:           for(int i = 0; i < dim; ++i) {
2446:             array[p].v[i] = v[++j];
2447:           }
2448:         }
2449:         // Should be closure()
2450:         const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);

2452:         for(typename sieve_type::coneSequence::iterator p_iter = cone->begin(); p_iter != cone->end(); ++p_iter) {
2453:           if (chart.count(*p_iter)) {
2454:             const int& dim = this->_atlas->restrict(patch, *p_iter)[0];

2456:             for(int i = 0; i < dim; ++i) {
2457:               array[*p_iter].v[i] = v[++j];
2458:             }
2459:           }
2460:         }
2461:       } else {
2462:         throw ALE::Exception("Update is not yet implemented for interpolated sieves");
2463:       }
2464:     };
2465:     void updateAdd(const patch_type& patch, const point_type& p, const value_type v[]) {
2466:       this->_atlas->checkPatch(patch);
2467:       const chart_type& chart = this->getPatch(patch);
2468:       array_type& array = this->_arrays[patch];
2469:       int         j     = -1;

2471:       if (this->getTopology()->height(patch) < 2) {
2472:         // Only avoids the copy of closure()
2473:         const int& dim = this->_atlas->restrict(patch, p)[0];

2475:         if (chart.count(p)) {
2476:           for(int i = 0; i < dim; ++i) {
2477:             array[p].v[i] += v[++j];
2478:           }
2479:         }
2480:         // Should be closure()
2481:         const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);

2483:         for(typename sieve_type::coneSequence::iterator p_iter = cone->begin(); p_iter != cone->end(); ++p_iter) {
2484:           if (chart.count(*p_iter)) {
2485:             const int& dim = this->_atlas->restrict(patch, *p_iter)[0];

2487:             for(int i = 0; i < dim; ++i) {
2488:               array[*p_iter].v[i] += v[++j];
2489:             }
2490:           }
2491:         }
2492:       } else {
2493:         throw ALE::Exception("Not yet implemented for interpolated sieves");
2494:       }
2495:     };
2496:     // Return only the values associated to this point, not its closure
2497:     const value_type *restrictPoint(const patch_type& patch, const point_type& p) {
2498:       this->checkPatch(patch);
2499:       return this->_arrays[patch][p].v;
2500:     };
2501:     const value_type *restrictPoint(const point_type& p) {
2502:       this->checkPatch(0);
2503:       return this->_arrays[0][p].v;
2504:     };
2505:     // Update only the values associated to this point, not its closure
2506:     void updatePoint(const patch_type& patch, const point_type& p, const value_type v[]) {
2507:       this->_atlas->checkPatch(patch);
2508:       for(int i = 0; i < fiberDim; ++i) {
2509:         this->_arrays[patch][p].v[i] = v[i];
2510:       }
2511:     };
2512:     // Update only the values associated to this point, not its closure
2513:     void updateAddPoint(const patch_type& patch, const point_type& p, const value_type v[]) {
2514:       this->_atlas->checkPatch(patch);
2515:       for(int i = 0; i < fiberDim; ++i) {
2516:         this->_arrays[patch][p].v[i] += v[i];
2517:       }
2518:     };
2519:   public:
2520:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) {
2521:       ostringstream txt;
2522:       int rank;

2524:       if (comm == MPI_COMM_NULL) {
2525:         comm = this->comm();
2526:         rank = this->commRank();
2527:       } else {
2528:         MPI_Comm_rank(comm, &rank);
2529:       }
2530:       if (name == "") {
2531:         if(rank == 0) {
2532:           txt << "viewing a UniformSection" << std::endl;
2533:         }
2534:       } else {
2535:         if(rank == 0) {
2536:           txt << "viewing UniformSection '" << name << "'" << std::endl;
2537:         }
2538:       }
2539:       for(typename values_type::const_iterator a_iter = this->_arrays.begin(); a_iter != this->_arrays.end(); ++a_iter) {
2540:         const patch_type& patch = a_iter->first;
2541:         array_type&       array = this->_arrays[patch];

2543:         txt << "[" << this->commRank() << "]: Patch " << patch << std::endl;
2544:         const typename atlas_type::chart_type& chart = this->_atlas->getPatch(patch);

2546:         for(typename atlas_type::chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
2547:           const point_type&                     point = *p_iter;
2548:           const typename atlas_type::value_type dim   = this->_atlas->restrict(patch, point)[0];

2550:           if (dim != 0) {
2551:             txt << "[" << this->commRank() << "]:   " << point << " dim " << dim << "  ";
2552:             for(int i = 0; i < dim; i++) {
2553:               txt << " " << array[point].v[i];
2554:             }
2555:             txt << std::endl;
2556:           }
2557:         }
2558:       }
2559:       PetscSynchronizedPrintf(comm, txt.str().c_str());
2560:       PetscSynchronizedFlush(comm);
2561:     };
2562:   };

2564:     // A Section is our most general construct (more general ones could be envisioned)
2565:     //   The Atlas is a UniformSection of dimension 1 and value type Point
2566:     //     to hold each fiber dimension and offsets into a contiguous patch array
2567:     template<typename Topology_, typename Value_>
2568:     class Section : public ALE::ParallelObject {
2569:     public:
2570:       typedef Topology_                                 topology_type;
2571:       typedef typename topology_type::patch_type        patch_type;
2572:       typedef typename topology_type::sieve_type        sieve_type;
2573:       typedef typename topology_type::point_type        point_type;
2574:       typedef ALE::Point                                index_type;
2575:       typedef UniformSection<topology_type, index_type> atlas_type;
2576:       typedef typename atlas_type::chart_type           chart_type;
2577:       typedef Value_                                    value_type;
2578:       typedef value_type *                              array_type;
2579:       typedef std::map<patch_type, array_type>          values_type;
2580:       typedef std::vector<index_type>                   IndexArray;
2581:     protected:
2582:       Obj<atlas_type> _atlas;
2583:       Obj<atlas_type> _atlasNew;
2584:       values_type     _arrays;
2585:       Obj<IndexArray> _indexArray;
2586:     public:
2587:       Section(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {
2588:         this->_atlas      = new atlas_type(comm, debug);
2589:         this->_atlasNew   = NULL;
2590:         this->_indexArray = new IndexArray();
2591:       };
2592:       Section(const Obj<topology_type>& topology) : ParallelObject(topology->comm(), topology->debug()), _atlasNew(NULL) {
2593:         this->_atlas      = new atlas_type(topology);
2594:         this->_indexArray = new IndexArray();
2595:       };
2596:       Section(const Obj<atlas_type>& atlas) : ParallelObject(atlas->comm(), atlas->debug()), _atlas(atlas), _atlasNew(NULL) {
2597:         this->_indexArray = new IndexArray();
2598:       };
2599:       virtual ~Section() {
2600:         for(typename values_type::iterator a_iter = this->_arrays.begin(); a_iter != this->_arrays.end(); ++a_iter) {
2601:           delete [] a_iter->second;
2602:           a_iter->second = NULL;
2603:         }
2604:       };
2605:     protected:
2606:       value_type *getRawArray(const int size) {
2607:         static value_type *array   = NULL;
2608:         static int         maxSize = 0;

2610:         if (size > maxSize) {
2611:           maxSize = size;
2612:           if (array) delete [] array;
2613:           array = new value_type[maxSize];
2614:         };
2615:         return array;
2616:       };
2617:     public: // Verifiers
2618:       void checkPatch(const patch_type& patch) {
2619:         this->_atlas->checkPatch(patch);
2620:         if (this->_arrays.find(patch) == this->_arrays.end()) {
2621:           ostringstream msg;
2622:           msg << "Invalid section patch: " << patch << std::endl;
2623:           throw ALE::Exception(msg.str().c_str());
2624:         }
2625:       };
2626:       bool hasPatch(const patch_type& patch) {
2627:         return this->_atlas->hasPatch(patch);
2628:       };
2629:     public: // Accessors
2630:       const Obj<atlas_type>& getAtlas() {return this->_atlas;};
2631:       void setAtlas(const Obj<atlas_type>& atlas) {this->_atlas = atlas;};
2632:       const Obj<topology_type>& getTopology() {return this->_atlas->getTopology();};
2633:       void setTopology(const Obj<topology_type>& topology) {this->_atlas->setTopology(topology);};
2634:       const chart_type& getPatch(const patch_type& patch) {
2635:         return this->_atlas->getPatch(patch);
2636:       };
2637:       bool hasPoint(const patch_type& patch, const point_type& point) {
2638:         return this->_atlas->hasPoint(patch, point);
2639:       };
2640:     public: // Sizes
2641:       void clear() {
2642:         this->_atlas->clear();
2643:         this->_arrays.clear();
2644:       };
2645:       int getFiberDimension(const patch_type& patch, const point_type& p) const {
2646:         // Could check for non-existence here
2647:         return this->_atlas->restrictPoint(patch, p)->prefix;
2648:       };
2649:       int getFiberDimension(const Obj<atlas_type>& atlas, const patch_type& patch, const point_type& p) const {
2650:         // Could check for non-existence here
2651:         return atlas->restrictPoint(patch, p)->prefix;
2652:       };
2653:       void setFiberDimension(const patch_type& patch, const point_type& p, int dim) {
2654:         const index_type idx(dim, -1);
2655:         this->_atlas->updatePatch(patch, p);
2656:         this->_atlas->updatePoint(patch, p, &idx);
2657:       };
2658:       template<typename Sequence>
2659:       void setFiberDimension(const patch_type& patch, const Obj<Sequence>& points, int dim) {
2660:         for(typename topology_type::label_sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
2661:           this->setFiberDimension(patch, *p_iter, dim);
2662:         }
2663:       };
2664:       void addFiberDimension(const patch_type& patch, const point_type& p, int dim) {
2665:         if (this->_atlas->hasPatch(patch) && this->_atlas->hasPoint(patch, p)) {
2666:           const index_type values(dim, 0);
2667:           this->_atlas->updateAddPoint(patch, p, &values);
2668:         } else {
2669:           this->setFiberDimension(patch, p, dim);
2670:         }
2671:       };
2672:       void setFiberDimensionByDepth(const patch_type& patch, int depth, int dim) {
2673:         this->setFiberDimension(patch, this->getTopology()->getLabelStratum(patch, "depth", depth), dim);
2674:       };
2675:       void setFiberDimensionByHeight(const patch_type& patch, int height, int dim) {
2676:         this->setFiberDimension(patch, this->getTopology()->getLabelStratum(patch, "height", height), dim);
2677:       };
2678:       int size(const patch_type& patch) {
2679:         const typename atlas_type::chart_type& points = this->_atlas->getPatch(patch);
2680:         int size = 0;

2682:         for(typename atlas_type::chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
2683:           size += std::max(0, this->getFiberDimension(patch, *p_iter));
2684:         }
2685:         return size;
2686:       };
2687:       int sizeWithBC(const patch_type& patch) {
2688:         const typename atlas_type::chart_type& points = this->_atlas->getPatch(patch);
2689:         int size = 0;

2691:         for(typename atlas_type::chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
2692:           size += std::abs(this->getFiberDimension(patch, *p_iter));
2693:         }
2694:         return size;
2695:       };
2696:       int size(const patch_type& patch, const point_type& p) {
2697:         if (this->getTopology()->depth() > 1) throw ALE::Exception("Compatibility layer is not for interpolated meshes");
2698:         const typename atlas_type::chart_type&  points  = this->_atlas->getPatch(patch);
2699:         const Obj<typename sieve_type::coneSequence> closure = this->getTopology()->getPatch(patch)->cone(p);
2700:         typename sieve_type::coneSequence::iterator  end     = closure->end();
2701:         int size = 0;

2703:         size += std::max(0, this->getFiberDimension(patch, p));
2704:         for(typename sieve_type::coneSequence::iterator c_iter = closure->begin(); c_iter != end; ++c_iter) {
2705:           if (points.count(*c_iter)) {
2706:             size += std::max(0, this->getFiberDimension(patch, *c_iter));
2707:           }
2708:         }
2709:         return size;
2710:       };
2711:       int sizeWithBC(const patch_type& patch, const point_type& p) {
2712:         if (this->getTopology()->depth() > 1) throw ALE::Exception("Compatibility layer is not for interpolated meshes");
2713:         const typename atlas_type::chart_type&  points  = this->_atlas->getPatch(patch);
2714:         const Obj<typename sieve_type::coneSequence> closure = this->getTopology()->getPatch(patch)->cone(p);
2715:         typename sieve_type::coneSequence::iterator  end     = closure->end();
2716:         int size = 0;

2718:         size += std::abs(this->getFiberDimension(patch, p));
2719:         for(typename sieve_type::coneSequence::iterator c_iter = closure->begin(); c_iter != end; ++c_iter) {
2720:           if (points.count(*c_iter)) {
2721:             size += std::abs(this->getFiberDimension(patch, *c_iter));
2722:           }
2723:         }
2724:         return size;
2725:       };
2726:       int size(const Obj<atlas_type>& atlas, const patch_type& patch) {
2727:         const typename atlas_type::chart_type& points = atlas->getPatch(patch);
2728:         int size = 0;

2730:         for(typename atlas_type::chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
2731:           size += std::max(0, this->getFiberDimension(atlas, patch, *p_iter));
2732:         }
2733:         return size;
2734:       };
2735:     public: // Index retrieval
2736:       const index_type& getIndex(const patch_type& patch, const point_type& p) {
2737:         this->checkPatch(patch);
2738:         return this->_atlas->restrictPoint(patch, p)[0];
2739:       };
2740:       template<typename Numbering>
2741:       const index_type getIndex(const patch_type& patch, const point_type& p, const Obj<Numbering>& numbering) {
2742:         this->checkPatch(patch);
2743:         return index_type(this->getFiberDimension(patch, p), numbering->getIndex(p));
2744:       };
2745:       const Obj<IndexArray>& getIndices(const patch_type& patch, const point_type& p, const int level = -1) {
2746:         this->_indexArray->clear();

2748:         if (level == 0) {
2749:           this->_indexArray->push_back(this->getIndex(patch, p));
2750:         } else if ((level == 1) || (this->getTopology()->height(patch) == 1)) {
2751:           const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
2752:           typename sieve_type::coneSequence::iterator   end  = cone->end();

2754:           this->_indexArray->push_back(this->getIndex(patch, p));
2755:           for(typename sieve_type::coneSequence::iterator p_iter = cone->begin(); p_iter != end; ++p_iter) {
2756:             this->_indexArray->push_back(this->getIndex(patch, *p_iter));
2757:           }
2758:         } else if (level == -1) {
2759: #if 1
2760:           throw ALE::Exception("Call should be moved to Bundle");
2761: #else
2762:           const Obj<typename sieve_type::coneSet> closure = this->getTopology()->getPatch(patch)->closure(p);
2763:           typename sieve_type::coneSet::iterator  end     = closure->end();

2765:           for(typename sieve_type::coneSet::iterator p_iter = closure->begin(); p_iter != end; ++p_iter) {
2766:             this->_indexArray->push_back(this->getIndex(patch, *p_iter));
2767:           }
2768: #endif
2769:         } else {
2770:           const Obj<typename sieve_type::coneArray> cone = this->getTopology()->getPatch(patch)->nCone(p, level);
2771:           typename sieve_type::coneArray::iterator  end  = cone->end();

2773:           for(typename sieve_type::coneArray::iterator p_iter = cone->begin(); p_iter != end; ++p_iter) {
2774:             this->_indexArray->push_back(this->getIndex(patch, *p_iter));
2775:           }
2776:         }
2777:         return this->_indexArray;
2778:       };
2779:       template<typename Numbering>
2780:       const Obj<IndexArray>& getIndices(const patch_type& patch, const point_type& p, const Obj<Numbering>& numbering, const int level = -1) {
2781:         this->_indexArray->clear();

2783:         if (level == 0) {
2784:           this->_indexArray->push_back(this->getIndex(patch, p, numbering));
2785:         } else if ((level == 1) || (this->getTopology()->height(patch) == 1)) {
2786:           const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
2787:           typename sieve_type::coneSequence::iterator   end  = cone->end();

2789:           this->_indexArray->push_back(this->getIndex(patch, p, numbering));
2790:           for(typename sieve_type::coneSequence::iterator p_iter = cone->begin(); p_iter != end; ++p_iter) {
2791:             this->_indexArray->push_back(this->getIndex(patch, *p_iter, numbering));
2792:           }
2793:         } else if (level == -1) {
2794: #if 1
2795:           throw ALE::Exception("Call should be moved to Bundle");
2796: #else
2797:           const Obj<typename sieve_type::coneSet> closure = this->getTopology()->getPatch(patch)->closure(p);
2798:           typename sieve_type::coneSet::iterator  end     = closure->end();

2800:           for(typename sieve_type::coneSet::iterator p_iter = closure->begin(); p_iter != end; ++p_iter) {
2801:             this->_indexArray->push_back(this->getIndex(patch, *p_iter, numbering));
2802:           }
2803: #endif
2804:         } else {
2805:           const Obj<typename sieve_type::coneArray> cone = this->getTopology()->getPatch(patch)->nCone(p, level);
2806:           typename sieve_type::coneArray::iterator  end  = cone->end();

2808:           for(typename sieve_type::coneArray::iterator p_iter = cone->begin(); p_iter != end; ++p_iter) {
2809:             this->_indexArray->push_back(this->getIndex(patch, *p_iter, numbering));
2810:           }
2811:         }
2812:         return this->_indexArray;
2813:       };
2814:     public: // Allocation
2815:       void orderPoint(const Obj<atlas_type>& atlas, const Obj<sieve_type>& sieve, const patch_type& patch, const point_type& point, typename atlas_type::value_type::index_type& offset, typename atlas_type::value_type::index_type& bcOffset, const bool postponeGhosts = false) {
2816:         const Obj<typename sieve_type::coneSequence>& cone = sieve->cone(point);
2817:         typename sieve_type::coneSequence::iterator   end  = cone->end();
2818:         index_type                                    idx  = atlas->restrictPoint(patch, point)[0];
2819:         const int&                                    dim  = idx.prefix;
2820:         const index_type                              defaultIdx(0, -1);

2822:         if (atlas->getPatch(patch).count(point) == 0) {
2823:           idx = defaultIdx;
2824:         }
2825:         if (idx.index == -1) {
2826:           for(typename sieve_type::coneSequence::iterator c_iter = cone->begin(); c_iter != end; ++c_iter) {
2827:             if (this->_debug > 1) {std::cout << "    Recursing to " << *c_iter << std::endl;}
2828:             this->orderPoint(atlas, sieve, patch, *c_iter, offset, bcOffset);
2829:           }
2830:           if (dim > 0) {
2831:             bool number = true;

2833:             // Maybe use template specialization here
2834:             if (postponeGhosts && this->getTopology()->getSendOverlap()->capContains(point)) {
2835:               const Obj<typename topology_type::send_overlap_type::supportSequence>& ranks = this->getTopology()->getSendOverlap()->support(point);

2837:               for(typename topology_type::send_overlap_type::supportSequence::iterator r_iter = ranks->begin(); r_iter != ranks->end(); ++r_iter) {
2838:                 if (this->commRank() > *r_iter) {
2839:                   number = false;
2840:                   break;
2841:                 }
2842:               }
2843:             }
2844:             if (number) {
2845:               if (this->_debug > 1) {std::cout << "  Ordering point " << point << " at " << offset << std::endl;}
2846:               idx.index = offset;
2847:               atlas->updatePoint(patch, point, &idx);
2848:               offset += dim;
2849:             } else {
2850:               if (this->_debug > 1) {std::cout << "  Ignoring ghost point " << point << std::endl;}
2851:             }
2852:           } else if (dim < 0) {
2853:             if (this->_debug > 1) {std::cout << "  Ordering boundary point " << point << " at " << bcOffset << std::endl;}
2854:             idx.index = bcOffset;
2855:             atlas->updatePoint(patch, point, &idx);
2856:             bcOffset += dim;
2857:           }
2858:         }
2859:       }
2860:       void orderPatch(const Obj<atlas_type>& atlas, const patch_type& patch, typename atlas_type::value_type::index_type& offset, typename atlas_type::value_type::index_type& bcOffset, const bool postponeGhosts = false) {
2861:         const typename atlas_type::chart_type& chart = atlas->getPatch(patch);

2863:         for(typename atlas_type::chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
2864:           if (this->_debug > 1) {std::cout << "Ordering closure of point " << *p_iter << std::endl;}
2865:           this->orderPoint(atlas, this->getTopology()->getPatch(patch), patch, *p_iter, offset, bcOffset, postponeGhosts);
2866:         }
2867:         for(typename atlas_type::chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
2868:           index_type idx = atlas->restrictPoint(patch, *p_iter)[0];
2869:           const int& dim = idx.prefix;

2871:           if (dim < 0) {
2872:             if (this->_debug > 1) {std::cout << "Correcting boundary offset of point " << *p_iter << std::endl;}
2873:             idx.index = offset - (idx.index+2);
2874:             atlas->updatePoint(patch, *p_iter, &idx);
2875:           }
2876:         }
2877:       };
2878:       void orderPatches(const Obj<atlas_type>& atlas, const bool postponeGhosts = false) {
2879:         const typename topology_type::sheaf_type& patches = this->getTopology()->getPatches();

2881:         for(typename topology_type::sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
2882:           if (this->_debug > 1) {std::cout << "Ordering patch " << p_iter->first << std::endl;}
2883:           typename atlas_type::value_type::index_type offset = 0, bcOffset = -2;

2885:           if (!atlas->hasPatch(p_iter->first)) continue;
2886:           this->orderPatch(atlas, p_iter->first, offset, bcOffset, postponeGhosts);
2887:         }
2888:       };
2889:       void orderPatches(const bool postponeGhosts = false) {
2890:         this->orderPatches(this->_atlas, postponeGhosts);
2891:       };
2892:       void allocateStorage() {
2893:         const typename topology_type::sheaf_type& patches = this->getTopology()->getPatches();

2895:         for(typename topology_type::sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
2896:           if (!this->_atlas->hasPatch(p_iter->first)) continue;
2897:           this->_arrays[p_iter->first] = new value_type[this->sizeWithBC(p_iter->first)];
2898:           PetscMemzero(this->_arrays[p_iter->first], this->sizeWithBC(p_iter->first) * sizeof(value_type));
2899:         }
2900:       };
2901:       void allocate(const bool postponeGhosts = false) {
2902:         bool doGhosts = false;

2904:         if (postponeGhosts && !this->getTopology()->getSendOverlap().isNull()) {
2905:           doGhosts = true;
2906:         }
2907:         this->orderPatches(doGhosts);
2908:         if (doGhosts) {
2909:           const typename topology_type::sheaf_type& patches = this->getTopology()->getPatches();

2911:           for(typename topology_type::sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
2912:             if (this->_debug > 1) {std::cout << "Ordering patch " << p_iter->first << " for ghosts" << std::endl;}
2913:             const typename atlas_type::chart_type& points = this->_atlas->getPatch(p_iter->first);
2914:             typename atlas_type::value_type::index_type offset = 0, bcOffset = -2;

2916:             for(typename atlas_type::chart_type::iterator point = points.begin(); point != points.end(); ++point) {
2917:               const index_type& idx = this->_atlas->restrictPoint(p_iter->first, *point)[0];

2919:               offset = std::max(offset, idx.index + std::abs(idx.prefix));
2920:             }
2921:             if (!this->_atlas->hasPatch(p_iter->first)) continue;
2922:             this->orderPatch(this->_atlas, p_iter->first, offset, bcOffset);
2923:             if (offset != this->sizeWithBC(p_iter->first)) throw ALE::Exception("Inconsistent array sizes in section");
2924:           }
2925:         }
2926:         this->allocateStorage();
2927:       };
2928:       void addPoint(const patch_type& patch, const point_type& point, const int dim) {
2929:         if (dim == 0) return;
2930:         //const typename atlas_type::chart_type& chart = this->_atlas->getPatch(patch);

2932:         //if (chart.find(point) == chart.end()) {
2933:         if (this->_atlasNew.isNull()) {
2934:           this->_atlasNew = new atlas_type(this->getTopology());
2935:           this->_atlasNew->copy(this->_atlas);
2936:         }
2937:         const index_type idx(dim, -1);
2938:         this->_atlasNew->updatePatch(patch, point);
2939:         this->_atlasNew->updatePoint(patch, point, &idx);
2940:       };
2941:       void reallocate() {
2942:         if (this->_atlasNew.isNull()) return;
2943:         const typename topology_type::sheaf_type& patches = this->getTopology()->getPatches();

2945:         // Since copy() preserves offsets, we must reinitialize them before ordering
2946:         for(typename topology_type::sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
2947:           const patch_type&                      patch = p_iter->first;
2948:           const typename atlas_type::chart_type& chart = this->_atlasNew->getPatch(patch);
2949:           index_type                             defaultIdx(0, -1);

2951:           for(typename atlas_type::chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
2952:             defaultIdx.prefix = this->_atlasNew->restrictPoint(patch, *c_iter)[0].prefix;
2953:             this->_atlasNew->updatePoint(patch, *c_iter, &defaultIdx);
2954:           }
2955:         }
2956:         this->orderPatches(this->_atlasNew);
2957:         // Copy over existing values
2958:         for(typename topology_type::sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
2959:           const patch_type&                      patch    = p_iter->first;
2960:           value_type                            *newArray = new value_type[this->size(this->_atlasNew, patch)];

2962:           if (!this->_atlas->hasPatch(patch)) {
2963:             this->_arrays[patch] = newArray;
2964:             continue;
2965:           }
2966:           const typename atlas_type::chart_type& chart    = this->_atlas->getPatch(patch);
2967:           const value_type                      *array    = this->_arrays[patch];

2969:           for(typename atlas_type::chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
2970:             const index_type& idx       = this->_atlas->restrictPoint(patch, *c_iter)[0];
2971:             const int         size      = idx.prefix;
2972:             const int         offset    = idx.index;
2973:             const int&        newOffset = this->_atlasNew->restrictPoint(patch, *c_iter)[0].index;

2975:             for(int i = 0; i < size; ++i) {
2976:               newArray[newOffset+i] = array[offset+i];
2977:             }
2978:           }
2979:           delete [] this->_arrays[patch];
2980:           this->_arrays[patch] = newArray;
2981:         }
2982:         this->_atlas    = this->_atlasNew;
2983:         this->_atlasNew = NULL;
2984:       };
2985:     public: // Restriction and Update
2986:       // Zero entries
2987:       void zero(const patch_type& patch) {
2988:         this->checkPatch(patch);
2989:         memset(this->_arrays[patch], 0, this->size(patch)* sizeof(value_type));
2990:       };
2991:       // Return a pointer to the entire contiguous storage array
2992:       const value_type *restrict(const patch_type& patch) {
2993:         this->checkPatch(patch);
2994:         return this->_arrays[patch];
2995:       };
2996:       // Update the entire contiguous storage array
2997:       void update(const patch_type& patch, const value_type v[]) {
2998:         const value_type *array = this->_arrays[patch];
2999:         const int         size  = this->size(patch);

3001:         for(int i = 0; i < size; i++) {
3002:           array[i] = v[i];
3003:         }
3004:       };
3005:       // Return the values for the closure of this point
3006:       //   use a smart pointer?
3007:       const value_type *restrict(const patch_type& patch, const point_type& p) {
3008:         this->checkPatch(patch);
3009:         const value_type *a      = this->_arrays[patch];
3010:         const int         size   = this->sizeWithBC(patch, p);
3011:         value_type       *values = this->getRawArray(size);
3012:         int               j      = -1;

3014:         if (this->getTopology()->height(patch) < 2) {
3015:           // Avoids the copy of both
3016:           //   points  in topology->closure()
3017:           //   indices in _atlas->restrict()
3018:           const index_type& pInd = this->_atlas->restrictPoint(patch, p)[0];

3020:           for(int i = pInd.index; i < std::abs(pInd.prefix) + pInd.index; ++i) {
3021:             values[++j] = a[i];
3022:           }
3023:           const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
3024:           typename sieve_type::coneSequence::iterator   end  = cone->end();

3026:           for(typename sieve_type::coneSequence::iterator p_iter = cone->begin(); p_iter != end; ++p_iter) {
3027:             const index_type& ind    = this->_atlas->restrictPoint(patch, *p_iter)[0];
3028:             const int&        start  = ind.index;
3029:             const int&        length = std::abs(ind.prefix);

3031:             for(int i = start; i < start + length; ++i) {
3032:               values[++j] = a[i];
3033:             }
3034:           }
3035:         } else {
3036:           const Obj<IndexArray>& ind = this->getIndices(patch, p);

3038:           for(typename IndexArray::iterator i_iter = ind->begin(); i_iter != ind->end(); ++i_iter) {
3039:             const int& start  = i_iter->index;
3040:             const int& length = std::abs(i_iter->prefix);

3042:             for(int i = start; i < start + length; ++i) {
3043:               values[++j] = a[i];
3044:             }
3045:           }
3046:         }
3047:         if (j != size-1) {
3048:           ostringstream txt;

3050:           txt << "Invalid restrict to point " << p << std::endl;
3051:           txt << "  j " << j << " should be " << (size-1) << std::endl;
3052:           std::cout << txt.str();
3053:           throw ALE::Exception(txt.str().c_str());
3054:         }
3055:         return values;
3056:       };
3057:       // Update the values for the closure of this point
3058:       void update(const patch_type& patch, const point_type& p, const value_type v[]) {
3059:         this->checkPatch(patch);
3060:         value_type *a = this->_arrays[patch];
3061:         int         j = -1;

3063:         if (this->getTopology()->height(patch) < 2) {
3064:           // Avoids the copy of both
3065:           //   points  in topology->closure()
3066:           //   indices in _atlas->restrict()
3067:           const index_type& pInd = this->_atlas->restrictPoint(patch, p)[0];

3069:           for(int i = pInd.index; i < pInd.prefix + pInd.index; ++i) {
3070:             a[i] = v[++j];
3071:           }
3072:           j += std::max(0, -pInd.prefix);
3073:           const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
3074:           typename sieve_type::coneSequence::iterator   end  = cone->end();

3076:           for(typename sieve_type::coneSequence::iterator p_iter = cone->begin(); p_iter != end; ++p_iter) {
3077:             const index_type& ind    = this->_atlas->restrictPoint(patch, *p_iter)[0];
3078:             const int&        start  = ind.index;
3079:             const int&        length = ind.prefix;

3081:             for(int i = start; i < start + length; ++i) {
3082:               a[i] = v[++j];
3083:             }
3084:             j += std::max(0, -length);
3085:           }
3086:         } else {
3087:           const Obj<IndexArray>& ind = this->getIndices(patch, p);

3089:           for(typename IndexArray::iterator i_iter = ind->begin(); i_iter != ind->end(); ++i_iter) {
3090:             const int& start  = i_iter->index;
3091:             const int& length = i_iter->prefix;

3093:             for(int i = start; i < start + length; ++i) {
3094:               a[i] = v[++j];
3095:             }
3096:             j += std::max(0, -length);
3097:           }
3098:         }
3099:       };
3100:       // Update the values for the closure of this point
3101:       void updateAdd(const patch_type& patch, const point_type& p, const value_type v[]) {
3102:         this->checkPatch(patch);
3103:         value_type *a = this->_arrays[patch];
3104:         int         j = -1;

3106:         if (this->getTopology()->height(patch) < 2) {
3107:           // Avoids the copy of both
3108:           //   points  in topology->closure()
3109:           //   indices in _atlas->restrict()
3110:           const index_type& pInd = this->_atlas->restrictPoint(patch, p)[0];

3112:           for(int i = pInd.index; i < pInd.prefix + pInd.index; ++i) {
3113:             a[i] += v[++j];
3114:           }
3115:           j += std::max(0, -pInd.prefix);
3116:           const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
3117:           typename sieve_type::coneSequence::iterator   end  = cone->end();

3119:           for(typename sieve_type::coneSequence::iterator p_iter = cone->begin(); p_iter != end; ++p_iter) {
3120:             const index_type& ind    = this->_atlas->restrictPoint(patch, *p_iter)[0];
3121:             const int&        start  = ind.index;
3122:             const int&        length = ind.prefix;

3124:             for(int i = start; i < start + length; ++i) {
3125:               a[i] += v[++j];
3126:             }
3127:             j += std::max(0, -length);
3128:           }
3129:         } else {
3130:           const Obj<IndexArray>& ind = this->getIndices(patch, p);

3132:           for(typename IndexArray::iterator i_iter = ind->begin(); i_iter != ind->end(); ++i_iter) {
3133:             const int& start  = i_iter->index;
3134:             const int& length = i_iter->prefix;

3136:             for(int i = start; i < start + length; ++i) {
3137:               a[i] += v[++j];
3138:             }
3139:             j += std::max(0, -length);
3140:           }
3141:         }
3142:       };
3143:       // Update the values for the closure of this point
3144:       template<typename Input>
3145:       void update(const patch_type& patch, const point_type& p, const Obj<Input>& v) {
3146:         this->checkPatch(patch);
3147:         value_type *a = this->_arrays[patch];

3149:         if (this->getTopology()->height(patch) == 1) {
3150:           // Only avoids the copy
3151:           const index_type& pInd = this->_atlas->restrictPoint(patch, p)[0];
3152:           typename Input::iterator v_iter = v->begin();
3153:           typename Input::iterator v_end  = v->end();

3155:           for(int i = pInd.index; i < pInd.prefix + pInd.index; ++i) {
3156:             a[i] = *v_iter;
3157:             ++v_iter;
3158:           }
3159:           const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
3160:           typename sieve_type::coneSequence::iterator   end  = cone->end();

3162:           for(typename sieve_type::coneSequence::iterator p_iter = cone->begin(); p_iter != end; ++p_iter) {
3163:             const index_type& ind    = this->_atlas->restrictPoint(patch, *p_iter)[0];
3164:             const int&        start  = ind.index;
3165:             const int&        length = ind.prefix;

3167:             for(int i = start; i < start + length; ++i) {
3168:               a[i] = *v_iter;
3169:               ++v_iter;
3170:             }
3171:           }
3172:         } else {
3173:           const Obj<IndexArray>& ind = this->getIndices(patch, p);
3174:           typename Input::iterator v_iter = v->begin();
3175:           typename Input::iterator v_end  = v->end();

3177:           for(typename IndexArray::iterator i_iter = ind->begin(); i_iter != ind->end(); ++i_iter) {
3178:             const int& start  = i_iter->index;
3179:             const int& length = i_iter->prefix;

3181:             for(int i = start; i < start + length; ++i) {
3182:               a[i] = *v_iter;
3183:               ++v_iter;
3184:             }
3185:           }
3186:         }
3187:       };
3188:       void updateBC(const patch_type& patch, const point_type& p, const value_type v[]) {
3189:         this->checkPatch(patch);
3190:         value_type *a = this->_arrays[patch];
3191:         int         j = -1;

3193:         if (this->getTopology()->height(patch) < 2) {
3194:           // Avoids the copy of both
3195:           //   points  in topology->closure()
3196:           //   indices in _atlas->restrict()
3197:           const index_type& pInd = this->_atlas->restrictPoint(patch, p)[0];

3199:           for(int i = pInd.index; i < std::abs(pInd.prefix) + pInd.index; ++i) {
3200:             a[i] = v[++j];
3201:           }
3202:           const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
3203:           typename sieve_type::coneSequence::iterator   end  = cone->end();

3205:           for(typename sieve_type::coneSequence::iterator p_iter = cone->begin(); p_iter != end; ++p_iter) {
3206:             const index_type& ind    = this->_atlas->restrictPoint(patch, *p_iter)[0];
3207:             const int&        start  = ind.index;
3208:             const int&        length = std::abs(ind.prefix);

3210:             for(int i = start; i < start + length; ++i) {
3211:               a[i] = v[++j];
3212:             }
3213:           }
3214:         } else {
3215:           const Obj<IndexArray>& ind = this->getIndices(patch, p);

3217:           for(typename IndexArray::iterator i_iter = ind->begin(); i_iter != ind->end(); ++i_iter) {
3218:             const int& start  = i_iter->index;
3219:             const int& length = std::abs(i_iter->prefix);

3221:             for(int i = start; i < start + length; ++i) {
3222:               a[i] = v[++j];
3223:             }
3224:           }
3225:         }
3226:       };
3227:       // Return only the values associated to this point, not its closure
3228:       const value_type *restrictPoint(const patch_type& patch, const point_type& p) {
3229:         this->checkPatch(patch);
3230:         return &(this->_arrays[patch][this->_atlas->restrictPoint(patch, p)[0].index]);
3231:       };
3232:       // Update only the values associated to this point, not its closure
3233:       void updatePoint(const patch_type& patch, const point_type& p, const value_type v[]) {
3234:         this->checkPatch(patch);
3235:         const index_type& idx = this->_atlas->restrictPoint(patch, p)[0];
3236:         value_type       *a   = &(this->_arrays[patch][idx.index]);

3238:         for(int i = 0; i < idx.prefix; ++i) {
3239:           a[i] = v[i];
3240:         }
3241:       };
3242:       // Update only the values associated to this point, not its closure
3243:       void updateAddPoint(const patch_type& patch, const point_type& p, const value_type v[]) {
3244:         this->checkPatch(patch);
3245:         const index_type& idx = this->_atlas->restrictPoint(patch, p)[0];
3246:         value_type       *a   = &(this->_arrays[patch][idx.index]);

3248:         for(int i = 0; i < idx.prefix; ++i) {
3249:           a[i] += v[i];
3250:         }
3251:       };
3252:       void updatePointBC(const patch_type& patch, const point_type& p, const value_type v[]) {
3253:         this->checkPatch(patch);
3254:         const index_type& idx = this->_atlas->restrictPoint(patch, p)[0];
3255:         value_type       *a   = &(this->_arrays[patch][idx.index]);

3257:         for(int i = 0; i < std::abs(idx.prefix); ++i) {
3258:           a[i] = v[i];
3259:         }
3260:       };
3261:     public: // BC
3262:       void copyBC(const Obj<Section>& section) {
3263:         const typename topology_type::sheaf_type& patches = this->getTopology()->getPatches();

3265:         for(typename topology_type::sheaf_type::const_iterator patch_iter = patches.begin(); patch_iter != patches.end(); ++patch_iter) {
3266:           const typename atlas_type::chart_type& chart = this->_atlas->getPatch(patch_iter->first);

3268:           for(typename atlas_type::chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
3269:             const index_type& idx = this->_atlas->restrictPoint(patch_iter->first, *p_iter)[0];

3271:             if (idx.prefix < 0) {
3272:               this->updatePointBC(patch_iter->first, *p_iter, section->restrictPoint(patch_iter->first, *p_iter));
3273:             }
3274:           }
3275:         }
3276:       };
3277:     public:
3278:       void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
3279:         ostringstream txt;
3280:         int rank;

3282:         if (comm == MPI_COMM_NULL) {
3283:           comm = this->comm();
3284:           rank = this->commRank();
3285:         } else {
3286:           MPI_Comm_rank(comm, &rank);
3287:         }
3288:         if (name == "") {
3289:           if(rank == 0) {
3290:             txt << "viewing a Section" << std::endl;
3291:           }
3292:         } else {
3293:           if(rank == 0) {
3294:             txt << "viewing Section '" << name << "'" << std::endl;
3295:           }
3296:         }
3297:         for(typename values_type::const_iterator a_iter = this->_arrays.begin(); a_iter != this->_arrays.end(); ++a_iter) {
3298:           const patch_type&  patch = a_iter->first;
3299:           const value_type  *array = a_iter->second;

3301:           txt << "[" << this->commRank() << "]: Patch " << patch << std::endl;
3302:           const typename atlas_type::chart_type& chart = this->_atlas->getPatch(patch);

3304:           for(typename atlas_type::chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
3305:             const point_type& point = *p_iter;
3306:             const index_type& idx   = this->_atlas->restrictPoint(patch, point)[0];

3308:             if (idx.prefix != 0) {
3309:               txt << "[" << this->commRank() << "]:   " << point << " dim " << idx.prefix << " offset " << idx.index << "  ";
3310:               for(int i = 0; i < std::abs(idx.prefix); i++) {
3311:                 txt << " " << array[idx.index+i];
3312:               }
3313:               txt << std::endl;
3314:             }
3315:           }
3316:         }
3317:         if (this->_arrays.empty()) {
3318:           txt << "[" << this->commRank() << "]: empty" << std::endl;
3319:         }
3320:         PetscSynchronizedPrintf(comm, txt.str().c_str());
3321:         PetscSynchronizedFlush(comm);
3322:       };
3323:     };

3325:     // An Overlap is a Sifter describing the overlap of two Sieves
3326:     //   Each arrow is local point ---(remote point)---> remote rank right now
3327:     //     For XSifter, this should change to (local patch, local point) ---> (remote rank, remote patch, remote point)

3329:     template<typename Topology_, typename Value_>
3330:     class OldConstantSection : public ALE::ParallelObject {
3331:     public:
3332:       typedef OldConstantSection<Topology_, Value_> section_type;
3333:       typedef Topology_                          topology_type;
3334:       typedef typename topology_type::patch_type patch_type;
3335:       typedef typename topology_type::sieve_type sieve_type;
3336:       typedef typename topology_type::point_type point_type;
3337:       typedef Value_                             value_type;
3338:     protected:
3339:       Obj<topology_type> _topology;
3340:       const value_type   _value;
3341:       Obj<section_type>  _section;
3342:     public:
3343:       OldConstantSection(MPI_Comm comm, const value_type value, const int debug = 0) : ParallelObject(comm, debug), _value(value) {
3344:         this->_topology = new topology_type(comm, debug);
3345:         this->_section  = this;
3346:         this->_section.addRef();
3347:       };
3348:       OldConstantSection(const Obj<topology_type>& topology, const value_type value) : ParallelObject(topology->comm(), topology->debug()), _topology(topology), _value(value) {
3349:         this->_section  = this;
3350:         this->_section.addRef();
3351:       };
3352:       virtual ~OldConstantSection() {};
3353:     public: // Verifiers
3354:       bool hasPoint(const patch_type& patch, const point_type& point) const {return true;};
3355:     public: // Restriction
3356:       const value_type *restrict(const patch_type& patch) {return &this->_value;};
3357:       const value_type *restrictPoint(const patch_type& patch, const point_type& p) {return &this->_value;};
3358:     public: // Adapter
3359:       const Obj<section_type>& getSection(const patch_type& patch) {return this->_section;};
3360:       const value_type *restrictPoint(const point_type& p) {return &this->_value;};
3361:     public:
3362:       void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
3363:         ostringstream txt;
3364:         int rank;

3366:         if (comm == MPI_COMM_NULL) {
3367:           comm = this->comm();
3368:           rank = this->commRank();
3369:         } else {
3370:           MPI_Comm_rank(comm, &rank);
3371:         }
3372:         if (name == "") {
3373:           if(rank == 0) {
3374:             txt << "viewing a OldConstantSection with value " << this->_value << std::endl;
3375:           }
3376:         } else {
3377:           if(rank == 0) {
3378:             txt << "viewing OldConstantSection '" << name << "' with value " << this->_value << std::endl;
3379:           }
3380:         }
3381:         PetscSynchronizedPrintf(comm, txt.str().c_str());
3382:         PetscSynchronizedFlush(comm);
3383:       };
3384:     };

3386:     template<typename Overlap_, typename Topology_, typename Value_>
3387:     class OverlapValues : public Section<Topology_, Value_> {
3388:     public:
3389:       typedef Overlap_                          overlap_type;
3390:       typedef Section<Topology_, Value_>        base_type;
3391:       typedef typename base_type::topology_type topology_type;
3392:       typedef typename base_type::patch_type    patch_type;
3393:       typedef typename base_type::chart_type    chart_type;
3394:       typedef typename base_type::atlas_type    atlas_type;
3395:       typedef typename base_type::value_type    value_type;
3396:       typedef enum {SEND, RECEIVE}              request_type;
3397:       typedef std::map<patch_type, MPI_Request> requests_type;
3398:     protected:
3399:       int           _tag;
3400:       MPI_Datatype  _datatype;
3401:       requests_type _requests;
3402:     public:
3403:       OverlapValues(MPI_Comm comm, const int debug = 0) : Section<Topology_, Value_>(comm, debug) {
3404:         this->_tag      = this->getNewTag();
3405:         this->_datatype = this->getMPIDatatype();
3406:       };
3407:       OverlapValues(MPI_Comm comm, const int tag, const int debug) : Section<Topology_, Value_>(comm, debug), _tag(tag) {
3408:         this->_datatype = this->getMPIDatatype();
3409:       };
3410:       virtual ~OverlapValues() {};
3411:     protected:
3412:       MPI_Datatype getMPIDatatype() {
3413:         if (sizeof(value_type) == 4) {
3414:           return MPI_INT;
3415:         } else if (sizeof(value_type) == 8) {
3416:           return MPI_DOUBLE;
3417:         } else if (sizeof(value_type) == 28) {
3418:           int          blen[2];
3419:           MPI_Aint     indices[2];
3420:           MPI_Datatype oldtypes[2], newtype;
3421:           blen[0] = 1; indices[0] = 0;           oldtypes[0] = MPI_INT;
3422:           blen[1] = 3; indices[1] = sizeof(int); oldtypes[1] = MPI_DOUBLE;
3423:           MPI_Type_struct(2, blen, indices, oldtypes, &newtype);
3424:           MPI_Type_commit(&newtype);
3425:           return newtype;
3426:         } else if (sizeof(value_type) == 32) {
3427:           int          blen[2];
3428:           MPI_Aint     indices[2];
3429:           MPI_Datatype oldtypes[2], newtype;
3430:           blen[0] = 1; indices[0] = 0;           oldtypes[0] = MPI_DOUBLE;
3431:           blen[1] = 3; indices[1] = sizeof(int); oldtypes[1] = MPI_DOUBLE;
3432:           MPI_Type_struct(2, blen, indices, oldtypes, &newtype);
3433:           MPI_Type_commit(&newtype);
3434:           return newtype;
3435:         }
3436:         throw ALE::Exception("Cannot determine MPI type for value type");
3437:       };
3438:       int getNewTag() {
3439:         static int tagKeyval = MPI_KEYVAL_INVALID;
3440:         int *tagvalp = NULL, *maxval, flg;

3442:         if (tagKeyval == MPI_KEYVAL_INVALID) {
3443:           tagvalp = (int *) malloc(sizeof(int));
3444:           MPI_Keyval_create(MPI_NULL_COPY_FN, Mesh_DelTag, &tagKeyval, (void *) NULL);
3445:           MPI_Attr_put(this->_comm, tagKeyval, tagvalp);
3446:           tagvalp[0] = 0;
3447:         }
3448:         MPI_Attr_get(this->_comm, tagKeyval, (void **) &tagvalp, &flg);
3449:         if (tagvalp[0] < 1) {
3450:           MPI_Attr_get(MPI_COMM_WORLD, MPI_TAG_UB, (void **) &maxval, &flg);
3451:           tagvalp[0] = *maxval - 128; // hope that any still active tags were issued right at the beginning of the run
3452:         }
3453:         if (this->debug()) {
3454:           std::cout << "[" << this->commRank() << "]Got new tag " << tagvalp[0] << std::endl;
3455:         }
3456:         return tagvalp[0]--;
3457:       };
3458:     public: // Accessors
3459:       int getTag() const {return this->_tag;};
3460:       void setTag(const int tag) {this->_tag = tag;};
3461:     public:
3462:       void construct(const int size) {
3463:         const typename topology_type::sheaf_type& patches = this->getTopology()->getPatches();

3465:         for(typename topology_type::sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
3466:           const Obj<typename topology_type::sieve_type::baseSequence>& base = p_iter->second->base();
3467:           int                                  rank = p_iter->first;

3469:           for(typename topology_type::sieve_type::baseSequence::iterator b_iter = base->begin(); b_iter != base->end(); ++b_iter) {
3470:             this->setFiberDimension(rank, *b_iter, size);
3471:           }
3472:         }
3473:       };
3474:       template<typename Sizer>
3475:       void construct(const Obj<Sizer>& sizer) {
3476:         const typename topology_type::sheaf_type& patches = this->getTopology()->getPatches();

3478:         for(typename topology_type::sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
3479:           const Obj<typename topology_type::sieve_type::baseSequence>& base = p_iter->second->base();
3480:           int                                  rank = p_iter->first;

3482:           for(typename topology_type::sieve_type::baseSequence::iterator b_iter = base->begin(); b_iter != base->end(); ++b_iter) {
3483:             this->setFiberDimension(rank, *b_iter, *(sizer->restrictPoint(rank, *b_iter)));
3484:           }
3485:         }
3486:       };
3487:       void constructCommunication(const request_type& requestType) {
3488:         const typename topology_type::sheaf_type& patches = this->getAtlas()->getTopology()->getPatches();

3490:         for(typename topology_type::sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
3491:           const patch_type patch = p_iter->first;
3492:           MPI_Request request;

3494:           if (requestType == RECEIVE) {
3495:             if (this->_debug) {std::cout <<"["<<this->commRank()<<"] Receiving data(" << this->size(patch) << ") from " << patch << " tag " << this->_tag << std::endl;}
3496:             MPI_Recv_init(this->_arrays[patch], this->size(patch), this->_datatype, patch, this->_tag, this->_comm, &request);
3497:           } else {
3498:             if (this->_debug) {std::cout <<"["<<this->commRank()<<"] Sending data (" << this->size(patch) << ") to " << patch << " tag " << this->_tag << std::endl;}
3499:             MPI_Send_init(this->_arrays[patch], this->size(patch), this->_datatype, patch, this->_tag, this->_comm, &request);
3500:           }
3501:           this->_requests[patch] = request;
3502:         }
3503:       };
3504:       void startCommunication() {
3505:         const typename topology_type::sheaf_type& patches = this->getAtlas()->getTopology()->getPatches();

3507:         for(typename topology_type::sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
3508:           MPI_Request request = this->_requests[p_iter->first];

3510:           MPI_Start(&request);
3511:         }
3512:       };
3513:       void endCommunication() {
3514:         const typename topology_type::sheaf_type& patches = this->getAtlas()->getTopology()->getPatches();
3515:         MPI_Status status;

3517:         for(typename topology_type::sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
3518:           MPI_Request request = this->_requests[p_iter->first];

3520:           MPI_Wait(&request, &status);
3521:         }
3522:       };
3523:     };
3524:   }
3525: }
3526: #endif