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