SeedMaster_test.cc
Go to the documentation of this file.
1 /**
2  * @file SeedMaster_test.cc
3  * @brief Test the SeedMaster object, core of NuRandomService
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date December 3rd, 2014
6  * @see NuRandomService.h SeedTest01_module.cc
7  *
8  * The test runs based on the configuration file specified on the command line.
9  *
10  * Usage: SeedMaster_test ConfigFile [ParameterSetPath [ModuleType ...]]
11  *
12  * In general, the configuration files good for SeedTest01 module should be
13  * good for this one as well (as long as ParameterSetPath is specified as
14  * services.NuRandomService).
15  *
16  * The configuration is in FHiCL format; no search of the FHiCL file is
17  * performed: the path of the configuration file must be available from the
18  * current directory (or you can specify it as absolute path).
19  *
20  * The optional parameter set path selects which part of the configuration file
21  * should be used to configure the SeedMaster. For a typical art configuration,
22  * it would be "services.NuRandomService". An empty path (default) uses the
23  * whole configuration directly.
24  *
25  * For each specified ModuleType, all the art modules with that type are
26  * considered as having test module configuration (in a art-like
27  * configuration, "physics.analyzers" and "physics.producers").
28  */
29 
30 // C/C++ standard libraries
31 #include <cstdlib>
32 #include <string>
33 #include <vector>
34 #include <algorithm> // std::find()
35 #include <iostream>
36 
37 // CET libraries
38 #include "cetlib/filepath_maker.h"
39 
40 // utility libraries
41 #include "fhiclcpp/ParameterSet.h"
44 #include "fhiclcpp/parse.h"
45 #include "fhiclcpp/exception.h"
47 
48 // art libraries
50 
51 // art extensions
52 #include "nutools/RandomUtils/Providers/SeedMaster.h"
53 
54 
55 //------------------------------------------------------------------------------
56 //--- stuff to facilitate the interaction with SeedMaster
57 //---
58 using seed_t = unsigned long;
60 
61 /// Returns the seed for the specified module/instance, or 0 on error
63  (SeedMaster_t& seeds, std::string module_name, std::string instance_name = "")
64 {
65  // Returns the seed for the specified engine instance, or 0 in case of
66  // configuration error (in which case, an error counter is increased)
67  try {
68  return seeds.getSeed(instance_name.empty()?
69  SeedMaster_t::EngineId(module_name):
70  SeedMaster_t::EngineId(module_name, instance_name)
71  );
72  }
73  catch(art::Exception& e) {
74  mf::LogError("SeedMaster") << "Caught an exception while asking seed for '"
75  << module_name << "." << instance_name << ":\n"
76  << e.what();
77  return 0;
78  }
79 } // ObtainSeed()
80 
81 
82 //------------------------------------------------------------------------------
83 //--- stuff to facilitate reading configuration
84 //---
86  (const fhicl::ParameterSet& full_pset, std::string key)
87 {
88  return key.empty()? full_pset: full_pset.get<fhicl::ParameterSet>(key);
89 } // GetConfiguration()
90 
91 
93  const fhicl::ParameterSet& full_pset,
94  std::string key = "services.NuRandomService"
95 ) {
96  return GetConfiguration(full_pset, key);
97 } // FindSeedServiceConfiguration()
98 
99 
100 std::vector<fhicl::ParameterSet> FindModulesConfiguration(
101  const fhicl::ParameterSet& full_pset,
102  const std::vector<std::string>& module_types,
103  std::string base_key = "physics.analyzers"
104 ) {
105  fhicl::ParameterSet base_pset = GetConfiguration(full_pset, base_key);
106 
107  // if this element has "module_type"
109  if (base_pset.get_if_present("module_type", module_type)) {
110  // so this is a module configuration;
111  // is this module among the ones we are looking for?
112  if (std::find(module_types.begin(), module_types.end(), module_type)
113  != module_types.end()
114  )
115  return { base_pset };
116  else return {};
117  } // if module configuration
118 
119  // not a module; maybe a module is nested somewhere in?
120  std::vector<fhicl::ParameterSet> psets;
121  for (std::string pset_key: base_pset.get_pset_names()) {
122  std::vector<fhicl::ParameterSet> new_psets = FindModulesConfiguration(
123  base_pset.get<fhicl::ParameterSet>(pset_key),
124  module_types, ""
125  );
126  psets.insert(psets.end(), new_psets.begin(), new_psets.end());
127  } // for
128  return psets;
129 } // FindModulesConfiguration()
130 
131 
132 /// Returns a string "ModuleType[ModuleName]" out of specified module config
134  return pset.get<std::string>("module_type", "Unknown")
135  + "[" + pset.get<std::string>("module_name", "unknown") + "]";
136 } // GetModuleID()
137 
138 
139 //------------------------------------------------------------------------------
140 //--- stuff to facilitate the use of message facility
141 //---
143  fhicl::ParameterSet mf_pset;
144  if (!pset.get_if_present("services.message", mf_pset)) {
145  // a destination which will react to messages more severe than DEBUG
146  std::string MessageFacilityConfiguration = R"(
147  destinations : {
148  stdout: {
149  type: cout
150  threshold: INFO
151  categories: {
152  default: {
153  limit : 10
154  }
155  } // categories
156  } // stdout
157  } // destinations
158  statistics: cout
159  )";
160  fhicl::make_ParameterSet(MessageFacilityConfiguration, mf_pset);
161  std::cout << "Using default message facility configuration:\n"
162  << mf_pset.to_indented_string(1) << std::endl;
163  } // if no configuration is available
164 
165  mf::StartMessageFacility(mf_pset);
166  mf::SetApplicationName("SeedMaster_test");
167  mf::SetContextIteration("Initialization");
168  mf::LogInfo("MessageFacility") << "MessageFacility started.";
169 } // StartMessageFacility()
170 
171 
172 //------------------------------------------------------------------------------
173 //--- stuff to facilitate the tests
174 //---
175 
176 /// Tests a "module" with a given configuration
177 int TestModule(SeedMaster_t& seeds, const fhicl::ParameterSet& pset) {
178 
179  mf::SetContextSinglet("TestModule");
180 
182 
183  std::string module_name
184  = pset.get<std::string>("module_name", "unknown");
185  std::string module_id = GetModuleID(pset);
186 
187  // read the instance
188  std::vector<std::string> instance_names;
189  pset.get_if_present("instanceNames", instance_names);
190  unsigned int nExpectedErrors = pset.get<unsigned int>("expectedErrors", 0);
191 
192  unsigned int nErrors = 0;
193  if (instance_names.empty()) {
194  instance_names.push_back("");
195  mf::LogInfo("SeedMaster_test") << "Added a default engine instance.";
196  }
197  mf::LogVerbatim("SeedMaster_test")
198  << module_id << " has " << instance_names.size() << " seed instances:";
199 
200  // seed test: do we successfully get seeds?
201  std::vector<seed_t> our_seeds;
202  for (std::string instance_name: instance_names) {
203  seed_t seed = ObtainSeed(seeds, module_name, instance_name);
204  mf::LogVerbatim("SeedMaster_test")
205  << "Seed for '" << instance_name << "' is: " << seed;
206  if (seed == 0) {
207  MF_LOG_ERROR(module_id)
208  << "instance " << instance_name << " got seed 0!";
209  if (++nErrors <= nExpectedErrors) {
210  mf::LogProblem(module_id) << " (error #" << nErrors
211  << ", " << nExpectedErrors << " expected)";
212  }
213  }
214  our_seeds.push_back(seed);
215  } // for declaration loop
216 
217  // consistency test: are they still the same?
218  std::vector<seed_t>::const_iterator iOldSeed = our_seeds.begin();
219  for (std::string instance_name: instance_names) {
220  seed_t seed = ObtainSeed(seeds, module_name, instance_name);
221  mf::LogVerbatim("SeedMaster_test")
222  << "Seed for '" << instance_name << "' is: " << seed << " (second query)";
223  if (seed != *iOldSeed) {
224  MF_LOG_ERROR(module_id)
225  << "seed has changed for instance "
226  << instance_name << ": " << *iOldSeed << " => " << seed;
227  if (++nErrors <= nExpectedErrors) {
228  mf::LogProblem(module_id) << " error " << nErrors
229  << ", " << nExpectedErrors << " expected";
230  }
231  } // if different from before
232  if (*iOldSeed == 0) {
233  MF_LOG_ERROR(module_id)
234  << "instance " << instance_name << " got seed 0!";
235  if (++nErrors <= nExpectedErrors) {
236  mf::LogProblem(module_id) << " (error #" << nErrors
237  << ", " << nExpectedErrors << " expected)";
238  }
239  } // if seed is 0
240  ++iOldSeed;
241  } // for consistency check
242 
243  // as many errors as expected, balance is even
244  return (nErrors > nExpectedErrors)?
245  nErrors - nExpectedErrors: nExpectedErrors - nErrors;
246 } // TestModule()
247 
248 
249 
250 //------------------------------------------------------------------------------
251 //--- stuff to run the facilitated stuff
252 //---
253 int main(int argc, const char** argv) {
254 
255  //****************************************************************************
256  //*** parse command line options
257  //***
258  std::string config_path;
259  std::string parameter_set_name;
260  std::vector<std::string> module_types{ "SeedTestPolicy" };
261 
262  int iParam = 0;
263  // configuration file path (mandatory)
264  if (++iParam < argc) {
265  config_path = argv[iParam];
266  }
267  else {
268  std::cerr
269  << "SeedMaster_test: please specify a configuration file." << std::endl;
270  return 1;
271  }
272 
273  // configuration key for the SeedMaster (optional)
274  if (++iParam < argc) {
275  parameter_set_name = argv[iParam];
276  }
277 
278  // module types for modules autodetection (optional)
279  if (++iParam < argc) {
280  module_types.assign(argv + iParam, argv + argc);
281  }
282 
283 
284  //****************************************************************************
285  //*** read the configuration from the file specified on the command line
286  //***
287  // simple file lookup policy: assume the file name specification is complete
288  cet::filepath_maker policy;
289 
290  // parse a configuration file; obtain intermediate form
292  fhicl::parse_document(config_path, policy, table);
293 
294  // translate into a parameter set
295  fhicl::ParameterSet global_pset;
296  fhicl::make_ParameterSet(table, global_pset);
297 
298  // initialize the message facility
299  StartMessageFacility(global_pset);
300  mf::SetContextSinglet("main");
301 
302  // read the configuration of the seed service
303  fhicl::ParameterSet pset;
304  try {
305  pset = FindSeedServiceConfiguration(global_pset, parameter_set_name);
306  }
307  catch (...) {
308  mf::LogError("SeedMaster_t")
309  << "Failed to read the '" << parameter_set_name
310  << "' parameters set from configuration file '" << config_path << "'";
311  throw;
312  }
313 
314  mf::LogInfo("SeedMaster_test") << "Parameters from '" << config_path << "':\n"
315  << pset.to_indented_string();
316 
317  // look for test modules
318  std::string module_base_key = "physics.analyzers";
319  std::vector<fhicl::ParameterSet> module_psets
320  = FindModulesConfiguration(global_pset, module_types, module_base_key);
321  if (module_psets.empty()) {
322  mf::LogError("SeedMaster_test")
323  << "could not find any suitable module configuration in '"
324  << module_base_key << "' of '" << config_path
325  << "'";
326  return 1;
327  } // if no modules
328 
329  { // anonymous block
330  mf::LogInfo log("SeedMaster_test");
331  log << "Found configurations for " << module_psets.size() << " modules.";
332  for (const fhicl::ParameterSet& pset: module_psets) {
333  std::string module_id = GetModuleID(pset);
334  log << '\n' << "*** " << module_id << " ***"
335  << std::string(72 - 8 - module_id.length(), '*')
336  << '\n' << pset.to_indented_string(1);
337  } // for
338  log << '\n' << std::string(72, '*');
339  } // end anonymous block
340 
341  bool endOfJobSummary = pset.get<bool>("endOfJobSummary", false);
342 
343  //****************************************************************************
344  //*** perform the tests...
345  //***
346  // create a new SeedMaster with the specified parameters set
347  std::unique_ptr<SeedMaster_t> pSeeds;
348  try {
349  pSeeds.reset(new SeedMaster_t(pset));
350  }
351  catch (const art::Exception& e) {
352  mf::LogError("SeedMaster_test")
353  << "Exception caught while initializing SeedMaster:\n"
354  << e.what();
355  return 1;
356  }
357  catch (const fhicl::exception& e) {
358  mf::LogError("SeedMaster_test")
359  << "FHiCL exception caught while initializing SeedMaster:\n"
360  << e.what();
361  return 1;
362  }
363 
364  unsigned int nErrors = 0;
365  for (const fhicl::ParameterSet& module_pset: module_psets) {
366  try {
367  nErrors += TestModule(*pSeeds, module_pset);
368  }
369  catch(const art::Exception& e) {
370  mf::LogError("SeedMaster_test")
371  << "Exception caught while testing module " << GetModuleID(module_pset)
372  << ":\n"
373  << e.what();
374  ++nErrors;
375  }
376  } // for
377  mf::SetContextSinglet("main");
378 
379 
380  //****************************************************************************
381  //*** print the outcome and go
382  //***
383 
384  if (endOfJobSummary) pSeeds->print();
385 
386  if (nErrors > 0) {
387  mf::LogError("SeedMaster_test")
388  << "Test terminated with " << nErrors << " errors.";
389  return nErrors;
390  }
391  mf::LogInfo("SeedMaster_test") << "Test successful.";
392  return 0;
393 } // main()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< fhicl::ParameterSet > FindModulesConfiguration(const fhicl::ParameterSet &full_pset, const std::vector< std::string > &module_types, std::string base_key="physics.analyzers")
std::string string
Definition: nybbler.cc:12
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
fhicl::ParameterSet FindSeedServiceConfiguration(const fhicl::ParameterSet &full_pset, std::string key="services.NuRandomService")
rndm::SeedMaster< seed_t > SeedMaster_t
fhicl::ParameterSet GetConfiguration(const fhicl::ParameterSet &full_pset, std::string key)
#define MF_LOG_ERROR(category)
unsigned long seed_t
void make_ParameterSet(intermediate_table const &tbl, ParameterSet &ps)
intermediate_table::const_iterator const_iterator
ModuleType module_type(std::string const &full_key)
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
std::string GetModuleID(fhicl::ParameterSet const &pset)
Returns a string "ModuleType[ModuleName]" out of specified module config.
void SetContextIteration(string const &val)
MaybeLogger_< ELseverityLevel::ELsev_error, true > LogProblem
std::vector< std::string > get_pset_names() const
void StartMessageFacility(fhicl::ParameterSet const &pset, string const &applicationName)
const double e
seed_t seed_t
type of served seeds
Definition: SeedMaster.h:210
SeedMasterHelper::EngineId EngineId
type of engine ID
Definition: SeedMaster.h:213
def key(type, name=None)
Definition: graph.py:13
int main(int argc, const char **argv)
T get(std::string const &key) const
Definition: ParameterSet.h:231
std::string to_indented_string() const
bool get_if_present(std::string const &key, T &value) const
Definition: ParameterSet.h:208
int TestModule(SeedMaster_t &seeds, const fhicl::ParameterSet &pset)
Tests a "module" with a given configuration.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::vector< TrajPoint > seeds
Definition: DataStructs.cxx:13
seed_t ObtainSeed(SeedMaster_t &seeds, std::string module_name, std::string instance_name="")
Returns the seed for the specified module/instance, or 0 on error.
seed_t getSeed(std::string moduleLabel)
Returns the seed value for this module label.
Definition: SeedMaster.h:509
void SetContextSinglet(string const &val)
void SetApplicationName(string const &applicationName)
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
void parse_document(std::string const &filename, cet::filepath_maker &maker, intermediate_table &result)
Definition: parse.cc:825
void StartMessageFacility(fhicl::ParameterSet const &pset)
QTextStream & endl(QTextStream &s)