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: Wrapper class for C++ code from packages/quadrature/sparse_grid
11 //- Owner: Mike Eldred
12 //- Revised by:
13 //- Version:
14
15 #ifndef SPARSE_GRID_DRIVER_HPP
16 #define SPARSE_GRID_DRIVER_HPP
17
18 #include "IntegrationDriver.hpp"
19 #include "sandia_rules.hpp"
20
21 namespace Pecos {
22
23
24 /// Derived integration driver class that generates N-dimensional
25 /// Smolyak sparse grids for numerical evaluation of expectation
26 /// integrals over independent standard random variables.
27
28 /** This class is used by Dakota::NonDSparseGrid, but could also be
29 used for general numerical integration of moments. It employs 1-D
30 Clenshaw-Curtis, Newton-Cotes, and Gaussian quadrature rules
31 within Smolyak sparse grids. */
32
33 class SparseGridDriver: public IntegrationDriver
34 {
35 public:
36
37 //
38 //- Heading: Constructors and destructor
39 //
40
41 /// default constructor
42 SparseGridDriver();
43 /// constructor
44 SparseGridDriver(unsigned short ssg_level, const RealVector& dim_pref,
45 short growth_rate, short refine_control);
46 /// destructor
47 ~SparseGridDriver();
48
49 //
50 //- Heading: New virtual functions
51 //
52
53 /// initializes old/active/evaluation sets for use within the
54 /// generalized sparse grid procedure
55 virtual void initialize_sets();
56 /// update smolyakMultiIndex with a new trial set for use within the
57 /// generalized sparse grid procedure
58 virtual void increment_smolyak_multi_index(const UShortArray& set);
59
60 /// determine whether trial set is available for restoration (by push)
61 virtual bool push_trial_available(const UShortArray& key,
62 const UShortArray& tr_set);
63 /// determine whether trial set is available for restoration (by push
64 virtual bool push_trial_available(const UShortArray& key);
65 /// determine whether trial set is available for restoration (by push
66 virtual bool push_trial_available();
67
68 /// determine index of trial set for restoration (by push)
69 virtual size_t push_trial_index(const UShortArray& key,
70 const UShortArray& tr_set);
71 /// determine index of trial set for restoration (by push)
72 virtual size_t push_trial_index(const UShortArray& key);
73 /// determine index of trial set for restoration (by push)
74 virtual size_t push_trial_index();
75
76 /// return pushIndex (cached lookup result in derived Driver classes),
77 /// which may be combined (flattened) or hierarchical (level-specific) index
78 virtual size_t push_index(const UShortArray& key) const;
79 /// map pushIndex to consistent (flattened) representation
80 virtual size_t restore_index(const UShortArray& key) const;
81 /// return consistent (flattened) index
82 virtual size_t finalize_index(size_t i, const UShortArray& key) const;
83
84 /// update collocKey, collocIndices, and uniqueIndexMapping based on
85 /// restoration of previous trial to smolyakMultiIndex
86 virtual void push_set();
87 /// remove the previously pushed trial set from smolyakMultiIndex
88 /// during the course of the generalized sparse grid procedure
89 virtual void pop_set();
90 /// accept all remaining trial sets within the generalized sparse
91 /// grid procedure
92 virtual void finalize_sets(bool output_sets, bool converged_within_tol,
93 bool reverted);
94
95 /// computes the tensor grid for the trial index set used in
96 /// increment_smolyak_multi_index()
97 virtual void compute_trial_grid(RealMatrix& var_sets);
98
99 /// computes a grid increment and evaluates the new parameter sets
100 virtual void compute_increment(RealMatrix& var_sets);
101 /// restores a previously computed grid increment (no new evaluations)
102 virtual void push_increment();
103 /// removes a previously computed grid increment
104 virtual void pop_increment();
105 /// merges a grid increment into the reference grid
106 virtual void merge_unique();
107
108 /// update derived reference data, if required
109 virtual void update_reference();
110
111 /// return the trial index set used in increment_smolyak_multi_index()
112 /// that corresponds to key
113 virtual const UShortArray& trial_set(const UShortArray& key) const;
114 /// return the trial index set used in increment_smolyak_multi_index()
115 /// that corresponds to activeKey
116 virtual const UShortArray& trial_set() const;
117
118 /// return the number of unique collocation points in the trial index set
119 virtual int unique_trial_points() const;
120
121 /// update smolyakMultiIndex and smolyakCoeffs while adapting grid
122 virtual void update_smolyak_arrays();
123 /// print smolyakMultiIndex
124 virtual void print_smolyak_multi_index() const = 0;
125
126 /// update active iterators based on activeKey
127 virtual void update_active_iterators();
128
129 //
130 //- Heading: virtual function redefinitions
131 //
132
133 void active_key(const UShortArray& key);
134 void clear_inactive();
135 void clear_keys();
136 void reset();
137 void initialize_grid_parameters(const MultivariateDistribution& mv_dist);
138
139 //
140 //- Heading: Member functions
141 //
142
143 /// return number of collocation points in active grid
144 int collocation_points() const;
145
146 /// initialize all sparse grid settings except for distribution params
147 void initialize_grid(unsigned short ssg_level, const RealVector& dim_pref,
148 const MultivariateDistribution& u_dist,
149 const ExpansionConfigOptions& ec_options, BasisConfigOptions& bc_options,
150 short growth_rate = MODERATE_RESTRICTED_GROWTH);
151
152 /// set flag indicating that grid details have changed and the size
153 /// calculation requires updating
154 void clear_size();
155
156 /// return pushIndex (cached lookup result in derived Driver classes)
157 size_t push_index() const;
158
159 /// precompute quadrature rules to the maximum current order for each basis
160 /// polynomial (efficiency optimization when rules are expensive to compute)
161 void precompute_rules();
162
163 // initialize collocPts1D and type{1,2}CollocWts1D
164 //void assign_1d_collocation_points_weights();
165 /// expand and update collocPts1D and type{1,2}CollocWts1D
166 void update_1d_collocation_points_weights();
167 /// reset collocPts1D and type{1,2}CollocWts1D for variables with a
168 /// distribution parameter change
169 void reset_1d_collocation_points_weights();
170
171 /// update axisLowerBounds
172 void update_axis_lower_bounds();
173
174 /// accept the best of several trial sets and update old/active
175 /// within the generalized sparse grid procedure
176 void update_sets(const UShortArray& set_star);
177 /// update activeMultiIndex from the passed trial set for use within
178 /// the generalized sparse grid procedure
179 void add_active_neighbors(const UShortArray& set, bool frontier);
180
181 /// converts an array of sparse grid levels to an array of
182 /// quadrature orders based on apiIntegrationRules/apiGrowthRules
183 void level_to_order(size_t i, unsigned short level,
184 unsigned short& order);
185 /// converts an array of sparse grid levels to an array of
186 /// quadrature orders based on apiIntegrationRules/apiGrowthRules
187 void level_to_order(const UShortArray& levels, UShortArray& orders);
188
189 /// set active ssgLevel
190 void level(unsigned short ssg_level);
191 /// return active ssgLevel
192 unsigned short level() const;
193
194 /// convert dimension preference and set anisoLevelWts
195 void dimension_preference(const RealVector& dim_pref);
196 /// set anisoLevelWts
197 void anisotropic_weights(const RealVector& aniso_wts);
198 /// return anisoLevelWts
199 const RealVector& anisotropic_weights() const;
200 /// indicates isotropic (empty) weights on sparse grid dimension levels
201 bool isotropic() const;
202
203 /// set growthRate
204 void growth_rate(short growth_rate);
205 /// get growthRate
206 short growth_rate() const;
207
208 // get refineType
209 //short refinement_type() const;
210 /// set refineControl
211 void refinement_control(short cntl);
212 /// get refineControl
213 short refinement_control() const;
214
215 /// return entry from activeMultiIndex corresponding to key
216 const UShortArraySet& active_multi_index(const UShortArray& key) const;
217 /// return entry from activeMultiIndex corresponding to activeKey
218 const UShortArraySet& active_multi_index() const;
219
220 protected:
221
222 //
223 //- Heading: Convenience functions
224 //
225
226 /// level to order mapping for interpolation with nested Genz-Keister rules
227 static int level_to_order_exp_hgk_interp(int level, int growth);
228 /// level to order mapping for interpolation with nested closed rules
229 static int level_to_order_exp_closed_interp(int level, int growth);
230 /// level to order mapping for interpolation with nested open rules
231 static int level_to_order_exp_open_interp(int level, int growth);
232
233 /// print an index set
234 void print_index_set(std::ostream& s, const UShortArray& mi) const;
235
236 //
237 //- Heading: Data
238 //
239
240 /// Smolyak sparse grid levels for each active key
241 std::map<UShortArray, unsigned short> ssgLevel;
242 /// iterator to the active Smolyak sparse grid level
243 std::map<UShortArray, unsigned short>::iterator ssgLevIter;
244
245 /// weighting vector for dimension anisotropic grids
246 std::map<UShortArray, RealVector> anisoLevelWts;
247 /// weighting vector for dimension anisotropic grids
248 std::map<UShortArray, RealVector>::iterator anisoWtsIter;
249
250 /// enumeration for rate of exponential growth in nested rules
251 short growthRate;
252
253 // type of expansion refinement
254 //short refineType;
255 /// algorithm control governing expansion refinement
256 short refineControl;
257
258 /// the number of unique points in each grid
259 std::map<UShortArray, int> numCollocPts;
260 /// iterator to the number of unique points in the active grid
261 std::map<UShortArray, int>::iterator numPtsIter;
262
263 /// old reference index sets for generalized sparse grids. Use std::set
264 /// for efficient lookups in add_active_neighbors().
265 std::map<UShortArray, UShortArraySet> oldMultiIndex;
266 /// active index sets under current consideration for inclusion in a
267 /// generalized sparse grid. Use std::set for ordering of candidates.
268 std::map<UShortArray, UShortArraySet> activeMultiIndex;
269 /// subset of active trial sets that have been evaluated but not selected.
270 /// Use std::deque to retain append ordering (mirroring SurrogateData).
271 std::map<UShortArray, UShortArrayDeque> poppedTrialSets;
272
273 /// database key indicating the currently active integration configuration.
274 /// the key is a multi-index managing multiple modeling dimensions such as
275 /// model form, discretization level, etc.
276 UShortArray activeKey;
277
278 private:
279
280 //
281 //- Heading: Convenience functions
282 //
283
284 /// reset collocPts1D[*][i] and type{1,2}CollocWts1D[*][i] for all levels
285 void reset_1d_collocation_points_weights(size_t i);
286 /// resize arrays: collocPts1D,type1CollocWts1D,type2CollocWts1D
287 void resize_1d_collocation_points_weights();
288
289 //
290 //- Heading: Data
291 //
292
293 /// refinement constraints that ensure that level/anisotropic weight updates
294 /// contain all previous multi-index sets
295 std::map<UShortArray, RealVector> axisLowerBounds;
296 // iterator to the active set of axis lower bounds
297 //std::map<UShortArray, RealVector>::iterator axisLBndsIter;
298 };
299
300
SparseGridDriver()301 inline SparseGridDriver::SparseGridDriver():
302 IntegrationDriver(BaseConstructor()), growthRate(MODERATE_RESTRICTED_GROWTH),
303 //ssgLevel(0), numCollocPts(0),
304 refineControl(NO_CONTROL)//, refineType(NO_REFINEMENT)
305 {
306 std::pair<UShortArray, unsigned short> us_pair(activeKey, 0);
307 ssgLevIter = ssgLevel.insert(us_pair).first;
308
309 std::pair<UShortArray, int> ui_pair(activeKey, 0);
310 numPtsIter = numCollocPts.insert(ui_pair).first;
311 }
312
313
314 inline SparseGridDriver::
SparseGridDriver(unsigned short ssg_level,const RealVector & dim_pref,short growth_rate,short refine_control)315 SparseGridDriver(unsigned short ssg_level, const RealVector& dim_pref,
316 short growth_rate, short refine_control):
317 IntegrationDriver(BaseConstructor()), growthRate(growth_rate),
318 //ssgLevel(ssg_level), numCollocPts(0),
319 refineControl(refine_control) //refineType(NO_REFINEMENT)
320 {
321 std::pair<UShortArray, unsigned short> us_pair(activeKey, ssg_level);
322 ssgLevIter = ssgLevel.insert(us_pair).first;
323
324 std::pair<UShortArray, int> ui_pair(activeKey, 0);
325 numPtsIter = numCollocPts.insert(ui_pair).first; // count to be updated
326
327 if (!dim_pref.empty()) {
328 numVars = dim_pref.length(); // unit length option not supported
329 dimension_preference(dim_pref);
330 }
331 }
332
333
~SparseGridDriver()334 inline SparseGridDriver::~SparseGridDriver()
335 { }
336
337
active_key(const UShortArray & key)338 inline void SparseGridDriver::active_key(const UShortArray& key)
339 {
340 if (activeKey != key) {
341 activeKey = key;
342 update_active_iterators();
343 }
344 }
345
346
update_active_iterators()347 inline void SparseGridDriver::update_active_iterators()
348 {
349 ssgLevIter = ssgLevel.find(activeKey);
350 if (ssgLevIter == ssgLevel.end()) {
351 std::pair<UShortArray, unsigned short> us_pair(activeKey, 0);
352 ssgLevIter = ssgLevel.insert(us_pair).first;
353 }
354 numPtsIter = numCollocPts.find(activeKey);
355 if (numPtsIter == numCollocPts.end()) {
356 // assign special value for grid_size() (instead of 1 pt for ssgLev 0)
357 std::pair<UShortArray, int> ui_pair(activeKey, 0);
358 numPtsIter = numCollocPts.insert(ui_pair).first;
359 }
360 anisoWtsIter = anisoLevelWts.find(activeKey);
361 if (anisoWtsIter == anisoLevelWts.end()) {
362 std::pair<UShortArray, RealVector> urv_pair(activeKey, RealVector());
363 anisoWtsIter = anisoLevelWts.insert(urv_pair).first;
364 }
365 /*
366 axisLBndsIter = axisLowerBounds.find(activeKey);
367 if (axisLBndsIter == axisLowerBounds.end()) {
368 std::pair<UShortArray, RealVector> urv_pair(activeKey, RealVector());
369 axisLBndsIter = axisLowerBounds.insert(urv_pair).first;
370 }
371 */
372 }
373
374
clear_keys()375 inline void SparseGridDriver::clear_keys()
376 {
377 activeKey.clear();
378
379 ssgLevel.clear(); ssgLevIter = ssgLevel.end();
380 numCollocPts.clear(); numPtsIter = numCollocPts.end();
381 anisoLevelWts.clear(); anisoWtsIter = anisoLevelWts.end();
382 axisLowerBounds.clear(); //axisLBndsIter = axisLowerBounds.end();
383
384 oldMultiIndex.clear(); activeMultiIndex.clear(); poppedTrialSets.clear();
385
386 // this database is shared among all keys
387 clear_1d_collocation_points_weights();
388 }
389
390
collocation_points() const391 inline int SparseGridDriver::collocation_points() const
392 { return numPtsIter->second; }
393
394
clear_size()395 inline void SparseGridDriver::clear_size()
396 { numPtsIter->second = 0; } // special value indicating a grid update is reqd
397
398
reset()399 inline void SparseGridDriver::reset()
400 { IntegrationDriver::reset(); clear_size(); }
401
402
push_index() const403 inline size_t SparseGridDriver::push_index() const
404 { return push_index(activeKey); }
405
406
level() const407 inline unsigned short SparseGridDriver::level() const
408 { return ssgLevIter->second; }
409
410
level(unsigned short ssg_level)411 inline void SparseGridDriver::level(unsigned short ssg_level)
412 {
413 if (ssgLevIter->second != ssg_level) {
414 ssgLevIter->second = ssg_level;
415 clear_size();
416 }
417 }
418
419
anisotropic_weights() const420 inline const RealVector& SparseGridDriver::anisotropic_weights() const
421 { return anisoWtsIter->second; }
422
423
isotropic() const424 inline bool SparseGridDriver::isotropic() const
425 { return anisoWtsIter->second.empty(); }
426
427
428 //inline short SparseGridDriver::refinement_type() const
429 //{ return refineType; }
430
431
refinement_control(short cntl)432 inline void SparseGridDriver::refinement_control(short cntl)
433 { refineControl = cntl; }
434
435
refinement_control() const436 inline short SparseGridDriver::refinement_control() const
437 { return refineControl; }
438
439
growth_rate(short growth_rate)440 inline void SparseGridDriver::growth_rate(short growth_rate)
441 { growthRate = growth_rate; }
442
443
growth_rate() const444 inline short SparseGridDriver::growth_rate() const
445 { return growthRate; }
446
447
448 inline const UShortArraySet& SparseGridDriver::
active_multi_index(const UShortArray & key) const449 active_multi_index(const UShortArray& key) const
450 {
451 std::map<UShortArray, UShortArraySet>::const_iterator cit
452 = activeMultiIndex.find(key);
453 if (cit == activeMultiIndex.end()) {
454 PCerr << "Error: active key not found in SparseGridDriver::"
455 << "active_multi_index()." << std::endl;
456 abort_handler(-1);
457 }
458 return cit->second;
459 }
460
461
active_multi_index() const462 inline const UShortArraySet& SparseGridDriver::active_multi_index() const
463 { return active_multi_index(activeKey); }
464
465
466 inline void SparseGridDriver::
level_to_order(size_t i,unsigned short level,unsigned short & order)467 level_to_order(size_t i, unsigned short level, unsigned short& order)
468 {
469 //int ilevel = level, iorder;
470 //webbur::level_growth_to_order(1, &ilevel, &apiIntegrationRules[i],
471 // &apiGrowthRules[i], &iorder);
472 //order = iorder;
473
474 // if INTERPOLATION_MODE, use mappings that synchronize on the number of
475 // interpolated points. For INTEGRATION_MODE or DEFAULT_MODE, use mappings
476 // that synchronize on integrand precision.
477 switch (collocRules[i]) {
478 case GAUSS_PATTERSON:
479 order = (driverMode == INTERPOLATION_MODE) ?
480 level_to_order_exp_open_interp(level, growthRate) :
481 webbur::level_to_order_exp_gp(level, growthRate); break;
482 case GENZ_KEISTER:
483 order = (driverMode == INTERPOLATION_MODE) ?
484 level_to_order_exp_hgk_interp(level, growthRate) :
485 webbur::level_to_order_exp_hgk(level, growthRate); break;
486 case CLENSHAW_CURTIS: case NEWTON_COTES:
487 order = (driverMode == INTERPOLATION_MODE) ?
488 level_to_order_exp_closed_interp(level, growthRate) :
489 webbur::level_to_order_exp_cc(level, growthRate); break;
490 case FEJER2:
491 order = (driverMode == INTERPOLATION_MODE) ?
492 level_to_order_exp_open_interp(level, growthRate) :
493 webbur::level_to_order_exp_f2(level, growthRate); break;
494 case GAUSS_HERMITE: case GAUSS_LEGENDRE: // weakly nested Gaussian
495 order = webbur::level_to_order_linear_wn(level, growthRate); break;
496 default: // non-nested Gaussian
497 order = webbur::level_to_order_linear_nn(level, growthRate); break;
498 }
499 }
500
501
502 inline void SparseGridDriver::
level_to_order(const UShortArray & levels,UShortArray & orders)503 level_to_order(const UShortArray& levels, UShortArray& orders)
504 {
505 size_t i, num_lev = levels.size();
506 if (orders.size() != num_lev)
507 orders.resize(num_lev);
508 for (i=0; i<num_lev; ++i)
509 level_to_order(i, levels[i], orders[i]);
510 }
511
512
513 inline void SparseGridDriver::
print_index_set(std::ostream & s,const UShortArray & mi) const514 print_index_set(std::ostream& s, const UShortArray& mi) const
515 {
516 size_t j, num_mi = mi.size();
517 for (j=0; j<num_mi; ++j)
518 s << std::setw(5) << mi[j];
519 s << '\n';
520 }
521
522 } // namespace Pecos
523
524 #endif
525