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