OPAL (Object Oriented Parallel Accelerator Library)  2024.1
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 <filesystem>
23 #include <iostream>
24 #include <string>
25 #include <limits>
26 
27 #include "Sample/Sampler.h"
28 
29 #include "OPALconfig.h"
30 #include "Utilities/Util.h"
31 
32 #include "Util/OptPilotException.h"
33 #include "Util/MPIHelper.h"
34 
35 #include <boost/property_tree/json_parser.hpp>
36 #include <boost/property_tree/ptree.hpp>
37 
39  Expressions::Named_t /*constraints*/,
40  DVarContainer_t /*dvars*/,
41  size_t /*dim*/, Comm::Bundle_t comms,
42  CmdArguments_t /*args*/,
43  std::vector<double> /*hypervolRef*/,
44  int /*nrWorkerGroups*/)
45  : Optimizer(comms.opt)
46 {
47  throw OptPilotException("Sampler::Sampler",
48  "We shouldn't get here!");
49 }
50 
51 
52 Sampler::Sampler(const std::map<std::string,
53  std::shared_ptr<SamplingMethod>
54  >& sampleMethods,
55  Expressions::Named_t objectives,
56  DVarContainer_t dvars,
57  Comm::Bundle_t comms,
58  CmdArguments_t args)
59  : Optimizer(comms.opt)
60  , sampleMethods_m(sampleMethods)
61  , comms_(comms)
62  , dvars_m(dvars)
63  , objectives_m(objectives)
64  , args_(args)
65 {
66  my_local_pid_ = 0;
67  MPI_Comm_rank(comms_.opt, &my_local_pid_);
68 
69  std::string resultFile = args->getArg<std::string>("outfile", "output", false);
70  std::string resultDir = args->getArg<std::string>("outdir", "samples", false);
71  jsonDumpFreq_m = args->getArg<std::size_t>("jsonDumpFreq", true);
72 
73  std::ostringstream filename;
74  filename << resultDir << "/" << resultFile
75  << "_samples_" << comms_.island_id << ".json";
76  jsonFname_m = filename.str();
77 
78  if ( !std::filesystem::exists(resultDir) ) {
79  std::filesystem::create_directory(resultDir);
80  }
81 
83  for(itr = dvars_m.begin(); itr != dvars_m.end(); itr++) {
84  dVarBounds_m.push_back(
85  std::pair<double, double>
86  (boost::get<LOWER_BOUND>(itr->second),
87  boost::get<UPPER_BOUND>(itr->second)));
88  }
89 
91 }
92 
93 
95 
96  nSamples_m = args_->getArg<int>("nsamples", true);
97  act_sample_m = 0;
98  done_sample_m = 0;
100 
101  int nMasters = args_->getArg<int>("num-masters", true);
102 
103  if ( nMasters > nSamples_m )
104  throw OptPilotException("Sampler::initialize",
105  "More masters than samples.");
106 
107  // unique job id
108  int nLocSamples = nSamples_m / nMasters;
109  int rest = nSamples_m - nMasters * nLocSamples;
110 
111  if ( comms_.island_id < rest )
112  nLocSamples++;
113 
114  if ( rest == 0 )
115  gid = nLocSamples * comms_.island_id;
116  else {
117  if ( comms_.island_id < rest ) {
118  gid = nLocSamples * comms_.island_id;
119  } else {
120  gid = (nLocSamples + 1) * rest + (comms_.island_id - rest) * nLocSamples;
121  }
122  }
123 
124  nSamples_m = nLocSamples;
125 
126  // start poll loop
127  run();
128 }
129 
130 
131 bool Sampler::onMessage(MPI_Status status, size_t length) {
132  MPITag_t tag = MPITag_t(status.MPI_TAG);
133  switch(tag) {
134  case REQUEST_FINISHED: {
135  unsigned int jid = static_cast<unsigned int>(length);
136  typename std::map<size_t, std::shared_ptr<Individual_t> >::iterator it;
137  it = jobmapping_m.find(jid);
138 
139  if(it == jobmapping_m.end()) {
140  std::cout << "NON-EXISTING JOB with ID = " << jid << std::endl;
141  throw OptPilotException("Sampler::onMessage",
142  "non-existing job");
143  }
144 
145 
146  std::shared_ptr<Individual_t> ind = it->second;
147 
148  reqVarContainer_t res;
149  MPI_Recv_reqvars(res, status.MPI_SOURCE, comms_.opt);
150 
151  ind->objectives.clear();
152 
153  reqVarContainer_t::iterator itr = res.begin();
154  for(; itr != res.end(); ++itr) {
155  // mark invalid if expression could not be evaluated or constraint does not hold
156  if(!itr->second.is_valid || (itr->second.value.size() > 1 && !itr->second.value[0])) {
157  ind->objectives.push_back(std::numeric_limits<double>::infinity());
158  } else {
159  // update objective value for valid objective
160  if(itr->second.value.size() == 1)
161  ind->objectives.push_back(itr->second.value[0]);
162  }
163  }
164 
165  addIndividualToJSON(ind);
166 
167  jobmapping_m.erase(it);
168 
169  done_sample_m++;
170 
171  return true;
172  }
173  default: {
174  std::cout << "(Sampler) Error: unexpected MPI_TAG: "
175  << status.MPI_TAG << std::endl;
176  return false;
177  }
178  }
179 }
180 
181 
183 
184  if ( act_sample_m < nSamples_m ) {
185  this->createNewIndividual();
186  }
187 
188  runStateMachine();
189 }
190 
191 
193 
194  std::vector<std::string> dNames;
195 
197  for(itr = dvars_m.begin(); itr != dvars_m.end(); itr++) {
198  std::string dName = boost::get<VAR_NAME>(itr->second);
199  dNames.push_back(dName);
200  }
201 
202  std::shared_ptr<Individual_t> ind = std::shared_ptr<Individual_t>( new Individual_t(dNames));
203 
204  ind->id = gid++;
205 
206  for(itr = dvars_m.begin(); itr != dvars_m.end(); itr++) {
207  std::string dName = boost::get<VAR_NAME>(itr->second);
208  int i = ind->getIndex(dName);
209  sampleMethods_m[dName]->create(ind, i);
210  }
211 
212 
213  individuals_m.push(ind);
214 }
215 
216 
218  namespace pt = boost::property_tree;
219 
220  pt::ptree tree;
221 
222  tree.put("name", "sampler");
223  tree.put(OPAL_PROJECT_NAME " version", OPAL_PROJECT_VERSION);
224  tree.put("git revision", Util::getGitRevision());
225 
226  std::stringstream bounds;
227  DVarContainer_t::iterator itr = dvars_m.begin();
228  for (bounds_t::iterator it = dVarBounds_m.begin();
229  it != dVarBounds_m.end(); ++it, ++itr)
230  {
231  std::string dvar = boost::get<VAR_NAME>(itr->second);
232  bounds << "[ " << it->first << ", " << it->second << " ]";
233  tree.put("dvar-bounds." + dvar, bounds.str());
234  bounds.str("");
235  }
236 
237  pt::write_json(jsonFname_m, tree);
238 }
239 
240 
242 
243  if (individualsToDump_m.empty()) {
244  return;
245  }
246 
247  namespace pt = boost::property_tree;
248 
249  pt::ptree tree;
250  pt::read_json(jsonFname_m, tree);
251 
252  pt::ptree samples;
253 
254  if ( tree.get_optional<std::string>("samples") ) {
255  /* we already have individuals in the JSON
256  * file
257  */
258  samples = tree.get_child("samples");
259  tree.erase("samples");
260  }
261 
262  while (!individualsToDump_m.empty()) {
263  Individual_t ind = individualsToDump_m.front();
264  individualsToDump_m.pop_front();
265 
266  std::string id = std::to_string(ind.id);
267 
269  for(itr = dvars_m.begin(); itr != dvars_m.end(); itr++) {
270  std::string name = boost::get<VAR_NAME>(itr->second);
271  int i = ind.getIndex(name);
272  samples.put(id + ".dvar." + name, ind.genes[i]);
273  }
274 
276  expr_it = objectives_m.begin();
277 
278  for(size_t i=0; i < ind.objectives.size(); i++, expr_it++) {
279  std::string name = expr_it->first;
280 
281  // skip dummy objective (in constructor of SamplePilot.h)
282  if ( name == "dummy" )
283  continue;
284 
285  samples.put(id + ".obj." + name, ind.objectives[i]);
286  }
287  }
288 
289  tree.add_child("samples", samples);
290  boost::property_tree::write_json(jsonFname_m, tree);
291 }
292 
293 
294 void Sampler::addIndividualToJSON(const std::shared_ptr<Individual_t>& ind) {
295  individualsToDump_m.push_back(*ind);
296 
297  if (jsonDumpFreq_m <= individualsToDump_m.size()) {
299  }
300 }
301 
302 
304 
305  switch(curState_m) {
306 
307  case SUBMIT: {
308  if ( done_sample_m == nSamples_m) {
309  curState_m = STOP;
310  } else {
311  if ( act_sample_m != nSamples_m ) {
313  }
314  }
315  break;
316  }
317  case STOP: {
318 
320 
322 
323  // notify pilot that we have converged
324  int dummy = 0;
325  MPI_Request req;
326  MPI_Isend(&dummy, 1, MPI_INT, comms_.master_local_pid,
328 
329  break;
330  }
331 
332  case TERMINATE: {
333  break;
334  }
335  }
336 }
337 
338 
340 
341  while ( !individuals_m.empty() ) {
342  std::shared_ptr<Individual_t> ind = individuals_m.front();
343 
344  individuals_m.pop();
345 
346  Param_t params;
348 
349  for(itr = dvars_m.begin(); itr != dvars_m.end(); itr++) {
350  std::string dName = boost::get<VAR_NAME>(itr->second);
351  int i = ind->getIndex(dName);
352  params.insert(
353  std::pair<std::string, double>
354  (dName, ind->genes[i]));
355  }
356 
357  size_t jid = static_cast<size_t>(ind->id);
358  int pilot_rank = comms_.master_local_pid;
359 
360 
361  act_sample_m++;
362 
363  // now send the request to the pilot
364  MPI_Send(&jid, 1, MPI_UNSIGNED_LONG, pilot_rank, OPT_NEW_JOB_TAG, comms_.opt);
365 
366  MPI_Send_params(params, pilot_rank, comms_.opt);
367 
368  jobmapping_m.insert(
369  std::pair<size_t, std::shared_ptr<Individual_t> >(jid, ind));
370  }
371 }
int island_id
Definition: types.h:33
namedVariableCollection_t Param_t
Definition: Types.h:48
unsigned int id
id
and that you know you can do these things To protect your we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights These restrictions translate to certain responsibilities for you if you distribute copies of the or if you modify it For if you distribute copies of such a whether gratis or for a you must give the recipients all the rights that you have You must make sure that receive or can get the source code And you must show them these terms so they know their rights We protect your rights with two distribute and or modify the software for each author s protection and we want to make certain that everyone understands that there is no warranty for this free software If the software is modified by someone else and passed we want its recipients to know that what they have is not the so that any problems introduced by others will not reflect on the original authors reputations any free program is threatened constantly by software patents We wish to avoid the danger that redistributors of a free program will individually obtain patent in effect making the program proprietary To prevent we have made it clear that any patent must be licensed for everyone s free use or not licensed at all The precise terms and conditions for distribution and modification follow GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR DISTRIBUTION AND MODIFICATION This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License The refers to any such program or and a work based on the Program means either the Program or any derivative work under copyright a work containing the Program or a portion of it
Definition: LICENSE:43
void writeJsonHeader()
Definition: Sampler.cpp:217
#define OPAL_PROJECT_VERSION
Definition: config.h.in:5
int done_sample_m
Definition: Sampler.h:144
bounds_t dVarBounds_m
bounds on each specified gene
Definition: Sampler.h:127
void createNewIndividual()
Definition: Sampler.cpp:192
std::map< std::string, std::shared_ptr< SamplingMethod > > sampleMethods_m
Definition: Sampler.h:109
std::string getGitRevision()
Definition: Util.cpp:33
#define OPAL_PROJECT_NAME
Definition: config.h.in:2
int gid
Definition: Sampler.h:112
std::map< std::string, DVar_t > DVarContainer_t
Definition: Types.h:92
void bounds(const PETE_Expr< T1 > &expr, Vektor< T2, D > &minval, Vektor< T2, D > &maxval)
CmdArguments_t args_
command line arguments specified by the user
Definition: Sampler.h:139
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
MPI_Comm opt
Definition: types.h:38
std::map< std::string, Expressions::Expr_t * > Named_t
type of an expressions with a name
Definition: Expression.h:74
void postPoll()
executed after handling (if any) new request
Definition: Sampler.cpp:182
std::string::iterator iterator
Definition: MSLang.h:15
bool onMessage(MPI_Status status, size_t length)
Definition: Sampler.cpp:131
std::map< size_t, std::shared_ptr< Individual_t > > jobmapping_m
mapping from unique job ID to individual
Definition: Sampler.h:122
void dumpIndividualsToJSON()
Definition: Sampler.cpp:241
int master_local_pid
Definition: types.h:36
Comm::Bundle_t comms_
communicator bundle for the optimizer
Definition: Sampler.h:119
int act_sample_m
current generation
Definition: Sampler.h:142
objectives_t objectives
values of objectives of an individual
std::shared_ptr< CmdArguments > CmdArguments_t
Definition: CmdArguments.h:176
int my_local_pid_
Definition: Sampler.h:114
void addIndividualToJSON(const std::shared_ptr< Individual_t > &ind)
Definition: Sampler.cpp:294
std::size_t jsonDumpFreq_m
Dumps id, design variables and bound.
Definition: Sampler.h:155
#define MPI_OPT_CONVERGED_TAG
optimizer notifies pilot that optimization has converged (EXIT)
Definition: MPIHelper.h:48
DVarContainer_t dvars_m
design variables
Definition: Sampler.h:130
std::list< Individual_t > individualsToDump_m
Definition: Sampler.h:158
void MPI_Recv_reqvars(reqVarContainer_t &reqvars, size_t pid, MPI_Comm comm)
Definition: MPIHelper.cpp:165
const std::string name
Expressions::Named_t objectives_m
objectives
Definition: Sampler.h:133
bundles all communicators for a specific role/pid
Definition: types.h:32
genes_t genes
genes of an individual
int nSamples_m
Definition: Sampler.h:135
void runStateMachine()
Definition: Sampler.cpp:303
void MPI_Send_params(Param_t params, size_t pid, MPI_Comm comm)
Definition: MPIHelper.cpp:87
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:38
int getIndex(std::string name)
virtual void initialize()
Initialization and start algorithm.
Definition: Sampler.cpp:94
std::map< std::string, reqVarInfo_t > reqVarContainer_t
Definition: Types.h:79
SampleIndividual Individual_t
Definition: Sampler.h:116
std::queue< std::shared_ptr< Individual_t > > individuals_m
Definition: Sampler.h:124
MPITag_t
Definition: MPIHelper.h:71
void dispatch_forward_solves()
Definition: Sampler.cpp:339
virtual void run()
Definition: Poller.h:79
std::string jsonFname_m
Definition: Sampler.h:156
State curState_m
Definition: Sampler.h:152