diff --git a/CMakeLists.txt b/CMakeLists.txt index c3f12ea11df1f961377fd7fadc2cc64ec3391c15..a31965840a3cc8399b2edd29b35f66441170efb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -292,6 +292,7 @@ if(NOT XDMF_BUILD_CORE_ONLY) XdmfGridCollection XdmfGridCollectionType XdmfGridController + XdmfGridTemplate XdmfItemFactory XdmfMap XdmfReader @@ -299,6 +300,7 @@ if(NOT XDMF_BUILD_CORE_ONLY) XdmfRegularGrid XdmfSet XdmfSetType + XdmfTemplate XdmfTime XdmfTopology XdmfTopologyType diff --git a/XdmfGridTemplate.cpp b/XdmfGridTemplate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e67990b54e33f2e341d566506901808f700b149 --- /dev/null +++ b/XdmfGridTemplate.cpp @@ -0,0 +1,975 @@ +/*****************************************************************************/ +/* XDMF */ +/* eXtensible Data Model and Format */ +/* */ +/* Id : XdmfTemplate.cpp */ +/* */ +/* Author: */ +/* Andrew Burns */ +/* andrew.j.burns2@us.army.mil */ +/* US Army Research Laboratory */ +/* Aberdeen Proving Ground, MD */ +/* */ +/* Copyright @ 2013 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 +#include +#include "XdmfArray.hpp" +#include "XdmfCurvilinearGrid.hpp" +#include "XdmfItem.hpp" +#include "XdmfItemFactory.hpp" +#include "XdmfReader.hpp" +#include "XdmfGridCollection.hpp" +#include "XdmfGridCollectionType.hpp" +#include "XdmfGridTemplate.hpp" +#include "XdmfRectilinearGrid.hpp" +#include "XdmfRegularGrid.hpp" +#include "XdmfTemplate.hpp" +#include "XdmfTopology.hpp" +#include "XdmfError.hpp" +#include "XdmfUnstructuredGrid.hpp" +#include "XdmfVisitor.hpp" +#include "XdmfWriter.hpp" + +#include "XdmfSystemUtils.hpp" + +#include + +#include + +shared_ptr +XdmfGridTemplate::New() +{ + shared_ptr p(new XdmfGridTemplate()); + return p; +} + + +XdmfGridTemplate::XdmfGridTemplate() : + XdmfTemplate(), + XdmfGridCollection(), + mTimeCollection(XdmfArray::New()) +{ + mTimeCollection->setName("Time Collection"); +} + +XdmfGridTemplate::XdmfGridTemplate(XdmfGridTemplate & refTemplate) : + XdmfTemplate(refTemplate), + XdmfGridCollection(refTemplate), + mTimeCollection(refTemplate.mTimeCollection) +{ +} + +XdmfGridTemplate::~XdmfGridTemplate() +{ +} + +const std::string XdmfGridTemplate::ItemTag = "Template"; + +unsigned int +XdmfGridTemplate::addStep() +{ + XdmfTemplate::addStep(); + if (shared_dynamic_cast(mBase)->getTime()) { + if (!mTimeCollection->isInitialized()) { + mTimeCollection->read(); + } + mTimeCollection->pushBack(shared_dynamic_cast(mBase)->getTime()->getValue()); + } + return mCurrentStep; +} + +std::map +XdmfGridTemplate::getItemProperties() const +{ + std::map templateProperties = XdmfGridCollection::getItemProperties(); + + templateProperties["BaseType"] = "Grid"; + return templateProperties; +} + +std::string +XdmfGridTemplate::getItemTag() const +{ + return ItemTag; +} + +shared_ptr +XdmfGridTemplate::getTimes() +{ + return mTimeCollection; +} + +shared_ptr +XdmfGridTemplate::getGridCollection(const unsigned int index) +{ + if (mBase) { + if (index < getNumberSteps()) { + this->clearStep(); + this->setStep(index); + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get GridCollection from template without a base"); + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getGridCollection(const unsigned int index) const +{ + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (index != mCurrentStep) + { + XdmfError::message(XdmfError::FATAL, "Error: GridTemplates can not return a constant reference to its base on an index other than the currently loaded one."); + return shared_ptr(); + } + else + { + return grid; + } + } + else { + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getGridCollection(const std::string & Name) +{ + if (mBase) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (grid->getName().compare(Name) == 0) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get GridCollection from template without a base"); + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getGridCollection(const std::string & Name) const +{ + if (mBase) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (grid->getName().compare(Name) == 0) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get GridCollection from template without a base"); + return shared_ptr(); + } +} + +unsigned int +XdmfGridTemplate::getNumberGridCollections() const +{ + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + return this->getNumberSteps(); + } + else { + return 0; + } +} + +void +XdmfGridTemplate::insert(const shared_ptr GridCollection) +{ + XdmfError::message(XdmfError::FATAL, "Error: Attempting to use insert to add an XdmfGridCollection to an XdmfGridTemplate. " + "Use addStep instead of insert to add to an XdmfGridTemplate"); +} + +void +XdmfGridTemplate::removeGridCollection(const unsigned int index) +{ + if (mBase) { + if (index < getNumberSteps()) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + this->removeStep(index); + } + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get GridCollection from template without a base"); + } +} + +void +XdmfGridTemplate::removeGridCollection(const std::string & Name) +{ + XdmfError::message(XdmfError::FATAL, "Error: Removing Grids by name from XdmfGridTemplate is not supported"); +} + +shared_ptr +XdmfGridTemplate::getCurvilinearGrid(const unsigned int index) +{ + if (mBase) { + if (index < getNumberSteps()) { + this->clearStep(); + this->setStep(index); + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get CurvilinearGrid from template without a base"); + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getCurvilinearGrid(const unsigned int index) const +{ + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (index != mCurrentStep) + { + XdmfError::message(XdmfError::FATAL, "Error: GridTemplates can not return a constant reference to its base on an index other than the currently loaded one."); + return shared_ptr(); + } + else + { + return grid; + } + } + else { + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getCurvilinearGrid(const std::string & Name) +{ + if (mBase) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (grid->getName().compare(Name) == 0) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get CurvilinearGrid from template without a base"); + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getCurvilinearGrid(const std::string & Name) const +{ + if (mBase) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (grid->getName().compare(Name) == 0) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get CurvilinearGrid from template without a base"); + return shared_ptr(); + } +} + +unsigned int +XdmfGridTemplate::getNumberCurvilinearGrids() const +{ + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + return this->getNumberSteps(); + } + else { + return 0; + } +} + +void +XdmfGridTemplate::insert(const shared_ptr CurvilinearGrid) +{ + XdmfError::message(XdmfError::FATAL, "Error: Attempting to use insert to add an XdmfCurvilinearGrid to an XdmfGridTemplate. " + "Use addStep instead of insert to add to an XdmfGridTemplate"); +} + +void +XdmfGridTemplate::removeCurvilinearGrid(const unsigned int index) +{ + if (mBase) { + if (index < getNumberSteps()) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + this->removeStep(index); + } + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get CurvilinearGrid from template without a base"); + } +} + +void +XdmfGridTemplate::removeCurvilinearGrid(const std::string & Name) +{ + XdmfError::message(XdmfError::FATAL, "Error: Removing Grids by name from XdmfGridTemplate is not supported"); +} + +shared_ptr +XdmfGridTemplate::getRectilinearGrid(const unsigned int index) +{ + if (mBase) { + if (index < getNumberSteps()) { + this->clearStep(); + this->setStep(index); + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get RectilinearGrid from template without a base"); + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getRectilinearGrid(const unsigned int index) const +{ + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (index != mCurrentStep) + { + XdmfError::message(XdmfError::FATAL, "Error: GridTemplates can not return a constant reference to its base on an index other than the currently loaded one."); + return shared_ptr(); + } + else + { + return grid; + } + } + else { + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getRectilinearGrid(const std::string & Name) +{ + if (mBase) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (grid->getName().compare(Name) == 0) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get RectilinearGrid from template without a base"); + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getRectilinearGrid(const std::string & Name) const +{ + if (mBase) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (grid->getName().compare(Name) == 0) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get RectilinearGrid from template without a base"); + return shared_ptr(); + } +} + +unsigned int +XdmfGridTemplate::getNumberRectilinearGrids() const +{ + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + return this->getNumberSteps(); + } + else { + return 0; + } +} + +void +XdmfGridTemplate::insert(const shared_ptr RectilinearGrid) +{ + XdmfError::message(XdmfError::FATAL, "Error: Attempting to use insert to add a XdmfRectilinearGrid to an XdmfGridTemplate." + "Use addStep instead of insert to add to an XdmfGridTemplate"); +} + +void +XdmfGridTemplate::removeRectilinearGrid(const unsigned int index) +{ + if (mBase) { + if (index < getNumberSteps()) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + this->removeStep(index); + } + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get RectilinearGrid from template without a base"); + } +} + +void +XdmfGridTemplate::removeRectilinearGrid(const std::string & Name) +{ + XdmfError::message(XdmfError::FATAL, "Error: Removing Grids by name from XdmfGridTemplate is not supported"); +} + +shared_ptr +XdmfGridTemplate::getRegularGrid(const unsigned int index) +{ + if (mBase) { + if (index < getNumberSteps()) { + this->clearStep(); + this->setStep(index); + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get RegularGrid from template without a base"); + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getRegularGrid(const unsigned int index) const +{ + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (index != mCurrentStep) + { + XdmfError::message(XdmfError::FATAL, "Error: GridTemplates can not return a constant reference to its base on an index other than the currently loaded one."); + return shared_ptr(); + } + else + { + return grid; + } + } + else { + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getRegularGrid(const std::string & Name) +{ + if (mBase) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (grid->getName().compare(Name) == 0) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get RegularGrid from template without a base"); + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getRegularGrid(const std::string & Name) const +{ + if (mBase) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (grid->getName().compare(Name) == 0) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get RegularGrid from template without a base"); + return shared_ptr(); + } +} + +unsigned int +XdmfGridTemplate::getNumberRegularGrids() const +{ + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + return this->getNumberSteps(); + } + else { + return 0; + } +} + +void +XdmfGridTemplate::insert(const shared_ptr RegularGrid) +{ + XdmfError::message(XdmfError::FATAL, "Error: Attempting to use insert to add an XdmfRegularGrid to an XdmfGridTemplate." + "Use addStep instead of insert to add to an XdmfGridTemplate"); +} + +void +XdmfGridTemplate::removeRegularGrid(const unsigned int index) +{ + if (mBase) { + if (index < getNumberSteps()) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + this->removeStep(index); + } + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get RegularGrid from template without a base"); + } +} + +void +XdmfGridTemplate::removeRegularGrid(const std::string & Name) +{ + XdmfError::message(XdmfError::FATAL, "Error: Removing Grids by name from XdmfGridTemplate is not supported"); +} + +shared_ptr +XdmfGridTemplate::getUnstructuredGrid(const unsigned int index) +{ + if (mBase) { + if (index < getNumberSteps()) { + this->clearStep(); + this->setStep(index); + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get UnstructuredGrid from template without a base"); + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getUnstructuredGrid(const unsigned int index) const +{ + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (index != mCurrentStep) + { + XdmfError::message(XdmfError::FATAL, "Error: GridTemplates can not return a constant reference to its base on an index other than the currently loaded one."); + return shared_ptr(); + } + else + { + return grid; + } + } + else { + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getUnstructuredGrid(const std::string & Name) +{ + if (mBase) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (grid->getName().compare(Name) == 0) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get UnstructuredGrid from template without a base"); + return shared_ptr(); + } +} + +shared_ptr +XdmfGridTemplate::getUnstructuredGrid(const std::string & Name) const +{ + if (mBase) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + if (grid->getName().compare(Name) == 0) { + return grid; + } + else { + return shared_ptr(); + } + } + else { + return shared_ptr(); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get UnstructuredGrid from template without a base"); + return shared_ptr(); + } +} + +unsigned int +XdmfGridTemplate::getNumberUnstructuredGrids() const +{ + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + return this->getNumberSteps(); + } + else { + return 0; + } +} + + +void +XdmfGridTemplate::insert(const shared_ptr UnstructuredGrid) +{ + XdmfError::message(XdmfError::FATAL, "Error: Attempting to use insert to add an XdmfUnstructuredGrid to an XdmfGridTemplate." + "Use addStep instead of insert to add to an XdmfGridTemplate"); +} + +void +XdmfGridTemplate::removeUnstructuredGrid(const unsigned int index) +{ + if (mBase) { + if (index < getNumberSteps()) { + if (shared_ptr grid = + shared_dynamic_cast(mBase)) { + this->removeStep(index); + } + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Attempting to get UnstructuredGrid from template without a base"); + } +} + + +void +XdmfGridTemplate::removeUnstructuredGrid(const std::string & Name) +{ + XdmfError::message(XdmfError::FATAL, "Error: Removing Grids by name from XdmfGridTemplate is not supported"); +} + +void +XdmfGridTemplate::populateItem(const std::map & itemProperties, + const std::vector > & childItems, + const XdmfCoreReader * const reader) +{ + // We are overrriding the populate item of the template and grid collection here + // The template functions internally different from either. + + this->setType(XdmfGridCollectionType::New(itemProperties)); + + // The first child item is the base + mBase = childItems[0]; + mCurrentStep = 0; + + if (childItems.size() > 1) { + for(std::vector >::const_iterator iter = + childItems.begin() + 1; + iter != childItems.end(); + ++iter) { + if(shared_ptr array = shared_dynamic_cast(*iter)) { + if (array->getName().compare("Data Description") == 0) { + // Split description into substrings based on the " character + + if (array->getNumberHeavyDataControllers() > 0 & !mHeavyWriter) { + mHeavyWriter = reader->generateHeavyDataWriter(array->getHeavyDataController(0)->getName(), array->getHeavyDataController(0)->getFilePath()); + } + + array->read(); + + // If a character array, create std::string version? TODO + std::string descriptionString; + if (array->getArrayType() == XdmfArrayType::Int8()) + { + descriptionString = std::string((char *)array->getValuesInternal()); + } + else if (array->getArrayType() == XdmfArrayType::String()) + { + descriptionString = array->getValue(0); + } + + size_t index = descriptionString.find_first_of("\""); + size_t previousIndex = 0; + + if (index != std::string::npos) { + // Removing the prepended " + previousIndex = index + 1; + index = descriptionString.find_first_of("\"", previousIndex); + } + + while (index != std::string::npos) { + std::string type = descriptionString.substr(previousIndex, index - previousIndex); + mDataTypes.push_back(type); + previousIndex = index + 1; + index = descriptionString.find_first_of("\"", previousIndex); + if (index - previousIndex > 0) { + std::string description; + description = descriptionString.substr(previousIndex, index - previousIndex); + mDataDescriptions.push_back(description); + // create controllers here based on the type/description? + // Is array type already filled? + // Potentially call "fillControllers" after populating? + if (index != std::string::npos) { + previousIndex = index + 1; + index = descriptionString.find_first_of("\"", previousIndex); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Type without a description in XdmfTemplate::populateItem"); + } + } + } + else if (array->getName().compare("Time Collection") == 0) { + mTimeCollection = array; + } + else { + mTrackedArrays.push_back(array.get()); + mTrackedArrayDims.push_back(array->getDimensions()); + mTrackedArrayTypes.push_back(array->getArrayType()); + } + } + } + } + mDataControllers.resize(mDataTypes.size()); + if (!mItemFactory) { + mItemFactory = XdmfItemFactory::New(); + } + std::map populateProperties; + if (mHeavyWriter) { + // The heavy writer provides the XMLDir, which is used to get full paths for the controllers + // It is assumed that the files that the controllers reference are in the same directory + // as the file that the writer references + std::string filepath = XdmfSystemUtils::getRealPath(mHeavyWriter->getFilePath()); + size_t index = filepath.find_last_of("/\\"); + filepath = filepath.substr(0, index + 1); + populateProperties["XMLDir"] = filepath; + } + for (unsigned int i = 0; i < mDataDescriptions.size(); ++i) { + populateProperties["Content"] = mDataDescriptions[i]; + std::vector > readControllers = + reader->generateHeavyDataControllers(populateProperties, mTrackedArrayDims[i % mTrackedArrays.size()], mTrackedArrayTypes[i % mTrackedArrays.size()], mDataTypes[i]); + if (readControllers.size() > 0) { + // Heavy data controllers reference the data + for (unsigned int j = 0; j < readControllers.size(); ++j) { + mDataControllers[i].push_back(readControllers[j]); + } + } + } + // Compare the first set of controllers to the size of the first array + unsigned int controllerTotal = 0; + for (unsigned int i = 0; i < mDataControllers[0].size(); ++i) + { + controllerTotal += mDataControllers[0][i]->getSize(); + } + // If the array is smaller, set the writer to append. + if (controllerTotal > mTrackedArrays[0]->getSize()) + { + mHeavyWriter->setMode(XdmfHeavyDataWriter::Append); + mNumSteps = controllerTotal / mTrackedArrays[0]->getSize(); + } + else { + mNumSteps = mDataControllers.size() / mTrackedArrays.size(); + } +} + +void +XdmfGridTemplate::removeStep(unsigned int stepId) +{ + if (stepId < this->getNumberSteps()) { + XdmfTemplate::removeStep(stepId); + mTimeCollection->erase(stepId); + } + this->setIsChanged(true); +} + +void +XdmfGridTemplate::setBase(shared_ptr newBase) +{ + if (shared_ptr grid = shared_dynamic_cast(newBase)) { + XdmfTemplate::setBase(newBase); + } + else { + XdmfError::message(XdmfError::FATAL, "Error: XdmfGridTemplate::setBase," + " attempting to set a Base that is not grid type."); + } +} + +void +XdmfGridTemplate::setStep(unsigned int stepId) +{ + XdmfTemplate::setStep(stepId); + if (mTimeCollection->getSize() >= stepId) { + if (!mTimeCollection->isInitialized()) { + mTimeCollection->read(); + } + if (shared_dynamic_cast(mBase)->getTime()) { + shared_dynamic_cast(mBase)->getTime()->setValue(mTimeCollection->getValue(stepId)); + } + else { + shared_dynamic_cast(mBase)->setTime(XdmfTime::New(mTimeCollection->getValue(stepId))); + } + } +} + +void +XdmfGridTemplate::setStep(shared_ptr time) +{ + if (mTimeCollection->getSize() > 0) + { + if (!mTimeCollection->isInitialized()) { + mTimeCollection->read(); + } + unsigned int index = 0; + while (index < mTimeCollection->getSize() && + time->getValue() != mTimeCollection->getValue(index)) + { + ++index; + } + if (index < mTimeCollection->getSize()) + { + this->setStep(index); + } + } +} + +void +XdmfGridTemplate::traverse(const shared_ptr visitor) +{ + // We are only using the template traverse + // since the grid data is only held in the Base + if (mTimeCollection->getSize() > 0) + { + this->setType(XdmfGridCollectionType::Temporal()); + } + else + { + this->setType(XdmfGridCollectionType::Spatial()); + } + XdmfTemplate::traverse(visitor); + mTimeCollection->accept(visitor); +} + +XDMF_ITEM_C_CHILD_WRAPPER(XdmfGridTemplate, XDMFGRIDTEMPLATE) diff --git a/XdmfGridTemplate.hpp b/XdmfGridTemplate.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b9b203a8178d1081bb1acfd100912545fd7dfb91 --- /dev/null +++ b/XdmfGridTemplate.hpp @@ -0,0 +1,224 @@ +/*****************************************************************************/ +/* XDMF */ +/* eXtensible Data Model and Format */ +/* */ +/* Id : XdmfTemplate.hpp */ +/* */ +/* Author: */ +/* Andrew Burns */ +/* andrew.j.burns2@us.army.mil */ +/* US Army Research Laboratory */ +/* Aberdeen Proving Ground, MD */ +/* */ +/* Copyright @ 2013 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. */ +/* */ +/*****************************************************************************/ + +#ifndef XDMFGRIDTEMPLATE_HPP_ +#define XDMFGRIDTEMPLATE_HPP_ + +// C Compatible Includes +#include "Xdmf.hpp" +#include "XdmfItem.hpp" +#include "XdmfGridCollection.hpp" +#include "XdmfItemFactory.hpp" +#include "XdmfTemplate.hpp" +#include "XdmfArray.hpp" +#include "XdmfHeavyDataWriter.hpp" + +#ifdef __cplusplus + +// Includes + +/** + * @brief Defines a template that can be filled with multiple sets of data. + * + * An XdmfTemplate defines a structure. The arrays within that structure + * are stored if they are not initialized when the structure is first set. + * Steps can then be added and references to heavy data are produced and + * stored for later retrieval. + * + * This effectively lets an object have several variations with different + * contained data. + */ +class XDMF_EXPORT XdmfGridTemplate : public XdmfTemplate, + public XdmfGridCollection { + +public: + + /** + * Creates a new instance of the XdmfTemplate object + * + * @return A constructed XdmfTemplate object. + */ + static shared_ptr New(); + + virtual ~XdmfGridTemplate(); + + LOKI_DEFINE_VISITABLE(XdmfGridTemplate, XdmfGrid); + static const std::string ItemTag; + + /** + * Writes all tracked arrays to heavy data via the provided + * heavy data writer then stores the heavy data descriptions. + * + * @return The ID of the step that was added + */ + virtual unsigned int addStep(); + + std::map getItemProperties() const; + + std::string getItemTag() const; + + using XdmfGrid::insert; + + // Overriding the parent versions so that all of these reference the Base item + // instead of the template + + virtual shared_ptr getTimes(); + + virtual shared_ptr getGridCollection(const unsigned int index); + + virtual shared_ptr getGridCollection(const unsigned int index) const; + + virtual shared_ptr getGridCollection(const std::string & Name); + + virtual shared_ptr getGridCollection(const std::string & Name) const; + + virtual unsigned int getNumberGridCollections() const; + + virtual void insert(const shared_ptr GridCollection); + + virtual void removeGridCollection(const unsigned int index); + + virtual void removeGridCollection(const std::string & Name); + + virtual shared_ptr getCurvilinearGrid(const unsigned int index); + + virtual shared_ptr getCurvilinearGrid(const unsigned int index) const; + + virtual shared_ptr getCurvilinearGrid(const std::string & Name); + + virtual shared_ptr getCurvilinearGrid(const std::string & Name) const; + + virtual unsigned int getNumberCurvilinearGrids() const; + + virtual void insert(const shared_ptr CurvilinearGrid); + + virtual void removeCurvilinearGrid(const unsigned int index); + + virtual void removeCurvilinearGrid(const std::string & Name); + + virtual shared_ptr getRectilinearGrid(const unsigned int index); + + virtual shared_ptr getRectilinearGrid(const unsigned int index) const; + + virtual shared_ptr getRectilinearGrid(const std::string & Name); + + virtual shared_ptr getRectilinearGrid(const std::string & Name) const; + + virtual unsigned int getNumberRectilinearGrids() const; + + virtual void insert(const shared_ptr RectilinearGrid); + + virtual void removeRectilinearGrid(const unsigned int index); + + virtual void removeRectilinearGrid(const std::string & Name); + + virtual shared_ptr getRegularGrid(const unsigned int index); + + virtual shared_ptr getRegularGrid(const unsigned int index) const; + + virtual shared_ptr getRegularGrid(const std::string & Name); + + virtual shared_ptr getRegularGrid(const std::string & Name) const; + + virtual unsigned int getNumberRegularGrids() const; + + virtual void insert(const shared_ptr RegularGrid); + + virtual void removeRegularGrid(const unsigned int index); + + virtual void removeRegularGrid(const std::string & Name); + + virtual shared_ptr getUnstructuredGrid(const unsigned int index); + + virtual shared_ptr getUnstructuredGrid(const unsigned int index) const; + + virtual shared_ptr getUnstructuredGrid(const std::string & Name); + + virtual shared_ptr getUnstructuredGrid(const std::string & Name) const; + + virtual unsigned int getNumberUnstructuredGrids() const; + + virtual void insert(const shared_ptr UnstructuredGrid); + + virtual void removeUnstructuredGrid(const unsigned int index); + + virtual void removeUnstructuredGrid(const std::string & Name); + + /** + * + */ + virtual void removeStep(unsigned int stepId); + + virtual void setBase(shared_ptr newBase); + + /** + * Reads in the heavy data associated with the provided step id. + * + * @param stepId The id of the step whose heavy data + * is to be read in from file + */ + void setStep(unsigned int stepId); + + void setStep(shared_ptr time); + + void traverse(const shared_ptr visitor); + + XdmfGridTemplate(XdmfGridTemplate &); + +protected: + + XdmfGridTemplate(); + + virtual void + populateItem(const std::map & itemProperties, + const std::vector > & childItems, + const XdmfCoreReader * const reader); + + shared_ptr mTimeCollection; + +private: + + XdmfGridTemplate(const XdmfGridTemplate &); // Not implemented. + void operator=(const XdmfGridTemplate &); // Not implemented. + +}; + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// C wrappers go here + +struct XDMFGRIDTEMPLATE; // Simply as a typedef to ensure correct typing +typedef struct XDMFGRIDTEMPLATE XDMFGRIDTEMPLATE; + +XDMF_ITEM_C_CHILD_DECLARE(XdmfGridTemplate, XDMFGRIDTEMPLATE, XDMF) + +#ifdef __cplusplus +} +#endif + + +#endif /* XDMFGRIDTEMPLATE_HPP_ */ diff --git a/XdmfItemFactory.cpp b/XdmfItemFactory.cpp index 6ac3258806c4a6a244495b457c6c86d7d5254af1..7642209690edbc096f2ef72bf5af09c1d4b72919 100644 --- a/XdmfItemFactory.cpp +++ b/XdmfItemFactory.cpp @@ -32,6 +32,7 @@ #include "XdmfGeometryType.hpp" #include "XdmfGraph.hpp" #include "XdmfGridCollection.hpp" +#include "XdmfGridTemplate.hpp" #include "XdmfInformation.hpp" #include "XdmfItemFactory.hpp" #include "XdmfAggregate.hpp" @@ -40,6 +41,7 @@ #include "XdmfRegularGrid.hpp" #include "XdmfSet.hpp" #include "XdmfSparseMatrix.hpp" +#include "XdmfTemplate.hpp" #include "XdmfTime.hpp" #include "XdmfTopology.hpp" #include "XdmfUnstructuredGrid.hpp" @@ -230,6 +232,22 @@ XdmfItemFactory::createItem(const std::string & itemTag, else if(itemTag.compare(XdmfSparseMatrix::ItemTag) == 0) { return XdmfSparseMatrix::New(0, 0); } + else if (itemTag.compare(XdmfTemplate::ItemTag) == 0) { + std::map::const_iterator type = + itemProperties.find("BaseType"); + if(type == itemProperties.end()) { + return XdmfTemplate::New(); + } + else { + if (type->second.compare("Grid") == 0) { + return XdmfGridTemplate::New(); + } + else { + return XdmfTemplate::New(); + } + } + return XdmfTemplate::New(); + } else if(itemTag.compare(XdmfTime::ItemTag) == 0) { return XdmfTime::New(); } diff --git a/XdmfTemplate.cpp b/XdmfTemplate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b9c19af52e9d6f92ba75fe154308f3d8a51cadf8 --- /dev/null +++ b/XdmfTemplate.cpp @@ -0,0 +1,1244 @@ +/*****************************************************************************/ +/* XDMF */ +/* eXtensible Data Model and Format */ +/* */ +/* Id : XdmfTemplate.cpp */ +/* */ +/* Author: */ +/* Andrew Burns */ +/* andrew.j.burns2@us.army.mil */ +/* US Army Research Laboratory */ +/* Aberdeen Proving Ground, MD */ +/* */ +/* Copyright @ 2013 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 +#include +#include +#include +#include "XdmfArray.hpp" +#include "XdmfHDF5Controller.hpp" +#include "XdmfBinaryController.hpp" +#include "XdmfItem.hpp" +#include "XdmfItemFactory.hpp" +#include "XdmfReader.hpp" +#include "XdmfTemplate.hpp" +#include "XdmfError.hpp" +#include "XdmfVisitor.hpp" +#include "XdmfWriter.hpp" + +#include "XdmfSystemUtils.hpp" + +#include + +#include + +std::vector > +getStepControllers(unsigned int stepId, + std::vector stepDims, + std::vector > datasetControllers) +{ + std::vector > returnVector; + if (datasetControllers.size() > 0) + { + unsigned int sizePerStep = 1; + for (unsigned int i = 0; i < stepDims.size(); ++i) + { + sizePerStep *= stepDims[i]; + } +// unsigned int offset = (sizePerStep * stepId); +// unsigned int offsetStepsRemaining = 0; + unsigned int offset = 0; + unsigned int offsetStepsRemaining = stepId; + // grabbing the subset is a little different for each type + // Right now we assume controllers are of the same type + unsigned int controllerIndex = 0; + unsigned int sizeRemaining = sizePerStep; + unsigned int arrayoffset = 0; + while (sizeRemaining > 0) + { +//printf("sizeRemaining = %u\n", sizeRemaining); + // We don't reset the controller index between runs of the while loop + // On iterations after the first it should only execute the loop once + // because offset is set to 0 + while (controllerIndex < datasetControllers.size()) + { +//printf("offset = %u\n", offset); +//printf("%u >= %u\n", offset, datasetControllers[controllerIndex]->getSize()); + //Iterate until we find the controller that the step starts in + if (offset >= datasetControllers[controllerIndex]->getSize()) + { + offset -= datasetControllers[controllerIndex]->getSize(); + ++controllerIndex; + } + else + { + if (offsetStepsRemaining == 0) + { + // offset is within the current controller + break; + } + else + { + // There are steps left to offset +//printf("accounting for step %d\n", offsetStepsRemaining); + offset += sizePerStep; + --offsetStepsRemaining; + } + } + } +//printf("final offset = %u\n", offset); + std::vector newDimVector; + std::vector newStarts; +//printf("after creating dim vector but before filling it\n"); +//printf("%d < %d\n", controllerIndex, datasetControllers.size()); +//printf("size left %d\n", sizeRemaining); + if (offset + sizeRemaining <= datasetControllers[controllerIndex]->getSize()) + { +//printf("step is entirely in the controller\n"); + // step is entirely within this controller + newStarts.push_back(offset + datasetControllers[controllerIndex]->getStart()[0]); // TODO multidim version + newDimVector.push_back(sizeRemaining); + sizeRemaining = 0; + } + else + { +//printf("step is partially in the controller\n"); + if (controllerIndex + 1 >= datasetControllers.size()) { + // Error, step doesn't fit in the data set provided + XdmfError::message(XdmfError::FATAL, "Error: Step does not fit in data step provided"); + } + // step is partially in this controller + newDimVector.push_back(sizeRemaining - + (sizeRemaining - (datasetControllers[controllerIndex]->getSize() - offset))); + newStarts.push_back(offset+datasetControllers[controllerIndex]->getStart()[0]); // TODO multidim version + sizeRemaining -= newDimVector[0]; + } +//printf("size for other controllers %d\n", sizeRemaining); +//printf("before creating the new controller\n"); + // Using the remaining space in the controller + // Slightly differen creation method for each controller + if (datasetControllers[0]->getName().compare("Binary") == 0) { + shared_ptr createdController = + XdmfBinaryController::New(datasetControllers[0]->getFilePath(), + datasetControllers[0]->getType(), + shared_dynamic_cast( + datasetControllers[0])->getEndian(), + newStarts[0], + newDimVector); + returnVector.push_back(createdController); + } + else if (datasetControllers[0]->getName().compare("HDF") == 0) { + // TODO + // The writer should only write to contiguous sets when in this mode. + // A user would need to do something custom to foul this up. + std::vector newStrides; + newStrides.push_back(1); + shared_ptr createdController = + XdmfHDF5Controller::New(datasetControllers[controllerIndex]->getFilePath(), + shared_dynamic_cast( + datasetControllers[controllerIndex])->getDataSetPath(), + datasetControllers[0]->getType(), + newStarts, + newStrides, + newDimVector, + shared_dynamic_cast( + datasetControllers[controllerIndex])->getDataspaceDimensions()); + returnVector.push_back(createdController); + } +//printf("after creating the new controller\n"); + returnVector[returnVector.size()-1]->setArrayOffset(arrayoffset); + arrayoffset += returnVector[returnVector.size()-1]->getSize(); + offset = 0; + ++controllerIndex; + // Starts at the beggining of the next controller + } + } +/* +printf("size of return vector = %d\n", returnVector.size()); +for (unsigned int i = 0; i < returnVector.size(); ++i) +{ + shared_ptr currentController = shared_dynamic_cast(returnVector[i]); +assert(currentController); + printf("file = %s\n", currentController->getFilePath().c_str()); + printf("dataset = %s\n", currentController->getDataSetPath().c_str()); + printf("start = %u\n", currentController->getStart()[0]); + printf("dimension = %u\n", currentController->getDimensions()[0]); + printf("dataspace = %u\n", currentController->getDataspaceDimensions()[0]); +} +*/ + return returnVector; +} + +std::vector > +getControllersExcludingStep(unsigned int stepId, + std::vector stepDims, + std::vector > datasetControllers) +{ + std::vector > returnVector; + if (datasetControllers.size() > 0) + { + unsigned int sizePerStep = 1; + for (unsigned int i = 0; i < stepDims.size(); ++i) + { + sizePerStep *= stepDims[i]; + } + unsigned int offset = sizePerStep * stepId; + unsigned int sizeRemaining = sizePerStep; +//printf("base offset = %u\nstarting size remaining = %u\ncutting from %u controllers\n", offset, sizeRemaining, datasetControllers.size()); + // grabbing the subset is a little different for each type + // Right now we assume controllers are of the same type + for (unsigned int controllerIndex = 0; controllerIndex < datasetControllers.size(); ++controllerIndex) + { +//printf("offset = %u out of controller size %u\n", offset, datasetControllers[controllerIndex]->getSize()); + if (offset >= datasetControllers[controllerIndex]->getSize()) + { + // The removed step isn't in the controller provided + // Simply add it back into the return set + returnVector.push_back(datasetControllers[controllerIndex]); + // then subtract the size from the offset + offset -= datasetControllers[controllerIndex]->getSize(); + } + else + { + // The removed step is inside the controller provided + if (offset > 0) + { +//printf("removed step is inside this controller\n"); + // If offset is greater than zero the controller has a section chopped off the front + std::vector newDim; + newDim.push_back(offset); + // Dataspace is the same + // stride is the same + // start is the same + // TODO dims is reduced to just cover the offset size + if (datasetControllers[controllerIndex]->getName().compare("Binary") == 0) { + shared_ptr createdController = + XdmfBinaryController::New(datasetControllers[controllerIndex]->getFilePath(), + datasetControllers[controllerIndex]->getType(), + shared_dynamic_cast( + datasetControllers[controllerIndex])->getEndian(), + shared_dynamic_cast( + datasetControllers[controllerIndex])->getSeek(), + datasetControllers[controllerIndex]->getStart(), + datasetControllers[controllerIndex]->getStride(), + newDim, + datasetControllers[controllerIndex]->getDataspaceDimensions()); + returnVector.push_back(createdController); + } + else if (datasetControllers[controllerIndex]->getName().compare("HDF") == 0) { + // TODO + // The writer should only write to contiguous sets when in this mode. + // A user would need to do something custom to foul this up. + shared_ptr createdController = + XdmfHDF5Controller::New(datasetControllers[controllerIndex]->getFilePath(), + shared_dynamic_cast( + datasetControllers[controllerIndex])->getDataSetPath(), + datasetControllers[controllerIndex]->getType(), + datasetControllers[controllerIndex]->getStart(), + datasetControllers[controllerIndex]->getStride(), + newDim, + shared_dynamic_cast( + datasetControllers[controllerIndex])->getDataspaceDimensions()); + returnVector.push_back(createdController); + } + // These are the stats for the first half of the dataset + if (sizeRemaining <= datasetControllers[controllerIndex]->getSize() - offset) + { + // The controller is large enough to need to be split into two controllers + std::vector newStart; //TODO we're assuming one dim for now + newStart.push_back(datasetControllers[controllerIndex]->getStart()[0] +sizeRemaining + offset); + std::vector newDim; + newDim.push_back(datasetControllers[controllerIndex]->getSize() - (sizeRemaining + offset)); + // These are the stats of the second controller + sizeRemaining = 0; + if (datasetControllers[controllerIndex]->getName().compare("Binary") == 0) { + shared_ptr createdController = + XdmfBinaryController::New(datasetControllers[controllerIndex]->getFilePath(), + datasetControllers[controllerIndex]->getType(), + shared_dynamic_cast( + datasetControllers[controllerIndex])->getEndian(), + shared_dynamic_cast( + datasetControllers[controllerIndex])->getSeek(), + newStart, + datasetControllers[controllerIndex]->getStride(), + newDim, + datasetControllers[controllerIndex]->getDataspaceDimensions()); + returnVector.push_back(createdController); + } + else if (datasetControllers[controllerIndex]->getName().compare("HDF") == 0) { + // TODO + // The writer should only write to contiguous sets when in this mode. + // A user would need to do something custom to foul this up. + shared_ptr createdController = + XdmfHDF5Controller::New(datasetControllers[controllerIndex]->getFilePath(), + shared_dynamic_cast( + datasetControllers[controllerIndex])->getDataSetPath(), + datasetControllers[controllerIndex]->getType(), + newStart, + datasetControllers[controllerIndex]->getStride(), + newDim, + shared_dynamic_cast( + datasetControllers[controllerIndex])->getDataspaceDimensions()); + returnVector.push_back(createdController); + } + } + else { + // The controller only contains part of the dataset + sizeRemaining -= (datasetControllers[controllerIndex]->getSize() - offset); + } + offset = 0; + } + else + { + // in the case of 0 offset, we either need to trim from the front or just use the whole controller + if (sizeRemaining > 0) + { + if (sizeRemaining < datasetControllers[controllerIndex]->getSize()) + { + std::vector newStart; + newStart.push_back(sizeRemaining); + std::vector newDim; + newDim.push_back(datasetControllers[controllerIndex]->getSize() - sizeRemaining); + sizeRemaining = 0; + if (datasetControllers[controllerIndex]->getName().compare("Binary") == 0) { + shared_ptr createdController = + XdmfBinaryController::New(datasetControllers[controllerIndex]->getFilePath(), + datasetControllers[controllerIndex]->getType(), + shared_dynamic_cast( + datasetControllers[controllerIndex])->getEndian(), + shared_dynamic_cast( + datasetControllers[controllerIndex])->getSeek(), + newStart, + datasetControllers[controllerIndex]->getStride(), + newDim, + datasetControllers[controllerIndex]->getDataspaceDimensions()); + returnVector.push_back(createdController); + } + else if (datasetControllers[controllerIndex]->getName().compare("HDF") == 0) { + // TODO + // The writer should only write to contiguous sets when in this mode. + // A user would need to do something custom to foul this up. + shared_ptr createdController = + XdmfHDF5Controller::New(datasetControllers[controllerIndex]->getFilePath(), + shared_dynamic_cast( + datasetControllers[controllerIndex])->getDataSetPath(), + datasetControllers[controllerIndex]->getType(), + newStart, + datasetControllers[controllerIndex]->getStride(), + newDim, + shared_dynamic_cast( + datasetControllers[controllerIndex])->getDataspaceDimensions()); + returnVector.push_back(createdController); + } + } + else { + sizeRemaining -= datasetControllers[controllerIndex]->getSize(); + } + } + else + { + // Just use the current controller + returnVector.push_back(datasetControllers[controllerIndex]); + } + } + } + } + } + return returnVector; +} + +class XdmfArrayGatherer : public XdmfVisitor, public Loki::Visitor +{ + public: + + static shared_ptr + New(std::vector * storageVector) + { + shared_ptr p(new XdmfArrayGatherer(storageVector)); + return p; + } + + ~XdmfArrayGatherer() + { + } + + virtual void + visit(XdmfArray & array, + const shared_ptr visitor) + { + ++mDepth; + if (!array.isInitialized()) + { +// mStorage->push_back(&array); + mArrayCollection.insert(&array); + } + array.traverse(visitor); + --mDepth; + if (mDepth == 0) + { + moveToStorage(); + } + } + + virtual void + visit(XdmfItem & item, + const shared_ptr visitor) + { + ++mDepth; + item.traverse(visitor); + --mDepth; + if (mDepth == 0) + { + moveToStorage(); + } + } + + void + moveToStorage() + { + for (std::set::iterator iter = mArrayCollection.begin(); + iter != mArrayCollection.end(); + ++iter) + { + mStorage->push_back(*iter); + } + } + + private: + + XdmfArrayGatherer(std::vector * storageVector) : + mDepth(0), + mStorage(storageVector) + { + } + + unsigned int mDepth; + std::set mArrayCollection; + std::vector * mStorage; +}; + +shared_ptr +XdmfTemplate::New() +{ + shared_ptr p(new XdmfTemplate()); + return p; +} + + +XdmfTemplate::XdmfTemplate() : + mHeavyWriter(shared_ptr()), + mBase(shared_ptr()), + mCurrentStep(-1), + mNumSteps(0), + mItemFactory(shared_ptr()) +{ +} + +XdmfTemplate::XdmfTemplate(XdmfTemplate & refTemplate) : + XdmfItem(refTemplate), + mBase(refTemplate.mBase), + mCurrentStep(refTemplate.mCurrentStep), + mNumSteps(refTemplate.mNumSteps), + mItemFactory(refTemplate.mItemFactory) +{ +} + +XdmfTemplate::~XdmfTemplate() +{ +} + +const std::string XdmfTemplate::ItemTag = "Template"; + +unsigned int +XdmfTemplate::addStep() +{ + mCurrentStep = this->getNumberSteps(); + std::stringstream datastream; + if (mTrackedArrays.size() < 1) { + XdmfError::message(XdmfError::FATAL, + "Error: XdmfTemplate attempting to add a step when no arrays are tracked"); + } + for (unsigned int arrayIndex = 0; arrayIndex < mTrackedArrays.size(); ++arrayIndex) { + if (mTrackedArrayTypes.size() < mTrackedArrays.size()){ + mTrackedArrayTypes.resize(mTrackedArrays.size()); + } + if (mTrackedArrayDims.size() < mTrackedArrays.size()){ + mTrackedArrayDims.resize(mTrackedArrays.size()); + } + if (!mTrackedArrayTypes[arrayIndex]) { + mTrackedArrayTypes[arrayIndex] = mTrackedArrays[arrayIndex]->getArrayType(); + } + if (mTrackedArrayDims[arrayIndex].size() == 0) { + mTrackedArrayDims[arrayIndex] = mTrackedArrays[arrayIndex]->getDimensions(); + } + // Write the tracked arrays to heavy data if they aren't already + if (mHeavyWriter) { + bool revertToAppend = false; + if (mHeavyWriter->getMode() == XdmfHeavyDataWriter::Append) { + // Set to original heavy data controllers for append + if (mDataControllers.size() > arrayIndex) + { + if (mDataControllers[arrayIndex].size() > 0) + { + while (mTrackedArrays[arrayIndex]->getNumberHeavyDataControllers() > 0) { + mTrackedArrays[arrayIndex]->removeHeavyDataController(0); + } + for (unsigned int i = 0; i < mDataControllers[arrayIndex].size(); ++i) + { + mTrackedArrays[arrayIndex]->insert(mDataControllers[arrayIndex][i]); + } + } + } + else + { + // Creating new Dataset + // Set to default mode so that it doesn't overlap + mHeavyWriter->setMode(XdmfHeavyDataWriter::Default); + revertToAppend = true; + } + } + else if (mHeavyWriter->getMode() == XdmfHeavyDataWriter::Hyperslab) { + // Use the controller that references the subset that will be overwritten + if (!(arrayIndex < mDataControllers.size())) + { + // When in overwrite mode the dataset must be preallocated + XdmfError::message(XdmfError::FATAL, "Error: Heavy Data dataset must be preallocated " + "to use Hyperslab mode Templates"); + } + std::vector > overwriteControllers = + getStepControllers(mCurrentStep, mTrackedArrayDims[arrayIndex], mDataControllers[arrayIndex]); + mTrackedArrays[arrayIndex]->setHeavyDataController(overwriteControllers); + } + mTrackedArrays[arrayIndex]->accept(mHeavyWriter); + if (revertToAppend) + { + mHeavyWriter->setMode(XdmfHeavyDataWriter::Append); + } + } + datastream.str(std::string()); + for (unsigned int controllerIndex = 0; controllerIndex < mTrackedArrays[arrayIndex]->getNumberHeavyDataControllers(); ++controllerIndex) { + // TODO throw error if controller types don't match + // For each heavy data controller + std::string writerPath = XdmfSystemUtils::getRealPath(mHeavyWriter->getFilePath()); + std::string heavyDataPath = + mTrackedArrays[arrayIndex]->getHeavyDataController(controllerIndex)->getFilePath(); + size_t index = heavyDataPath.find_last_of("/\\"); + if(index != std::string::npos) { + // If path is not a folder + // put the directory path into this variable + const std::string heavyDataDir = heavyDataPath.substr(0, index + 1); + // If the directory is in the XML File Path + if(writerPath.find(heavyDataDir) == 0) { + heavyDataPath = + heavyDataPath.substr(heavyDataDir.size(), + heavyDataPath.size() - heavyDataDir.size()); + // Pull the file off of the end and place it in the DataPath + } + // Otherwise the full path is required + } + datastream << heavyDataPath; + datastream << mTrackedArrays[arrayIndex]->getHeavyDataController(controllerIndex)->getDescriptor(); + datastream << "|"; + for (unsigned int i = 0; i < mTrackedArrays[arrayIndex]->getHeavyDataController(controllerIndex)->getDimensions().size(); ++i) { + datastream << mTrackedArrays[arrayIndex]->getHeavyDataController(controllerIndex)->getDimensions()[i]; + if (i < mTrackedArrays[arrayIndex]->getHeavyDataController(controllerIndex)->getDimensions().size() - 1) { + datastream << " "; + } + } + if (controllerIndex + 1 < mTrackedArrays[arrayIndex]->getNumberHeavyDataControllers()) { + datastream << "|"; + } + } + if (mHeavyWriter) { + if (mHeavyWriter->getMode() == XdmfHeavyDataWriter::Append) { + if (mDataControllers.size() > arrayIndex) + { + // If controllers already exist + // Store the overarching controllers again + mDataControllers[arrayIndex].clear(); + for (unsigned int i = 0; i < mTrackedArrays[arrayIndex]->getNumberHeavyDataControllers(); ++i) + { + mDataControllers[arrayIndex].push_back(mTrackedArrays[arrayIndex]->getHeavyDataController(i)); + } + // Clear controllers from the array + while (mTrackedArrays[arrayIndex]->getNumberHeavyDataControllers() > 0) { + mTrackedArrays[arrayIndex]->removeHeavyDataController(0); + } + // If append set controller to the correct subsection of the whole + std::vector > readControllers = getStepControllers(mCurrentStep, mTrackedArrayDims[arrayIndex], mDataControllers[arrayIndex]); + mTrackedArrays[arrayIndex]->setHeavyDataController(readControllers); + // Replace with updated description + mDataDescriptions[arrayIndex] = datastream.str(); + } + else + { + // If a new dataset, as normal + mDataControllers.push_back(std::vector >()); + for (unsigned int i = 0; i < mTrackedArrays[arrayIndex]->getNumberHeavyDataControllers(); ++i) { + mDataControllers[mDataControllers.size()-1].push_back((mTrackedArrays[arrayIndex]->getHeavyDataController(i))); + } + if (mTrackedArrays[arrayIndex]->getNumberHeavyDataControllers() > 0) { + mDataTypes.push_back(mTrackedArrays[arrayIndex]->getHeavyDataController(0)->getName()); + mDataDescriptions.push_back(datastream.str()); + } + } + } + else if (mHeavyWriter->getMode() == XdmfHeavyDataWriter::Hyperslab) { + // Hyperslab is already storing the base controller + // So nothing is done here, the controller should already be pointing to the correct location + // TODO, to what the file index was before the add, as opposed to 0 + mHeavyWriter->setFileIndex(0); + } + else { + mDataControllers.push_back(std::vector >()); + for (unsigned int i = 0; i < mTrackedArrays[arrayIndex]->getNumberHeavyDataControllers(); ++i) { + mDataControllers[mDataControllers.size()-1].push_back((mTrackedArrays[arrayIndex]->getHeavyDataController(i))); + } + if (mTrackedArrays[arrayIndex]->getNumberHeavyDataControllers() > 0) { + mDataTypes.push_back(mTrackedArrays[arrayIndex]->getHeavyDataController(0)->getName()); + mDataDescriptions.push_back(datastream.str()); + } + } + } + else { + mDataControllers.push_back(std::vector >()); + mDataTypes.push_back("XML"); + mDataDescriptions.push_back(mTrackedArrays[arrayIndex]->getValuesString()); + } + } + ++mNumSteps; + this->setIsChanged(true); + return mCurrentStep; +} + +void +XdmfTemplate::clearStep() +{ + for (unsigned int i = 0; i < mTrackedArrays.size(); ++i) { + mTrackedArrays[i]->release(); + while (mTrackedArrays[i]->getNumberHeavyDataControllers() > 0) { + mTrackedArrays[i]->removeHeavyDataController(0); + } + } + mCurrentStep = -1; +} + +shared_ptr +XdmfTemplate::getBase() +{ + return mBase; +} + +shared_ptr +XdmfTemplate::getHeavyDataWriter() +{ + return mHeavyWriter; +} + +std::map +XdmfTemplate::getItemProperties() const +{ + std::map templateProperties; +/* + std::stringstream value; + value << mValue; + timeProperties.insert(std::make_pair("Value", value.str())); +*/ + return templateProperties; +} + +std::string +XdmfTemplate::getItemTag() const +{ + return ItemTag; +} + +unsigned int +XdmfTemplate::getNumberSteps() const +{ + return mNumSteps; +} + +unsigned int +XdmfTemplate::getNumberTrackedArrays() const +{ + return mTrackedArrays.size(); +} + +XdmfArray * +XdmfTemplate::getTrackedArray(unsigned int index) +{ + return mTrackedArrays[index]; +} + + +void +XdmfTemplate::populateItem(const std::map & itemProperties, + const std::vector > & childItems, + const XdmfCoreReader * const reader) +{ + XdmfItem::populateItem(itemProperties, childItems, reader); + + // The first child item is the base + mBase = childItems[0]; + mCurrentStep = 0; + + std::string referenceHDF5File = ""; + + if (childItems.size() > 1) { + for(std::vector >::const_iterator iter = + childItems.begin() + 1; + iter != childItems.end(); + ++iter) { + if(shared_ptr array = shared_dynamic_cast(*iter)) { + // Pull hdf5 reference data from the first provided array + if (array->getNumberHeavyDataControllers() > 0 & !mHeavyWriter) { + mHeavyWriter = reader->generateHeavyDataWriter(array->getHeavyDataController(0)->getName(), array->getHeavyDataController(0)->getFilePath()); + } + if (array->getName().compare("Data Description") == 0) { + // Split description into substrings based on the " character + array->read(); + + std::string descriptionString; + if (array->getArrayType() == XdmfArrayType::Int8()) + { + descriptionString = std::string((char *)array->getValuesInternal()); + } + else if (array->getArrayType() == XdmfArrayType::String()) + { + std::stringstream descriptionstream; + for (unsigned int i = 0; i < array->getSize(); ++i) + { + descriptionstream << array->getValue(i); + if (i < array->getSize() - 1) + { + descriptionstream << '|'; + } + } + descriptionString = descriptionstream.str(); + } + + size_t index = descriptionString.find_first_of("\""); + size_t previousIndex = 0; + + if (index != std::string::npos) { + // Removing the prepended " + previousIndex = index + 1; + index = descriptionString.find_first_of("\"", previousIndex); + } + + while (index != std::string::npos) { + std::string type = descriptionString.substr(previousIndex, index - previousIndex); + mDataTypes.push_back(type); + previousIndex = index + 1; + index = descriptionString.find_first_of("\"", previousIndex); + if (index - previousIndex > 0) { + std::string description; + description = descriptionString.substr(previousIndex, index - previousIndex); + mDataDescriptions.push_back(description); + // create controllers here based on the type/description? + // Is array type already filled? + // Potentially call "fillControllers" after populating? + if (index != std::string::npos) { + previousIndex = index + 1; + index = descriptionString.find_first_of("\"", previousIndex); + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Type without a description in XdmfTemplate::populateItem"); + } + } + } + else { + mTrackedArrays.push_back(array.get()); + mTrackedArrayDims.push_back(array->getDimensions()); + mTrackedArrayTypes.push_back(array->getArrayType()); + } + } + } + } + for (unsigned int i = 0; i < mDataTypes.size(); ++i) + { + mDataControllers.push_back(std::vector >()); + } + mDataControllers.resize(mDataTypes.size()); + if (!mItemFactory) { + mItemFactory = XdmfItemFactory::New(); + } + std::map populateProperties; + if (mHeavyWriter) { + // The heavy writer provides the XMLDir, which is used to get full paths for the controllers + // It is assumed that the files that the controllers reference are in the same directory + // as the file that the writer references + std::string filepath = XdmfSystemUtils::getRealPath(mHeavyWriter->getFilePath()); + size_t index = filepath.find_last_of("/\\"); + filepath = filepath.substr(0, index + 1); + populateProperties["XMLDir"] = filepath; + } + else + { + // Error because a writer is required? TODO + } + for (unsigned int i = 0; i < mDataDescriptions.size(); ++i) { + populateProperties["Content"] = mDataDescriptions[i]; + std::vector > readControllers = + reader->generateHeavyDataControllers(populateProperties, mTrackedArrayDims[i % mTrackedArrays.size()], mTrackedArrayTypes[i % mTrackedArrays.size()], mDataTypes[i]); + if (readControllers.size() > 0) { + // Heavy data controllers reference the data + for (unsigned int j = 0; j < readControllers.size(); ++j) { + mDataControllers[i].push_back(readControllers[j]); + } + } + } + // Compare the first set of controllers to the size of the first array + unsigned int controllerTotal = 0; + + for (unsigned int i = 0; i < mDataControllers[0].size(); ++i) + { + unsigned int previousTotal = controllerTotal; + controllerTotal += mDataControllers[0][i]->getSize(); + if (previousTotal != controllerTotal - mDataControllers[0][i]->getSize()) + { + controllerTotal = UINT_MAX; + break; + } + } + // If the array is smaller, set the writer to append. + if (controllerTotal > mTrackedArrays[0]->getSize()) + { + mHeavyWriter->setMode(XdmfHeavyDataWriter::Append); + mNumSteps = 0; + unsigned int currentTotal = 0; + for (unsigned int controllerIndex = 0; controllerIndex < mDataControllers[0].size(); ++controllerIndex) + { + currentTotal += mDataControllers[0][controllerIndex]->getSize(); + while (currentTotal >= mTrackedArrays[0]->getSize()) + { + currentTotal -= mTrackedArrays[0]->getSize(); + ++mNumSteps; + } + } +// mNumSteps = controllerTotal / mTrackedArrays[0]->getSize(); + } + else { + mNumSteps = mDataControllers.size() / mTrackedArrays.size(); + } + this->setStep(0); +} + +void +XdmfTemplate::preallocateSteps(unsigned int numSteps) +{ + // Preallocate steps based on the current size of the arrays + // Use a temporary array to write data to hdf5 + shared_ptr tempArray = XdmfArray::New(); + // Set to Default mode so that the new allocations are in new locations + mHeavyWriter->setMode(XdmfHeavyDataWriter::Default); + int preallocatedSize = 0; + int numberSetsPreallocated = 0; + std::stringstream datastream; + for (unsigned int i = 0; i < mTrackedArrays.size(); ++i) { + preallocatedSize = mTrackedArrays[i]->getSize() * numSteps; +///* + numberSetsPreallocated = 1; + + int adjustment = 1; + while (preallocatedSize / (numSteps/adjustment) != mTrackedArrays[i]->getSize() || 0 > (int)preallocatedSize) { +// XdmfError::message(XdmfError::WARNING, "Overflow error"); + ++adjustment; + while (numSteps % adjustment != 0) { +//printf("%d / %d remainder %d\n", numSteps, adjustment, (numSteps % adjustment)); + ++adjustment; + } + numberSetsPreallocated = numberSetsPreallocated * adjustment; + preallocatedSize = mTrackedArrays[i]->getSize() * (numSteps / adjustment); +//printf("%d / %d = %d ?= %d\n", preallocatedSize , (numSteps/adjustment), preallocatedSize / (numSteps/adjustment), mTrackedArrays[i]->getSize()); + } + + // If adjusted, split one more time, to ensure that the dataset fits. + if (adjustment > 1) { + ++adjustment; + while (numSteps % adjustment != 0) { + ++adjustment; + } + numberSetsPreallocated = numberSetsPreallocated * adjustment; + preallocatedSize = mTrackedArrays[i]->getSize() * (numSteps / adjustment); + } + + bool allocateSucceeded = false; + while (!allocateSucceeded) + { + try { + mHeavyWriter->openFile(); +//printf("now size %d allocated %d times\n", preallocatedSize, numberSetsPreallocated); + for (unsigned int allocateIteration = 0; + allocateIteration < numberSetsPreallocated; + ++allocateIteration) + { +//printf("allocating subsection %u\n", allocateIteration); +//*/ +//printf("initializing base array\n"); + tempArray->initialize(mTrackedArrays[i]->getArrayType(), preallocatedSize); +//printf("writing subsection"); + tempArray->accept(mHeavyWriter); +//printf("subsection written\n"); +// mHeavyWriter->clearCache(); +///* + if (mDataControllers.size() <= i) { + mDataControllers.push_back(std::vector >()); + } + // Clean Array for the next iteration + while (tempArray->getNumberHeavyDataControllers() > 0) { + mDataControllers[i].push_back(tempArray->getHeavyDataController(0)); + if (mDataTypes.size() <= i) { + mDataTypes.push_back(tempArray->getHeavyDataController(0)->getName()); + } + tempArray->removeHeavyDataController(0); + } + tempArray->release(); +//*/ +///* +//printf("moving to next allocation\n"); + } + mHeavyWriter->closeFile(); + allocateSucceeded = true; +//*/ +//TODO catch the controllers created by this. +///* + } + catch (...) + { + while (tempArray->getNumberHeavyDataControllers() > 0) { + tempArray->removeHeavyDataController(0); + } + tempArray->release(); +// XdmfError::message(XdmfError::WARNING, "Array Allocation failed"); + int factor = 2; + while (preallocatedSize % factor != 0) { +//printf("%d / %d remainder %d\n", preallocatedSize, factor, (preallocatedSize % factor)); + factor = factor + 1; + } +//printf("adjusted factor %d\n", factor); + numberSetsPreallocated = numberSetsPreallocated * factor; + preallocatedSize = (preallocatedSize) / factor; +//printf("now size %d allocated %d times\n", preallocatedSize, numberSetsPreallocated); + } + } +//printf("Done writing to hdf5\n"); +//*/ +/* + // Transfer controllers to the appropriate slot before clearing them + if (mDataControllers.size() <= i) { + mDataControllers.push_back(std::vector >()); + } + // Clean Array for the next iteration + while (tempArray->getNumberHeavyDataControllers() > 0) { + mDataControllers[i].push_back(tempArray->getHeavyDataController(0)); + if (mDataTypes.size() <= i) { + mDataTypes.push_back(tempArray->getHeavyDataController(0)->getName()); + } + tempArray->removeHeavyDataController(0); + } + tempArray->release(); +*/ + datastream.str(std::string()); + for (unsigned int controllerIndex = 0; controllerIndex < mDataControllers[i].size(); ++controllerIndex) { + // TODO throw error if controller types don't match + // For each heavy data controller + std::string writerPath = XdmfSystemUtils::getRealPath(mHeavyWriter->getFilePath()); + std::string heavyDataPath = + mDataControllers[i][controllerIndex]->getFilePath(); + size_t index = heavyDataPath.find_last_of("/\\"); + if(index != std::string::npos) { + // If path is not a folder + // put the directory path into this variable + const std::string heavyDataDir = heavyDataPath.substr(0, index + 1); + // If the directory is in the XML File Path + if(writerPath.find(heavyDataDir) == 0) { + heavyDataPath = + heavyDataPath.substr(heavyDataDir.size(), + heavyDataPath.size() - heavyDataDir.size()); + // Pull the file off of the end and place it in the DataPath + } + // Otherwise the full path is required + } + datastream << heavyDataPath; + datastream << mDataControllers[i][controllerIndex]->getDescriptor(); + datastream << "|"; + for (unsigned int j = 0; j < mDataControllers[i][controllerIndex]->getDimensions().size(); ++j) { + datastream << mDataControllers[i][controllerIndex]->getDimensions()[j]; + if (j < mDataControllers[i][controllerIndex]->getDimensions().size() - 1) { + datastream << " "; + } + } + if (controllerIndex + 1 < mDataControllers[i].size()) { + datastream << "|"; + } + } + mDataDescriptions.push_back(datastream.str()); + } + // To end set the heavy writer to overwrite mode + mHeavyWriter->setMode(XdmfHeavyDataWriter::Hyperslab); +} + + +void +XdmfTemplate::removeStep(unsigned int stepId) +{ + if (stepId < this->getNumberSteps()) { + for (unsigned int i = 0; i < mTrackedArrays.size(); ++i) { + if (mHeavyWriter->getMode() == XdmfHeavyDataWriter::Append || + mHeavyWriter->getMode() == XdmfHeavyDataWriter::Hyperslab) { + std::vector > replacementControllers = getControllersExcludingStep(stepId, mTrackedArrayDims[i], mDataControllers[i]); + for (unsigned int j = 0; j < replacementControllers.size(); ++j) + { + if (mDataControllers[i].size() > j) { + mDataControllers[i][j] = replacementControllers[j]; + } + else { + mDataControllers[i].push_back(replacementControllers[j]); + } + } + } + else { + mDataTypes.erase(mDataTypes.begin() + (stepId*mTrackedArrays.size())); + mDataDescriptions.erase(mDataDescriptions.begin() + (stepId*mTrackedArrays.size())); + mDataControllers.erase(mDataControllers.begin() + (stepId*mTrackedArrays.size())); + } + } + --mNumSteps; + } + mCurrentStep = -1; + this->setIsChanged(true); +} + +void +XdmfTemplate::setBase(shared_ptr newBase) +{ + shared_ptr accumulator = XdmfArrayGatherer::New(&mTrackedArrays); + newBase->accept(accumulator); + mBase = newBase; + this->setIsChanged(true); +} + +void +XdmfTemplate::setHeavyDataWriter(shared_ptr writer) +{ + mHeavyWriter = writer; +} + +void +XdmfTemplate::setStep(unsigned int stepId) +{ + if (stepId != mCurrentStep) { + if (!mItemFactory) { + mItemFactory = XdmfItemFactory::New(); + } + if (stepId < this->getNumberSteps()) { + for (unsigned int i = 0; i < mTrackedArrays.size(); ++i) { + unsigned int arrayIndex = 0; + if (mHeavyWriter) { + if (mHeavyWriter->getMode() == XdmfHeavyDataWriter::Append || + mHeavyWriter->getMode() == XdmfHeavyDataWriter::Hyperslab) { + arrayIndex = i; + } + else { + arrayIndex = i+(stepId*mTrackedArrays.size()); + } + } + else { + arrayIndex = i+(stepId*mTrackedArrays.size()); + } + if (mDataControllers[arrayIndex].size() > 0) { + if(mHeavyWriter) { + if (mHeavyWriter->getMode() == XdmfHeavyDataWriter::Append || + mHeavyWriter->getMode() == XdmfHeavyDataWriter::Hyperslab) { + std::vector > insertVector = + getStepControllers(stepId, mTrackedArrayDims[i], mDataControllers[i]); + mTrackedArrays[i]->setHeavyDataController(insertVector); + } + else { + mTrackedArrays[i]->setHeavyDataController(mDataControllers[i+(stepId*mTrackedArrays.size())]); + } + } + else { + mTrackedArrays[i]->setHeavyDataController(mDataControllers[i+(stepId*mTrackedArrays.size())]); + } + } + else { + std::map populateProperties; + if (mHeavyWriter) { + // The heavy writer provides the XMLDir, which is used to get full paths for the controllers + // It is assumed that the files that the controllers reference are in the same directory + // as the file that the writer references + std::string filepath = XdmfSystemUtils::getRealPath(mHeavyWriter->getFilePath()); + size_t index = filepath.find_last_of("/\\"); + filepath = filepath.substr(0, index + 1); + populateProperties["XMLDir"] = filepath; + } + populateProperties["Content"] = mDataDescriptions[arrayIndex]; + std::vector > readControllers; + if (mHeavyWriter) { + if (mHeavyWriter->getMode() == XdmfHeavyDataWriter::Append || + mHeavyWriter->getMode() == XdmfHeavyDataWriter::Hyperslab) { + std::vector > totalControllers = + mItemFactory->generateHeavyDataControllers(populateProperties, mTrackedArrayDims[i], mTrackedArrayTypes[i], mDataTypes[i+(stepId*mTrackedArrays.size())]); + readControllers = getStepControllers(stepId, mTrackedArrayDims[i], totalControllers); + } + else { + readControllers = mItemFactory->generateHeavyDataControllers(populateProperties, mTrackedArrayDims[i], mTrackedArrayTypes[i], mDataTypes[i+(stepId*mTrackedArrays.size())]); + } + } + else { + readControllers = mItemFactory->generateHeavyDataControllers(populateProperties, mTrackedArrayDims[i], mTrackedArrayTypes[i], mDataTypes[i+(stepId*mTrackedArrays.size())]); + } + if (readControllers.size() > 0) { + // Heavy data controllers reference the data + mTrackedArrays[i]->setHeavyDataController(readControllers); + mDataControllers[arrayIndex] = readControllers; + } + else { + // Data is contained in the content + std::string content = mDataDescriptions[i+(stepId*mTrackedArrays.size())]; + + mTrackedArrays[i]->initialize(mTrackedArrayTypes[i], mTrackedArrayDims[i]); + + unsigned int index = 0; + boost::char_separator sep(" \t\n"); + boost::tokenizer > valtokens(content, sep); + if(mTrackedArrayTypes[i] == XdmfArrayType::String()) { + for(boost::tokenizer >::const_iterator + iter = valtokens.begin(); + iter != valtokens.end(); + ++iter, ++index) { + mTrackedArrays[i]->insert(index, *iter); + } + } + else { + for(boost::tokenizer >::const_iterator + iter = valtokens.begin(); + iter != valtokens.end(); + ++iter, ++index) { + mTrackedArrays[i]->insert(index, atof((*iter).c_str())); + } + } + } + } + } + } + else { + XdmfError::message(XdmfError::FATAL, "Error: Template attempting to load invalid step"); + } + mCurrentStep = stepId; + } +} + +void +XdmfTemplate::trackArray(shared_ptr newArray) +{ + bool found = false; + + for (unsigned int i = 0; i < mTrackedArrays.size() && !found; ++i) { + if (mTrackedArrays[i] == newArray.get()) { + found = true; + } + } + + if (!found) { + mTrackedArrays.push_back(newArray.get()); + } + this->setIsChanged(true); +} + +void +XdmfTemplate::traverse(const shared_ptr visitor) +{ + // Set to the first step when writing, as the first step is the model for the rest of the template + // Will fail if there are no steps + if (this->getNumberSteps() == 0) { + XdmfError::message(XdmfError::FATAL, "Error: No steps in template in XdmfTemplate::traverse"); + } + this->clearStep(); + + unsigned int arraysize = 1; + for (unsigned int i = 0; i < mTrackedArrayDims[0].size(); ++i) + { + arraysize *= mTrackedArrayDims[0][i]; + } + + unsigned int controllersize = 0; + for (unsigned int i = 0; i < mDataControllers[0].size(); ++i) + { + controllersize += mDataControllers[0][i]->getSize(); + } + + XdmfHeavyDataWriter::Mode originalMode; + + if (mHeavyWriter) + { + originalMode = mHeavyWriter->getMode(); + if (controllersize > arraysize) { + mHeavyWriter->setMode(XdmfHeavyDataWriter::Append); + } + } + + this->setStep(0); + + if (mHeavyWriter) + { + mHeavyWriter->setMode(originalMode); + } + + // Sending visitor to the base first so that it appears first when reading. + mBase->accept(visitor); + + for (unsigned int i = 0; i < mTrackedArrays.size(); ++i) { + mTrackedArrays[i]->release(); + mTrackedArrays[i]->accept(visitor); + } + + // Create an array to hold all of the data information strings + + bool originalXPath; + + if (shared_ptr writer = + shared_dynamic_cast(visitor)) { + originalXPath = writer->getWriteXPaths(); + writer->setWriteXPaths(false); + } + + shared_ptr dataInfoArray = XdmfArray::New(); + + dataInfoArray->setName("Data Description"); + + unsigned int i = 0; + + std::stringstream arrayInfo; + while (i < mDataTypes.size()) { + arrayInfo << "\"" << mDataTypes[i] << "\"" << mDataDescriptions[i]; + ++i; + } + dataInfoArray->insert(0, arrayInfo.str().c_str(), arrayInfo.str().length()); + dataInfoArray->insert(dataInfoArray->getSize(), 0); + + dataInfoArray->accept(visitor); + + if (shared_ptr writer = + shared_dynamic_cast(visitor)) { + writer->setWriteXPaths(originalXPath); + } + + XdmfItem::traverse(visitor); +} + +XDMF_ITEM_C_CHILD_WRAPPER(XdmfTemplate, XDMFTEMPLATE) diff --git a/XdmfTemplate.hpp b/XdmfTemplate.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8ea7d4464377862eb3923270be8fe4a767b0f07a --- /dev/null +++ b/XdmfTemplate.hpp @@ -0,0 +1,218 @@ +/*****************************************************************************/ +/* XDMF */ +/* eXtensible Data Model and Format */ +/* */ +/* Id : XdmfTemplate.hpp */ +/* */ +/* Author: */ +/* Andrew Burns */ +/* andrew.j.burns2@us.army.mil */ +/* US Army Research Laboratory */ +/* Aberdeen Proving Ground, MD */ +/* */ +/* Copyright @ 2013 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. */ +/* */ +/*****************************************************************************/ + +#ifndef XDMFTEMPLATE_HPP_ +#define XDMFTEMPLATE_HPP_ + +// C Compatible Includes +#include "Xdmf.hpp" +#include "XdmfItem.hpp" +#include "XdmfItemFactory.hpp" +#include "XdmfArray.hpp" +#include "XdmfHeavyDataWriter.hpp" + +#ifdef __cplusplus + +// Includes + +/** + * @brief Defines a template that can be filled with multiple sets of data. + * + * An XdmfTemplate defines a structure. The arrays within that structure + * are stored if they are not initialized when the structure is first set. + * Steps can then be added and references to heavy data are produced and + * stored for later retrieval. + * + * This effectively lets an object have several variations with different + * contained data. + */ +class XDMF_EXPORT XdmfTemplate : public virtual XdmfItem { + +public: + + /** + * Creates a new instance of the XdmfTemplate object + * + * @return A constructed XdmfTemplate object. + */ + static shared_ptr New(); + + virtual ~XdmfTemplate(); + + LOKI_DEFINE_VISITABLE(XdmfTemplate, XdmfItem); + static const std::string ItemTag; + + /** + * Writes all tracked arrays to heavy data via the provided + * heavy data writer then stores the heavy data descriptions. + * + * @return The ID of the step that was added + */ + virtual unsigned int addStep(); + + /** + * Clears the current data from the tracked arrays. + */ + virtual void clearStep(); + + /** + * Gets the XdmfItem that serves as the structure for the template. + * + * @return The XdmfItem that serves as the structure for the template. + */ + virtual shared_ptr getBase(); + + /** + * Gets the heavy data writer that is used to write step data to heavy data. + * + * @return The heavy data writer + */ + shared_ptr getHeavyDataWriter(); + + std::map getItemProperties() const; + + std::string getItemTag() const; + + /** + * Gets the number of steps currently contained within the template. + * + * @return The number of steps contained within the template. + */ + unsigned int getNumberSteps() const; + + /** + * Gets the number of arrays tracked across timesteps. + * + * @return The numer of tracked arrays. + */ + unsigned int getNumberTrackedArrays() const; + + /** + * Gets the tracked array at the specified index. The index of the array + * depends on when the internal visitor encountered the array in question. + * + * @return The requested array. + */ + XdmfArray * getTrackedArray(unsigned int index); + + using XdmfItem::insert; + + /* + * + */ + virtual void preallocateSteps(unsigned int numSteps); + + /** + * + */ + virtual void removeStep(unsigned int stepId); + + /** + * Sets the item to define the structure for each step of the template. + * + * When the base is set all uninitialized arrays are added to + * the list of tracked arrays. + * + * @param newBase The item to serve as the structure. + */ + virtual void setBase(shared_ptr newBase); + + /** + * Sets the heavy data writer with which the template will write + * to heavy data when adding a step. + * + * @param writer The writer to be used to write to heavy data. + */ + void setHeavyDataWriter(shared_ptr writer); + + /** + * Reads in the heavy data associated with the provided step id. + * + * @param stepId The id of the step whose heavy data + * is to be read in from file + */ + virtual void setStep(unsigned int stepId); + + /** + * Adds an array to the list of tracked arrays if that array + * is not already there. + * + * The setBase method automatically sets uninitialized arrays + * to be tracked, this can be used to add any missed by setBase. + * + * @param newArray The array to be tracked. + */ + virtual void trackArray(shared_ptr newArray); + + virtual void traverse(const shared_ptr visitor); + + XdmfTemplate(XdmfTemplate &); + +protected: + + XdmfTemplate(); + + virtual void + populateItem(const std::map & itemProperties, + const std::vector > & childItems, + const XdmfCoreReader * const reader); + + shared_ptr mHeavyWriter; + + shared_ptr mBase; + std::vector mTrackedArrays; + std::vector mDataTypes; + std::vector mDataDescriptions; + std::vector > > mDataControllers; + std::vector > mTrackedArrayTypes; + std::vector > mTrackedArrayDims; + int mCurrentStep; + unsigned int mNumSteps; + shared_ptr mItemFactory; + +private: + + XdmfTemplate(const XdmfTemplate &); // Not implemented. + void operator=(const XdmfTemplate &); // Not implemented. + +}; + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// C wrappers go here + +struct XDMFTEMPLATE; // Simply as a typedef to ensure correct typing +typedef struct XDMFTEMPLATE XDMFTEMPLATE; + +XDMF_ITEM_C_CHILD_DECLARE(XdmfTemplate, XDMFTEMPLATE, XDMF) + +#ifdef __cplusplus +} +#endif + + +#endif /* XDMFTEMPLATE_HPP_ */