OPAL (Object Oriented Parallel Accelerator Library) 2024.2
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
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
52Sampler::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
82 DVarContainer_t::iterator itr;
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
131bool 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
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
166
167 jobmapping_m.erase(it);
168
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
189}
190
191
193
194 std::vector<std::string> dNames;
195
196 DVarContainer_t::iterator itr;
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
268 DVarContainer_t::iterator itr;
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
275 Expressions::Named_t::iterator expr_it;
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
294void 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) {
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,
327 MPI_OPT_CONVERGED_TAG, comms_.opt, &req);
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;
347 DVarContainer_t::iterator itr;
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}
void bounds(const PETE_Expr< T1 > &expr, Vektor< T2, D > &minval, Vektor< T2, D > &maxval)
#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)
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::shared_ptr< CmdArguments > CmdArguments_t
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 getGitRevision()
Definition Util.cpp:33
bundles all communicators for a specific role/pid
Definition types.h: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
void addIndividualToJSON(const std::shared_ptr< Individual_t > &ind)
Definition Sampler.cpp:294
SampleIndividual Individual_t
Definition Sampler.h:116
std::string jsonFname_m
Definition Sampler.h:156
int nSamples_m
Definition Sampler.h:135
bool onMessage(MPI_Status status, size_t length)
Definition Sampler.cpp:131
int done_sample_m
Definition Sampler.h:144
void postPoll()
executed after handling (if any) new request
Definition Sampler.cpp:182
int my_local_pid_
Definition Sampler.h:114
State curState_m
Definition Sampler.h:152
void dispatch_forward_solves()
Definition Sampler.cpp:339
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:94
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::queue< std::shared_ptr< Individual_t > > individuals_m
Definition Sampler.h:124
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
void dumpIndividualsToJSON()
Definition Sampler.cpp:241
CmdArguments_t args_
command line arguments specified by the user
Definition Sampler.h:139
void runStateMachine()
Definition Sampler.cpp:303
std::map< size_t, std::shared_ptr< Individual_t > > jobmapping_m
mapping from unique job ID to individual
Definition Sampler.h:122
void writeJsonHeader()
Definition Sampler.cpp:217
int act_sample_m
current generation
Definition Sampler.h:142
@ 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:38
void createNewIndividual()
Definition Sampler.cpp:192
bounds_t dVarBounds_m
bounds on each specified gene
Definition Sampler.h:127
Optimizer(MPI_Comm comm)
Definition Optimizer.h:35
virtual void run()
Definition Poller.h:79
T getArg(const std::string name, bool isFatal=false)