OPAL (Object Oriented Parallel Accelerator Library) 2022.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 <iostream>
23#include <string>
24#include <limits>
25
26#include "Sample/Sampler.h"
27
28#include "OPALconfig.h"
29#include "Utilities/Util.h"
30
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
53Sampler::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;
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
132bool 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
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
167
168 jobmapping_m.erase(it);
169
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
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;
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
295void 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) {
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
#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
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
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
boost::shared_ptr< CmdArguments > CmdArguments_t
Definition: CmdArguments.h:176
const std::string name
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:32
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