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: RecastModel
10 //- Description: Implementation code for the RecastModel class
11 //- Owner: Mike Eldred
12 //- Checked by:
13
14 #include "dakota_system_defs.hpp"
15 #include "RecastModel.hpp"
16 #include "EvaluationStore.hpp"
17
18 static const char rcsId[]="@(#) $Id: RecastModel.cpp 7029 2010-10-22 00:17:02Z mseldre $";
19
20
21 using namespace std;
22
23 namespace Dakota {
24
25 //#define DEBUG
26
27 // init static var
28 StringStringPairIntMap RecastModel::recastModelIdCounters;
29
30
31 /** Default recast model constructor. Requires full definition of the
32 transformation; if any mappings are NULL, they are assumed to
33 remain so in later initialization or updates. Parameter
34 vars_comps_totals indicates the number of each type of variable {4
35 types} x {3 domains} in the recast variable space. Note:
36 recast_secondary_offset is the start index for equality
37 constraints, typically num nonlinear ineq constraints. */
38 RecastModel::
RecastModel(const Model & sub_model,const Sizet2DArray & vars_map_indices,const SizetArray & vars_comps_totals,const BitArray & all_relax_di,const BitArray & all_relax_dr,bool nonlinear_vars_mapping,void (* variables_map)(const Variables & recast_vars,Variables & sub_model_vars),void (* set_map)(const Variables & recast_vars,const ActiveSet & recast_set,ActiveSet & sub_model_set),const Sizet2DArray & primary_resp_map_indices,const Sizet2DArray & secondary_resp_map_indices,size_t recast_secondary_offset,short recast_resp_order,const BoolDequeArray & nonlinear_resp_mapping,void (* primary_resp_map)(const Variables & sub_model_vars,const Variables & recast_vars,const Response & sub_model_response,Response & recast_response),void (* secondary_resp_map)(const Variables & sub_model_vars,const Variables & recast_vars,const Response & sub_model_response,Response & recast_response))39 RecastModel(const Model& sub_model, const Sizet2DArray& vars_map_indices,
40 const SizetArray& vars_comps_totals, const BitArray& all_relax_di,
41 const BitArray& all_relax_dr, bool nonlinear_vars_mapping,
42 void (*variables_map) (const Variables& recast_vars,
43 Variables& sub_model_vars),
44 void (*set_map) (const Variables& recast_vars,
45 const ActiveSet& recast_set,
46 ActiveSet& sub_model_set),
47 const Sizet2DArray& primary_resp_map_indices,
48 const Sizet2DArray& secondary_resp_map_indices,
49 size_t recast_secondary_offset, short recast_resp_order,
50 const BoolDequeArray& nonlinear_resp_mapping,
51 void (*primary_resp_map) (const Variables& sub_model_vars,
52 const Variables& recast_vars,
53 const Response& sub_model_response,
54 Response& recast_response),
55 void (*secondary_resp_map) (const Variables& sub_model_vars,
56 const Variables& recast_vars,
57 const Response& sub_model_response,
58 Response& recast_response)):
59 Model(LightWtBaseConstructor(), sub_model.problem_description_db(),
60 sub_model.parallel_library()),
61 subModel(sub_model), varsMapIndices(vars_map_indices),
62 nonlinearVarsMapping(nonlinear_vars_mapping),
63 primaryRespMapIndices(primary_resp_map_indices),
64 secondaryRespMapIndices(secondary_resp_map_indices),
65 nonlinearRespMapping(nonlinear_resp_mapping), recastModelEvalCntr(0),
66 variablesMapping(variables_map), setMapping(set_map),
67 primaryRespMapping(primary_resp_map),
68 secondaryRespMapping(secondary_resp_map), invVarsMapping(NULL),
69 invSetMapping(NULL), invPriRespMapping(NULL), invSecRespMapping(NULL)
70 {
71 modelType = "recast";
72 supportsEstimDerivs = false; // subModel estimates derivatives by default
73
74 // synchronize output level and grad/Hess settings with subModel
75 initialize_data_from_submodel();
76
77 // recasting of variables; only reshape if change in variable type counts
78 bool reshape_vars = false;
79 if (variablesMapping) {
80 // reshape as dictated by variable type changes
81 reshape_vars =
82 init_variables(vars_comps_totals, all_relax_di, all_relax_dr);
83 }
84 else {
85 // variables are not mapped: deep copy of vars to allow independence, but
86 // shallow copy of svd since types/labels/ids can be kept consistent
87 currentVariables = subModel.current_variables().copy(); // shared svd
88 numDerivVars = currentVariables.cv();
89 }
90
91 if (nonlinearRespMapping.size() !=
92 primaryRespMapIndices.size() + secondaryRespMapIndices.size()) {
93 Cerr << "Error: size mismatch in response mapping configuration." << endl;
94 abort_handler(-1);
95 }
96
97 if (primaryRespMapping || secondaryRespMapping) {
98 init_response(primaryRespMapIndices.size(), secondaryRespMapIndices.size(),
99 recast_resp_order, reshape_vars);
100 }
101 else {
102 currentResponse = subModel.current_response().copy();
103 numFns = currentResponse.num_functions();
104 }
105
106 init_constraints(secondaryRespMapIndices.size(),
107 recast_secondary_offset, reshape_vars);
108
109 modelId = RecastModel::recast_model_id(root_model_id(), "RECAST");
110 }
111
112
113 /** This alternate constructor defers initialization of the function
114 pointers until a separate call to initialize(), and accepts the
115 minimum information needed to construct currentVariables,
116 currentResponse, and userDefinedConstraints. The resulting model
117 is sufficiently complete for passing to an Iterator. Parameter
118 vars_comps_totals indicates the number of each type of variable {4
119 types} x {3 domains} in the recast variable space. Note:
120 recast_secondary_offset is the start index for equality
121 constraints, typically num nonlinear ineq constraints. */
122 RecastModel::
RecastModel(const Model & sub_model,const SizetArray & vars_comps_totals,const BitArray & all_relax_di,const BitArray & all_relax_dr,size_t num_recast_primary_fns,size_t num_recast_secondary_fns,size_t recast_secondary_offset,short recast_resp_order)123 RecastModel(const Model& sub_model, //size_t num_deriv_vars,
124 const SizetArray& vars_comps_totals, const BitArray& all_relax_di,
125 const BitArray& all_relax_dr, size_t num_recast_primary_fns,
126 size_t num_recast_secondary_fns, size_t recast_secondary_offset,
127 short recast_resp_order):
128 Model(LightWtBaseConstructor(), sub_model.problem_description_db(),
129 sub_model.parallel_library()),
130 subModel(sub_model), nonlinearVarsMapping(false), recastModelEvalCntr(0),
131 variablesMapping(NULL), setMapping(NULL), primaryRespMapping(NULL),
132 secondaryRespMapping(NULL), invVarsMapping(NULL), invSetMapping(NULL),
133 invPriRespMapping(NULL), invSecRespMapping(NULL)
134 {
135 modelType = "recast";
136 supportsEstimDerivs = false; // subModel estimates derivatives by default
137
138 // synchronize output level and grad/Hess settings with subModel
139 initialize_data_from_submodel();
140
141 // initialize Variables, Response, and Constraints based on sizes
142 init_sizes(vars_comps_totals, all_relax_di, all_relax_dr,
143 num_recast_primary_fns, num_recast_secondary_fns,
144 recast_secondary_offset, recast_resp_order);
145 modelId = RecastModel::recast_model_id(root_model_id(), "RECAST");
146 }
147
148
RecastModel(ProblemDescDB & problem_db,const Model & sub_model)149 RecastModel::RecastModel(ProblemDescDB& problem_db, const Model& sub_model):
150 Model(BaseConstructor(), problem_db), subModel(sub_model),
151 recastModelEvalCntr(0), variablesMapping(NULL), setMapping(NULL),
152 primaryRespMapping(NULL), secondaryRespMapping(NULL), invVarsMapping(NULL),
153 invSetMapping(NULL), invPriRespMapping(NULL), invSecRespMapping(NULL)
154 {
155 modelType = "recast";
156 supportsEstimDerivs = false; // subModel estimates derivatives by default
157
158 // synchronize output level and grad/Hess settings with subModel
159 initialize_data_from_submodel();
160 modelId = RecastModel::recast_model_id(root_model_id(), "RECAST");
161 }
162
163
RecastModel(const Model & sub_model)164 RecastModel::RecastModel(const Model& sub_model):
165 Model(LightWtBaseConstructor(), sub_model.problem_description_db(),
166 sub_model.parallel_library()),
167 subModel(sub_model), recastModelEvalCntr(0), variablesMapping(NULL),
168 setMapping(NULL), primaryRespMapping(NULL), secondaryRespMapping(NULL),
169 invVarsMapping(NULL), invSetMapping(NULL), invPriRespMapping(NULL),
170 invSecRespMapping(NULL)
171 {
172 modelType = "recast";
173 supportsEstimDerivs = false; // subModel estimates derivatives by default
174
175 // synchronize output level and grad/Hess settings with subModel
176 initialize_data_from_submodel();
177 numFns = sub_model.response_size();
178 modelId = RecastModel::recast_model_id(root_model_id(), "RECAST");
179 }
180
181
182 void RecastModel::
init_sizes(const SizetArray & vars_comps_totals,const BitArray & all_relax_di,const BitArray & all_relax_dr,size_t num_recast_primary_fns,size_t num_recast_secondary_fns,size_t recast_secondary_offset,short recast_resp_order)183 init_sizes(const SizetArray& vars_comps_totals, const BitArray& all_relax_di,
184 const BitArray& all_relax_dr, size_t num_recast_primary_fns,
185 size_t num_recast_secondary_fns, size_t recast_secondary_offset,
186 short recast_resp_order)
187 {
188 // recasting of variables; only reshape if change in variable type counts
189 bool reshape_vars =
190 init_variables(vars_comps_totals, all_relax_di, all_relax_dr);
191
192 // Currently this reshape is subspace-specific and handled in derived classes
193 //if (reshape_vars) // else full-space initialization is sufficient
194 // init_distribution(rv_types, vars_comps_totals); // reshape mvDist
195
196 // recasting of response and constraints
197 init_response(num_recast_primary_fns, num_recast_secondary_fns,
198 recast_resp_order, reshape_vars);
199
200 init_constraints(num_recast_secondary_fns,
201 recast_secondary_offset, reshape_vars);
202 }
203
204
205 /** This function is used for late initialization of the recasting
206 functions. It is used in concert with the alternate constructor. */
207 void RecastModel::
init_maps(const Sizet2DArray & vars_map_indices,bool nonlinear_vars_mapping,void (* variables_map)(const Variables & recast_vars,Variables & sub_model_vars),void (* set_map)(const Variables & recast_vars,const ActiveSet & recast_set,ActiveSet & sub_model_set),const Sizet2DArray & primary_resp_map_indices,const Sizet2DArray & secondary_resp_map_indices,const BoolDequeArray & nonlinear_resp_mapping,void (* primary_resp_map)(const Variables & sub_model_vars,const Variables & recast_vars,const Response & sub_model_response,Response & recast_response),void (* secondary_resp_map)(const Variables & sub_model_vars,const Variables & recast_vars,const Response & sub_model_response,Response & recast_response))208 init_maps(const Sizet2DArray& vars_map_indices,
209 bool nonlinear_vars_mapping,
210 void (*variables_map) (const Variables& recast_vars,
211 Variables& sub_model_vars),
212 void (*set_map) (const Variables& recast_vars,
213 const ActiveSet& recast_set,
214 ActiveSet& sub_model_set),
215 const Sizet2DArray& primary_resp_map_indices,
216 const Sizet2DArray& secondary_resp_map_indices,
217 const BoolDequeArray& nonlinear_resp_mapping,
218 void (*primary_resp_map) (const Variables& sub_model_vars,
219 const Variables& recast_vars,
220 const Response& sub_model_response,
221 Response& recast_response),
222 void (*secondary_resp_map) (const Variables& sub_model_vars,
223 const Variables& recast_vars,
224 const Response& sub_model_response,
225 Response& recast_response))
226 {
227 varsMapIndices = vars_map_indices;
228 nonlinearVarsMapping = nonlinear_vars_mapping;
229 variablesMapping = variables_map;
230 setMapping = set_map;
231 primaryRespMapIndices = primary_resp_map_indices;
232 secondaryRespMapIndices = secondary_resp_map_indices;
233 nonlinearRespMapping = nonlinear_resp_mapping;
234 primaryRespMapping = primary_resp_map;
235 secondaryRespMapping = secondary_resp_map;
236
237 if (nonlinearRespMapping.size() != primaryRespMapIndices.size() +
238 secondaryRespMapIndices.size()) {
239 Cerr << "Error: size mismatch in response mapping configuration." << endl;
240 abort_handler(-1);
241 }
242 }
243
244
response_order(const Model & sub_model)245 short RecastModel::response_order(const Model& sub_model)
246 {
247 const Response& curr_resp = sub_model.current_response();
248
249 short recast_resp_order = 1; // recast resp order to be same as original resp
250 if (!curr_resp.function_gradients().empty()) recast_resp_order |= 2;
251 if (!curr_resp.function_hessians().empty()) recast_resp_order |= 4;
252
253 return recast_resp_order;
254 }
255
256
recast_model_id(const String & root_id,const String & type)257 String RecastModel::recast_model_id(const String &root_id, const String &type) {
258 auto key = std::make_pair(root_id, type);
259 int id;
260 if(recastModelIdCounters.find(key) == recastModelIdCounters.end())
261 recastModelIdCounters[key] = id = 1;
262 else
263 id = ++recastModelIdCounters[key];
264 return String("RECAST_") + root_id + "_" + type + "_" + std::to_string(id);
265 }
266
267
268 bool RecastModel::
init_variables(const SizetArray & vars_comps_totals,const BitArray & all_relax_di,const BitArray & all_relax_dr)269 init_variables(const SizetArray& vars_comps_totals,
270 const BitArray& all_relax_di, const BitArray& all_relax_dr)
271 {
272 const Variables& sub_model_vars = subModel.current_variables();
273 const SharedVariablesData& svd = sub_model_vars.shared_data();
274
275 // BMA: We actually don't allow the case of a change in
276 // vars_comp_totals, but no mapping, but have to allow it here in
277 // case mapping not yet provided.
278
279 // if any change in variable types, will need a new SharedVariablesData
280 bool vars_char_same =
281 ( vars_comps_totals.empty() ||
282 svd.components_totals() == vars_comps_totals ) &&
283 ( all_relax_di.empty() ||
284 svd.all_relaxed_discrete_int() == all_relax_di ) &&
285 ( all_relax_dr.empty() ||
286 svd.all_relaxed_discrete_real() == all_relax_dr );
287
288 // check change in character first as mapping may not yet be present...
289 if (vars_char_same) {
290 // variables are mapped but not resized: deep copy of vars and
291 // same svd, since types may change in transformed space
292 currentVariables = sub_model_vars.copy(true); // independent svd
293 }
294 else {
295 // variables are resized; need new SVD regardless
296 SharedVariablesData recast_svd(sub_model_vars.view(), vars_comps_totals,
297 all_relax_di, all_relax_dr);
298 currentVariables = Variables(recast_svd);
299 }
300
301 // propagate number of active continuous vars to derivative vars
302 numDerivVars = currentVariables.cv();
303
304 return !vars_char_same; // return reshape_vars
305 }
306
307
308 void RecastModel::
init_response(size_t num_recast_primary_fns,size_t num_recast_secondary_fns,short recast_resp_order,bool reshape_vars)309 init_response(size_t num_recast_primary_fns, size_t num_recast_secondary_fns,
310 short recast_resp_order, bool reshape_vars)
311 {
312 numFns = num_recast_primary_fns + num_recast_secondary_fns;
313
314 // recasting of response
315 const Response& sub_model_resp = subModel.current_response();
316 currentResponse = sub_model_resp.copy();
317
318 bool grad_flag = (recast_resp_order & 2),
319 hess_flag = (recast_resp_order & 4),
320 sm_grad_flag = !sub_model_resp.function_gradients().empty(),
321 sm_hess_flag = !sub_model_resp.function_hessians().empty();
322 const Variables& sub_model_vars = subModel.current_variables();
323 if ( sub_model_vars.cv() != numDerivVars ||
324 sub_model_resp.num_functions() != numFns ||
325 grad_flag != sm_grad_flag || hess_flag != sm_hess_flag )
326 currentResponse.reshape(numFns, numDerivVars, grad_flag, hess_flag);
327 }
328
329
330 void RecastModel::
reshape_response(size_t num_recast_primary_fns,size_t num_recast_secondary_fns)331 reshape_response(size_t num_recast_primary_fns, size_t num_recast_secondary_fns)
332 {
333 numFns = num_recast_primary_fns + num_recast_secondary_fns;
334 bool grad_flag = !currentResponse.function_gradients().empty();
335 bool hess_flag = !currentResponse.function_hessians().empty();
336
337 currentResponse.reshape(numFns, numDerivVars, grad_flag, hess_flag);
338 }
339
340
341 void RecastModel::
init_constraints(size_t num_recast_secondary_fns,size_t recast_secondary_offset,bool reshape_vars)342 init_constraints(size_t num_recast_secondary_fns,
343 size_t recast_secondary_offset, bool reshape_vars)
344 {
345 // recasting of constraints
346 SharedVariablesData recast_svd = currentVariables.shared_data();
347 const Constraints& sub_model_cons = subModel.user_defined_constraints();
348 userDefinedConstraints = (reshape_vars) ?
349 Constraints(recast_svd) : sub_model_cons.copy();
350
351 // the recast_secondary_offset cannot in general be inferred from the
352 // contributing fns in secondaryRespMapIndices (recast constraints may be
353 // defined, e.g., with no contributing fns), and must therefore be passed.
354 size_t num_recast_nln_ineq = recast_secondary_offset,
355 num_recast_nln_eq = num_recast_secondary_fns - num_recast_nln_ineq;
356 if ( num_recast_nln_ineq != sub_model_cons.num_nonlinear_ineq_constraints()
357 || num_recast_nln_eq != sub_model_cons.num_nonlinear_eq_constraints() )
358 userDefinedConstraints.reshape(num_recast_nln_ineq, num_recast_nln_eq,
359 sub_model_cons.num_linear_ineq_constraints(),
360 sub_model_cons.num_linear_eq_constraints());
361 }
362
363
inverse_mappings(void (* inv_vars_map)(const Variables & recast_vars,Variables & sub_model_vars),void (* inv_set_map)(const Variables & recast_vars,const ActiveSet & recast_set,ActiveSet & sub_model_set),void (* inv_pri_resp_map)(const Variables & sub_model_vars,const Variables & recast_vars,const Response & sub_model_resp,Response & recast_resp),void (* inv_sec_resp_map)(const Variables & sub_model_vars,const Variables & recast_vars,const Response & sub_model_resp,Response & recast_resp))364 void RecastModel::inverse_mappings(
365 void (*inv_vars_map) (const Variables& recast_vars,
366 Variables& sub_model_vars),
367 void (*inv_set_map) (const Variables& recast_vars,
368 const ActiveSet& recast_set,
369 ActiveSet& sub_model_set),
370 void (*inv_pri_resp_map) (const Variables& sub_model_vars,
371 const Variables& recast_vars,
372 const Response& sub_model_resp,
373 Response& recast_resp),
374 void (*inv_sec_resp_map) (const Variables& sub_model_vars,
375 const Variables& recast_vars,
376 const Response& sub_model_resp,
377 Response& recast_resp))
378 {
379 invVarsMapping = inv_vars_map; invSetMapping = inv_set_map;
380 invPriRespMapping = inv_pri_resp_map; invSecRespMapping = inv_sec_resp_map;
381 }
382
383
384 /** The RecastModel is evaluated by an Iterator for a recast problem
385 formulation. Therefore, the currentVariables, incoming active set,
386 and output currentResponse all correspond to the recast inputs/outputs. */
derived_evaluate(const ActiveSet & set)387 void RecastModel::derived_evaluate(const ActiveSet& set)
388 {
389 ++recastModelEvalCntr;
390
391 // transform from recast (Iterator) to sub-model (user) variables
392 transform_variables(currentVariables, subModel.current_variables());
393
394 // the incoming set is for the recast problem, which must be converted
395 // back to the underlying response set for evaluation by the subModel.
396 ActiveSet sub_model_set;
397 transform_set(currentVariables, set, sub_model_set);
398
399 // evaluate the subModel in the original fn set definition. Doing this here
400 // eliminates the need for eval tracking logic within the separate eval fns.
401 subModel.evaluate(sub_model_set);
402
403 // recast the subModel response ("user space") into the currentResponse
404 // ("iterator space")
405 currentResponse.active_set(set);
406 if (primaryRespMapping || secondaryRespMapping)
407 transform_response(currentVariables, subModel.current_variables(),
408 subModel.current_response(), currentResponse);
409 else
410 currentResponse.update(subModel.current_response());
411
412 #ifdef DEBUG
413 Cout << "Recast variables:\n" << currentVariables
414 << "subModel variables:\n" << subModel.current_variables()
415 << "subModel response:\n" << subModel.current_response()
416 << "Recast response:\n" << currentResponse;
417 #endif
418 }
419
420
derived_evaluate_nowait(const ActiveSet & set)421 void RecastModel::derived_evaluate_nowait(const ActiveSet& set)
422 {
423 ++recastModelEvalCntr;
424
425 // transform from recast (Iterator) to sub-model (user) variables
426 transform_variables(currentVariables, subModel.current_variables());
427
428 // the incoming set is for the recast problem, which must be converted
429 // back to the underlying response set for evaluation by the subModel.
430 ActiveSet sub_model_set;
431 transform_set(currentVariables, set, sub_model_set);
432
433 // evaluate the subModel in the original fn set definition. Doing this here
434 // eliminates the need for eval tracking logic within the separate eval fns.
435 subModel.evaluate_nowait(sub_model_set);
436 // in almost all cases, use of the subModel eval ids is sufficient, but
437 // protect against the rare case where not all subModel evaluations being
438 // scheduled were spawned from the RecastModel (e.g., a HierarchicalModel
439 // that uses an ActiveSubspaceModel as LF and the original model as HF).
440 recastIdMap[subModel.evaluation_id()] = recastModelEvalCntr;
441
442 // bookkeep variables for use in primaryRespMapping/secondaryRespMapping
443 if (primaryRespMapping || secondaryRespMapping) {
444 recastSetMap[recastModelEvalCntr] = set;
445 recastVarsMap[recastModelEvalCntr] = currentVariables.copy();
446 if (variablesMapping)
447 subModelVarsMap[recastModelEvalCntr]
448 = subModel.current_variables().copy();
449 }
450 }
451
452
derived_synchronize()453 const IntResponseMap& RecastModel::derived_synchronize()
454 {
455 recastResponseMap.clear();
456
457 if (primaryRespMapping || secondaryRespMapping) {
458 IntResponseMap resp_map_rekey;
459 rekey_synch(subModel, true, recastIdMap, resp_map_rekey);
460 transform_response_map(resp_map_rekey, recastResponseMap);
461 }
462 else
463 rekey_synch(subModel, true, recastIdMap, recastResponseMap);
464
465 return recastResponseMap;
466 }
467
468
derived_synchronize_nowait()469 const IntResponseMap& RecastModel::derived_synchronize_nowait()
470 {
471 recastResponseMap.clear();
472
473 if (primaryRespMapping || secondaryRespMapping) {
474 IntResponseMap resp_map_rekey;
475 rekey_synch(subModel, false, recastIdMap, resp_map_rekey);
476 transform_response_map(resp_map_rekey, recastResponseMap);
477 }
478 else
479 rekey_synch(subModel, false, recastIdMap, recastResponseMap);
480
481 return recastResponseMap;
482 }
483
484
485 void RecastModel::
transform_response_map(const IntResponseMap & old_resp_map,IntResponseMap & new_resp_map)486 transform_response_map(const IntResponseMap& old_resp_map,
487 IntResponseMap& new_resp_map)
488 {
489 IntRespMCIter r_cit; IntASMIter s_it; IntVarsMIter v_it, sm_v_it;
490 for (r_cit=old_resp_map.begin(); r_cit!=old_resp_map.end(); ++r_cit) {
491 int native_id = r_cit->first;
492 s_it = recastSetMap.find(native_id);
493 v_it = recastVarsMap.find(native_id);
494 if (variablesMapping) sm_v_it = subModelVarsMap.find(native_id);
495 else sm_v_it = v_it;
496
497 Response new_resp(currentResponse.copy()); // correct size, labels, etc.
498 new_resp.active_set(s_it->second);
499 transform_response(v_it->second, sm_v_it->second, r_cit->second, new_resp);
500 new_resp_map[native_id] = new_resp;
501
502 // cleanup
503 recastSetMap.erase(s_it); recastVarsMap.erase(v_it);
504 if (variablesMapping) subModelVarsMap.erase(sm_v_it);
505 }
506 }
507
508
509 void RecastModel::
transform_variables(const Variables & recast_vars,Variables & sub_model_vars)510 transform_variables(const Variables& recast_vars, Variables& sub_model_vars)
511 {
512 // typical flow: mapping from recast variables ("iterator space")
513 // into the sub-model variables ("user space")
514 if (variablesMapping) {
515 assign_instance();
516 variablesMapping(recast_vars, sub_model_vars);
517 }
518 else
519 sub_model_vars.active_variables(recast_vars);
520 }
521
522
523 void RecastModel::
inverse_transform_variables(const Variables & sub_model_vars,Variables & recast_vars)524 inverse_transform_variables(const Variables& sub_model_vars,
525 Variables& recast_vars)
526 {
527 // atypical flow: mapping from sub-model variables ("user space")
528 // into the recast variables ("iterator space")
529 if (invVarsMapping) {
530 assign_instance();
531 invVarsMapping(sub_model_vars, recast_vars);
532 }
533 else
534 recast_vars.active_variables(sub_model_vars);
535 }
536
537
538 void RecastModel::
transform_set(const Variables & recast_vars,const ActiveSet & recast_set,ActiveSet & sub_model_set)539 transform_set(const Variables& recast_vars, const ActiveSet& recast_set,
540 ActiveSet& sub_model_set)
541 {
542 // typical flow: mapping from recast set ("iterator space") into the
543 // sub-model set ("user space")
544
545 size_t i, j, num_recast_primary_fns = primaryRespMapIndices.size(),
546 num_recast_secondary_fns = secondaryRespMapIndices.size(),
547 num_recast_fns = num_recast_primary_fns + num_recast_secondary_fns;
548 const ShortArray& recast_asv = recast_set.request_vector();
549 if (recast_asv.size() != num_recast_fns) {
550 Cerr << "Error: inconsistent asv sizing in RecastModel::transform_set().\n"
551 << " recast asv size = " << recast_asv.size() << '\n'
552 << " recast functions = " << num_recast_fns << endl;
553 abort_handler(-1);
554 }
555
556 // Define default request vector and derivative vector mappings:
557 // For the ASV, project each recast_asv request onto the contributing
558 // set of functions within the sub_model_asv. In the case of nonlinear
559 // input/output mappings, the recast_asv request is augmented with
560 // additional data requirements derived from chain rule differentiation.
561 // The default sub-model DVV is just a copy of the recast DVV.
562 ShortArray sub_model_asv(subModel.response_size(), 0);
563 for (i=0; i<num_recast_fns; i++) {
564 short asv_val = recast_asv[i];
565 // For nonlinear variable mappings, gradient required to transform Hessian.
566 // A single nonlinear variable mapping affects all function derivatives.
567 if (nonlinearVarsMapping && (asv_val & 4))
568 asv_val |= 2;
569 // assign the asv_val to each contributing sub-model function
570 const SizetArray& recast_fn_contributors = (i<num_recast_primary_fns) ?
571 primaryRespMapIndices[i] :
572 secondaryRespMapIndices[i-num_recast_primary_fns];
573 size_t num_contributors = recast_fn_contributors.size();
574 for (j=0; j<num_contributors; j++) {
575 short sub_model_asv_val = asv_val;
576 // Bit deletions: for NLS recasting for full Newton without LeastSq term
577 // Hessians, could remove 4 bit based on {gradient,hessian}Type, but this
578 // is better accomplished from an Iterator's configuration using the
579 // setMapping plug-in below (e.g., see Optimizer::gnewton_set_recast()).
580
581 // Bit additions: for nonlinear resp mappings, derivatives require all
582 // lower order data. The nonlinearity of each fn contribution is employed.
583 if (nonlinearRespMapping[i][j]) {
584 if (asv_val & 4)
585 sub_model_asv_val |= 3;
586 else if (asv_val & 2)
587 sub_model_asv_val |= 1;
588 }
589 sub_model_asv[recast_fn_contributors[j]] |= sub_model_asv_val;
590 }
591 }
592 sub_model_set.request_vector(sub_model_asv);
593 sub_model_set.derivative_vector(recast_set.derivative_vector()); // copy
594
595 // a setMapping (provided in the RecastModel ctor or initialize()) augments
596 // the standard mappings. Current examples include NonD::set_u_to_x_mapping,
597 // NonDReliability::PMA2_set_mapping, and Optimizer::gauss_newton_set_recast.
598 // This follows the standard mappings so that provided mappings don't get
599 // overwritten by the standard logic. However, this means that any provided
600 // additions will not be automatically augmented by nonlinear mapping logic
601 // above. This should not be a significant problem, since the provided
602 // additions have case-specific context whereas the logic above is generic.
603 // It would be preferable if provided mappings focused on updating the
604 // sub_model_set rather than generating it from recast_set.
605 if (setMapping) {
606 assign_instance();
607 setMapping(recast_vars, recast_set, sub_model_set);
608 }
609 }
610
611
612 void RecastModel::
inverse_transform_set(const Variables & sub_model_vars,const ActiveSet & sub_model_set,ActiveSet & recast_set)613 inverse_transform_set(const Variables& sub_model_vars,
614 const ActiveSet& sub_model_set, ActiveSet& recast_set)
615 {
616 // atypical flow: mapping from sub-model set ("user space") into the
617 // recast set ("iterator space")
618
619 /* TO DO: modify mapping below from forward to inverse
620
621 size_t i, j, num_recast_primary_fns = primaryRespMapIndices.size(),
622 num_recast_secondary_fns = secondaryRespMapIndices.size(),
623 num_recast_fns = num_recast_primary_fns + num_recast_secondary_fns;
624 const ShortArray& recast_asv = recast_set.request_vector();
625 if (recast_asv.size() != num_recast_fns) {
626 Cerr << "Error: inconsistent asv sizing in RecastModel::"
627 << "inverse_transform_set()." << std::endl;
628 abort_handler(-1);
629 }
630
631 // Define default request vector and derivative vector mappings:
632 // For the ASV, project each recast_asv request onto the contributing
633 // set of functions within the sub_model_asv. In the case of nonlinear
634 // input/output mappings, the recast_asv request is augmented with
635 // additional data requirements derived from chain rule differentiation.
636 // The default sub-model DVV is just a copy of the recast DVV.
637 ShortArray sub_model_asv(subModel.response_size(), 0);
638 for (i=0; i<num_recast_fns; i++) {
639 short asv_val = recast_asv[i];
640 // For nonlinear variable mappings, gradient required to transform Hessian.
641 // A single nonlinear variable mapping affects all function derivatives.
642 if (nonlinearVarsMapping && (asv_val & 4))
643 asv_val |= 2;
644 // assign the asv_val to each contributing sub-model function
645 const SizetArray& recast_fn_contributors = (i<num_recast_primary_fns) ?
646 primaryRespMapIndices[i] :
647 secondaryRespMapIndices[i-num_recast_primary_fns];
648 size_t num_contributors = recast_fn_contributors.size();
649 for (j=0; j<num_contributors; j++) {
650 short sub_model_asv_val = asv_val;
651 // Bit deletions: for NLS recasting for full Newton without LeastSq term
652 // Hessians, could remove 4 bit based on {gradient,hessian}Type, but this
653 // is better accomplished from an Iterator's configuration using the
654 // setMapping plug-in below (e.g., see Optimizer::gnewton_set_recast()).
655
656 // Bit additions: for nonlinear resp mappings, derivatives require all
657 // lower order data. The nonlinearity of each fn contribution is employed.
658 if (nonlinearRespMapping[i][j]) {
659 if (asv_val & 4)
660 sub_model_asv_val |= 3;
661 else if (asv_val & 2)
662 sub_model_asv_val |= 1;
663 }
664 sub_model_asv[recast_fn_contributors[j]] |= sub_model_asv_val;
665 }
666 }
667 sub_model_set.request_vector(sub_model_asv);
668 sub_model_set.derivative_vector(recast_set.derivative_vector()); // copy
669 */
670
671 // an invSetMapping (provided in inverse_mappings()) augments the standard
672 // mappings above, such that the provided mappings don't get overwritten by
673 // the standard logic.
674 if (invSetMapping) {
675 assign_instance();
676 invSetMapping(sub_model_vars, sub_model_set, recast_set);
677 }
678 }
679
680
681 void RecastModel::
transform_response(const Variables & recast_vars,const Variables & sub_model_vars,const Response & sub_model_resp,Response & recast_resp)682 transform_response(const Variables& recast_vars,
683 const Variables& sub_model_vars,
684 const Response& sub_model_resp, Response& recast_resp)
685 {
686 // typical flow: mapping from sub-model response ("user space") into
687 // the recast response ("iterator space")
688
689 size_t num_recast_1_fns = primaryRespMapIndices.size();
690
691 if (primaryRespMapping || secondaryRespMapping)
692 assign_instance();
693
694 if (primaryRespMapping)
695 primaryRespMapping(sub_model_vars, recast_vars,
696 sub_model_resp, recast_resp);
697 else // number of recast primary = number of sub-model primary
698 recast_resp.update_partial(0, num_recast_1_fns, sub_model_resp, 0);
699
700 if (secondaryRespMapping)
701 secondaryRespMapping(sub_model_vars, recast_vars,
702 sub_model_resp, recast_resp);
703 else {
704 // number of recast secondary = number of sub-model secondary,
705 // but primary offsets may differ
706 size_t num_recast_2_fns = secondaryRespMapIndices.size(),
707 num_sm_1_fns = sub_model_resp.num_functions() - num_recast_2_fns;
708 recast_resp.update_partial(num_recast_1_fns, num_recast_2_fns,
709 sub_model_resp, num_sm_1_fns);
710 }
711 }
712
713
714 void RecastModel::
inverse_transform_response(const Variables & sub_model_vars,const Variables & recast_vars,const Response & recast_resp,Response & sub_model_resp)715 inverse_transform_response(const Variables& sub_model_vars,
716 const Variables& recast_vars,
717 const Response& recast_resp,
718 Response& sub_model_resp)
719 {
720 // atypical flow: mapping from the recast response ("iterator space")
721 // into the sub-model response ("user space")
722
723 size_t num_recast_1_fns = primaryRespMapIndices.size();
724
725 if (invPriRespMapping || invSecRespMapping)
726 assign_instance();
727
728 if (invPriRespMapping)
729 invPriRespMapping(recast_vars, sub_model_vars, recast_resp, sub_model_resp);
730 else // number of recast primary = number of sub-model primary
731 sub_model_resp.update_partial(0, num_recast_1_fns, recast_resp, 0);
732
733 if (invSecRespMapping)
734 invSecRespMapping(recast_vars, sub_model_vars, recast_resp, sub_model_resp);
735 else {
736 // number of recast secondary = number of sub-model secondary,
737 // but primary offsets may differ
738 size_t num_recast_2_fns = secondaryRespMapIndices.size(),
739 num_sm_1_fns = sub_model_resp.num_functions() - num_recast_2_fns;
740 sub_model_resp.update_partial(num_sm_1_fns, num_recast_2_fns,
741 recast_resp, num_recast_1_fns);
742 }
743 }
744
745
initialize_data_from_submodel()746 void RecastModel::initialize_data_from_submodel()
747 {
748 componentParallelMode = SUB_MODEL_MODE;
749 outputLevel = subModel.output_level();
750
751 gradientType = subModel.gradient_type();
752 methodSource = subModel.method_source();
753 ignoreBounds = subModel.ignore_bounds();
754 centralHess = subModel.central_hess();
755 intervalType = subModel.interval_type();
756 fdGradStepSize = subModel.fd_gradient_step_size();
757 fdGradStepType = subModel.fd_gradient_step_type();
758 gradIdAnalytic = subModel.gradient_id_analytic();
759 gradIdNumerical = subModel.gradient_id_numerical();
760
761 hessianType = subModel.hessian_type();
762 quasiHessType = subModel.quasi_hessian_type();
763 fdHessByFnStepSize = subModel.fd_hessian_by_fn_step_size();
764 fdHessByGradStepSize = subModel.fd_hessian_by_grad_step_size();
765 fdHessStepType = subModel.fd_hessian_step_type();
766 hessIdAnalytic = subModel.hessian_id_analytic();
767 hessIdNumerical = subModel.hessian_id_numerical();
768 hessIdQuasi = subModel.hessian_id_quasi();
769
770 scalingOpts = subModel.scaling_options();
771 }
772
773
774 /** Update inactive values and labels in currentVariables and inactive
775 bound constraints in userDefinedConstraints from variables and
776 constraints data within subModel. */
update_from_model(Model & model)777 void RecastModel::update_from_model(Model& model)
778 {
779 // break up into pieces so that derived Recasts can override with subsets
780
781 bool update_active_complement = update_variables_from_model(model);
782
783 if (update_active_complement)
784 update_variables_active_complement_from_model(model);
785
786 update_response_from_model(model);
787 }
788
789
update_variables_from_model(Model & model)790 bool RecastModel::update_variables_from_model(Model& model)
791 {
792 bool update_active_complement = true;
793 if (invVarsMapping) { // inv mapping provided: sub-model -> recast
794 assign_instance();
795
796 // generally restricted to active variables
797 invVarsMapping(model.current_variables(), currentVariables);
798
799 // BMA TODO: there may be cases where we also want to update the
800 // constraints and values, but there's currently no mechanism to
801 // do so. The client of a RecastModel must manage this.
802 }
803 else if (variablesMapping) { // only fwd mapping for recast -> sub-model
804 // no reasonable default for active vars
805
806 // can't just apply variables mapping to values/bounds, since need inverse
807 // of variablesMapping to go from model vars to currentVariables
808
809 // any label, uncertain variable distributions, and linear
810 // constraint mappings must be performed explicitly
811
812 // for partial mapping of variables that are unmodified by a variable
813 // transformation, see NonDExpansion::initialize_expansion()
814
815 // for mapping of distribution parameters that are part of a variable
816 // transformation, see ProbabilityTransformModel::update_transformation()
817 }
818 else {
819 update_active_complement = false; // can use all view updates below
820
821 // variable values
822 currentVariables.all_continuous_variables(
823 model.all_continuous_variables());
824 currentVariables.all_discrete_int_variables(
825 model.all_discrete_int_variables());
826 currentVariables.all_discrete_string_variables(
827 model.all_discrete_string_variables());
828 currentVariables.all_discrete_real_variables(
829 model.all_discrete_real_variables());
830 // variable bounds
831 userDefinedConstraints.all_continuous_lower_bounds(
832 model.all_continuous_lower_bounds());
833 userDefinedConstraints.all_continuous_upper_bounds(
834 model.all_continuous_upper_bounds());
835 userDefinedConstraints.all_discrete_int_lower_bounds(
836 model.all_discrete_int_lower_bounds());
837 userDefinedConstraints.all_discrete_int_upper_bounds(
838 model.all_discrete_int_upper_bounds());
839 userDefinedConstraints.all_discrete_real_lower_bounds(
840 model.all_discrete_real_lower_bounds());
841 userDefinedConstraints.all_discrete_real_upper_bounds(
842 model.all_discrete_real_upper_bounds());
843 // variable labels
844 currentVariables.all_continuous_variable_labels(
845 model.all_continuous_variable_labels());
846 currentVariables.all_discrete_int_variable_labels(
847 model.all_discrete_int_variable_labels());
848 currentVariables.all_discrete_string_variable_labels(
849 model.all_discrete_string_variable_labels());
850 currentVariables.all_discrete_real_variable_labels(
851 model.all_discrete_real_variable_labels());
852
853 // uncertain variable distribution data
854 // > deep copies were used previously for Pecos::DistributionParams
855 //mvDist.update(model.multivariate_distribution());
856 // Current approach: rep is shared
857 // > tramples an mvDist construction from Model(BaseConstructor) ....
858 // > populates mvDist for Model(LightWtBaseConstructor)
859 // > reassignments protected by smart ptr management
860 // Note: becomes less important w/ broader use of ProbabilityTransformModel
861 mvDist = subModel.multivariate_distribution(); // shared rep
862
863 // linear constraints
864 if (model.num_linear_ineq_constraints()) {
865 userDefinedConstraints.linear_ineq_constraint_coeffs(
866 model.linear_ineq_constraint_coeffs());
867 userDefinedConstraints.linear_ineq_constraint_lower_bounds(
868 model.linear_ineq_constraint_lower_bounds());
869 userDefinedConstraints.linear_ineq_constraint_upper_bounds(
870 model.linear_ineq_constraint_upper_bounds());
871 }
872 if (model.num_linear_eq_constraints()) {
873 userDefinedConstraints.linear_eq_constraint_coeffs(
874 model.linear_eq_constraint_coeffs());
875 userDefinedConstraints.linear_eq_constraint_targets(
876 model.linear_eq_constraint_targets());
877 }
878 }
879
880 return update_active_complement;
881 }
882
883
update_variables_active_complement_from_model(Model & model)884 void RecastModel::update_variables_active_complement_from_model(Model& model)
885 {
886 size_t i, cv_begin = currentVariables.cv_start(),
887 num_cv = currentVariables.cv(), cv_end = cv_begin + num_cv,
888 num_acv = currentVariables.acv();
889 const RealVector& acv = model.all_continuous_variables();
890 const RealVector& acv_l_bnds = model.all_continuous_lower_bounds();
891 const RealVector& acv_u_bnds = model.all_continuous_upper_bounds();
892 StringMultiArrayConstView acv_labels
893 = model.all_continuous_variable_labels();
894 for (i=0; i<cv_begin; ++i) {
895 currentVariables.all_continuous_variable(acv[i], i);
896 userDefinedConstraints.all_continuous_lower_bound(acv_l_bnds[i], i);
897 userDefinedConstraints.all_continuous_upper_bound(acv_u_bnds[i], i);
898 currentVariables.all_continuous_variable_label(acv_labels[i], i);
899 }
900 for (i=cv_end; i<num_acv; ++i) {
901 currentVariables.all_continuous_variable(acv[i], i);
902 userDefinedConstraints.all_continuous_lower_bound(acv_l_bnds[i], i);
903 userDefinedConstraints.all_continuous_upper_bound(acv_u_bnds[i], i);
904 currentVariables.all_continuous_variable_label(acv_labels[i], i);
905 }
906
907 size_t div_begin = currentVariables.div_start(),
908 num_div = currentVariables.div(), div_end = div_begin + num_div,
909 num_adiv = currentVariables.adiv();
910 const IntVector& adiv = model.all_discrete_int_variables();
911 const IntVector& adiv_l_bnds = model.all_discrete_int_lower_bounds();
912 const IntVector& adiv_u_bnds = model.all_discrete_int_upper_bounds();
913 StringMultiArrayConstView adiv_labels
914 = model.all_discrete_int_variable_labels();
915 for (i=0; i<div_begin; ++i) {
916 currentVariables.all_discrete_int_variable(adiv[i], i);
917 userDefinedConstraints.all_discrete_int_lower_bound(adiv_l_bnds[i], i);
918 userDefinedConstraints.all_discrete_int_upper_bound(adiv_u_bnds[i], i);
919 currentVariables.all_discrete_int_variable_label(adiv_labels[i], i);
920 }
921 for (i=div_end; i<num_adiv; ++i) {
922 currentVariables.all_discrete_int_variable(adiv[i], i);
923 userDefinedConstraints.all_discrete_int_lower_bound(adiv_l_bnds[i], i);
924 userDefinedConstraints.all_discrete_int_upper_bound(adiv_u_bnds[i], i);
925 currentVariables.all_discrete_int_variable_label(adiv_labels[i], i);
926 }
927
928 size_t dsv_begin = currentVariables.dsv_start(),
929 num_dsv = currentVariables.dsv(), dsv_end = dsv_begin + num_dsv,
930 num_adsv = currentVariables.adsv();
931 StringMultiArrayConstView adsv = model.all_discrete_string_variables();
932 StringMultiArrayConstView adsv_labels
933 = model.all_discrete_string_variable_labels();
934 for (i=0; i<dsv_begin; ++i) {
935 currentVariables.all_discrete_string_variable(adsv[i], i);
936 currentVariables.all_discrete_string_variable_label(adsv_labels[i], i);
937 }
938 for (i=dsv_end; i<num_adsv; ++i) {
939 currentVariables.all_discrete_string_variable(adsv[i], i);
940 currentVariables.all_discrete_string_variable_label(adsv_labels[i], i);
941 }
942
943 size_t drv_begin = currentVariables.drv_start(),
944 num_drv = currentVariables.drv(), drv_end = drv_begin + num_drv,
945 num_adrv = currentVariables.adrv();
946 const RealVector& adrv = model.all_discrete_real_variables();
947 const RealVector& adrv_l_bnds = model.all_discrete_real_lower_bounds();
948 const RealVector& adrv_u_bnds = model.all_discrete_real_upper_bounds();
949 StringMultiArrayConstView adrv_labels
950 = model.all_discrete_real_variable_labels();
951 for (i=0; i<drv_begin; ++i) {
952 currentVariables.all_discrete_real_variable(adrv[i], i);
953 userDefinedConstraints.all_discrete_real_lower_bound(adrv_l_bnds[i], i);
954 userDefinedConstraints.all_discrete_real_upper_bound(adrv_u_bnds[i], i);
955 currentVariables.all_discrete_real_variable_label(adrv_labels[i], i);
956 }
957 for (i=drv_end; i<num_adrv; ++i) {
958 currentVariables.all_discrete_real_variable(adrv[i], i);
959 userDefinedConstraints.all_discrete_real_lower_bound(adrv_l_bnds[i], i);
960 userDefinedConstraints.all_discrete_real_upper_bound(adrv_u_bnds[i], i);
961 currentVariables.all_discrete_real_variable_label(adrv_labels[i], i);
962 }
963 }
964
965
update_response_from_model(Model & model)966 void RecastModel::update_response_from_model(Model& model)
967 {
968 if (primaryRespMapping) {
969 // response mappings are in opposite direction from variables
970 // mappings, so primaryRespMapping could potentially be used to
971 // update currentResponse from model primary fns
972 }
973 else {
974 // primary response function weights
975 primaryRespFnWts = model.primary_response_fn_weights();
976 // primary response function sense (min or max)
977 primaryRespFnSense = model.primary_response_fn_sense();
978
979 // primary response function labels
980 const StringArray& sm_resp_labels = model.response_labels();
981 size_t i, num_primary = numFns
982 - userDefinedConstraints.num_nonlinear_eq_constraints()
983 - userDefinedConstraints.num_nonlinear_ineq_constraints();
984 for (i=0; i<num_primary; i++)
985 currentResponse.shared_data().function_label(sm_resp_labels[i], i);
986 }
987
988 if (secondaryRespMapping) {
989 // response mappings are in opposite direction from variables
990 // mappings, so secondaryRespMapping could potentially be used to
991 // update currentResponse from model secondary fns
992 }
993 else {
994 // secondary response function labels
995 const StringArray& sm_resp_labels = model.response_labels();
996 size_t i,
997 num_nln_con = userDefinedConstraints.num_nonlinear_eq_constraints() +
998 userDefinedConstraints.num_nonlinear_ineq_constraints(),
999 num_primary = numFns - num_nln_con,
1000 num_sm_primary = model.response_size() - num_nln_con;
1001 for (i=0; i<num_nln_con; i++)
1002 currentResponse.shared_data().function_label(
1003 sm_resp_labels[num_sm_primary+i], num_primary+i);
1004
1005 // nonlinear constraint bounds/targets
1006 if (model.num_nonlinear_ineq_constraints()) {
1007 userDefinedConstraints.nonlinear_ineq_constraint_lower_bounds(
1008 model.nonlinear_ineq_constraint_lower_bounds());
1009 userDefinedConstraints.nonlinear_ineq_constraint_upper_bounds(
1010 model.nonlinear_ineq_constraint_upper_bounds());
1011 }
1012 if (model.num_nonlinear_eq_constraints())
1013 userDefinedConstraints.nonlinear_eq_constraint_targets(
1014 model.nonlinear_eq_constraint_targets());
1015 }
1016 }
1017
1018
error_estimates()1019 const RealVector& RecastModel::error_estimates()
1020 {
1021 // linear mappings are fine (see NestedModel), but general nonlinear mappings
1022 // are problematic.
1023 if (primaryRespMapping || secondaryRespMapping) {
1024
1025 // preclude nonlinear mappings and multi-component mappings for now.
1026 // Note: a linear multi-component mapping can be supported by NestedModel::
1027 // iterator_error_estimation(), because the mapping coeffs are known.
1028
1029 size_t i, num_recast_fns = nonlinearRespMapping.size();
1030 for (i=0; i<num_recast_fns; ++i) {
1031 const BoolDeque& nln_resp_map_i = nonlinearRespMapping[i];
1032 if (nln_resp_map_i.size() > 1 ||
1033 std::find(nln_resp_map_i.begin(), nln_resp_map_i.end(), true) !=
1034 nln_resp_map_i.end()) {
1035 Cerr << "Error: error estimation not currently supported for Recast"
1036 << "Model with nonlinear or multi-component response mapping."
1037 << std::endl;
1038 abort_handler(MODEL_ERROR);
1039 }
1040 }
1041
1042 // push errors through linear single-component mapping (individual scaling)
1043
1044 // make dummy responses for use with transform_response()
1045 const Response& sm_resp = subModel.current_response();
1046 ActiveSet sm_set = sm_resp.active_set(),
1047 recast_set = currentResponse.active_set();
1048 sm_set.request_values(1); recast_set.request_values(1);
1049 Response sm_error_est(sm_resp.shared_data(), sm_set),
1050 recast_error_est(currentResponse.shared_data(), recast_set);
1051 // transform the error estimates as Response::functionValues
1052 sm_error_est.function_values(subModel.error_estimates());
1053 if (outputLevel >= DEBUG_OUTPUT) // distinguish ScalingModel debug blocks
1054 Cout << "Transforming Error Estimates:\n";
1055 transform_response(currentVariables, subModel.current_variables(),
1056 sm_error_est, recast_error_est);
1057 mappedErrorEstimates = recast_error_est.function_values();
1058 return mappedErrorEstimates;
1059 }
1060 else
1061 return subModel.error_estimates();
1062 }
1063
1064
resize_response_mapping()1065 void RecastModel::resize_response_mapping()
1066 {
1067 // reshaping primaryRespMapIndices, secondaryRespMapIndices
1068 size_t num_curr_fns = response_size(),
1069 num_curr_secondary = num_secondary_fns(),
1070 num_curr_primary = num_curr_fns - num_curr_secondary,
1071 num_sm_fns = subModel.response_size(),
1072 num_sm_secondary = subModel.num_secondary_fns(),
1073 num_sm_primary = num_sm_fns - num_sm_secondary,
1074 num_replicates, num_ind, offset, i, j, k;
1075
1076 primaryRespMapIndices.resize(num_sm_primary);
1077 secondaryRespMapIndices.resize(num_sm_secondary);
1078 nonlinearRespMapping.resize(num_sm_fns);
1079
1080 // the number of mappings to replicate corresponds to the number
1081 // of data sets being aggregated in, e.g., AGGREGATED_MODELS mode
1082
1083 if (num_sm_primary > num_curr_primary) { // inflate existing mappings
1084 num_replicates = num_sm_primary / num_curr_primary;
1085 if (num_sm_primary % num_curr_primary) {
1086 Cerr << "Error: non-integer multiplier for response aggregation in "
1087 << "RecastModel::resize_response_mapping()" << std::endl;
1088 abort_handler(MODEL_ERROR);
1089 }
1090 for (i=0; i<num_curr_primary; ++i) {
1091 // mirror pattern within new response indices, but offset index mapping
1092 SizetArray& primary_ind_i = primaryRespMapIndices[i];
1093 num_ind = primary_ind_i.size();
1094 for (j=1; j<num_replicates; ++j) {
1095 offset = j * num_curr_primary;
1096 SizetArray& primary_ind_j = primaryRespMapIndices[i + offset];
1097 primary_ind_j.resize(num_ind);
1098 for (k=0; k<num_ind; ++k)
1099 primary_ind_j[k] = primary_ind_i[k] + offset;
1100 }
1101 }
1102 }
1103 if (num_sm_secondary > num_curr_secondary) { // inflate existing mappings
1104 num_replicates = num_sm_secondary / num_curr_secondary;
1105 if (num_sm_secondary % num_curr_secondary) {
1106 Cerr << "Error: non-integer multiplier for response aggregation in "
1107 << "RecastModel::resize_response_mapping()" << std::endl;
1108 abort_handler(MODEL_ERROR);
1109 }
1110 for (i=0; i<num_curr_secondary; ++i) {
1111 // mirror pattern within new response indices, but offset index mapping
1112 SizetArray& secondary_ind_i = secondaryRespMapIndices[i];
1113 num_ind = secondary_ind_i.size();
1114 for (j=1; j<num_replicates; ++j) {
1115 offset = j * num_curr_secondary;
1116 SizetArray& secondary_ind_j = secondaryRespMapIndices[i + offset];
1117 secondary_ind_j.resize(num_ind);
1118 for (k=0; k<num_ind; ++k)
1119 secondary_ind_j[k] = secondary_ind_i[k] + offset;
1120 }
1121 }
1122 }
1123 if (num_sm_fns > num_curr_fns) { // inflate existing mappings
1124 num_replicates = num_sm_fns / num_curr_fns;
1125 if (num_sm_fns % num_curr_fns) {
1126 Cerr << "Error: non-integer multiplier for response aggregation in "
1127 << "RecastModel::resize_response_mapping()" << std::endl;
1128 abort_handler(MODEL_ERROR);
1129 }
1130 for (i=0; i<num_curr_fns; ++i) {
1131 // mirror pattern within new response indices, but offset index mapping
1132 BoolDeque& nonlin_resp_map_i = nonlinearRespMapping[i];
1133 for (j=1; j<num_replicates; ++j)
1134 nonlinearRespMapping[i + j * num_curr_fns] = nonlin_resp_map_i;
1135 }
1136 }
1137 }
1138
1139
1140 bool RecastModel::
db_lookup(const Variables & search_vars,const ActiveSet & search_set,Response & found_resp)1141 db_lookup(const Variables& search_vars, const ActiveSet& search_set,
1142 Response& found_resp)
1143 {
1144 // transform from recast (Iterator) to sub-model (user) variables;
1145 // making copy to avoid modifying submodel state during the lookup
1146 Variables sub_model_vars(subModel.current_variables().copy());
1147 transform_variables(search_vars, sub_model_vars);
1148
1149 // the incoming set is for the recast problem, which must be converted
1150 // back to the underlying response set for evaluation by the subModel.
1151 ActiveSet sub_model_set;
1152 transform_set(search_vars, search_set, sub_model_set);
1153
1154 // invoke submodel lookup; making copy to avoid modifying submodel state
1155 // during the lookup
1156 Response sub_model_resp(subModel.current_response().copy());
1157 // sub_model_resp must have right ASV so lookup's update will pull right data
1158 sub_model_resp.active_set(sub_model_set);
1159 bool eval_found
1160 = subModel.db_lookup(sub_model_vars, sub_model_set, sub_model_resp);
1161 if (!eval_found)
1162 return false;
1163
1164 // recast the subModel response ("user space") into the "iterator space"
1165 found_resp.active_set(search_set);
1166 if (primaryRespMapping || secondaryRespMapping)
1167 transform_response(search_vars, sub_model_vars, sub_model_resp, found_resp);
1168 else
1169 found_resp.update(sub_model_resp);
1170
1171 return eval_found;
1172 }
1173
1174
assign_instance()1175 void RecastModel::assign_instance()
1176 { } // no static instance pointer to assign at base (default is no-op)
1177
1178
root_model_id()1179 String RecastModel::root_model_id() {
1180 return subModel.root_model_id();
1181 }
1182
1183
default_active_set()1184 ActiveSet RecastModel::default_active_set() {
1185 // The "base class" implementation assumes that supportsEstimDerivs is false
1186 // and that gradients/hessians, if available, are computed by a submodel and
1187 // hence can be provided by this model.
1188 ActiveSet set;
1189 set.derivative_vector(currentVariables.all_continuous_variable_ids());
1190 bool has_deriv_vars = set.derivative_vector().size() != 0;
1191 ShortArray asv(numFns, 1);
1192 if(has_deriv_vars) {
1193 if(gradientType != "none")// && (gradientType == "analytic" || supportsEstimDerivs))
1194 for(auto &a : asv)
1195 a |= 2;
1196
1197 if(hessianType != "none") // && (hessianType == "analytic" || supportsEstimDerivs))
1198 for(auto &a : asv)
1199 a |= 4;
1200 }
1201 set.request_vector(asv);
1202 return set;
1203 }
1204
1205
declare_sources()1206 void RecastModel::declare_sources() {
1207 evaluationsDB.declare_source(modelId, modelType, subModel.model_id(), subModel.model_type());
1208 }
1209
1210 } // namespace Dakota
1211