/*========================================================================= Program: Visualization Toolkit Module: vtkXdmfReaderInternal.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm 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 "vtkXdmfReaderInternal.h" #include "vtkDataArray.h" #include "vtkSmartPointer.h" #include "vtkVariant.h" #include "vtkXdmfDataArray.h" #define USE_IMAGE_DATA // otherwise uniformgrid // As soon as num-grids (sub-grids and all) grows beyond this number, we assume // that the grids are way too numerous for the user to select individually and // hence only the top-level grids are made accessible. #define MAX_COLLECTABLE_NUMBER_OF_GRIDS 1000 template T vtkMAX(T a, T b) { return (a > b ? a : b); } using namespace xdmf2; //------------------------------------------------------------------------------ vtkXdmfDocument::vtkXdmfDocument() { this->ActiveDomain = nullptr; this->ActiveDomainIndex = -1; this->LastReadContents = nullptr; this->LastReadContentsLength = 0; } //------------------------------------------------------------------------------ vtkXdmfDocument::~vtkXdmfDocument() { delete this->ActiveDomain; delete[] this->LastReadContents; } //------------------------------------------------------------------------------ bool vtkXdmfDocument::Parse(const char* xmffilename) { if (!xmffilename) { return false; } if (this->LastReadFilename == xmffilename) { return true; } this->ActiveDomainIndex = -1; delete this->ActiveDomain; this->ActiveDomain = nullptr; delete[] this->LastReadContents; this->LastReadContents = nullptr; this->LastReadContentsLength = 0; this->LastReadFilename = std::string(); this->XMLDOM.SetInputFileName(xmffilename); if (!this->XMLDOM.Parse()) { return false; } // Tell the parser what the working directory is. std::string directory = vtksys::SystemTools::GetFilenamePath(xmffilename) + "/"; if (directory == "/") { directory = vtksys::SystemTools::GetCurrentWorkingDirectory() + "/"; } this->XMLDOM.SetWorkingDirectory(directory.c_str()); this->LastReadFilename = xmffilename; this->UpdateDomains(); return true; } //------------------------------------------------------------------------------ bool vtkXdmfDocument::ParseString(const char* xmfdata, size_t length) { if (!xmfdata || !length) { return false; } if (this->LastReadContents && this->LastReadContentsLength == length && STRNCASECMP(xmfdata, this->LastReadContents, length) == 0) { return true; } this->ActiveDomainIndex = -1; delete this->ActiveDomain; this->ActiveDomain = nullptr; delete this->LastReadContents; this->LastReadContentsLength = 0; this->LastReadFilename = std::string(); this->LastReadContents = new char[length + 1]; this->LastReadContentsLength = length; memcpy(this->LastReadContents, xmfdata, length); this->LastReadContents[length] = 0; this->XMLDOM.SetInputFileName(nullptr); if (!this->XMLDOM.Parse(this->LastReadContents)) { delete this->LastReadContents; this->LastReadContents = nullptr; this->LastReadContentsLength = 0; return false; } this->UpdateDomains(); return true; } //------------------------------------------------------------------------------ void vtkXdmfDocument::UpdateDomains() { this->Domains.clear(); XdmfXmlNode domain = this->XMLDOM.FindElement("Domain", 0); while (domain) { XdmfConstString domainName = this->XMLDOM.Get(domain, "Name"); if (domainName) { this->Domains.emplace_back(domainName); } else { std::ostringstream str; str << "Domain" << this->Domains.size() << ends; this->Domains.push_back(str.str()); } domain = this->XMLDOM.FindNextElement("Domain", domain); } } //------------------------------------------------------------------------------ bool vtkXdmfDocument::SetActiveDomain(const char* domainname) { for (int cc = 0; cc < static_cast(this->Domains.size()); cc++) { if (this->Domains[cc] == domainname) { return this->SetActiveDomain(cc); } } return false; } //------------------------------------------------------------------------------ bool vtkXdmfDocument::SetActiveDomain(int index) { if (this->ActiveDomainIndex == index) { return true; } this->ActiveDomainIndex = -1; delete this->ActiveDomain; this->ActiveDomain = nullptr; vtkXdmfDomain* domain = new vtkXdmfDomain(&this->XMLDOM, index); if (!domain->IsValid()) { delete domain; return false; } this->ActiveDomain = domain; this->ActiveDomainIndex = index; return true; } //***************************************************************************** // vtkXdmfDomain //------------------------------------------------------------------------------ vtkXdmfDomain::vtkXdmfDomain(XdmfDOM* xmlDom, int domain_index) { this->XMLDOM = nullptr; this->XMFGrids = nullptr; this->NumberOfGrids = 0; this->SIL = vtkMutableDirectedGraph::New(); this->SILBuilder = vtkSILBuilder::New(); this->SILBuilder->SetSIL(this->SIL); this->PointArrays = new vtkXdmfArraySelection; this->CellArrays = new vtkXdmfArraySelection; this->Grids = new vtkXdmfArraySelection; this->Sets = new vtkXdmfArraySelection; this->XMLDomain = xmlDom->FindElement("Domain", domain_index); if (!this->XMLDomain) { // no such domain exists!!! return; } this->XMLDOM = xmlDom; // Allocate XdmfGrid instances for each of the grids in this domain. this->NumberOfGrids = this->XMLDOM->FindNumberOfElements("Grid", this->XMLDomain); this->XMFGrids = new XdmfGrid[this->NumberOfGrids + 1]; XdmfXmlNode xmlGrid = this->XMLDOM->FindElement("Grid", 0, this->XMLDomain); XdmfInt64 cc = 0; while (xmlGrid) { this->XMFGrids[cc].SetDOM(this->XMLDOM); this->XMFGrids[cc].SetElement(xmlGrid); // Read the light data for this grid (and all its sub-grids, if // applicable). this->XMFGrids[cc].UpdateInformation(); xmlGrid = this->XMLDOM->FindNextElement("Grid", xmlGrid); cc++; } // There are a few meta-information that we need to collect from the domain // * number of data-arrays so that the user can choose which to load. // * grid-structure so that the user can choose the hierarchy // * time information so that reader can report the number of timesteps // available. this->CollectMetaData(); } //------------------------------------------------------------------------------ vtkXdmfDomain::~vtkXdmfDomain() { // free the XdmfGrid allocated. delete[] this->XMFGrids; this->XMFGrids = nullptr; this->SIL->Delete(); this->SIL = nullptr; this->SILBuilder->Delete(); this->SILBuilder = nullptr; delete this->PointArrays; delete this->CellArrays; delete this->Grids; delete this->Sets; } //------------------------------------------------------------------------------ XdmfGrid* vtkXdmfDomain::GetGrid(XdmfInt64 cc) { if (cc >= 0 && cc < this->NumberOfGrids) { return &this->XMFGrids[cc]; } return nullptr; } //------------------------------------------------------------------------------ int vtkXdmfDomain::GetVTKDataType() { if (this->NumberOfGrids > 1) { return VTK_MULTIBLOCK_DATA_SET; } if (this->NumberOfGrids == 1) { return this->GetVTKDataType(&this->XMFGrids[0]); } return -1; } //------------------------------------------------------------------------------ int vtkXdmfDomain::GetVTKDataType(XdmfGrid* xmfGrid) { XdmfInt32 gridType = xmfGrid->GetGridType(); if ((gridType & XDMF_GRID_COLLECTION) && xmfGrid->GetCollectionType() == XDMF_GRID_COLLECTION_TEMPORAL) { // this is a temporal collection, the type depends on the child with // correct time-stamp. But since we assume that all items in a temporal // collection must be of the same type, we simply use the first child. return this->GetVTKDataType(xmfGrid->GetChild(0)); } if ((gridType & XDMF_GRID_COLLECTION) || (gridType & XDMF_GRID_TREE)) { return VTK_MULTIBLOCK_DATA_SET; } if (xmfGrid->GetTopology()->GetClass() == XDMF_UNSTRUCTURED) { return VTK_UNSTRUCTURED_GRID; } XdmfInt32 topologyType = xmfGrid->GetTopology()->GetTopologyType(); if (topologyType == XDMF_2DSMESH || topologyType == XDMF_3DSMESH) { return VTK_STRUCTURED_GRID; } else if (topologyType == XDMF_2DCORECTMESH || topologyType == XDMF_3DCORECTMESH) { #ifdef USE_IMAGE_DATA return VTK_IMAGE_DATA; #else return VTK_UNIFORM_GRID; #endif } else if (topologyType == XDMF_2DRECTMESH || topologyType == XDMF_3DRECTMESH) { return VTK_RECTILINEAR_GRID; } return -1; } //------------------------------------------------------------------------------ int vtkXdmfDomain::GetIndexForTime(double time) { std::map::const_iterator iter = this->TimeSteps.find(time); if (iter != this->TimeSteps.end()) { return iter->second; } iter = this->TimeSteps.upper_bound(time); if (iter == this->TimeSteps.begin()) { // The requested time step is before any available time. We will use it by // doing nothing here. } else { // Back up one to the item we really want. --iter; } std::map::iterator iter2 = this->TimeSteps.begin(); int counter = 0; while (iter2 != iter) { ++iter2; counter++; } return counter; } //------------------------------------------------------------------------------ XdmfGrid* vtkXdmfDomain::GetGrid(XdmfGrid* xmfGrid, double time) { XdmfInt32 gridType = xmfGrid->GetGridType(); if ((gridType & XDMF_GRID_COLLECTION) && xmfGrid->GetCollectionType() == XDMF_GRID_COLLECTION_TEMPORAL) { for (XdmfInt32 cc = 0; cc < xmfGrid->GetNumberOfChildren(); cc++) { XdmfGrid* child = xmfGrid->GetChild(cc); if (child && child->GetTime()->IsValid(time, time)) { return child; } } // It's possible that user has not specified a