LCOV - code coverage report
Current view: top level - src/IO - ParmParse.H (source / functions) Coverage Total Hit
Test: coverage_merged.info Lines: 54.7 % 510 279
Test Date: 2025-08-12 17:45:17 Functions: 63.5 % 203 129

            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         1007 :     void Define() 
     119              :     {
     120         1007 :         if (checked_for_input_files) return;
     121           39 :         int k = 0;
     122           39 :         std::string inputfile = "";
     123           39 :         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           39 :         checked_for_input_files = true;
     130           39 :     }
     131              :     static bool checked_for_input_files;
     132              :     
     133              : public:
     134          693 :     ParmParse(std::string arg) : amrex::ParmParse::ParmParse(arg) {Define();} ;
     135          314 :     ParmParse() : amrex::ParmParse::ParmParse() {Define();} ;
     136         9555 :     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          275 :     void forbid(std::string name, std::string explanation)
     161              :     {
     162          275 :         if (amrex::ParmParse::contains(full(name).c_str()))
     163              :         {
     164            0 :             Util::ParmParseException(INFO,full(name),full(name)," forbidden: ", explanation);
     165              :         }
     166          275 :         std::set<std::string> subs = amrex::ParmParse::getEntries(full(name));
     167          275 :         if (subs.size())
     168              :         {
     169            0 :             Util::ParmParseException(INFO,full(name),full(name)," forbidden: ", explanation);
     170              :         }
     171          275 :     }
     172              : 
     173         2953 :     bool contains(std::string name)
     174              :     {
     175         2953 :         if (amrex::ParmParse::contains(name.c_str()))
     176         1110 :             return true;
     177         1843 :         if (amrex::ParmParse::contains(full(name).c_str()))
     178            0 :             return true;
     179              :         {
     180         1843 :             std::set<std::string> subs = amrex::ParmParse::getEntries(name.c_str());
     181         1843 :             if (subs.size())
     182           52 :                 return true;
     183         1843 :         }
     184              :         {
     185         1791 :             std::set<std::string> subs = amrex::ParmParse::getEntries(full(name).c_str());
     186         1791 :             if (subs.size())
     187            0 :                 return true;
     188         1791 :         }
     189         1791 :         return false;
     190              :     }
     191              : 
     192          283 :     int queryunit (std::string name, Unit &value)
     193              :     {
     194              :         try
     195              :         {
     196          283 :             std::string strvalue;
     197          283 :             int retval = amrex::ParmParse::query(name.c_str(),strvalue);
     198          283 :             value = Unit::Parse(strvalue);
     199         1415 :             Util::DebugMessage(INFO,full(name),": ",strvalue," ==> ",value);
     200          283 :             return retval;
     201          283 :         }
     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          236 :     int queryunit (std::string name, Unit &value, const Unit type)
     214              :     {
     215              :         try
     216              :         {
     217          236 :             int retval = queryunit(name,value);
     218          236 :             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          236 :             return retval;
     225              :         }
     226            0 :         catch (...)
     227              :         {
     228            0 :             Util::ParmParseException(INFO,full(name));
     229            0 :         }
     230            0 :         return -1;
     231              :     }
     232          236 :     int queryunit (std::string name, Set::Scalar &value, const Unit type)
     233              :     {
     234              :         try
     235              :         {
     236          236 :             Unit read;
     237          236 :             int retval = queryunit(name,read,type);
     238          236 :             value = read.normalized_value();
     239          236 :             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          173 :     int query_required( std::string name, T & value)
     250              :     {
     251              :         try
     252              :         {
     253          346 :             if (!contains(name.c_str()))
     254              :             {
     255            0 :                 Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
     256              :             }
     257          173 :             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           99 :     int query_required( std::string name, T & value, const Unit type)
     272              :     {
     273              :         try
     274              :         {
     275          198 :             if (!contains(name.c_str()))
     276              :             {
     277            0 :                 Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
     278              :             }
     279          198 :             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         1295 :     int query_default(  std::string name, T & value, T defaultvalue)
     294              :     {
     295              :         try
     296              :         {
     297         2590 :             if (!contains(name.c_str()))
     298              :             {
     299         1055 :                 add(name.c_str(),defaultvalue);
     300              :             }
     301         1295 :             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          137 :     int query_default(  std::string name, T & value, std::string defaultvalue, const Unit type)
     316              :     {
     317              :         try
     318              :         {
     319          274 :             if (!contains(name.c_str()))
     320              :             {
     321           85 :                 add(name.c_str(),defaultvalue);
     322              :             }
     323          274 :             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            3 :     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            3 :             value = possibleintvals[0];
     344              : 
     345              :             // get the read value (if it exists)
     346            3 :             int retval = query(name.c_str(),value);
     347              : 
     348              :             // check to make sure the read value matches one of the inpus
     349            3 :             bool ok = false;
     350           12 :             for (unsigned int i = 0; i < possibleintvals.size(); i++)
     351              :             {
     352            9 :                 if (value == possibleintvals[i]) ok = true;
     353              :             }
     354              : 
     355            3 :             if (ok) return retval;
     356              : 
     357            0 :             std::stringstream ss;
     358            0 :             ss << possibleintvals[0];
     359            0 :             for (unsigned int i = 1; i < possibleintvals.size(); i++)
     360            0 :                 ss << "," << possibleintvals[i];
     361              : 
     362            0 :             Util::ParmParseException(INFO,full(name),"' expected [", ss.str(), "] but got ", value);
     363            0 :         }
     364            0 :         catch (std::runtime_error & e)
     365              :         {
     366            0 :             Util::ParmParseException(INFO,full(name),e.what());
     367            0 :         }
     368            0 :         catch (...)
     369              :         {
     370            0 :             Util::ParmParseException(INFO,full(name));
     371            0 :         }
     372            0 :         return -1;
     373              :     }
     374              : 
     375              : 
     376           99 :     int query_validate( std::string name, std::string & value, std::vector<const char *> possiblecharvals, bool firstbydefault)
     377              :     {        
     378              :         try
     379              :         {
     380              :             // if not using default values, then the input must be specified
     381           99 :             if (!firstbydefault)
     382              :             {
     383            0 :                 if (!contains(name.c_str()))
     384              :                 {
     385            0 :                     Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
     386              :                 }
     387              :             }
     388              : 
     389              :             // set default value
     390           99 :             value = std::string(possiblecharvals[0]);
     391              : 
     392              :             // get the read value (if it exists)
     393           99 :             int retval = amrex::ParmParse::query(name.c_str(),value);
     394              : 
     395              :             // check to make sure the read value matches one of the inpus
     396           99 :             bool ok = false;
     397          394 :             for (unsigned int i = 0; i < possiblecharvals.size(); i++)
     398              :             {
     399          590 :                 if (value == std::string(possiblecharvals[i])) ok = true;
     400              :             }
     401              :         
     402           99 :             if (ok) return retval;
     403              : 
     404            0 :             std::stringstream ss;
     405            0 :             ss << possiblecharvals[0];
     406            0 :             for (unsigned int i = 1; i < possiblecharvals.size(); i++)
     407            0 :                 ss << "," << possiblecharvals[i];
     408              : 
     409            0 :             Util::ParmParseException(INFO,full(name),"' expected [", ss.str(), "] but got ", value);
     410            0 :         }
     411            0 :         catch (std::runtime_error & e)
     412              :         {
     413            0 :             Util::ParmParseException(INFO,full(name),e.what());
     414            0 :         }
     415            0 :         catch (...)
     416              :         {
     417            0 :             Util::ParmParseException(INFO,full(name));
     418            0 :         }
     419              : 
     420            0 :         return -1;
     421              :     }
     422              : 
     423           99 :     int query_validate( std::string name, std::string & value, std::vector<const char *> possiblecharvals)
     424              :     {
     425              :         try
     426              :         {
     427           99 :             return query_validate(name,value,possiblecharvals,true);
     428              :         }
     429            0 :         catch (std::runtime_error & e)
     430              :         {
     431            0 :             Util::ParmParseException(INFO,full(name),e.what());
     432            0 :         }
     433            0 :         catch (...)
     434              :         {
     435            0 :             Util::ParmParseException(INFO,full(name));
     436            0 :         }
     437            0 :         return -1;
     438              :     }
     439              : 
     440              :     
     441              :     // special case for strings
     442          267 :     int query_default(  std::string name, std::string & value, const char *defaultvalue)
     443              :     {
     444              :         try
     445              :         {
     446          534 :             return query_default(name, value, std::string(defaultvalue));
     447              :         }
     448            0 :         catch (std::runtime_error & e)
     449              :         {
     450            0 :             Util::ParmParseException(INFO,full(name),e.what());
     451            0 :         }
     452            0 :         catch (...)
     453              :         {
     454            0 :             Util::ParmParseException(INFO,full(name));
     455            0 :         }
     456            0 :         return -1;
     457              :     }
     458              :     // special case for bools
     459           66 :     int query_default(  std::string name, int & value, bool defaultvalue)
     460              :     {
     461              :         try
     462              :         {
     463           66 :             int defaultint = 0;
     464           66 :             if (defaultvalue) defaultint = 1;
     465           66 :             return query_default(name, value, defaultint);
     466              :         }
     467            0 :         catch (std::runtime_error & e)
     468              :         {
     469            0 :             Util::ParmParseException(INFO,full(name),e.what());
     470            0 :         }
     471            0 :         catch (...)
     472              :         {
     473            0 :             Util::ParmParseException(INFO,full(name));
     474            0 :         }
     475            0 :         return -1;
     476              :     }
     477              : 
     478              : 
     479              :     // validate filenames
     480            2 :     int query_file( std::string name, std::string & value, bool copyfile, bool checkfile)
     481              :     {
     482              :         try
     483              :         {
     484            4 :             if (!contains(name.c_str()))
     485              :             {
     486            0 :                 Util::ParmParseException(INFO,full(name),full(name)," must be specified");
     487              :             }
     488              : 
     489            2 :             int retval = query(name.c_str(),value);
     490              : 
     491            2 :             if (amrex::ParallelDescriptor::IOProcessor())
     492              :             {
     493            2 :                 if ( checkfile && ! std::filesystem::exists(value))
     494              :                 {
     495            0 :                     Util::ParmParseException(INFO,full(name),full(name)," does not exist");
     496              :                 }
     497            2 :                 if ( checkfile && !std::filesystem::is_regular_file(value))
     498              :                 {
     499            0 :                     Util::ParmParseException(INFO,full(name),full(name)," is not a regular file");
     500              :                 }
     501            2 :                 if ( copyfile )
     502              :                 {
     503            2 :                     Util::CopyFileToOutputDir(value, true, full(name));
     504              :                 }
     505              :             }
     506            2 :             return retval;
     507              :         }
     508            0 :         catch (std::runtime_error & e)
     509              :         {
     510            0 :             Util::ParmParseException(INFO,full(name),e.what());
     511            0 :         }
     512            0 :         catch (...)
     513              :         {
     514            0 :             Util::ParmParseException(INFO,full(name));
     515            0 :         }
     516            0 :         return -1;
     517              :     }
     518              :     int query_file( std::string name, std::string & value, bool copyfile)
     519              :     {
     520              :         return query_file(name,value,copyfile,true);
     521              :     }
     522            2 :     int query_file( std::string name, std::string & value)
     523              :     {
     524            2 :         return query_file(name,value,true,true);
     525              :     }
     526              : 
     527              : 
     528              :     template<typename T>
     529           91 :     int queryarr(   std::string name, std::vector<T> & value)
     530              :     {
     531              :         try
     532              :         {
     533           91 :             return amrex::ParmParse::queryarr(name.c_str(),value);
     534              :         }
     535            0 :         catch (...)
     536              :         {
     537            0 :             Util::ParmParseException(INFO,full(name));
     538              :         }
     539            0 :         return -1;
     540              :     }
     541          153 :     int queryarr(   std::string name, std::vector<Set::Scalar> & value, Unit unit = Unit::Less())
     542              :     {
     543              :         try
     544              :         {
     545          153 :             if (unit.isType(Unit::Less()))
     546              :             {
     547           65 :                 return amrex::ParmParse::queryarr(name.c_str(),value);
     548              :             }
     549              :             else
     550              :             {
     551           88 :                 value.clear();
     552           88 :                 std::vector<std::string> valstrings;
     553           88 :                 int retval = amrex::ParmParse::queryarr(name.c_str(), valstrings);
     554          336 :                 for (unsigned int i = 0; i < valstrings.size(); i++)
     555              :                 {
     556          248 :                     Unit unitvalue = Unit::Parse(valstrings[i]);
     557         1240 :                     Util::DebugMessage(INFO,full(name),": ",valstrings[i]," ==> ",unitvalue);
     558              : 
     559          248 :                     if (!unitvalue.isType(unit) && !unitvalue.isType(Unit::Less()))
     560              :                     {
     561            0 :                         Util::Exception(INFO,"value specified had wrong units:", valstrings[i]);
     562              :                     }
     563          248 :                     value.push_back(unitvalue.normalized_value());
     564              :                 }
     565           88 :                 return retval;
     566           88 :             }
     567              :         }
     568            0 :         catch (std::runtime_error &e)
     569              :         {
     570            0 :             Util::ParmParseException(INFO,full(name), e.what());
     571            0 :         }
     572            0 :         catch (...)
     573              :         {
     574            0 :             Util::ParmParseException(INFO,full(name));
     575            0 :         }
     576            0 :         return -1;
     577              :     }
     578            8 :     int queryarr(   std::string name, Set::Vector & value, Unit unit = Unit::Less())
     579              :     {
     580              :         try
     581              :         {
     582            8 :             std::vector<Set::Scalar> vals;
     583            8 :             queryarr(name.c_str(), vals, unit);
     584            8 :             if (vals.size() < AMREX_SPACEDIM) 
     585              :             {
     586            0 :                 Util::ParmParseException(   INFO,full(name),full(name),
     587            0 :                                             " requires at least ", AMREX_SPACEDIM, 
     588            0 :                                             " arguments, got ",vals.size());
     589              :             }
     590           24 :             for (int i = 0; i < AMREX_SPACEDIM; i++) value(i) = vals[i];
     591            8 :             return 0;
     592            8 :         }
     593            0 :         catch(...)
     594              :         {
     595            0 :             Util::ParmParseException(INFO,full(name));
     596            0 :         }
     597            0 :         return -1;
     598              :     }
     599            6 :     int queryarr(   std::string name, Set::Matrix & value, Unit unit = Unit::Less())
     600              :     {
     601            6 :         std::vector<Set::Scalar> vals;
     602            6 :         queryarr(name.c_str(), vals,unit);
     603            6 :         if (vals.size() == 9)
     604              :         {
     605              : #if AMREX_SPACEDIM==2
     606           20 :             Util::Warning(INFO, "Reading a 3D matrix (",full(name),")into a 2D code - some values will be ignored.");
     607            4 :             value(0,0) = vals[0];  value(0,1)= vals[1];
     608            4 :             value(1,0) = vals[3];  value(1,1)= vals[4];
     609              : #endif
     610              : #if AMREX_SPACEDIM==3
     611            2 :             value(0,0) = vals[0];  value(0,1)= vals[1];  value(0,2)= vals[2];
     612            2 :             value(1,0) = vals[3];  value(1,1)= vals[4];  value(1,2)= vals[5];
     613            2 :             value(2,0) = vals[6];  value(2,1)= vals[7];  value(2,2)= vals[8];
     614              : #endif
     615              :         }
     616            0 :         else if (vals.size() == 4)
     617              :         {
     618              : #if AMREX_SPACEDIM==2
     619            0 :             value(0,0) = vals[0];  value(0,1)= vals[1];
     620            0 :             value(1,0) = vals[2];  value(1,1)= vals[3];
     621              : #endif
     622              : #if AMREX_SPACEDIM==3
     623            0 :             Util::Warning(INFO,"Reading a 2D matrix (",full(name),")into a 3D code - remaining values will be set to zero.");
     624            0 :             value(0,0) = vals[0];  value(0,1)= vals[1];  value(0,2)= 0.0;
     625            0 :             value(1,0) = vals[2];  value(1,1)= vals[3];  value(1,2)= 0.0;
     626            0 :             value(2,0) = 0.0;      value(2,1)= 0.0;      value(2,2)= 0.0;
     627              : #endif
     628              :         }
     629              :         else
     630              :         {
     631            0 :             Util::ParmParseException(INFO,full(name),full(name)," needs either 4 or 9 components, but got ",vals.size());
     632              :         }    
     633            6 :         return 0;
     634            6 :     }
     635              : 
     636              :     template<typename T>
     637              :     int queryarr_required(  std::string name, std::vector<T> & value)
     638              :     {
     639              :         if (!contains(name.c_str()))
     640              :         {
     641              :             Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
     642              :         }        
     643              :         return queryarr<T>(name,value);
     644              :     }
     645              : 
     646           47 :     int queryarr_required(  std::string name, std::vector<Set::Scalar> & value, Unit unit = Unit::Less())
     647              :     {
     648           94 :         if (!contains(name.c_str()))
     649              :         {
     650            0 :             Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
     651              :         }        
     652           47 :         return queryarr(name,value,unit);
     653              :     }
     654          500 :     int queryarr_default(   std::string name, std::vector<std::string> & value, std::vector<std::string> defaultvalue)
     655              :     {
     656         1000 :         if (!contains(name.c_str()))
     657              :         {
     658          253 :             addarr(name.c_str(),defaultvalue);
     659              :         }
     660          500 :         return amrex::ParmParse::queryarr(name.c_str(),value);
     661              :     }
     662              : 
     663              :     int queryarr_default(   std::string name, Set::Vector & value, Set::Vector defaultvalue)
     664              :     {
     665              :         try
     666              :         {
     667              :             if (!contains(name.c_str()))
     668              :             {
     669              :                 add(name.c_str(),Util::String::Join(defaultvalue));
     670              :                 value = defaultvalue;
     671              :                 return 0;
     672              :             }
     673              :             return queryarr(name.c_str(),value);
     674              :         }
     675              :         catch (...)
     676              :         {
     677              :             Util::ParmParseException(INFO,full(name));
     678              :         }
     679              :         return -1;
     680              :     }
     681              :     
     682            0 :     int queryarr_default(   std::string name, Set::Matrix & value, Set::Matrix defaultvalue)
     683              :     {
     684              :         try
     685              :         {
     686            0 :             if (!contains(name.c_str()))
     687              :             {
     688            0 :                 add(name.c_str(),Util::String::Join(defaultvalue));
     689            0 :                 value = defaultvalue;
     690            0 :                 return 0;
     691              :             }
     692            0 :             return queryarr(name.c_str(),value);
     693              :         }
     694            0 :         catch (...)
     695              :         {
     696            0 :             Util::ParmParseException(INFO,full(name));
     697            0 :         }
     698            0 :         return -1;
     699              :     }
     700              : 
     701              :     int queryarr_default(   std::string name, std::vector<double> & value, std::vector<double> defaultvalue)
     702              :     {
     703              :         try
     704              :         {
     705              :             if (!contains(name.c_str()))
     706              :             {
     707              :                 addarr(name.c_str(),defaultvalue);
     708              :             }
     709              :             return queryarr(name.c_str(),value);
     710              :         }
     711              :         catch (...)
     712              :         {
     713              :             Util::ParmParseException(INFO,full(name));
     714              :         }
     715              :         return -1;
     716              :     }
     717              : 
     718              :     int queryarr_default(   std::string name, std::vector<double> & value, std::vector<std::string> defaultvalue, Unit unit)
     719              :     {
     720              :         try
     721              :         {
     722              :             if (!contains(name.c_str()))
     723              :             {
     724              :                 addarr(name.c_str(),defaultvalue);
     725              :             }
     726              :             return queryarr(name,value, unit);
     727              :         }
     728              :         catch (...)
     729              :         {
     730              :             Util::ParmParseException(INFO,full(name));
     731              :         }
     732              :         return -1;
     733              :     }
     734              : 
     735              : 
     736              :     template <typename T>
     737              :     int
     738           18 :     queryclass_enumerate(std::string a_name, std::vector<T> &value, int number = 1)
     739              :     {
     740           18 :         value.clear();
     741              : 
     742              :         //
     743              :         // If only one is present with no subscript, then read
     744              :         // it only and return.
     745              :         //
     746           18 :         std::string name = a_name;
     747           18 :         if (this->contains(name))
     748              :         {
     749            8 :             for (int n = 0; n < number; n++)
     750              :             {
     751            4 :                 T tmp;
     752            4 :                 this->queryclass<T>(name, tmp);
     753            4 :                 value.push_back(tmp);
     754              :             }
     755            4 :             return 0;
     756              :         }
     757              : 
     758              :         //
     759              :         // Some logic to determine whether we are starting with zero
     760              :         // (model0, model1, model2, ...)
     761              :         // or one
     762              :         // (model1, model2, model3, ...)
     763              :         // since both are supported
     764              :         //
     765           14 :         int start = -1;
     766           14 :         std::string name0 = a_name + std::to_string(0);
     767           14 :         std::string name1 = a_name + std::to_string(1);
     768           28 :         if (this->contains(name0.c_str()))
     769              :         {
     770            0 :             start = 0;
     771            0 :             name = name0;
     772              :         }
     773           28 :         else if (this->contains(name1.c_str()))
     774              :         {
     775           14 :             start = 1;
     776           14 :             name = name1;
     777              :         }
     778              :         else
     779              :         {
     780            0 :             Util::ParmParseException(INFO,full(name), "Enumerations must begin with 0 or 1");
     781              :         }
     782              : 
     783              :         //
     784              :         // Iterate over items called (model0), model1, model2, etc
     785              :         // until no more are found then exit. 
     786              :         //
     787           76 :         for (int cntr = start; this->contains(name.c_str()); cntr++)
     788              :         {
     789           34 :             if (this->contains(name.c_str()))
     790              :             {
     791           17 :                 T tmp;
     792           17 :                 this->queryclass<T>(name, tmp);
     793           17 :                 value.push_back(tmp);
     794           17 :             }
     795           17 :             name = a_name + std::to_string(cntr+1);
     796              :         }
     797              : 
     798           14 :         return 0;
     799           18 :     }
     800              : 
     801              : 
     802              :     template <typename T>
     803              :     int
     804           23 :     query_enumerate(std::string a_name, std::vector<T> &value, int number = 1)
     805              :     {
     806           23 :         value.clear();
     807              : 
     808              :         //
     809              :         // If only one is present with no subscript, then read
     810              :         // it only and return.
     811              :         //
     812           23 :         std::string name = a_name;
     813           23 :         if (this->contains(name))
     814              :         {
     815            0 :             for (int n = 0; n < number; n++)
     816              :             {
     817            0 :                 T tmp;
     818            0 :                 this->query_required(name, tmp);
     819            0 :                 value.push_back(tmp);
     820              :             }
     821            0 :             return 0;
     822              :         }
     823              : 
     824              :         //
     825              :         // Some logic to determine whether we are starting with zero
     826              :         // (model0, model1, model2, ...)
     827              :         // or one
     828              :         // (model1, model2, model3, ...)
     829              :         // since both are supported
     830              :         //
     831           23 :         int start = -1;
     832           23 :         std::string name0 = a_name + std::to_string(0);
     833           23 :         std::string name1 = a_name + std::to_string(1);
     834           46 :         if (this->contains(name0.c_str()))
     835              :         {
     836           23 :             start = 0;
     837           23 :             name = name0;
     838              :         }
     839            0 :         else if (this->contains(name1.c_str()))
     840              :         {
     841            0 :             start = 1;
     842            0 :             name = name1;
     843              :         }
     844              :         else
     845              :         {
     846            0 :             Util::ParmParseException(INFO,full(name), "Enumerations must begin with 0 or 1");
     847              :         }
     848              : 
     849              :         //
     850              :         // Iterate over items called (model0), model1, model2, etc
     851              :         // until no more are found then exit. 
     852              :         //
     853          129 :         for (int cntr = start; this->contains(name.c_str()); cntr++)
     854              :         {
     855           60 :             if (this->contains(name.c_str()))
     856              :             {
     857           30 :                 T tmp;
     858           30 :                 this->query_required(name, tmp);
     859           30 :                 value.push_back(tmp);
     860           30 :             }
     861           30 :             name = a_name + std::to_string(cntr+1);
     862              :         }
     863              : 
     864           23 :         return 0;
     865           23 :     }
     866              : 
     867              : 
     868              : 
     869            9 :     int AnyUnusedInputs(bool inscopeonly = true, bool verbose = false)
     870              :     {
     871            9 :         int cnt = 0;
     872         1476 :         for (auto li = m_table->begin(), End = m_table->end(); li != End; ++li)
     873              :         {
     874         1467 :                 if (!li->second.m_count)
     875              :                 {
     876            0 :                     if (inscopeonly && getPrefix() != "")
     877              :                     {
     878            0 :                         if (li->first.rfind(getPrefix()+".",0) != std::string::npos)
     879              :                         {
     880            0 :                             if (verbose) Util::Warning(INFO,li->first);
     881            0 :                             cnt++;
     882              :                         }
     883              :                     }
     884              :                     else
     885              :                     {
     886            0 :                         if (verbose) Util::Warning(INFO,li->first);
     887            0 :                         cnt++;
     888              :                     }
     889              :                 }
     890              :         }
     891            9 :         return cnt;
     892              :     }
     893              : 
     894          201 :     std::vector<std::string> GetUnusedInputs()
     895              :     {
     896          201 :         std::vector<std::string> ret;
     897        27032 :         for (auto li = m_table->begin(), End = m_table->end(); li != End; ++li)
     898              :         {
     899        26831 :             if (!li->second.m_count && li->first.rfind(getPrefix()+".",0) != std::string::npos)
     900              :             {
     901            0 :                 ret.push_back(li->first);
     902              :             }
     903              :         }
     904          201 :         return ret;
     905            0 :     }
     906              : 
     907            0 :     static int AllUnusedInputs()
     908              :     {
     909            0 :         ParmParse pp;
     910            0 :         int cnt = 0;
     911            0 :         for (auto li = pp.m_table->begin(), End = pp.m_table->end(); li != End; ++li)
     912              :         {
     913            0 :             if (!li->second.m_count)
     914              :             {
     915            0 :                 Util::Warning(INFO,li->first);
     916            0 :                 cnt++;
     917              :             }
     918              :         }
     919            0 :         return cnt;
     920            0 :     }
     921            0 :     std::string prefix ()
     922              :     {
     923            0 :         return getPrefix();
     924              :     }
     925         4721 :     std::string full (std::string name)
     926              :     {
     927         4721 :         std::string prefix = getPrefix();
     928         4721 :         if (prefix != "") return getPrefix() + "." + name;
     929         2196 :         else return name;
     930         4721 :     }
     931              : 
     932              : 
     933              :     template<class T>
     934              :     void queryclass(std::string name, T * value)
     935              :     {
     936              :         auto old_prefix = m_prefix;
     937              :         try
     938              :         {
     939              :             if (old_prefix.empty()) m_prefix = name;
     940              :             else m_prefix.append(".").append(name);
     941              :             T::Parse(*value, *this);
     942              :             std::vector<std::string> unused_inputs = GetUnusedInputs();
     943              :             if (unused_inputs.size())
     944              :             {
     945              :                 std::stringstream ss;
     946              :                 for (unsigned int i=0; i < unused_inputs.size(); i++)
     947              :                     ss << "\n\t" << unused_inputs[i];
     948              :                 Util::ParmParseException(INFO,name,"The following inputs were specified but not used",ss.str());
     949              :             }
     950              :         }
     951              :         catch (...)
     952              :         {
     953              :             m_prefix = old_prefix;
     954              :             Util::ParmParseException(INFO,full(name));
     955              :         }
     956              :         m_prefix = old_prefix;
     957              :     }
     958              :     template<class T>
     959          201 :     void queryclass(std::string name, T & value)
     960              :     {
     961          201 :         auto old_prefix = m_prefix;
     962              :         try
     963              :         {
     964          201 :             if (old_prefix.empty()) m_prefix = name;
     965            0 :             else m_prefix.append(".").append(name);
     966          201 :             T::Parse(value, *this);
     967          201 :             std::vector<std::string> unused_inputs = GetUnusedInputs();
     968          201 :             if (unused_inputs.size())
     969              :             {
     970            0 :                 std::stringstream ss;
     971            0 :                 for (unsigned int i=0; i < unused_inputs.size(); i++)
     972            0 :                     ss << "\n\t" << unused_inputs[i];
     973            0 :                 Util::ParmParseException(INFO,name,"The following inputs were specified but not used",ss.str());
     974            0 :             }
     975          201 :         }
     976            0 :         catch (std::runtime_error &e)
     977              :         {
     978            0 :             Util::ParmParseException(INFO,full(name),e.what());
     979              :         }
     980            0 :         catch (...)
     981              :         {
     982            0 :             m_prefix = old_prefix;
     983            0 :             Util::ParmParseException(INFO,full(name));
     984              :         }
     985          201 :         m_prefix = old_prefix;
     986          201 :     }
     987              : 
     988              :     template<class T>
     989              :     void queryclass(T * value)
     990              :     {
     991              :         try
     992              :         {
     993              :             T::Parse(*value, *this);
     994              :         }
     995              :         catch (std::runtime_error &e)
     996              :         {
     997              :             Util::ParmParseException(INFO,getPrefix(), e.what());
     998              :         }
     999              :         catch (...)
    1000              :         {
    1001              :             Util::ParmParseException(INFO,getPrefix());
    1002              :         }
    1003              :     }
    1004              :     template<class T>
    1005          459 :     void queryclass(T & value)
    1006              :     {
    1007              :         try
    1008              :         {
    1009          459 :             T::Parse(value, *this);
    1010              :         }
    1011            0 :         catch (std::runtime_error &e)
    1012              :         {
    1013            0 :             Util::ParmParseException(INFO,getPrefix(), e.what());
    1014              :         }
    1015            0 :         catch (...)
    1016              :         {
    1017            0 :             Util::ParmParseException(INFO, getPrefix());
    1018              :         }
    1019          459 :     }
    1020              : 
    1021              :     //
    1022              :     // Variadic template parsing operator to assign a pointer to
    1023              :     // one of a set of possible class objects, then call that method's
    1024              :     // Parse function.
    1025              :     //
    1026              :     // If there is more than one instantiating class, then type must be set.
    1027              :     // Otherwise, no type is necessary.
    1028              :     //
    1029              :     template<typename... IC, typename... Args, typename PTRTYPE>
    1030           44 :     void select (std::string name, PTRTYPE *& ic_eta, Args&&... args)
    1031              :     {
    1032              :         try
    1033              :         {
    1034              :             // if there is only one IC arg provided, we don't need to check the type - assume that
    1035              :             // it is the default.
    1036              :             if constexpr (sizeof...(IC) == 0)
    1037              :             {
    1038              :                 using first_IC = std::tuple_element_t<0, std::tuple<IC...>>;
    1039              :                 ic_eta = new first_IC(std::forward<Args>(args)..., (*this), name + "." + std::string(first_IC::name));
    1040              :             }
    1041              :             // otherwise, check the type.
    1042              :             else
    1043              :             {
    1044           44 :                 std::string type = "";
    1045           44 :                 this->query_required(name + ".type", type);
    1046           48 :                 bool matched = ((   type == IC::name 
    1047          157 :                                     ? (ic_eta = new IC(std::forward<Args>(args)..., (*this), name + "." + std::string(IC::name))),
    1048              :                                     true
    1049          114 :                                     : false) || ...);
    1050           44 :                 if (!matched)
    1051            0 :                     Util::ParmParseException(INFO,full(name), type, " not a valid type for ", name);
    1052           44 :             }
    1053              :         }
    1054            0 :         catch (std::runtime_error &e)
    1055              :         {
    1056            0 :             Util::ParmParseException(INFO,getPrefix(),e.what());
    1057              :         }
    1058            0 :         catch (...)
    1059              :         {
    1060            0 :             Util::ParmParseException(INFO,getPrefix());
    1061              :         }
    1062           44 :     }
    1063              : 
    1064              :     //
    1065              :     // Identical to the above, except sets the type automatically to the
    1066              :     // firs specified 
    1067              :     //
    1068              :     template<typename FirstIC, typename... IC, typename... Args, typename PTRTYPE>
    1069          108 :     void select_default (std::string name, PTRTYPE *& ic_eta, Args&&... args)
    1070              :     {
    1071          108 :         std::string type = "";
    1072              : 
    1073          108 :         this->query_default(name + ".type", type, FirstIC::name);
    1074              : 
    1075            0 :         bool matched =
    1076          216 :             ((  type == FirstIC::name 
    1077          270 :                 ? (ic_eta = new FirstIC(std::forward<Args>(args)..., (*this), name + "." + std::string(FirstIC::name))),
    1078              :                 true : false))
    1079          216 :             || 
    1080           27 :             ((  type == IC::name 
    1081          183 :                 ? (ic_eta = new IC(std::forward<Args>(args)..., (*this), name + "." + std::string(IC::name))),
    1082              :                 true : false) || ...);
    1083              : 
    1084              : 
    1085          108 :         if (!matched)
    1086            0 :             Util::ParmParseException(INFO,full(name), type," not a valid type for ",name);
    1087          108 :     }
    1088              : 
    1089              : 
    1090              :     //
    1091              :     //
    1092              :     template<typename... IC, typename... Args, typename PTRTYPE>
    1093            0 :     void select_enumerate (std::string a_name, std::vector<PTRTYPE*> & value, Args&&... args)
    1094              :     {
    1095              : 
    1096            0 :         value.clear();
    1097              : 
    1098              :         //
    1099              :         // If only one is present with no subscript, then read
    1100              :         // it only and return.
    1101              :         //
    1102            0 :         std::string name = a_name;
    1103            0 :         if (this->contains(name))
    1104              :         {
    1105              :             PTRTYPE *tmp;
    1106            0 :             this->select<IC...>(a_name, tmp, args...);
    1107            0 :             value.push_back(tmp);
    1108            0 :             return;
    1109              :         }
    1110              : 
    1111              :         //
    1112              :         // Some logic to determine whether we are starting with zero
    1113              :         // (model0, model1, model2, ...)
    1114              :         // or one
    1115              :         // (model1, model2, model3, ...)
    1116              :         // since both are supported
    1117              :         //
    1118            0 :         int start = -1;
    1119            0 :         std::string name0 = a_name + std::to_string(0);
    1120            0 :         std::string name1 = a_name + std::to_string(1);
    1121            0 :         if (this->contains(name0.c_str()))
    1122              :         {
    1123            0 :             start = 0;
    1124            0 :             name = name0;
    1125              :         }
    1126            0 :         else if (this->contains(name1.c_str()))
    1127              :         {
    1128            0 :             start = 1;
    1129            0 :             name = name1;
    1130              :         }
    1131              :         else
    1132              :         {
    1133            0 :             Util::ParmParseException(INFO,full(name), "Enumerations must begin with 0 or 1");
    1134              :         }
    1135              : 
    1136              :         //
    1137              :         // Iterate over items called (model0), model1, model2, etc
    1138              :         // until no more are found then exit. 
    1139              :         //
    1140            0 :         for (int cntr = start; this->contains(name.c_str()); cntr++)
    1141              :         {
    1142            0 :             if (this->contains(name.c_str()))
    1143              :             {
    1144              :                 PTRTYPE *tmp;
    1145            0 :                 this->select<IC...>(name, tmp, args...);
    1146            0 :                 value.push_back(tmp);
    1147              :             }
    1148            0 :             name = a_name + std::to_string(cntr+1);
    1149              :         }
    1150            0 :     }
    1151              : 
    1152              : 
    1153              : 
    1154              :     //
    1155              :     // Similar to select but specialized for main functions
    1156              :     //
    1157              :     template<typename... INTEGRATOR, typename... Args, typename PTRTYPE>
    1158              :     void select_main (PTRTYPE *& ic_eta, Args&&... args)
    1159              :     {
    1160              :         std::string type = "";
    1161              : 
    1162              :         this->query_required("alamo.program", type);
    1163              :         
    1164              :         bool matched = ((type == INTEGRATOR::name 
    1165              :                         ? (ic_eta = new INTEGRATOR(std::forward<Args>(args)..., (*this))),
    1166              :                         true
    1167              :                         : false) || ...);
    1168              :         if (!matched)
    1169              :             Util::ParmParseException(INFO,getPrefix(),type," not a valid type for ",type);
    1170              :     }
    1171              : 
    1172              :     //
    1173              :     // Similar to select_main but works for one function only
    1174              :     // and doesn't require a type specifier.
    1175              :     //
    1176              : 
    1177              :     // with variadic arguments
    1178              :     template<typename INTEGRATOR, typename Args, typename PTRTYPE>
    1179              :     void select_only (PTRTYPE *& ic_eta, Args&& args)
    1180              :     {
    1181              :         ic_eta = new INTEGRATOR(std::forward<Args>(args), (*this));
    1182              :     }
    1183              :     // without variadic arguments
    1184              :     template<typename INTEGRATOR, typename PTRTYPE>
    1185           37 :     void select_only (PTRTYPE *& ic_eta)
    1186              :     {
    1187           37 :         ic_eta = new INTEGRATOR((*this));
    1188           37 :     }
    1189              : 
    1190              :     
    1191              :     //
    1192              :     // functionally simlar to other kinds of select, execpt works on
    1193              :     // template-based static dispatch.
    1194              :     //
    1195              : 
    1196              :     template <typename... OBJ, typename CLASS>
    1197            3 :     void select(std::string name, CLASS& value)
    1198              :     {
    1199            3 :         pushPrefix(name);
    1200            3 :         static_polymorphism_parser<CLASS, 0, OBJ...>(value);
    1201            3 :         popPrefix();
    1202            3 :     }
    1203              : 
    1204              : private:
    1205              :     //
    1206              :     // This function is a virtual "swtich / case" block for static
    1207              :     // dispatch. It works on a faux-virtual class "CLASS" that must 
    1208              :     // contain a tuple of "obj" with each "obj" being a derived type.
    1209              :     // Recursion is used to unroll the list, identify the correct class
    1210              :     // based on "name/type", set the "selected" index, then call the
    1211              :     // appropriate class' Parse function.
    1212              :     // 
    1213              :     // This is only for use by the "select" functions.
    1214              :     // 
    1215              :     template <typename CLASS, int N, typename... OBJ>
    1216            4 :     void static_polymorphism_parser(CLASS& value)
    1217              :     {
    1218              :         if constexpr (N == 0)
    1219              :         {
    1220            3 :             std::string type;
    1221            6 :             query_default("type",type,value.names[0]);
    1222              : 
    1223           12 :             for (unsigned int i = 0; i < sizeof...(OBJ); i++)
    1224            9 :                 if (type == value.names[i])
    1225            3 :                     value.selected = i;
    1226              : 
    1227            3 :             if (value.selected < 0)
    1228            0 :                 Util::ParmParseException(INFO,getPrefix(),
    1229              :                                 "Error reading " + getPrefix() + 
    1230              :                                 ", invalid type " + type);
    1231              : 
    1232              :             
    1233            3 :             pushPrefix(type);
    1234            3 :         }
    1235              : 
    1236              :         if constexpr (N < sizeof...(OBJ))
    1237              :         {
    1238            4 :             if (value.selected == N)
    1239              :             {
    1240            3 :                 std::get<N>(value.obj).Parse(std::get<N>(value.obj), *this);
    1241            3 :                 popPrefix();
    1242            3 :                 return;
    1243              :             }
    1244              :             else 
    1245            1 :                 return static_polymorphism_parser<CLASS, N+1, OBJ...>(value);
    1246              :         }
    1247            0 :         else Util::Abort(INFO);
    1248            0 :     }
    1249              : 
    1250              : public:
    1251              : 
    1252              :     template <int N>
    1253           20 :     void query_exactly( std::vector<std::string> names, std::pair<std::string, Set::Scalar> values[N],
    1254              :                         std::vector<Unit> units = std::vector<Unit>())
    1255              :     {
    1256              :         try
    1257              :         {
    1258          140 :             Util::AssertException(  INFO,TEST(units.size() == 0 || units.size() == names.size()),
    1259           20 :                                     "# of units must be 0, 1, or ", names.size(), " but got ", units.size());
    1260              : 
    1261           20 :             int cnt = 0;
    1262           20 :             std::vector<std::string> read;
    1263          117 :             for (unsigned int n = 0; n < names.size(); n++)
    1264              :             {
    1265           97 :                 if (amrex::ParmParse::contains(names[n].c_str()))
    1266              :                 {
    1267           40 :                     read.push_back(names[n]);
    1268           40 :                     cnt++;
    1269              :                 }
    1270              :             }
    1271          180 :             Util::AssertException(  INFO, TEST(cnt == N),
    1272              :                                     " Incorrect number of values specified: only ", N,
    1273              :                                     " values are allowed, but received ",
    1274              :                                     Util::String::Join(read,", "));
    1275              : 
    1276              : 
    1277           20 :             cnt = 0;
    1278          117 :             for (unsigned int n = 0; n < names.size(); n++)
    1279              :             {
    1280           97 :                 if (amrex::ParmParse::contains(names[n].c_str()))
    1281              :                 {
    1282           40 :                     values[cnt].first = names[n];
    1283              : 
    1284           40 :                     if (units.size() == 0)
    1285           34 :                         query_required(names[n],values[cnt].second);
    1286            6 :                     else if (units.size() == 1)
    1287            0 :                         query_required(names[n],values[cnt].second,units[0]);
    1288              :                     else
    1289            6 :                         query_required(names[n],values[cnt].second,units[n]);
    1290           40 :                     cnt++;
    1291              :                 }
    1292              :             }
    1293           20 :         }
    1294            0 :         catch(...)
    1295              :         {
    1296            0 :             std::string names_str = "[";
    1297            0 :             for (unsigned int i = 0; i < names.size(); i++)
    1298              :             {
    1299            0 :                 names_str += full(names[i]);
    1300            0 :                 if (i < names.size()-1) names_str += ", ";
    1301              :             }
    1302            0 :             names_str += "]";
    1303            0 :             Util::ParmParseException(INFO,names_str);
    1304            0 :         }
    1305           20 :     }
    1306              : 
    1307              : 
    1308              : 
    1309              : 
    1310              : };
    1311              : }
    1312              : #endif
        

Generated by: LCOV version 2.0-1