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