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