1 /*  _______________________________________________________________________
2 
3     DAKOTA: Design Analysis Kit for Optimization and Terascale Applications
4     Copyright 2014-2020 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
5     This software is distributed under the GNU Lesser General Public License.
6     For more information, see the README file in the top Dakota directory.
7     _______________________________________________________________________ */
8 
9 //- Class:	 NonDSampling
10 //- Description: Implementation code for NonDSampling class
11 //- Owner:       Mike Eldred
12 //- Checked by:
13 //- Version:
14 
15 #include "dakota_data_types.hpp"
16 #include "dakota_system_defs.hpp"
17 #include "DakotaModel.hpp"
18 #include "DakotaResponse.hpp"
19 #include "NonDSampling.hpp"
20 #include "ProblemDescDB.hpp"
21 #include "SensAnalysisGlobal.hpp"
22 #include "ProbabilityTransformation.hpp"
23 #include "dakota_stat_util.hpp"
24 #include "pecos_data_types.hpp"
25 #include "NormalRandomVariable.hpp"
26 #include <algorithm>
27 
28 #include <boost/math/special_functions/beta.hpp>
29 
30 static const char rcsId[]="@(#) $Id: NonDSampling.cpp 7036 2010-10-22 23:20:24Z mseldre $";
31 
32 
33 namespace Dakota {
34 
35 
36 /** This constructor is called for a standard letter-envelope iterator
37     instantiation.  In this case, set_db_list_nodes has been called and
38     probDescDB can be queried for settings from the method specification. */
NonDSampling(ProblemDescDB & problem_db,Model & model)39 NonDSampling::NonDSampling(ProblemDescDB& problem_db, Model& model):
40   NonD(problem_db, model), seedSpec(probDescDB.get_int("method.random_seed")),
41   randomSeed(seedSpec), samplesSpec(probDescDB.get_int("method.samples")),
42   samplesRef(samplesSpec), numSamples(samplesSpec),
43   rngName(probDescDB.get_string("method.random_number_generator")),
44   sampleType(probDescDB.get_ushort("method.sample_type")), samplesIncrement(0),
45   statsFlag(true), allDataFlag(false), samplingVarsMode(ACTIVE),
46   sampleRanksMode(IGNORE_RANKS),
47   varyPattern(!probDescDB.get_bool("method.fixed_seed")),
48   backfillFlag(probDescDB.get_bool("method.backfill")),
49   wilksFlag(probDescDB.get_bool("method.wilks")), numLHSRuns(0)
50 {
51   // pushed down as some derived classes (MLMC) use a MC default
52   //if (!sampleType)
53   //  sampleType = SUBMETHOD_LHS;
54 
55   if (epistemicStats && totalLevelRequests) {
56     Cerr << "\nError: sampling does not support level requests for "
57 	 << "analyses containing epistemic uncertainties." << std::endl;
58     abort_handler(METHOD_ERROR);
59   }
60 
61   // initialize finalStatistics using the default statistics set
62   initialize_final_statistics();
63 
64   if ( wilksFlag ) {
65     // Only works with sample_type of random
66     // BMA: consider relaxing, despite no theory
67     if ( sampleType != SUBMETHOD_RANDOM ) {
68       Cerr << "Error: Wilks sample sizes require use of \"random\" sample_type."
69 	   << std::endl;
70       abort_handler(METHOD_ERROR);
71     }
72 
73     // Check for conflicting samples spec. Note that this still allows
74     // a user to specify "samples = 0" alongside wilks
75     if ( numSamples > 0 ) {
76       Cerr << "Error: Cannot specify both \"samples\" and \"wilks\"."
77 	   << std::endl;
78       abort_handler(METHOD_ERROR);
79     }
80 
81     // Wilks order statistics
82     wilksOrder = probDescDB.get_ushort("method.order");
83     // Wilks interval sidedness
84     wilksSidedness = probDescDB.get_short("method.wilks.sided_interval");
85     bool wilks_twosided = (wilksSidedness == TWO_SIDED);
86 
87     // Support multiple probability_levels
88     Real max_prob_level = 0.0;
89     for (size_t i=0; i<numFunctions; ++i) {
90       size_t pl_len = requestedProbLevels[i].length();
91       for (size_t j=0; j<pl_len; ++j) {
92         if (requestedProbLevels[i][j] > max_prob_level)
93           max_prob_level = requestedProbLevels[i][j] ;
94       }
95     }
96     wilksAlpha = max_prob_level;
97     if (wilksAlpha <= 0.0) // Assign a default if probability_levels unspecified
98       wilksAlpha = 0.95;
99 
100     wilksBeta = probDescDB.get_real("method.confidence_level");
101     if (wilksBeta <= 0.0) // Assign a default if probability_levels unspecified
102       wilksBeta = 0.95;
103     numSamples = compute_wilks_sample_size(wilksOrder, wilksAlpha,
104 					   wilksBeta, wilks_twosided);
105     samplesRef = numSamples;
106   }
107 
108   // update concurrency
109   if (numSamples) // samples is optional (default = 0)
110     maxEvalConcurrency *= numSamples;
111 }
112 
113 
114 /** This alternate constructor is used for generation and evaluation
115     of on-the-fly sample sets. */
116 NonDSampling::
NonDSampling(unsigned short method_name,Model & model,unsigned short sample_type,int samples,int seed,const String & rng,bool vary_pattern,short sampling_vars_mode)117 NonDSampling(unsigned short method_name, Model& model,
118 	     unsigned short sample_type, int samples, int seed,
119 	     const String& rng, bool vary_pattern, short sampling_vars_mode):
120   NonD(method_name, model), seedSpec(seed), randomSeed(seed),
121   samplesSpec(samples), samplesRef(samples), numSamples(samples), rngName(rng),
122   sampleType(sample_type), wilksFlag(false), samplesIncrement(0),
123   statsFlag(false), allDataFlag(true), samplingVarsMode(sampling_vars_mode),
124   sampleRanksMode(IGNORE_RANKS), varyPattern(vary_pattern), backfillFlag(false),
125   numLHSRuns(0)
126 {
127   subIteratorFlag = true; // suppress some output
128 
129   // override default epistemicStats setting from NonD ctor
130   const Variables& vars = iteratedModel.current_variables();
131   const SizetArray& ac_totals = vars.shared_data().active_components_totals();
132   bool euv = (ac_totals[TOTAL_CEUV]  || ac_totals[TOTAL_DEUIV] ||
133 	      ac_totals[TOTAL_DEUSV] || ac_totals[TOTAL_DEURV]);
134   bool aleatory_mode = (samplingVarsMode == ALEATORY_UNCERTAIN ||
135 			samplingVarsMode == ALEATORY_UNCERTAIN_UNIFORM);
136   epistemicStats = (euv && !aleatory_mode);
137 
138   // enforce LHS as default sample type
139   if (!sampleType)
140     sampleType = SUBMETHOD_LHS;
141 
142   // not used but included for completeness
143   if (numSamples) // samples is optional (default = 0)
144     maxEvalConcurrency *= numSamples;
145 }
146 
147 
148 /** This alternate constructor is used by ConcurrentStrategy for
149     generation of uniform, uncorrelated sample sets. */
150 NonDSampling::
NonDSampling(unsigned short sample_type,int samples,int seed,const String & rng,const RealVector & lower_bnds,const RealVector & upper_bnds)151 NonDSampling(unsigned short sample_type, int samples, int seed,
152 	     const String& rng, const RealVector& lower_bnds,
153 	     const RealVector& upper_bnds):
154   NonD(RANDOM_SAMPLING, lower_bnds, upper_bnds), seedSpec(seed),
155   randomSeed(seed), samplesSpec(samples), samplesRef(samples),
156   numSamples(samples), rngName(rng), sampleType(sample_type), wilksFlag(false),
157   samplesIncrement(0), statsFlag(false), allDataFlag(true),
158   samplingVarsMode(ACTIVE_UNIFORM), sampleRanksMode(IGNORE_RANKS),
159   varyPattern(true), backfillFlag(false), numLHSRuns(0)
160 {
161   subIteratorFlag = true; // suppress some output
162 
163   // enforce LHS as default sample type
164   if (!sampleType)
165     sampleType = SUBMETHOD_LHS;
166 
167   // not used but included for completeness
168   if (numSamples) // samples is optional (default = 0)
169     maxEvalConcurrency *= numSamples;
170 }
171 
172 
173 /** This alternate constructor is used by ConcurrentStrategy for
174     generation of normal, correlated sample sets. */
175 NonDSampling::
NonDSampling(unsigned short sample_type,int samples,int seed,const String & rng,const RealVector & means,const RealVector & std_devs,const RealVector & lower_bnds,const RealVector & upper_bnds,RealSymMatrix & correl)176 NonDSampling(unsigned short sample_type, int samples, int seed,
177 	     const String& rng, const RealVector& means,
178              const RealVector& std_devs, const RealVector& lower_bnds,
179 	     const RealVector& upper_bnds, RealSymMatrix& correl):
180   NonD(RANDOM_SAMPLING, lower_bnds, upper_bnds), seedSpec(seed),
181   randomSeed(seed), samplesSpec(samples), samplesRef(samples),
182   numSamples(samples), rngName(rng), sampleType(sample_type), wilksFlag(false),
183   samplesIncrement(0), statsFlag(false), allDataFlag(true),
184   samplingVarsMode(ACTIVE), sampleRanksMode(IGNORE_RANKS), varyPattern(true),
185   backfillFlag(false), numLHSRuns(0)
186 {
187   subIteratorFlag = true; // suppress some output
188 
189   // enforce LHS as default sample type
190   if (!sampleType)
191     sampleType = SUBMETHOD_LHS;
192 
193   // not used but included for completeness
194   if (numSamples) // samples is optional (default = 0)
195     maxEvalConcurrency *= numSamples;
196 }
197 
198 
199 /** This alternate constructor defines allSamples from an incoming
200     sample matrix. */
201 NonDSampling::
NonDSampling(Model & model,const RealMatrix & sample_matrix)202 NonDSampling(Model& model, const RealMatrix& sample_matrix):
203   NonD(LIST_SAMPLING, model), seedSpec(0), randomSeed(0),
204   samplesSpec(sample_matrix.numCols()), sampleType(SUBMETHOD_DEFAULT),
205   wilksFlag(false), samplesIncrement(0), statsFlag(true), allDataFlag(true),
206   samplingVarsMode(ACTIVE), sampleRanksMode(IGNORE_RANKS),
207   varyPattern(false), backfillFlag(false), numLHSRuns(0)
208 {
209   allSamples = sample_matrix; compactMode = true;
210   samplesRef = numSamples = samplesSpec;
211 
212   subIteratorFlag = true; // suppress some output
213 
214   // not used but included for completeness
215   if (numSamples)
216     maxEvalConcurrency *= numSamples;
217 }
218 
219 
~NonDSampling()220 NonDSampling::~NonDSampling()
221 { }
222 
223 
224 void NonDSampling::
transform_samples(Pecos::ProbabilityTransformation & nataf,RealMatrix & sample_matrix,int num_samples,bool x_to_u)225 transform_samples(Pecos::ProbabilityTransformation& nataf,
226 		  RealMatrix& sample_matrix, int num_samples, bool x_to_u)
227 {
228   if (num_samples == 0)
229     num_samples = sample_matrix.numCols();
230   else if (sample_matrix.numCols() != num_samples)
231     sample_matrix.shapeUninitialized(numContinuousVars, num_samples);
232 
233   if (x_to_u)
234     for (size_t i=0; i<num_samples; ++i) {
235       RealVector x_samp(Teuchos::Copy, sample_matrix[i], numContinuousVars);
236       RealVector u_samp(Teuchos::View, sample_matrix[i], numContinuousVars);
237       nataf.trans_X_to_U(x_samp, u_samp);
238     }
239   else
240     for (size_t i=0; i<num_samples; ++i) {
241       RealVector u_samp(Teuchos::Copy, sample_matrix[i], numContinuousVars);
242       RealVector x_samp(Teuchos::View, sample_matrix[i], numContinuousVars);
243       nataf.trans_U_to_X(u_samp, x_samp);
244     }
245 }
246 
247 
get_parameter_sets(Model & model,const int num_samples,RealMatrix & design_matrix,bool write_msg)248 void NonDSampling::get_parameter_sets(Model& model, const int num_samples,
249                                       RealMatrix& design_matrix, bool write_msg)
250 {
251   initialize_lhs(write_msg, num_samples);
252 
253   // Invoke LHSDriver to generate samples within the specified distributions
254 
255   switch (samplingVarsMode) {
256   case ACTIVE_UNIFORM:  case ALL_UNIFORM:  case UNCERTAIN_UNIFORM:
257   case ALEATORY_UNCERTAIN_UNIFORM:  case EPISTEMIC_UNCERTAIN_UNIFORM: {
258     short model_view = model.current_variables().view().first;
259     // Use LHSDriver::generate_uniform_samples() between lower/upper bounds
260     RealSymMatrix corr; // uncorrelated samples
261     if ( samplingVarsMode == ACTIVE_UNIFORM ||
262 	 ( samplingVarsMode == ALL_UNIFORM &&
263 	   ( model_view == RELAXED_ALL || model_view == MIXED_ALL ) ) ||
264 	 ( samplingVarsMode == UNCERTAIN_UNIFORM &&
265 	   ( model_view == RELAXED_UNCERTAIN ||
266 	     model_view == MIXED_UNCERTAIN ) ) ||
267 	 ( samplingVarsMode == ALEATORY_UNCERTAIN_UNIFORM &&
268 	   ( model_view == RELAXED_ALEATORY_UNCERTAIN ||
269 	     model_view == MIXED_ALEATORY_UNCERTAIN ) ) ||
270 	 ( samplingVarsMode == EPISTEMIC_UNCERTAIN_UNIFORM &&
271 	   ( model_view == RELAXED_EPISTEMIC_UNCERTAIN ||
272 	     model_view == MIXED_EPISTEMIC_UNCERTAIN ) ) ) {
273       // sample uniformly from ACTIVE lower/upper bounds (regardless of model
274       // view), from UNCERTAIN lower/upper bounds (with model in DISTINCT view),
275       // or from ALL lower/upper bounds (with model in ALL view).
276       // loss of sampleRanks control is OK since NonDIncremLHS uses ACTIVE mode.
277       // TO DO: add support for uniform discrete
278       lhsDriver.generate_uniform_samples(model.continuous_lower_bounds(),
279 					 model.continuous_upper_bounds(),
280 					 corr, num_samples, design_matrix);
281     }
282     else if (samplingVarsMode == ALL_UNIFORM) {
283       // sample uniformly from ALL lower/upper bnds with model in distinct view.
284       // loss of sampleRanks control is OK since NonDIncremLHS uses ACTIVE mode.
285       // TO DO: add support for uniform discrete
286       lhsDriver.generate_uniform_samples(model.all_continuous_lower_bounds(),
287 					 model.all_continuous_upper_bounds(),
288 					 corr, num_samples, design_matrix);
289     }
290     else { // A, E, A+E UNCERTAIN_UNIFORM
291       // sample uniformly from {A,E,A+E} UNCERTAIN lower/upper bounds
292       // with model using a non-corresponding view (corresponding views
293       // handled in first case above)
294       size_t start_acv, num_acv, dummy;
295       mode_counts(model.current_variables(), start_acv, num_acv,
296 		  dummy, dummy, dummy, dummy, dummy, dummy);
297       if (!num_acv) {
298 	Cerr << "Error: no active continuous variables for sampling in "
299 	     << "uniform mode" << std::endl;
300 	abort_handler(METHOD_ERROR);
301       }
302       const RealVector& all_c_l_bnds = model.all_continuous_lower_bounds();
303       const RealVector& all_c_u_bnds = model.all_continuous_upper_bounds();
304       RealVector uncertain_c_l_bnds(Teuchos::View,
305 	const_cast<Real*>(&all_c_l_bnds[start_acv]), num_acv);
306       RealVector uncertain_c_u_bnds(Teuchos::View,
307 	const_cast<Real*>(&all_c_u_bnds[start_acv]), num_acv);
308       // loss of sampleRanks control is OK since NonDIncremLHS uses ACTIVE mode
309       // TO DO: add support for uniform discrete
310       lhsDriver.generate_uniform_samples(uncertain_c_l_bnds, uncertain_c_u_bnds,
311 					 corr, num_samples, design_matrix);
312     }
313     break;
314   }
315 
316   case ACTIVE: { // utilize model view to sample active variables
317     Pecos::MultivariateDistribution& mv_dist
318       = model.multivariate_distribution();
319     if (backfillFlag)
320       lhsDriver.generate_unique_samples(mv_dist.random_variables(),
321 	mv_dist.correlation_matrix(), num_samples, design_matrix, sampleRanks,
322 	mv_dist.active_variables(), mv_dist.active_correlations());
323       // sampleRanks remains empty. See LHSDriver::generate_unique_samples()
324     else
325       lhsDriver.generate_samples(mv_dist.random_variables(),
326 	mv_dist.correlation_matrix(), num_samples, design_matrix, sampleRanks,
327 	mv_dist.active_variables(), mv_dist.active_correlations());
328     break;
329   }
330 
331   case DESIGN: case ALEATORY_UNCERTAIN: case EPISTEMIC_UNCERTAIN:
332   case UNCERTAIN: case STATE: case ALL: {
333     // override active model view to sample alternate subset/superset
334     BitArray active_vars, active_corr;
335     mode_bits(model.current_variables(), active_vars, active_corr);
336     Pecos::MultivariateDistribution& mv_dist
337       = model.multivariate_distribution();
338     if (backfillFlag)
339       lhsDriver.generate_unique_samples(mv_dist.random_variables(),
340 	mv_dist.correlation_matrix(), num_samples, design_matrix, sampleRanks,
341 	active_vars, active_corr);
342       // sampleRanks remains empty. See LHSDriver::generate_unique_samples()
343     else
344       lhsDriver.generate_samples(mv_dist.random_variables(),
345 	mv_dist.correlation_matrix(), num_samples, design_matrix, sampleRanks,
346 	active_vars, active_corr);
347     break;
348   }
349   }
350 }
351 
352 
353 /** This version of get_parameter_sets() does not extract data from the
354     user-defined model, but instead relies on the incoming bounded region
355     definition.  It only support a UNIFORM sampling mode, where the
356     distinction of ACTIVE_UNIFORM vs. ALL_UNIFORM is handled elsewhere. */
357 void NonDSampling::
get_parameter_sets(const RealVector & lower_bnds,const RealVector & upper_bnds)358 get_parameter_sets(const RealVector& lower_bnds, const RealVector& upper_bnds)
359 {
360   initialize_lhs(true, numSamples);
361   RealSymMatrix correl; // uncorrelated
362   lhsDriver.generate_uniform_samples(lower_bnds, upper_bnds, correl,
363 				     numSamples, allSamples);
364 }
365 
366 
367 /** This version of get_parameter_sets() does not extract data from the
368     user-defined model, but instead relies on the incoming
369     definition.  It only supports the sampling of normal variables. */
370 void NonDSampling::
get_parameter_sets(const RealVector & means,const RealVector & std_devs,const RealVector & lower_bnds,const RealVector & upper_bnds,RealSymMatrix & correl)371 get_parameter_sets(const RealVector& means, const RealVector& std_devs,
372                    const RealVector& lower_bnds, const RealVector& upper_bnds,
373                    RealSymMatrix& correl)
374 {
375   initialize_lhs(true, numSamples);
376   lhsDriver.generate_normal_samples(means, std_devs, lower_bnds, upper_bnds,
377 				    correl, numSamples, allSamples);
378 }
379 
380 
381 // Map the active variables from vars to sample_vars (a column in allSamples)
382 void NonDSampling::
sample_to_variables(const Real * sample_vars,Variables & vars,Model & model)383 sample_to_variables(const Real* sample_vars, Variables& vars, Model& model)
384 {
385   // sample_vars are in RandomVariable order, which mirrors the XML spec
386   // vars updates utilize all continuous,discrete {int,string,real} indexing
387 
388   const SharedVariablesData& svd = vars.shared_data();
389   short vars_mode;
390   switch (samplingVarsMode) {
391   case ACTIVE:
392     switch (vars.view().first) {
393     case RELAXED_ALL:       case MIXED_ALL:       vars_mode = ALL;        break;
394     case RELAXED_DESIGN:    case MIXED_DESIGN:    vars_mode = DESIGN;     break;
395     case RELAXED_UNCERTAIN: case MIXED_UNCERTAIN: vars_mode = UNCERTAIN;  break;
396     case RELAXED_ALEATORY_UNCERTAIN:   case MIXED_ALEATORY_UNCERTAIN:
397       vars_mode = ALEATORY_UNCERTAIN;                                     break;
398     case RELAXED_EPISTEMIC_UNCERTAIN:  case MIXED_EPISTEMIC_UNCERTAIN:
399       vars_mode = EPISTEMIC_UNCERTAIN;                                    break;
400     case RELAXED_STATE:     case MIXED_STATE:     vars_mode = STATE;      break;
401     }
402     break;
403   case ACTIVE_UNIFORM:
404     switch (vars.view().first) {
405     case RELAXED_ALL:     case MIXED_ALL:    vars_mode = ALL_UNIFORM;     break;
406     case RELAXED_DESIGN:  case MIXED_DESIGN:
407       vars_mode = DESIGN/*_UNIFORM*/;                                     break;
408     case RELAXED_UNCERTAIN:            case MIXED_UNCERTAIN:
409       vars_mode = UNCERTAIN_UNIFORM;                                      break;
410     case RELAXED_ALEATORY_UNCERTAIN:   case MIXED_ALEATORY_UNCERTAIN:
411       vars_mode = ALEATORY_UNCERTAIN_UNIFORM;                             break;
412     case RELAXED_EPISTEMIC_UNCERTAIN:  case MIXED_EPISTEMIC_UNCERTAIN:
413       vars_mode = EPISTEMIC_UNCERTAIN_UNIFORM;                            break;
414     case RELAXED_STATE:                case MIXED_STATE:
415       vars_mode = STATE/*_UNIFORM*/;                                      break;
416     }
417     break;
418   default:  vars_mode = samplingVarsMode;                                 break;
419   }
420 
421   size_t cv_index, num_cv, div_index, num_div, dsv_index, num_dsv,
422     drv_index, num_drv, samp_index = 0;
423   switch (vars_mode) {
424   case DESIGN:
425     cv_index = div_index = dsv_index = drv_index = 0;
426     svd.design_counts(num_cv, num_div, num_dsv, num_drv);
427     sample_to_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
428 		   dsv_index, num_dsv, drv_index, num_drv, samp_index, model);
429     break;
430   //case DESIGN_UNIFORM:
431   //  cv_index = div_index = dsv_index = drv_index = 0;
432   //  svd.design_counts(num_cv, num_div, num_dsv, num_drv);
433   //  sample_to_cv_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
434   // 		        dsv_index, num_dsv, drv_index, num_drv, samp_index);
435   //  break;
436   case ALEATORY_UNCERTAIN:
437     // design vars define starting indices
438     svd.design_counts(cv_index, div_index, dsv_index, drv_index);
439     // aleatory uncertain vars define counts
440     svd.aleatory_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
441     sample_to_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
442 		   dsv_index, num_dsv, drv_index, num_drv, samp_index, model);
443     break;
444   case ALEATORY_UNCERTAIN_UNIFORM:
445     // continuous design vars define starting indices
446     svd.design_counts(cv_index, div_index, dsv_index, drv_index);
447     // continuous aleatory uncertain vars define counts
448     svd.aleatory_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
449     sample_to_cv_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
450 		      dsv_index, num_dsv, drv_index, num_drv, samp_index);
451     break;
452   case EPISTEMIC_UNCERTAIN:
453     // design + aleatory uncertain vars define starting indices
454     svd.design_counts(cv_index, div_index, dsv_index, drv_index);
455     svd.aleatory_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
456     cv_index  += num_cv;   div_index += num_div;
457     dsv_index += num_dsv;  drv_index += num_drv;
458     svd.epistemic_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
459     sample_to_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
460 		   dsv_index, num_dsv, drv_index, num_drv, samp_index, model);
461     break;
462   case EPISTEMIC_UNCERTAIN_UNIFORM:
463     // continuous design + aleatory uncertain vars define starting indices
464     svd.design_counts(cv_index, div_index, dsv_index, drv_index);
465     svd.aleatory_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
466     cv_index  += num_cv;   div_index += num_div;
467     dsv_index += num_dsv;  drv_index += num_drv;
468     svd.epistemic_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
469     sample_to_cv_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
470 		      dsv_index, num_dsv, drv_index, num_drv, samp_index);
471     break;
472   case UNCERTAIN:
473     // aleatory
474     svd.design_counts(cv_index, div_index, dsv_index, drv_index);
475     svd.aleatory_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
476     sample_to_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
477 		   dsv_index, num_dsv, drv_index, num_drv, samp_index, model);
478     // epistemic
479     svd.epistemic_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
480     sample_to_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
481 		   dsv_index, num_dsv, drv_index, num_drv, samp_index, model);
482     break;
483   case UNCERTAIN_UNIFORM:
484     // aleatory
485     svd.design_counts(cv_index, div_index, dsv_index, drv_index);
486     svd.aleatory_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
487     sample_to_cv_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
488 		      dsv_index, num_dsv, drv_index, num_drv, samp_index);
489     // epistemic
490     svd.epistemic_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
491     sample_to_cv_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
492 		      dsv_index, num_dsv, drv_index, num_drv, samp_index);
493     break;
494   case STATE:
495     svd.design_counts(cv_index, div_index, dsv_index, drv_index);
496     svd.aleatory_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
497     cv_index  += num_cv;  div_index += num_div;
498     dsv_index += num_dsv; drv_index += num_drv;
499     svd.epistemic_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
500     cv_index  += num_cv;  div_index += num_div;
501     dsv_index += num_dsv; drv_index += num_drv;
502     svd.state_counts(num_cv, num_div, num_dsv, num_drv);
503     sample_to_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
504 		   dsv_index, num_dsv, drv_index, num_drv, samp_index, model);
505     break;
506   //case STATE_UNIFORM:
507   //  svd.design_counts(cv_index, div_index, dsv_index, drv_index);
508   //  svd.aleatory_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
509   //  cv_index  += num_cv;  div_index += num_div;
510   //  dsv_index += num_dsv; drv_index += num_drv;
511   //  svd.epistemic_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
512   //  cv_index  += num_cv;  div_index += num_div;
513   //  dsv_index += num_dsv; drv_index += num_drv;
514   //  svd.state_counts(num_cv, num_div, num_dsv, num_drv);
515   //  sample_to_cv_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
516   //	      dsv_index, num_dsv, drv_index, num_drv, samp_index);
517   //  break;
518   case ALL:
519     // design
520     cv_index = div_index = dsv_index = drv_index = 0;
521     svd.design_counts(num_cv, num_div, num_dsv, num_drv);
522     sample_to_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
523 		   dsv_index, num_dsv, drv_index, num_drv, samp_index, model);
524     // aleatory
525     svd.aleatory_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
526     sample_to_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
527 		   dsv_index, num_dsv, drv_index, num_drv, samp_index, model);
528     // epistemic
529     svd.epistemic_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
530     sample_to_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
531 		   dsv_index, num_dsv, drv_index, num_drv, samp_index, model);
532     // state
533     svd.state_counts(num_cv, num_div, num_dsv, num_drv);
534     sample_to_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
535 		   dsv_index, num_dsv, drv_index, num_drv, samp_index, model);
536     break;
537   case ALL_UNIFORM:
538     // design
539     cv_index = div_index = dsv_index = drv_index = 0;
540     svd.design_counts(num_cv, num_div, num_dsv, num_drv);
541     sample_to_cv_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
542 		      dsv_index, num_dsv, drv_index, num_drv, samp_index);
543     // aleatory
544     svd.aleatory_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
545     sample_to_cv_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
546 		      dsv_index, num_dsv, drv_index, num_drv, samp_index);
547     // epistemic
548     svd.epistemic_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
549     sample_to_cv_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
550 		      dsv_index, num_dsv, drv_index, num_drv, samp_index);
551     // state
552     svd.state_counts(num_cv, num_div, num_dsv, num_drv);
553     sample_to_cv_type(sample_vars, vars, cv_index, num_cv, div_index, num_div,
554 		      dsv_index, num_dsv, drv_index, num_drv, samp_index);
555     break;
556   }
557 }
558 
559 
560 /*
561 // TO DO: avoid inefficiency from repeated lookups...
562 void NonDSampling::
563 sample_to_variables(const Real* sample_vars, Variables& vars, size_t acv_start,
564 		    size_t num_acv, size_t adiv_start, size_t num_adiv,
565 		    size_t adsv_start, size_t num_adsv, size_t adrv_start,
566 		    size_t num_adrv, const StringSetArray& dss_values)
567 {
568   const SharedVariablesData& svd = vars.shared_data();
569 
570   // sampled continuous vars (by value)
571   size_t i, end = acv_start + num_acv;
572   for (i=acv_start; i<end; ++i)
573     vars.all_continuous_variable(sample_vars[svd.acv_index_to_all_index(i)], i);
574   // sampled discrete int vars (by value cast from Real)
575   end = adiv_start + num_adiv;
576   for (i=adiv_start; i<end; ++i)
577     vars.all_discrete_int_variable(
578       (int)sample_vars[svd.adiv_index_to_all_index(i)], i);
579   // sampled discrete string vars (by index cast from Real)
580   end = adsv_start + num_adsv;
581   for (i=adsv_start; i<end; ++i)
582     vars.all_discrete_string_variable(set_index_to_value(
583       (size_t)sample_vars[svd.adsv_index_to_all_index(i)], dss_values[i]),i);
584   // sampled discrete real vars (by value)
585   end = adrv_start + num_adrv;
586   for (i=adrv_start; i<end; ++i)
587     vars.all_discrete_real_variable(
588       sample_vars[svd.adrv_index_to_all_index(i)], i);
589 }
590 */
591 
592 
593 // Some inefficiency is acceptable here, as this is for one-time imports,
594 // so retain the compact approach of per-index conversion for now
595 void NonDSampling::
variables_to_sample(const Variables & vars,Real * sample_vars)596 variables_to_sample(const Variables& vars, Real* sample_vars)
597 {
598   size_t acv_start, num_acv, adiv_start, num_adiv, adsv_start, num_adsv,
599     adrv_start, num_adrv;
600   mode_counts(vars, acv_start, num_acv, adiv_start, num_adiv,
601 	      adsv_start, num_adsv, adrv_start, num_adrv);
602 
603   const SharedVariablesData& svd = vars.shared_data();
604 
605   // sampled continuous vars (by value)
606   size_t i, end = acv_start + num_acv;
607   for (i=acv_start; i<end; ++i)
608     sample_vars[svd.acv_index_to_all_index(i)]
609       = vars.all_continuous_variables()[i];
610   // sampled discrete int vars (cast value to Real)
611   end = adiv_start + num_adiv;
612   for (i=adiv_start; i<end; ++i)
613     sample_vars[svd.adiv_index_to_all_index(i)]
614       = (Real)vars.all_discrete_int_variables()[i];
615   // sampled discrete string vars (cast index to Real)
616   if (num_adsv) { // incur overhead of extracting DSS values
617     short active_view = vars.view().first;
618     bool relax = (active_view == RELAXED_ALL ||
619       ( active_view >= RELAXED_DESIGN && active_view <= RELAXED_STATE ) );
620     short all_view = (relax) ? RELAXED_ALL : MIXED_ALL;
621     const StringSetArray& dss_values
622       = iteratedModel.discrete_set_string_values(all_view);
623     end = adsv_start + num_adsv;
624     for (i=adsv_start; i<end; ++i)
625       sample_vars[svd.adsv_index_to_all_index(i)] = (Real)set_value_to_index(
626 	vars.all_discrete_string_variables()[i], dss_values[i]);
627   }
628   // sampled discrete real vars (by value)
629   end = adrv_start + num_adrv;
630   for (i=adrv_start; i<end; ++i)
631     sample_vars[svd.adrv_index_to_all_index(i)]
632       = vars.all_discrete_real_variables()[i];
633 }
634 
635 
636 /** This function and its helpers to follow are needed since NonDSampling
637     supports a richer set of sampling modes than just the active variable
638     subset.  mode_counts() manages the samplingVarsMode setting, while its
639     helper functions (view_{design,aleatory_uncertain,epistemic_uncertain,
640     uncertain,state}_counts) manage the active variables view.  Similar
641     to the computation of starts and counts in creating active variable
642     views, the results of this function are starts and counts for use
643     within model.all_*() set/get functions. */
644 void NonDSampling::
mode_counts(const Variables & vars,size_t & cv_start,size_t & num_cv,size_t & div_start,size_t & num_div,size_t & dsv_start,size_t & num_dsv,size_t & drv_start,size_t & num_drv) const645 mode_counts(const Variables& vars, size_t& cv_start,  size_t& num_cv,
646 	    size_t& div_start,     size_t& num_div,   size_t& dsv_start,
647 	    size_t& num_dsv,       size_t& drv_start, size_t& num_drv) const
648 {
649   cv_start = div_start = dsv_start = drv_start = 0;
650   num_cv   = num_div   = num_dsv   = num_drv   = 0;
651   const SharedVariablesData& svd = vars.shared_data();
652   size_t dummy;
653   // Note: UNIFORM views do not currently support non-relaxed discrete
654   switch (samplingVarsMode) {
655   case DESIGN:
656     // design vars define counts
657     svd.design_counts(num_cv, num_div, num_dsv, num_drv);
658     break;
659   //case DESIGN_UNIFORM:
660   //  // continuous design vars define counts
661   //  svd.design_counts(num_cv, dummy, dummy, dummy);
662   //  break;
663   case ALEATORY_UNCERTAIN:
664     // design vars define starting indices
665     svd.design_counts(cv_start, div_start, dsv_start, drv_start);
666     // aleatory uncertain vars define counts
667     svd.aleatory_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
668     break;
669   case ALEATORY_UNCERTAIN_UNIFORM:
670     // continuous design vars define starting indices
671     svd.design_counts(cv_start, dummy, dummy, dummy);
672     // continuous aleatory uncertain vars define counts
673     svd.aleatory_uncertain_counts(num_cv, dummy, dummy, dummy);
674     break;
675   case EPISTEMIC_UNCERTAIN:
676     // design + aleatory uncertain vars define starting indices
677     svd.design_counts(cv_start, div_start, dsv_start, drv_start);
678     svd.aleatory_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
679     cv_start  += num_cv;  div_start += num_div;
680     dsv_start += num_dsv; drv_start += num_drv;
681     // epistemic uncertain vars define counts
682     svd.epistemic_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
683     break;
684   case EPISTEMIC_UNCERTAIN_UNIFORM:
685     // continuous design + aleatory uncertain vars define starting indices
686     svd.design_counts(cv_start, dummy, dummy, dummy);
687     svd.aleatory_uncertain_counts(num_cv, dummy, dummy, dummy);
688     cv_start += num_cv;
689     // continuous epistemic uncertain vars define counts
690     svd.epistemic_uncertain_counts(num_cv, dummy, dummy, dummy);
691     break;
692   case UNCERTAIN:
693     // design vars define starting indices
694     svd.design_counts(cv_start, div_start, dsv_start, drv_start);
695     // aleatory+epistemic uncertain vars define counts
696     svd.uncertain_counts(num_cv, num_div, num_dsv, num_drv);
697     break;
698   case UNCERTAIN_UNIFORM:
699     // continuous design vars define starting indices
700     svd.design_counts(cv_start, dummy, dummy, dummy);
701     // continuous aleatory+epistemic uncertain vars define counts
702     svd.uncertain_counts(num_cv, dummy, dummy, dummy);
703     break;
704   case STATE:
705     // design + aleatory + epistemic vars define starting indices
706     svd.design_counts(cv_start, div_start, dsv_start, drv_start);
707     svd.aleatory_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
708     cv_start  += num_cv;  div_start += num_div;
709     dsv_start += num_dsv; drv_start += num_drv;
710     svd.epistemic_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
711     cv_start  += num_cv;  div_start += num_div;
712     dsv_start += num_dsv; drv_start += num_drv;
713     // state vars define counts
714     svd.state_counts(num_cv, num_div, num_dsv, num_drv);
715     break;
716   //case STATE_UNIFORM:
717   //  // continuous design + aleatory + epistemic vars define starting indices
718   //  svd.design_counts(cv_start, dummy, dummy, dummy);
719   //  svd.aleatory_uncertain_counts(num_cv, dummy, dummy, dummy);
720   //  cv_start += num_cv;
721   //  svd.epistemic_uncertain_counts(num_cv, dummy, dummy, dummy);
722   //  cv_start += num_cv;
723   //  // continuous state vars define counts
724   //  svd.state_counts(num_cv, dummy, dummy, dummy);
725   //  break;
726   case ACTIVE:
727     cv_start  = vars.cv_start();  num_cv  = vars.cv();
728     div_start = vars.div_start(); num_div = vars.div();
729     dsv_start = vars.dsv_start(); num_dsv = vars.dsv();
730     drv_start = vars.drv_start(); num_drv = vars.drv();   break;
731   case ACTIVE_UNIFORM:
732     cv_start  = vars.cv_start();  num_cv  = vars.cv();    break;
733   case ALL:
734     num_cv    = vars.acv();       num_div = vars.adiv();
735     num_dsv   = vars.adsv();      num_drv = vars.adrv();  break;
736   case ALL_UNIFORM:
737     num_cv    = vars.acv();                               break;
738   }
739 }
740 
741 
742 void NonDSampling::
mode_bits(const Variables & vars,BitArray & active_vars,BitArray & active_corr) const743 mode_bits(const Variables& vars, BitArray& active_vars,
744 	  BitArray& active_corr) const
745 {
746   const SharedVariablesData& svd = vars.shared_data();
747   size_t num_v = vars.tv(), num_cv, num_div, num_dsv, num_drv,
748     num_dv, num_auv, num_euv;
749   svd.design_counts(num_cv, num_div, num_dsv, num_drv);
750   num_dv = num_cv + num_div + num_dsv + num_drv,
751   svd.aleatory_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
752   num_auv = num_cv + num_div + num_dsv + num_drv;
753   active_corr.resize(num_v, false);
754   assign_value(active_corr, true, num_dv, num_auv);
755 
756   switch (samplingVarsMode) {
757   case DESIGN:
758     active_vars.resize(num_v, false);
759     assign_value(active_vars, true, 0, num_dv);  break;
760   case ALEATORY_UNCERTAIN:
761     active_vars = active_corr;  break;
762   case EPISTEMIC_UNCERTAIN:
763     svd.epistemic_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
764     active_vars.resize(num_v, false);
765     assign_value(active_vars, true, num_dv + num_auv,
766 		 num_cv + num_div + num_dsv + num_drv);
767     break;
768   case UNCERTAIN:
769     svd.epistemic_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
770     active_vars.resize(num_v, false);
771     assign_value(active_vars, true, num_dv,
772 		 num_auv + num_cv + num_div + num_dsv + num_drv);
773     break;
774   case STATE:
775     svd.epistemic_uncertain_counts(num_cv, num_div, num_dsv, num_drv);
776     num_euv = num_cv + num_div + num_dsv + num_drv;
777     svd.state_counts(num_cv, num_div, num_dsv, num_drv);
778     active_vars.resize(num_v, false);
779     assign_value(active_vars, true, num_dv + num_auv + num_euv,
780 		 num_cv + num_div + num_dsv + num_drv);
781     break;
782   case ALL:
783     active_vars.clear(); break; // no subset, all are active
784   //case ALEATORY_UNCERTAIN_UNIFORM:
785   //case EPISTEMIC_UNCERTAIN_UNIFORM:
786   //case UNCERTAIN_UNIFORM:
787   default:
788     Cerr << "Error: unsupported sampling mode in NonDSampling::mode_bits()."
789 	 << std::endl;
790     abort_handler(METHOD_ERROR);  break;
791   }
792 }
793 
794 
initialize_lhs(bool write_message,int num_samples)795 void NonDSampling::initialize_lhs(bool write_message, int num_samples)
796 {
797   // keep track of number of LHS executions for this object
798   ++numLHSRuns;
799 
800   //Cout << "numLHSRuns = " << numLHSRuns << " seedSpec = " << seedSpec
801   //     << " randomSeed = " << randomSeed << " varyPattern = " << varyPattern
802   //     << std::endl;
803 
804   // Set seed value for input to LHS's RNG: a user-specified seed gives
805   // repeatable behavior but no specification gives random behavior based on
806   // querying a system clock.  For cases where get_parameter_sets() may be
807   // called multiple times for the same sampling iterator (e.g., SBO), support
808   // a deterministic sequence of seed values to allow the sampling pattern to
809   // vary from one run to the next in a repeatable manner (required for RNG
810   // without a persistent state, such as rnum2).
811   bool seed_assigned = false, seed_advanced = false;
812   if (numLHSRuns == 1) { // set initial seed
813     lhsDriver.rng(rngName);
814     if (!seedSpec) { // no user specification --> nonrepeatable behavior
815       // Generate initial seed from a system clock.  NOTE: the system clock
816       // should not used for multiple LHS calls since (1) clock granularity can
817       // be too coarse (can repeat on subsequent runs for inexpensive test fns)
818       // and (2) seed progression can be highly structured, which could induce
819       // correlation between sample sets.  Instead, the clock-generated case
820       // varies the seed below using the same approach as the user-specified
821       // case.  This has the additional benefit that a random run can be
822       // recreated by specifying the clock-generated seed in the input file.
823       randomSeed = generate_system_seed();
824     }
825     lhsDriver.seed(randomSeed);  seed_assigned = true;
826   }
827   // We must distinguish two advancement use cases and allow them to co-exist:
828   // > an update to NonDSampling::randomSeed due to random_seed_sequence spec
829   // > an update to Pecos::LHSDriver::randomSeed using LHSDriver::
830   //   advance_seed_sequence() in support of varyPattern for rnum2
831   else if (seedSpec && seedSpec != randomSeed) // random_seed_sequence advance
832     { seedSpec = randomSeed; lhsDriver.seed(randomSeed); seed_assigned = true; }
833   else if (varyPattern && rngName == "rnum2") // vary pattern by advancing seed
834     { lhsDriver.advance_seed_sequence();                 seed_advanced = true; }
835   else if (!varyPattern) // reset orig / machine-generated (don't continue RNG)
836     { lhsDriver.seed(randomSeed);                        seed_assigned = true; }
837 
838   // Needed a way to turn this off when LHS sampling is being used in
839   // NonDAdaptImpSampling because it gets written a _LOT_
840   String sample_string = submethod_enum_to_string(sampleType);
841   if (write_message) {
842     Cout << "\nNonD " << sample_string << " Samples = " << num_samples;
843     if (seed_assigned) {
844       if (seedSpec) Cout << " Seed (user-specified) = ";
845       else          Cout << " Seed (system-generated) = ";
846       Cout << randomSeed << '\n';
847     }
848     else if (seed_advanced) {
849       if (seedSpec) Cout << " Seed (sequence from user-specified) = ";
850       else          Cout << " Seed (sequence from system-generated) = ";
851       Cout << lhsDriver.seed() << '\n';
852     }
853     else // default Boost Mersenne twister
854       Cout << " Seed not reset from previous LHS execution\n";
855   }
856 
857   lhsDriver.initialize(sample_string, sampleRanksMode, !subIteratorFlag);
858 }
859 
860 
861 /** Map ASV/DVV requests in final statistics into activeSet for use in
862     evaluate_parameter_sets() */
active_set_mapping()863 void NonDSampling::active_set_mapping()
864 {
865   // Adapted from NonDExpansion::compute_expansion()
866 
867   // Note: the ASV within finalStatistics corresponds to the stats vector,
868   // not the QoI vector, but the DVV carries over.
869   const ShortArray& final_asv = finalStatistics.active_set_request_vector();
870   size_t num_final_stats = final_asv.size();
871   if (!num_final_stats) // finalStatistics not initialized
872     return;             // leave activeSet as is; nothing to augment
873 
874   // activeSet ASV/DVV can include active-variable derivatives for surrogate
875   // creation (use_derivatives spec option).  Cannot easily support both this
876   // and moment gradients w.r.t. inactive variables without new logic for an
877   // aggregate DVV; however, the former case occurs in DataFitSurrModel
878   // contexts and the latter case occurs in NestedModel contexts:
879   // > for now, augment the incoming ASV (preserve the DataFitSurrModel case)
880   //   with any moment grad requirements and only overwrite the incoming DVV
881   //   when moment gradients are required (support the NestedModel case).
882   // > Model recursions that embed a derivative-enhanced DataFitSurrModel
883   //   within a NestedModel may dictate additional care...
884   ShortArray sampler_asv = activeSet.request_vector();//(numFunctions, 0);
885   bool assign_dvv = false, qoi_fn, qoi_grad, moment1_grad, moment2_grad;
886   size_t i, j, rl_len, pl_len, bl_len, gl_len, total_i, cntr = 0,
887     moment_offset = (finalMomentsType) ? 2 : 0;
888   for (i=0; i<numFunctions; ++i) {
889 
890     if (totalLevelRequests) {
891       rl_len = requestedRespLevels[i].length();
892       pl_len = requestedProbLevels[i].length();
893       bl_len = requestedRelLevels[i].length();
894       gl_len = requestedGenRelLevels[i].length();
895     }
896     else // requested level arrays may not be sized
897       rl_len = pl_len = bl_len = gl_len = 0;
898 
899     // map final_asv value bits into qoi_fns requirements
900     qoi_fn = qoi_grad = moment1_grad = moment2_grad = false;
901     total_i = moment_offset + rl_len + pl_len + bl_len + gl_len;
902     for (j=0; j<total_i; ++j)
903       if (final_asv[cntr+j] & 1)
904         { qoi_fn = true; break; }
905 
906     // map final_asv gradient bits into moment grad requirements
907     if (finalMomentsType) {
908       if (final_asv[cntr++] & 2) moment1_grad = true;
909       if (final_asv[cntr++] & 2) moment2_grad = true;
910     }
911     if (respLevelTarget == RELIABILITIES)
912       for (j=0; j<rl_len; ++j) // dbeta/ds requires mu,sigma,dmu/ds,dsigma/ds
913 	if (final_asv[cntr+j] & 2)
914 	  { moment1_grad = moment2_grad = qoi_fn = true; break;}
915     cntr += rl_len + pl_len;
916     for (j=0; j<bl_len; ++j)   // dz/ds requires dmu/ds, dsigma/ds
917       if (final_asv[cntr+j] & 2)
918 	{ moment1_grad = moment2_grad = true; break; }
919     cntr += bl_len + gl_len;
920     if (moment1_grad) assign_dvv = qoi_grad = true;
921     if (moment2_grad) assign_dvv = qoi_grad = qoi_fn = true;
922 
923     // map qoi_{fn,grad} requirements into ASV settings
924     if (qoi_fn)                    sampler_asv[i] |= 1;
925     if (qoi_grad /*|| useDerivs*/) sampler_asv[i] |= 2; // future aggregation...
926   }
927   activeSet.request_vector(sampler_asv);
928 
929   if (assign_dvv)
930     activeSet.derivative_vector(finalStatistics.active_set_derivative_vector());
931   //else leave DVV as default active cv's (from Iterator::update_from_model())
932 }
933 
934 
935 /** Default implementation generates allResponses from either allSamples
936     or allVariables. */
core_run()937 void NonDSampling::core_run()
938 {
939   bool log_resp_flag = (allDataFlag || statsFlag), log_best_flag = false;
940   evaluate_parameter_sets(iteratedModel, log_resp_flag, log_best_flag);
941 }
942 
943 
944 void NonDSampling::
compute_statistics(const RealMatrix & vars_samples,const IntResponseMap & resp_samples)945 compute_statistics(const RealMatrix&     vars_samples,
946 		   const IntResponseMap& resp_samples)
947 {
948   StringMultiArrayConstView
949     acv_labels  = iteratedModel.all_continuous_variable_labels(),
950     adiv_labels = iteratedModel.all_discrete_int_variable_labels(),
951     adsv_labels = iteratedModel.all_discrete_string_variable_labels(),
952     adrv_labels = iteratedModel.all_discrete_real_variable_labels();
953   size_t cv_start, num_cv, div_start, num_div, dsv_start, num_dsv,
954     drv_start, num_drv;
955   mode_counts(iteratedModel.current_variables(), cv_start, num_cv,
956 	      div_start, num_div, dsv_start, num_dsv, drv_start, num_drv);
957   StringMultiArrayConstView
958     cv_labels  =
959       acv_labels[boost::indices[idx_range(cv_start, cv_start+num_cv)]],
960     div_labels =
961       adiv_labels[boost::indices[idx_range(div_start, div_start+num_div)]],
962     dsv_labels =
963       adsv_labels[boost::indices[idx_range(dsv_start, dsv_start+num_dsv)]],
964     drv_labels =
965       adrv_labels[boost::indices[idx_range(drv_start, drv_start+num_drv)]];
966 
967   // archive the active variables with the results
968   if (resultsDB.active()) {
969     if (num_cv)
970       resultsDB.insert(run_identifier(), resultsNames.cv_labels, cv_labels);
971     if (num_div)
972       resultsDB.insert(run_identifier(), resultsNames.div_labels, div_labels);
973     if (num_dsv)
974       resultsDB.insert(run_identifier(), resultsNames.dsv_labels, dsv_labels);
975     if (num_drv)
976       resultsDB.insert(run_identifier(), resultsNames.drv_labels, drv_labels);
977     resultsDB.insert(run_identifier(), resultsNames.fn_labels,
978 		     iteratedModel.response_labels());
979   }
980 
981   if (epistemicStats) // Epistemic/mixed
982     compute_intervals(resp_samples); // compute min/max response intervals
983   else { // Aleatory
984     // compute means and std deviations with confidence intervals
985     compute_moments(resp_samples);
986     // compute CDF/CCDF mappings of z to p/beta and p/beta to z
987     if (totalLevelRequests)
988       compute_level_mappings(resp_samples);
989   }
990 
991   if (!subIteratorFlag) {
992     nonDSampCorr.compute_correlations(vars_samples, resp_samples);
993     // archive the correlations to the results DB
994 //    nonDSampCorr.archive_correlations(run_identifier(), resultsDB, cv_labels,
995 //				      div_labels, dsv_labels, drv_labels,
996 //				      iteratedModel.response_labels());
997   }
998 
999   // push results into finalStatistics
1000   update_final_statistics();
1001 }
1002 
1003 
1004 void NonDSampling::
compute_intervals(RealRealPairArray & extreme_fns,const IntResponseMap & samples)1005 compute_intervals(RealRealPairArray& extreme_fns, const IntResponseMap& samples)
1006 {
1007   // For the samples array, calculate min/max response intervals
1008 
1009   size_t i, j, num_obs = samples.size(), num_samp;
1010   const StringArray& resp_labels = iteratedModel.response_labels();
1011 
1012   extreme_fns.resize(numFunctions);
1013   IntRespMCIter it;
1014   for (i=0; i<numFunctions; ++i) {
1015     num_samp = 0;
1016     Real min = DBL_MAX, max = -DBL_MAX;
1017     for (it=samples.begin(); it!=samples.end(); ++it) {
1018       Real sample = it->second.function_value(i);
1019       if (std::isfinite(sample)) { // neither NaN nor +/-Inf
1020 	if (sample < min) min = sample;
1021 	if (sample > max) max = sample;
1022 	++num_samp;
1023       }
1024     }
1025     extreme_fns[i].first  = min;
1026     extreme_fns[i].second = max;
1027     if (num_samp != num_obs)
1028       Cerr << "Warning: sampling statistics for " << resp_labels[i] << " omit "
1029 	   << num_obs-num_samp << " failed evaluations out of " << num_obs
1030 	   << " samples.\n";
1031   }
1032 
1033   if (resultsDB.active()) {
1034     MetaDataType md;
1035     md["Row Labels"] = make_metadatavalue("Min", "Max");
1036     md["Column Labels"] = make_metadatavalue(resp_labels);
1037     resultsDB.insert(run_identifier(), resultsNames.extreme_values,
1038 		     extreme_fns, md);
1039   }
1040 }
1041 
1042 
1043 void NonDSampling::
compute_moments(const IntResponseMap & samples,RealMatrix & moment_stats,RealMatrix & moment_grads,RealMatrix & moment_conf_ints,short moments_type,const StringArray & labels)1044 compute_moments(const IntResponseMap& samples, RealMatrix& moment_stats,
1045 		RealMatrix& moment_grads, RealMatrix& moment_conf_ints,
1046 		short moments_type, const StringArray& labels)
1047 {
1048   // For the samples array, calculate 1st four moments and confidence intervals
1049 
1050   // if subIteratorFlag, final_asv will be general.  If not a sub-iterator, then
1051   // NonD::initialize_final_statistics() sets default request vector to 1's.
1052   const ShortArray& final_asv = finalStatistics.active_set_request_vector();
1053 
1054   // if statsFlag, always compute moments for output regardless of final ASV.
1055   // else define moment requirements from final_asv and finalMomentsType.
1056   bool mom_fns = statsFlag, mom_grads = false;
1057   size_t i, l, m, cntr, num_lev, num_obs = samples.size();
1058   for (i=0, cntr=0; i<numFunctions; ++i) {
1059     if (finalMomentsType) { // only compute moments if needed
1060       for (m=0; m<2; ++m, ++cntr) {
1061         if (final_asv[cntr] & 1) mom_fns   = true;
1062         if (final_asv[cntr] & 2) mom_grads = true;
1063       }
1064     }
1065     if (respLevelTarget == RELIABILITIES) {
1066       num_lev = requestedRespLevels[i].length();
1067       for (l=0; l<num_lev; ++l, ++cntr) {
1068         if (final_asv[cntr] & 1) mom_fns = true;
1069         // dbeta/ds requires mu,sigma,dmu/ds,dsigma/ds
1070         if (final_asv[cntr] & 2) mom_fns = mom_grads = true;
1071       }
1072     }
1073     else
1074       cntr += requestedRespLevels[i].length();
1075     cntr += requestedProbLevels[i].length();
1076     num_lev = requestedRelLevels[i].length();
1077     for (l=0; l<num_lev; ++l, ++cntr) {
1078       if (final_asv[cntr] & 1) mom_fns = true;
1079       // dz/ds requires dmu/ds, dsigma/ds
1080       if (final_asv[cntr] & 2) mom_grads = true;
1081     }
1082     cntr += requestedGenRelLevels[i].length();
1083   }
1084   if (!mom_fns && !mom_grads)
1085     return;
1086 
1087   RealVectorArray fn_samples(num_obs);
1088   SizetArray sample_counts;
1089   IntRespMCIter it;
1090   for (it=samples.begin(), i=0; it!=samples.end(); ++it, ++i)
1091     fn_samples[i] = it->second.function_values_view();
1092 
1093   if (mom_fns) {
1094     compute_moments(fn_samples,sample_counts,moment_stats,moments_type,labels);
1095     compute_moment_confidence_intervals(moment_stats, moment_conf_ints,
1096 					sample_counts, moments_type);
1097     functionMomentsComputed = true;
1098   }
1099 
1100   if (mom_grads) {
1101     RealMatrixArray grad_samples(num_obs);
1102     for (it=samples.begin(), i=0; it!=samples.end(); ++it, ++i)
1103       grad_samples[i] = it->second.function_gradients_view();
1104     compute_moment_gradients(fn_samples, grad_samples, moment_stats,
1105 			     moment_grads, moments_type);
1106   }
1107 }
1108 
1109 
1110 void NonDSampling::
compute_moments(const RealVectorArray & fn_samples,SizetArray & sample_counts,RealMatrix & moment_stats,short moments_type,const StringArray & labels)1111 compute_moments(const RealVectorArray& fn_samples, SizetArray& sample_counts,
1112 		RealMatrix& moment_stats, short moments_type,
1113 		const StringArray& labels)
1114 {
1115   size_t i, j, num_obs = fn_samples.size(), num_qoi;
1116   if (num_obs)
1117     num_qoi = fn_samples[0].length();
1118   else {
1119     Cerr << "Error: empty samples array in NonDSampling::compute_moments()."
1120 	 << std::endl;
1121     abort_handler(METHOD_ERROR);
1122   }
1123   Real sum, cm2, cm3, cm4, sample;
1124 
1125   if (moment_stats.empty()) moment_stats.shapeUninitialized(4, num_qoi);
1126   sample_counts.resize(num_qoi);
1127 
1128   for (i=0; i<num_qoi; ++i) {
1129     size_t& num_samp = sample_counts[i];
1130     Real*  moments_i =  moment_stats[i];
1131     accumulate_mean(fn_samples, i, num_samp, moments_i[0]);
1132     if (num_samp != num_obs)
1133       Cerr << "Warning: sampling statistics for " << labels[i] << " omit "
1134 	   << num_obs-num_samp << " failed evaluations out of " << num_obs
1135 	   << " samples.\n";
1136 
1137     if (num_samp)
1138       accumulate_moments(fn_samples, i, moments_type, moments_i);
1139     else {
1140       Cerr << "Warning: Number of samples for " << labels[i]
1141 	   << " must be nonzero for moment calculation in NonDSampling::"
1142 	   << "compute_moments().\n";
1143       for (int j=0; j<4; ++j)
1144 	moments_i[j] = std::numeric_limits<double>::quiet_NaN();
1145     }
1146   }
1147 }
1148 
1149 
1150 void NonDSampling::
compute_moments(const RealVectorArray & fn_samples,RealMatrix & moment_stats,short moments_type)1151 compute_moments(const RealVectorArray& fn_samples, RealMatrix& moment_stats,
1152 		short moments_type)
1153 {
1154   size_t i, j, num_obs = fn_samples.size(), num_qoi, num_samp;
1155   if (num_obs)
1156     num_qoi = fn_samples[0].length();
1157   else {
1158     Cerr << "Error: empty samples array in NonDSampling::compute_moments()."
1159 	 << std::endl;
1160     abort_handler(METHOD_ERROR);
1161   }
1162 
1163   if (moment_stats.empty()) moment_stats.shapeUninitialized(4, num_qoi);
1164 
1165   for (i=0; i<num_qoi; ++i) {
1166 
1167     Real* moments_i = moment_stats[i];
1168     accumulate_mean(fn_samples, i, num_samp, moments_i[0]);
1169     if (num_samp != num_obs)
1170       Cerr << "Warning: sampling statistics for quantity " << i+1 << " omit "
1171 	   << num_obs-num_samp << " failed evaluations out of " << num_obs
1172 	   << " samples.\n";
1173 
1174     if (num_samp)
1175       accumulate_moments(fn_samples, i, moments_type, moments_i);
1176     else {
1177       Cerr << "Warning: Number of samples for quantity " << i+1
1178 	   << " must be nonzero in NonDSampling::compute_moments().\n";
1179       for (size_t j=0; j<4; ++j)
1180 	moments_i[j] = std::numeric_limits<double>::quiet_NaN();
1181     }
1182   }
1183 }
1184 
1185 
1186 void NonDSampling::
compute_moments(const RealMatrix & fn_samples,RealMatrix & moment_stats,short moments_type)1187 compute_moments(const RealMatrix& fn_samples, RealMatrix& moment_stats,
1188 		short moments_type)
1189 {
1190   int i, num_qoi = fn_samples.numRows(), num_obs = fn_samples.numCols();
1191   RealVectorArray rva_samples(num_obs);
1192   for (i=0; i<num_obs; ++i)
1193     rva_samples[i]
1194       = RealVector(Teuchos::View, const_cast<Real*>(fn_samples[i]), num_qoi);
1195   compute_moments(rva_samples, moment_stats, moments_type);
1196 }
1197 
1198 
1199 void NonDSampling::
compute_moment_confidence_intervals(const RealMatrix & moment_stats,RealMatrix & moment_conf_ints,const SizetArray & sample_counts,short moments_type)1200 compute_moment_confidence_intervals(const RealMatrix& moment_stats,
1201 				    RealMatrix& moment_conf_ints,
1202 				    const SizetArray& sample_counts,
1203 				    short moments_type)
1204 {
1205   size_t i, num_qoi = moment_stats.numCols();
1206   if (moment_conf_ints.empty())
1207     moment_conf_ints.shapeUninitialized(4, num_qoi);
1208 
1209   Real mean, std_dev, var, qnan = std::numeric_limits<double>::quiet_NaN();
1210   for (i=0; i<num_qoi; ++i) {
1211     if (sample_counts[i] > 1) {
1212       const Real* moment_i = moment_stats[i];
1213       Real*    moment_ci_i = moment_conf_ints[i];
1214       mean = moment_i[0];
1215       if (moments_type == CENTRAL_MOMENTS)
1216         { var = moment_i[1]; std_dev = std::sqrt(var); }
1217       else
1218         { std_dev = moment_i[1]; var = std_dev * std_dev; }
1219       if (mean == qnan || std_dev == qnan || var == qnan)
1220 	for (size_t j=0; j<4; ++j)
1221 	  moment_ci_i[j] = qnan;
1222       else {
1223 	// 95% confidence intervals (2-sided interval, not 1-sided limit)
1224 	Real ns = (Real)sample_counts[i], dof = ns - 1.;
1225 	// mean: the better formula does not assume known variance but requires
1226 	// a function for the Student's t-distr. with (num_samp-1) degrees of
1227 	// freedom (Haldar & Mahadevan, p. 127).
1228 	Pecos::students_t_dist t_dist(dof);
1229 	Real mean_ci_delta = std_dev*bmth::quantile(t_dist,0.975)/std::sqrt(ns);
1230 	moment_ci_i[0] = mean - mean_ci_delta;
1231 	moment_ci_i[1] = mean + mean_ci_delta;
1232 	// std dev: chi-square distribution with (num_samp-1) degrees of freedom
1233 	// (Haldar & Mahadevan, p. 132).
1234 	Pecos::chi_squared_dist chisq(dof);
1235 	Real z_975 = bmth::quantile(chisq, 0.975),
1236 	     z_025 = bmth::quantile(chisq, 0.025);
1237 	if (moments_type == CENTRAL_MOMENTS) {
1238 	  moment_ci_i[2] = var*dof/z_975;
1239 	  moment_ci_i[3] = var*dof/z_025;
1240 	}
1241 	else {
1242 	  moment_ci_i[2] = std_dev*std::sqrt(dof/z_975);
1243 	  moment_ci_i[3] = std_dev*std::sqrt(dof/z_025);
1244 	}
1245       }
1246     }
1247     else
1248       for (size_t j=0; j<4; ++j)
1249 	moment_conf_ints(j,i) = 0.;
1250   }
1251 }
1252 
1253 
1254 void NonDSampling::
compute_moment_gradients(const RealVectorArray & fn_samples,const RealMatrixArray & grad_samples,const RealMatrix & moment_stats,RealMatrix & moment_grads,short moments_type)1255 compute_moment_gradients(const RealVectorArray& fn_samples,
1256 			 const RealMatrixArray& grad_samples,
1257 			 const RealMatrix& moment_stats,
1258 			 RealMatrix& moment_grads, short moments_type)
1259 {
1260   const ShortArray& final_asv = finalStatistics.active_set_request_vector();
1261   size_t q, cntr = 0;
1262   int m1_index, m2_index, num_mom = 2*numFunctions,
1263     num_deriv_vars = finalStatistics.active_set_derivative_vector().size();
1264   if (moment_grads.numRows() != num_deriv_vars ||
1265       moment_grads.numRows() != num_mom)
1266     moment_grads.shape(num_deriv_vars, num_mom); // init to 0.
1267   else
1268     moment_grads = 0.;
1269 
1270   for (q=0; q<numFunctions; ++q) {
1271     m1_index = 2*q; m2_index = m1_index + 1;
1272     // Compute moment_grads
1273     accumulate_moment_gradients(fn_samples, grad_samples, q, moments_type,
1274 				moment_stats(0,q), moment_stats(1,q),
1275 				moment_grads[m1_index], moment_grads[m2_index]);
1276     // Assign moment_grads into finalStatistics (could do this in one step,
1277     // but retain API of moment_stats and moment_grads as their own matrices).
1278     // > NonDExpansion and NonDLocalReliability do not store moment grads as
1279     //   member variables; they update finalStats directly in NonDExpansion::
1280     //   compute_analytic_statistics() and NonDLocalRel::update_level_data().
1281     //   Note: NonDExpansion::update_final_statistics_gradients() provides
1282     //   post-processing for special cases (combined vars, insertion).
1283     // > NonDSampling could retain a class member or use a local variable for
1284     //   moment_grads (currently a local, whereas momentStats is a member)
1285     if (moments_type) {
1286       if (final_asv[cntr] & 2) // moment 1 (mean) gradient
1287 	finalStatistics.function_gradient(
1288 	  Teuchos::getCol(Teuchos::View, moment_grads, m1_index), cntr);
1289       ++cntr;
1290       if (final_asv[cntr] & 2) // moment 2 (var or stdev) gradient
1291 	finalStatistics.function_gradient(
1292 	  Teuchos::getCol(Teuchos::View, moment_grads, m2_index), cntr);
1293       cntr += 1 +
1294 	requestedRespLevels[q].length() + requestedProbLevels[q].length() +
1295 	requestedRelLevels[q].length()  + requestedGenRelLevels[q].length();
1296     }
1297   }
1298 }
1299 
1300 
1301 void NonDSampling::
accumulate_mean(const RealVectorArray & fn_samples,size_t q,size_t & num_samp,Real & mean)1302 accumulate_mean(const RealVectorArray& fn_samples, size_t q, size_t& num_samp,
1303 		Real& mean)
1304 {
1305   num_samp = 0;
1306   Real sum = 0., sample;
1307   size_t s, num_obs = fn_samples.size();
1308   for (s=0; s<num_obs; ++s) {
1309     sample = fn_samples[s][q];
1310     if (std::isfinite(sample)) { // neither NaN nor +/-Inf
1311       sum += sample;
1312       ++num_samp;
1313     }
1314   }
1315 
1316   if (num_samp)
1317     mean = sum / (Real)num_samp;
1318 }
1319 
1320 
1321 void NonDSampling::
accumulate_moments(const RealVectorArray & fn_samples,size_t q,short moments_type,Real * moments)1322 accumulate_moments(const RealVectorArray& fn_samples, size_t q,
1323 		   short moments_type, Real* moments)
1324 {
1325   // accumulate central moments (e.g., variance)
1326   size_t s, num_obs = fn_samples.size(), num_samp = 0;
1327   Real& mean = moments[0]; // already computed in accumulate_mean()
1328   Real sample, centered_fn, pow_fn, sum2 = 0., sum3 = 0., sum4 = 0.;
1329   for (s=0; s<num_obs; ++s) {
1330     sample = fn_samples[s][q];
1331     if (std::isfinite(sample)) { // neither NaN nor +/-Inf
1332       pow_fn  = centered_fn = sample - mean;
1333       pow_fn *= centered_fn; sum2 += pow_fn; // variance
1334       pow_fn *= centered_fn; sum3 += pow_fn; // 3rd central moment
1335       pow_fn *= centered_fn; sum4 += pow_fn; // 4th central moment
1336       ++num_samp;
1337     }
1338   }
1339   Real ns = (Real)num_samp, nm1 = ns - 1., nm2 = ns - 2., ns_sq = ns * ns;
1340   // biased central moment estimators (bypass and use raw sums below):
1341   //biased_cm2 = sum2 / ns; biased_cm3 = sum3 / ns; biased_cm4 = sum4 / ns;
1342 
1343   // unbiased moment estimators (central and standardized):
1344   bool central = (moments_type == CENTRAL_MOMENTS), pos_var = (sum2 > 0.);
1345   Real cm2 = sum2 / nm1;
1346   if (num_samp > 1 && pos_var)
1347     moments[1] = (central) ? cm2 : std::sqrt(cm2); // unbiased central : std dev
1348   else moments[1] = 0.;
1349 
1350   if (num_samp > 2 && pos_var)
1351     moments[2] = (central) ?
1352       // unbiased central:
1353       sum3 * ns / (nm1 * nm2) :
1354       // unbiased standard: cm3 / sigma^3 = N / (nm1 nm2) sum3 / (cm2)^1.5
1355       sum3 * ns / (nm1 * nm2 * std::pow(cm2, 1.5));
1356   else moments[2] = 0.;
1357 
1358   if (num_samp > 3 && pos_var)
1359     moments[3] = (central) ?
1360       // unbiased central (non-excess) from "Modeling with Data," Klemens 2009
1361       // (Appendix M):  unbiased_cm4 =
1362       // ( N^3 biased_cm4 / (N-1) - (6N - 9) unbiased_cm2^2 ) / (N^2 - 3N + 3)
1363       //(ns * ns * sum4 / nm1 - (6.*ns - 9.) * cm2 * cm2) / (ns*(ns - 3.) + 3.) :
1364       //[fm] above estimator is not unbiased since cm2 * cm2 is biased, unbiased correction:
1365       (ns_sq * sum4 / nm1 - (6.*ns - 9.)*(ns_sq - ns)/(ns_sq - 2. * ns + 3) * cm2 * cm2) / ( (ns*(ns - 3.) + 3.) - ( (6.*ns - 9.)*(ns_sq - ns) )/( ns * (ns_sq - 2.*ns + 3) ) ) :
1366       // unbiased standard (excess kurtosis) from Wikipedia ("Estimators of
1367       // population kurtosis")
1368       nm1 * ((ns + 1.) * ns * sum4 / (sum2*sum2) - 3.*nm1) / (nm2*(ns - 3.));
1369   else moments[3] = (central) ? 0. : -3.;
1370 }
1371 
1372 
1373 void NonDSampling::
accumulate_moment_gradients(const RealVectorArray & fn_samples,const RealMatrixArray & grad_samples,size_t q,short moments_type,Real mean,Real mom2,Real * mean_grad,Real * mom2_grad)1374 accumulate_moment_gradients(const RealVectorArray& fn_samples,
1375 			    const RealMatrixArray& grad_samples, size_t q,
1376 			    short moments_type, Real mean, Real mom2,
1377 			    Real* mean_grad, Real* mom2_grad)
1378 {
1379   size_t s, v, num_deriv_vars,
1380     num_obs = std::min(fn_samples.size(), grad_samples.size());
1381   if (num_obs)
1382     num_deriv_vars = grad_samples[0].numRows(); // functionGradients = V x Q
1383   else {
1384     Cerr << "Error: emply samples array in NonDSampling::"
1385 	 << "accumulate_moment_gradients()" << std::endl;
1386     abort_handler(METHOD_ERROR);
1387   }
1388   //for (v=0; v<num_deriv_vars; ++v)
1389   //  mean_grad[v] = mom2_grad[v] = 0.;
1390 
1391   SizetArray num_samp(num_deriv_vars, 0);
1392   for (s=0; s<num_obs; ++s) {
1393     // manage faults hierarchically as in Pecos::SurrogateData::response_check()
1394     Real fn = fn_samples[s][q];
1395     if (std::isfinite(fn)) {          // neither NaN nor +/-Inf
1396       const Real* grad = grad_samples[s][q];
1397       for (v=0; v<num_deriv_vars; ++v)
1398 	if (std::isfinite(grad[v])) { // neither NaN nor +/-Inf
1399 	  mean_grad[v] += grad[v];
1400 	  mom2_grad[v] += fn * grad[v];
1401 	  ++num_samp[v];
1402 	}
1403     }
1404   }
1405 
1406   Real ns, nm1; size_t nsv;
1407   bool central_mom = (moments_type == CENTRAL_MOMENTS);
1408   for (v=0; v<num_deriv_vars; ++v) {
1409     nsv = num_samp[v];
1410     if (nsv) {
1411       ns = (Real)nsv;
1412       // dMean/ds = E[dQ/ds] --> unbiased estimator 1/N Sum(dQ/ds)
1413       mean_grad[v] /= ns;
1414     }
1415     if (nsv > 1) {
1416       nm1 = ns - 1.;
1417       // dVar/ds = 2 E[(Q - Mean)(dQ/ds - dMean/ds)] --> unbiased var estimator:
1418       // = 2/(N-1) [ Sum(Q dQ/ds) - Mean Sum(dQ/ds) -
1419       //             dMean/ds Sum(Q) + N Mean Mean/ds ]
1420       // = 2/(N-1) [ Sum(Q dQ/ds) - Mean dMean/ds (N + N - N) ]
1421       // = 2/(N-1) [ Sum(Q dQ/ds) - N Mean dMean/ds ]
1422       // dVar/ds = 2 Sigma dSigma/ds -->
1423       // dSigma/ds = [ Sum(Q dQ/ds) - N Mean dMean/ds ] / (Sigma (N-1))
1424       mom2_grad[v]  = (central_mom) ?
1425 	2. * ( mom2_grad[v] - ns * mean * mean_grad[v] ) / nm1 :
1426 	     ( mom2_grad[v] - ns * mean * mean_grad[v] ) / (mom2 * nm1);
1427     }
1428   }
1429 }
1430 
1431 
1432 void NonDSampling::
archive_moments(size_t inc_id)1433 archive_moments(size_t inc_id)
1434 {
1435   if(!resultsDB.active()) return;
1436 
1437   const StringArray &labels = iteratedModel.response_labels();
1438 
1439   // archive the moments to results DB
1440   MetaDataType md_moments;
1441   md_moments["Row Labels"] = (finalMomentsType == CENTRAL_MOMENTS) ?
1442     make_metadatavalue("Mean", "Variance", "3rdCentral", "4thCentral") :
1443     make_metadatavalue("Mean", "Standard Deviation", "Skewness", "Kurtosis");
1444   md_moments["Column Labels"] = make_metadatavalue(labels);
1445   resultsDB.insert(run_identifier(), resultsNames.moments_std, momentStats,
1446 		   md_moments);
1447 
1448   // send to prototype hdf5DB, too
1449   StringArray location;
1450   if(inc_id) location.push_back(String("increment:") + std::to_string(inc_id));
1451   location.push_back("moments");
1452   location.push_back("");
1453   for(int i = 0; i < numFunctions; ++i) {
1454     location.back() = labels[i];
1455     DimScaleMap scales;
1456     if(finalMomentsType == CENTRAL_MOMENTS)
1457       scales.emplace(0,
1458                      StringScale("moments",
1459                      {"mean", "variance", "third_central", "fourth_central"},
1460                      ScaleScope::SHARED));
1461     else
1462       scales.emplace(0,
1463                      StringScale("moments",
1464                      {"mean", "std_deviation", "skewness", "kurtosis"},
1465                      ScaleScope::SHARED));
1466     // extract column or row of moment_stats
1467     resultsDB.insert(run_identifier(), location,
1468         Teuchos::getCol<int,double>(Teuchos::View, *const_cast<RealMatrix*>(&momentStats), i), scales);
1469   }
1470 }
1471 
1472 
1473 void NonDSampling::
archive_moment_confidence_intervals(size_t inc_id)1474 archive_moment_confidence_intervals(size_t inc_id)
1475 {
1476   if(!resultsDB.active())
1477     return;
1478 
1479   const StringArray &labels = iteratedModel.response_labels();
1480   // archive the confidence intervals to results DB
1481   MetaDataType md;
1482   md["Row Labels"] = (finalMomentsType == CENTRAL_MOMENTS) ?
1483     make_metadatavalue("LowerCI_Mean", "UpperCI_Mean",
1484 		       "LowerCI_Variance", "UpperCI_Variance") :
1485     make_metadatavalue("LowerCI_Mean", "UpperCI_Mean",
1486 		       "LowerCI_StdDev", "UpperCI_StdDev");
1487   md["Column Labels"] = make_metadatavalue(labels);
1488   resultsDB.insert(run_identifier(), resultsNames.moment_cis,
1489 		   momentCIs, md);
1490   // archive in HDF5. Store in a 2d dataset with mean and var/stdev on the 1st dimension
1491   // and lower and upper bounds on the 2nd dimension
1492   DimScaleMap scales;
1493   scales.emplace(0, StringScale("bounds", {"lower", "upper"}));
1494   if(finalMomentsType == CENTRAL_MOMENTS)
1495     scales.emplace(1, StringScale("moments", {"mean", "variance"}));
1496   else
1497     scales.emplace(1, StringScale("moments", {"mean", "std_deviation"}));
1498 
1499   StringArray location;
1500   if(inc_id) location.push_back(String("increment:") + std::to_string(inc_id));
1501   location.push_back("moment_confidence_intervals");
1502   location.push_back("");
1503   for(int i = 0; i < numFunctions; ++i) { // loop over responses
1504     location.back() = labels[i];
1505     RealMatrix ci(2,2,false);
1506     ci(0,0) = momentCIs(0,i);
1507     ci(1,0) = momentCIs(1,i);
1508     ci(0,1) = momentCIs(2,i);
1509     ci(1,1) = momentCIs(3,i);
1510     resultsDB.insert(run_identifier(), location, ci, scales);
1511   }
1512 }
1513 
1514 void NonDSampling::
archive_extreme_responses(size_t inc_id)1515 archive_extreme_responses(size_t inc_id) {
1516   const StringArray &labels = iteratedModel.response_labels();
1517   StringArray location;
1518   if(inc_id) location.push_back(String("increment:") + std::to_string(inc_id));
1519   location.push_back("extreme_responses");
1520   location.push_back("");
1521   DimScaleMap scales;
1522   scales.emplace(0, StringScale("extremes", {"minimum", "maximum"}));
1523   for(int i = 0; i < numFunctions; ++i) { // loop over responses
1524     location.back() = labels[i];
1525     RealVector extreme_values(2);
1526     extreme_values[0] = extremeValues[i].first;
1527     extreme_values[1] = extremeValues[i].second;
1528     resultsDB.insert(run_identifier(), location, extreme_values, scales);
1529   }
1530 }
1531 
1532 int NonDSampling::
compute_wilks_sample_size(unsigned short order,Real alpha,Real beta,bool twosided)1533 compute_wilks_sample_size(unsigned short order, Real alpha, Real beta,
1534 			  bool twosided)
1535 {
1536   Real rorder = (Real) order;
1537 
1538   if( !twosided && (order==1) )
1539     return std::ceil(std::log(1.0-beta)/std::log(alpha));
1540 
1541   Real n = rorder + 1.0;
1542   if( twosided ) {
1543     n = 2.0*rorder;
1544     while( boost::math::ibeta<Real>(n-2.0*rorder+1.0, 2.0*rorder, alpha) >
1545 	   1.0-beta )
1546       n += 1.0;
1547   }
1548   else {
1549     while( boost::math::ibeta<Real>(rorder, n-rorder+1.0, 1-alpha) < beta )
1550       n += 1.0;
1551   }
1552 
1553   return std::ceil(n);
1554 }
1555 
1556 
1557 Real NonDSampling::
compute_wilks_residual(unsigned short order,int nsamples,Real alpha,Real beta,bool twosided)1558 compute_wilks_residual(unsigned short order, int nsamples, Real alpha,
1559 		       Real beta, bool twosided)
1560 {
1561   Real rorder = (Real) order;
1562 
1563   if( !twosided && (order==1) )
1564     return std::log(1.0-beta)/std::log(alpha) - (Real) nsamples;
1565 
1566   if( twosided )
1567     return boost::math::ibeta<Real>((Real)nsamples-2.0*rorder+1.0, 2.0*rorder, alpha) - (1.0-beta);
1568   else
1569     return boost::math::ibeta<Real>(rorder, (Real)nsamples-rorder+1.0, 1-alpha) - beta;
1570 }
1571 
1572 
1573 Real NonDSampling::
compute_wilks_alpha(unsigned short order,int nsamples,Real beta,bool twosided)1574 compute_wilks_alpha(unsigned short order, int nsamples, Real beta,
1575 		    bool twosided)
1576 {
1577   Real rorder = (Real) order;
1578 
1579   Real alpha_l = get_wilks_alpha_min(); // initial lower bound
1580   Real alpha_u = get_wilks_alpha_max(); // initial upper bound
1581   Real resid_l = compute_wilks_residual(order, nsamples, alpha_l, beta, twosided);
1582   Real resid_u = compute_wilks_residual(order, nsamples, alpha_u, beta, twosided);
1583   if( resid_l*resid_u > 0 )
1584     throw std::runtime_error("Cannot obtain valid bounds for wilks alpha bisection.");
1585 
1586   //Cout << "\nalpha = " << alpha << ", resid = " << resid << std::endl;
1587   Real tol = 1.e-10;
1588   //Real eps = 1.e-8;
1589   Real alpha = alpha_l;
1590   Real resid = resid_l;
1591 
1592   while( std::fabs(resid) > tol )
1593   {
1594     // Newton approach is too fragile - RWH
1595     //Real resid_plus  = compute_wilks_residual(order, nsamples, alpha+eps, beta, twosided);
1596     //Real resid_minus = compute_wilks_residual(order, nsamples, alpha-eps, beta, twosided);
1597     //alpha -= resid/( (resid_plus-resid_minus)/(2.0*eps) );
1598     alpha = 0.5*(alpha_l+alpha_u);
1599     resid = compute_wilks_residual(order, nsamples, alpha, beta, twosided);
1600     if( resid*resid_u > 0 ) {
1601       alpha_u = alpha;
1602       resid_u = resid;
1603     }
1604     else {
1605       alpha_l = alpha;
1606       resid_l = resid;
1607     }
1608     //Cout << "alpha = " << alpha << ", resid = " << resid << std::endl;
1609   }
1610   //Cout << "Converged: alpha = " << alpha << ", resid = " << resid << std::endl;
1611 
1612   return alpha;
1613 }
1614 
1615 
1616 Real NonDSampling::
compute_wilks_beta(unsigned short order,int nsamples,Real alpha,bool twosided)1617 compute_wilks_beta(unsigned short order, int nsamples, Real alpha,
1618 		   bool twosided)
1619 {
1620   Real rorder = (Real) order;
1621 
1622   Real beta_l = get_wilks_beta_min(); // initial lower bound
1623   Real beta_u = get_wilks_beta_max(); // initial upper bound
1624   Real resid_l = compute_wilks_residual(order, nsamples, alpha, beta_l, twosided);
1625   Real resid_u = compute_wilks_residual(order, nsamples, alpha, beta_u, twosided);
1626   if( resid_l*resid_u > 0 )
1627     throw std::runtime_error("Cannot obtain valid bounds for wilks beta bisection.");
1628 
1629   Real tol = 1.e-10;
1630   Real beta = beta_l;
1631   Real resid = resid_l;
1632 
1633   while( std::fabs(resid) > tol )
1634   {
1635     beta = 0.5*(beta_l+beta_u);
1636     resid = compute_wilks_residual(order, nsamples, alpha, beta, twosided);
1637     if( resid*resid_u > 0 ) {
1638       beta_u = beta;
1639       resid_u = resid;
1640     }
1641     else {
1642       beta_l = beta;
1643       resid_l = resid;
1644     }
1645     //Cout << "beta = " << beta << ", resid = " << resid << std::endl;
1646   }
1647   //Cout << "Converged: beta = " << beta << ", resid = " << resid << std::endl;
1648 
1649   return beta;
1650 }
1651 
1652 
1653 /** Computes CDF/CCDF based on sample binning.  A PDF is inferred from a
1654     CDF/CCDF within compute_densities() after level computation. */
compute_level_mappings(const IntResponseMap & samples)1655 void NonDSampling::compute_level_mappings(const IntResponseMap& samples)
1656 {
1657   // Size the output arrays here instead of in the ctor in order to support
1658   // alternate sampling ctors.
1659   initialize_level_mappings();
1660   archive_allocate_mappings();
1661 
1662   // For the samples array, calculate the following statistics:
1663   // > CDF/CCDF mappings of response levels to probability/reliability levels
1664   // > CDF/CCDF mappings of probability/reliability levels to response levels
1665   size_t i, j, k, num_obs = samples.size(), num_samp, bin_accumulator;
1666   const StringArray& resp_labels = iteratedModel.response_labels();
1667   std::multiset<Real> sorted_samples; // STL-based array for sorting
1668   SizetArray bins; Real min, max, sample;
1669 
1670   // check if moments are required, and if so, compute them now
1671   if (momentStats.empty()) {
1672     bool need_moments = false;
1673     for (i=0; i<numFunctions; ++i)
1674       if ( !requestedRelLevels[i].empty() ||
1675 	   ( !requestedRespLevels[i].empty() &&
1676 	     respLevelTarget == RELIABILITIES ) )
1677 	{ need_moments = true; break; }
1678     if (need_moments) {
1679       Cerr << "Error: required moments not available in compute_distribution_"
1680 	   << "mappings().  Call compute_moments() first." << std::endl;
1681       abort_handler(METHOD_ERROR);
1682       // Issue with the following approach is that subsequent invocations of
1683       // compute_level_mappings() without compute_moments() would not be
1684       // detected and old moments would be used.  Performing more rigorous
1685       // bookkeeping of moment updates is overkill for current use cases.
1686       //Cerr << "Warning: moments not available in compute_distribution_"
1687       //     << "mappings(); computing them now." << std::endl;
1688       //compute_moments(samples);
1689     }
1690   }
1691 
1692   if (pdfOutput) extremeValues.resize(numFunctions);
1693   IntRespMCIter s_it; std::multiset<Real>::iterator ss_it;
1694   const ShortArray& final_asv = finalStatistics.active_set_request_vector();
1695   bool extrapolated_mappings = false,
1696     central_mom = (finalMomentsType == CENTRAL_MOMENTS);
1697   size_t cntr = 0,
1698     num_deriv_vars = finalStatistics.active_set_derivative_vector().size(),
1699     moment_offset = (finalMomentsType) ? 2 : 0;
1700   RealVector mean_grad, mom2_grad;
1701   for (i=0; i<numFunctions; ++i) {
1702 
1703     // CDF/CCDF mappings: z -> p/beta/beta* and p/beta/beta* -> z
1704     size_t rl_len = requestedRespLevels[i].length(),
1705            pl_len = requestedProbLevels[i].length(),
1706            bl_len = requestedRelLevels[i].length(),
1707            gl_len = requestedGenRelLevels[i].length();
1708 
1709     // ----------------------------------------------------------------------
1710     // Preliminaries: define finite subset, sort (if needed), and bin samples
1711     // ----------------------------------------------------------------------
1712     num_samp = 0;
1713     if (pl_len || gl_len) { // sort samples array for p/beta* -> z mappings
1714       sorted_samples.clear();
1715       for (s_it=samples.begin(); s_it!=samples.end(); ++s_it) {
1716         sample = s_it->second.function_value(i);
1717 	if (std::isfinite(sample))
1718 	  { ++num_samp; sorted_samples.insert(sample); }
1719       }
1720       // sort in ascending order
1721       if (pdfOutput)
1722         { min = *sorted_samples.begin(); max = *(--sorted_samples.end()); }
1723       // in case of rl_len mixed with pl_len/gl_len, bin using sorted array.
1724       if (rl_len && respLevelTarget != RELIABILITIES) {
1725 	const RealVector& req_rl_i = requestedRespLevels[i];
1726         bins.assign(rl_len+1, 0); ss_it = sorted_samples.begin();
1727 	for (j=0; j<rl_len; ++j)
1728 	  while (ss_it!=sorted_samples.end() && *ss_it <= req_rl_i[j])// p(g<=z)
1729 	    { ++bins[j]; ++ss_it; }
1730 	bins[rl_len] += std::distance(ss_it, sorted_samples.end());
1731       }
1732     }
1733     else if (rl_len && respLevelTarget != RELIABILITIES) {
1734       // in case of rl_len without pl_len/gl_len, bin from original sample set
1735       const RealVector& req_rl_i = requestedRespLevels[i];
1736       bins.assign(rl_len+1, 0); min = DBL_MAX; max = -DBL_MAX;
1737       for (s_it=samples.begin(); s_it!=samples.end(); ++s_it) {
1738 	sample = s_it->second.function_value(i);
1739 	if (std::isfinite(sample)) {
1740 	  ++num_samp;
1741 	  if (pdfOutput) {
1742 	    if (sample < min) min = sample;
1743 	    if (sample > max) max = sample;
1744 	  }
1745 	  // 1st PDF bin from -inf to 1st resp lev; last PDF bin from last resp
1746 	  // lev to +inf.
1747 	  bool found = false;
1748 	  for (k=0; k<rl_len; ++k)
1749 	    if (sample <= req_rl_i[k]) // cumulative p(g<=z)
1750 	      { ++bins[k]; found = true; break; }
1751 	  if (!found)
1752 	    ++bins[rl_len];
1753 	}
1754       }
1755     }
1756     if (pdfOutput)
1757       { extremeValues[i].first = min; extremeValues[i].second = max; }
1758 
1759     cntr += moment_offset;
1760     // ----------------
1761     // Process mappings
1762     // ----------------
1763     if (rl_len) {
1764       switch (respLevelTarget) {
1765       case PROBABILITIES: case GEN_RELIABILITIES: // z -> p/beta* (from binning)
1766 	bin_accumulator = 0;
1767 	for (j=0; j<rl_len; ++j, ++cntr) { // compute CDF/CCDF p/beta*
1768 	  bin_accumulator += bins[j];
1769 	  Real cdf_prob = (Real)bin_accumulator/(Real)num_samp;
1770 	  Real computed_prob = (cdfFlag) ? cdf_prob : 1. - cdf_prob;
1771 	  if (respLevelTarget == PROBABILITIES)
1772 	    computedProbLevels[i][j] = computed_prob;
1773 	  else
1774 	    computedGenRelLevels[i][j]
1775 	      = -Pecos::NormalRandomVariable::inverse_std_cdf(computed_prob);
1776 	}
1777 	break;
1778       case RELIABILITIES: { // z -> beta (from moment projection)
1779 	Real mean  = momentStats(0,i);
1780 	Real stdev = (central_mom) ?
1781 	  std::sqrt(momentStats(1,i)) : momentStats(1,i);
1782 	if (!momentGrads.empty()) {
1783 	  int i2 = 2*i;
1784 	  mean_grad = Teuchos::getCol(Teuchos::View, momentGrads, i2);
1785 	  mom2_grad = Teuchos::getCol(Teuchos::View, momentGrads, i2+1);
1786 	}
1787 	for (j=0; j<rl_len; j++, ++cntr) {
1788 	  // *** beta
1789 	  Real z_bar = requestedRespLevels[i][j];
1790 	  if (stdev > Pecos::SMALL_NUMBER)
1791 	    computedRelLevels[i][j] = (cdfFlag) ?
1792 	      (mean - z_bar)/stdev : (z_bar - mean)/stdev;
1793 	  else
1794 	    computedRelLevels[i][j]
1795 	      = ( (cdfFlag && mean <= z_bar) || (!cdfFlag && mean > z_bar) )
1796 	      ? -Pecos::LARGE_NUMBER : Pecos::LARGE_NUMBER;
1797 	  // *** beta gradient
1798 	  if (final_asv[cntr] & 2) {
1799 	    RealVector beta_grad = finalStatistics.function_gradient_view(cntr);
1800 	    if (stdev > Pecos::SMALL_NUMBER) {
1801 	      for (k=0; k<num_deriv_vars; ++k) {
1802 		Real stdev_grad = (central_mom) ?
1803 		  mom2_grad[k] / (2.*stdev) : mom2_grad[k];
1804 		Real dratio_dx = (stdev*mean_grad[k] - (mean-z_bar)*stdev_grad)
1805 		               / std::pow(stdev, 2);
1806 		beta_grad[k] = (cdfFlag) ? dratio_dx : -dratio_dx;
1807 	      }
1808 	    }
1809 	    else
1810 	      beta_grad = 0.;
1811 	  }
1812 	}
1813 	break;
1814       }
1815       }
1816     }
1817     for (j=0; j<pl_len+gl_len; j++, ++cntr) { // p/beta* -> z
1818       Real p = (j<pl_len) ? requestedProbLevels[i][j] :	Pecos::
1819 	NormalRandomVariable::std_cdf(-requestedGenRelLevels[i][j-pl_len]);
1820       Real p_cdf = (cdfFlag) ? p : 1. - p;
1821       // since each sample has 1/N probability, p can be directly converted
1822       // to an index within sorted_samples (id = p * N; index = id - 1)
1823       // Note 1: duplicate samples are not aggregated (separate id increments).
1824       // Note 2: since p_cdf(min_sample) = 1/N and p_cdf(max_sample) = 1, we
1825       //   extrapolate to the left of min, but not to the right of max.
1826       //   id < 1 indicates this extrapolation left of the min sample.
1827       // Note 3: we exclude any extrapolated z from extremeValues; should we
1828       //   omit any out-of-bounds resp levels within NonD::compute_densities()?
1829       //   --> PDF estimation based only on z->p binning or p->z interpolation
1830       //       within the sample bounds.
1831       Real cdf_incr_id = p_cdf * (Real)num_samp, lo_id;
1832       ss_it = sorted_samples.begin();
1833       if (cdf_incr_id < 1.) { // extrapolate left of min sample using 1st slope
1834 	lo_id = 1.; extrapolated_mappings = true;
1835 	Cerr << "Warning: extrapolation required for response " << i+1;
1836 	if (j<pl_len) Cerr <<    " for probability level " << j+1       <<".\n";
1837 	else Cerr << " for generalized reliability level " << j+1-pl_len<<".\n";
1838       }
1839       else { // linear interpolation between closest neighbors in sequence
1840         lo_id = std::floor(cdf_incr_id);
1841 	std::advance(ss_it, (size_t)lo_id - 1);
1842       }
1843       Real z, z_lo = *ss_it; ++ss_it;
1844       if (ss_it == sorted_samples.end()) z = z_lo;
1845       else          z = z_lo + (cdf_incr_id - lo_id) * (*ss_it - z_lo);
1846       if (j<pl_len) computedRespLevels[i][j] = z;
1847       else          computedRespLevels[i][j+bl_len] = z;
1848     }
1849     if (bl_len) {
1850       Real mean  = momentStats(0,i);
1851       Real stdev = (finalMomentsType == CENTRAL_MOMENTS) ?
1852 	std::sqrt(momentStats(1,i)) : momentStats(1,i);
1853       if (!momentGrads.empty()) {
1854 	int i2 = 2*i;
1855 	mean_grad = Teuchos::getCol(Teuchos::View, momentGrads, i2);
1856 	mom2_grad = Teuchos::getCol(Teuchos::View, momentGrads, i2+1);
1857       }
1858       for (j=0; j<bl_len; j++, ++cntr) {
1859 	// beta_bar -> z
1860 	Real beta_bar = requestedRelLevels[i][j];
1861 	computedRespLevels[i][j+pl_len] = (cdfFlag) ?
1862 	  mean - beta_bar * stdev : mean + beta_bar * stdev;
1863 	// *** z gradient
1864 	if (final_asv[cntr] & 2) {
1865 	  RealVector z_grad = finalStatistics.function_gradient_view(cntr);
1866 	  for (k=0; k<num_deriv_vars; ++k) {
1867 	    Real stdev_grad = (central_mom) ?
1868 	      mom2_grad[k] / (2.*stdev) : mom2_grad[k];
1869 	    z_grad[k] = (cdfFlag) ? mean_grad[k] - beta_bar * stdev_grad
1870 	                          : mean_grad[k] + beta_bar * stdev_grad;
1871 	  }
1872 	}
1873       }
1874     }
1875   }
1876 
1877   if (extrapolated_mappings)
1878     Cerr << "Warning: extrapolations required to evaluate inverse mappings.  "
1879 	 << "Consistent slope\n         (uniform density) assumed for "
1880 	 << "extrapolation into distribution tail.\n\n";
1881 
1882   // post-process computed z/p/beta* levels to form PDFs (prob_refined and
1883   // all_levels_computed default to false).  embedding this call within
1884   // compute_level_mappings() simplifies management of min/max.
1885   compute_densities(extremeValues);
1886 }
1887 
1888 
update_final_statistics()1889 void NonDSampling::update_final_statistics()
1890 {
1891   if (finalStatistics.is_null()) // some ctor chains do not track final stats
1892     return;
1893 
1894   if (epistemicStats) {
1895     size_t i, cntr = 0;
1896     for (i=0; i<numFunctions; ++i) {
1897       finalStatistics.function_value(extremeValues[i].first,  cntr++);
1898       finalStatistics.function_value(extremeValues[i].second, cntr++);
1899     }
1900   }
1901   else // moments + level mappings
1902     NonD::update_final_statistics();
1903 }
1904 
1905 
print_statistics(std::ostream & s) const1906 void NonDSampling::print_statistics(std::ostream& s) const
1907 {
1908   if (epistemicStats) // output only min & max values in the epistemic case
1909     print_intervals(s);
1910   else {
1911     print_moments(s);
1912     if (totalLevelRequests) {
1913       print_level_mappings(s);
1914       print_system_mappings(s);
1915     }
1916     if( wilksFlag )
1917       print_wilks_stastics(s); //, "response function", iteratedModel.response_labels());
1918   }
1919   if (!subIteratorFlag) {
1920     StringMultiArrayConstView
1921       acv_labels  = iteratedModel.all_continuous_variable_labels(),
1922       adiv_labels = iteratedModel.all_discrete_int_variable_labels(),
1923       adsv_labels = iteratedModel.all_discrete_string_variable_labels(),
1924       adrv_labels = iteratedModel.all_discrete_real_variable_labels();
1925     size_t cv_start, num_cv, div_start, num_div, dsv_start, num_dsv,
1926       drv_start, num_drv;
1927     mode_counts(iteratedModel.current_variables(), cv_start, num_cv,
1928 		div_start, num_div, dsv_start, num_dsv, drv_start, num_drv);
1929     StringMultiArrayConstView
1930       cv_labels  =
1931         acv_labels[boost::indices[idx_range(cv_start, cv_start+num_cv)]],
1932       div_labels =
1933         adiv_labels[boost::indices[idx_range(div_start, div_start+num_div)]],
1934       dsv_labels =
1935         adsv_labels[boost::indices[idx_range(dsv_start, dsv_start+num_dsv)]],
1936       drv_labels =
1937         adrv_labels[boost::indices[idx_range(drv_start, drv_start+num_drv)]];
1938     nonDSampCorr.print_correlations(s, cv_labels, div_labels, dsv_labels,
1939 				    drv_labels,iteratedModel.response_labels());
1940   }
1941 }
1942 
1943 
1944 void NonDSampling::
print_intervals(std::ostream & s,String qoi_type,const StringArray & interval_labels) const1945 print_intervals(std::ostream& s, String qoi_type,
1946 		const StringArray& interval_labels) const
1947 {
1948   s << std::scientific << std::setprecision(write_precision)
1949     << "\nMin and Max samples for each " << qoi_type << ":\n";
1950   size_t i, num_qoi = extremeValues.size();
1951   for (size_t i=0; i<num_qoi; ++i)
1952     s << interval_labels[i] << ":  Min = " << extremeValues[i].first
1953       << "  Max = " << extremeValues[i].second << '\n';
1954 }
1955 
1956 
1957 void NonDSampling::
print_moments(std::ostream & s,const RealMatrix & moment_stats,const RealMatrix moment_cis,String qoi_type,short moments_type,const StringArray & moment_labels,bool print_cis)1958 print_moments(std::ostream& s, const RealMatrix& moment_stats,
1959 	      const RealMatrix moment_cis, String qoi_type, short moments_type,
1960 	      const StringArray& moment_labels, bool print_cis)
1961 {
1962   size_t i, j, width = write_precision+7, num_moments = moment_stats.numRows(),
1963     num_qoi = moment_stats.numCols();
1964 
1965   s << "\nSample moment statistics for each " << qoi_type << ":\n"
1966     << std::scientific << std::setprecision(write_precision)
1967     << std::setw(width+15) << "Mean";
1968   if (moments_type == CENTRAL_MOMENTS)
1969     s << std::setw(width+1) << "Variance" << std::setw(width+1) << "3rdCentral"
1970       << std::setw(width+2) << "4thCentral\n";
1971   else
1972     s << std::setw(width+1) << "Std Dev" << std::setw(width+1)  << "Skewness"
1973       << std::setw(width+2) << "Kurtosis\n";
1974   //<< std::setw(width+2)  << "Coeff of Var\n";
1975   for (i=0; i<num_qoi; ++i) {
1976     const Real* moments_i = moment_stats[i];
1977     s << std::setw(14) << moment_labels[i];
1978     for (j=0; j<num_moments; ++j)
1979       s << ' ' << std::setw(width) << moments_i[j];
1980     s << '\n';
1981   }
1982   if (print_cis && !moment_cis.empty()) {
1983     // output 95% confidence intervals as (,) interval
1984     s << "\n95% confidence intervals for each " << qoi_type << ":\n"
1985       << std::setw(width+15) << "LowerCI_Mean" << std::setw(width+1)
1986       << "UpperCI_Mean" << std::setw(width+1);
1987     if (moments_type == CENTRAL_MOMENTS)
1988       s << "LowerCI_Variance" << std::setw(width+2) << "UpperCI_Variance\n";
1989     else
1990       s << "LowerCI_StdDev"   << std::setw(width+2) << "UpperCI_StdDev\n";
1991     for (i=0; i<num_qoi; ++i)
1992       s << std::setw(14) << moment_labels[i]
1993 	<< ' ' << std::setw(width) << moment_cis(0, i)
1994 	<< ' ' << std::setw(width) << moment_cis(1, i)
1995 	<< ' ' << std::setw(width) << moment_cis(2, i)
1996 	<< ' ' << std::setw(width) << moment_cis(3, i) << '\n';
1997   }
1998 }
1999 
2000 
2001 void NonDSampling::
print_wilks_stastics(std::ostream & s) const2002 print_wilks_stastics(std::ostream& s) const
2003 {
2004   //std::multiset<Real> sorted_resp;
2005   //IntRespMCIter it2;
2006   //std::multiset<Real>::const_iterator cit2;
2007   //for (int i=0; i<numFunctions; ++i) {
2008   //  sorted_resp.clear();
2009   //  for( it2 = allResponses.begin(); it2!=allResponses.end(); ++it2)
2010   //  {
2011   //    Cout << "It #" << it2->first << "\t" << it2->second.function_value(i) << std::endl;
2012   //    sorted_resp.insert(it2->second.function_value(i));
2013   //  }
2014   //  int count = 0;
2015   //  for( it2 = allResponses.begin(), cit2 = sorted_resp.begin(); cit2 != sorted_resp.end(); ++cit2, ++count, ++it2 )
2016   //    Cout << "It #" << count << "\t" << it2->second.function_value(i) << "\t" << *cit2 << std::endl;
2017   //}
2018 
2019   bool wilks_twosided = (wilksSidedness == TWO_SIDED);
2020 
2021   size_t j, width = write_precision+7, w2p2 = 2*width+2, w3p4 = 3*width+4;
2022 
2023   std::multiset<Real> sorted_resp_subset;
2024   std::multiset<Real>::const_iterator cit;
2025   std::multiset<Real>::const_reverse_iterator crit;
2026   IntRespMCIter it;
2027   int n;
2028   Real min, max;
2029 
2030   for (size_t fn_index=0; fn_index<numFunctions; ++fn_index) {
2031     s << "\n\n" << "Wilks Statistics for "
2032       << (wilks_twosided ? "Two-" : "One-") << "Sided "
2033       << 100.0*wilksBeta << "% Confidence Level, Order = " << wilksOrder
2034       << " for "  << iteratedModel.response_labels()[fn_index] << ":\n\n";
2035 
2036     if(wilks_twosided) {
2037       s << "    Coverage Level     Lower Bound        Upper Bound     Number of Samples\n"
2038         << "    --------------  -----------------  -----------------  -----------------\n";
2039     } else {
2040       s << "    Coverage Level       " << (wilksSidedness == ONE_SIDED_UPPER ? "Upper" : "Lower")
2041         << " Bound     Number of Samples\n"
2042         << "    --------------   -----------------  -----------------\n";
2043     }
2044 
2045     // Create a default probability level if none given
2046     RealVector prob_levels;
2047     size_t num_prob_levels = requestedProbLevels[fn_index].length();
2048     if( 0 == num_prob_levels ) {
2049       num_prob_levels = 1;
2050       prob_levels.resize(1);
2051       prob_levels[0] = 0.95; // default probability level
2052     }
2053     else
2054       prob_levels = requestedProbLevels[fn_index];
2055 
2056     for (j=0; j<num_prob_levels; ++j)
2057     {
2058       Real prob_level = prob_levels[j];
2059       int num_samples = compute_wilks_sample_size(wilksOrder, prob_level, wilksBeta, wilks_twosided);
2060 
2061       // Grab the first num_samples subset in sorted order (could also randomly sample) - RWH
2062       sorted_resp_subset.clear();
2063       for (n=0, it=allResponses.begin(); n<num_samples; ++n, ++it)
2064       {
2065         Real sample = it->second.function_value(fn_index);
2066         if (std::isfinite(sample)) // neither NaN nor +/-Inf
2067           sorted_resp_subset.insert(sample);
2068       }
2069       cit = sorted_resp_subset.begin();
2070       crit = sorted_resp_subset.rbegin();
2071       for( int i=0; i<wilksOrder-1; ++i, ++cit, ++crit ) continue;
2072       min = *cit;
2073       max = *crit;
2074 
2075       s << "  " << std::setw(width) << prob_levels[j];
2076       if( wilks_twosided )
2077         s << "  " << min;
2078       s << "   " << ( (wilks_twosided || wilksSidedness == ONE_SIDED_UPPER) ? max : min )
2079         << "        " << num_samples
2080         << '\n';
2081     }
2082   }
2083 }
2084 
2085 } // namespace Dakota
2086