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:       NonDExpansion
10 //- Description: Iterator base class for polynomial expansion methods for UQ
11 //- Owner:       Mike Eldred, Sandia National Laboratories
12 
13 #ifndef NOND_EXPANSION_H
14 #define NOND_EXPANSION_H
15 
16 #include "DakotaNonD.hpp"
17 
18 
19 namespace Dakota {
20 
21 /// Base class for polynomial chaos expansions (PCE), stochastic
22 /// collocation (SC) and functional tensor train (FT)
23 
24 /** The NonDExpansion class provides a base class for methods that use
25     polynomial expansions to approximate the effect of parameter
26     uncertainties on response functions of interest. */
27 
28 class NonDExpansion: public NonD
29 {
30 public:
31 
32   //
33   //- Heading: Constructors and destructor
34   //
35 
36   /// standard constructor
37   NonDExpansion(ProblemDescDB& problem_db, Model& model);
38   /// alternate constructor
39   NonDExpansion(unsigned short method_name, Model& model,
40 		short exp_coeffs_approach, const RealVector& dim_pref, int seed,
41 		short refine_type, short refine_control, short covar_control,
42 		Real colloc_ratio, short rule_nest, short rule_growth,
43 		bool piecewise_basis, bool use_derivs);
44   /// destructor
45   ~NonDExpansion();
46 
47   //
48   //- Heading: Virtual function redefinitions
49   //
50 
51   bool resize();
52   void derived_init_communicators(ParLevLIter pl_iter);
53   void derived_set_communicators(ParLevLIter pl_iter);
54   void derived_free_communicators(ParLevLIter pl_iter);
55 
56   void nested_variable_mappings(const SizetArray& c_index1,
57 				const SizetArray& di_index1,
58 				const SizetArray& ds_index1,
59 				const SizetArray& dr_index1,
60 				const ShortArray& c_target2,
61 				const ShortArray& di_target2,
62 				const ShortArray& ds_target2,
63 				const ShortArray& dr_target2);
64 
65   /// perform a forward uncertainty propagation using PCE/SC methods
66   void core_run();
67   /// print the final statistics
68   void print_results(std::ostream& s, short results_state = FINAL_RESULTS);
69 
70   const Model& algorithm_space_model() const;
71 
72   //
73   //- Heading: Virtual functions
74   //
75 
76   /// return specification for number of collocation points (may be
77   /// part of a sequence specification)
78   virtual size_t collocation_points() const;
79   /// return specification for random seed (may be part of a sequence
80   /// specification)
81   virtual int random_seed() const;
82   /// return first seed in sequence specification (defaults to random_seed())
83   virtual int first_seed() const;
84 
85   /// evaluate allSamples for inclusion in the (PCE regression) approximation
86   /// and retain the best set (well spaced) of size batch_size
87   virtual void select_refinement_points(
88     const RealVectorArray& candidate_samples, unsigned short batch_size,
89     RealMatrix& best_samples);
90 
91   /// generate numSamplesOnModel, append to approximation data, and update
92   /// QoI expansions
93   virtual void append_expansion();
94   /// append new data to uSpaceModel and, when appropriate,
95   /// update expansion order
96   virtual void append_expansion(const RealMatrix& samples,
97 				const IntResponseMap& resp_map);
98 
99   /// verify supported and define default discrepancy emulation mode
100   virtual void assign_discrepancy_mode();
101   /// define the surrogate response mode for a hierarchical model in
102   /// multilevel/multifidelity expansions
103   virtual void assign_hierarchical_response_mode();
104 
105   virtual void infer_pilot_sample(/*Real ratio, */SizetArray& delta_N_l);
106 
107   //
108   //- Heading: Member functions
109   //
110 
111   /// return maxRefineIterations
112   int maximum_refinement_iterations() const;
113   /// set maxRefineIterations
114   void maximum_refinement_iterations(int max_refine_iter);
115 
116 protected:
117 
118   //
119   //- Heading: Virtual functions
120   //
121 
122   /// perform error checks and mode overrides
123   virtual void resolve_inputs(short& u_space_type, short& data_order);
124   /// initialize uSpaceModel polynomial approximations with PCE/SC data
125   virtual void initialize_u_space_model();
126   /// initialize random variable definitions and final stats arrays
127   virtual void initialize_expansion();
128   /// form the expansion by calling uSpaceModel.build_approximation()
129   virtual void compute_expansion();
130   /// finalize mappings for the uSpaceModel
131   virtual void finalize_expansion();
132   /// assign the current values from the input specification sequence
133   virtual void assign_specification_sequence();
134   /// increment the input specification sequence and assign values
135   virtual void increment_specification_sequence();
136   /// update an expansion; avoids overhead in compute_expansion()
137   virtual void update_expansion();
138   /// combine coefficients, promote to active, and update statsMetricMode
139   virtual void combined_to_active();
140   /// archive expansion coefficients, as supported by derived instance
141   virtual void archive_coefficients();
142 
143   /// helper function to manage different push increment cases
144   virtual void push_increment();
145   /// helper function to manage different pop increment cases
146   virtual void pop_increment();
147 
148   /// compute 2-norm of change in response covariance
149   virtual Real compute_covariance_metric(bool revert, bool print_metric);
150   /// compute 2-norm of change in final statistics
151   virtual Real compute_level_mappings_metric(bool revert, bool print_metric);
152   // compute 2-norm of change in final statistics
153   //virtual Real compute_final_statistics_metric(bool revert,bool print_metric);
154 
155   /// calculate analytic and numerical statistics from the expansion,
156   /// supporting {REFINEMENT,INTERMEDIATE,FINAL}_RESULTS modes
157   virtual void compute_statistics(short results_state = FINAL_RESULTS);
158   /// extract statistics from native stats arrays for a selected candidate
159   virtual void pull_candidate(RealVector& stats_star);
160   /// restore statistics into native stats arrays for a selected candidate
161   virtual void push_candidate(const RealVector& stats_star);
162 
163   /// initializations for multilevel_regression()
164   virtual void initialize_ml_regression(size_t num_lev, bool& import_pilot);
165   /// increment sequence in numSamplesOnModel for multilevel_regression()
166   virtual void increment_sample_sequence(size_t new_samp, size_t total_samp,
167 					 size_t step);
168   /// accumulate one of the level metrics for {RIP,RANK}_SAMPLING cases
169   virtual void sample_allocation_metric(Real& metric, Real power);
170   /// compute delta_N_l for {RIP,RANK}_SAMPLING cases
171   virtual void compute_sample_increment(const RealVector& lev_metrics,
172 					const SizetArray& N_l,
173 					SizetArray& delta_N_l);
174   /// finalizations for multilevel_regression()
175   virtual void finalize_ml_regression();
176 
177   /// update numSamplesOnModel after an order increment
178   virtual void update_samples_from_order_increment();
179   /// update (restore previous) numSamplesOnModel after an order decrement
180   virtual void update_samples_from_order_decrement();
181 
182   /// print global sensitivity indices
183   virtual void print_sobol_indices(std::ostream& s);
184 
185   //
186   //- Heading: Virtual function redefinitions
187   //
188 
189   /// set covarianceControl defaults and shape respCovariance
190   void initialize_response_covariance();
191   /// update function values within finalStatistics
192   void update_final_statistics();
193   /// update function gradients within finalStatistics
194   void update_final_statistics_gradients();
195 
196   //
197   //- Heading: Member functions
198   //
199 
200   /// helper for initializing a numerical integration grid
201   void initialize_u_space_grid();
202 
203   /// check length and content of dimension preference vector
204   void check_dimension_preference(const RealVector& dim_pref) const;
205 
206   /// assign a NonDCubature instance within u_space_sampler
207   void construct_cubature(Iterator& u_space_sampler, Model& g_u_model,
208 			  unsigned short cub_int_order);
209   /// assign a NonDQuadrature instance within u_space_sampler based on
210   /// a quad_order specification
211   void construct_quadrature(Iterator& u_space_sampler, Model& g_u_model,
212 			    unsigned short quad_order,
213 			    const RealVector& dim_pref);
214   /// assign a NonDQuadrature instance within u_space_sampler that
215   /// generates a filtered tensor product sample set
216   void construct_quadrature(Iterator& u_space_sampler, Model& g_u_model,
217 			    unsigned short quad_order,
218 			    const RealVector& dim_pref, int filtered_samples);
219   /// assign a NonDQuadrature instance within u_space_sampler that
220   /// samples randomly from a tensor product multi-index
221   void construct_quadrature(Iterator& u_space_sampler, Model& g_u_model,
222 			    unsigned short quad_order,
223 			    const RealVector& dim_pref,
224 			    int random_samples, int seed);
225   /// assign a NonDSparseGrid instance within u_space_sampler
226   void construct_sparse_grid(Iterator& u_space_sampler, Model& g_u_model,
227 			     unsigned short ssg_level,
228 			     const RealVector& dim_pref);
229   // assign a NonDIncremLHSSampling instance within u_space_sampler
230   //void construct_incremental_lhs(Iterator& u_space_sampler, Model& u_model,
231   //				 int num_samples, int seed, const String& rng);
232 
233   /// configure exp_orders from inputs
234   void configure_expansion_orders(unsigned short exp_order,
235 				  const RealVector& dim_pref,
236 				  UShortArray& exp_orders);
237 
238   /// configure expansion and basis configuration options for Pecos
239   /// polynomial approximations
240   void configure_pecos_options();
241 
242   /// construct the expansionSampler for evaluating samples on uSpaceModel
243   void construct_expansion_sampler(unsigned short sample_type,
244     const String& rng, unsigned short integration_refine = NO_INT_REFINE,
245     const IntVector& refine_samples = IntVector(),
246     const String& import_approx_file = String(),
247     unsigned short import_approx_format = TABULAR_ANNOTATED,
248     bool import_approx_active_only = false);
249 
250   /// construct a multifidelity expansion, across model forms or
251   /// discretization levels
252   void multifidelity_expansion();
253   /// allocate a multilevel expansion based on some approximation to an
254   /// optimal resource allocation across model forms/discretization levels
255   void multilevel_regression();
256 
257   /// configure fidelity/level counts from model hierarchy
258   void configure_sequence(unsigned short& num_steps,
259 			  unsigned short& fixed_index,
260 			  bool& multilevel, bool mf_precedence);
261   /// extract cost estimates from model hierarchy (forms or resolutions)
262   void configure_cost(unsigned short num_steps, bool multilevel,
263 		      RealVector& cost);
264   /// extract cost estimates from model hierarchy, if available
265   bool query_cost(unsigned short num_steps, bool multilevel, RealVector& cost);
266   /// configure response mode and active/truth/surrogate model keys within a
267   /// hierarchical model.  s_index is the sequence index that defines the
268   /// active dimension for a model sequence.
269   void configure_indices(unsigned short group, unsigned short form,
270 			 unsigned short lev,   unsigned short s_index);
271   /// return aggregate cost (one or more models) for a level sample
272   Real sequence_cost(unsigned short step, const RealVector& cost);
273   /// compute equivHFEvals from samples per level and cost per evaluation
274   void compute_equivalent_cost(const SizetArray& N_l, const RealVector& cost);
275 
276   /// compute increment in samples for multilevel_regression() based
277   /// on ESTIMATOR_VARIANCE
278   void compute_sample_increment(const RealVector& agg_var,
279 				const RealVector& cost, Real sum_root_var_cost,
280 				Real eps_sq_div_2, const SizetArray& N_l,
281 				SizetArray& delta_N_l);
282 
283   /// return number of collocation points for index within model sequence
284   size_t collocation_points(size_t index) const;
285   /// return random seed for index within model sequence
286   int random_seed(size_t index) const;
287 
288   /// refine the reference expansion found by compute_expansion() using
289   /// uniform/adaptive p-/h-refinement strategies
290   void refine_expansion();
291   /// initialization of expansion refinement, if necessary
292   void pre_refinement();
293   /// advance the refinement strategy one step
294   size_t core_refinement(Real& metric, bool revert = false,
295 			 bool print_metric = true);
296   /// finalization of expansion refinement, if necessary
297   void post_refinement(Real& metric, bool reverted = false);
298 
299   /// helper function to manage different grid increment cases
300   void increment_grid(bool update_anisotropy = true);
301   /// helper function to manage different grid decrement cases
302   void decrement_grid();
303   /// helper function to manage different grid merge cases
304   void merge_grid();
305 
306   /// uniformly increment the expansion order and structured/unstructured grid
307   /// (PCE and FT)
308   void increment_order_and_grid();
309   /// uniformly decrement the expansion order and structured/unstructured grid
310   /// (PCE and FT)
311   void decrement_order_and_grid();
312 
313   /// publish numSamplesOnModel update to the DataFitSurrModel instance
314   void update_model_from_samples();
315 
316   /// perform sampler updates after a change to numSamplesOnModel
317   /// (shared code from ML/MF updaters)
318   void update_u_space_sampler(size_t sequence_index,
319 			      const UShortArray& approx_orders);
320 
321   /// update statsMetricMode, here and in Pecos::ExpansionConfigOptions
322   void refinement_statistics_mode(short stats_mode);//, bool clear_bits = true);
323 
324   /// perform any required expansion roll-ups prior to metric computation
325   void metric_roll_up(short results_state = FINAL_RESULTS);
326 
327   /// Aggregate variance across the set of QoI for a particular model level
328   void aggregate_variance(Real& agg_var_l);
329 
330   /// calculate the response covariance (diagonal or full matrix) for
331   /// the expansion indicated by statsMetricMode
332   void compute_covariance();
333   /// calculate the response covariance of the active expansion
334   void compute_active_covariance();
335   /// calculate the response covariance of the combined expansion
336   void compute_combined_covariance();
337 
338   /// calculate the diagonal response variance of the active expansion
339   void compute_active_diagonal_variance();
340   /// calculate the diagonal response variance of the cmbined expansion
341   void compute_combined_diagonal_variance();
342 
343   /// calculate off diagonal terms in respCovariance(i,j) for j<i for
344   /// the expansion indicated by statsMetricMode
345   void compute_off_diagonal_covariance();
346   /// calculate off diagonal terms in respCovariance(i,j) for j<i
347   /// using the active expansion coefficients
348   void compute_active_off_diagonal_covariance();
349   /// calculate off diagonal terms in respCovariance(i,j) for j<i
350   /// using the combined expansion coefficients
351   void compute_combined_off_diagonal_covariance();
352 
353   /// compute expansion moments; this uses a lightweight approach for
354   /// incremental statistics (no additional moments; no finalStatistics update)
355   void compute_moments();
356   /// compute all analytic/numerical level mappings; this uses a lightweight
357   /// approach for incremental statistics (no derivatives, no finalStatistics
358   /// update)
359   void compute_level_mappings();
360   /// compute only numerical level mappings; this uses a lightweight approach
361   /// for incremental statistics (no derivatives, no finalStatistics update)
362   void compute_numerical_level_mappings();
363   /// compute Sobol' indices for main, interaction, and total effects; this
364   /// is intended for incremental statistics
365   void compute_sobol_indices();
366 
367   /// print resp{Variance,Covariance}
368   void print_covariance(std::ostream& s);
369   /// print resp_var (response variance vector) using optional pre-pend
370   void print_variance(std::ostream& s, const RealVector& resp_var,
371 		      const String& prepend = "");
372   /// print resp_covar (response covariance matrix) using optional pre-pend
373   void print_covariance(std::ostream& s, const RealSymMatrix& resp_covar,
374 			const String& prepend = "");
375 
376   /// archive the central moments (numerical and expansion) to ResultsDB
377   void archive_moments();
378 
379   /// archive the Sobol' indices to the resultsDB
380   void archive_sobol_indices();
381 
382   void pull_reference(RealVector& stats_ref);
383   void push_reference(const RealVector& stats_ref);
384 
385   /// pull lower triangle of symmetric matrix into vector
386   void pull_lower_triangle(const RealSymMatrix& mat, RealVector& vec,
387 			   size_t offset = 0);
388   /// push vector into lower triangle of symmetric matrix
389   void push_lower_triangle(const RealVector& vec, RealSymMatrix& mat,
390 			   size_t offset = 0);
391 
392   /// convert number of regression terms and collocation ratio to a
393   /// number of collocation samples
394   int  terms_ratio_to_samples(size_t num_exp_terms, Real colloc_ratio);
395   /// convert number of regression terms and number of collocation samples
396   /// to a collocation ratio
397   Real terms_samples_to_ratio(size_t num_exp_terms, int samples);
398 
399   //
400   //- Heading: Data
401   //
402 
403   /// Model representing the approximate response function in u-space,
404   /// after u-space recasting and polynomial data fit recursions
405   Model uSpaceModel;
406 
407   /// Iterator used for sampling on the uSpaceModel to generate approximate
408   /// probability/reliability/response level statistics.  Currently this is
409   /// an LHS sampling instance, but AIS could also be used.
410   Iterator expansionSampler;
411   /// Iterator used to refine the approximate probability estimates
412   /// generated by the expansionSampler using importance sampling
413   Iterator importanceSampler;
414 
415   /// method for collocation point generation and subsequent
416   /// calculation of the expansion coefficients
417   short expansionCoeffsApproach;
418   /// type of expansion basis: DEFAULT_BASIS or
419   /// Pecos::{NODAL,HIERARCHICAL}_INTERPOLANT for SC or
420   /// Pecos::{TENSOR_PRODUCT,TOTAL_ORDER,ADAPTED}_BASIS for PCE regression
421   short expansionBasisType;
422 
423   /// type of statistical metric roll-up: {NO,ACTIVE,COMBINED}_EXPANSION_STATS
424   short statsMetricMode;
425   /// flag indicating the use of relative scaling in refinement metrics
426   bool relativeMetric;
427 
428   /// user specification for dimension_preference
429   RealVector dimPrefSpec;
430 
431   /// user specification of number of initial samples per model instance,
432   /// including adaptive cases where an optimal sample profile is the
433   /// target of iteration (e.g., multilevel_regression())
434   SizetArray collocPtsSeqSpec;
435   /// factor applied to terms^termsOrder in computing number of regression
436   /// points, either user-specified or inferred
437   Real collocRatio;
438   /// exponent applied to number of expansion terms for computing
439   /// number of regression points (usually 1)
440   Real termsOrder;
441 
442   /// seed for random number generator (used for regression with LHS
443   /// and sub-sampled tensor grids, as well as for expansionSampler)
444   int randomSeed;
445   /// user specification for seed_sequence
446   SizetArray randomSeedSeqSpec;
447   /// don't continue an existing random number sequence, rather reset
448   /// seed each time within some sampling-based iteration
449   bool fixedSeed;
450   /// top level iteration counter in adaptive NonDExpansion ML/MF algorithms,
451   /// allowing special updating logic for some sequence handlers
452   size_t mlmfIter;
453 
454   /// flag for combined variable expansions which include a
455   /// non-probabilistic subset (design, epistemic, state)
456   bool allVars;
457   /// option for regression FT using a filtered set of tensor-product
458   /// quadrature points
459   bool tensorRegression;
460 
461   /// type of sample allocation scheme for discretization levels / model forms
462   /// within multilevel / multifidelity methods
463   short multilevAllocControl;
464   /// emulation approach for multilevel / multifidelity discrepancy:
465   /// distinct or recursive
466   short multilevDiscrepEmulation;
467 
468   /// number of samples allocated to each level of a discretization/model
469   /// hierarchy within multilevel/multifidelity methods
470   SizetArray NLev;
471   /// equivalent number of high fidelity evaluations accumulated using samples
472   /// across multiple model forms and/or discretization levels
473   Real equivHFEvals;
474   /// rate parameter for allocation by ESTIMATOR_VARIANCE in
475   /// multilevel_regression()
476   Real kappaEstimatorRate;
477   /// scale parameter for allocation by ESTIMATOR_VARIANCE in
478   /// multilevel_regression()
479   Real gammaEstimatorScale;
480 
481   /// number of truth samples performed on g_u_model to form the expansion
482   int numSamplesOnModel;
483   /// number of approximation samples performed on the polynomial
484   /// expansion in order to estimate probabilities
485   int numSamplesOnExpansion;
486 
487   /// flag for indicating state of \c nested and \c non_nested overrides of
488   /// default rule nesting, which depends on the type of integration driver;
489   /// this is defined in construct_{quadrature,sparse_grid}(), such that
490   /// override attributes (defined in ctors) must be used upstream
491   bool nestedRules;
492   /// user override of default rule nesting: NO_NESTING_OVERRIDE,
493   /// NESTED, or NON_NESTED
494   short ruleNestingOverride;
495   /// user override of default rule growth: NO_GROWTH_OVERRIDE,
496   /// RESTRICTED, or UNRESTRICTED
497   short ruleGrowthOverride;
498 
499   /// flag for \c piecewise specification, indicating usage of local
500   /// basis polynomials within the stochastic expansion
501   bool piecewiseBasis;
502 
503   /// flag for \c use_derivatives specification, indicating usage of derivative
504   /// data (with respect to expansion variables) to enhance the calculation of
505   /// the stochastic expansion.
506   /** This is part of the method specification since the instantiation of the
507       global data fit surrogate is implicit with no user specification.  This
508       behavior is distinct from the usage of response derivatives with respect
509       to auxilliary variables (design, epistemic) for computing derivatives of
510       aleatory expansion statistics with respect to these variables. */
511   bool useDerivs;
512 
513   /// stores the initial variables data in u-space
514   RealVector initialPtU;
515 
516   /// refinement type: NO_REFINEMENT, P_REFINEMENT, or H_REFINEMENT
517   short refineType;
518   /// refinement control: NO_CONTROL, UNIFORM_CONTROL, LOCAL_ADAPTIVE_CONTROL,
519   /// DIMENSION_ADAPTIVE_CONTROL_SOBOL, DIMENSION_ADAPTIVE_CONTROL_DECAY, or
520   /// DIMENSION_ADAPTIVE_CONTROL_GENERALIZED
521   short refineControl;
522   /// refinement metric: NO_METRIC, COVARIANCE_METRIC, LEVEL_STATS_METRIC,
523   /// or MIXED_STATS_METRIC
524   short refineMetric;
525 
526   /// enumeration for controlling response covariance calculation and
527   /// output: {DEFAULT,DIAGONAL,FULL}_COVARIANCE
528   short covarianceControl;
529 
530   /// number of consecutive iterations within tolerance required to
531   /// indicate soft convergence
532   unsigned short softConvLimit;
533 
534   /// symmetric matrix of analytic response covariance (full response
535   /// covariance option)
536   RealSymMatrix respCovariance;
537   /// vector of response variances (diagonal response covariance option)
538   RealVector respVariance;
539 
540   /// stats of the best refinement candidate for the current model indices
541   RealVector statsStar;
542 
543   /// number of invocations of core_run()
544   size_t numUncertainQuant;
545 
546 private:
547 
548   //
549   //- Heading: Convenience function definitions
550   //
551 
552   /// initialize data based on variable counts
553   void initialize_counts();
554 
555   /// set response mode to AGGREGATED_MODELS and recur response size updates
556   void aggregated_models_mode();
557   /// set response mode to BYPASS_SURROGATE and recur response size updates
558   void bypass_surrogate_mode();
559 
560   /// generate a set of reference expansions across a model hierarchy
561   void multifidelity_reference_expansion();
562   /// separately refine each of the multifidelity reference expansions
563   void multifidelity_individual_refinement();
564   /// refine each of the multifidelity reference expansions within an
565   /// integrated competition
566   void multifidelity_integrated_refinement();
567 
568   /// compute average of total Sobol' indices (from VBD) across the
569   /// response set for use as an anisotropy indicator
570   void reduce_total_sobol_sets(RealVector& avg_sobol);
571   /// compute minimum of spectral coefficient decay rates across the
572   /// response set for use as an anisotropy indicator
573   void reduce_decay_rate_sets(RealVector& min_decay);
574 
575   /// print additional refinement diagnostics not covered by compute_*_metric()
576   void print_refinement_diagnostics(std::ostream& s);
577 
578   /// perform an adaptive refinement increment using generalized sparse grids
579   size_t increment_sets(Real& delta_star, bool revert, bool print_metric);
580   /// finalization of adaptive refinement using generalized sparse grids
581   void finalize_sets(bool converged_within_tol, bool reverted = false);
582 
583   /// promote selected candidate into reference grid + expansion
584   void select_candidate(size_t best_candidate);
585   /// promote selected index set candidate into reference grid + expansion
586   void select_index_set_candidate(
587     std::set<UShortArray>::const_iterator cit_star);
588   /// promote selected refinement increment candidate into reference
589   /// grid + expansion
590   void select_increment_candidate();
591 
592   /// analytic portion of compute_statistics() from post-processing of
593   /// expansion coefficients (used for FINAL_RESULTS)
594   void compute_analytic_statistics();
595   /// numerical portion of compute_statistics() from sampling on the
596   /// expansion (used for FINAL_RESULTS)
597   void compute_numerical_statistics();
598   /// refinements to numerical probability statistics from importanceSampler
599   void compute_numerical_stat_refinements(RealVectorArray& imp_sampler_stats,
600 					  RealRealPairArray& min_max_fns);
601 
602   /// helper to define the expansionSampler's data requests when sampling on
603   /// the expansion
604   void define_sampler_asv(ShortArray& sampler_asv);
605   /// helper to run the expansionSampler and compute its statistics
606   void run_sampler(const ShortArray& sampler_asv,
607 		   RealVector& exp_sampler_stats);
608   /// helper to refine the results from expansionSampler with importance
609   /// sampling (for probability levels) or bounds post-processing (for PDFs)
610   void refine_sampler(RealVectorArray& imp_sampler_stats,
611 		      RealRealPairArray& min_max_fns);
612 
613   /// print expansion and numerical moments
614   void print_moments(std::ostream& s);
615   /// print local sensitivities evaluated at initialPtU
616   void print_local_sensitivity(std::ostream& s);
617 
618   //
619   //- Heading: Data
620   //
621 
622   /// derivative of the expansion with respect to the x-space variables
623   /// evaluated at the means (used as uncertainty importance metrics)
624   RealMatrix expGradsMeanX;
625 
626   /// maximum number of uniform/adaptive refinement iterations
627   /// (specialization of maxIterations)
628   int maxRefineIterations;
629   /// maximum number of regression solver iterations (specialization
630   /// of maxIterations)
631   int maxSolverIterations;
632 
633   /// flag indicating the activation of variance-bsaed decomposition
634   /// for computing Sobol' indices
635   bool vbdFlag;
636   /// limits the order of interactions within the component Sobol' indices
637   unsigned short vbdOrderLimit;
638   /// tolerance for omitting output of small VBD indices
639   Real vbdDropTol;
640 
641   // sample type for \c expansion_samples approach to estimating PCE
642   // coefficients (supports construct_incremental_lhs())
643   //String expansionSampleType;
644 };
645 
646 
647 inline void NonDExpansion::
nested_variable_mappings(const SizetArray & c_index1,const SizetArray & di_index1,const SizetArray & ds_index1,const SizetArray & dr_index1,const ShortArray & c_target2,const ShortArray & di_target2,const ShortArray & ds_target2,const ShortArray & dr_target2)648 nested_variable_mappings(const SizetArray& c_index1,
649 			 const SizetArray& di_index1,
650 			 const SizetArray& ds_index1,
651 			 const SizetArray& dr_index1,
652 			 const ShortArray& c_target2,
653 			 const ShortArray& di_target2,
654 			 const ShortArray& ds_target2,
655 			 const ShortArray& dr_target2)
656 {
657   uSpaceModel.nested_variable_mappings(c_index1, di_index1, ds_index1,
658 				       dr_index1, c_target2, di_target2,
659 				       ds_target2, dr_target2);
660 }
661 
662 
collocation_points(size_t index) const663 inline size_t NonDExpansion::collocation_points(size_t index) const
664 {
665   if (collocPtsSeqSpec.empty()) return std::numeric_limits<size_t>::max();
666   else
667     return (index < collocPtsSeqSpec.size()) ?
668       collocPtsSeqSpec[index] : collocPtsSeqSpec.back();
669 }
670 
671 
random_seed() const672 inline int NonDExpansion::random_seed() const
673 { return randomSeed; } // default (overridden in case of seed_sequence)
674 
675 
first_seed() const676 inline int NonDExpansion::first_seed() const
677 { return random_seed(); } // default (overridden for multilevel)
678 
679 
680 /** extract an active seed from a seed sequence */
random_seed(size_t index) const681 inline int NonDExpansion::random_seed(size_t index) const
682 {
683   // return 0 for cases where seed is undefined or will not be updated
684 
685   if (randomSeedSeqSpec.empty()) return 0; // no spec -> non-repeatable samples
686   else if (fixedSeed) // continually reset seed to specified value
687     return (index < randomSeedSeqSpec.size()) ?
688       randomSeedSeqSpec[index] : randomSeedSeqSpec.back();
689   // only set sequence of seeds for first pass, then let RNG state continue
690   else if (mlmfIter == 0 && index < randomSeedSeqSpec.size()) // pilot iter only
691     return randomSeedSeqSpec[index];
692   else return 0; // seed sequence exhausted, do not update
693 }
694 
695 
maximum_refinement_iterations() const696 inline int NonDExpansion::maximum_refinement_iterations() const
697 { return maxRefineIterations; }
698 
699 
maximum_refinement_iterations(int max_refine_iter)700 inline void NonDExpansion::maximum_refinement_iterations(int max_refine_iter)
701 { maxRefineIterations = max_refine_iter; }
702 
703 
algorithm_space_model() const704 inline const Model& NonDExpansion::algorithm_space_model() const
705 { return uSpaceModel; }
706 
707 
708 inline void NonDExpansion::
configure_cost(unsigned short num_steps,bool multilevel,RealVector & cost)709 configure_cost(unsigned short num_steps, bool multilevel, RealVector& cost)
710 {
711   bool cost_defined = query_cost(num_steps, multilevel, cost);
712   if (!cost_defined) {
713     Cerr << "Error: missing required simulation cost data in NonDExpansion::"
714 	 << "configure_cost()." << std::endl;
715     abort_handler(METHOD_ERROR);
716   }
717 }
718 
719 
collocation_points() const720 inline size_t NonDExpansion::collocation_points() const
721 { return 0; }
722 
723 
aggregated_models_mode()724 inline void NonDExpansion::aggregated_models_mode()
725 {
726   // update iteratedModel / uSpaceModel in separate calls rather than using
727   // uSpaceModel.surrogate_response_mode(mode) since DFSurrModel must pass
728   // mode along to iteratedModel (a HierarchSurrModel) without absorbing it
729   if (iteratedModel.surrogate_response_mode() != AGGREGATED_MODELS) {
730     iteratedModel.surrogate_response_mode(AGGREGATED_MODELS);//MODEL_DISCREPANCY
731     uSpaceModel.resize_from_subordinate_model();// recurs until hits aggregation
732   }
733 }
734 
735 
bypass_surrogate_mode()736 inline void NonDExpansion::bypass_surrogate_mode()
737 {
738   // update iteratedModel / uSpaceModel in separate calls rather than using
739   // uSpaceModel.surrogate_response_mode(mode) since DFSurrModel must pass
740   // mode along to iteratedModel (a HierarchSurrModel) without absorbing it
741   if (iteratedModel.surrogate_response_mode() != BYPASS_SURROGATE) {
742     iteratedModel.surrogate_response_mode(BYPASS_SURROGATE); // single level
743     uSpaceModel.resize_from_subordinate_model();// recurs until hits aggregation
744   }
745 }
746 
747 
748 inline Real NonDExpansion::
sequence_cost(unsigned short step,const RealVector & cost)749 sequence_cost(unsigned short step, const RealVector& cost)
750 {
751   if (cost.empty())
752     return 0.;
753   else {
754     Real cost_l = cost[step];
755     if (step && multilevDiscrepEmulation == DISTINCT_EMULATION)
756       cost_l += cost[step-1]; // discrepancies incur 2 level costs
757     return cost_l;
758   }
759 }
760 
761 
metric_roll_up(short results_state)762 inline void NonDExpansion::metric_roll_up(short results_state)
763 {
764   // if COMBINED_EXPANSIONS_STATS, assess refinement candidates using combined
765   // stat metrics, which by default require expansion combination (overridden
766   // for hierarchical SC)
767   if (statsMetricMode == Pecos::COMBINED_EXPANSION_STATS)
768     switch (results_state) {
769     case REFINEMENT_RESULTS:
770       // PCE and Nodal SC require combined expansion coefficients for computing
771       // combined stat metrics, but Hierarchical SC can efficiently compute
772       // deltas based only on active expansions (no combination required)
773       if (expansionBasisType != Pecos::HIERARCHICAL_INTERPOLANT)
774 	uSpaceModel.combine_approximation();
775       break;
776     case INTERMEDIATE_RESULTS:
777       uSpaceModel.combine_approximation(); break;
778     // FINAL_RESULTS should not occur: no roll up after combined_to_active()
779     }
780 
781   // TO DO: case of level mappings for numerical stats --> sampling on
782   //        combined expansion
783 }
784 
785 
compute_active_covariance()786 inline void NonDExpansion::compute_active_covariance()
787 {
788   switch (covarianceControl) {
789   case DIAGONAL_COVARIANCE:
790     compute_active_diagonal_variance(); break;
791   case FULL_COVARIANCE:
792     compute_active_diagonal_variance();
793     compute_active_off_diagonal_covariance(); break;
794   }
795 }
796 
797 
compute_combined_covariance()798 inline void NonDExpansion::compute_combined_covariance()
799 {
800   switch (covarianceControl) {
801   case DIAGONAL_COVARIANCE:
802     compute_combined_diagonal_variance(); break;
803   case FULL_COVARIANCE:
804     compute_combined_diagonal_variance();
805     compute_combined_off_diagonal_covariance(); break;
806   }
807 }
808 
809 
compute_off_diagonal_covariance()810 inline void NonDExpansion::compute_off_diagonal_covariance()
811 {
812   if (numFunctions <= 1)
813     return;
814 
815   // See also full_covar_stats logic in compute_analytic_statistics() ...
816 
817   switch (statsMetricMode) {
818   case Pecos::ACTIVE_EXPANSION_STATS:
819     compute_active_off_diagonal_covariance();   break;
820   case Pecos::COMBINED_EXPANSION_STATS:
821     compute_combined_off_diagonal_covariance(); break;
822   }
823 }
824 
825 
compute_covariance()826 inline void NonDExpansion::compute_covariance()
827 {
828   switch (statsMetricMode) {
829   // multifidelity_expansion() is outer loop:
830   // > use of refine_expansion(): refine individually based on level covariance
831   // > after combine_approx(), combined_to_active() enables use of active covar
832   case Pecos::ACTIVE_EXPANSION_STATS:
833     compute_active_covariance();   break;
834   // if COMBINED_EXPANSIONS_STATS:
835   // > roll up effect of refinement candidate on combined multilevel covariance,
836   //   avoiding combined_to_active() promotion until end
837   // > limited stats support for combinedExpCoeffs: only compute_covariance()
838   case Pecos::COMBINED_EXPANSION_STATS:
839     compute_combined_covariance(); break;
840   }
841 }
842 
843 
844 inline void NonDExpansion::
pull_lower_triangle(const RealSymMatrix & mat,RealVector & vec,size_t offset)845 pull_lower_triangle(const RealSymMatrix& mat, RealVector& vec, size_t offset)
846 {
847   size_t i, j, cntr = offset, nr = mat.numRows(),
848     min_vec_len = offset + (nr*nr + nr)/2;
849   if (vec.length() < min_vec_len) vec.resize(min_vec_len);
850   for (i=0; i<nr; ++i)
851     for (j=0; j<=i; ++j, ++cntr)
852       vec[cntr] = mat(i,j); // pull from lower triangle
853 }
854 
855 
856 inline void NonDExpansion::
push_lower_triangle(const RealVector & vec,RealSymMatrix & mat,size_t offset)857 push_lower_triangle(const RealVector& vec, RealSymMatrix& mat, size_t offset)
858 {
859   size_t i, j, cntr = offset, nr = mat.numRows(),
860     min_vec_len = offset + (nr*nr + nr)/2;
861   if (vec.length() < min_vec_len) {
862     Cerr << "Error: insufficient vector length in NonDExpansion::"
863 	 << "push_lower_triangle()" << std::endl;
864     abort_handler(METHOD_ERROR);
865   }
866   for (i=0; i<nr; ++i)
867     for (j=0; j<=i; ++j, ++cntr)
868       mat(i,j) = vec[cntr]; // push to lower triangle
869 }
870 
871 
pull_candidate(RealVector & stats_star)872 inline void NonDExpansion::pull_candidate(RealVector& stats_star)
873 { pull_reference(stats_star); } // default implementation: candidate same as ref
874 
875 
push_candidate(const RealVector & stats_star)876 inline void NonDExpansion::push_candidate(const RealVector& stats_star)
877 { push_reference(stats_star); } // default implementation: candidate same as ref
878 
879 
update_final_statistics()880 inline void NonDExpansion::update_final_statistics()
881 {
882   // aleatory final stats & their grads are updated directly within
883   // compute_statistics() (NonD::update_aleatory_final_statistics() is awkward
884   // for NonDExpansion since Pecos manages the moment arrays), such that all
885   // that remains are system final stats and additional gradient scaling.
886   if (respLevelTargetReduce) {
887     update_system_final_statistics();
888     update_system_final_statistics_gradients();
889   }
890   update_final_statistics_gradients();
891 }
892 
893 
archive_coefficients()894 inline void NonDExpansion::archive_coefficients()
895 { /* default is no-op */ }
896 
897 
898 inline void NonDExpansion::
check_dimension_preference(const RealVector & dim_pref) const899 check_dimension_preference(const RealVector& dim_pref) const
900 {
901   size_t len = dim_pref.length();
902   if (len) {
903     if (len != numContinuousVars) {
904       Cerr << "Error: length of dimension preference specification (" << len
905 	   << ") is inconsistent with continuous expansion variables ("
906 	   << numContinuousVars << ")." << std::endl;
907       abort_handler(METHOD_ERROR);
908     }
909     else
910       for (size_t i=0; i<len; ++i)
911 	if (dim_pref[i] < 0.) { // allow zero preference
912 	  Cerr << "Error: bad dimension preference value (" << dim_pref[i]
913 	       << ")." << std::endl;
914 	  abort_handler(METHOD_ERROR);
915 	}
916   }
917 }
918 
919 
920 inline int NonDExpansion::
terms_ratio_to_samples(size_t num_exp_terms,Real colloc_ratio)921 terms_ratio_to_samples(size_t num_exp_terms, Real colloc_ratio)
922 {
923   // for under-determined solves (compressed sensing), colloc_ratio can be < 1
924   size_t data_per_pt = (useDerivs) ? numContinuousVars + 1 : 1;
925   Real min_pts = std::pow((Real)num_exp_terms, termsOrder) / (Real)data_per_pt;
926   int tgt_samples = (int)std::floor(colloc_ratio*min_pts + .5); // rounded
927   if (colloc_ratio >= 1.) {
928     // logic is to round to the nearest integral sample count for the given
929     // colloc_ratio, but with a lower bound determined by rounding up with a
930     // unit colloc_ratio.  The lower bound prevents creating an under-determined
931     // system due to rounding down when the intent is over- or uniquely
932     // determined (can only happen with non-integral min_pts due to use of
933     // derivative enhancement).
934     int min_samples = (int)std::ceil(min_pts); // lower bound
935     return std::max(min_samples, tgt_samples);
936   }
937   else
938     // for under-determined systems, data starvation is not a problem and we
939     // just need at least one sample.
940     return std::max(tgt_samples, 1);
941 }
942 
943 
944 inline Real NonDExpansion::
terms_samples_to_ratio(size_t num_exp_terms,int samples)945 terms_samples_to_ratio(size_t num_exp_terms, int samples)
946 {
947   size_t data_per_pt = (useDerivs) ? numContinuousVars + 1 : 1;
948   return (Real)(samples * data_per_pt) /
949     std::pow((Real)num_exp_terms, termsOrder);
950 }
951 
952 } // namespace Dakota
953 
954 #endif
955