OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
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 <boost/filesystem.hpp>
60 
61 #include <map>
62 #include <set>
63 #include <string>
64 #include <vector>
65 
66 extern Inform *gmsg;
67 
68 namespace {
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");
119  itsAttr[RASTER] = Attributes::makeBool
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 
137 SampleCmd::SampleCmd(const std::string &name, SampleCmd *parent):
138  Action(name, parent)
139 { }
140 
142 { }
143 
144 SampleCmd *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 
203  functionDictionary_t funcs;
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]) != "") {
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]) == "") {
364  throw OpalException("SampleCmd::execute",
365  "The argument INPUT has to be provided");
366  }
367 
368  if (Attributes::getString(itsAttr[OUTDIR]) != "") {
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]) != "") {
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]) != "") {
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]) != "") {
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())
487  popEnvironment();
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:62
const double pi
Definition: fftpack.cpp:894
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
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
std::map< std::string, client::function::type > functionDictionary_t
Definition: Expression.h:56
const std::string name
boost::shared_ptr< CmdArguments > CmdArguments_t
Definition: CmdArguments.h:176
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::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:211
static OpalData * getInstance()
Definition: OpalData.cpp:195
static OpalData * popInstance()
Definition: OpalData.cpp:222
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:97
void initialize(const std::string &dvarName, double lower, double upper, size_t modulo=1, bool sequence=false)
Definition: OpalSample.cpp:108
unsigned int getSize() const
Definition: OpalSample.h:74
std::shared_ptr< SamplingMethod > sampleMethod_m
Definition: OpalSample.h:59
std::string getVariable() const
Definition: OpalSample.cpp:192
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:82
static void stash()
Definition: Track.cpp:75
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()