1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: TestStructuredGridGhostDataGenerator.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 // .NAME TestStructuredGridGhostDataGenerator.cxx -- Tests generation of ghost
16 // data for structured grids.
17 //
18 // .SECTION Description
19 // Serial tests for 2-D and 3-D ghost data generation of multi-block structured
20 // grid datasets. The tests apply an XYZ field to the nodes and cells of the
21 // domain and ensure that the created ghost data have the correct fields.
22
23 // C++ includes
24 #include <iostream>
25 #include <sstream>
26 #include <cassert>
27 #include <string>
28 #include <vector>
29 #include <set>
30
31 // VTK includes
32 #include "vtkDataSet.h"
33 #include "vtkStructuredGrid.h"
34 #include "vtkMultiBlockDataSet.h"
35 #include "vtkStructuredGridPartitioner.h"
36 #include "vtkStructuredGridGhostDataGenerator.h"
37 #include "vtkXMLMultiBlockDataWriter.h"
38 #include "vtkPointData.h"
39 #include "vtkCellData.h"
40 #include "vtkCell.h"
41 #include "vtkDoubleArray.h"
42 #include "vtkMathUtilities.h"
43 #include "vtkUniformGrid.h"
44 #include "vtkImageToStructuredGrid.h"
45
46
47 //#define DEBUG_ON
48
49 namespace
50 {
51
52 //------------------------------------------------------------------------------
53 // Description:
54 // Write the uniform grid multi-block dataset into an XML file.
WriteMultiBlock(vtkMultiBlockDataSet * mbds,const std::string & prefix)55 void WriteMultiBlock( vtkMultiBlockDataSet *mbds, const std::string &prefix )
56 {
57 #ifdef DEBUG_ON
58 assert( "pre: Multi-block is nullptr!" && (mbds != nullptr) );
59
60 vtkXMLMultiBlockDataWriter *writer = vtkXMLMultiBlockDataWriter::New();
61 assert( "pre: Cannot allocate writer" && (writer != nullptr) );
62
63 std::ostringstream oss;
64 oss.str("");
65 oss << prefix << mbds->GetNumberOfBlocks() << "."
66 << writer->GetDefaultFileExtension();
67 writer->SetFileName( oss.str().c_str() );
68 writer->SetInputData( mbds );
69 writer->Write();
70
71 writer->Delete();
72 #else
73 (void)(prefix);
74 (void)(mbds);
75 #endif
76 }
77
78 //------------------------------------------------------------------------------
CheckNodeFieldsForGrid(vtkStructuredGrid * grid)79 bool CheckNodeFieldsForGrid( vtkStructuredGrid *grid )
80 {
81 assert("pre: grid should not be nullptr" && (grid != nullptr) );
82 assert("pre: grid should have a NODE-XYZ array" &&
83 grid->GetPointData()->HasArray("NODE-XYZ") );
84
85 double xyz[3];
86 vtkDoubleArray *array =
87 vtkArrayDownCast<vtkDoubleArray>( grid->GetPointData()->GetArray("NODE-XYZ") );
88 assert("pre: num tuples must match number of nodes" &&
89 (array->GetNumberOfTuples() == grid->GetNumberOfPoints()) );
90 assert("pre: num components must be 3" &&
91 (array->GetNumberOfComponents()==3));
92
93 for( vtkIdType idx=0; idx < grid->GetNumberOfPoints(); ++idx )
94 {
95 grid->GetPoint( idx, xyz );
96
97 for( int i=0; i < 3; ++i )
98 {
99 if( !vtkMathUtilities::FuzzyCompare(xyz[i],array->GetComponent(idx,i) ) )
100 {
101 std::cout << "Node Data mismatch: " << xyz[i] << " ";
102 std::cout << array->GetComponent(idx,i);
103 std::cout << std::endl;
104 std::cout.flush();
105 return false;
106 } // END if fuzzy-compare
107 } // END for all components
108 } // END for all nodes
109 return true;
110 }
111
112 //------------------------------------------------------------------------------
CheckCellFieldsForGrid(vtkStructuredGrid * grid)113 bool CheckCellFieldsForGrid( vtkStructuredGrid *grid )
114 {
115 assert("pre: grid should not be nullptr" && (grid != nullptr) );
116 assert("pre: grid should have a NODE-XYZ array" &&
117 grid->GetCellData()->HasArray("CELL-XYZ") );
118
119 double centroid[3];
120 double xyz[3];
121 vtkDoubleArray *array =
122 vtkArrayDownCast<vtkDoubleArray>(grid->GetCellData()->GetArray("CELL-XYZ") );
123 assert("pre: num tuples must match number of nodes" &&
124 (array->GetNumberOfTuples() == grid->GetNumberOfCells()) );
125 assert("pre: num components must be 3" &&
126 (array->GetNumberOfComponents()==3));
127
128 vtkIdList *nodeIds = vtkIdList::New();
129 for( vtkIdType cellIdx=0; cellIdx < grid->GetNumberOfCells(); ++cellIdx )
130 {
131 nodeIds->Initialize();
132 grid->GetCellPoints(cellIdx,nodeIds);
133 double xsum = 0.0;
134 double ysum = 0.0;
135 double zsum = 0.0;
136 for( vtkIdType node=0; node < nodeIds->GetNumberOfIds(); ++node )
137 {
138 vtkIdType meshPntIdx = nodeIds->GetId( node );
139 grid->GetPoint( meshPntIdx, xyz );
140 xsum += xyz[0];
141 ysum += xyz[1];
142 zsum += xyz[2];
143 } // END for all nodes
144
145 centroid[0] = centroid[1] = centroid[2] = 0.0;
146 centroid[0] = xsum / static_cast<double>( nodeIds->GetNumberOfIds() );
147 centroid[1] = ysum / static_cast<double>( nodeIds->GetNumberOfIds() );
148 centroid[2] = zsum / static_cast<double>( nodeIds->GetNumberOfIds() );
149
150 for( int i=0; i < 3; ++i )
151 {
152 if( !vtkMathUtilities::FuzzyCompare(
153 centroid[i],array->GetComponent(cellIdx,i)) )
154 {
155 std::cout << "Cell Data mismatch: " << centroid[i] << " ";
156 std::cout << array->GetComponent(cellIdx,i);
157 std::cout << std::endl;
158 std::cout.flush();
159 nodeIds->Delete();
160 return false;
161 } // END if fuzz-compare
162 } // END for all components
163 } // END for all cells
164 nodeIds->Delete();
165 return true;
166 }
167
168 //------------------------------------------------------------------------------
CheckFields(vtkMultiBlockDataSet * mbds,bool hasNodeData,bool hasCellData)169 int CheckFields( vtkMultiBlockDataSet *mbds,bool hasNodeData,bool hasCellData )
170 {
171 assert("pre: input multi-block is nullptr" && (mbds != nullptr) );
172
173 if( !hasNodeData && !hasCellData )
174 {
175 return 0;
176 }
177
178 for(unsigned int block=0; block < mbds->GetNumberOfBlocks(); ++block )
179 {
180 vtkStructuredGrid *grid =
181 vtkStructuredGrid::SafeDownCast(mbds->GetBlock(block));
182 assert("pre: grid is not nullptr" && (grid != nullptr) );
183
184 if( hasNodeData )
185 {
186 if( !CheckNodeFieldsForGrid( grid ) )
187 {
188 return 1;
189 }
190 }
191
192 if( hasCellData )
193 {
194 if( !CheckCellFieldsForGrid( grid ) )
195 {
196 std::cout << "CheckCellFieldsForGrid failed for block " << block << "\n";
197 std::cout.flush();
198 return 1;
199 }
200 }
201
202 } // END for all blocks
203
204 return 0;
205 }
206
207 //------------------------------------------------------------------------------
208 // Description:
209 // Adds and XYZ vector field in the nodes of the data-set
AddNodeCenteredXYZField(vtkMultiBlockDataSet * mbds)210 void AddNodeCenteredXYZField( vtkMultiBlockDataSet *mbds )
211 {
212 assert("pre: Multi-block is nullptr!" && (mbds != nullptr) );
213
214 for( unsigned int block=0; block < mbds->GetNumberOfBlocks(); ++block )
215 {
216 vtkStructuredGrid *grid =
217 vtkStructuredGrid::SafeDownCast(mbds->GetBlock(block));
218 assert("pre: grid is nullptr for the given block" && (grid != nullptr) );
219
220 vtkDoubleArray *nodeXYZArray = vtkDoubleArray::New();
221 nodeXYZArray->SetName( "NODE-XYZ" );
222 nodeXYZArray->SetNumberOfComponents( 3 );
223 nodeXYZArray->SetNumberOfTuples( grid->GetNumberOfPoints() );
224
225 double xyz[3];
226 for( vtkIdType pntIdx=0; pntIdx < grid->GetNumberOfPoints(); ++pntIdx )
227 {
228 grid->GetPoint( pntIdx, xyz );
229 nodeXYZArray->SetComponent( pntIdx, 0, xyz[0] );
230 nodeXYZArray->SetComponent( pntIdx, 1, xyz[1] );
231 nodeXYZArray->SetComponent( pntIdx, 2, xyz[2] );
232 } // END for all points
233
234 grid->GetPointData()->AddArray( nodeXYZArray );
235 nodeXYZArray->Delete();
236 } // END for all blocks
237
238 }
239
240 //------------------------------------------------------------------------------
241 // Description:
242 // Adds and XYZ vector field in the nodes of the dataset
AddCellCenteredXYZField(vtkMultiBlockDataSet * mbds)243 void AddCellCenteredXYZField( vtkMultiBlockDataSet *mbds )
244 {
245 assert("pre: Multi-block is nullptr!" && (mbds != nullptr) );
246
247 for( unsigned int block=0; block < mbds->GetNumberOfBlocks(); ++block )
248 {
249 vtkStructuredGrid *grid =
250 vtkStructuredGrid::SafeDownCast(mbds->GetBlock(block));
251 assert("pre: grid is nullptr for the given block" && (grid != nullptr) );
252
253 vtkDoubleArray *cellXYZArray = vtkDoubleArray::New();
254 cellXYZArray->SetName( "CELL-XYZ" );
255 cellXYZArray->SetNumberOfComponents( 3 );
256 cellXYZArray->SetNumberOfTuples( grid->GetNumberOfCells() );
257
258 double centroid[3];
259 double xyz[3];
260 for( vtkIdType cellIdx=0; cellIdx < grid->GetNumberOfCells(); ++cellIdx )
261 {
262 vtkCell *c = grid->GetCell( cellIdx );
263 assert( "pre: cell is not nullptr" && (c != nullptr) );
264
265 double xsum = 0.0;
266 double ysum = 0.0;
267 double zsum = 0.0;
268 for( vtkIdType node=0; node < c->GetNumberOfPoints(); ++node )
269 {
270 vtkIdType meshPntIdx = c->GetPointId( node );
271 grid->GetPoint( meshPntIdx, xyz );
272 xsum += xyz[0];
273 ysum += xyz[1];
274 zsum += xyz[2];
275 } // END for all nodes
276
277 centroid[0] = xsum / c->GetNumberOfPoints();
278 centroid[1] = ysum / c->GetNumberOfPoints();
279 centroid[2] = zsum / c->GetNumberOfPoints();
280
281 cellXYZArray->SetComponent( cellIdx, 0, centroid[0] );
282 cellXYZArray->SetComponent( cellIdx, 1, centroid[1] );
283 cellXYZArray->SetComponent( cellIdx, 2, centroid[2] );
284 } // END for all cells
285
286 grid->GetCellData()->AddArray( cellXYZArray );
287 cellXYZArray->Delete();
288 } // END for all blocks
289 }
290
291 //------------------------------------------------------------------------------
292 // Description:
293 // Creates a test data-set.
GetDataSet(double globalOrigin[3],int WholeExtent[6],double gridSpacing[3],const int numPartitions,const int numGhosts,const bool AddNodeData,const bool AddCellData)294 vtkMultiBlockDataSet* GetDataSet(
295 double globalOrigin[3], int WholeExtent[6],double gridSpacing[3],
296 const int numPartitions, const int numGhosts,
297 const bool AddNodeData, const bool AddCellData )
298 {
299 // STEP 0: Get the global grid dimensions
300 int dims[3];
301 vtkStructuredData::GetDimensionsFromExtent( WholeExtent, dims );
302
303 // STEP 1: Get the whole grid as a uniform grid instance
304 vtkUniformGrid *wholeGrid = vtkUniformGrid::New();
305 wholeGrid->SetOrigin( globalOrigin );
306 wholeGrid->SetSpacing( gridSpacing );
307 wholeGrid->SetDimensions( dims );
308
309 // STEP 2: Conver to structured grid
310 vtkImageToStructuredGrid *img2sgrid = vtkImageToStructuredGrid::New();
311 assert("pre:" && (img2sgrid != nullptr));
312 img2sgrid->SetInputData( wholeGrid );
313 img2sgrid->Update();
314 vtkStructuredGrid *wholeStructuredGrid = vtkStructuredGrid::New();
315 wholeStructuredGrid->DeepCopy( img2sgrid->GetOutput() );
316 img2sgrid->Delete();
317 wholeGrid->Delete();
318
319 // STEP 3: Partition the structured grid domain
320 vtkStructuredGridPartitioner *gridPartitioner =
321 vtkStructuredGridPartitioner::New();
322 gridPartitioner->SetInputData( wholeStructuredGrid );
323 gridPartitioner->SetNumberOfPartitions( numPartitions );
324 gridPartitioner->SetNumberOfGhostLayers( numGhosts );
325 gridPartitioner->Update();
326
327 // STEP 4: Get the partitioned dataset
328 vtkMultiBlockDataSet *mbds =
329 vtkMultiBlockDataSet::SafeDownCast(gridPartitioner->GetOutput() );
330 mbds->SetReferenceCount( mbds->GetReferenceCount()+1 );
331
332 // STEP 5: Delete temporary data
333 wholeStructuredGrid->Delete();
334 gridPartitioner->Delete();
335
336 // STEP 6: Add node-centered and cell-centered fields
337 if( AddNodeData )
338 {
339 AddNodeCenteredXYZField( mbds );
340 }
341
342 if( AddCellData )
343 {
344 AddCellCenteredXYZField( mbds );
345 }
346
347 return( mbds );
348 }
349
350 //------------------------------------------------------------------------------
351 // Description:
352 // Test 2-D StructuredGridGhostDataGenerator
Test2D(const bool hasNodeData,const bool hasCellData,const int numPartitions,const int numGhosts)353 int Test2D(
354 const bool hasNodeData, const bool hasCellData,
355 const int numPartitions, const int numGhosts )
356 {
357 std::cout << "===================\n";
358 std::cout << "Testing 2-D ghost generation....\n";
359 std::cout << "Number of Partitions: " << numPartitions << std::endl;
360 std::cout << "Number of ghost-layers in the input: " << numGhosts << "\n";
361 std::cout << "Number of ghost-layers to be generated: 1\n";
362 std::cout << "Node-centered data: ";
363 if( hasNodeData )
364 {
365 std::cout << "Yes\n";
366 }
367 else
368 {
369 std::cout << "No\n";
370 }
371 std::cout << "Cell-centered data: ";
372 if( hasCellData )
373 {
374 std::cout << "Yes\n";
375 }
376 else
377 {
378 std::cout << "No\n";
379 }
380 std::cout.flush();
381
382 int rc = 0;
383
384 int WholeExtent[6] = {0,49,0,49,0,0};
385 double h[3] = {0.5,0.5,0.5};
386 double p[3] = {0.0,0.0,0.0};
387
388 vtkMultiBlockDataSet *mbds = GetDataSet(p,WholeExtent,h,
389 numPartitions,numGhosts,hasNodeData,hasCellData);
390 WriteMultiBlock( mbds, "STRUCTUREDINITIAL");
391
392 vtkStructuredGridGhostDataGenerator *ghostDataGenerator =
393 vtkStructuredGridGhostDataGenerator::New();
394
395 ghostDataGenerator->SetInputData( mbds );
396 ghostDataGenerator->SetNumberOfGhostLayers( 1 );
397 ghostDataGenerator->Update();
398
399 vtkMultiBlockDataSet *ghostDataSet = ghostDataGenerator->GetOutput();
400 WriteMultiBlock( ghostDataSet, "STRUCTUREDGHOSTED" );
401
402 rc = CheckFields( ghostDataSet, hasNodeData, hasCellData );
403 mbds->Delete();
404 ghostDataGenerator->Delete();
405 return( rc );
406 }
407
408 //------------------------------------------------------------------------------
409 // Description:
410 // Test 2-D StructuredGridGhostDataGenerator
Test3D(const bool hasNodeData,const bool hasCellData,const int numPartitions,const int numGhosts)411 int Test3D(
412 const bool hasNodeData, const bool hasCellData,
413 const int numPartitions, const int numGhosts )
414 {
415 std::cout << "===================\n";
416 std::cout << "Testing 3-D ghost generation....\n";
417 std::cout << "Number of Partitions: " << numPartitions << std::endl;
418 std::cout << "Number of ghost-layers in the input: " << numGhosts << "\n";
419 std::cout << "Number of ghost-layers to be generated: 1\n";
420 std::cout << "Node-centered data: ";
421 if( hasNodeData )
422 {
423 std::cout << "Yes\n";
424 }
425 else
426 {
427 std::cout << "No\n";
428 }
429 std::cout << "Cell-centered data: ";
430 if( hasCellData )
431 {
432 std::cout << "Yes\n";
433 }
434 else
435 {
436 std::cout << "No\n";
437 }
438 std::cout.flush();
439
440 int rc = 0;
441 int WholeExtent[6] = {0,49,0,49,0,49};
442 double h[3] = {0.5,0.5,0.5};
443 double p[3] = {0.0,0.0,0.0};
444
445 vtkMultiBlockDataSet *mbds = GetDataSet(p,WholeExtent,h,
446 numPartitions,numGhosts,hasNodeData,hasCellData);
447 WriteMultiBlock( mbds, "STRUCTUREDINITIAL");
448
449 vtkStructuredGridGhostDataGenerator *ghostDataGenerator =
450 vtkStructuredGridGhostDataGenerator::New();
451 ghostDataGenerator->SetInputData( mbds );
452 ghostDataGenerator->SetNumberOfGhostLayers( 1 );
453 ghostDataGenerator->Update();
454
455 vtkMultiBlockDataSet *ghostedDataSet = ghostDataGenerator->GetOutput();
456 WriteMultiBlock( ghostedDataSet, "STRUCTUREDGHOSTED" );
457
458 rc = CheckFields( ghostedDataSet, hasNodeData, hasCellData );
459 mbds->Delete();
460 ghostDataGenerator->Delete();
461
462 return( rc );
463 }
464
465 //------------------------------------------------------------------------------
466 // Description:
467 // Tests StructuredGridGhostDataGenerator
TestStructuredGridGhostDataGenerator_internal(int,char * [])468 int TestStructuredGridGhostDataGenerator_internal(int, char *[])
469 {
470 int rc = 0;
471 rc += Test2D(false,false,4,0);
472 rc += Test2D(true,false,4,0);
473 rc += Test2D(false,true,4,0);
474 rc += Test2D(true,true,4,0);
475
476 rc += Test3D(true,false,32,0);
477 rc += Test3D(false,true,32,0);
478 rc += Test3D(true,true,32,0);
479 return( rc );
480 }
481
482 }
483
484 //------------------------------------------------------------------------------
485 // Description:
486 // Program main
TestStructuredGridGhostDataGenerator(int argc,char * argv[])487 int TestStructuredGridGhostDataGenerator( int argc, char *argv[] )
488 {
489 if( argc==1 )
490 {
491 return( TestStructuredGridGhostDataGenerator_internal(argc, argv) );
492 }
493 int rc = 0;
494 int NumBlocks = 0;
495 int NumGhostLayers = 0;
496 if( argc != 3 )
497 {
498 std::cout << "Usage: ./bin/TestStructuredGridGhostDataGenerator <N> <NG>\n";
499 std::cout.flush();
500 return 0;
501 }
502
503 NumBlocks = atoi(argv[1]);
504 NumGhostLayers = atoi(argv[2]);
505
506 std::cout << "Running 2-D Test with just geometry...";
507 std::cout.flush();
508 rc += Test2D(false,false,NumBlocks,NumGhostLayers);
509 if( rc == 0 )
510 {
511 std::cout << "[OK]\n";
512 std::cout.flush();
513 }
514 else
515 {
516 std::cout << "FAILED!!!!\n";
517 std::cout.flush();
518 }
519
520
521 std::cout << "Running 2-D Test with node fields...";
522 std::cout.flush();
523 rc += Test2D(true, false, NumBlocks, NumGhostLayers );
524 if( rc == 0 )
525 {
526 std::cout << "[OK]\n";
527 std::cout.flush();
528 }
529 else
530 {
531 std::cout << "FAILED!!!!\n";
532 std::cout.flush();
533 }
534
535 std::cout << "Running 2-D Test with both cell/node fields...";
536 std::cout.flush();
537 rc += Test2D(true,true,NumBlocks,NumGhostLayers);
538 if( rc == 0 )
539 {
540 std::cout << "[OK]\n";
541 std::cout.flush();
542 }
543 else
544 {
545 std::cout << "FAILED!!!!\n";
546 std::cout.flush();
547 }
548 return 0;
549 }
550
551