1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: TestRandomMomentStatisticsMPI.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 /*
16 * Copyright 2011 Sandia Corporation.
17 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
18 * license for use of this work by or on behalf of the
19 * U.S. Government. Redistribution and use in source and binary forms, with
20 * or without modification, are permitted provided that this Notice and any
21 * statement of authorship are reproduced on all copies.
22 */
23 // .SECTION Thanks
24 // Thanks to Philippe Pebay, David Thompson and Janine Bennett from Sandia National Laboratories
25 // for implementing this test.
26 // This class was extended to auto-correlative statistics by Philippe Pebay, Kitware 2013
27
28 #include <vtk_mpi.h>
29
30 #include "vtkCorrelativeStatistics.h"
31 #include "vtkDescriptiveStatistics.h"
32 #include "vtkMultiCorrelativeStatistics.h"
33 #include "vtkPAutoCorrelativeStatistics.h"
34 #include "vtkPCorrelativeStatistics.h"
35 #include "vtkPDescriptiveStatistics.h"
36 #include "vtkPMultiCorrelativeStatistics.h"
37 #include "vtkPPCAStatistics.h"
38
39 #include "vtkDoubleArray.h"
40 #include "vtkIdTypeArray.h"
41 #include "vtkInformation.h"
42 #include "vtkMPIController.h"
43 #include "vtkMath.h"
44 #include "vtkMultiBlockDataSet.h"
45 #include "vtkStdString.h"
46 #include "vtkTable.h"
47 #include "vtkTimerLog.h"
48 #include "vtkVariantArray.h"
49
50 #include "vtksys/CommandLineArguments.hxx"
51
52 #include <sstream>
53
54 namespace
55 {
56
57 struct RandomSampleStatisticsArgs
58 {
59 int nVals;
60 double absTol;
61 bool skipDescriptive;
62 bool skipPDescriptive;
63 bool skipPAutoCorrelative;
64 bool skipPCorrelative;
65 bool skipPMultiCorrelative;
66 bool skipPPCA;
67 int* retVal;
68 int ioRank;
69 };
70
71 // This will be called by all processes
RandomSampleStatistics(vtkMultiProcessController * controller,void * arg)72 void RandomSampleStatistics(vtkMultiProcessController* controller, void* arg)
73 {
74 // Get test parameters
75 RandomSampleStatisticsArgs* args = reinterpret_cast<RandomSampleStatisticsArgs*>(arg);
76 *(args->retVal) = 0;
77
78 // Get MPI communicator
79 vtkMPICommunicator* com = vtkMPICommunicator::SafeDownCast(controller->GetCommunicator());
80
81 // Get local rank
82 int myRank = com->GetLocalProcessId();
83
84 // Seed random number generator
85 vtkMath::RandomSeed(static_cast<int>(vtkTimerLog::GetUniversalTime()) * (myRank + 1));
86
87 // Generate an input table that contains samples of mutually independent random variables
88 int nUniform = 2;
89 int nNormal = 2;
90 int nVariables = nUniform + nNormal;
91
92 vtkTable* inputData = vtkTable::New();
93 vtkDoubleArray* doubleArray[4];
94 vtkStdString columnNames[] = { "Standard Uniform 0", "Standard Uniform 1", "Standard Normal 0",
95 "Standard Normal 1" };
96
97 // Standard uniform samples
98 for (int c = 0; c < nUniform; ++c)
99 {
100 doubleArray[c] = vtkDoubleArray::New();
101 doubleArray[c]->SetNumberOfComponents(1);
102 doubleArray[c]->SetName(columnNames[c]);
103
104 double x;
105 for (int r = 0; r < args->nVals; ++r)
106 {
107 x = vtkMath::Random();
108 doubleArray[c]->InsertNextValue(x);
109 }
110
111 inputData->AddColumn(doubleArray[c]);
112 doubleArray[c]->Delete();
113 }
114
115 // Standard normal samples
116 for (int c = nUniform; c < nVariables; ++c)
117 {
118 doubleArray[c] = vtkDoubleArray::New();
119 doubleArray[c]->SetNumberOfComponents(1);
120 doubleArray[c]->SetName(columnNames[c]);
121
122 double x;
123 for (int r = 0; r < args->nVals; ++r)
124 {
125 x = vtkMath::Gaussian();
126 doubleArray[c]->InsertNextValue(x);
127 }
128
129 inputData->AddColumn(doubleArray[c]);
130 doubleArray[c]->Delete();
131 }
132
133 // Create timer to be used by all tests
134 vtkTimerLog* timer = vtkTimerLog::New();
135
136 // Storage for cross-checking between aggregated serial vs. parallel descriptive statistics
137 int n2Rows = 2 * nVariables;
138 double* extrema_agg = new double[n2Rows];
139 double* extrema_par = new double[n2Rows];
140 double* cardsAndMeans_agg = new double[n2Rows];
141 double* cardsAndMeans_par = new double[n2Rows];
142
143 // ************************** Serial descriptive Statistics **************************
144
145 // Skip serial descriptive statistics if requested
146 if (!args->skipDescriptive)
147 {
148 // Synchronize and start clock
149 com->Barrier();
150 timer->StartTimer();
151
152 // For verification, instantiate a serial descriptive statistics engine and set its ports
153 vtkDescriptiveStatistics* ds = vtkDescriptiveStatistics::New();
154 ds->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, inputData);
155
156 // Select all columns
157 for (int c = 0; c < nVariables; ++c)
158 {
159 ds->AddColumn(columnNames[c]);
160 }
161
162 // Test (serially) with Learn operation only (this is only to verify parallel statistics)
163 ds->SetLearnOption(true);
164 ds->SetDeriveOption(false);
165 ds->SetAssessOption(false);
166 ds->SetTestOption(false);
167 ds->Update();
168
169 // Get output data and meta tables
170 vtkMultiBlockDataSet* outputMetaDS = vtkMultiBlockDataSet::SafeDownCast(
171 ds->GetOutputDataObject(vtkStatisticsAlgorithm::OUTPUT_MODEL));
172 vtkTable* outputPrimary = vtkTable::SafeDownCast(outputMetaDS->GetBlock(0));
173
174 // Collect and aggregate serial cardinalities, extrema, and means
175 int nRows = outputPrimary->GetNumberOfRows();
176
177 // Make sure that the correct number of rows were retrieved
178 if (nRows != nVariables)
179 {
180 vtkGenericWarningMacro(
181 "Incorrect number of retrieved variables: " << nRows << " <> " << nVariables);
182 *(args->retVal) = 1;
183 }
184
185 // Aggregate serial results
186 double* extrema_l = new double[n2Rows];
187 double* cardsAndMeans_l = new double[n2Rows];
188 double dn;
189 for (vtkIdType r = 0; r < nRows; ++r)
190 {
191 dn = outputPrimary->GetValueByName(r, "Cardinality").ToDouble();
192 cardsAndMeans_l[2 * r] = dn;
193 cardsAndMeans_l[2 * r + 1] = dn * outputPrimary->GetValueByName(r, "Mean").ToDouble();
194
195 extrema_l[2 * r] = outputPrimary->GetValueByName(r, "Minimum").ToDouble();
196 // Collect -max instead of max so a single reduce op. (minimum) can process both extrema at a
197 // time
198 extrema_l[2 * r + 1] = -outputPrimary->GetValueByName(r, "Maximum").ToDouble();
199 }
200
201 // Reduce all extremal values, and gather all cardinalities and means, directly on I/O node
202 if (!com->Reduce(extrema_l, extrema_agg, n2Rows, vtkCommunicator::MIN_OP, args->ioRank))
203 {
204 vtkGenericWarningMacro("MPI error: process "
205 << myRank
206 << "could not reduce extrema. Serial vs. parallel cross-check will be meaningless.");
207 *(args->retVal) = 1;
208 }
209
210 if (!com->Reduce(
211 cardsAndMeans_l, cardsAndMeans_agg, n2Rows, vtkCommunicator::SUM_OP, args->ioRank))
212 {
213 vtkGenericWarningMacro("MPI error: process "
214 << myRank
215 << "could not reduce cardinalities and means. Serial vs. parallel cross-check will be "
216 "meaningless.");
217 *(args->retVal) = 1;
218 }
219
220 // Synchronize and stop clock
221 com->Barrier();
222 timer->StopTimer();
223
224 if (myRank == args->ioRank)
225 {
226 cout << "\n## Completed serial calculations of descriptive statistics:\n"
227 << " With partial aggregation calculated on process " << args->ioRank << "\n"
228 << " Wall time: " << timer->GetElapsedTime() << " sec.\n";
229
230 cout << " Calculated the following primary statistics:\n";
231 for (vtkIdType r = 0; r < nRows; ++r)
232 {
233 cout << " " << outputPrimary->GetColumnName(0) << "="
234 << outputPrimary->GetValue(r, 0).ToString() << " "
235 << "Cardinality"
236 << "=" << cardsAndMeans_agg[2 * r] << " "
237 << "Minimum"
238 << "=" << extrema_agg[2 * r] << " "
239 << "Maximum"
240 << "=" << -extrema_agg[2 * r + 1] << " "
241 << "Mean"
242 << "=" << cardsAndMeans_agg[2 * r + 1] / cardsAndMeans_agg[2 * r] << "\n";
243 }
244 }
245
246 // Clean up
247 delete[] cardsAndMeans_l;
248 delete[] extrema_l;
249 ds->Delete();
250 } // if ( ! args->skipDescriptive )
251 else if (myRank == args->ioRank)
252 {
253 cout << "\n## Skipped serial calculations of descriptive statistics.\n";
254 }
255
256 // ************************** Parallel Descriptive Statistics **************************
257
258 // Skip parallel descriptive statistics if requested
259 if (!args->skipPDescriptive)
260 {
261 // Now on to the actual parallel descriptive engine
262 // "68-95-99.7 rule" for 1 up to numRuleVal standard deviations
263 int numRuleVal = 6;
264
265 // Reference values
266 double sigmaRuleVal[] = { 68.2689492137, 95.4499736104, 99.7300203937, 99.9936657516,
267 99.9999426697, 99.9999998027 };
268
269 // Tolerances
270 double sigmaRuleTol[] = { 1., .5, .1, .05, .01, .005 };
271
272 // Synchronize and start clock
273 com->Barrier();
274 timer->StartTimer();
275
276 // Instantiate a parallel descriptive statistics engine and set its input data
277 vtkPDescriptiveStatistics* pds = vtkPDescriptiveStatistics::New();
278 pds->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, inputData);
279
280 // Select all columns
281 for (int c = 0; c < nVariables; ++c)
282 {
283 pds->AddColumn(columnNames[c]);
284 }
285
286 // Test (in parallel) with Learn, Derive, and Assess operations turned on
287 pds->SetLearnOption(true);
288 pds->SetDeriveOption(true);
289 pds->SetAssessOption(true);
290 pds->SetTestOption(false);
291 pds->SignedDeviationsOff(); // Use unsigned deviations
292 pds->Update();
293
294 // Synchronize and stop clock
295 com->Barrier();
296 timer->StopTimer();
297
298 // Get output data and meta tables
299 vtkMultiBlockDataSet* outputMetaDS = vtkMultiBlockDataSet::SafeDownCast(
300 pds->GetOutputDataObject(vtkStatisticsAlgorithm::OUTPUT_MODEL));
301 vtkTable* outputPrimary = vtkTable::SafeDownCast(outputMetaDS->GetBlock(0));
302 vtkTable* outputDerived = vtkTable::SafeDownCast(outputMetaDS->GetBlock(1));
303 vtkTable* outputData = pds->GetOutput(vtkStatisticsAlgorithm::OUTPUT_DATA);
304
305 if (myRank == args->ioRank)
306 {
307 cout << "\n## Completed parallel calculation of descriptive statistics (with assessment):\n"
308 << " Total sample size: " << outputPrimary->GetValueByName(0, "Cardinality").ToInt()
309 << " \n"
310 << " Wall time: " << timer->GetElapsedTime() << " sec.\n";
311
312 cout << " Calculated the following primary statistics:\n";
313 for (vtkIdType r = 0; r < outputPrimary->GetNumberOfRows(); ++r)
314 {
315 cout << " ";
316 for (int i = 0; i < outputPrimary->GetNumberOfColumns(); ++i)
317 {
318 cout << outputPrimary->GetColumnName(i) << "=" << outputPrimary->GetValue(r, i).ToString()
319 << " ";
320 }
321 cout << "\n";
322
323 // Store cardinalities, extremal and means for cross-verification
324 double dn = outputPrimary->GetValueByName(r, "Cardinality").ToDouble();
325
326 cardsAndMeans_par[2 * r] = dn;
327 cardsAndMeans_par[2 * r + 1] = dn * outputPrimary->GetValueByName(r, "Mean").ToDouble();
328
329 extrema_par[2 * r] = outputPrimary->GetValueByName(r, "Minimum").ToDouble();
330 extrema_par[2 * r + 1] = -outputPrimary->GetValueByName(r, "Maximum").ToDouble();
331 }
332
333 cout << " Calculated the following derived statistics:\n";
334 for (vtkIdType r = 0; r < outputDerived->GetNumberOfRows(); ++r)
335 {
336 cout << " ";
337 for (int i = 0; i < outputDerived->GetNumberOfColumns(); ++i)
338 {
339 cout << outputDerived->GetColumnName(i) << "=" << outputDerived->GetValue(r, i).ToString()
340 << " ";
341 }
342 cout << "\n";
343 }
344 }
345
346 // Verify that the DISTRIBUTED standard normal samples indeed satisfy the 68-95-99.7 rule
347 if (myRank == args->ioRank)
348 {
349 cout << "\n## Verifying whether the distributed standard normal samples satisfy the "
350 "68-95-99.7 rule:\n";
351 }
352
353 // For each normal variable, count deviations of more than 1, ..., numRuleVal standard
354 // deviations from the mean
355 for (int c = 0; c < nNormal; ++c)
356 {
357 // Use assessed values (relative deviations) to check distribution
358 std::ostringstream relDevName;
359 relDevName << "d(Standard Normal " << c << ")";
360
361 // Verification can be done only if assessed column is present
362 vtkAbstractArray* relDevArr = outputData->GetColumnByName(relDevName.str().c_str());
363 if (relDevArr)
364 {
365 // Assessed column should be an array of doubles
366 vtkDoubleArray* relDev = vtkArrayDownCast<vtkDoubleArray>(relDevArr);
367 if (relDev)
368 {
369 // Allocate and initialize counters
370 int* outsideStdv_l = new int[numRuleVal];
371 for (int d = 0; d < numRuleVal; ++d)
372 {
373 outsideStdv_l[d] = 0;
374 }
375
376 // Count outliers
377 double dev;
378 int n = outputData->GetNumberOfRows();
379 for (vtkIdType r = 0; r < n; ++r)
380 {
381 dev = relDev->GetValue(r);
382
383 // Count for all deviations from 1 to numRuleVal
384 for (int d = 0; d < numRuleVal; ++d)
385 {
386 if (dev >= 1. + d)
387 {
388 ++outsideStdv_l[d];
389 }
390 } //
391 } // for ( vtkIdType r = 0; r < n; ++ r )
392
393 // Sum all local counters
394 int* outsideStdv_g = new int[numRuleVal];
395 com->AllReduce(outsideStdv_l, outsideStdv_g, numRuleVal, vtkCommunicator::SUM_OP);
396
397 // Print out percentages of sample points within 1, ..., numRuleVal standard deviations
398 // from the mean.
399 if (myRank == args->ioRank)
400 {
401 cout << " " << outputData->GetColumnName(nUniform + c) << ":\n";
402 for (int d = 0; d < numRuleVal; ++d)
403 {
404 double testVal =
405 (1. -
406 outsideStdv_g[d] /
407 static_cast<double>(outputPrimary->GetValueByName(0, "Cardinality").ToInt())) *
408 100.;
409
410 cout << " " << testVal << "% within " << d + 1
411 << " standard deviation(s) from the mean.\n";
412
413 // Test some statistics
414 if (fabs(testVal - sigmaRuleVal[d]) > sigmaRuleTol[d])
415 {
416 vtkGenericWarningMacro("Incorrect value.");
417 *(args->retVal) = 1;
418 }
419 }
420 }
421
422 // Clean up
423 delete[] outsideStdv_l;
424 delete[] outsideStdv_g;
425 } // if ( relDev )
426 else
427 {
428 vtkGenericWarningMacro("Column " << relDevName.str().c_str() << " on process " << myRank
429 << " is not of type double.");
430 *(args->retVal) = 1;
431 }
432
433 } // if ( relDevArr )
434 else
435 {
436 vtkGenericWarningMacro(
437 "No assessment column called " << relDevName.str().c_str() << " on process " << myRank);
438 *(args->retVal) = 1;
439 }
440 } // for ( int c = 0; c < nNormal; ++ c )
441
442 // Clean up
443 pds->Delete();
444 } // if ( ! args->skipPDescriptive )
445 else if (myRank == args->ioRank)
446 {
447 cout << "\n## Skipped calculation of parallel descriptive statistics.\n";
448 }
449
450 // Cross-verify aggregated serial vs. parallel results only if both were calculated
451 if (!args->skipDescriptive && !args->skipPDescriptive)
452 {
453 if (myRank == args->ioRank)
454 {
455 cout << "\n## Cross-verifying aggregated serial vs. parallel descriptive statistics (within "
456 << args->absTol << " absolute tolerance).\n";
457 for (int i = 0; i < n2Rows; ++i)
458 {
459 if (fabs(cardsAndMeans_agg[i] - cardsAndMeans_par[i]) > args->absTol)
460 {
461 vtkGenericWarningMacro(
462 "Incorrect value(s) : " << cardsAndMeans_agg[i] << " <> " << cardsAndMeans_par[i]);
463 *(args->retVal) = 1;
464 }
465 if (extrema_agg[i] != extrema_par[i])
466 {
467 vtkGenericWarningMacro(
468 "Incorrect value(s) : " << extrema_agg[i] << " <> " << extrema_par[i]);
469 *(args->retVal) = 1;
470 }
471 } // for ( int i = 0; i < n2Rows; ++ i )
472 } // if ( myRank == args->ioRank )
473 } // if ( ! args->skipPDescriptive && ! args->skipPDescriptive )
474 else if (myRank == args->ioRank)
475 {
476 cout << "\n## Skipped cross-verification of aggregated serial vs. parallel descriptive "
477 "statistics.\n";
478 }
479
480 // Clean up
481 delete[] cardsAndMeans_agg;
482 delete[] cardsAndMeans_par;
483 delete[] extrema_agg;
484 delete[] extrema_par;
485
486 // ************************** Parallel Auto-Correlative Statistics **************************
487
488 // Skip parallel correlative statistics if requested
489 if (!args->skipPAutoCorrelative)
490 {
491 // Synchronize and start clock
492 com->Barrier();
493 timer->StartTimer();
494
495 // Instantiate a parallel auto-correlative statistics engine and set its input
496 vtkPAutoCorrelativeStatistics* pas = vtkPAutoCorrelativeStatistics::New();
497 pas->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, inputData);
498
499 // Select all columns
500 for (int c = 0; c < nVariables; ++c)
501 {
502 pas->AddColumn(columnNames[c]);
503 }
504
505 // Create input parameter table for the stationary case
506 vtkIdTypeArray* timeLags = vtkIdTypeArray::New();
507 timeLags->SetName("Time Lags");
508 timeLags->SetNumberOfTuples(1);
509 timeLags->SetValue(0, 0);
510 vtkTable* paramTable = vtkTable::New();
511 paramTable->AddColumn(timeLags);
512 timeLags->Delete();
513
514 // Set spatial cardinality
515 pas->SetSliceCardinality(args->nVals);
516
517 // Set parameters for autocorrelation of whole data set with respect to itself
518 pas->SetInputData(vtkStatisticsAlgorithm::LEARN_PARAMETERS, paramTable);
519 paramTable->Delete();
520
521 // Test (in parallel) with Learn, Derive operations turned on
522 pas->SetLearnOption(true);
523 pas->SetDeriveOption(true);
524 pas->SetAssessOption(false);
525 pas->SetTestOption(false);
526 pas->Update();
527
528 // Get output data and meta tables
529 vtkMultiBlockDataSet* outputMetaDS = vtkMultiBlockDataSet::SafeDownCast(
530 pas->GetOutputDataObject(vtkStatisticsAlgorithm::OUTPUT_MODEL));
531
532 // Synchronize and stop clock
533 com->Barrier();
534 timer->StopTimer();
535
536 if (myRank == args->ioRank)
537 {
538 cout << "\n## Completed parallel calculation of auto-correlative statistics (without "
539 "assessment):\n"
540 << " Total sample size: "
541 << vtkTable::SafeDownCast(outputMetaDS->GetBlock(0))
542 ->GetValueByName(0, "Cardinality")
543 .ToInt()
544 << " \n"
545 << " Wall time: " << timer->GetElapsedTime() << " sec.\n";
546
547 cout << " Calculated the following statistics:\n";
548 unsigned int nbm1 = outputMetaDS->GetNumberOfBlocks() - 1;
549 for (unsigned int b = 0; b < nbm1; ++b)
550 {
551 const char* tabName = outputMetaDS->GetMetaData(b)->Get(vtkCompositeDataSet::NAME());
552 cerr << " " << tabName << "\n";
553 vtkTable* outputMeta = vtkTable::SafeDownCast(outputMetaDS->GetBlock(b));
554 for (vtkIdType r = 0; r < outputMeta->GetNumberOfRows(); ++r)
555 {
556 cout << " ";
557 for (int i = 0; i < outputMeta->GetNumberOfColumns(); ++i)
558 {
559 cout << outputMeta->GetColumnName(i) << "=" << outputMeta->GetValue(r, i).ToString()
560 << " ";
561 }
562 cout << "\n";
563 }
564 }
565 const char* tabName = outputMetaDS->GetMetaData(nbm1)->Get(vtkCompositeDataSet::NAME());
566 cerr << " " << tabName << "\n";
567 vtkTable* outputMeta = vtkTable::SafeDownCast(outputMetaDS->GetBlock(nbm1));
568 outputMeta->Dump();
569 }
570
571 // Clean up
572 pas->Delete();
573 } // if ( ! args->skipPAutoCorrelative )
574 else if (myRank == args->ioRank)
575 {
576 cout << "\n## Skipped calculation of parallel auto-correlative statistics.\n";
577 }
578
579 // ************************** Parallel Correlative Statistics **************************
580
581 // Skip parallel correlative statistics if requested
582 if (!args->skipPCorrelative)
583 {
584 // Synchronize and start clock
585 com->Barrier();
586 timer->StartTimer();
587
588 // Instantiate a parallel correlative statistics engine and set its input
589 vtkPCorrelativeStatistics* pcs = vtkPCorrelativeStatistics::New();
590 pcs->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, inputData);
591
592 // Select column pairs (uniform vs. uniform, normal vs. normal)
593 pcs->AddColumnPair(columnNames[0], columnNames[1]);
594 pcs->AddColumnPair(columnNames[2], columnNames[3]);
595
596 // Test (in parallel) with Learn, Derive operations turned on
597 pcs->SetLearnOption(true);
598 pcs->SetDeriveOption(true);
599 pcs->SetAssessOption(false);
600 pcs->SetTestOption(false);
601 pcs->Update();
602
603 // Get output data and meta tables
604 vtkMultiBlockDataSet* outputMetaDS = vtkMultiBlockDataSet::SafeDownCast(
605 pcs->GetOutputDataObject(vtkStatisticsAlgorithm::OUTPUT_MODEL));
606 vtkTable* outputPrimary = vtkTable::SafeDownCast(outputMetaDS->GetBlock(0));
607 vtkTable* outputDerived = vtkTable::SafeDownCast(outputMetaDS->GetBlock(1));
608
609 // Synchronize and stop clock
610 com->Barrier();
611 timer->StopTimer();
612
613 if (myRank == args->ioRank)
614 {
615 cout << "\n## Completed parallel calculation of correlative statistics (with assessment):\n"
616 << " Total sample size: " << outputPrimary->GetValueByName(0, "Cardinality").ToInt()
617 << " \n"
618 << " Wall time: " << timer->GetElapsedTime() << " sec.\n";
619
620 cout << " Calculated the following primary statistics:\n";
621 for (vtkIdType r = 0; r < outputPrimary->GetNumberOfRows(); ++r)
622 {
623 cout << " ";
624 for (int i = 0; i < outputPrimary->GetNumberOfColumns(); ++i)
625 {
626 cout << outputPrimary->GetColumnName(i) << "=" << outputPrimary->GetValue(r, i).ToString()
627 << " ";
628 }
629 cout << "\n";
630 }
631
632 cout << " Calculated the following derived statistics:\n";
633 for (vtkIdType r = 0; r < outputDerived->GetNumberOfRows(); ++r)
634 {
635 cout << " ";
636 for (int i = 0; i < outputDerived->GetNumberOfColumns(); ++i)
637 {
638 cout << outputDerived->GetColumnName(i) << "=" << outputDerived->GetValue(r, i).ToString()
639 << " ";
640 }
641 cout << "\n";
642 }
643 }
644
645 // Clean up
646 pcs->Delete();
647 } // if ( ! args->skipPCorrelative )
648 else if (myRank == args->ioRank)
649 {
650 cout << "\n## Skipped calculation of parallel correlative statistics.\n";
651 }
652
653 // ************************** Parallel Multi-Correlative Statistics **************************
654
655 // Skip parallel multi-correlative statistics if requested
656 if (!args->skipPMultiCorrelative)
657 {
658 // Synchronize and start clock
659 com->Barrier();
660 timer->StartTimer();
661
662 // Instantiate a parallel correlative statistics engine and set its ports
663 vtkPMultiCorrelativeStatistics* pmcs = vtkPMultiCorrelativeStatistics::New();
664 pmcs->SetInputData(0, inputData);
665
666 // Select column pairs (uniform vs. uniform, normal vs. normal)
667 pmcs->SetColumnStatus(columnNames[0], true);
668 pmcs->SetColumnStatus(columnNames[1], true);
669 pmcs->RequestSelectedColumns();
670
671 pmcs->ResetAllColumnStates();
672 pmcs->SetColumnStatus(columnNames[2], true);
673 pmcs->SetColumnStatus(columnNames[3], true);
674 pmcs->RequestSelectedColumns();
675
676 pmcs->ResetAllColumnStates();
677 pmcs->SetColumnStatus(columnNames[0], true);
678 pmcs->SetColumnStatus(columnNames[1], true);
679 pmcs->SetColumnStatus(columnNames[2], true);
680 pmcs->SetColumnStatus(columnNames[3], true);
681 pmcs->RequestSelectedColumns();
682
683 // Test (in parallel) with Learn, Derive, and Assess operations turned on
684 // Test is not implemented for multi-correlative
685 pmcs->SetLearnOption(true);
686 pmcs->SetDeriveOption(true);
687 pmcs->SetAssessOption(true);
688 pmcs->SetTestOption(true);
689 pmcs->Update();
690
691 // Get output meta tables
692 vtkMultiBlockDataSet* outputMetaDS = vtkMultiBlockDataSet::SafeDownCast(
693 pmcs->GetOutputDataObject(vtkStatisticsAlgorithm::OUTPUT_MODEL));
694
695 // Synchronize and stop clock
696 com->Barrier();
697 timer->StopTimer();
698
699 if (myRank == args->ioRank)
700 {
701 cout
702 << "\n## Completed parallel calculation of multi-correlative statistics (with "
703 "assessment):\n"
704 << " Total sample size: "
705 << vtkTable::SafeDownCast(outputMetaDS->GetBlock(0))->GetValueByName(0, "Entries").ToInt()
706 << " \n"
707 << " Wall time: " << timer->GetElapsedTime() << " sec.\n";
708
709 vtkTable* outputMeta;
710 for (unsigned int b = 1; b < outputMetaDS->GetNumberOfBlocks(); ++b)
711 {
712 outputMeta = vtkTable::SafeDownCast(outputMetaDS->GetBlock(b));
713 outputMeta->Dump();
714 }
715 }
716
717 // Clean up
718 pmcs->Delete();
719 } // if ( ! args->skipPMultiCorrelative )
720 else if (myRank == args->ioRank)
721 {
722 cout << "\n## Skipped calculation of parallel multi-correlative statistics.\n";
723 }
724
725 // ************************** Parallel PCA Statistics **************************
726
727 // Skip parallel PCA statistics if requested
728 if (!args->skipPPCA)
729 {
730 // Synchronize and start clock
731 com->Barrier();
732 timer->StartTimer();
733
734 // Instantiate a parallel pca statistics engine and set its ports
735 vtkPPCAStatistics* pcas = vtkPPCAStatistics::New();
736 pcas->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, inputData);
737
738 // Select column pairs (uniform vs. uniform, normal vs. normal)
739 pcas->SetColumnStatus(columnNames[0], true);
740 pcas->SetColumnStatus(columnNames[1], true);
741 pcas->RequestSelectedColumns();
742
743 pcas->ResetAllColumnStates();
744 pcas->SetColumnStatus(columnNames[2], true);
745 pcas->SetColumnStatus(columnNames[3], true);
746 pcas->RequestSelectedColumns();
747
748 pcas->ResetAllColumnStates();
749 pcas->SetColumnStatus(columnNames[0], true);
750 pcas->SetColumnStatus(columnNames[1], true);
751 pcas->SetColumnStatus(columnNames[2], true);
752 pcas->SetColumnStatus(columnNames[3], true);
753 pcas->RequestSelectedColumns();
754
755 // Test (in parallel) with all operations except for Test (not implemented in parallel for PCA)
756 pcas->SetLearnOption(true);
757 pcas->SetDeriveOption(true);
758 pcas->SetAssessOption(true);
759 pcas->SetTestOption(false);
760 pcas->Update();
761
762 // Get output meta tables
763 vtkMultiBlockDataSet* outputMetaDS = vtkMultiBlockDataSet::SafeDownCast(
764 pcas->GetOutputDataObject(vtkStatisticsAlgorithm::OUTPUT_MODEL));
765
766 // Synchronize and stop clock
767 com->Barrier();
768 timer->StopTimer();
769
770 if (myRank == args->ioRank)
771 {
772 cout
773 << "\n## Completed parallel calculation of pca statistics (with assessment):\n"
774 << " Total sample size: "
775 << vtkTable::SafeDownCast(outputMetaDS->GetBlock(0))->GetValueByName(0, "Entries").ToInt()
776 << " \n"
777 << " Wall time: " << timer->GetElapsedTime() << " sec.\n";
778
779 vtkTable* outputMeta;
780 for (unsigned int b = 1; b < outputMetaDS->GetNumberOfBlocks(); ++b)
781 {
782 outputMeta = vtkTable::SafeDownCast(outputMetaDS->GetBlock(b));
783 outputMeta->Dump();
784 }
785 }
786
787 // Clean up
788 pcas->Delete();
789 } // if ( ! args->skipPPCA )
790 else if (myRank == args->ioRank)
791 {
792 cout << "\n## Skipped calculation of parallel PCA statistics.\n";
793 }
794
795 // Clean up
796 inputData->Delete();
797 timer->Delete();
798 }
799
800 }
801
802 //------------------------------------------------------------------------------
TestRandomPMomentStatisticsMPI(int argc,char * argv[])803 int TestRandomPMomentStatisticsMPI(int argc, char* argv[])
804 {
805 // **************************** MPI Initialization ***************************
806 vtkMPIController* controller = vtkMPIController::New();
807 controller->Initialize(&argc, &argv);
808
809 // If an MPI controller was not created, terminate in error.
810 if (!controller->IsA("vtkMPIController"))
811 {
812 vtkGenericWarningMacro("Failed to initialize a MPI controller.");
813 controller->Delete();
814 return 1;
815 }
816
817 vtkMPICommunicator* com = vtkMPICommunicator::SafeDownCast(controller->GetCommunicator());
818
819 // ************************** Find an I/O node ********************************
820 int* ioPtr;
821 int ioRank;
822 int flag;
823
824 MPI_Comm_get_attr(MPI_COMM_WORLD, MPI_IO, &ioPtr, &flag);
825
826 if ((!flag) || (*ioPtr == MPI_PROC_NULL))
827 {
828 // Getting MPI attributes did not return any I/O node found.
829 ioRank = MPI_PROC_NULL;
830 vtkGenericWarningMacro("No MPI I/O nodes found.");
831
832 // As no I/O node was found, we need an unambiguous way to report the problem.
833 // This is the only case when a testValue of -1 will be returned
834 controller->Finalize();
835 controller->Delete();
836
837 return -1;
838 }
839 else
840 {
841 if (*ioPtr == MPI_ANY_SOURCE)
842 {
843 // Anyone can do the I/O trick--just pick node 0.
844 ioRank = 0;
845 }
846 else
847 {
848 // Only some nodes can do I/O. Make sure everyone agrees on the choice (min).
849 com->AllReduce(ioPtr, &ioRank, 1, vtkCommunicator::MIN_OP);
850 }
851 }
852
853 // Get local rank and print out of I/O node
854 int myRank = com->GetLocalProcessId();
855 if (myRank == ioRank)
856 {
857 cout << "\n# Process " << ioRank << " will be the I/O node.\n";
858 }
859
860 // Check how many processes have been made available
861 int numProcs = controller->GetNumberOfProcesses();
862 if (myRank == ioRank)
863 {
864 cout << "\n# Running test with " << numProcs << " processes...\n";
865 }
866
867 // **************************** Parse command line ***************************
868 // Set default argument values
869 int nVals = 100000;
870 double absTol = 1.e-6;
871 bool skipDescriptive = false;
872 bool skipPDescriptive = false;
873 bool skipPAutoCorrelative = false;
874 bool skipPCorrelative = false;
875 bool skipPMultiCorrelative = false;
876 bool skipPPCA = false;
877
878 // Initialize command line argument parser
879 vtksys::CommandLineArguments clArgs;
880 clArgs.Initialize(argc, argv);
881 clArgs.StoreUnusedArguments(false);
882
883 // Parse per-process cardinality of each pseudo-random sample
884 clArgs.AddArgument("--n-per-proc", vtksys::CommandLineArguments::SPACE_ARGUMENT, &nVals,
885 "Per-process cardinality of each pseudo-random sample");
886
887 // Parse absolute tolerance to cross-verify aggregated serial vs. parallel descriptive stats
888 clArgs.AddArgument("--abs-tol", vtksys::CommandLineArguments::SPACE_ARGUMENT, &absTol,
889 "Absolute tolerance to cross-verify aggregated serial and parallel descriptive statistics");
890
891 // Parse whether serial descriptive statistics should be skipped (for faster testing)
892 clArgs.AddArgument("--skip-Descriptive", vtksys::CommandLineArguments::NO_ARGUMENT,
893 &skipDescriptive, "Skip serial descriptive statistics");
894
895 // Parse whether parallel descriptive statistics should be skipped (for faster testing)
896 clArgs.AddArgument("--skip-PDescriptive", vtksys::CommandLineArguments::NO_ARGUMENT,
897 &skipPDescriptive, "Skip parallel descriptive statistics");
898
899 // Parse whether parallel auto-correlative statistics should be skipped (for faster testing)
900 clArgs.AddArgument("--skip-PAutoCorrelative", vtksys::CommandLineArguments::NO_ARGUMENT,
901 &skipPAutoCorrelative, "Skip parallel auto-correlative statistics");
902
903 // Parse whether parallel correlative statistics should be skipped (for faster testing)
904 clArgs.AddArgument("--skip-PCorrelative", vtksys::CommandLineArguments::NO_ARGUMENT,
905 &skipPCorrelative, "Skip parallel correlative statistics");
906
907 // Parse whether parallel multi-correlative statistics should be skipped (for faster testing)
908 clArgs.AddArgument("--skip-PMultiCorrelative", vtksys::CommandLineArguments::NO_ARGUMENT,
909 &skipPMultiCorrelative, "Skip parallel multi-correlative statistics");
910
911 // Parse whether parallel PCA statistics should be skipped (for faster testing)
912 clArgs.AddArgument("--skip-PPCA", vtksys::CommandLineArguments::NO_ARGUMENT, &skipPPCA,
913 "Skip parallel PCA statistics");
914
915 // If incorrect arguments were provided, provide some help and terminate in error.
916 if (!clArgs.Parse())
917 {
918 if (myRank == ioRank)
919 {
920 cerr << "Usage: " << clArgs.GetHelp() << "\n";
921 }
922
923 controller->Finalize();
924 controller->Delete();
925
926 return 1;
927 }
928
929 // ************************** Initialize test *********************************
930 // Parameters for regression test.
931 int testValue = 0;
932 RandomSampleStatisticsArgs args;
933 args.nVals = nVals;
934 args.absTol = absTol;
935 args.skipDescriptive = skipDescriptive;
936 args.skipPDescriptive = skipPDescriptive;
937 args.skipPAutoCorrelative = skipPAutoCorrelative;
938 args.skipPCorrelative = skipPCorrelative;
939 args.skipPMultiCorrelative = skipPMultiCorrelative;
940 args.skipPPCA = skipPPCA;
941 args.retVal = &testValue;
942 args.ioRank = ioRank;
943
944 // Execute the function named "process" on both processes
945 controller->SetSingleMethod(RandomSampleStatistics, &args);
946 controller->SingleMethodExecute();
947
948 // Clean up and exit
949 if (com->GetLocalProcessId() == ioRank)
950 {
951 cout << "\n# Test completed.\n\n";
952 }
953
954 controller->Finalize();
955 controller->Delete();
956
957 return testValue;
958 }
959