LCOV - code coverage report
Current view: top level - src/IO - ParmParse.H (source / functions) Coverage Total Hit
Test: coverage_merged.info Lines: 72.7 % 326 237
Test Date: 2025-06-26 20:08:28 Functions: 65.9 % 185 122

            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              : 
      94              : #include "Util/Util.H"
      95              : #include "Set/Set.H"
      96              : #include "AMReX_ParmParse.H"
      97              : 
      98              : 
      99              : #define pp_query_required(...) pp.query_required(__VA_ARGS__,INFO)
     100              : #define pp_query_default(...) pp.query_default(__VA_ARGS__,INFO)
     101              : #define pp_query_validate(...) pp.query_validate(__VA_ARGS__,INFO)
     102              : #define pp_query_file(...) pp.query_file(__VA_ARGS__,INFO)
     103              : #define pp_queryarr(...) pp.queryarr(__VA_ARGS__,INFO)
     104              : #define pp_queryarr_required(...) pp.queryarr_required(__VA_ARGS__,INFO)
     105              : #define pp_queryarr_default(...) pp.queryarr_default(__VA_ARGS__,INFO)
     106              : #define pp_query(...) pp.query(__VA_ARGS__)
     107              : #define pp_queryclass(...) pp.queryclass(__VA_ARGS__,INFO)
     108              : #define pp_forbid(...) pp.forbid(__VA_ARGS__,INFO)
     109              : 
     110              : 
     111              : namespace IO
     112              : {
     113              : class ParmParse : public amrex::ParmParse
     114              : {
     115              : private:
     116          917 :     void Define() 
     117              :     {
     118          917 :         if (checked_for_input_files) return;
     119           38 :         int k = 0;
     120           38 :         std::string inputfile = "";
     121           38 :         while (this->querykth("input",k,inputfile)) 
     122              :         {
     123            0 :             Util::Message(INFO,"Including inputs from "+inputfile);
     124            0 :             this->addfile(inputfile);
     125            0 :             k++;
     126              :         }
     127           38 :         checked_for_input_files = true;
     128           38 :     }
     129              :     static bool checked_for_input_files;
     130              :     
     131              : public:
     132          648 :     ParmParse(std::string arg) : amrex::ParmParse::ParmParse(arg) {Define();} ;
     133          269 :     ParmParse() : amrex::ParmParse::ParmParse() {Define();} ;
     134         8216 :     std::string getPrefix() const {return m_prefix;};
     135          396 :     void ignore(std::string name)
     136              :     {
     137          396 :         (void)amrex::ParmParse::contains(name.c_str());
     138          396 :     }
     139              :     
     140            6 :     void pushPrefix(const std::string prefix)
     141              :     {
     142            6 :         if (m_prefix.length())
     143            3 :             m_prefix = m_prefix + "." + prefix;
     144              :         else
     145            3 :             m_prefix = prefix;
     146            6 :     }
     147              : 
     148            6 :     void popPrefix()
     149              :     {
     150            6 :         size_t pos = m_prefix.rfind('.');
     151            6 :         if (pos == std::string::npos)
     152            3 :             m_prefix = "";
     153              :         else
     154            3 :             m_prefix = m_prefix.substr(0, pos);
     155            6 :     }
     156              : 
     157              : 
     158          275 :     void forbid(std::string name, std::string explanation,
     159              :                 std::string file = "", std::string func = "", int line = -1)
     160              :     {
     161          275 :         if (amrex::ParmParse::contains(full(name).c_str()))
     162              :         {
     163            0 :             Util::ParmParseException(INFO,file,func,line,full(name),full(name)," forbidden: ", explanation);
     164              :         }
     165          275 :         std::set<std::string> subs = amrex::ParmParse::getEntries(full(name));
     166          275 :         if (subs.size())
     167              :         {
     168            0 :             Util::ParmParseException(INFO,file,func,line,full(name),full(name)," forbidden: ", explanation);
     169              :         }
     170          275 :     }
     171              : 
     172         2738 :     bool contains(std::string name)
     173              :     {
     174         2738 :         if (amrex::ParmParse::contains(name.c_str()))
     175         1049 :             return true;
     176         1689 :         if (amrex::ParmParse::contains(full(name).c_str()))
     177            0 :             return true;
     178              :         {
     179         1689 :             std::set<std::string> subs = amrex::ParmParse::getEntries(name.c_str());
     180         1689 :             if (subs.size())
     181           52 :                 return true;
     182         1689 :         }
     183              :         {
     184         1637 :             std::set<std::string> subs = amrex::ParmParse::getEntries(full(name).c_str());
     185         1637 :             if (subs.size())
     186            0 :                 return true;
     187         1637 :         }
     188         1637 :         return false;
     189              :     }
     190              : 
     191              :     template<typename T> 
     192          264 :     int query_required( std::string name, T & value,
     193              :                         std::string file = "", std::string func = "", int line = -1)
     194              :     {
     195          528 :         if (!contains(name.c_str()))
     196              :         {
     197            0 :             Util::ParmParseException(INFO,file,func,line,full(name),"required value for ",full(name)," missing");
     198              :         }
     199          264 :         return query(name.c_str(),value);
     200              :     }
     201              : 
     202              :     template<typename T>
     203         1302 :     int query_default(  std::string name, T & value, T defaultvalue,
     204              :                         std::string = "", std::string = "", int = -1)
     205              :     {
     206         2604 :         if (!contains(name.c_str()))
     207              :         {
     208         1015 :             add(name.c_str(),defaultvalue);
     209              :         }
     210         1302 :         return query(name.c_str(),value);
     211              :     } 
     212              : 
     213            1 :     int query_validate( std::string name, int & value, std::vector<int> possibleintvals,
     214              :                         std::string file = "", std::string func = "", int line = -1)
     215              :     {
     216              :         // First value is accepted by default...
     217              : 
     218              :         // set default value
     219            1 :         value = possibleintvals[0];
     220              : 
     221              :         // get the read value (if it exists)
     222            1 :         int retval = query(name.c_str(),value);
     223              : 
     224              :         // check to make sure the read value matches one of the inpus
     225            1 :         bool ok = false;
     226            4 :         for (unsigned int i = 0; i < possibleintvals.size(); i++)
     227              :         {
     228            3 :             if (value == possibleintvals[i]) ok = true;
     229              :         }
     230              : 
     231            1 :         if (ok) return retval;
     232              : 
     233            0 :         std::stringstream ss;
     234            0 :         ss << possibleintvals[0];
     235            0 :         for (unsigned int i = 1; i < possibleintvals.size(); i++)
     236            0 :             ss << "," << possibleintvals[i];
     237              : 
     238            0 :         Util::ParmParseException(INFO,file,func,line,full(name),"' expected [", ss.str(), "] but got ", value);
     239              : 
     240            0 :         return -1;
     241            0 :     }
     242              : 
     243              : 
     244           94 :     int query_validate( std::string name, std::string & value, std::vector<const char *> possiblecharvals, bool firstbydefault,
     245              :                         std::string file = "", std::string func = "", int line = -1)
     246              :     {        
     247              :         // if not using default values, then the input must be specified
     248           94 :         if (!firstbydefault)
     249              :         {
     250            0 :             if (!contains(name.c_str()))
     251              :             {
     252            0 :                 Util::ParmParseException(INFO,file,func,line,full(name),"required value for ",full(name)," missing");
     253              :             }
     254              :         }
     255              : 
     256              :         // set default value
     257           94 :         value = std::string(possiblecharvals[0]);
     258              : 
     259              :         // get the read value (if it exists)
     260           94 :         int retval = query(name.c_str(),value);
     261              : 
     262              :         // check to make sure the read value matches one of the inpus
     263           94 :         bool ok = false;
     264          370 :         for (unsigned int i = 0; i < possiblecharvals.size(); i++)
     265              :         {
     266          552 :             if (value == std::string(possiblecharvals[i])) ok = true;
     267              :         }
     268              :         
     269           94 :         if (ok) return retval;
     270              : 
     271            0 :         std::stringstream ss;
     272            0 :         ss << possiblecharvals[0];
     273            0 :         for (unsigned int i = 1; i < possiblecharvals.size(); i++)
     274            0 :             ss << "," << possiblecharvals[i];
     275              : 
     276            0 :         Util::ParmParseException(INFO,file,func,line,full(name),"' expected [", ss.str(), "] but got ", value);
     277              : 
     278            0 :         return -1;
     279            0 :     }
     280              : 
     281           94 :     int query_validate( std::string name, std::string & value, std::vector<const char *> possiblecharvals,
     282              :                         std::string file = "", std::string func = "", int line = -1)
     283              :     {
     284           94 :         return query_validate(name,value,possiblecharvals,true,file,func,line);
     285              :     }
     286              : 
     287              :     
     288              :     // special case for strings
     289          163 :     int query_default(  std::string name, std::string & value, const char *defaultvalue,
     290              :                         std::string file = "", std::string func = "", int line = -1)
     291              :     {
     292          489 :         return query_default(name, value, std::string(defaultvalue), file, func, line);
     293              :     }
     294              :     // special case for bools
     295           61 :     int query_default(  std::string name, int & value, bool defaultvalue,
     296              :                         std::string file = "", std::string func = "query_default", int line = -1)
     297              :     {
     298           61 :         int defaultint = 0;
     299           61 :         if (defaultvalue) defaultint = 1;
     300           61 :         return query_default(name, value, defaultint, file, func, line);
     301              :     }
     302              : 
     303              : 
     304              : 
     305              :     // validate filenames
     306            1 :     int query_file( std::string name, std::string & value, bool copyfile, bool checkfile,
     307              :                     std::string file = "", std::string func = "query_file", int line = -1)
     308              :     {
     309              :         try
     310              :         {
     311            2 :             if (!contains(name.c_str()))
     312              :             {
     313            0 :                 Util::ParmParseException(INFO,file,func,line,full(name),full(name)," must be specified");
     314              :             }
     315              : 
     316            1 :             int retval = query(name.c_str(),value);
     317              : 
     318            1 :             if (amrex::ParallelDescriptor::IOProcessor())
     319              :             {
     320            1 :                 if ( checkfile && ! std::filesystem::exists(value))
     321              :                 {
     322            0 :                     Util::ParmParseException(INFO,file,func,line,full(name),full(name)," does not exist");
     323              :                 }
     324            1 :                 if ( checkfile && !std::filesystem::is_regular_file(value))
     325              :                 {
     326            0 :                     Util::ParmParseException(INFO,file,func,line,full(name),full(name)," is not a regular file");
     327              :                 }
     328            1 :                 if ( copyfile )
     329              :                 {
     330            1 :                     Util::CopyFileToOutputDir(value, true, full(name));
     331              :                 }
     332              :             }
     333            1 :             return retval;
     334              :         }
     335            0 :         catch (...)
     336              :         {
     337            0 :             Util::ParmParseException(INFO,file,func,line,full(name));
     338            0 :         }
     339            0 :         return -1;
     340              :     }
     341              :     int query_file( std::string name, std::string & value, bool copyfile, 
     342              :                     std::string file = "", std::string func = "query_file", int line = -1)
     343              :     {
     344              :         return query_file(name,value,copyfile,true,file,func,line);
     345              :     }
     346            1 :     int query_file( std::string name, std::string & value, 
     347              :                     std::string file = "", std::string func = "query_file", int line = -1)
     348              :     {
     349            1 :         return query_file(name,value,true,true,file,func,line);
     350              :     }
     351              : 
     352              : 
     353              :     template<typename T>
     354          180 :     int queryarr(   std::string name, std::vector<T> & value,
     355              :                     std::string /*file*/, std::string /*func*/, int /*line*/)
     356              :     {
     357          180 :         return amrex::ParmParse::queryarr(name.c_str(),value);
     358              :     }
     359            9 :     int queryarr(   std::string name, Set::Vector & value,
     360              :                     std::string file = "", std::string func = "queryarr", int line = -1)
     361              :     {
     362            9 :         std::vector<Set::Scalar> vals;
     363            9 :         amrex::ParmParse::queryarr(name.c_str(), vals);
     364            9 :         if (vals.size() < AMREX_SPACEDIM) 
     365              :         {
     366            0 :             Util::ParmParseException(INFO,file,func,line,full(name),full(name)," requires at least ", AMREX_SPACEDIM, " arguments, got ",vals.size());
     367              :         }
     368           28 :         for (int i = 0; i < AMREX_SPACEDIM; i++) value(i) = vals[i];
     369            9 :         return 0;
     370            9 :     }
     371            6 :     int queryarr(   std::string name, Set::Matrix & value,
     372              :                     std::string file = "", std::string func = "queryarr", int line = -1)
     373              :     {
     374            6 :         std::vector<Set::Scalar> vals;
     375            6 :         amrex::ParmParse::queryarr(name.c_str(), vals);
     376            6 :         if (vals.size() == 9)
     377              :         {
     378              : #if AMREX_SPACEDIM==2
     379            4 :             Util::Warning(file,func,line,"Reading a 3D matrix (",full(name),")into a 2D code - some values will be ignored.");
     380            4 :             value(0,0) = vals[0];  value(0,1)= vals[1];
     381            4 :             value(1,0) = vals[3];  value(1,1)= vals[4];
     382              : #endif
     383              : #if AMREX_SPACEDIM==3
     384            2 :             value(0,0) = vals[0];  value(0,1)= vals[1];  value(0,2)= vals[2];
     385            2 :             value(1,0) = vals[3];  value(1,1)= vals[4];  value(1,2)= vals[5];
     386            2 :             value(2,0) = vals[6];  value(2,1)= vals[7];  value(2,2)= vals[8];
     387              : #endif
     388              :         }
     389            0 :         else if (vals.size() == 4)
     390              :         {
     391              : #if AMREX_SPACEDIM==2
     392            0 :             value(0,0) = vals[0];  value(0,1)= vals[1];
     393            0 :             value(1,0) = vals[2];  value(1,1)= vals[3];
     394              : #endif
     395              : #if AMREX_SPACEDIM==3
     396            0 :             Util::Warning(file,func,line,"Reading a 2D matrix (",full(name),")into a 3D code - remaining values will be set to zero.");
     397            0 :             value(0,0) = vals[0];  value(0,1)= vals[1];  value(0,2)= 0.0;
     398            0 :             value(1,0) = vals[2];  value(1,1)= vals[3];  value(1,2)= 0.0;
     399            0 :             value(2,0) = 0.0;      value(2,1)= 0.0;      value(2,2)= 0.0;
     400              : #endif
     401              :         }
     402              :         else
     403              :         {
     404            0 :             Util::ParmParseException(INFO,file,func,line,full(name),full(name)," needs either 4 or 9 components, but got ",vals.size());
     405              :         }    
     406            6 :         return 0;
     407            6 :     }
     408              :     template<typename T>
     409           47 :     int queryarr_required(  std::string name, std::vector<T> & value,
     410              :                             std::string file, std::string func, int line)
     411              :     {
     412           94 :         if (!contains(name.c_str()))
     413              :         {
     414            0 :             Util::ParmParseException(INFO,file,func,line,full(name),"required value for ",full(name)," missing");
     415              :         }        
     416           47 :         return queryarr(name,value,file,func,line);
     417              :     }
     418              : 
     419              : 
     420          456 :     int queryarr_default(   std::string name, std::vector<std::string> & value, std::string defaultvalue,
     421              :                             std::string = "", std::string = "", int = -1)
     422              :     {
     423          912 :         if (!contains(name.c_str()))
     424              :         {
     425          224 :             add(name.c_str(),defaultvalue);
     426              :         }
     427          456 :         return queryarr(name.c_str(),value);
     428              :     }
     429              : 
     430              :     
     431              : 
     432              :     template <typename T>
     433              :     int
     434           18 :     queryclass_enumerate(std::string a_name, std::vector<T> &value, int number = 1,
     435              :                             std::string file = "", std::string func = "", int line = __LINE__)
     436              :     {
     437           18 :         value.clear();
     438              : 
     439              :         //
     440              :         // If only one is present with no subscript, then read
     441              :         // it only and return.
     442              :         //
     443           18 :         std::string name = a_name;
     444           18 :         if (this->contains(name))
     445              :         {
     446            8 :             for (int n = 0; n < number; n++)
     447              :             {
     448            4 :                 T tmp;
     449            4 :                 this->queryclass<T>(name, tmp, file, func, line);
     450            4 :                 value.push_back(tmp);
     451              :             }
     452            4 :             return 0;
     453              :         }
     454              : 
     455              :         //
     456              :         // Some logic to determine whether we are starting with zero
     457              :         // (model0, model1, model2, ...)
     458              :         // or one
     459              :         // (model1, model2, model3, ...)
     460              :         // since both are supported
     461              :         //
     462           14 :         int start = -1;
     463           14 :         std::string name0 = a_name + std::to_string(0);
     464           14 :         std::string name1 = a_name + std::to_string(1);
     465           28 :         if (this->contains(name0.c_str()))
     466              :         {
     467            0 :             start = 0;
     468            0 :             name = name0;
     469              :         }
     470           28 :         else if (this->contains(name1.c_str()))
     471              :         {
     472           14 :             start = 1;
     473           14 :             name = name1;
     474              :         }
     475              :         else
     476              :         {
     477            0 :             Util::Exception(INFO,"Enumerations must begin with 0 or 1");
     478              :         }
     479              : 
     480              :         //
     481              :         // Iterate over items called (model0), model1, model2, etc
     482              :         // until no more are found then exit. 
     483              :         //
     484           76 :         for (int cntr = start; this->contains(name.c_str()); cntr++)
     485              :         {
     486           34 :             if (this->contains(name.c_str()))
     487              :             {
     488           17 :                 T tmp;
     489           17 :                 this->queryclass<T>(name, tmp, file, func, line);
     490           17 :                 value.push_back(tmp);
     491           17 :             }
     492           17 :             name = a_name + std::to_string(cntr+1);
     493              :         }
     494              : 
     495           14 :         return 0;
     496           18 :     }
     497              : 
     498              : 
     499              :     template <typename T>
     500              :     int
     501           22 :     query_enumerate(std::string a_name, std::vector<T> &value, int number = 1,
     502              :                     std::string file = "", std::string func = "", int line = __LINE__)
     503              :     {
     504           22 :         value.clear();
     505              : 
     506              :         //
     507              :         // If only one is present with no subscript, then read
     508              :         // it only and return.
     509              :         //
     510           22 :         std::string name = a_name;
     511           22 :         if (this->contains(name))
     512              :         {
     513            0 :             for (int n = 0; n < number; n++)
     514              :             {
     515            0 :                 T tmp;
     516            0 :                 this->query_required(name, tmp, file, func, line);
     517            0 :                 value.push_back(tmp);
     518              :             }
     519            0 :             return 0;
     520              :         }
     521              : 
     522              :         //
     523              :         // Some logic to determine whether we are starting with zero
     524              :         // (model0, model1, model2, ...)
     525              :         // or one
     526              :         // (model1, model2, model3, ...)
     527              :         // since both are supported
     528              :         //
     529           22 :         int start = -1;
     530           22 :         std::string name0 = a_name + std::to_string(0);
     531           22 :         std::string name1 = a_name + std::to_string(1);
     532           44 :         if (this->contains(name0.c_str()))
     533              :         {
     534           22 :             start = 0;
     535           22 :             name = name0;
     536              :         }
     537            0 :         else if (this->contains(name1.c_str()))
     538              :         {
     539            0 :             start = 1;
     540            0 :             name = name1;
     541              :         }
     542              :         else
     543              :         {
     544            0 :             Util::Exception(INFO,"Enumerations must begin with 0 or 1");
     545              :         }
     546              : 
     547              :         //
     548              :         // Iterate over items called (model0), model1, model2, etc
     549              :         // until no more are found then exit. 
     550              :         //
     551          124 :         for (int cntr = start; this->contains(name.c_str()); cntr++)
     552              :         {
     553           58 :             if (this->contains(name.c_str()))
     554              :             {
     555           29 :                 T tmp;
     556           29 :                 this->query_required(name, tmp, file, func, line);
     557           29 :                 value.push_back(tmp);
     558           29 :             }
     559           29 :             name = a_name + std::to_string(cntr+1);
     560              :         }
     561              : 
     562           22 :         return 0;
     563           22 :     }
     564              : 
     565              : 
     566              : 
     567            9 :     int AnyUnusedInputs(bool inscopeonly = true, bool verbose = false)
     568              :     {
     569            9 :         int cnt = 0;
     570         1390 :         for (auto li = m_table->begin(), End = m_table->end(); li != End; ++li)
     571              :         {
     572         1381 :                 if (!li->second.m_count)
     573              :                 {
     574            0 :                     if (inscopeonly && getPrefix() != "")
     575              :                     {
     576            0 :                         if (li->first.rfind(getPrefix()+".",0) != std::string::npos)
     577              :                         {
     578            0 :                             if (verbose) Util::Warning(INFO,li->first);
     579            0 :                             cnt++;
     580              :                         }
     581              :                     }
     582              :                     else
     583              :                     {
     584            0 :                         if (verbose) Util::Warning(INFO,li->first);
     585            0 :                         cnt++;
     586              :                     }
     587              :                 }
     588              :         }
     589            9 :         return cnt;
     590              :     }
     591              : 
     592          199 :     std::vector<std::string> GetUnusedInputs()
     593              :     {
     594          199 :         std::vector<std::string> ret;
     595        25197 :         for (auto li = m_table->begin(), End = m_table->end(); li != End; ++li)
     596              :         {
     597        24998 :             if (!li->second.m_count && li->first.rfind(getPrefix()+".",0) != std::string::npos)
     598              :             {
     599            0 :                 ret.push_back(li->first);
     600              :             }
     601              :         }
     602          199 :         return ret;
     603            0 :     }
     604              : 
     605            0 :     static int AllUnusedInputs()
     606              :     {
     607            0 :         ParmParse pp;
     608            0 :         int cnt = 0;
     609            0 :         for (auto li = pp.m_table->begin(), End = pp.m_table->end(); li != End; ++li)
     610              :         {
     611            0 :             if (!li->second.m_count)
     612              :             {
     613            0 :                 Util::Warning(INFO,li->first);
     614            0 :                 cnt++;
     615              :             }
     616              :         }
     617            0 :         return cnt;
     618            0 :     }
     619            0 :     std::string prefix ()
     620              :     {
     621            0 :         return getPrefix();
     622              :     }
     623         3881 :     std::string full (std::string name)
     624              :     {
     625         3881 :         std::string prefix = getPrefix();
     626         3881 :         if (prefix != "") return getPrefix() + "." + name;
     627         1854 :         else return name;
     628         3881 :     }
     629              : 
     630              : 
     631              :     using amrex::ParmParse::queryarr;
     632              :     template<class T>
     633              :     void queryclass(std::string name, T * value,
     634              :                     std::string file = "", std::string func = "", int line = -1)
     635              :     {
     636              :         auto old_prefix = m_prefix;
     637              :         try
     638              :         {
     639              :             if (old_prefix.empty()) m_prefix = name;
     640              :             else m_prefix.append(".").append(name);
     641              :             T::Parse(*value, *this);
     642              :             std::vector<std::string> unused_inputs = GetUnusedInputs();
     643              :             if (unused_inputs.size())
     644              :             {
     645              :                 std::stringstream ss;
     646              :                 for (unsigned int i=0; i < unused_inputs.size(); i++)
     647              :                     ss << "\n\t" << unused_inputs[i];
     648              :                 Util::ParmParseException(INFO,file,func,line,name,"The following inputs were specified but not used",ss.str());
     649              :             }
     650              :         }
     651              :         catch (...)
     652              :         {
     653              :             m_prefix = old_prefix;
     654              :             Util::ParmParseException(INFO,file,func,line,full(name));
     655              :         }
     656              :         m_prefix = old_prefix;
     657              :     }
     658              :     template<class T>
     659          199 :     void queryclass(std::string name, T & value,
     660              :                     std::string file = "", std::string func = "", int line = __LINE__)
     661              :     {
     662          199 :         auto old_prefix = m_prefix;
     663              :         try
     664              :         {
     665          199 :             if (old_prefix.empty()) m_prefix = name;
     666            0 :             else m_prefix.append(".").append(name);
     667          199 :             T::Parse(value, *this);
     668          199 :             std::vector<std::string> unused_inputs = GetUnusedInputs();
     669          199 :             if (unused_inputs.size())
     670              :             {
     671            0 :                 std::stringstream ss;
     672            0 :                 for (unsigned int i=0; i < unused_inputs.size(); i++)
     673            0 :                     ss << "\n\t" << unused_inputs[i];
     674            0 :                 Util::ParmParseException(INFO,file,func,line,name,"The following inputs were specified but not used",ss.str());
     675            0 :             }
     676          199 :         }
     677            0 :         catch (...)
     678              :         {
     679            0 :             m_prefix = old_prefix;
     680            0 :             Util::ParmParseException(INFO,file,func,line,full(name));
     681              :         }
     682          199 :         m_prefix = old_prefix;
     683          199 :     }
     684              : 
     685              :     template<class T>
     686              :     void queryclass(T * value,
     687              :                     std::string file = "", std::string func = "", int line = __LINE__)
     688              :     {
     689              :         try
     690              :         {
     691              :             T::Parse(*value, *this);
     692              :         }
     693              :         catch (...)
     694              :         {
     695              :             Util::ParmParseException(INFO,file,func,line,getPrefix());
     696              :         }
     697              :     }
     698              :     template<class T>
     699          459 :     void queryclass(T & value,
     700              :                     std::string file = "", std::string func = "", int line = __LINE__)
     701              :     {
     702              :         try
     703              :         {
     704          459 :             T::Parse(value, *this);
     705              :         }
     706            0 :         catch (...)
     707              :         {
     708            0 :             Util::ParmParseException(INFO,file,func,line,getPrefix());
     709              :         }
     710          459 :     }
     711              : 
     712              :     //
     713              :     // Variadic template parsing operator to assign a pointer to
     714              :     // one of a set of possible class objects, then call that method's
     715              :     // Parse function.
     716              :     //
     717              :     // If there is more than one instantiating class, then type must be set.
     718              :     // Otherwise, no type is necessary.
     719              :     //
     720              :     template<typename... IC, typename... Args, typename PTRTYPE>
     721           44 :     void select (std::string name, PTRTYPE *& ic_eta, Args&&... args)
     722              :     {
     723              :         // if there is only one IC arg provided, we don't need to check the type - assume that
     724              :         // it is the default.
     725              :         if constexpr (sizeof...(IC) == 0)
     726              :         {
     727              :             using first_IC = std::tuple_element_t<0, std::tuple<IC...>>;
     728              :             ic_eta = new first_IC(std::forward<Args>(args)..., (*this), name + "." + std::string(first_IC::name));
     729              :         }
     730              :         // otherwise, check the type.
     731              :         else
     732              :         {
     733           88 :             std::string type = "";
     734          132 :             this->query_required(name + ".type", type);
     735           48 :             bool matched = ((   type == IC::name 
     736          157 :                                 ? (ic_eta = new IC(std::forward<Args>(args)..., (*this), name + "." + std::string(IC::name))),
     737              :                                 true
     738          114 :                                 : false) || ...);
     739           44 :             if (!matched)
     740            0 :                 Util::Exception(INFO, type, " not a valid type for ", name);
     741           44 :         }
     742           44 :     }
     743              : 
     744              :     //
     745              :     // Identical to the above, except sets the type automatically to the
     746              :     // firs specified 
     747              :     //
     748              :     template<typename FirstIC, typename... IC, typename... Args, typename PTRTYPE>
     749          106 :     void select_default (std::string name, PTRTYPE *& ic_eta, Args&&... args)
     750              :     {
     751          212 :         std::string type = "";
     752              : 
     753          318 :         this->query_default(name + ".type", type, FirstIC::name);
     754              : 
     755            0 :         bool matched =
     756          212 :             ((  type == FirstIC::name 
     757          266 :                 ? (ic_eta = new FirstIC(std::forward<Args>(args)..., (*this), name + "." + std::string(FirstIC::name))),
     758              :                 true : false))
     759          212 :             || 
     760           26 :             ((  type == IC::name 
     761          180 :                 ? (ic_eta = new IC(std::forward<Args>(args)..., (*this), name + "." + std::string(IC::name))),
     762              :                 true : false) || ...);
     763              : 
     764              : 
     765          106 :         if (!matched)
     766            0 :             Util::Exception(INFO,type," not a valid type for ",name);
     767          106 :     }
     768              : 
     769              : 
     770              :     //
     771              :     //
     772              :     template<typename... IC, typename... Args, typename PTRTYPE>
     773              :     void select_enumerate (std::string a_name, std::vector<PTRTYPE*> & value, Args&&... args)
     774              :     {
     775              : 
     776              :         value.clear();
     777              : 
     778              :         //
     779              :         // If only one is present with no subscript, then read
     780              :         // it only and return.
     781              :         //
     782              :         std::string name = a_name;
     783              :         if (this->contains(name))
     784              :         {
     785              :             PTRTYPE *tmp;
     786              :             this->select<IC...>(a_name, tmp, args...);
     787              :             value.push_back(tmp);
     788              :             return;
     789              :         }
     790              : 
     791              :         //
     792              :         // Some logic to determine whether we are starting with zero
     793              :         // (model0, model1, model2, ...)
     794              :         // or one
     795              :         // (model1, model2, model3, ...)
     796              :         // since both are supported
     797              :         //
     798              :         int start = -1;
     799              :         std::string name0 = a_name + std::to_string(0);
     800              :         std::string name1 = a_name + std::to_string(1);
     801              :         if (this->contains(name0.c_str()))
     802              :         {
     803              :             start = 0;
     804              :             name = name0;
     805              :         }
     806              :         else if (this->contains(name1.c_str()))
     807              :         {
     808              :             start = 1;
     809              :             name = name1;
     810              :         }
     811              :         else
     812              :         {
     813              :             Util::Exception(INFO,"Enumerations must begin with 0 or 1");
     814              :         }
     815              : 
     816              :         //
     817              :         // Iterate over items called (model0), model1, model2, etc
     818              :         // until no more are found then exit. 
     819              :         //
     820              :         for (int cntr = start; this->contains(name.c_str()); cntr++)
     821              :         {
     822              :             if (this->contains(name.c_str()))
     823              :             {
     824              :                 PTRTYPE *tmp;
     825              :                 this->select<IC...>(name, tmp, args...);
     826              :                 value.push_back(tmp);
     827              :             }
     828              :             name = a_name + std::to_string(cntr+1);
     829              :         }
     830              :     }
     831              : 
     832              : 
     833              : 
     834              :     //
     835              :     // Similar to select but specialized for main functions
     836              :     //
     837              :     template<typename... INTEGRATOR, typename... Args, typename PTRTYPE>
     838              :     void select_main (PTRTYPE *& ic_eta, Args&&... args)
     839              :     {
     840              :         std::string type = "";
     841              : 
     842              :         this->query_required("alamo.program", type);
     843              :         
     844              :         bool matched = ((type == INTEGRATOR::name 
     845              :                         ? (ic_eta = new INTEGRATOR(std::forward<Args>(args)..., (*this))),
     846              :                         true
     847              :                         : false) || ...);
     848              :         if (!matched)
     849              :             Util::Exception(INFO,type," not a valid type for ",type);
     850              :     }
     851              : 
     852              :     //
     853              :     // Similar to select_main but works for one function only
     854              :     // and doesn't require a type specifier.
     855              :     //
     856              : 
     857              :     // with variadic arguments
     858              :     template<typename INTEGRATOR, typename Args, typename PTRTYPE>
     859              :     void select_only (PTRTYPE *& ic_eta, Args&& args)
     860              :     {
     861              :         ic_eta = new INTEGRATOR(std::forward<Args>(args), (*this));
     862              :     }
     863              :     // without variadic arguments
     864              :     template<typename INTEGRATOR, typename PTRTYPE>
     865           36 :     void select_only (PTRTYPE *& ic_eta)
     866              :     {
     867           36 :         ic_eta = new INTEGRATOR((*this));
     868           36 :     }
     869              : 
     870              :     
     871              :     //
     872              :     // functionally simlar to other kinds of select, execpt works on
     873              :     // template-based static dispatch.
     874              :     //
     875              : 
     876              :     template <typename... OBJ, typename CLASS>
     877            3 :     void select(std::string name, CLASS& value)
     878              :     {
     879            3 :         pushPrefix(name);
     880            3 :         static_polymorphism_parser<CLASS, 0, OBJ...>(value);
     881            3 :         popPrefix();
     882            3 :     }
     883              : 
     884              : private:
     885              :     //
     886              :     // This function is a virtual "swtich / case" block for static
     887              :     // dispatch. It works on a faux-virtual class "CLASS" that must 
     888              :     // contain a tuple of "obj" with each "obj" being a derived type.
     889              :     // Recursion is used to unroll the list, identify the correct class
     890              :     // based on "name/type", set the "selected" index, then call the
     891              :     // appropriate class' Parse function.
     892              :     // 
     893              :     // This is only for use by the "select" functions.
     894              :     // 
     895              :     template <typename CLASS, int N, typename... OBJ>
     896            4 :     void static_polymorphism_parser(CLASS& value)
     897              :     {
     898              :         if constexpr (N == 0)
     899              :         {
     900            3 :             std::string type;
     901           15 :             query_default("type",type,value.names[0]);
     902              : 
     903           12 :             for (unsigned int i = 0; i < sizeof...(OBJ); i++)
     904            9 :                 if (type == value.names[i])
     905            3 :                     value.selected = i;
     906              : 
     907            3 :             if (value.selected < 0)
     908            0 :                 Util::Exception(INFO,
     909              :                                 "Error reading " + getPrefix() + 
     910              :                                 ", invalid type " + type);
     911              : 
     912              :             
     913            3 :             pushPrefix(type);
     914            3 :         }
     915              : 
     916              :         if constexpr (N < sizeof...(OBJ))
     917              :         {
     918            4 :             if (value.selected == N)
     919              :             {
     920            3 :                 std::get<N>(value.obj).Parse(std::get<N>(value.obj), *this);
     921            3 :                 popPrefix();
     922            3 :                 return;
     923              :             }
     924              :             else 
     925            1 :                 return static_polymorphism_parser<CLASS, N+1, OBJ...>(value);
     926              :         }
     927            0 :         else Util::Abort(INFO);
     928            0 :     }
     929              : 
     930              : public:
     931              : 
     932              :     template <int N>
     933           17 :     void query_exactly(std::vector<std::string> names, std::pair<std::string, Set::Scalar> values[N])
     934              :     {
     935           17 :         int cnt = 0;
     936           17 :         std::vector<std::string> read;
     937          102 :         for (unsigned int n = 0; n < names.size(); n++)
     938              :         {
     939           85 :             if (amrex::ParmParse::contains(names[n].c_str()))
     940              :             {
     941           34 :                 read.push_back(names[n]);
     942           34 :                 cnt++;
     943              :             }
     944              :         }
     945          136 :         Util::AssertException(  INFO, TEST(cnt == N), "incorrect number of values specified: only ", N,
     946              :                                 " values are allowed, but received ",Util::String::Join(read));
     947              : 
     948              : 
     949           17 :         cnt = 0;
     950          102 :         for (unsigned int n = 0; n < names.size(); n++)
     951              :         {
     952           85 :             if (amrex::ParmParse::contains(names[n].c_str()))
     953              :             {
     954           34 :                 values[cnt].first = names[n];
     955          102 :                 query_required(names[n],values[cnt].second);
     956           34 :                 cnt++;
     957              :             }
     958              :         }
     959           17 :     }
     960              : 
     961              : 
     962              : 
     963              : 
     964              : };
     965              : }
     966              : #endif
        

Generated by: LCOV version 2.0-1