Project

General

Profile

fhiclcpp types in detail


Parameter constructors

General comments

  • The Name argument is required for each of the fhiclcpp types.
  • Neither the Table<T> parameter nor any of the Optional* parameters support a default value.
  • None of the examples below include a use of the conditional configuration facility (i.e. std::function<bool()> maybeUse). An explanation of how users can take advantage of the facility is given here.
  • The Name&& and Comment&& references are explained here. The double-ampersand is a way of (almost unconditionally) requiring users to provide a temporary object by specifying (e.g.) Name("some_name") for each parameter.
  • In addition to Optional* parameters not supporting default values, they also cannot be used as template arguments to any fhiclcpp types:
    Sequence< OptionalSequence<int> >     e1 { ... };  // error
    Sequence< OptionalSequence<int,2u> >  e2 { ... };  // error
    Sequence< OptionalTuple<int,double> > e3 { ... };  // error
    OptionalSequence< Sequence<int> >     ok { ... };  // ok
    

Atom<T>

Allowed constructors

explicit Atom(Name&&);
explicit Atom(Name&&, Comment&&);
explicit Atom(Name&&, Comment&&, std::function<bool()> maybeUse);

// c'tors supporting default values
explicit Atom(Name&&, T const& t);
explicit Atom(Name&&, Comment&&, T const& t);
explicit Atom(Name&&, Comment&&, std::function<bool()> maybeUse, T const& t);

Examples

Atom<int> var { Name("var") };
Atom<int> var { Name("var"), 9 };
Atom<int> var { Name("var"), Comment("A parameter description") };
Atom<int> var { Name("var"), Comment("A parameter description"), 9 };

OptionalAtom<T>

Allowed constructors

explicit OptionalAtom(Name&&);
explicit OptionalAtom(Name&&, Comment&&);
explicit OptionalAtom(Name&&, Comment&&, std::function<bool()> maybeUse);

Examples

OptionalAtom<int> var { Name("var") };
OptionalAtom<int> var { Name("var"), Comment("A parameter description") };

OptionalSequence<T>

This class template is used for unbounded sequences.

Allowed constructors

explicit OptionalSequence(Name&&);
explicit OptionalSequence(Name&&, Comment&&);
explicit OptionalSequence(Name&&, Comment&&, std::function<bool()> maybeUse);

Examples

OptionalSequence<int> seq { Name("seq") };
OptionalSequence<int> seq { Name("seq"), Comment("A sequence") };

OptionalSequence<T,std::size_t>

This class template is used for sequences of a specific length, known at compile time.

Allowed constructors

explicit OptionalSequence(Name&&);
explicit OptionalSequence(Name&&, Comment&&);
explicit OptionalSequence(Name&&, Comment&&, std::function<bool()> maybeUse);

Examples

OptionalSequence<int,3u> seq { Name("seq") };
OptionalSequence<int,3u> seq { Name("seq"), Comment("A sequence") };

OptionalTable<T>

Allowed constructors

explicit OptionalTable(Name&&);
explicit OptionalTable(Name&&, Comment&&);
explicit OptionalTable(Name&&, Comment&&, std::function<bool()> maybeUse);

Examples

OptionalTable<T> config { Name("config") };
OptionalTable<T> config { Name("config"), Comment("This describes the table") };

OptionalTuple<T...>

Allowed constructors

explicit OptionalTuple(Name&&);
explicit OptionalTuple(Name&&, Comment&&);
explicit OptionalTuple(Name&&, Comment&&, std::function<bool()> maybeUse);

Examples

OptionalTuple<string,bool> tuple { Name("tuple") };
OptionalTuple<string,bool> tuple { Name("tuple"), Comment("A tuple") };

Sequence<T>

This class template is used for unbounded sequences. See the caveat below regarding narrowing conversions.

Allowed constructors

explicit Sequence(Name&&);
explicit Sequence(Name&&, Comment&&);
explicit Sequence(Name&&, Comment&&, std::function<bool()> maybeUse);

// c'tors supporting default values
explicit Sequence(Name&&, std::vector<T> const& t);
explicit Sequence(Name&&, Comment&&, std::vector<T> const& t);
explicit Sequence(Name&&, Comment&&, std::function<bool()> maybeUse, std::vector<T> const& t);

Examples

Sequence<int> seq { Name("seq") };
Sequence<int> seq { Name("seq"), Comment("A sequence") };
Sequence<int> seq { Name("seq"), std::vector<int>{ 4, 5, 6, 7 } };
Sequence<int> seq { Name("seq"), { 4, 5, 6, 7 } };
Sequence<int> seq { Name("seq"), Comment("A sequence"), std::vector<int>{ 4, 5, 6, 7 } };
Sequence<int> seq { Name("seq"), Comment("A sequence"), { 4, 5, 6, 7 } };

Precaution regarding narrowing conversions and std::initializer_list objects

The following configuration will trigger a compilation warning:

Sequence<int> seq1 { Name("seq1"), std::vector<int>{ 1, 2.4e-4 } };
Sequence<int> seq2 { Name("seq2"), { 1, 2.4e-4 } };

that looks similar to this:

warning: narrowing conversion of ‘2.4000000000000001e-4’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]

For build systems that convert compile-time warnings to errors, this will result in a build failure. The warning results from the nature of an std::initializer_list object (also referred to as a brace-enclosed initializer), signified by '{1, 2.4e-4}', which is used to initialize the sequence objects. For std::initializer_list objects, narrowing conversions are not allowed--that is, converting a double to an int is an example of narrowing that results in loss of information. This is the most likely example of where you may find a narrowing conversion.

Sequence<T,std::size_t>

This class template is used for sequences of a specific length, known at compile time.

Allowed constructors

The dtype is a type alias that allows users to specify as a default argument either an std::array<T,N> object or a brace-enclosed std::initializer_list<T> object. It is preferred that users provide an std::array object as a default value since the size of the supplied array is checked against the expected size at compile time.

explicit Sequence(Name&&);
explicit Sequence(Name&&, Comment&&);
explicit Sequence(Name&&, Comment&&, std::function<bool()> maybeUse);

// c'tors supporting default values
explicit Sequence(Name&&, dtype const& t);
explicit Sequence(Name&&, Comment&&, dtype const& t);
explicit Sequence(Name&&, Comment&&, std::function<bool()> maybeUse, dtype const& t);

Examples

Sequence<int,3u> seq { Name("seq") };
Sequence<int,3u> seq { Name("seq"), Comment("A sequence") };
Sequence<int,3u> seq { Name("seq"), std::array<int,3u>{ 4, 5, 6 } };
Sequence<int,3u> seq { Name("seq"), { 4, 5, 6 } };
Sequence<int,3u> seq { Name("seq"), Comment("A sequence"), std::array<int,3u>{ 4, 5, 6 } };
Sequence<int,3u> seq { Name("seq"), Comment("A sequence"), { 4, 5, 6 } };

The warning regarding narrowing conversions above applies for bounded sequences as well.

Table<T>

Allowed constructors

explicit Table(Name&&);
explicit Table(Name&&, Comment&&);
explicit Table(Name&&, Comment&&, std::function<bool()> maybeUse);
Table(ParameterSet const& pset); // performs validation of 'pset' against supported configuration

Examples

Table<T> config { Name("config") };
Table<T> config { Name("config"), Comment("This describes the table") };
Table<T> config { pset }; // validate 'pset' against allowed configuration 'T'

Table<T, KeysToIgnore>

This version of the Table template is used whenever there are specific keys (and nested keys) that are intended to be ignored during the validation step.

Allowed constructors

Table(ParameterSet const&);

N.B. The explicit constructors as indicated above for Table<T> are also allowed, but the KeysToIgnore::operator() function is not used in such a case.

Example

struct KeysToIgnore {
  std::set<std::string> operator()()
  {
    return {"otherTable", "otherAtom", "nested.sequence"};
  }
};

auto const& pset = get_ParameterSet_from_somewhere();
Table<T, KeysToIgnore> config {pset};

Notice that the KeysToIgnore type must contain an operator() function that returns an std::set<std::string> object containing the list of keys that should be ignored during the validation step. The validation skips any keys that match any of the strings specified by the operator() function are skipped. If the ignorable key is a table, all of the table's contents are ignored as well.

Tuple<T...>

Allowed constructors

The dtype is a type alias that allows users to specify as a default argument either an std::tuple<T...> object or a brace-enclosed initializer, which, in this case, is not an std::initializer_list object.

explicit Tuple(Name&&);
explicit Tuple(Name&&, Comment&&);
explicit Tuple(Name&&, Comment&&, std::function<bool()> maybeUse);

// c'tors supporting default values
explicit Tuple(Name&&, dtype const& t);
explicit Tuple(Name&&, Comment&&, dtype const& t);
explicit Tuple(Name&&, Comment&&, std::function<bool()> maybeUse, dtype const& t);

Examples

Tuple<string,bool> tuple { Name("tuple") };
Tuple<string,bool> tuple { Name("tuple"), Comment("A tuple") };
Tuple<string,bool> tuple { Name("tuple"), std::tuple<string,bool>{"explicit?", true} };
Tuple<string,bool> tuple { Name("tuple"), {"compact?", true } };
Tuple<string,bool> tuple { Name("tuple"), Comment("A tuple"), std::tuple<string,bool>{ "Particle physics is neat.", true } };
Tuple<string,bool> tuple { Name("tuple"), Comment("A tuple"), { "This is false", false } };

Standard parameters - return types

[ In what follows, array, string, tuple, and vector should each be prefaced with the appropriate namespace resolution: 'std::'. ]

fhiclcpp parameter Function call Return type
Simple fhiclcpp parameters
Atom<string> label; label() string const&
Sequence<int> counts; counts() vector<int>
counts(1) int
Sequence<double, 3u> point; point() array<double, 3u>
point(0) double
Tuple<string, double> assoc; assoc() tuple<string, double>
assoc.get<0>() string
assoc.get<double>() double
Table<Config> config; config() Config const&
Nested fhiclcpp parameters
Sequence< Sequence<int> > datasets; datasets() vector< vector<int> >
datasets(17) vector<int>
Sequence< Sequence<int>, 2u > twoDatasets; twoDatasets() array< vector<int>, 2u >
twoDatasets(1) vector<int>
Sequence< Sequence<int, 2u> > intPairs; intPairs() vector< array<int, 2u> >
intPairs(42) array<int, 2u>
Sequence< Tuple<string, int, bool> > triplets; triplets() vector< tuple<string, int, bool> >
triplets(3) tuple<string, int, bool>
Sequence< Table<Config> > manyConfigTables; manyConfigTables() vector< Config >
manyConfigTables(6) Config const&
Tuple< string, Table<Config> > configAssoc; configAssoc() tuple< string, Config >
configAssoc.get<0>() string
configAssoc.get<1>() Config
Tuple< Tuple<string,bool>, Sequence<int> > awkward; awkward() tuple< tuple<string, bool>, vector<int> >
awkward.get<0>() tuple<string,bool>
awkward.get<1>() vector<int>

Optional parameters - argument types

The usage pattern for Optional fhiclcpp parameters is:

OptionalAtom<string> message { Name("message") };

string filled_msg; // passed argument

if ( message(filled_msg) ) {
   // use 'filled_msg'
}

The following table gives the required passed-argument types for a given Optional parameter.

[ In what follows, array, string, tuple, and vector should each be prefaced with the appropriate namespace resolution: 'std::'. ]

fhiclcpp parameter Passed argument Function call
Simple fhiclcpp parameters
OptionalAtom<string> label; string l; bool exists = label(l);
OptionalSequence<int> counts; vector<int> v; bool exists = counts(v);
OptionalSequence<double, 3u> point; array<double, 3u> p; bool exists = point(p);
OptionalTuple<string, double> assoc; tuple<string, double> t; bool exists = assoc(t);
OptionalTable<Config> config; Config c; bool exists = config(c);
Nested fhiclcpp parameters
OptionalSequence< Sequence<int> > datasets; vector< vector<int> > sets; bool exists = datasets(sets);
OptionalSequence< Sequence<int>, 2u > twoDatasets; array< vector<int>, 2u > sets; bool exists = twoDatasets(sets);
OptionalSequence< Sequence<int, 2u> > intPairs; vector< array<int, 2u> > prs; bool exists = intPairs(prs);
OptionalSequence< Tuple<string, int, bool> > triplets; vector< tuple<string, int, bool> > trps; bool exists = triplets(trps);
OptionalSequence< Table<Config> > manyConfigTables; vector< Config > tbls; bool exists = manyConfigTables(tbls);
OptionalTuple< string, Table<Config> > configAssoc; tuple< string, Config > assoc; bool exists = configAssoc(assoc);
OptionalTuple< Tuple<string,bool>, Sequence<int> > awkward; tuple< tuple<string, bool>, vector<int> > wow; bool exists = awkward(wow);

Additional functions for Table<T>

The Table template offers a few extra functions that the user can call:

fhicl::ParameterSet const& get_PSet() const;

void print_allowed_configuration(std::ostream& os,
                                 std::string const& tab = std::string(3,' ') ) const;

// Expert-level functions
void validate_ParameterSet(fhicl::ParameterSet const& pset,
                           std::set<std::string> const& keysToIgnore = {} );

get_PSet

A call to this function returns a const reference to the ParameterSet object that was used to fill the values of the individual Table members. This is helpful for users who need to interact with the ParameterSet object itself.

print_allowed_configuration

For any Table<Config> object, print_allowed_configuration will fill a user-supplied std::ostream object with the allowed configuration as defined by the Config struct. The optional second argument specifies the number of spaces per indentation. The default is 3 spaces but is, of course, user-configurable.


[ N.B. The following function should not normally be invoked by users. It is meant to be called only in contexts outside of art. Please consult for guidance.]

validate_ParameterSet (expert)

This function is intended for experts who need to validate the pset object themselves. The keysToIgnore variable represents a set of keys for which the validation step will ignore. The validation function will ignore any nested keys as well--i.e. if a user specifies an ignorable key as table1, the (e.g.) table1.someAtom key would be ignored in addition to just the table1 name. An indexed parameter (e.g.) seq[1] is considered a nested parameter of its parent seq. Providing or not providing the ignorable key in a configuration will lead to no error upon validation of the ParameterSet.

Should the validation step fail, an exception is thrown of type fhicl::detail::validationException. This behavior is not currently configurable.


Common parameter accessors

Each of the fhiclcpp types has the following accessors:

std::string key()            const;
std::string name()           const;
std::string comment()        const;
bool        has_default()    const;
bool        is_optional()    const;
bool        is_conditional() const;
par_type    parameter_type() const;
bool        should_use()     const;

To call these functions, the difference in syntax is crucial:

Atom<int> val { Name("val") };

auto key1 = val.key();   //   correct
auto key2 = val().key(); // ! compile-time ERROR - 'val()' is an int, which has no accessor called 'key()' 

key()

A call to key() returns the full key, including all enclosing tables. For example, consider a module that is designed to allow the following configuration:

pset: {
  list: [ { particle: electron },
          { particle: muon } ]
}
For a suitably declared set of fhiclcpp parameters, the returned key corresponding to "muon" would be pset.list[1].particle.

name()

The name is the most-nested name in the key. For the above "muon" parameter, a key of pset.list[1].particle has a corresponding name of particle. If the parameter in question were pset.list[1], the name would be1 list[1].

1 Technically, this is inaccurate -- sequence elements do not have names. However, for the sake of parameter identification, a sequence element has a name whose value is the sequence name with the appropriate sequence element index/indices appended.

comment()

Returns the comment supplied as the string literal in (e.g.) Comment("Here is the comment"). If no Comment argument is provided in the fhiclcpp parameter constructor, a call to this function returns an empty string.

has_default()

Returns true or false depending on whether the user supplied a default value for the parameter.

is_optional()

Returns true if the parameter is an Optional* fhiclcpp type; false otherwise.

is_conditional()

Returns true if a configuration predicate (either through fhicl::use_if, fhicl::use_unless, or some supplied lambda function) has been provided by the user; false otherwise.

parameter_type()

Returns an enumeration value based on the parameter type:

enum class par_type {
  ATOM,        // (Optional)Atom<T>
  TABLE,       // (Optional)Table<T>
  SEQ_VECTOR,  // (Optional)Sequence<T>
  SEQ_ARRAY,   // (Optional)Sequence<T,std::size_t>
  TUPLE,       // (Optional)Tuple<T...>
  NTYPES       // Signifies invalid parameter 
};

should_use()

Returns true unless a user-provided configuration predicate returns false.