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