Athena++/Atmosphere
Planetary Atmosphere Simulator
parameter_input.cpp
Go to the documentation of this file.
1 //========================================================================================
2 // Athena++ astrophysical MHD code
3 // Copyright(C) 2014 James M. Stone <jmstone@princeton.edu> and other code contributors
4 // Licensed under the 3-clause BSD License, see LICENSE file for details
5 //========================================================================================
7 // \brief implementation of functions in class ParameterInput
8 //
9 // PURPOSE: Member functions of this class are used to read and parse the input file.
10 // Functionality is loosely modeled after FORTRAN namelist.
11 //
12 // EXAMPLE of input file in 'Athena++' format:
13 // <blockname1> # block name; must be on a line by itself
14 // # everything after a hash symbol is a comment and is ignored
15 // name1=value # each parameter name must be on a line by itself
16 // name2 = value1 # whitespace around the = is optional
17 // # blank lines are OK
18 // # my comment here comment lines are OK
19 // # name3 = value3 values (and blocks) that are commented out are ignored
20 //
21 // <blockname2> # start new block
22 // name1 = value1 # note that same parameter names can appear in different blocks
23 // name2 = value2 # empty lines (like following) are OK
24 //
25 // <blockname1> # same blockname can re-appear, although NOT recommended
26 // name3 = value3 # this would be the 3rd parameter name in blockname1
27 // name1 = value4 # if parameter name is repeated, previous value is overwritten!
28 //
29 // LIMITATIONS:
30 // - parameter specification (name=val #comment) must all be on a single line
31 //
32 // HISTORY:
33 // - Nov 2002: Created for Athena1.0/Cambridge release by Peter Teuben
34 // - 2003-2008: Many improvements and extensions by T. Gardiner and J.M. Stone
35 // - Jan 2014: Rewritten in C++ for the Athena++ code by J.M. Stone
36 //========================================================================================
37 
38 // C headers
39 
40 // C++ headers
41 #include <algorithm> // transform
42 #include <cmath> // std::fmod()
43 #include <cstdlib> // atoi(), atof(), nullptr, std::size_t
44 #include <fstream> // ifstream
45 #include <iostream> // endl, ostream
46 #include <sstream> // stringstream
47 #include <stdexcept> // runtime_error
48 #include <string> // string
49 
50 // Athena++ headers
51 #include "athena.hpp"
52 #include "defs.hpp"
53 #include "globals.hpp"
54 #include "parameter_input.hpp"
55 
56 // OpenMP header
57 #ifdef OPENMP_PARALLEL
58 #include <omp.h>
59 #endif
60 
61 //----------------------------------------------------------------------------------------
62 // ParameterInput constructor
63 
64 ParameterInput::ParameterInput() :pfirst_block{}, last_filename_{} {
65 #ifdef OPENMP_PARALLEL
66  omp_init_lock(&lock_);
67 #endif
68 }
69 
70 // ParameterInput destructor- iterates through nested singly linked lists of blocks/lines
71 // and deletes each InputBlock node (whose destructor below deletes linked list "line"
72 // nodes)
73 
75  InputBlock *pib = pfirst_block;
76  while (pib != nullptr) {
77  InputBlock *pold_block = pib;
78  pib = pib->pnext;
79  delete pold_block;
80  }
81 #ifdef OPENMP_PARALLEL
82  omp_destroy_lock(&lock_);
83 #endif
84 }
85 
86 // InputBlock destructor- iterates through singly linked list of "line" nodes and deletes
87 // them
88 
90  InputLine *pil = pline;
91  while (pil != nullptr) {
92  InputLine *pold_line = pil;
93  pil = pil->pnext;
94  delete pold_line;
95  }
96 }
97 
98 //----------------------------------------------------------------------------------------
100 // \brief Load input parameters from a stream
101 
102 // Input block names are allocated and stored in a singly linked list of InputBlocks.
103 // Within each InputBlock the names, values, and comments of each parameter are allocated
104 // and stored in a singly linked list of InputLines.
105 
106 void ParameterInput::LoadFromStream(std::istream &is) {
107  std::string line, block_name, param_name, param_value, param_comment;
108  std::size_t first_char, last_char;
109  std::stringstream msg;
110  InputBlock *pib{};
111  int line_num{-1}, blocks_found{0};
112 
113  while (is.good()) {
114  std::getline(is, line);
115  line_num++;
116  if (line.find('\t') != std::string::npos) {
117  line.erase(std::remove(line.begin(), line.end(), '\t'), line.end());
118  // msg << "### FATAL ERROR in function [ParameterInput::LoadFromStream]"
119  // << std::endl << "Tab characters are forbidden in input files";
120  // ATHENA_ERROR(msg);
121  }
122  if (line.empty()) continue; // skip blank line
123  first_char = line.find_first_not_of(" "); // skip white space
124  if (first_char == std::string::npos) continue; // line is all white space
125  if (line.compare(first_char, 1, "#") == 0) continue; // skip comments
126  if (line.compare(first_char, 9, "<par_end>") == 0) break; // stop on <par_end>
127 
128  if (line.compare(first_char, 1, "<") == 0) { // a new block
129  first_char++;
130  last_char = (line.find_first_of(">", first_char));
131  block_name.assign(line, first_char, last_char-1); // extract block name
132 
133  if (last_char == std::string::npos) {
134  msg << "### FATAL ERROR in function [ParameterInput::LoadFromStream]"
135  << std::endl << "Block name '" << block_name
136  << "' in the input stream'" << "' not properly ended";
137  ATHENA_ERROR(msg);
138  }
139 
140  pib = FindOrAddBlock(block_name); // find or add block to singly linked list
141 
142  if (pib == nullptr) {
143  msg << "### FATAL ERROR in function [ParameterInput::LoadFromStream]"
144  << std::endl << "Block name '" << block_name
145  << "' could not be found/added";
146  ATHENA_ERROR(msg);
147  }
148  blocks_found++;
149  continue; // skip to next line if block name was found
150  } // end "a new block was found"
151 
152  // if line does not contain a block name or skippable information (comments,
153  // whitespace), it must contain a parameter value
154  if (blocks_found == 0) {
155  msg << "### FATAL ERROR in function [ParameterInput::LoadFromStream]"
156  << std::endl << "Input file must specify a block name before the first"
157  << " parameter = value line";
158  ATHENA_ERROR(msg);
159  }
160  // parse line and add name/value/comment strings (if found) to current block name
161  ParseLine(pib, line, param_name, param_value, param_comment);
162  AddParameter(pib, param_name, param_value, param_comment);
163  }
164  return;
165 }
166 
167 //----------------------------------------------------------------------------------------
169 // \brief Read the parameters from an input file or restarting file.
170 // Return the position at the end of the header, which is used in restarting
171 
172 void ParameterInput::LoadFromFile(IOWrapper &input) {
173  std::stringstream par, msg;
174  constexpr int kBufSize = 4096;
175  char buf[kBufSize];
176  IOWrapperSizeT header = 0, ret, loc;
177 
178  // search <par_end> or EOF.
179  do {
180  if (Globals::my_rank == 0) // only the master process reads the header from the file
181  ret = input.Read(buf, sizeof(char), kBufSize);
182 #ifdef MPI_PARALLEL
183  // then broadcasts it
184  MPI_Bcast(&ret, sizeof(IOWrapperSizeT), MPI_BYTE, 0, MPI_COMM_WORLD);
185  MPI_Bcast(buf, ret, MPI_BYTE, 0, MPI_COMM_WORLD);
186 #endif
187  par.write(buf, ret); // add the buffer into the stream
188  header += ret;
189  std::string sbuf = par.str(); // create string for search
190  loc = sbuf.find("<par_end>", 0); // search from the top of the stream
191  if (loc != std::string::npos) { // found <par_end>
192  header = loc + 10; // store the header length
193  break;
194  }
195  if (header > kBufSize*10) {
196  msg << "### FATAL ERROR in function [ParameterInput::LoadFromFile]"
197  << "<par_end> is not found in the first 40KBytes." << std::endl
198  << "Probably the file is broken or a wrong file is specified" << std::endl;
199  ATHENA_ERROR(msg);
200  }
201  } while (ret == kBufSize); // till EOF (or par_end is found)
202 
203  // Now par contains the parameter inputs + some additional including <par_end>
204  // Read the stream and load the parameters
205  LoadFromStream(par);
206  // Seek the file to the end of the header
207  input.Seek(header);
208 
209  return;
210 }
211 
212 //----------------------------------------------------------------------------------------
214 // \brief find or add specified InputBlock. Returns pointer to block.
215 
217  InputBlock *pib, *plast;
218  plast = pfirst_block;
219  pib = pfirst_block;
220 
221  // Search singly linked list of InputBlocks to see if name exists, return if found.
222  while (pib != nullptr) {
223  if (name.compare(pib->block_name) == 0) return pib;
224  plast = pib;
225  pib = pib->pnext;
226  }
227 
228  // Create new block in list if not found above
229  pib = new InputBlock;
230  pib->block_name.assign(name); // store the new block name
231  pib->pline = nullptr; // Terminate the InputLine list
232  pib->pnext = nullptr; // Terminate the InputBlock list
233 
234  // if this is the first block in list, save pointer to it in class
235  if (pfirst_block == nullptr) {
236  pfirst_block = pib;
237  } else {
238  plast->pnext = pib; // link new node into list
239  }
240 
241  return pib;
242 }
243 
244 //----------------------------------------------------------------------------------------
246 // std::string& name, std::string& value, std::string& comment)
247 // \brief parse "name = value # comment" format, return name/value/comment strings.
248 
250  std::string& name, std::string& value,
251  std::string& comment) {
252  std::size_t first_char, last_char, equal_char, hash_char, len;
253 
254  first_char = line.find_first_not_of(" "); // find first non-white space
255  equal_char = line.find_first_of("="); // find "=" char
256  hash_char = line.find_first_of("#"); // find "#" (optional)
257 
258  // copy substring into name, remove white space at end of name
259  len = equal_char - first_char;
260  name.assign(line, first_char, len);
261 
262  last_char = name.find_last_not_of(" ");
263  name.erase(last_char+1, std::string::npos);
264 
265  // copy substring into value, remove white space at start and end
266  len = hash_char - equal_char - 1;
267  value.assign(line, equal_char+1, len);
268 
269  first_char = value.find_first_not_of(" ");
270  value.erase(0, first_char);
271 
272  last_char = value.find_last_not_of(" ");
273  value.erase(last_char+1, std::string::npos);
274 
275  // copy substring into comment, if present
276  if (hash_char != std::string::npos) {
277  comment = line.substr(hash_char);
278  } else {
279  comment = "";
280  }
281 }
282 
283 //----------------------------------------------------------------------------------------
285 // std::string value, std::string comment)
286 // \brief add name/value/comment tuple to the InputLine singly linked list in block *pb.
287 // If a parameter with the same name already exists, the value and comment strings
288 // are replaced (overwritten).
289 
290 void ParameterInput::AddParameter(InputBlock *pb, std::string name,
291  std::string value, std::string comment) {
292  InputLine *pl, *plast;
293  // Search singly linked list of InputLines to see if name exists. This also sets *plast
294  // to point to the tail node (but not storing a pointer to the tail node in InputBlock)
295  pl = pb->pline;
296  plast = pb->pline;
297  while (pl != nullptr) {
298  if (name.compare(pl->param_name) == 0) { // param name already exists
299  pl->param_value.assign(value); // replace existing param value
300  pl->param_comment.assign(comment); // replace exisiting param comment
301  if (value.length() > pb->max_len_parvalue) pb->max_len_parvalue = value.length();
302  return;
303  }
304  plast = pl;
305  pl = pl->pnext;
306  }
307 
308  // Create new node in singly linked list if name does not already exist
309  pl = new InputLine;
310  pl->param_name.assign(name);
311  pl->param_value.assign(value);
312  pl->param_comment.assign(comment);
313  pl->pnext = nullptr;
314 
315  // if this is the first parameter in list, save pointer to it in block.
316  if (pb->pline == nullptr) {
317  pb->pline = pl;
318  pb->max_len_parname = name.length();
319  pb->max_len_parvalue = value.length();
320  } else {
321  plast->pnext = pl; // link new node into list
322  if (name.length() > pb->max_len_parname) pb->max_len_parname = name.length();
323  if (value.length() > pb->max_len_parvalue) pb->max_len_parvalue = value.length();
324  }
325 
326  return;
327 }
328 
329 //----------------------------------------------------------------------------------------
331 // \brief parse commandline for changes to input parameters
332 // Note this function is very forgiving (no warnings!) if there is an error in format
333 
334 void ParameterInput::ModifyFromCmdline(int argc, char *argv[]) {
335  std::string input_text, block,name, value;
336  std::stringstream msg;
337  InputBlock *pb;
338  InputLine *pl;
339 
340  for (int i=1; i<argc; i++) {
341  input_text = argv[i];
342  std::size_t slash_posn = input_text.find_first_of("/"); // find "/" character
343  std::size_t equal_posn = input_text.find_first_of("="); // find "=" character
344 
345  // skip if either "/" or "=" do not exist in input
346  if ((slash_posn == std::string::npos) || (equal_posn == std::string::npos)) continue;
347 
348  // extract block/name/value strings
349  block = input_text.substr(0, slash_posn);
350  name = input_text.substr(slash_posn+1, (equal_posn - slash_posn - 1));
351  value = input_text.substr(equal_posn+1, std::string::npos);
352 
353  // get pointer to node with same block name in singly linked list of InputBlocks
354  pb = GetPtrToBlock(block);
355  if (pb == nullptr) {
356  msg << "### FATAL ERROR in function [ParameterInput::ModifyFromCmdline]"
357  << std::endl << "Block name '" << block << "' on command line not found";
358  ATHENA_ERROR(msg);
359  }
360 
361  // get pointer to node with same parameter name in singly linked list of InputLines
362  pl = pb->GetPtrToLine(name);
363  if (pl == nullptr) {
364  msg << "### FATAL ERROR in function [ParameterInput::ModifyFromCmdline]"
365  << std::endl << "Parameter '" << name << "' in block '" << block
366  << "' on command line not found";
367  ATHENA_ERROR(msg);
368  }
369  pl->param_value.assign(value); // replace existing value
370 
371  if (value.length() > pb->max_len_parvalue) pb->max_len_parvalue = value.length();
372  }
373 }
374 
375 //----------------------------------------------------------------------------------------
377 // \brief return pointer to specified InputBlock if it exists
378 
380  InputBlock *pb;
381  for (pb = pfirst_block; pb != nullptr; pb = pb->pnext) {
382  if (name.compare(pb->block_name) == 0) return pb;
383  }
384  return nullptr;
385 }
386 
387 //----------------------------------------------------------------------------------------
389 // \brief check whether parameter of given name in given block exists
390 
391 int ParameterInput::DoesParameterExist(std::string block, std::string name) {
392  InputLine *pl;
393  InputBlock *pb;
394  pb = GetPtrToBlock(block);
395  if (pb == nullptr) return 0;
396  pl = pb->GetPtrToLine(name);
397  return (pl == nullptr ? 0 : 1);
398 }
399 
400 //----------------------------------------------------------------------------------------
402 // \brief returns integer value of string stored in block/name
403 
404 int ParameterInput::GetInteger(std::string block, std::string name) {
405  InputBlock* pb;
406  InputLine* pl;
407  std::stringstream msg;
408 
409  Lock();
410 
411  // get pointer to node with same block name in singly linked list of InputBlocks
412  pb = GetPtrToBlock(block);
413  if (pb == nullptr) {
414  msg << "### FATAL ERROR in function [ParameterInput::GetInteger]" << std::endl
415  << "Block name '" << block << "' not found when trying to set value "
416  << "for parameter '" << name << "'";
417  ATHENA_ERROR(msg);
418  }
419 
420  // get pointer to node with same parameter name in singly linked list of InputLines
421  pl = pb->GetPtrToLine(name);
422  if (pl == nullptr) {
423  msg << "### FATAL ERROR in function [ParameterInput::GetInteger]" << std::endl
424  << "Parameter name '" << name << "' not found in block '" << block << "'";
425  ATHENA_ERROR(msg);
426  }
427 
428  std::string val=pl->param_value;
429  Unlock();
430 
431  // Convert string to integer and return value
432  return atoi(val.c_str());
433 }
434 
435 //----------------------------------------------------------------------------------------
437 // \brief returns real value of string stored in block/name
438 
439 Real ParameterInput::GetReal(std::string block, std::string name) {
440  InputBlock* pb;
441  InputLine* pl;
442  std::stringstream msg;
443 
444  Lock();
445 
446  // get pointer to node with same block name in singly linked list of InputBlocks
447  pb = GetPtrToBlock(block);
448  if (pb == nullptr) {
449  msg << "### FATAL ERROR in function [ParameterInput::GetReal]" << std::endl
450  << "Block name '" << block << "' not found when trying to set value "
451  << "for parameter '" << name << "'";
452  ATHENA_ERROR(msg);
453  }
454 
455  // get pointer to node with same parameter name in singly linked list of InputLines
456  pl = pb->GetPtrToLine(name);
457  if (pl == nullptr) {
458  msg << "### FATAL ERROR in function [ParameterInput::GetReal]" << std::endl
459  << "Parameter name '" << name << "' not found in block '" << block << "'";
460  ATHENA_ERROR(msg);
461  }
462 
463  std::string val=pl->param_value;
464  Unlock();
465 
466  // Convert string to real and return value
467  return static_cast<Real>(atof(val.c_str()));
468 }
469 
470 //----------------------------------------------------------------------------------------
472 // \brief returns boolean value of string stored in block/name
473 
474 bool ParameterInput::GetBoolean(std::string block, std::string name) {
475  InputBlock* pb;
476  InputLine* pl;
477  std::stringstream msg;
478 
479  Lock();
480 
481  // get pointer to node with same block name in singly linked list of InputBlocks
482  pb = GetPtrToBlock(block);
483  if (pb == nullptr) {
484  msg << "### FATAL ERROR in function [ParameterInput::GetReal]" << std::endl
485  << "Block name '" << block << "' not found when trying to set value "
486  << "for parameter '" << name << "'";
487  ATHENA_ERROR(msg);
488  }
489 
490  // get pointer to node with same parameter name in singly linked list of InputLines
491  pl = pb->GetPtrToLine(name);
492  if (pl == nullptr) {
493  msg << "### FATAL ERROR in function [ParameterInput::GetReal]" << std::endl
494  << "Parameter name '" << name << "' not found in block '" << block << "'";
495  ATHENA_ERROR(msg);
496  }
497 
498  std::string val=pl->param_value;
499  Unlock();
500 
501  // check is string contains integers 0 or 1 (instead of true or false) and return
502  if (val.compare(0, 1, "0")==0 || val.compare(0, 1, "1")==0) {
503  return static_cast<bool>(atoi(val.c_str()));
504  }
505 
506  // convert string to all lower case
507  std::transform(val.begin(), val.end(), val.begin(), ::tolower);
508  // Convert string to bool and return value
509  bool b;
510  std::istringstream is(val);
511  is >> std::boolalpha >> b;
512 
513  return (b);
514 }
515 
516 //----------------------------------------------------------------------------------------
518 // \brief returns string stored in block/name
519 
520 std::string ParameterInput::GetString(std::string block, std::string name) {
521  InputBlock* pb;
522  InputLine* pl;
523  std::stringstream msg;
524 
525  Lock();
526 
527  // get pointer to node with same block name in singly linked list of InputBlocks
528  pb = GetPtrToBlock(block);
529  if (pb == nullptr) {
530  msg << "### FATAL ERROR in function [ParameterInput::GetReal]" << std::endl
531  << "Block name '" << block << "' not found when trying to set value "
532  << "for parameter '" << name << "'";
533  ATHENA_ERROR(msg);
534  }
535 
536  // get pointer to node with same parameter name in singly linked list of InputLines
537  pl = pb->GetPtrToLine(name);
538  if (pl == nullptr) {
539  msg << "### FATAL ERROR in function [ParameterInput::GetReal]" << std::endl
540  << "Parameter name '" << name << "' not found in block '" << block << "'";
541  ATHENA_ERROR(msg);
542  }
543 
544  std::string val=pl->param_value;
545  Unlock();
546 
547  // return value
548  return val;
549 }
550 
551 //----------------------------------------------------------------------------------------
553 // int default_value)
554 // \brief returns integer value stored in block/name if it exists, or creates and sets
555 // value to def_value if it does not exist
556 
557 int ParameterInput::GetOrAddInteger(std::string block, std::string name, int def_value) {
558  InputBlock* pb;
559  InputLine *pl;
560  std::stringstream ss_value;
561  int ret;
562 
563  Lock();
564  if (DoesParameterExist(block, name)) {
565  pb = GetPtrToBlock(block);
566  pl = pb->GetPtrToLine(name);
567  std::string val = pl->param_value;
568  ret = atoi(val.c_str());
569  } else {
570  pb = FindOrAddBlock(block);
571  ss_value << def_value;
572  AddParameter(pb, name, ss_value.str(), "# Default value added at run time");
573  ret = def_value;
574  }
575  Unlock();
576  return ret;
577 }
578 
579 //----------------------------------------------------------------------------------------
581 // Real def_value)
582 // \brief returns real value stored in block/name if it exists, or creates and sets
583 // value to def_value if it does not exist
584 
585 Real ParameterInput::GetOrAddReal(std::string block, std::string name, Real def_value) {
586  InputBlock* pb;
587  InputLine *pl;
588  std::stringstream ss_value;
589  Real ret;
590 
591  Lock();
592  if (DoesParameterExist(block, name)) {
593  pb = GetPtrToBlock(block);
594  pl = pb->GetPtrToLine(name);
595  std::string val = pl->param_value;
596  ret = static_cast<Real>(atof(val.c_str()));
597  } else {
598  pb = FindOrAddBlock(block);
599  ss_value << def_value;
600  AddParameter(pb, name, ss_value.str(), "# Default value added at run time");
601  ret = def_value;
602  }
603  Unlock();
604  return ret;
605 }
606 
607 //----------------------------------------------------------------------------------------
609 // bool def_value)
610 // \brief returns boolean value stored in block/name if it exists, or creates and sets
611 // value to def_value if it does not exist
612 
613 bool ParameterInput::GetOrAddBoolean(std::string block,std::string name, bool def_value) {
614  InputBlock* pb;
615  InputLine *pl;
616  std::stringstream ss_value;
617  bool ret;
618 
619  Lock();
620  if (DoesParameterExist(block, name)) {
621  pb = GetPtrToBlock(block);
622  pl = pb->GetPtrToLine(name);
623  std::string val = pl->param_value;
624  if (val.compare(0, 1, "0")==0 || val.compare(0, 1, "1")==0) {
625  ret = static_cast<bool>(atoi(val.c_str()));
626  } else {
627  std::transform(val.begin(), val.end(), val.begin(), ::tolower);
628  std::istringstream is(val);
629  is >> std::boolalpha >> ret;
630  }
631  } else {
632  pb = FindOrAddBlock(block);
633  ss_value << def_value;
634  AddParameter(pb, name, ss_value.str(), "# Default value added at run time");
635  ret = def_value;
636  }
637  Unlock();
638  return ret;
639 }
640 
641 //----------------------------------------------------------------------------------------
643 // std::string def_value)
644 // \brief returns string value stored in block/name if it exists, or creates and sets
645 // value to def_value if it does not exist
646 
647 std::string ParameterInput::GetOrAddString(std::string block, std::string name,
648  std::string def_value) {
649  InputBlock* pb;
650  InputLine *pl;
651  std::stringstream ss_value;
652  std::string ret;
653 
654  Lock();
655  if (DoesParameterExist(block, name)) {
656  pb = GetPtrToBlock(block);
657  pl = pb->GetPtrToLine(name);
658  ret = pl->param_value;
659  } else {
660  pb = FindOrAddBlock(block);
661  AddParameter(pb, name, def_value, "# Default value added at run time");
662  ret = def_value;
663  }
664  Unlock();
665  return ret;
666 }
667 
668 //----------------------------------------------------------------------------------------
670 // \brief updates an integer parameter; creates it if it does not exist
671 
672 int ParameterInput::SetInteger(std::string block, std::string name, int value) {
673  InputBlock* pb;
674  std::stringstream ss_value;
675 
676  Lock();
677  pb = FindOrAddBlock(block);
678  ss_value << value;
679  AddParameter(pb, name, ss_value.str(), "# Updated during run time");
680  Unlock();
681  return value;
682 }
683 
684 //----------------------------------------------------------------------------------------
686 // \brief updates a real parameter; creates it if it does not exist
687 
688 Real ParameterInput::SetReal(std::string block, std::string name, Real value) {
689  InputBlock* pb;
690  std::stringstream ss_value;
691 
692  Lock();
693  pb = FindOrAddBlock(block);
694  ss_value << value;
695  AddParameter(pb, name, ss_value.str(), "# Updated during run time");
696  Unlock();
697  return value;
698 }
699 
700 //----------------------------------------------------------------------------------------
702 // \brief updates a boolean parameter; creates it if it does not exist
703 
704 bool ParameterInput::SetBoolean(std::string block, std::string name, bool value) {
705  InputBlock* pb;
706  std::stringstream ss_value;
707 
708  Lock();
709  pb = FindOrAddBlock(block);
710  ss_value << value;
711  AddParameter(pb, name, ss_value.str(), "# Updated during run time");
712  Unlock();
713  return value;
714 }
715 
716 //----------------------------------------------------------------------------------------
718 // std::string value)
719 // \brief updates a string parameter; creates it if it does not exist
720 
721 std::string ParameterInput::SetString(std::string block, std::string name,
722  std::string value) {
723  InputBlock* pb;
724 
725  Lock();
726  pb = FindOrAddBlock(block);
727  AddParameter(pb, name, value, "# Updated during run time");
728  Unlock();
729  return value;
730 }
731 
732 //----------------------------------------------------------------------------------------
734 // \brief rollback next_time by dt for each output block
735 
737  InputBlock *pb = pfirst_block;
738  InputLine* pl;
739  std::stringstream msg;
740  Real next_time;
741 
742  while (pb != nullptr) {
743  if (pb->block_name.compare(0, 6, "output") == 0) {
744  pl = pb->GetPtrToLine("next_time");
745  if (pl == nullptr) {
746  msg << "### FATAL ERROR in function [ParameterInput::RollbackNextTime]"
747  << std::endl << "Parameter name 'next_time' not found in block '"
748  << pb->block_name << "'";
749  ATHENA_ERROR(msg);
750  }
751  next_time = static_cast<Real>(atof(pl->param_value.c_str()));
752  pl = pb->GetPtrToLine("dt");
753  if (pl == nullptr) {
754  msg << "### FATAL ERROR in function [ParameterInput::RollbackNextTime]"
755  << std::endl << "Parameter name 'dt' not found in block '"
756  << pb->block_name << "'";
757  ATHENA_ERROR(msg);
758  }
759  next_time -= static_cast<Real>(atof(pl->param_value.c_str()));
760  msg << next_time;
761  //AddParameter(pb, "next_time", msg.str().c_str(), "# Updated during run time");
762  SetReal(pb->block_name, "next_time", next_time);
763  }
764  pb = pb->pnext;
765  }
766 }
767 
768 //----------------------------------------------------------------------------------------
770 // \brief add dt to next_time until next_time > mesh_time - dt for each output block
771 
773  InputBlock *pb = pfirst_block;
774  InputLine* pl;
775  Real next_time;
776  Real dt0, dt;
777  bool fresh = false;
778 
779  while (pb != nullptr) {
780  if (pb->block_name.compare(0, 6, "output") == 0) {
781  std::stringstream msg;
782  pl = pb->GetPtrToLine("next_time");
783  if (pl == nullptr) {
784  next_time = mesh_time;
785  // This is a freshly added output
786  fresh = true;
787  } else {
788  next_time = static_cast<Real>(atof(pl->param_value.c_str()));
789  }
790  pl = pb->GetPtrToLine("dt");
791  if (pl == nullptr) {
792  msg << "### FATAL ERROR in function [ParameterInput::ForwardNextTime]"
793  << std::endl << "Parameter name 'dt' not found in block '"
794  << pb->block_name << "'";
795  ATHENA_ERROR(msg);
796  }
797  dt0 = static_cast<Real>(atof(pl->param_value.c_str()));
798  dt = dt0 * static_cast<int>((mesh_time - next_time) / dt0) + dt0;
799  if (dt > 0) {
800  next_time += dt;
801  // If the user has added a new/fresh output round to multiple of dt0,
802  // and make sure that mesh_time - dt0 < next_time < mesh_time,
803  // to ensure immediate writing
804  if (fresh) next_time -= std::fmod(next_time, dt0) + dt0;
805  }
806  msg << next_time;
807  AddParameter(pb, "next_time", msg.str().c_str(), "# Updated during run time");
808  }
809  pb = pb->pnext;
810  }
811 }
812 
813 //----------------------------------------------------------------------------------------
815 // \brief output entire InputBlock/InputLine hierarchy to specified stream
816 
817 void ParameterInput::ParameterDump(std::ostream& os) {
818  InputBlock *pb;
819  InputLine *pl;
820  std::string param_name,param_value;
821  std::size_t len;
822 
823  os<< "#------------------------- PAR_DUMP -------------------------" << std::endl;
824 
825  for (pb = pfirst_block; pb != nullptr; pb = pb->pnext) { // loop over InputBlocks
826  os<< "<" << pb->block_name << ">" << std::endl; // write block name
827  for (pl = pb->pline; pl != nullptr; pl = pl->pnext) { // loop over InputLines
828  param_name.assign(pl->param_name);
829  param_value.assign(pl->param_value);
830 
831  len = pb->max_len_parname - param_name.length() + 1;
832  param_name.append(len,' '); // pad name to align vertically
833  len = pb->max_len_parvalue - param_value.length() + 1;
834  param_value.append(len,' '); // pad value to align vertically
835 
836  os<< param_name << "= " << param_value << pl->param_comment << std::endl;
837  }
838  }
839 
840  os<< "#------------------------- PAR_DUMP -------------------------" << std::endl;
841  os<< "<par_end>" << std::endl; // finish with par-end (useful in restart files)
842 }
843 
844 //----------------------------------------------------------------------------------------
846 // \brief return pointer to InputLine containing specified parameter if it exists
847 
849  for (InputLine* pl = pline; pl != nullptr; pl = pl->pnext) {
850  if (name.compare(pl->param_name) == 0) return pl;
851  }
852  return nullptr;
853 }
854 
855 
856 //----------------------------------------------------------------------------------------
858 // \brief Lock ParameterInput for reading and writing
860 #ifdef OPENMP_PARALLEL
861  omp_set_lock(&lock_);
862 #endif
863  return;
864 }
865 
866 //----------------------------------------------------------------------------------------
868 // \brief Unlock ParameterInput for reading and writing
870 #ifdef OPENMP_PARALLEL
871  omp_unset_lock(&lock_);
872 #endif
873  return;
874 }
double Real
Definition: athena.hpp:29
InputLine * GetPtrToLine(std::string name)
std::size_t max_len_parvalue
std::size_t max_len_parname
InputLine * pline
InputBlock * pnext
std::string block_name
Real GetReal(std::string block, std::string name)
int DoesParameterExist(std::string block, std::string name)
void AddParameter(InputBlock *pib, std::string name, std::string value, std::string comment)
void LoadFromStream(std::istream &is)
std::string GetString(std::string block, std::string name)
void ParseLine(InputBlock *pib, std::string line, std::string &name, std::string &value, std::string &comment)
void ParameterDump(std::ostream &os)
int GetOrAddInteger(std::string block, std::string name, int value)
int GetInteger(std::string block, std::string name)
InputBlock * GetPtrToBlock(std::string name)
int SetInteger(std::string block, std::string name, int value)
Real SetReal(std::string block, std::string name, Real value)
bool GetBoolean(std::string block, std::string name)
std::string GetOrAddString(std::string block, std::string name, std::string value)
bool GetOrAddBoolean(std::string block, std::string name, bool value)
bool SetBoolean(std::string block, std::string name, bool value)
std::string SetString(std::string block, std::string name, std::string value)
void ModifyFromCmdline(int argc, char *argv[])
void ParameterInput::ModifyFromCmdline(int argc, char *argv[])
void LoadFromFile(IOWrapper &input)
InputBlock * FindOrAddBlock(std::string name)
Real GetOrAddReal(std::string block, std::string name, Real value)
InputBlock * pfirst_block
void ForwardNextTime(Real time)
int my_rank
Definition: globals.cpp:23
std::string param_value
std::string param_name
std::string param_comment
InputLine * pnext