LCOV - code coverage report
Current view: top level - src/IO - ParmParse.H (source / functions) Coverage Total Hit
Test: coverage_merged.info Lines: 54.2 % 544 295
Test Date: 2026-06-29 14:20:01 Functions: 71.9 % 217 156

            Line data    Source code
       1              : //
       2              : // This is a thin wrapper to the amrex::ParmParse class
       3              : // This class exists to add some additional parsing capability, 
       4              : // e.g. parsing Set::Matrix and Set::Vector data types.
       5              : //
       6              : // :ref:`IO::ParmParse` uses static :code:`Parse()` functions to 
       7              : // perform cascading class-based input parsing.
       8              : // See the :ref:`autodoc` section for instructions on adding documentation.
       9              : // 
      10              : // :bdg-warning-line:`This is standard infrastructure code; make sure you know what you ard doing before you change it.`
      11              : //
      12              : // .. _query-directives:
      13              : //
      14              : // **Query directives**
      15              : //
      16              : // Alamo uses different query directives to standardize reading inputs and automatic documentation.
      17              : // The type of query that is used (query vs query_required, etc) triggers different handlers and different
      18              : // automatic documentation procedures.
      19              : // For instance, the use of a :code:`query_default` causes a default value to be set and added to the metadata
      20              : // file, and it also serves as a flag for the autodoc system to document that a default value is available.
      21              : // The following table is a reference for the different kinds of query directives.
      22              : //
      23              : //
      24              : // .. table::
      25              : //    :widths: 1 99
      26              : //
      27              : //    +---------------------------------+-----------------------------------------------------------------+
      28              : //    | BC Type                         | Description                                                     |
      29              : //    +=================================+=================================================================+
      30              : //    | :bdg-warning:`query`            | Standard IO for bool, string, Set::Scalarthat does not enforce  |
      31              : //    |                                 | defaults or required values. Not recommended for general use.   |
      32              : //    +---------------------------------+-----------------------------------------------------------------+
      33              : //    | :bdg-success:`query_required`   | Similar to query, but will abort if no value is specified.      |
      34              : //    |                                 | Required values are indicated by :bdg-danger-line:`required`.   |
      35              : //    +---------------------------------+-----------------------------------------------------------------+
      36              : //    | :bdg-success:`query_default`    | Similar to query, but will fill with default value if no value  |
      37              : //    |                                 | is provided. Will also add default value to metadata.           |
      38              : //    |                                 | Default values are indicated by green badge values, e.g.        |
      39              : //    |                                 | :bdg-success:`0.0`.                                             |
      40              : //    +---------------------------------+-----------------------------------------------------------------+
      41              : //    | :bdg-success:`query_validate`   | For strings, read in a value and enforce that the value is one  |
      42              : //    |                                 | of a supplied number of values. Optionally make required, or    |
      43              : //    |                                 | set the default value to the first supplied value.              | 
      44              : //    |                                 | Acceptable options are indicated by blue badge values, e.g.     | 
      45              : //    |                                 | :bdg-primary:`1.0`, :bdg-primary:`2.0`. If a default value is   | 
      46              : //    |                                 | available, it is indicated by a green badge, e.g.               | 
      47              : //    |                                 | :bdg-success:`1.0`.                                             | 
      48              : //    +---------------------------------+-----------------------------------------------------------------+
      49              : //    | :bdg-success:`query_file`       | Read in a string that defines a file name.                      |
      50              : //    |                                 | Check to make sure that the file exists and is a regular file,  |
      51              : //    |                                 | and print an informative error message if not (this can be      |
      52              : //    |                                 | disabled).                                                      |
      53              : //    |                                 | Also, copy the file to the output directory, with the full path |
      54              : //    |                                 | preserved by replacing / with _.                                |
      55              : //    |                                 | (This can also be disabled, but doing so is discouraged.)       |
      56              : //    |                                 | Default values are not allowed.                                 |
      57              : //    |                                 | File paths are indicated by :bdg-secondary-line:`file path`.    |
      58              : //    +---------------------------------+-----------------------------------------------------------------+
      59              : //    | :bdg-primary:`queryarr`         | Read in an array of numbers into either a standard vector or    |
      60              : //    |                                 | into a :code:`Set::Vector` or :code:`Set::Scalar`.              |
      61              : //    |                                 | No defaults or existence checking is performed.                 |
      62              : //    +---------------------------------+-----------------------------------------------------------------+
      63              : //    | :bdg-primary:`queryclass`       | Read a class object with a specified prefix.                    |
      64              : //    |                                 | How that class is read in is determined by its :code:`Parse`    |
      65              : //    |                                 | function.                                                       |
      66              : //    +---------------------------------+-----------------------------------------------------------------+
      67              : // 
      68              : // .. _query_locator_macros:
      69              : //
      70              : // **Query macros**
      71              : //
      72              : // A set of preprocessor macros are defined so that you can call a query function using :code:`pp_` instead
      73              : // of :code:`pp.`.
      74              : // For instance, the following two can be used interchangeably:
      75              : //
      76              : // .. code-block:: cpp
      77              : //
      78              : //     pp.query_required("myvar",myvar); /* function version */
      79              : //     pp_query_required("myvar",myvar); /* preprocessor macro version - preferred*/
      80              : // 
      81              : // Using the preprocessor macros enables code location information to be passed to the parser, so that
      82              : // more informative error messages will be printed out.
      83              : // Note that **the ParmParse object must always be called** :code:`pp` **for this to work**.
      84              : // 
      85              : //
      86              : 
      87              : #ifndef IO_PARMPARSE
      88              : #define IO_PARMPARSE
      89              : 
      90              : #include <filesystem>
      91              : #include <exception>
      92              : #include <list>
      93              : #include <stdexcept>
      94              : 
      95              : #include "Util/Util.H"
      96              : #include "Unit/Unit.H"
      97              : #include "Set/Base.H"
      98              : #include "AMReX_ParmParse.H"
      99              : 
     100              : 
     101              : #define pp_query_required(...) pp.query_required(__VA_ARGS__)
     102              : #define pp_query_default(...) pp.query_default(__VA_ARGS__)
     103              : #define pp_query_validate(...) pp.query_validate(__VA_ARGS__)
     104              : #define pp_query_file(...) pp.query_file(__VA_ARGS__)
     105              : #define pp_queryarr(...) pp.queryarr(__VA_ARGS__)
     106              : #define pp_queryarr_required(...) pp.queryarr_required(__VA_ARGS__)
     107              : #define pp_queryarr_default(...) pp.queryarr_default(__VA_ARGS__)
     108              : #define pp_query(...) pp.query(__VA_ARGS__)
     109              : #define pp_queryclass(...) pp.queryclass(__VA_ARGS__)
     110              : #define pp_forbid(...) pp.forbid(__VA_ARGS__)
     111              : 
     112              : 
     113              : namespace IO
     114              : {
     115              : class ParmParse : public amrex::ParmParse
     116              : {
     117              : private:
     118         1343 :     void Define() 
     119              :     {
     120         1343 :         if (checked_for_input_files) return;
     121           54 :         int k = 0;
     122           54 :         std::string inputfile = "";
     123           54 :         while (this->querykth("input",k,inputfile)) 
     124              :         {
     125            0 :             Util::Message(INFO,"Including inputs from "+inputfile);
     126            0 :             this->addfile(inputfile);
     127            0 :             k++;
     128              :         }
     129           54 :         checked_for_input_files = true;
     130           54 :     }
     131              :     static bool checked_for_input_files;
     132              :     
     133              : public:
     134          898 :     ParmParse(std::string arg) : amrex::ParmParse::ParmParse(arg) {Define();} ;
     135          445 :     ParmParse() : amrex::ParmParse::ParmParse() {Define();} ;
     136        14585 :     std::string getPrefix() const {return m_prefix;};
     137          684 :     void ignore(std::string name)
     138              :     {
     139          684 :         (void)amrex::ParmParse::contains(name.c_str());
     140          684 :     }
     141              :     
     142           54 :     void pushPrefix(const std::string prefix)
     143              :     {
     144           54 :         if (m_prefix.length())
     145           51 :             m_prefix = m_prefix + "." + prefix;
     146              :         else
     147            3 :             m_prefix = prefix;
     148           54 :     }
     149              : 
     150           54 :     void popPrefix()
     151              :     {
     152           54 :         size_t pos = m_prefix.rfind('.');
     153           54 :         if (pos == std::string::npos)
     154            3 :             m_prefix = "";
     155              :         else
     156           51 :             m_prefix = m_prefix.substr(0, pos);
     157           54 :     }
     158              : 
     159              : 
     160          349 :     void forbid(std::string name, std::string explanation)
     161              :     {
     162          349 :         if (amrex::ParmParse::contains(full(name).c_str()))
     163              :         {
     164            0 :             Util::ParmParseException(INFO,full(name),full(name)," forbidden: ", explanation);
     165              :         }
     166          349 :         std::set<std::string> subs = amrex::ParmParse::getEntries(full(name));
     167          349 :         if (subs.size())
     168              :         {
     169            0 :             Util::ParmParseException(INFO,full(name),full(name)," forbidden: ", explanation);
     170              :         }
     171          349 :     }
     172              : 
     173         4837 :     bool contains(std::string name)
     174              :     {
     175         4837 :         if (amrex::ParmParse::contains(name.c_str()))
     176         1627 :             return true;
     177         3210 :         if (amrex::ParmParse::contains(full(name).c_str()))
     178            0 :             return true;
     179              :         {
     180         3210 :             std::set<std::string> subs = amrex::ParmParse::getEntries(name.c_str());
     181         3210 :             if (subs.size())
     182           75 :                 return true;
     183         3210 :         }
     184              :         {
     185         3135 :             std::set<std::string> subs = amrex::ParmParse::getEntries(full(name).c_str());
     186         3135 :             if (subs.size())
     187            0 :                 return true;
     188         3135 :         }
     189         3135 :         return false;
     190              :     }
     191              : 
     192          409 :     int queryunit (std::string name, Unit &value)
     193              :     {
     194              :         try
     195              :         {
     196          409 :             std::string strvalue;
     197          409 :             int retval = amrex::ParmParse::query(name.c_str(),strvalue);
     198          409 :             value = Unit::Parse(strvalue);
     199         2045 :             Util::DebugMessage(INFO,full(name),": ",strvalue," ==> ",value);
     200          409 :             return retval;
     201          409 :         }
     202            0 :         catch (std::runtime_error & e)
     203              :         {
     204            0 :             Util::ParmParseException(INFO,full(name), e.what());
     205            0 :         }
     206            0 :         catch (...)
     207              :         {
     208            0 :             Util::ParmParseException(INFO,full(name));
     209            0 :         }
     210            0 :         return -1;
     211              :     }
     212              : 
     213          335 :     int queryunit (std::string name, Unit &value, const Unit type)
     214              :     {
     215              :         try
     216              :         {
     217          335 :             int retval = queryunit(name,value);
     218          335 :             if (!value.isType(type) && !value.isType(Unit::Less()))
     219              :             {
     220            0 :                 Util::ParmParseException(INFO, full(name),
     221            0 :                                 "value requiested had wrong units:", value.normalized_unitstring(),
     222            0 :                                 ", units requested are of SI type ",type.normalized_unitstring());
     223              :             }
     224          335 :             return retval;
     225              :         }
     226            0 :         catch (...)
     227              :         {
     228            0 :             Util::ParmParseException(INFO,full(name));
     229            0 :         }
     230            0 :         return -1;
     231              :     }
     232          335 :     int queryunit (std::string name, Set::Scalar &value, const Unit type)
     233              :     {
     234              :         try
     235              :         {
     236          335 :             Unit read;
     237          335 :             int retval = queryunit(name,read,type);
     238          335 :             value = read.normalized_value();
     239          335 :             return retval;
     240              :         }
     241            0 :         catch (std::runtime_error &e)
     242              :         {
     243            0 :             Util::ParmParseException(INFO,full(name), e.what());
     244            0 :         }
     245            0 :         return -1;
     246              :     }
     247              : 
     248              :     template<typename T> 
     249          181 :     int query_required( std::string name, T & value)
     250              :     {
     251              :         try
     252              :         {
     253          362 :             if (!contains(name.c_str()))
     254              :             {
     255            0 :                 Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
     256              :             }
     257          181 :             return query(name.c_str(),value);
     258              :         }
     259            0 :         catch (std::runtime_error & e)
     260              :         {
     261            0 :             Util::ParmParseException(INFO,full(name),e.what());
     262              :         }
     263            0 :         catch (...)
     264              :         {
     265            0 :             Util::ParmParseException(INFO,full(name));
     266              :         }
     267            0 :         return -1;
     268              :     }
     269              : 
     270              :     template<typename T> 
     271          153 :     int query_required( std::string name, T & value, const Unit type)
     272              :     {
     273              :         try
     274              :         {
     275          306 :             if (!contains(name.c_str()))
     276              :             {
     277            0 :                 Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
     278              :             }
     279          306 :             return queryunit(name.c_str(), value, type);
     280              :         }
     281            0 :         catch (std::runtime_error & e)
     282              :         {
     283            0 :             Util::ParmParseException(INFO,full(name),e.what());
     284              :         }
     285            0 :         catch (...)
     286              :         {
     287            0 :             Util::ParmParseException(INFO,full(name));
     288              :         }
     289            0 :         return -1;
     290              :     }
     291              : 
     292              :     template<typename T>
     293         2480 :     int query_default(  std::string name, T & value, T defaultvalue)
     294              :     {
     295              :         try
     296              :         {
     297         4960 :             if (!contains(name.c_str()))
     298              :             {
     299         2085 :                 add(name.c_str(),defaultvalue);
     300              :             }
     301         2480 :             return query(name.c_str(),value);
     302              :         }
     303            0 :         catch (std::runtime_error & e)
     304              :         {
     305            0 :             Util::ParmParseException(INFO,full(name),e.what());
     306              :         }
     307            0 :         catch (...)
     308              :         {
     309            0 :             Util::ParmParseException(INFO,full(name));
     310              :         }
     311            0 :         return -1;
     312              :     } 
     313              : 
     314              :     template<typename T>
     315          182 :     int query_default(  std::string name, T & value, std::string defaultvalue, const Unit type)
     316              :     {
     317              :         try
     318              :         {
     319          364 :             if (!contains(name.c_str()))
     320              :             {
     321          118 :                 add(name.c_str(),defaultvalue);
     322              :             }
     323          364 :             return queryunit(name.c_str(),value,type);
     324              :         }
     325            0 :         catch (std::runtime_error & e)
     326              :         {
     327            0 :             Util::ParmParseException(INFO,full(name),e.what());
     328              :         }
     329            0 :         catch (...)
     330              :         {
     331            0 :             Util::ParmParseException(INFO,full(name));
     332              :         }
     333            0 :         return -1;
     334              :     } 
     335              : 
     336            7 :     int query_validate( std::string name, int & value, std::vector<int> possibleintvals)
     337              :     {
     338              :         try
     339              :         {
     340              :             // First value is accepted by default...
     341              : 
     342              :             // set default value
     343           14 :             if (!contains(name.c_str()))
     344              :             {
     345            2 :                 add(name.c_str(), possibleintvals[0]);
     346              :             }
     347              : 
     348              :             // get the read value (if it exists)
     349            7 :             int retval = query(name.c_str(),value);
     350              : 
     351              :             // check to make sure the read value matches one of the inpus
     352            7 :             bool ok = false;
     353           32 :             for (unsigned int i = 0; i < possibleintvals.size(); i++)
     354              :             {
     355           25 :                 if (value == possibleintvals[i]) ok = true;
     356              :             }
     357              : 
     358            7 :             if (ok) return retval;
     359              : 
     360            0 :             std::stringstream ss;
     361            0 :             ss << possibleintvals[0];
     362            0 :             for (unsigned int i = 1; i < possibleintvals.size(); i++)
     363            0 :                 ss << "," << possibleintvals[i];
     364              : 
     365            0 :             Util::ParmParseException(INFO,full(name),"' expected [", ss.str(), "] but got ", value);
     366            0 :         }
     367            0 :         catch (std::runtime_error & e)
     368              :         {
     369            0 :             Util::ParmParseException(INFO,full(name),e.what());
     370            0 :         }
     371            0 :         catch (...)
     372              :         {
     373            0 :             Util::ParmParseException(INFO,full(name));
     374            0 :         }
     375            0 :         return -1;
     376              :     }
     377              : 
     378              : 
     379          195 :     int query_validate( std::string name, std::string & value, std::vector<const char *> possiblecharvals, bool firstbydefault)
     380              :     {        
     381              :         try
     382              :         {
     383              :             // if not using default values, then the input must be specified
     384          195 :             if (!firstbydefault)
     385              :             {
     386            0 :                 if (!amrex::ParmParse::contains(name.c_str()))
     387              :                 {
     388            0 :                     Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
     389              :                 }
     390              :             }
     391              : 
     392              :             // set default value
     393          195 :             if (!amrex::ParmParse::contains(name.c_str()))
     394              :             {
     395          345 :                 add(name.c_str(), std::string(possiblecharvals[0]));
     396              :             }
     397              : 
     398              :             // get the read value (if it exists)
     399          195 :             int retval = amrex::ParmParse::query(name.c_str(),value);
     400              : 
     401              :             // check to make sure the read value matches one of the inpus
     402          195 :             bool ok = false;
     403          682 :             for (unsigned int i = 0; i < possiblecharvals.size(); i++)
     404              :             {
     405          974 :                 if (value == std::string(possiblecharvals[i])) ok = true;
     406              :             }
     407              :         
     408          195 :             if (ok) return retval;
     409              : 
     410            0 :             std::stringstream ss;
     411            0 :             ss << possiblecharvals[0];
     412            0 :             for (unsigned int i = 1; i < possiblecharvals.size(); i++)
     413            0 :                 ss << "," << possiblecharvals[i];
     414              : 
     415            0 :             Util::ParmParseException(INFO,full(name),"' expected [", ss.str(), "] but got ", value);
     416            0 :         }
     417            0 :         catch (std::runtime_error & e)
     418              :         {
     419            0 :             Util::ParmParseException(INFO,full(name),e.what());
     420            0 :         }
     421            0 :         catch (...)
     422              :         {
     423            0 :             Util::ParmParseException(INFO,full(name));
     424            0 :         }
     425              : 
     426            0 :         return -1;
     427              :     }
     428              : 
     429          195 :     int query_validate( std::string name, std::string & value, std::vector<const char *> possiblecharvals)
     430              :     {
     431              :         try
     432              :         {
     433          195 :             return query_validate(name,value,possiblecharvals,true);
     434              :         }
     435            0 :         catch (std::runtime_error & e)
     436              :         {
     437            0 :             Util::ParmParseException(INFO,full(name),e.what());
     438            0 :         }
     439            0 :         catch (...)
     440              :         {
     441            0 :             Util::ParmParseException(INFO,full(name));
     442            0 :         }
     443            0 :         return -1;
     444              :     }
     445              : 
     446              :     
     447              :     // special case for strings
     448          818 :     int query_default(  std::string name, std::string & value, const char *defaultvalue)
     449              :     {
     450              :         try
     451              :         {
     452         1636 :             return query_default(name, value, std::string(defaultvalue));
     453              :         }
     454            0 :         catch (std::runtime_error & e)
     455              :         {
     456            0 :             Util::ParmParseException(INFO,full(name),e.what());
     457            0 :         }
     458            0 :         catch (...)
     459              :         {
     460            0 :             Util::ParmParseException(INFO,full(name));
     461            0 :         }
     462            0 :         return -1;
     463              :     }
     464              :     // special case for bools
     465           75 :     int query_default(  std::string name, int & value, bool defaultvalue)
     466              :     {
     467              :         try
     468              :         {
     469           75 :             int defaultint = 0;
     470           75 :             if (defaultvalue) defaultint = 1;
     471           75 :             return query_default(name, value, defaultint);
     472              :         }
     473            0 :         catch (std::runtime_error & e)
     474              :         {
     475            0 :             Util::ParmParseException(INFO,full(name),e.what());
     476            0 :         }
     477            0 :         catch (...)
     478              :         {
     479            0 :             Util::ParmParseException(INFO,full(name));
     480            0 :         }
     481            0 :         return -1;
     482              :     }
     483              : 
     484              : 
     485              :     // validate filenames
     486            2 :     int query_file( std::string name, std::string & value, bool copyfile, bool checkfile)
     487              :     {
     488              :         try
     489              :         {
     490            4 :             if (!contains(name.c_str()))
     491              :             {
     492            0 :                 Util::ParmParseException(INFO,full(name),full(name)," must be specified");
     493              :             }
     494              : 
     495            2 :             int retval = query(name.c_str(),value);
     496              : 
     497            2 :             if (amrex::ParallelDescriptor::IOProcessor())
     498              :             {
     499            2 :                 if ( checkfile && ! std::filesystem::exists(value))
     500              :                 {
     501            0 :                     Util::ParmParseException(INFO,full(name),full(name)," does not exist");
     502              :                 }
     503            2 :                 if ( checkfile && !std::filesystem::is_regular_file(value))
     504              :                 {
     505            0 :                     Util::ParmParseException(INFO,full(name),full(name)," is not a regular file");
     506              :                 }
     507            2 :                 if ( copyfile )
     508              :                 {
     509            2 :                     Util::CopyFileToOutputDir(value, true, full(name));
     510              :                 }
     511              :             }
     512            2 :             return retval;
     513              :         }
     514            0 :         catch (std::runtime_error & e)
     515              :         {
     516            0 :             Util::ParmParseException(INFO,full(name),e.what());
     517            0 :         }
     518            0 :         catch (...)
     519              :         {
     520            0 :             Util::ParmParseException(INFO,full(name));
     521            0 :         }
     522            0 :         return -1;
     523              :     }
     524              :     int query_file( std::string name, std::string & value, bool copyfile)
     525              :     {
     526              :         return query_file(name,value,copyfile,true);
     527              :     }
     528            2 :     int query_file( std::string name, std::string & value)
     529              :     {
     530            2 :         return query_file(name,value,true,true);
     531              :     }
     532              : 
     533              : 
     534              :     template<typename T>
     535          167 :     int queryarr(   std::string name, std::vector<T> & value)
     536              :     {
     537              :         try
     538              :         {
     539          167 :             return amrex::ParmParse::queryarr(name.c_str(),value);
     540              :         }
     541            0 :         catch (...)
     542              :         {
     543            0 :             Util::ParmParseException(INFO,full(name));
     544              :         }
     545            0 :         return -1;
     546              :     }
     547          258 :     int queryarr(   std::string name, std::vector<Set::Scalar> & value, Unit unit = Unit::Less())
     548              :     {
     549              :         try
     550              :         {
     551          258 :             if (unit.isType(Unit::Less()))
     552              :             {
     553           80 :                 return amrex::ParmParse::queryarr(name.c_str(),value);
     554              :             }
     555              :             else
     556              :             {
     557          178 :                 value.clear();
     558          178 :                 std::vector<std::string> valstrings;
     559          178 :                 int retval = amrex::ParmParse::queryarr(name.c_str(), valstrings);
     560          584 :                 for (unsigned int i = 0; i < valstrings.size(); i++)
     561              :                 {
     562          406 :                     Unit unitvalue = Unit::Parse(valstrings[i]);
     563         2030 :                     Util::DebugMessage(INFO,full(name),": ",valstrings[i]," ==> ",unitvalue);
     564              : 
     565          406 :                     if (!unitvalue.isType(unit) && !unitvalue.isType(Unit::Less()))
     566              :                     {
     567            0 :                         Util::Exception(INFO,"value specified had wrong units:", valstrings[i]);
     568              :                     }
     569          406 :                     value.push_back(unitvalue.normalized_value());
     570              :                 }
     571          178 :                 return retval;
     572          178 :             }
     573              :         }
     574            0 :         catch (std::runtime_error &e)
     575              :         {
     576            0 :             Util::ParmParseException(INFO,full(name), e.what());
     577            0 :         }
     578            0 :         catch (...)
     579              :         {
     580            0 :             Util::ParmParseException(INFO,full(name));
     581            0 :         }
     582            0 :         return -1;
     583              :     }
     584           12 :     int queryarr(   std::string name, Set::Vector & value, Unit unit = Unit::Less())
     585              :     {
     586              :         try
     587              :         {
     588           12 :             std::vector<Set::Scalar> vals;
     589           12 :             queryarr(name.c_str(), vals, unit);
     590           12 :             if (vals.size() < AMREX_SPACEDIM) 
     591              :             {
     592            0 :                 Util::ParmParseException(   INFO,full(name),full(name),
     593            0 :                                             " requires at least ", AMREX_SPACEDIM, 
     594            0 :                                             " arguments, got ",vals.size());
     595              :             }
     596           36 :             for (int i = 0; i < AMREX_SPACEDIM; i++) value(i) = vals[i];
     597           12 :             return 0;
     598           12 :         }
     599            0 :         catch(...)
     600              :         {
     601            0 :             Util::ParmParseException(INFO,full(name));
     602            0 :         }
     603            0 :         return -1;
     604              :     }
     605            7 :     int queryarr(   std::string name, Set::Matrix & value, Unit unit = Unit::Less())
     606              :     {
     607            7 :         std::vector<Set::Scalar> vals;
     608            7 :         queryarr(name.c_str(), vals,unit);
     609            7 :         if (vals.size() == 9)
     610              :         {
     611              : #if AMREX_SPACEDIM==2
     612           20 :             Util::Warning(INFO, "Reading a 3D matrix (",full(name),")into a 2D code - some values will be ignored.");
     613            4 :             value(0,0) = vals[0];  value(0,1)= vals[1];
     614            4 :             value(1,0) = vals[3];  value(1,1)= vals[4];
     615              : #endif
     616              : #if AMREX_SPACEDIM==3
     617            3 :             value(0,0) = vals[0];  value(0,1)= vals[1];  value(0,2)= vals[2];
     618            3 :             value(1,0) = vals[3];  value(1,1)= vals[4];  value(1,2)= vals[5];
     619            3 :             value(2,0) = vals[6];  value(2,1)= vals[7];  value(2,2)= vals[8];
     620              : #endif
     621              :         }
     622            0 :         else if (vals.size() == 4)
     623              :         {
     624              : #if AMREX_SPACEDIM==2
     625            0 :             value(0,0) = vals[0];  value(0,1)= vals[1];
     626            0 :             value(1,0) = vals[2];  value(1,1)= vals[3];
     627              : #endif
     628              : #if AMREX_SPACEDIM==3
     629            0 :             Util::Warning(INFO,"Reading a 2D matrix (",full(name),")into a 3D code - remaining values will be set to zero.");
     630            0 :             value(0,0) = vals[0];  value(0,1)= vals[1];  value(0,2)= 0.0;
     631            0 :             value(1,0) = vals[2];  value(1,1)= vals[3];  value(1,2)= 0.0;
     632            0 :             value(2,0) = 0.0;      value(2,1)= 0.0;      value(2,2)= 0.0;
     633              : #endif
     634              :         }
     635              :         else
     636              :         {
     637            0 :             Util::ParmParseException(INFO,full(name),full(name)," needs either 4 or 9 components, but got ",vals.size());
     638              :         }    
     639            7 :         return 0;
     640            7 :     }
     641              : 
     642              :     template<typename T>
     643              :     int queryarr_required(  std::string name, std::vector<T> & value)
     644              :     {
     645              :         if (!contains(name.c_str()))
     646              :         {
     647              :             Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
     648              :         }        
     649              :         return queryarr<T>(name,value);
     650              :     }
     651              : 
     652          117 :     int queryarr_required(  std::string name, std::vector<Set::Scalar> & value, Unit unit = Unit::Less())
     653              :     {
     654          234 :         if (!contains(name.c_str()))
     655              :         {
     656            0 :             Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
     657              :         }        
     658          117 :         return queryarr(name,value,unit);
     659              :     }
     660          620 :     int queryarr_default(   std::string name, std::vector<std::string> & value, std::vector<std::string> defaultvalue)
     661              :     {
     662         1240 :         if (!contains(name.c_str()))
     663              :         {
     664          317 :             addarr(name.c_str(),defaultvalue);
     665              :         }
     666          620 :         return amrex::ParmParse::queryarr(name.c_str(),value);
     667              :     }
     668              : 
     669            2 :     int queryarr_default(   std::string name, Set::Vector & value, std::string defaultvalue, Unit unit)
     670              :     {
     671              :         try
     672              :         {
     673            4 :             if (!contains(name.c_str()))
     674              :             {
     675            0 :                 this->addarr(name.c_str(),Util::String::Split(defaultvalue));
     676              :             }
     677            4 :             return queryarr(name.c_str(),value,unit);
     678              :         }
     679            0 :         catch (std::runtime_error &e)
     680              :         {
     681            0 :             Util::ParmParseException(INFO,full(name), e.what());
     682            0 :         }
     683            0 :         catch (...)
     684              :         {
     685            0 :             Util::ParmParseException(INFO,full(name));
     686            0 :         }
     687            0 :         return -1;
     688              :     }
     689            8 :     int queryarr_default(   std::string name, Set::Vector & value, Set::Vector defaultvalue)
     690              :     {
     691              :         try
     692              :         {
     693           16 :             if (!contains(name.c_str()))
     694              :             {
     695            8 :                 std::vector<Set::Scalar> def_data(AMREX_SPACEDIM);
     696           24 :                 for (unsigned int i = 0; i < def_data.size(); i++)
     697           16 :                     def_data[i] = defaultvalue[i];
     698              :                 
     699           24 :                 add(name.c_str(),Util::String::Join(def_data));
     700            8 :                 value = defaultvalue;
     701            8 :                 return 0;
     702            8 :             }
     703            0 :             return queryarr(name.c_str(),value);
     704              :         }
     705            0 :         catch (...)
     706              :         {
     707            0 :             Util::ParmParseException(INFO,full(name));
     708            0 :         }
     709            0 :         return -1;
     710              :     }
     711              :     
     712            0 :     int queryarr_default(   std::string name, Set::Matrix & value, Set::Matrix def)
     713              :     {
     714              :         try
     715              :         {
     716            0 :             if (!contains(name.c_str()))
     717              :             {
     718            0 :                 std::vector<Set::Scalar> def_data(AMREX_SPACEDIM*AMREX_SPACEDIM);
     719            0 :                 for (unsigned int i = 0; i < def_data.size(); i++)
     720            0 :                     def_data[i] = def.data()[i];
     721              : 
     722            0 :                 add(name.c_str(),Util::String::Join(def_data));
     723            0 :                 value = def;
     724            0 :                 return 0;
     725            0 :             }
     726            0 :             return queryarr(name.c_str(),value);
     727              :         }
     728            0 :         catch (...)
     729              :         {
     730            0 :             Util::ParmParseException(INFO,full(name));
     731            0 :         }
     732            0 :         return -1;
     733              :     }
     734              : 
     735              :     int queryarr_default(   std::string name, std::vector<double> & value, std::vector<double> defaultvalue)
     736              :     {
     737              :         try
     738              :         {
     739              :             if (!contains(name.c_str()))
     740              :             {
     741              :                 addarr(name.c_str(),defaultvalue);
     742              :             }
     743              :             return queryarr(name.c_str(),value);
     744              :         }
     745              :         catch (...)
     746              :         {
     747              :             Util::ParmParseException(INFO,full(name));
     748              :         }
     749              :         return -1;
     750              :     }
     751              : 
     752              :     int queryarr_default(   std::string name, std::vector<double> & value, std::vector<std::string> defaultvalue, Unit unit)
     753              :     {
     754              :         try
     755              :         {
     756              :             if (!contains(name.c_str()))
     757              :             {
     758              :                 addarr(name.c_str(),defaultvalue);
     759              :             }
     760              :             return queryarr(name,value, unit);
     761              :         }
     762              :         catch (...)
     763              :         {
     764              :             Util::ParmParseException(INFO,full(name));
     765              :         }
     766              :         return -1;
     767              :     }
     768              : 
     769              : 
     770              :     template <typename T>
     771              :     int
     772           29 :     queryclass_enumerate(std::string a_name, std::vector<T> &value, int number = 1)
     773              :     {
     774           29 :         value.clear();
     775              : 
     776              :         //
     777              :         // If only one is present with no subscript, then read
     778              :         // it only and return.
     779              :         //
     780           29 :         std::string name = a_name;
     781           29 :         if (this->contains(name))
     782              :         {
     783           18 :             for (int n = 0; n < number; n++)
     784              :             {
     785            9 :                 T tmp;
     786            9 :                 this->queryclass<T>(name, tmp);
     787            9 :                 value.push_back(tmp);
     788              :             }
     789            9 :             return 0;
     790              :         }
     791              : 
     792              :         //
     793              :         // Some logic to determine whether we are starting with zero
     794              :         // (model0, model1, model2, ...)
     795              :         // or one
     796              :         // (model1, model2, model3, ...)
     797              :         // since both are supported
     798              :         //
     799           20 :         int start = -1;
     800           20 :         std::string name0 = a_name + std::to_string(0);
     801           20 :         std::string name1 = a_name + std::to_string(1);
     802           40 :         if (this->contains(name0.c_str()))
     803              :         {
     804            0 :             start = 0;
     805            0 :             name = name0;
     806              :         }
     807           40 :         else if (this->contains(name1.c_str()))
     808              :         {
     809           20 :             start = 1;
     810           20 :             name = name1;
     811              :         }
     812              :         else
     813              :         {
     814            0 :             Util::ParmParseException(INFO,full(name), "Enumerations must begin with 0 or 1");
     815              :         }
     816              : 
     817              :         //
     818              :         // Iterate over items called (model0), model1, model2, etc
     819              :         // until no more are found then exit. 
     820              :         //
     821          106 :         for (int cntr = start; this->contains(name.c_str()); cntr++)
     822              :         {
     823           46 :             if (this->contains(name.c_str()))
     824              :             {
     825           23 :                 T tmp;
     826           23 :                 this->queryclass<T>(name, tmp);
     827           23 :                 value.push_back(tmp);
     828            0 :             }
     829           23 :             name = a_name + std::to_string(cntr+1);
     830              :         }
     831              : 
     832           20 :         return 0;
     833           29 :     }
     834              : 
     835              : 
     836              :     template <typename T>
     837              :     int
     838           34 :     query_enumerate(std::string a_name, std::vector<T> &value, int number = 1)
     839              :     {
     840           34 :         value.clear();
     841              : 
     842              :         //
     843              :         // If only one is present with no subscript, then read
     844              :         // it only and return.
     845              :         //
     846           34 :         std::string name = a_name;
     847           34 :         if (this->contains(name))
     848              :         {
     849            0 :             for (int n = 0; n < number; n++)
     850              :             {
     851            0 :                 T tmp;
     852            0 :                 this->query_required(name, tmp);
     853            0 :                 value.push_back(tmp);
     854              :             }
     855            0 :             return 0;
     856              :         }
     857              : 
     858              :         //
     859              :         // Some logic to determine whether we are starting with zero
     860              :         // (model0, model1, model2, ...)
     861              :         // or one
     862              :         // (model1, model2, model3, ...)
     863              :         // since both are supported
     864              :         //
     865           34 :         int start = -1;
     866           34 :         std::string name0 = a_name + std::to_string(0);
     867           34 :         std::string name1 = a_name + std::to_string(1);
     868           68 :         if (this->contains(name0.c_str()))
     869              :         {
     870           34 :             start = 0;
     871           34 :             name = name0;
     872              :         }
     873            0 :         else if (this->contains(name1.c_str()))
     874              :         {
     875            0 :             start = 1;
     876            0 :             name = name1;
     877              :         }
     878              :         else
     879              :         {
     880            0 :             Util::ParmParseException(INFO,full(name), "Enumerations must begin with 0 or 1");
     881              :         }
     882              : 
     883              :         //
     884              :         // Iterate over items called (model0), model1, model2, etc
     885              :         // until no more are found then exit. 
     886              :         //
     887          198 :         for (int cntr = start; this->contains(name.c_str()); cntr++)
     888              :         {
     889           96 :             if (this->contains(name.c_str()))
     890              :             {
     891           48 :                 T tmp;
     892           48 :                 this->query_required(name, tmp);
     893           48 :                 value.push_back(tmp);
     894           48 :             }
     895           48 :             name = a_name + std::to_string(cntr+1);
     896              :         }
     897              : 
     898           34 :         return 0;
     899           34 :     }
     900              : 
     901              : 
     902              : 
     903           11 :     int AnyUnusedInputs(bool inscopeonly = true, bool verbose = false)
     904              :     {
     905           11 :         int cnt = 0;
     906         2064 :         for (auto li = m_table->begin(), End = m_table->end(); li != End; ++li)
     907              :         {
     908         2053 :                 if (!li->second.m_count)
     909              :                 {
     910            0 :                     if (inscopeonly && getPrefix() != "")
     911              :                     {
     912            0 :                         if (li->first.rfind(getPrefix()+".",0) != std::string::npos)
     913              :                         {
     914            0 :                             if (verbose) Util::Warning(INFO,li->first);
     915            0 :                             cnt++;
     916              :                         }
     917              :                     }
     918              :                     else
     919              :                     {
     920            0 :                         if (verbose) Util::Warning(INFO,li->first);
     921            0 :                         cnt++;
     922              :                     }
     923              :                 }
     924              :         }
     925           11 :         return cnt;
     926              :     }
     927              : 
     928          281 :     std::vector<std::string> GetUnusedInputs()
     929              :     {
     930          281 :         std::vector<std::string> ret;
     931        42690 :         for (auto li = m_table->begin(), End = m_table->end(); li != End; ++li)
     932              :         {
     933        42409 :             if (!li->second.m_count && li->first.rfind(getPrefix()+".",0) != std::string::npos)
     934              :             {
     935            0 :                 ret.push_back(li->first);
     936              :             }
     937              :         }
     938          281 :         return ret;
     939            0 :     }
     940              : 
     941            0 :     static int AllUnusedInputs()
     942              :     {
     943            0 :         ParmParse pp;
     944            0 :         int cnt = 0;
     945            0 :         for (auto li = pp.m_table->begin(), End = pp.m_table->end(); li != End; ++li)
     946              :         {
     947            0 :             if (!li->second.m_count)
     948              :             {
     949            0 :                 Util::Warning(INFO,li->first);
     950            0 :                 cnt++;
     951              :             }
     952              :         }
     953            0 :         return cnt;
     954            0 :     }
     955            0 :     std::string prefix ()
     956              :     {
     957            0 :         return getPrefix();
     958              :     }
     959         7864 :     std::string full (std::string name)
     960              :     {
     961         7864 :         std::string prefix = getPrefix();
     962         7864 :         if (prefix != "") return getPrefix() + "." + name;
     963         5653 :         else return name;
     964         7864 :     }
     965              : 
     966              : 
     967              :     template<class T>
     968              :     void queryclass(std::string name, T * value)
     969              :     {
     970              :         auto old_prefix = m_prefix;
     971              :         try
     972              :         {
     973              :             if (old_prefix.empty()) m_prefix = name;
     974              :             else m_prefix.append(".").append(name);
     975              :             T::Parse(*value, *this);
     976              :             std::vector<std::string> unused_inputs = GetUnusedInputs();
     977              :             if (unused_inputs.size())
     978              :             {
     979              :                 std::stringstream ss;
     980              :                 for (unsigned int i=0; i < unused_inputs.size(); i++)
     981              :                     ss << "\n\t" << unused_inputs[i];
     982              :                 Util::ParmParseException(INFO,name,"The following inputs were specified but not used",ss.str());
     983              :             }
     984              :         }
     985              :         catch (...)
     986              :         {
     987              :             m_prefix = old_prefix;
     988              :             Util::ParmParseException(INFO,full(name));
     989              :         }
     990              :         m_prefix = old_prefix;
     991              :     }
     992              :     template<class T>
     993          281 :     void queryclass(std::string name, T & value)
     994              :     {
     995          281 :         auto old_prefix = m_prefix;
     996              :         try
     997              :         {
     998          281 :             if (old_prefix.empty()) m_prefix = name;
     999            0 :             else m_prefix.append(".").append(name);
    1000          281 :             T::Parse(value, *this);
    1001          281 :             std::vector<std::string> unused_inputs = GetUnusedInputs();
    1002          281 :             if (unused_inputs.size())
    1003              :             {
    1004            0 :                 std::stringstream ss;
    1005            0 :                 for (unsigned int i=0; i < unused_inputs.size(); i++)
    1006            0 :                     ss << "\n\t" << unused_inputs[i];
    1007            0 :                 Util::ParmParseException(INFO,name,"The following inputs were specified but not used",ss.str());
    1008            0 :             }
    1009          281 :         }
    1010            0 :         catch (std::runtime_error &e)
    1011              :         {
    1012            0 :             Util::ParmParseException(INFO,full(name),e.what());
    1013              :         }
    1014            0 :         catch (...)
    1015              :         {
    1016            0 :             m_prefix = old_prefix;
    1017            0 :             Util::ParmParseException(INFO,full(name));
    1018              :         }
    1019          281 :         m_prefix = old_prefix;
    1020          281 :     }
    1021              : 
    1022              :     template<class T>
    1023              :     void queryclass(T * value)
    1024              :     {
    1025              :         try
    1026              :         {
    1027              :             T::Parse(*value, *this);
    1028              :         }
    1029              :         catch (std::runtime_error &e)
    1030              :         {
    1031              :             Util::ParmParseException(INFO,getPrefix(), e.what());
    1032              :         }
    1033              :         catch (...)
    1034              :         {
    1035              :             Util::ParmParseException(INFO,getPrefix());
    1036              :         }
    1037              :     }
    1038              :     template<class T>
    1039          779 :     void queryclass(T & value)
    1040              :     {
    1041              :         try
    1042              :         {
    1043          779 :             T::Parse(value, *this);
    1044              :         }
    1045            0 :         catch (std::runtime_error &e)
    1046              :         {
    1047            0 :             Util::ParmParseException(INFO,getPrefix(), e.what());
    1048              :         }
    1049            0 :         catch (...)
    1050              :         {
    1051            0 :             Util::ParmParseException(INFO, getPrefix());
    1052              :         }
    1053          779 :     }
    1054              : 
    1055              :     //
    1056              :     // Variadic template parsing operator to assign a pointer to
    1057              :     // one of a set of possible class objects, then call that method's
    1058              :     // Parse function.
    1059              :     //
    1060              :     // If there is more than one instantiating class, then type must be set.
    1061              :     // Otherwise, no type is necessary.
    1062              :     //
    1063              :     template<typename... IC, typename... Args, typename PTRTYPE>
    1064           60 :     void select (std::string name, PTRTYPE *& ic_eta, Args&&... args)
    1065              :     {
    1066              :         try
    1067              :         {
    1068              :             // if there is only one IC arg provided, we don't need to check the type - assume that
    1069              :             // it is the default.
    1070              :             if constexpr (sizeof...(IC) == 0)
    1071              :             {
    1072              :                 using first_IC = std::tuple_element_t<0, std::tuple<IC...>>;
    1073              :                 ic_eta = new first_IC(std::forward<Args>(args)..., (*this), name + "." + std::string(first_IC::name));
    1074              :             }
    1075              :             // otherwise, check the type.
    1076              :             else
    1077              :             {
    1078           60 :                 std::string type = "";
    1079           60 :                 this->query_required(name + ".type", type);
    1080           61 :                 bool matched = ((   type == IC::name 
    1081          218 :                                     ? (ic_eta = new IC(std::forward<Args>(args)..., (*this), name + "." + std::string(IC::name))),
    1082              :                                     true
    1083          154 :                                     : false) || ...);
    1084           60 :                 if (!matched)
    1085            0 :                     Util::ParmParseException(INFO,full(name), type, " not a valid type for ", name);
    1086           60 :             }
    1087              :         }
    1088            0 :         catch (std::runtime_error &e)
    1089              :         {
    1090            0 :             Util::ParmParseException(INFO,getPrefix(),e.what());
    1091              :         }
    1092            0 :         catch (...)
    1093              :         {
    1094            0 :             Util::ParmParseException(INFO,getPrefix());
    1095              :         }
    1096           60 :     }
    1097              : 
    1098              :     //
    1099              :     // Identical to the above, except sets the type automatically to the
    1100              :     // firs specified 
    1101              :     //
    1102              :     template<typename FirstIC, typename... IC, typename... Args, typename PTRTYPE>
    1103          142 :     void select_default (std::string name, PTRTYPE *& ic_eta, Args&&... args)
    1104              :     {
    1105          142 :         std::string type = "";
    1106              : 
    1107          142 :         this->query_default(name + ".type", type, FirstIC::name);
    1108              : 
    1109            0 :         bool matched =
    1110          284 :             ((  type == FirstIC::name 
    1111          356 :                 ? (ic_eta = new FirstIC(std::forward<Args>(args)..., (*this), name + "." + std::string(FirstIC::name))),
    1112              :                 true : false))
    1113          284 :             || 
    1114           35 :             ((  type == IC::name 
    1115          241 :                 ? (ic_eta = new IC(std::forward<Args>(args)..., (*this), name + "." + std::string(IC::name))),
    1116              :                 true : false) || ...);
    1117              : 
    1118              : 
    1119          142 :         if (!matched)
    1120            0 :             Util::ParmParseException(INFO,full(name), type," not a valid type for ",name);
    1121          142 :     }
    1122              : 
    1123              : 
    1124              :     //
    1125              :     //
    1126              :     template<typename... IC, typename... Args, typename PTRTYPE>
    1127            0 :     void select_enumerate (std::string a_name, std::vector<PTRTYPE*> & value, Args&&... args)
    1128              :     {
    1129              : 
    1130            0 :         value.clear();
    1131              : 
    1132              :         //
    1133              :         // If only one is present with no subscript, then read
    1134              :         // it only and return.
    1135              :         //
    1136            0 :         std::string name = a_name;
    1137            0 :         if (this->contains(name))
    1138              :         {
    1139              :             PTRTYPE *tmp;
    1140            0 :             this->select<IC...>(a_name, tmp, args...);
    1141            0 :             value.push_back(tmp);
    1142            0 :             return;
    1143              :         }
    1144              : 
    1145              :         //
    1146              :         // Some logic to determine whether we are starting with zero
    1147              :         // (model0, model1, model2, ...)
    1148              :         // or one
    1149              :         // (model1, model2, model3, ...)
    1150              :         // since both are supported
    1151              :         //
    1152            0 :         int start = -1;
    1153            0 :         std::string name0 = a_name + std::to_string(0);
    1154            0 :         std::string name1 = a_name + std::to_string(1);
    1155            0 :         if (this->contains(name0.c_str()))
    1156              :         {
    1157            0 :             start = 0;
    1158            0 :             name = name0;
    1159              :         }
    1160            0 :         else if (this->contains(name1.c_str()))
    1161              :         {
    1162            0 :             start = 1;
    1163            0 :             name = name1;
    1164              :         }
    1165              :         else
    1166              :         {
    1167            0 :             Util::ParmParseException(INFO,full(name), "Enumerations must begin with 0 or 1");
    1168              :         }
    1169              : 
    1170              :         //
    1171              :         // Iterate over items called (model0), model1, model2, etc
    1172              :         // until no more are found then exit. 
    1173              :         //
    1174            0 :         for (int cntr = start; this->contains(name.c_str()); cntr++)
    1175              :         {
    1176            0 :             if (this->contains(name.c_str()))
    1177              :             {
    1178              :                 PTRTYPE *tmp;
    1179            0 :                 this->select<IC...>(name, tmp, args...);
    1180            0 :                 value.push_back(tmp);
    1181              :             }
    1182            0 :             name = a_name + std::to_string(cntr+1);
    1183              :         }
    1184            0 :     }
    1185              : 
    1186              : 
    1187              : 
    1188              :     //
    1189              :     // Similar to select but specialized for main functions
    1190              :     //
    1191              :     template<typename... INTEGRATOR, typename... Args, typename PTRTYPE>
    1192              :     void select_main (PTRTYPE *& ic_eta, Args&&... args)
    1193              :     {
    1194              :         std::string type = "";
    1195              : 
    1196              :         this->query_required("alamo.program", type);
    1197              :         
    1198              :         bool matched = ((type == INTEGRATOR::name 
    1199              :                         ? (ic_eta = new INTEGRATOR(std::forward<Args>(args)..., (*this))),
    1200              :                         true
    1201              :                         : false) || ...);
    1202              :         if (!matched)
    1203              :             Util::ParmParseException(INFO,getPrefix(),type," not a valid type for ",type);
    1204              :     }
    1205              : 
    1206              :     //
    1207              :     // Similar to select_main but works for one function only
    1208              :     // and doesn't require a type specifier.
    1209              :     //
    1210              : 
    1211              :     // with variadic arguments
    1212              :     template<typename INTEGRATOR, typename Args, typename PTRTYPE>
    1213              :     void select_only (PTRTYPE *& ic_eta, Args&& args)
    1214              :     {
    1215              :         ic_eta = new INTEGRATOR(std::forward<Args>(args), (*this));
    1216              :     }
    1217              :     // without variadic arguments
    1218              :     template<typename INTEGRATOR, typename PTRTYPE>
    1219           52 :     void select_only (PTRTYPE *& ic_eta)
    1220              :     {
    1221           52 :         ic_eta = new INTEGRATOR((*this));
    1222           52 :     }
    1223              : 
    1224              :     
    1225              :     //
    1226              :     // functionally simlar to other kinds of select, execpt works on
    1227              :     // template-based static dispatch.
    1228              :     //
    1229              : 
    1230              :     template <typename... OBJ, typename CLASS, typename... Args>
    1231           27 :     void select(std::string name, CLASS& value, Args&&... args)
    1232              :     {
    1233           27 :         pushPrefix(name);
    1234           27 :         static_polymorphism_parser<CLASS, 0, OBJ...>(value, std::forward<Args>(args)...);
    1235           27 :         popPrefix();
    1236           27 :     }
    1237              : 
    1238              : private:
    1239              :     //
    1240              :     // This function is a virtual "swtich / case" block for static
    1241              :     // dispatch. It works on a faux-virtual class "CLASS" that must 
    1242              :     // contain a tuple of "obj" with each "obj" being a derived type.
    1243              :     // Recursion is used to unroll the list, identify the correct class
    1244              :     // based on "name/type", set the "selected" index, then call the
    1245              :     // appropriate class' Parse function.
    1246              :     // 
    1247              :     // This is only for use by the "select" functions.
    1248              :     // 
    1249              :     template <typename CLASS, int N, typename... OBJ, typename... Args>
    1250           28 :     void static_polymorphism_parser(CLASS& value, Args&&... args)
    1251              :     {
    1252              :         if constexpr (N == 0)
    1253              :         {
    1254           27 :             std::string type;
    1255           54 :             query_default("type",type,value.names[0]);
    1256              : 
    1257           60 :             for (unsigned int i = 0; i < sizeof...(OBJ); i++)
    1258           33 :                 if (type == value.names[i])
    1259           27 :                     value.selected = i;
    1260              : 
    1261           27 :             if (value.selected < 0)
    1262            0 :                 Util::ParmParseException(INFO,getPrefix(),
    1263              :                                 "Error reading " + getPrefix() + 
    1264              :                                 ", invalid type " + type);
    1265              : 
    1266              :             
    1267           27 :             pushPrefix(type);
    1268           27 :         }
    1269              : 
    1270              :         if constexpr (N < sizeof...(OBJ))
    1271              :         {
    1272           28 :             if (value.selected == N)
    1273              :             {
    1274           62 :                 std::get<N>(value.obj).Parse(
    1275           35 :                     std::get<N>(value.obj), *this, std::forward<Args>(args)...);
    1276           27 :                 popPrefix();
    1277           27 :                 return;
    1278              :             }
    1279              :             else 
    1280            1 :                 return static_polymorphism_parser<CLASS, N+1, OBJ...>(
    1281            1 :                     value, std::forward<Args>(args)...);
    1282              :         }
    1283            0 :         else Util::Abort(INFO);
    1284            0 :     }
    1285              : 
    1286              : public:
    1287              : 
    1288              :     template <int N>
    1289           23 :     void query_exactly( std::vector<std::string> names, std::pair<std::string, Set::Scalar> values[N],
    1290              :                         std::vector<Unit> units = std::vector<Unit>())
    1291              :     {
    1292              :         try
    1293              :         {
    1294          161 :             Util::AssertException(  INFO,TEST(units.size() == 0 || units.size() == names.size()),
    1295           23 :                                     "# of units must be 0, 1, or ", names.size(), " but got ", units.size());
    1296              : 
    1297           23 :             int cnt = 0;
    1298           23 :             std::vector<std::string> read;
    1299          135 :             for (unsigned int n = 0; n < names.size(); n++)
    1300              :             {
    1301          112 :                 if (amrex::ParmParse::contains(names[n].c_str()))
    1302              :                 {
    1303           46 :                     read.push_back(names[n]);
    1304           46 :                     cnt++;
    1305              :                 }
    1306              :             }
    1307          184 :             Util::AssertException(  INFO, TEST(cnt == N),
    1308              :                                     " Incorrect number of values specified: only ", N,
    1309              :                                     " values are allowed, but received ",
    1310           23 :                                     Util::String::Join(read,", "));
    1311              : 
    1312              : 
    1313           23 :             cnt = 0;
    1314          135 :             for (unsigned int n = 0; n < names.size(); n++)
    1315              :             {
    1316          112 :                 if (amrex::ParmParse::contains(names[n].c_str()))
    1317              :                 {
    1318           46 :                     values[cnt].first = names[n];
    1319              : 
    1320           46 :                     if (units.size() == 0)
    1321           32 :                         query_required(names[n],values[cnt].second);
    1322           14 :                     else if (units.size() == 1)
    1323            0 :                         query_required(names[n],values[cnt].second,units[0]);
    1324              :                     else
    1325           14 :                         query_required(names[n],values[cnt].second,units[n]);
    1326           46 :                     cnt++;
    1327              :                 }
    1328              :             }
    1329           23 :         }
    1330            0 :         catch(...)
    1331              :         {
    1332            0 :             std::string names_str = "[";
    1333            0 :             for (unsigned int i = 0; i < names.size(); i++)
    1334              :             {
    1335            0 :                 names_str += full(names[i]);
    1336            0 :                 if (i < names.size()-1) names_str += ", ";
    1337              :             }
    1338            0 :             names_str += "]";
    1339            0 :             Util::ParmParseException(INFO,names_str);
    1340            0 :         }
    1341           23 :     }
    1342              : };
    1343              : }
    1344              : #endif
        

Generated by: LCOV version 2.0-1