All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
geometry_unit_test_base.h
Go to the documentation of this file.
1 /**
2  * @file geometry_unit_test_base.h
3  * @brief Base class for objects initializing a geometry
4  * @date May 7th, 2015
5  * @author petrillo@fnal.gov
6  * @see unit_test_base.h
7  *
8  * Provides an environment for easy set up of a Geometry-aware test.
9  * Keep in mind that, as much as I could push on flexibility, the channel
10  * mapping algorithm must be hard-coded and, if using Boost unit test,
11  * the configuration file location must be hard coded too
12  * (or you can use the provided configuration).
13  *
14  * For an example of usage, see larcore/test/Geometry/geometry_iterator_test.cxx
15  *
16  * The standard TesterEnvironment<> class can't handle geo::GeometryCore.
17  * The reason is twofold: for once, ExptGeoHelperInterface service is not
18  * factorized, so we need to choose explicitly the ChannelMapAlg implementation
19  * (here this is obtained by a template argument). Another is that GeometryCore
20  * both is required and requires ChannelMapAlg to have a complete
21  * initialisation. There are ways to overcome the issue at the cost of added
22  * complication.
23  *
24  * Currently provides:
25  * - BasicGeometryEnvironmentConfiguration: a test environment configuration
26  * - GeometryTesterEnvironment: a prepacked geometry-aware test environment
27  *
28  */
29 
30 
31 #ifndef TEST_GEOMETRY_UNIT_TEST_BASE_H
32 #define TEST_GEOMETRY_UNIT_TEST_BASE_H
33 
34 // LArSoft libraries
38 
39 // utility libraries
40 #include "fhiclcpp/ParameterSet.h"
41 #include "messagefacility/MessageLogger/MessageLogger.h"
42 
43 // CET libraries
44 #include "cetlib/filesystem.h" // cet::is_absolute_filepath()
45 #include "cetlib/filepath_maker.h"
46 #include "cetlib/search_path.h"
47 
48 // C/C++ standard libraries
49 #include <iostream> // for output before message facility is set up
50 #include <string>
51 #include <memory> // std::unique_ptr<>
52 #include <map>
53 
54 
55 namespace testing {
56 
57 
58  /** **************************************************************************
59  * @brief Class holding a configuration for a test environment
60  * @tparam CHANNELMAP the class used for channel mapping
61  * @see GeometryTesterEnvironment
62  *
63  * This class needs to be fully constructed by the default constructor
64  * in order to be useful as Boost unit test fixture.
65  * It is supposed to be passed as a template parameter to another class
66  * that can store an instance of it and extract configuration information
67  * from it.
68  */
69  template <typename CHANNELMAP>
72  {
73  using ChannelMapClass = CHANNELMAP;
74 
75  /// Default constructor; this is what is used in Boost unit test
78  { LocalInit(); }
79 
80  /// Constructor: acquires parameters from the command line
81  BasicGeometryEnvironmentConfiguration(int argc, char** argv):
83  { LocalInit(); }
84 
85  /// Constructor; accepts the name as parameter
88  { LocalInit(); }
89 
91  (int argc, char** argv, std::string name):
92  BasicEnvironmentConfiguration(argc, argv, name)
93  { LocalInit(); }
94 
95 
96  /// @{
97  /// @name Access to configuration
98  /// FHiCL path for the geometry configuration
99  std::string GeometryParameterSetPath() const
101 
102  /// A string describing the default parameter set to configure geometry
103  std::string DefaultGeometryConfiguration() const
105 
106  ///@}
107 
108 
109  /// @{
110  /// @name Set configuration
111 
112  /// Sets the FHiCL path for the geometry configuration
115 
116  /// Sets a string describing the default parameter set to configure geometry
117  void SetDefaultGeometryConfiguration(std::string cfg)
119 
120  ///@}
121 
122 
123  /// Returns the name of the service
124  static std::string GeometryServiceName() { return "Geometry"; }
125 
126  protected:
127 
128  /// Initialize with some default values
129  void LocalInit()
130  {
131  SetDefaultGeometryConfiguration(R"( SurfaceY: 200. # in cm, vertical distance to the surface Name: "lartpcdetector" GDML: "LArTPCdetector.gdml" ROOT: "LArTPCdetector.gdml" SortingParameters: {} # empty parameter set for default )");
132  } // LocalInit()
133 
134  }; // class BasicGeometryEnvironmentConfiguration<>
135 
136 
137 
138  /** **************************************************************************
139  * @brief Environment for a geometry test
140  * @tparam ConfigurationClass a class providing compile-time configuration
141  *
142  * The test environment is set up on construction.
143  *
144  * The environment provides:
145  * - Geometry() method to access geometry (as a constant pointer)
146  * - Parameters() method returning the complete FHiCL configuration
147  * - TesterParameters() method returning the configuration for the test
148  *
149  * This class or a derived one can be used as global fixture for unit tests
150  * that require the presence of geometry (in the form of geo::GeometryCore
151  * instance).
152  *
153  * Unfortunately Boost does not give any control on the initialization of the
154  * object, so everything must be ready to go as hard coded.
155  * The ConfigurationClass class tries to alleviate that.
156  * That is another, small static class that GeometryTesterEnvironment uses to
157  * get its parameters.
158  *
159  * The requirements for the ConfigurationClass are:
160  * - `ChannelMapClass`: concrete type of channel mapping algorithm class
161  * - `std::string ApplicationName()`: the application name
162  * - `std::string ConfigurationPath()`: path to the configuration file
163  * - `std::string GeometryParameterSetPath()`: FHiCL path to the configuration
164  * of the geometry; in art is `"services.Geometry"`
165  * - `std::string TesterParameterSetPath()`: FHiCL path to the configuration
166  * of the geometry
167  * - `std::string DefaultGeometryConfiguration()` returning a FHiCL string
168  * to be parsed to extract the default geometry configuration
169  * - `std::string DefaultTesterConfiguration()` returning a FHiCL string
170  * to be parsed to extract the default test configuration
171  *
172  * Whether the configuration comes from a file or from the two provided
173  * defaults, it is always expected within the parameter set paths:
174  * the default configuration must also contain that path.
175  *
176  * Note that there is no room for polymorphism here since the setup happens
177  * on construction.
178  * Some methods are declared virtual in order to allow to tweak some steps
179  * of the set up, but it's not trivial to create a derived class that works
180  * correctly: the derived class must declare a new default constructor,
181  * and that default constructor must call the protected constructor
182  * (GeometryTesterEnvironment<ConfigurationClass>(no_setup))
183  */
184  template <typename ConfigurationClass>
185  class GeometryTesterEnvironment
186  : public TesterEnvironment<ConfigurationClass>
187  {
188 
189  /// Base class
190  using TesterEnvironment_t = TesterEnvironment<ConfigurationClass>;
192  /// this implements the singleton interface
194 
195  public:
197 
198  /**
199  * @brief Constructor: sets everything up and declares the test started
200  *
201  * The configuration is from a default-constructed ConfigurationClass.
202  * This is suitable for use as Boost unit test fixture.
203  */
204  GeometryTesterEnvironment(bool bSetup = true)
206  { if (bSetup) Setup(); }
207 
208  //@{
209  /**
210  * @brief Setup from a configuration
211  * @param configurer an instance of ConfigurationClass
212  *
213  * The configuration is from the specified configurer class.
214  *
215  * This constructor allows to use a non-default-constructed configuration.
216  * This can't be used (at best of my knowledge) when using this class as
217  * Boost unit test fixture.
218  *
219  * In the r-value-reference constructor, the configurer is moved.
220  */
222  (ConfigurationClass const& cfg_obj, bool bSetup = true)
223  : TesterEnvironment_t(cfg_obj, false)
224  { if (bSetup) Setup(); }
225  GeometryTesterEnvironment(ConfigurationClass&& cfg_obj, bool bSetup = true)
226  : TesterEnvironment_t(std::move(cfg_obj), false)
227  { if (bSetup) Setup(); }
228  //@}
229 
230  /// Destructor: closing remarks
232 
233 
234  //@{
235  /// Returns a pointer to the geometry
236  geo::GeometryCore const* Geometry() const { return geom.get(); }
237  SharedGeoPtr_t SharedGeometry() const { return geom; }
238  //@}
239 
240 
241  /// Returns the current global geometry instance
242  /// @throws std::out_of_range if not present
244  { return &GeoResources_t::Resource(); }
245 
246  /// Returns the current global geometry instance (may be nullptr if none)
248  { return GeoResources_t::ShareResource(); }
250  protected:
251 
252  using ChannelMapClass = typename ConfigurationClass::ChannelMapClass;
254 
255  /// The complete initialization, ran at construction by default
256  virtual void Setup();
257 
258  /// Creates a new geometry
259  virtual std::unique_ptr<geo::GeometryCore> CreateNewGeometry() const;
260 
261  //@{
262  /// Get ownership of the specified geometry and registers it as global
263  virtual void RegisterGeometry(SharedGeoPtr_t new_geom);
264  virtual void RegisterGeometry(geo::GeometryCore const* new_geom)
265  { RegisterGeometry(SharedGeoPtr_t(new_geom)); }
266  //@}
267 
268  /// Sets up the geometry (creates and registers it)
269  virtual void SetupGeometry();
271  private:
272 
273  ConfigurationClass config; ///< instance of the configurer
274 
275  SharedGeoPtr_t geom; ///< pointer to the geometry
276 
277  }; // class GeometryTesterEnvironment<>
278 
280 
281  //****************************************************************************
282  template <typename ConfigurationClass>
284 
285  mf::LogInfo("Test") << config.ApplicationName() << " completed.";
286 
287  } // GeometryTesterEnvironment<>::~GeometryTesterEnvironment()
288 
290  /** **************************************************************************
291  * @brief Sets the geometry of the standard detector up
292  *
293  * This function sets up the geometry according to the provided information:
294  * - the configuration must contain enough information to locate the geometry
295  * description file
296  * - we trust that that geometry works well with the ChannelMapClass specified
297  * in ConfigurationClass
298  *
299  */
300  template <typename ConfigurationClass>
301  std::unique_ptr<geo::GeometryCore>
303  {
304 
305  std::string ProviderParameterSetPath
306  = this->Config().GeometryParameterSetPath();
307 
308  //
309  // create the new geometry service provider
310  //
311  fhicl::ParameterSet ProviderConfig
312  = this->Parameters().template get<fhicl::ParameterSet>
313  (ProviderParameterSetPath);
314  auto new_geom = std::make_unique<geo::GeometryCore>(ProviderConfig);
315 
316  std::string RelativePath
317  = ProviderConfig.get< std::string>("RelativePath", "");
318 
319  std::string
320  GDMLFileName = RelativePath + ProviderConfig.get<std::string>("GDML"),
321  ROOTFileName = RelativePath + ProviderConfig.get<std::string>("ROOT");
322 
323  // Search all reasonable locations for the geometry file;
324  // we see if by any chance art's FW_SEARCH_PATH directory is set and try
325  // there;
326  // if not, we do expect the path to be complete enough for ROOT to cope.
327  cet::search_path sp("FW_SEARCH_PATH");
328 
329  std::string ROOTfile;
330  if (!sp.find_file(ROOTFileName, ROOTfile)) ROOTfile = ROOTFileName;
331 
332  // we really don't care of GDML file, since we are not going to run Geant4
333  std::string GDMLfile;
334  if (!sp.find_file(GDMLFileName, GDMLfile)) {
335  mf::LogWarning("CreateNewGeometry") << "GDML file '"
336  << GDMLfile << "' not found.";
337  }
338 
339  // initialize the geometry with the files we have found
340  new_geom->LoadGeometryFile(GDMLfile, ROOTfile);
341 
342 
343  //
344  // create the new channel map
345  //
346  auto const SortingParameters
347  = ProviderConfig.get<fhicl::ParameterSet>("SortingParameters", {});
348 
349  // connect the channel map with the geometry, that shares ownsership
350  // (we give up ours at the end of this method)
351  new_geom->ApplyChannelMap(std::make_unique<ChannelMapClass>(SortingParameters));
352 
353  return new_geom;
354  } // GeometryTesterEnvironment<>::CreateNewGeometry()
355 
356 
357  template <typename ConfigurationClass>
359  (SharedGeoPtr_t new_geom)
360  {
361  // update the current geometry, that becomes owner;
362  // also update the global one if it happens to be already our previous
363  // (in this case, it becomes co-owner)
364  SharedGeoPtr_t my_old_geom = geom;
365  geom = new_geom;
366  // if the global geometry is already the one we register, don't bother
367  if (SharedGlobalGeometry() != new_geom)
368  GeoResources_t::ReplaceDefaultSharedResource(my_old_geom, new_geom);
369  } // GeometryTesterEnvironment<>::RegisterGeometry()
370 
371 
372 
373  template <typename ConfigurationClass>
375  //
376  // horrible, shameful hack to support the "new" testing environment
377  // while the old one, informally deprecated, is still around;
378  // we will have TWO versions of GeometryCore around.
379  // Ugh.
380  //
381  RegisterGeometry(CreateNewGeometry()); // old
382  // new
383  this->template AcquireProvider<geo::GeometryCore>(CreateNewGeometry());
384  } // GeometryTesterEnvironment<>::SetupGeometry()
385 
386 
387 
388  template <typename ConfigurationClass>
390 
391  //
392  // parse configuration, set up message facility
393  //
394  TesterEnvironment_t::Setup();
396  //
397  // set up the geometry
398  //
399  SetupGeometry();
400 
401  mf::LogInfo("Test")
402  << config.ApplicationName() << " Geometry setup complete.";
403 
404  } // GeometryTesterEnvironment<>::Setup()
405 
406 
407 } // namespace testing
408 
409 #endif // TEST_GEOMETRY_UNIT_TEST_BASE_H
410 
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
virtual ~GeometryTesterEnvironment()
Destructor: closing remarks.
static std::string GeometryServiceName()
Returns the name of the service.
BasicGeometryEnvironmentConfiguration()
Default constructor; this is what is used in Boost unit test.
void LocalInit()
Initialize with some default values.
static geo::GeometryCore const * GlobalGeometry()
std::shared_ptr< Resource_t > ResourcePtr_t
std::string DefaultGeometryConfiguration() const
A string describing the default parameter set to configure geometry.
virtual void RegisterGeometry(SharedGeoPtr_t new_geom)
Get ownership of the specified geometry and registers it as global.
Class holding a configuration for a test environment.
typename StandardGeometryConfiguration::ChannelMapClass ChannelMapClass
SharedGeoPtr_t geom
pointer to the geometry
std::string ROOTFileName
static SharedGeoPtr_t SharedGlobalGeometry()
Returns the current global geometry instance (may be nullptr if none)
void AddDefaultServiceConfiguration(std::string service_name, std::string service_cfg)
Adds a default configuration for the specified service.
BEGIN_PROLOG triggeremu_data_config_icarus settings PMTADCthresholds sequence::icarus_stage0_multiTPC_TPC physics sequence::icarus_stage0_EastHits_TPC physics sequence::icarus_stage0_WestHits_TPC physics producers purityana0 caloskimCalorimetryCryoE physics caloskimCalorimetryCryoW physics path
Access the description of detector geometry.
std::string ServiceParameterSetPath(std::string name) const
FHiCL path for the configuration of the service.
ConfigurationClass config
instance of the configurer
BasicGeometryEnvironmentConfiguration(int argc, char **argv)
Constructor: acquires parameters from the command line.
void SetGeometryParameterSetPath(std::string path)
Sets the FHiCL path for the geometry configuration.
std::string DefaultServiceConfiguration(std::string service_name) const
A string describing the default parameter set to configure the test.
static Resource_t & Resource(std::string name="")
Retrieves the specified resource, or throws if not available.
static ResourcePtr_t ShareResource(std::string name="")
Retrieves the specified resource for sharing (nullptr if none)
GeometryTesterEnvironment(bool bSetup=true)
Constructor: sets everything up and declares the test started.
Utility class providing singleton objects to the derived classes.
void SetDefaultGeometryConfiguration(std::string cfg)
Sets a string describing the default parameter set to configure geometry.
Description of geometry of one entire detector.
virtual void SetupGeometry()
Sets up the geometry (creates and registers it)
BasicEnvironmentConfiguration()
Default constructor; this is what is used in Boost unit test.
fhicl::Table< sbnd::crt::CRTDetSimParams > Parameters
Class holding a configuration for a test environment.
std::unique_ptr< geo::GeometryCore > SetupGeometry(fhicl::ParameterSet const &pset, Args &&...args)
Initializes a LArSoft geometry object.
std::string GDMLFileName
virtual std::unique_ptr< geo::GeometryCore > CreateNewGeometry() const
Creates a new geometry.
BasicGeometryEnvironmentConfiguration(std::string name)
Constructor; accepts the name as parameter.
then echo fcl name
virtual void Setup()
The complete initialization, ran at construction by default.
Interface to algorithm class for a specific detector channel mapping.
geo::GeometryCore const * Geometry() const
Returns a pointer to the geometry.
Base class for unit tests using FHiCL configuration.
void SetServiceParameterSetPath(std::string service_name, std::string path)
Sets the FHiCL path for the configuration of a test algorithm.
BEGIN_PROLOG vertical distance to the surface table::sbnd_geo_source SortingParameters
TesterEnvironment< ConfigurationClass > TesterEnvironment_t
Base class.