text: /*****************************************************************************/
  /*                                    XDMF                                   */
  /*                       eXtensible Data Model and Format                    */
  /*                                                                           */
  /*  Id : XdmfCurviliniearGrid.cpp                                            */
  /*                                                                           */
  /*  Author:                                                                  */
  /*     Kenneth Leiter                                                        */
  /*     kenneth.leiter@arl.army.mil                                           */
  /*     US Army Research Laboratory                                           */
  /*     Aberdeen Proving Ground, MD                                           */
  /*                                                                           */
  /*     Copyright @ 2011 US Army Research Laboratory                          */
  /*     All Rights Reserved                                                   */
  /*     See Copyright.txt for details                                         */
  /*                                                                           */
  /*     This software is distributed WITHOUT ANY WARRANTY; without            */
  /*     even the implied warranty of MERCHANTABILITY or FITNESS               */
  /*     FOR A PARTICULAR PURPOSE.  See the above copyright notice             */
  /*     for more information.                                                 */
  /*                                                                           */
  /*****************************************************************************/
  
  #include <cmath>
  #include "XdmfArray.hpp"
  #include "XdmfCurvilinearGrid.hpp"
  #include "XdmfGeometry.hpp"
  #include "XdmfTopology.hpp"
  #include "XdmfTopologyType.hpp"
  #include "XdmfError.hpp"
  
  /**
   * PIMPL
   */
  class XdmfCurvilinearGrid::XdmfCurvilinearGridImpl : public XdmfGridImpl {
  
  public:
  
    class XdmfTopologyCurvilinear : public XdmfTopology
    {
  
    public:
  
      static shared_ptr<XdmfTopologyCurvilinear>
      New(const XdmfCurvilinearGrid * const curvilinearGrid)
      {
        shared_ptr<XdmfTopologyCurvilinear> 
          p(new XdmfTopologyCurvilinear(curvilinearGrid));
        return p;
      }
  
      bool isInitialized() const
      {
        return true;
      }
  
      unsigned int
      getNumberElements() const
      {
        const shared_ptr<const XdmfArray> dimensions = 
          mCurvilinearGrid->getDimensions();
        if(dimensions->getSize() == 0) {
          return 0;
        }
        unsigned int toReturn = 1;
        for(unsigned int i=0; i<dimensions->getSize(); ++i) {
          toReturn *= (dimensions->getValue<unsigned int>(i) - 1);
        }
        return toReturn;
      }
  
    private:
  
      XdmfTopologyCurvilinear(const XdmfCurvilinearGrid * const curvilinearGrid) :
        mCurvilinearGrid(curvilinearGrid)
      {
        this->setType(XdmfTopologyTypeCurvilinear::New(curvilinearGrid));
      }
  
      const XdmfCurvilinearGrid * const mCurvilinearGrid;
    };
  
    class XdmfTopologyTypeCurvilinear : public XdmfTopologyType
    {
  
    public:
  
      static shared_ptr<const XdmfTopologyTypeCurvilinear>
      New(const XdmfCurvilinearGrid * const curvilinearGrid)
      {
        shared_ptr<const XdmfTopologyTypeCurvilinear>
          p(new XdmfTopologyTypeCurvilinear(curvilinearGrid));
        return p;
      }
  
      unsigned int
      getEdgesPerElement() const
      {
        return calculateHypercubeNumElements(mCurvilinearGrid->getDimensions()->getSize(), 1);
  /*
        const unsigned int dimensions = 
          mCurvilinearGrid->getDimensions()->getSize();
        if (dimensions == 1) {
          return 1;
        }
        if(dimensions == 2) {
          return 4;
        }
        else if(dimensions >= 3) {
          return 12;
        }
        else {
          XdmfError::message(XdmfError::FATAL, 
                             "Grid dimensions not 2 or 3 in "
                             "XdmfTopologyTypeCurvilinear::getEdgesPerElement");
        }
        return 0;
  */
      }
  
      unsigned int
      getFacesPerElement() const
      {
        return calculateHypercubeNumElements(mCurvilinearGrid->getDimensions()->getSize(), 2);
  /*
        const unsigned int dimensions = 
          mCurvilinearGrid->getDimensions()->getSize();
        if (dimensions == 1) {
          return 0;
        }
        else if(dimensions == 2) {
          return 1;
        }
        else if(dimensions == 3) {
          return 6;
        }
        else {
          XdmfError::message(XdmfError::FATAL, 
                             "Grid dimensions not 2 or 3 in "
                             "XdmfTopologyTypeCurvilinear::getFacesPerElement");
        }
        return 0;
  */
      }
  
      unsigned int
      getNodesPerElement() const
      {
        return calculateHypercubeNumElements(mCurvilinearGrid->getDimensions()->getSize(), 0);
        // 2^Dimensions
        // e.g. 1D = 2 nodes per element and 2D = 4 nodes per element.
  //      return (unsigned int)
  //        std::pow(2, (double)mCurvilinearGrid->getDimensions()->getSize());
      }
  
      void
      getProperties(std::map<std::string, std::string> & collectedProperties) const
      {
        shared_ptr<const XdmfArray> dimensions =
          mCurvilinearGrid->getDimensions();
        if(dimensions->getSize() == 3) {
          collectedProperties["Type"] = "3DSMesh";
        }
        else if(dimensions->getSize() == 2) {
          collectedProperties["Type"] = "2DSMesh";
        }
        else {
          collectedProperties["Type"] = "SMesh";
  //        XdmfError::message(XdmfError::FATAL, 
  //                           "Grid dimensions not 2 or 3 in "
  //                           "XdmfTopologyTypeCurvilinear::getProperties");
        }
        collectedProperties["Dimensions"] = dimensions->getValuesString();
      }
  
    private:
  
      XdmfTopologyTypeCurvilinear(const XdmfCurvilinearGrid * const curvilinearGrid) :
        XdmfTopologyType(0,
                         0,
                         std::vector<shared_ptr<const XdmfTopologyType> >(),
                         0,
                         "foo",
                         XdmfTopologyType::Structured,
                         0x1110),
        mCurvilinearGrid(curvilinearGrid)
      {
      }
  
      const XdmfCurvilinearGrid * const mCurvilinearGrid;
  
    };
  
    XdmfCurvilinearGridImpl(const shared_ptr<XdmfArray> numPoints) :
      mDimensions(numPoints)
    {
       mGridType ="Curvilinear";
    }
  
    XdmfGridImpl * duplicate()
    {
      return new XdmfCurvilinearGridImpl(mDimensions);
    }
  
    shared_ptr<XdmfArray> mDimensions;
  };
  
  shared_ptr<XdmfCurvilinearGrid>
  XdmfCurvilinearGrid::New(const unsigned int xNumPoints,
                           const unsigned int yNumPoints)
  {
    shared_ptr<XdmfArray> numPoints = XdmfArray::New();
    numPoints->initialize<unsigned int>(2);
    numPoints->insert(0, xNumPoints);
    numPoints->insert(1, yNumPoints);
    shared_ptr<XdmfCurvilinearGrid> p(new XdmfCurvilinearGrid(numPoints));
    return p;
  }
  
  shared_ptr<XdmfCurvilinearGrid>
  XdmfCurvilinearGrid::New(const unsigned int xNumPoints,
                           const unsigned int yNumPoints,
                           const unsigned int zNumPoints)
  {
    shared_ptr<XdmfArray> numPoints = XdmfArray::New();
    numPoints->initialize<unsigned int>(3);
    numPoints->insert(0, xNumPoints);
    numPoints->insert(1, yNumPoints);
    numPoints->insert(2, zNumPoints);
    shared_ptr<XdmfCurvilinearGrid> p(new XdmfCurvilinearGrid(numPoints));
    return p;
  }
  
  shared_ptr<XdmfCurvilinearGrid>
  XdmfCurvilinearGrid::New(const shared_ptr<XdmfArray> numPoints)
  {
    shared_ptr<XdmfCurvilinearGrid> p(new XdmfCurvilinearGrid(numPoints));
    return p;
  }
  
  XdmfCurvilinearGrid::XdmfCurvilinearGrid(const shared_ptr<XdmfArray> numPoints) :
    XdmfGrid(XdmfGeometry::New(),
             XdmfCurvilinearGridImpl::XdmfTopologyCurvilinear::New(this))
  {
    mImpl = new XdmfCurvilinearGridImpl(numPoints);
  }
  
  XdmfCurvilinearGrid::XdmfCurvilinearGrid(XdmfCurvilinearGrid & refGrid) :
    XdmfGrid(refGrid)
  {
    mTopology = XdmfCurvilinearGridImpl::XdmfTopologyCurvilinear::New(this);
  }
  
  XdmfCurvilinearGrid::~XdmfCurvilinearGrid()
  {
    if (mImpl) {
      delete mImpl;
    }
    mImpl = NULL;
  }
  
  const std::string XdmfCurvilinearGrid::ItemTag = "Grid";
  
  void
  XdmfCurvilinearGrid::copyGrid(shared_ptr<XdmfGrid> sourceGrid)
  {
    XdmfGrid::copyGrid(sourceGrid);
    if (shared_ptr<XdmfCurvilinearGrid> classedGrid = shared_dynamic_cast<XdmfCurvilinearGrid>(sourceGrid))
    {
      // Copy stucture from read grid to this grid
      this->setGeometry(classedGrid->getGeometry());
      this->setDimensions(classedGrid->getDimensions());
    }
  }
  
  shared_ptr<XdmfArray>
  XdmfCurvilinearGrid::getDimensions()
  {
    return boost::const_pointer_cast<XdmfArray>
      (static_cast<const XdmfCurvilinearGrid &>(*this).getDimensions());
  }
  
  shared_ptr<const XdmfArray>
  XdmfCurvilinearGrid::getDimensions() const
  {
    return ((XdmfCurvilinearGridImpl *)mImpl)->mDimensions;
  }
  
  shared_ptr<XdmfGeometry>
  XdmfCurvilinearGrid::getGeometry()
  {
    return boost::const_pointer_cast<XdmfGeometry>
      (static_cast<const XdmfGrid &>(*this).getGeometry());
  }
  
  void
  XdmfCurvilinearGrid::populateItem(const std::map<std::string, std::string> & itemProperties,
                                    const std::vector<shared_ptr<XdmfItem> > & childItems,
                                    const XdmfCoreReader * const reader)
  {
    XdmfGrid::populateItem(itemProperties, childItems, reader);
  
    for(std::vector<shared_ptr<XdmfItem> >::const_iterator iter =
          childItems.begin();
        iter != childItems.end();
        ++iter) {
      if(shared_ptr<XdmfCurvilinearGrid> curvilinearGrid =
         shared_dynamic_cast<XdmfCurvilinearGrid>(*iter)) {
        ((XdmfCurvilinearGridImpl *)mImpl)->mDimensions = curvilinearGrid->getDimensions();
      }
    }
  }
  
  void
  XdmfCurvilinearGrid::read()
  {
    if (mGridController)
    {
      if (shared_ptr<XdmfCurvilinearGrid> grid = shared_dynamic_cast<XdmfCurvilinearGrid>(mGridController->read()))
      { 
        // Copy stucture from read grid to this grid
        copyGrid(grid);
      }
      else if (shared_ptr<XdmfGrid> grid = shared_dynamic_cast<XdmfGrid>(mGridController->read()))
      {
        XdmfError::message(XdmfError::FATAL, "Error: Grid Type Mismatch");
      }
      else
      {
        XdmfError::message(XdmfError::FATAL, "Error: Invalid Grid Reference");
      }
    }
  }
  
  void
  XdmfCurvilinearGrid::release()
  {
    XdmfGrid::release();
    this->setGeometry(shared_ptr<XdmfGeometry>());
    this->setDimensions(shared_ptr<XdmfArray>());
  }
  
  void
  XdmfCurvilinearGrid::setDimensions(const shared_ptr<XdmfArray> dimensions)
  {
    ((XdmfCurvilinearGridImpl *)mImpl)->mDimensions = dimensions;
    this->setIsChanged(true);
  }
  
  void
  XdmfCurvilinearGrid::setGeometry(const shared_ptr<XdmfGeometry> geometry)
  {
    mGeometry = geometry;
    this->setIsChanged(true);
  }
  
  // C Wrappers
  
  XDMFCURVILINEARGRID * XdmfCurvilinearGridNew2D(unsigned int xNumPoints,
                                                 unsigned int yNumPoints)
  {
    try
    {
      shared_ptr<XdmfCurvilinearGrid> generatedGrid = XdmfCurvilinearGrid::New(xNumPoints, yNumPoints);
      return (XDMFCURVILINEARGRID *)((void *)((XdmfItem *)(new XdmfCurvilinearGrid(*generatedGrid.get()))));
    }
    catch (...)
    {
      shared_ptr<XdmfCurvilinearGrid> generatedGrid = XdmfCurvilinearGrid::New(xNumPoints, yNumPoints);
      return (XDMFCURVILINEARGRID *)((void *)((XdmfItem *)(new XdmfCurvilinearGrid(*generatedGrid.get()))));
    }
  }
  
  XDMFCURVILINEARGRID * XdmfCurvilinearGridNew3D(unsigned int xNumPoints,
                                                 unsigned int yNumPoints,
                                                 unsigned int zNumPoints)
  {
    try
    {
      shared_ptr<XdmfCurvilinearGrid> generatedGrid = XdmfCurvilinearGrid::New(xNumPoints, yNumPoints, zNumPoints);
      return (XDMFCURVILINEARGRID *)((void *)((XdmfItem *)(new XdmfCurvilinearGrid(*generatedGrid.get()))));
    }
    catch (...)
    {
      shared_ptr<XdmfCurvilinearGrid> generatedGrid = XdmfCurvilinearGrid::New(xNumPoints, yNumPoints, zNumPoints);
      return (XDMFCURVILINEARGRID *)((void *)((XdmfItem *)(new XdmfCurvilinearGrid(*generatedGrid.get()))));
    }
  }
  
  XDMFCURVILINEARGRID * XdmfCurvilinearGridNew(XDMFARRAY * numPoints, int * status)
  {
    XDMF_ERROR_WRAP_START(status)
    try
    {
      shared_ptr<XdmfArray> tempArray = shared_ptr<XdmfArray>((XdmfArray *)numPoints, XdmfNullDeleter());
      shared_ptr<XdmfCurvilinearGrid> generatedGrid = XdmfCurvilinearGrid::New(tempArray);
      return (XDMFCURVILINEARGRID *)((void *)((XdmfItem *)(new XdmfCurvilinearGrid(*generatedGrid.get()))));
    }
    catch (...)
    {
      shared_ptr<XdmfArray> tempArray = shared_ptr<XdmfArray>((XdmfArray *)numPoints, XdmfNullDeleter());
      shared_ptr<XdmfCurvilinearGrid> generatedGrid = XdmfCurvilinearGrid::New(tempArray);
      return (XDMFCURVILINEARGRID *)((void *)((XdmfItem *)(new XdmfCurvilinearGrid(*generatedGrid.get()))));
    }
    XDMF_ERROR_WRAP_END(status)
    return NULL;
  }
  
  XDMFARRAY * XdmfCurvilinearGridGetDimensions(XDMFCURVILINEARGRID * grid, int * status)
  {
    XDMF_ERROR_WRAP_START(status)
    try
    {
      XdmfItem * classedPointer = (XdmfItem *)grid;
      XdmfCurvilinearGrid * gridPointer = dynamic_cast<XdmfCurvilinearGrid *>(classedPointer);
      shared_ptr<XdmfArray> generatedArray = gridPointer->getDimensions();
      return (XDMFARRAY *)((void *)generatedArray.get());
    }
    catch (...)
    {
      XdmfItem * classedPointer = (XdmfItem *)grid;
      XdmfCurvilinearGrid * gridPointer = dynamic_cast<XdmfCurvilinearGrid *>(classedPointer);
      shared_ptr<XdmfArray> generatedArray = gridPointer->getDimensions();
      return (XDMFARRAY *)((void *)generatedArray.get());
    }
    XDMF_ERROR_WRAP_END(status)
    return NULL;
  }
  
  XDMFGEOMETRY * XdmfCurvilinearGridGetGeometry(XDMFCURVILINEARGRID * grid)
  {
    XdmfItem * classedPointer = (XdmfItem *)grid;
    XdmfCurvilinearGrid * gridPointer = dynamic_cast<XdmfCurvilinearGrid *>(classedPointer);
    shared_ptr<XdmfGeometry> generatedGeometry = gridPointer->getGeometry();
    return (XDMFGEOMETRY *)((void *)generatedGeometry.get());
  }
  
  void XdmfCurvilinearGridSetDimensions(XDMFCURVILINEARGRID * grid, XDMFARRAY * dimensions, int passControl, int * status)
  {
    XDMF_ERROR_WRAP_START(status)
    XdmfItem * classedPointer = (XdmfItem *)grid;
    XdmfCurvilinearGrid * gridPointer = dynamic_cast<XdmfCurvilinearGrid *>(classedPointer);
    if (passControl) {
      gridPointer->setDimensions(shared_ptr<XdmfArray>((XdmfArray *)dimensions));
    }
    else {
      gridPointer->setDimensions(shared_ptr<XdmfArray>((XdmfArray *)dimensions, XdmfNullDeleter()));
    }
    XDMF_ERROR_WRAP_END(status)
  }
  
  void XdmfCurvilinearGridSetGeometry(XDMFCURVILINEARGRID * grid, XDMFGEOMETRY * geometry, int passControl)
  {
    XdmfItem * classedPointer = (XdmfItem *)grid;
    XdmfCurvilinearGrid * gridPointer = dynamic_cast<XdmfCurvilinearGrid *>(classedPointer);
    if (passControl) {
      gridPointer->setGeometry(shared_ptr<XdmfGeometry>((XdmfGeometry *)geometry));
    }
    else {
      gridPointer->setGeometry(shared_ptr<XdmfGeometry>((XdmfGeometry *)geometry, XdmfNullDeleter()));
    }
  }
  
  XDMF_ITEM_C_CHILD_WRAPPER(XdmfCurvilinearGrid, XDMFCURVILINEARGRID)
  XDMF_GRID_C_CHILD_WRAPPER(XdmfCurvilinearGrid, XDMFCURVILINEARGRID)
  