Nektar++
BasicUtils/SessionReader.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: SessionReader.cpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Session reader
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
35 #ifndef TIXML_USE_STL
36 #define TIXML_USE_STL
37 #endif
38 
41 
42 #include <fstream>
43 #include <iostream>
44 #include <string>
45 
46 #include <boost/algorithm/string.hpp>
47 #include <boost/iostreams/copy.hpp>
48 #include <boost/iostreams/filter/gzip.hpp>
49 #include <boost/iostreams/filtering_streambuf.hpp>
50 
51 #include <tinyxml.h>
52 
60 
61 #include <boost/format.hpp>
62 #include <boost/program_options.hpp>
63 
64 #ifndef NEKTAR_VERSION
65 #define NEKTAR_VERSION "Unknown"
66 #endif
67 
68 using namespace std;
69 
70 namespace po = boost::program_options;
71 namespace io = boost::iostreams;
72 
73 namespace Nektar
74 {
75 namespace LibUtilities
76 {
77 /**
78  * @class SessionReader
79  *
80  * This class provides an interface to Nektar++-specific content in a
81  * supplied XML document. It also initialises a Nektar++ session
82  * including setting up communication for parallel execution and where
83  * necessary partitioning the supplied mesh for running across multiple
84  * processes.
85  *
86  * A session should be initialised at the beginning of a user's
87  * application by passing the command-line arguments. This not only
88  * allows the SessionReader to extract the name of the XML document to
89  * load containing Nektar++ session information, but also supplies the
90  * MPI arguments necessary for setting up parallel communication. The
91  * SessionReader should be initialised using the #CreateInstance
92  * function:
93  * @code
94  * LibUtilities::SessionReaderSharedPtr vSession
95  * = LibUtilities::SessionReader::CreateInstance(argc, argv);
96  * @endcode
97  * The instance \c vSession can now be passed to other key Nektar++
98  * components during their construction.
99  * @note At the end of the user application, it is important to call the
100  * #Finalise routine in order to finalise any MPI communication and
101  * correctly free resources.
102  *
103  * The SessionReader class provides streamlined, validated access to
104  * session parameters, solver information and functions defined within a
105  * Nektar++ XML document. The available routines and their usage is
106  * documented below.
107  *
108  * In the case of solver information properties, the classes to which
109  * these parameters are pertinent may register with the SessionReader
110  * class the set of valid values for a given property. Such values may
111  * also be associated with an enumeration value for more transparent use
112  * of the property values in code.
113  */
114 
115 /**
116  * This map of maps stores the list of valid string values for a number
117  * of solver information parameters. The top level map connects
118  * different parameter names to their list of possible values. The list
119  * of possible values is also a map, mapping a valid string to a
120  * corresponding enum value.
121  *
122  * This list is populated through the #RegisterEnumValue static member
123  * function which is called statically from various classes to register
124  * the valid values for solver info parameters associated with them. The
125  * map is therefore fully populated before the SessionReader class is
126  * instantiated and a file is read in and parsed.
127  */
128 EnumMapList &SessionReader::GetSolverInfoEnums()
129 {
130  static EnumMapList solverInfoEnums;
131  return solverInfoEnums;
132 }
133 
134 /**
135  * List of default values for solver information parameters to be used
136  * in the case of them not being provided.
137  *
138  * This list is populated through the #RegisterDefaultSolverInfo static
139  * member variable which is called statically from various classes to
140  * register the default value for a given parameter.
141  */
142 SolverInfoMap &SessionReader::GetSolverInfoDefaults()
143 {
144  static SolverInfoMap solverInfoMap;
145  return solverInfoMap;
146 }
147 
148 /**
149  * List of values for GlobalSysSoln parameters to be used to override
150  * details given in SolverInfo
151  *
152  * This list is populated by ReadGlobalSysSoln if the
153  * GLOBALSYSSOLNINFO section is defined in the input file.
154  * This List allows for details to define for the Global Sys
155  * solver for each variable.
156  */
157 GloSysSolnInfoList &SessionReader::GetGloSysSolnList()
158 {
159  static GloSysSolnInfoList gloSysSolnInfoList;
160  return gloSysSolnInfoList;
161 }
162 
163 /**
164  * Lists the possible command-line argument which can be specified for
165  * this executable.
166  *
167  * This list is populated through the #RegisterCmdLineArgument static
168  * member function which is called statically from various classes to
169  * register command-line arguments they need.
170  */
171 CmdLineArgMap &SessionReader::GetCmdLineArgMap()
172 {
173  static CmdLineArgMap cmdLineArguments;
174  return cmdLineArguments;
175 }
176 
177 /**
178  * This constructor parses the command-line arguments given to the user
179  * application to set up any MPI communication, read supplied XML
180  * session files, and partition meshes where necessary.
181  *
182  * @param argc Number of command-line arguments
183  * @param argv Array of command-line arguments
184  */
185 SessionReader::SessionReader(int argc, char *argv[])
186 {
187  m_xmlDoc = 0;
188  m_filenames = ParseCommandLineArguments(argc, argv);
189 
190  ASSERTL0(m_filenames.size() > 0, "No session file(s) given.");
191 
192  m_sessionName = ParseSessionName(m_filenames);
193 
194  // Create communicator
195  CreateComm(argc, argv);
196 
197  TestSharedFilesystem();
198 
199  // If running in parallel change the default global sys solution
200  // type.
201  if (m_comm->GetSize() > 1)
202  {
203  GetSolverInfoDefaults()["GLOBALSYSSOLN"] = "IterativeStaticCond";
204  }
205 
207  m_interpreter->SetRandomSeed((m_comm->GetRank() + 1) *
208  (unsigned int)time(NULL));
209 
210  // Split up the communicator
211  PartitionComm();
212 }
213 
214 /**
215  *
216  */
217 SessionReader::SessionReader(int argc, char *argv[],
218  const std::vector<std::string> &pFilenames,
219  const CommSharedPtr &pComm)
220 {
221  ASSERTL0(pFilenames.size() > 0, "No filenames specified.");
222 
223  ParseCommandLineArguments(argc, argv);
224  m_xmlDoc = 0;
225  m_filenames = pFilenames;
226 
227  m_sessionName = ParseSessionName(m_filenames);
228 
229  // Create communicator
230  if (!pComm.get())
231  {
232  CreateComm(argc, argv);
233  }
234  else
235  {
236  m_comm = pComm;
237  }
238 
239  TestSharedFilesystem();
240 
241  // If running in parallel change the default global sys solution
242  // type.
243  if (m_comm->GetSize() > 1)
244  {
245  GetSolverInfoDefaults()["GLOBALSYSSOLN"] = "IterativeStaticCond";
246  }
247 
249  m_interpreter->SetRandomSeed((m_comm->GetRank() + 1) *
250  (unsigned int)time(NULL));
251 
252  // Split up the communicator
253  PartitionComm();
254 }
255 
256 /**
257  *
258  */
259 SessionReader::~SessionReader()
260 {
261  if (m_xmlDoc)
262  {
263  delete m_xmlDoc;
264  }
265 }
266 
267 /**
268  * Performs the main initialisation of the object. The XML file provided
269  * on the command-line is loaded and any mesh partitioning is done. The
270  * resulting process-specific XML file (containing the process's
271  * geometry partition) is then reloaded and parsed.
272  */
273 void SessionReader::InitSession(const std::vector<std::string> &filenames)
274 {
275  // Re-load filenames for session if required.
276  if (filenames.size() > 0)
277  {
278  m_filenames = filenames;
279  }
280 
281  // check specified opt file
282  std::string optfile;
283  int exists;
284 
285  if (DefinesCmdLineArgument("useoptfile"))
286  {
287  optfile = m_cmdLineOptions.find("useoptfile")->second.as<std::string>();
288  exists = (bool)boost::filesystem::exists(optfile.c_str());
289  ASSERTL0(exists, "A valid .opt file was not specified "
290  "with the --useoptfile command line option");
291 
292  m_filenames.push_back(optfile);
293 
294  // put opt file at beginning
295  std::rotate(m_filenames.rbegin(), m_filenames.rbegin() + 1,
296  m_filenames.rend());
297  }
298  else // check for writeoptfile
299  {
300  // check for opt file
301  optfile = m_sessionName + ".opt";
302  exists = (bool)boost::filesystem::exists(optfile.c_str());
303  if (exists)
304  {
305  m_filenames.push_back(optfile);
306  // rotate order so opt file can be overwritten by
307  // direct choice in xml file
308  std::rotate(m_filenames.rbegin(), m_filenames.rbegin() + 1,
309  m_filenames.rend());
310  }
311  else
312  {
313  m_updateOptFile = true;
314  }
315  }
316 
317  // Merge document if required.
318  if (m_xmlDoc)
319  {
320  delete m_xmlDoc;
321  }
322 
323  m_xmlDoc = MergeDoc(m_filenames);
324 
325  // Parse the XML data in #m_xmlDoc
326  ParseDocument();
327 
328  // Override SOLVERINFO and parameters with any specified on the
329  // command line.
330  CmdLineOverride();
331 
332  // Verify SOLVERINFO values
333  VerifySolverInfo();
334 
335  // Disable backups if NEKTAR_DISABLE_BACKUPS is set.
336  if (std::getenv("NEKTAR_DISABLE_BACKUPS") != nullptr)
337  {
338  m_backups = false;
339  }
340 
341  // In verbose mode, print out parameters and solver info sections
342  if (m_verbose && m_comm)
343  {
344  if (m_comm->TreatAsRankZero() && m_parameters.size() > 0)
345  {
346  cout << "Parameters:" << endl;
347  for (auto &x : m_parameters)
348  {
349  cout << "\t" << x.first << " = " << x.second << endl;
350  }
351  cout << endl;
352  }
353 
354  if (m_comm->TreatAsRankZero() && m_solverInfo.size() > 0)
355  {
356  cout << "Solver Info:" << endl;
357  for (auto &x : m_solverInfo)
358  {
359  cout << "\t" << x.first << " = " << x.second << endl;
360  }
361  cout << endl;
362  }
363  }
364 }
365 
366 void SessionReader::TestSharedFilesystem()
367 {
368  m_sharedFilesystem = false;
369 
370  if (m_comm->GetSize() > 1)
371  {
372  if (m_comm->GetRank() == 0)
373  {
374  std::ofstream testfile("shared-fs-testfile");
375  testfile << "" << std::endl;
376  ASSERTL1(!testfile.fail(), "Test file creation failed");
377  testfile.close();
378  }
379  m_comm->Block();
380 
381  int exists = (bool)boost::filesystem::exists("shared-fs-testfile");
382  m_comm->AllReduce(exists, LibUtilities::ReduceSum);
383 
384  m_sharedFilesystem = (exists == m_comm->GetSize());
385 
386  if ((m_sharedFilesystem && m_comm->GetRank() == 0) ||
387  !m_sharedFilesystem)
388  {
389  std::remove("shared-fs-testfile");
390  }
391  }
392  else
393  {
394  m_sharedFilesystem = false;
395  }
396 
397  if (m_verbose && m_comm->GetRank() == 0 && m_sharedFilesystem)
398  {
399  cout << "Shared filesystem detected" << endl;
400  }
401 }
402 
403 /**
404  * @brief Parses the command-line arguments for known options and
405  * filenames.
406  */
407 std::vector<std::string> SessionReader::ParseCommandLineArguments(int argc,
408  char *argv[])
409 {
410  // List the publically visible options (listed using --help).
411  po::options_description desc("Allowed options");
412 
413  // clang-format off
414  desc.add_options()
415  ("verbose,v", "be verbose")
416  ("version,V", "print version information")
417  ("help,h", "print this help message")
418  ("solverinfo,I", po::value<vector<std::string> >(),
419  "override a SOLVERINFO property")
420  ("parameter,P", po::value<vector<std::string> >(),
421  "override a parameter")
422  ("npx", po::value<int>(),
423  "number of procs in X-dir")
424  ("npy", po::value<int>(),
425  "number of procs in Y-dir")
426  ("npz", po::value<int>(),
427  "number of procs in Z-dir")
428  ("nsz", po::value<int>(),
429  "number of slices in Z-dir")
430  ("npt", po::value<int>(),
431  "number of procs in T-dir (parareal)")
432  ("part-only", po::value<int>(),
433  "only partition mesh into N partitions.")
434  ("part-only-overlapping", po::value<int>(),
435  "only partition mesh into N overlapping partitions.")
436  ("part-info", "Output partition information")
437  ("forceoutput,f", "Disables backups files and forces output to be "
438  "written without any checks")
439  ("writeoptfile", "write an optimisation file")
440  ("useoptfile", po::value<std::string>(),
441  "use an optimisation file");
442  // clang-format on
443 #ifdef NEKTAR_USE_CWIPI
444  desc.add_options()("cwipi", po::value<std::string>(), "set CWIPI name");
445 #endif
446 
447  for (auto &cmdIt : GetCmdLineArgMap())
448  {
449  std::string names = cmdIt.first;
450  if (cmdIt.second.shortName != "")
451  {
452  names += "," + cmdIt.second.shortName;
453  }
454  if (cmdIt.second.isFlag)
455  {
456  desc.add_options()(names.c_str(), cmdIt.second.description.c_str());
457  }
458  else
459  {
460  desc.add_options()(names.c_str(), po::value<std::string>(),
461  cmdIt.second.description.c_str());
462  }
463  }
464 
465  // List hidden options (e.g. session file arguments are not actually
466  // specified using the input-file option by the user).
467  po::options_description hidden("Hidden options");
468 
469  hidden.add_options()("input-file", po::value<vector<string>>(),
470  "input filename");
471 
472  // Combine all options for the parser
473  po::options_description all("All options");
474  all.add(desc).add(hidden);
475 
476  // Session file is a positional option
477  po::positional_options_description p;
478  p.add("input-file", -1);
479 
480  // Parse the command-line options
481  po::parsed_options parsed = po::command_line_parser(argc, argv)
482  .options(all)
483  .positional(p)
484  .allow_unregistered()
485  .run();
486 
487  // Extract known options to map and update
488  po::store(parsed, m_cmdLineOptions);
489  po::notify(m_cmdLineOptions);
490 
491  // Help message
492  if (m_cmdLineOptions.count("help"))
493  {
494  cout << desc;
495  exit(0);
496  }
497 
498  // Version information
499  if (m_cmdLineOptions.count("version"))
500  {
501  cout << "Nektar++ version " << NEKTAR_VERSION;
502 
503  if (NekConstants::kGitSha1 != "GITDIR-NOTFOUND")
504  {
505  string sha1(NekConstants::kGitSha1);
506  string branch(NekConstants::kGitBranch);
507  boost::replace_all(branch, "refs/heads/", "");
508 
509  cout << " (git changeset " << sha1.substr(0, 8) << ", ";
510 
511  if (branch == "")
512  {
513  cout << "detached head";
514  }
515  else
516  {
517  cout << "head " << branch;
518  }
519 
520  cout << ")";
521  }
522 
523  cout << endl;
524  exit(0);
525  }
526 
527  // Enable verbose mode
528  if (m_cmdLineOptions.count("verbose"))
529  {
530  m_verbose = true;
531  }
532  else
533  {
534  m_verbose = false;
535  }
536 
537  // Disable backups
538  if (m_cmdLineOptions.count("forceoutput"))
539  {
540  m_backups = false;
541  }
542  else
543  {
544  m_backups = true;
545  }
546 
547  // Enable update optimisation file
548  if (m_cmdLineOptions.count("writeoptfile"))
549  {
550  m_updateOptFile = true;
551  }
552  else
553  {
554  m_updateOptFile = false;
555  }
556 
557  // Print a warning for unknown options
558  for (auto &x : parsed.options)
559  {
560  if (x.unregistered)
561  {
562  cout << "Warning: Unknown option: " << x.string_key << endl;
563  }
564  }
565 
566  // Return the vector of filename(s) given as positional options
567  if (m_cmdLineOptions.count("input-file"))
568  {
569  return m_cmdLineOptions["input-file"].as<std::vector<std::string>>();
570  }
571  else
572  {
573  return std::vector<std::string>();
574  }
575 }
576 
577 /**
578  *
579  */
580 std::string SessionReader::ParseSessionName(std::vector<std::string> &filenames)
581 {
582  ASSERTL0(!filenames.empty(), "At least one filename expected.");
583 
584  std::string retval = "";
585 
586  // First input file defines the session name
587  std::string fname = filenames[0];
588 
589  // If loading a pre-partitioned mesh, remove _xml extension
590  if (fname.size() > 4 && fname.substr(fname.size() - 4, 4) == "_xml")
591  {
592  retval = fname.substr(0, fname.find_last_of("_"));
593  }
594  // otherwise remove the .xml extension
595  else if (fname.size() > 4 && fname.substr(fname.size() - 4, 4) == ".xml")
596  {
597  retval = fname.substr(0, fname.find_last_of("."));
598  }
599  // If compressed .xml.gz, remove both extensions
600  else if (fname.size() > 7 && fname.substr(fname.size() - 7, 7) == ".xml.gz")
601  {
602  retval = fname.substr(0, fname.find_last_of("."));
603  retval = retval.substr(0, retval.find_last_of("."));
604  }
605 
606  return retval;
607 }
608 
609 /**
610  *
611  */
612 TiXmlDocument &SessionReader::GetDocument()
613 {
614  ASSERTL1(m_xmlDoc, "XML Document not defined.");
615  return *m_xmlDoc;
616 }
617 
618 /**
619  * The single parameter specifies a path to the requested element in a
620  * similar format to the filesystem path. Given the following XML:
621  * @code
622  * <NEKTAR>
623  * <CONDITIONS>
624  * <PARAMETERS>
625  * ...
626  * </PARAMETERS>
627  * </CONDITIONS>
628  * </NEKTAR>
629  * @endcode
630  * the PARAMETERS element would be retrieved by requesting the path:
631  * @code
632  * Nektar/Conditions/Parameters
633  * @endcode
634  * @note Paths are case-insensitive.
635  *
636  * @param pPath Path to requested element.
637  *
638  * @return Direct pointer to requested XML Element.
639  */
640 TiXmlElement *SessionReader::GetElement(const string &pPath)
641 {
642  std::string vPath = boost::to_upper_copy(pPath);
643  std::vector<std::string> st;
644  boost::split(st, vPath, boost::is_any_of("\\/ "));
645  ASSERTL0(st.size() > 0, "No path given in XML element request.");
646 
647  TiXmlElement *vReturn = m_xmlDoc->FirstChildElement(st[0].c_str());
648  ASSERTL0(vReturn,
649  std::string("Cannot find element '") + st[0] + std::string("'."));
650  for (int i = 1; i < st.size(); ++i)
651  {
652  vReturn = vReturn->FirstChildElement(st[i].c_str());
653  ASSERTL0(vReturn, std::string("Cannot find element '") + st[i] +
654  std::string("'."));
655  }
656  return vReturn;
657 }
658 
659 /**
660  *
661  */
662 bool SessionReader::DefinesElement(const std::string &pPath) const
663 {
664  std::string vPath = boost::to_upper_copy(pPath);
665  std::vector<std::string> st;
666  boost::split(st, vPath, boost::is_any_of("\\/ "));
667  ASSERTL0(st.size() > 0, "No path given in XML element request.");
668 
669  TiXmlElement *vReturn = m_xmlDoc->FirstChildElement(st[0].c_str());
670  ASSERTL0(vReturn,
671  std::string("Cannot find element '") + st[0] + std::string("'."));
672  for (int i = 1; i < st.size(); ++i)
673  {
674  vReturn = vReturn->FirstChildElement(st[i].c_str());
675  if (!vReturn)
676  return false;
677  }
678  return true;
679 }
680 
681 /**
682  *
683  */
684 const std::vector<std::string> &SessionReader::GetFilenames() const
685 {
686  return m_filenames;
687 }
688 
689 /**
690  *
691  */
692 const std::string &SessionReader::GetSessionName() const
693 {
694  return m_sessionName;
695 }
696 
697 /**
698  * Output is of the form [sessionName]_P[idx] where idx is the rank
699  * of the process.
700  */
701 const std::string SessionReader::GetSessionNameRank() const
702 {
703  std::string dirname = m_sessionName + "_xml";
704  fs::path pdirname(dirname);
705 
706  std::string vFilename =
707  "P" + boost::lexical_cast<std::string>(m_comm->GetRowComm()->GetRank());
708  fs::path pFilename(vFilename);
709 
710  fs::path fullpath = pdirname / pFilename;
711 
712  return PortablePath(fullpath);
713 }
714 
715 /**
716  *
717  */
718 CommSharedPtr SessionReader::GetComm()
719 {
720  return m_comm;
721 }
722 
723 bool SessionReader::GetSharedFilesystem()
724 {
725  return m_sharedFilesystem;
726 }
727 
728 /**
729  * This routine finalises any parallel communication.
730  *
731  * @note This routine should be called at the very end of a users
732  * application.
733  */
735 {
736  m_comm->Finalise();
737 }
738 
739 /**
740  *
741  */
742 bool SessionReader::DefinesParameter(const std::string &pName) const
743 {
744  std::string vName = boost::to_upper_copy(pName);
745  return m_parameters.find(vName) != m_parameters.end();
746 }
747 
748 /**
749  * If the parameter is not defined, termination occurs. Therefore, the
750  * parameters existence should be tested for using #DefinesParameter
751  * before calling this function.
752  *
753  * @param pName The name of a floating-point parameter.
754  * @returns The value of the floating-point parameter.
755  */
756 const NekDouble &SessionReader::GetParameter(const std::string &pName) const
757 {
758  std::string vName = boost::to_upper_copy(pName);
759  auto paramIter = m_parameters.find(vName);
760 
761  ASSERTL0(paramIter != m_parameters.end(),
762  "Unable to find requested parameter: " + pName);
763 
764  return paramIter->second;
765 }
766 
767 /**
768  *
769  */
770 void SessionReader::LoadParameter(const std::string &pName, int &pVar) const
771 {
772  std::string vName = boost::to_upper_copy(pName);
773  auto paramIter = m_parameters.find(vName);
774  ASSERTL0(paramIter != m_parameters.end(),
775  "Required parameter '" + pName + "' not specified in session.");
776  NekDouble param = round(paramIter->second);
777  pVar = checked_cast<int>(param);
778 }
779 
780 /**
781  *
782  */
783 void SessionReader::LoadParameter(const std::string &pName, int &pVar,
784  const int &pDefault) const
785 {
786  std::string vName = boost::to_upper_copy(pName);
787  auto paramIter = m_parameters.find(vName);
788  if (paramIter != m_parameters.end())
789  {
790  NekDouble param = round(paramIter->second);
791  pVar = checked_cast<int>(param);
792  }
793  else
794  {
795  pVar = pDefault;
796  }
797 }
798 
799 /**
800  *
801  */
802 void SessionReader::LoadParameter(const std::string &pName, size_t &pVar) const
803 {
804  std::string vName = boost::to_upper_copy(pName);
805  auto paramIter = m_parameters.find(vName);
806  ASSERTL0(paramIter != m_parameters.end(),
807  "Required parameter '" + pName + "' not specified in session.");
808  NekDouble param = round(paramIter->second);
809  pVar = checked_cast<int>(param);
810 }
811 
812 /**
813  *
814  */
815 void SessionReader::LoadParameter(const std::string &pName, size_t &pVar,
816  const size_t &pDefault) const
817 {
818  std::string vName = boost::to_upper_copy(pName);
819  auto paramIter = m_parameters.find(vName);
820  if (paramIter != m_parameters.end())
821  {
822  NekDouble param = round(paramIter->second);
823  pVar = checked_cast<int>(param);
824  }
825  else
826  {
827  pVar = pDefault;
828  }
829 }
830 
831 /**
832  *
833  */
834 void SessionReader::LoadParameter(const std::string &pName,
835  NekDouble &pVar) const
836 {
837  std::string vName = boost::to_upper_copy(pName);
838  auto paramIter = m_parameters.find(vName);
839  ASSERTL0(paramIter != m_parameters.end(),
840  "Required parameter '" + pName + "' not specified in session.");
841  pVar = paramIter->second;
842 }
843 
844 /**
845  *
846  */
847 void SessionReader::LoadParameter(const std::string &pName, NekDouble &pVar,
848  const NekDouble &pDefault) const
849 {
850  std::string vName = boost::to_upper_copy(pName);
851  auto paramIter = m_parameters.find(vName);
852  if (paramIter != m_parameters.end())
853  {
854  pVar = paramIter->second;
855  }
856  else
857  {
858  pVar = pDefault;
859  }
860 }
861 
862 /**
863  *
864  */
865 void SessionReader::SetParameter(const std::string &pName, int &pVar)
866 {
867  std::string vName = boost::to_upper_copy(pName);
868  m_parameters[vName] = pVar;
869 }
870 
871 /**
872  *
873  */
874 void SessionReader::SetParameter(const std::string &pName, size_t &pVar)
875 {
876  std::string vName = boost::to_upper_copy(pName);
877  m_parameters[vName] = pVar;
878 }
879 
880 /**
881  *
882  */
883 void SessionReader::SetParameter(const std::string &pName, NekDouble &pVar)
884 {
885  std::string vName = boost::to_upper_copy(pName);
886  m_parameters[vName] = pVar;
887 }
888 
889 /**
890  *
891  */
892 bool SessionReader::DefinesSolverInfo(const std::string &pName) const
893 {
894  std::string vName = boost::to_upper_copy(pName);
895  auto infoIter = m_solverInfo.find(vName);
896  return (infoIter != m_solverInfo.end());
897 }
898 
899 /**
900  *
901  */
902 const std::string &SessionReader::GetSolverInfo(
903  const std::string &pProperty) const
904 {
905  std::string vProperty = boost::to_upper_copy(pProperty);
906  auto iter = m_solverInfo.find(vProperty);
907 
908  ASSERTL1(iter != m_solverInfo.end(),
909  "Unable to find requested property: " + pProperty);
910 
911  return iter->second;
912 }
913 
914 /**
915  *
916  */
917 void SessionReader::SetSolverInfo(const std::string &pProperty,
918  const std::string &pValue)
919 {
920  std::string vProperty = boost::to_upper_copy(pProperty);
921  auto iter = m_solverInfo.find(vProperty);
922 
923  ASSERTL1(iter != m_solverInfo.end(),
924  "Unable to find requested property: " + pProperty);
925 
926  iter->second = pValue;
927 }
928 
929 /**
930  *
931  */
932 void SessionReader::LoadSolverInfo(const std::string &pName, std::string &pVar,
933  const std::string &pDefault) const
934 {
935  std::string vName = boost::to_upper_copy(pName);
936  auto infoIter = m_solverInfo.find(vName);
937  if (infoIter != m_solverInfo.end())
938  {
939  pVar = infoIter->second;
940  }
941  else
942  {
943  pVar = pDefault;
944  }
945 }
946 
947 /**
948  *
949  */
950 void SessionReader::MatchSolverInfo(const std::string &pName,
951  const std::string &pTrueVal, bool &pVar,
952  const bool &pDefault) const
953 {
954  std::string vName = boost::to_upper_copy(pName);
955  auto infoIter = m_solverInfo.find(vName);
956  if (infoIter != m_solverInfo.end())
957  {
958  pVar = boost::iequals(infoIter->second, pTrueVal);
959  }
960  else
961  {
962  pVar = pDefault;
963  }
964 }
965 
966 /**
967  *
968  */
969 bool SessionReader::MatchSolverInfo(const std::string &pName,
970  const std::string &pTrueVal) const
971 {
972  if (DefinesSolverInfo(pName))
973  {
974  std::string vName = boost::to_upper_copy(pName);
975  auto iter = m_solverInfo.find(vName);
976  if (iter != m_solverInfo.end())
977  {
978  return boost::iequals(iter->second, pTrueVal);
979  }
980  }
981  return false;
982 }
983 
984 /**
985  *
986  */
987 bool SessionReader::DefinesGlobalSysSolnInfo(const std::string &pVariable,
988  const std::string &pProperty) const
989 {
990  auto iter = GetGloSysSolnList().find(pVariable);
991  if (iter == GetGloSysSolnList().end())
992  {
993  return false;
994  }
995 
996  std::string vProperty = boost::to_upper_copy(pProperty);
997 
998  auto iter1 = iter->second.find(vProperty);
999  if (iter1 == iter->second.end())
1000  {
1001  return false;
1002  }
1003 
1004  return true;
1005 }
1006 
1007 /**
1008  *
1009  */
1010 const std::string &SessionReader::GetGlobalSysSolnInfo(
1011  const std::string &pVariable, const std::string &pProperty) const
1012 {
1013  auto iter = GetGloSysSolnList().find(pVariable);
1014  ASSERTL0(iter != GetGloSysSolnList().end(),
1015  "Failed to find variable in GlobalSysSolnInfoList");
1016 
1017  std::string vProperty = boost::to_upper_copy(pProperty);
1018  auto iter1 = iter->second.find(vProperty);
1019 
1020  ASSERTL0(iter1 != iter->second.end(),
1021  "Failed to find property: " + vProperty +
1022  " in GlobalSysSolnInfoList");
1023 
1024  return iter1->second;
1025 }
1026 
1027 /**
1028  * @brief Returns true if the TIMEINTEGRATIONSCHEME section is defined
1029  * in the session file.
1030  */
1031 bool SessionReader::DefinesTimeIntScheme() const
1032 {
1033  return m_timeIntScheme.method != "";
1034 }
1035 
1036 /**
1037  * @brief Returns the time integration scheme structure #m_timeIntScheme
1038  * from the session file.
1039  */
1040 const TimeIntScheme &SessionReader::GetTimeIntScheme() const
1041 {
1042  return m_timeIntScheme;
1043 }
1044 
1045 std::string SessionReader::GetGeometryType() const
1046 {
1047  TiXmlElement *xmlGeom =
1048  m_xmlDoc->FirstChildElement("NEKTAR")->FirstChildElement("GEOMETRY");
1049  ASSERTL1(xmlGeom, "Failed to find a GEOMETRY section in m_xmlDoc");
1050 
1051  TiXmlAttribute *attr = xmlGeom->FirstAttribute();
1052  while (attr)
1053  {
1054  std::string attrName(attr->Name());
1055  if (attrName == "HDF5FILE")
1056  {
1057  // there is a file pointer, therefore is HDF5
1058  return "HDF5";
1059  }
1060  // Get the next attribute.
1061  attr = attr->Next();
1062  }
1063 
1064  // Check the VERTEX block. If this is compressed, assume the file is
1065  // compressed, otherwise assume uncompressed.
1066  TiXmlElement *element = xmlGeom->FirstChildElement("VERTEX");
1067  string IsCompressed;
1068  element->QueryStringAttribute("COMPRESSED", &IsCompressed);
1069 
1070  if (IsCompressed.size() > 0)
1071  {
1072  return "XmlCompressed";
1073  }
1074 
1075  // no file pointer or compressed, just standard xml
1076  return "Xml";
1077 }
1078 
1079 /**
1080  *
1081  */
1082 bool SessionReader::DefinesGeometricInfo(const std::string &pName) const
1083 {
1084  std::string vName = boost::to_upper_copy(pName);
1085  return m_geometricInfo.find(vName) != m_geometricInfo.end();
1086 }
1087 
1088 /**
1089  *
1090  */
1091 void SessionReader::LoadGeometricInfo(const std::string &pName,
1092  std::string &pVar,
1093  const std::string &pDefault) const
1094 {
1095  std::string vName = boost::to_upper_copy(pName);
1096  auto iter = m_geometricInfo.find(vName);
1097  if (iter != m_geometricInfo.end())
1098  {
1099  pVar = iter->second;
1100  }
1101  else
1102  {
1103  pVar = pDefault;
1104  }
1105 }
1106 
1107 /**
1108  *
1109  */
1110 void SessionReader::LoadGeometricInfo(const std::string &pName, bool &pVar,
1111  const bool &pDefault) const
1112 {
1113  std::string vName = boost::to_upper_copy(pName);
1114  auto iter = m_geometricInfo.find(vName);
1115  if (iter != m_geometricInfo.end())
1116  {
1117  if (iter->second == "TRUE")
1118  {
1119  pVar = true;
1120  }
1121  else
1122  {
1123  pVar = false;
1124  }
1125  }
1126  else
1127  {
1128  pVar = pDefault;
1129  }
1130 }
1131 
1132 /**
1133  *
1134  */
1135 void SessionReader::LoadGeometricInfo(const std::string &pName, NekDouble &pVar,
1136  const NekDouble &pDefault) const
1137 {
1138  std::string vName = boost::to_upper_copy(pName);
1139  auto iter = m_geometricInfo.find(vName);
1140  if (iter != m_geometricInfo.end())
1141  {
1142  pVar = std::atoi(iter->second.c_str());
1143  }
1144  else
1145  {
1146  pVar = pDefault;
1147  }
1148 }
1149 
1150 /**
1151  *
1152  */
1153 void SessionReader::MatchGeometricInfo(const std::string &pName,
1154  const std::string &pTrueVal, bool &pVar,
1155  const bool &pDefault) const
1156 {
1157  std::string vName = boost::to_upper_copy(pName);
1158  auto iter = m_geometricInfo.find(vName);
1159  if (iter != m_geometricInfo.end())
1160  {
1161  pVar = boost::iequals(iter->second, pTrueVal);
1162  }
1163  else
1164  {
1165  pVar = pDefault;
1166  }
1167 }
1168 
1169 /**
1170  *
1171  */
1172 const std::string &SessionReader::GetVariable(const unsigned int &idx) const
1173 {
1174  ASSERTL0(idx < m_variables.size(), "Variable index out of range.");
1175  return m_variables[idx];
1176 }
1177 
1178 /**
1179  *
1180  */
1181 void SessionReader::SetVariable(const unsigned int &idx, std::string newname)
1182 {
1183  ASSERTL0(idx < m_variables.size(), "Variable index out of range.");
1184  m_variables[idx] = newname;
1185 }
1186 
1187 /**
1188  *
1189  */
1190 std::vector<std::string> SessionReader::GetVariables() const
1191 {
1192  return m_variables;
1193 }
1194 
1195 /**
1196  *
1197  */
1198 bool SessionReader::GetBackups() const
1199 {
1200  return m_backups;
1201 }
1202 
1203 /**
1204  *
1205  */
1206 bool SessionReader::DefinesFunction(const std::string &pName) const
1207 {
1208  std::string vName = boost::to_upper_copy(pName);
1209  return m_functions.find(vName) != m_functions.end();
1210 }
1211 
1212 /**
1213  *
1214  */
1215 bool SessionReader::DefinesFunction(const std::string &pName,
1216  const std::string &pVariable,
1217  const int pDomain) const
1218 {
1219  std::string vName = boost::to_upper_copy(pName);
1220 
1221  // Check function exists
1222  auto it1 = m_functions.find(vName);
1223  if (it1 != m_functions.end())
1224  {
1225  pair<std::string, int> key(pVariable, pDomain);
1226  pair<std::string, int> defkey("*", pDomain);
1227  bool varExists = it1->second.find(key) != it1->second.end() ||
1228  it1->second.find(defkey) != it1->second.end();
1229  return varExists;
1230  }
1231  return false;
1232 }
1233 
1234 /**
1235  *
1236  */
1237 EquationSharedPtr SessionReader::GetFunction(const std::string &pName,
1238  const std::string &pVariable,
1239  const int pDomain) const
1240 {
1241  std::string vName = boost::to_upper_copy(pName);
1242  auto it1 = m_functions.find(vName);
1243 
1244  ASSERTL0(it1 != m_functions.end(),
1245  std::string("No such function '") + pName +
1246  std::string("' has been defined in the session file."));
1247 
1248  // Check for specific and wildcard definitions
1249  pair<std::string, int> key(pVariable, pDomain);
1250  pair<std::string, int> defkey("*", pDomain);
1251 
1252  auto it2 = it1->second.find(key);
1253  auto it3 = it1->second.find(defkey);
1254  bool specific = it2 != it1->second.end();
1255  bool wildcard = it3 != it1->second.end();
1256 
1257  // Check function is defined somewhere
1258  ASSERTL0(specific || wildcard,
1259  "No such variable " + pVariable + " in domain " +
1260  boost::lexical_cast<string>(pDomain) +
1261  " defined for function " + pName + " in session file.");
1262 
1263  // If not specific, must be wildcard
1264  if (!specific)
1265  {
1266  it2 = it3;
1267  }
1268 
1269  ASSERTL0((it2->second.m_type == eFunctionTypeExpression),
1270  std::string("Function is defined by a file."));
1271  return it2->second.m_expression;
1272 }
1273 
1274 /**
1275  *
1276  */
1277 EquationSharedPtr SessionReader::GetFunction(const std::string &pName,
1278  const unsigned int &pVar,
1279  const int pDomain) const
1280 {
1281  ASSERTL0(pVar < m_variables.size(), "Variable index out of range.");
1282  return GetFunction(pName, m_variables[pVar], pDomain);
1283 }
1284 
1285 /**
1286  *
1287  */
1288 enum FunctionType SessionReader::GetFunctionType(const std::string &pName,
1289  const std::string &pVariable,
1290  const int pDomain) const
1291 {
1292  std::string vName = boost::to_upper_copy(pName);
1293  auto it1 = m_functions.find(vName);
1294 
1295  ASSERTL0(it1 != m_functions.end(),
1296  std::string("Function '") + pName + std::string("' not found."));
1297 
1298  // Check for specific and wildcard definitions
1299  pair<std::string, int> key(pVariable, pDomain);
1300  pair<std::string, int> defkey("*", pDomain);
1301 
1302  auto it2 = it1->second.find(key);
1303  auto it3 = it1->second.find(defkey);
1304  bool specific = it2 != it1->second.end();
1305  bool wildcard = it3 != it1->second.end();
1306 
1307  // Check function is defined somewhere
1308  ASSERTL0(specific || wildcard,
1309  "No such variable " + pVariable + " in domain " +
1310  boost::lexical_cast<string>(pDomain) +
1311  " defined for function " + pName + " in session file.");
1312 
1313  // If not specific, must be wildcard
1314  if (!specific)
1315  {
1316  it2 = it3;
1317  }
1318 
1319  return it2->second.m_type;
1320 }
1321 
1322 /**
1323  *
1324  */
1325 enum FunctionType SessionReader::GetFunctionType(const std::string &pName,
1326  const unsigned int &pVar,
1327  const int pDomain) const
1328 {
1329  ASSERTL0(pVar < m_variables.size(), "Variable index out of range.");
1330  return GetFunctionType(pName, m_variables[pVar], pDomain);
1331 }
1332 
1333 /**
1334  *
1335  */
1336 std::string SessionReader::GetFunctionFilename(const std::string &pName,
1337  const std::string &pVariable,
1338  const int pDomain) const
1339 {
1340  std::string vName = boost::to_upper_copy(pName);
1341  auto it1 = m_functions.find(vName);
1342 
1343  ASSERTL0(it1 != m_functions.end(),
1344  std::string("Function '") + pName + std::string("' not found."));
1345 
1346  // Check for specific and wildcard definitions
1347  pair<std::string, int> key(pVariable, pDomain);
1348  pair<std::string, int> defkey("*", pDomain);
1349 
1350  auto it2 = it1->second.find(key);
1351  auto it3 = it1->second.find(defkey);
1352  bool specific = it2 != it1->second.end();
1353  bool wildcard = it3 != it1->second.end();
1354 
1355  // Check function is defined somewhere
1356  ASSERTL0(specific || wildcard,
1357  "No such variable " + pVariable + " in domain " +
1358  boost::lexical_cast<string>(pDomain) +
1359  " defined for function " + pName + " in session file.");
1360 
1361  // If not specific, must be wildcard
1362  if (!specific)
1363  {
1364  it2 = it3;
1365  }
1366 
1367  return it2->second.m_filename;
1368 }
1369 
1370 /**
1371  *
1372  */
1373 std::string SessionReader::GetFunctionFilename(const std::string &pName,
1374  const unsigned int &pVar,
1375  const int pDomain) const
1376 {
1377  ASSERTL0(pVar < m_variables.size(), "Variable index out of range.");
1378  return GetFunctionFilename(pName, m_variables[pVar], pDomain);
1379 }
1380 
1381 /**
1382  *
1383  */
1384 std::string SessionReader::GetFunctionFilenameVariable(
1385  const std::string &pName, const std::string &pVariable,
1386  const int pDomain) const
1387 {
1388  std::string vName = boost::to_upper_copy(pName);
1389  auto it1 = m_functions.find(vName);
1390 
1391  ASSERTL0(it1 != m_functions.end(),
1392  std::string("Function '") + pName + std::string("' not found."));
1393 
1394  // Check for specific and wildcard definitions
1395  pair<std::string, int> key(pVariable, pDomain);
1396  pair<std::string, int> defkey("*", pDomain);
1397 
1398  auto it2 = it1->second.find(key);
1399  auto it3 = it1->second.find(defkey);
1400  bool specific = it2 != it1->second.end();
1401  bool wildcard = it3 != it1->second.end();
1402 
1403  // Check function is defined somewhere
1404  ASSERTL0(specific || wildcard,
1405  "No such variable " + pVariable + " in domain " +
1406  boost::lexical_cast<string>(pDomain) +
1407  " defined for function " + pName + " in session file.");
1408 
1409  // If not specific, must be wildcard
1410  if (!specific)
1411  {
1412  it2 = it3;
1413  }
1414 
1415  return it2->second.m_fileVariable;
1416 }
1417 
1418 /**
1419  *
1420  */
1421 bool SessionReader::DefinesTag(const std::string &pName) const
1422 {
1423  std::string vName = boost::to_upper_copy(pName);
1424  return m_tags.find(vName) != m_tags.end();
1425 }
1426 
1427 /**
1428  *
1429  */
1430 void SessionReader::SetTag(const std::string &pName, const std::string &pValue)
1431 {
1432  std::string vName = boost::to_upper_copy(pName);
1433  m_tags[vName] = pValue;
1434 }
1435 
1436 /**
1437  *
1438  */
1439 const std::string &SessionReader::GetTag(const std::string &pName) const
1440 {
1441  std::string vName = boost::to_upper_copy(pName);
1442  auto vTagIterator = m_tags.find(vName);
1443  ASSERTL0(vTagIterator != m_tags.end(), "Requested tag does not exist.");
1444  return vTagIterator->second;
1445 }
1446 
1447 /**
1448  *
1449  */
1450 const FilterMap &SessionReader::GetFilters() const
1451 {
1452  return m_filters;
1453 }
1454 
1455 /**
1456  *
1457  */
1458 bool SessionReader::DefinesCmdLineArgument(const std::string &pName) const
1459 {
1460  return (m_cmdLineOptions.find(pName) != m_cmdLineOptions.end());
1461 }
1462 
1463 /**
1464  *
1465  */
1466 void SessionReader::SubstituteExpressions(std::string &pExpr)
1467 {
1468  for (auto &exprIter : m_expressions)
1469  {
1470  boost::replace_all(pExpr, exprIter.first, exprIter.second);
1471  }
1472 }
1473 
1474 /**
1475  *
1476  */
1477 void SessionReader::LoadDoc(const std::string &pFilename,
1478  TiXmlDocument *pDoc) const
1479 {
1480  if (pFilename.size() > 3 &&
1481  pFilename.substr(pFilename.size() - 3, 3) == ".gz")
1482  {
1483  ifstream file(pFilename.c_str(), ios_base::in | ios_base::binary);
1484  ASSERTL0(file.good(), "Unable to open file: " + pFilename);
1485  stringstream ss;
1486  io::filtering_streambuf<io::input> in;
1487  in.push(io::gzip_decompressor());
1488  in.push(file);
1489  try
1490  {
1491  io::copy(in, ss);
1492  ss >> (*pDoc);
1493  }
1494  catch (io::gzip_error &)
1495  {
1496  NEKERROR(ErrorUtil::efatal,
1497  "Error: File '" + pFilename + "' is corrupt.");
1498  }
1499  }
1500  else if (pFilename.size() > 4 &&
1501  pFilename.substr(pFilename.size() - 4, 4) == "_xml")
1502  {
1503  fs::path pdirname(pFilename);
1504  boost::format pad("P%1$07d.xml");
1505  pad % m_comm->GetSpaceComm()->GetRank();
1506  fs::path pRankFilename(pad.str());
1507  fs::path fullpath = pdirname / pRankFilename;
1508 
1509  ifstream file(PortablePath(fullpath).c_str());
1510  ASSERTL0(file.good(), "Unable to open file: " + fullpath.string());
1511  file >> (*pDoc);
1512  }
1513  else
1514  {
1515  ifstream file(pFilename.c_str());
1516  ASSERTL0(file.good(), "Unable to open file: " + pFilename);
1517  file >> (*pDoc);
1518  }
1519 }
1520 
1521 /**
1522  *
1523  */
1524 TiXmlDocument *SessionReader::MergeDoc(
1525  const std::vector<std::string> &pFilenames) const
1526 {
1527  ASSERTL0(pFilenames.size() > 0, "No filenames for merging.");
1528 
1529  // Read the first document
1530  TiXmlDocument *vMainDoc = new TiXmlDocument;
1531  LoadDoc(pFilenames[0], vMainDoc);
1532 
1533  TiXmlHandle vMainHandle(vMainDoc);
1534  TiXmlElement *vMainNektar =
1535  GetChildElementOrThrow(pFilenames[0], "NEKTAR", vMainHandle);
1536 
1537  // Read all subsequent XML documents.
1538  // For each element within the NEKTAR tag, use it to replace the
1539  // version already present in the loaded XML data.
1540  for (int i = 1; i < pFilenames.size(); ++i)
1541  {
1542  if ((pFilenames[i].compare(pFilenames[i].size() - 3, 3, "xml") == 0) ||
1543  (pFilenames[i].compare(pFilenames[i].size() - 6, 6, "xml.gz") ==
1544  0) ||
1545  (pFilenames[i].compare(pFilenames[i].size() - 3, 3, "opt") == 0))
1546  {
1547  TiXmlDocument *vTempDoc = new TiXmlDocument;
1548  LoadDoc(pFilenames[i], vTempDoc);
1549 
1550  TiXmlHandle docHandle(vTempDoc);
1551  TiXmlElement *vTempNektar =
1552  GetChildElementOrThrow(pFilenames[i], "NEKTAR", docHandle);
1553  TiXmlElement *p = vTempNektar->FirstChildElement();
1554 
1555  while (p)
1556  {
1557  TiXmlElement *vMainEntry =
1558  vMainNektar->FirstChildElement(p->Value());
1559 
1560  // First check if the new item is in fact blank
1561  // replace if it is a COLLECTIONS section however.
1562 
1563  if (!p->FirstChild() && vMainEntry &&
1564  !boost::iequals(p->Value(), "COLLECTIONS"))
1565  {
1566  std::string warningmsg =
1567  "File " + pFilenames[i] + " contains " +
1568  "an empty XML element " + std::string(p->Value()) +
1569  " which will be ignored.";
1570  NEKERROR(ErrorUtil::ewarning, warningmsg.c_str());
1571  }
1572  else
1573  {
1574  if (vMainEntry)
1575  {
1576  vMainNektar->RemoveChild(vMainEntry);
1577  }
1578  TiXmlElement *q = new TiXmlElement(*p);
1579  vMainNektar->LinkEndChild(q);
1580  }
1581  p = p->NextSiblingElement();
1582  }
1583 
1584  delete vTempDoc;
1585  }
1586  }
1587  return vMainDoc;
1588 }
1589 
1590 /**
1591  *
1592  */
1593 void SessionReader::ParseDocument()
1594 {
1595  // Check we actually have a document loaded.
1596  ASSERTL0(m_xmlDoc, "No XML document loaded.");
1597 
1598  // Look for all data in CONDITIONS block.
1599  TiXmlHandle docHandle(m_xmlDoc);
1600  TiXmlElement *e;
1601  e = docHandle.FirstChildElement("NEKTAR")
1602  .FirstChildElement("CONDITIONS")
1603  .Element();
1604 
1605  // Read the various sections of the CONDITIONS block
1606  ReadParameters(e);
1607  ReadSolverInfo(e);
1608  ReadGlobalSysSolnInfo(e);
1609  ReadTimeIntScheme(e);
1610  ReadExpressions(e);
1611  ReadVariables(e);
1612  ReadFunctions(e);
1613 
1614  e = docHandle.FirstChildElement("NEKTAR")
1615  .FirstChildElement("FILTERS")
1616  .Element();
1617 
1618  ReadFilters(e);
1619 }
1620 
1621 /**
1622  *
1623  */
1624 void SessionReader::CreateComm(int &argc, char *argv[])
1625 {
1626  if (argc == 0)
1627  {
1628  m_comm = GetCommFactory().CreateInstance("Serial", 0, 0);
1629  }
1630  else
1631  {
1632  string vCommModule("Serial");
1633  if (GetCommFactory().ModuleExists("ParallelMPI"))
1634  {
1635  vCommModule = "ParallelMPI";
1636  }
1637  if (m_cmdLineOptions.count("cwipi") &&
1638  GetCommFactory().ModuleExists("CWIPI"))
1639  {
1640  vCommModule = "CWIPI";
1641  }
1642 
1643  m_comm = GetCommFactory().CreateInstance(vCommModule, argc, argv);
1644  }
1645 }
1646 
1647 /**
1648  * Splits the processes into a cartesian grid and creates communicators
1649  * for each row and column of the grid. The grid is defined by the
1650  * PROC_X parameter which, if specified, gives the number of processes
1651  * spanned by the Fourier direction. PROC_X must exactly divide the
1652  * total number of processes or an error is thrown.
1653  */
1654 void SessionReader::PartitionComm()
1655 {
1656  if (m_comm->GetSize() > 1)
1657  {
1658  int nProcZ = 1;
1659  int nProcY = 1;
1660  int nProcX = 1;
1661  int nStripZ = 1;
1662  int nTime = 1;
1663  if (DefinesCmdLineArgument("npx"))
1664  {
1665  nProcX = GetCmdLineArgument<int>("npx");
1666  }
1667  if (DefinesCmdLineArgument("npy"))
1668  {
1669  nProcY = GetCmdLineArgument<int>("npy");
1670  }
1671  if (DefinesCmdLineArgument("npz"))
1672  {
1673  nProcZ = GetCmdLineArgument<int>("npz");
1674  }
1675  if (DefinesCmdLineArgument("nsz"))
1676  {
1677  nStripZ = GetCmdLineArgument<int>("nsz");
1678  }
1679  if (DefinesCmdLineArgument("npt"))
1680  {
1681  nTime = GetCmdLineArgument<int>("npt");
1682  }
1683  ASSERTL0(m_comm->GetSize() % nTime == 0,
1684  "Cannot exactly partition time using npt value.");
1685  ASSERTL0((m_comm->GetSize() / nTime) % (nProcZ * nProcY * nProcX) == 0,
1686  "Cannot exactly partition using PROC_Z value.");
1687  ASSERTL0(nProcZ % nProcY == 0,
1688  "Cannot exactly partition using PROC_Y value.");
1689  ASSERTL0(nProcY % nProcX == 0,
1690  "Cannot exactly partition using PROC_X value.");
1691 
1692  // Number of processes associated with the spectral method
1693  int nProcSm = nProcZ * nProcY * nProcX;
1694 
1695  // Number of processes associated with the spectral element
1696  // method.
1697  int nProcSem = m_comm->GetSize() / nTime / nProcSm;
1698 
1699  m_comm->SplitComm(nProcSm, nProcSem, nTime);
1700  m_comm->GetColumnComm()->SplitComm(nProcZ / nStripZ, nStripZ);
1701  m_comm->GetColumnComm()->GetColumnComm()->SplitComm((nProcY * nProcX),
1702  nProcZ / nStripZ);
1703  m_comm->GetColumnComm()->GetColumnComm()->GetColumnComm()->SplitComm(
1704  nProcX, nProcY);
1705  }
1706 }
1707 
1708 /**
1709  *
1710  */
1711 void SessionReader::ReadParameters(TiXmlElement *conditions)
1712 {
1713  m_parameters.clear();
1714 
1715  if (!conditions)
1716  {
1717  return;
1718  }
1719 
1720  TiXmlElement *parametersElement =
1721  conditions->FirstChildElement("PARAMETERS");
1722 
1723  // See if we have parameters defined. They are optional so we go on
1724  // if not.
1725  if (parametersElement)
1726  {
1727  TiXmlElement *parameter = parametersElement->FirstChildElement("P");
1728 
1729  ParameterMap caseSensitiveParameters;
1730 
1731  // Multiple nodes will only occur if there is a comment in
1732  // between definitions.
1733  while (parameter)
1734  {
1735  stringstream tagcontent;
1736  tagcontent << *parameter;
1737  TiXmlNode *node = parameter->FirstChild();
1738 
1739  while (node && node->Type() != TiXmlNode::TINYXML_TEXT)
1740  {
1741  node = node->NextSibling();
1742  }
1743 
1744  if (node)
1745  {
1746  // Format is "paramName = value"
1747  std::string line = node->ToText()->Value(), lhs, rhs;
1748 
1749  try
1750  {
1751  ParseEquals(line, lhs, rhs);
1752  }
1753  catch (...)
1754  {
1755  NEKERROR(ErrorUtil::efatal,
1756  "Syntax error in parameter expression '" + line +
1757  "' in XML element: \n\t'" + tagcontent.str() +
1758  "'");
1759  }
1760 
1761  // We want the list of parameters to have their RHS
1762  // evaluated, so we use the expression evaluator to do
1763  // the dirty work.
1764  if (!lhs.empty() && !rhs.empty())
1765  {
1766  NekDouble value = 0.0;
1767  try
1768  {
1769  LibUtilities::Equation expession(m_interpreter, rhs);
1770  value = expession.Evaluate();
1771  }
1772  catch (const std::runtime_error &)
1773  {
1774  NEKERROR(ErrorUtil::efatal,
1775  "Error evaluating parameter expression"
1776  " '" +
1777  rhs + "' in XML element: \n\t'" +
1778  tagcontent.str() + "'");
1779  }
1780  m_interpreter->SetParameter(lhs, value);
1781  caseSensitiveParameters[lhs] = value;
1782  boost::to_upper(lhs);
1783  m_parameters[lhs] = value;
1784  }
1785  }
1786 
1787  parameter = parameter->NextSiblingElement();
1788  }
1789  }
1790 }
1791 
1792 /**
1793  *
1794  */
1795 void SessionReader::ReadSolverInfo(TiXmlElement *conditions)
1796 {
1797  m_solverInfo.clear();
1798  m_solverInfo = GetSolverInfoDefaults();
1799 
1800  if (!conditions)
1801  {
1802  return;
1803  }
1804 
1805  TiXmlElement *solverInfoElement =
1806  conditions->FirstChildElement("SOLVERINFO");
1807 
1808  if (solverInfoElement)
1809  {
1810  TiXmlElement *solverInfo = solverInfoElement->FirstChildElement("I");
1811 
1812  while (solverInfo)
1813  {
1814  std::stringstream tagcontent;
1815  tagcontent << *solverInfo;
1816  // read the property name
1817  ASSERTL0(solverInfo->Attribute("PROPERTY"),
1818  "Missing PROPERTY attribute in solver info "
1819  "XML element: \n\t'" +
1820  tagcontent.str() + "'");
1821  std::string solverProperty = solverInfo->Attribute("PROPERTY");
1822  ASSERTL0(!solverProperty.empty(),
1823  "PROPERTY attribute must be non-empty in XML "
1824  "element: \n\t'" +
1825  tagcontent.str() + "'");
1826 
1827  // make sure that solver property is capitalised
1828  std::string solverPropertyUpper =
1829  boost::to_upper_copy(solverProperty);
1830 
1831  // read the value
1832  ASSERTL0(solverInfo->Attribute("VALUE"),
1833  "Missing VALUE attribute in solver info "
1834  "XML element: \n\t'" +
1835  tagcontent.str() + "'");
1836  std::string solverValue = solverInfo->Attribute("VALUE");
1837  ASSERTL0(!solverValue.empty(),
1838  "VALUE attribute must be non-empty in XML "
1839  "element: \n\t'" +
1840  tagcontent.str() + "'");
1841 
1842  // Set Variable
1843  m_solverInfo[solverPropertyUpper] = solverValue;
1844  solverInfo = solverInfo->NextSiblingElement("I");
1845  }
1846  }
1847 
1848  if (m_comm && m_comm->GetRowComm()->GetSize() > 1)
1849  {
1850  ASSERTL0(
1851  m_solverInfo["GLOBALSYSSOLN"] == "IterativeFull" ||
1852  m_solverInfo["GLOBALSYSSOLN"] == "IterativeStaticCond" ||
1853  m_solverInfo["GLOBALSYSSOLN"] ==
1854  "IterativeMultiLevelStaticCond" ||
1855  m_solverInfo["GLOBALSYSSOLN"] == "XxtFull" ||
1856  m_solverInfo["GLOBALSYSSOLN"] == "XxtStaticCond" ||
1857  m_solverInfo["GLOBALSYSSOLN"] == "XxtMultiLevelStaticCond" ||
1858  m_solverInfo["GLOBALSYSSOLN"] == "PETScFull" ||
1859  m_solverInfo["GLOBALSYSSOLN"] == "PETScStaticCond" ||
1860  m_solverInfo["GLOBALSYSSOLN"] == "PETScMultiLevelStaticCond",
1861  "A parallel solver must be used when run in parallel.");
1862  }
1863 }
1864 
1865 /**
1866  *
1867  */
1868 void SessionReader::ReadGlobalSysSolnInfo(TiXmlElement *conditions)
1869 {
1870  GetGloSysSolnList().clear();
1871 
1872  if (!conditions)
1873  {
1874  return;
1875  }
1876 
1877  TiXmlElement *GlobalSys =
1878  conditions->FirstChildElement("GLOBALSYSSOLNINFO");
1879 
1880  if (!GlobalSys)
1881  {
1882  return;
1883  }
1884 
1885  TiXmlElement *VarInfo = GlobalSys->FirstChildElement("V");
1886 
1887  while (VarInfo)
1888  {
1889  std::stringstream tagcontent;
1890  tagcontent << *VarInfo;
1891  ASSERTL0(VarInfo->Attribute("VAR"),
1892  "Missing VAR attribute in GobalSysSolnInfo XML "
1893  "element: \n\t'" +
1894  tagcontent.str() + "'");
1895 
1896  std::string VarList = VarInfo->Attribute("VAR");
1897  ASSERTL0(!VarList.empty(),
1898  "VAR attribute must be non-empty in XML element:\n\t'" +
1899  tagcontent.str() + "'");
1900 
1901  // generate a list of variables.
1902  std::vector<std::string> varStrings;
1903  bool valid = ParseUtils::GenerateVector(VarList, varStrings);
1904 
1905  ASSERTL0(valid, "Unable to process list of variable in XML "
1906  "element \n\t'" +
1907  tagcontent.str() + "'");
1908 
1909  if (varStrings.size())
1910  {
1911  TiXmlElement *SysSolnInfo = VarInfo->FirstChildElement("I");
1912 
1913  while (SysSolnInfo)
1914  {
1915  tagcontent.clear();
1916  tagcontent << *SysSolnInfo;
1917  // read the property name
1918  ASSERTL0(SysSolnInfo->Attribute("PROPERTY"),
1919  "Missing PROPERTY attribute in "
1920  "GlobalSysSolnInfo for variable(s) '" +
1921  VarList + "' in XML element: \n\t'" +
1922  tagcontent.str() + "'");
1923 
1924  std::string SysSolnProperty =
1925  SysSolnInfo->Attribute("PROPERTY");
1926 
1927  ASSERTL0(!SysSolnProperty.empty(),
1928  "GlobalSysSolnIno properties must have a "
1929  "non-empty name for variable(s) : '" +
1930  VarList + "' in XML element: \n\t'" +
1931  tagcontent.str() + "'");
1932 
1933  // make sure that solver property is capitalised
1934  std::string SysSolnPropertyUpper =
1935  boost::to_upper_copy(SysSolnProperty);
1936 
1937  // read the value
1938  ASSERTL0(SysSolnInfo->Attribute("VALUE"),
1939  "Missing VALUE attribute in GlobalSysSolnInfo "
1940  "for variable(s) '" +
1941  VarList + "' in XML element: \n\t" +
1942  tagcontent.str() + "'");
1943 
1944  std::string SysSolnValue = SysSolnInfo->Attribute("VALUE");
1945  ASSERTL0(!SysSolnValue.empty(),
1946  "GlobalSysSolnInfo properties must have a "
1947  "non-empty value for variable(s) '" +
1948  VarList + "' in XML element: \n\t'" +
1949  tagcontent.str() + "'");
1950 
1951  // Store values under variable map.
1952  for (int i = 0; i < varStrings.size(); ++i)
1953  {
1954  auto x = GetGloSysSolnList().find(varStrings[i]);
1955  if (x == GetGloSysSolnList().end())
1956  {
1957  (GetGloSysSolnList()[varStrings[i]])
1958  [SysSolnPropertyUpper] = SysSolnValue;
1959  }
1960  else
1961  {
1962  x->second[SysSolnPropertyUpper] = SysSolnValue;
1963  }
1964  }
1965 
1966  SysSolnInfo = SysSolnInfo->NextSiblingElement("I");
1967  }
1968  VarInfo = VarInfo->NextSiblingElement("V");
1969  }
1970  }
1971 
1972  if (m_verbose && GetGloSysSolnList().size() > 0 && m_comm)
1973  {
1974  if (m_comm->GetRank() == 0)
1975  {
1976  cout << "GlobalSysSoln Info:" << endl;
1977 
1978  for (auto &x : GetGloSysSolnList())
1979  {
1980  cout << "\t Variable: " << x.first << endl;
1981 
1982  for (auto &y : x.second)
1983  {
1984  cout << "\t\t " << y.first << " = " << y.second << endl;
1985  }
1986  }
1987  cout << endl;
1988  }
1989  }
1990 }
1991 
1992 /**
1993  * @brief Read the time-integration scheme structure, if present.
1994  */
1995 void SessionReader::ReadTimeIntScheme(TiXmlElement *conditions)
1996 {
1997  if (!conditions)
1998  {
1999  return;
2000  }
2001 
2002  TiXmlElement *timeInt =
2003  conditions->FirstChildElement("TIMEINTEGRATIONSCHEME");
2004 
2005  if (!timeInt)
2006  {
2007  return;
2008  }
2009 
2010  TiXmlElement *method = timeInt->FirstChildElement("METHOD");
2011  TiXmlElement *variant = timeInt->FirstChildElement("VARIANT");
2012  TiXmlElement *order = timeInt->FirstChildElement("ORDER");
2013  TiXmlElement *params = timeInt->FirstChildElement("FREEPARAMETERS");
2014 
2015  // Only the method and order are required.
2016  ASSERTL0(method, "Missing METHOD tag inside "
2017  "TIMEINTEGRATIONSCHEME.");
2018  ASSERTL0(order, "Missing ORDER tag inside "
2019  "TIMEINTEGRATIONSCHEME.");
2020 
2021  m_timeIntScheme.method = method->GetText();
2022 
2023  std::string orderStr = order->GetText();
2024 
2025  // Only the method and order are required.
2026  ASSERTL0(m_timeIntScheme.method.size() > 0,
2027  "Empty text inside METHOD tag in TIMEINTEGRATIONSCHEME.");
2028  ASSERTL0(orderStr.size() > 0,
2029  "Empty text inside ORDER tag in TIMEINTEGRATIONSCHEME.");
2030  try
2031  {
2032  m_timeIntScheme.order = boost::lexical_cast<unsigned int>(orderStr);
2033  }
2034  catch (...)
2035  {
2036  NEKERROR(ErrorUtil::efatal, "In ORDER tag, unable to convert "
2037  "string '" +
2038  orderStr + "' to an unsigned integer.");
2039  }
2040 
2041  if (variant)
2042  {
2043  m_timeIntScheme.variant = variant->GetText();
2044  }
2045 
2046  if (params)
2047  {
2048  std::string paramsStr = params->GetText();
2049  ASSERTL0(paramsStr.size() > 0,
2050  "Empty text inside FREEPARAMETERS tag in "
2051  "TIMEINTEGRATIONSCHEME.");
2052 
2053  std::vector<std::string> pSplit;
2054  boost::split(pSplit, paramsStr, boost::is_any_of(" "));
2055 
2056  m_timeIntScheme.freeParams.resize(pSplit.size());
2057  for (size_t i = 0; i < pSplit.size(); ++i)
2058  {
2059  try
2060  {
2061  m_timeIntScheme.freeParams[i] =
2062  boost::lexical_cast<NekDouble>(pSplit[i]);
2063  }
2064  catch (...)
2065  {
2066  NEKERROR(ErrorUtil::efatal, "In FREEPARAMETERS tag, "
2067  "unable to convert string '" +
2068  pSplit[i] +
2069  "' "
2070  "to a floating-point value.");
2071  }
2072  }
2073  }
2074 
2075  if (m_verbose && m_comm)
2076  {
2077  if (m_comm->GetRank() == 0)
2078  {
2079  cout << "Trying to use time integration scheme:" << endl;
2080  cout << "\t Method : " << m_timeIntScheme.method << endl;
2081  cout << "\t Variant: " << m_timeIntScheme.variant << endl;
2082  cout << "\t Order : " << m_timeIntScheme.order << endl;
2083 
2084  if (m_timeIntScheme.freeParams.size() > 0)
2085  {
2086  cout << "\t Params :";
2087  for (auto &x : m_timeIntScheme.freeParams)
2088  {
2089  cout << " " << x;
2090  }
2091  cout << endl;
2092  }
2093  }
2094  }
2095 }
2096 
2097 /**
2098  *
2099  */
2100 void SessionReader::ReadExpressions(TiXmlElement *conditions)
2101 {
2102  m_expressions.clear();
2103 
2104  if (!conditions)
2105  {
2106  return;
2107  }
2108 
2109  TiXmlElement *expressionsElement =
2110  conditions->FirstChildElement("EXPRESSIONS");
2111 
2112  if (expressionsElement)
2113  {
2114  TiXmlElement *expr = expressionsElement->FirstChildElement("E");
2115 
2116  while (expr)
2117  {
2118  stringstream tagcontent;
2119  tagcontent << *expr;
2120  ASSERTL0(expr->Attribute("NAME"),
2121  "Missing NAME attribute in expression "
2122  "definition: \n\t'" +
2123  tagcontent.str() + "'");
2124  std::string nameString = expr->Attribute("NAME");
2125  ASSERTL0(!nameString.empty(),
2126  "Expressions must have a non-empty name: \n\t'" +
2127  tagcontent.str() + "'");
2128 
2129  ASSERTL0(expr->Attribute("VALUE"),
2130  "Missing VALUE attribute in expression "
2131  "definition: \n\t'" +
2132  tagcontent.str() + "'");
2133  std::string valString = expr->Attribute("VALUE");
2134  ASSERTL0(!valString.empty(),
2135  "Expressions must have a non-empty value: \n\t'" +
2136  tagcontent.str() + "'");
2137 
2138  auto exprIter = m_expressions.find(nameString);
2139  ASSERTL0(exprIter == m_expressions.end(),
2140  std::string("Expression '") + nameString +
2141  std::string("' already specified."));
2142 
2143  m_expressions[nameString] = valString;
2144  expr = expr->NextSiblingElement("E");
2145  }
2146  }
2147 }
2148 
2149 /**
2150  *
2151  */
2152 void SessionReader::ReadVariables(TiXmlElement *conditions)
2153 {
2154  m_variables.clear();
2155 
2156  if (!conditions)
2157  {
2158  return;
2159  }
2160 
2161  TiXmlElement *variablesElement = conditions->FirstChildElement("VARIABLES");
2162 
2163  // See if we have parameters defined. They are optional so we go on
2164  // if not.
2165  if (variablesElement)
2166  {
2167  TiXmlElement *varElement = variablesElement->FirstChildElement("V");
2168 
2169  // Sequential counter for the composite numbers.
2170  int nextVariableNumber = -1;
2171 
2172  while (varElement)
2173  {
2174  stringstream tagcontent;
2175  tagcontent << *varElement;
2176 
2177  /// All elements are of the form: "<V ID="#"> name = value
2178  /// </V>", with ? being the element type.
2179  nextVariableNumber++;
2180 
2181  int i;
2182  int err = varElement->QueryIntAttribute("ID", &i);
2183  ASSERTL0(err == TIXML_SUCCESS,
2184  "Variables must have a unique ID number attribute "
2185  "in XML element: \n\t'" +
2186  tagcontent.str() + "'");
2187  ASSERTL0(i == nextVariableNumber,
2188  "ID numbers for variables must begin with zero and"
2189  " be sequential in XML element: \n\t'" +
2190  tagcontent.str() + "'");
2191 
2192  TiXmlNode *varChild = varElement->FirstChild();
2193  // This is primarily to skip comments that may be present.
2194  // Comments appear as nodes just like elements. We are
2195  // specifically looking for text in the body of the
2196  // definition.
2197  while (varChild && varChild->Type() != TiXmlNode::TINYXML_TEXT)
2198  {
2199  varChild = varChild->NextSibling();
2200  }
2201 
2202  ASSERTL0(varChild, "Unable to read variable definition body for "
2203  "variable with ID " +
2204  boost::lexical_cast<string>(i) +
2205  " in XML element: \n\t'" + tagcontent.str() +
2206  "'");
2207  std::string variableName = varChild->ToText()->ValueStr();
2208 
2209  std::istringstream variableStrm(variableName);
2210  variableStrm >> variableName;
2211 
2212  ASSERTL0(std::find(m_variables.begin(), m_variables.end(),
2213  variableName) == m_variables.end(),
2214  "Variable with ID " + boost::lexical_cast<string>(i) +
2215  " in XML element \n\t'" + tagcontent.str() +
2216  "'\nhas already been defined.");
2217 
2218  m_variables.push_back(variableName);
2219 
2220  varElement = varElement->NextSiblingElement("V");
2221  }
2222 
2223  ASSERTL0(nextVariableNumber > -1,
2224  "Number of variables must be greater than zero.");
2225  }
2226 }
2227 
2228 /**
2229  *
2230  */
2231 void SessionReader::ReadFunctions(TiXmlElement *conditions)
2232 {
2233  m_functions.clear();
2234 
2235  if (!conditions)
2236  {
2237  return;
2238  }
2239 
2240  // Scan through conditions section looking for functions.
2241  TiXmlElement *function = conditions->FirstChildElement("FUNCTION");
2242  while (function)
2243  {
2244  stringstream tagcontent;
2245  tagcontent << *function;
2246 
2247  // Every function must have a NAME attribute
2248  ASSERTL0(function->Attribute("NAME"),
2249  "Functions must have a NAME attribute defined in XML "
2250  "element: \n\t'" +
2251  tagcontent.str() + "'");
2252  std::string functionStr = function->Attribute("NAME");
2253  ASSERTL0(!functionStr.empty(),
2254  "Functions must have a non-empty name in XML "
2255  "element: \n\t'" +
2256  tagcontent.str() + "'");
2257 
2258  // Store function names in uppercase to remain case-insensitive.
2259  boost::to_upper(functionStr);
2260 
2261  // Retrieve first entry (variable, or file)
2262  TiXmlElement *variable = function->FirstChildElement();
2263 
2264  // Create new function structure with default type of none.
2265  FunctionVariableMap functionVarMap;
2266 
2267  // Process all entries in the function block
2268  while (variable)
2269  {
2271  std::string conditionType = variable->Value();
2272 
2273  // If no var is specified, assume wildcard
2274  std::string variableStr;
2275  if (!variable->Attribute("VAR"))
2276  {
2277  variableStr = "*";
2278  }
2279  else
2280  {
2281  variableStr = variable->Attribute("VAR");
2282  }
2283 
2284  // Parse list of variables
2285  std::vector<std::string> variableList;
2286  ParseUtils::GenerateVector(variableStr, variableList);
2287 
2288  // If no domain string put to 0
2289  std::string domainStr;
2290  if (!variable->Attribute("DOMAIN"))
2291  {
2292  domainStr = "0";
2293  }
2294  else
2295  {
2296  domainStr = variable->Attribute("DOMAIN");
2297  }
2298 
2299  // If no domain string put to 0
2300  std::string evarsStr = "x y z t";
2301  if (variable->Attribute("EVARS"))
2302  {
2303  evarsStr =
2304  evarsStr + std::string(" ") + variable->Attribute("EVARS");
2305  }
2306 
2307  // Parse list of variables
2308  std::vector<std::string> varSplit;
2309  std::vector<unsigned int> domainList;
2310  ParseUtils::GenerateSeqVector(domainStr, domainList);
2311 
2312  // Expressions are denoted by E
2313  if (conditionType == "E")
2314  {
2315  funcDef.m_type = eFunctionTypeExpression;
2316 
2317  // Expression must have a VALUE.
2318  ASSERTL0(variable->Attribute("VALUE"),
2319  "Attribute VALUE expected for function '" +
2320  functionStr + "'.");
2321  std::string fcnStr = variable->Attribute("VALUE");
2322 
2323  ASSERTL0(!fcnStr.empty(),
2324  (std::string("Expression for var: ") + variableStr +
2325  std::string(" must be specified."))
2326  .c_str());
2327 
2328  SubstituteExpressions(fcnStr);
2329 
2330  // set expression
2331  funcDef.m_expression =
2333  m_interpreter, fcnStr, evarsStr);
2334  }
2335 
2336  // Files are denoted by F
2337  else if (conditionType == "F")
2338  {
2339  if (variable->Attribute("TIMEDEPENDENT") &&
2340  boost::lexical_cast<bool>(
2341  variable->Attribute("TIMEDEPENDENT")))
2342  {
2344  }
2345  else
2346  {
2347  funcDef.m_type = eFunctionTypeFile;
2348  }
2349 
2350  // File must have a FILE.
2351  ASSERTL0(variable->Attribute("FILE"),
2352  "Attribute FILE expected for function '" +
2353  functionStr + "'.");
2354  std::string filenameStr = variable->Attribute("FILE");
2355 
2356  ASSERTL0(!filenameStr.empty(),
2357  "A filename must be specified for the FILE "
2358  "attribute of function '" +
2359  functionStr + "'.");
2360 
2361  std::vector<std::string> fSplit;
2362  boost::split(fSplit, filenameStr, boost::is_any_of(":"));
2363 
2364  ASSERTL0(fSplit.size() == 1 || fSplit.size() == 2,
2365  "Incorrect filename specification in function " +
2366  functionStr +
2367  "'. "
2368  "Specify variables inside file as: "
2369  "filename:var1,var2");
2370 
2371  // set the filename
2372  fs::path fullpath = fSplit[0];
2373  fs::path ftype = fullpath.extension();
2374  if (fullpath.parent_path().extension() == ".pit")
2375  {
2376  string filename = fullpath.stem().string();
2377  fullpath = fullpath.parent_path();
2378  size_t start = filename.find_last_of("_") + 1;
2379  int index =
2380  atoi(filename.substr(start, filename.size()).c_str());
2381  fullpath /= filename.substr(0, start) +
2382  std::to_string(
2383  index + m_comm->GetTimeComm()->GetRank()) +
2384  ftype.string();
2385  }
2386  funcDef.m_filename = fullpath.string();
2387 
2388  if (fSplit.size() == 2)
2389  {
2390  ASSERTL0(variableList[0] != "*",
2391  "Filename variable mapping not valid "
2392  "when using * as a variable inside "
2393  "function '" +
2394  functionStr + "'.");
2395 
2396  boost::split(varSplit, fSplit[1], boost::is_any_of(","));
2397  ASSERTL0(varSplit.size() == variableList.size(),
2398  "Filename variables should contain the "
2399  "same number of variables defined in "
2400  "VAR in function " +
2401  functionStr + "'.");
2402  }
2403  }
2404 
2405  // Nothing else supported so throw an error
2406  else
2407  {
2408  stringstream tagcontent;
2409  tagcontent << *variable;
2410 
2411  NEKERROR(ErrorUtil::efatal,
2412  "Identifier " + conditionType + " in function " +
2413  std::string(function->Attribute("NAME")) +
2414  " is not recognised in XML element: \n\t'" +
2415  tagcontent.str() + "'");
2416  }
2417 
2418  // Add variables to function
2419  for (unsigned int i = 0; i < variableList.size(); ++i)
2420  {
2421  for (unsigned int j = 0; j < domainList.size(); ++j)
2422  {
2423  // Check it has not already been defined
2424  pair<std::string, int> key(variableList[i], domainList[j]);
2425  auto fcnsIter = functionVarMap.find(key);
2426  ASSERTL0(
2427  fcnsIter == functionVarMap.end(),
2428  "Error setting expression '" + variableList[i] +
2429  " in domain " +
2430  boost::lexical_cast<std::string>(domainList[j]) +
2431  "' in function '" + functionStr +
2432  "'. "
2433  "Expression has already been defined.");
2434 
2435  if (varSplit.size() > 0)
2436  {
2437  FunctionVariableDefinition funcDef2 = funcDef;
2438  funcDef2.m_fileVariable = varSplit[i];
2439  functionVarMap[key] = funcDef2;
2440  }
2441  else
2442  {
2443  functionVarMap[key] = funcDef;
2444  }
2445  }
2446  }
2447 
2448  variable = variable->NextSiblingElement();
2449  }
2450  // Add function definition to map
2451  m_functions[functionStr] = functionVarMap;
2452  function = function->NextSiblingElement("FUNCTION");
2453  }
2454 }
2455 
2456 /**
2457  *
2458  */
2459 void SessionReader::ReadFilters(TiXmlElement *filters)
2460 {
2461  if (!filters)
2462  {
2463  return;
2464  }
2465 
2466  m_filters.clear();
2467 
2468  TiXmlElement *filter = filters->FirstChildElement("FILTER");
2469  while (filter)
2470  {
2471  ASSERTL0(filter->Attribute("TYPE"),
2472  "Missing attribute 'TYPE' for filter.");
2473  std::string typeStr = filter->Attribute("TYPE");
2474 
2475  std::map<std::string, std::string> vParams;
2476 
2477  TiXmlElement *param = filter->FirstChildElement("PARAM");
2478  while (param)
2479  {
2480  ASSERTL0(param->Attribute("NAME"),
2481  "Missing attribute 'NAME' for parameter in filter " +
2482  typeStr + "'.");
2483  std::string nameStr = param->Attribute("NAME");
2484 
2485  ASSERTL0(param->GetText(), "Empty value string for param.");
2486  std::string valueStr = param->GetText();
2487 
2488  vParams[nameStr] = valueStr;
2489 
2490  param = param->NextSiblingElement("PARAM");
2491  }
2492 
2493  m_filters.push_back(
2494  std::pair<std::string, FilterParams>(typeStr, vParams));
2495 
2496  filter = filter->NextSiblingElement("FILTER");
2497  }
2498 }
2499 
2500 void SessionReader::ParseEquals(const std::string &line, std::string &lhs,
2501  std::string &rhs)
2502 {
2503  /// Pull out lhs and rhs and eliminate any spaces.
2504  size_t beg = line.find_first_not_of(" ");
2505  size_t end = line.find_first_of("=");
2506  // Check for no parameter name
2507  if (beg == end)
2508  throw 1;
2509  // Check for no parameter value
2510  if (end != line.find_last_of("="))
2511  throw 1;
2512  // Check for no equals sign
2513  if (end == std::string::npos)
2514  throw 1;
2515 
2516  lhs = line.substr(line.find_first_not_of(" "), end - beg);
2517  lhs = lhs.substr(0, lhs.find_last_not_of(" ") + 1);
2518  rhs = line.substr(line.find_last_of("=") + 1);
2519  rhs = rhs.substr(rhs.find_first_not_of(" "));
2520  rhs = rhs.substr(0, rhs.find_last_not_of(" ") + 1);
2521 }
2522 
2523 /**
2524  *
2525  */
2526 void SessionReader::CmdLineOverride()
2527 {
2528  // Parse solver info overrides
2529  if (m_cmdLineOptions.count("solverinfo"))
2530  {
2531  std::vector<std::string> solverInfoList =
2532  m_cmdLineOptions["solverinfo"].as<std::vector<std::string>>();
2533 
2534  for (size_t i = 0; i < solverInfoList.size(); ++i)
2535  {
2536  std::string lhs, rhs;
2537 
2538  try
2539  {
2540  ParseEquals(solverInfoList[i], lhs, rhs);
2541  }
2542  catch (...)
2543  {
2544  NEKERROR(ErrorUtil::efatal, "Parse error with command line "
2545  "option: " +
2546  solverInfoList[i]);
2547  }
2548 
2549  std::string lhsUpper = boost::to_upper_copy(lhs);
2550  m_solverInfo[lhsUpper] = rhs;
2551  }
2552  }
2553 
2554  if (m_cmdLineOptions.count("parameter"))
2555  {
2556  std::vector<std::string> parametersList =
2557  m_cmdLineOptions["parameter"].as<std::vector<std::string>>();
2558 
2559  for (size_t i = 0; i < parametersList.size(); ++i)
2560  {
2561  std::string lhs, rhs;
2562 
2563  try
2564  {
2565  ParseEquals(parametersList[i], lhs, rhs);
2566  }
2567  catch (...)
2568  {
2569  NEKERROR(ErrorUtil::efatal, "Parse error with command line "
2570  "option: " +
2571  parametersList[i]);
2572  }
2573 
2574  std::string lhsUpper = boost::to_upper_copy(lhs);
2575 
2576  try
2577  {
2578  m_parameters[lhsUpper] = boost::lexical_cast<NekDouble>(rhs);
2579  }
2580  catch (...)
2581  {
2582  NEKERROR(ErrorUtil::efatal, "Unable to convert string: " + rhs +
2583  "to double value.");
2584  }
2585  }
2586  }
2587 }
2588 
2589 void SessionReader::VerifySolverInfo()
2590 {
2591  for (auto &x : m_solverInfo)
2592  {
2593  std::string solverProperty = x.first;
2594  std::string solverValue = x.second;
2595 
2596  auto propIt = GetSolverInfoEnums().find(solverProperty);
2597  if (propIt != GetSolverInfoEnums().end())
2598  {
2599  auto valIt = propIt->second.find(solverValue);
2600  ASSERTL0(valIt != propIt->second.end(), "Value '" + solverValue +
2601  "' is not valid for "
2602  "property '" +
2603  solverProperty + "'");
2604  }
2605  }
2606 }
2607 
2608 InterpreterSharedPtr SessionReader::GetInterpreter()
2609 {
2610  return m_interpreter;
2611 }
2612 
2613 /**
2614  * Helper function that gets a pointer to a child element, or throws an
2615  * exception if no such element exists
2616  */
2617 TiXmlElement *GetChildElementOrThrow(const std::string &filename,
2618  std::string elementName,
2619  const TiXmlHandle &docHandle)
2620 {
2621  TiXmlElement *element = docHandle.FirstChildElement(elementName).Element();
2622  if (element)
2623  {
2624  return element;
2625  }
2626  else
2627  {
2628  NEKERROR(ErrorUtil::efatal, "Unable to find '" + elementName +
2629  "' XML node in " + filename);
2630  return nullptr; // Never reached; purely to keep gcc happy...
2631  }
2632 }
2633 
2634 } // namespace LibUtilities
2635 } // namespace Nektar
#define NEKTAR_VERSION
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:209
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:249
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
def copy(self)
Definition: pycml.py:2663
static void Finalise(gs_data *pGsh)
Deallocates the GSLib mapping data.
Definition: GsLib.hpp:251
std::shared_ptr< Interpreter > InterpreterSharedPtr
Definition: Interpreter.h:324
std::map< std::string, std::string > SolverInfoMap
Definition: SessionReader.h:58
std::map< std::string, GloSysInfoMap > GloSysSolnInfoList
Definition: SessionReader.h:80
std::map< std::pair< std::string, int >, FunctionVariableDefinition > FunctionVariableMap
std::string PortablePath(const boost::filesystem::path &path)
create portable path on different platforms for boost::filesystem path
Definition: FileSystem.cpp:45
std::map< std::string, NekDouble > ParameterMap
Definition: SessionReader.h:59
std::shared_ptr< Equation > EquationSharedPtr
Definition: Equation.h:129
TiXmlElement * GetChildElementOrThrow(const std::string &filename, std::string elementName, const TiXmlHandle &docHandle)
std::map< std::string, EnumMap > EnumMapList
Definition: SessionReader.h:77
std::vector< std::pair< std::string, FilterParams > > FilterMap
Definition: SessionReader.h:65
CommFactory & GetCommFactory()
std::map< std::string, CmdLineArg > CmdLineArgMap
Definition: SessionReader.h:74
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:54
const std::string kGitBranch
const std::string kGitSha1
InputIterator find(InputIterator first, InputIterator last, InputIterator startingpoint, const EqualityComparable &value)
Definition: StdRegions.hpp:444
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
double NekDouble