Line data Source code
1 0 : \cond NEVER 2 : Distributed under the MIT License. 3 : See LICENSE.txt for details. 4 : \endcond 5 : # Option Parsing {#dev_guide_option_parsing} 6 : 7 : \tableofcontents 8 : 9 : SpECTRE can read YAML configuration files at runtime to set parameters 10 : and choose between classes implementing an interface. %Options are 11 : parsed during code initialization and can be used to construct objects 12 : placed in the Parallel::GlobalCache and options passed to the 13 : parallel components. The types necessary to mark objects for parsing 14 : are declared in `Options/Options.hpp`. 15 : 16 : ## Metadata and options 17 : 18 : YAML input files begin with a metadata section, terminated by `---`, and 19 : followed by the executable options: 20 : 21 : ```yaml 22 : # Metadata here 23 : Description: | 24 : Briefly describe the configuration and link to papers for details. 25 : --- 26 : # Options start here 27 : ``` 28 : 29 : The metadata section may also be empty: 30 : 31 : ```yaml 32 : --- 33 : --- 34 : # Options start here 35 : ``` 36 : 37 : You only need the leading `---` marker if the metadata section is empty. This is 38 : YAML's "document start marker" (see the [YAML spec](https://yaml.org/spec/1.2)). 39 : Any metadata fields at the beginning of the file also imply the start of a 40 : document, so you don't need the first `---` marker. 41 : 42 : Metadata provide information for tools, whereas options provide information to 43 : the executable. See tools like `CheckOutputFiles` for details on the metadata 44 : fields that they use. Metadata can also provide information on how to run the 45 : input file, such as the name and version of the executable, and a description 46 : that may refer to published papers for details on the configuration. 47 : Options are defined by the executable and detailed below. 48 : 49 : ## General option format 50 : 51 : An option is defined by an "option tag", represented by a `struct`. At minimum, 52 : the struct must declare the type of the object to be parsed and provide a brief 53 : description of the meaning. The name of the option in the input file 54 : defaults to the name of the struct (excluding any template parameters 55 : and scope information), but can be overridden by providing a static 56 : `name()` function. Several other pieces of information, such as 57 : suggestions, limits and grouping, may be provided if desired. This 58 : information is all included in the generated help output. 59 : 60 : If an option has a suggested value, the value is specified in the 61 : input file as usual, but a warning will be issued if the specified 62 : value does not match the suggestion. 63 : 64 : Examples: 65 : \snippet Test_Options.cpp options_example_scalar_struct 66 : \snippet Test_Options.cpp options_example_vector_struct 67 : 68 : The option type can be any type understood natively by yaml-cpp 69 : (fundamentals, `std::string`, and `std::map`, `std::vector`, 70 : `std::list`, `std::array`, and `std::pair` of parsable types) and 71 : types SpECTRE adds support for. SpECTRE adds `std::unordered_map` 72 : (but only with ordered keys), `std::variant` (with alternatives tested 73 : in order), and various classes marked as constructible in their 74 : declarations. 75 : 76 : An option tag can be placed in a group by adding a `group` type alias to the 77 : struct. The alias should refer to a type that, like option tags, defines a help 78 : string and may override a static `name()` function. 79 : 80 : Example: 81 : \snippet Test_Options.cpp options_example_group 82 : 83 : ## Constructible classes 84 : 85 : A class that defines `static constexpr Options::String help` and a 86 : typelist of option structs `options` can be created by the option 87 : parser. When the class is requested, the option parser will parse 88 : each of the options in the `options` list, and then supply them to the 89 : constructor of the class. A class can use Options::Alternatives to 90 : support more than one possible set of options for its creation. (See 91 : [Custom parsing](#custom-parsing) below for more general creation 92 : mechanisms.) 93 : 94 : Unlike option descriptions, which should be brief, the class help 95 : string has no length limits and should give a description of the class 96 : and any necessary discussion of its options beyond what can be 97 : described in their individual help strings. 98 : 99 : Creatable classes must be default constructible and move assignable. 100 : 101 : The `Options::Context` is an optional argument to the constructor that should be 102 : used when the constructor checks for validity of the input. If the input is 103 : invalid, `PARSE_ERROR` is used to propagate the error message back through the 104 : options ensuring that the error message will have a full backtrace so it is easy 105 : for the user to diagnose. 106 : 107 : Example: 108 : \snippet Test_CustomTypeConstruction.cpp class_creation_example 109 : 110 : Classes may use the Metavariables struct, which is effectively the compile time 111 : input file, in their parsing by templating the `options` type alias or by taking 112 : the Metavariables as a final argument to the constructor (after the 113 : `Options::Context`). 114 : 115 : Example: 116 : \snippet Test_CustomTypeConstruction.cpp class_creation_example_with_metavariables 117 : 118 : ## Factory 119 : 120 : The factory interface creates an object of type 121 : `std::unique_ptr<Base>` containing a pointer to some class derived 122 : from `Base`. The list of creatable derived classes is specified in 123 : the `factory_creation` struct in the metavariables, which must contain 124 : a `factory_classes` type alias that is a `tmpl::map` from base classes 125 : to lists of derived classes: 126 : \snippet Test_Factory.cpp factory_creation 127 : 128 : When a `std::unique_ptr<Base>` is requested, the factory will expect a 129 : single YAML argument specifying the name of the class (as given by a 130 : static `name()` function or, lacking that, the actual class name). If 131 : the derived class takes no arguments, the name can be given as a YAML 132 : string, otherwise it must be given as a single key-value pair, with 133 : the key the name of the class. The value portion of this pair is then 134 : used to create the requested derived class in the same way as an 135 : explicitly constructible class. Examples: 136 : \snippet Test_Factory.cpp factory_without_arguments 137 : \snippet Test_Factory.cpp factory_with_arguments 138 : 139 : \anchor custom-parsing 140 : ## Custom parsing 141 : 142 : Occasionally, the requirements imposed by the default creation 143 : mechanism are too stringent. In these cases, the construction 144 : algorithm can be overridden by providing a specialization of the 145 : struct 146 : \code{cpp} 147 : template <typename T> 148 : struct Options::create_from_yaml { 149 : template <typename Metavariables> 150 : static T create(const Options::Option& options); 151 : }; 152 : \endcode 153 : The create function can perform any operations required to construct 154 : the object. 155 : 156 : Example of using a specialization to parse an enum: 157 : \snippet Test_CustomTypeConstruction.cpp enum_creation_example 158 : 159 : Note that in the case where the `create` function does *not* need to use the 160 : `Metavariables` it is recommended that a general implementation forward to an 161 : explicit instantiation with `void` as the `Metavariables` type. The reason for 162 : using `void` specialization is to reduce compile time. Since we only need one 163 : full implementation of the function independent of what type `Metavariables` is, 164 : we should only parse and compile it once. By having a specialization on `void` 165 : (or some other non-metavariables type like `NoSuchType`) we can handle the 166 : metavariables-independent case efficiently. As a concrete example, the general 167 : definition and forward declaration of the `void` specialization in the header 168 : file would be: 169 : 170 : \snippet Test_CustomTypeConstruction.cpp enum_void_creation_header_example 171 : 172 : while in the `cpp` file the definition of the `void` specialization is: 173 : 174 : \snippet Test_CustomTypeConstruction.cpp enum_void_creation_cpp_example