Ice Sheet System Model  4.18
Code documentation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
dakota_core.cpp
Go to the documentation of this file.
1 
29  /* \brief: run core ISSM solution using Dakota inputs coming from CPU 0.
30  * \sa qmu.cpp DakotaPlugin.cpp
31  *
32  * This routine needs to be understood simultaneously with qmu.cpp and DakotaPlugin.
33  * DakotaSpawnCoreParallel is called by all CPUS, with CPU 0 holding Dakota variable values, along
34  * with variable descriptors.
35  *
36  * DakotaSpawnCoreParallel takes care of broadcasting the variables and their descriptors across the MPI
37  * ring. Once this is done, we use the variables to modify the inputs for the solution core.
38  * For ex, if "rho_ice" is provided, for ex 920, we include "rho_ice" in the inputs, then
39  * call the core with the modified inputs. This is the way we get Dakota to explore the parameter
40  * space of the core.
41  *
42  * Once the core is called, we process the results of the core, and using the processed results,
43  * we compute response functions. The responses are computed on all CPUS, but they are targeted
44  * for CPU 0, which will get these values back to the Dakota engine.
45  *
46  */
47 
48 /*include config: {{{*/
49 #ifdef HAVE_CONFIG_H
50 #include <config.h>
51 #else
52 #error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
53 #endif
54 /*}}}*/
55 
56 /*include ISSM files: */
57 #include "./cores.h"
58 #include "../toolkits/toolkits.h"
59 #include "../shared/shared.h"
60 #include "../classes/classes.h"
61 #include "../modules/modules.h"
62 
63 #if defined(_HAVE_DAKOTA_) && (_DAKOTA_MAJOR_ <= 5) //this only works for Dakota <=5, which had no effective parallel capabilities yet.
64 /*Dakota include files:{{{*/
65 #if (_DAKOTA_MAJOR_ < 5 || (_DAKOTA_MAJOR_ == 5 && _DAKOTA_MINOR_ < 3))
66 #include <ParallelLibrary.H>
67 #include <ProblemDescDB.H>
68 #include <DakotaStrategy.H>
69 #include <DakotaModel.H>
70 #include <DakotaInterface.H>
71 #else
72 #include <ParallelLibrary.hpp>
73 #include <ProblemDescDB.hpp>
74 #include <DakotaStrategy.hpp>
75 #include <DakotaModel.hpp>
76 #include <DakotaInterface.hpp>
77 #endif
78 /*}}}*/
79 
80 void DakotaFree(double** pvariables,char*** pvariables_descriptors,char*** presponses_descriptors,int numvariables,int numresponses){ /*{{{*/
81 
82  /*\brief DakotaFree: free allocations on other CPUs, not done by Dakota.*/
83 
84  int i;
85  int my_rank;
86 
87  double *variables = NULL;
88  char **variables_descriptors = NULL;
89  char **responses_descriptors = NULL;
90  char *string = NULL;
91 
92  /*recover pointers: */
93  variables=*pvariables;
94  variables_descriptors=*pvariables_descriptors;
95  responses_descriptors=*presponses_descriptors;
96 
97  /*recover my_rank:*/
98  my_rank=IssmComm::GetRank();
99 
100  /*Free variables and variables_descriptors only on CPU !=0*/
101  if(my_rank!=0){
102  xDelete<double>(variables);
103  for(i=0;i<numvariables;i++){
104  string=variables_descriptors[i];
105  xDelete<char>(string);
106  }
107  xDelete<char*>(variables_descriptors);
108  }
109 
110  //responses descriptors on every CPU
111  for(i=0;i<numresponses;i++){
112  string=responses_descriptors[i];
113  xDelete<char>(string);
114  }
115  //rest of dynamic allocations.
116  xDelete<char*>(responses_descriptors);
117 
118  /*Assign output pointers:*/
119  *pvariables=variables;
120  *pvariables_descriptors=variables_descriptors;
121  *presponses_descriptors=responses_descriptors;
122 } /*}}}*/
123 void DakotaMPI_Bcast(double** pvariables, char*** pvariables_descriptors,int* pnumvariables, int* pnumresponses){ /*{{{*/
124 
125  /* * \brief: broadcast variables_descriptors, variables, numvariables and numresponses
126  * from CPU 0 to all other CPUs.
127  */
128 
129  int i;
130  int my_rank;
131 
132  /*inputs and outputs: */
133  double* variables=NULL;
134  char** variables_descriptors=NULL;
135  int numvariables;
136  int numresponses;
137 
138  /*intermediary: */
139  char* string=NULL;
140  int string_length;
141 
142  /*recover my_rank:*/
143  my_rank=IssmComm::GetRank();
144 
145  /*recover inputs from pointers: */
146  variables=*pvariables;
147  variables_descriptors=*pvariables_descriptors;
148  numvariables=*pnumvariables;
149  numresponses=*pnumresponses;
150 
151  /*numvariables: */
152  ISSM_MPI_Bcast(&numvariables,1,ISSM_MPI_INT,0,IssmComm::GetComm());
153 
154  /*variables:*/
155  if(my_rank!=0)variables=xNew<double>(numvariables);
156  ISSM_MPI_Bcast(variables,numvariables,MPI_DOUBLE,0,IssmComm::GetComm());
157 
158  /*variables_descriptors: */
159  if(my_rank!=0){
160  variables_descriptors=xNew<char*>(numvariables);
161  }
162  for(i=0;i<numvariables;i++){
163  if(my_rank==0){
164  string=variables_descriptors[i];
165  string_length=(strlen(string)+1)*sizeof(char);
166  }
167  ISSM_MPI_Bcast(&string_length,1,ISSM_MPI_INT,0,IssmComm::GetComm());
168  if(my_rank!=0)string=xNew<char>(string_length);
169  ISSM_MPI_Bcast(string,string_length,ISSM_MPI_CHAR,0,IssmComm::GetComm());
170  if(my_rank!=0)variables_descriptors[i]=string;
171  }
172 
173  /*numresponses: */
174  ISSM_MPI_Bcast(&numresponses,1,ISSM_MPI_INT,0,IssmComm::GetComm());
175 
176  /*Assign output pointers:*/
177  *pnumvariables=numvariables;
178  *pvariables=variables;
179  *pvariables_descriptors=variables_descriptors;
180  *pnumresponses=numresponses;
181 } /*}}}*/
182 int DakotaSpawnCore(double* d_responses, int d_numresponses, double* d_variables, char** d_variables_descriptors,int d_numvariables, void* void_femmodel,int counter){ /*{{{*/
183 
184  /*Notice the d_, which prefixes anything that is being provided to us by the Dakota plugin. Careful: some things are ours; some are DDkota's!: */
185 
186  char **responses_descriptors = NULL; //these are our! there are only numresponsedescriptors of them, not d_numresponses!!!
187  int numresponsedescriptors;
188  int solution_type;
189  bool control_analysis = false;
190  void (*solutioncore)(FemModel*) = NULL;
191  FemModel *femmodel = NULL;
192  bool nodakotacore = true;
193 
194  /*If counter==-1 on CPU 0, it means that the Dakota runs are done. In which case, bail out and return 0: */
196  if(counter==-1)return 0;
197 
198  /*cast void_femmodel to FemModel, and at the same time, make a copy, so we start this new core run for this specific sample
199  *with a brand new copy of the model, which has not been tempered with by previous Dakota runs: */
200  femmodel=(reinterpret_cast<FemModel*>(void_femmodel))->copy();
201 
202  /*retrieve parameters: */
203  femmodel->parameters->FindParam(&responses_descriptors,&numresponsedescriptors,QmuResponsedescriptorsEnum);
204  femmodel->parameters->FindParam(&solution_type,SolutionTypeEnum);
206 
207  if(VerboseQmu()) _printf0_("qmu iteration: " << counter << "\n");
208 
209  /* only CPU 0, running Dakota is providing us with variables and variables_descriptors and numresponses: broadcast onto other CPUs: */
210  DakotaMPI_Bcast(&d_variables,&d_variables_descriptors,&d_numvariables,&d_numresponses);
211 
212  /*Modify core inputs in objects contained in femmodel, to reflect the dakota variables inputs: */
213  InputUpdateFromDakotax(femmodel,d_variables,d_variables_descriptors,d_numvariables);
214 
215  /*Determine solution sequence: */
216  if(VerboseQmu()) _printf0_("Starting " << EnumToStringx(solution_type) << " core:\n");
217  WrapperCorePointerFromSolutionEnum(&solutioncore,femmodel->parameters,solution_type,nodakotacore);
218 
219  /*Run the core solution sequence: */
220  solutioncore(femmodel);
221 
222  /*compute responses: */
223  if(VerboseQmu()) _printf0_("compute dakota responses:\n");
224  femmodel->DakotaResponsesx(d_responses,responses_descriptors,numresponsedescriptors,d_numresponses);
225 
226  /*output for this core:*/
227  if(VerboseQmu()) _printf0_("outputing results for this core:\n");
229 
230  /*Free ressources:*/
231  DakotaFree(&d_variables,&d_variables_descriptors,&responses_descriptors, d_numvariables, numresponsedescriptors);
232 
233  /*Avoid leaks here: */
234  delete femmodel;
235 
236  return 1; //this is critical! do not return 0, otherwise, dakota_core will stop running!
237 }
238 /*}}}*/
239 void dakota_core(FemModel* femmodel){ /*{{{*/
240 
241  int my_rank;
242  char *dakota_input_file = NULL;
243  char *dakota_output_file = NULL;
244  char *dakota_error_file = NULL;
245  Dakota::ModelLIter ml_iter;
246 
247  /*Recover dakota_input_file, dakota_output_file and dakota_error_file, in the parameters dataset in parallel */
248  femmodel->parameters->FindParam(&dakota_input_file,QmuInNameEnum);
249  femmodel->parameters->FindParam(&dakota_output_file,QmuOutNameEnum);
250  femmodel->parameters->FindParam(&dakota_error_file,QmuErrNameEnum);
251 
252  /*recover my_rank:*/
253  my_rank=IssmComm::GetRank();
254 
255  if(my_rank==0){
256 
257  // Instantiate/initialize the parallel library and problem description
258  // database objects.
259  char* dakotamode=xNew<char>(strlen("serial")+1);
260  xMemCpy<char>(dakotamode,"serial",strlen("serial")+1);
261  Dakota::ParallelLibrary parallel_lib(dakotamode); //use our own ISSM Dakota library mode constructor, which only fires up Dakota on CPU 0.
262  Dakota::ProblemDescDB problem_db(parallel_lib);
263  xDelete<char>(dakotamode);
264 
265  // Manage input file parsing, output redirection, and restart processing
266  // without a CommandLineHandler. This version relies on parsing of an
267  // input file.
268  problem_db.manage_inputs(dakota_input_file);
269  // specify_outputs_restart() is only necessary if specifying non-defaults
270  parallel_lib.specify_outputs_restart(dakota_output_file,dakota_error_file,NULL,NULL);
271 
272  // Instantiate the Strategy object (which instantiates all Model and
273  // Iterator objects) using the parsed information in problem_db.
274  Dakota::Strategy selected_strategy(problem_db);
275 
276  // convenience function for iterating over models and performing any
277  // interface plug-ins
278  Dakota::ModelList& models = problem_db.model_list();
279 
280  for (ml_iter = models.begin(); ml_iter != models.end(); ml_iter++) {
281 
282  Dakota::Interface& interface = ml_iter->interface();
283 
284  //set DB nodes to the existing Model specification
285  problem_db.set_db_model_nodes(ml_iter->model_id());
286 
287  // Serial case: plug in derived Interface object without an analysisComm
288  interface.assign_rep(new SIM::IssmDirectApplicInterface(problem_db,(void*)femmodel), false);
289  }
290 
291  // Execute the strategy
292  problem_db.lock(); // prevent run-time DB queries
293  selected_strategy.run_strategy();
294 
295  //Warn other CPUs that we are done running the Dakota iterator, by setting the counter to -1:
296  DakotaSpawnCore(NULL,0, NULL,NULL,0,femmodel,-1);
297 
298  }
299  else{
300 
301  for(;;){
302  if(!DakotaSpawnCore(NULL,0, NULL,NULL,0,femmodel,0)) break; //counter came in at -1 on CPU 0, bail out.
303  }
304  }
305 
306  /*Free resources:*/
307  xDelete<char>(dakota_input_file);
308  xDelete<char>(dakota_error_file);
309  xDelete<char>(dakota_output_file);
310 
311 } /*}}}*/
312 #else
314  _error_("dakota_core for versions of Dakota >=6 should not be used anymore! Use instead the issm_dakota executable!");
315 }
316 #endif
QmuErrNameEnum
@ QmuErrNameEnum
Definition: EnumDefinitions.h:286
OutputResultsx
void OutputResultsx(FemModel *femmodel)
Definition: OutputResultsx.cpp:17
QmuOutNameEnum
@ QmuOutNameEnum
Definition: EnumDefinitions.h:289
_printf0_
#define _printf0_(StreamArgs)
Definition: Print.h:29
cores.h
FemModel::parameters
Parameters * parameters
Definition: FemModel.h:46
IssmComm::GetComm
static ISSM_MPI_Comm GetComm(void)
Definition: IssmComm.cpp:30
InversionIscontrolEnum
@ InversionIscontrolEnum
Definition: EnumDefinitions.h:218
VerboseQmu
bool VerboseQmu(void)
Definition: Verbosity.cpp:28
QmuInNameEnum
@ QmuInNameEnum
Definition: EnumDefinitions.h:287
ISSM_MPI_INT
#define ISSM_MPI_INT
Definition: issmmpi.h:127
EnumToStringx
const char * EnumToStringx(int enum_in)
Definition: EnumToStringx.cpp:15
QmuResponsedescriptorsEnum
@ QmuResponsedescriptorsEnum
Definition: EnumDefinitions.h:292
SolutionTypeEnum
@ SolutionTypeEnum
Definition: EnumDefinitions.h:398
WrapperCorePointerFromSolutionEnum
void WrapperCorePointerFromSolutionEnum(void(**psolutioncore)(FemModel *), Parameters *parameters, int solutiontype, bool nodakotacore=false)
Definition: WrapperCorePointerFromSolutionEnum.cpp:17
ISSM_MPI_Bcast
int ISSM_MPI_Bcast(void *buffer, int count, ISSM_MPI_Datatype datatype, int root, ISSM_MPI_Comm comm)
Definition: issmmpi.cpp:162
FemModel
Definition: FemModel.h:31
IssmComm::GetRank
static int GetRank(void)
Definition: IssmComm.cpp:34
ISSM_MPI_CHAR
#define ISSM_MPI_CHAR
Definition: issmmpi.h:124
dakota_core
void dakota_core(FemModel *femmodel)
Definition: dakota_core.cpp:313
_error_
#define _error_(StreamArgs)
Definition: exceptions.h:49
InputUpdateFromDakotax
void InputUpdateFromDakotax(FemModel *femmodel, double *variables, char **variables_descriptors, int numdakotavariables)
Definition: InputUpdateFromDakotax.cpp:12
Parameters::FindParam
void FindParam(bool *pinteger, int enum_type)
Definition: Parameters.cpp:262
FemModel::copy
FemModel * copy()
Definition: FemModel.cpp:320
femmodel
FemModel * femmodel
Definition: esmfbinders.cpp:16