/*========================================================================= Program: Visualization Toolkit Module: vtkAMRInformation.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 "vtkAMRInformation.h" #include "vtkObjectFactory.h" #include "vtkUnsignedIntArray.h" #include "vtkIntArray.h" #include "vtkMath.h" #include "vtkStructuredGrid.h" #include "vtkBoundingBox.h" #include "vtkAMRBox.h" #include "vtkDoubleArray.h" #include #include vtkStandardNewMacro(vtkAMRInformation); namespace { inline bool Inside(double q[3], double gbounds[6]) { if ((q[0] < gbounds[0]) || (q[0] > gbounds[1]) || (q[1] < gbounds[2]) || (q[1] > gbounds[3]) || (q[2] < gbounds[4]) || (q[2] > gbounds[5])) { return false; } else { return true; } } // Utility class used to store bin properties // and contents class DataSetBinner { std::vector > Bins; unsigned int NBins[3]; unsigned int LoCorner[3]; // Binsize in "extent coordinates" unsigned int BinSize[3]; size_t TotalNumBins; public: // Create a set of bins given: // - number of bins in x, y, z // - lower extent of the binned space // - the size of bins in "extent coordinates" DataSetBinner(unsigned int nbins[3], unsigned int locorner[3], unsigned int binsize[3]) { memcpy(this->NBins, nbins, 3*sizeof(unsigned int)); memcpy(this->LoCorner, locorner, 3*sizeof(unsigned int)); memcpy(this->BinSize, binsize, 3*sizeof(unsigned int)); this->TotalNumBins = nbins[0]*nbins[1]*nbins[2]; this->Bins.resize(this->TotalNumBins); for (size_t i=0; iTotalNumBins; i++) { this->Bins[i].reserve(5); } } // Note that this does not check if the bin already // contains the blockId. This works fine for what this // class is used for. void AddToBin(unsigned int binIndex[3], int blockId) { size_t idx = binIndex[2] + binIndex[1]*this->NBins[2] + binIndex[0]*this->NBins[2]*this->NBins[1]; std::vector& bin = this->Bins[idx]; bin.push_back(blockId); } const std::vector& GetBin(unsigned int binIndex[3]) const { size_t idx = binIndex[2] + binIndex[1]*this->NBins[2] + binIndex[0]*this->NBins[2]*this->NBins[1]; return this->Bins[idx]; } // Given an input AMR box, return all boxes in the bins that intersect it void GetBoxesInIntersectingBins(const vtkAMRBox& box, std::set& boxes) { boxes.clear(); unsigned int minbin[3]; unsigned int maxbin[3]; const int* loCorner = box.GetLoCorner(); int hiCorner[3]; box.GetValidHiCorner(hiCorner); for (int j=0; j<3; j++) { minbin[j] = (loCorner[j] - this->LoCorner[j]) / this->BinSize[j]; maxbin[j] = (hiCorner[j] - this->LoCorner[j]) / this->BinSize[j]; } unsigned int idx[3]; for (idx[0]=minbin[0]; idx[0]<=maxbin[0]; idx[0]++) for (idx[1]=minbin[1]; idx[1]<=maxbin[1]; idx[1]++) for (idx[2]=minbin[2]; idx[2]<=maxbin[2]; idx[2]++) { const std::vector& bin = this->GetBin(idx); std::vector::const_iterator iter; for(iter=bin.begin(); iter!=bin.end(); ++iter) { boxes.insert(*iter); } } } }; }; //---------------------------------------------------------------------------- vtkAMRInformation::vtkAMRInformation(): NumBlocks(1,0) { this->Refinement = vtkSmartPointer::New(); this->SourceIndex = nullptr; this->GridDescription = -1; this->Origin[0] = this->Origin[1] = this->Origin[2] = DBL_MAX; this->Spacing =nullptr; this->BlockLevel = nullptr; this->Bounds[0] = VTK_DOUBLE_MAX; this->Bounds[1] = VTK_DOUBLE_MIN; this->Bounds[2] = VTK_DOUBLE_MAX; this->Bounds[3] = VTK_DOUBLE_MIN; this->Bounds[4] = VTK_DOUBLE_MAX; this->Bounds[5] = VTK_DOUBLE_MIN; } vtkAMRInformation::~vtkAMRInformation() { } void vtkAMRInformation::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Grid description: " << this->GetGridDescription()<< "\n"; os << indent << "Global origin: (" << this->GetOrigin()[0] <<", " << this->GetOrigin()[1] <<", " << this->GetOrigin()[2] <<")\n "; os<< indent << "Number of blocks per level: "; for(unsigned int i=1; iNumBlocks.size();i++) { os<NumBlocks[i]-this->NumBlocks[i-1]<<" "; } os<<"\n"; os<HasRefinementRatio()) { for(unsigned int i=0; iGetNumberOfLevels();i++) { os<GetRefinementRatio(i)<<" "; } os<<"\n"; } else { os<<"None\n"; } for (unsigned int levelIdx=0; levelIdxGetNumberOfLevels(); levelIdx++) { unsigned int numDataSets = this->GetNumberOfDataSets( levelIdx ); os<GetAMRBox(levelIdx,dataIdx); os<HasChildrenInformation()) { os<GetNumberOfLevels(); levelIdx++) { unsigned int numDataSets = this->GetNumberOfDataSets( levelIdx ); for( unsigned int dataIdx=0; dataIdx < numDataSets; ++dataIdx ) { this->PrintParentChildInfo(levelIdx,dataIdx); } } } os<<"\n"; } bool vtkAMRInformation::Audit() { int emptyDimension(-1); switch (this->GridDescription) { case VTK_YZ_PLANE: emptyDimension = 0; break; case VTK_XZ_PLANE: emptyDimension = 1; break; case VTK_XY_PLANE: emptyDimension = 2; break; } //Check origin for(int d = 0; d<3; d++) { if(d!=emptyDimension) { if(this->Origin[d]!=this->Bounds[2*d]) { vtkErrorMacro("Bound min does not match origin at dimension "<Origin[d]<<" != "<< this->Bounds[2*d]); } } } //check refinement levels if(this->HasRefinementRatio() && static_cast(this->Refinement->GetNumberOfTuples())!=this->GetNumberOfLevels()) { vtkErrorMacro("Refinement levels wrong "<< this->Refinement->GetNumberOfTuples()); } //check spacing for(unsigned int i=0; iGetNumberOfLevels(); i++) { double h[3]; this->GetSpacing(i,h); for(int d=0; d<3; d++) { if(h[d]<0) { vtkErrorMacro("Invalid spacing at level "<Boxes.size();i++) { const vtkAMRBox& box = this->Boxes[i]; if(box.IsInvalid()) { vtkErrorMacro("Invalid AMR Box"); } bool valid(true); switch (this->GridDescription) { case VTK_YZ_PLANE: valid = box.EmptyDimension(0); break; case VTK_XZ_PLANE: valid = box.EmptyDimension(1); break; case VTK_XY_PLANE: valid = box.EmptyDimension(2); break; } if(!valid) { vtkErrorMacro("Invalid AMRBox. Wrong dimension"); } } return true; } void vtkAMRInformation::Initialize(int numLevels, const int* blocksPerLevel) { if(numLevels<0) { vtkErrorMacro("Number of levels must be at least 0: "<NumBlocks.resize(numLevels+1,0); for(unsigned int i=0; i(numLevels);i++) { this->NumBlocks[i+1] = this->NumBlocks[i] + blocksPerLevel[i]; } int numBlocks = this->NumBlocks.back(); this->AllocateBoxes(numBlocks); this->Spacing = vtkSmartPointer::New(); this->Spacing->SetNumberOfTuples(3*numLevels); this->Spacing->SetNumberOfComponents(3); for(int i=0; iSpacing->SetTuple(i,h); } } unsigned int vtkAMRInformation::GetNumberOfDataSets(unsigned int level) const { if( level>= this->GetNumberOfLevels()) { cerr<<"WARNING: No data set at this level"<NumBlocks[level+1]-this->NumBlocks[level]; } void vtkAMRInformation::AllocateBoxes(unsigned int n) { this->Boxes.clear(); for(unsigned int i=0; iBoxes.push_back(box); } for(unsigned int i=0; iBoxes[i].Invalidate(); } } void vtkAMRInformation::SetAMRBox(unsigned int level, unsigned int id, const vtkAMRBox& box) { unsigned int index = this->GetIndex(level,id); this->Boxes[index] = box; if(this->HasSpacing(level)) //has valid spacing { this->UpdateBounds(level,id); } } int vtkAMRInformation::GetAMRBlockSourceIndex(int index) { return this->SourceIndex->GetValue(index); } void vtkAMRInformation::SetAMRBlockSourceIndex(int index, int sourceId) { if(!this->SourceIndex) { this->SourceIndex = vtkSmartPointer::New(); this->SourceIndex->SetNumberOfValues(this->GetTotalNumberOfBlocks()); } if(index>=this->SourceIndex->GetNumberOfTuples()) { vtkErrorMacro("Invalid index"); return; } SourceIndex->SetValue(index,sourceId); } void vtkAMRInformation::ComputeIndexPair(unsigned int index, unsigned int& level, unsigned int& id) { this->GenerateBlockLevel(); level = this->BlockLevel->GetValue(static_cast(index)); id = index - this->NumBlocks[level] ; } void vtkAMRInformation::GetOrigin( double o[3] ) { for( int i=0; i < 3; ++i ) { o[i] = this->Origin[i]; } } double* vtkAMRInformation::GetOrigin() { if(!this->HasValidOrigin()) { vtkErrorMacro("Invalid Origin"); } return this->Origin; } void vtkAMRInformation::SetOrigin(const double* origin) { for(int d=0; d<3; d++) { this->Origin[d] = origin[d]; } } int vtkAMRInformation::GetRefinementRatio(unsigned int level) const { return this->Refinement->GetValue(level); } void vtkAMRInformation::SetRefinementRatio(unsigned int level, int refRatio) { if(!HasRefinementRatio()) { this->Refinement->SetNumberOfTuples(this->GetNumberOfLevels()); } this->Refinement->SetValue(level,refRatio); } bool vtkAMRInformation::HasRefinementRatio() { return this->Refinement && static_cast(this->Refinement->GetNumberOfTuples())==this->GetNumberOfLevels(); } void vtkAMRInformation::GenerateRefinementRatio() { this->Refinement->SetNumberOfTuples(this->GetNumberOfLevels()); // sanity check int numLevels = this->GetNumberOfLevels(); if( numLevels < 1 ) { // Dataset is empty! return; } if( numLevels == 1) { // No refinement, data-set has only a single level. // The refinement ratio is set to 2 to satisfy the // vtkOverlappingAMR requirement. this->Refinement->SetValue(0,2); return; } for( int level=0; level < numLevels-1; ++level ) { int childLevel = level+1; if(this->GetNumberOfDataSets(childLevel)<1 || this->GetNumberOfDataSets(level)<1 ) { continue; } unsigned int id =0; for(; id< this->GetNumberOfDataSets(level);id++) { if(!this->GetAMRBox(level,id).IsInvalid()) { break; } } double childSpacing[3]; this->GetSpacing(childLevel, childSpacing); double currentSpacing[3]; this->GetSpacing(level, currentSpacing ); // Note current implementation assumes uniform spacing. The // refinement ratio is the same in each dimension i,j,k. int nonEmptyDimension = 0; switch(this->GridDescription) { case VTK_XY_PLANE: nonEmptyDimension = 0;break; case VTK_YZ_PLANE: nonEmptyDimension = 1;break; case VTK_XZ_PLANE: nonEmptyDimension = 2;break; } int ratio = vtkMath::Round(currentSpacing[nonEmptyDimension]/childSpacing[nonEmptyDimension]); // Set the ratio at the last level, i.e., level numLevels-1, to be the // same as the ratio at the previous level,since the highest level // doesn't really have a refinement ratio. if( level==numLevels-2 ) { this->Refinement->SetValue(level+1,ratio); } this->Refinement->SetValue(level,ratio); } // END for all hi-res levels } bool vtkAMRInformation::HasChildrenInformation() { return !this->AllChildren.empty(); } unsigned int *vtkAMRInformation::GetParents(unsigned int level, unsigned int index, unsigned int& num) { if(level>=this->AllParents.size() || index>=this->AllParents[level].size() || this->AllParents[level][index].empty()) { num = 0; return nullptr; } num = static_cast(this->AllParents[level][index].size()); return &this->AllParents[level][index][0]; } unsigned int *vtkAMRInformation:: GetChildren(unsigned int level, unsigned int index, unsigned int& size) { if(level>=this->AllChildren.size() || index>=this->AllChildren[level].size() || this->AllChildren[level][index].empty()) { size = 0; return nullptr; } size = static_cast(this->AllChildren[level][index].size()); return &this->AllChildren[level][index][0]; } void vtkAMRInformation:: PrintParentChildInfo(unsigned int level, unsigned int index) { unsigned int *ptr, i, numParents; std::cerr << "Parent Child Info for block " << index << " of Level: " << level << endl; ptr = this->GetParents(level, index, numParents); std::cerr << " Parents: "; for (i = 0; i < numParents; i++) { std::cerr << ptr[i] << " "; } std::cerr << endl; std::cerr << " Children: "; unsigned int numChildren; ptr = this->GetChildren(level, index,numChildren); for (i = 0; i HasRefinementRatio()) { this->GenerateRefinementRatio(); } this->AllChildren.resize(this->GetNumberOfLevels()); this->AllParents.resize(this->GetNumberOfLevels()); unsigned int numLevels = this->GetNumberOfLevels(); for(unsigned int i=1; iCalculateParentChildRelationShip(i, this->AllChildren[i-1], this->AllParents[i]); } } bool vtkAMRInformation::HasValidOrigin() { return this->Origin[0]!=DBL_MAX && this->Origin[1]!=DBL_MAX && this->Origin[2]!=DBL_MAX; } bool vtkAMRInformation::HasValidBounds() { return this->Bounds[0]!=DBL_MAX && this->Bounds[1]!=DBL_MAX && this->Bounds[2]!=DBL_MAX; } void vtkAMRInformation::SetGridDescription(int description) { if (description < VTK_SINGLE_POINT || description > VTK_EMPTY) { vtkErrorMacro("Invalid grid description for a vtkUniformGrid."); return; } this->GridDescription = description; } void vtkAMRInformation::SetSpacing(unsigned int level, const double* h) { double* spacing = this->Spacing->GetTuple(level); for(unsigned int i=0; i<3; i++) { if(spacing[i]>0 && spacing[i]!=h[i]) { vtkWarningMacro("Inconsistent spacing: "<GetAMRBox(level - 1, i); if (!box.IsInvalid()) { unsigned int minbin[3]; unsigned int maxbin[3]; box.Refine(refinementRatio); const int* loCorner = box.GetLoCorner(); int hiCorner[3]; box.GetValidHiCorner(hiCorner); for (int j=0; j<3; j++) { minbin[j] = (loCorner[j] - extents[2*j]) / binsize[j]; maxbin[j] = (hiCorner[j] - extents[2*j]) / binsize[j]; } unsigned int idx[3]; for (idx[0]=minbin[0]; idx[0]<=maxbin[0]; idx[0]++) { for (idx[1]=minbin[1]; idx[1]<=maxbin[1]; idx[1]++) { for (idx[2]=minbin[2]; idx[2]<=maxbin[2]; idx[2]++) { binner.AddToBin(idx, i); } } } } } // Write bins for debugging // WriteBins(origin, spacing, extents, binsize, nbins, binner); // Actually find parent-children relationship // between blocks in level and level-1 children.resize(this->GetNumberOfDataSets(level-1)); parents.resize(this->GetNumberOfDataSets(level)); unsigned int numDataSets = this->GetNumberOfDataSets(level); for (unsigned int i=0; iGetAMRBox(level, i); if (!box.IsInvalid()) { std::set boxes; binner.GetBoxesInIntersectingBins(box, boxes); std::set::iterator iter; for (iter=boxes.begin(); iter!=boxes.end(); ++iter) { vtkAMRBox potentialParent = this->GetAMRBox(level - 1, *iter); if (!potentialParent.IsInvalid()) { potentialParent.Refine(refinementRatio); if (box.DoesIntersect(potentialParent)) { children[*iter].push_back(i); parents[i].push_back(*iter); } } } } } } bool vtkAMRInformation::FindCell(double q[3],unsigned int level, unsigned int id,int &cellIdx) { double h[3]; this->GetSpacing(level,h); const vtkAMRBox& box = this->GetAMRBox(level,id); double gbounds[6]; this->GetBounds(level,id,gbounds); if ((q[0] < gbounds[0]) || (q[0] > gbounds[1]) || (q[1] < gbounds[2]) || (q[1] > gbounds[3]) || (q[2] < gbounds[4]) || (q[2] > gbounds[5])) { return false; } int ijk[3]; double pcoords[3]; int status = vtkAMRBox::ComputeStructuredCoordinates(box, this->Origin, h, q, ijk, pcoords ); if( status == 1 ) { int dims[3]; box.GetNumberOfNodes(dims); cellIdx=vtkStructuredData::ComputeCellId(dims,ijk); return true; } return false; } bool vtkAMRInformation::GetCoarsenedAMRBox(unsigned int level, unsigned int id, vtkAMRBox& box) const { box = this->GetAMRBox(level,id); if(box.IsInvalid()) { std::cerr<<"Invalid AMR box."<GetRefinementRatio(level-1); box.Coarsen(refinementRatio); return true; } bool vtkAMRInformation::operator==(const vtkAMRInformation& other) { if(this->GridDescription!=other.GridDescription) { return false; } if(this->NumBlocks.size()!=other.NumBlocks.size()) { return false; } for(int i=0; i<3; i++) { if(this->Origin[i]!=other.Origin[i]) { return false; } } for(size_t i=0; iNumBlocks.size();i++) { if(this->NumBlocks[i]!=other.NumBlocks[i]) { return false; } } for(size_t i=0; iBoxes.size(); i++) { if(this->Boxes[i]!=other.Boxes[i]) { return false; } } if(this->SourceIndex && other.SourceIndex) { for(vtkIdType i=0; iSourceIndex->GetNumberOfTuples();i++) { if(this->SourceIndex->GetValue(i)!=other.SourceIndex->GetValue(i)) { return false; } } } if(this->Spacing->GetNumberOfTuples()!=other.Spacing->GetNumberOfTuples()) { return false; } for(vtkIdType i=0; iSpacing->GetNumberOfTuples();i++) { if(this->Spacing->GetValue(i)!=other.Spacing->GetValue(i)) { return false; } } return true; } bool vtkAMRInformation::GetOrigin(unsigned int level, unsigned int id, double* origin) { const vtkAMRBox& box = this->Boxes[this->GetIndex(level,id)]; vtkAMRBox::GetBoxOrigin(box, this->Origin, this->Spacing->GetTuple(level), origin); return true; } void vtkAMRInformation::UpdateBounds(const int level, const int id) { double bb[6]; vtkAMRBox::GetBounds(this->GetAMRBox(level,id), this->Origin, this->Spacing->GetTuple(level), bb); for( int i=0; i < 3; ++i ) { if( bb[i*2] < this->Bounds[i*2] ) { this->Bounds[i*2] = bb[i*2]; } if( bb[i*2+1] > this->Bounds[i*2+1]) { this->Bounds[i*2+1] = bb[i*2+1]; } } // END for each dimension } void vtkAMRInformation::DeepCopy(vtkAMRInformation *other) { this->GridDescription = other->GridDescription; memcpy(this->Origin, other->Origin, sizeof(double)*3); this->Boxes = other->Boxes; this->NumBlocks = other->NumBlocks; if(other->SourceIndex) { this->SourceIndex = vtkSmartPointer::New(); this->SourceIndex->DeepCopy(other->SourceIndex); } if(other->Spacing) { this->Spacing = vtkSmartPointer::New(); this->Spacing->DeepCopy(other->Spacing); } memcpy(this->Bounds, other->Bounds, sizeof(double)*6); } bool vtkAMRInformation::HasSpacing(unsigned int level) { return this->Spacing->GetTuple(level)[0] >=0 || this->Spacing->GetTuple(level)[1] >=0 || this->Spacing->GetTuple(level)[2] >=0; } const double* vtkAMRInformation::GetBounds() { if(!HasValidBounds()) { for(unsigned int i=0; iGetNumberOfLevels();i++) { for(unsigned int j=0; jGetNumberOfDataSets(i);j++) { this->UpdateBounds(i,j); } } } return this->Bounds; } bool vtkAMRInformation::FindGrid(double q[3], unsigned int& level, unsigned int& gridId) { if (!this->HasChildrenInformation()) { this->GenerateParentChildInformation(); } if (!this->FindGrid(q, 0,gridId)) { return false; } unsigned int maxLevels = this->GetNumberOfLevels(); for(level=0; levelGetChildren(level, gridId,n); if (children == nullptr) { break; } unsigned int i; for (i = 0; i < n; i++) { double bb[6]; this->GetBounds(level+1, children[i],bb); if(Inside(q,bb)) { gridId = children[i]; break; } } if(i>=n) { break; } } return true; } bool vtkAMRInformation::FindGrid(double q[3], int level, unsigned int& gridId) { for(unsigned int i = 0; i < this->GetNumberOfDataSets(level); i++ ) { double gbounds[6]; this->GetBounds(level,i,gbounds); bool inside = Inside(q,gbounds); if(inside) { gridId = i; return true; } } return false; }