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:       SimulationModel
10 //- Description: Implementation code for the SimulationModel class
11 //- Owner:       Mike Eldred
12 //- Checked by:
13 
14 #include "dakota_system_defs.hpp"
15 #include "SimulationModel.hpp"
16 #include "ProblemDescDB.hpp"
17 #include "MarginalsCorrDistribution.hpp"
18 
19 static const char rcsId[]="@(#) $Id: SimulationModel.cpp 6492 2009-12-19 00:04:28Z briadam $";
20 
21 
22 using namespace std;
23 
24 namespace Dakota {
25 
26 
SimulationModel(ProblemDescDB & problem_db)27 SimulationModel::SimulationModel(ProblemDescDB& problem_db):
28   Model(BaseConstructor(), problem_db),
29   userDefinedInterface(problem_db.get_interface()),
30   solnCntlVarType(EMPTY_TYPE), solnCntlADVIndex(0), solnCntlRVIndex(0),
31   simModelEvalCntr(0)
32 {
33   componentParallelMode = INTERFACE_MODE;
34   ignoreBounds = problem_db.get_bool("responses.ignore_bounds");
35   centralHess  = problem_db.get_bool("responses.central_hess");
36 
37   initialize_solution_control(
38     problem_db.get_string("model.simulation.solution_level_control"),
39     problem_db.get_rv("model.simulation.solution_level_cost"));
40 
41 }
42 
43 
44 void SimulationModel::
initialize_solution_control(const String & control,const RealVector & cost)45 initialize_solution_control(const String& control, const RealVector& cost)
46 {
47   solnCntlCostMap.clear();
48 
49   size_t cost_len = cost.length();
50   if (control.empty()) {
51     // cost_len of 0: empty map for no solution control
52     // cost_len of 1: nominal cost for model w/o any soln levels
53     // cost_len  > 1: error
54     if (cost_len == 1)   // nominal cost with no solution control
55       solnCntlCostMap.insert(std::pair<Real, size_t>(cost[0], _NPOS));
56     else if (cost_len) { // more than 1 cost requires associated control
57       Cerr << "Error: vector-valued solution cost requires an associated "
58 	   << "solution control." << std::endl;
59       abort_handler(MODEL_ERROR);
60     }
61     return;
62   }
63 
64   // find the variable label used for solution control within the discrete
65   // variables (all view).  It must be a discrete variable so that the number
66   // of levels is finite; however, the discrete values may be int, string, or
67   // real.  It should not be an active variable, but may not be an inactive
68   // variable (inactive view assigned from a higher level context).
69   solnCntlADVIndex = find_index(
70     currentVariables.all_discrete_int_variable_labels(), control);
71   if (solnCntlADVIndex != _NPOS) {
72     solnCntlVarType = currentVariables.
73       all_discrete_int_variable_types()[solnCntlADVIndex];
74     if (find_index(currentVariables.discrete_int_variable_labels(), control)
75 	!= _NPOS) {
76       Cerr << "Error: solution_level_control cannot be an active variable."
77 	   << std::endl;
78       abort_handler(MODEL_ERROR);
79     }
80   }
81   else {
82     solnCntlADVIndex = find_index(
83       currentVariables.all_discrete_string_variable_labels(), control);
84     if (solnCntlADVIndex != _NPOS) {
85       solnCntlVarType = currentVariables.
86 	all_discrete_string_variable_types()[solnCntlADVIndex];
87       if (find_index(currentVariables.discrete_string_variable_labels(),
88 	  control) != _NPOS) {
89 	Cerr << "Error: solution_level_control cannot be an active variable."
90 	     << std::endl;
91 	abort_handler(MODEL_ERROR);
92       }
93     }
94     else {
95       solnCntlADVIndex = find_index(
96 	currentVariables.all_discrete_real_variable_labels(), control);
97       if (solnCntlADVIndex != _NPOS) {
98 	solnCntlVarType = currentVariables.
99 	  all_discrete_real_variable_types()[solnCntlADVIndex];
100 	if (find_index(currentVariables.discrete_real_variable_labels(),
101 	    control) != _NPOS) {
102 	  Cerr << "Error: solution_level_control cannot be an active variable."
103 	       << std::endl;
104 	  abort_handler(MODEL_ERROR);
105 	}
106       }
107       else {
108 	Cerr << "Error: solution_level_control string identifier not found "
109 	     << "within discrete variable labels." << std::endl;
110 	abort_handler(MODEL_ERROR);
111       }
112     }
113   }
114 
115   // get size of corresponding set values
116   size_t i, num_lev;
117   std::shared_ptr<Pecos::MarginalsCorrDistribution> mvd_rep =
118     std::static_pointer_cast<Pecos::MarginalsCorrDistribution>
119     (mvDist.multivar_dist_rep());
120   const SharedVariablesData& svd = currentVariables.shared_data();
121   switch (solnCntlVarType) {
122   case DISCRETE_DESIGN_RANGE: case DISCRETE_INTERVAL_UNCERTAIN:
123   case DISCRETE_STATE_RANGE:
124     //solnCntlRVIndex = svd.adiv_index_to_all_index(solnCntlADVIndex);
125     num_lev =
126       userDefinedConstraints.all_discrete_int_upper_bounds()[solnCntlADVIndex] -
127       userDefinedConstraints.all_discrete_int_lower_bounds()[solnCntlADVIndex];
128     break;
129   case DISCRETE_DESIGN_SET_INT: case DISCRETE_STATE_SET_INT:
130     solnCntlRVIndex = svd.adiv_index_to_all_index(solnCntlADVIndex);
131     num_lev = mvd_rep->
132       pull_parameter_size<IntSet>(solnCntlRVIndex, Pecos::DSI_VALUES);
133     break;
134   case DISCRETE_DESIGN_SET_STRING: case DISCRETE_STATE_SET_STRING:
135     solnCntlRVIndex = svd.adsv_index_to_all_index(solnCntlADVIndex);
136     num_lev = mvd_rep->
137       pull_parameter_size<StringSet>(solnCntlRVIndex, Pecos::DSS_VALUES);
138     break;
139   case DISCRETE_DESIGN_SET_REAL: case DISCRETE_STATE_SET_REAL:
140     solnCntlRVIndex = svd.adrv_index_to_all_index(solnCntlADVIndex);
141     num_lev = mvd_rep->
142       pull_parameter_size<RealSet>(solnCntlRVIndex, Pecos::DSR_VALUES);
143     break;
144   case DISCRETE_UNCERTAIN_SET_INT:
145     solnCntlRVIndex = svd.adiv_index_to_all_index(solnCntlADVIndex);
146     num_lev = mvd_rep->
147       pull_parameter_size<IntRealMap>(solnCntlRVIndex,Pecos::DUSI_VALUES_PROBS);
148     break;
149   case DISCRETE_UNCERTAIN_SET_STRING:
150     solnCntlRVIndex = svd.adsv_index_to_all_index(solnCntlADVIndex);
151     num_lev = mvd_rep->
152       pull_parameter_size<StringRealMap>(solnCntlRVIndex,
153 					 Pecos::DUSS_VALUES_PROBS);
154     break;
155   case DISCRETE_UNCERTAIN_SET_REAL:
156     solnCntlRVIndex = svd.adrv_index_to_all_index(solnCntlADVIndex);
157     num_lev = mvd_rep->
158       pull_parameter_size<RealRealMap>(solnCntlRVIndex,
159 				       Pecos::DUSR_VALUES_PROBS);
160     break;
161   default:
162     Cerr << "Error: unsupported variable type in SimulationModel::"
163 	 << "initialize_solution_control" << std::endl;
164     abort_handler(MODEL_ERROR); break;
165   }
166 
167   // process cost array to create ordered map.
168   // Specified set values are sorted on input, but specified costs are not
169   // --> solnCntlCostMap sorts on cost key and maps to the unordered index
170   //     of these sorted values.
171   // > Example 1:
172   //     model simulation
173   //       solution_level_control = 'dssiv1'
174   //       solution_level_cost = 10. 2. 200.
175   //   results in solnCntlCostMap = { {2., 1}, {10., 0}, {200., 2} }
176   // > Example 2:
177   //     model simulation
178   //       solution_level_control = 'dssiv1'
179   //       solution_level_cost = 10. # scalar multiplier
180   // results in solnCntlCostMap = { {1., 0}, {10., 1}, {100., 2} }
181   if (cost.length() == num_lev)
182     for (i=0; i<num_lev; ++i)
183       solnCntlCostMap.insert(std::pair<Real, size_t>(cost[i], i));
184   else if (cost.length() == 1) {
185     Real multiplier = cost[0], prod = 1.;
186     for (i=0; i<num_lev; ++i) { // assume increasing cost
187       solnCntlCostMap.insert(std::pair<Real, size_t>(prod, i));
188       prod *= multiplier;
189     }
190   }
191   else {
192     Cerr << "Error: solution_level_cost specification of length "
193 	 << cost.length() << " provided;\n       expected scalar or vector "
194 	 << "of length " << num_lev << "." << std::endl;
195     abort_handler(MODEL_ERROR);
196   }
197 }
198 
199 
solution_level_index(unsigned short lev_index)200 /* Real */void SimulationModel::solution_level_index(unsigned short lev_index)
201 {
202   // incoming soln level index is an index into the ordered solnCntlCostMap,
203   // not to be confused with the value in the key-value pair that corresponds
204   // to the discrete variable value index (val_index below).
205   if (lev_index == USHRT_MAX) { // just return quietly to simplify calling code
206     return;                     // (rather than always checking index validity)
207 
208     //Cerr << "Error: USHRT_MAX passed to SimulationModel::"
209     //     << "solution_level_index()." << std::endl;
210     //abort_handler(MODEL_ERROR);
211   }
212 
213   std::map<Real, size_t>::const_iterator c_cit = solnCntlCostMap.begin();
214   std::advance(c_cit, lev_index);
215   size_t val_index = c_cit->second;
216 
217   std::shared_ptr<Pecos::MarginalsCorrDistribution> mvd_rep =
218     std::static_pointer_cast<Pecos::MarginalsCorrDistribution>
219     (mvDist.multivar_dist_rep());
220   switch (solnCntlVarType) {
221   case DISCRETE_DESIGN_RANGE: case DISCRETE_INTERVAL_UNCERTAIN:
222   case DISCRETE_STATE_RANGE: {
223     int val = val_index + userDefinedConstraints.
224       all_discrete_int_lower_bounds()[solnCntlADVIndex];
225     currentVariables.all_discrete_int_variable(val, solnCntlADVIndex);
226     break;
227   }
228   //////////////////////////////
229   case DISCRETE_DESIGN_SET_INT: case DISCRETE_STATE_SET_INT: {
230     IntSet is;
231     mvd_rep->pull_parameter<IntSet>(solnCntlRVIndex, Pecos::DSI_VALUES, is);
232     ISIter is_it = is.begin();  std::advance(is_it, val_index);
233     currentVariables.all_discrete_int_variable(*is_it, solnCntlADVIndex);
234     break;
235   }
236   case DISCRETE_DESIGN_SET_STRING: case DISCRETE_STATE_SET_STRING: {
237     StringSet ss;
238     mvd_rep->pull_parameter<StringSet>(solnCntlRVIndex, Pecos::DSS_VALUES, ss);
239     SSCIter ss_it = ss.begin();  std::advance(ss_it, val_index);
240     currentVariables.all_discrete_string_variable(*ss_it, solnCntlADVIndex);
241     break;
242   }
243   case DISCRETE_DESIGN_SET_REAL: case DISCRETE_STATE_SET_REAL: {
244     RealSet rs;
245     mvd_rep->pull_parameter<RealSet>(solnCntlRVIndex, Pecos::DSR_VALUES, rs);
246     RSIter rs_it = rs.begin();  std::advance(rs_it, val_index);
247     currentVariables.all_discrete_real_variable(*rs_it, solnCntlADVIndex);
248     break;
249   }
250   //////////////////////////////
251   case DISCRETE_UNCERTAIN_SET_INT: {
252     IntRealMap irm;
253     mvd_rep->pull_parameter<IntRealMap>(solnCntlRVIndex,
254 					Pecos::DUSI_VALUES_PROBS, irm);
255     IRMIter ir_it = irm.begin();  std::advance(ir_it, val_index);
256     currentVariables.all_discrete_int_variable(ir_it->first, solnCntlADVIndex);
257     break;
258   }
259   case DISCRETE_UNCERTAIN_SET_STRING: {
260     StringRealMap srm;
261     mvd_rep->pull_parameter<StringRealMap>(solnCntlRVIndex,
262 					   Pecos::DUSS_VALUES_PROBS, srm);
263     SRMIter sr_it = srm.begin();  std::advance(sr_it, val_index);
264     currentVariables.all_discrete_string_variable(sr_it->first,
265 						  solnCntlADVIndex);
266     break;
267   }
268   case DISCRETE_UNCERTAIN_SET_REAL: {
269     RealRealMap rrm;
270     mvd_rep->pull_parameter<RealRealMap>(solnCntlRVIndex,
271 					 Pecos::DUSR_VALUES_PROBS, rrm);
272     RRMIter rr_it = rrm.begin();  std::advance(rr_it, val_index);
273     currentVariables.all_discrete_real_variable(rr_it->first, solnCntlADVIndex);
274     break;
275   }
276   }
277 
278   //return c_cit->first; // cost estimate for this solution level index
279 }
280 
281 
solution_level_index() const282 unsigned short SimulationModel::solution_level_index() const
283 {
284   size_t val_index;
285   std::shared_ptr<Pecos::MarginalsCorrDistribution> mvd_rep =
286     std::static_pointer_cast<Pecos::MarginalsCorrDistribution>
287     (mvDist.multivar_dist_rep());
288   switch (solnCntlVarType) {
289   case DISCRETE_DESIGN_RANGE: case DISCRETE_INTERVAL_UNCERTAIN:
290   case DISCRETE_STATE_RANGE: {
291     int val = currentVariables.all_discrete_int_variables()[solnCntlADVIndex],
292       l_bnd = userDefinedConstraints.all_discrete_int_lower_bounds()
293         [solnCntlADVIndex];
294     val_index = (size_t)(val - l_bnd);
295     break;
296   }
297   //////////////////////////////
298   case DISCRETE_DESIGN_SET_INT: case DISCRETE_STATE_SET_INT: {
299     IntSet is;
300     mvd_rep->pull_parameter<IntSet>(solnCntlRVIndex, Pecos::DSI_VALUES, is);
301     val_index = set_value_to_index(
302       currentVariables.all_discrete_int_variables()[solnCntlADVIndex], is);
303     break;
304   }
305   case DISCRETE_DESIGN_SET_STRING: case DISCRETE_STATE_SET_STRING: {
306     StringSet ss;
307     mvd_rep->pull_parameter<StringSet>(solnCntlRVIndex, Pecos::DSS_VALUES, ss);
308     val_index = set_value_to_index(
309       currentVariables.all_discrete_string_variables()[solnCntlADVIndex], ss);
310     break;
311   }
312   case DISCRETE_DESIGN_SET_REAL: case DISCRETE_STATE_SET_REAL: {
313     RealSet rs;
314     mvd_rep->pull_parameter<RealSet>(solnCntlRVIndex, Pecos::DSR_VALUES, rs);
315     val_index = set_value_to_index(
316       currentVariables.all_discrete_real_variables()[solnCntlADVIndex], rs);
317     break;
318   }
319   //////////////////////////////
320   case DISCRETE_UNCERTAIN_SET_INT: {
321     IntRealMap irm;
322     mvd_rep->pull_parameter<IntRealMap>(solnCntlRVIndex,
323 					Pecos::DUSI_VALUES_PROBS, irm);
324     val_index = map_key_to_index(
325       currentVariables.all_discrete_int_variables()[solnCntlADVIndex], irm);
326     break;
327   }
328   case DISCRETE_UNCERTAIN_SET_STRING: {
329     StringRealMap srm;
330     mvd_rep->pull_parameter<StringRealMap>(solnCntlRVIndex,
331 					   Pecos::DUSS_VALUES_PROBS, srm);
332     val_index = map_key_to_index(
333       currentVariables.all_discrete_string_variables()[solnCntlADVIndex], srm);
334     break;
335   }
336   case DISCRETE_UNCERTAIN_SET_REAL: {
337     RealRealMap rrm;
338     mvd_rep->pull_parameter<RealRealMap>(solnCntlRVIndex,
339 					 Pecos::DUSR_VALUES_PROBS, rrm);
340     val_index = map_key_to_index(
341       currentVariables.all_discrete_real_variables()[solnCntlADVIndex], rrm);
342     break;
343   }
344   //////////////////////////////
345   default: // EMPTY_TYPE (no solution_level_control provided)
346     return USHRT_MAX; break;
347   }
348 
349   // convert val_index to lev_index and return
350   size_t lev_index = map_value_to_index(val_index, solnCntlCostMap);
351   return (lev_index == _NPOS) ? USHRT_MAX : (unsigned short)lev_index;
352 }
353 
354 
solution_level_costs() const355 RealVector SimulationModel::solution_level_costs() const
356 {
357   RealVector cost_levels(solnCntlCostMap.size(), false);
358   std::map<Real, size_t>::const_iterator cit; size_t i;
359   for (cit=solnCntlCostMap.begin(), i=0; cit!=solnCntlCostMap.end(); ++cit, ++i)
360     cost_levels[i] = cit->first;
361   return cost_levels;
362 }
363 
364 
solution_level_cost() const365 Real SimulationModel::solution_level_cost() const
366 {
367   std::map<Real, size_t>::const_iterator cit = solnCntlCostMap.begin();
368   if (cit == solnCntlCostMap.end()) return 0.;
369   else {
370     unsigned short lev_index = solution_level_index();
371     if (lev_index != USHRT_MAX)
372       std::advance(cit, lev_index);
373     return cit->first;
374   }
375 }
376 
377 
378 /*
379 void SimulationModel::component_parallel_mode(short mode)
380 {
381   if (mode != INTERFACE_MODE) {
382     Cerr << "Error: SimulationModel only supports the INTERFACE_MODE component "
383 	 << "parallel mode." << std::endl;
384     abort_handler(MODEL_ERROR);
385   }
386   parallelLib.parallel_configuration_iterator(modelPCIter);
387   //componentParallelMode = mode;
388 }
389 */
390 
391 
392 /** SimulationModel doesn't need to change the tagging, so just forward to
393     Interface */
eval_tag_prefix(const String & eval_id_str)394 void SimulationModel::eval_tag_prefix(const String& eval_id_str)
395 {
396   // Simulation model uses the counter from the interface
397   bool append_iface_id = true;
398   userDefinedInterface.eval_tag_prefix(eval_id_str, append_iface_id);
399 }
400 
401 /*ActiveSet SimulationModel::default_active_set() {
402   ActiveSet set(numFns, numDerivVars);
403   ShortArray asv(numFns, 1);
404 
405   if(gradientType != "none" && (gradientType == "analytic" || supportsEstimDerivs))
406       for(auto &a : asv)
407         a |=  2;
408 
409   if(hessianType != "none" && (hessianType == "analytic" || supportsEstimDerivs))
410       for(auto &a : asv)
411         a |=  4;
412 
413   set.request_vector(asv);
414   return set;
415 }
416 */
default_interface_active_set()417 ActiveSet SimulationModel::default_interface_active_set() {
418   // compute the default active set for the user-defined interface
419   ActiveSet set;
420   set.derivative_vector(currentVariables.all_continuous_variable_ids());
421   bool has_deriv_vars = set.derivative_vector().size() != 0;
422   ShortArray asv(numFns, 1);
423   if(has_deriv_vars) {
424     if(gradientType == "analytic") {
425       for(auto &a : asv)
426         a |=  2;
427     } else if(gradientType == "mixed") {
428       for(const auto &gi : gradIdAnalytic)
429         asv[gi-1] |= 2;
430     }
431 
432     if(hessianType == "analytic") {
433       for(auto &a : asv)
434         a |=  4;
435     } else if(hessianType == "mixed") {
436       for(const auto &hi : hessIdAnalytic)
437         asv[hi-1] |= 4;
438     }
439   }
440   set.request_vector(asv);
441   return set;
442 }
443 
declare_sources()444 void SimulationModel::declare_sources() {
445   evaluationsDB.declare_source(modelId, modelType, interface_id(), "interface");
446 }
447 } // namespace Dakota
448