1 /*=========================================================================
2 
3  Program:   Visualization Toolkit
4  Module:    vtkAMRUtilities.cxx
5 
6  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7  All rights reserved.
8  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10  This software is distributed WITHOUT ANY WARRANTY; without even
11  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12  PURPOSE.  See the above copyright notice for more information.
13 
14  =========================================================================*/
15 #include "vtkAMRBox.h"
16 #include "vtkAMRInformation.h"
17 #include "vtkAMRUtilities.h"
18 #include "vtkCellData.h"
19 #include "vtkCompositeDataIterator.h"
20 #include "vtkDataArray.h"
21 #include "vtkFieldData.h"
22 #include "vtkOverlappingAMR.h"
23 #include "vtkPointData.h"
24 #include "vtkStructuredData.h"
25 #include "vtkUniformGrid.h"
26 #include "vtkUnsignedCharArray.h"
27 #include <cmath>
28 #include <limits>
29 #include <cassert>
30 
31 #define IMIN(ext) ext[0]
32 #define IMAX(ext) ext[1]
33 #define JMIN(ext) ext[2]
34 #define JMAX(ext) ext[3]
35 #define KMIN(ext) ext[4]
36 #define KMAX(ext) ext[5]
37 
38 //------------------------------------------------------------------------------
PrintSelf(std::ostream & os,vtkIndent indent)39 void vtkAMRUtilities::PrintSelf( std::ostream& os, vtkIndent indent )
40 {
41   this->Superclass::PrintSelf( os, indent );
42 }
43 
44 //------------------------------------------------------------------------------
HasPartiallyOverlappingGhostCells(vtkOverlappingAMR * amr)45 bool vtkAMRUtilities::HasPartiallyOverlappingGhostCells(
46     vtkOverlappingAMR *amr)
47 {
48   assert("pre: input AMR data is NULL" && (amr != NULL) );
49   int numLevels = static_cast<int>( amr->GetNumberOfLevels() );
50   int levelIdx  = numLevels-1;
51   for(; levelIdx > 0; --levelIdx )
52     {
53     int r = amr->GetRefinementRatio( levelIdx );
54     unsigned int numDataSets = amr->GetNumberOfDataSets( levelIdx );
55     for( unsigned int dataIdx=0; dataIdx < numDataSets; ++dataIdx )
56       {
57       const vtkAMRBox& myBox = amr->GetAMRInfo()->GetAMRBox(levelIdx,dataIdx);
58       const int* lo = myBox.GetLoCorner();
59       int hi[3];
60       myBox.GetValidHiCorner(hi);
61       vtkAMRBox coarsenedBox = myBox;
62       coarsenedBox.Coarsen(r);
63 
64       // Detecting partially overlapping boxes is based on the following:
65       // Cell location k at level L-1 holds the range [k*r,k*r+(r-1)] of
66       // level L, where r is the refinement ratio. Consequently, if the
67       // min extent of the box is greater than k*r or if the max extent
68       // of the box is less than k*r+(r-1), then the grid partially overlaps.
69       for( int i=0; i < 3; ++i )
70         {
71         if(myBox.EmptyDimension(i))
72           {
73           continue;
74           }
75         int minRange[2];
76         minRange[0] = coarsenedBox.GetLoCorner()[i]*r;
77         minRange[1] = coarsenedBox.GetLoCorner()[i]*r + (r-1);
78         if( lo[i] > minRange[0] )
79           {
80           return true;
81           }
82 
83         int coarseHi[3];
84         coarsenedBox.GetValidHiCorner(coarseHi);
85         int maxRange[2];
86         maxRange[0] = coarseHi[i]*r;
87         maxRange[1] = coarseHi[i]*r + (r-1);
88         if( hi[i] < maxRange[1] )
89           {
90           return true;
91           }
92         } // END for all dimensions
93 
94       } // END for all data at the current level
95     } // END for all levels
96   return false;
97 }
98 
99 
100 //------------------------------------------------------------------------------
CopyFieldData(vtkFieldData * target,vtkIdType targetIdx,vtkFieldData * source,vtkIdType srcIdx)101 void vtkAMRUtilities::CopyFieldData(
102     vtkFieldData *target, vtkIdType targetIdx,
103     vtkFieldData *source, vtkIdType srcIdx )
104 {
105   assert("pre: target should not be NULL" && (target != NULL) );
106   assert("pre: source should not be NULL" && (source != NULL) );
107   assert("pre: number of arrays between source and target does not match!" &&
108          (source->GetNumberOfArrays()==target->GetNumberOfArrays() ) );
109 
110   for( int arrayIdx=0; arrayIdx < source->GetNumberOfArrays(); ++arrayIdx )
111     {
112     vtkDataArray *targetArray = target->GetArray( arrayIdx );
113     vtkDataArray *srcArray    = source->GetArray( arrayIdx );
114     assert( "pre: target array is NULL!" && (targetArray != NULL) );
115     assert( "pre: source array is NULL!" && (srcArray != NULL) );
116     assert( "pre: targer/source array number of components mismatch!" &&
117             (targetArray->GetNumberOfComponents()==
118              srcArray->GetNumberOfComponents() ) );
119     assert( "pre: target/source array names mismatch!" &&
120             (strcmp(targetArray->GetName(),srcArray->GetName()) == 0) );
121     assert( "pre: source index is out-of-bounds" &&
122             (srcIdx >=0) &&
123             (srcIdx < srcArray->GetNumberOfTuples() ) );
124     assert( "pre: target index is out-of-bounds" &&
125             (targetIdx >= 0) &&
126             (targetIdx < targetArray->GetNumberOfTuples() ) );
127 
128     // copy the tuple from the source array
129     targetArray->SetTuple( targetIdx, srcIdx, srcArray );
130     } // END for all arrays
131 
132 }
133 
134 //------------------------------------------------------------------------------
CopyFieldsWithinRealExtent(int realExtent[6],vtkUniformGrid * ghostedGrid,vtkUniformGrid * strippedGrid)135 void vtkAMRUtilities::CopyFieldsWithinRealExtent(
136     int realExtent[6],
137     vtkUniformGrid *ghostedGrid,
138     vtkUniformGrid *strippedGrid)
139 {
140   assert("pre: input ghost grid is NULL" && (ghostedGrid != NULL) );
141   assert("pre: input stripped grid is NULL" && (strippedGrid != NULL) );
142 
143   // STEP 0: Initialize the unghosted grid fields (point/cell data)
144   strippedGrid->GetPointData()->CopyAllOn();
145   strippedGrid->GetPointData()->CopyAllocate(
146       ghostedGrid->GetPointData(),strippedGrid->GetNumberOfPoints() );
147   strippedGrid->GetCellData()->CopyAllOn();
148   strippedGrid->GetCellData()->CopyAllocate(
149       ghostedGrid->GetCellData(),strippedGrid->GetNumberOfCells() );
150 
151   // STEP 1: Ensure each array has the right number of tuples, for some reason
152   // CopyAllocate does not allocate the arrays with the prescribed size.
153   int arrayIdx = 0;
154   for(;arrayIdx < strippedGrid->GetPointData()->GetNumberOfArrays();++arrayIdx)
155     {
156     strippedGrid->GetPointData()->GetArray(arrayIdx)->
157         SetNumberOfTuples(strippedGrid->GetNumberOfPoints() );
158     } // END for all node arrays
159 
160   for(;arrayIdx < strippedGrid->GetCellData()->GetNumberOfArrays();++arrayIdx)
161     {
162     strippedGrid->GetCellData()->GetArray(arrayIdx)->
163         SetNumberOfTuples( strippedGrid->GetNumberOfCells() );
164     } // END for all cell arrays
165 
166   // STEP 2: Get the data-description
167   int dataDescription =
168       vtkStructuredData::GetDataDescriptionFromExtent(realExtent);
169   // NOTE: a mismatch in the description here is possible but, very unlikely.
170   // For example, consider a grid on the XY-PLANE that is padded with ghost
171   // nodes along the z-dimension. Consequently, the ghosted grid will have
172   // a 3-D data-description and the unghosted grid will be 2-D. Again, although
173   // possible, this is not a realistic use-case. We will just catch this error
174   // here and fix if we ever come across such use-case.
175   assert("pre: description of ghosted and non-ghosted grid mismatch!" &&
176          (dataDescription == vtkStructuredData::GetDataDescription(
177                  ghostedGrid->GetDimensions())));
178 
179   // STEP 3: Get the corresponding cell-extent for accessing cell fields
180   int realCellExtent[6];
181   vtkStructuredData::GetCellExtentFromPointExtent(
182       realExtent,realCellExtent,dataDescription);
183 
184   // STEP 4: Loop through all real nodes/cells and copy the fields onto the
185   // stripped grid.
186   int ijk[3];
187   int lijk[3];
188   for(int i=IMIN(realExtent); i <= IMAX(realExtent); ++i)
189     {
190     for(int j=JMIN(realExtent); j <= JMAX(realExtent); ++j)
191       {
192       for( int k=KMIN(realExtent); k <= KMAX(realExtent); ++k)
193         {
194         // Vectorize i,j,k
195         ijk[0]=i; ijk[1]=j; ijk[2]=k;
196 
197         // Compute the local i,j,k on the un-ghosted grid
198         vtkStructuredData::GetLocalStructuredCoordinates(
199             ijk,realExtent,lijk,dataDescription);
200 
201         // Compute the source index w.r.t. the ghosted grid dimensions
202         vtkIdType sourceIdx =
203             vtkStructuredData::ComputePointId(
204                 ghostedGrid->GetDimensions(), ijk, dataDescription );
205 
206         // Compute the target index w.r.t the real extent
207         vtkIdType targetIdx =
208             vtkStructuredData::ComputePointIdForExtent(
209                 realExtent,ijk,dataDescription);
210 
211         // Copy node-centered data
212         vtkAMRUtilities::CopyFieldData(
213             strippedGrid->GetPointData(),targetIdx,
214             ghostedGrid->GetPointData(),sourceIdx);
215 
216         // If within the cell-extent, copy cell-centered data
217         if( (i >= IMIN(realCellExtent)) && (i <= IMAX(realCellExtent))&&
218             (j >= JMIN(realCellExtent)) && (j <= JMAX(realCellExtent))&&
219             (k >= KMIN(realCellExtent)) && (k <= KMAX(realCellExtent)) )
220           {
221           // Compute the source cell index w.r.t. the ghosted grid
222           vtkIdType sourceCellIdx =
223               vtkStructuredData::ComputeCellId(
224                   ghostedGrid->GetDimensions(),ijk,dataDescription);
225 
226           // Compute the target cell index w.r.t. the un-ghosted grid
227           vtkIdType targetCellIdx =
228               vtkStructuredData::ComputeCellId(
229                   strippedGrid->GetDimensions(),lijk,dataDescription);
230 
231           // Copy cell-centered data
232           vtkAMRUtilities::CopyFieldData(
233               strippedGrid->GetCellData(),targetCellIdx,
234               ghostedGrid->GetCellData(),sourceCellIdx);
235           } // END if within the cell extent
236 
237         } // END for all k
238       } // END for all j
239     } // END for all i
240 }
241 
242 //------------------------------------------------------------------------------
StripGhostLayersFromGrid(vtkUniformGrid * grid,int ghost[6])243 vtkUniformGrid* vtkAMRUtilities::StripGhostLayersFromGrid(
244       vtkUniformGrid* grid, int ghost[6] )
245 {
246   assert("pre: input grid is NULL" && (grid != NULL) );
247 
248   // STEP 0: Get the grid properties, i.e., origin, dims, extent, etc.
249   double origin[3];
250   double spacing[3];
251   int dims[3];
252   int ghostedGridDims[3];
253 
254   grid->GetOrigin( origin );
255   grid->GetSpacing( spacing );
256   grid->GetDimensions( ghostedGridDims );
257   grid->GetDimensions( dims );
258 
259   int copyExtent[6];
260   grid->GetExtent( copyExtent );
261 
262   // STEP 1: Adjust origin, copyExtent, dims according to the supplied ghost
263   // vector.
264   for( int i=0; i < 3; ++i )
265     {
266     if( ghost[i*2] > 0)
267       {
268       copyExtent[i*2] += ghost[i*2];
269       dims[i]         -= ghost[i*2];
270       origin[i]       += ghost[i*2]*spacing[i];
271       }
272     if( ghost[i*2+1] > 0 )
273       {
274       dims[i]           -= ghost[i*2+1];
275       copyExtent[i*2+1] -= ghost[i*2+1];
276       }
277     } // END for all dimensions
278 
279   // STEP 2: Initialize the unghosted grid
280   vtkUniformGrid *myGrid = vtkUniformGrid::New();
281   myGrid->Initialize();
282   myGrid->SetOrigin(origin);
283   myGrid->SetSpacing(spacing);
284   myGrid->SetDimensions( dims );
285 
286   // STEP 3: Copy the field data within the real extent
287   vtkAMRUtilities::CopyFieldsWithinRealExtent(copyExtent,grid,myGrid);
288   return( myGrid );
289 }
290 
291 //------------------------------------------------------------------------------
StripGhostLayers(vtkOverlappingAMR * ghostedAMRData,vtkOverlappingAMR * strippedAMRData)292 void vtkAMRUtilities::StripGhostLayers(
293         vtkOverlappingAMR *ghostedAMRData,
294         vtkOverlappingAMR *strippedAMRData)
295 {
296   assert("pre: input AMR data is NULL" && (ghostedAMRData != NULL) );
297   assert("pre: outputAMR data is NULL" && (strippedAMRData != NULL) );
298   double spacing[3];
299 
300   if( !vtkAMRUtilities::HasPartiallyOverlappingGhostCells( ghostedAMRData ) )
301     {
302     strippedAMRData->ShallowCopy(ghostedAMRData);
303     return;
304     }
305 
306   // TODO: At some point we should check for overlapping cells within the
307   // same level, e.g., consider a level 0 with 2 abutting blocks that is
308   // ghosted by N !!!!
309   std::vector<int> blocksPerLevel(ghostedAMRData->GetNumberOfLevels());
310   for(unsigned int i=0; i<blocksPerLevel.size();i++)
311     {
312     blocksPerLevel[i] = ghostedAMRData->GetNumberOfDataSets(i);
313     }
314   strippedAMRData->Initialize(static_cast<int>(blocksPerLevel.size()),&blocksPerLevel[0]);
315   strippedAMRData->SetOrigin(ghostedAMRData->GetOrigin());
316   strippedAMRData->SetGridDescription(ghostedAMRData->GetGridDescription());
317 
318   ghostedAMRData->GetSpacing(0,spacing);
319   strippedAMRData->SetSpacing(0, spacing);
320   unsigned int dataIdx=0;
321   for( ;dataIdx < ghostedAMRData->GetNumberOfDataSets(0); ++dataIdx)
322     {
323     vtkUniformGrid* grid = ghostedAMRData->GetDataSet(0,dataIdx);
324     const vtkAMRBox& box = ghostedAMRData->GetAMRBox(0,dataIdx);
325     strippedAMRData->SetAMRBox(0,dataIdx,box);
326     strippedAMRData->SetDataSet(0,dataIdx,grid);
327     } // END for all data at level 0
328 
329   int ghost[6];
330   unsigned int levelIdx = 1;
331   for( ;levelIdx < ghostedAMRData->GetNumberOfLevels(); ++levelIdx )
332     {
333     dataIdx=0;
334     ghostedAMRData->GetSpacing(levelIdx,spacing);
335     strippedAMRData->SetSpacing(levelIdx, spacing);
336     for(;dataIdx < ghostedAMRData->GetNumberOfDataSets(levelIdx); ++dataIdx)
337       {
338       vtkUniformGrid *grid = ghostedAMRData->GetDataSet( levelIdx, dataIdx );
339       int r = ghostedAMRData->GetRefinementRatio( levelIdx );
340       vtkAMRBox myBox=ghostedAMRData->GetAMRBox(levelIdx,dataIdx);
341       vtkAMRBox strippedBox = myBox;
342       strippedBox.RemoveGhosts(r);
343 
344       strippedAMRData->SetAMRBox(levelIdx,dataIdx, strippedBox);
345       if( grid !=NULL )
346         {
347         myBox.GetGhostVector(r, ghost);
348 
349         vtkUniformGrid *strippedGrid=
350           vtkAMRUtilities::StripGhostLayersFromGrid(grid,ghost);
351 
352         assert(strippedBox == vtkAMRBox(strippedGrid->GetOrigin(), strippedGrid->GetDimensions(), strippedGrid->GetSpacing(),strippedAMRData->GetOrigin(),strippedGrid->GetGridDescription()));
353         strippedAMRData->SetAMRBox(levelIdx,dataIdx,strippedBox);
354         strippedAMRData->SetDataSet(levelIdx,dataIdx,strippedGrid);
355         strippedGrid->Delete();
356         }
357       } // END for all data at the given level
358     } // END for all levels
359 }
360 
361 //------------------------------------------------------------------------------
BlankCells(vtkOverlappingAMR * amr)362 void vtkAMRUtilities::BlankCells(vtkOverlappingAMR* amr)
363 {
364   vtkAMRInformation* info = amr->GetAMRInfo();
365   if(!info->HasRefinementRatio())
366     {
367     info->GenerateRefinementRatio();
368     }
369   if(!info->HasChildrenInformation())
370     {
371     info->GenerateParentChildInformation();
372     }
373 
374   std::vector<int> processorMap;
375   processorMap.resize(amr->GetTotalNumberOfBlocks(),-1);
376   vtkSmartPointer<vtkCompositeDataIterator> iter;
377   iter.TakeReference(amr->NewIterator());
378   iter->SkipEmptyNodesOn();
379 
380   for(iter->GoToFirstItem(); !iter->IsDoneWithTraversal(); iter->GoToNextItem())
381     {
382     unsigned int index = iter->GetCurrentFlatIndex();
383     processorMap[index] = 0;
384     }
385 
386   unsigned int numLevels =info->GetNumberOfLevels();
387   for(unsigned int i=0; i<numLevels; i++)
388     {
389     BlankGridsAtLevel(amr, i, info->GetChildrenAtLevel(i),processorMap);
390     }
391 }
392 
393 //------------------------------------------------------------------------------
BlankGridsAtLevel(vtkOverlappingAMR * amr,int levelIdx,std::vector<std::vector<unsigned int>> & children,const std::vector<int> & processMap)394 void vtkAMRUtilities::BlankGridsAtLevel(vtkOverlappingAMR* amr, int levelIdx,
395                         std::vector<std::vector<unsigned int> >& children,
396                         const std::vector<int>& processMap)
397 {
398   unsigned int numDataSets = amr->GetNumberOfDataSets(levelIdx);
399   int N;
400 
401   for( unsigned int dataSetIdx=0; dataSetIdx<numDataSets; dataSetIdx++)
402     {
403     const vtkAMRBox& box = amr->GetAMRBox(levelIdx, dataSetIdx);
404     vtkUniformGrid* grid = amr->GetDataSet(levelIdx, dataSetIdx);
405     if (grid == NULL )
406       {
407       continue;
408       }
409     N = grid->GetNumberOfCells();
410 
411     vtkUnsignedCharArray* vis = vtkUnsignedCharArray::New();
412     vis->SetName("visibility");
413     vis->SetNumberOfTuples( N );
414     vis->FillComponent(0,static_cast<char>(1));
415     grid->SetCellVisibilityArray(vis);
416     vis->Delete();
417 
418     if (children.size() <= dataSetIdx)
419       continue;
420 
421     std::vector<unsigned int>& dsChildren = children[dataSetIdx];
422     std::vector<unsigned int>::iterator iter;
423 
424     // For each higher res box fill in the cells that
425     // it covers
426     for (iter=dsChildren.begin(); iter!=dsChildren.end(); iter++)
427       {
428       vtkAMRBox ibox;;
429       int childGridIndex  = amr->GetCompositeIndex(levelIdx+1, *iter);
430       if(processMap[childGridIndex]<0)
431         {
432         continue;
433         }
434       if (amr->GetAMRInfo()->GetCoarsenedAMRBox(levelIdx+1, *iter, ibox))
435         {
436         ibox.Intersect(box);
437         const int *loCorner=ibox.GetLoCorner();
438         int hi[3];
439         ibox.GetValidHiCorner(hi);
440         for( int iz=loCorner[2]; iz<=hi[2]; iz++ )
441           {
442           for( int iy=loCorner[1]; iy<=hi[1]; iy++ )
443             {
444             for( int ix=loCorner[0]; ix<=hi[0]; ix++ )
445               {
446               vtkIdType id =  vtkAMRBox::GetCellLinearIndex(box,ix, iy, iz, grid->GetDimensions());
447               vis->SetValue(id, 0);
448               } // END for x
449             } // END for y
450           } // END for z
451         }
452       } // Processing all higher boxes for a specific coarse grid
453     }
454 }
455