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