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