OPAL (Object Oriented Parallel Accelerator Library)  2024.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 
30 #include "Attributes/Attributes.h"
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"
41 #include "Util/OptPilotException.h"
42 
43 #include "Comm/CommSplitter.h"
47 
49 #include "Expression/FromFile.h"
50 #include "Expression/SumErrSq.h"
52 #include "Expression/RadialPeak.h"
57 #include "Expression/SeptumExpr.h"
58 
59 #include <map>
60 #include <set>
61 #include <string>
62 #include <vector>
63 
64 extern Inform *gmsg;
65 
66 namespace {
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");
117  itsAttr[RASTER] = Attributes::makeBool
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)",
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)",
133 }
134 
135 SampleCmd::SampleCmd(const std::string &name, SampleCmd *parent):
136  Action(name, parent)
137 { }
138 
140 { }
141 
142 SampleCmd *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 
201  functionDictionary_t funcs;
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())
485  popEnvironment();
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 
495  Ippl::stash();
497  Track::stash();
499 }
500 
502  Ippl::pop();
505  Track::pop();
506 }
Attribute makeReal(const std::string &name, const std::string &help)
Make real attribute.
Definition: Attributes.cpp:240
static OpalData * getInstance()
Definition: OpalData.cpp:196
unsigned int getSize() const
Definition: OpalSample.h:82
int seed
The current random seed.
Definition: Options.cpp:37
std::string getVariable() const
Definition: DVar.cpp:37
The base class for all OPAL objects.
Definition: Object.h:48
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
std::string getString(const Attribute &attr)
Get string value.
Definition: Attributes.cpp:343
static void stash()
Definition: IpplInfo.cpp:988
boost::function< boost::tuple< double, bool >arguments_t)> type
Definition: function.hpp:21
static OpalData * popInstance()
Definition: OpalData.cpp:223
virtual const char * what() const
virtual ~SampleCmd()
Definition: SampleCmd.cpp:139
virtual void execute()
Execute the command.
Definition: SampleCmd.cpp:146
static void pop()
Definition: IpplInfo.cpp:1053
double getUpperBound() const
Definition: DVar.cpp:45
std::map< std::string, DVar_t > DVarContainer_t
Definition: Types.h:92
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
static Track * pop()
Definition: Track.cpp:83
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:76
Definition: DVar.h:6
std::shared_ptr< SamplingMethod > sampleMethod_m
Definition: OpalSample.h:58
std::map< std::string, Expressions::Expr_t * > Named_t
type of an expressions with a name
Definition: Expression.h:74
std::string getVariable() const
Definition: OpalSample.cpp:232
SampleCmd()
Exemplar constructor.
Definition: SampleCmd.cpp:90
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:84
std::string getExpression() const
Definition: Objective.cpp:31
bool getBool(const Attribute &attr)
Return logical value.
Definition: Attributes.cpp:100
std::string::iterator iterator
Definition: MSLang.h:15
std::pair< std::string, DVar_t > namedDVar_t
Definition: Types.h:91
Attribute makeBool(const std::string &name, const std::string &help)
Make logical attribute.
Definition: Attributes.cpp:90
double FromFile(std::string file, const std::vector< double > &referencePoint)
alter the names
Definition: LICENSE:330
void initialize(const std::string &dvarName, double lower, double upper, size_t modulo=1, bool sequence=false)
Definition: OpalSample.cpp:115
boost::tuple< std::string, double, double > DVar_t
type of design variables
Definition: Types.h:84
void registerOwnership(const AttributeHandler::OwnerType &itsClass) const
Definition: Object.cpp:191
FRONT * fs
Definition: hypervolume.cpp:59
The base class for all OPAL exceptions.
Definition: OpalException.h:28
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
opt DVARS
Definition: Problem.in:12
Definition: Inform.h:42
std::shared_ptr< CmdArguments > CmdArguments_t
Definition: CmdArguments.h:176
static void stashInstance()
Definition: OpalData.cpp:212
Attribute makeString(const std::string &name, const std::string &help)
Make string attribute.
Definition: Attributes.cpp:332
virtual SampleCmd * clone(const std::string &name)
Make clone.
Definition: SampleCmd.cpp:142
std::map< std::string, client::function::type > functionDictionary_t
Definition: Expression.h:56
void stashEnvironment()
Definition: SampleCmd.cpp:494
static OpalSample * find(const std::string &name)
Find sampling method.
Definition: OpalSample.cpp:104
std::vector< Attribute > itsAttr
The object attributes.
Definition: Object.h:216
double getLowerBound() const
Definition: DVar.cpp:41
const std::string name
const double pi
Definition: fftpack.cpp:894
double getReal(const Attribute &attr)
Return real value.
Definition: Attributes.cpp:252
static void stash()
Definition: Track.cpp:76
std::vector< std::string > getStringArray(const Attribute &attr)
Get string array value.
Definition: Attributes.cpp:478
constexpr double e
The value of .
Definition: Physics.h:39
static void pop()
static void setGlobalSeed(unsigned int seed)
Definition: RNGStream.cpp:53
The base class for all OPAL actions.
Definition: Action.h:30
opt OBJECTIVES
Definition: Problem.in:12
static void stash()
SDDS1 &description type
Definition: test.stat:4
void popEnvironment()
Definition: SampleCmd.cpp:501
Inform * gmsg
Definition: Main.cpp:70
std::pair< std::string, Expressions::Expr_t * > SingleNamed_t
Definition: Expression.h:77
Concrete implementation of an Opal simulation wrapper.