LCOV - code coverage report
Current view: top level - src/IO - ParmParse.H (source / functions) Coverage Total Hit
Test: coverage_merged.info Lines: 53.7 % 523 281
Test Date: 2025-12-10 23:45:13 Functions: 63.4 % 205 130

            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         1097 :     void Define() 
     119              :     {
     120         1097 :         if (checked_for_input_files) return;
     121           42 :         int k = 0;
     122           42 :         std::string inputfile = "";
     123           42 :         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           42 :         checked_for_input_files = true;
     130           42 :     }
     131              :     static bool checked_for_input_files;
     132              :     
     133              : public:
     134          754 :     ParmParse(std::string arg) : amrex::ParmParse::ParmParse(arg) {Define();} ;
     135          343 :     ParmParse() : amrex::ParmParse::ParmParse() {Define();} ;
     136        10813 :     std::string getPrefix() const {return m_prefix;};
     137          396 :     void ignore(std::string name)
     138              :     {
     139          396 :         (void)amrex::ParmParse::contains(name.c_str());
     140          396 :     }
     141              :     
     142            6 :     void pushPrefix(const std::string prefix)
     143              :     {
     144            6 :         if (m_prefix.length())
     145            3 :             m_prefix = m_prefix + "." + prefix;
     146              :         else
     147            3 :             m_prefix = prefix;
     148            6 :     }
     149              : 
     150            6 :     void popPrefix()
     151              :     {
     152            6 :         size_t pos = m_prefix.rfind('.');
     153            6 :         if (pos == std::string::npos)
     154            3 :             m_prefix = "";
     155              :         else
     156            3 :             m_prefix = m_prefix.substr(0, pos);
     157            6 :     }
     158              : 
     159              : 
     160          298 :     void forbid(std::string name, std::string explanation)
     161              :     {
     162          298 :         if (amrex::ParmParse::contains(full(name).c_str()))
     163              :         {
     164            0 :             Util::ParmParseException(INFO,full(name),full(name)," forbidden: ", explanation);
     165              :         }
     166          298 :         std::set<std::string> subs = amrex::ParmParse::getEntries(full(name));
     167          298 :         if (subs.size())
     168              :         {
     169            0 :             Util::ParmParseException(INFO,full(name),full(name)," forbidden: ", explanation);
     170              :         }
     171          298 :     }
     172              : 
     173         3393 :     bool contains(std::string name)
     174              :     {
     175         3393 :         if (amrex::ParmParse::contains(name.c_str()))
     176         1223 :             return true;
     177         2170 :         if (amrex::ParmParse::contains(full(name).c_str()))
     178            0 :             return true;
     179              :         {
     180         2170 :             std::set<std::string> subs = amrex::ParmParse::getEntries(name.c_str());
     181         2170 :             if (subs.size())
     182           52 :                 return true;
     183         2170 :         }
     184              :         {
     185         2118 :             std::set<std::string> subs = amrex::ParmParse::getEntries(full(name).c_str());
     186         2118 :             if (subs.size())
     187            0 :                 return true;
     188         2118 :         }
     189         2118 :         return false;
     190              :     }
     191              : 
     192          329 :     int queryunit (std::string name, Unit &value)
     193              :     {
     194              :         try
     195              :         {
     196          329 :             std::string strvalue;
     197          329 :             int retval = amrex::ParmParse::query(name.c_str(),strvalue);
     198          329 :             value = Unit::Parse(strvalue);
     199         1645 :             Util::DebugMessage(INFO,full(name),": ",strvalue," ==> ",value);
     200          329 :             return retval;
     201          329 :         }
     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          274 :     int queryunit (std::string name, Unit &value, const Unit type)
     214              :     {
     215              :         try
     216              :         {
     217          274 :             int retval = queryunit(name,value);
     218          274 :             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          274 :             return retval;
     225              :         }
     226            0 :         catch (...)
     227              :         {
     228            0 :             Util::ParmParseException(INFO,full(name));
     229            0 :         }
     230            0 :         return -1;
     231              :     }
     232          274 :     int queryunit (std::string name, Set::Scalar &value, const Unit type)
     233              :     {
     234              :         try
     235              :         {
     236          274 :             Unit read;
     237          274 :             int retval = queryunit(name,read,type);
     238          274 :             value = read.normalized_value();
     239          274 :             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          166 :     int query_required( std::string name, T & value)
     250              :     {
     251              :         try
     252              :         {
     253          332 :             if (!contains(name.c_str()))
     254              :             {
     255            0 :                 Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
     256              :             }
     257          166 :             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          121 :     int query_required( std::string name, T & value, const Unit type)
     272              :     {
     273              :         try
     274              :         {
     275          242 :             if (!contains(name.c_str()))
     276              :             {
     277            0 :                 Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
     278              :             }
     279          242 :             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         1586 :     int query_default(  std::string name, T & value, T defaultvalue)
     294              :     {
     295              :         try
     296              :         {
     297         3172 :             if (!contains(name.c_str()))
     298              :             {
     299         1322 :                 add(name.c_str(),defaultvalue);
     300              :             }
     301         1586 :             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          153 :     int query_default(  std::string name, T & value, std::string defaultvalue, const Unit type)
     316              :     {
     317              :         try
     318              :         {
     319          306 :             if (!contains(name.c_str()))
     320              :             {
     321           95 :                 add(name.c_str(),defaultvalue);
     322              :             }
     323          306 :             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            3 :                 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          142 :     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          142 :             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          142 :             if (!amrex::ParmParse::contains(name.c_str()))
     394              :             {
     395          255 :                 add(name.c_str(), std::string(possiblecharvals[0]));
     396              :             }
     397              : 
     398              :             // get the read value (if it exists)
     399          142 :             int retval = amrex::ParmParse::query(name.c_str(),value);
     400              : 
     401              :             // check to make sure the read value matches one of the inpus
     402          142 :             bool ok = false;
     403          531 :             for (unsigned int i = 0; i < possiblecharvals.size(); i++)
     404              :             {
     405          778 :                 if (value == std::string(possiblecharvals[i])) ok = true;
     406              :             }
     407              :         
     408          142 :             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          142 :     int query_validate( std::string name, std::string & value, std::vector<const char *> possiblecharvals)
     430              :     {
     431              :         try
     432              :         {
     433          142 :             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          508 :     int query_default(  std::string name, std::string & value, const char *defaultvalue)
     449              :     {
     450              :         try
     451              :         {
     452         1016 :             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           68 :     int query_default(  std::string name, int & value, bool defaultvalue)
     466              :     {
     467              :         try
     468              :         {
     469           68 :             int defaultint = 0;
     470           68 :             if (defaultvalue) defaultint = 1;
     471           68 :             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           94 :     int queryarr(   std::string name, std::vector<T> & value)
     536              :     {
     537              :         try
     538              :         {
     539           94 :             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          168 :     int queryarr(   std::string name, std::vector<Set::Scalar> & value, Unit unit = Unit::Less())
     548              :     {
     549              :         try
     550              :         {
     551          168 :             if (unit.isType(Unit::Less()))
     552              :             {
     553           72 :                 return amrex::ParmParse::queryarr(name.c_str(),value);
     554              :             }
     555              :             else
     556              :             {
     557           96 :                 value.clear();
     558           96 :                 std::vector<std::string> valstrings;
     559           96 :                 int retval = amrex::ParmParse::queryarr(name.c_str(), valstrings);
     560          368 :                 for (unsigned int i = 0; i < valstrings.size(); i++)
     561              :                 {
     562          272 :                     Unit unitvalue = Unit::Parse(valstrings[i]);
     563         1360 :                     Util::DebugMessage(INFO,full(name),": ",valstrings[i]," ==> ",unitvalue);
     564              : 
     565          272 :                     if (!unitvalue.isType(unit) && !unitvalue.isType(Unit::Less()))
     566              :                     {
     567            0 :                         Util::Exception(INFO,"value specified had wrong units:", valstrings[i]);
     568              :                     }
     569          272 :                     value.push_back(unitvalue.normalized_value());
     570              :                 }
     571           96 :                 return retval;
     572           96 :             }
     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           10 :     int queryarr(   std::string name, Set::Vector & value, Unit unit = Unit::Less())
     585              :     {
     586              :         try
     587              :         {
     588           10 :             std::vector<Set::Scalar> vals;
     589           10 :             queryarr(name.c_str(), vals, unit);
     590           10 :             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           30 :             for (int i = 0; i < AMREX_SPACEDIM; i++) value(i) = vals[i];
     597           10 :             return 0;
     598           10 :         }
     599            0 :         catch(...)
     600              :         {
     601            0 :             Util::ParmParseException(INFO,full(name));
     602            0 :         }
     603            0 :         return -1;
     604              :     }
     605            6 :     int queryarr(   std::string name, Set::Matrix & value, Unit unit = Unit::Less())
     606              :     {
     607            6 :         std::vector<Set::Scalar> vals;
     608            6 :         queryarr(name.c_str(), vals,unit);
     609            6 :         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            2 :             value(0,0) = vals[0];  value(0,1)= vals[1];  value(0,2)= vals[2];
     618            2 :             value(1,0) = vals[3];  value(1,1)= vals[4];  value(1,2)= vals[5];
     619            2 :             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            6 :         return 0;
     640            6 :     }
     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           54 :     int queryarr_required(  std::string name, std::vector<Set::Scalar> & value, Unit unit = Unit::Less())
     653              :     {
     654          108 :         if (!contains(name.c_str()))
     655              :         {
     656            0 :             Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
     657              :         }        
     658           54 :         return queryarr(name,value,unit);
     659              :     }
     660          572 :     int queryarr_default(   std::string name, std::vector<std::string> & value, std::vector<std::string> defaultvalue)
     661              :     {
     662         1144 :         if (!contains(name.c_str()))
     663              :         {
     664          285 :             addarr(name.c_str(),defaultvalue);
     665              :         }
     666          572 :         return amrex::ParmParse::queryarr(name.c_str(),value);
     667              :     }
     668              : 
     669            0 :     int queryarr_default(   std::string name, Set::Vector & value, std::string defaultvalue, Unit unit)
     670              :     {
     671              :         try
     672              :         {
     673            0 :             if (!contains(name.c_str()))
     674              :             {
     675            0 :                 this->addarr(name.c_str(),Util::String::Split(defaultvalue));
     676              :             }
     677            0 :             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              :     int queryarr_default(   std::string name, Set::Vector & value, Set::Vector defaultvalue)
     690              :     {
     691              :         try
     692              :         {
     693              :             if (!contains(name.c_str()))
     694              :             {
     695              :                 add(name.c_str(),Util::String::Join(defaultvalue));
     696              :                 value = defaultvalue;
     697              :                 return 0;
     698              :             }
     699              :             return queryarr(name.c_str(),value);
     700              :         }
     701              :         catch (...)
     702              :         {
     703              :             Util::ParmParseException(INFO,full(name));
     704              :         }
     705              :         return -1;
     706              :     }
     707              :     
     708            0 :     int queryarr_default(   std::string name, Set::Matrix & value, Set::Matrix defaultvalue)
     709              :     {
     710              :         try
     711              :         {
     712            0 :             if (!contains(name.c_str()))
     713              :             {
     714            0 :                 add(name.c_str(),Util::String::Join(defaultvalue));
     715            0 :                 value = defaultvalue;
     716            0 :                 return 0;
     717              :             }
     718            0 :             return queryarr(name.c_str(),value);
     719              :         }
     720            0 :         catch (...)
     721              :         {
     722            0 :             Util::ParmParseException(INFO,full(name));
     723            0 :         }
     724            0 :         return -1;
     725              :     }
     726              : 
     727              :     int queryarr_default(   std::string name, std::vector<double> & value, std::vector<double> defaultvalue)
     728              :     {
     729              :         try
     730              :         {
     731              :             if (!contains(name.c_str()))
     732              :             {
     733              :                 addarr(name.c_str(),defaultvalue);
     734              :             }
     735              :             return queryarr(name.c_str(),value);
     736              :         }
     737              :         catch (...)
     738              :         {
     739              :             Util::ParmParseException(INFO,full(name));
     740              :         }
     741              :         return -1;
     742              :     }
     743              : 
     744              :     int queryarr_default(   std::string name, std::vector<double> & value, std::vector<std::string> defaultvalue, Unit unit)
     745              :     {
     746              :         try
     747              :         {
     748              :             if (!contains(name.c_str()))
     749              :             {
     750              :                 addarr(name.c_str(),defaultvalue);
     751              :             }
     752              :             return queryarr(name,value, unit);
     753              :         }
     754              :         catch (...)
     755              :         {
     756              :             Util::ParmParseException(INFO,full(name));
     757              :         }
     758              :         return -1;
     759              :     }
     760              : 
     761              : 
     762              :     template <typename T>
     763              :     int
     764           18 :     queryclass_enumerate(std::string a_name, std::vector<T> &value, int number = 1)
     765              :     {
     766           18 :         value.clear();
     767              : 
     768              :         //
     769              :         // If only one is present with no subscript, then read
     770              :         // it only and return.
     771              :         //
     772           18 :         std::string name = a_name;
     773           18 :         if (this->contains(name))
     774              :         {
     775            8 :             for (int n = 0; n < number; n++)
     776              :             {
     777            4 :                 T tmp;
     778            4 :                 this->queryclass<T>(name, tmp);
     779            4 :                 value.push_back(tmp);
     780              :             }
     781            4 :             return 0;
     782              :         }
     783              : 
     784              :         //
     785              :         // Some logic to determine whether we are starting with zero
     786              :         // (model0, model1, model2, ...)
     787              :         // or one
     788              :         // (model1, model2, model3, ...)
     789              :         // since both are supported
     790              :         //
     791           14 :         int start = -1;
     792           14 :         std::string name0 = a_name + std::to_string(0);
     793           14 :         std::string name1 = a_name + std::to_string(1);
     794           28 :         if (this->contains(name0.c_str()))
     795              :         {
     796            0 :             start = 0;
     797            0 :             name = name0;
     798              :         }
     799           28 :         else if (this->contains(name1.c_str()))
     800              :         {
     801           14 :             start = 1;
     802           14 :             name = name1;
     803              :         }
     804              :         else
     805              :         {
     806            0 :             Util::ParmParseException(INFO,full(name), "Enumerations must begin with 0 or 1");
     807              :         }
     808              : 
     809              :         //
     810              :         // Iterate over items called (model0), model1, model2, etc
     811              :         // until no more are found then exit. 
     812              :         //
     813           76 :         for (int cntr = start; this->contains(name.c_str()); cntr++)
     814              :         {
     815           34 :             if (this->contains(name.c_str()))
     816              :             {
     817           17 :                 T tmp;
     818           17 :                 this->queryclass<T>(name, tmp);
     819           17 :                 value.push_back(tmp);
     820           17 :             }
     821           17 :             name = a_name + std::to_string(cntr+1);
     822              :         }
     823              : 
     824           14 :         return 0;
     825           18 :     }
     826              : 
     827              : 
     828              :     template <typename T>
     829              :     int
     830           26 :     query_enumerate(std::string a_name, std::vector<T> &value, int number = 1)
     831              :     {
     832           26 :         value.clear();
     833              : 
     834              :         //
     835              :         // If only one is present with no subscript, then read
     836              :         // it only and return.
     837              :         //
     838           26 :         std::string name = a_name;
     839           26 :         if (this->contains(name))
     840              :         {
     841            0 :             for (int n = 0; n < number; n++)
     842              :             {
     843            0 :                 T tmp;
     844            0 :                 this->query_required(name, tmp);
     845            0 :                 value.push_back(tmp);
     846              :             }
     847            0 :             return 0;
     848              :         }
     849              : 
     850              :         //
     851              :         // Some logic to determine whether we are starting with zero
     852              :         // (model0, model1, model2, ...)
     853              :         // or one
     854              :         // (model1, model2, model3, ...)
     855              :         // since both are supported
     856              :         //
     857           26 :         int start = -1;
     858           26 :         std::string name0 = a_name + std::to_string(0);
     859           26 :         std::string name1 = a_name + std::to_string(1);
     860           52 :         if (this->contains(name0.c_str()))
     861              :         {
     862           26 :             start = 0;
     863           26 :             name = name0;
     864              :         }
     865            0 :         else if (this->contains(name1.c_str()))
     866              :         {
     867            0 :             start = 1;
     868            0 :             name = name1;
     869              :         }
     870              :         else
     871              :         {
     872            0 :             Util::ParmParseException(INFO,full(name), "Enumerations must begin with 0 or 1");
     873              :         }
     874              : 
     875              :         //
     876              :         // Iterate over items called (model0), model1, model2, etc
     877              :         // until no more are found then exit. 
     878              :         //
     879          146 :         for (int cntr = start; this->contains(name.c_str()); cntr++)
     880              :         {
     881           68 :             if (this->contains(name.c_str()))
     882              :             {
     883           34 :                 T tmp;
     884           34 :                 this->query_required(name, tmp);
     885           34 :                 value.push_back(tmp);
     886           34 :             }
     887           34 :             name = a_name + std::to_string(cntr+1);
     888              :         }
     889              : 
     890           26 :         return 0;
     891           26 :     }
     892              : 
     893              : 
     894              : 
     895           10 :     int AnyUnusedInputs(bool inscopeonly = true, bool verbose = false)
     896              :     {
     897           10 :         int cnt = 0;
     898         1735 :         for (auto li = m_table->begin(), End = m_table->end(); li != End; ++li)
     899              :         {
     900         1725 :                 if (!li->second.m_count)
     901              :                 {
     902            0 :                     if (inscopeonly && getPrefix() != "")
     903              :                     {
     904            0 :                         if (li->first.rfind(getPrefix()+".",0) != std::string::npos)
     905              :                         {
     906            0 :                             if (verbose) Util::Warning(INFO,li->first);
     907            0 :                             cnt++;
     908              :                         }
     909              :                     }
     910              :                     else
     911              :                     {
     912            0 :                         if (verbose) Util::Warning(INFO,li->first);
     913            0 :                         cnt++;
     914              :                     }
     915              :                 }
     916              :         }
     917           10 :         return cnt;
     918              :     }
     919              : 
     920          220 :     std::vector<std::string> GetUnusedInputs()
     921              :     {
     922          220 :         std::vector<std::string> ret;
     923        31451 :         for (auto li = m_table->begin(), End = m_table->end(); li != End; ++li)
     924              :         {
     925        31231 :             if (!li->second.m_count && li->first.rfind(getPrefix()+".",0) != std::string::npos)
     926              :             {
     927            0 :                 ret.push_back(li->first);
     928              :             }
     929              :         }
     930          220 :         return ret;
     931            0 :     }
     932              : 
     933            0 :     static int AllUnusedInputs()
     934              :     {
     935            0 :         ParmParse pp;
     936            0 :         int cnt = 0;
     937            0 :         for (auto li = pp.m_table->begin(), End = pp.m_table->end(); li != End; ++li)
     938              :         {
     939            0 :             if (!li->second.m_count)
     940              :             {
     941            0 :                 Util::Warning(INFO,li->first);
     942            0 :                 cnt++;
     943              :             }
     944              :         }
     945            0 :         return cnt;
     946            0 :     }
     947            0 :     std::string prefix ()
     948              :     {
     949            0 :         return getPrefix();
     950              :     }
     951         5491 :     std::string full (std::string name)
     952              :     {
     953         5491 :         std::string prefix = getPrefix();
     954         5491 :         if (prefix != "") return getPrefix() + "." + name;
     955         2732 :         else return name;
     956         5491 :     }
     957              : 
     958              : 
     959              :     template<class T>
     960              :     void queryclass(std::string name, T * value)
     961              :     {
     962              :         auto old_prefix = m_prefix;
     963              :         try
     964              :         {
     965              :             if (old_prefix.empty()) m_prefix = name;
     966              :             else m_prefix.append(".").append(name);
     967              :             T::Parse(*value, *this);
     968              :             std::vector<std::string> unused_inputs = GetUnusedInputs();
     969              :             if (unused_inputs.size())
     970              :             {
     971              :                 std::stringstream ss;
     972              :                 for (unsigned int i=0; i < unused_inputs.size(); i++)
     973              :                     ss << "\n\t" << unused_inputs[i];
     974              :                 Util::ParmParseException(INFO,name,"The following inputs were specified but not used",ss.str());
     975              :             }
     976              :         }
     977              :         catch (...)
     978              :         {
     979              :             m_prefix = old_prefix;
     980              :             Util::ParmParseException(INFO,full(name));
     981              :         }
     982              :         m_prefix = old_prefix;
     983              :     }
     984              :     template<class T>
     985          220 :     void queryclass(std::string name, T & value)
     986              :     {
     987          220 :         auto old_prefix = m_prefix;
     988              :         try
     989              :         {
     990          220 :             if (old_prefix.empty()) m_prefix = name;
     991            0 :             else m_prefix.append(".").append(name);
     992          220 :             T::Parse(value, *this);
     993          220 :             std::vector<std::string> unused_inputs = GetUnusedInputs();
     994          220 :             if (unused_inputs.size())
     995              :             {
     996            0 :                 std::stringstream ss;
     997            0 :                 for (unsigned int i=0; i < unused_inputs.size(); i++)
     998            0 :                     ss << "\n\t" << unused_inputs[i];
     999            0 :                 Util::ParmParseException(INFO,name,"The following inputs were specified but not used",ss.str());
    1000            0 :             }
    1001          220 :         }
    1002            0 :         catch (std::runtime_error &e)
    1003              :         {
    1004            0 :             Util::ParmParseException(INFO,full(name),e.what());
    1005              :         }
    1006            0 :         catch (...)
    1007              :         {
    1008            0 :             m_prefix = old_prefix;
    1009            0 :             Util::ParmParseException(INFO,full(name));
    1010              :         }
    1011          220 :         m_prefix = old_prefix;
    1012          220 :     }
    1013              : 
    1014              :     template<class T>
    1015              :     void queryclass(T * value)
    1016              :     {
    1017              :         try
    1018              :         {
    1019              :             T::Parse(*value, *this);
    1020              :         }
    1021              :         catch (std::runtime_error &e)
    1022              :         {
    1023              :             Util::ParmParseException(INFO,getPrefix(), e.what());
    1024              :         }
    1025              :         catch (...)
    1026              :         {
    1027              :             Util::ParmParseException(INFO,getPrefix());
    1028              :         }
    1029              :     }
    1030              :     template<class T>
    1031          460 :     void queryclass(T & value)
    1032              :     {
    1033              :         try
    1034              :         {
    1035          460 :             T::Parse(value, *this);
    1036              :         }
    1037            0 :         catch (std::runtime_error &e)
    1038              :         {
    1039            0 :             Util::ParmParseException(INFO,getPrefix(), e.what());
    1040              :         }
    1041            0 :         catch (...)
    1042              :         {
    1043            0 :             Util::ParmParseException(INFO, getPrefix());
    1044              :         }
    1045          460 :     }
    1046              : 
    1047              :     //
    1048              :     // Variadic template parsing operator to assign a pointer to
    1049              :     // one of a set of possible class objects, then call that method's
    1050              :     // Parse function.
    1051              :     //
    1052              :     // If there is more than one instantiating class, then type must be set.
    1053              :     // Otherwise, no type is necessary.
    1054              :     //
    1055              :     template<typename... IC, typename... Args, typename PTRTYPE>
    1056           44 :     void select (std::string name, PTRTYPE *& ic_eta, Args&&... args)
    1057              :     {
    1058              :         try
    1059              :         {
    1060              :             // if there is only one IC arg provided, we don't need to check the type - assume that
    1061              :             // it is the default.
    1062              :             if constexpr (sizeof...(IC) == 0)
    1063              :             {
    1064              :                 using first_IC = std::tuple_element_t<0, std::tuple<IC...>>;
    1065              :                 ic_eta = new first_IC(std::forward<Args>(args)..., (*this), name + "." + std::string(first_IC::name));
    1066              :             }
    1067              :             // otherwise, check the type.
    1068              :             else
    1069              :             {
    1070           44 :                 std::string type = "";
    1071           44 :                 this->query_required(name + ".type", type);
    1072           48 :                 bool matched = ((   type == IC::name 
    1073          157 :                                     ? (ic_eta = new IC(std::forward<Args>(args)..., (*this), name + "." + std::string(IC::name))),
    1074              :                                     true
    1075          114 :                                     : false) || ...);
    1076           44 :                 if (!matched)
    1077            0 :                     Util::ParmParseException(INFO,full(name), type, " not a valid type for ", name);
    1078           44 :             }
    1079              :         }
    1080            0 :         catch (std::runtime_error &e)
    1081              :         {
    1082            0 :             Util::ParmParseException(INFO,getPrefix(),e.what());
    1083              :         }
    1084            0 :         catch (...)
    1085              :         {
    1086            0 :             Util::ParmParseException(INFO,getPrefix());
    1087              :         }
    1088           44 :     }
    1089              : 
    1090              :     //
    1091              :     // Identical to the above, except sets the type automatically to the
    1092              :     // firs specified 
    1093              :     //
    1094              :     template<typename FirstIC, typename... IC, typename... Args, typename PTRTYPE>
    1095          127 :     void select_default (std::string name, PTRTYPE *& ic_eta, Args&&... args)
    1096              :     {
    1097          127 :         std::string type = "";
    1098              : 
    1099          127 :         this->query_default(name + ".type", type, FirstIC::name);
    1100              : 
    1101            0 :         bool matched =
    1102          254 :             ((  type == FirstIC::name 
    1103          315 :                 ? (ic_eta = new FirstIC(std::forward<Args>(args)..., (*this), name + "." + std::string(FirstIC::name))),
    1104              :                 true : false))
    1105          254 :             || 
    1106           33 :             ((  type == IC::name 
    1107          220 :                 ? (ic_eta = new IC(std::forward<Args>(args)..., (*this), name + "." + std::string(IC::name))),
    1108              :                 true : false) || ...);
    1109              : 
    1110              : 
    1111          127 :         if (!matched)
    1112            0 :             Util::ParmParseException(INFO,full(name), type," not a valid type for ",name);
    1113          127 :     }
    1114              : 
    1115              : 
    1116              :     //
    1117              :     //
    1118              :     template<typename... IC, typename... Args, typename PTRTYPE>
    1119            0 :     void select_enumerate (std::string a_name, std::vector<PTRTYPE*> & value, Args&&... args)
    1120              :     {
    1121              : 
    1122            0 :         value.clear();
    1123              : 
    1124              :         //
    1125              :         // If only one is present with no subscript, then read
    1126              :         // it only and return.
    1127              :         //
    1128            0 :         std::string name = a_name;
    1129            0 :         if (this->contains(name))
    1130              :         {
    1131              :             PTRTYPE *tmp;
    1132            0 :             this->select<IC...>(a_name, tmp, args...);
    1133            0 :             value.push_back(tmp);
    1134            0 :             return;
    1135              :         }
    1136              : 
    1137              :         //
    1138              :         // Some logic to determine whether we are starting with zero
    1139              :         // (model0, model1, model2, ...)
    1140              :         // or one
    1141              :         // (model1, model2, model3, ...)
    1142              :         // since both are supported
    1143              :         //
    1144            0 :         int start = -1;
    1145            0 :         std::string name0 = a_name + std::to_string(0);
    1146            0 :         std::string name1 = a_name + std::to_string(1);
    1147            0 :         if (this->contains(name0.c_str()))
    1148              :         {
    1149            0 :             start = 0;
    1150            0 :             name = name0;
    1151              :         }
    1152            0 :         else if (this->contains(name1.c_str()))
    1153              :         {
    1154            0 :             start = 1;
    1155            0 :             name = name1;
    1156              :         }
    1157              :         else
    1158              :         {
    1159            0 :             Util::ParmParseException(INFO,full(name), "Enumerations must begin with 0 or 1");
    1160              :         }
    1161              : 
    1162              :         //
    1163              :         // Iterate over items called (model0), model1, model2, etc
    1164              :         // until no more are found then exit. 
    1165              :         //
    1166            0 :         for (int cntr = start; this->contains(name.c_str()); cntr++)
    1167              :         {
    1168            0 :             if (this->contains(name.c_str()))
    1169              :             {
    1170              :                 PTRTYPE *tmp;
    1171            0 :                 this->select<IC...>(name, tmp, args...);
    1172            0 :                 value.push_back(tmp);
    1173              :             }
    1174            0 :             name = a_name + std::to_string(cntr+1);
    1175              :         }
    1176            0 :     }
    1177              : 
    1178              : 
    1179              : 
    1180              :     //
    1181              :     // Similar to select but specialized for main functions
    1182              :     //
    1183              :     template<typename... INTEGRATOR, typename... Args, typename PTRTYPE>
    1184              :     void select_main (PTRTYPE *& ic_eta, Args&&... args)
    1185              :     {
    1186              :         std::string type = "";
    1187              : 
    1188              :         this->query_required("alamo.program", type);
    1189              :         
    1190              :         bool matched = ((type == INTEGRATOR::name 
    1191              :                         ? (ic_eta = new INTEGRATOR(std::forward<Args>(args)..., (*this))),
    1192              :                         true
    1193              :                         : false) || ...);
    1194              :         if (!matched)
    1195              :             Util::ParmParseException(INFO,getPrefix(),type," not a valid type for ",type);
    1196              :     }
    1197              : 
    1198              :     //
    1199              :     // Similar to select_main but works for one function only
    1200              :     // and doesn't require a type specifier.
    1201              :     //
    1202              : 
    1203              :     // with variadic arguments
    1204              :     template<typename INTEGRATOR, typename Args, typename PTRTYPE>
    1205              :     void select_only (PTRTYPE *& ic_eta, Args&& args)
    1206              :     {
    1207              :         ic_eta = new INTEGRATOR(std::forward<Args>(args), (*this));
    1208              :     }
    1209              :     // without variadic arguments
    1210              :     template<typename INTEGRATOR, typename PTRTYPE>
    1211           40 :     void select_only (PTRTYPE *& ic_eta)
    1212              :     {
    1213           40 :         ic_eta = new INTEGRATOR((*this));
    1214           40 :     }
    1215              : 
    1216              :     
    1217              :     //
    1218              :     // functionally simlar to other kinds of select, execpt works on
    1219              :     // template-based static dispatch.
    1220              :     //
    1221              : 
    1222              :     template <typename... OBJ, typename CLASS>
    1223            3 :     void select(std::string name, CLASS& value)
    1224              :     {
    1225            3 :         pushPrefix(name);
    1226            3 :         static_polymorphism_parser<CLASS, 0, OBJ...>(value);
    1227            3 :         popPrefix();
    1228            3 :     }
    1229              : 
    1230              : private:
    1231              :     //
    1232              :     // This function is a virtual "swtich / case" block for static
    1233              :     // dispatch. It works on a faux-virtual class "CLASS" that must 
    1234              :     // contain a tuple of "obj" with each "obj" being a derived type.
    1235              :     // Recursion is used to unroll the list, identify the correct class
    1236              :     // based on "name/type", set the "selected" index, then call the
    1237              :     // appropriate class' Parse function.
    1238              :     // 
    1239              :     // This is only for use by the "select" functions.
    1240              :     // 
    1241              :     template <typename CLASS, int N, typename... OBJ>
    1242            4 :     void static_polymorphism_parser(CLASS& value)
    1243              :     {
    1244              :         if constexpr (N == 0)
    1245              :         {
    1246            3 :             std::string type;
    1247            6 :             query_default("type",type,value.names[0]);
    1248              : 
    1249           12 :             for (unsigned int i = 0; i < sizeof...(OBJ); i++)
    1250            9 :                 if (type == value.names[i])
    1251            3 :                     value.selected = i;
    1252              : 
    1253            3 :             if (value.selected < 0)
    1254            0 :                 Util::ParmParseException(INFO,getPrefix(),
    1255              :                                 "Error reading " + getPrefix() + 
    1256              :                                 ", invalid type " + type);
    1257              : 
    1258              :             
    1259            3 :             pushPrefix(type);
    1260            3 :         }
    1261              : 
    1262              :         if constexpr (N < sizeof...(OBJ))
    1263              :         {
    1264            4 :             if (value.selected == N)
    1265              :             {
    1266            3 :                 std::get<N>(value.obj).Parse(std::get<N>(value.obj), *this);
    1267            3 :                 popPrefix();
    1268            3 :                 return;
    1269              :             }
    1270              :             else 
    1271            1 :                 return static_polymorphism_parser<CLASS, N+1, OBJ...>(value);
    1272              :         }
    1273            0 :         else Util::Abort(INFO);
    1274            0 :     }
    1275              : 
    1276              : public:
    1277              : 
    1278              :     template <int N>
    1279           20 :     void query_exactly( std::vector<std::string> names, std::pair<std::string, Set::Scalar> values[N],
    1280              :                         std::vector<Unit> units = std::vector<Unit>())
    1281              :     {
    1282              :         try
    1283              :         {
    1284          140 :             Util::AssertException(  INFO,TEST(units.size() == 0 || units.size() == names.size()),
    1285           20 :                                     "# of units must be 0, 1, or ", names.size(), " but got ", units.size());
    1286              : 
    1287           20 :             int cnt = 0;
    1288           20 :             std::vector<std::string> read;
    1289          117 :             for (unsigned int n = 0; n < names.size(); n++)
    1290              :             {
    1291           97 :                 if (amrex::ParmParse::contains(names[n].c_str()))
    1292              :                 {
    1293           40 :                     read.push_back(names[n]);
    1294           40 :                     cnt++;
    1295              :                 }
    1296              :             }
    1297          180 :             Util::AssertException(  INFO, TEST(cnt == N),
    1298              :                                     " Incorrect number of values specified: only ", N,
    1299              :                                     " values are allowed, but received ",
    1300              :                                     Util::String::Join(read,", "));
    1301              : 
    1302              : 
    1303           20 :             cnt = 0;
    1304          117 :             for (unsigned int n = 0; n < names.size(); n++)
    1305              :             {
    1306           97 :                 if (amrex::ParmParse::contains(names[n].c_str()))
    1307              :                 {
    1308           40 :                     values[cnt].first = names[n];
    1309              : 
    1310           40 :                     if (units.size() == 0)
    1311           34 :                         query_required(names[n],values[cnt].second);
    1312            6 :                     else if (units.size() == 1)
    1313            0 :                         query_required(names[n],values[cnt].second,units[0]);
    1314              :                     else
    1315            6 :                         query_required(names[n],values[cnt].second,units[n]);
    1316           40 :                     cnt++;
    1317              :                 }
    1318              :             }
    1319           20 :         }
    1320            0 :         catch(...)
    1321              :         {
    1322            0 :             std::string names_str = "[";
    1323            0 :             for (unsigned int i = 0; i < names.size(); i++)
    1324              :             {
    1325            0 :                 names_str += full(names[i]);
    1326            0 :                 if (i < names.size()-1) names_str += ", ";
    1327              :             }
    1328            0 :             names_str += "]";
    1329            0 :             Util::ParmParseException(INFO,names_str);
    1330            0 :         }
    1331           20 :     }
    1332              : };
    1333              : }
    1334              : #endif
        

Generated by: LCOV version 2.0-1