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_, typename Alloc_ = std::allocator<Point_> >
 33:   class DiscreteSieve {
 34:   public:
 35:     typedef Point_                              point_type;
 36:     typedef Alloc_                              alloc_type;
 37:     typedef std::vector<point_type, alloc_type> coneSequence;
 38:     typedef std::vector<point_type, alloc_type> coneSet;
 39:     typedef std::vector<point_type, alloc_type> coneArray;
 40:     typedef std::vector<point_type, alloc_type> supportSequence;
 41:     typedef std::vector<point_type, alloc_type> supportSet;
 42:     typedef std::vector<point_type, alloc_type> supportArray;
 43:     typedef std::set<point_type, std::less<point_type>, alloc_type>   points_type;
 44:     typedef points_type                                               baseSequence;
 45:     typedef points_type                                               capSequence;
 46:     typedef typename alloc_type::template rebind<points_type>::other  points_alloc_type;
 47:     typedef typename points_alloc_type::pointer                       points_ptr;
 48:     typedef typename alloc_type::template rebind<coneSequence>::other coneSequence_alloc_type;
 49:     typedef typename coneSequence_alloc_type::pointer                 coneSequence_ptr;
 50:   protected:
 51:     Obj<points_type>  _points;
 52:     Obj<coneSequence> _empty;
 53:     Obj<coneSequence> _return;
 54:     alloc_type        _allocator;
 55:     void _init() {
 56:       points_ptr pPoints = points_alloc_type(this->_allocator).allocate(1);
 57:       points_alloc_type(this->_allocator).construct(pPoints, points_type());
 58:       this->_points = Obj<points_type>(pPoints, sizeof(points_type));
 59:       ///this->_points = new points_type();
 60:       coneSequence_ptr pEmpty = coneSequence_alloc_type(this->_allocator).allocate(1);
 61:       coneSequence_alloc_type(this->_allocator).construct(pEmpty, coneSequence());
 62:       this->_empty = Obj<coneSequence>(pEmpty, sizeof(coneSequence));
 63:       ///this->_empty  = new coneSequence();
 64:       coneSequence_ptr pReturn = coneSequence_alloc_type(this->_allocator).allocate(1);
 65:       coneSequence_alloc_type(this->_allocator).construct(pReturn, coneSequence());
 66:       this->_return = Obj<coneSequence>(pReturn, sizeof(coneSequence));
 67:       ///this->_return = new coneSequence();
 68:     };
 69:   public:
 70:     DiscreteSieve() {
 71:       this->_init();
 72:     };
 73:     template<typename Input>
 74:     DiscreteSieve(const Obj<Input>& points) {
 75:       this->_init();
 76:       this->_points->insert(points->begin(), points->end());
 77:     };
 78:     virtual ~DiscreteSieve() {};
 79:   public:
 80:     void addPoint(const point_type& point) {
 81:       this->_points->insert(point);
 82:     };
 83:     template<typename Input>
 84:     void addPoints(const Obj<Input>& points) {
 85:       this->_points->insert(points->begin(), points->end());
 86:     };
 87:     const Obj<coneSequence>& cone(const point_type& p) {return this->_empty;};
 88:     template<typename Input>
 89:     const Obj<coneSequence>& cone(const Input& p) {return this->_empty;};
 90:     const Obj<coneSet>& nCone(const point_type& p, const int level) {
 91:       if (level == 0) {
 92:         return this->closure(p);
 93:       } else {
 94:         return this->_empty;
 95:       }
 96:     };
 97:     const Obj<coneArray>& closure(const point_type& p) {
 98:       this->_return->clear();
 99:       this->_return->push_back(p);
100:       return this->_return;
101:     };
102:     const Obj<supportSequence>& support(const point_type& p) {return this->_empty;};
103:     template<typename Input>
104:     const Obj<supportSequence>& support(const Input& p) {return this->_empty;};
105:     const Obj<supportSet>& nSupport(const point_type& p, const int level) {
106:       if (level == 0) {
107:         return this->star(p);
108:       } else {
109:         return this->_empty;
110:       }
111:     };
112:     const Obj<supportArray>& star(const point_type& p) {
113:       this->_return->clear();
114:       this->_return->push_back(p);
115:       return this->_return;
116:     };
117:     const Obj<capSequence>& roots() {return this->_points;};
118:     const Obj<capSequence>& cap() {return this->_points;};
119:     const Obj<baseSequence>& leaves() {return this->_points;};
120:     const Obj<baseSequence>& base() {return this->_points;};
121:     template<typename Color>
122:     void addArrow(const point_type& p, const point_type& q, const Color& color) {
123:       throw ALE::Exception("Cannot add an arrow to a DiscreteSieve");
124:     };
125:     void stratify() {};
126:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
127:       ostringstream txt;
128:       int rank;

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

210:       this->addPoint(chart);
211:       this->_value = section->restrict(*chart.begin())[0];
212:     };
213:   public: // Sizes
214:     void clear() {
215:       this->_chart.clear();
216:     };
217:     int getFiberDimension(const point_type& p) const {
218:       if (this->hasPoint(p)) return 1;
219:       return 0;
220:     };
221:     void setFiberDimension(const point_type& p, int dim) {
222:       this->checkDimension(dim);
223:       this->addPoint(p);
224:     };
225:     template<typename Sequence>
226:     void setFiberDimension(const Obj<Sequence>& points, int dim) {
227:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
228:         this->setFiberDimension(*p_iter, dim);
229:       }
230:     };
231:     void addFiberDimension(const point_type& p, int dim) {
232:       if (this->_chart.find(p) != this->_chart.end()) {
233:         ostringstream msg;
234:         msg << "Invalid addition to fiber dimension " << dim << " cannot exceed 1" << std::endl;
235:         throw ALE::Exception(msg.str().c_str());
236:       } else {
237:         this->setFiberDimension(p, dim);
238:       }
239:     };
240:     int size(const point_type& p) {return this->getFiberDimension(p);};
241:   public: // Restriction
242:     const value_type *restrict(const point_type& p) const {
243:       if (this->hasPoint(p)) {
244:         return &this->_value;
245:       }
246:       return &this->_defaultValue;
247:     };
248:     const value_type *restrictPoint(const point_type& p) const {return this->restrict(p);};
249:     void update(const point_type& p, const value_type v[]) {
250:       this->_value = v[0];
251:     };
252:     void updatePoint(const point_type& p, const value_type v[]) {return this->update(p, v);};
253:     void updateAdd(const point_type& p, const value_type v[]) {
254:       this->_value += v[0];
255:     };
256:     void updateAddPoint(const point_type& p, const value_type v[]) {return this->updateAdd(p, v);};
257:   public:
258:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
259:       ostringstream txt;
260:       int rank;

262:       if (comm == MPI_COMM_NULL) {
263:         comm = this->comm();
264:         rank = this->commRank();
265:       } else {
266:         MPI_Comm_rank(comm, &rank);
267:       }
268:       if (name == "") {
269:         if(rank == 0) {
270:           txt << "viewing a ConstantSection" << std::endl;
271:         }
272:       } else {
273:         if(rank == 0) {
274:           txt << "viewing ConstantSection '" << name << "'" << std::endl;
275:         }
276:       }
277:       txt <<"["<<this->commRank()<<"]: Value " << this->_value << std::endl;
278:       PetscSynchronizedPrintf(comm, txt.str().c_str());
279:       PetscSynchronizedFlush(comm);
280:     };
281:   };
282:   // A UniformSection often acts as an Atlas
283:   //   All fibers are the same dimension
284:   //     Note we can use a ConstantSection for this Atlas
285:   //   Each point may have a different vector
286:   //     Thus we need storage for values, and hence must implement completion
287:   template<typename Point_, typename Value_, int fiberDim = 1, typename Alloc_ = std::allocator<Value_> >
288:   class UniformSection : public ALE::ParallelObject {
289:   public:
290:     typedef Point_                                           point_type;
291:     typedef Value_                                           value_type;
292:     typedef Alloc_                                           alloc_type;
293:     typedef typename alloc_type::template rebind<point_type>::other point_alloc_type;
294:     typedef ConstantSection<point_type, int, point_alloc_type> atlas_type;
295:     typedef typename atlas_type::chart_type                  chart_type;
296:     typedef struct {value_type v[fiberDim];}                 fiber_type;
297:     typedef typename alloc_type::template rebind<std::pair<const point_type, fiber_type> >::other pair_alloc_type;
298:     typedef std::map<point_type, fiber_type, std::less<point_type>, pair_alloc_type>              values_type;
299:     typedef typename alloc_type::template rebind<atlas_type>::other                               atlas_alloc_type;
300:     typedef typename atlas_alloc_type::pointer                                                    atlas_ptr;
301:   protected:
302:     size_t          _contiguous_array_size;
303:     value_type     *_contiguous_array;
304:     Obj<atlas_type> _atlas;
305:     values_type     _array;
306:     fiber_type      _emptyValue;
307:     alloc_type      _allocator;
308:   public:
309:     UniformSection(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug), _contiguous_array_size(0), _contiguous_array(NULL) {
310:       atlas_ptr pAtlas = atlas_alloc_type(this->_allocator).allocate(1);
311:       atlas_alloc_type(this->_allocator).construct(pAtlas, atlas_type(comm, debug));
312:       this->_atlas = Obj<atlas_type>(pAtlas, sizeof(atlas_type));
313:       int dim = fiberDim;
314:       this->_atlas->update(*this->_atlas->getChart().begin(), &dim);
315:       for(int i = 0; i < fiberDim; ++i) this->_emptyValue.v[i] = value_type();
316:     };
317:     UniformSection(const Obj<atlas_type>& atlas) : ParallelObject(atlas->comm(), atlas->debug()), _contiguous_array_size(0), _contiguous_array(NULL), _atlas(atlas) {
318:       int dim = fiberDim;
319:       this->_atlas->update(*this->_atlas->getChart().begin(), &dim);
320:       for(int i = 0; i < fiberDim; ++i) this->_emptyValue.v[i] = value_type();
321:     };
322:     virtual ~UniformSection() {
323:       this->_atlas = NULL;
324:       if (this->_contiguous_array) {
325:         for(size_t i = 0; i < this->_contiguous_array_size; ++i) {this->_allocator.destroy(this->_contiguous_array+i);}
326:         this->_allocator.deallocate(this->_contiguous_array, this->_contiguous_array_size);
327:       }
328:     };
329:   public:
330:     value_type *getRawArray(const int size) {
331:       static value_type *array   = NULL;
332:       static int         maxSize = 0;

334:       if (size > maxSize) {
335:         const value_type dummy(0);

337:         if (array) {
338:           for(int i = 0; i < maxSize; ++i) {this->_allocator.destroy(array+i);}
339:           this->_allocator.deallocate(array, maxSize);
340:           ///delete [] array;
341:         }
342:         maxSize = size;
343:         array   = this->_allocator.allocate(maxSize);
344:         for(int i = 0; i < maxSize; ++i) {this->_allocator.construct(array+i, dummy);}
345:         ///array = new value_type[maxSize];
346:       };
347:       return array;
348:     };
349:   public: // Verifiers
350:     bool hasPoint(const point_type& point) {
351:       return this->_atlas->hasPoint(point);
352:     };
353:     void checkDimension(const int& dim) {
354:       if (dim != fiberDim) {
355:         ostringstream msg;
356:         msg << "Invalid fiber dimension " << dim << " must be " << fiberDim << std::endl;
357:         throw ALE::Exception(msg.str().c_str());
358:       }
359:     };
360:   public: // Accessors
361:     const chart_type& getChart() {return this->_atlas->getChart();};
362:     const Obj<atlas_type>& getAtlas() {return this->_atlas;};
363:     void setAtlas(const Obj<atlas_type>& atlas) {this->_atlas = atlas;};
364:     void addPoint(const point_type& point) {
365:       this->setFiberDimension(point, fiberDim);
366:     };
367:     template<typename Points>
368:     void addPoint(const Obj<Points>& points) {
369:       for(typename Points::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
370:         this->setFiberDimension(*p_iter, fiberDim);
371:       }
372:     };
373:     void copy(const Obj<UniformSection>& section) {
374:       this->getAtlas()->copy(section->getAtlas());
375:       const chart_type& chart = section->getChart();

377:       for(typename chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
378:         this->updatePoint(*c_iter, section->restrictPoint(*c_iter));
379:       }
380:     };
381:   public: // Sizes
382:     void clear() {
383:       this->_atlas->clear();
384:       this->_array.clear();
385:     };
386:     int getFiberDimension(const point_type& p) const {
387:       return this->_atlas->restrictPoint(p)[0];
388:     };
389:     void setFiberDimension(const point_type& p, int dim) {
390:       this->update();
391:       this->checkDimension(dim);
392:       this->_atlas->addPoint(p);
393:       this->_atlas->updatePoint(p, &dim);
394:     };
395:     template<typename Sequence>
396:     void setFiberDimension(const Obj<Sequence>& points, int dim) {
397:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
398:         this->setFiberDimension(*p_iter, dim);
399:       }
400:     };
401:     void setFiberDimension(const std::set<point_type>& points, int dim) {
402:       for(typename std::set<point_type>::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
403:         this->setFiberDimension(*p_iter, dim);
404:       }
405:     };
406:     void addFiberDimension(const point_type& p, int dim) {
407:       if (this->hasPoint(p)) {
408:         ostringstream msg;
409:         msg << "Invalid addition to fiber dimension " << dim << " cannot exceed " << fiberDim << std::endl;
410:         throw ALE::Exception(msg.str().c_str());
411:       } else {
412:         this->setFiberDimension(p, dim);
413:       }
414:     };
415:     int size() const {
416:       const chart_type& points = this->_atlas->getChart();
417:       int               size   = 0;

419:       for(typename chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
420:         size += this->getFiberDimension(*p_iter);
421:       }
422:       return size;
423:     };
424:     int sizeWithBC() const {
425:       return this->size();
426:     };
427:     void allocatePoint() {};
428:   public: // Restriction
429:     const value_type *restrict() {
430:       const chart_type& chart = this->getChart();
431:       const value_type  dummy = 0;
432:       int               k     = 0;

434:       if (chart.size() > this->_contiguous_array_size*fiberDim) {
435:         if (this->_contiguous_array) {
436:           for(size_t i = 0; i < this->_contiguous_array_size; ++i) {this->_allocator.destroy(this->_contiguous_array+i);}
437:           this->_allocator.deallocate(this->_contiguous_array, this->_contiguous_array_size);
438:         }
439:         this->_contiguous_array_size = chart.size()*fiberDim;
440:         this->_contiguous_array = this->_allocator.allocate(this->_contiguous_array_size*fiberDim);
441:         for(size_t i = 0; i < this->_contiguous_array_size; ++i) {this->_allocator.construct(this->_contiguous_array+i, dummy);}
442:       }
443:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
444:         const value_type *a = this->_array[*p_iter].v;

446:         for(int i = 0; i < fiberDim; ++i, ++k) {
447:           this->_contiguous_array[k] = a[i];
448:         }
449:       }
450:       return this->_contiguous_array;
451:     };
452:     void update() {
453:       if (this->_contiguous_array) {
454:         const chart_type& chart = this->getChart();
455:         int               k     = 0;

457:         for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
458:           value_type *a = this->_array[*p_iter].v;

460:           for(int i = 0; i < fiberDim; ++i, ++k) {
461:             a[i] = this->_contiguous_array[k];
462:           }
463:         }
464:         for(size_t i = 0; i < this->_contiguous_array_size; ++i) {this->_allocator.destroy(this->_contiguous_array+i);}
465:         this->_allocator.deallocate(this->_contiguous_array, this->_contiguous_array_size);
466:         this->_contiguous_array_size = 0;
467:         this->_contiguous_array      = NULL;
468:       }
469:     };
470:     // Return only the values associated to this point, not its closure
471:     const value_type *restrictPoint(const point_type& p) {
472:       if (this->_array.find(p) == this->_array.end()) return this->_emptyValue.v;
473:       this->update();
474:       return this->_array[p].v;
475:     };
476:     // Update only the values associated to this point, not its closure
477:     void updatePoint(const point_type& p, const value_type v[]) {
478:       this->update();
479:       for(int i = 0; i < fiberDim; ++i) {
480:         this->_array[p].v[i] = v[i];
481:       }
482:     };
483:     // Update only the values associated to this point, not its closure
484:     void updateAddPoint(const point_type& p, const value_type v[]) {
485:       this->update();
486:       for(int i = 0; i < fiberDim; ++i) {
487:         this->_array[p].v[i] += v[i];
488:       }
489:     };
490:     void updatePointAll(const point_type& p, const value_type v[]) {
491:       this->updatePoint(p, v);
492:     };
493:   public:
494:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) {
495:       ostringstream txt;
496:       int rank;

498:       this->update();
499:       if (comm == MPI_COMM_NULL) {
500:         comm = this->comm();
501:         rank = this->commRank();
502:       } else {
503:         MPI_Comm_rank(comm, &rank);
504:       }
505:       if (name == "") {
506:         if(rank == 0) {
507:           txt << "viewing a UniformSection" << std::endl;
508:         }
509:       } else {
510:         if(rank == 0) {
511:           txt << "viewing UniformSection '" << name << "'" << std::endl;
512:         }
513:       }
514:       const typename atlas_type::chart_type& chart = this->_atlas->getChart();
515:       values_type&                           array = this->_array;

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

521:         if (dim != 0) {
522:           txt << "[" << this->commRank() << "]:   " << point << " dim " << dim << "  ";
523:           for(int i = 0; i < dim; i++) {
524:             txt << " " << array[point].v[i];
525:           }
526:           txt << std::endl;
527:         }
528:       }
529:       if (chart.size() == 0) {
530:         txt << "[" << this->commRank() << "]: empty" << std::endl;
531:       }
532:       PetscSynchronizedPrintf(comm, txt.str().c_str());
533:       PetscSynchronizedFlush(comm);
534:     };
535:   };

537:   // A FauxConstantSection is the simplest Section
538:   //   All fibers are dimension 1
539:   //   All values are equal to a constant
540:   //     We need no value storage and no communication for completion
541:   template<typename Point_, typename Value_, typename Alloc_ = std::allocator<Point_> >
542:   class FauxConstantSection : public ALE::ParallelObject {
543:   public:
544:     typedef Point_ point_type;
545:     typedef Value_ value_type;
546:     typedef Alloc_ alloc_type;
547:   protected:
548:     value_type _value;
549:   public:
550:     FauxConstantSection(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {};
551:     FauxConstantSection(MPI_Comm comm, const value_type& value, const int debug) : ParallelObject(comm, debug), _value(value) {};
552:   public: // Verifiers
553:     void checkDimension(const int& dim) {
554:       if (dim != 1) {
555:         ostringstream msg;
556:         msg << "Invalid fiber dimension " << dim << " must be 1" << std::endl;
557:         throw ALE::Exception(msg.str().c_str());
558:       }
559:     };
560:   public: // Accessors
561:     void addPoint(const point_type& point) {
562:     };
563:     template<typename Points>
564:     void addPoint(const Obj<Points>& points) {
565:     };
566:     template<typename Points>
567:     void addPoint(const Points& points) {
568:     };
569:     void copy(const Obj<FauxConstantSection>& section) {
570:       this->_value = section->restrict(point_type())[0];
571:     };
572:   public: // Sizes
573:     void clear() {
574:     };
575:     int getFiberDimension(const point_type& p) const {
576:       return 1;
577:     };
578:     void setFiberDimension(const point_type& p, int dim) {
579:       this->checkDimension(dim);
580:       this->addPoint(p);
581:     };
582:     template<typename Sequence>
583:     void setFiberDimension(const Obj<Sequence>& points, int dim) {
584:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
585:         this->setFiberDimension(*p_iter, dim);
586:       }
587:     };
588:     void addFiberDimension(const point_type& p, int dim) {
589:       this->setFiberDimension(p, dim);
590:     };
591:     int size(const point_type& p) {return this->getFiberDimension(p);};
592:   public: // Restriction
593:     const value_type *restrict(const point_type& p) const {
594:       return &this->_value;
595:     };
596:     const value_type *restrictPoint(const point_type& p) const {return this->restrict(p);};
597:     void update(const point_type& p, const value_type v[]) {
598:       this->_value = v[0];
599:     };
600:     void updatePoint(const point_type& p, const value_type v[]) {return this->update(p, v);};
601:     void updateAdd(const point_type& p, const value_type v[]) {
602:       this->_value += v[0];
603:     };
604:     void updateAddPoint(const point_type& p, const value_type v[]) {return this->updateAdd(p, v);};
605:   public:
606:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
607:       ostringstream txt;
608:       int rank;

610:       if (comm == MPI_COMM_NULL) {
611:         comm = this->comm();
612:         rank = this->commRank();
613:       } else {
614:         MPI_Comm_rank(comm, &rank);
615:       }
616:       if (name == "") {
617:         if(rank == 0) {
618:           txt << "viewing a FauxConstantSection" << std::endl;
619:         }
620:       } else {
621:         if(rank == 0) {
622:           txt << "viewing FauxConstantSection '" << name << "'" << std::endl;
623:         }
624:       }
625:       txt <<"["<<this->commRank()<<"]: Value " << this->_value << std::endl;
626:       PetscSynchronizedPrintf(comm, txt.str().c_str());
627:       PetscSynchronizedFlush(comm);
628:     };
629:   };
630:   // Make a simple set from the keys of a map
631:   template<typename Map>
632:   class SetFromMap {
633:   public:
634:     typedef typename Map::size_type size_type;
635:     class const_iterator {
636:     public:
637:       typedef typename Map::key_type  value_type;
638:       typedef typename Map::size_type size_type;
639:     protected:
640:       typename Map::const_iterator _iter;
641:     public:
642:       const_iterator(const typename Map::const_iterator& iter): _iter(iter) {};
643:       ~const_iterator() {};
644:     public:
645:       const_iterator& operator=(const const_iterator& iter) {this->_iter = iter._iter;};
646:       bool operator==(const const_iterator& iter) const {return this->_iter == iter._iter;};
647:       bool operator!=(const const_iterator& iter) const {return this->_iter != iter._iter;};
648:       const_iterator& operator++() {++this->_iter; return *this;}
649:       const_iterator& operator++(int) {
650:         const_iterator tmp(*this);
651:         ++(*this);
652:         return tmp;
653:       };
654:       const_iterator& operator--() {--this->_iter; return *this;}
655:       const_iterator& operator--(int) {
656:         const_iterator tmp(*this);
657:         --(*this);
658:         return tmp;
659:       };
660:       value_type operator*() const {return this->_iter->first;};
661:       size_type size() const {return this->_iter->size();};
662:     };
663:   protected:
664:     const Map& _map;
665:   public:
666:     SetFromMap(const Map& map): _map(map) {};
667:   public:
668:     const_iterator begin() const {return const_iterator(this->_map.begin());};
669:     const_iterator end()   const {return const_iterator(this->_map.end());};
670:     size_type      size()  const {return this->_map.size();};
671:   };
672:   // A NewUniformSection often acts as an Atlas
673:   //   All fibers are the same dimension
674:   //     Note we can use a ConstantSection for this Atlas
675:   //   Each point may have a different vector
676:   //     Thus we need storage for values, and hence must implement completion
677:   template<typename Point_, typename Value_, int fiberDim = 1, typename Alloc_ = std::allocator<Value_> >
678:   class NewUniformSection : public ALE::ParallelObject {
679:   public:
680:     typedef Point_                                           point_type;
681:     typedef Value_                                           value_type;
682:     typedef Alloc_                                           alloc_type;
683:     typedef typename alloc_type::template rebind<point_type>::other                               point_alloc_type;
684:     typedef FauxConstantSection<point_type, int, point_alloc_type>                                atlas_type;
685:     typedef struct {value_type v[fiberDim];}                                                      fiber_type;
686:     typedef typename alloc_type::template rebind<std::pair<const point_type, fiber_type> >::other pair_alloc_type;
687:     typedef std::map<point_type, fiber_type, std::less<point_type>, pair_alloc_type>              values_type;
688:     typedef SetFromMap<values_type>                                                               chart_type;
689:     typedef typename alloc_type::template rebind<atlas_type>::other                               atlas_alloc_type;
690:     typedef typename atlas_alloc_type::pointer                                                    atlas_ptr;
691:   protected:
692:     values_type     _array;
693:     chart_type      _chart;
694:     size_t          _contiguous_array_size;
695:     value_type     *_contiguous_array;
696:     Obj<atlas_type> _atlas;
697:     fiber_type      _emptyValue;
698:     alloc_type      _allocator;
699:   public:
700:     NewUniformSection(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug), _chart(_array), _contiguous_array_size(0), _contiguous_array(NULL) {
701:       atlas_ptr pAtlas = atlas_alloc_type(this->_allocator).allocate(1);
702:       atlas_alloc_type(this->_allocator).construct(pAtlas, atlas_type(comm, debug));
703:       this->_atlas = Obj<atlas_type>(pAtlas, sizeof(atlas_type));
704:       int dim = fiberDim;
705:       this->_atlas->update(point_type(), &dim);
706:       for(int i = 0; i < fiberDim; ++i) this->_emptyValue.v[i] = value_type();
707:     };
708:     NewUniformSection(const Obj<atlas_type>& atlas) : ParallelObject(atlas->comm(), atlas->debug()), _chart(_array), _contiguous_array_size(0), _contiguous_array(NULL), _atlas(atlas) {
709:       int dim = fiberDim;
710:       this->_atlas->update(point_type(), &dim);
711:       for(int i = 0; i < fiberDim; ++i) this->_emptyValue.v[i] = value_type();
712:     };
713:     ~NewUniformSection() {
714:       this->_atlas = NULL;
715:       if (this->_contiguous_array) {
716:         for(size_t i = 0; i < this->_contiguous_array_size; ++i) {this->_allocator.destroy(this->_contiguous_array+i);}
717:         this->_allocator.deallocate(this->_contiguous_array, this->_contiguous_array_size);
718:       }
719:     };
720:   public:
721:     value_type *getRawArray(const int size) {
722:       static value_type *array   = NULL;
723:       static int         maxSize = 0;

725:       if (size > maxSize) {
726:         const value_type dummy(0);

728:         if (array) {
729:           for(int i = 0; i < maxSize; ++i) {this->_allocator.destroy(array+i);}
730:           this->_allocator.deallocate(array, maxSize);
731:           ///delete [] array;
732:         }
733:         maxSize = size;
734:         array   = this->_allocator.allocate(maxSize);
735:         for(int i = 0; i < maxSize; ++i) {this->_allocator.construct(array+i, dummy);}
736:         ///array = new value_type[maxSize];
737:       };
738:       return array;
739:     };
740:   public: // Verifiers
741:     bool hasPoint(const point_type& point) {
742:       return (this->_values.find(point) != this->_values.end());
743:       ///return this->_atlas->hasPoint(point);
744:     };
745:     void checkDimension(const int& dim) {
746:       if (dim != fiberDim) {
747:         ostringstream msg;
748:         msg << "Invalid fiber dimension " << dim << " must be " << fiberDim << std::endl;
749:         throw ALE::Exception(msg.str().c_str());
750:       }
751:     };
752:   public: // Accessors
753:     const chart_type& getChart() {return this->_chart;};
754:     const Obj<atlas_type>& getAtlas() {return this->_atlas;};
755:     void setAtlas(const Obj<atlas_type>& atlas) {this->_atlas = atlas;};
756:     void addPoint(const point_type& point) {
757:       this->setFiberDimension(point, fiberDim);
758:     };
759:     template<typename Points>
760:     void addPoint(const Obj<Points>& points) {
761:       for(typename Points::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
762:         this->setFiberDimension(*p_iter, fiberDim);
763:       }
764:     };
765:     void copy(const Obj<NewUniformSection>& section) {
766:       this->getAtlas()->copy(section->getAtlas());
767:       const chart_type& chart = section->getChart();

769:       for(typename chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
770:         this->updatePoint(*c_iter, section->restrictPoint(*c_iter));
771:       }
772:     };
773:   public: // Sizes
774:     void clear() {
775:       this->_atlas->clear();
776:       this->_array.clear();
777:     };
778:     int getFiberDimension(const point_type& p) const {
779:       return fiberDim;
780:     };
781:     void setFiberDimension(const point_type& p, int dim) {
782:       this->update();
783:       this->checkDimension(dim);
784:       this->_atlas->addPoint(p);
785:       this->_atlas->updatePoint(p, &dim);
786:       this->_array[p] = fiber_type();
787:     };
788:     template<typename Sequence>
789:     void setFiberDimension(const Obj<Sequence>& points, int dim) {
790:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
791:         this->setFiberDimension(*p_iter, dim);
792:       }
793:     };
794:     void setFiberDimension(const std::set<point_type>& points, int dim) {
795:       for(typename std::set<point_type>::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
796:         this->setFiberDimension(*p_iter, dim);
797:       }
798:     };
799:     void addFiberDimension(const point_type& p, int dim) {
800:       if (this->hasPoint(p)) {
801:         ostringstream msg;
802:         msg << "Invalid addition to fiber dimension " << dim << " cannot exceed " << fiberDim << std::endl;
803:         throw ALE::Exception(msg.str().c_str());
804:       } else {
805:         this->setFiberDimension(p, dim);
806:       }
807:     };
808:     int size() const {
809:       const chart_type& points = this->getChart();
810:       int               size   = 0;

812:       for(typename chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
813:         size += this->getFiberDimension(*p_iter);
814:       }
815:       return size;
816:     };
817:     int sizeWithBC() const {
818:       return this->size();
819:     };
820:     void allocatePoint() {};
821:   public: // Restriction
822:     // Return a pointer to the entire contiguous storage array
823:     const value_type *restrict() {
824:       const chart_type& chart = this->getChart();
825:       const value_type  dummy = 0;
826:       int               k     = 0;

828:       if (chart.size() > this->_contiguous_array_size*fiberDim) {
829:         if (this->_contiguous_array) {
830:           for(size_t i = 0; i < this->_contiguous_array_size; ++i) {this->_allocator.destroy(this->_contiguous_array+i);}
831:           this->_allocator.deallocate(this->_contiguous_array, this->_contiguous_array_size);
832:         }
833:         this->_contiguous_array_size = chart.size()*fiberDim;
834:         this->_contiguous_array = this->_allocator.allocate(this->_contiguous_array_size*fiberDim);
835:         for(size_t i = 0; i < this->_contiguous_array_size; ++i) {this->_allocator.construct(this->_contiguous_array+i, dummy);}
836:       }
837:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
838:         const value_type *a = this->_array[*p_iter].v;

840:         for(int i = 0; i < fiberDim; ++i, ++k) {
841:           this->_contiguous_array[k] = a[i];
842:         }
843:       }
844:       return this->_contiguous_array;
845:     };
846:     void update() {
847:       if (this->_contiguous_array) {
848:         const chart_type& chart = this->getChart();
849:         int               k     = 0;

851:         for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
852:           value_type *a = this->_array[*p_iter].v;

854:           for(int i = 0; i < fiberDim; ++i, ++k) {
855:             a[i] = this->_contiguous_array[k];
856:           }
857:         }
858:         for(size_t i = 0; i < this->_contiguous_array_size; ++i) {this->_allocator.destroy(this->_contiguous_array+i);}
859:         this->_allocator.deallocate(this->_contiguous_array, this->_contiguous_array_size);
860:         this->_contiguous_array_size = 0;
861:         this->_contiguous_array      = NULL;
862:       }
863:     };
864:     // Return only the values associated to this point, not its closure
865:     const value_type *restrictPoint(const point_type& p) {
866:       if (this->_array.find(p) == this->_array.end()) return this->_emptyValue.v;
867:       this->update();
868:       return this->_array[p].v;
869:     };
870:     // Update only the values associated to this point, not its closure
871:     void updatePoint(const point_type& p, const value_type v[]) {
872:       this->update();
873:       for(int i = 0; i < fiberDim; ++i) {
874:         this->_array[p].v[i] = v[i];
875:       }
876:     };
877:     // Update only the values associated to this point, not its closure
878:     void updateAddPoint(const point_type& p, const value_type v[]) {
879:       this->update();
880:       for(int i = 0; i < fiberDim; ++i) {
881:         this->_array[p].v[i] += v[i];
882:       }
883:     };
884:     void updatePointAll(const point_type& p, const value_type v[]) {
885:       this->updatePoint(p, v);
886:     };
887:   public:
888:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) {
889:       ostringstream txt;
890:       int rank;

892:       this->update();
893:       if (comm == MPI_COMM_NULL) {
894:         comm = this->comm();
895:         rank = this->commRank();
896:       } else {
897:         MPI_Comm_rank(comm, &rank);
898:       }
899:       if (name == "") {
900:         if(rank == 0) {
901:           txt << "viewing a NewUniformSection" << std::endl;
902:         }
903:       } else {
904:         if(rank == 0) {
905:           txt << "viewing NewUniformSection '" << name << "'" << std::endl;
906:         }
907:       }
908:       const chart_type& chart = this->getChart();
909:       values_type&      array = this->_array;

911:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
912:         const point_type& point = *p_iter;

914:         if (fiberDim != 0) {
915:           txt << "[" << this->commRank() << "]:   " << point << " dim " << fiberDim << "  ";
916:           for(int i = 0; i < fiberDim; i++) {
917:             txt << " " << array[point].v[i];
918:           }
919:           txt << std::endl;
920:         }
921:       }
922:       if (chart.size() == 0) {
923:         txt << "[" << this->commRank() << "]: empty" << std::endl;
924:       }
925:       PetscSynchronizedPrintf(comm, txt.str().c_str());
926:       PetscSynchronizedFlush(comm);
927:     };
928:   };
929:   // A Section is our most general construct (more general ones could be envisioned)
930:   //   The Atlas is a UniformSection of dimension 1 and value type Point
931:   //     to hold each fiber dimension and offsets into a contiguous patch array
932:   template<typename Point_, typename Value_, typename Alloc_ = std::allocator<Value_>,
933:            typename Atlas_ = UniformSection<Point_, Point, 1, typename Alloc_::template rebind<Point>::other> >
934:   class Section : public ALE::ParallelObject {
935:   public:
936:     typedef Point_                                                  point_type;
937:     typedef Value_                                                  value_type;
938:     typedef Alloc_                                                  alloc_type;
939:     typedef Atlas_                                                  atlas_type;
940:     typedef Point                                                   index_type;
941:     typedef typename atlas_type::chart_type                         chart_type;
942:     typedef value_type *                                            values_type;
943:     typedef typename alloc_type::template rebind<atlas_type>::other atlas_alloc_type;
944:     typedef typename atlas_alloc_type::pointer                      atlas_ptr;
945:   protected:
946:     Obj<atlas_type> _atlas;
947:     Obj<atlas_type> _atlasNew;
948:     values_type     _array;
949:     alloc_type      _allocator;
950:   public:
951:     Section(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {
952:       atlas_ptr pAtlas = atlas_alloc_type(this->_allocator).allocate(1);
953:       atlas_alloc_type(this->_allocator).construct(pAtlas, atlas_type(comm, debug));
954:       this->_atlas    = Obj<atlas_type>(pAtlas, sizeof(atlas_type));
955:       this->_atlasNew = NULL;
956:       this->_array    = NULL;
957:     };
958:     Section(const Obj<atlas_type>& atlas) : ParallelObject(atlas->comm(), atlas->debug()), _atlas(atlas), _atlasNew(NULL), _array(NULL) {};
959:     virtual ~Section() {
960:       if (this->_array) {
961:         const int totalSize = this->sizeWithBC();

963:         for(int i = 0; i < totalSize; ++i) {this->_allocator.destroy(this->_array+i);}
964:         this->_allocator.deallocate(this->_array, totalSize);
965:         ///delete [] this->_array;
966:         this->_array = NULL;
967:       }
968:     };
969:   public:
970:     value_type *getRawArray(const int size) {
971:       static value_type *array   = NULL;
972:       static int         maxSize = 0;

974:       if (size > maxSize) {
975:         const value_type dummy(0);

977:         if (array) {
978:           for(int i = 0; i < maxSize; ++i) {this->_allocator.destroy(array+i);}
979:           this->_allocator.deallocate(array, maxSize);
980:           ///delete [] array;
981:         }
982:         maxSize = size;
983:         array   = this->_allocator.allocate(maxSize);
984:         for(int i = 0; i < maxSize; ++i) {this->_allocator.construct(array+i, dummy);}
985:         ///array = new value_type[maxSize];
986:       };
987:       return array;
988:     };
989:     int getStorageSize() const {
990:       return this->sizeWithBC();
991:     };
992:   public: // Verifiers
993:     bool hasPoint(const point_type& point) {
994:       return this->_atlas->hasPoint(point);
995:     };
996:   public: // Accessors
997:     const Obj<atlas_type>& getAtlas() {return this->_atlas;};
998:     void setAtlas(const Obj<atlas_type>& atlas) {this->_atlas = atlas;};
999:     const Obj<atlas_type>& getNewAtlas() {return this->_atlasNew;};
1000:     void setNewAtlas(const Obj<atlas_type>& atlas) {this->_atlasNew = atlas;};
1001:     const chart_type& getChart() const {return this->_atlas->getChart();};
1002:   public: // BC
1003:     // Returns the number of constraints on a point
1004:     const int getConstraintDimension(const point_type& p) const {
1005:       return std::max(0, -this->_atlas->restrictPoint(p)->prefix);
1006:     };
1007:     // Set the number of constraints on a point
1008:     //   We only allow the entire point to be constrained, so these will be the
1009:     //   only dofs on the point
1010:     void setConstraintDimension(const point_type& p, const int numConstraints) {
1011:       this->setFiberDimension(p, -numConstraints);
1012:     };
1013:     void addConstraintDimension(const point_type& p, const int numConstraints) {
1014:       throw ALE::Exception("Variable constraint dimensions not available for this Section type");
1015:     };
1016:     void copyBC(const Obj<Section>& section) {
1017:       const chart_type& chart = this->getChart();

1019:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
1020:         if (this->getConstraintDimension(*p_iter)) {
1021:           this->updatePointBC(*p_iter, section->restrictPoint(*p_iter));
1022:         }
1023:       }
1024:     };
1025:     void defaultConstraintDof() {};
1026:   public: // Sizes
1027:     void clear() {
1028:       const int totalSize = this->sizeWithBC();

1030:       this->_atlas->clear();
1031:       for(int i = 0; i < totalSize; ++i) {this->_allocator.destroy(this->_array+i);}
1032:       this->_allocator.deallocate(this->_array, totalSize);
1033:       ///delete [] this->_array;
1034:       this->_array = NULL;
1035:     };
1036:     // Return the total number of dofs on the point (free and constrained)
1037:     int getFiberDimension(const point_type& p) const {
1038:       return std::abs(this->_atlas->restrictPoint(p)->prefix);
1039:     };
1040:     int getFiberDimension(const Obj<atlas_type>& atlas, const point_type& p) const {
1041:       return std::abs(atlas->restrictPoint(p)->prefix);
1042:     };
1043:     // Set the total number of dofs on the point (free and constrained)
1044:     void setFiberDimension(const point_type& p, int dim) {
1045:       const index_type idx(dim, -1);
1046:       this->_atlas->addPoint(p);
1047:       this->_atlas->updatePoint(p, &idx);
1048:     };
1049:     template<typename Sequence>
1050:     void setFiberDimension(const Obj<Sequence>& points, int dim) {
1051:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
1052:         this->setFiberDimension(*p_iter, dim);
1053:       }
1054:     };
1055:     void addFiberDimension(const point_type& p, int dim) {
1056:       if (this->_atlas->hasPoint(p)) {
1057:         const index_type values(dim, 0);
1058:         this->_atlas->updateAddPoint(p, &values);
1059:       } else {
1060:         this->setFiberDimension(p, dim);
1061:       }
1062:     };
1063:     // Return the number of constrained dofs on this point
1064:     //   If constrained, this is equal to the fiber dimension
1065:     //   Otherwise, 0
1066:     int getConstrainedFiberDimension(const point_type& p) const {
1067:       return std::max(0, this->_atlas->restrictPoint(p)->prefix);
1068:     };
1069:     // Return the total number of free dofs
1070:     int size() const {
1071:       const chart_type& points = this->getChart();
1072:       int size = 0;

1074:       for(typename chart_type::const_iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
1075:         size += this->getConstrainedFiberDimension(*p_iter);
1076:       }
1077:       return size;
1078:     };
1079:     // Return the total number of dofs (free and constrained)
1080:     int sizeWithBC() const {
1081:       const chart_type& points = this->getChart();
1082:       int size = 0;

1084:       for(typename chart_type::const_iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
1085:         size += this->getFiberDimension(*p_iter);
1086:       }
1087:       return size;
1088:     };
1089:   public: // Index retrieval
1090:     const typename index_type::index_type& getIndex(const point_type& p) {
1091:       return this->_atlas->restrictPoint(p)->index;
1092:     };
1093:     void setIndex(const point_type& p, const typename index_type::index_type& index) {
1094:       ((typename atlas_type::value_type *) this->_atlas->restrictPoint(p))->index = index;
1095:     };
1096:     void setIndexBC(const point_type& p, const typename index_type::index_type& index) {
1097:       this->setIndex(p, index);
1098:     };
1099:     void getIndices(const point_type& p, PetscInt indices[], PetscInt *indx, const int orientation = 1, const bool freeOnly = false, const bool skipConstraints = false) {
1100:       this->getIndices(p, this->getIndex(p), indices, indx, orientation, freeOnly, skipConstraints);
1101:     };
1102:     template<typename Order_>
1103:     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) {
1104:       this->getIndices(p, order->getIndex(p), indices, indx, orientation, freeOnly, skipConstraints);
1105:     };
1106:     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) {
1107:       const int& dim   = this->getFiberDimension(p);
1108:       const int& cDim  = this->getConstraintDimension(p);
1109:       const int  end   = start + dim;

1111:       if (!cDim) {
1112:         if (orientation >= 0) {
1113:           for(int i = start; i < end; ++i) {
1114:             indices[(*indx)++] = i;
1115:           }
1116:         } else {
1117:           for(int i = end-1; i >= start; --i) {
1118:             indices[(*indx)++] = i;
1119:           }
1120:         }
1121:       } else {
1122:         if (!freeOnly) {
1123:           for(int i = start; i < end; ++i) {
1124:             indices[(*indx)++] = -1;
1125:           }
1126:         }
1127:       }
1128:     };
1129:   public: // Allocation
1130:     void allocateStorage() {
1131:       const int totalSize = this->sizeWithBC();
1132:       const value_type dummy(0);

1134:       this->_array = this->_allocator.allocate(totalSize);
1135:       ///this->_array = new value_type[totalSize];
1136:       for(int i = 0; i < totalSize; ++i) {this->_allocator.construct(this->_array+i, dummy);}
1137:       ///PetscMemzero(this->_array, totalSize * sizeof(value_type));
1138:     };
1139:     void replaceStorage(value_type *newArray) {
1140:       delete [] this->_array;
1141:       this->_array    = newArray;
1142:       this->_atlasNew = NULL;
1143:     };
1144:     void addPoint(const point_type& point, const int dim) {
1145:       if (dim == 0) return;
1146:       if (this->_atlasNew.isNull()) {
1147:         this->_atlasNew = new atlas_type(this->comm(), this->debug());
1148:         this->_atlasNew->copy(this->_atlas);
1149:       }
1150:       const index_type idx(dim, -1);
1151:       this->_atlasNew->addPoint(point);
1152:       this->_atlasNew->updatePoint(point, &idx);
1153:     };
1154:     template<typename Sequence>
1155:     void addPoints(const Obj<Sequence>& points, const int dim) {
1156:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
1157:         this->addPoint(*p_iter, dim);
1158:       }
1159:     };
1160:     void orderPoints(const Obj<atlas_type>& atlas){
1161:       const chart_type& chart    = this->getChart();
1162:       int               offset   = 0;
1163:       int               bcOffset = this->size();

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

1169:         if (dim >= 0) {
1170:           idx.index = offset;
1171:           atlas->updatePoint(*c_iter, &idx);
1172:           offset += dim;
1173:         } else {
1174:           idx.index = bcOffset;
1175:           atlas->updatePoint(*c_iter, &idx);
1176:           bcOffset -= dim;
1177:         }
1178:       }
1179:     };
1180:     void allocatePoint() {
1181:       this->orderPoints(this->_atlas);
1182:       this->allocateStorage();
1183:     };
1184:   public: // Restriction and Update
1185:     // Zero entries
1186:     void zero() {
1187:       memset(this->_array, 0, this->size()* sizeof(value_type));
1188:     };
1189:     // Return a pointer to the entire contiguous storage array
1190:     const value_type *restrict() {
1191:       return this->_array;
1192:     };
1193:     // Update the entire contiguous storage array
1194:     void update(const value_type v[]) {
1195:       const value_type *array = this->_array;
1196:       const int         size  = this->size();

1198:       for(int i = 0; i < size; i++) {
1199:         array[i] = v[i];
1200:       }
1201:     };
1202:     // Return the free values on a point
1203:     const value_type *restrictPoint(const point_type& p) {
1204:       return &(this->_array[this->_atlas->restrictPoint(p)[0].index]);
1205:     };
1206:     // Update the free values on a point
1207:     void updatePoint(const point_type& p, const value_type v[], const int orientation = 1) {
1208:       const index_type& idx = this->_atlas->restrictPoint(p)[0];
1209:       value_type       *a   = &(this->_array[idx.index]);

1211:       if (orientation >= 0) {
1212:         for(int i = 0; i < idx.prefix; ++i) {
1213:           a[i] = v[i];
1214:         }
1215:       } else {
1216:         const int last = idx.prefix-1;

1218:         for(int i = 0; i < idx.prefix; ++i) {
1219:           a[i] = v[last-i];
1220:         }
1221:       }
1222:     };
1223:     // Update the free values on a point
1224:     void updateAddPoint(const point_type& p, const value_type v[], const int orientation = 1) {
1225:       const index_type& idx = this->_atlas->restrictPoint(p)[0];
1226:       value_type       *a   = &(this->_array[idx.index]);

1228:       if (orientation >= 0) {
1229:         for(int i = 0; i < idx.prefix; ++i) {
1230:           a[i] += v[i];
1231:         }
1232:       } else {
1233:         const int last = idx.prefix-1;

1235:         for(int i = 0; i < idx.prefix; ++i) {
1236:           a[i] += v[last-i];
1237:         }
1238:       }
1239:     };
1240:     // Update only the constrained dofs on a point
1241:     void updatePointBC(const point_type& p, const value_type v[], const int orientation = 1) {
1242:       const index_type& idx = this->_atlas->restrictPoint(p)[0];
1243:       const int         dim = -idx.prefix;
1244:       value_type       *a   = &(this->_array[idx.index]);

1246:       if (orientation >= 0) {
1247:         for(int i = 0; i < dim; ++i) {
1248:           a[i] = v[i];
1249:         }
1250:       } else {
1251:         const int last = dim-1;

1253:         for(int i = 0; i < dim; ++i) {
1254:           a[i] = v[last-i];
1255:         }
1256:       }
1257:     };
1258:     // Update all dofs on a point (free and constrained)
1259:     void updatePointAll(const point_type& p, const value_type v[], const int orientation = 1) {
1260:       const index_type& idx = this->_atlas->restrictPoint(p)[0];
1261:       const int         dim = std::abs(idx.prefix);
1262:       value_type       *a   = &(this->_array[idx.index]);

1264:       if (orientation >= 0) {
1265:         for(int i = 0; i < dim; ++i) {
1266:           a[i] = v[i];
1267:         }
1268:       } else {
1269:         const int last = dim-1;

1271:         for(int i = 0; i < dim; ++i) {
1272:           a[i] = v[last-i];
1273:         }
1274:       }
1275:     };
1276:   public:
1277:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
1278:       ostringstream txt;
1279:       int rank;

1281:       if (comm == MPI_COMM_NULL) {
1282:         comm = this->comm();
1283:         rank = this->commRank();
1284:       } else {
1285:         MPI_Comm_rank(comm, &rank);
1286:       }
1287:       if(rank == 0) {
1288:         txt << "viewing Section " << this->getName() << std::endl;
1289:         if (name != "") {
1290:           txt << ": " << name << "'";
1291:         }
1292:         txt << std::endl;
1293:       }
1294:       const typename atlas_type::chart_type& chart = this->_atlas->getChart();
1295:       const value_type                      *array = this->_array;

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

1302:         if (idx.prefix != 0) {
1303:           txt << "[" << this->commRank() << "]:   " << point << " dim " << idx.prefix << " offset " << idx.index << "  ";
1304:           for(int i = 0; i < dim; i++) {
1305:             txt << " " << array[idx.index+i];
1306:           }
1307:           txt << std::endl;
1308:         }
1309:       }
1310:       if (chart.size() == 0) {
1311:         txt << "[" << this->commRank() << "]: empty" << std::endl;
1312:       }
1313:       PetscSynchronizedPrintf(comm, txt.str().c_str());
1314:       PetscSynchronizedFlush(comm);
1315:     };
1316:   public: // Fibrations
1317:     void setConstraintDof(const point_type& p, const int dofs[]) {};
1318:     int getNumSpaces() const {return 1;};
1319:     void addSpace() {};
1320:     int getFiberDimension(const point_type& p, const int space) {return this->getFiberDimension(p);};
1321:     void setFiberDimension(const point_type& p, int dim, const int space) {this->setFiberDimension(p, dim);};
1322:     template<typename Sequence>
1323:     void setFiberDimension(const Obj<Sequence>& points, int dim, const int space) {
1324:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
1325:         this->setFiberDimension(*p_iter, dim, space);
1326:       }
1327:     };
1328:     void setConstraintDimension(const point_type& p, const int numConstraints, const int space) {
1329:       this->setConstraintDimension(p, numConstraints);
1330:     };
1331:   };
1332:   // GeneralSection will support BC on a subset of unknowns on a point
1333:   //   We make a separate constraint Atlas to mark constrained dofs on a point
1334:   //   Storage will be contiguous by node, just as in Section
1335:   //     This allows fast restrict(p)
1336:   //     Then update() is accomplished by skipping constrained unknowns
1337:   //     We must eliminate restrict() since it does not correspond to the constrained system
1338:   //   Numbering will have to be rewritten to calculate correct mappings
1339:   //     I think we can just generate multiple tuples per point
1340:   template<typename Point_, typename Value_, typename Alloc_ = std::allocator<Value_>,
1341:            typename Atlas_ = UniformSection<Point_, Point, 1, typename Alloc_::template rebind<Point>::other>,
1342:            typename BCAtlas_ = Section<Point_, int, typename Alloc_::template rebind<int>::other> >
1343:   class GeneralSection : public ALE::ParallelObject {
1344:   public:
1345:     typedef Point_                                                  point_type;
1346:     typedef Value_                                                  value_type;
1347:     typedef Alloc_                                                  alloc_type;
1348:     typedef Atlas_                                                  atlas_type;
1349:     typedef BCAtlas_                                                bc_type;
1350:     typedef Point                                                   index_type;
1351:     typedef typename atlas_type::chart_type                         chart_type;
1352:     typedef value_type *                                            values_type;
1353:     typedef std::pair<const int *, const int *>                     customAtlasInd_type;
1354:     typedef std::pair<customAtlasInd_type, bool>                    customAtlas_type;
1355:     typedef typename alloc_type::template rebind<atlas_type>::other atlas_alloc_type;
1356:     typedef typename atlas_alloc_type::pointer                      atlas_ptr;
1357:     typedef typename alloc_type::template rebind<bc_type>::other    bc_alloc_type;
1358:     typedef typename bc_alloc_type::pointer                         bc_ptr;
1359:   protected:
1360:     Obj<atlas_type> _atlas;
1361:     Obj<atlas_type> _atlasNew;
1362:     values_type     _array;
1363:     bool            _sharedStorage;
1364:     int             _sharedStorageSize;
1365:     Obj<bc_type>    _bc;
1366:     alloc_type      _allocator;
1367:     std::vector<Obj<atlas_type> > _spaces;
1368:     std::vector<Obj<bc_type> >    _bcs;
1369:     // Optimization
1370:     std::vector<customAtlas_type> _customRestrictAtlas;
1371:     std::vector<customAtlas_type> _customUpdateAtlas;
1372:   public:
1373:     GeneralSection(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {
1374:       atlas_ptr pAtlas = atlas_alloc_type(this->_allocator).allocate(1);
1375:       atlas_alloc_type(this->_allocator).construct(pAtlas, atlas_type(comm, debug));
1376:       this->_atlas         = Obj<atlas_type>(pAtlas, sizeof(atlas_type));
1377:       bc_ptr pBC           = bc_alloc_type(this->_allocator).allocate(1);
1378:       bc_alloc_type(this->_allocator).construct(pBC, bc_type(comm, debug));
1379:       this->_bc            = Obj<bc_type>(pBC, sizeof(bc_type));
1380:       this->_atlasNew      = NULL;
1381:       this->_array         = NULL;
1382:       this->_sharedStorage = false;
1383:     };
1384:     GeneralSection(const Obj<atlas_type>& atlas) : ParallelObject(atlas->comm(), atlas->debug()), _atlas(atlas), _atlasNew(NULL), _array(NULL), _sharedStorage(false), _sharedStorageSize(0) {
1385:       bc_ptr pBC = bc_alloc_type(this->_allocator).allocate(1);
1386:       bc_alloc_type(this->_allocator).construct(pBC, bc_type(comm, debug));
1387:       this->_bc  = Obj<bc_type>(pBC, sizeof(bc_type));
1388:     };
1389:     ~GeneralSection() {
1390:       if (this->_array && !this->_sharedStorage) {
1391:         const int totalSize = this->sizeWithBC();

1393:         for(int i = 0; i < totalSize; ++i) {this->_allocator.destroy(this->_array+i);}
1394:         this->_allocator.deallocate(this->_array, totalSize);
1395:         ///delete [] this->_array;
1396:         this->_array = NULL;
1397:       }
1398:       for(std::vector<customAtlas_type>::iterator a_iter = this->_customRestrictAtlas.begin(); a_iter != this->_customRestrictAtlas.end(); ++a_iter) {
1399:         if (a_iter->second) {
1400:           delete [] a_iter->first.first;
1401:           delete [] a_iter->first.second;
1402:         }
1403:       }
1404:       for(std::vector<customAtlas_type>::iterator a_iter = this->_customUpdateAtlas.begin(); a_iter != this->_customUpdateAtlas.end(); ++a_iter) {
1405:         if (a_iter->second) {
1406:           delete [] a_iter->first.first;
1407:           delete [] a_iter->first.second;
1408:         }
1409:       }
1410:     };
1411:   public:
1412:     value_type *getRawArray(const int size) {
1413:       // Put in a sentinel value that deallocates the array
1414:       static value_type *array   = NULL;
1415:       static int         maxSize = 0;

1417:       if (size > maxSize) {
1418:         const value_type dummy(0);

1420:         if (array) {
1421:           for(int i = 0; i < maxSize; ++i) {this->_allocator.destroy(array+i);}
1422:           this->_allocator.deallocate(array, maxSize);
1423:           ///delete [] array;
1424:         }
1425:         maxSize = size;
1426:         array   = this->_allocator.allocate(maxSize);
1427:         for(int i = 0; i < maxSize; ++i) {this->_allocator.construct(array+i, dummy);}
1428:         ///array = new value_type[maxSize];
1429:       };
1430:       return array;
1431:     };
1432:     int getStorageSize() const {
1433:       if (this->_sharedStorage) {
1434:         return this->_sharedStorageSize;
1435:       }
1436:       return this->sizeWithBC();
1437:     };
1438:   public: // Verifiers
1439:     bool hasPoint(const point_type& point) {
1440:       return this->_atlas->hasPoint(point);
1441:     };
1442:   public: // Accessors
1443:     const Obj<atlas_type>& getAtlas() const {return this->_atlas;};
1444:     void setAtlas(const Obj<atlas_type>& atlas) {this->_atlas = atlas;};
1445:     const Obj<atlas_type>& getNewAtlas() const {return this->_atlasNew;};
1446:     void setNewAtlas(const Obj<atlas_type>& atlas) {this->_atlasNew = atlas;};
1447:     const Obj<bc_type>& getBC() const {return this->_bc;};
1448:     void setBC(const Obj<bc_type>& bc) {this->_bc = bc;};
1449:     const chart_type& getChart() const {return this->_atlas->getChart();};
1450:   public: // BC
1451:     // Returns the number of constraints on a point
1452:     const int getConstraintDimension(const point_type& p) const {
1453:       if (!this->_bc->hasPoint(p)) return 0;
1454:       return this->_bc->getFiberDimension(p);
1455:     };
1456:     // Set the number of constraints on a point
1457:     void setConstraintDimension(const point_type& p, const int numConstraints) {
1458:       this->_bc->setFiberDimension(p, numConstraints);
1459:     };
1460:     // Increment the number of constraints on a point
1461:     void addConstraintDimension(const point_type& p, const int numConstraints) {
1462:       this->_bc->addFiberDimension(p, numConstraints);
1463:     };
1464:     // Return the local dofs which are constrained on a point
1465:     const int *getConstraintDof(const point_type& p) {
1466:       return this->_bc->restrictPoint(p);
1467:     };
1468:     // Set the local dofs which are constrained on a point
1469:     void setConstraintDof(const point_type& p, const int dofs[]) {
1470:       this->_bc->updatePoint(p, dofs);
1471:     };
1472:     void copyBC(const Obj<GeneralSection>& section) {
1473:       this->setBC(section->getBC());
1474:       const chart_type& chart = this->getChart();

1476:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
1477:         if (this->getConstraintDimension(*p_iter)) {
1478:           this->updatePointBCFull(*p_iter, section->restrictPoint(*p_iter));
1479:         }
1480:       }
1481:       this->copyFibration(section);
1482:     };
1483:     void defaultConstraintDof() {
1484:       const chart_type& chart = this->getChart();
1485:       int size = 0;

1487:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
1488:         size = std::max(size, this->getConstraintDimension(*p_iter));
1489:       }
1490:       int *dofs = new int[size];
1491:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
1492:         const int cDim = this->getConstraintDimension(*p_iter);

1494:         if (cDim) {
1495:           for(int d = 0; d < cDim; ++d) {
1496:             dofs[d] = d;
1497:           }
1498:           this->_bc->updatePoint(*p_iter, dofs);
1499:         }
1500:       }
1501:       delete [] dofs;
1502:     };
1503:   public: // Sizes
1504:     void clear() {
1505:       this->_atlas->clear();
1506:       if (!this->_sharedStorage) {
1507:         const int totalSize = this->sizeWithBC();

1509:         for(int i = 0; i < totalSize; ++i) {this->_allocator.destroy(this->_array+i);}
1510:         this->_allocator.deallocate(this->_array, totalSize);
1511:         ///delete [] this->_array;
1512:       }
1513:       this->_array = NULL;
1514:       this->_bc->clear();
1515:     };
1516:     // Return the total number of dofs on the point (free and constrained)
1517:     int getFiberDimension(const point_type& p) const {
1518:       return this->_atlas->restrictPoint(p)->prefix;
1519:     };
1520:     int getFiberDimension(const Obj<atlas_type>& atlas, const point_type& p) const {
1521:       return atlas->restrictPoint(p)->prefix;
1522:     };
1523:     // Set the total number of dofs on the point (free and constrained)
1524:     void setFiberDimension(const point_type& p, int dim) {
1525:       const index_type idx(dim, -1);
1526:       this->_atlas->addPoint(p);
1527:       this->_atlas->updatePoint(p, &idx);
1528:     };
1529:     template<typename Sequence>
1530:     void setFiberDimension(const Obj<Sequence>& points, int dim) {
1531:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
1532:         this->setFiberDimension(*p_iter, dim);
1533:       }
1534:     };
1535:     void addFiberDimension(const point_type& p, int dim) {
1536:       if (this->_atlas->hasPoint(p)) {
1537:         const index_type values(dim, 0);
1538:         this->_atlas->updateAddPoint(p, &values);
1539:       } else {
1540:         this->setFiberDimension(p, dim);
1541:       }
1542:     };
1543:     // Return the number of constrained dofs on this point
1544:     int getConstrainedFiberDimension(const point_type& p) const {
1545:       return this->getFiberDimension(p) - this->getConstraintDimension(p);
1546:     };
1547:     // Return the total number of free dofs
1548:     int size() const {
1549:       const chart_type& points = this->getChart();
1550:       int               size   = 0;

1552:       for(typename chart_type::const_iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
1553:         size += this->getConstrainedFiberDimension(*p_iter);
1554:       }
1555:       return size;
1556:     };
1557:     // Return the total number of dofs (free and constrained)
1558:     int sizeWithBC() const {
1559:       const chart_type& points = this->getChart();
1560:       int               size   = 0;

1562:       for(typename chart_type::const_iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
1563:         size += this->getFiberDimension(*p_iter);
1564:       }
1565:       return size;
1566:     };
1567:   public: // Index retrieval
1568:     const typename index_type::index_type& getIndex(const point_type& p) {
1569:       return this->_atlas->restrictPoint(p)->index;
1570:     };
1571:     void setIndex(const point_type& p, const typename index_type::index_type& index) {
1572:       ((typename atlas_type::value_type *) this->_atlas->restrictPoint(p))->index = index;
1573:     };
1574:     void setIndexBC(const point_type& p, const typename index_type::index_type& index) {};
1575:     void getIndices(const point_type& p, PetscInt indices[], PetscInt *indx, const int orientation = 1, const bool freeOnly = false, const bool skipConstraints = true) {
1576:       this->getIndices(p, this->getIndex(p), indices, indx, orientation, freeOnly, skipConstraints);
1577:     };
1578:     template<typename Order_>
1579:     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) {
1580:       this->getIndices(p, order->getIndex(p), indices, indx, orientation, freeOnly, skipConstraints);
1581:     };
1582:     void getIndicesRaw(const point_type& p, const int start, PetscInt indices[], PetscInt *indx, const int orientation) {
1583:       if (orientation >= 0) {
1584:         const int& dim = this->getFiberDimension(p);
1585:         const int  end = start + dim;

1587:         for(int i = start; i < end; ++i) {
1588:           indices[(*indx)++] = i;
1589:         }
1590:       } else {
1591:         const int numSpaces = this->getNumSpaces();
1592:         int offset = start;

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

1597:           for(int i = offset+dim-1; i >= offset; --i) {
1598:             indices[(*indx)++] = i;
1599:           }
1600:           offset += dim;
1601:         }
1602:         if (!numSpaces) {
1603:           const int& dim = this->getFiberDimension(p);

1605:           for(int i = offset+dim-1; i >= offset; --i) {
1606:             indices[(*indx)++] = i;
1607:           }
1608:           offset += dim;
1609:         }
1610:       }
1611:     }
1612:     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) {
1613:       const int& cDim = this->getConstraintDimension(p);

1615:       if (!cDim) {
1616:         this->getIndicesRaw(p, start, indices, indx, orientation);
1617:       } else {
1618:         if (orientation >= 0) {
1619:           const int&                          dim  = this->getFiberDimension(p);
1620:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
1621:           int                                 cInd = 0;

1623:           for(int i = start, k = 0; k < dim; ++k) {
1624:             if ((cInd < cDim) && (k == cDof[cInd])) {
1625:               if (!freeOnly) indices[(*indx)++] = -(k+1);
1626:               if (skipConstraints) ++i;
1627:               ++cInd;
1628:             } else {
1629:               indices[(*indx)++] = i++;
1630:             }
1631:           }
1632:         } else {
1633:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
1634:           int                                 offset  = 0;
1635:           int                                 cOffset = 0;
1636:           int                                 j       = -1;

1638:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1639:             const int  dim = this->getFiberDimension(p, space);
1640:             const int tDim = this->getConstrainedFiberDimension(p, space);
1641:             int       cInd = (dim - tDim)-1;

1643:             j += dim;
1644:             for(int i = 0, k = start+tDim+offset; i < dim; ++i, --j) {
1645:               if ((cInd >= 0) && (j == cDof[cInd+cOffset])) {
1646:                 if (!freeOnly) indices[(*indx)++] = -(offset+i+1);
1647:                 if (skipConstraints) --k;
1648:                 --cInd;
1649:               } else {
1650:                 indices[(*indx)++] = --k;
1651:               }
1652:             }
1653:             j       += dim;
1654:             offset  += dim;
1655:             cOffset += dim - tDim;
1656:           }
1657:         }
1658:       }
1659:     };
1660:   public: // Allocation
1661:     void allocateStorage() {
1662:       const int totalSize = this->sizeWithBC();
1663:       const value_type dummy(0) ;

1665:       this->_array             = this->_allocator.allocate(totalSize);
1666:       ///this->_array             = new value_type[totalSize];
1667:       this->_sharedStorage     = false;
1668:       this->_sharedStorageSize = 0;
1669:       for(int i = 0; i < totalSize; ++i) {this->_allocator.construct(this->_array+i, dummy);}
1670:       ///PetscMemzero(this->_array, totalSize * sizeof(value_type));
1671:       this->_bc->allocatePoint();
1672:     };
1673:     void replaceStorage(value_type *newArray, const bool sharedStorage = false, const int sharedStorageSize = 0) {
1674:       if (this->_array && !this->_sharedStorage) {
1675:         const int totalSize = this->sizeWithBC();

1677:         for(int i = 0; i < totalSize; ++i) {this->_allocator.destroy(this->_array+i);}
1678:         this->_allocator.deallocate(this->_array, totalSize);
1679:         ///delete [] this->_array;
1680:       }
1681:       this->_array             = newArray;
1682:       this->_sharedStorage     = sharedStorage;
1683:       this->_sharedStorageSize = sharedStorageSize;
1684:       this->_atlas             = this->_atlasNew;
1685:       this->_atlasNew          = NULL;
1686:     };
1687:     void addPoint(const point_type& point, const int dim) {
1688:       if (dim == 0) return;
1689:       if (this->_atlasNew.isNull()) {
1690:         this->_atlasNew = new atlas_type(this->comm(), this->debug());
1691:         this->_atlasNew->copy(this->_atlas);
1692:       }
1693:       const index_type idx(dim, -1);
1694:       this->_atlasNew->addPoint(point);
1695:       this->_atlasNew->updatePoint(point, &idx);
1696:     };
1697:     void orderPoints(const Obj<atlas_type>& atlas){
1698:       const chart_type& chart  = this->getChart();
1699:       int               offset = 0;

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

1705:         idx.index = offset;
1706:         atlas->updatePoint(*c_iter, &idx);
1707:         offset += dim;
1708:       }
1709:     };
1710:     void allocatePoint() {
1711:       this->orderPoints(this->_atlas);
1712:       this->allocateStorage();
1713:     };
1714:   public: // Restriction and Update
1715:     // Zero entries
1716:     void zero() {
1717:       this->set(0.0);
1718:     };
1719:     void set(const value_type value) {
1720:       //memset(this->_array, 0, this->sizeWithBC()* sizeof(value_type));
1721:       const chart_type& chart = this->getChart();

1723:       for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
1724:         value_type *array = (value_type *) this->restrictPoint(*c_iter);
1725:         const int&  dim   = this->getFiberDimension(*c_iter);
1726:         const int&  cDim  = this->getConstraintDimension(*c_iter);

1728:         if (!cDim) {
1729:           for(int i = 0; i < dim; ++i) {
1730:             array[i] = value;
1731:           }
1732:         } else {
1733:           const typename bc_type::value_type *cDof = this->getConstraintDof(*c_iter);
1734:           int                                 cInd = 0;

1736:           for(int i = 0; i < dim; ++i) {
1737:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
1738:             array[i] = value;
1739:           }
1740:         }
1741:       }
1742:     };
1743:     // Add two sections and put the result in a third
1744:     void add(const Obj<GeneralSection>& x, const Obj<GeneralSection>& y) {
1745:       // Check atlases
1746:       const chart_type& chart = this->getChart();

1748:       for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
1749:         value_type       *array  = (value_type *) this->restrictPoint(*c_iter);
1750:         const value_type *xArray = x->restrictPoint(*c_iter);
1751:         const value_type *yArray = y->restrictPoint(*c_iter);
1752:         const int&        dim    = this->getFiberDimension(*c_iter);
1753:         const int&        cDim   = this->getConstraintDimension(*c_iter);

1755:         if (!cDim) {
1756:           for(int i = 0; i < dim; ++i) {
1757:             array[i] = xArray[i] + yArray[i];
1758:           }
1759:         } else {
1760:           const typename bc_type::value_type *cDof = this->getConstraintDof(*c_iter);
1761:           int                                 cInd = 0;

1763:           for(int i = 0; i < dim; ++i) {
1764:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
1765:             array[i] = xArray[i] + yArray[i];
1766:           }
1767:         }
1768:       }
1769:     };
1770:     // this = this + alpha * x
1771:     void axpy(const value_type alpha, const Obj<GeneralSection>& x) {
1772:       // Check atlases
1773:       const chart_type& chart = this->getChart();

1775:       for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
1776:         value_type       *array  = (value_type *) this->restrictPoint(*c_iter);
1777:         const value_type *xArray = x->restrictPoint(*c_iter);
1778:         const int&        dim    = this->getFiberDimension(*c_iter);
1779:         const int&        cDim   = this->getConstraintDimension(*c_iter);

1781:         if (!cDim) {
1782:           for(int i = 0; i < dim; ++i) {
1783:             array[i] += alpha*xArray[i];
1784:           }
1785:         } else {
1786:           const typename bc_type::value_type *cDof = this->getConstraintDof(*c_iter);
1787:           int                                 cInd = 0;

1789:           for(int i = 0; i < dim; ++i) {
1790:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
1791:             array[i] += alpha*xArray[i];
1792:           }
1793:         }
1794:       }
1795:     };
1796:     // Return the free values on a point
1797:     const value_type *restrict() const {
1798:       return this->_array;
1799:     };
1800:     // Return the free values on a point
1801:     const value_type *restrictPoint(const point_type& p) const {
1802:       return &(this->_array[this->_atlas->restrictPoint(p)[0].index]);
1803:     };
1804:     // Update the free values on a point
1805:     //   Takes a full array and ignores constrained values
1806:     void updatePoint(const point_type& p, const value_type v[], const int orientation = 1) {
1807:       value_type *array = (value_type *) this->restrictPoint(p);
1808:       const int&  cDim  = this->getConstraintDimension(p);

1810:       if (!cDim) {
1811:         if (orientation >= 0) {
1812:           const int& dim = this->getFiberDimension(p);

1814:           for(int i = 0; i < dim; ++i) {
1815:             array[i] = v[i];
1816:           }
1817:         } else {
1818:           int offset = 0;
1819:           int j      = -1;

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

1824:             for(int i = dim-1; i >= 0; --i) {
1825:               array[++j] = v[i+offset];
1826:             }
1827:             offset += dim;
1828:           }
1829:         }
1830:       } else {
1831:         if (orientation >= 0) {
1832:           const int&                          dim  = this->getFiberDimension(p);
1833:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
1834:           int                                 cInd = 0;

1836:           for(int i = 0; i < dim; ++i) {
1837:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
1838:             array[i] = v[i];
1839:           }
1840:         } else {
1841:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
1842:           int                                 offset  = 0;
1843:           int                                 cOffset = 0;
1844:           int                                 j       = 0;

1846:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1847:             const int  dim = this->getFiberDimension(p, space);
1848:             const int tDim = this->getConstrainedFiberDimension(p, space);
1849:             const int sDim = dim - tDim;
1850:             int       cInd = 0;

1852:             for(int i = 0, k = dim+offset-1; i < dim; ++i, ++j, --k) {
1853:               if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
1854:               array[j] = v[k];
1855:             }
1856:             offset  += dim;
1857:             cOffset += dim - tDim;
1858:           }
1859:         }
1860:       }
1861:     };
1862:     // Update the free values on a point
1863:     //   Takes a full array and ignores constrained values
1864:     void updateAddPoint(const point_type& p, const value_type v[], const int orientation = 1) {
1865:       value_type *array = (value_type *) this->restrictPoint(p);
1866:       const int&  cDim  = this->getConstraintDimension(p);

1868:       if (!cDim) {
1869:         if (orientation >= 0) {
1870:           const int& dim = this->getFiberDimension(p);

1872:           for(int i = 0; i < dim; ++i) {
1873:             array[i] += v[i];
1874:           }
1875:         } else {
1876:           int offset = 0;
1877:           int j      = -1;

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

1882:             for(int i = dim-1; i >= 0; --i) {
1883:               array[++j] += v[i+offset];
1884:             }
1885:             offset += dim;
1886:           }
1887:         }
1888:       } else {
1889:         if (orientation >= 0) {
1890:           const int&                          dim  = this->getFiberDimension(p);
1891:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
1892:           int                                 cInd = 0;

1894:           for(int i = 0; i < dim; ++i) {
1895:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
1896:             array[i] += v[i];
1897:           }
1898:         } else {
1899:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
1900:           int                                 offset  = 0;
1901:           int                                 cOffset = 0;
1902:           int                                 j       = 0;

1904:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1905:             const int  dim = this->getFiberDimension(p, space);
1906:             const int tDim = this->getConstrainedFiberDimension(p, space);
1907:             const int sDim = dim - tDim;
1908:             int       cInd = 0;

1910:             for(int i = 0, k = dim+offset-1; i < dim; ++i, ++j, --k) {
1911:               if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
1912:               array[j] += v[k];
1913:             }
1914:             offset  += dim;
1915:             cOffset += dim - tDim;
1916:           }
1917:         }
1918:       }
1919:     };
1920:     // Update the free values on a point
1921:     //   Takes ONLY unconstrained values
1922:     void updateFreePoint(const point_type& p, const value_type v[], const int orientation = 1) {
1923:       value_type *array = (value_type *) this->restrictPoint(p);
1924:       const int&  cDim  = this->getConstraintDimension(p);

1926:       if (!cDim) {
1927:         if (orientation >= 0) {
1928:           const int& dim = this->getFiberDimension(p);

1930:           for(int i = 0; i < dim; ++i) {
1931:             array[i] = v[i];
1932:           }
1933:         } else {
1934:           int offset = 0;
1935:           int j      = -1;

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

1940:             for(int i = dim-1; i >= 0; --i) {
1941:               array[++j] = v[i+offset];
1942:             }
1943:             offset += dim;
1944:           }
1945:         }
1946:       } else {
1947:         if (orientation >= 0) {
1948:           const int&                          dim  = this->getFiberDimension(p);
1949:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
1950:           int                                 cInd = 0;

1952:           for(int i = 0, k = -1; i < dim; ++i) {
1953:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
1954:             array[i] = v[++k];
1955:           }
1956:         } else {
1957:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
1958:           int                                 offset  = 0;
1959:           int                                 cOffset = 0;
1960:           int                                 j       = 0;

1962:           for(int space = 0; space < this->getNumSpaces(); ++space) {
1963:             const int  dim = this->getFiberDimension(p, space);
1964:             const int tDim = this->getConstrainedFiberDimension(p, space);
1965:             const int sDim = dim - tDim;
1966:             int       cInd = 0;

1968:             for(int i = 0, k = tDim+offset-1; i < dim; ++i, ++j) {
1969:               if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
1970:               array[j] = v[--k];
1971:             }
1972:             offset  += dim;
1973:             cOffset += dim - tDim;
1974:           }
1975:         }
1976:       }
1977:     };
1978:     // Update the free values on a point
1979:     //   Takes ONLY unconstrained values
1980:     void updateFreeAddPoint(const point_type& p, const value_type v[], const int orientation = 1) {
1981:       value_type *array = (value_type *) this->restrictPoint(p);
1982:       const int&  cDim  = this->getConstraintDimension(p);

1984:       if (!cDim) {
1985:         if (orientation >= 0) {
1986:           const int& dim = this->getFiberDimension(p);

1988:           for(int i = 0; i < dim; ++i) {
1989:             array[i] += v[i];
1990:           }
1991:         } else {
1992:           int offset = 0;
1993:           int j      = -1;

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

1998:             for(int i = dim-1; i >= 0; --i) {
1999:               array[++j] += v[i+offset];
2000:             }
2001:             offset += dim;
2002:           }
2003:         }
2004:       } else {
2005:         if (orientation >= 0) {
2006:           const int&                          dim  = this->getFiberDimension(p);
2007:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
2008:           int                                 cInd = 0;

2010:           for(int i = 0, k = -1; i < dim; ++i) {
2011:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
2012:             array[i] += v[++k];
2013:           }
2014:         } else {
2015:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
2016:           int                                 offset  = 0;
2017:           int                                 cOffset = 0;
2018:           int                                 j       = 0;

2020:           for(int space = 0; space < this->getNumSpaces(); ++space) {
2021:             const int  dim = this->getFiberDimension(p, space);
2022:             const int tDim = this->getConstrainedFiberDimension(p, space);
2023:             const int sDim = dim - tDim;
2024:             int       cInd = 0;

2026:             for(int i = 0, k = tDim+offset-1; i < dim; ++i, ++j) {
2027:               if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
2028:               array[j] += v[--k];
2029:             }
2030:             offset  += dim;
2031:             cOffset += dim - tDim;
2032:           }
2033:         }
2034:       }
2035:     };
2036:     // Update only the constrained dofs on a point
2037:     //   This takes an array with ONLY bc values
2038:     void updatePointBC(const point_type& p, const value_type v[], const int orientation = 1) {
2039:       value_type *array = (value_type *) this->restrictPoint(p);
2040:       const int&  cDim  = this->getConstraintDimension(p);

2042:       if (cDim) {
2043:         if (orientation >= 0) {
2044:           const int&                          dim  = this->getFiberDimension(p);
2045:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
2046:           int                                 cInd = 0;

2048:           for(int i = 0; i < dim; ++i) {
2049:             if (cInd == cDim) break;
2050:             if (i == cDof[cInd]) {
2051:               array[i] = v[cInd];
2052:               ++cInd;
2053:             }
2054:           }
2055:         } else {
2056:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
2057:           int                                 cOffset = 0;
2058:           int                                 j       = 0;

2060:           for(int space = 0; space < this->getNumSpaces(); ++space) {
2061:             const int  dim = this->getFiberDimension(p, space);
2062:             const int tDim = this->getConstrainedFiberDimension(p, space);
2063:             int       cInd = 0;

2065:             for(int i = 0; i < dim; ++i, ++j) {
2066:               if (cInd < 0) break;
2067:               if (j == cDof[cInd+cOffset]) {
2068:                 array[j] = v[cInd+cOffset];
2069:                 ++cInd;
2070:               }
2071:             }
2072:             cOffset += dim - tDim;
2073:           }
2074:         }
2075:       }
2076:     };
2077:     // Update only the constrained dofs on a point
2078:     //   This takes an array with ALL values, not just BC
2079:     void updatePointBCFull(const point_type& p, const value_type v[], const int orientation = 1) {
2080:       value_type *array = (value_type *) this->restrictPoint(p);
2081:       const int&  cDim  = this->getConstraintDimension(p);

2083:       if (cDim) {
2084:         if (orientation >= 0) {
2085:           const int&                          dim  = this->getFiberDimension(p);
2086:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
2087:           int                                 cInd = 0;

2089:           for(int i = 0; i < dim; ++i) {
2090:             if (cInd == cDim) break;
2091:             if (i == cDof[cInd]) {
2092:               array[i] = v[i];
2093:               ++cInd;
2094:             }
2095:           }
2096:         } else {
2097:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
2098:           int                                 offset  = 0;
2099:           int                                 cOffset = 0;
2100:           int                                 j       = 0;

2102:           for(int space = 0; space < this->getNumSpaces(); ++space) {
2103:             const int  dim = this->getFiberDimension(p, space);
2104:             const int tDim = this->getConstrainedFiberDimension(p, space);
2105:             int       cInd = 0;

2107:             for(int i = 0, k = dim+offset-1; i < dim; ++i, ++j, --k) {
2108:               if (cInd < 0) break;
2109:               if (j == cDof[cInd+cOffset]) {
2110:                 array[j] = v[k];
2111:                 ++cInd;
2112:               }
2113:             }
2114:             offset  += dim;
2115:             cOffset += dim - tDim;
2116:           }
2117:         }
2118:       }
2119:     };
2120:     // Update all dofs on a point (free and constrained)
2121:     void updatePointAll(const point_type& p, const value_type v[], const int orientation = 1) {
2122:       value_type *array = (value_type *) this->restrictPoint(p);

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

2127:         for(int i = 0; i < dim; ++i) {
2128:           array[i] = v[i];
2129:         }
2130:       } else {
2131:         int offset = 0;
2132:         int j      = -1;

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

2137:           for(int i = dim-1; i >= 0; --i) {
2138:             array[++j] = v[i+offset];
2139:           }
2140:           offset += dim;
2141:         }
2142:       }
2143:     };
2144:     // Update all dofs on a point (free and constrained)
2145:     void updatePointAllAdd(const point_type& p, const value_type v[], const int orientation = 1) {
2146:       value_type *array = (value_type *) this->restrictPoint(p);

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

2151:         for(int i = 0; i < dim; ++i) {
2152:           array[i] += v[i];
2153:         }
2154:       } else {
2155:         int offset = 0;
2156:         int j      = -1;

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

2161:           for(int i = dim-1; i >= 0; --i) {
2162:             array[++j] += v[i+offset];
2163:           }
2164:           offset += dim;
2165:         }
2166:       }
2167:     };
2168:   public: // Fibrations
2169:     int getNumSpaces() const {return this->_spaces.size();};
2170:     const std::vector<Obj<atlas_type> >& getSpaces() {return this->_spaces;};
2171:     const std::vector<Obj<bc_type> >& getBCs() {return this->_bcs;};
2172:     void addSpace() {
2173:       Obj<atlas_type> space = new atlas_type(this->comm(), this->debug());
2174:       Obj<bc_type>    bc    = new bc_type(this->comm(), this->debug());
2175:       this->_spaces.push_back(space);
2176:       this->_bcs.push_back(bc);
2177:     };
2178:     int getFiberDimension(const point_type& p, const int space) const {
2179:       return this->_spaces[space]->restrictPoint(p)->prefix;
2180:     };
2181:     void setFiberDimension(const point_type& p, int dim, const int space) {
2182:       const index_type idx(dim, -1);
2183:       this->_spaces[space]->addPoint(p);
2184:       this->_spaces[space]->updatePoint(p, &idx);
2185:     };
2186:     template<typename Sequence>
2187:     void setFiberDimension(const Obj<Sequence>& points, int dim, const int space) {
2188:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
2189:         this->setFiberDimension(*p_iter, dim, space);
2190:       }
2191:     };
2192:     const int getConstraintDimension(const point_type& p, const int space) const {
2193:       if (!this->_bcs[space]->hasPoint(p)) return 0;
2194:       return this->_bcs[space]->getFiberDimension(p);
2195:     };
2196:     void setConstraintDimension(const point_type& p, const int numConstraints, const int space) {
2197:       this->_bcs[space]->setFiberDimension(p, numConstraints);
2198:     };
2199:     int getConstrainedFiberDimension(const point_type& p, const int space) const {
2200:       return this->getFiberDimension(p, space) - this->getConstraintDimension(p, space);
2201:     };
2202:     void copyFibration(const Obj<GeneralSection>& section) {
2203:       const std::vector<Obj<atlas_type> >& spaces = section->getSpaces();
2204:       const std::vector<Obj<bc_type> >&    bcs    = section->getBCs();

2206:       this->_spaces.clear();
2207:       for(typename std::vector<Obj<atlas_type> >::const_iterator s_iter = spaces.begin(); s_iter != spaces.end(); ++s_iter) {
2208:         this->_spaces.push_back(*s_iter);
2209:       }
2210:       this->_bcs.clear();
2211:       for(typename std::vector<Obj<bc_type> >::const_iterator b_iter = bcs.begin(); b_iter != bcs.end(); ++b_iter) {
2212:         this->_bcs.push_back(*b_iter);
2213:       }
2214:     };
2215:     Obj<GeneralSection> getFibration(const int space) const {
2216:       Obj<GeneralSection> field = new GeneralSection(this->comm(), this->debug());
2217: //     Obj<atlas_type> _atlas;
2218: //     std::vector<Obj<atlas_type> > _spaces;
2219: //     Obj<bc_type>    _bc;
2220: //     std::vector<Obj<bc_type> >    _bcs;
2221:       field->addSpace();
2222:       const chart_type& chart = this->getChart();

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

2229:         if (fDim) {
2230:           field->setFiberDimension(*c_iter, fDim);
2231:           field->setFiberDimension(*c_iter, fDim, 0);
2232:         }
2233:         if (cDim) {
2234:           field->setConstraintDimension(*c_iter, cDim);
2235:           field->setConstraintDimension(*c_iter, cDim, 0);
2236:         }
2237:       }
2238:       field->allocateStorage();
2239:       Obj<atlas_type>   newAtlas = new atlas_type(this->comm(), this->debug());
2240:       const chart_type& newChart = field->getChart();

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

2246:         if (cDim) {
2247:           field->setConstraintDof(*c_iter, dof);
2248:         }
2249:       }
2250:       // Copy offsets
2251:       for(typename chart_type::iterator c_iter = newChart.begin(); c_iter != newChart.end(); ++c_iter) {
2252:         index_type idx;

2254:         idx.prefix = field->getFiberDimension(*c_iter);
2255:         idx.index  = this->_atlas->restrictPoint(*c_iter)[0].index;
2256:         for(int s = 0; s < space; ++s) {
2257:           idx.index += this->getFiberDimension(*c_iter, s);
2258:         }
2259:         newAtlas->addPoint(*c_iter);
2260:         newAtlas->updatePoint(*c_iter, &idx);
2261:       }
2262:       field->replaceStorage(this->_array, true, this->getStorageSize());
2263:       field->setAtlas(newAtlas);
2264:       return field;
2265:     };
2266:   public: // Optimization
2267:     void getCustomRestrictAtlas(const int tag, const int *offsets[], const int *indices[]) {
2268:       *offsets = this->_customRestrictAtlas[tag].first.first;
2269:       *indices = this->_customRestrictAtlas[tag].first.second;
2270:     };
2271:     void getCustomUpdateAtlas(const int tag, const int *offsets[], const int *indices[]) {
2272:       *offsets = this->_customUpdateAtlas[tag].first.first;
2273:       *indices = this->_customUpdateAtlas[tag].first.second;
2274:     };
2275:     // This returns the tag assigned to the atlas
2276:     int setCustomAtlas(const int restrictOffsets[], const int restrictIndices[], const int updateOffsets[], const int updateIndices[], bool autoFree = true) {
2277:       this->_customRestrictAtlas.push_back(customAtlas_type(customAtlasInd_type(restrictOffsets, restrictIndices), autoFree));
2278:       this->_customUpdateAtlas.push_back(customAtlas_type(customAtlasInd_type(updateOffsets, updateIndices), autoFree));
2279:       return this->_customUpdateAtlas.size()-1;
2280:     };
2281:     int copyCustomAtlas(const Obj<GeneralSection>& section, const int tag) {
2282:       const int *rOffsets, *rIndices, *uOffsets, *uIndices;

2284:       section->getCustomRestrictAtlas(tag, &rOffsets, &rIndices);
2285:       section->getCustomUpdateAtlas(tag, &uOffsets, &uIndices);
2286:       return this->setCustomAtlas(rOffsets, rIndices, uOffsets, uIndices, false);
2287:     };
2288:   public:
2289:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
2290:       ostringstream txt;
2291:       int rank;

2293:       if (comm == MPI_COMM_NULL) {
2294:         comm = this->comm();
2295:         rank = this->commRank();
2296:       } else {
2297:         MPI_Comm_rank(comm, &rank);
2298:       }
2299:       if (name == "") {
2300:         if(rank == 0) {
2301:           txt << "viewing a GeneralSection" << std::endl;
2302:         }
2303:       } else {
2304:         if (rank == 0) {
2305:           txt << "viewing GeneralSection '" << name << "'" << std::endl;
2306:         }
2307:       }
2308:       if (rank == 0) {
2309:         txt << "  Fields: " << this->getNumSpaces() << std::endl;
2310:       }
2311:       const chart_type& chart = this->getChart();

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

2317:         if (dim != 0) {
2318:           txt << "[" << this->commRank() << "]:   " << *p_iter << " dim " << dim << " offset " << this->_atlas->restrictPoint(*p_iter)->index << "  ";
2319:           for(int i = 0; i < dim; i++) {
2320:             txt << " " << array[i];
2321:           }
2322:           const int& dim = this->getConstraintDimension(*p_iter);

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

2327:             txt << " constrained";
2328:             for(int i = 0; i < dim; ++i) {
2329:               txt << " " << bcArray[i];
2330:             }
2331:           }
2332:           txt << std::endl;
2333:         }
2334:       }
2335:       if (chart.size() == 0) {
2336:         txt << "[" << this->commRank() << "]: empty" << std::endl;
2337:       }
2338:       PetscSynchronizedPrintf(comm, txt.str().c_str());
2339:       PetscSynchronizedFlush(comm);
2340:     };
2341:   };
2342:   // A Field combines several sections
2343:   template<typename Overlap_, typename Patch_, typename Section_>
2344:   class Field : public ALE::ParallelObject {
2345:   public:
2346:     typedef Overlap_                                 overlap_type;
2347:     typedef Patch_                                   patch_type;
2348:     typedef Section_                                 section_type;
2349:     typedef typename section_type::point_type        point_type;
2350:     typedef typename section_type::chart_type        chart_type;
2351:     typedef typename section_type::value_type        value_type;
2352:     typedef std::map<patch_type, Obj<section_type> > sheaf_type;
2353:     typedef enum {SEND, RECEIVE}                     request_type;
2354:     typedef std::map<patch_type, MPI_Request>        requests_type;
2355:   protected:
2356:     sheaf_type    _sheaf;
2357:     int           _tag;
2358:     MPI_Datatype  _datatype;
2359:     requests_type _requests;
2360:   public:
2361:     Field(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {
2362:       this->_tag      = this->getNewTag();
2363:       this->_datatype = this->getMPIDatatype();
2364:     };
2365:     Field(MPI_Comm comm, const int tag, const int debug) : ParallelObject(comm, debug), _tag(tag) {
2366:       this->_datatype = this->getMPIDatatype();
2367:     };
2368:     virtual ~Field() {};
2369:   protected:
2370:     MPI_Datatype getMPIDatatype() {
2371:       if (sizeof(value_type) == 4) {
2372:         return MPI_INT;
2373:       } else if (sizeof(value_type) == 8) {
2374:         return MPI_DOUBLE;
2375:       } else if (sizeof(value_type) == 28) {
2376:         int          blen[2];
2377:         MPI_Aint     indices[2];
2378:         MPI_Datatype oldtypes[2], newtype;
2379:         blen[0] = 1; indices[0] = 0;           oldtypes[0] = MPI_INT;
2380:         blen[1] = 3; indices[1] = sizeof(int); oldtypes[1] = MPI_DOUBLE;
2381:         MPI_Type_struct(2, blen, indices, oldtypes, &newtype);
2382:         MPI_Type_commit(&newtype);
2383:         return newtype;
2384:       } else if (sizeof(value_type) == 32) {
2385:         int          blen[2];
2386:         MPI_Aint     indices[2];
2387:         MPI_Datatype oldtypes[2], newtype;
2388:         blen[0] = 1; indices[0] = 0;           oldtypes[0] = MPI_DOUBLE;
2389:         blen[1] = 3; indices[1] = sizeof(int); oldtypes[1] = MPI_DOUBLE;
2390:         MPI_Type_struct(2, blen, indices, oldtypes, &newtype);
2391:         MPI_Type_commit(&newtype);
2392:         return newtype;
2393:       }
2394:       throw ALE::Exception("Cannot determine MPI type for value type");
2395:     };
2396:     int getNewTag() {
2397:       static int tagKeyval = MPI_KEYVAL_INVALID;
2398:       int *tagvalp = NULL, *maxval, flg;

2400:       if (tagKeyval == MPI_KEYVAL_INVALID) {
2401:         tagvalp = (int *) malloc(sizeof(int));
2402:         MPI_Keyval_create(MPI_NULL_COPY_FN, Mesh_DelTag, &tagKeyval, (void *) NULL);
2403:         MPI_Attr_put(this->_comm, tagKeyval, tagvalp);
2404:         tagvalp[0] = 0;
2405:       }
2406:       MPI_Attr_get(this->_comm, tagKeyval, (void **) &tagvalp, &flg);
2407:       if (tagvalp[0] < 1) {
2408:         MPI_Attr_get(MPI_COMM_WORLD, MPI_TAG_UB, (void **) &maxval, &flg);
2409:         tagvalp[0] = *maxval - 128; // hope that any still active tags were issued right at the beginning of the run
2410:       }
2411:       if (this->debug()) {
2412:         std::cout << "[" << this->commRank() << "]Got new tag " << tagvalp[0] << std::endl;
2413:       }
2414:       return tagvalp[0]--;
2415:     };
2416:   public: // Verifiers
2417:     void checkPatch(const patch_type& patch) const {
2418:       if (this->_sheaf.find(patch) == this->_sheaf.end()) {
2419:         ostringstream msg;
2420:         msg << "Invalid field patch " << patch << std::endl;
2421:         throw ALE::Exception(msg.str().c_str());
2422:       }
2423:     };
2424:     bool hasPatch(const patch_type& patch) {
2425:       if (this->_sheaf.find(patch) == this->_sheaf.end()) {
2426:         return false;
2427:       }
2428:       return true;
2429:     };
2430:   public: // Accessors
2431:     int getTag() const {return this->_tag;};
2432:     void setTag(const int tag) {this->_tag = tag;};
2433:     Obj<section_type>& getSection(const patch_type& patch) {
2434:       if (this->_sheaf.find(patch) == this->_sheaf.end()) {
2435:         this->_sheaf[patch] = new section_type(this->comm(), this->debug());
2436:       }
2437:       return this->_sheaf[patch];
2438:     };
2439:     void setSection(const patch_type& patch, const Obj<section_type>& section) {this->_sheaf[patch] = section;};
2440:     const sheaf_type& getPatches() {
2441:       return this->_sheaf;
2442:     };
2443:     void clear() {
2444:       for(typename sheaf_type::const_iterator p_iter = this->_sheaf.begin(); p_iter != this->_sheaf.end(); ++p_iter) {
2445:         p_iter->second->clear();
2446:       }
2447:     };
2448:   public: //  Adapter
2449:     template<typename Topology_>
2450:     void setTopology(const Obj<Topology_>& topology) {
2451:       const typename Topology_::sheaf_type& patches = topology->getPatches();

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

2458:         for(typename Topology_::sieve_type::baseSequence::iterator b_iter = base->begin(); b_iter != base->end(); ++b_iter) {
2459:           section->setFiberDimension(*b_iter, 1);
2460:         }
2461:       }
2462:     };
2463:     void allocate() {
2464:       for(typename sheaf_type::const_iterator p_iter = this->_sheaf.begin(); p_iter != this->_sheaf.end(); ++p_iter) {
2465:         p_iter->second->allocatePoint();
2466:       }
2467:     };
2468:   public: // Communication
2469:     void construct(const int size) {
2470:       const sheaf_type& patches = this->getPatches();

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

2477:         for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
2478:           section->setFiberDimension(*c_iter, size);
2479:         }
2480:       }
2481:     };
2482:     template<typename Sizer>
2483:     void construct(const Obj<Sizer>& sizer) {
2484:       const sheaf_type& patches = this->getPatches();

2486:       for(typename sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
2487:         const patch_type         rank    = p_iter->first;
2488:         const Obj<section_type>& section = this->getSection(rank);
2489:         const chart_type&        chart   = section->getChart();
2490: 
2491:         for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
2492:           section->setFiberDimension(*c_iter, *(sizer->getSection(rank)->restrictPoint(*c_iter)));
2493:         }
2494:       }
2495:     };
2496:     void constructCommunication(const request_type& requestType) {
2497:       const sheaf_type& patches = this->getPatches();

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

2504:         if (requestType == RECEIVE) {
2505:           if (this->_debug) {std::cout <<"["<<this->commRank()<<"] Receiving data(" << section->size() << ") from " << patch << " tag " << this->_tag << std::endl;}
2506:           MPI_Recv_init((void *) section->restrict(), section->size(), this->_datatype, patch, this->_tag, this->comm(), &request);
2507:         } else {
2508:           if (this->_debug) {std::cout <<"["<<this->commRank()<<"] Sending data (" << section->size() << ") to " << patch << " tag " << this->_tag << std::endl;}
2509:           MPI_Send_init((void *) section->restrict(), section->size(), this->_datatype, patch, this->_tag, this->comm(), &request);
2510:         }
2511:         this->_requests[patch] = request;
2512:       }
2513:     };
2514:     void startCommunication() {
2515:       const sheaf_type& patches = this->getPatches();

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

2520:         MPI_Start(&request);
2521:       }
2522:     };
2523:     void endCommunication() {
2524:       const sheaf_type& patches = this->getPatches();
2525:       MPI_Status status;

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

2530:         MPI_Wait(&request, &status);
2531:       }
2532:     };
2533:   public:
2534:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
2535:       ostringstream txt;
2536:       int rank;

2538:       if (comm == MPI_COMM_NULL) {
2539:         comm = this->comm();
2540:         rank = this->commRank();
2541:       } else {
2542:         MPI_Comm_rank(comm, &rank);
2543:       }
2544:       if (name == "") {
2545:         if(rank == 0) {
2546:           txt << "viewing a Field" << std::endl;
2547:         }
2548:       } else {
2549:         if(rank == 0) {
2550:           txt << "viewing Field '" << name << "'" << std::endl;
2551:         }
2552:       }
2553:       PetscSynchronizedPrintf(comm, txt.str().c_str());
2554:       PetscSynchronizedFlush(comm);
2555:       for(typename sheaf_type::const_iterator p_iter = this->_sheaf.begin(); p_iter != this->_sheaf.end(); ++p_iter) {
2556:         ostringstream txt1;

2558:         txt1 << "[" << this->commRank() << "]: Patch " << p_iter->first << std::endl;
2559:         PetscSynchronizedPrintf(comm, txt1.str().c_str());
2560:         PetscSynchronizedFlush(comm);
2561:         p_iter->second->view("field section", comm);
2562:       }
2563:     };
2564:   };
2565: }

2567: namespace ALECompat {
2568:   namespace New {
2569:     using ALE::Obj;
2570:   // A ConstantSection is the simplest Section
2571:   //   All fibers are dimension 1
2572:   //   All values are equal to a constant
2573:   //     We need no value storage and no communication for completion
2574:   template<typename Topology_, typename Value_>
2575:   class NewConstantSection : public ALE::ParallelObject {
2576:   public:
2577:     typedef Topology_                          topology_type;
2578:     typedef typename topology_type::patch_type patch_type;
2579:     typedef typename topology_type::sieve_type sieve_type;
2580:     typedef typename topology_type::point_type point_type;
2581:     typedef std::set<point_type>               chart_type;
2582:     typedef std::map<patch_type, chart_type>   atlas_type;
2583:     typedef Value_                             value_type;
2584:   protected:
2585:     Obj<topology_type> _topology;
2586:     atlas_type         _atlas;
2587:     chart_type         _emptyChart;
2588:     value_type         _value;
2589:     value_type         _defaultValue;
2590:   public:
2591:     NewConstantSection(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug), _defaultValue(0) {
2592:       this->_topology = new topology_type(comm, debug);
2593:     };
2594:     NewConstantSection(const Obj<topology_type>& topology) : ParallelObject(topology->comm(), topology->debug()), _topology(topology) {};
2595:     NewConstantSection(const Obj<topology_type>& topology, const value_type& value) : ParallelObject(topology->comm(), topology->debug()), _topology(topology), _value(value), _defaultValue(value) {};
2596:     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) {};
2597:   public: // Verifiers
2598:     void checkPatch(const patch_type& patch) const {
2599:       this->_topology->checkPatch(patch);
2600:       if (this->_atlas.find(patch) == this->_atlas.end()) {
2601:         ostringstream msg;
2602:         msg << "Invalid atlas patch " << patch << std::endl;
2603:         throw ALE::Exception(msg.str().c_str());
2604:       }
2605:     };
2606:     void checkPoint(const patch_type& patch, const point_type& point) const {
2607:       this->checkPatch(patch);
2608:       if (this->_atlas.find(patch)->second.find(point) == this->_atlas.find(patch)->second.end()) {
2609:         ostringstream msg;
2610:         msg << "Invalid section point " << point << std::endl;
2611:         throw ALE::Exception(msg.str().c_str());
2612:       }
2613:     };
2614:     void checkDimension(const int& dim) {
2615:       if (dim != 1) {
2616:         ostringstream msg;
2617:         msg << "Invalid fiber dimension " << dim << " must be 1" << std::endl;
2618:         throw ALE::Exception(msg.str().c_str());
2619:       }
2620:     };
2621:     bool hasPatch(const patch_type& patch) {
2622:       if (this->_atlas.find(patch) == this->_atlas.end()) {
2623:         return false;
2624:       }
2625:       return true;
2626:     };
2627:     bool hasPoint(const patch_type& patch, const point_type& point) const {
2628:       this->checkPatch(patch);
2629:       return this->_atlas.find(patch)->second.count(point) > 0;
2630:     };
2631:     bool hasPoint(const point_type& point) const {
2632:       this->checkPatch(0);
2633:       return this->_atlas.find(0)->second.count(point) > 0;
2634:     };
2635:   public: // Accessors
2636:     const Obj<topology_type>& getTopology() const {return this->_topology;};
2637:     void setTopology(const Obj<topology_type>& topology) {this->_topology = topology;};
2638:     const chart_type& getPatch(const patch_type& patch) {
2639:       if (this->hasPatch(patch)) {
2640:         return this->_atlas[patch];
2641:       }
2642:       return this->_emptyChart;
2643:     };
2644:     void updatePatch(const patch_type& patch, const point_type& point) {
2645:       this->_atlas[patch].insert(point);
2646:     };
2647:     template<typename Points>
2648:     void updatePatch(const patch_type& patch, const Obj<Points>& points) {
2649:       this->_atlas[patch].insert(points->begin(), points->end());
2650:     };
2651:     value_type getDefaultValue() {return this->_defaultValue;};
2652:     void setDefaultValue(const value_type value) {this->_defaultValue = value;};
2653:   public: // Sizes
2654:     void clear() {
2655:       this->_atlas.clear();
2656:     };
2657:     int getFiberDimension(const patch_type& patch, const point_type& p) const {
2658:       if (this->hasPoint(patch, p)) return 1;
2659:       return 0;
2660:     };
2661:     void setFiberDimension(const patch_type& patch, const point_type& p, int dim) {
2662:       this->checkDimension(dim);
2663:       this->updatePatch(patch, p);
2664:     };
2665:     template<typename Sequence>
2666:     void setFiberDimension(const patch_type& patch, const Obj<Sequence>& points, int dim) {
2667:       for(typename topology_type::label_sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
2668:         this->setFiberDimension(patch, *p_iter, dim);
2669:       }
2670:     };
2671:     void addFiberDimension(const patch_type& patch, const point_type& p, int dim) {
2672:       if (this->hasPatch(patch) && (this->_atlas[patch].find(p) != this->_atlas[patch].end())) {
2673:         ostringstream msg;
2674:         msg << "Invalid addition to fiber dimension " << dim << " cannot exceed 1" << std::endl;
2675:         throw ALE::Exception(msg.str().c_str());
2676:       } else {
2677:         this->setFiberDimension(patch, p, dim);
2678:       }
2679:     };
2680:     void setFiberDimensionByDepth(const patch_type& patch, int depth, int dim) {
2681:       this->setFiberDimension(patch, this->_topology->getLabelStratum(patch, "depth", depth), dim);
2682:     };
2683:     void setFiberDimensionByHeight(const patch_type& patch, int height, int dim) {
2684:       this->setFiberDimension(patch, this->_topology->getLabelStratum(patch, "height", height), dim);
2685:     };
2686:     int size(const patch_type& patch) {return this->_atlas[patch].size();};
2687:     int size(const patch_type& patch, const point_type& p) {return this->getFiberDimension(patch, p);};
2688:   public: // Restriction
2689:     const value_type *restrict(const patch_type& patch, const point_type& p) const {
2690:       //std::cout <<"["<<this->commRank()<<"]: Constant restrict ("<<patch<<","<<p<<") from " << std::endl;
2691:       //for(typename chart_type::iterator c_iter = this->_atlas.find(patch)->second.begin(); c_iter != this->_atlas.find(patch)->second.end(); ++c_iter) {
2692:       //  std::cout <<"["<<this->commRank()<<"]:   point " << *c_iter << std::endl;
2693:       //}
2694:       if (this->hasPoint(patch, p)) {
2695:         return &this->_value;
2696:       }
2697:       return &this->_defaultValue;
2698:     };
2699:     const value_type *restrictPoint(const patch_type& patch, const point_type& p) const {return this->restrict(patch, p);};
2700:     const value_type *restrictPoint(const point_type& p) const {return this->restrict(0, p);};
2701:     void update(const patch_type& patch, const point_type& p, const value_type v[]) {
2702:       this->checkPatch(patch);
2703:       this->_value = v[0];
2704:     };
2705:     void updatePoint(const patch_type& patch, const point_type& p, const value_type v[]) {return this->update(patch, p, v);};
2706:     void updateAdd(const patch_type& patch, const point_type& p, const value_type v[]) {
2707:       this->checkPatch(patch);
2708:       this->_value += v[0];
2709:     };
2710:     void updateAddPoint(const patch_type& patch, const point_type& p, const value_type v[]) {return this->updateAdd(patch, p, v);};
2711:   public:
2712:     void copy(const Obj<NewConstantSection>& section) {
2713:       const typename topology_type::sheaf_type& patches = this->_topology->getPatches();

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

2720:         for(typename chart_type::iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
2721:           this->updatePatch(patch, *c_iter);
2722:         }
2723:         this->_value = section->restrict(patch, *chart.begin())[0];
2724:       }
2725:     };
2726:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
2727:       ostringstream txt;
2728:       int rank;

2730:       if (comm == MPI_COMM_NULL) {
2731:         comm = this->comm();
2732:         rank = this->commRank();
2733:       } else {
2734:         MPI_Comm_rank(comm, &rank);
2735:       }
2736:       if (name == "") {
2737:         if(rank == 0) {
2738:           txt << "viewing a NewConstantSection" << std::endl;
2739:         }
2740:       } else {
2741:         if(rank == 0) {
2742:           txt << "viewing NewConstantSection '" << name << "'" << std::endl;
2743:         }
2744:       }
2745:       const typename topology_type::sheaf_type& sheaf = this->_topology->getPatches();

2747:       for(typename topology_type::sheaf_type::const_iterator p_iter = sheaf.begin(); p_iter != sheaf.end(); ++p_iter) {
2748:         txt <<"["<<this->commRank()<<"]: Patch " << p_iter->first << std::endl;
2749:         txt <<"["<<this->commRank()<<"]:   Value " << this->_value << std::endl;
2750:       }
2751:       PetscSynchronizedPrintf(comm, txt.str().c_str());
2752:       PetscSynchronizedFlush(comm);
2753:     };
2754:   };

2756:   // A UniformSection often acts as an Atlas
2757:   //   All fibers are the same dimension
2758:   //     Note we can use a ConstantSection for this Atlas
2759:   //   Each point may have a different vector
2760:   //     Thus we need storage for values, and hence must implement completion
2761:   template<typename Topology_, typename Value_, int fiberDim = 1>
2762:   class UniformSection : public ALE::ParallelObject {
2763:   public:
2764:     typedef Topology_                              topology_type;
2765:     typedef typename topology_type::patch_type     patch_type;
2766:     typedef typename topology_type::sieve_type     sieve_type;
2767:     typedef typename topology_type::point_type     point_type;
2768:     typedef NewConstantSection<topology_type, int> atlas_type;
2769:     typedef typename atlas_type::chart_type        chart_type;
2770:     typedef Value_                                 value_type;
2771:     typedef struct {value_type v[fiberDim];}       fiber_type;
2772:     typedef std::map<point_type, fiber_type>       array_type;
2773:     typedef std::map<patch_type, array_type>       values_type;
2774:   protected:
2775:     Obj<atlas_type> _atlas;
2776:     values_type     _arrays;
2777:   public:
2778:     UniformSection(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {
2779:       this->_atlas = new atlas_type(comm, debug);
2780:     };
2781:     UniformSection(const Obj<topology_type>& topology) : ParallelObject(topology->comm(), topology->debug()) {
2782:       this->_atlas = new atlas_type(topology, fiberDim, 0);
2783:     };
2784:     UniformSection(const Obj<atlas_type>& atlas) : ParallelObject(atlas->comm(), atlas->debug()), _atlas(atlas) {};
2785:   protected:
2786:     value_type *getRawArray(const int size) {
2787:       static value_type *array   = NULL;
2788:       static int         maxSize = 0;

2790:       if (size > maxSize) {
2791:         maxSize = size;
2792:         if (array) delete [] array;
2793:         array = new value_type[maxSize];
2794:       };
2795:       return array;
2796:     };
2797:   public: // Verifiers
2798:     void checkPatch(const patch_type& patch) {
2799:       this->_atlas->checkPatch(patch);
2800:       if (this->_arrays.find(patch) == this->_arrays.end()) {
2801:         ostringstream msg;
2802:         msg << "Invalid section patch: " << patch << std::endl;
2803:         throw ALE::Exception(msg.str().c_str());
2804:       }
2805:     };
2806:     bool hasPatch(const patch_type& patch) {
2807:       return this->_atlas->hasPatch(patch);
2808:     };
2809:     bool hasPoint(const patch_type& patch, const point_type& point) {
2810:       return this->_atlas->hasPoint(patch, point);
2811:     };
2812:     bool hasPoint(const point_type& point) {
2813:       return this->_atlas->hasPoint(0, point);
2814:     };
2815:     void checkDimension(const int& dim) {
2816:       if (dim != fiberDim) {
2817:         ostringstream msg;
2818:         msg << "Invalid fiber dimension " << dim << " must be " << fiberDim << std::endl;
2819:         throw ALE::Exception(msg.str().c_str());
2820:       }
2821:     };
2822:   public: // Accessors
2823:     const Obj<atlas_type>& getAtlas() {return this->_atlas;};
2824:     void setAtlas(const Obj<atlas_type>& atlas) {this->_atlas = atlas;};
2825:     const Obj<topology_type>& getTopology() {return this->_atlas->getTopology();};
2826:     void setTopology(const Obj<topology_type>& topology) {this->_atlas->setTopology(topology);};
2827:     const chart_type& getPatch(const patch_type& patch) {
2828:       return this->_atlas->getPatch(patch);
2829:     };
2830:     void updatePatch(const patch_type& patch, const point_type& point) {
2831:       this->setFiberDimension(patch, point, 1);
2832:     };
2833:     template<typename Points>
2834:     void updatePatch(const patch_type& patch, const Obj<Points>& points) {
2835:       for(typename Points::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
2836:         this->setFiberDimension(patch, *p_iter, 1);
2837:       }
2838:     };
2839:     void copy(const Obj<UniformSection<Topology_, Value_, fiberDim> >& section) {
2840:       this->getAtlas()->copy(section->getAtlas());
2841:       const typename topology_type::sheaf_type& sheaf = section->getTopology()->getPatches();

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

2848:         for(typename chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
2849:           this->updatePoint(s_iter->first, *c_iter, section->restrictPoint(s_iter->first, *c_iter));
2850:         }
2851:       }
2852:     };
2853:   public: // Sizes
2854:     void clear() {
2855:       this->_atlas->clear();
2856:       this->_arrays.clear();
2857:     };
2858:     int getFiberDimension(const patch_type& patch, const point_type& p) const {
2859:       // Could check for non-existence here
2860:       return this->_atlas->restrictPoint(patch, p)[0];
2861:     };
2862:     void setFiberDimension(const patch_type& patch, const point_type& p, int dim) {
2863:       this->checkDimension(dim);
2864:       this->_atlas->updatePatch(patch, p);
2865:       this->_atlas->updatePoint(patch, p, &dim);
2866:     };
2867:     template<typename Sequence>
2868:     void setFiberDimension(const patch_type& patch, const Obj<Sequence>& points, int dim) {
2869:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
2870:         this->setFiberDimension(patch, *p_iter, dim);
2871:       }
2872:     };
2873:     void setFiberDimension(const patch_type& patch, const std::set<point_type>& points, int dim) {
2874:       for(typename std::set<point_type>::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
2875:         this->setFiberDimension(patch, *p_iter, dim);
2876:       }
2877:     };
2878:     void addFiberDimension(const patch_type& patch, const point_type& p, int dim) {
2879:       if (this->hasPatch(patch) && (this->_atlas[patch].find(p) != this->_atlas[patch].end())) {
2880:         ostringstream msg;
2881:         msg << "Invalid addition to fiber dimension " << dim << " cannot exceed " << fiberDim << std::endl;
2882:         throw ALE::Exception(msg.str().c_str());
2883:       } else {
2884:         this->setFiberDimension(patch, p, dim);
2885:       }
2886:     };
2887:     void setFiberDimensionByDepth(const patch_type& patch, int depth, int dim) {
2888:       this->setFiberDimension(patch, this->getTopology()->getLabelStratum(patch, "depth", depth), dim);
2889:     };
2890:     void setFiberDimensionByHeight(const patch_type& patch, int height, int dim) {
2891:       this->setFiberDimension(patch, this->getTopology()->getLabelStratum(patch, "height", height), dim);
2892:     };
2893:     int size(const patch_type& patch) {
2894:       const typename atlas_type::chart_type& points = this->_atlas->getPatch(patch);
2895:       int size = 0;

2897:       for(typename atlas_type::chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
2898:         size += this->getFiberDimension(patch, *p_iter);
2899:       }
2900:       return size;
2901:     };
2902:     int size(const patch_type& patch, const point_type& p) {
2903:       const typename atlas_type::chart_type&  points  = this->_atlas->getPatch(patch);
2904:       const Obj<typename sieve_type::coneSet> closure = this->getTopology()->getPatch(patch)->closure(p);
2905:       typename sieve_type::coneSet::iterator  end     = closure->end();
2906:       int size = 0;

2908:       for(typename sieve_type::coneSet::iterator c_iter = closure->begin(); c_iter != end; ++c_iter) {
2909:         if (points.count(*c_iter)) {
2910:           size += this->getFiberDimension(patch, *c_iter);
2911:         }
2912:       }
2913:       return size;
2914:     };
2915:     void orderPatches() {};
2916:   public: // Restriction
2917:     // Return a pointer to the entire contiguous storage array
2918:     const array_type& restrict(const patch_type& patch) {
2919:       this->checkPatch(patch);
2920:       return this->_arrays[patch];
2921:     };
2922:     // Return the values for the closure of this point
2923:     //   use a smart pointer?
2924:     const value_type *restrict(const patch_type& patch, const point_type& p) {
2925:       this->checkPatch(patch);
2926:       const chart_type& chart = this->getPatch(patch);
2927:       array_type& array  = this->_arrays[patch];
2928:       const int   size   = this->size(patch, p);
2929:       value_type *values = this->getRawArray(size);
2930:       int         j      = -1;

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

2937:         if (chart.count(p)) {
2938:           for(int i = 0; i < dim; ++i) {
2939:             values[++j] = array[p].v[i];
2940:           }
2941:         }
2942:         // Need only the cone
2943:         const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
2944:         typename sieve_type::coneSequence::iterator   end  = cone->end();

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

2950:             for(int i = 0; i < dim; ++i) {
2951:               values[++j] = array[*p_iter].v[i];
2952:             }
2953:           }
2954:         }
2955:       } else {
2956:         // Right now, we have no way of consistently ordering the closure()
2957:         const Obj<typename sieve_type::coneSet>& closure = this->getTopology()->getPatch(patch)->closure(p);
2958:         typename sieve_type::coneSet::iterator   end     = closure->end();

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

2964:             for(int i = 0; i < dim; ++i) {
2965:               values[++j] = array[*p_iter].v[i];
2966:             }
2967:           }
2968:         }
2969:       }
2970:       if (j != size-1) {
2971:         ostringstream txt;

2973:         txt << "Invalid restrict to point " << p << std::endl;
2974:         txt << "  j " << j << " should be " << (size-1) << std::endl;
2975:         std::cout << txt.str();
2976:         throw ALE::Exception(txt.str().c_str());
2977:       }
2978:       return values;
2979:     };
2980:     void update(const patch_type& patch, const point_type& p, const value_type v[]) {
2981:       this->_atlas->checkPatch(patch);
2982:       const chart_type& chart = this->getPatch(patch);
2983:       array_type& array = this->_arrays[patch];
2984:       int         j     = -1;

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

2990:         if (chart.count(p)) {
2991:           for(int i = 0; i < dim; ++i) {
2992:             array[p].v[i] = v[++j];
2993:           }
2994:         }
2995:         // Should be closure()
2996:         const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);

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

3002:             for(int i = 0; i < dim; ++i) {
3003:               array[*p_iter].v[i] = v[++j];
3004:             }
3005:           }
3006:         }
3007:       } else {
3008:         throw ALE::Exception("Update is not yet implemented for interpolated sieves");
3009:       }
3010:     };
3011:     void updateAdd(const patch_type& patch, const point_type& p, const value_type v[]) {
3012:       this->_atlas->checkPatch(patch);
3013:       const chart_type& chart = this->getPatch(patch);
3014:       array_type& array = this->_arrays[patch];
3015:       int         j     = -1;

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

3021:         if (chart.count(p)) {
3022:           for(int i = 0; i < dim; ++i) {
3023:             array[p].v[i] += v[++j];
3024:           }
3025:         }
3026:         // Should be closure()
3027:         const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);

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

3033:             for(int i = 0; i < dim; ++i) {
3034:               array[*p_iter].v[i] += v[++j];
3035:             }
3036:           }
3037:         }
3038:       } else {
3039:         throw ALE::Exception("Not yet implemented for interpolated sieves");
3040:       }
3041:     };
3042:     // Return only the values associated to this point, not its closure
3043:     const value_type *restrictPoint(const patch_type& patch, const point_type& p) {
3044:       this->checkPatch(patch);
3045:       return this->_arrays[patch][p].v;
3046:     };
3047:     const value_type *restrictPoint(const point_type& p) {
3048:       this->checkPatch(0);
3049:       return this->_arrays[0][p].v;
3050:     };
3051:     // Update only the values associated to this point, not its closure
3052:     void updatePoint(const patch_type& patch, const point_type& p, const value_type v[]) {
3053:       this->_atlas->checkPatch(patch);
3054:       for(int i = 0; i < fiberDim; ++i) {
3055:         this->_arrays[patch][p].v[i] = v[i];
3056:       }
3057:     };
3058:     // Update only the values associated to this point, not its closure
3059:     void updateAddPoint(const patch_type& patch, const point_type& p, const value_type v[]) {
3060:       this->_atlas->checkPatch(patch);
3061:       for(int i = 0; i < fiberDim; ++i) {
3062:         this->_arrays[patch][p].v[i] += v[i];
3063:       }
3064:     };
3065:   public:
3066:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) {
3067:       ostringstream txt;
3068:       int rank;

3070:       if (comm == MPI_COMM_NULL) {
3071:         comm = this->comm();
3072:         rank = this->commRank();
3073:       } else {
3074:         MPI_Comm_rank(comm, &rank);
3075:       }
3076:       if (name == "") {
3077:         if(rank == 0) {
3078:           txt << "viewing a UniformSection" << std::endl;
3079:         }
3080:       } else {
3081:         if(rank == 0) {
3082:           txt << "viewing UniformSection '" << name << "'" << std::endl;
3083:         }
3084:       }
3085:       for(typename values_type::const_iterator a_iter = this->_arrays.begin(); a_iter != this->_arrays.end(); ++a_iter) {
3086:         const patch_type& patch = a_iter->first;
3087:         array_type&       array = this->_arrays[patch];

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

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

3096:           if (dim != 0) {
3097:             txt << "[" << this->commRank() << "]:   " << point << " dim " << dim << "  ";
3098:             for(int i = 0; i < dim; i++) {
3099:               txt << " " << array[point].v[i];
3100:             }
3101:             txt << std::endl;
3102:           }
3103:         }
3104:       }
3105:       PetscSynchronizedPrintf(comm, txt.str().c_str());
3106:       PetscSynchronizedFlush(comm);
3107:     };
3108:   };

3110:     // A Section is our most general construct (more general ones could be envisioned)
3111:     //   The Atlas is a UniformSection of dimension 1 and value type Point
3112:     //     to hold each fiber dimension and offsets into a contiguous patch array
3113:     template<typename Topology_, typename Value_>
3114:     class Section : public ALE::ParallelObject {
3115:     public:
3116:       typedef Topology_                                 topology_type;
3117:       typedef typename topology_type::patch_type        patch_type;
3118:       typedef typename topology_type::sieve_type        sieve_type;
3119:       typedef typename topology_type::point_type        point_type;
3120:       typedef ALE::Point                                index_type;
3121:       typedef UniformSection<topology_type, index_type> atlas_type;
3122:       typedef typename atlas_type::chart_type           chart_type;
3123:       typedef Value_                                    value_type;
3124:       typedef value_type *                              array_type;
3125:       typedef std::map<patch_type, array_type>          values_type;
3126:       typedef std::vector<index_type>                   IndexArray;
3127:     protected:
3128:       Obj<atlas_type> _atlas;
3129:       Obj<atlas_type> _atlasNew;
3130:       values_type     _arrays;
3131:       Obj<IndexArray> _indexArray;
3132:     public:
3133:       Section(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {
3134:         this->_atlas      = new atlas_type(comm, debug);
3135:         this->_atlasNew   = NULL;
3136:         this->_indexArray = new IndexArray();
3137:       };
3138:       Section(const Obj<topology_type>& topology) : ParallelObject(topology->comm(), topology->debug()), _atlasNew(NULL) {
3139:         this->_atlas      = new atlas_type(topology);
3140:         this->_indexArray = new IndexArray();
3141:       };
3142:       Section(const Obj<atlas_type>& atlas) : ParallelObject(atlas->comm(), atlas->debug()), _atlas(atlas), _atlasNew(NULL) {
3143:         this->_indexArray = new IndexArray();
3144:       };
3145:       virtual ~Section() {
3146:         for(typename values_type::iterator a_iter = this->_arrays.begin(); a_iter != this->_arrays.end(); ++a_iter) {
3147:           delete [] a_iter->second;
3148:           a_iter->second = NULL;
3149:         }
3150:       };
3151:     protected:
3152:       value_type *getRawArray(const int size) {
3153:         static value_type *array   = NULL;
3154:         static int         maxSize = 0;

3156:         if (size > maxSize) {
3157:           maxSize = size;
3158:           if (array) delete [] array;
3159:           array = new value_type[maxSize];
3160:         };
3161:         return array;
3162:       };
3163:     public: // Verifiers
3164:       void checkPatch(const patch_type& patch) {
3165:         this->_atlas->checkPatch(patch);
3166:         if (this->_arrays.find(patch) == this->_arrays.end()) {
3167:           ostringstream msg;
3168:           msg << "Invalid section patch: " << patch << std::endl;
3169:           throw ALE::Exception(msg.str().c_str());
3170:         }
3171:       };
3172:       bool hasPatch(const patch_type& patch) {
3173:         return this->_atlas->hasPatch(patch);
3174:       };
3175:     public: // Accessors
3176:       const Obj<atlas_type>& getAtlas() {return this->_atlas;};
3177:       void setAtlas(const Obj<atlas_type>& atlas) {this->_atlas = atlas;};
3178:       const Obj<topology_type>& getTopology() {return this->_atlas->getTopology();};
3179:       void setTopology(const Obj<topology_type>& topology) {this->_atlas->setTopology(topology);};
3180:       const chart_type& getPatch(const patch_type& patch) {
3181:         return this->_atlas->getPatch(patch);
3182:       };
3183:       bool hasPoint(const patch_type& patch, const point_type& point) {
3184:         return this->_atlas->hasPoint(patch, point);
3185:       };
3186:     public: // Sizes
3187:       void clear() {
3188:         this->_atlas->clear();
3189:         this->_arrays.clear();
3190:       };
3191:       int getFiberDimension(const patch_type& patch, const point_type& p) const {
3192:         // Could check for non-existence here
3193:         return this->_atlas->restrictPoint(patch, p)->prefix;
3194:       };
3195:       int getFiberDimension(const Obj<atlas_type>& atlas, const patch_type& patch, const point_type& p) const {
3196:         // Could check for non-existence here
3197:         return atlas->restrictPoint(patch, p)->prefix;
3198:       };
3199:       void setFiberDimension(const patch_type& patch, const point_type& p, int dim) {
3200:         const index_type idx(dim, -1);
3201:         this->_atlas->updatePatch(patch, p);
3202:         this->_atlas->updatePoint(patch, p, &idx);
3203:       };
3204:       template<typename Sequence>
3205:       void setFiberDimension(const patch_type& patch, const Obj<Sequence>& points, int dim) {
3206:         for(typename topology_type::label_sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
3207:           this->setFiberDimension(patch, *p_iter, dim);
3208:         }
3209:       };
3210:       void addFiberDimension(const patch_type& patch, const point_type& p, int dim) {
3211:         if (this->_atlas->hasPatch(patch) && this->_atlas->hasPoint(patch, p)) {
3212:           const index_type values(dim, 0);
3213:           this->_atlas->updateAddPoint(patch, p, &values);
3214:         } else {
3215:           this->setFiberDimension(patch, p, dim);
3216:         }
3217:       };
3218:       void setFiberDimensionByDepth(const patch_type& patch, int depth, int dim) {
3219:         this->setFiberDimension(patch, this->getTopology()->getLabelStratum(patch, "depth", depth), dim);
3220:       };
3221:       void setFiberDimensionByHeight(const patch_type& patch, int height, int dim) {
3222:         this->setFiberDimension(patch, this->getTopology()->getLabelStratum(patch, "height", height), dim);
3223:       };
3224:       int size(const patch_type& patch) {
3225:         const typename atlas_type::chart_type& points = this->_atlas->getPatch(patch);
3226:         int size = 0;

3228:         for(typename atlas_type::chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
3229:           size += std::max(0, this->getFiberDimension(patch, *p_iter));
3230:         }
3231:         return size;
3232:       };
3233:       int sizeWithBC(const patch_type& patch) {
3234:         const typename atlas_type::chart_type& points = this->_atlas->getPatch(patch);
3235:         int size = 0;

3237:         for(typename atlas_type::chart_type::const_iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
3238:           size += std::abs(this->getFiberDimension(patch, *p_iter));
3239:         }
3240:         return size;
3241:       };
3242:       int size(const patch_type& patch, const point_type& p) {
3243:         if (this->getTopology()->depth() > 1) throw ALE::Exception("Compatibility layer is not for interpolated meshes");
3244:         const typename atlas_type::chart_type&  points  = this->_atlas->getPatch(patch);
3245:         const Obj<typename sieve_type::coneSequence> closure = this->getTopology()->getPatch(patch)->cone(p);
3246:         typename sieve_type::coneSequence::iterator  end     = closure->end();
3247:         int size = 0;

3249:         size += std::max(0, this->getFiberDimension(patch, p));
3250:         for(typename sieve_type::coneSequence::iterator c_iter = closure->begin(); c_iter != end; ++c_iter) {
3251:           if (points.count(*c_iter)) {
3252:             size += std::max(0, this->getFiberDimension(patch, *c_iter));
3253:           }
3254:         }
3255:         return size;
3256:       };
3257:       int sizeWithBC(const patch_type& patch, const point_type& p) {
3258:         if (this->getTopology()->depth() > 1) throw ALE::Exception("Compatibility layer is not for interpolated meshes");
3259:         const typename atlas_type::chart_type&  points  = this->_atlas->getPatch(patch);
3260:         const Obj<typename sieve_type::coneSequence> closure = this->getTopology()->getPatch(patch)->cone(p);
3261:         typename sieve_type::coneSequence::iterator  end     = closure->end();
3262:         int size = 0;

3264:         size += std::abs(this->getFiberDimension(patch, p));
3265:         for(typename sieve_type::coneSequence::iterator c_iter = closure->begin(); c_iter != end; ++c_iter) {
3266:           if (points.count(*c_iter)) {
3267:             size += std::abs(this->getFiberDimension(patch, *c_iter));
3268:           }
3269:         }
3270:         return size;
3271:       };
3272:       int size(const Obj<atlas_type>& atlas, const patch_type& patch) {
3273:         const typename atlas_type::chart_type& points = atlas->getPatch(patch);
3274:         int size = 0;

3276:         for(typename atlas_type::chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
3277:           size += std::max(0, this->getFiberDimension(atlas, patch, *p_iter));
3278:         }
3279:         return size;
3280:       };
3281:     public: // Index retrieval
3282:       const index_type& getIndex(const patch_type& patch, const point_type& p) {
3283:         this->checkPatch(patch);
3284:         return this->_atlas->restrictPoint(patch, p)[0];
3285:       };
3286:       template<typename Numbering>
3287:       const index_type getIndex(const patch_type& patch, const point_type& p, const Obj<Numbering>& numbering) {
3288:         this->checkPatch(patch);
3289:         return index_type(this->getFiberDimension(patch, p), numbering->getIndex(p));
3290:       };
3291:       const Obj<IndexArray>& getIndices(const patch_type& patch, const point_type& p, const int level = -1) {
3292:         this->_indexArray->clear();

3294:         if (level == 0) {
3295:           this->_indexArray->push_back(this->getIndex(patch, p));
3296:         } else if ((level == 1) || (this->getTopology()->height(patch) == 1)) {
3297:           const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
3298:           typename sieve_type::coneSequence::iterator   end  = cone->end();

3300:           this->_indexArray->push_back(this->getIndex(patch, p));
3301:           for(typename sieve_type::coneSequence::iterator p_iter = cone->begin(); p_iter != end; ++p_iter) {
3302:             this->_indexArray->push_back(this->getIndex(patch, *p_iter));
3303:           }
3304:         } else if (level == -1) {
3305: #if 1
3306:           throw ALE::Exception("Call should be moved to Bundle");
3307: #else
3308:           const Obj<typename sieve_type::coneSet> closure = this->getTopology()->getPatch(patch)->closure(p);
3309:           typename sieve_type::coneSet::iterator  end     = closure->end();

3311:           for(typename sieve_type::coneSet::iterator p_iter = closure->begin(); p_iter != end; ++p_iter) {
3312:             this->_indexArray->push_back(this->getIndex(patch, *p_iter));
3313:           }
3314: #endif
3315:         } else {
3316:           const Obj<typename sieve_type::coneArray> cone = this->getTopology()->getPatch(patch)->nCone(p, level);
3317:           typename sieve_type::coneArray::iterator  end  = cone->end();

3319:           for(typename sieve_type::coneArray::iterator p_iter = cone->begin(); p_iter != end; ++p_iter) {
3320:             this->_indexArray->push_back(this->getIndex(patch, *p_iter));
3321:           }
3322:         }
3323:         return this->_indexArray;
3324:       };
3325:       template<typename Numbering>
3326:       const Obj<IndexArray>& getIndices(const patch_type& patch, const point_type& p, const Obj<Numbering>& numbering, const int level = -1) {
3327:         this->_indexArray->clear();

3329:         if (level == 0) {
3330:           this->_indexArray->push_back(this->getIndex(patch, p, numbering));
3331:         } else if ((level == 1) || (this->getTopology()->height(patch) == 1)) {
3332:           const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
3333:           typename sieve_type::coneSequence::iterator   end  = cone->end();

3335:           this->_indexArray->push_back(this->getIndex(patch, p, numbering));
3336:           for(typename sieve_type::coneSequence::iterator p_iter = cone->begin(); p_iter != end; ++p_iter) {
3337:             this->_indexArray->push_back(this->getIndex(patch, *p_iter, numbering));
3338:           }
3339:         } else if (level == -1) {
3340: #if 1
3341:           throw ALE::Exception("Call should be moved to Bundle");
3342: #else
3343:           const Obj<typename sieve_type::coneSet> closure = this->getTopology()->getPatch(patch)->closure(p);
3344:           typename sieve_type::coneSet::iterator  end     = closure->end();

3346:           for(typename sieve_type::coneSet::iterator p_iter = closure->begin(); p_iter != end; ++p_iter) {
3347:             this->_indexArray->push_back(this->getIndex(patch, *p_iter, numbering));
3348:           }
3349: #endif
3350:         } else {
3351:           const Obj<typename sieve_type::coneArray> cone = this->getTopology()->getPatch(patch)->nCone(p, level);
3352:           typename sieve_type::coneArray::iterator  end  = cone->end();

3354:           for(typename sieve_type::coneArray::iterator p_iter = cone->begin(); p_iter != end; ++p_iter) {
3355:             this->_indexArray->push_back(this->getIndex(patch, *p_iter, numbering));
3356:           }
3357:         }
3358:         return this->_indexArray;
3359:       };
3360:     public: // Allocation
3361:       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) {
3362:         const Obj<typename sieve_type::coneSequence>& cone = sieve->cone(point);
3363:         typename sieve_type::coneSequence::iterator   end  = cone->end();
3364:         index_type                                    idx  = atlas->restrictPoint(patch, point)[0];
3365:         const int&                                    dim  = idx.prefix;
3366:         const index_type                              defaultIdx(0, -1);

3368:         if (atlas->getPatch(patch).count(point) == 0) {
3369:           idx = defaultIdx;
3370:         }
3371:         if (idx.index == -1) {
3372:           for(typename sieve_type::coneSequence::iterator c_iter = cone->begin(); c_iter != end; ++c_iter) {
3373:             if (this->_debug > 1) {std::cout << "    Recursing to " << *c_iter << std::endl;}
3374:             this->orderPoint(atlas, sieve, patch, *c_iter, offset, bcOffset);
3375:           }
3376:           if (dim > 0) {
3377:             bool number = true;

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

3383:               for(typename topology_type::send_overlap_type::supportSequence::iterator r_iter = ranks->begin(); r_iter != ranks->end(); ++r_iter) {
3384:                 if (this->commRank() > *r_iter) {
3385:                   number = false;
3386:                   break;
3387:                 }
3388:               }
3389:             }
3390:             if (number) {
3391:               if (this->_debug > 1) {std::cout << "  Ordering point " << point << " at " << offset << std::endl;}
3392:               idx.index = offset;
3393:               atlas->updatePoint(patch, point, &idx);
3394:               offset += dim;
3395:             } else {
3396:               if (this->_debug > 1) {std::cout << "  Ignoring ghost point " << point << std::endl;}
3397:             }
3398:           } else if (dim < 0) {
3399:             if (this->_debug > 1) {std::cout << "  Ordering boundary point " << point << " at " << bcOffset << std::endl;}
3400:             idx.index = bcOffset;
3401:             atlas->updatePoint(patch, point, &idx);
3402:             bcOffset += dim;
3403:           }
3404:         }
3405:       }
3406:       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) {
3407:         const typename atlas_type::chart_type& chart = atlas->getPatch(patch);

3409:         for(typename atlas_type::chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
3410:           if (this->_debug > 1) {std::cout << "Ordering closure of point " << *p_iter << std::endl;}
3411:           this->orderPoint(atlas, this->getTopology()->getPatch(patch), patch, *p_iter, offset, bcOffset, postponeGhosts);
3412:         }
3413:         for(typename atlas_type::chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
3414:           index_type idx = atlas->restrictPoint(patch, *p_iter)[0];
3415:           const int& dim = idx.prefix;

3417:           if (dim < 0) {
3418:             if (this->_debug > 1) {std::cout << "Correcting boundary offset of point " << *p_iter << std::endl;}
3419:             idx.index = offset - (idx.index+2);
3420:             atlas->updatePoint(patch, *p_iter, &idx);
3421:           }
3422:         }
3423:       };
3424:       void orderPatches(const Obj<atlas_type>& atlas, const bool postponeGhosts = false) {
3425:         const typename topology_type::sheaf_type& patches = this->getTopology()->getPatches();

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

3431:           if (!atlas->hasPatch(p_iter->first)) continue;
3432:           this->orderPatch(atlas, p_iter->first, offset, bcOffset, postponeGhosts);
3433:         }
3434:       };
3435:       void orderPatches(const bool postponeGhosts = false) {
3436:         this->orderPatches(this->_atlas, postponeGhosts);
3437:       };
3438:       void allocateStorage() {
3439:         const typename topology_type::sheaf_type& patches = this->getTopology()->getPatches();

3441:         for(typename topology_type::sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
3442:           if (!this->_atlas->hasPatch(p_iter->first)) continue;
3443:           this->_arrays[p_iter->first] = new value_type[this->sizeWithBC(p_iter->first)];
3444:           PetscMemzero(this->_arrays[p_iter->first], this->sizeWithBC(p_iter->first) * sizeof(value_type));
3445:         }
3446:       };
3447:       void allocate(const bool postponeGhosts = false) {
3448:         bool doGhosts = false;

3450:         if (postponeGhosts && !this->getTopology()->getSendOverlap().isNull()) {
3451:           doGhosts = true;
3452:         }
3453:         this->orderPatches(doGhosts);
3454:         if (doGhosts) {
3455:           const typename topology_type::sheaf_type& patches = this->getTopology()->getPatches();

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

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

3465:               offset = std::max(offset, idx.index + std::abs(idx.prefix));
3466:             }
3467:             if (!this->_atlas->hasPatch(p_iter->first)) continue;
3468:             this->orderPatch(this->_atlas, p_iter->first, offset, bcOffset);
3469:             if (offset != this->sizeWithBC(p_iter->first)) throw ALE::Exception("Inconsistent array sizes in section");
3470:           }
3471:         }
3472:         this->allocateStorage();
3473:       };
3474:       void addPoint(const patch_type& patch, const point_type& point, const int dim) {
3475:         if (dim == 0) return;
3476:         //const typename atlas_type::chart_type& chart = this->_atlas->getPatch(patch);

3478:         //if (chart.find(point) == chart.end()) {
3479:         if (this->_atlasNew.isNull()) {
3480:           this->_atlasNew = new atlas_type(this->getTopology());
3481:           this->_atlasNew->copy(this->_atlas);
3482:         }
3483:         const index_type idx(dim, -1);
3484:         this->_atlasNew->updatePatch(patch, point);
3485:         this->_atlasNew->updatePoint(patch, point, &idx);
3486:       };
3487:       void reallocate() {
3488:         if (this->_atlasNew.isNull()) return;
3489:         const typename topology_type::sheaf_type& patches = this->getTopology()->getPatches();

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

3497:           for(typename atlas_type::chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
3498:             defaultIdx.prefix = this->_atlasNew->restrictPoint(patch, *c_iter)[0].prefix;
3499:             this->_atlasNew->updatePoint(patch, *c_iter, &defaultIdx);
3500:           }
3501:         }
3502:         this->orderPatches(this->_atlasNew);
3503:         // Copy over existing values
3504:         for(typename topology_type::sheaf_type::const_iterator p_iter = patches.begin(); p_iter != patches.end(); ++p_iter) {
3505:           const patch_type&                      patch    = p_iter->first;
3506:           value_type                            *newArray = new value_type[this->size(this->_atlasNew, patch)];

3508:           if (!this->_atlas->hasPatch(patch)) {
3509:             this->_arrays[patch] = newArray;
3510:             continue;
3511:           }
3512:           const typename atlas_type::chart_type& chart    = this->_atlas->getPatch(patch);
3513:           const value_type                      *array    = this->_arrays[patch];

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

3521:             for(int i = 0; i < size; ++i) {
3522:               newArray[newOffset+i] = array[offset+i];
3523:             }
3524:           }
3525:           delete [] this->_arrays[patch];
3526:           this->_arrays[patch] = newArray;
3527:         }
3528:         this->_atlas    = this->_atlasNew;
3529:         this->_atlasNew = NULL;
3530:       };
3531:     public: // Restriction and Update
3532:       // Zero entries
3533:       void zero(const patch_type& patch) {
3534:         this->checkPatch(patch);
3535:         memset(this->_arrays[patch], 0, this->size(patch)* sizeof(value_type));
3536:       };
3537:       // Return a pointer to the entire contiguous storage array
3538:       const value_type *restrict(const patch_type& patch) {
3539:         this->checkPatch(patch);
3540:         return this->_arrays[patch];
3541:       };
3542:       // Update the entire contiguous storage array
3543:       void update(const patch_type& patch, const value_type v[]) {
3544:         const value_type *array = this->_arrays[patch];
3545:         const int         size  = this->size(patch);

3547:         for(int i = 0; i < size; i++) {
3548:           array[i] = v[i];
3549:         }
3550:       };
3551:       // Return the values for the closure of this point
3552:       //   use a smart pointer?
3553:       const value_type *restrict(const patch_type& patch, const point_type& p) {
3554:         this->checkPatch(patch);
3555:         const value_type *a      = this->_arrays[patch];
3556:         const int         size   = this->sizeWithBC(patch, p);
3557:         value_type       *values = this->getRawArray(size);
3558:         int               j      = -1;

3560:         if (this->getTopology()->height(patch) < 2) {
3561:           // Avoids the copy of both
3562:           //   points  in topology->closure()
3563:           //   indices in _atlas->restrict()
3564:           const index_type& pInd = this->_atlas->restrictPoint(patch, p)[0];

3566:           for(int i = pInd.index; i < std::abs(pInd.prefix) + pInd.index; ++i) {
3567:             values[++j] = a[i];
3568:           }
3569:           const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
3570:           typename sieve_type::coneSequence::iterator   end  = cone->end();

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

3577:             for(int i = start; i < start + length; ++i) {
3578:               values[++j] = a[i];
3579:             }
3580:           }
3581:         } else {
3582:           const Obj<IndexArray>& ind = this->getIndices(patch, p);

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

3588:             for(int i = start; i < start + length; ++i) {
3589:               values[++j] = a[i];
3590:             }
3591:           }
3592:         }
3593:         if (j != size-1) {
3594:           ostringstream txt;

3596:           txt << "Invalid restrict to point " << p << std::endl;
3597:           txt << "  j " << j << " should be " << (size-1) << std::endl;
3598:           std::cout << txt.str();
3599:           throw ALE::Exception(txt.str().c_str());
3600:         }
3601:         return values;
3602:       };
3603:       // Update the values for the closure of this point
3604:       void update(const patch_type& patch, const point_type& p, const value_type v[]) {
3605:         this->checkPatch(patch);
3606:         value_type *a = this->_arrays[patch];
3607:         int         j = -1;

3609:         if (this->getTopology()->height(patch) < 2) {
3610:           // Avoids the copy of both
3611:           //   points  in topology->closure()
3612:           //   indices in _atlas->restrict()
3613:           const index_type& pInd = this->_atlas->restrictPoint(patch, p)[0];

3615:           for(int i = pInd.index; i < pInd.prefix + pInd.index; ++i) {
3616:             a[i] = v[++j];
3617:           }
3618:           j += std::max(0, -pInd.prefix);
3619:           const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
3620:           typename sieve_type::coneSequence::iterator   end  = cone->end();

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

3627:             for(int i = start; i < start + length; ++i) {
3628:               a[i] = v[++j];
3629:             }
3630:             j += std::max(0, -length);
3631:           }
3632:         } else {
3633:           const Obj<IndexArray>& ind = this->getIndices(patch, p);

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

3639:             for(int i = start; i < start + length; ++i) {
3640:               a[i] = v[++j];
3641:             }
3642:             j += std::max(0, -length);
3643:           }
3644:         }
3645:       };
3646:       // Update the values for the closure of this point
3647:       void updateAdd(const patch_type& patch, const point_type& p, const value_type v[]) {
3648:         this->checkPatch(patch);
3649:         value_type *a = this->_arrays[patch];
3650:         int         j = -1;

3652:         if (this->getTopology()->height(patch) < 2) {
3653:           // Avoids the copy of both
3654:           //   points  in topology->closure()
3655:           //   indices in _atlas->restrict()
3656:           const index_type& pInd = this->_atlas->restrictPoint(patch, p)[0];

3658:           for(int i = pInd.index; i < pInd.prefix + pInd.index; ++i) {
3659:             a[i] += v[++j];
3660:           }
3661:           j += std::max(0, -pInd.prefix);
3662:           const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
3663:           typename sieve_type::coneSequence::iterator   end  = cone->end();

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

3670:             for(int i = start; i < start + length; ++i) {
3671:               a[i] += v[++j];
3672:             }
3673:             j += std::max(0, -length);
3674:           }
3675:         } else {
3676:           const Obj<IndexArray>& ind = this->getIndices(patch, p);

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

3682:             for(int i = start; i < start + length; ++i) {
3683:               a[i] += v[++j];
3684:             }
3685:             j += std::max(0, -length);
3686:           }
3687:         }
3688:       };
3689:       // Update the values for the closure of this point
3690:       template<typename Input>
3691:       void update(const patch_type& patch, const point_type& p, const Obj<Input>& v) {
3692:         this->checkPatch(patch);
3693:         value_type *a = this->_arrays[patch];

3695:         if (this->getTopology()->height(patch) == 1) {
3696:           // Only avoids the copy
3697:           const index_type& pInd = this->_atlas->restrictPoint(patch, p)[0];
3698:           typename Input::iterator v_iter = v->begin();
3699:           typename Input::iterator v_end  = v->end();

3701:           for(int i = pInd.index; i < pInd.prefix + pInd.index; ++i) {
3702:             a[i] = *v_iter;
3703:             ++v_iter;
3704:           }
3705:           const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
3706:           typename sieve_type::coneSequence::iterator   end  = cone->end();

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

3713:             for(int i = start; i < start + length; ++i) {
3714:               a[i] = *v_iter;
3715:               ++v_iter;
3716:             }
3717:           }
3718:         } else {
3719:           const Obj<IndexArray>& ind = this->getIndices(patch, p);
3720:           typename Input::iterator v_iter = v->begin();
3721:           typename Input::iterator v_end  = v->end();

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

3727:             for(int i = start; i < start + length; ++i) {
3728:               a[i] = *v_iter;
3729:               ++v_iter;
3730:             }
3731:           }
3732:         }
3733:       };
3734:       void updateBC(const patch_type& patch, const point_type& p, const value_type v[]) {
3735:         this->checkPatch(patch);
3736:         value_type *a = this->_arrays[patch];
3737:         int         j = -1;

3739:         if (this->getTopology()->height(patch) < 2) {
3740:           // Avoids the copy of both
3741:           //   points  in topology->closure()
3742:           //   indices in _atlas->restrict()
3743:           const index_type& pInd = this->_atlas->restrictPoint(patch, p)[0];

3745:           for(int i = pInd.index; i < std::abs(pInd.prefix) + pInd.index; ++i) {
3746:             a[i] = v[++j];
3747:           }
3748:           const Obj<typename sieve_type::coneSequence>& cone = this->getTopology()->getPatch(patch)->cone(p);
3749:           typename sieve_type::coneSequence::iterator   end  = cone->end();

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

3756:             for(int i = start; i < start + length; ++i) {
3757:               a[i] = v[++j];
3758:             }
3759:           }
3760:         } else {
3761:           const Obj<IndexArray>& ind = this->getIndices(patch, p);

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

3767:             for(int i = start; i < start + length; ++i) {
3768:               a[i] = v[++j];
3769:             }
3770:           }
3771:         }
3772:       };
3773:       // Return only the values associated to this point, not its closure
3774:       const value_type *restrictPoint(const patch_type& patch, const point_type& p) {
3775:         this->checkPatch(patch);
3776:         return &(this->_arrays[patch][this->_atlas->restrictPoint(patch, p)[0].index]);
3777:       };
3778:       // Update only the values associated to this point, not its closure
3779:       void updatePoint(const patch_type& patch, const point_type& p, const value_type v[]) {
3780:         this->checkPatch(patch);
3781:         const index_type& idx = this->_atlas->restrictPoint(patch, p)[0];
3782:         value_type       *a   = &(this->_arrays[patch][idx.index]);

3784:         for(int i = 0; i < idx.prefix; ++i) {
3785:           a[i] = v[i];
3786:         }
3787:       };
3788:       // Update only the values associated to this point, not its closure
3789:       void updateAddPoint(const patch_type& patch, const point_type& p, const value_type v[]) {
3790:         this->checkPatch(patch);
3791:         const index_type& idx = this->_atlas->restrictPoint(patch, p)[0];
3792:         value_type       *a   = &(this->_arrays[patch][idx.index]);

3794:         for(int i = 0; i < idx.prefix; ++i) {
3795:           a[i] += v[i];
3796:         }
3797:       };
3798:       void updatePointBC(const patch_type& patch, const point_type& p, const value_type v[]) {
3799:         this->checkPatch(patch);
3800:         const index_type& idx = this->_atlas->restrictPoint(patch, p)[0];
3801:         value_type       *a   = &(this->_arrays[patch][idx.index]);

3803:         for(int i = 0; i < std::abs(idx.prefix); ++i) {
3804:           a[i] = v[i];
3805:         }
3806:       };
3807:     public: // BC
3808:       void copyBC(const Obj<Section>& section) {
3809:         const typename topology_type::sheaf_type& patches = this->getTopology()->getPatches();

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

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

3817:             if (idx.prefix < 0) {
3818:               this->updatePointBC(patch_iter->first, *p_iter, section->restrictPoint(patch_iter->first, *p_iter));
3819:             }
3820:           }
3821:         }
3822:       };
3823:     public:
3824:       void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
3825:         ostringstream txt;
3826:         int rank;

3828:         if (comm == MPI_COMM_NULL) {
3829:           comm = this->comm();
3830:           rank = this->commRank();
3831:         } else {
3832:           MPI_Comm_rank(comm, &rank);
3833:         }
3834:         if (name == "") {
3835:           if(rank == 0) {
3836:             txt << "viewing a Section" << std::endl;
3837:           }
3838:         } else {
3839:           if(rank == 0) {
3840:             txt << "viewing Section '" << name << "'" << std::endl;
3841:           }
3842:         }
3843:         for(typename values_type::const_iterator a_iter = this->_arrays.begin(); a_iter != this->_arrays.end(); ++a_iter) {
3844:           const patch_type&  patch = a_iter->first;
3845:           const value_type  *array = a_iter->second;

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

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

3854:             if (idx.prefix != 0) {
3855:               txt << "[" << this->commRank() << "]:   " << point << " dim " << idx.prefix << " offset " << idx.index << "  ";
3856:               for(int i = 0; i < std::abs(idx.prefix); i++) {
3857:                 txt << " " << array[idx.index+i];
3858:               }
3859:               txt << std::endl;
3860:             }
3861:           }
3862:         }
3863:         if (this->_arrays.empty()) {
3864:           txt << "[" << this->commRank() << "]: empty" << std::endl;
3865:         }
3866:         PetscSynchronizedPrintf(comm, txt.str().c_str());
3867:         PetscSynchronizedFlush(comm);
3868:       };
3869:     };

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

3875:     template<typename Topology_, typename Value_>
3876:     class OldConstantSection : public ALE::ParallelObject {
3877:     public:
3878:       typedef OldConstantSection<Topology_, Value_> section_type;
3879:       typedef Topology_                          topology_type;
3880:       typedef typename topology_type::patch_type patch_type;
3881:       typedef typename topology_type::sieve_type sieve_type;
3882:       typedef typename topology_type::point_type point_type;
3883:       typedef Value_                             value_type;
3884:     protected:
3885:       Obj<topology_type> _topology;
3886:       const value_type   _value;
3887:       Obj<section_type>  _section;
3888:     public:
3889:       OldConstantSection(MPI_Comm comm, const value_type value, const int debug = 0) : ParallelObject(comm, debug), _value(value) {
3890:         this->_topology = new topology_type(comm, debug);
3891:         this->_section  = this;
3892:         this->_section.addRef();
3893:       };
3894:       OldConstantSection(const Obj<topology_type>& topology, const value_type value) : ParallelObject(topology->comm(), topology->debug()), _topology(topology), _value(value) {
3895:         this->_section  = this;
3896:         this->_section.addRef();
3897:       };
3898:       virtual ~OldConstantSection() {};
3899:     public: // Verifiers
3900:       bool hasPoint(const patch_type& patch, const point_type& point) const {return true;};
3901:     public: // Restriction
3902:       const value_type *restrict(const patch_type& patch) {return &this->_value;};
3903:       const value_type *restrictPoint(const patch_type& patch, const point_type& p) {return &this->_value;};
3904:     public: // Adapter
3905:       const Obj<section_type>& getSection(const patch_type& patch) {return this->_section;};
3906:       const value_type *restrictPoint(const point_type& p) {return &this->_value;};
3907:     public:
3908:       void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
3909:         ostringstream txt;
3910:         int rank;

3912:         if (comm == MPI_COMM_NULL) {
3913:           comm = this->comm();
3914:           rank = this->commRank();
3915:         } else {
3916:           MPI_Comm_rank(comm, &rank);
3917:         }
3918:         if (name == "") {
3919:           if(rank == 0) {
3920:             txt << "viewing a OldConstantSection with value " << this->_value << std::endl;
3921:           }
3922:         } else {
3923:           if(rank == 0) {
3924:             txt << "viewing OldConstantSection '" << name << "' with value " << this->_value << std::endl;
3925:           }
3926:         }
3927:         PetscSynchronizedPrintf(comm, txt.str().c_str());
3928:         PetscSynchronizedFlush(comm);
3929:       };
3930:     };

3932:     template<typename Overlap_, typename Topology_, typename Value_>
3933:     class OverlapValues : public Section<Topology_, Value_> {
3934:     public:
3935:       typedef Overlap_                          overlap_type;
3936:       typedef Section<Topology_, Value_>        base_type;
3937:       typedef typename base_type::topology_type topology_type;
3938:       typedef typename base_type::patch_type    patch_type;
3939:       typedef typename base_type::chart_type    chart_type;
3940:       typedef typename base_type::atlas_type    atlas_type;
3941:       typedef typename base_type::value_type    value_type;
3942:       typedef enum {SEND, RECEIVE}              request_type;
3943:       typedef std::map<patch_type, MPI_Request> requests_type;
3944:     protected:
3945:       int           _tag;
3946:       MPI_Datatype  _datatype;
3947:       requests_type _requests;
3948:     public:
3949:       OverlapValues(MPI_Comm comm, const int debug = 0) : Section<Topology_, Value_>(comm, debug) {
3950:         this->_tag      = this->getNewTag();
3951:         this->_datatype = this->getMPIDatatype();
3952:       };
3953:       OverlapValues(MPI_Comm comm, const int tag, const int debug) : Section<Topology_, Value_>(comm, debug), _tag(tag) {
3954:         this->_datatype = this->getMPIDatatype();
3955:       };
3956:       virtual ~OverlapValues() {};
3957:     protected:
3958:       MPI_Datatype getMPIDatatype() {
3959:         if (sizeof(value_type) == 4) {
3960:           return MPI_INT;
3961:         } else if (sizeof(value_type) == 8) {
3962:           return MPI_DOUBLE;
3963:         } else if (sizeof(value_type) == 28) {
3964:           int          blen[2];
3965:           MPI_Aint     indices[2];
3966:           MPI_Datatype oldtypes[2], newtype;
3967:           blen[0] = 1; indices[0] = 0;           oldtypes[0] = MPI_INT;
3968:           blen[1] = 3; indices[1] = sizeof(int); oldtypes[1] = MPI_DOUBLE;
3969:           MPI_Type_struct(2, blen, indices, oldtypes, &newtype);
3970:           MPI_Type_commit(&newtype);
3971:           return newtype;
3972:         } else if (sizeof(value_type) == 32) {
3973:           int          blen[2];
3974:           MPI_Aint     indices[2];
3975:           MPI_Datatype oldtypes[2], newtype;
3976:           blen[0] = 1; indices[0] = 0;           oldtypes[0] = MPI_DOUBLE;
3977:           blen[1] = 3; indices[1] = sizeof(int); oldtypes[1] = MPI_DOUBLE;
3978:           MPI_Type_struct(2, blen, indices, oldtypes, &newtype);
3979:           MPI_Type_commit(&newtype);
3980:           return newtype;
3981:         }
3982:         throw ALE::Exception("Cannot determine MPI type for value type");
3983:       };
3984:       int getNewTag() {
3985:         static int tagKeyval = MPI_KEYVAL_INVALID;
3986:         int *tagvalp = NULL, *maxval, flg;

3988:         if (tagKeyval == MPI_KEYVAL_INVALID) {
3989:           tagvalp = (int *) malloc(sizeof(int));
3990:           MPI_Keyval_create(MPI_NULL_COPY_FN, Mesh_DelTag, &tagKeyval, (void *) NULL);
3991:           MPI_Attr_put(this->_comm, tagKeyval, tagvalp);
3992:           tagvalp[0] = 0;
3993:         }
3994:         MPI_Attr_get(this->_comm, tagKeyval, (void **) &tagvalp, &flg);
3995:         if (tagvalp[0] < 1) {
3996:           MPI_Attr_get(MPI_COMM_WORLD, MPI_TAG_UB, (void **) &maxval, &flg);
3997:           tagvalp[0] = *maxval - 128; // hope that any still active tags were issued right at the beginning of the run
3998:         }
3999:         if (this->debug()) {
4000:           std::cout << "[" << this->commRank() << "]Got new tag " << tagvalp[0] << std::endl;
4001:         }
4002:         return tagvalp[0]--;
4003:       };
4004:     public: // Accessors
4005:       int getTag() const {return this->_tag;};
4006:       void setTag(const int tag) {this->_tag = tag;};
4007:     public:
4008:       void construct(const int size) {
4009:         const typename topology_type::sheaf_type& patches = this->getTopology()->getPatches();

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

4015:           for(typename topology_type::sieve_type::baseSequence::iterator b_iter = base->begin(); b_iter != base->end(); ++b_iter) {
4016:             this->setFiberDimension(rank, *b_iter, size);
4017:           }
4018:         }
4019:       };
4020:       template<typename Sizer>
4021:       void construct(const Obj<Sizer>& sizer) {
4022:         const typename topology_type::sheaf_type& patches = this->getTopology()->getPatches();

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

4028:           for(typename topology_type::sieve_type::baseSequence::iterator b_iter = base->begin(); b_iter != base->end(); ++b_iter) {
4029:             this->setFiberDimension(rank, *b_iter, *(sizer->restrictPoint(rank, *b_iter)));
4030:           }
4031:         }
4032:       };
4033:       void constructCommunication(const request_type& requestType) {
4034:         const typename topology_type::sheaf_type& patches = this->getAtlas()->getTopology()->getPatches();

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

4040:           if (requestType == RECEIVE) {
4041:             if (this->_debug) {std::cout <<"["<<this->commRank()<<"] Receiving data(" << this->size(patch) << ") from " << patch << " tag " << this->_tag << std::endl;}
4042:             MPI_Recv_init(this->_arrays[patch], this->size(patch), this->_datatype, patch, this->_tag, this->_comm, &request);
4043:           } else {
4044:             if (this->_debug) {std::cout <<"["<<this->commRank()<<"] Sending data (" << this->size(patch) << ") to " << patch << " tag " << this->_tag << std::endl;}
4045:             MPI_Send_init(this->_arrays[patch], this->size(patch), this->_datatype, patch, this->_tag, this->_comm, &request);
4046:           }
4047:           this->_requests[patch] = request;
4048:         }
4049:       };
4050:       void startCommunication() {
4051:         const typename topology_type::sheaf_type& patches = this->getAtlas()->getTopology()->getPatches();

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

4056:           MPI_Start(&request);
4057:         }
4058:       };
4059:       void endCommunication() {
4060:         const typename topology_type::sheaf_type& patches = this->getAtlas()->getTopology()->getPatches();
4061:         MPI_Status status;

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

4066:           MPI_Wait(&request, &status);
4067:         }
4068:       };
4069:     };
4070:   }
4071: }
4072: #endif