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:       DataTransformModel
10 //- Description: Specialization of a RecastModel that manages the mapping from
11 //-              a simulation model to residuals based on data differencing.
12 //- Owner:       Brian Adams
13 //- Checked by:
14 //- Version: $Id$
15 
16 #ifndef DATA_TRANSFORM_MODEL_H
17 #define DATA_TRANSFORM_MODEL_H
18 
19 #include "RecastModel.hpp"
20 #include "dakota_results_types.hpp"
21 namespace Dakota {
22 
23 /// forward declarations
24 class ExperimentData;
25 class ResultsManager;
26 
27 // BMA TODO: Consider using separate RecastModel to include hyper-parameters
28 
29 /// Data transformation specialization of RecastModel
30 
31 /** Specialization of RecastModel to create a residual model that maps
32     (1) from an augmented set of calibration parameters (including
33     hyper-parameters) to those needed by the underlying simulation
34     model and (2) from the simulation model response to a set of
35     residuals, whose overall size may differ from the simulation
36     (sub-model) response.  The residuals may be scaled by experiment
37     covariance information.  This class provides a simple constructor
38     that forwards to the more complicated RecastModel API */
39 class DataTransformModel: public RecastModel
40 {
41 public:
42 
43   //
44   //- Heading: Constructor and destructor
45   //
46 
47   /// standard constructor
48   DataTransformModel(const Model& sub_model, const ExperimentData& exp_data,
49                      size_t num_hyper = 0,
50                      unsigned short mult_mode = CALIBRATE_NONE,
51                      short recast_resp_deriv_order = 1);
52 
53   /// destructor
54   ~DataTransformModel();
55 
56   /// Convenience function to help recover a residual response from the submodel
57   void data_transform_response(const Variables& sub_model_vars,
58                                const Response& sub_model_resp,
59                                Response& residual_resp);
60 
61   /// The size of the ExperimentData changed; update the residualModel size
62   void data_resize();
63 
64 
65   /// manage best responses including residuals and model responses per config
66   void print_best_responses(std::ostream& s,
67                             const Variables& best_submodel_vars,
68                             const Response& best_submodel_resp,
69                             size_t num_best, size_t best_ind);
70 
71   /// archive best responses
72   void archive_best_responses(const ResultsManager &results_db,
73                               const StrStrSizet iterator_id,
74                               const Variables& best_submodel_vars,
75                               const Response& best_submodel_resp,
76                               size_t num_best, size_t best_ind);
77 
78   /// return number of configuration variables
79   int num_config_vars() const;
80 
81 protected:
82 
83   void assign_instance();
84 
85   void update_from_subordinate_model(size_t depth =
86 				     std::numeric_limits<size_t>::max());
87 
88   // ---
89   // Construct time convenience functions
90   // ---
91 
92   /// expand the variable counts to account for hyper-parameters
93   static SizetArray variables_expand(const Model& sub_model, size_t num_hyper);
94 
95   /// determine the index into vc_totals corresponding to where the
96   /// hyper-parameters go
97   static int get_hyperparam_vc_index(const Model& sub_model);
98 
99   /// helper to compute the recast response order during member
100   /// initialization; recast_resp_order passed is the minimum request
101   /// client needs
102   static short response_order(const Model& sub_model,
103                               short recast_resp_order = 1);
104 
105   /// compute the primary response map for a data transform RecastModel
106   void gen_primary_resp_map(const SharedResponseData& srd,
107 			    Sizet2DArray& primary_resp_map_indices,
108 			    BoolDequeArray& nonlinear_resp_map) const;
109 
110   /// specialization of evaluate that iterates over configuration variables
111   void derived_evaluate(const ActiveSet& set);
112   /// specialization of evaluate that iterates over configuration variables
113   void derived_evaluate_nowait(const ActiveSet& set);
114 
115   /// synchronize all evaluations (all residuals for all experiment
116   /// configurations)
117   const IntResponseMap& derived_synchronize();
118 
119   /// return any evaluations for which all experiment configurations
120   /// have completed
121   const IntResponseMap& derived_synchronize_nowait();
122 
123   // Synchronize the subModel and filter the IntResponseMap in-place,
124   // caching any that we didn't schedule.
125   const IntResponseMap& filter_submodel_responses();
126 
127   /// cache the subModel responses into a per-RecastModel eval ID map
128   void cache_submodel_responses(const IntResponseMap& sm_resp_map,
129                                 bool deep_copy);
130 
131   /// collect any (or force all) completed subModel evals and populate
132   /// recastResponseMap with residuals for those that are fully completed
133   void collect_residuals(bool collect_all);
134 
135   /// transform a set of per-configuration subModel Responses to a
136   /// single evaluation's residuals
137   void transform_response_map(const IntResponseMap& submodel_resp,
138 			      const Variables& recast_vars,
139 			      Response& residual_resp) ;
140 
141   // ---
142   // Callback functions that perform data transform during the Recast operations
143   // ---
144 
145   /// map the inbound expanded variables to the sub-model, discarding
146   /// hyperparams (assumes hyper-parameters are at end of active
147   /// continuous variables)
148   static void vars_mapping(const Variables& recast_vars,
149 			   Variables& submodel_vars);
150 
151   // BMA TODO: inverse isn't well-defined, but may need for active vars...
152 
153   /// map the inbound ActiveSet to the sub-model (map derivative variables)
154   static void set_mapping(const Variables& recast_vars,
155 			  const ActiveSet& recast_set,
156 			  ActiveSet& sub_model_set);
157 
158   // BMA TODO: shouldn't need static in this context; find another way
159   /// Recast callback function to difference residuals with observed data
160   static void primary_resp_differencer(const Variables& submodel_vars,
161 				       const Variables& recast_vars,
162 				       const Response& submodel_response,
163 				       Response& recast_response);
164 
165   /// scale the populated residual response by any covariance
166   /// information, including hyper-parameter multipliers
167   void scale_response(const Variables& submodel_vars,
168 		      const Variables& recast_vars,
169 		      Response& recast_response);
170 
171   // NOTE: Shouldn't need non-default active set or secondary response
172   // recast; default based on indices should suffice.
173 
174   /// Initialize continuous variable values/labels
175   void init_continuous_vars();
176 
177   // TODO: Update comments
178 
179   /// (if non-empty) expand submodel_array by replicates to populate a
180   /// recast_array
181 
182   /// If size greater than 1, expand submodel_array by replicates to
183   /// populate a pre-sized recast_array, otherwise copy
184 
185   template<typename T>
186   void expand_primary_array(size_t submodel_size, const T& submodel_array,
187 			    size_t recast_size, T& recast_array) const;
188 
189   void print_residual_response(const Response& resid_resp);
190 
191   void recover_submodel_responses(std::ostream& s,
192                                   const Variables& best_submodel_vars,
193                                   size_t num_best, size_t best_ind,
194                                   Response& residual_resp);
195 
196   /// archive original model responses
197   void archive_submodel_responses(const ResultsManager &results_db,
198                                   const StrStrSizet &iterator_id,
199                                   const Variables& best_submodel_vars,
200                                   size_t num_best, size_t best_ind,
201                                   Response& residual_resp);
202 
203 
204   /// Archive the best model reponses (undifferenced with experimental data) for
205   /// experiment exp_index and final solution soln_index.
206   void archive_best_original(const ResultsManager &results_db,
207                              const StrStrSizet &iterator_id,
208                              const RealVector &function_values,
209                              const int &exp_index, const int &num_best,
210                              const int &best_index);
211 
212   /// Archive the best configuration variables associated with each model response
213   void archive_best_config_variables(const ResultsManager &results_db,
214                              const StrStrSizet &iterator_id,
215                              const Variables &vars,
216                              const int &exp_index, const int &num_best,
217                              const int &best_index);
218 
219   /// Archive the best residuals
220   void archive_best_residuals(const ResultsManager &results_db,
221                               const StrStrSizet &iterator_id,
222                               const int num_fns,
223                               const RealVector &best_terms,
224                               const Real wssr, const int num_points,
225                               const int point_index);
226   /// Reference to the experiment data used to construct this Model
227   const ExperimentData& expData;
228 
229   /// static pointer to this class for use in static callbacks
230   static DataTransformModel* dtModelInstance;
231 
232   /// Number of calibrated variance multipliers
233   size_t numHyperparams;
234 
235   /// Calibration mode for the hyper-parameters
236   unsigned short obsErrorMultiplierMode;
237 
238   // BMA TODO: fix this terrible typedef
239   typedef std::map<int, IntResponseMap> IntIntResponseMapMap;
240   IntIntResponseMapMap cachedResp;
241 
242 };
243 
244 
assign_instance()245 inline void DataTransformModel::assign_instance()
246 { dtModelInstance = this; }
247 
248 
update_from_subordinate_model(size_t depth)249 inline void DataTransformModel::update_from_subordinate_model(size_t depth)
250 {
251   // data flows from the bottom-up, so recurse first
252   if (depth == std::numeric_limits<size_t>::max())
253     subModel.update_from_subordinate_model(depth); // retain special value (inf)
254   else if (depth)
255     subModel.update_from_subordinate_model(depth - 1); // decrement
256   //else depth exhausted --> update this level only
257 
258   // Instead of RecastModel::update_from_model(subModel), manage pieces
259   // of the base implementation to avoid indexing inconsistencies due to
260   // hyper-parameter insertion:
261 
262   bool update_active_complement = update_variables_from_model(subModel);
263   // Can't do this due if complement variables are re-indexed due to
264   // hyper-parameter insertion.
265   // *** TO DO: write new update fns for this type of variable growth -> don't
266   // *** break chain of updates for additional Model recursions above this one.
267   if (update_active_complement && !numHyperparams)
268     update_variables_active_complement_from_model(subModel);
269   update_response_from_model(subModel);
270 }
271 
272 } // namespace Dakota
273 
274 #endif
275