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: SurrogateModel
10 //- Description: Implementation code for the SurrogateModel class
11 //- Owner: Mike Eldred
12 //- Checked by:
13
14 #include "dakota_system_defs.hpp"
15 #include "SurrogateModel.hpp"
16 #include "ProblemDescDB.hpp"
17 #include "ParallelLibrary.hpp"
18 #include "ParamResponsePair.hpp"
19 #include "PRPMultiIndex.hpp"
20 #include "dakota_data_io.hpp"
21 #include "SurrogateData.hpp"
22
23 static const char rcsId[]="@(#) $Id: SurrogateModel.cpp 7024 2010-10-16 01:24:42Z mseldre $";
24
25 //#define DEBUG
26
27
28 namespace Dakota {
29
SurrogateModel(ProblemDescDB & problem_db)30 SurrogateModel::SurrogateModel(ProblemDescDB& problem_db):
31 Model(BaseConstructor(), problem_db),
32 surrogateFnIndices(problem_db.get_is("model.surrogate.function_indices")),
33 corrType(problem_db.get_short("model.surrogate.correction_type")),
34 surrModelEvalCntr(0), approxBuilds(0)
35 {
36 // assign default responseMode based on correction specification;
37 // NO_CORRECTION (0) is default
38 responseMode = (corrType) ? AUTO_CORRECTED_SURROGATE : UNCORRECTED_SURROGATE;
39
40 // process surrogateFnIndices. IntSets are sorted and unique.
41 if (surrogateFnIndices.empty()) // default: all fns are approximated
42 for (int i=0; i<numFns; ++i)
43 surrogateFnIndices.insert(i);
44 else {
45 // check for out of range values
46 if (*surrogateFnIndices.begin() < 0 ||
47 *(--surrogateFnIndices.end()) >= numFns) {
48 Cerr << "Error: id_surrogates out of range." << std::endl;
49 abort_handler(-1);
50 }
51 }
52 }
53
54
55 SurrogateModel::
SurrogateModel(ProblemDescDB & problem_db,ParallelLibrary & parallel_lib,const SharedVariablesData & svd,bool share_svd,const SharedResponseData & srd,bool share_srd,const ActiveSet & set,short corr_type,short output_level)56 SurrogateModel(ProblemDescDB& problem_db, ParallelLibrary& parallel_lib,
57 const SharedVariablesData& svd, bool share_svd,
58 const SharedResponseData& srd, bool share_srd,
59 const ActiveSet& set, short corr_type, short output_level):
60 // Allow DFSModel to employ sizing differences (e.g., consuming aggregations)
61 Model(LightWtBaseConstructor(), problem_db, parallel_lib, svd, share_svd,
62 srd, share_srd, set, output_level),
63 corrType(corr_type), surrModelEvalCntr(0), approxBuilds(0)
64 {
65 modelType = "surrogate";
66
67 // assign default responseMode based on correction specification;
68 // NO_CORRECTION (0) is default
69 responseMode = (corrType) ? AUTO_CORRECTED_SURROGATE : UNCORRECTED_SURROGATE;
70
71 // set up surrogateFnIndices to use default (all fns are approximated)
72 for (int i=0; i<numFns; ++i)
73 surrogateFnIndices.insert(i);
74 }
75
76
check_submodel_compatibility(const Model & sub_model)77 void SurrogateModel::check_submodel_compatibility(const Model& sub_model)
78 {
79 // Check for compatible array sizing between sub_model and currentVariables,
80 // accounting for the use of different views in different variables sets:
81 // > common case for local/multipoint/hierarchical: the variables view in
82 // sub_model and currentVariables are the same.
83 // > common case for global: sub_model has an "All" vars view due to DACE
84 // usage and the currentVariables view may vary depending on the type
85 // of iterator interfaced with this SurrogateModel. Enforcing an "all"
86 // view in the data returned from currentVariables ensures consistency.
87 short active_view = currentVariables.view().first,
88 sm_active_view = sub_model.current_variables().view().first;
89 bool error_flag = false;
90 if ( active_view == sm_active_view ) {
91 // common cases: Distinct on Distinct (e.g., opt/UQ on local/multipt/hier)
92 // All on All (e.g., DACE/PStudy on global)
93 size_t sm_cv = sub_model.cv(), sm_div = sub_model.div(),
94 sm_dsv = sub_model.dsv(), sm_drv = sub_model.drv(),
95 cv = currentVariables.cv(), div = currentVariables.div(),
96 dsv = currentVariables.dsv(), drv = currentVariables.drv();
97 if (sm_cv != cv || sm_div != div || sm_dsv != dsv || sm_drv != drv) {
98 Cerr << "Error: incompatibility between approximate and actual model "
99 << "variable sets within SurrogateModel:\n Active approximate "
100 << "= " << cv << " continuous, " << div << " discrete int, " << dsv
101 << " discrete string, and " << drv << " discrete real.\n "
102 << "Active actual = " << sm_cv << " continuous, " << sm_div
103 << " discrete int, " << sm_dsv << " discrete string, and " << sm_drv
104 << " discrete real.\n Check consistency of variables "
105 << "specifications." << std::endl;
106 error_flag = true;
107 }
108 }
109 else if ( ( sm_active_view == RELAXED_ALL || sm_active_view == MIXED_ALL ) &&
110 active_view >= RELAXED_DESIGN ) {
111 // common case: Distinct on All (e.g., opt/UQ on global surrogate)
112 size_t sm_cv = sub_model.cv(), sm_div = sub_model.div(),
113 sm_dsv = sub_model.dsv(), sm_drv = sub_model.drv(),
114 acv = currentVariables.acv(), adiv = currentVariables.adiv(),
115 adsv = currentVariables.adsv(), adrv = currentVariables.adrv();
116 if (sm_cv != acv || sm_div != adiv || sm_dsv != adsv || sm_drv != adrv) {
117 Cerr << "Error: incompatibility between approximate and actual model "
118 << "variable sets within SurrogateModel:\n Active "
119 << "approximate = " << acv << " continuous, " << adiv
120 << " discrete int, " << adsv << " discrete string, and " << adrv
121 << " discrete real (All view).\n Active actual = "
122 << sm_cv << " continuous, " << sm_div << " discrete int, " << sm_dsv
123 << " discrete string, and " << sm_drv << " discrete real.\n "
124 << "Check consistency of variables specifications."<< std::endl;
125 error_flag = true;
126 }
127 }
128 else if ( ( active_view == RELAXED_ALL || active_view == MIXED_ALL ) &&
129 sm_active_view >= RELAXED_DESIGN ) {
130 // common case: All on Distinct (e.g., DACE/PStudy on local/multipt/hier)
131 // Note: force_rebuild() is critical for this case (prevents interrogation
132 // of a surrogate for inconsistent values for vars not included in build)
133 size_t sm_acv = sub_model.acv(), sm_adiv = sub_model.adiv(),
134 sm_adsv = sub_model.adsv(), sm_adrv = sub_model.adrv(),
135 cv = currentVariables.cv(), div = currentVariables.div(),
136 dsv = currentVariables.dsv(), drv = currentVariables.drv();
137 if (sm_acv != cv || sm_adiv != div || sm_adsv != dsv || sm_adrv != drv) {
138 Cerr << "Error: incompatibility between approximate and actual model "
139 << "variable sets within SurrogateModel:\n Active "
140 << "approximate = " << cv << " continuous, " << div
141 << " discrete int, " << dsv << " discrete string, and " << drv
142 << " discrete real.\n Active actual = " << sm_acv
143 << " continuous, " << sm_adiv << " discrete int, " << sm_adsv
144 << " discrete string, and " << sm_adrv << " discrete real (All "
145 << "view).\n Check consistency of variables specifications."
146 << std::endl;
147 error_flag = true;
148 }
149 }
150 //else: other options are specific to DataFit and Hierarch surrogates
151
152 if (error_flag)
153 abort_handler(-1);
154 }
155
156
157 /** This function forces a rebuild of the approximation according to
158 the sub-model variables view, the approximation type, and whether
159 the active approximation bounds or inactive variable values have
160 changed since the last approximation build. */
force_rebuild()161 bool SurrogateModel::force_rebuild()
162 {
163 // force rebuild for change in inactive vars based on sub-model view. It
164 // is assumed that any recastings within Model recursions do not affect the
165 // inactive variables (while RecastModel::variablesMapping has access to
166 // all of the vars, the convention is to modify only the active vars).
167
168 // for global surrogates, force rebuild for change in active bounds
169
170 Model& actual_model = truth_model();
171
172 // Don't force rebuild for active subspace model:
173 // JAM TODO: There is probably a more elegant way to accomodate subspace models
174 if (actual_model.model_type() == "active_subspace")
175 return false;
176
177 short approx_active_view = currentVariables.view().first;
178 if (actual_model.is_null()) {
179 // compare reference vars against current inactive top-level data
180 if ( referenceICVars != currentVariables.inactive_continuous_variables() ||
181 referenceIDIVars !=
182 currentVariables.inactive_discrete_int_variables() ||
183 referenceIDSVars !=
184 currentVariables.inactive_discrete_string_variables() ||
185 referenceIDRVars !=
186 currentVariables.inactive_discrete_real_variables() )
187 return true;
188
189 if ( strbegins(surrogateType, "global_") &&
190 // compare reference bounds against current active top-level data
191 ( referenceCLBnds != userDefinedConstraints.continuous_lower_bounds()||
192 referenceCUBnds != userDefinedConstraints.continuous_upper_bounds()||
193 referenceDILBnds !=
194 userDefinedConstraints.discrete_int_lower_bounds() ||
195 referenceDIUBnds !=
196 userDefinedConstraints.discrete_int_upper_bounds() ||
197 // no discrete string bounds
198 referenceDRLBnds !=
199 userDefinedConstraints.discrete_real_lower_bounds() ||
200 referenceDRUBnds !=
201 userDefinedConstraints.discrete_real_upper_bounds() ) )
202 return true;
203 }
204 else { // actual_model is defined
205 const Variables& actual_vars = actual_model.current_variables();
206 short sub_model_active_view = actual_vars.view().first;
207
208 // compare reference vars against current inactive top-level data
209 if ( approx_active_view == sub_model_active_view &&
210 approx_active_view >= RELAXED_DESIGN &&
211 // compare inactive top-level data against inactive sub-model data
212 ( referenceICVars != currentVariables.inactive_continuous_variables()||
213 referenceIDIVars !=
214 currentVariables.inactive_discrete_int_variables() ||
215 referenceIDSVars !=
216 currentVariables.inactive_discrete_string_variables() ||
217 referenceIDRVars !=
218 currentVariables.inactive_discrete_real_variables() ) )
219 return true;
220 else if ( ( approx_active_view == RELAXED_ALL ||
221 approx_active_view == MIXED_ALL ) &&
222 sub_model_active_view >= RELAXED_DESIGN ) {
223 // coerce top level data to sub-model view, but don't update sub-model
224 if (truthModelVars.is_null())
225 truthModelVars = actual_vars.copy();
226 truthModelVars.all_continuous_variables(
227 currentVariables.continuous_variables());
228 truthModelVars.all_discrete_int_variables(
229 currentVariables.discrete_int_variables());
230 truthModelVars.all_discrete_string_variables(
231 currentVariables.discrete_string_variables());
232 truthModelVars.all_discrete_real_variables(
233 currentVariables.discrete_real_variables());
234 // perform check on inactive data at sub-model level
235 if ( referenceICVars != truthModelVars.inactive_continuous_variables() ||
236 referenceIDIVars !=
237 truthModelVars.inactive_discrete_int_variables() ||
238 referenceIDSVars !=
239 truthModelVars.inactive_discrete_string_variables() ||
240 referenceIDRVars !=
241 truthModelVars.inactive_discrete_real_variables() )
242 return true;
243 }
244 // TO DO: extend for aleatory/epistemic uncertain views
245 /*
246 Model sub_model = actual_model.subordinate_model();
247 while (sub_model.model_type() == "recast")
248 sub_model = sub_model.subordinate_model();
249 if ( referenceICVars != sub_model.inactive_continuous_variables() ||
250 referenceIDIVars != sub_model.inactive_discrete_int_variables() ||
251 referenceIDSVars != sub_model.inactive_discrete_string_variables() ||
252 referenceIDRVars != sub_model.inactive_discrete_real_variables() )
253 return true;
254 */
255
256 // compare reference bounds against current active top-level data
257 if ( strbegins(surrogateType, "global_") ) {
258
259 if (actual_model.model_type() == "recast") {
260 // check for internal changes within subModel definition since the
261 // SurrogateModel may be in a standard variable space (such that the
262 // outer level values/bounds do not reflect inner level updates).
263
264 // force_rebuild() is called within the context of an approximate
265 // derived_evaluate(), whereas update_actual_model() and update_global()
266 // are called w/i the context of build_approximation(). Therefore, one
267 // must be cautious with assuming that top-level updates have propagated
268 // to lower levels. (The only current use case involves
269 // uSpaceModel.force_rebuild() w/i NonDExpansion::compute_expansion(),
270 // although it may prove useful for other u-space approximations within
271 // PCE/SC and local/global reliability).
272
273 // Dive through Model recursion to bypass recasting. This is not readily
274 // handled within new Model virtual fns since the type of approximation
275 // (known here, but not w/i virtual fns) could dictate different checks.
276 Model sub_model = actual_model.subordinate_model();
277 while (sub_model.model_type() == "recast")
278 sub_model = sub_model.subordinate_model();
279
280 if (referenceCLBnds != sub_model.continuous_lower_bounds() ||
281 referenceCUBnds != sub_model.continuous_upper_bounds() ||
282 referenceDILBnds != sub_model.discrete_int_lower_bounds() ||
283 referenceDIUBnds != sub_model.discrete_int_upper_bounds() ||
284 // no discrete string bounds
285 referenceDRLBnds != sub_model.discrete_real_lower_bounds() ||
286 referenceDRUBnds != sub_model.discrete_real_upper_bounds())
287 return true;
288 }
289 else if ( approx_active_view == sub_model_active_view &&
290 // compare active top-level data against active sub-model data
291 ( referenceCLBnds !=
292 userDefinedConstraints.continuous_lower_bounds() ||
293 referenceCUBnds !=
294 userDefinedConstraints.continuous_upper_bounds() ||
295 referenceDILBnds !=
296 userDefinedConstraints.discrete_int_lower_bounds() ||
297 referenceDIUBnds !=
298 userDefinedConstraints.discrete_int_upper_bounds() ||
299 // no discrete string bounds
300 referenceDRLBnds !=
301 userDefinedConstraints.discrete_real_lower_bounds() ||
302 referenceDRUBnds !=
303 userDefinedConstraints.discrete_real_upper_bounds() ) )
304 return true;
305 else if ( approx_active_view >= RELAXED_DESIGN &&
306 ( sub_model_active_view == RELAXED_ALL ||
307 sub_model_active_view == MIXED_ALL ) &&
308 // compare top-level data in All view w/ active sub-model data
309 ( referenceCLBnds !=
310 userDefinedConstraints.all_continuous_lower_bounds() ||
311 referenceCUBnds !=
312 userDefinedConstraints.all_continuous_upper_bounds() ||
313 referenceDILBnds !=
314 userDefinedConstraints.all_discrete_int_lower_bounds() ||
315 referenceDIUBnds !=
316 userDefinedConstraints.all_discrete_int_upper_bounds() ||
317 // no discrete string bounds
318 referenceDRLBnds !=
319 userDefinedConstraints.all_discrete_real_lower_bounds() ||
320 referenceDRUBnds !=
321 userDefinedConstraints.all_discrete_real_upper_bounds() ) )
322 return true;
323 else if ( ( approx_active_view == RELAXED_ALL ||
324 approx_active_view == MIXED_ALL ) &&
325 sub_model_active_view >= RELAXED_DESIGN ) {
326 // coerce top level data to sub-model view, but don't update sub-model
327 if (truthModelCons.is_null())
328 truthModelCons = actual_model.user_defined_constraints().copy();
329 truthModelCons.all_continuous_lower_bounds(
330 userDefinedConstraints.continuous_lower_bounds());
331 truthModelCons.all_continuous_upper_bounds(
332 userDefinedConstraints.continuous_upper_bounds());
333 truthModelCons.all_discrete_int_lower_bounds(
334 userDefinedConstraints.discrete_int_lower_bounds());
335 truthModelCons.all_discrete_int_upper_bounds(
336 userDefinedConstraints.discrete_int_upper_bounds());
337 // no discrete string bounds
338 truthModelCons.all_discrete_real_lower_bounds(
339 userDefinedConstraints.discrete_real_lower_bounds());
340 truthModelCons.all_discrete_real_upper_bounds(
341 userDefinedConstraints.discrete_real_upper_bounds());
342 // perform check on active data at sub-model level
343 if ( referenceCLBnds != truthModelCons.continuous_lower_bounds() ||
344 referenceCUBnds != truthModelCons.continuous_upper_bounds() ||
345 referenceDILBnds != truthModelCons.discrete_int_lower_bounds() ||
346 referenceDIUBnds != truthModelCons.discrete_int_upper_bounds() ||
347 // no discrete string bounds
348 referenceDRLBnds != truthModelCons.discrete_real_lower_bounds() ||
349 referenceDRUBnds != truthModelCons.discrete_real_upper_bounds() )
350 return true;
351 }
352
353 /*
354 // -----------------------COLLAPSED----------------------------------
355 if ( // SBO: rebuild over {d} for each new TR of {d}
356 // OUU All view: rebuild over {u}+{d} for each new TR of {d}
357 active_bounds_differ ||
358 // OUU Distinct view: rebuild over {u} for each new instance of {d}
359 ( sub_model_active_view >= RELAXED_DESIGN &&
360 inactive_values_differ ) )
361 return true;
362
363 // -----------------------EXPANDED-----------------------------------
364 if (approx_active_view == sub_model_active_view &&
365 approx_active_view >= RELAXED_DESIGN) { // Distinct to Distinct
366 // SBO: rebuild over {d} for each new TR of {d}
367 // OUU: force rebuild over {u} for each new instance of {d}
368 // inactive bounds are irrelevant
369 if (active_bounds_differ || inactive_values_differ)
370 return true;
371 }
372 else if ( approx_active_view == sub_model_active_view &&
373 ( approx_active_view == RELAXED_ALL ||
374 approx_active_view == MIXED_ALL ) ) { // All to All
375 // unusual case: Surrogate-based DACE,PStudy
376 // there are no inactive vars/bounds
377 if (active_bounds_differ)
378 return true;
379 }
380 else if ( approx_active_view >= RELAXED_DESIGN &&
381 ( sub_model_active_view == RELAXED_ALL ||
382 sub_model_active_view == MIXED_ALL ) ) { // Distinct to All
383 // OUU: force rebuild over {u}+{d} for each new TR of {d}
384 if (active_bounds_differ)
385 return true;
386 }
387 else if ( ( approx_active_view == RELAXED_ALL ||
388 approx_active_view == MIXED_ALL ) &&
389 sub_model_active_view >= RELAXED_DESIGN ) { // All->Distinct
390 // unusual case: approx over subset of active top-level vars
391 if (active_bounds_differ || inactive_values_differ)
392 return true;
393 }
394 */
395 }
396 /*
397 else { // local, multipoint, hierarchical
398
399 // For local/multipoint/hierarchical, the approximation is not dependent
400 // on the bounds. For an "All" sub-model view, the surrogate accounts for
401 // _all_ continuous variables and a rebuild never needs to be forced
402 // (although many surrogate-based algorithms will rebuild for each new
403 // approx region). For a "Distinct" view, a rebuild is required for any
404 // change in inactive variable values.
405
406 // -------------------------COLLAPSED------------------------------
407 if ( // OUU Distinct view: rebuild over {u} for each new instance of {d}
408 sub_model_active_view >= RELAXED_DESIGN &&
409 inactive_values_differ )
410 return true;
411
412 // -------------------------EXPANDED-------------------------------
413 if (approx_active_view == sub_model_active_view &&
414 approx_active_view >= RELAXED_DESIGN) { // Distinct to Distinct
415 // SBO: rebuild over {d} for each new TR of {d}
416 // OUU: force rebuild over {u} for each new instance of {d}
417 // inactive bounds are irrelevant
418 if (inactive_values_differ)
419 return true;
420 }
421 else if ( approx_active_view == sub_model_active_view &&
422 ( approx_active_view == RELAXED_ALL ||
423 approx_active_view == MIXED_ALL ) ) { // All to All
424 // unusual case: Surrogate-based DACE,PStudy
425 // there are no inactive vars
426 }
427 else if ( approx_active_view >= RELAXED_DESIGN &&
428 ( sub_model_active_view == RELAXED_ALL ||
429 sub_model_active_view == MIXED_ALL ) ) { // Distinct to All
430 // OUU: force rebuild over {u}+{d} for each new TR of {d}
431 }
432 else if ( ( approx_active_view == RELAXED_ALL ||
433 approx_active_view == MIXED_ALL ) &&
434 sub_model_active_view >= RELAXED_DESIGN ) { // All->Distinct
435 // unusual case: approx over subset of active top-level vars
436 if (inactive_values_differ)
437 return true;
438 }
439 }
440 */
441 }
442
443 return false; // no rebuild required
444 }
445
446
447 void SurrogateModel::
asv_split(const ShortArray & orig_asv,ShortArray & actual_asv,ShortArray & approx_asv,bool build_flag)448 asv_split(const ShortArray& orig_asv, ShortArray& actual_asv,
449 ShortArray& approx_asv, bool build_flag)
450 {
451 size_t i, num_qoi = qoi();
452 switch (responseMode) {
453 case AGGREGATED_MODELS: {
454 // split actual & approx asv (can ignore build_flag)
455 if (orig_asv.size() != 2*num_qoi) {
456 Cerr << "Error: ASV not aggregated for AGGREGATED_MODELS mode in "
457 << "SurrogateModel::asv_split()." << std::endl;
458 abort_handler(MODEL_ERROR);
459 }
460 approx_asv.resize(num_qoi); actual_asv.resize(num_qoi);
461 // aggregated response uses {HF,LF} order:
462 for (i=0; i<num_qoi; ++i)
463 actual_asv[i] = orig_asv[i];
464 for (i=0; i<num_qoi; ++i)
465 approx_asv[i] = orig_asv[i+num_qoi];
466 break;
467 }
468 default: // non-aggregated modes have consistent ASV request vector lengths
469 if (surrogateFnIndices.size() == num_qoi) {
470 if (build_flag) actual_asv = orig_asv;
471 else approx_asv = orig_asv;
472 }
473 // else response set is mixed:
474 else if (build_flag) { // construct mode: define actual_asv
475 actual_asv.assign(num_qoi, 0);
476 for (ISIter it=surrogateFnIndices.begin();
477 it!=surrogateFnIndices.end(); ++it)
478 actual_asv[*it] = orig_asv[*it];
479 }
480 else { // eval mode: define actual_asv & approx_asv contributions
481 for (i=0; i<num_qoi; ++i) {
482 short orig_asv_val = orig_asv[i];
483 if (orig_asv_val) {
484 if (surrogateFnIndices.count(i)) {
485 if (approx_asv.empty()) // keep empty if no active requests
486 approx_asv.assign(num_qoi, 0);
487 approx_asv[i] = orig_asv_val;
488 }
489 else {
490 if (actual_asv.empty()) // keep empty if no active requests
491 actual_asv.assign(num_qoi, 0);
492 actual_asv[i] = orig_asv_val;
493 }
494 }
495 }
496 }
497 break;
498 }
499 }
500
501
502 void SurrogateModel::
asv_combine(const ShortArray & actual_asv,const ShortArray & approx_asv,ShortArray & combined_asv)503 asv_combine(const ShortArray& actual_asv, const ShortArray& approx_asv,
504 ShortArray& combined_asv)
505 {
506 if (actual_asv.empty())
507 combined_asv = approx_asv;
508 else if (approx_asv.empty())
509 combined_asv = actual_asv;
510 else {
511 combined_asv.resize(numFns);
512 for (size_t i=0; i<numFns; ++i)
513 combined_asv[i] = (surrogateFnIndices.count(i)) ?
514 approx_asv[i] : actual_asv[i];
515 }
516 }
517
518
519 void SurrogateModel::
response_combine(const Response & actual_response,const Response & approx_response,Response & combined_response)520 response_combine(const Response& actual_response,
521 const Response& approx_response, Response& combined_response)
522 {
523 const ShortArray& actual_asv = actual_response.active_set_request_vector();
524 const ShortArray& approx_asv = approx_response.active_set_request_vector();
525 ShortArray combined_asv;
526 if (combined_response.is_null()) {
527 combined_response = currentResponse.copy();
528 asv_combine(actual_asv, approx_asv, combined_asv);
529 combined_response.active_set_request_vector(combined_asv);
530 }
531 else
532 combined_asv = combined_response.active_set_request_vector();
533
534 if (approx_asv.empty())
535 combined_response.update(actual_response);
536 else if (actual_asv.empty())
537 combined_response.update(approx_response);
538 else { // combined
539 const RealVector& actual_fns = actual_response.function_values();
540 const RealVector& approx_fns = approx_response.function_values();
541 //const RealMatrix& actual_grads = actual_response.function_gradients();
542 //const RealMatrix& approx_grads = approx_response.function_gradients();
543 const RealSymMatrixArray& actual_hessians
544 = actual_response.function_hessians();
545 const RealSymMatrixArray& approx_hessians
546 = approx_response.function_hessians();
547 for (size_t i=0; i<numFns; i++) {
548 if (surrogateFnIndices.count(i)) {
549 if (combined_asv[i] & 1)
550 combined_response.function_value(approx_fns[i], i);
551 if (combined_asv[i] & 2)
552 combined_response.function_gradient(
553 approx_response.function_gradient_view(i), i);
554 if (combined_asv[i] & 4)
555 combined_response.function_hessian(approx_hessians[i], i);
556 }
557 else {
558 if (combined_asv[i] & 1)
559 combined_response.function_value(actual_fns[i], i);
560 if (combined_asv[i] & 2)
561 combined_response.function_gradient(
562 actual_response.function_gradient_view(i), i);
563 if (combined_asv[i] & 4)
564 combined_response.function_hessian(actual_hessians[i], i);
565 }
566 }
567 }
568 }
569
570
571 void SurrogateModel::
aggregate_response(const Response & hf_resp,const Response & lf_resp,Response & agg_resp)572 aggregate_response(const Response& hf_resp, const Response& lf_resp,
573 Response& agg_resp)
574 {
575 if (agg_resp.is_null())
576 agg_resp = currentResponse.copy(); // resized to 2x in resize_response()
577
578 const ShortArray& lf_asv = lf_resp.active_set_request_vector();
579 const ShortArray& hf_asv = hf_resp.active_set_request_vector();
580 ShortArray agg_asv = agg_resp.active_set_request_vector();
581 size_t i, offset_i, num_lf_fns = lf_asv.size(), num_hf_fns = hf_asv.size();
582 short asv_i;
583
584 // Order with HF first since it corresponds to the active model key
585 for (i=0; i<num_hf_fns; ++i) {
586 agg_asv[i] = asv_i = hf_asv[i];
587 if (asv_i & 1) agg_resp.function_value(hf_resp.function_value(i), i);
588 if (asv_i & 2)
589 agg_resp.function_gradient(hf_resp.function_gradient_view(i), i);
590 if (asv_i & 4)
591 agg_resp.function_hessian(hf_resp.function_hessian(i), i);
592 }
593
594 // Order with LF second since it corresponds to a previous/decremented key
595 for (i=0; i<num_lf_fns; ++i) {
596 offset_i = i + num_hf_fns;
597 agg_asv[offset_i] = asv_i = lf_asv[i];
598 if (asv_i & 1) agg_resp.function_value(lf_resp.function_value(i), offset_i);
599 if (asv_i & 2)
600 agg_resp.function_gradient(lf_resp.function_gradient_view(i), offset_i);
601 if (asv_i & 4)
602 agg_resp.function_hessian(lf_resp.function_hessian(i), offset_i);
603 }
604
605 agg_resp.active_set_request_vector(agg_asv);
606 }
607
608 } // namespace Dakota
609