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 std::vector<Set::Scalar> def_data(AMREX_SPACEDIM);
696 for (unsigned int i = 0; i < def_data.size(); i++)
697 def_data[i] = defaultvalue[i];
698
699 add(name.c_str(),Util::String::Join(def_data));
700 value = defaultvalue;
701 return 0;
702 }
703 return queryarr(name.c_str(),value);
704 }
705 catch (...)
706 {
708 }
709 return -1;
710 }
711
712 int queryarr_default( std::string name, Set::Matrix & value, Set::Matrix def)
713 {
714 try
715 {
716 if (!contains(name.c_str()))
717 {
718 std::vector<Set::Scalar> def_data(AMREX_SPACEDIM*AMREX_SPACEDIM);
719 for (unsigned int i = 0; i < def_data.size(); i++)
720 def_data[i] = def.data()[i];
721
722 add(name.c_str(),Util::String::Join(def_data));
723 value = def;
724 return 0;
725 }
726 return queryarr(name.c_str(),value);
727 }
728 catch (...)
729 {
731 }
732 return -1;
733 }
734
735 int queryarr_default( std::string name, std::vector<double> & value, std::vector<double> defaultvalue)
736 {
737 try
738 {
739 if (!contains(name.c_str()))
740 {
741 addarr(name.c_str(),defaultvalue);
742 }
743 return queryarr(name.c_str(),value);
744 }
745 catch (...)
746 {
748 }
749 return -1;
750 }
751
752 int queryarr_default( std::string name, std::vector<double> & value, std::vector<std::string> defaultvalue, Unit unit)
753 {
754 try
755 {
756 if (!contains(name.c_str()))
757 {
758 addarr(name.c_str(),defaultvalue);
759 }
760 return queryarr(name,value, unit);
761 }
762 catch (...)
763 {
765 }
766 return -1;
767 }
768
769
770 template <typename T>
771 int
772 queryclass_enumerate(std::string a_name, std::vector<T> &value, int number = 1)
773 {
774 value.clear();
775
776 //
777 // If only one is present with no subscript, then read
778 // it only and return.
779 //
780 std::string name = a_name;
781 if (this->contains(name))
782 {
783 for (int n = 0; n < number; n++)
784 {
785 T tmp;
786 this->queryclass<T>(name, tmp);
787 value.push_back(tmp);
788 }
789 return 0;
790 }
791
792 //
793 // Some logic to determine whether we are starting with zero
794 // (model0, model1, model2, ...)
795 // or one
796 // (model1, model2, model3, ...)
797 // since both are supported
798 //
799 int start = -1;
800 std::string name0 = a_name + std::to_string(0);
801 std::string name1 = a_name + std::to_string(1);
802 if (this->contains(name0.c_str()))
803 {
804 start = 0;
805 name = name0;
806 }
807 else if (this->contains(name1.c_str()))
808 {
809 start = 1;
810 name = name1;
811 }
812 else
813 {
814 Util::ParmParseException(INFO,full(name), "Enumerations must begin with 0 or 1");
815 }
816
817 //
818 // Iterate over items called (model0), model1, model2, etc
819 // until no more are found then exit.
820 //
821 for (int cntr = start; this->contains(name.c_str()); cntr++)
822 {
823 if (this->contains(name.c_str()))
824 {
825 T tmp;
826 this->queryclass<T>(name, tmp);
827 value.push_back(tmp);
828 }
829 name = a_name + std::to_string(cntr+1);
830 }
831
832 return 0;
833 }
834
835
836 template <typename T>
837 int
838 query_enumerate(std::string a_name, std::vector<T> &value, int number = 1)
839 {
840 value.clear();
841
842 //
843 // If only one is present with no subscript, then read
844 // it only and return.
845 //
846 std::string name = a_name;
847 if (this->contains(name))
848 {
849 for (int n = 0; n < number; n++)
850 {
851 T tmp;
852 this->query_required(name, tmp);
853 value.push_back(tmp);
854 }
855 return 0;
856 }
857
858 //
859 // Some logic to determine whether we are starting with zero
860 // (model0, model1, model2, ...)
861 // or one
862 // (model1, model2, model3, ...)
863 // since both are supported
864 //
865 int start = -1;
866 std::string name0 = a_name + std::to_string(0);
867 std::string name1 = a_name + std::to_string(1);
868 if (this->contains(name0.c_str()))
869 {
870 start = 0;
871 name = name0;
872 }
873 else if (this->contains(name1.c_str()))
874 {
875 start = 1;
876 name = name1;
877 }
878 else
879 {
880 Util::ParmParseException(INFO,full(name), "Enumerations must begin with 0 or 1");
881 }
882
883 //
884 // Iterate over items called (model0), model1, model2, etc
885 // until no more are found then exit.
886 //
887 for (int cntr = start; this->contains(name.c_str()); cntr++)
888 {
889 if (this->contains(name.c_str()))
890 {
891 T tmp;
892 this->query_required(name, tmp);
893 value.push_back(tmp);
894 }
895 name = a_name + std::to_string(cntr+1);
896 }
897
898 return 0;
899 }
900
901
902
903 int AnyUnusedInputs(bool inscopeonly = true, bool verbose = false)
904 {
905 int cnt = 0;
906 for (auto li = m_table->begin(), End = m_table->end(); li != End; ++li)
907 {
908 if (!li->second.m_count)
909 {
910 if (inscopeonly && getPrefix() != "")
911 {
912 if (li->first.rfind(getPrefix()+".",0) != std::string::npos)
913 {
914 if (verbose) Util::Warning(INFO,li->first);
915 cnt++;
916 }
917 }
918 else
919 {
920 if (verbose) Util::Warning(INFO,li->first);
921 cnt++;
922 }
923 }
924 }
925 return cnt;
926 }
927
928 std::vector<std::string> GetUnusedInputs()
929 {
930 std::vector<std::string> ret;
931 for (auto li = m_table->begin(), End = m_table->end(); li != End; ++li)
932 {
933 if (!li->second.m_count && li->first.rfind(getPrefix()+".",0) != std::string::npos)
934 {
935 ret.push_back(li->first);
936 }
937 }
938 return ret;
939 }
940
941 static int AllUnusedInputs()
942 {
943 ParmParse pp;
944 int cnt = 0;
945 for (auto li = pp.m_table->begin(), End = pp.m_table->end(); li != End; ++li)
946 {
947 if (!li->second.m_count)
948 {
949 Util::Warning(INFO,li->first);
950 cnt++;
951 }
952 }
953 return cnt;
954 }
955 std::string prefix ()
956 {
957 return getPrefix();
958 }
959 std::string full (std::string name)
960 {
961 std::string prefix = getPrefix();
962 if (prefix != "") return getPrefix() + "." + name;
963 else return name;
964 }
965
966
967 template<class T>
968 void queryclass(std::string name, T * value)
969 {
970 auto old_prefix = m_prefix;
971 try
972 {
973 if (old_prefix.empty()) m_prefix = name;
974 else m_prefix.append(".").append(name);
975 T::Parse(*value, *this);
976 std::vector<std::string> unused_inputs = GetUnusedInputs();
977 if (unused_inputs.size())
978 {
979 std::stringstream ss;
980 for (unsigned int i=0; i < unused_inputs.size(); i++)
981 ss << "\n\t" << unused_inputs[i];
982 Util::ParmParseException(INFO,name,"The following inputs were specified but not used",ss.str());
983 }
984 }
985 catch (...)
986 {
987 m_prefix = old_prefix;
989 }
990 m_prefix = old_prefix;
991 }
992 template<class T>
993 void queryclass(std::string name, T & value)
994 {
995 auto old_prefix = m_prefix;
996 try
997 {
998 if (old_prefix.empty()) m_prefix = name;
999 else m_prefix.append(".").append(name);
1000 T::Parse(value, *this);
1001 std::vector<std::string> unused_inputs = GetUnusedInputs();
1002 if (unused_inputs.size())
1003 {
1004 std::stringstream ss;
1005 for (unsigned int i=0; i < unused_inputs.size(); i++)
1006 ss << "\n\t" << unused_inputs[i];
1007 Util::ParmParseException(INFO,name,"The following inputs were specified but not used",ss.str());
1008 }
1009 }
1010 catch (std::runtime_error &e)
1011 {
1012 Util::ParmParseException(INFO,full(name),e.what());
1013 }
1014 catch (...)
1015 {
1016 m_prefix = old_prefix;
1018 }
1019 m_prefix = old_prefix;
1020 }
1021
1022 template<class T>
1023 void queryclass(T * value)
1024 {
1025 try
1026 {
1027 T::Parse(*value, *this);
1028 }
1029 catch (std::runtime_error &e)
1030 {
1032 }
1033 catch (...)
1034 {
1036 }
1037 }
1038 template<class T>
1039 void queryclass(T & value)
1040 {
1041 try
1042 {
1043 T::Parse(value, *this);
1044 }
1045 catch (std::runtime_error &e)
1046 {
1048 }
1049 catch (...)
1050 {
1052 }
1053 }
1054
1055 //
1056 // Variadic template parsing operator to assign a pointer to
1057 // one of a set of possible class objects, then call that method's
1058 // Parse function.
1059 //
1060 // If there is more than one instantiating class, then type must be set.
1061 // Otherwise, no type is necessary.
1062 //
1063 template<typename... IC, typename... Args, typename PTRTYPE>
1064 void select (std::string name, PTRTYPE *& ic_eta, Args&&... args)
1065 {
1066 try
1067 {
1068 // if there is only one IC arg provided, we don't need to check the type - assume that
1069 // it is the default.
1070 if constexpr (sizeof...(IC) == 0)
1071 {
1072 using first_IC = std::tuple_element_t<0, std::tuple<IC...>>;
1073 ic_eta = new first_IC(std::forward<Args>(args)..., (*this), name + "." + std::string(first_IC::name));
1074 }
1075 // otherwise, check the type.
1076 else
1077 {
1078 std::string type = "";
1079 this->query_required(name + ".type", type);
1080 bool matched = (( type == IC::name
1081 ? (ic_eta = new IC(std::forward<Args>(args)..., (*this), name + "." + std::string(IC::name))),
1082 true
1083 : false) || ...);
1084 if (!matched)
1085 Util::ParmParseException(INFO,full(name), type, " not a valid type for ", name);
1086 }
1087 }
1088 catch (std::runtime_error &e)
1089 {
1091 }
1092 catch (...)
1093 {
1095 }
1096 }
1097
1098 //
1099 // Identical to the above, except sets the type automatically to the
1100 // firs specified
1101 //
1102 template<typename FirstIC, typename... IC, typename... Args, typename PTRTYPE>
1103 void select_default (std::string name, PTRTYPE *& ic_eta, Args&&... args)
1104 {
1105 std::string type = "";
1106
1107 this->query_default(name + ".type", type, FirstIC::name);
1108
1109 bool matched =
1110 (( type == FirstIC::name
1111 ? (ic_eta = new FirstIC(std::forward<Args>(args)..., (*this), name + "." + std::string(FirstIC::name))),
1112 true : false))
1113 ||
1114 (( type == IC::name
1115 ? (ic_eta = new IC(std::forward<Args>(args)..., (*this), name + "." + std::string(IC::name))),
1116 true : false) || ...);
1117
1118
1119 if (!matched)
1120 Util::ParmParseException(INFO,full(name), type," not a valid type for ",name);
1121 }
1122
1123
1124 //
1125 //
1126 template<typename... IC, typename... Args, typename PTRTYPE>
1127 void select_enumerate (std::string a_name, std::vector<PTRTYPE*> & value, Args&&... args)
1128 {
1129
1130 value.clear();
1131
1132 //
1133 // If only one is present with no subscript, then read
1134 // it only and return.
1135 //
1136 std::string name = a_name;
1137 if (this->contains(name))
1138 {
1139 PTRTYPE *tmp;
1140 this->select<IC...>(a_name, tmp, args...);
1141 value.push_back(tmp);
1142 return;
1143 }
1144
1145 //
1146 // Some logic to determine whether we are starting with zero
1147 // (model0, model1, model2, ...)
1148 // or one
1149 // (model1, model2, model3, ...)
1150 // since both are supported
1151 //
1152 int start = -1;
1153 std::string name0 = a_name + std::to_string(0);
1154 std::string name1 = a_name + std::to_string(1);
1155 if (this->contains(name0.c_str()))
1156 {
1157 start = 0;
1158 name = name0;
1159 }
1160 else if (this->contains(name1.c_str()))
1161 {
1162 start = 1;
1163 name = name1;
1164 }
1165 else
1166 {
1167 Util::ParmParseException(INFO,full(name), "Enumerations must begin with 0 or 1");
1168 }
1169
1170 //
1171 // Iterate over items called (model0), model1, model2, etc
1172 // until no more are found then exit.
1173 //
1174 for (int cntr = start; this->contains(name.c_str()); cntr++)
1175 {
1176 if (this->contains(name.c_str()))
1177 {
1178 PTRTYPE *tmp;
1179 this->select<IC...>(name, tmp, args...);
1180 value.push_back(tmp);
1181 }
1182 name = a_name + std::to_string(cntr+1);
1183 }
1184 }
1185
1186
1187
1188 //
1189 // Similar to select but specialized for main functions
1190 //
1191 template<typename... INTEGRATOR, typename... Args, typename PTRTYPE>
1192 void select_main (PTRTYPE *& ic_eta, Args&&... args)
1193 {
1194 std::string type = "";
1195
1196 this->query_required("alamo.program", type);
1197
1198 bool matched = ((type == INTEGRATOR::name
1199 ? (ic_eta = new INTEGRATOR(std::forward<Args>(args)..., (*this))),
1200 true
1201 : false) || ...);
1202 if (!matched)
1203 Util::ParmParseException(INFO,getPrefix(),type," not a valid type for ",type);
1204 }
1205
1206 //
1207 // Similar to select_main but works for one function only
1208 // and doesn't require a type specifier.
1209 //
1210
1211 // with variadic arguments
1212 template<typename INTEGRATOR, typename Args, typename PTRTYPE>
1213 void select_only (PTRTYPE *& ic_eta, Args&& args)
1214 {
1215 ic_eta = new INTEGRATOR(std::forward<Args>(args), (*this));
1216 }
1217 // without variadic arguments
1218 template<typename INTEGRATOR, typename PTRTYPE>
1219 void select_only (PTRTYPE *& ic_eta)
1220 {
1221 ic_eta = new INTEGRATOR((*this));
1222 }
1223
1224
1225 //
1226 // functionally simlar to other kinds of select, execpt works on
1227 // template-based static dispatch.
1228 //
1229
1230 template <typename... OBJ, typename CLASS, typename... Args>
1231 void select(std::string name, CLASS& value, Args&&... args)
1232 {
1233 pushPrefix(name);
1234 static_polymorphism_parser<CLASS, 0, OBJ...>(value, std::forward<Args>(args)...);
1235 popPrefix();
1236 }
1237
1238private:
1239 //
1240 // This function is a virtual "swtich / case" block for static
1241 // dispatch. It works on a faux-virtual class "CLASS" that must
1242 // contain a tuple of "obj" with each "obj" being a derived type.
1243 // Recursion is used to unroll the list, identify the correct class
1244 // based on "name/type", set the "selected" index, then call the
1245 // appropriate class' Parse function.
1246 //
1247 // This is only for use by the "select" functions.
1248 //
1249 template <typename CLASS, int N, typename... OBJ, typename... Args>
1250 void static_polymorphism_parser(CLASS& value, Args&&... args)
1251 {
1252 if constexpr (N == 0)
1253 {
1254 std::string type;
1255 query_default("type",type,value.names[0]);
1256
1257 for (unsigned int i = 0; i < sizeof...(OBJ); i++)
1258 if (type == value.names[i])
1259 value.selected = i;
1260
1261 if (value.selected < 0)
1263 "Error reading " + getPrefix() +
1264 ", invalid type " + type);
1265
1266
1267 pushPrefix(type);
1268 }
1269
1270 if constexpr (N < sizeof...(OBJ))
1271 {
1272 if (value.selected == N)
1273 {
1274 std::get<N>(value.obj).Parse(
1275 std::get<N>(value.obj), *this, std::forward<Args>(args)...);
1276 popPrefix();
1277 return;
1278 }
1279 else
1280 return static_polymorphism_parser<CLASS, N+1, OBJ...>(
1281 value, std::forward<Args>(args)...);
1282 }
1283 else Util::Abort(INFO);
1284 }
1285
1286public:
1287
1288 template <int N>
1289 void query_exactly( std::vector<std::string> names, std::pair<std::string, Set::Scalar> values[N],
1290 std::vector<Unit> units = std::vector<Unit>())
1291 {
1292 try
1293 {
1294 Util::AssertException( INFO,TEST(units.size() == 0 || units.size() == names.size()),
1295 "# of units must be 0, 1, or ", names.size(), " but got ", units.size());
1296
1297 int cnt = 0;
1298 std::vector<std::string> read;
1299 for (unsigned int n = 0; n < names.size(); n++)
1300 {
1301 if (amrex::ParmParse::contains(names[n].c_str()))
1302 {
1303 read.push_back(names[n]);
1304 cnt++;
1305 }
1306 }
1307 Util::AssertException( INFO, TEST(cnt == N),
1308 " Incorrect number of values specified: only ", N,
1309 " values are allowed, but received ",
1310 Util::String::Join(read,", "));
1311
1312
1313 cnt = 0;
1314 for (unsigned int n = 0; n < names.size(); n++)
1315 {
1316 if (amrex::ParmParse::contains(names[n].c_str()))
1317 {
1318 values[cnt].first = names[n];
1319
1320 if (units.size() == 0)
1321 query_required(names[n],values[cnt].second);
1322 else if (units.size() == 1)
1323 query_required(names[n],values[cnt].second,units[0]);
1324 else
1325 query_required(names[n],values[cnt].second,units[n]);
1326 cnt++;
1327 }
1328 }
1329 }
1330 catch(...)
1331 {
1332 std::string names_str = "[";
1333 for (unsigned int i = 0; i < names.size(); i++)
1334 {
1335 names_str += full(names[i]);
1336 if (i < names.size()-1) names_str += ", ";
1337 }
1338 names_str += "]";
1339 Util::ParmParseException(INFO,names_str);
1340 }
1341 }
1342};
1343}
1344#endif
#define TEST(x)
Definition Util.H:25
#define INFO
Definition Util.H:24
int queryarr_default(std::string name, std::vector< double > &value, std::vector< std::string > defaultvalue, Unit unit)
Definition ParmParse.H:752
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
int query_enumerate(std::string a_name, std::vector< T > &value, int number=1)
Definition ParmParse.H:838
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:903
int queryarr(std::string name, Set::Matrix &value, Unit unit=Unit::Less())
Definition ParmParse.H:605
std::vector< std::string > GetUnusedInputs()
Definition ParmParse.H:928
void queryclass(std::string name, T &value)
Definition ParmParse.H:993
std::string getPrefix() const
Definition ParmParse.H:136
static bool checked_for_input_files
Definition ParmParse.H:131
std::string prefix()
Definition ParmParse.H:955
void select(std::string name, PTRTYPE *&ic_eta, Args &&... args)
Definition ParmParse.H:1064
void queryclass(std::string name, T *value)
Definition ParmParse.H:968
int queryclass_enumerate(std::string a_name, std::vector< T > &value, int number=1)
Definition ParmParse.H:772
int query_required(std::string name, T &value)
Definition ParmParse.H:249
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:1103
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
void static_polymorphism_parser(CLASS &value, Args &&... args)
Definition ParmParse.H:1250
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:1127
void queryclass(T &value)
Definition ParmParse.H:1039
static int AllUnusedInputs()
Definition ParmParse.H:941
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:1023
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 select_only(PTRTYPE *&ic_eta, Args &&args)
Definition ParmParse.H:1213
void select_main(PTRTYPE *&ic_eta, Args &&... args)
Definition ParmParse.H:1192
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:1219
void ignore(std::string name)
Definition ParmParse.H:137
std::string full(std::string name)
Definition ParmParse.H:959
int query_validate(std::string name, int &value, std::vector< int > possibleintvals)
Definition ParmParse.H:336
int queryarr_default(std::string name, Set::Matrix &value, Set::Matrix def)
Definition ParmParse.H:712
void select(std::string name, CLASS &value, Args &&... args)
Definition ParmParse.H:1231
int queryarr_default(std::string name, std::vector< double > &value, std::vector< double > defaultvalue)
Definition ParmParse.H:735
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:1289
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:19
Eigen::Matrix< amrex::Real, AMREX_SPACEDIM, 1 > Vector
Definition Base.H:21
Eigen::Matrix< amrex::Real, AMREX_SPACEDIM, AMREX_SPACEDIM > Matrix
Definition Base.H:24
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:176
AMREX_FORCE_INLINE void AssertException(std::string file, std::string func, int line, std::string smt, bool pass, Args const &... args)
Definition Util.H:254
void Abort(const char *msg)
Definition Util.cpp:268
void CopyFileToOutputDir(std::string a_path, bool fullpath, std::string prefix)
Definition Util.cpp:59
void Warning(std::string file, std::string func, int line, Args const &... args)
Definition Util.H:202
void Message(std::string file, std::string func, int line, Args const &... args)
Definition Util.H:129
void ParmParseException(std::string file, std::string func, int line, std::string fullname, Args const &... args)
Definition Util.H:284
void Exception(std::string file, std::string func, int line, Args const &... args)
Definition Util.H:226
Definition Unit.H:21
bool isType(const Unit &test) const
Definition Unit.H:425
std::string normalized_unitstring() const
Definition Unit.H:515
static Unit Parse(double val, std::string unitstring, bool verbose=false)
Definition Unit.H:270
double normalized_value() const
Definition Unit.H:506
static Unit Less()
Definition Unit.H:197