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