OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
OPAL
Sampler.cpp
Go to the documentation of this file.
1 //
2 // Class Sampler
3 // This class creates, dispatches and dumps new individuals.
4 //
5 // Copyright (c) 2018, Matthias Frey, Paul Scherrer Institut, Villigen PSI, Switzerland
6 // Yves Ineichen, ETH Zürich
7 // All rights reserved
8 //
9 // Implemented as part of the PhD thesis
10 // "Precise Simulations of Multibunches in High Intensity Cyclotrons"
11 //
12 // This file is part of OPAL.
13 //
14 // OPAL is free software: you can redistribute it and/or modify
15 // it under the terms of the GNU General Public License as published by
16 // the Free Software Foundation, either version 3 of the License, or
17 // (at your option) any later version.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with OPAL. If not, see <https://www.gnu.org/licenses/>.
21 //
22 #include <iostream>
23 #include <string>
24 #include <limits>
25 
26 #include "Sample/Sampler.h"
27 
28 #include "OPALconfig.h"
29 #include "Utilities/Util.h"
30 
31 #include "Util/OptPilotException.h"
32 #include "Util/MPIHelper.h"
33 
34 #include <boost/property_tree/json_parser.hpp>
35 #include <boost/property_tree/ptree.hpp>
36 
37 #include <boost/filesystem.hpp>
38 
40  Expressions::Named_t /*constraints*/,
41  DVarContainer_t /*dvars*/,
42  size_t /*dim*/, Comm::Bundle_t comms,
43  CmdArguments_t /*args*/,
44  std::vector<double> /*hypervolRef*/,
45  int /*nrWorkerGroups*/)
46  : Optimizer(comms.opt)
47 {
48  throw OptPilotException("Sampler::Sampler",
49  "We shouldn't get here!");
50 }
51 
52 
53 Sampler::Sampler(const std::map<std::string,
54  std::shared_ptr<SamplingMethod>
55  >& sampleMethods,
56  Expressions::Named_t objectives,
57  DVarContainer_t dvars,
58  Comm::Bundle_t comms,
59  CmdArguments_t args)
60  : Optimizer(comms.opt)
61  , sampleMethods_m(sampleMethods)
62  , comms_(comms)
63  , dvars_m(dvars)
64  , objectives_m(objectives)
65  , args_(args)
66 {
67  my_local_pid_ = 0;
68  MPI_Comm_rank(comms_.opt, &my_local_pid_);
69 
70  std::string resultFile = args->getArg<std::string>("outfile", "output", false);
71  std::string resultDir = args->getArg<std::string>("outdir", "samples", false);
72  jsonDumpFreq_m = args->getArg<std::size_t>("jsonDumpFreq", true);
73 
74  std::ostringstream filename;
75  filename << resultDir << "/" << resultFile
76  << "_samples_" << comms_.island_id << ".json";
77  jsonFname_m = filename.str();
78 
79  if ( !boost::filesystem::exists(resultDir) ) {
80  boost::filesystem::create_directory(resultDir);
81  }
82 
84  for(itr = dvars_m.begin(); itr != dvars_m.end(); itr++) {
85  dVarBounds_m.push_back(
86  std::pair<double, double>
87  (boost::get<LOWER_BOUND>(itr->second),
88  boost::get<UPPER_BOUND>(itr->second)));
89  }
90 
92 }
93 
94 
96 
97  nSamples_m = args_->getArg<int>("nsamples", true);
98  act_sample_m = 0;
99  done_sample_m = 0;
100  curState_m = SUBMIT;
101 
102  int nMasters = args_->getArg<int>("num-masters", true);
103 
104  if ( nMasters > nSamples_m )
105  throw OptPilotException("Sampler::initialize",
106  "More masters than samples.");
107 
108  // unique job id
109  int nLocSamples = nSamples_m / nMasters;
110  int rest = nSamples_m - nMasters * nLocSamples;
111 
112  if ( comms_.island_id < rest )
113  nLocSamples++;
114 
115  if ( rest == 0 )
116  gid = nLocSamples * comms_.island_id;
117  else {
118  if ( comms_.island_id < rest ) {
119  gid = nLocSamples * comms_.island_id;
120  } else {
121  gid = (nLocSamples + 1) * rest + (comms_.island_id - rest) * nLocSamples;
122  }
123  }
124 
125  nSamples_m = nLocSamples;
126 
127  // start poll loop
128  run();
129 }
130 
131 
132 bool Sampler::onMessage(MPI_Status status, size_t length) {
133  MPITag_t tag = MPITag_t(status.MPI_TAG);
134  switch(tag) {
135  case REQUEST_FINISHED: {
136  unsigned int jid = static_cast<unsigned int>(length);
137  typename std::map<size_t, boost::shared_ptr<Individual_t> >::iterator it;
138  it = jobmapping_m.find(jid);
139 
140  if(it == jobmapping_m.end()) {
141  std::cout << "NON-EXISTING JOB with ID = " << jid << std::endl;
142  throw OptPilotException("Sampler::onMessage",
143  "non-existing job");
144  }
145 
146 
147  boost::shared_ptr<Individual_t> ind = it->second;
148 
149  reqVarContainer_t res;
150  MPI_Recv_reqvars(res, status.MPI_SOURCE, comms_.opt);
151 
152  ind->objectives.clear();
153 
154  reqVarContainer_t::iterator itr = res.begin();
155  for(; itr != res.end(); ++itr) {
156  // mark invalid if expression could not be evaluated or constraint does not hold
157  if(!itr->second.is_valid || (itr->second.value.size() > 1 && !itr->second.value[0])) {
158  ind->objectives.push_back(std::numeric_limits<double>::infinity());
159  } else {
160  // update objective value for valid objective
161  if(itr->second.value.size() == 1)
162  ind->objectives.push_back(itr->second.value[0]);
163  }
164  }
165 
166  addIndividualToJSON(ind);
167 
168  jobmapping_m.erase(it);
169 
170  done_sample_m++;
171 
172  return true;
173  }
174  default: {
175  std::cout << "(Sampler) Error: unexpected MPI_TAG: "
176  << status.MPI_TAG << std::endl;
177  return false;
178  }
179  }
180 }
181 
182 
184 
185  if ( act_sample_m < nSamples_m ) {
186  this->createNewIndividual();
187  }
188 
189  runStateMachine();
190 }
191 
192 
194 
195  std::vector<std::string> dNames;
196 
198  for(itr = dvars_m.begin(); itr != dvars_m.end(); itr++) {
199  std::string dName = boost::get<VAR_NAME>(itr->second);
200  dNames.push_back(dName);
201  }
202 
203  boost::shared_ptr<Individual_t> ind = boost::shared_ptr<Individual_t>( new Individual_t(dNames));
204 
205  ind->id = gid++;
206 
207  for(itr = dvars_m.begin(); itr != dvars_m.end(); itr++) {
208  std::string dName = boost::get<VAR_NAME>(itr->second);
209  int i = ind->getIndex(dName);
210  sampleMethods_m[dName]->create(ind, i);
211  }
212 
213 
214  individuals_m.push(ind);
215 }
216 
217 
219  namespace pt = boost::property_tree;
220 
221  pt::ptree tree;
222 
223  tree.put("name", "sampler");
224  tree.put(OPAL_PROJECT_NAME " version", OPAL_PROJECT_VERSION);
225  tree.put("git revision", Util::getGitRevision());
226 
227  std::stringstream bounds;
228  DVarContainer_t::iterator itr = dvars_m.begin();
229  for (bounds_t::iterator it = dVarBounds_m.begin();
230  it != dVarBounds_m.end(); ++it, ++itr)
231  {
232  std::string dvar = boost::get<VAR_NAME>(itr->second);
233  bounds << "[ " << it->first << ", " << it->second << " ]";
234  tree.put("dvar-bounds." + dvar, bounds.str());
235  bounds.str("");
236  }
237 
238  pt::write_json(jsonFname_m, tree);
239 }
240 
241 
243 
244  if (individualsToDump_m.empty()) {
245  return;
246  }
247 
248  namespace pt = boost::property_tree;
249 
250  pt::ptree tree;
251  pt::read_json(jsonFname_m, tree);
252 
253  pt::ptree samples;
254 
255  if ( tree.get_optional<std::string>("samples") ) {
256  /* we already have individuals in the JSON
257  * file
258  */
259  samples = tree.get_child("samples");
260  tree.erase("samples");
261  }
262 
263  while (!individualsToDump_m.empty()) {
264  Individual_t ind = individualsToDump_m.front();
265  individualsToDump_m.pop_front();
266 
267  std::string id = std::to_string(ind.id);
268 
270  for(itr = dvars_m.begin(); itr != dvars_m.end(); itr++) {
271  std::string name = boost::get<VAR_NAME>(itr->second);
272  int i = ind.getIndex(name);
273  samples.put(id + ".dvar." + name, ind.genes[i]);
274  }
275 
277  expr_it = objectives_m.begin();
278 
279  for(size_t i=0; i < ind.objectives.size(); i++, expr_it++) {
280  std::string name = expr_it->first;
281 
282  // skip dummy objective (in constructor of SamplePilot.h)
283  if ( name == "dummy" )
284  continue;
285 
286  samples.put(id + ".obj." + name, ind.objectives[i]);
287  }
288  }
289 
290  tree.add_child("samples", samples);
291  boost::property_tree::write_json(jsonFname_m, tree);
292 }
293 
294 
295 void Sampler::addIndividualToJSON(const boost::shared_ptr<Individual_t>& ind) {
296  individualsToDump_m.push_back(*ind);
297 
298  if (jsonDumpFreq_m <= individualsToDump_m.size()) {
300  }
301 }
302 
303 
305 
306  switch(curState_m) {
307 
308  case SUBMIT: {
309  if ( done_sample_m == nSamples_m) {
310  curState_m = STOP;
311  } else {
312  if ( act_sample_m != nSamples_m ) {
314  }
315  }
316  break;
317  }
318  case STOP: {
319 
321 
323 
324  // notify pilot that we have converged
325  int dummy = 0;
326  MPI_Request req;
327  MPI_Isend(&dummy, 1, MPI_INT, comms_.master_local_pid,
329 
330  break;
331  }
332 
333  case TERMINATE: {
334  break;
335  }
336  }
337 }
338 
339 
341 
342  while ( !individuals_m.empty() ) {
343  boost::shared_ptr<Individual_t> ind = individuals_m.front();
344 
345  individuals_m.pop();
346 
347  Param_t params;
349 
350  for(itr = dvars_m.begin(); itr != dvars_m.end(); itr++) {
351  std::string dName = boost::get<VAR_NAME>(itr->second);
352  int i = ind->getIndex(dName);
353  params.insert(
354  std::pair<std::string, double>
355  (dName, ind->genes[i]));
356  }
357 
358  size_t jid = static_cast<size_t>(ind->id);
359  int pilot_rank = comms_.master_local_pid;
360 
361 
362  act_sample_m++;
363 
364  // now send the request to the pilot
365  MPI_Send(&jid, 1, MPI_UNSIGNED_LONG, pilot_rank, OPT_NEW_JOB_TAG, comms_.opt);
366 
367  MPI_Send_params(params, pilot_rank, comms_.opt);
368 
369  jobmapping_m.insert(
370  std::pair<size_t, boost::shared_ptr<Individual_t> >(jid, ind));
371  }
372 }
#define OPAL_PROJECT_VERSION
Definition: OPALconfig.h:5
#define OPAL_PROJECT_NAME
Definition: OPALconfig.h:2
void bounds(const PETE_Expr< T1 > &expr, Vektor< T2, D > &minval, Vektor< T2, D > &maxval)
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
const std::string name
boost::shared_ptr< CmdArguments > CmdArguments_t
Definition: CmdArguments.h:176
void MPI_Send_params(Param_t params, size_t pid, MPI_Comm comm)
Definition: MPIHelper.cpp:87
void MPI_Recv_reqvars(reqVarContainer_t &reqvars, size_t pid, MPI_Comm comm)
Definition: MPIHelper.cpp:165
#define MPI_OPT_CONVERGED_TAG
optimizer notifies pilot that optimization has converged (EXIT)
Definition: MPIHelper.h:48
MPITag_t
Definition: MPIHelper.h:71
@ REQUEST_FINISHED
Definition: MPIHelper.h:76
@ OPT_NEW_JOB_TAG
Definition: MPIHelper.h:73
std::map< std::string, DVar_t > DVarContainer_t
Definition: Types.h:92
std::map< std::string, reqVarInfo_t > reqVarContainer_t
Definition: Types.h:79
namedVariableCollection_t Param_t
Definition: Types.h:48
std::map< std::string, Expressions::Expr_t * > Named_t
type of an expressions with a name
Definition: Expression.h:74
std::string::iterator iterator
Definition: MSLang.h:16
std::string getGitRevision()
Definition: Util.cpp:18
genes_t genes
genes of an individual
unsigned int id
id
int getIndex(std::string name)
objectives_t objectives
values of objectives of an individual
SampleIndividual Individual_t
Definition: Sampler.h:116
std::string jsonFname_m
Definition: Sampler.h:156
std::map< size_t, boost::shared_ptr< Individual_t > > jobmapping_m
mapping from unique job ID to individual
Definition: Sampler.h:122
int nSamples_m
Definition: Sampler.h:135
bool onMessage(MPI_Status status, size_t length)
Definition: Sampler.cpp:132
int done_sample_m
Definition: Sampler.h:144
void postPoll()
executed after handling (if any) new request
Definition: Sampler.cpp:183
int my_local_pid_
Definition: Sampler.h:114
State curState_m
Definition: Sampler.h:152
void dispatch_forward_solves()
Definition: Sampler.cpp:340
std::list< Individual_t > individualsToDump_m
Definition: Sampler.h:158
Expressions::Named_t objectives_m
objectives
Definition: Sampler.h:133
virtual void initialize()
Initialization and start algorithm.
Definition: Sampler.cpp:95
std::size_t jsonDumpFreq_m
Dumps id, design variables and bound.
Definition: Sampler.h:155
Comm::Bundle_t comms_
communicator bundle for the optimizer
Definition: Sampler.h:119
std::map< std::string, std::shared_ptr< SamplingMethod > > sampleMethods_m
Definition: Sampler.h:109
int gid
Definition: Sampler.h:112
DVarContainer_t dvars_m
design variables
Definition: Sampler.h:130
std::queue< boost::shared_ptr< Individual_t > > individuals_m
Definition: Sampler.h:124
void dumpIndividualsToJSON()
Definition: Sampler.cpp:242
CmdArguments_t args_
command line arguments specified by the user
Definition: Sampler.h:139
void runStateMachine()
Definition: Sampler.cpp:304
void writeJsonHeader()
Definition: Sampler.cpp:218
int act_sample_m
current generation
Definition: Sampler.h:142
void addIndividualToJSON(const boost::shared_ptr< Individual_t > &ind)
Definition: Sampler.cpp:295
@ STOP
Definition: Sampler.h:148
@ SUBMIT
Definition: Sampler.h:147
@ TERMINATE
Definition: Sampler.h:149
Sampler(Expressions::Named_t objectives, Expressions::Named_t constraints, DVarContainer_t dvars, size_t dim, Comm::Bundle_t comms, CmdArguments_t args, std::vector< double > hypervolRef, int nrWorkerGroups)
Definition: Sampler.cpp:39
void createNewIndividual()
Definition: Sampler.cpp:193
bounds_t dVarBounds_m
bounds on each specified gene
Definition: Sampler.h:127
bundles all communicators for a specific role/pid
Definition: types.h:32
int island_id
Definition: types.h:33
MPI_Comm opt
Definition: types.h:38
int master_local_pid
Definition: types.h:36
virtual void run()
Definition: Poller.h:79