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