Actual source code: Field.hh
petsc-3.4.2 2013-07-02

      1: #ifndef included_ALE_Field_hh
      2: #define included_ALE_Field_hh

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

      8: extern "C" PetscMPIInt DMMesh_DelTag(MPI_Comm comm,PetscMPIInt keyval,void* attr_val,void* extra_state);

     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_ = malloc_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_ = malloc_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[2];
    166:   public:
    167:     ConstantSection(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {
    168:       _value[1] = 0;
    169:     };
    170:     ConstantSection(MPI_Comm comm, const value_type& value, const int debug) : ParallelObject(comm, debug) {
    171:       _value[0] = value;
    172:       _value[1] = value;
    173:     };
    174:     ConstantSection(MPI_Comm comm, const value_type& value, const value_type& defaultValue, const int debug) : ParallelObject(comm, debug) {
    175:       _value[0] = value;
    176:       _value[1] = defaultValue;
    177:     };
    178:   public: // Verifiers
    179:     void checkPoint(const point_type& point) const {
    180:       if (this->_chart.find(point) == this->_chart.end()) {
    181:         ostringstream msg;
    182:         msg << "Invalid section point " << point << std::endl;
    183:         throw ALE::Exception(msg.str().c_str());
    184:       }
    185:     };
    186:     void checkDimension(const int& dim) {
    187:       if (dim != 1) {
    188:         ostringstream msg;
    189:         msg << "Invalid fiber dimension " << dim << " must be 1" << std::endl;
    190:         throw ALE::Exception(msg.str().c_str());
    191:       }
    192:     };
    193:     bool hasPoint(const point_type& point) const {
    194:       return this->_chart.count(point) > 0;
    195:     };
    196:   public: // Accessors
    197:     const chart_type& getChart() {return this->_chart;};
    198:     void addPoint(const point_type& point) {
    199:       this->_chart.insert(point);
    200:     };
    201:     template<typename Points>
    202:     void addPoint(const Obj<Points>& points) {
    203:       this->_chart.insert(points->begin(), points->end());
    204:     }
    205:     template<typename Points>
    206:     void addPoint(const Points& points) {
    207:       this->_chart.insert(points.begin(), points.end());
    208:     }
    209: //     void addPoint(const std::set<point_type>& points) {
    210: //       this->_chart.insert(points.begin(), points.end());
    211: //     };
    212:     value_type getDefaultValue() {return this->_value[1];};
    213:     void setDefaultValue(const value_type value) {this->_value[1] = value;};
    214:     void copy(const Obj<ConstantSection>& section) {
    215:       const chart_type& chart = section->getChart();

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

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

    343:       if (size > maxSize) {
    344:         const value_type dummy(0);

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

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

    428:       for(typename chart_type::iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
    429:         size += this->getFiberDimension(*p_iter);
    430:       }
    431:       return size;
    432:     };
    433:     int sizeWithBC() const {
    434:       return this->size();
    435:     };
    436:     void allocatePoint() {};
    437:   public: // Restriction
    438:     const value_type *restrictSpace() {
    439:       const chart_type& chart = this->getChart();
    440:       const value_type  dummy = 0;
    441:       int               k     = 0;

    443:       if (chart.size() > this->_contiguous_array_size*fiberDim) {
    444:         if (this->_contiguous_array) {
    445:           for(size_t i = 0; i < this->_contiguous_array_size; ++i) {this->_allocator.destroy(this->_contiguous_array+i);}
    446:           this->_allocator.deallocate(this->_contiguous_array, this->_contiguous_array_size);
    447:         }
    448:         this->_contiguous_array_size = chart.size()*fiberDim;
    449:         this->_contiguous_array = this->_allocator.allocate(this->_contiguous_array_size*fiberDim);
    450:         for(size_t i = 0; i < this->_contiguous_array_size; ++i) {this->_allocator.construct(this->_contiguous_array+i, dummy);}
    451:       }
    452:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
    453:         const value_type *a = this->_array[*p_iter].v;

    455:         for(int i = 0; i < fiberDim; ++i, ++k) {
    456:           this->_contiguous_array[k] = a[i];
    457:         }
    458:       }
    459:       return this->_contiguous_array;
    460:     };
    461:     void update() {
    462:       if (this->_contiguous_array) {
    463:         const chart_type& chart = this->getChart();
    464:         int               k     = 0;

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

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

    507:       this->update();
    508:       if (comm == MPI_COMM_NULL) {
    509:         comm = this->comm();
    510:         rank = this->commRank();
    511:       } else {
    512:         MPI_Comm_rank(comm, &rank);
    513:       }
    514:       if (name == "") {
    515:         if(rank == 0) {
    516:           txt << "viewing a UniformSection" << std::endl;
    517:         }
    518:       } else {
    519:         if(rank == 0) {
    520:           txt << "viewing UniformSection '" << name << "'" << std::endl;
    521:         }
    522:       }
    523:       const typename atlas_type::chart_type& chart = this->_atlas->getChart();
    524:       values_type&                           array = this->_array;

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

    530:         if (dim != 0) {
    531:           txt << "[" << this->commRank() << "]:   " << point << " dim " << dim << "  ";
    532:           for(int i = 0; i < dim; i++) {
    533:             txt << " " << array[point].v[i];
    534:           }
    535:           txt << std::endl;
    536:         }
    537:       }
    538:       if (chart.size() == 0) {
    539:         txt << "[" << this->commRank() << "]: empty" << std::endl;
    540:       }
    541:       PetscSynchronizedPrintf(comm, txt.str().c_str());
    542:       PetscSynchronizedFlush(comm);
    543:     };
    544:   };

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

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

    730:       if (size > maxSize) {
    731:         const value_type dummy(0);

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

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

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

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

    845:         for(int i = 0; i < fiberDim; ++i, ++k) {
    846:           this->_contiguous_array[k] = a[i];
    847:         }
    848:       }
    849:       return this->_contiguous_array;
    850:     };
    851:     void update() {
    852:       if (this->_contiguous_array) {
    853:         const chart_type& chart = this->getChart();
    854:         int               k     = 0;

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

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

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

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

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

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

    979:       if (size > maxSize) {
    980:         const value_type dummy(0);

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

    1026:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
    1027:         if (this->getConstraintDimension(*p_iter)) {
    1028:           this->updatePointBC(*p_iter, section->restrictPoint(*p_iter));
    1029:         }
    1030:       }
    1031:     };
    1032:     void defaultConstraintDof() {};
    1033:   public: // Sizes
    1034:     void clear() {
    1035:       const int totalSize = this->sizeWithBC();

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

    1081:       for(typename chart_type::const_iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
    1082:         size += this->getConstrainedFiberDimension(*p_iter);
    1083:       }
    1084:       return size;
    1085:     };
    1086:     // Return the total number of dofs (free and constrained)
    1087:     int sizeWithBC() const {
    1088:       const chart_type& points = this->getChart();
    1089:       int size = 0;

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

    1118:       if (!cDim) {
    1119:         if (orientation >= 0) {
    1120:           for(int i = start; i < end; ++i) {
    1121:             indices[(*indx)++] = i;
    1122:           }
    1123:         } else {
    1124:           for(int i = end-1; i >= start; --i) {
    1125:             indices[(*indx)++] = i;
    1126:           }
    1127:         }
    1128:       } else {
    1129:         if (!freeOnly) {
    1130:           for(int i = start; i < end; ++i) {
    1131:             indices[(*indx)++] = -1;
    1132:           }
    1133:         }
    1134:       }
    1135:     };
    1136:   public: // Allocation
    1137:     void allocateStorage() {
    1138:       const int totalSize = this->sizeWithBC();
    1139:       const value_type dummy(0);

    1141:       this->_array = this->_allocator.allocate(totalSize);
    1142:       ///this->_array = new value_type[totalSize];
    1143:       for(int i = 0; i < totalSize; ++i) {this->_allocator.construct(this->_array+i, dummy);}
    1144:       ///PetscMemzero(this->_array, totalSize * sizeof(value_type));
    1145:     };
    1146:     void replaceStorage(value_type *newArray) {
    1147:       const int totalSize = this->sizeWithBC();

    1149:       for(int i = 0; i < totalSize; ++i) {this->_allocator.destroy(this->_array+i);}
    1150:       this->_allocator.deallocate(this->_array, totalSize);
    1151:       ///delete [] this->_array;
    1152:       this->_array    = newArray;
    1153:       this->_atlasNew = NULL;
    1154:     };
    1155:     void addPoint(const point_type& point, const int dim) {
    1156:       if (dim == 0) return;
    1157:       if (this->_atlasNew.isNull()) {
    1158:         this->_atlasNew = new atlas_type(this->comm(), this->debug());
    1159:         this->_atlasNew->copy(this->_atlas);
    1160:       }
    1161:       const index_type idx(dim, -1);
    1162:       this->_atlasNew->addPoint(point);
    1163:       this->_atlasNew->updatePoint(point, &idx);
    1164:     };
    1165:     template<typename Sequence>
    1166:     void addPoints(const Obj<Sequence>& points, const int dim) {
    1167:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
    1168:         this->addPoint(*p_iter, dim);
    1169:       }
    1170:     }
    1171:     void orderPoints(const Obj<atlas_type>& atlas){
    1172:       const chart_type& chart    = this->getChart();
    1173:       int               offset   = 0;
    1174:       int               bcOffset = this->size();

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

    1180:         if (dim >= 0) {
    1181:           idx.index = offset;
    1182:           atlas->updatePoint(*c_iter, &idx);
    1183:           offset += dim;
    1184:         } else {
    1185:           idx.index = bcOffset;
    1186:           atlas->updatePoint(*c_iter, &idx);
    1187:           bcOffset -= dim;
    1188:         }
    1189:       }
    1190:     };
    1191:     void allocatePoint() {
    1192:       this->orderPoints(this->_atlas);
    1193:       this->allocateStorage();
    1194:     };
    1195:   public: // Restriction and Update
    1196:     // Zero entries
    1197:     void zero() {
    1198:       memset(this->_array, 0, this->size()* sizeof(value_type));
    1199:     };
    1200:     // Return a pointer to the entire contiguous storage array
    1201:     const value_type *restrictSpace() {
    1202:       return this->_array;
    1203:     };
    1204:     // Update the entire contiguous storage array
    1205:     void update(const value_type v[]) {
    1206:       const value_type *array = this->_array;
    1207:       const int         size  = this->size();

    1209:       for(int i = 0; i < size; i++) {
    1210:         array[i] = v[i];
    1211:       }
    1212:     };
    1213:     // Return the free values on a point
    1214:     const value_type *restrictPoint(const point_type& p) {
    1215:       return &(this->_array[this->_atlas->restrictPoint(p)[0].index]);
    1216:     };
    1217:     // Update the free values on a point
    1218:     void updatePoint(const point_type& p, const value_type v[], const int orientation = 1) {
    1219:       const index_type& idx = this->_atlas->restrictPoint(p)[0];
    1220:       value_type       *a   = &(this->_array[idx.index]);

    1222:       if (orientation >= 0) {
    1223:         for(int i = 0; i < idx.prefix; ++i) {
    1224:           a[i] = v[i];
    1225:         }
    1226:       } else {
    1227:         const int last = idx.prefix-1;

    1229:         for(int i = 0; i < idx.prefix; ++i) {
    1230:           a[i] = v[last-i];
    1231:         }
    1232:       }
    1233:     };
    1234:     // Update the free values on a point
    1235:     void updateAddPoint(const point_type& p, const value_type v[], const int orientation = 1) {
    1236:       const index_type& idx = this->_atlas->restrictPoint(p)[0];
    1237:       value_type       *a   = &(this->_array[idx.index]);

    1239:       if (orientation >= 0) {
    1240:         for(int i = 0; i < idx.prefix; ++i) {
    1241:           a[i] += v[i];
    1242:         }
    1243:       } else {
    1244:         const int last = idx.prefix-1;

    1246:         for(int i = 0; i < idx.prefix; ++i) {
    1247:           a[i] += v[last-i];
    1248:         }
    1249:       }
    1250:     };
    1251:     // Update only the constrained dofs on a point
    1252:     void updatePointBC(const point_type& p, const value_type v[], const int orientation = 1) {
    1253:       const index_type& idx = this->_atlas->restrictPoint(p)[0];
    1254:       const int         dim = -idx.prefix;
    1255:       value_type       *a   = &(this->_array[idx.index]);

    1257:       if (orientation >= 0) {
    1258:         for(int i = 0; i < dim; ++i) {
    1259:           a[i] = v[i];
    1260:         }
    1261:       } else {
    1262:         const int last = dim-1;

    1264:         for(int i = 0; i < dim; ++i) {
    1265:           a[i] = v[last-i];
    1266:         }
    1267:       }
    1268:     };
    1269:     // Update all dofs on a point (free and constrained)
    1270:     void updatePointAll(const point_type& p, const value_type v[], const int orientation = 1) {
    1271:       const index_type& idx = this->_atlas->restrictPoint(p)[0];
    1272:       const int         dim = std::abs(idx.prefix);
    1273:       value_type       *a   = &(this->_array[idx.index]);

    1275:       if (orientation >= 0) {
    1276:         for(int i = 0; i < dim; ++i) {
    1277:           a[i] = v[i];
    1278:         }
    1279:       } else {
    1280:         const int last = dim-1;

    1282:         for(int i = 0; i < dim; ++i) {
    1283:           a[i] = v[last-i];
    1284:         }
    1285:       }
    1286:     };
    1287:   public:
    1288:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
    1289:       ostringstream txt;
    1290:       int rank;

    1292:       if (comm == MPI_COMM_NULL) {
    1293:         comm = this->comm();
    1294:         rank = this->commRank();
    1295:       } else {
    1296:         MPI_Comm_rank(comm, &rank);
    1297:       }
    1298:       if(rank == 0) {
    1299:         txt << "viewing Section " << this->getName() << std::endl;
    1300:         if (name != "") {
    1301:           txt << ": " << name << "'";
    1302:         }
    1303:         txt << std::endl;
    1304:       }
    1305:       const typename atlas_type::chart_type& chart = this->_atlas->getChart();
    1306:       const value_type                      *array = this->_array;

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

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

    1412:         for(int i = 0; i < totalSize; ++i) {this->_allocator.destroy(this->_array+i);}
    1413:         this->_allocator.deallocate(this->_array, totalSize);
    1414:         ///delete [] this->_array;
    1415:         this->_array = NULL;
    1416:       }
    1417:       for(std::vector<customAtlas_type>::iterator a_iter = this->_customRestrictAtlas.begin(); a_iter != this->_customRestrictAtlas.end(); ++a_iter) {
    1418:         if (a_iter->second) {
    1419:           delete [] a_iter->first.first;
    1420:           delete [] a_iter->first.second;
    1421:         }
    1422:       }
    1423:       for(std::vector<customAtlas_type>::iterator a_iter = this->_customUpdateAtlas.begin(); a_iter != this->_customUpdateAtlas.end(); ++a_iter) {
    1424:         if (a_iter->second) {
    1425:           delete [] a_iter->first.first;
    1426:           delete [] a_iter->first.second;
    1427:         }
    1428:       }
    1429:     };
    1430:   public:
    1431:     value_type *getRawArray(const int size) {
    1432:       // Put in a sentinel value that deallocates the array
    1433:       static value_type *array   = NULL;
    1434:       static int         maxSize = 0;

    1436:       if (size > maxSize) {
    1437:         const value_type dummy(0);

    1439:         if (array) {
    1440:           for(int i = 0; i < maxSize; ++i) {this->_allocator.destroy(array+i);}
    1441:           this->_allocator.deallocate(array, maxSize);
    1442:           ///delete [] array;
    1443:         }
    1444:         maxSize = size;
    1445:         array   = this->_allocator.allocate(maxSize);
    1446:         for(int i = 0; i < maxSize; ++i) {this->_allocator.construct(array+i, dummy);}
    1447:         ///array = new value_type[maxSize];
    1448:       };
    1449:       return array;
    1450:     };
    1451:     int getStorageSize() const {
    1452:       if (this->_sharedStorage) {
    1453:         return this->_sharedStorageSize;
    1454:       }
    1455:       return this->sizeWithBC();
    1456:     };
    1457:     bool sharedStorage() const {return this->_sharedStorage;};
    1458:   public: // Verifiers
    1459:     bool hasPoint(const point_type& point) {
    1460:       return this->_atlas->hasPoint(point);
    1461:     };
    1462:   public: // Accessors
    1463:     const Obj<atlas_type>& getAtlas() const {return this->_atlas;};
    1464:     void setAtlas(const Obj<atlas_type>& atlas) {this->_atlas = atlas;};
    1465:     const Obj<atlas_type>& getNewAtlas() const {return this->_atlasNew;};
    1466:     void setNewAtlas(const Obj<atlas_type>& atlas) {this->_atlasNew = atlas;};
    1467:     const Obj<bc_type>& getBC() const {return this->_bc;};
    1468:     void setBC(const Obj<bc_type>& bc) {this->_bc = bc;};
    1469:     const chart_type& getChart() const {return this->_atlas->getChart();};
    1470:     void setChart(const chart_type& chart) {throw ALE::Exception("setChart() for GeneralSection is invalid");};
    1471:   public: // BC
    1472:     // Returns the number of constraints on a point
    1473:     int getConstraintDimension(const point_type& p) const {
    1474:       if (!this->_bc->hasPoint(p)) return 0;
    1475:       return this->_bc->getFiberDimension(p);
    1476:     }
    1477:     // Set the number of constraints on a point
    1478:     void setConstraintDimension(const point_type& p, const int numConstraints) {
    1479:       this->_bc->setFiberDimension(p, numConstraints);
    1480:     }
    1481:     // Increment the number of constraints on a point
    1482:     void addConstraintDimension(const point_type& p, const int numConstraints) {
    1483:       this->_bc->addFiberDimension(p, numConstraints);
    1484:     }
    1485:     // Return the local dofs which are constrained on a point
    1486:     const int *getConstraintDof(const point_type& p) const {
    1487:       return this->_bc->restrictPoint(p);
    1488:     }
    1489:     // Set the local dofs which are constrained on a point
    1490:     void setConstraintDof(const point_type& p, const int dofs[]) {
    1491:       this->_bc->updatePoint(p, dofs);
    1492:     }
    1493:     template<typename OtherSection>
    1494:     void copyBC(const Obj<OtherSection>& section) {
    1495:       this->setBC(section->getBC());
    1496:       const chart_type& chart = this->getChart();

    1498:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
    1499:         if (this->getConstraintDimension(*p_iter)) {
    1500:           this->updatePointBCFull(*p_iter, section->restrictPoint(*p_iter));
    1501:         }
    1502:       }
    1503:       this->copySpaces(section);
    1504:     }
    1505:     void defaultConstraintDof() {
    1506:       const chart_type& chart = this->getChart();
    1507:       int size = 0;

    1509:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
    1510:         size = std::max(size, this->getConstraintDimension(*p_iter));
    1511:       }
    1512:       int *dofs = new int[size];
    1513:       for(typename chart_type::const_iterator p_iter = chart.begin(); p_iter != chart.end(); ++p_iter) {
    1514:         const int cDim = this->getConstraintDimension(*p_iter);

    1516:         if (cDim) {
    1517:           for(int d = 0; d < cDim; ++d) {
    1518:             dofs[d] = d;
    1519:           }
    1520:           this->_bc->updatePoint(*p_iter, dofs);
    1521:         }
    1522:       }
    1523:       delete [] dofs;
    1524:     };
    1525:   public: // Sizes
    1526:     void clear() {
    1527:       if (!this->_sharedStorage) {
    1528:         const int totalSize = this->sizeWithBC();

    1530:         for(int i = 0; i < totalSize; ++i) {this->_allocator.destroy(this->_array+i);}
    1531:         this->_allocator.deallocate(this->_array, totalSize);
    1532:         ///delete [] this->_array;
    1533:       }
    1534:       this->_array = NULL;
    1535:       this->_atlas->clear();
    1536:       this->_bc->clear();
    1537:     };
    1538:     // Return the total number of dofs on the point (free and constrained)
    1539:     int getFiberDimension(const point_type& p) const {
    1540:       return this->_atlas->restrictPoint(p)->prefix;
    1541:     };
    1542:     int getFiberDimension(const Obj<atlas_type>& atlas, const point_type& p) const {
    1543:       return atlas->restrictPoint(p)->prefix;
    1544:     };
    1545:     // Set the total number of dofs on the point (free and constrained)
    1546:     void setFiberDimension(const point_type& p, int dim) {
    1547:       const index_type idx(dim, -1);
    1548:       this->_atlas->addPoint(p);
    1549:       this->_atlas->updatePoint(p, &idx);
    1550:     };
    1551:     template<typename Sequence>
    1552:     void setFiberDimension(const Obj<Sequence>& points, int dim) {
    1553:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
    1554:         this->setFiberDimension(*p_iter, dim);
    1555:       }
    1556:     }
    1557:     void addFiberDimension(const point_type& p, int dim) {
    1558:       if (this->_atlas->hasPoint(p)) {
    1559:         const index_type values(dim, 0);
    1560:         this->_atlas->updateAddPoint(p, &values);
    1561:       } else {
    1562:         this->setFiberDimension(p, dim);
    1563:       }
    1564:     };
    1565:     // Return the number of constrained dofs on this point
    1566:     int getConstrainedFiberDimension(const point_type& p) const {
    1567:       return this->getFiberDimension(p) - this->getConstraintDimension(p);
    1568:     };
    1569:     // Return the total number of free dofs
    1570:     int size() const {
    1571:       const chart_type& points = this->getChart();
    1572:       int               size   = 0;

    1574:       for(typename chart_type::const_iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
    1575:         size += this->getConstrainedFiberDimension(*p_iter);
    1576:       }
    1577:       return size;
    1578:     };
    1579:     // Return the total number of dofs (free and constrained)
    1580:     int sizeWithBC() const {
    1581:       const chart_type& points = this->getChart();
    1582:       int               size   = 0;

    1584:       for(typename chart_type::const_iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
    1585:         size += this->getFiberDimension(*p_iter);
    1586:       }
    1587:       return size;
    1588:     };
    1589:   public: // Index retrieval
    1590:     const typename index_type::index_type& getIndex(const point_type& p) {
    1591:       return this->_atlas->restrictPoint(p)->index;
    1592:     };
    1593:     void setIndex(const point_type& p, const typename index_type::index_type& index) {
    1594:       ((typename atlas_type::value_type *) this->_atlas->restrictPoint(p))->index = index;
    1595:     };
    1596:     void setIndexBC(const point_type& p, const typename index_type::index_type& index) {};
    1597:     void getIndicesRaw(const point_type& p, PetscInt indices[], PetscInt *indx, const int orientation = 1) {
    1598:       this->getIndicesRaw(p, this->getIndex(p), indices, indx, orientation);
    1599:     };
    1600:     template<typename Order_>
    1601:     void getIndicesRaw(const point_type& p, const Obj<Order_>& order, PetscInt indices[], PetscInt *indx, const int orientation = 1) {
    1602:       this->getIndicesRaw(p, order->getIndex(p), indices, indx, orientation);
    1603:     }
    1604:     void getIndices(const point_type& p, PetscInt indices[], PetscInt *indx, const int orientation = 1, const bool freeOnly = false, const bool skipConstraints = true) {
    1605:       this->getIndices(p, this->getIndex(p), indices, indx, orientation, freeOnly, skipConstraints);
    1606:     };
    1607:     template<typename Order_>
    1608:     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) {
    1609:       this->getIndices(p, order->getIndex(p), indices, indx, orientation, freeOnly, skipConstraints);
    1610:     }
    1611:     void getIndicesRaw(const point_type& p, const int start, PetscInt indices[], PetscInt *indx, const int orientation) {
    1612:       if (orientation >= 0) {
    1613:         const int& dim = this->getFiberDimension(p);
    1614:         const int  end = start + dim;

    1616:         for(int i = start; i < end; ++i) {
    1617:           indices[(*indx)++] = i;
    1618:         }
    1619:       } else {
    1620:         const int numSpaces = this->getNumSpaces();
    1621:         int offset = start;

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

    1626:           for(int i = offset+dim-1; i >= offset; --i) {
    1627:             indices[(*indx)++] = i;
    1628:           }
    1629:           offset += dim;
    1630:         }
    1631:         if (!numSpaces) {
    1632:           const int& dim = this->getFiberDimension(p);

    1634:           for(int i = offset+dim-1; i >= offset; --i) {
    1635:             indices[(*indx)++] = i;
    1636:           }
    1637:           offset += dim;
    1638:         }
    1639:       }
    1640:     }
    1641:     /*
    1642:       p           - The Sieve point
    1643:       start       - Offset for the set of indices on this point
    1644:       indices     - Storage for the indices
    1645:       indx        - Pointer to an offset into the indices argument (to allow composition of index sets)
    1646:       orientation - A negative argument reverses the indices
    1647:       freeOnly        - If false, include constrained dofs with negative indices, otherwise leave them out
    1648:       skipConstraints - If true, when a constrained dof is encountered, increment the index (even though it is not placed in indices[])
    1649:      */
    1650:     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) {
    1651:       const int& cDim = this->getConstraintDimension(p);

    1653:       if (!cDim) {
    1654:         this->getIndicesRaw(p, start, indices, indx, orientation);
    1655:       } else {
    1656:         if (orientation >= 0) {
    1657:           const int&                          dim  = this->getFiberDimension(p);
    1658:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
    1659:           int                                 cInd = 0;

    1661:           /* i is the returned index, k is the local dof number */
    1662:           for(int i = start, k = 0; k < dim; ++k) {
    1663:             if ((cInd < cDim) && (k == cDof[cInd])) {
    1664:               /* Constrained dof */
    1665:               if (!freeOnly) indices[(*indx)++] = -(k+1);
    1666:               if (skipConstraints) ++i;
    1667:               ++cInd;
    1668:             } else {
    1669:               /* Unconstrained dof */
    1670:               indices[(*indx)++] = i++;
    1671:             }
    1672:           }
    1673:         } else {
    1674:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
    1675:           int                                 offset  = 0;
    1676:           int                                 cOffset = 0;
    1677:           int                                 j       = -1;

    1679:           for(int space = 0; space < this->getNumSpaces(); ++space) {
    1680:             const int  dim = this->getFiberDimension(p, space);
    1681:             const int tDim = this->getConstrainedFiberDimension(p, space);
    1682:             int       cInd = (dim - tDim)-1;

    1684:             j += dim;
    1685:             for(int i = 0, k = start+tDim+offset; i < dim; ++i, --j) {
    1686:               if ((cInd >= 0) && (j == cDof[cInd+cOffset])) {
    1687:                 if (!freeOnly) indices[(*indx)++] = -(offset+i+1);
    1688:                 if (skipConstraints) --k;
    1689:                 --cInd;
    1690:               } else {
    1691:                 indices[(*indx)++] = --k;
    1692:               }
    1693:             }
    1694:             j       += dim;
    1695:             offset  += dim;
    1696:             cOffset += dim - tDim;
    1697:           }
    1698:         }
    1699:       }
    1700:     };
    1701:   public: // Allocation
    1702:     void allocateStorage() {
    1703:       const int totalSize = this->sizeWithBC();
    1704:       const value_type dummy(0) ;

    1706:       this->_array             = this->_allocator.allocate(totalSize);
    1707:       ///this->_array             = new value_type[totalSize];
    1708:       this->_sharedStorage     = false;
    1709:       this->_sharedStorageSize = 0;
    1710:       for(int i = 0; i < totalSize; ++i) {this->_allocator.construct(this->_array+i, dummy);}
    1711:       ///PetscMemzero(this->_array, totalSize * sizeof(value_type));
    1712:       this->_bc->allocatePoint();
    1713:       for(typename std::vector<Obj<bc_type> >::const_iterator b_iter = this->_bcs.begin(); b_iter != this->_bcs.end(); ++b_iter) {
    1714:         (*b_iter)->allocatePoint();;
    1715:       }
    1716:     };
    1717:     void replaceStorage(value_type *newArray, const bool sharedStorage = false, const int sharedStorageSize = 0) {
    1718:       if (this->_array && !this->_sharedStorage) {
    1719:         const int totalSize = this->sizeWithBC();

    1721:         for(int i = 0; i < totalSize; ++i) {this->_allocator.destroy(this->_array+i);}
    1722:         this->_allocator.deallocate(this->_array, totalSize);
    1723:         ///delete [] this->_array;
    1724:       }
    1725:       this->_array             = newArray;
    1726:       this->_sharedStorage     = sharedStorage;
    1727:       this->_sharedStorageSize = sharedStorageSize;
    1728:       this->_atlas             = this->_atlasNew;
    1729:       this->_atlasNew          = NULL;
    1730:     };
    1731:     // DANGEROUS
    1732:     void setStorage(value_type *newArray) {
    1733:       this->_array = newArray;
    1734:     };
    1735:     void addPoint(const point_type& point, const int dim) {
    1736:       if (dim == 0) return;
    1737:       if (this->_atlasNew.isNull()) {
    1738:         this->_atlasNew = new atlas_type(this->comm(), this->debug());
    1739:         this->_atlasNew->copy(this->_atlas);
    1740:       }
    1741:       const index_type idx(dim, -1);
    1742:       this->_atlasNew->addPoint(point);
    1743:       this->_atlasNew->updatePoint(point, &idx);
    1744:     };
    1745:     void orderPoints(const Obj<atlas_type>& atlas){
    1746:       const chart_type& chart  = this->getChart();
    1747:       int               offset = 0;

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

    1753:         idx.index = offset;
    1754:         atlas->updatePoint(*c_iter, &idx);
    1755:         offset += dim;
    1756:       }
    1757:     };
    1758:     void allocatePoint() {
    1759:       this->orderPoints(this->_atlas);
    1760:       this->allocateStorage();
    1761:     };
    1762:   public: // Restriction and Update
    1763:     // Zero entries
    1764:     void zero() {
    1765:       this->set((value_type) 0.0);
    1766:     };
    1767:     void zeroWithBC() {
    1768:       memset(this->_array, 0, this->sizeWithBC()* sizeof(value_type));
    1769:     };
    1770:     void set(const value_type value) {
    1771:       //memset(this->_array, 0, this->sizeWithBC()* sizeof(value_type));
    1772:       const chart_type& chart = this->getChart();

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

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

    1787:           for(int i = 0; i < dim; ++i) {
    1788:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
    1789:             array[i] = value;
    1790:           }
    1791:         }
    1792:       }
    1793:     };
    1794:     // Add two sections and put the result in a third
    1795:     void add(const Obj<GeneralSection>& x, const Obj<GeneralSection>& y) {
    1796:       // Check atlases
    1797:       const chart_type& chart = this->getChart();

    1799:       for(typename chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
    1800:         value_type       *array  = (value_type *) this->restrictPoint(*c_iter);
    1801:         const value_type *xArray = x->restrictPoint(*c_iter);
    1802:         const value_type *yArray = y->restrictPoint(*c_iter);
    1803:         const int&        dim    = this->getFiberDimension(*c_iter);
    1804:         const int&        cDim   = this->getConstraintDimension(*c_iter);

    1806:         if (!cDim) {
    1807:           for(int i = 0; i < dim; ++i) {
    1808:             array[i] = xArray[i] + yArray[i];
    1809:           }
    1810:         } else {
    1811:           const typename bc_type::value_type *cDof = this->getConstraintDof(*c_iter);
    1812:           int                                 cInd = 0;

    1814:           for(int i = 0; i < dim; ++i) {
    1815:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
    1816:             array[i] = xArray[i] + yArray[i];
    1817:           }
    1818:         }
    1819:       }
    1820:     };
    1821:     // this = this + alpha * x
    1822:     template<typename OtherSection>
    1823:     void axpy(const value_type alpha, const Obj<OtherSection>& x) {
    1824:       // Check atlases
    1825:       const chart_type& chart = this->getChart();

    1827:       for(typename chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
    1828:         value_type       *array  = (value_type *) this->restrictPoint(*c_iter);
    1829:         const value_type *xArray = x->restrictPoint(*c_iter);
    1830:         const int&        dim    = this->getFiberDimension(*c_iter);
    1831:         const int&        cDim   = this->getConstraintDimension(*c_iter);

    1833:         if (!cDim) {
    1834:           for(int i = 0; i < dim; ++i) {
    1835:             array[i] += alpha*xArray[i];
    1836:           }
    1837:         } else {
    1838:           const typename bc_type::value_type *cDof = this->getConstraintDof(*c_iter);
    1839:           int                                 cInd = 0;

    1841:           for(int i = 0; i < dim; ++i) {
    1842:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
    1843:             array[i] += alpha*xArray[i];
    1844:           }
    1845:         }
    1846:       }
    1847:     }
    1848:     // Return the free values on a point
    1849:     const value_type *restrictSpace() const {
    1850:       return this->_array;
    1851:     }
    1852:     // Return the free values on a point
    1853:     const value_type *restrictPoint(const point_type& p) const {
    1854:       return &(this->_array[this->_atlas->restrictPoint(p)[0].index]);
    1855:     }
    1856:     void restrictPoint(const point_type& p, value_type values[], const int size) const {
    1857:       assert(this->_atlas->restrictPoint(p)[0].prefix == size);
    1858:       const value_type *v = &(this->_array[this->_atlas->restrictPoint(p)[0].index]);

    1860:       for(int i = 0; i < size; ++i) {
    1861:         values[i] = v[i];
    1862:       }
    1863:     };
    1864:     // Update the free values on a point
    1865:     //   Takes a full array and ignores constrained values
    1866:     void updatePoint(const point_type& p, const value_type v[], const int orientation = 1) {
    1867:       value_type *array = (value_type *) this->restrictPoint(p);
    1868:       const int&  cDim  = this->getConstraintDimension(p);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    2028:             for(int i = 0, k = tDim+offset-1; i < dim; ++i, ++j) {
    2029:               if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
    2030:               array[j] = v[--k];
    2031:             }
    2032:             offset  += dim;
    2033:             cOffset += dim - tDim;
    2034:           }
    2035:         }
    2036:       }
    2037:     };
    2038:     // Update the free values on a point
    2039:     //   Takes ONLY unconstrained values
    2040:     void updateFreeAddPoint(const point_type& p, const value_type v[], const int orientation = 1) {
    2041:       value_type *array = (value_type *) this->restrictPoint(p);
    2042:       const int&  cDim  = this->getConstraintDimension(p);

    2044:       if (!cDim) {
    2045:         if (orientation >= 0) {
    2046:           const int& dim = this->getFiberDimension(p);

    2048:           for(int i = 0; i < dim; ++i) {
    2049:             array[i] += v[i];
    2050:           }
    2051:         } else {
    2052:           int offset = 0;
    2053:           int j      = -1;

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

    2058:             for(int i = dim-1; i >= 0; --i) {
    2059:               array[++j] += v[i+offset];
    2060:             }
    2061:             offset += dim;
    2062:           }
    2063:         }
    2064:       } else {
    2065:         if (orientation >= 0) {
    2066:           const int&                          dim  = this->getFiberDimension(p);
    2067:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
    2068:           int                                 cInd = 0;

    2070:           for(int i = 0, k = -1; i < dim; ++i) {
    2071:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
    2072:             array[i] += v[++k];
    2073:           }
    2074:         } else {
    2075:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
    2076:           int                                 offset  = 0;
    2077:           int                                 cOffset = 0;
    2078:           int                                 j       = 0;

    2080:           for(int space = 0; space < this->getNumSpaces(); ++space) {
    2081:             const int  dim = this->getFiberDimension(p, space);
    2082:             const int tDim = this->getConstrainedFiberDimension(p, space);
    2083:             const int sDim = dim - tDim;
    2084:             int       cInd = 0;

    2086:             for(int i = 0, k = tDim+offset-1; i < dim; ++i, ++j) {
    2087:               if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
    2088:               array[j] += v[--k];
    2089:             }
    2090:             offset  += dim;
    2091:             cOffset += dim - tDim;
    2092:           }
    2093:         }
    2094:       }
    2095:     };
    2096:     // Update only the constrained dofs on a point
    2097:     //   This takes an array with ONLY bc values
    2098:     void updatePointBC(const point_type& p, const value_type v[], const int orientation = 1) {
    2099:       value_type *array = (value_type *) this->restrictPoint(p);
    2100:       const int&  cDim  = this->getConstraintDimension(p);

    2102:       if (cDim) {
    2103:         if (orientation >= 0) {
    2104:           const int&                          dim  = this->getFiberDimension(p);
    2105:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
    2106:           int                                 cInd = 0;

    2108:           for(int i = 0; i < dim; ++i) {
    2109:             if (cInd == cDim) break;
    2110:             if (i == cDof[cInd]) {
    2111:               array[i] = v[cInd];
    2112:               ++cInd;
    2113:             }
    2114:           }
    2115:         } else {
    2116:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
    2117:           int                                 cOffset = 0;
    2118:           int                                 j       = 0;

    2120:           for(int space = 0; space < this->getNumSpaces(); ++space) {
    2121:             const int  dim = this->getFiberDimension(p, space);
    2122:             const int tDim = this->getConstrainedFiberDimension(p, space);
    2123:             int       cInd = 0;

    2125:             for(int i = 0; i < dim; ++i, ++j) {
    2126:               if (cInd < 0) break;
    2127:               if (j == cDof[cInd+cOffset]) {
    2128:                 array[j] = v[cInd+cOffset];
    2129:                 ++cInd;
    2130:               }
    2131:             }
    2132:             cOffset += dim - tDim;
    2133:           }
    2134:         }
    2135:       }
    2136:     };
    2137:     // Update only the constrained dofs on a point
    2138:     //   This takes an array with ALL values, not just BC
    2139:     void updatePointBCFull(const point_type& p, const value_type v[], const int orientation = 1) {
    2140:       value_type *array = (value_type *) this->restrictPoint(p);
    2141:       const int&  cDim  = this->getConstraintDimension(p);

    2143:       if (cDim) {
    2144:         if (orientation >= 0) {
    2145:           const int&                          dim  = this->getFiberDimension(p);
    2146:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
    2147:           int                                 cInd = 0;

    2149:           for(int i = 0; i < dim; ++i) {
    2150:             if (cInd == cDim) break;
    2151:             if (i == cDof[cInd]) {
    2152:               array[i] = v[i];
    2153:               ++cInd;
    2154:             }
    2155:           }
    2156:         } else {
    2157:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
    2158:           int                                 offset  = 0;
    2159:           int                                 cOffset = 0;
    2160:           int                                 j       = 0;

    2162:           for(int space = 0; space < this->getNumSpaces(); ++space) {
    2163:             const int  dim = this->getFiberDimension(p, space);
    2164:             const int tDim = this->getConstrainedFiberDimension(p, space);
    2165:             int       cInd = 0;

    2167:             for(int i = 0, k = dim+offset-1; i < dim; ++i, ++j, --k) {
    2168:               if (cInd < 0) break;
    2169:               if (j == cDof[cInd+cOffset]) {
    2170:                 array[j] = v[k];
    2171:                 ++cInd;
    2172:               }
    2173:             }
    2174:             offset  += dim;
    2175:             cOffset += dim - tDim;
    2176:           }
    2177:         }
    2178:       }
    2179:     };
    2180:     // Update all dofs on a point (free and constrained)
    2181:     void updatePointAll(const point_type& p, const value_type v[], const int orientation = 1) {
    2182:       value_type *array = (value_type *) this->restrictPoint(p);

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

    2187:         for(int i = 0; i < dim; ++i) {
    2188:           array[i] = v[i];
    2189:         }
    2190:       } else {
    2191:         int offset = 0;
    2192:         int j      = -1;

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

    2197:           for(int i = dim-1; i >= 0; --i) {
    2198:             array[++j] = v[i+offset];
    2199:           }
    2200:           offset += dim;
    2201:         }
    2202:       }
    2203:     };
    2204:     // Update all dofs on a point (free and constrained)
    2205:     void updatePointAllAdd(const point_type& p, const value_type v[], const int orientation = 1) {
    2206:       value_type *array = (value_type *) this->restrictPoint(p);

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

    2211:         for(int i = 0; i < dim; ++i) {
    2212:           array[i] += v[i];
    2213:         }
    2214:       } else {
    2215:         int offset = 0;
    2216:         int j      = -1;

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

    2221:           for(int i = dim-1; i >= 0; --i) {
    2222:             array[++j] += v[i+offset];
    2223:           }
    2224:           offset += dim;
    2225:         }
    2226:       }
    2227:     };
    2228:   public: // Fibrations
    2229:     int getNumSpaces() const {return this->_spaces.size();};
    2230:     const std::vector<Obj<atlas_type> >& getSpaces() {return this->_spaces;};
    2231:     const std::vector<Obj<bc_type> >& getBCs() {return this->_bcs;};
    2232:     void addSpace(int comp = 1) {
    2233:       Obj<atlas_type> space = new atlas_type(this->comm(), this->debug());
    2234:       Obj<bc_type>    bc    = new bc_type(this->comm(), this->debug());
    2235:       this->_comps.push_back(comp);
    2236:       this->_spaces.push_back(space);
    2237:       this->_bcs.push_back(bc);
    2238:     };
    2239:     int getSpaceComponents(const int space) {return this->_comps[space];};
    2240:     int getFiberDimension(const point_type& p, const int space) const {
    2241:       return this->_spaces[space]->restrictPoint(p)->prefix;
    2242:     };
    2243:     void setFiberDimension(const point_type& p, int dim, const int space) {
    2244:       const index_type idx(dim, -1);
    2245:       this->_spaces[space]->addPoint(p);
    2246:       this->_spaces[space]->updatePoint(p, &idx);
    2247:     };
    2248:     template<typename Sequence>
    2249:     void setFiberDimension(const Obj<Sequence>& points, int dim, const int space) {
    2250:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
    2251:         this->setFiberDimension(*p_iter, dim, space);
    2252:       }
    2253:     }
    2254:     int getConstraintDimension(const point_type& p, const int space) const {
    2255:       if (!this->_bcs[space]->hasPoint(p)) return 0;
    2256:       return this->_bcs[space]->getFiberDimension(p);
    2257:     }
    2258:     void setConstraintDimension(const point_type& p, const int numConstraints, const int space) {
    2259:       this->_bcs[space]->setFiberDimension(p, numConstraints);
    2260:     }
    2261:     void addConstraintDimension(const point_type& p, const int numConstraints, const int space) {
    2262:       this->_bcs[space]->addFiberDimension(p, numConstraints);
    2263:     }
    2264:     int getConstrainedFiberDimension(const point_type& p, const int space) const {
    2265:       return this->getFiberDimension(p, space) - this->getConstraintDimension(p, space);
    2266:     }
    2267:     // Return the local dofs which are constrained on a point
    2268:     const int *getConstraintDof(const point_type& p, const int space) const {
    2269:       return this->_bcs[space]->restrictPoint(p);
    2270:     }
    2271:     // Set the local dofs which are constrained on a point
    2272:     void setConstraintDof(const point_type& p, const int dofs[], const int space) {
    2273:       this->_bcs[space]->updatePoint(p, dofs);
    2274:     }
    2275:     // Return the total number of free dofs
    2276:     int size(const int space) const {
    2277:       const chart_type& points = this->getChart();
    2278:       int               size   = 0;

    2280:       for(typename chart_type::const_iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
    2281:         size += this->getConstrainedFiberDimension(*p_iter, space);
    2282:       }
    2283:       return size;
    2284:     };
    2285:     template<typename OtherSection>
    2286:     void copySpaces(const Obj<OtherSection>& section) {
    2287:       const std::vector<Obj<atlas_type> >& spaces = section->getSpaces();
    2288:       const std::vector<Obj<bc_type> >&    bcs    = section->getBCs();

    2290:       this->_spaces.clear();
    2291:       for(typename std::vector<Obj<atlas_type> >::const_iterator s_iter = spaces.begin(); s_iter != spaces.end(); ++s_iter) {
    2292:         this->_spaces.push_back(*s_iter);
    2293:       }
    2294:       this->_bcs.clear();
    2295:       for(typename std::vector<Obj<bc_type> >::const_iterator b_iter = bcs.begin(); b_iter != bcs.end(); ++b_iter) {
    2296:         this->_bcs.push_back(*b_iter);
    2297:       }
    2298:     }
    2299:     Obj<GeneralSection> getFibration(const int space) const {
    2300:       Obj<GeneralSection> field = new GeneralSection(this->comm(), this->debug());
    2301: //     Obj<atlas_type> _atlas;
    2302: //     std::vector<Obj<atlas_type> > _spaces;
    2303: //     Obj<bc_type>    _bc;
    2304: //     std::vector<Obj<bc_type> >    _bcs;
    2305:       field->addSpace();
    2306:       const chart_type& chart = this->getChart();

    2308:       // Copy sizes
    2309:       for(typename chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
    2310:         const int fDim = this->getFiberDimension(*c_iter, space);
    2311:         const int cDim = this->getConstraintDimension(*c_iter, space);

    2313:         if (fDim) {
    2314:           field->setFiberDimension(*c_iter, fDim);
    2315:           field->setFiberDimension(*c_iter, fDim, 0);
    2316:         }
    2317:         if (cDim) {
    2318:           field->setConstraintDimension(*c_iter, cDim);
    2319:           field->setConstraintDimension(*c_iter, cDim, 0);
    2320:         }
    2321:       }
    2322:       field->allocateStorage();
    2323:       Obj<atlas_type>   newAtlas = new atlas_type(this->comm(), this->debug());
    2324:       const chart_type& newChart = field->getChart();

    2326:       for(typename chart_type::const_iterator c_iter = newChart.begin(); c_iter != newChart.end(); ++c_iter) {
    2327:         const int cDim   = field->getConstraintDimension(*c_iter);
    2328:         //const int dof[1] = {0};

    2330:         if (cDim) {
    2331:           field->setConstraintDof(*c_iter, this->getConstraintDof(*c_iter, space));
    2332:         }
    2333:       }
    2334:       // Copy offsets
    2335:       for(typename chart_type::const_iterator c_iter = newChart.begin(); c_iter != newChart.end(); ++c_iter) {
    2336:         index_type idx;

    2338:         idx.prefix = field->getFiberDimension(*c_iter);
    2339:         idx.index  = this->_atlas->restrictPoint(*c_iter)[0].index;
    2340:         for(int s = 0; s < space; ++s) {
    2341:           idx.index += this->getFiberDimension(*c_iter, s);
    2342:         }
    2343:         newAtlas->addPoint(*c_iter);
    2344:         newAtlas->updatePoint(*c_iter, &idx);
    2345:       }
    2346:       field->replaceStorage(this->_array, true, this->getStorageSize());
    2347:       field->setAtlas(newAtlas);
    2348:       return field;
    2349:     };
    2350:   public: // Optimization
    2351:     void getCustomRestrictAtlas(const int tag, const int *offsets[], const int *indices[]) {
    2352:       *offsets = this->_customRestrictAtlas[tag].first.first;
    2353:       *indices = this->_customRestrictAtlas[tag].first.second;
    2354:     };
    2355:     void getCustomUpdateAtlas(const int tag, const int *offsets[], const int *indices[]) {
    2356:       *offsets = this->_customUpdateAtlas[tag].first.first;
    2357:       *indices = this->_customUpdateAtlas[tag].first.second;
    2358:     };
    2359:     // This returns the tag assigned to the atlas
    2360:     int setCustomAtlas(const int restrictOffsets[], const int restrictIndices[], const int updateOffsets[], const int updateIndices[], bool autoFree = true) {
    2361:       this->_customRestrictAtlas.push_back(customAtlas_type(customAtlasInd_type(restrictOffsets, restrictIndices), autoFree));
    2362:       this->_customUpdateAtlas.push_back(customAtlas_type(customAtlasInd_type(updateOffsets, updateIndices), autoFree));
    2363:       return this->_customUpdateAtlas.size()-1;
    2364:     };
    2365:     int copyCustomAtlas(const Obj<GeneralSection>& section, const int tag) {
    2366:       const int *rOffsets, *rIndices, *uOffsets, *uIndices;

    2368:       section->getCustomRestrictAtlas(tag, &rOffsets, &rIndices);
    2369:       section->getCustomUpdateAtlas(tag, &uOffsets, &uIndices);
    2370:       return this->setCustomAtlas(rOffsets, rIndices, uOffsets, uIndices, false);
    2371:     };
    2372:   public:
    2373:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
    2374:       ostringstream txt;
    2375:       int rank;

    2377:       if (comm == MPI_COMM_NULL) {
    2378:         comm = this->comm();
    2379:         rank = this->commRank();
    2380:       } else {
    2381:         MPI_Comm_rank(comm, &rank);
    2382:       }
    2383:       if (name == "") {
    2384:         if(rank == 0) {
    2385:           txt << "viewing a GeneralSection" << std::endl;
    2386:         }
    2387:       } else {
    2388:         if (rank == 0) {
    2389:           txt << "viewing GeneralSection '" << name << "'" << std::endl;
    2390:         }
    2391:       }
    2392:       if (rank == 0) {
    2393:         txt << "  Fields: " << this->getNumSpaces() << std::endl;
    2394:       }
    2395:       const chart_type& chart = this->getChart();

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

    2401:         if (dim != 0) {
    2402:           txt << "[" << this->commRank() << "]:   " << *p_iter << " dim " << dim << " offset " << this->_atlas->restrictPoint(*p_iter)->index << "  ";
    2403:           for(int i = 0; i < dim; i++) {
    2404:             txt << " " << array[i];
    2405:           }
    2406:           const int& dim = this->getConstraintDimension(*p_iter);

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

    2411:             txt << " constrained";
    2412:             for(int i = 0; i < dim; ++i) {
    2413:               txt << " " << bcArray[i];
    2414:             }
    2415:           }
    2416:           txt << std::endl;
    2417:         }
    2418:       }
    2419:       if (chart.size() == 0) {
    2420:         txt << "[" << this->commRank() << "]: empty" << std::endl;
    2421:       }
    2422:       PetscSynchronizedPrintf(comm, txt.str().c_str());
    2423:       PetscSynchronizedFlush(comm);
    2424:     };
    2425:   };
    2426:   // FEMSection will support vector BC on a subset of unknowns on a point
    2427:   //   We make a separate constraint Section to hold the transformation and projection operators
    2428:   //   Storage will be contiguous by node, just as in Section
    2429:   //     This allows fast restrict(p)
    2430:   //     Then update() is accomplished by projecting constrained unknowns
    2431:   template<typename Point_, typename Value_, typename Alloc_ = malloc_allocator<Value_>,
    2432:            typename Atlas_ = UniformSection<Point_, Point, 1, typename Alloc_::template rebind<Point>::other>,
    2433:            typename BCAtlas_ = UniformSection<Point_, int, 1, typename Alloc_::template rebind<int>::other>,
    2434:            typename BC_ = Section<Point_, double, typename Alloc_::template rebind<double>::other> >
    2435:   class FEMSection : public ALE::ParallelObject {
    2436:   public:
    2437:     typedef Point_                                                  point_type;
    2438:     typedef Value_                                                  value_type;
    2439:     typedef Alloc_                                                  alloc_type;
    2440:     typedef Atlas_                                                  atlas_type;
    2441:     typedef BCAtlas_                                                bc_atlas_type;
    2442:     typedef BC_                                                     bc_type;
    2443:     typedef Point                                                   index_type;
    2444:     typedef typename atlas_type::chart_type                         chart_type;
    2445:     typedef value_type *                                            values_type;
    2446:     typedef typename alloc_type::template rebind<atlas_type>::other atlas_alloc_type;
    2447:     typedef typename atlas_alloc_type::pointer                      atlas_ptr;
    2448:     typedef typename alloc_type::template rebind<bc_type>::other    bc_atlas_alloc_type;
    2449:     typedef typename bc_atlas_alloc_type::pointer                   bc_atlas_ptr;
    2450:     typedef typename alloc_type::template rebind<bc_type>::other    bc_alloc_type;
    2451:     typedef typename bc_alloc_type::pointer                         bc_ptr;
    2452:   protected:
    2453:     Obj<atlas_type>    _atlas;
    2454:     Obj<bc_atlas_type> _bc_atlas;
    2455:     Obj<bc_type>       _bc;
    2456:     values_type        _array;
    2457:     bool               _sharedStorage;
    2458:     int                _sharedStorageSize;
    2459:     alloc_type         _allocator;
    2460:     std::vector<Obj<atlas_type> > _spaces;
    2461:     std::vector<Obj<bc_type> >    _bcs;
    2462:   public:
    2463:     FEMSection(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {
    2464:       atlas_ptr pAtlas      = atlas_alloc_type(this->_allocator).allocate(1);
    2465:       atlas_alloc_type(this->_allocator).construct(pAtlas, atlas_type(comm, debug));
    2466:       this->_atlas          = Obj<atlas_type>(pAtlas, sizeof(atlas_type));
    2467:       bc_atlas_ptr pBCAtlas = bc_atlas_alloc_type(this->_allocator).allocate(1);
    2468:       bc_atlas_alloc_type(this->_allocator).construct(pBCAtlas, bc_atlas_type(comm, debug));
    2469:       this->_bc_atlas       = Obj<bc_atlas_type>(pBCAtlas, sizeof(bc_atlas_type));
    2470:       bc_ptr pBC            = bc_alloc_type(this->_allocator).allocate(1);
    2471:       bc_alloc_type(this->_allocator).construct(pBC, bc_type(comm, debug));
    2472:       this->_bc             = Obj<bc_type>(pBC, sizeof(bc_type));
    2473:       this->_array          = NULL;
    2474:       this->_sharedStorage  = false;
    2475:     };
    2476:     FEMSection(const Obj<atlas_type>& atlas) : ParallelObject(atlas->comm(), atlas->debug()), _atlas(atlas), _array(NULL), _sharedStorage(false), _sharedStorageSize(0) {
    2477:       bc_atlas_ptr pBCAtlas = bc_atlas_alloc_type(this->_allocator).allocate(1);
    2478:       bc_atlas_alloc_type(this->_allocator).construct(pBCAtlas, bc_atlas_type(this->comm(), this->debug()));
    2479:       this->_bc_atlas       = Obj<bc_atlas_type>(pBCAtlas, sizeof(bc_atlas_type));
    2480:       bc_ptr pBC            = bc_alloc_type(this->_allocator).allocate(1);
    2481:       bc_alloc_type(this->_allocator).construct(pBC, bc_type(this->comm(), this->debug()));
    2482:       this->_bc             = Obj<bc_type>(pBC, sizeof(bc_type));
    2483:     };
    2484:     ~FEMSection() {
    2485:       if (this->_array && !this->_sharedStorage) {
    2486:         const int totalSize = this->sizeWithBC();

    2488:         for(int i = 0; i < totalSize; ++i) {this->_allocator.destroy(this->_array+i);}
    2489:         this->_allocator.deallocate(this->_array, totalSize);
    2490:         this->_array = NULL;
    2491:       }
    2492:     };
    2493:   public:
    2494:     value_type *getRawArray(const int size) {
    2495:       // Put in a sentinel value that deallocates the array
    2496:       static value_type *array   = NULL;
    2497:       static int         maxSize = 0;

    2499:       if (size > maxSize) {
    2500:         const value_type dummy(0);

    2502:         if (array) {
    2503:           for(int i = 0; i < maxSize; ++i) {this->_allocator.destroy(array+i);}
    2504:           this->_allocator.deallocate(array, maxSize);
    2505:         }
    2506:         maxSize = size;
    2507:         array   = this->_allocator.allocate(maxSize);
    2508:         for(int i = 0; i < maxSize; ++i) {this->_allocator.construct(array+i, dummy);}
    2509:       };
    2510:       return array;
    2511:     };
    2512:     int getStorageSize() const {
    2513:       if (this->_sharedStorage) {
    2514:         return this->_sharedStorageSize;
    2515:       }
    2516:       return this->sizeWithBC();
    2517:     };
    2518:   public: // Verifiers
    2519:     bool hasPoint(const point_type& point) {
    2520:       return this->_atlas->hasPoint(point);
    2521:     };
    2522:   public: // Accessors
    2523:     const chart_type& getChart() const {return this->_atlas->getChart();};
    2524:     const Obj<atlas_type>& getAtlas() const {return this->_atlas;};
    2525:     void setAtlas(const Obj<atlas_type>& atlas) {this->_atlas = atlas;};
    2526:     const Obj<bc_type>& getBC() const {return this->_bc;};
    2527:     void setBC(const Obj<bc_type>& bc) {this->_bc = bc;};
    2528:   public: // BC
    2529:     // Returns the number of constraints on a point
    2530:     int getConstraintDimension(const point_type& p) const {
    2531:       if (!this->_bc_atlas->hasPoint(p)) return 0;
    2532:       return this->_bc_atlas->restrictPoint(p)[0];
    2533:     };
    2534:     // Set the number of constraints on a point
    2535:     void setConstraintDimension(const point_type& p, const int numConstraints) {
    2536:       this->_bc_atlas->updatePoint(p, &numConstraints);
    2537:     };
    2538:     // Increment the number of constraints on a point
    2539:     void addConstraintDimension(const point_type& p, const int numConstraints) {
    2540:       this->_bc_atlas->updatePointAdd(p, &numConstraints);
    2541:     };
    2542:     const int *getConstraintDof(const point_type& p) const {
    2543:       return this->_bc->restrictPoint(p);
    2544:     }
    2545:   public: // Sizes
    2546:     void clear() {
    2547:       if (!this->_sharedStorage) {
    2548:         const int totalSize = this->sizeWithBC();

    2550:         for(int i = 0; i < totalSize; ++i) {this->_allocator.destroy(this->_array+i);}
    2551:         this->_allocator.deallocate(this->_array, totalSize);
    2552:       }
    2553:       this->_array = NULL;
    2554:       this->_atlas->clear();
    2555:       this->_bc_atlas->clear();
    2556:       this->_bc->clear();
    2557:     };
    2558:     // Return the total number of dofs on the point (free and constrained)
    2559:     int getFiberDimension(const point_type& p) const {
    2560:       return this->_atlas->restrictPoint(p)->prefix;
    2561:     };
    2562:     int getFiberDimension(const Obj<atlas_type>& atlas, const point_type& p) const {
    2563:       return atlas->restrictPoint(p)->prefix;
    2564:     };
    2565:     // Set the total number of dofs on the point (free and constrained)
    2566:     void setFiberDimension(const point_type& p, int dim) {
    2567:       const index_type idx(dim, -1);
    2568:       this->_atlas->addPoint(p);
    2569:       this->_atlas->updatePoint(p, &idx);
    2570:     };
    2571:     template<typename Sequence>
    2572:     void setFiberDimension(const Obj<Sequence>& points, int dim) {
    2573:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
    2574:         this->setFiberDimension(*p_iter, dim);
    2575:       }
    2576:     }
    2577:     void addFiberDimension(const point_type& p, int dim) {
    2578:       if (this->_atlas->hasPoint(p)) {
    2579:         const index_type values(dim, 0);
    2580:         this->_atlas->updateAddPoint(p, &values);
    2581:       } else {
    2582:         this->setFiberDimension(p, dim);
    2583:       }
    2584:     };
    2585:     // Return the number of constrained dofs on this point
    2586:     int getConstrainedFiberDimension(const point_type& p) const {
    2587:       return this->getFiberDimension(p) - this->getConstraintDimension(p);
    2588:     };
    2589:     // Return the total number of free dofs
    2590:     int size() const {
    2591:       const chart_type& points = this->getChart();
    2592:       int               size   = 0;

    2594:       for(typename chart_type::const_iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
    2595:         size += this->getConstrainedFiberDimension(*p_iter);
    2596:       }
    2597:       return size;
    2598:     };
    2599:     // Return the total number of dofs (free and constrained)
    2600:     int sizeWithBC() const {
    2601:       const chart_type& points = this->getChart();
    2602:       int               size   = 0;

    2604:       for(typename chart_type::const_iterator p_iter = points.begin(); p_iter != points.end(); ++p_iter) {
    2605:         size += this->getFiberDimension(*p_iter);
    2606:       }
    2607:       return size;
    2608:     };
    2609:   public: // Allocation
    2610:     void allocateStorage() {
    2611:       const int totalSize = this->sizeWithBC();
    2612:       const value_type dummy(0) ;

    2614:       this->_array             = this->_allocator.allocate(totalSize);
    2615:       this->_sharedStorage     = false;
    2616:       this->_sharedStorageSize = 0;
    2617:       for(int i = 0; i < totalSize; ++i) {this->_allocator.construct(this->_array+i, dummy);}
    2618:       this->_bc_atlas->allocatePoint();
    2619:       this->_bc->allocatePoint();
    2620:     };
    2621:     void orderPoints(const Obj<atlas_type>& atlas){
    2622:       const chart_type& chart  = this->getChart();
    2623:       int               offset = 0;

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

    2629:         idx.index = offset;
    2630:         atlas->updatePoint(*c_iter, &idx);
    2631:         offset += dim;
    2632:       }
    2633:     };
    2634:     void allocatePoint() {
    2635:       this->orderPoints(this->_atlas);
    2636:       this->allocateStorage();
    2637:     };
    2638:   public: // Restriction and Update
    2639:     // Zero entries
    2640:     void zero() {
    2641:       this->set(0.0);
    2642:     };
    2643:     void set(const value_type value) {
    2644:       //memset(this->_array, 0, this->sizeWithBC()* sizeof(value_type));
    2645:       const chart_type& chart = this->getChart();

    2647:       for(typename chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
    2648:         value_type *array = (value_type *) this->restrictPoint(*c_iter);
    2649:         const int&  dim   = this->getFiberDimension(*c_iter);
    2650:         const int&  cDim  = this->getConstraintDimension(*c_iter);

    2652:         if (!cDim) {
    2653:           for(int i = 0; i < dim; ++i) {
    2654:             array[i] = value;
    2655:           }
    2656:         } else {
    2657:           const typename bc_type::value_type *cDof = this->getConstraintDof(*c_iter);
    2658:           int                                 cInd = 0;

    2660:           for(int i = 0; i < dim; ++i) {
    2661:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
    2662:             array[i] = value;
    2663:           }
    2664:         }
    2665:       }
    2666:     };
    2667:     // Add two sections and put the result in a third
    2668:     void add(const Obj<FEMSection>& x, const Obj<FEMSection>& y) {
    2669:       // Check atlases
    2670:       const chart_type& chart = this->getChart();

    2672:       for(typename chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
    2673:         value_type       *array  = (value_type *) this->restrictPoint(*c_iter);
    2674:         const value_type *xArray = x->restrictPoint(*c_iter);
    2675:         const value_type *yArray = y->restrictPoint(*c_iter);
    2676:         const int&        dim    = this->getFiberDimension(*c_iter);
    2677:         const int&        cDim   = this->getConstraintDimension(*c_iter);

    2679:         if (!cDim) {
    2680:           for(int i = 0; i < dim; ++i) {
    2681:             array[i] = xArray[i] + yArray[i];
    2682:           }
    2683:         } else {
    2684:           const typename bc_type::value_type *cDof = this->getConstraintDof(*c_iter);
    2685:           int                                 cInd = 0;

    2687:           for(int i = 0; i < dim; ++i) {
    2688:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
    2689:             array[i] = xArray[i] + yArray[i];
    2690:           }
    2691:         }
    2692:       }
    2693:     };
    2694:     // this = this + alpha * x
    2695:     void axpy(const value_type alpha, const Obj<FEMSection>& x) {
    2696:       // Check atlases
    2697:       const chart_type& chart = this->getChart();

    2699:       for(typename chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
    2700:         value_type       *array  = (value_type *) this->restrictPoint(*c_iter);
    2701:         const value_type *xArray = x->restrictPoint(*c_iter);
    2702:         const int&        dim    = this->getFiberDimension(*c_iter);
    2703:         const int&        cDim   = this->getConstraintDimension(*c_iter);

    2705:         if (!cDim) {
    2706:           for(int i = 0; i < dim; ++i) {
    2707:             array[i] += alpha*xArray[i];
    2708:           }
    2709:         } else {
    2710:           const typename bc_type::value_type *cDof = this->getConstraintDof(*c_iter);
    2711:           int                                 cInd = 0;

    2713:           for(int i = 0; i < dim; ++i) {
    2714:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
    2715:             array[i] += alpha*xArray[i];
    2716:           }
    2717:         }
    2718:       }
    2719:     };
    2720:     // Return the free values on a point
    2721:     const value_type *restrictSpace() const {
    2722:       return this->_array;
    2723:     };
    2724:     // Return the free values on a point
    2725:     const value_type *restrictPoint(const point_type& p) const {
    2726:       return &(this->_array[this->_atlas->restrictPoint(p)[0].index]);
    2727:     };
    2728:     // Update the free values on a point
    2729:     //   Takes a full array and ignores constrained values
    2730:     void updatePoint(const point_type& p, const value_type v[], const int orientation = 1) {
    2731:       value_type *array = (value_type *) this->restrictPoint(p);
    2732:       const int&  cDim  = this->getConstraintDimension(p);

    2734:       if (!cDim) {
    2735:         if (orientation >= 0) {
    2736:           const int& dim = this->getFiberDimension(p);

    2738:           for(int i = 0; i < dim; ++i) {
    2739:             array[i] = v[i];
    2740:           }
    2741:         } else {
    2742:           int offset = 0;
    2743:           int j      = -1;

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

    2748:             for(int i = dim-1; i >= 0; --i) {
    2749:               array[++j] = v[i+offset];
    2750:             }
    2751:             offset += dim;
    2752:           }
    2753:         }
    2754:       } else {
    2755:         if (orientation >= 0) {
    2756:           const int&                          dim  = this->getFiberDimension(p);
    2757:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
    2758:           int                                 cInd = 0;

    2760:           for(int i = 0; i < dim; ++i) {
    2761:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
    2762:             array[i] = v[i];
    2763:           }
    2764:         } else {
    2765:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
    2766:           int                                 offset  = 0;
    2767:           int                                 cOffset = 0;
    2768:           int                                 j       = 0;

    2770:           for(int space = 0; space < this->getNumSpaces(); ++space) {
    2771:             const int  dim = this->getFiberDimension(p, space);
    2772:             const int tDim = this->getConstrainedFiberDimension(p, space);
    2773:             const int sDim = dim - tDim;
    2774:             int       cInd = 0;

    2776:             for(int i = 0, k = dim+offset-1; i < dim; ++i, ++j, --k) {
    2777:               if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
    2778:               array[j] = v[k];
    2779:             }
    2780:             offset  += dim;
    2781:             cOffset += dim - tDim;
    2782:           }
    2783:         }
    2784:       }
    2785:     };
    2786:     // Update the free values on a point
    2787:     //   Takes a full array and ignores constrained values
    2788:     void updateAddPoint(const point_type& p, const value_type v[], const int orientation = 1) {
    2789:       value_type *array = (value_type *) this->restrictPoint(p);
    2790:       const int&  cDim  = this->getConstraintDimension(p);

    2792:       if (!cDim) {
    2793:         if (orientation >= 0) {
    2794:           const int& dim = this->getFiberDimension(p);

    2796:           for(int i = 0; i < dim; ++i) {
    2797:             array[i] += v[i];
    2798:           }
    2799:         } else {
    2800:           int offset = 0;
    2801:           int j      = -1;

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

    2806:             for(int i = dim-1; i >= 0; --i) {
    2807:               array[++j] += v[i+offset];
    2808:             }
    2809:             offset += dim;
    2810:           }
    2811:         }
    2812:       } else {
    2813:         if (orientation >= 0) {
    2814:           const int&                          dim  = this->getFiberDimension(p);
    2815:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
    2816:           int                                 cInd = 0;

    2818:           for(int i = 0; i < dim; ++i) {
    2819:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
    2820:             array[i] += v[i];
    2821:           }
    2822:         } else {
    2823:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
    2824:           int                                 offset  = 0;
    2825:           int                                 cOffset = 0;
    2826:           int                                 j       = 0;

    2828:           for(int space = 0; space < this->getNumSpaces(); ++space) {
    2829:             const int  dim = this->getFiberDimension(p, space);
    2830:             const int tDim = this->getConstrainedFiberDimension(p, space);
    2831:             const int sDim = dim - tDim;
    2832:             int       cInd = 0;

    2834:             for(int i = 0, k = dim+offset-1; i < dim; ++i, ++j, --k) {
    2835:               if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
    2836:               array[j] += v[k];
    2837:             }
    2838:             offset  += dim;
    2839:             cOffset += dim - tDim;
    2840:           }
    2841:         }
    2842:       }
    2843:     };
    2844:     // Update the free values on a point
    2845:     //   Takes ONLY unconstrained values
    2846:     void updateFreePoint(const point_type& p, const value_type v[], const int orientation = 1) {
    2847:       value_type *array = (value_type *) this->restrictPoint(p);
    2848:       const int&  cDim  = this->getConstraintDimension(p);

    2850:       if (!cDim) {
    2851:         if (orientation >= 0) {
    2852:           const int& dim = this->getFiberDimension(p);

    2854:           for(int i = 0; i < dim; ++i) {
    2855:             array[i] = v[i];
    2856:           }
    2857:         } else {
    2858:           int offset = 0;
    2859:           int j      = -1;

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

    2864:             for(int i = dim-1; i >= 0; --i) {
    2865:               array[++j] = v[i+offset];
    2866:             }
    2867:             offset += dim;
    2868:           }
    2869:         }
    2870:       } else {
    2871:         if (orientation >= 0) {
    2872:           const int&                          dim  = this->getFiberDimension(p);
    2873:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
    2874:           int                                 cInd = 0;

    2876:           for(int i = 0, k = -1; i < dim; ++i) {
    2877:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
    2878:             array[i] = v[++k];
    2879:           }
    2880:         } else {
    2881:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
    2882:           int                                 offset  = 0;
    2883:           int                                 cOffset = 0;
    2884:           int                                 j       = 0;

    2886:           for(int space = 0; space < this->getNumSpaces(); ++space) {
    2887:             const int  dim = this->getFiberDimension(p, space);
    2888:             const int tDim = this->getConstrainedFiberDimension(p, space);
    2889:             const int sDim = dim - tDim;
    2890:             int       cInd = 0;

    2892:             for(int i = 0, k = tDim+offset-1; i < dim; ++i, ++j) {
    2893:               if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
    2894:               array[j] = v[--k];
    2895:             }
    2896:             offset  += dim;
    2897:             cOffset += dim - tDim;
    2898:           }
    2899:         }
    2900:       }
    2901:     };
    2902:     // Update the free values on a point
    2903:     //   Takes ONLY unconstrained values
    2904:     void updateFreeAddPoint(const point_type& p, const value_type v[], const int orientation = 1) {
    2905:       value_type *array = (value_type *) this->restrictPoint(p);
    2906:       const int&  cDim  = this->getConstraintDimension(p);

    2908:       if (!cDim) {
    2909:         if (orientation >= 0) {
    2910:           const int& dim = this->getFiberDimension(p);

    2912:           for(int i = 0; i < dim; ++i) {
    2913:             array[i] += v[i];
    2914:           }
    2915:         } else {
    2916:           int offset = 0;
    2917:           int j      = -1;

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

    2922:             for(int i = dim-1; i >= 0; --i) {
    2923:               array[++j] += v[i+offset];
    2924:             }
    2925:             offset += dim;
    2926:           }
    2927:         }
    2928:       } else {
    2929:         if (orientation >= 0) {
    2930:           const int&                          dim  = this->getFiberDimension(p);
    2931:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
    2932:           int                                 cInd = 0;

    2934:           for(int i = 0, k = -1; i < dim; ++i) {
    2935:             if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
    2936:             array[i] += v[++k];
    2937:           }
    2938:         } else {
    2939:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
    2940:           int                                 offset  = 0;
    2941:           int                                 cOffset = 0;
    2942:           int                                 j       = 0;

    2944:           for(int space = 0; space < this->getNumSpaces(); ++space) {
    2945:             const int  dim = this->getFiberDimension(p, space);
    2946:             const int tDim = this->getConstrainedFiberDimension(p, space);
    2947:             const int sDim = dim - tDim;
    2948:             int       cInd = 0;

    2950:             for(int i = 0, k = tDim+offset-1; i < dim; ++i, ++j) {
    2951:               if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
    2952:               array[j] += v[--k];
    2953:             }
    2954:             offset  += dim;
    2955:             cOffset += dim - tDim;
    2956:           }
    2957:         }
    2958:       }
    2959:     };
    2960:     // Update only the constrained dofs on a point
    2961:     //   This takes an array with ONLY bc values
    2962:     void updatePointBC(const point_type& p, const value_type v[], const int orientation = 1) {
    2963:       value_type *array = (value_type *) this->restrictPoint(p);
    2964:       const int&  cDim  = this->getConstraintDimension(p);

    2966:       if (cDim) {
    2967:         if (orientation >= 0) {
    2968:           const int&                          dim  = this->getFiberDimension(p);
    2969:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
    2970:           int                                 cInd = 0;

    2972:           for(int i = 0; i < dim; ++i) {
    2973:             if (cInd == cDim) break;
    2974:             if (i == cDof[cInd]) {
    2975:               array[i] = v[cInd];
    2976:               ++cInd;
    2977:             }
    2978:           }
    2979:         } else {
    2980:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
    2981:           int                                 cOffset = 0;
    2982:           int                                 j       = 0;

    2984:           for(int space = 0; space < this->getNumSpaces(); ++space) {
    2985:             const int  dim = this->getFiberDimension(p, space);
    2986:             const int tDim = this->getConstrainedFiberDimension(p, space);
    2987:             int       cInd = 0;

    2989:             for(int i = 0; i < dim; ++i, ++j) {
    2990:               if (cInd < 0) break;
    2991:               if (j == cDof[cInd+cOffset]) {
    2992:                 array[j] = v[cInd+cOffset];
    2993:                 ++cInd;
    2994:               }
    2995:             }
    2996:             cOffset += dim - tDim;
    2997:           }
    2998:         }
    2999:       }
    3000:     };
    3001:     // Update only the constrained dofs on a point
    3002:     //   This takes an array with ALL values, not just BC
    3003:     void updatePointBCFull(const point_type& p, const value_type v[], const int orientation = 1) {
    3004:       value_type *array = (value_type *) this->restrictPoint(p);
    3005:       const int&  cDim  = this->getConstraintDimension(p);

    3007:       if (cDim) {
    3008:         if (orientation >= 0) {
    3009:           const int&                          dim  = this->getFiberDimension(p);
    3010:           const typename bc_type::value_type *cDof = this->getConstraintDof(p);
    3011:           int                                 cInd = 0;

    3013:           for(int i = 0; i < dim; ++i) {
    3014:             if (cInd == cDim) break;
    3015:             if (i == cDof[cInd]) {
    3016:               array[i] = v[i];
    3017:               ++cInd;
    3018:             }
    3019:           }
    3020:         } else {
    3021:           const typename bc_type::value_type *cDof    = this->getConstraintDof(p);
    3022:           int                                 offset  = 0;
    3023:           int                                 cOffset = 0;
    3024:           int                                 j       = 0;

    3026:           for(int space = 0; space < this->getNumSpaces(); ++space) {
    3027:             const int  dim = this->getFiberDimension(p, space);
    3028:             const int tDim = this->getConstrainedFiberDimension(p, space);
    3029:             int       cInd = 0;

    3031:             for(int i = 0, k = dim+offset-1; i < dim; ++i, ++j, --k) {
    3032:               if (cInd < 0) break;
    3033:               if (j == cDof[cInd+cOffset]) {
    3034:                 array[j] = v[k];
    3035:                 ++cInd;
    3036:               }
    3037:             }
    3038:             offset  += dim;
    3039:             cOffset += dim - tDim;
    3040:           }
    3041:         }
    3042:       }
    3043:     };
    3044:     // Update all dofs on a point (free and constrained)
    3045:     void updatePointAll(const point_type& p, const value_type v[], const int orientation = 1) {
    3046:       value_type *array = (value_type *) this->restrictPoint(p);

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

    3051:         for(int i = 0; i < dim; ++i) {
    3052:           array[i] = v[i];
    3053:         }
    3054:       } else {
    3055:         int offset = 0;
    3056:         int j      = -1;

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

    3061:           for(int i = dim-1; i >= 0; --i) {
    3062:             array[++j] = v[i+offset];
    3063:           }
    3064:           offset += dim;
    3065:         }
    3066:       }
    3067:     };
    3068:     // Update all dofs on a point (free and constrained)
    3069:     void updatePointAllAdd(const point_type& p, const value_type v[], const int orientation = 1) {
    3070:       value_type *array = (value_type *) this->restrictPoint(p);

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

    3075:         for(int i = 0; i < dim; ++i) {
    3076:           array[i] += v[i];
    3077:         }
    3078:       } else {
    3079:         int offset = 0;
    3080:         int j      = -1;

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

    3085:           for(int i = dim-1; i >= 0; --i) {
    3086:             array[++j] += v[i+offset];
    3087:           }
    3088:           offset += dim;
    3089:         }
    3090:       }
    3091:     };
    3092:   public: // Fibrations
    3093:     int getNumSpaces() const {return this->_spaces.size();};
    3094:     const std::vector<Obj<atlas_type> >& getSpaces() {return this->_spaces;};
    3095:     const std::vector<Obj<bc_type> >& getBCs() {return this->_bcs;};
    3096:     void addSpace() {
    3097:       Obj<atlas_type> space = new atlas_type(this->comm(), this->debug());
    3098:       Obj<bc_type>    bc    = new bc_type(this->comm(), this->debug());
    3099:       this->_spaces.push_back(space);
    3100:       this->_bcs.push_back(bc);
    3101:     };
    3102:     int getFiberDimension(const point_type& p, const int space) const {
    3103:       return this->_spaces[space]->restrictPoint(p)->prefix;
    3104:     };
    3105:     void setFiberDimension(const point_type& p, int dim, const int space) {
    3106:       const index_type idx(dim, -1);
    3107:       this->_spaces[space]->addPoint(p);
    3108:       this->_spaces[space]->updatePoint(p, &idx);
    3109:     };
    3110:     template<typename Sequence>
    3111:     void setFiberDimension(const Obj<Sequence>& points, int dim, const int space) {
    3112:       for(typename Sequence::iterator p_iter = points->begin(); p_iter != points->end(); ++p_iter) {
    3113:         this->setFiberDimension(*p_iter, dim, space);
    3114:       }
    3115:     }
    3116:     int getConstraintDimension(const point_type& p, const int space) const {
    3117:       if (!this->_bcs[space]->hasPoint(p)) return 0;
    3118:       return this->_bcs[space]->getFiberDimension(p);
    3119:     };
    3120:     void setConstraintDimension(const point_type& p, const int numConstraints, const int space) {
    3121:       this->_bcs[space]->setFiberDimension(p, numConstraints);
    3122:     };
    3123:     int getConstrainedFiberDimension(const point_type& p, const int space) const {
    3124:       return this->getFiberDimension(p, space) - this->getConstraintDimension(p, space);
    3125:     };
    3126:     void copyFibration(const Obj<FEMSection>& section) {
    3127:       const std::vector<Obj<atlas_type> >& spaces = section->getSpaces();
    3128:       const std::vector<Obj<bc_type> >&    bcs    = section->getBCs();

    3130:       this->_spaces.clear();
    3131:       for(typename std::vector<Obj<atlas_type> >::const_iterator s_iter = spaces.begin(); s_iter != spaces.end(); ++s_iter) {
    3132:         this->_spaces.push_back(*s_iter);
    3133:       }
    3134:       this->_bcs.clear();
    3135:       for(typename std::vector<Obj<bc_type> >::const_iterator b_iter = bcs.begin(); b_iter != bcs.end(); ++b_iter) {
    3136:         this->_bcs.push_back(*b_iter);
    3137:       }
    3138:     };
    3139:     Obj<FEMSection> getFibration(const int space) const {
    3140:       Obj<FEMSection> field = new FEMSection(this->comm(), this->debug());
    3141: //     Obj<atlas_type> _atlas;
    3142: //     std::vector<Obj<atlas_type> > _spaces;
    3143: //     Obj<bc_type>    _bc;
    3144: //     std::vector<Obj<bc_type> >    _bcs;
    3145:       field->addSpace();
    3146:       const chart_type& chart = this->getChart();

    3148:       // Copy sizes
    3149:       for(typename chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
    3150:         const int fDim = this->getFiberDimension(*c_iter, space);
    3151:         const int cDim = this->getConstraintDimension(*c_iter, space);

    3153:         if (fDim) {
    3154:           field->setFiberDimension(*c_iter, fDim);
    3155:           field->setFiberDimension(*c_iter, fDim, 0);
    3156:         }
    3157:         if (cDim) {
    3158:           field->setConstraintDimension(*c_iter, cDim);
    3159:           field->setConstraintDimension(*c_iter, cDim, 0);
    3160:         }
    3161:       }
    3162:       field->allocateStorage();
    3163:       Obj<atlas_type>   newAtlas = new atlas_type(this->comm(), this->debug());
    3164:       const chart_type& newChart = field->getChart();

    3166:       for(typename chart_type::const_iterator c_iter = newChart.begin(); c_iter != newChart.end(); ++c_iter) {
    3167:         const int cDim   = field->getConstraintDimension(*c_iter);
    3168:         const int dof[1] = {0};

    3170:         if (cDim) {
    3171:           field->setConstraintDof(*c_iter, dof);
    3172:         }
    3173:       }
    3174:       // Copy offsets
    3175:       for(typename chart_type::const_iterator c_iter = newChart.begin(); c_iter != newChart.end(); ++c_iter) {
    3176:         index_type idx;

    3178:         idx.prefix = field->getFiberDimension(*c_iter);
    3179:         idx.index  = this->_atlas->restrictPoint(*c_iter)[0].index;
    3180:         for(int s = 0; s < space; ++s) {
    3181:           idx.index += this->getFiberDimension(*c_iter, s);
    3182:         }
    3183:         newAtlas->addPoint(*c_iter);
    3184:         newAtlas->updatePoint(*c_iter, &idx);
    3185:       }
    3186:       field->replaceStorage(this->_array, true, this->getStorageSize());
    3187:       field->setAtlas(newAtlas);
    3188:       return field;
    3189:     };
    3190:   public:
    3191:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
    3192:       ostringstream txt;
    3193:       int rank;

    3195:       if (comm == MPI_COMM_NULL) {
    3196:         comm = this->comm();
    3197:         rank = this->commRank();
    3198:       } else {
    3199:         MPI_Comm_rank(comm, &rank);
    3200:       }
    3201:       if (name == "") {
    3202:         if(rank == 0) {
    3203:           txt << "viewing a FEMSection" << std::endl;
    3204:         }
    3205:       } else {
    3206:         if (rank == 0) {
    3207:           txt << "viewing FEMSection '" << name << "'" << std::endl;
    3208:         }
    3209:       }
    3210:       if (rank == 0) {
    3211:         txt << "  Fields: " << this->getNumSpaces() << std::endl;
    3212:       }
    3213:       const chart_type& chart = this->getChart();

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

    3219:         if (dim != 0) {
    3220:           txt << "[" << this->commRank() << "]:   " << *p_iter << " dim " << dim << " offset " << this->_atlas->restrictPoint(*p_iter)->index << "  ";
    3221:           for(int i = 0; i < dim; i++) {
    3222:             txt << " " << array[i];
    3223:           }
    3224:           const int& dim = this->getConstraintDimension(*p_iter);

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

    3229:             txt << " constrained";
    3230:             for(int i = 0; i < dim; ++i) {
    3231:               txt << " " << bcArray[i];
    3232:             }
    3233:           }
    3234:           txt << std::endl;
    3235:         }
    3236:       }
    3237:       if (chart.size() == 0) {
    3238:         txt << "[" << this->commRank() << "]: empty" << std::endl;
    3239:       }
    3240:       PetscSynchronizedPrintf(comm, txt.str().c_str());
    3241:       PetscSynchronizedFlush(comm);
    3242:     };
    3243:   };
    3244:   // A Field combines several sections
    3245:   template<typename Overlap_, typename Patch_, typename Section_>
    3246:   class Field : public ALE::ParallelObject {
    3247:   public:
    3248:     typedef Overlap_                                 overlap_type;
    3249:     typedef Patch_                                   patch_type;
    3250:     typedef Section_                                 section_type;
    3251:     typedef typename section_type::point_type        point_type;
    3252:     typedef typename section_type::chart_type        chart_type;
    3253:     typedef typename section_type::value_type        value_type;
    3254:     typedef std::map<patch_type, Obj<section_type> > sheaf_type;
    3255:     typedef enum {SEND, RECEIVE}                     request_type;
    3256:     typedef std::map<patch_type, MPI_Request>        requests_type;
    3257:   protected:
    3258:     sheaf_type    _sheaf;
    3259:     int           _tag;
    3260:     MPI_Datatype  _datatype;
    3261:     requests_type _requests;
    3262:   public:
    3263:     Field(MPI_Comm comm, const int debug = 0) : ParallelObject(comm, debug) {
    3264:       this->_tag      = this->getNewTag();
    3265:       this->_datatype = this->getMPIDatatype();
    3266:     };
    3267:     Field(MPI_Comm comm, const int tag, const int debug) : ParallelObject(comm, debug), _tag(tag) {
    3268:       this->_datatype = this->getMPIDatatype();
    3269:     };
    3270:     virtual ~Field() {};
    3271:   protected:
    3272:     MPI_Datatype getMPIDatatype() {
    3273:       if (sizeof(value_type) == 4) {
    3274:         return MPI_INT;
    3275:       } else if (sizeof(value_type) == 8) {
    3276:         return MPI_DOUBLE;
    3277:       } else if (sizeof(value_type) == 28) {
    3278:         int          blen[2];
    3279:         MPI_Aint     indices[2];
    3280:         MPI_Datatype oldtypes[2], newtype;
    3281:         blen[0] = 1; indices[0] = 0;           oldtypes[0] = MPI_INT;
    3282:         blen[1] = 3; indices[1] = sizeof(int); oldtypes[1] = MPI_DOUBLE;
    3283:         MPI_Type_struct(2, blen, indices, oldtypes, &newtype);
    3284:         MPI_Type_commit(&newtype);
    3285:         return newtype;
    3286:       } else if (sizeof(value_type) == 32) {
    3287:         int          blen[2];
    3288:         MPI_Aint     indices[2];
    3289:         MPI_Datatype oldtypes[2], newtype;
    3290:         blen[0] = 1; indices[0] = 0;           oldtypes[0] = MPI_DOUBLE;
    3291:         blen[1] = 3; indices[1] = sizeof(int); oldtypes[1] = MPI_DOUBLE;
    3292:         MPI_Type_struct(2, blen, indices, oldtypes, &newtype);
    3293:         MPI_Type_commit(&newtype);
    3294:         return newtype;
    3295:       }
    3296:       throw ALE::Exception("Cannot determine MPI type for value type");
    3297:     };
    3298:     int getNewTag() {
    3299:       static int tagKeyval = MPI_KEYVAL_INVALID;
    3300:       int *tagvalp = NULL, *maxval, flg;

    3302:       if (tagKeyval == MPI_KEYVAL_INVALID) {
    3303:         tagvalp = (int *) malloc(sizeof(int));
    3304:         MPI_Keyval_create(MPI_NULL_COPY_FN, DMMesh_DelTag, &tagKeyval, (void *) NULL);
    3305:         MPI_Attr_put(this->_comm, tagKeyval, tagvalp);
    3306:         tagvalp[0] = 0;
    3307:       }
    3308:       MPI_Attr_get(this->_comm, tagKeyval, (void **) &tagvalp, &flg);
    3309:       if (tagvalp[0] < 1) {
    3310:         MPI_Attr_get(MPI_COMM_WORLD, MPI_TAG_UB, (void **) &maxval, &flg);
    3311:         tagvalp[0] = *maxval - 128; // hope that any still active tags were issued right at the beginning of the run
    3312:       }
    3313:       if (this->debug()) {
    3314:         std::cout << "[" << this->commRank() << "]Got new tag " << tagvalp[0] << std::endl;
    3315:       }
    3316:       return tagvalp[0]--;
    3317:     };
    3318:   public: // Verifiers
    3319:     void checkPatch(const patch_type& patch) const {
    3320:       if (this->_sheaf.find(patch) == this->_sheaf.end()) {
    3321:         ostringstream msg;
    3322:         msg << "Invalid field patch " << patch << std::endl;
    3323:         throw ALE::Exception(msg.str().c_str());
    3324:       }
    3325:     };
    3326:     bool hasPatch(const patch_type& patch) {
    3327:       if (this->_sheaf.find(patch) == this->_sheaf.end()) {
    3328:         return false;
    3329:       }
    3330:       return true;
    3331:     };
    3332:   public: // Accessors
    3333:     int getTag() const {return this->_tag;};
    3334:     void setTag(const int tag) {this->_tag = tag;};
    3335:     Obj<section_type>& getSection(const patch_type& patch) {
    3336:       if (this->_sheaf.find(patch) == this->_sheaf.end()) {
    3337:         this->_sheaf[patch] = new section_type(this->comm(), this->debug());
    3338:       }
    3339:       return this->_sheaf[patch];
    3340:     };
    3341:     void setSection(const patch_type& patch, const Obj<section_type>& section) {this->_sheaf[patch] = section;};
    3342:     const sheaf_type& getPatches() {
    3343:       return this->_sheaf;
    3344:     };
    3345:     void clear() {
    3346:       for(typename sheaf_type::const_iterator p_iter = this->_sheaf.begin(); p_iter != this->_sheaf.end(); ++p_iter) {
    3347:         p_iter->second->clear();
    3348:       }
    3349:     };
    3350:   public: //  Adapter
    3351:     template<typename Topology_>
    3352:     void setTopology(const Obj<Topology_>& topology) {
    3353:       const typename Topology_::sheaf_type& patches = topology->getPatches();

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

    3360:         for(typename Topology_::sieve_type::baseSequence::iterator b_iter = base->begin(); b_iter != base->end(); ++b_iter) {
    3361:           section->setFiberDimension(*b_iter, 1);
    3362:         }
    3363:       }
    3364:     }
    3365:     void allocate() {
    3366:       for(typename sheaf_type::const_iterator p_iter = this->_sheaf.begin(); p_iter != this->_sheaf.end(); ++p_iter) {
    3367:         p_iter->second->allocatePoint();
    3368:       }
    3369:     }
    3370:   public: // Communication
    3371:     void construct(const int size) {
    3372:       const sheaf_type& patches = this->getPatches();

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

    3379:         for(typename chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
    3380:           section->setFiberDimension(*c_iter, size);
    3381:         }
    3382:       }
    3383:     };
    3384:     template<typename Sizer>
    3385:     void construct(const Obj<Sizer>& sizer) {
    3386:       const sheaf_type& patches = this->getPatches();

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

    3393:         for(typename chart_type::const_iterator c_iter = chart.begin(); c_iter != chart.end(); ++c_iter) {
    3394:           section->setFiberDimension(*c_iter, *(sizer->getSection(rank)->restrictPoint(*c_iter)));
    3395:         }
    3396:       }
    3397:     }
    3398:     void constructCommunication(const request_type& requestType) {
    3399:       const sheaf_type& patches = this->getPatches();

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

    3406:         if (requestType == RECEIVE) {
    3407:           if (this->_debug) {std::cout <<"["<<this->commRank()<<"] Receiving data(" << section->size() << ") from " << patch << " tag " << this->_tag << std::endl;}
    3408:           MPI_Recv_init((void *) section->restrictSpace(), section->size(), this->_datatype, patch, this->_tag, this->comm(), &request);
    3409:         } else {
    3410:           if (this->_debug) {std::cout <<"["<<this->commRank()<<"] Sending data (" << section->size() << ") to " << patch << " tag " << this->_tag << std::endl;}
    3411:           MPI_Send_init((void *) section->restrictSpace(), section->size(), this->_datatype, patch, this->_tag, this->comm(), &request);
    3412:         }
    3413:         this->_requests[patch] = request;
    3414:       }
    3415:     };
    3416:     void startCommunication() {
    3417:       const sheaf_type& patches = this->getPatches();

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

    3422:         MPI_Start(&request);
    3423:       }
    3424:     };
    3425:     void endCommunication() {
    3426:       const sheaf_type& patches = this->getPatches();
    3427:       MPI_Status status;

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

    3432:         MPI_Wait(&request, &status);
    3433:       }
    3434:     };
    3435:   public:
    3436:     void view(const std::string& name, MPI_Comm comm = MPI_COMM_NULL) const {
    3437:       ostringstream txt;
    3438:       int rank;

    3440:       if (comm == MPI_COMM_NULL) {
    3441:         comm = this->comm();
    3442:         rank = this->commRank();
    3443:       } else {
    3444:         MPI_Comm_rank(comm, &rank);
    3445:       }
    3446:       if (name == "") {
    3447:         if(rank == 0) {
    3448:           txt << "viewing a Field" << std::endl;
    3449:         }
    3450:       } else {
    3451:         if(rank == 0) {
    3452:           txt << "viewing Field '" << name << "'" << std::endl;
    3453:         }
    3454:       }
    3455:       PetscSynchronizedPrintf(comm, txt.str().c_str());
    3456:       PetscSynchronizedFlush(comm);
    3457:       for(typename sheaf_type::const_iterator p_iter = this->_sheaf.begin(); p_iter != this->_sheaf.end(); ++p_iter) {
    3458:         ostringstream txt1;

    3460:         txt1 << "[" << this->commRank() << "]: Patch " << p_iter->first << std::endl;
    3461:         PetscSynchronizedPrintf(comm, txt1.str().c_str());
    3462:         PetscSynchronizedFlush(comm);
    3463:         p_iter->second->view("field section", comm);
    3464:       }
    3465:     };
    3466:   };
    3467: }
    3468: #endif