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