Alamo
ParmParse.H
Go to the documentation of this file.
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
113namespace IO
114{
115class ParmParse : public amrex::ParmParse
116{
117private:
118 void Define()
119 {
120 if (checked_for_input_files) return;
121 int k = 0;
122 std::string inputfile = "";
123 while (this->querykth("input",k,inputfile))
124 {
125 Util::Message(INFO,"Including inputs from "+inputfile);
126 this->addfile(inputfile);
127 k++;
128 }
130 }
132
133public:
134 ParmParse(std::string arg) : amrex::ParmParse::ParmParse(arg) {Define();} ;
135 ParmParse() : amrex::ParmParse::ParmParse() {Define();} ;
136 std::string getPrefix() const {return m_prefix;};
137 void ignore(std::string name)
138 {
139 (void)amrex::ParmParse::contains(name.c_str());
140 }
141
142 void pushPrefix(const std::string prefix)
143 {
144 if (m_prefix.length())
145 m_prefix = m_prefix + "." + prefix;
146 else
147 m_prefix = prefix;
148 }
149
151 {
152 size_t pos = m_prefix.rfind('.');
153 if (pos == std::string::npos)
154 m_prefix = "";
155 else
156 m_prefix = m_prefix.substr(0, pos);
157 }
158
159
160 void forbid(std::string name, std::string explanation)
161 {
162 if (amrex::ParmParse::contains(full(name).c_str()))
163 {
164 Util::ParmParseException(INFO,full(name),full(name)," forbidden: ", explanation);
165 }
166 std::set<std::string> subs = amrex::ParmParse::getEntries(full(name));
167 if (subs.size())
168 {
169 Util::ParmParseException(INFO,full(name),full(name)," forbidden: ", explanation);
170 }
171 }
172
173 bool contains(std::string name)
174 {
175 if (amrex::ParmParse::contains(name.c_str()))
176 return true;
177 if (amrex::ParmParse::contains(full(name).c_str()))
178 return true;
179 {
180 std::set<std::string> subs = amrex::ParmParse::getEntries(name.c_str());
181 if (subs.size())
182 return true;
183 }
184 {
185 std::set<std::string> subs = amrex::ParmParse::getEntries(full(name).c_str());
186 if (subs.size())
187 return true;
188 }
189 return false;
190 }
191
192 int queryunit (std::string name, Unit &value)
193 {
194 try
195 {
196 std::string strvalue;
197 int retval = amrex::ParmParse::query(name.c_str(),strvalue);
198 value = Unit::Parse(strvalue);
199 Util::DebugMessage(INFO,full(name),": ",strvalue," ==> ",value);
200 return retval;
201 }
202 catch (std::runtime_error & e)
203 {
204 Util::ParmParseException(INFO,full(name), e.what());
205 }
206 catch (...)
207 {
209 }
210 return -1;
211 }
212
213 int queryunit (std::string name, Unit &value, const Unit type)
214 {
215 try
216 {
217 int retval = queryunit(name,value);
218 if (!value.isType(type) && !value.isType(Unit::Less()))
219 {
221 "value requiested had wrong units:", value.normalized_unitstring(),
222 ", units requested are of SI type ",type.normalized_unitstring());
223 }
224 return retval;
225 }
226 catch (...)
227 {
229 }
230 return -1;
231 }
232 int queryunit (std::string name, Set::Scalar &value, const Unit type)
233 {
234 try
235 {
236 Unit read;
237 int retval = queryunit(name,read,type);
238 value = read.normalized_value();
239 return retval;
240 }
241 catch (std::runtime_error &e)
242 {
243 Util::ParmParseException(INFO,full(name), e.what());
244 }
245 return -1;
246 }
247
248 template<typename T>
249 int query_required( std::string name, T & value)
250 {
251 try
252 {
253 if (!contains(name.c_str()))
254 {
255 Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
256 }
257 return query(name.c_str(),value);
258 }
259 catch (std::runtime_error & e)
260 {
261 Util::ParmParseException(INFO,full(name),e.what());
262 }
263 catch (...)
264 {
266 }
267 return -1;
268 }
269
270 template<typename T>
271 int query_required( std::string name, T & value, const Unit type)
272 {
273 try
274 {
275 if (!contains(name.c_str()))
276 {
277 Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
278 }
279 return queryunit(name.c_str(), value, type);
280 }
281 catch (std::runtime_error & e)
282 {
283 Util::ParmParseException(INFO,full(name),e.what());
284 }
285 catch (...)
286 {
288 }
289 return -1;
290 }
291
292 template<typename T>
293 int query_default( std::string name, T & value, T defaultvalue)
294 {
295 try
296 {
297 if (!contains(name.c_str()))
298 {
299 add(name.c_str(),defaultvalue);
300 }
301 return query(name.c_str(),value);
302 }
303 catch (std::runtime_error & e)
304 {
305 Util::ParmParseException(INFO,full(name),e.what());
306 }
307 catch (...)
308 {
310 }
311 return -1;
312 }
313
314 template<typename T>
315 int query_default( std::string name, T & value, std::string defaultvalue, const Unit type)
316 {
317 try
318 {
319 if (!contains(name.c_str()))
320 {
321 add(name.c_str(),defaultvalue);
322 }
323 return queryunit(name.c_str(),value,type);
324 }
325 catch (std::runtime_error & e)
326 {
327 Util::ParmParseException(INFO,full(name),e.what());
328 }
329 catch (...)
330 {
332 }
333 return -1;
334 }
335
336 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 if (!contains(name.c_str()))
344 {
345 add(name.c_str(), possibleintvals[0]);
346 }
347
348 // get the read value (if it exists)
349 int retval = query(name.c_str(),value);
350
351 // check to make sure the read value matches one of the inpus
352 bool ok = false;
353 for (unsigned int i = 0; i < possibleintvals.size(); i++)
354 {
355 if (value == possibleintvals[i]) ok = true;
356 }
357
358 if (ok) return retval;
359
360 std::stringstream ss;
361 ss << possibleintvals[0];
362 for (unsigned int i = 1; i < possibleintvals.size(); i++)
363 ss << "," << possibleintvals[i];
364
365 Util::ParmParseException(INFO,full(name),"' expected [", ss.str(), "] but got ", value);
366 }
367 catch (std::runtime_error & e)
368 {
369 Util::ParmParseException(INFO,full(name),e.what());
370 }
371 catch (...)
372 {
374 }
375 return -1;
376 }
377
378
379 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 if (!firstbydefault)
385 {
386 if (!amrex::ParmParse::contains(name.c_str()))
387 {
388 Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
389 }
390 }
391
392 // set default value
393 if (!amrex::ParmParse::contains(name.c_str()))
394 {
395 add(name.c_str(), std::string(possiblecharvals[0]));
396 }
397
398 // get the read value (if it exists)
399 int retval = amrex::ParmParse::query(name.c_str(),value);
400
401 // check to make sure the read value matches one of the inpus
402 bool ok = false;
403 for (unsigned int i = 0; i < possiblecharvals.size(); i++)
404 {
405 if (value == std::string(possiblecharvals[i])) ok = true;
406 }
407
408 if (ok) return retval;
409
410 std::stringstream ss;
411 ss << possiblecharvals[0];
412 for (unsigned int i = 1; i < possiblecharvals.size(); i++)
413 ss << "," << possiblecharvals[i];
414
415 Util::ParmParseException(INFO,full(name),"' expected [", ss.str(), "] but got ", value);
416 }
417 catch (std::runtime_error & e)
418 {
419 Util::ParmParseException(INFO,full(name),e.what());
420 }
421 catch (...)
422 {
424 }
425
426 return -1;
427 }
428
429 int query_validate( std::string name, std::string & value, std::vector<const char *> possiblecharvals)
430 {
431 try
432 {
433 return query_validate(name,value,possiblecharvals,true);
434 }
435 catch (std::runtime_error & e)
436 {
437 Util::ParmParseException(INFO,full(name),e.what());
438 }
439 catch (...)
440 {
442 }
443 return -1;
444 }
445
446
447 // special case for strings
448 int query_default( std::string name, std::string & value, const char *defaultvalue)
449 {
450 try
451 {
452 return query_default(name, value, std::string(defaultvalue));
453 }
454 catch (std::runtime_error & e)
455 {
456 Util::ParmParseException(INFO,full(name),e.what());
457 }
458 catch (...)
459 {
461 }
462 return -1;
463 }
464 // special case for bools
465 int query_default( std::string name, int & value, bool defaultvalue)
466 {
467 try
468 {
469 int defaultint = 0;
470 if (defaultvalue) defaultint = 1;
471 return query_default(name, value, defaultint);
472 }
473 catch (std::runtime_error & e)
474 {
475 Util::ParmParseException(INFO,full(name),e.what());
476 }
477 catch (...)
478 {
480 }
481 return -1;
482 }
483
484
485 // validate filenames
486 int query_file( std::string name, std::string & value, bool copyfile, bool checkfile)
487 {
488 try
489 {
490 if (!contains(name.c_str()))
491 {
492 Util::ParmParseException(INFO,full(name),full(name)," must be specified");
493 }
494
495 int retval = query(name.c_str(),value);
496
497 if (amrex::ParallelDescriptor::IOProcessor())
498 {
499 if ( checkfile && ! std::filesystem::exists(value))
500 {
501 Util::ParmParseException(INFO,full(name),full(name)," does not exist");
502 }
503 if ( checkfile && !std::filesystem::is_regular_file(value))
504 {
505 Util::ParmParseException(INFO,full(name),full(name)," is not a regular file");
506 }
507 if ( copyfile )
508 {
509 Util::CopyFileToOutputDir(value, true, full(name));
510 }
511 }
512 return retval;
513 }
514 catch (std::runtime_error & e)
515 {
516 Util::ParmParseException(INFO,full(name),e.what());
517 }
518 catch (...)
519 {
521 }
522 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 int query_file( std::string name, std::string & value)
529 {
530 return query_file(name,value,true,true);
531 }
532
533
534 template<typename T>
535 int queryarr( std::string name, std::vector<T> & value)
536 {
537 try
538 {
539 return amrex::ParmParse::queryarr(name.c_str(),value);
540 }
541 catch (...)
542 {
544 }
545 return -1;
546 }
547 int queryarr( std::string name, std::vector<Set::Scalar> & value, Unit unit = Unit::Less())
548 {
549 try
550 {
551 if (unit.isType(Unit::Less()))
552 {
553 return amrex::ParmParse::queryarr(name.c_str(),value);
554 }
555 else
556 {
557 value.clear();
558 std::vector<std::string> valstrings;
559 int retval = amrex::ParmParse::queryarr(name.c_str(), valstrings);
560 for (unsigned int i = 0; i < valstrings.size(); i++)
561 {
562 Unit unitvalue = Unit::Parse(valstrings[i]);
563 Util::DebugMessage(INFO,full(name),": ",valstrings[i]," ==> ",unitvalue);
564
565 if (!unitvalue.isType(unit) && !unitvalue.isType(Unit::Less()))
566 {
567 Util::Exception(INFO,"value specified had wrong units:", valstrings[i]);
568 }
569 value.push_back(unitvalue.normalized_value());
570 }
571 return retval;
572 }
573 }
574 catch (std::runtime_error &e)
575 {
576 Util::ParmParseException(INFO,full(name), e.what());
577 }
578 catch (...)
579 {
581 }
582 return -1;
583 }
584 int queryarr( std::string name, Set::Vector & value, Unit unit = Unit::Less())
585 {
586 try
587 {
588 std::vector<Set::Scalar> vals;
589 queryarr(name.c_str(), vals, unit);
590 if (vals.size() < AMREX_SPACEDIM)
591 {
593 " requires at least ", AMREX_SPACEDIM,
594 " arguments, got ",vals.size());
595 }
596 for (int i = 0; i < AMREX_SPACEDIM; i++) value(i) = vals[i];
597 return 0;
598 }
599 catch(...)
600 {
602 }
603 return -1;
604 }
605 int queryarr( std::string name, Set::Matrix & value, Unit unit = Unit::Less())
606 {
607 std::vector<Set::Scalar> vals;
608 queryarr(name.c_str(), vals,unit);
609 if (vals.size() == 9)
610 {
611#if AMREX_SPACEDIM==2
612 Util::Warning(INFO, "Reading a 3D matrix (",full(name),")into a 2D code - some values will be ignored.");
613 value(0,0) = vals[0]; value(0,1)= vals[1];
614 value(1,0) = vals[3]; value(1,1)= vals[4];
615#endif
616#if AMREX_SPACEDIM==3
617 value(0,0) = vals[0]; value(0,1)= vals[1]; value(0,2)= vals[2];
618 value(1,0) = vals[3]; value(1,1)= vals[4]; value(1,2)= vals[5];
619 value(2,0) = vals[6]; value(2,1)= vals[7]; value(2,2)= vals[8];
620#endif
621 }
622 else if (vals.size() == 4)
623 {
624#if AMREX_SPACEDIM==2
625 value(0,0) = vals[0]; value(0,1)= vals[1];
626 value(1,0) = vals[2]; value(1,1)= vals[3];
627#endif
628#if AMREX_SPACEDIM==3
629 Util::Warning(INFO,"Reading a 2D matrix (",full(name),")into a 3D code - remaining values will be set to zero.");
630 value(0,0) = vals[0]; value(0,1)= vals[1]; value(0,2)= 0.0;
631 value(1,0) = vals[2]; value(1,1)= vals[3]; value(1,2)= 0.0;
632 value(2,0) = 0.0; value(2,1)= 0.0; value(2,2)= 0.0;
633#endif
634 }
635 else
636 {
637 Util::ParmParseException(INFO,full(name),full(name)," needs either 4 or 9 components, but got ",vals.size());
638 }
639 return 0;
640 }
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 int queryarr_required( std::string name, std::vector<Set::Scalar> & value, Unit unit = Unit::Less())
653 {
654 if (!contains(name.c_str()))
655 {
656 Util::ParmParseException(INFO,full(name),"required value for ",full(name)," missing");
657 }
658 return queryarr(name,value,unit);
659 }
660 int queryarr_default( std::string name, std::vector<std::string> & value, std::vector<std::string> defaultvalue)
661 {
662 if (!contains(name.c_str()))
663 {
664 addarr(name.c_str(),defaultvalue);
665 }
666 return amrex::ParmParse::queryarr(name.c_str(),value);
667 }
668
669 int queryarr_default( std::string name, Set::Vector & value, std::string defaultvalue, Unit unit)
670 {
671 try
672 {
673 if (!contains(name.c_str()))
674 {
675 this->addarr(name.c_str(),Util::String::Split(defaultvalue));
676 }
677 return queryarr(name.c_str(),value,unit);
678 }
679 catch (std::runtime_error &e)
680 {
681 Util::ParmParseException(INFO,full(name), e.what());
682 }
683 catch (...)
684 {
686 }
687 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 {
704 }
705 return -1;
706 }
707
708 int queryarr_default( std::string name, Set::Matrix & value, Set::Matrix defaultvalue)
709 {
710 try
711 {
712 if (!contains(name.c_str()))
713 {
714 add(name.c_str(),Util::String::Join(defaultvalue));
715 value = defaultvalue;
716 return 0;
717 }
718 return queryarr(name.c_str(),value);
719 }
720 catch (...)
721 {
723 }
724 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 {
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 {
757 }
758 return -1;
759 }
760
761
762 template <typename T>
763 int
764 queryclass_enumerate(std::string a_name, std::vector<T> &value, int number = 1)
765 {
766 value.clear();
767
768 //
769 // If only one is present with no subscript, then read
770 // it only and return.
771 //
772 std::string name = a_name;
773 if (this->contains(name))
774 {
775 for (int n = 0; n < number; n++)
776 {
777 T tmp;
778 this->queryclass<T>(name, tmp);
779 value.push_back(tmp);
780 }
781 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 int start = -1;
792 std::string name0 = a_name + std::to_string(0);
793 std::string name1 = a_name + std::to_string(1);
794 if (this->contains(name0.c_str()))
795 {
796 start = 0;
797 name = name0;
798 }
799 else if (this->contains(name1.c_str()))
800 {
801 start = 1;
802 name = name1;
803 }
804 else
805 {
806 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 for (int cntr = start; this->contains(name.c_str()); cntr++)
814 {
815 if (this->contains(name.c_str()))
816 {
817 T tmp;
818 this->queryclass<T>(name, tmp);
819 value.push_back(tmp);
820 }
821 name = a_name + std::to_string(cntr+1);
822 }
823
824 return 0;
825 }
826
827
828 template <typename T>
829 int
830 query_enumerate(std::string a_name, std::vector<T> &value, int number = 1)
831 {
832 value.clear();
833
834 //
835 // If only one is present with no subscript, then read
836 // it only and return.
837 //
838 std::string name = a_name;
839 if (this->contains(name))
840 {
841 for (int n = 0; n < number; n++)
842 {
843 T tmp;
844 this->query_required(name, tmp);
845 value.push_back(tmp);
846 }
847 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 int start = -1;
858 std::string name0 = a_name + std::to_string(0);
859 std::string name1 = a_name + std::to_string(1);
860 if (this->contains(name0.c_str()))
861 {
862 start = 0;
863 name = name0;
864 }
865 else if (this->contains(name1.c_str()))
866 {
867 start = 1;
868 name = name1;
869 }
870 else
871 {
872 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 for (int cntr = start; this->contains(name.c_str()); cntr++)
880 {
881 if (this->contains(name.c_str()))
882 {
883 T tmp;
884 this->query_required(name, tmp);
885 value.push_back(tmp);
886 }
887 name = a_name + std::to_string(cntr+1);
888 }
889
890 return 0;
891 }
892
893
894
895 int AnyUnusedInputs(bool inscopeonly = true, bool verbose = false)
896 {
897 int cnt = 0;
898 for (auto li = m_table->begin(), End = m_table->end(); li != End; ++li)
899 {
900 if (!li->second.m_count)
901 {
902 if (inscopeonly && getPrefix() != "")
903 {
904 if (li->first.rfind(getPrefix()+".",0) != std::string::npos)
905 {
906 if (verbose) Util::Warning(INFO,li->first);
907 cnt++;
908 }
909 }
910 else
911 {
912 if (verbose) Util::Warning(INFO,li->first);
913 cnt++;
914 }
915 }
916 }
917 return cnt;
918 }
919
920 std::vector<std::string> GetUnusedInputs()
921 {
922 std::vector<std::string> ret;
923 for (auto li = m_table->begin(), End = m_table->end(); li != End; ++li)
924 {
925 if (!li->second.m_count && li->first.rfind(getPrefix()+".",0) != std::string::npos)
926 {
927 ret.push_back(li->first);
928 }
929 }
930 return ret;
931 }
932
933 static int AllUnusedInputs()
934 {
935 ParmParse pp;
936 int cnt = 0;
937 for (auto li = pp.m_table->begin(), End = pp.m_table->end(); li != End; ++li)
938 {
939 if (!li->second.m_count)
940 {
941 Util::Warning(INFO,li->first);
942 cnt++;
943 }
944 }
945 return cnt;
946 }
947 std::string prefix ()
948 {
949 return getPrefix();
950 }
951 std::string full (std::string name)
952 {
953 std::string prefix = getPrefix();
954 if (prefix != "") return getPrefix() + "." + name;
955 else return name;
956 }
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;
981 }
982 m_prefix = old_prefix;
983 }
984 template<class T>
985 void queryclass(std::string name, T & value)
986 {
987 auto old_prefix = m_prefix;
988 try
989 {
990 if (old_prefix.empty()) m_prefix = name;
991 else m_prefix.append(".").append(name);
992 T::Parse(value, *this);
993 std::vector<std::string> unused_inputs = GetUnusedInputs();
994 if (unused_inputs.size())
995 {
996 std::stringstream ss;
997 for (unsigned int i=0; i < unused_inputs.size(); i++)
998 ss << "\n\t" << unused_inputs[i];
999 Util::ParmParseException(INFO,name,"The following inputs were specified but not used",ss.str());
1000 }
1001 }
1002 catch (std::runtime_error &e)
1003 {
1004 Util::ParmParseException(INFO,full(name),e.what());
1005 }
1006 catch (...)
1007 {
1008 m_prefix = old_prefix;
1010 }
1011 m_prefix = old_prefix;
1012 }
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 {
1024 }
1025 catch (...)
1026 {
1028 }
1029 }
1030 template<class T>
1031 void queryclass(T & value)
1032 {
1033 try
1034 {
1035 T::Parse(value, *this);
1036 }
1037 catch (std::runtime_error &e)
1038 {
1040 }
1041 catch (...)
1042 {
1044 }
1045 }
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 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 std::string type = "";
1071 this->query_required(name + ".type", type);
1072 bool matched = (( type == IC::name
1073 ? (ic_eta = new IC(std::forward<Args>(args)..., (*this), name + "." + std::string(IC::name))),
1074 true
1075 : false) || ...);
1076 if (!matched)
1077 Util::ParmParseException(INFO,full(name), type, " not a valid type for ", name);
1078 }
1079 }
1080 catch (std::runtime_error &e)
1081 {
1083 }
1084 catch (...)
1085 {
1087 }
1088 }
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 void select_default (std::string name, PTRTYPE *& ic_eta, Args&&... args)
1096 {
1097 std::string type = "";
1098
1099 this->query_default(name + ".type", type, FirstIC::name);
1100
1101 bool matched =
1102 (( type == FirstIC::name
1103 ? (ic_eta = new FirstIC(std::forward<Args>(args)..., (*this), name + "." + std::string(FirstIC::name))),
1104 true : false))
1105 ||
1106 (( type == IC::name
1107 ? (ic_eta = new IC(std::forward<Args>(args)..., (*this), name + "." + std::string(IC::name))),
1108 true : false) || ...);
1109
1110
1111 if (!matched)
1112 Util::ParmParseException(INFO,full(name), type," not a valid type for ",name);
1113 }
1114
1115
1116 //
1117 //
1118 template<typename... IC, typename... Args, typename PTRTYPE>
1119 void select_enumerate (std::string a_name, std::vector<PTRTYPE*> & value, Args&&... args)
1120 {
1121
1122 value.clear();
1123
1124 //
1125 // If only one is present with no subscript, then read
1126 // it only and return.
1127 //
1128 std::string name = a_name;
1129 if (this->contains(name))
1130 {
1131 PTRTYPE *tmp;
1132 this->select<IC...>(a_name, tmp, args...);
1133 value.push_back(tmp);
1134 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 int start = -1;
1145 std::string name0 = a_name + std::to_string(0);
1146 std::string name1 = a_name + std::to_string(1);
1147 if (this->contains(name0.c_str()))
1148 {
1149 start = 0;
1150 name = name0;
1151 }
1152 else if (this->contains(name1.c_str()))
1153 {
1154 start = 1;
1155 name = name1;
1156 }
1157 else
1158 {
1159 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 for (int cntr = start; this->contains(name.c_str()); cntr++)
1167 {
1168 if (this->contains(name.c_str()))
1169 {
1170 PTRTYPE *tmp;
1171 this->select<IC...>(name, tmp, args...);
1172 value.push_back(tmp);
1173 }
1174 name = a_name + std::to_string(cntr+1);
1175 }
1176 }
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 void select_only (PTRTYPE *& ic_eta)
1212 {
1213 ic_eta = new INTEGRATOR((*this));
1214 }
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 void select(std::string name, CLASS& value)
1224 {
1225 pushPrefix(name);
1226 static_polymorphism_parser<CLASS, 0, OBJ...>(value);
1227 popPrefix();
1228 }
1229
1230private:
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>
1243 {
1244 if constexpr (N == 0)
1245 {
1246 std::string type;
1247 query_default("type",type,value.names[0]);
1248
1249 for (unsigned int i = 0; i < sizeof...(OBJ); i++)
1250 if (type == value.names[i])
1251 value.selected = i;
1252
1253 if (value.selected < 0)
1255 "Error reading " + getPrefix() +
1256 ", invalid type " + type);
1257
1258
1259 pushPrefix(type);
1260 }
1261
1262 if constexpr (N < sizeof...(OBJ))
1263 {
1264 if (value.selected == N)
1265 {
1266 std::get<N>(value.obj).Parse(std::get<N>(value.obj), *this);
1267 popPrefix();
1268 return;
1269 }
1270 else
1271 return static_polymorphism_parser<CLASS, N+1, OBJ...>(value);
1272 }
1273 else Util::Abort(INFO);
1274 }
1275
1276public:
1277
1278 template <int N>
1279 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 Util::AssertException( INFO,TEST(units.size() == 0 || units.size() == names.size()),
1285 "# of units must be 0, 1, or ", names.size(), " but got ", units.size());
1286
1287 int cnt = 0;
1288 std::vector<std::string> read;
1289 for (unsigned int n = 0; n < names.size(); n++)
1290 {
1291 if (amrex::ParmParse::contains(names[n].c_str()))
1292 {
1293 read.push_back(names[n]);
1294 cnt++;
1295 }
1296 }
1297 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 cnt = 0;
1304 for (unsigned int n = 0; n < names.size(); n++)
1305 {
1306 if (amrex::ParmParse::contains(names[n].c_str()))
1307 {
1308 values[cnt].first = names[n];
1309
1310 if (units.size() == 0)
1311 query_required(names[n],values[cnt].second);
1312 else if (units.size() == 1)
1313 query_required(names[n],values[cnt].second,units[0]);
1314 else
1315 query_required(names[n],values[cnt].second,units[n]);
1316 cnt++;
1317 }
1318 }
1319 }
1320 catch(...)
1321 {
1322 std::string names_str = "[";
1323 for (unsigned int i = 0; i < names.size(); i++)
1324 {
1325 names_str += full(names[i]);
1326 if (i < names.size()-1) names_str += ", ";
1327 }
1328 names_str += "]";
1329 Util::ParmParseException(INFO,names_str);
1330 }
1331 }
1332};
1333}
1334#endif
#define TEST(x)
Definition Util.H:22
#define INFO
Definition Util.H:21
int queryarr_default(std::string name, std::vector< double > &value, std::vector< std::string > defaultvalue, Unit unit)
Definition ParmParse.H:744
bool contains(std::string name)
Definition ParmParse.H:173
int queryunit(std::string name, Unit &value)
Definition ParmParse.H:192
int queryarr_default(std::string name, std::vector< std::string > &value, std::vector< std::string > defaultvalue)
Definition ParmParse.H:660
int queryarr_required(std::string name, std::vector< Set::Scalar > &value, Unit unit=Unit::Less())
Definition ParmParse.H:652
int queryarr(std::string name, std::vector< T > &value)
Definition ParmParse.H:535
void forbid(std::string name, std::string explanation)
Definition ParmParse.H:160
void select(std::string name, CLASS &value)
Definition ParmParse.H:1223
int query_enumerate(std::string a_name, std::vector< T > &value, int number=1)
Definition ParmParse.H:830
int queryarr(std::string name, std::vector< Set::Scalar > &value, Unit unit=Unit::Less())
Definition ParmParse.H:547
void pushPrefix(const std::string prefix)
Definition ParmParse.H:142
int query_validate(std::string name, std::string &value, std::vector< const char * > possiblecharvals, bool firstbydefault)
Definition ParmParse.H:379
int query_file(std::string name, std::string &value)
Definition ParmParse.H:528
int queryarr(std::string name, Set::Vector &value, Unit unit=Unit::Less())
Definition ParmParse.H:584
int queryarr_default(std::string name, Set::Vector &value, std::string defaultvalue, Unit unit)
Definition ParmParse.H:669
int query_file(std::string name, std::string &value, bool copyfile, bool checkfile)
Definition ParmParse.H:486
int AnyUnusedInputs(bool inscopeonly=true, bool verbose=false)
Definition ParmParse.H:895
int queryarr(std::string name, Set::Matrix &value, Unit unit=Unit::Less())
Definition ParmParse.H:605
std::vector< std::string > GetUnusedInputs()
Definition ParmParse.H:920
void queryclass(std::string name, T &value)
Definition ParmParse.H:985
std::string getPrefix() const
Definition ParmParse.H:136
static bool checked_for_input_files
Definition ParmParse.H:131
std::string prefix()
Definition ParmParse.H:947
void select(std::string name, PTRTYPE *&ic_eta, Args &&... args)
Definition ParmParse.H:1056
void queryclass(std::string name, T *value)
Definition ParmParse.H:960
int queryclass_enumerate(std::string a_name, std::vector< T > &value, int number=1)
Definition ParmParse.H:764
int query_required(std::string name, T &value)
Definition ParmParse.H:249
int queryarr_default(std::string name, Set::Matrix &value, Set::Matrix defaultvalue)
Definition ParmParse.H:708
int query_default(std::string name, T &value, std::string defaultvalue, const Unit type)
Definition ParmParse.H:315
void Define()
Definition ParmParse.H:118
void select_default(std::string name, PTRTYPE *&ic_eta, Args &&... args)
Definition ParmParse.H:1095
int queryarr_default(std::string name, Set::Vector &value, Set::Vector defaultvalue)
Definition ParmParse.H:689
int queryunit(std::string name, Unit &value, const Unit type)
Definition ParmParse.H:213
int query_default(std::string name, int &value, bool defaultvalue)
Definition ParmParse.H:465
int query_file(std::string name, std::string &value, bool copyfile)
Definition ParmParse.H:524
void select_enumerate(std::string a_name, std::vector< PTRTYPE * > &value, Args &&... args)
Definition ParmParse.H:1119
void queryclass(T &value)
Definition ParmParse.H:1031
static int AllUnusedInputs()
Definition ParmParse.H:933
int query_validate(std::string name, std::string &value, std::vector< const char * > possiblecharvals)
Definition ParmParse.H:429
void queryclass(T *value)
Definition ParmParse.H:1015
int queryarr_required(std::string name, std::vector< T > &value)
Definition ParmParse.H:643
int query_required(std::string name, T &value, const Unit type)
Definition ParmParse.H:271
void popPrefix()
Definition ParmParse.H:150
void static_polymorphism_parser(CLASS &value)
Definition ParmParse.H:1242
void select_only(PTRTYPE *&ic_eta, Args &&args)
Definition ParmParse.H:1205
void select_main(PTRTYPE *&ic_eta, Args &&... args)
Definition ParmParse.H:1184
int queryunit(std::string name, Set::Scalar &value, const Unit type)
Definition ParmParse.H:232
int query_default(std::string name, T &value, T defaultvalue)
Definition ParmParse.H:293
void select_only(PTRTYPE *&ic_eta)
Definition ParmParse.H:1211
void ignore(std::string name)
Definition ParmParse.H:137
std::string full(std::string name)
Definition ParmParse.H:951
int query_validate(std::string name, int &value, std::vector< int > possibleintvals)
Definition ParmParse.H:336
int queryarr_default(std::string name, std::vector< double > &value, std::vector< double > defaultvalue)
Definition ParmParse.H:727
void query_exactly(std::vector< std::string > names, std::pair< std::string, Set::Scalar > values[N], std::vector< Unit > units=std::vector< Unit >())
Definition ParmParse.H:1279
int query_default(std::string name, std::string &value, const char *defaultvalue)
Definition ParmParse.H:448
ParmParse(std::string arg)
Definition ParmParse.H:134
Initialize a spherical inclusion.
Definition BMP.H:20
amrex::Real Scalar
Definition Base.H:18
Eigen::Matrix< amrex::Real, AMREX_SPACEDIM, 1 > Vector
Definition Base.H:19
Eigen::Matrix< amrex::Real, AMREX_SPACEDIM, AMREX_SPACEDIM > Matrix
Definition Base.H:22
AMREX_FORCE_INLINE std::string Join(const std::vector< std::string > &vec, std::string separator="_")
Definition String.H:83
AMREX_FORCE_INLINE std::vector< std::string > Split(std::string &str, const char delim=' ')
Definition String.H:138
void DebugMessage(std::string, std::string, int, Args const &...)
Definition Util.H:173
AMREX_FORCE_INLINE void AssertException(std::string file, std::string func, int line, std::string smt, bool pass, Args const &... args)
Definition Util.H:251
void Abort(const char *msg)
Definition Util.cpp:243
void CopyFileToOutputDir(std::string a_path, bool fullpath, std::string prefix)
Definition Util.cpp:54
void Warning(std::string file, std::string func, int line, Args const &... args)
Definition Util.H:199
void Message(std::string file, std::string func, int line, Args const &... args)
Definition Util.H:126
void ParmParseException(std::string file, std::string func, int line, std::string fullname, Args const &... args)
Definition Util.H:281
void Exception(std::string file, std::string func, int line, Args const &... args)
Definition Util.H:223
Definition Unit.H:21
bool isType(const Unit &test) const
Definition Unit.H:425
std::string normalized_unitstring() const
Definition Unit.H:510
static Unit Parse(double val, std::string unitstring, bool verbose=false)
Definition Unit.H:270
double normalized_value() const
Definition Unit.H:501
static Unit Less()
Definition Unit.H:197