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