OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
SampleCmd.cpp
Go to the documentation of this file.
1//
2// Class SampleCmd
3// This class defines the SAMPLE command.
4//
5// Copyright (c) 2018, Matthias Frey, Paul Scherrer Institut, Villigen PSI, Switzerland
6// All rights reserved
7//
8// Implemented as part of the PhD thesis
9// "Precise Simulations of Multibunches in High Intensity Cyclotrons"
10//
11// This file is part of OPAL.
12//
13// OPAL is free software: you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation, either version 3 of the License, or
16// (at your option) any later version.
17//
18// You should have received a copy of the GNU General Public License
19// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
20//
21#include "Sample/SampleCmd.h"
22#include "Sample/Sampler.h"
23#include "Sample/OpalSample.h"
24#include "Sample/RNGStream.h"
25
26#include "Optimize/DVar.h"
27#include "Optimize/Objective.h"
29
33#include "Utilities/Util.h"
34
35#include "Utility/IpplInfo.h"
36#include "Utility/IpplTimings.h"
37#include "Track/Track.h"
38
39#include "Sample/SamplePilot.h"
40#include "Util/CmdArguments.h"
42
43#include "Comm/CommSplitter.h"
47
49#include "Expression/FromFile.h"
50#include "Expression/SumErrSq.h"
58
59#include <map>
60#include <set>
61#include <string>
62#include <vector>
63
64extern Inform *gmsg;
65
66namespace {
67 enum {
68 INPUT,
69 OUTPUT,
70 OUTDIR,
71 OBJECTIVES,
72 STOREOBJECTIVES,
73 DVARS,
74 SAMPLINGS,
75 NUMMASTERS,
76 NUMCOWORKERS,
77 TEMPLATEDIR,
78 FIELDMAPDIR,
79 DISTDIR,
80 RASTER,
81 SEED,
82 KEEP,
83 RESTART_FILE,
84 RESTART_STEP,
85 JSON_DUMP_FREQ,
86 SIZE
87 };
88}
89
91 Action(SIZE, "SAMPLE",
92 "The \"SAMPLE\" command initiates sampling.") {
94 ("INPUT", "Path to input file");
96 ("OUTPUT", "Name used in output file sample");
98 ("OUTDIR", "Name of directory used to run and store sample output files");
100 ("OBJECTIVES", "List of expressions to evaluate and store");
101 itsAttr[STOREOBJECTIVES] = Attributes::makeStringArray
102 ("STOREOBJECTIVES", "List of stat variables to store");
104 ("DVARS", "List of sampling variables to be used");
106 ("SAMPLINGS", "List of sampling methods to be used");
107 itsAttr[NUMMASTERS] = Attributes::makeReal
108 ("NUM_MASTERS", "Number of master nodes");
109 itsAttr[NUMCOWORKERS] = Attributes::makeReal
110 ("NUM_COWORKERS", "Number processors per worker");
111 itsAttr[TEMPLATEDIR] = Attributes::makeString
112 ("TEMPLATEDIR", "Directory where templates are stored");
113 itsAttr[FIELDMAPDIR] = Attributes::makeString
114 ("FIELDMAPDIR", "Directory where field maps are stored");
116 ("DISTDIR", "Directory where distributions are stored");
118 ("RASTER", "Scan full space given by design variables (default: true)", true);
120 ("SEED", "Seed for global random number generator (default: 42)", 42);
122 ("KEEP", "List of files to keep for each simulation. (default: all files kept)");
123 itsAttr[RESTART_FILE] = Attributes::makeString
124 ("RESTART_FILE", "H5 file to restart the OPAL simulations from (optional)", "");
125 itsAttr[RESTART_STEP] = Attributes::makeReal
126 ("RESTART_STEP", "Restart from given H5 step (optional)",
127 std::numeric_limits<int>::min());
128 itsAttr[JSON_DUMP_FREQ] = Attributes::makeReal
129 ("JSON_DUMP_FREQ", "Defines how often new individuals are appended to the final JSON file, "
130 "i.e. every time JSON_DUMP_FREQ samples finished they are written (optional)",
131 std::numeric_limits<size_t>::max());
133}
134
135SampleCmd::SampleCmd(const std::string &name, SampleCmd *parent):
136 Action(name, parent)
137{ }
138
141
142SampleCmd *SampleCmd::clone(const std::string &name) {
143 return new SampleCmd(name, this);
144}
145
147
148 namespace fs = std::filesystem;
149
150 auto opal = OpalData::getInstance();
151 opal->setOptimizerFlag();
152
153 fs::path inputfile(Attributes::getString(itsAttr[INPUT]));
154
155 unsigned int seed = Attributes::getReal(itsAttr[SEED]);
157
158 std::vector<std::string> objectivesstr = Attributes::getStringArray(itsAttr[OBJECTIVES]);
159 // FIXME Open issue #250 (https://gitlab.psi.ch/OPAL/src/issues/250)
160 std::vector<std::string> storeobjstr = Attributes::getStringArray(itsAttr[STOREOBJECTIVES]);
161 std::vector<std::string> dvarsstr = Attributes::getStringArray(itsAttr[DVARS]);
162 Expressions::Named_t objectives;
163 DVarContainer_t dvars;
164
165 std::vector<std::string> filesToKeep = Attributes::getStringArray(itsAttr[KEEP]);
166 std::vector<std::string> sampling = Attributes::getStringArray(itsAttr[SAMPLINGS]);
167
168 if ( sampling.size() != dvarsstr.size() )
169 throw OpalException("SampleCmd::execute",
170 "Number of sampling methods != number of design variables.");
171
172 typedef std::map< std::string, std::shared_ptr<SamplingMethod> > sampleMethods_t;
173 sampleMethods_t sampleMethods;
174
175 std::map<std::string, std::pair<double, double> > vars;
176
177 for (std::string &name : dvarsstr) {
178 Object *obj = opal->find(name);
179 DVar* dvar = dynamic_cast<DVar*>(obj);
180 if (dvar == nullptr) {
181 throw OpalException("SampleCmd::execute",
182 "The sampling variable " + name + " is not known");
183
184 }
185 std::string var = dvar->getVariable();
186 double lowerbound = dvar->getLowerBound();
187 double upperbound = dvar->getUpperBound();
188
189 auto ret = vars.insert(std::make_pair(var, std::make_pair(lowerbound, upperbound)));
190 if (ret.second == false) {
191 throw OpalException("SampleCmd::execute",
192 "There is already a design variable with the variable " + var + " defined");
193 }
194
195 DVar_t tmp = boost::make_tuple(var, lowerbound, upperbound);
196 dvars.insert(namedDVar_t(name, tmp));
197 }
198
200
203 ff = FromFile();
204 funcs.insert(std::pair<std::string, client::function::type>
205 ("fromFile", ff));
206
207 ff = SumErrSq();
208 funcs.insert(std::pair<std::string, client::function::type>
209 ("sumErrSq", ff));
210
211 ff = SDDSVariable();
212 funcs.insert(std::pair<std::string, client::function::type>
213 ("sddsVariableAt", ff));
214
215 ff = RadialPeak();
216 funcs.insert(std::pair<std::string, client::function::type>
217 ("radialPeak", ff));
218
219 ff = MaxNormRadialPeak();
220 funcs.insert(std::pair<std::string, client::function::type>
221 ("maxNormRadialPeak", ff));
222
223 ff = NumberOfPeaks();
224 funcs.insert(std::pair<std::string, client::function::type>
225 ("numberOfPeaks", ff));
226
227 ff = SumErrSqRadialPeak();
228 funcs.insert(std::pair<std::string, client::function::type>
229 ("sumErrSqRadialPeak", ff));
230
231 ff = ProbeVariable();
232 funcs.insert(std::pair<std::string, client::function::type>
233 ("probVariableWithID", ff));
234
235 std::string fname = inputfile.stem().native();
236 ff = sameSDDSVariable(fname);
237 funcs.insert(std::pair<std::string, client::function::type>
238 ("statVariableAt", ff));
239
240 ff = SeptumExpr();
241 funcs.insert(std::pair<std::string, client::function::type>
242 ("septum", ff));
243
245
246 std::set<std::string> objExpressions; // check if all unique objective expressions
247 for (std::string name: objectivesstr) {
248 Object *obj = opal->find(name);
249 Objective* objective = dynamic_cast<Objective*>(obj);
250 if (objective == nullptr) {
251 throw OpalException("OptimizeCmd::execute",
252 "The objective " + name + " is not known");
253
254 }
255 std::string expr = objective->getExpression();
256 objectives.insert(Expressions::SingleNamed_t(
257 name, new Expressions::Expr_t(expr, funcs)));
258 auto ret = objExpressions.insert(expr);
259 if (ret.second == false) {
260 throw OpalException("OptimizeCmd::execute",
261 "There is already a objective with the expression " + expr + " defined");
262 }
263 }
264
265 bool raster = Attributes::getBool(itsAttr[RASTER]);
266 size_t modulo = 1;
267 unsigned int nSample = std::numeric_limits<unsigned int>::max();
268
269 std::set<std::string> names; // check if all unique variables
270 for (size_t i = 0; i < sampling.size(); ++i) {
271 // corresponding sampling method
272 OpalSample *s = OpalSample::find(sampling[i]);
273 if (s == nullptr) {
274 throw OpalException("SampleCmd::execute",
275 "Sampling method not found.");
276 }
277
278 std::string name = s->getVariable();
279
280 if ( vars.find(name) == vars.end() ) {
281 throw OpalException("SampleCmd::execute",
282 "Variable '" + name + "' not a DVAR.");
283 }
284
285 auto ret = names.insert(name);
286 if (ret.second == false) {
287 throw OpalException("SampleCmd::execute",
288 "There is already a sampling method with the variable " + name + " defined");
289 }
290
291 s->initialize(name,
292 vars[name].first,
293 vars[name].second,
294 modulo,
295 raster);
296
297 if ( raster )
298 modulo *= s->getSize();
299
300 nSample = std::min(nSample, s->getSize());
301
302 sampleMethods[name] = s->sampleMethod_m;
303 }
304
305 // Setup/Configuration
307 typedef OpalSimulation Sim_t;
308
310 typedef SocialNetworkGraph< NoCommTopology > SolPropagationGraph_t;
311
313
315
316 std::vector<std::string> arguments(opal->getArguments());
317 std::vector<char*> argv;
318 std::map<unsigned int, std::string> argumentMapper({
319 {INPUT, "inputfile"},
320 {OUTPUT, "outfile"},
321 {OUTDIR, "outdir"},
322 {NUMMASTERS, "num-masters"},
323 {NUMCOWORKERS, "num-coworkers"},
324 {RESTART_FILE, "restartfile"},
325 {RESTART_STEP, "restartstep"},
326 {JSON_DUMP_FREQ, "jsonDumpFreq"}
327 });
328
329 auto it = argumentMapper.end();
330 for (unsigned int i = 0; i < SIZE; ++ i) {
331 if ((it = argumentMapper.find(i)) != argumentMapper.end()) {
332 std::string type = itsAttr[i].getType();
333 if (type == "string") {
334 if (!Attributes::getString(itsAttr[i]).empty()) {
335 std::string argument = "--" + (*it).second + "=" + Attributes::getString(itsAttr[i]);
336 arguments.push_back(argument);
337 }
338 } else if (type == "real") {
339 if (itsAttr[i]) {
340 std::string val = std::to_string (Attributes::getReal(itsAttr[i]));
341 size_t last = val.find_last_not_of('0');
342 if (val[last] != '.') ++ last;
343 val.erase (last, std::string::npos );
344 std::string argument = "--" + (*it).second + "=" + val;
345 arguments.push_back(argument);
346 }
347 } else if (type == "logical") {
348 if (itsAttr[i]) {
349 std::string argument = "--" + (*it).second + "=" + std::to_string(Attributes::getBool(itsAttr[i]));
350 arguments.push_back(argument);
351 }
352 }
353 }
354 }
355
356 if ( raster )
357 nSample = modulo;
358
359 arguments.push_back("--nsamples=" + std::to_string(nSample));
360
361 if (Attributes::getString(itsAttr[INPUT]).empty()) {
362 throw OpalException("SampleCmd::execute",
363 "The argument INPUT has to be provided");
364 }
365
366 if (!Attributes::getString(itsAttr[OUTDIR]).empty()) {
367 fs::path dir(Attributes::getString(itsAttr[OUTDIR]));
368 if (dir.is_relative()) {
369 fs::path path = fs::path(std::string(getenv("PWD")));
370 path /= dir;
371 dir = path;
372 }
373
374 if (!fs::exists(dir)) {
375 fs::create_directory(dir);
376 }
377 std::string argument = "--simtmpdir=" + dir.native();
378 arguments.push_back(argument);
379 }
380
381 if (!Attributes::getString(itsAttr[TEMPLATEDIR]).empty()) {
382 fs::path dir(Attributes::getString(itsAttr[TEMPLATEDIR]));
383 if (dir.is_relative()) {
384 fs::path path = fs::path(std::string(getenv("PWD")));
385 path /= dir;
386 dir = path;
387 }
388
389 std::string argument = "--templates=" + dir.native();
390 arguments.push_back(argument);
391 }
392
393 if (!Attributes::getString(itsAttr[FIELDMAPDIR]).empty()) {
394 fs::path dir(Attributes::getString(itsAttr[FIELDMAPDIR]));
395 if (dir.is_relative()) {
396 fs::path path = fs::path(std::string(getenv("PWD")));
397 path /= dir;
398 dir = path;
399 }
400
401 setenv("FIELDMAPS", dir.c_str(), 1);
402 }
403
404 if (!Attributes::getString(itsAttr[DISTDIR]).empty()) {
405 fs::path dir(Attributes::getString(itsAttr[DISTDIR]));
406 if (dir.is_relative()) {
407 fs::path path = fs::path(std::string(getenv("PWD")));
408 path /= dir;
409 dir = path;
410 }
411
412 setenv("DISTRIBUTIONS", dir.c_str(), 1);
413 }
414
415 {
416 std::string tmplFile = Attributes::getString(itsAttr[INPUT]);
417 size_t pos = tmplFile.find_last_of("/");
418 if(pos != std::string::npos)
419 tmplFile = tmplFile.substr(pos+1);
420 pos = tmplFile.find(".");
421 tmplFile = tmplFile.substr(0,pos);
422 tmplFile = Attributes::getString(itsAttr[TEMPLATEDIR]) + "/" + tmplFile + ".tmpl";
423
424 std::ifstream infile(tmplFile.c_str());
425
426 std::map<std::string, short> dvarCheck;
427 auto itr = dvars.begin();
428 for (; itr != dvars.end(); ++ itr) {
429 dvarCheck.insert(std::make_pair(boost::get<0>(itr->second), 0));
430 }
431
432 while(infile.good()) {
433 std::string line;
434 std::getline(infile, line, '\n');
435
436 //XXX doing the inverse would be better
437 for(auto &check: dvarCheck) {
438 size_t pos = line.find("_" + check.first + "_");
439 if (pos != std::string::npos &&
440 dvarCheck.find(check.first) != dvarCheck.end()) {
441 dvarCheck.at(check.first) = 1;
442 }
443 }
444 }
445 infile.close();
446
447 for (auto itr = dvarCheck.begin(); itr != dvarCheck.end(); ++ itr) {
448 if (itr->second == 0) {
449 throw OpalException("SampleCmd::execute()",
450 "Couldn't find the design variable '" + itr->first + "' in '" + tmplFile + "'!");
451 }
452 }
453 }
454
455 *gmsg << endl;
456 for (size_t i = 0; i < arguments.size(); ++ i) {
457 argv.push_back(const_cast<char*>(arguments[i].c_str()));
458 *gmsg << arguments[i] << " ";
459 }
460 *gmsg << endl;
461
462 std::map<std::string, std::string> userVariables = opal->getVariableData();
463
464 Inform *origGmsg = gmsg;
465 gmsg = 0;
466 try {
467 CmdArguments_t args(new CmdArguments(argv.size(), &argv[0]));
468
469 std::shared_ptr<Comm_t> comm(new Comm_t(args, MPI_COMM_WORLD));
470 if (comm->isWorker())
472
473 if ( comm->isOptimizer() ) {
474 for (sampleMethods_t::iterator it = sampleMethods.begin();
475 it != sampleMethods.end(); ++it)
476 {
477 it->second->allocate(args, comm->getBundle());
478 }
479 }
480
481 const std::unique_ptr<pilot_t> pi(new pilot_t(args, comm, funcs, dvars,
482 objectives, sampleMethods,
483 storeobjstr, filesToKeep, userVariables));
484 if (comm->isWorker())
486
487 } catch (OptPilotException &e) {
488 std::cout << "Exception caught: " << e.what() << std::endl;
489 MPI_Abort(MPI_COMM_WORLD, -100);
490 }
491 gmsg = origGmsg;
492}
493
500
@ SIZE
Definition IndexMap.cpp:174
Inform * gmsg
Definition Main.cpp:70
const double pi
Definition fftpack.cpp:894
Inform & endl(Inform &inf)
Definition Inform.cpp:42
boost::tuple< std::string, double, double > DVar_t
type of design variables
Definition Types.h:84
std::map< std::string, DVar_t > DVarContainer_t
Definition Types.h:92
std::pair< std::string, DVar_t > namedDVar_t
Definition Types.h:91
std::shared_ptr< CmdArguments > CmdArguments_t
const std::string name
std::map< std::string, client::function::type > functionDictionary_t
Definition Expression.h:56
std::map< std::string, Expressions::Expr_t * > Named_t
type of an expressions with a name
Definition Expression.h:74
Expression Expr_t
type of an expression
Definition Expression.h:63
std::pair< std::string, Expressions::Expr_t * > SingleNamed_t
Definition Expression.h:77
Attribute makeBool(const std::string &name, const std::string &help)
Make logical attribute.
double getReal(const Attribute &attr)
Return real value.
Attribute makeUpperCaseStringArray(const std::string &name, const std::string &help)
Make uppercase string array attribute.
Attribute makeStringArray(const std::string &name, const std::string &help)
Create a string array attribute.
Attribute makeReal(const std::string &name, const std::string &help)
Make real attribute.
bool getBool(const Attribute &attr)
Return logical value.
std::vector< std::string > getStringArray(const Attribute &attr)
Get string array value.
std::string getString(const Attribute &attr)
Get string value.
Attribute makeString(const std::string &name, const std::string &help)
Make string attribute.
boost::function< boost::tuple< double, bool >(arguments_t)> type
Definition function.hpp:21
Action(int size, const char *name, const char *help)
Constructor for exemplars.
Definition Action.cpp:54
void registerOwnership(const AttributeHandler::OwnerType &itsClass) const
Definition Object.cpp:191
Object(int size, const char *name, const char *help)
Constructor for exemplars.
Definition Object.cpp:356
std::vector< Attribute > itsAttr
The object attributes.
Definition Object.h:216
static void stashInstance()
Definition OpalData.cpp:212
static OpalData * getInstance()
Definition OpalData.cpp:196
static OpalData * popInstance()
Definition OpalData.cpp:223
Definition DVar.h:6
std::string getVariable() const
Definition DVar.cpp:37
double getUpperBound() const
Definition DVar.cpp:45
double getLowerBound() const
Definition DVar.cpp:41
std::string getExpression() const
Definition Objective.cpp:31
Concrete implementation of an Opal simulation wrapper.
Sampling method that reads design variable values from a text file.
static OpalSample * find(const std::string &name)
Find sampling method.
void initialize(const std::string &dvarName, double lower, double upper, size_t modulo=1, bool sequence=false)
unsigned int getSize() const
Definition OpalSample.h:82
std::shared_ptr< SamplingMethod > sampleMethod_m
Definition OpalSample.h:58
std::string getVariable() const
static void setGlobalSeed(unsigned int seed)
Definition RNGStream.cpp:53
virtual void execute()
Execute the command.
void stashEnvironment()
SampleCmd()
Exemplar constructor.
Definition SampleCmd.cpp:90
virtual SampleCmd * clone(const std::string &name)
Make clone.
virtual ~SampleCmd()
void popEnvironment()
static Track * pop()
Definition Track.cpp:83
static void stash()
Definition Track.cpp:76
The base class for all OPAL exceptions.
static void pop()
static void stash()
Definition IpplInfo.cpp:988
static void stash()
static void pop()