1 /*  _______________________________________________________________________
2 
3     PECOS: Parallel Environment for Creation Of Stochastics
4     Copyright (c) 2011, Sandia National Laboratories.
5     This software is distributed under the GNU Lesser General Public License.
6     For more information, see the README file in the top Pecos directory.
7     _______________________________________________________________________ */
8 
9 //- Class:	 SparseGridDriver
10 //- Description: Implementation code for SparseGridDriver class
11 //- Owner:       Mike Eldred
12 //- Revised by:
13 //- Version:
14 
15 #include "SparseGridDriver.hpp"
16 #include "PolynomialApproximation.hpp"
17 #include "sandia_sgmga.hpp"
18 #include "sandia_sgmgg.hpp"
19 #include "pecos_stat_util.hpp"
20 #include "MultivariateDistribution.hpp"
21 
22 static const char rcsId[]="@(#) $Id: SparseGridDriver.C,v 1.57 2004/06/21 19:57:32 mseldre Exp $";
23 
24 //#define DEBUG
25 
26 namespace Pecos {
27 
28 
dimension_preference(const RealVector & dim_pref)29 void SparseGridDriver::dimension_preference(const RealVector& dim_pref)
30 {
31   RealVector aniso_wts;
32   if (!dim_pref.empty()) {
33     size_t num_pref = dim_pref.length();
34     aniso_wts.sizeUninitialized(num_pref);
35     webbur::sandia_sgmga_importance_to_aniso(num_pref, dim_pref.values(),
36 					     aniso_wts.values());
37 #ifdef DEBUG
38     PCout << "dimension preference:\n" << dim_pref << "anisotropic weights "
39 	  << "after sandia_sgmga_importance_to_aniso():\n" << aniso_wts;
40 #endif
41   }
42   anisotropic_weights(aniso_wts);
43 }
44 
45 
anisotropic_weights(const RealVector & aniso_wts)46 void SparseGridDriver::anisotropic_weights(const RealVector& aniso_wts)
47 {
48   RealVector& curr_aniso_wts = anisoWtsIter->second;
49   if (aniso_wts.empty()) {
50     if (!curr_aniso_wts.empty()) { // change from current
51       curr_aniso_wts.sizeUninitialized(0);
52       clear_size(); // clear state to mandate a grid / grid size update
53     }
54   }
55   else {
56     if (aniso_wts.length() != numVars) {
57       PCerr << "Error: length of sparse grid anisotropic weights specification "
58 	    << "is inconsistent with\n       number of variables in SparseGrid"
59 	    << "Driver::anisotropic_weights()." << std::endl;
60       abort_handler(-1);
61     }
62 
63     // detect anisotropy
64     bool dim_iso = true;  size_t i;
65     const Real& wt0 = aniso_wts[0];
66     for (i=1; i<numVars; ++i)
67       if (std::abs(aniso_wts[i] - wt0) > DBL_EPSILON)
68 	{ dim_iso = false; break; }
69     // update active anisoLevelWts and grid update indicator
70     if (dim_iso) {
71       if (!curr_aniso_wts.empty()) {
72 	curr_aniso_wts.sizeUninitialized(0);
73 	clear_size(); // clear state to mandate a grid / grid size update
74       }
75     }
76     else {
77       RealVector prev_aniso_wts = curr_aniso_wts; // for update indicator
78       // truncate any negative values
79       curr_aniso_wts.resize(numVars);
80       for (i=0; i<numVars; ++i)
81 	curr_aniso_wts[i] = std::max(aniso_wts[i], 0.);
82       // normalize and enforce axis lower bounds/weight upper bounds
83       int option = 1; // weights scaled so that minimum nonzero entry is 1
84       webbur::sandia_sgmga_aniso_normalize(option, numVars,
85 					   curr_aniso_wts.values());
86 #ifdef DEBUG
87       PCout << "anisoLevelWts after sandia_sgmga_aniso_normalize():\n"
88 	    << curr_aniso_wts;
89 #endif
90       // enforce axis lower bounds, if present, for current ssgLevel.  An axis
91       // lower bound defines a weight upper bound based on the current ssgLevel:
92       // LB_i = level*wt_min/wt_i --> wt_i = level*wt_min/LB_i and wt_min=1.
93       // Catch special case of dim_pref_i = 0 --> wt_i = LB_i = 0.
94       const RealVector& axis_l_bnds
95 	= axisLowerBounds[activeKey];//axisLBndsIter->second;
96       if (!axis_l_bnds.empty()) {
97 	Real ssg_lev = (Real)(ssgLevIter->second);
98 	for (i=0; i<numVars; ++i)
99 	  if (axis_l_bnds[i] > SMALL_NUMBER) {                     // nonzero LB
100 	    Real wt_u_bnd = ssg_lev / axis_l_bnds[i];
101 	    curr_aniso_wts[i] = (curr_aniso_wts[i] > SMALL_NUMBER) // nonzero wt
102 	      ? std::min(wt_u_bnd, curr_aniso_wts[i]) : wt_u_bnd;
103 	  }
104 #ifdef DEBUG
105 	PCout << "anisoLevelWts after axisLowerBounds enforcement:\n"
106 	      << curr_aniso_wts;
107 #endif
108       }
109       // indicate need for numCollocPts update
110       if (curr_aniso_wts != prev_aniso_wts)
111 	clear_size(); // clear state to mandate a grid / grid size update
112     }
113   }
114 }
115 
116 
update_axis_lower_bounds()117 void SparseGridDriver::update_axis_lower_bounds()
118 {
119   const RealVector& aniso_wts = anisoWtsIter->second;
120   RealVector& axis_l_bnds = axisLowerBounds[activeKey];//axisLBndsIter->second;
121   if (axis_l_bnds.empty())
122     axis_l_bnds.sizeUninitialized(numVars);
123   // An axis lower bound is the maximum index coverage achieved on a coordinate
124   // axis (when all other indices are zero); it defines a constraint for
125   // minimum coordinate coverage in future refinements.  The linear index set
126   // constraint is level*wt_min-|wt| < j.wt <= level*wt_min, which becomes
127   // level-|wt| < j_i w_i <= level for wt_min=1 and all other indices=0.
128   // The max feasible j_i is then level/w_i (except for special case w_i=0).
129   Real ssg_lev = (Real)(ssgLevIter->second);
130   if (aniso_wts.empty())
131     axis_l_bnds = ssg_lev; // all weights = 1
132   else // min nonzero weight scaled to 1 --> just catch special case w_i=0
133     for (size_t i=0; i<numVars; ++i)
134       axis_l_bnds[i] = (aniso_wts[i] > SMALL_NUMBER) ? // nonzero wt
135 	ssg_lev / aniso_wts[i] : 0.;
136 }
137 
138 
139 void SparseGridDriver::
initialize_grid(unsigned short ssg_level,const RealVector & dim_pref,const MultivariateDistribution & u_dist,const ExpansionConfigOptions & ec_options,BasisConfigOptions & bc_options,short growth_rate)140 initialize_grid(unsigned short ssg_level, const RealVector& dim_pref,
141 		const MultivariateDistribution& u_dist,
142 		const ExpansionConfigOptions& ec_options,
143 		BasisConfigOptions& bc_options, short growth_rate)
144 {
145   growthRate             = growth_rate;
146   //refineType           = ec_options.refineType;
147   refineControl          = ec_options.refineControl;
148 
149   // For unrestricted exponential growth, use of nested rules is restricted
150   // to uniform/normal in order to enforce similar growth rates:
151   if (bc_options.nestedRules && growthRate == UNRESTRICTED_GROWTH) {
152     const ShortArray&   u_types = u_dist.random_variable_types();
153     const BitArray& active_vars = u_dist.active_variables();
154     size_t i, num_u_types = u_types.size(); // numVars not yet defined
155     bool no_mask = active_vars.empty();
156     for (i=0; i<num_u_types; ++i)
157       if ( ( no_mask || active_vars[i] ) &&
158 	   u_types[i] != STD_UNIFORM && u_types[i] != STD_NORMAL )
159 	{ bc_options.nestedRules = false; break; }
160   }
161   // For MODERATE and SLOW restricted exponential growth, nested rules
162   // can be used heterogeneously and synchronized with STANDARD and SLOW
163   // linear growth, respectively.
164 
165   IntegrationDriver::initialize_grid(u_dist, ec_options, bc_options);
166 
167   level(ssg_level);
168   dimension_preference(dim_pref);
169 }
170 
171 
172 void SparseGridDriver::
initialize_grid_parameters(const MultivariateDistribution & mv_dist)173 initialize_grid_parameters(const MultivariateDistribution& mv_dist)
174 {
175   IntegrationDriver::initialize_grid_parameters(mv_dist);
176   if (basisParamUpdates.any()) clear_size(); // clear number of colloc points
177 
178   // assign is unnecessary as reset/update are sufficiently robust
179   //if (collocPts1D.empty())
180   //  assign_1d_collocation_points_weights();
181   //else {
182     reset_1d_collocation_points_weights();  // replace invalidated pt/wt sets
183     update_1d_collocation_points_weights(); // augment 1-D pt/wt sets
184   //}
185 }
186 
187 
precompute_rules()188 void SparseGridDriver::precompute_rules()
189 {
190   unsigned short l, m, ssg_lev = ssgLevIter->second;
191   if (isotropic())
192     for (size_t i=0; i<numVars; ++i) {
193       level_to_order(i, ssg_lev, m); // max order is full level in this dim
194       polynomialBasis[i].precompute_rules(m);
195     }
196   else {
197     const RealVector& aniso_wts = anisoWtsIter->second;
198     Real wt_i;
199     for (size_t i=0; i<numVars; ++i) {
200       wt_i = aniso_wts[i];
201       l = (wt_i > 0.) ? (unsigned short)((Real)ssg_lev / wt_i) : 0;
202       level_to_order(i, l, m); // max order is full aniso level[dim]
203       polynomialBasis[i].precompute_rules(m);
204     }
205   }
206 }
207 
208 
resize_1d_collocation_points_weights()209 void SparseGridDriver::resize_1d_collocation_points_weights()
210 {
211   // resize arrays in a one-sided manner (don't prune 1D points)
212 
213   unsigned short ssg_lev = ssgLevIter->second;
214   size_t i, num_levels = ssg_lev + 1, curr_lev;
215   curr_lev = collocPts1D.size();
216   if (num_levels > curr_lev) {
217     collocPts1D.resize(num_levels);
218     for (i=curr_lev; i<num_levels; ++i)
219       collocPts1D[i].resize(numVars);
220   }
221   curr_lev = type1CollocWts1D.size();
222   if (num_levels > curr_lev) {
223     type1CollocWts1D.resize(num_levels);
224     for (i=curr_lev; i<num_levels; ++i)
225       type1CollocWts1D[i].resize(numVars);
226   }
227   curr_lev = type2CollocWts1D.size();
228   if (computeType2Weights && num_levels > curr_lev) {
229     type2CollocWts1D.resize(num_levels);
230     for (i=curr_lev; i<num_levels; ++i)
231       type2CollocWts1D[i].resize(numVars);
232   }
233 }
234 
235 
236 /*
237 void SparseGridDriver::assign_1d_collocation_points_weights()
238 {
239   resize_1d_collocation_points_weights();
240 
241   // level_index (j indexing) range is 0:w, level (i indexing) range is 1:w+1
242   unsigned short l_index, q_order, num_levels = ssgLevIter->second + 1;
243   for (size_t i=0; i<numVars; i++)
244     for (l_index=0; l_index<num_levels; ++l_index) {
245       level_to_order(i, l_index, q_order);
246       IntegrationDriver::
247 	assign_1d_collocation_points_weights(i, q_order, l_index);
248     }
249 }
250 */
251 
252 
update_1d_collocation_points_weights()253 void SparseGridDriver::update_1d_collocation_points_weights()
254 {
255   unsigned short curr_levels = collocPts1D.size();
256   resize_1d_collocation_points_weights();
257 
258   // level_index (j indexing) range is 0:w, level (i indexing) range is 1:w+1
259   unsigned short l_index, q_order, num_levels = ssgLevIter->second + 1;
260   for (l_index=curr_levels; l_index<num_levels; ++l_index)
261     for (size_t i=0; i<numVars; i++) {
262       level_to_order(i, l_index, q_order);
263       IntegrationDriver::
264 	assign_1d_collocation_points_weights(i, q_order, l_index);
265     }
266 }
267 
268 
reset_1d_collocation_points_weights()269 void SparseGridDriver::reset_1d_collocation_points_weights()
270 {
271   // re-assign 1D pts/wts per variable, if indicated by basisParamUpdates
272   size_t v, num_v = basisParamUpdates.size();
273   for (v=0; v<num_v; ++v)
274     if (basisParamUpdates[v])
275       reset_1d_collocation_points_weights(v);
276 }
277 
278 
reset_1d_collocation_points_weights(size_t i)279 void SparseGridDriver::reset_1d_collocation_points_weights(size_t i)
280 {
281   // replaces only the existing pts/wts (no resizing)
282 
283   unsigned short lev, order;  size_t num_lev = collocPts1D.size();
284   BasisPolynomial& poly_i = polynomialBasis[i];
285   for (lev=0; lev<num_lev; ++lev) {
286     level_to_order(i, lev, order);
287     collocPts1D[lev][i]        = poly_i.collocation_points(order);
288     type1CollocWts1D[lev][i]   = poly_i.type1_collocation_weights(order);
289     if (computeType2Weights)
290       type2CollocWts1D[lev][i] = poly_i.type2_collocation_weights(order);
291   }
292 }
293 
294 
initialize_sets()295 void SparseGridDriver::initialize_sets()
296 {
297   PCerr << "Error: no default implementation for SparseGridDriver::"
298 	<< "initialize_sets()." << std::endl;
299   abort_handler(-1);
300 }
301 
302 
increment_smolyak_multi_index(const UShortArray & set)303 void SparseGridDriver::increment_smolyak_multi_index(const UShortArray& set)
304 {
305   PCerr << "Error: no default implementation for SparseGridDriver::"
306 	<< "increment_smolyak_multi_index()." << std::endl;
307   abort_handler(-1);
308 }
309 
310 
311 bool SparseGridDriver::
push_trial_available(const UShortArray & key,const UShortArray & tr_set)312 push_trial_available(const UShortArray& key, const UShortArray& tr_set)
313 { return false; }
314 
315 
push_trial_available(const UShortArray & key)316 bool SparseGridDriver::push_trial_available(const UShortArray& key)
317 { return false; }
318 
319 
push_trial_available()320 bool SparseGridDriver::push_trial_available()
321 { return false; }
322 
323 
324 size_t SparseGridDriver::
push_trial_index(const UShortArray & key,const UShortArray & tr_set)325 push_trial_index(const UShortArray& key, const UShortArray& tr_set)
326 { return _NPOS; }
327 
328 
push_trial_index(const UShortArray & key)329 size_t SparseGridDriver::push_trial_index(const UShortArray& key)
330 { return _NPOS; }
331 
332 
push_trial_index()333 size_t SparseGridDriver::push_trial_index()
334 { return _NPOS; }
335 
336 
push_index(const UShortArray & key) const337 size_t SparseGridDriver::push_index(const UShortArray& key) const
338 { return _NPOS; }
339 
340 
restore_index(const UShortArray & key) const341 size_t SparseGridDriver::restore_index(const UShortArray& key) const
342 { return push_index(key); } // default for identity mapping (flat to flat)
343 
344 
finalize_index(size_t i,const UShortArray & key) const345 size_t SparseGridDriver::finalize_index(size_t i, const UShortArray& key) const
346 { return i; } // default is an identity mapping
347 
348 
push_set()349 void SparseGridDriver::push_set()
350 {
351   PCerr << "Error: no default implementation for SparseGridDriver::push_set()."
352 	<< std::endl;
353   abort_handler(-1);
354 }
355 
356 
pop_set()357 void SparseGridDriver::pop_set()
358 {
359   PCerr << "Error: no default implementation for SparseGridDriver::pop_set()."
360 	<< std::endl;
361   abort_handler(-1);
362 }
363 
364 
365 void SparseGridDriver::
finalize_sets(bool output_sets,bool converged_within_tol,bool reverted)366 finalize_sets(bool output_sets, bool converged_within_tol, bool reverted)
367 {
368   PCerr << "Error: no default implementation for SparseGridDriver::"
369 	<< "finalize_sets()." << std::endl;
370   abort_handler(-1);
371 }
372 
373 
update_reference()374 void SparseGridDriver::update_reference()
375 {
376   // Not needed for HierarchSparseGridDriver, so use no-op as default
377 
378   /*
379   PCerr << "Error: no default implementation for SparseGridDriver::"
380 	<< "update_reference()." << std::endl;
381   abort_handler(-1);
382   */
383 }
384 
385 
compute_trial_grid(RealMatrix & var_sets)386 void SparseGridDriver::compute_trial_grid(RealMatrix& var_sets)
387 {
388   PCerr << "Error: no default implementation for SparseGridDriver::"
389 	<< "compute_trial_grid()." << std::endl;
390   abort_handler(-1);
391 }
392 
393 
compute_increment(RealMatrix & var_sets)394 void SparseGridDriver::compute_increment(RealMatrix& var_sets)
395 {
396   PCerr << "Error: no default implementation for SparseGridDriver::"
397 	<< "compute_increment()." << std::endl;
398   abort_handler(-1);
399 }
400 
401 
push_increment()402 void SparseGridDriver::push_increment()
403 {
404   PCerr << "Error: no default implementation for SparseGridDriver::"
405 	<< "push_increment()." << std::endl;
406   abort_handler(-1);
407 }
408 
409 
pop_increment()410 void SparseGridDriver::pop_increment()
411 {
412   PCerr << "Error: no default implementation for SparseGridDriver::"
413 	<< "pop_increment()." << std::endl;
414   abort_handler(-1);
415 }
416 
417 
merge_unique()418 void SparseGridDriver::merge_unique()
419 { } // not needed for HierarchSparseGridDriver, so use no-op as default
420 
421 
trial_set(const UShortArray & key) const422 const UShortArray& SparseGridDriver::trial_set(const UShortArray& key) const
423 {
424   PCerr << "Error: no default implementation for SparseGridDriver::trial_set()."
425 	<< std::endl;
426   abort_handler(-1);
427   return key; // dummy UShortArray
428 }
429 
430 
trial_set() const431 const UShortArray& SparseGridDriver::trial_set() const
432 { return trial_set(activeKey); } // default implementation
433 
434 
unique_trial_points() const435 int SparseGridDriver::unique_trial_points() const
436 {
437   PCerr << "Error: no default implementation for SparseGridDriver::"
438 	<< "unique_trial_points()." << std::endl;
439   abort_handler(-1);
440   return 0;
441 }
442 
443 
update_smolyak_arrays()444 void SparseGridDriver::update_smolyak_arrays()
445 {
446   PCerr << "Error: no default implementation for SparseGridDriver::"
447 	<< "update_smolyak_arrays()." << std::endl;
448   abort_handler(-1);
449 }
450 
451 
update_sets(const UShortArray & set_star)452 void SparseGridDriver::update_sets(const UShortArray& set_star)
453 {
454   // set_star is passed as *cit_star from the best entry in activeMultiIndex.
455   // Therefore, we must use caution in updates to activeMultiIndex that can
456   // invalidate cit_star.
457 
458   // update smolyakMultiIndex (permanently, will not be popped)
459   increment_smolyak_multi_index(set_star);
460   push_set();     // calls increment_unique()      --> INC2
461   merge_unique(); // promotes increment to new ref --> INC3
462 
463   // use trial set rather than incoming set_star due to iterator invalidation
464   const UShortArray&    tr_set = trial_set();
465   UShortArrayDeque& pop_trials =  poppedTrialSets[activeKey];
466   UShortArraySet&    active_mi = activeMultiIndex[activeKey];
467   UShortArraySet&       old_mi =    oldMultiIndex[activeKey];
468 
469   // update set O by adding the trial set to oldMultiIndex:
470   old_mi.insert(tr_set);
471   // remove the trial set from set A by erasing from activeMultiIndex:
472   active_mi.erase(tr_set); // invalidates cit_star -> set_star
473   // update subset of A that have been evaluated as trial sets but not selected
474   UShortArrayDeque::iterator tr_it
475     = std::find(pop_trials.begin(), pop_trials.end(), tr_set);
476   if (tr_it != pop_trials.end()) pop_trials.erase(tr_it);
477 
478   // update set A (activeMultiIndex) based on neighbors of trial set
479   add_active_neighbors(tr_set, false);//, isotropic());
480 
481   // Note: pruning irrelevant sets that have Coeff = 0 would be tricky,
482   //       since a 0 close to the frontier can become nonzero
483 
484 #ifdef DEBUG
485   PCout << "Sets updated: (Smolyak,Old,Active,Trial) = (" << smolyak_size()
486 	<< ',' << old_mi.size() << ',' << active_mi.size() << ','
487 	<< pop_trials.size() << ')' << std::endl;
488 #endif // DEBUG
489 }
490 
491 
492 void SparseGridDriver::
add_active_neighbors(const UShortArray & set,bool frontier)493 add_active_neighbors(const UShortArray& set, bool frontier)
494 {
495   UShortArray     trial_set =    set;
496   UShortArraySet&    old_mi =    oldMultiIndex[activeKey];
497   UShortArraySet& active_mi = activeMultiIndex[activeKey];
498   UShortArraySet::const_iterator cit;
499   size_t i, j, num_v = set.size();
500   for (i=0; i<num_v; ++i) {
501     // i^{th} candidate for set A (active) computed from forward neighbor:
502     // increment by 1 in dimension i
503     unsigned short& trial_set_i = trial_set[i];
504     ++trial_set_i;
505     // if !frontier, then candidates could exist in oldMultiIndex
506     if (frontier || old_mi.find(trial_set) == old_mi.end()) {
507       // test all backwards neighbors for membership in set O (old)
508       bool backward_old = true;
509       for (j=0; j<num_v; ++j) {
510 	unsigned short& trial_set_j = trial_set[j];
511 	if (trial_set_j) { // if 0, then admissible by default
512 	  --trial_set_j;
513 	  cit = old_mi.find(trial_set);
514 	  ++trial_set_j; // restore
515 	  if (cit == old_mi.end())
516 	    { backward_old = false; break; }
517 	}
518       }
519       if (backward_old) // std::set<> will discard any active duplicates
520 	active_mi.insert(trial_set);
521     }
522     --trial_set_i; // restore
523   }
524 }
525 
526 
clear_inactive()527 void SparseGridDriver::clear_inactive()
528 {
529   // These are always defined in update_active_iterators()
530   std::map<UShortArray, unsigned short>::iterator sg_it = ssgLevel.begin();
531   std::map<UShortArray, RealVector>::iterator     aw_it = anisoLevelWts.begin();
532   std::map<UShortArray, int>::iterator            cp_it = numCollocPts.begin();
533   while (sg_it != ssgLevel.end())
534     if (sg_it == ssgLevIter) // preserve active
535       { ++sg_it; ++aw_it; ++cp_it; }
536     else { // clear inactive: postfix increments manage iterator invalidations
537       ssgLevel.erase(sg_it++);
538       anisoLevelWts.erase(aw_it++);
539       numCollocPts.erase(cp_it++);
540     }
541 
542   // Generalized sparse grid sets may be active
543   if (!oldMultiIndex.empty()) {
544     std::map<UShortArray, UShortArraySet>::iterator
545       om_it = oldMultiIndex.begin(), om_act_it = oldMultiIndex.find(activeKey);
546     std::map<UShortArray, UShortArraySet>::iterator am_it
547       = activeMultiIndex.begin();
548     std::map<UShortArray, UShortArrayDeque>::iterator pt_it
549       = poppedTrialSets.begin();
550     while (om_it != oldMultiIndex.end())
551       if (om_it == om_act_it) // preserve active
552 	{ ++om_it; ++am_it; ++pt_it; }
553       else { // clear inactive: postfix increments manage iterator invalidations
554 	oldMultiIndex.erase(om_it++);
555 	activeMultiIndex.erase(am_it++);
556 	poppedTrialSets.erase(pt_it++);
557       }
558   }
559 
560   // Anisotropic refinement bounds may be active
561   if (!axisLowerBounds.empty()) {
562     std::map<UShortArray, RealVector>::iterator ab_it = axisLowerBounds.begin(),
563       ab_act_it = axisLowerBounds.find(activeKey);
564     while (ab_it != axisLowerBounds.end())
565       if (ab_it == ab_act_it) // preserve active
566 	++ab_it;
567       else // clear inactive: postfix increments manage iterator invalidations
568 	axisLowerBounds.erase(ab_it++);
569   }
570 }
571 
572 
level_to_order_exp_hgk_interp(int level,int growth)573 int SparseGridDriver::level_to_order_exp_hgk_interp(int level, int growth)
574 {
575   if (level == 0) return 1;
576 
577   switch (growth) {
578   case SLOW_RESTRICTED_GROWTH: {
579     unsigned short level = 0, max_level = 5;
580     int m = 1, m_goal = level + 1;
581     while (level <= max_level && m < m_goal)
582       { ++level; m = orderGenzKeister[level]; }
583     return m; break;
584   }
585   case MODERATE_RESTRICTED_GROWTH: {
586     unsigned short level = 0, max_level = 5;
587     int m = 1, m_goal = 2 * level + 1;
588     while (level <= max_level && m < m_goal)
589       { ++level; m = orderGenzKeister[level]; }
590     return m; break;
591   }
592   case UNRESTRICTED_GROWTH:
593     return orderGenzKeister[std::min(level, 5)]; break;
594   }
595 }
596 
597 
level_to_order_exp_closed_interp(int level,int growth)598 int SparseGridDriver::level_to_order_exp_closed_interp(int level, int growth)
599 {
600   if (level == 0) return 1;
601 
602   switch (growth) {
603   case SLOW_RESTRICTED_GROWTH: {
604     int m = 1, lev_pow = 1, m_goal = level + 1;
605     while (m < m_goal)
606       { lev_pow *= 2; m = lev_pow + 1; } //std::pow(2.,level) + 1;
607     return m; break;
608   }
609   case MODERATE_RESTRICTED_GROWTH: {
610     int m = 1, lev_pow = 1, m_goal = 2 * level + 1;
611     while (m < m_goal)
612       { lev_pow *= 2; m = lev_pow + 1; } //std::pow(2.,level) + 1;
613     return m; break;
614   }
615   case UNRESTRICTED_GROWTH:
616     return (int)std::pow(2., level) + 1; break;
617   }
618 }
619 
620 
level_to_order_exp_open_interp(int level,int growth)621 int SparseGridDriver::level_to_order_exp_open_interp(int level, int growth)
622 {
623   if (level == 0) return 1;
624 
625   switch (growth) {
626   case SLOW_RESTRICTED_GROWTH: {
627     int m = 1, lev_pow = 2, m_goal = level + 1;
628     while (m < m_goal)
629       { lev_pow *= 2; m = lev_pow - 1; } //std::pow(2.,level+1) - 1;
630     return m; break;
631   }
632   case MODERATE_RESTRICTED_GROWTH: {
633     int m = 1, lev_pow = 2, m_goal = 2 * level + 1;
634     while (m < m_goal)
635       { lev_pow *= 2; m = lev_pow - 1; } //std::pow(2.,level+1) - 1;
636     return m; break;
637   }
638   case UNRESTRICTED_GROWTH:
639     return (int)std::pow(2., level+1) - 1; break;
640   }
641 }
642 
643 } // namespace Pecos
644