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