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