QMCPACK
InputSection.h
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2023 QMCPACK developers.
6 //
7 // File developed by: Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
8 // Peter W. Doak, doakpw@ornl.gov, Oak Ridge National Laboratory
9 //
10 //////////////////////////////////////////////////////////////////////////////////////
11 #ifndef QMCPLUSPLUS_INPUTSECTION_H
12 #define QMCPLUSPLUS_INPUTSECTION_H
13 
14 #include <typeinfo>
15 #include <any>
16 #include <stdexcept>
17 #include <exception>
18 #include <functional>
19 #include <unordered_set>
20 #include <unordered_map>
21 
22 #include "Configuration.h"
23 #include "OhmmsData/ParameterSet.h"
25 
27 
28 namespace qmcplusplus
29 {
30 
31 /** Input section provides basic parsing and a uniform method of access to the raw parsed input.
32  * It is still expected to be a composed part of the actual input class for a simulation class.
33  * It does not operate at reduced precision, i.e. numerical input is always parsed and retrieved
34  * at full precision. Gettting values from input section is strongly typed so you will get errors
35  * if you try to get numeric types at reduced precision.
36  */
38 {
39 public:
42 
43  InputSection() = default;
44  InputSection(const InputSection& other) = default;
45  InputSection& operator=(const InputSection& other) = default;
46 
47 protected:
48  // Internal data below comprise the input specification.
49  // Most apply attributes to input variables.
50  // Enables minimal listing of variable classification and default values in derived classes.
51  // Expand later to include allowed_values for input correctness checking
52 
53  // Becuase it hurts to read all the trailing _ in the constructors of input section subtypes
54  // NOLINTBEGIN(readability-indentifier-naming)
55 
56  /// "Name" of the input section, you must define this in the subtype and the ename, name, type, or method must match.
57  std::string section_name;
58 
59  /// For historical reasons some sections must recognize several different names. Assign them to this variable in your subtype.
60  std::vector<std::string> section_name_alternates;
61 
62  std::unordered_set<std::string> attributes; // list of attribute variables
63  std::unordered_set<std::string> parameters; // list of parameter variables
64  std::unordered_set<std::string> delegates; // input nodes delegate to next level of input parsing.
65  std::unordered_set<std::string> required; // list of required variables
66  std::unordered_set<std::string> multiple; // list of variables that can have multiple instances
67  std::unordered_set<std::string> strings; // list of string variables that can have one value
68  std::unordered_set<std::string> multi_strings; // list of string variables that can one or more values
69  std::unordered_set<std::string> multi_reals; // list of real variables
70  std::unordered_set<std::string> bools; // list of boolean variables
71  std::unordered_set<std::string> integers; // list of integer variables
72  std::unordered_set<std::string> reals; // list of real variables
73  std::unordered_set<std::string> positions; // list of position variables
74  std::unordered_set<std::string> custom; // list of parameter variables that have custom types
75  /** list of enum inputs which allow a finite set of strings to map to enum values
76  * The enum class types and values need only be known to IS subtypes
77  */
78  std::unordered_set<std::string> enums;
79  std::unordered_map<std::string, std::any> default_values; // default values for optional variables
80  std::unordered_map<std::string, std::function<std::any(xmlNodePtr cur, std::string& value_key)>> delegate_factories_;
81  // NOLINTEND(readability-indentifier-naming)
82  // Storage for variable values read from XML, etc.
83  std::unordered_map<std::string, std::any> values_;
84 
85 public:
86  // Query if a variable has been set
87  bool has(const std::string& name) const { return values_.find(name) != values_.end(); }
88 
89  // Enable read-only access to variable values.
90  // Needs updating to allow copy-less return.
91  template<typename T>
92  T get(const std::string& name) const
93  {
94  if constexpr (std::is_enum<T>::value)
95  {
96  std::any any_enum = assignAnyEnum(name);
97  return std::any_cast<T>(any_enum);
98  }
99  else
100  {
101  try
102  {
103  return std::any_cast<T>(values_.at(name));
104  }
105  catch (...)
106  {
107  std::throw_with_nested(UniformCommunicateError("Could not access value with name " + name));
108  }
109  }
110  }
111 
112  /** set var if input section has read the tag
113  * \param[out] var external variable to be set if tag was defined
114  * \param[in] tag string tag of value could be parameter or atttribute name
115  * \return whether input section has tag
116  *
117  * use this is you prefer have native c++ types for input class members
118  * as well as set default via native c++ declaration. See
119  * OneBodyDensityMatricesInput for example.
120  */
121  template<typename T>
122  bool setIfInInput(T& var, const std::string& tag)
123  {
124  if (has(tag))
125  {
126  var = get<T>(tag);
127  return true;
128  }
129  else
130  return false;
131  }
132 
133  /** Read variable values (initialize) from XML input, call checkValid.
134  *
135  * Ideally this will always be called from the constructor of an input class the InputSection
136  * is defined in the scope of.
137  */
138  void readXML(xmlNodePtr cur);
139 
140  // Initialize from unordered_map/initializer list
141  void init(const std::unordered_map<std::string, std::any>& init_values);
142 
143  /** Get string represtation of enum class type value from enum_val
144  *
145  * work around the lack of a bidirectional std c++ map type.
146  */
147  template<typename ENUM_T>
148  static std::string reverseLookupInputEnumMap(ENUM_T enum_val,
149  const std::unordered_map<std::string, std::any>& enum_map)
150  {
151  std::string lookup_str = "not found";
152  for (const auto& enum_node : enum_map)
153  {
154  if (enum_node.second.type() == typeid(decltype(enum_val)) &&
155  enum_val == std::any_cast<decltype(enum_val)>(enum_node.second))
156  {
157  lookup_str = enum_node.first;
158  break;
159  }
160  }
161  return lookup_str;
162  }
163 
164 protected:
165  /** reads attributes for both the root node and parameter/child nodes
166  * that aren't delegated.
167  *
168  * Side effect only method updates values_.
169  * \param[in] cur current xml node
170  * \param[in] element_name qualifying identifier with respect to the InputSection root node for the atttributes.
171  * \param[in] do_not_consume drop attributes used for element identification instead of the element name
172  * (this has complicated semantics in QMCPACK input)
173  * when a parameter has an ename="parameter" and the name attribute is used to identify the
174  * parameter we do not consume i.e. parse that name into the values_.
175  * If a top level section's indentifier is a name or type attribute we also need to avoid consuming it.
176  * Ideally any child node of significant complexity would be delegated to another input section.
177  */
178  void readAttributes(xmlNodePtr cur, const std::string& element_name, const std::vector<std::string>& do_not_consume);
179  /** Function that returns Input class as std::any
180  * \param[in] cur xml_node being delegated by the Input Class
181  * \param[out] value_name string key value to store the delegate with
182  */
183  using DelegateHandler = std::function<std::any(xmlNodePtr cur, std::string& value_name)>;
184  /** register factory function for delegate input
185  * \param[in] tag parmater name or node ename delgation is controlled by
186  * \param[in] delegate_handler factory function for delegated input function.
187  */
188  void registerDelegate(const std::string& tag, DelegateHandler delegate_handler);
189 
190  /** Do validation for a particular subtype of InputSection
191  * Called by check_valid.
192  * Default implementation is noop
193  * The InputSection subtype should make all correctness checks reasonable at parse time.
194  */
195  virtual void checkParticularValidity() {}
196  /** Derived class overrides this to get proper assignment of scoped enum values.
197  *
198  * In most cases all you'll need it to define the map and write:
199  * std::any DerivedInputSection::assignAnyEnum(const std::string& name) const
200  * {
201  * return lookupAnyEnum(name, get<std::string>(name), derived_input_lookup_enum);
202  * }
203  *
204  * See test_InputSection.cpp and OneBodyDensityMatricesInput
205  * You really should do this if your input class has a finite set of string values for an input
206  * example: OneBodyDensityMatricesInput
207  *
208  * can't be bothered then just define your enum option as a string.
209  */
210  [[noreturn]] virtual std::any assignAnyEnum(const std::string& tag) const;
211 
212  /** Derived class can overrides this to do custom parsing of the element values for Custom elements
213  * These can have a name attribute only.
214  * \param[in] ename name of the element svalue comes from, top level attributes do not have ename.
215  * \param[in] name name of the attribute
216  * \param[in] svalue input stream consisting of the contents of one element. It is expected that your
217  * custom stream handler will consume this entirely.
218  *
219  */
220  [[noreturn]] virtual void setFromStreamCustom(const std::string& ename,
221  const std::string& name,
222  std::istringstream& svalue);
223 
224  /** Assign any enum helper for InputSection derived class
225  * assumes enum lookup table of this form:
226  * inline static const std::unordered_map<std::string, std::any>
227  * lookup_input_enum_value{{"integrator-uniform_grid", Integrator::UNIFORM_GRID},
228  * {"integrator-uniform", Integrator::UNIFORM},
229  * {"integrator-density", Integrator::DENSITY},
230  * {"evaluator-loop", Evaluator::LOOP},
231  * {"evaluator-matrix", Evaluator::MATRIX}};
232  */
233  static std::any lookupAnyEnum(const std::string& enum_name,
234  const std::string& enum_value,
235  const std::unordered_map<std::string, std::any>& enum_map);
236 
237 protected:
238  // Simple dump of contents. Useful for developing and as
239  // debugging function useful when input sections local error reports
240  // may be insufficient.
241  void report() const;
242  void report(std::ostream& out) const;
243 
244 private:
245  // Query functions
246  bool isAttribute(const std::string& name) const { return attributes.find(name) != attributes.end(); }
247  bool isDelegate(const std::string& name) const { return delegates.find(name) != delegates.end(); }
248  bool isParameter(const std::string& name) const { return parameters.find(name) != parameters.end(); }
249  bool isRequired(const std::string& name) const { return required.find(name) != required.end(); }
250  bool isMultiple(const std::string& name) const { return multiple.find(name) != multiple.end(); }
251  bool isEnumString(const std::string& name) const { return enums.find(name) != enums.end(); }
252  bool isString(const std::string& name) const { return strings.find(name) != strings.end(); }
253  bool isMultiString(const std::string& name) const { return multi_strings.find(name) != multi_strings.end(); }
254  bool isMultiReal(const std::string& name) const { return multi_reals.find(name) != multi_reals.end(); }
255  bool isBool(const std::string& name) const { return bools.find(name) != bools.end(); }
256  bool isInteger(const std::string& name) const { return integers.find(name) != integers.end(); }
257  bool isReal(const std::string& name) const { return reals.find(name) != reals.end(); }
258  bool isPosition(const std::string& name) const { return positions.find(name) != positions.end(); }
259  bool isCustom(const std::string& name) const { return custom.find(name) != custom.end(); }
260  bool has_default(const std::string& name) const { return default_values.find(name) != default_values.end(); }
261 
262  // Set default values for optional inputs.
263  void setDefaults();
264 
265  // Perform typed read and assignment of input variables from strings
266  void setFromStream(const std::string& name, std::istringstream& svalue);
267 
268  /** Coerce input collected via init into types matching the definition of the input types
269  * defined in the InputSection subtype constructor.
270  */
271  void setFromValue(const std::string& name, const std::any& svalue);
272 
273  /** assign value into unordered map respecting values multiplicity
274  * It is a fatal exception to assign to a singular existing value.
275  *
276  * If the value isMultiple i.e. the value can legally appear multiple times in the input a vector of those
277  * values is built up at the key in the value map. If the value is never assigned to there is not an
278  * empty vector and that value is undefined in the map.
279  */
280  template<typename T>
281  void assignValue(const std::string& name, const T& value);
282 
283  /** factor out delegate handling code for sanity.
284  */
285  void handleDelegate(const std::string& ename, const xmlNodePtr element);
286 
287  /** Check validity of inputs
288  *
289  * This class just checks if required values_ are present and calls checkParticularValidity
290  * which the InputSection subtype should override.
291  */
292  void checkValid();
293 };
294 
295 
296 } // namespace qmcplusplus
297 #endif /* INPUTSECTION_H */
std::unordered_set< std::string > strings
Definition: InputSection.h:67
void handleDelegate(const std::string &ename, const xmlNodePtr element)
factor out delegate handling code for sanity.
std::unordered_set< std::string > reals
Definition: InputSection.h:72
void setFromValue(const std::string &name, const std::any &svalue)
Coerce input collected via init into types matching the definition of the input types defined in the ...
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
std::unordered_set< std::string > parameters
Definition: InputSection.h:63
bool isBool(const std::string &name) const
Definition: InputSection.h:255
std::unordered_map< std::string, std::function< std::any(xmlNodePtr cur, std::string &value_key)> > delegate_factories_
Definition: InputSection.h:80
std::vector< std::string > section_name_alternates
For historical reasons some sections must recognize several different names. Assign them to this vari...
Definition: InputSection.h:60
bool isMultiple(const std::string &name) const
Definition: InputSection.h:250
bool isCustom(const std::string &name) const
Definition: InputSection.h:259
std::unordered_set< std::string > positions
Definition: InputSection.h:73
std::unordered_map< std::string, std::any > default_values
Definition: InputSection.h:79
QMCTraits::FullPrecRealType Real
Definition: InputSection.h:40
std::unordered_set< std::string > custom
Definition: InputSection.h:74
void readAttributes(xmlNodePtr cur, const std::string &element_name, const std::vector< std::string > &do_not_consume)
reads attributes for both the root node and parameter/child nodes that aren&#39;t delegated.
std::unordered_set< std::string > delegates
Definition: InputSection.h:64
bool isEnumString(const std::string &name) const
Definition: InputSection.h:251
bool isMultiReal(const std::string &name) const
Definition: InputSection.h:254
void init(const std::unordered_map< std::string, std::any > &init_values)
virtual void checkParticularValidity()
Do validation for a particular subtype of InputSection Called by check_valid.
Definition: InputSection.h:195
std::function< std::any(xmlNodePtr cur, std::string &value_name)> DelegateHandler
Function that returns Input class as std::any.
Definition: InputSection.h:183
bool isDelegate(const std::string &name) const
Definition: InputSection.h:247
typename QMCTypes< Real, OHMMS_DIM >::PosType Position
Definition: InputSection.h:41
std::unordered_set< std::string > integers
Definition: InputSection.h:71
This a subclass for runtime errors that will occur on all ranks.
void readXML(xmlNodePtr cur)
Read variable values (initialize) from XML input, call checkValid.
void checkValid()
Check validity of inputs.
std::unordered_set< std::string > attributes
Definition: InputSection.h:62
bool isInteger(const std::string &name) const
Definition: InputSection.h:256
static std::any lookupAnyEnum(const std::string &enum_name, const std::string &enum_value, const std::unordered_map< std::string, std::any > &enum_map)
Assign any enum helper for InputSection derived class assumes enum lookup table of this form: inline ...
std::unordered_map< std::string, std::any > values_
Definition: InputSection.h:83
bool isAttribute(const std::string &name) const
Definition: InputSection.h:246
static std::string reverseLookupInputEnumMap(ENUM_T enum_val, const std::unordered_map< std::string, std::any > &enum_map)
Get string represtation of enum class type value from enum_val.
Definition: InputSection.h:148
void setFromStream(const std::string &name, std::istringstream &svalue)
void assignValue(const std::string &name, const T &value)
assign value into unordered map respecting values multiplicity It is a fatal exception to assign to a...
std::unordered_set< std::string > required
Definition: InputSection.h:65
bool isRequired(const std::string &name) const
Definition: InputSection.h:249
bool isString(const std::string &name) const
Definition: InputSection.h:252
bool isPosition(const std::string &name) const
Definition: InputSection.h:258
std::unordered_set< std::string > multi_strings
Definition: InputSection.h:68
std::unordered_set< std::string > bools
Definition: InputSection.h:70
bool isMultiString(const std::string &name) const
Definition: InputSection.h:253
std::unordered_set< std::string > multi_reals
Definition: InputSection.h:69
QTFull::RealType FullPrecRealType
Definition: Configuration.h:66
bool setIfInInput(T &var, const std::string &tag)
set var if input section has read the tag
Definition: InputSection.h:122
std::unordered_set< std::string > multiple
Definition: InputSection.h:66
Input section provides basic parsing and a uniform method of access to the raw parsed input...
Definition: InputSection.h:37
void registerDelegate(const std::string &tag, DelegateHandler delegate_handler)
register factory function for delegate input
bool isReal(const std::string &name) const
Definition: InputSection.h:257
bool isParameter(const std::string &name) const
Definition: InputSection.h:248
bool has(const std::string &name) const
Definition: InputSection.h:87
std::string section_name
"Name" of the input section, you must define this in the subtype and the ename, name, type, or method must match.
Definition: InputSection.h:57
bool has_default(const std::string &name) const
Definition: InputSection.h:260
InputSection & operator=(const InputSection &other)=default
virtual void setFromStreamCustom(const std::string &ename, const std::string &name, std::istringstream &svalue)
Derived class can overrides this to do custom parsing of the element values for Custom elements These...
std::unordered_set< std::string > enums
list of enum inputs which allow a finite set of strings to map to enum values The enum class types an...
Definition: InputSection.h:78
virtual std::any assignAnyEnum(const std::string &tag) const
Derived class overrides this to get proper assignment of scoped enum values.