Nektar++
Loading...
Searching...
No Matches
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
74{
75/**
76 * @class SessionReader
77 *
78 * This class provides an interface to Nektar++-specific content in a
79 * supplied XML document. It also initialises a Nektar++ session
80 * including setting up communication for parallel execution and where
81 * necessary partitioning the supplied mesh for running across multiple
82 * processes.
83 *
84 * A session should be initialised at the beginning of a user's
85 * application by passing the command-line arguments. This not only
86 * allows the SessionReader to extract the name of the XML document to
87 * load containing Nektar++ session information, but also supplies the
88 * MPI arguments necessary for setting up parallel communication. The
89 * SessionReader should be initialised using the #CreateInstance
90 * function:
91 * @code
92 * LibUtilities::SessionReaderSharedPtr vSession
93 * = LibUtilities::SessionReader::CreateInstance(argc, argv);
94 * @endcode
95 * The instance \c vSession can now be passed to other key Nektar++
96 * components during their construction.
97 * @note At the end of the user application, it is important to call the
98 * #Finalise routine in order to finalise any MPI communication and
99 * correctly free resources.
100 *
101 * The SessionReader class provides streamlined, validated access to
102 * session parameters, solver information and functions defined within a
103 * Nektar++ XML document. The available routines and their usage is
104 * documented below.
105 *
106 * In the case of solver information properties, the classes to which
107 * these parameters are pertinent may register with the SessionReader
108 * class the set of valid values for a given property. Such values may
109 * also be associated with an enumeration value for more transparent use
110 * of the property values in code.
111 */
112
113/**
114 * This map of maps stores the list of valid string values for a number
115 * of solver information parameters. The top level map connects
116 * different parameter names to their list of possible values. The list
117 * of possible values is also a map, mapping a valid string to a
118 * corresponding enum value.
119 *
120 * This list is populated through the #RegisterEnumValue static member
121 * function which is called statically from various classes to register
122 * the valid values for solver info parameters associated with them. The
123 * map is therefore fully populated before the SessionReader class is
124 * instantiated and a file is read in and parsed.
125 */
127{
128 static EnumMapList solverInfoEnums;
129 return solverInfoEnums;
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 */
141{
142 static SolverInfoMap solverInfoMap;
143 return solverInfoMap;
144}
145
146/**
147 * List of values for GlobalSysSoln parameters to be used to override
148 * details given in SolverInfo
149 *
150 * This list is populated by ReadGlobalSysSolnInfo if the
151 * GLOBALSYSSOLNINFO section is defined in the input file.
152 * This List allows for details to define for the Global Sys
153 * solver for each variable.
154 */
156{
157 static GloSysSolnInfoList gloSysSolnInfoList;
158 return gloSysSolnInfoList;
159}
160
161/**
162 * Lists the possible command-line argument which can be specified for
163 * this executable.
164 *
165 * This list is populated through the #RegisterCmdLineArgument static
166 * member function which is called statically from various classes to
167 * register command-line arguments they need.
168 */
170{
171 static CmdLineArgMap cmdLineArguments;
172 return cmdLineArguments;
173}
174
175/**
176 * This constructor parses the command-line arguments given to the user
177 * application to set up any MPI communication, read supplied XML
178 * session files, and partition meshes where necessary.
179 *
180 * @param argc Number of command-line arguments
181 * @param argv Array of command-line arguments
182 */
183SessionReader::SessionReader(int argc, char *argv[])
184{
185 m_xmlDoc = nullptr;
187
188 ASSERTL0(m_filenames.size() > 0, "No session file(s) given.");
189
191
192 // Create communicator
193 CreateComm(argc, argv);
194
196
197 // Split up the communicator
199
200 // If running in parallel change the default global sys solution
201 // type.
202 if (m_comm->GetSpaceComm()->GetSize() > 1)
203 {
204 GetSolverInfoDefaults()["GLOBALSYSSOLN"] = "IterativeStaticCond";
205 }
206
208 m_interpreter->SetRandomSeed((m_comm->GetSpaceComm()->GetRank() + 1) *
209 (unsigned int)time(nullptr));
210}
211
212/**
213 *
214 */
215SessionReader::SessionReader(int argc, char *argv[],
216 const std::vector<std::string> &pFilenames,
217 const CommSharedPtr &pComm, const int &timelevel)
218{
219 ASSERTL0(pFilenames.size() > 0, "No filenames specified.");
220
221 ParseCommandLineArguments(argc, argv);
222 m_xmlDoc = nullptr;
223 m_filenames = pFilenames;
224
226
227 // Create communicator
228 if (!pComm.get())
229 {
230 CreateComm(argc, argv);
231 }
232 else
233 {
234 m_comm = pComm;
235 }
236
238
239 // Split up the communicator
241
242 // If running in parallel change the default global sys solution
243 // type.
244 if (m_comm->GetSpaceComm()->GetSize() > 1)
245 {
246 GetSolverInfoDefaults()["GLOBALSYSSOLN"] = "IterativeStaticCond";
247 }
248
250 m_interpreter->SetRandomSeed((m_comm->GetSpaceComm()->GetRank() + 1) *
251 (unsigned int)time(nullptr));
252
253 // Set time level (Parallel-in-Time)
254 m_timeLevel = timelevel;
255}
256
257/**
258 *
259 */
261{
262 if (m_xmlDoc)
263 {
264 delete m_xmlDoc;
265 }
266}
267
268/**
269 * Performs the main initialisation of the object. The XML file provided
270 * on the command-line is loaded and any mesh partitioning is done. The
271 * resulting process-specific XML file (containing the process's
272 * geometry partition) is then reloaded and parsed.
273 */
274void SessionReader::InitSession(const std::vector<std::string> &filenames)
275{
276 // Re-load filenames for session if required.
277 if (filenames.size() > 0)
278 {
279 m_filenames = filenames;
280 }
281
282 // check specified opt file
283 std::string optfile;
284 int exists;
285
286 if (DefinesCmdLineArgument("use-opt-file"))
287 {
288 optfile =
289 m_cmdLineOptions.find("use-opt-file")->second.as<std::string>();
290 exists = fs::exists(optfile.c_str());
291 ASSERTL0(exists, "A valid .opt file was not specified "
292 "with the --use-opt-file command line option");
293
294 m_filenames.push_back(optfile);
295
296 // put opt file at beginning
297 std::rotate(m_filenames.rbegin(), m_filenames.rbegin() + 1,
298 m_filenames.rend());
299 }
300 else // check for write-opt-file
301 {
302 // check for opt file
303 optfile = m_sessionName.substr(0, m_sessionName.find("_xml/")) + ".opt";
304 exists = fs::exists(optfile.c_str());
305
306 // For Paralell-in-Time
307 if (exists && m_comm->IsParallelInTime())
308 {
309 TiXmlDocument doc;
310 doc.LoadFile(optfile);
311 TiXmlElement *xmlTag = doc.FirstChildElement("NEKTAR")
312 ->FirstChildElement("COLLECTIONS")
313 ->FirstChildElement("TIMELEVEL");
314 if (xmlTag)
315 {
316 // if there is a TIMELEVEL tag, then turn existing flag to false
317 // and check if the required time level is specified in the
318 // optfile.
319 exists = false;
320 while (xmlTag)
321 {
322 if (m_timeLevel == stoi(xmlTag->Attribute("VALUE")))
323 {
324 exists = true;
325 break;
326 }
327 xmlTag = xmlTag->NextSiblingElement();
328 }
329 }
330 }
331
332 if (exists)
333 {
334 m_filenames.push_back(optfile);
335 // rotate order so opt file can be overwritten by
336 // direct choice in xml file
337 std::rotate(m_filenames.rbegin(), m_filenames.rbegin() + 1,
338 m_filenames.rend());
339 }
340 else
341 {
342 m_updateOptFile = true;
343 }
344 }
345
346 // Merge document if required.
347 if (m_xmlDoc)
348 {
349 delete m_xmlDoc;
350 }
351
353
354 // Parse the XML data in #m_xmlDoc
356
357 // Override SOLVERINFO and parameters with any specified on the
358 // command line.
360
361 // Verify SOLVERINFO values
363
364 // Disable backups if NEKTAR_DISABLE_BACKUPS is set.
365 if (std::getenv("NEKTAR_DISABLE_BACKUPS") != nullptr)
366 {
367 m_backups = false;
368 }
369
370 // In verbose mode, print out parameters and solver info sections
371 if (m_verbose && m_comm)
372 {
373 if (m_comm->TreatAsRankZero() && m_parameters.size() > 0)
374 {
375 cout << "Parameters:" << endl;
376 for (auto &x : m_parameters)
377 {
378 cout << "\t" << x.first << " = " << x.second << endl;
379 }
380 cout << endl;
381 }
382
383 if (m_comm->TreatAsRankZero() && m_solverInfo.size() > 0)
384 {
385 cout << "Solver Info:" << endl;
386 for (auto &x : m_solverInfo)
387 {
388 cout << "\t" << x.first << " = " << x.second << endl;
389 }
390 cout << endl;
391 }
392 }
393}
394
395/**
396 *
397 */
399{
400 m_sharedFilesystem = false;
401
402 if (m_comm->GetSize() > 1)
403 {
404 if (m_comm->GetRank() == 0)
405 {
406 std::ofstream testfile("shared-fs-testfile");
407 testfile << "" << std::endl;
408 ASSERTL1(!testfile.fail(), "Test file creation failed");
409 testfile.close();
410 }
411 m_comm->Block();
412
413 int exists = fs::exists("shared-fs-testfile");
414 m_comm->AllReduce(exists, LibUtilities::ReduceSum);
415
416 m_sharedFilesystem = (exists == m_comm->GetSize());
417
418 if ((m_sharedFilesystem && m_comm->GetRank() == 0) ||
420 {
421 std::remove("shared-fs-testfile");
422 }
423 }
424 else
425 {
426 m_sharedFilesystem = false;
427 }
428
429 if (m_verbose && m_comm->GetRank() == 0 && m_sharedFilesystem)
430 {
431 cout << "Shared filesystem detected" << endl;
432 }
433}
434
435/**
436 * @brief Parses the command-line arguments for known options and
437 * filenames.
438 */
439std::vector<std::string> SessionReader::ParseCommandLineArguments(int argc,
440 char *argv[])
441{
442 // List the publically visible options (listed using --help).
443 po::options_description desc("Allowed options");
444 po::options_description dep("Deprecated options");
445
446 // clang-format off
447 desc.add_options()
448 ("force-output,f","disables backups files and forces output to be "
449 "written without any checks")
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 ("verbose,v", "be verbose")
456 ("version,V", "print version information")
457 ("no-exp-opt", "Do not use expansion optimisation for collections")
458 ("npx", po::value<int>(),
459 "number of procs in X-dir")
460 ("npy", po::value<int>(),
461 "number of procs in Y-dir")
462 ("npz", po::value<int>(),
463 "number of procs in Z-dir")
464 ("nsz", po::value<int>(),
465 "number of slices in Z-dir")
466 ("npt", po::value<int>(),
467 "number of procs in T-dir (parareal)")
468 ("part-only", po::value<int>(),
469 "only partition mesh into N partitions.")
470 ("part-only-overlapping", po::value<int>(),
471 "only partition mesh into N overlapping partitions.")
472 ("part-info", "output partition information")
473 ("write-opt-file","write an optimisation file")
474 ("use-opt-file", po::value<std::string>(),
475 "use an optimisation file");
476 // clang-format on
477
478#ifdef NEKTAR_USE_CWIPI
479 desc.add_options()("cwipi", po::value<std::string>(), "set CWIPI name");
480#endif
481
482 for (auto &cmdIt : GetCmdLineArgMap())
483 {
484 std::string names = cmdIt.first;
485 if (cmdIt.second.shortName != "")
486 {
487 names += "," + cmdIt.second.shortName;
488 }
489 if (cmdIt.second.isFlag)
490 {
491 desc.add_options()(names.c_str(), cmdIt.second.description.c_str());
492 }
493 else
494 {
495 desc.add_options()(names.c_str(), po::value<std::string>(),
496 cmdIt.second.description.c_str());
497 }
498 }
499
500 // Deprecated options: introduced in 5.4.0 to homogenise command-line
501 // options to use '-' instead of camelCase or no spaces.
502 std::map<std::string, std::string> deprecated = {
503 {"forceoutput", "force-output"},
504 {"writeoptfile", "write-opt-file"},
505 {"useoptfile", "use-opt-file"}};
506
507 for (auto &d : deprecated)
508 {
509 std::string description = "Deprecated: use --" + d.second;
510 dep.add_options()(d.first.c_str(), description.c_str());
511 }
512
513 // List hidden options (e.g. session file arguments are not actually
514 // specified using the input-file option by the user).
515 po::options_description hidden("Hidden options");
516
517 hidden.add_options()("input-file", po::value<vector<string>>(),
518 "input filename");
519
520 // Combine all options for the parser
521 po::options_description all("All options");
522 all.add(desc).add(dep).add(hidden);
523
524 // Session file is a positional option
525 po::positional_options_description p;
526 p.add("input-file", -1);
527
528 // Parse the command-line options
529 po::parsed_options parsed = po::command_line_parser(argc, argv)
530 .options(all)
531 .positional(p)
532 .allow_unregistered()
533 .run();
534
535 // Extract known options to map and update
536 po::store(parsed, m_cmdLineOptions);
537 po::notify(m_cmdLineOptions);
538
539 // Help message
540 if (m_cmdLineOptions.count("help"))
541 {
542 cout << desc;
543 exit(0);
544 }
545
546 // Version information
547 if (m_cmdLineOptions.count("version"))
548 {
549 cout << "Nektar++ version " << NEKTAR_VERSION;
550
551 if (NekConstants::kGitSha1 != "GITDIR-NOTFOUND")
552 {
554 string branch(NekConstants::kGitBranch);
555 boost::replace_all(branch, "refs/heads/", "");
556
557 cout << " (git changeset " << sha1.substr(0, 8) << ", ";
558
559 if (branch == "")
560 {
561 cout << "detached head";
562 }
563 else
564 {
565 cout << "head " << branch;
566 }
567
568 cout << ")";
569 }
570
571 cout << endl;
572 exit(0);
573 }
574
575 // Deal with deprecated options.
576 for (auto &d : deprecated)
577 {
578 if (m_cmdLineOptions.count(d.first))
579 {
580 std::cerr << "Warning: --" << d.first << " deprecated: use --"
581 << d.second << std::endl;
582 m_cmdLineOptions.emplace(
583 d.second, po::variable_value(m_cmdLineOptions[d.first]));
584 }
585 }
586
587 // Enable verbose mode
588 if (m_cmdLineOptions.count("verbose"))
589 {
590 m_verbose = true;
591 }
592 else
593 {
594 m_verbose = false;
595 }
596
597 // Disable backups
598 if (m_cmdLineOptions.count("force-output"))
599 {
600 m_backups = false;
601 }
602 else
603 {
604 m_backups = true;
605 }
606
607 // Enable update optimisation file
608 if (m_cmdLineOptions.count("write-opt-file"))
609 {
610 m_updateOptFile = true;
611 }
612 else
613 {
614 m_updateOptFile = false;
615 }
616
617 // Print a warning for unknown options
618 for (auto &x : parsed.options)
619 {
620 if (x.unregistered)
621 {
622 cout << "Warning: Unknown option: " << x.string_key << endl;
623 }
624 }
625
626 // Return the vector of filename(s) given as positional options
627 if (m_cmdLineOptions.count("input-file"))
628 {
629 return m_cmdLineOptions["input-file"].as<std::vector<std::string>>();
630 }
631 else
632 {
633 return std::vector<std::string>();
634 }
635}
636
637/**
638 *
639 */
640std::string SessionReader::ParseSessionName(std::vector<std::string> &filenames)
641{
642 ASSERTL0(!filenames.empty(), "At least one filename expected.");
643
644 std::string retval = "";
645
646 // First input file defines the session name
647 std::string fname = filenames[0];
648
649 // If loading a pre-partitioned mesh, remove _xml extension
650 if (fname.size() > 4 && fname.substr(fname.size() - 4, 4) == "_xml")
651 {
652 retval = fname.substr(0, fname.find_last_of("_"));
653 }
654 // otherwise remove the .xml extension
655 else if (fname.size() > 4 && fname.substr(fname.size() - 4, 4) == ".xml")
656 {
657 retval = fname.substr(0, fname.find_last_of("."));
658 }
659 // If compressed .xml.gz, remove both extensions
660 else if (fname.size() > 7 && fname.substr(fname.size() - 7, 7) == ".xml.gz")
661 {
662 retval = fname.substr(0, fname.find_last_of("."));
663 retval = retval.substr(0, retval.find_last_of("."));
664 }
665
666 return retval;
667}
668
669/**
670 *
671 */
673{
674 ASSERTL1(m_xmlDoc, "XML Document not defined.");
675 return *m_xmlDoc;
676}
677
678/**
679 * The single parameter specifies a path to the requested element in a
680 * similar format to the filesystem path. Given the following XML:
681 * @code
682 * <NEKTAR>
683 * <CONDITIONS>
684 * <PARAMETERS>
685 * ...
686 * </PARAMETERS>
687 * </CONDITIONS>
688 * </NEKTAR>
689 * @endcode
690 * the PARAMETERS element would be retrieved by requesting the path:
691 * @code
692 * Nektar/Conditions/Parameters
693 * @endcode
694 * @note Paths are case-insensitive.
695 *
696 * @param pPath Path to requested element.
697 *
698 * @return Direct pointer to requested XML Element.
699 */
700TiXmlElement *SessionReader::GetElement(const string &pPath)
701{
702 std::string vPath = boost::to_upper_copy(pPath);
703 std::vector<std::string> st;
704 boost::split(st, vPath, boost::is_any_of("\\/ "));
705 ASSERTL0(st.size() > 0, "No path given in XML element request.");
706
707 TiXmlElement *vReturn = m_xmlDoc->FirstChildElement(st[0].c_str());
708 ASSERTL0(vReturn,
709 std::string("Cannot find element '") + st[0] + std::string("'."));
710 for (int i = 1; i < st.size(); ++i)
711 {
712 vReturn = vReturn->FirstChildElement(st[i].c_str());
713 ASSERTL0(vReturn, std::string("Cannot find element '") + st[i] +
714 std::string("'."));
715 }
716 return vReturn;
717}
718
719/**
720 *
721 */
722bool SessionReader::DefinesElement(const std::string &pPath) const
723{
724 std::string vPath = boost::to_upper_copy(pPath);
725 std::vector<std::string> st;
726 boost::split(st, vPath, boost::is_any_of("\\/ "));
727 ASSERTL0(st.size() > 0, "No path given in XML element request.");
728
729 TiXmlElement *vReturn = m_xmlDoc->FirstChildElement(st[0].c_str());
730 ASSERTL0(vReturn,
731 std::string("Cannot find element '") + st[0] + std::string("'."));
732 for (int i = 1; i < st.size(); ++i)
733 {
734 vReturn = vReturn->FirstChildElement(st[i].c_str());
735 if (!vReturn)
736 {
737 return false;
738 }
739 }
740 return true;
741}
742
743/**
744 *
745 */
746const std::vector<std::string> &SessionReader::GetFilenames() const
747{
748 return m_filenames;
749}
750
751/**
752 *
753 */
754const std::string &SessionReader::GetSessionName() const
755{
756 return m_sessionName;
757}
758
759/**
760 *
761 */
766
771
772/**
773 * This routine finalises any parallel communication.
774 *
775 * @note This routine should be called at the very end of a users
776 * application.
777 */
779{
780 m_comm->Finalise();
781}
782
783/**
784 *
785 */
786bool SessionReader::DefinesParameter(const std::string &pName) const
787{
788 std::string vName = boost::to_upper_copy(pName);
789 return m_parameters.find(vName) != m_parameters.end();
790}
791
792/**
793 * If the parameter is not defined, termination occurs. Therefore, the
794 * parameters existence should be tested for using #DefinesParameter
795 * before calling this function.
796 *
797 * @param pName The name of a floating-point parameter.
798 * @returns The value of the floating-point parameter.
799 */
800const NekDouble &SessionReader::GetParameter(const std::string &pName) const
801{
802 std::string vName = boost::to_upper_copy(pName);
803 auto paramIter = m_parameters.find(vName);
804
805 ASSERTL0(paramIter != m_parameters.end(),
806 "Unable to find requested parameter: " + pName);
807
808 return paramIter->second;
809}
810
811/**
812 * Getter for the session's parameters
813 * @returns A reference to the parameter map
814 */
819
820/**
821 *
822 */
823void SessionReader::LoadParameter(const std::string &pName, int &pVar) const
824{
825 std::string vName = boost::to_upper_copy(pName);
826 auto paramIter = m_parameters.find(vName);
827 ASSERTL0(paramIter != m_parameters.end(),
828 "Required parameter '" + pName + "' not specified in session.");
829 NekDouble param = round(paramIter->second);
830 pVar = checked_cast<int>(param);
831}
832
833/**
834 *
835 */
836void SessionReader::LoadParameter(const std::string &pName, int &pVar,
837 const int &pDefault) const
838{
839 std::string vName = boost::to_upper_copy(pName);
840 auto paramIter = m_parameters.find(vName);
841 if (paramIter != m_parameters.end())
842 {
843 NekDouble param = round(paramIter->second);
844 pVar = checked_cast<int>(param);
845 }
846 else
847 {
848 pVar = pDefault;
849 }
850}
851
852/**
853 *
854 */
855void SessionReader::LoadParameter(const std::string &pName,
856 unsigned int &pVar) const
857{
858 std::string vName = boost::to_upper_copy(pName);
859 auto paramIter = m_parameters.find(vName);
860 ASSERTL0(paramIter != m_parameters.end(),
861 "Required parameter '" + pName + "' not specified in session.");
862 NekDouble param = round(paramIter->second);
863 pVar = checked_cast<unsigned int>(param);
864}
865
866/**
867 *
868 */
869void SessionReader::LoadParameter(const std::string &pName, unsigned int &pVar,
870 const unsigned int &pDefault) const
871{
872 std::string vName = boost::to_upper_copy(pName);
873 auto paramIter = m_parameters.find(vName);
874 if (paramIter != m_parameters.end())
875 {
876 NekDouble param = round(paramIter->second);
877 pVar = checked_cast<unsigned int>(param);
878 }
879 else
880 {
881 pVar = pDefault;
882 }
883}
884
885/**
886 *
887 */
888void SessionReader::LoadParameter(const std::string &pName, size_t &pVar) const
889{
890 std::string vName = boost::to_upper_copy(pName);
891 auto paramIter = m_parameters.find(vName);
892 ASSERTL0(paramIter != m_parameters.end(),
893 "Required parameter '" + pName + "' not specified in session.");
894 NekDouble param = round(paramIter->second);
895 pVar = checked_cast<int>(param);
896}
897
898/**
899 *
900 */
901void SessionReader::LoadParameter(const std::string &pName, size_t &pVar,
902 const size_t &pDefault) const
903{
904 std::string vName = boost::to_upper_copy(pName);
905 auto paramIter = m_parameters.find(vName);
906 if (paramIter != m_parameters.end())
907 {
908 NekDouble param = round(paramIter->second);
909 pVar = checked_cast<int>(param);
910 }
911 else
912 {
913 pVar = pDefault;
914 }
915}
916
917/**
918 *
919 */
920void SessionReader::LoadParameter(const std::string &pName,
921 NekDouble &pVar) const
922{
923 std::string vName = boost::to_upper_copy(pName);
924 auto paramIter = m_parameters.find(vName);
925 ASSERTL0(paramIter != m_parameters.end(),
926 "Required parameter '" + pName + "' not specified in session.");
927 pVar = paramIter->second;
928}
929
930/**
931 *
932 */
933void SessionReader::LoadParameter(const std::string &pName, NekDouble &pVar,
934 const NekDouble &pDefault) const
935{
936 std::string vName = boost::to_upper_copy(pName);
937 auto paramIter = m_parameters.find(vName);
938 if (paramIter != m_parameters.end())
939 {
940 pVar = paramIter->second;
941 }
942 else
943 {
944 pVar = pDefault;
945 }
946}
947
948/**
949 *
950 */
951void SessionReader::SetParameter(const std::string &pName, int &pVar)
952{
953 std::string vName = boost::to_upper_copy(pName);
954 m_parameters[vName] = pVar;
955 m_interpreter->SetParameter(pName, pVar);
956}
957
958/**
959 *
960 */
961void SessionReader::SetParameter(const std::string &pName, unsigned int &pVar)
962{
963 std::string vName = boost::to_upper_copy(pName);
964 m_parameters[vName] = pVar;
965 m_interpreter->SetParameter(pName, pVar);
966}
967
968/**
969 *
970 */
971void SessionReader::SetParameter(const std::string &pName, size_t &pVar)
972{
973 std::string vName = boost::to_upper_copy(pName);
974 m_parameters[vName] = pVar;
975 m_interpreter->SetParameter(pName, pVar);
976}
977
978/**
979 *
980 */
981void SessionReader::SetParameter(const std::string &pName, NekDouble &pVar)
982{
983 std::string vName = boost::to_upper_copy(pName);
984 m_parameters[vName] = pVar;
985 m_interpreter->SetParameter(pName, pVar);
986}
987
988/**
989 *
990 */
991bool SessionReader::DefinesSolverInfo(const std::string &pName) const
992{
993 std::string vName = boost::to_upper_copy(pName);
994 auto infoIter = m_solverInfo.find(vName);
995 return (infoIter != m_solverInfo.end());
996}
997
998/**
999 *
1000 */
1002 const std::string &pProperty) const
1003{
1004 std::string vProperty = boost::to_upper_copy(pProperty);
1005 auto iter = m_solverInfo.find(vProperty);
1006
1007 ASSERTL1(iter != m_solverInfo.end(),
1008 "Unable to find requested property: " + pProperty);
1009
1010 return iter->second;
1011}
1012
1013/**
1014 *
1015 */
1016void SessionReader::SetSolverInfo(const std::string &pProperty,
1017 const std::string &pValue)
1018{
1019 std::string vProperty = boost::to_upper_copy(pProperty);
1020 auto iter = m_solverInfo.find(vProperty);
1021
1022 ASSERTL1(iter != m_solverInfo.end(),
1023 "Unable to find requested property: " + pProperty);
1024
1025 iter->second = pValue;
1026}
1027
1028/**
1029 *
1030 */
1031void SessionReader::LoadSolverInfo(const std::string &pName, std::string &pVar,
1032 const std::string &pDefault) const
1033{
1034 std::string vName = boost::to_upper_copy(pName);
1035 auto infoIter = m_solverInfo.find(vName);
1036 if (infoIter != m_solverInfo.end())
1037 {
1038 pVar = infoIter->second;
1039 }
1040 else
1041 {
1042 pVar = pDefault;
1043 }
1044}
1045
1046/**
1047 *
1048 */
1049void SessionReader::MatchSolverInfo(const std::string &pName,
1050 const std::string &pTrueVal, bool &pVar,
1051 const bool &pDefault) const
1052{
1053 std::string vName = boost::to_upper_copy(pName);
1054 auto infoIter = m_solverInfo.find(vName);
1055 if (infoIter != m_solverInfo.end())
1056 {
1057 pVar = boost::iequals(infoIter->second, pTrueVal);
1058 }
1059 else
1060 {
1061 pVar = pDefault;
1062 }
1063}
1064
1065/**
1066 *
1067 */
1068bool SessionReader::MatchSolverInfo(const std::string &pName,
1069 const std::string &pTrueVal) const
1070{
1071 if (DefinesSolverInfo(pName))
1072 {
1073 std::string vName = boost::to_upper_copy(pName);
1074 auto iter = m_solverInfo.find(vName);
1075 if (iter != m_solverInfo.end())
1076 {
1077 return boost::iequals(iter->second, pTrueVal);
1078 }
1079 }
1080 return false;
1081}
1082
1083/**
1084 *
1085 */
1086bool SessionReader::DefinesGlobalSysSolnInfo(const std::string &pVariable,
1087 const std::string &pProperty) const
1088{
1089 auto iter = GetGloSysSolnList().find(pVariable);
1090 if (iter == GetGloSysSolnList().end())
1091 {
1092 return false;
1093 }
1094
1095 std::string vProperty = boost::to_upper_copy(pProperty);
1096
1097 auto iter1 = iter->second.find(vProperty);
1098 if (iter1 == iter->second.end())
1099 {
1100 return false;
1101 }
1102
1103 return true;
1104}
1105
1106/**
1107 *
1108 */
1110 const std::string &pVariable, const std::string &pProperty) const
1111{
1112 auto iter = GetGloSysSolnList().find(pVariable);
1113 ASSERTL0(iter != GetGloSysSolnList().end(),
1114 "Failed to find variable in GlobalSysSolnInfoList");
1115
1116 std::string vProperty = boost::to_upper_copy(pProperty);
1117 auto iter1 = iter->second.find(vProperty);
1118
1119 ASSERTL0(iter1 != iter->second.end(),
1120 "Failed to find property: " + vProperty +
1121 " in GlobalSysSolnInfoList");
1122
1123 return iter1->second;
1124}
1125
1126/**
1127 *
1128 */
1129void SessionReader::SetGlobalSysSolnInfo(const std::string &pVariable,
1130 const std::string &pProperty,
1131 const std::string &pValue)
1132{
1133
1134 std::string vProperty = boost::to_upper_copy(pProperty);
1135
1136 auto iter = GetGloSysSolnList().find(pVariable);
1137 if (iter == GetGloSysSolnList().end())
1138 {
1139 (GetGloSysSolnList()[pVariable])[vProperty] = pValue;
1140 }
1141 else
1142 {
1143 iter->second[vProperty] = pValue;
1144 }
1145}
1146
1147/**
1148 * @brief Returns true if the TIMEINTEGRATIONSCHEME section is defined
1149 * in the session file.
1150 */
1152{
1153 return m_timeIntScheme.method != "";
1154}
1155
1156/**
1157 * @brief Returns the time integration scheme structure #m_timeIntScheme
1158 * from the session file.
1159 */
1161{
1162 return m_timeIntScheme;
1163}
1164
1165/**
1166 *
1167 */
1169{
1170 TiXmlElement *xmlGeom =
1171 m_xmlDoc->FirstChildElement("NEKTAR")->FirstChildElement("GEOMETRY");
1172 ASSERTL1(xmlGeom, "Failed to find a GEOMETRY section in m_xmlDoc");
1173
1174 TiXmlAttribute *attr = xmlGeom->FirstAttribute();
1175 while (attr)
1176 {
1177 std::string attrName(attr->Name());
1178 if (attrName == "HDF5FILE")
1179 {
1180 // there is a file pointer, therefore is HDF5
1181 return "HDF5";
1182 }
1183 // Get the next attribute.
1184 attr = attr->Next();
1185 }
1186
1187 // Check the VERTEX block. If this is compressed, assume the file is
1188 // compressed, otherwise assume uncompressed.
1189 TiXmlElement *element = xmlGeom->FirstChildElement("VERTEX");
1190 string IsCompressed;
1191 element->QueryStringAttribute("COMPRESSED", &IsCompressed);
1192
1193 if (IsCompressed.size() > 0)
1194 {
1195 return "XmlCompressed";
1196 }
1197
1198 // no file pointer or compressed, just standard xml
1199 return "Xml";
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, "No such variable " + pVariable +
1292 " in domain " + std::to_string(pDomain) +
1293 " defined for function " + pName +
1294 " 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, "No such variable " + pVariable +
1342 " in domain " + std::to_string(pDomain) +
1343 " defined for function " + pName +
1344 " 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, "No such variable " + pVariable +
1390 " in domain " + std::to_string(pDomain) +
1391 " defined for function " + pName +
1392 " 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, "No such variable " + pVariable +
1438 " in domain " + std::to_string(pDomain) +
1439 " defined for function " + pName +
1440 " 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 enableCheck)
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 (enableCheck)
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 if (!p->FirstChild() && vMainEntry &&
1625 !boost::iequals(p->Value(), "COLLECTIONS"))
1626 {
1627 std::string warningmsg =
1628 "File " + pFilenames[i] + " contains " +
1629 "an empty XML element " + std::string(p->Value()) +
1630 " which will be ignored.";
1631 NEKERROR(ErrorUtil::ewarning, warningmsg.c_str());
1632 }
1633 else
1634 {
1635 if (vMainEntry)
1636 {
1637 vMainNektar->RemoveChild(vMainEntry);
1638 }
1639 TiXmlElement *q = new TiXmlElement(*p);
1640 vMainNektar->LinkEndChild(q);
1641 }
1642 p = p->NextSiblingElement();
1643 }
1644 delete vTempDoc;
1645 }
1646 }
1647 return vMainDoc;
1648}
1649
1650/**
1651 *
1652 */
1654{
1655 // Check we actually have a document loaded.
1656 ASSERTL0(m_xmlDoc, "No XML document loaded.");
1657
1658 TiXmlHandle docHandle(m_xmlDoc);
1659 TiXmlElement *e;
1660
1661 // Look for all data in CONDITIONS block.
1662 e = docHandle.FirstChildElement("NEKTAR")
1663 .FirstChildElement("CONDITIONS")
1664 .Element();
1665
1666 // Read the various sections of the CONDITIONS block
1667 ReadParameters(e);
1668 ReadSolverInfo(e);
1671 ReadVariables(e);
1672 ReadFunctions(e);
1673
1674 // Look for all data in FILTERS block.
1675 e = docHandle.FirstChildElement("NEKTAR")
1676 .FirstChildElement("FILTERS")
1677 .Element();
1678
1679 // Read the various sections of the FILTERS block
1680 ReadFilters(e);
1681}
1682
1683/**
1684 *
1685 */
1686void SessionReader::CreateComm(int &argc, char *argv[])
1687{
1688 if (argc == 0)
1689 {
1690 m_comm = GetCommFactory().CreateInstance("Serial", 0, 0);
1691 }
1692 else
1693 {
1694 string vCommModule("Serial");
1695 if (GetCommFactory().ModuleExists("ParallelMPI"))
1696 {
1697 vCommModule = "ParallelMPI";
1698 }
1699 if (m_cmdLineOptions.count("cwipi") &&
1700 GetCommFactory().ModuleExists("CWIPI"))
1701 {
1702 vCommModule = "CWIPI";
1703 }
1704
1705 m_comm = GetCommFactory().CreateInstance(vCommModule, argc, argv);
1706 }
1707}
1708
1709/**
1710 * Splits the processes into a cartesian grid and creates communicators
1711 * for each row and column of the grid.
1712 */
1714{
1715 if (m_comm->GetSize() > 1)
1716 {
1717 int nProcZ = 1;
1718 int nProcY = 1;
1719 int nProcX = 1;
1720 int nStripZ = 1;
1721 int nTime = 0;
1722 if (DefinesCmdLineArgument("npx"))
1723 {
1724 nProcX = GetCmdLineArgument<int>("npx");
1725 }
1726 if (DefinesCmdLineArgument("npy"))
1727 {
1728 nProcY = GetCmdLineArgument<int>("npy");
1729 }
1730 if (DefinesCmdLineArgument("npz"))
1731 {
1732 nProcZ = GetCmdLineArgument<int>("npz");
1733 }
1734 if (DefinesCmdLineArgument("nsz"))
1735 {
1736 nStripZ = GetCmdLineArgument<int>("nsz");
1737 }
1738 if (DefinesCmdLineArgument("npt"))
1739 {
1740 nTime = GetCmdLineArgument<int>("npt");
1741 }
1742
1743 if (nTime)
1744 {
1745 ASSERTL0(m_comm->GetSize() % nTime == 0,
1746 "Cannot exactly partition time using npt value.");
1747 ASSERTL0((m_comm->GetSize() / nTime) % (nProcZ * nProcY * nProcX) ==
1748 0,
1749 "Cannot exactly partition using PROC_Z value.");
1750 ASSERTL0(nProcZ % nProcY == 0,
1751 "Cannot exactly partition using PROC_Y value.");
1752 ASSERTL0(nProcY % nProcX == 0,
1753 "Cannot exactly partition using PROC_X value.");
1754 }
1755 else
1756 {
1757 ASSERTL0(m_comm->GetSize() % (nProcZ * nProcY * nProcX) == 0,
1758 "Cannot exactly partition using PROC_Z value.");
1759 ASSERTL0(nProcZ % nProcY == 0,
1760 "Cannot exactly partition using PROC_Y value.");
1761 ASSERTL0(nProcY % nProcX == 0,
1762 "Cannot exactly partition using PROC_X value.");
1763 }
1764
1765 // Number of processes associated with the spectral method
1766 int nProcSm = nProcZ * nProcY * nProcX;
1767
1768 // Number of processes associated with the spectral element
1769 // method.
1770 int nProcSem = nTime ? m_comm->GetSize() / nTime / nProcSm
1771 : m_comm->GetSize() / nProcSm;
1772
1773 m_comm->SplitComm(nProcSm, nProcSem, nTime);
1774 m_comm->GetColumnComm()->SplitComm(nProcZ / nStripZ, nStripZ);
1775 m_comm->GetColumnComm()->GetColumnComm()->SplitComm((nProcY * nProcX),
1776 nProcZ / nStripZ);
1777 m_comm->GetColumnComm()->GetColumnComm()->GetColumnComm()->SplitComm(
1778 nProcX, nProcY);
1779 }
1780}
1781
1782/**
1783 *
1784 */
1785void SessionReader::ReadParameters(TiXmlElement *conditions)
1786{
1787 m_parameters.clear();
1788
1789 if (!conditions)
1790 {
1791 return;
1792 }
1793
1794 TiXmlElement *parametersElement =
1795 conditions->FirstChildElement("PARAMETERS");
1796 GetXMLElementTimeLevel(parametersElement, m_timeLevel);
1797
1798 // See if we have parameters defined. They are optional so we go on
1799 // if not.
1800 if (parametersElement)
1801 {
1802 TiXmlElement *parameter = parametersElement->FirstChildElement("P");
1803
1804 ParameterMap caseSensitiveParameters;
1805
1806 // Multiple nodes will only occur if there is a comment in
1807 // between definitions.
1808 while (parameter)
1809 {
1810 stringstream tagcontent;
1811 tagcontent << *parameter;
1812 TiXmlNode *node = parameter->FirstChild();
1813
1814 while (node && node->Type() != TiXmlNode::TINYXML_TEXT)
1815 {
1816 node = node->NextSibling();
1817 }
1818
1819 if (node)
1820 {
1821 // Format is "paramName = value"
1822 std::string line = node->ToText()->Value(), lhs, rhs;
1823
1824 try
1825 {
1826 ParseEquals(line, lhs, rhs);
1827 }
1828 catch (...)
1829 {
1831 "Syntax error in parameter expression '" + line +
1832 "' in XML element: \n\t'" + tagcontent.str() +
1833 "'");
1834 }
1835
1836 // We want the list of parameters to have their RHS
1837 // evaluated, so we use the expression evaluator to do
1838 // the dirty work.
1839 if (!lhs.empty() && !rhs.empty())
1840 {
1841 NekDouble value = 0.0;
1842 try
1843 {
1844 LibUtilities::Equation expession(m_interpreter, rhs);
1845 value = expession.Evaluate();
1846 }
1847 catch (const std::runtime_error &)
1848 {
1850 "Error evaluating parameter expression"
1851 " '" +
1852 rhs + "' in XML element: \n\t'" +
1853 tagcontent.str() + "'");
1854 }
1855 m_interpreter->SetParameter(lhs, value);
1856 caseSensitiveParameters[lhs] = value;
1857 boost::to_upper(lhs);
1858 m_parameters[lhs] = value;
1859 }
1860 }
1861 parameter = parameter->NextSiblingElement();
1862 }
1863 }
1864}
1865
1866/**
1867 *
1868 */
1869void SessionReader::ReadSolverInfo(TiXmlElement *conditions)
1870{
1871 m_solverInfo.clear();
1873
1874 if (!conditions)
1875 {
1876 return;
1877 }
1878
1879 TiXmlElement *solverInfoElement =
1880 conditions->FirstChildElement("SOLVERINFO");
1881 GetXMLElementTimeLevel(solverInfoElement, m_timeLevel);
1882
1883 if (solverInfoElement)
1884 {
1885 TiXmlElement *solverInfo = solverInfoElement->FirstChildElement("I");
1886
1887 while (solverInfo)
1888 {
1889 std::stringstream tagcontent;
1890 tagcontent << *solverInfo;
1891 // read the property name
1892 ASSERTL0(solverInfo->Attribute("PROPERTY"),
1893 "Missing PROPERTY attribute in solver info "
1894 "XML element: \n\t'" +
1895 tagcontent.str() + "'");
1896 std::string solverProperty = solverInfo->Attribute("PROPERTY");
1897 ASSERTL0(!solverProperty.empty(),
1898 "PROPERTY attribute must be non-empty in XML "
1899 "element: \n\t'" +
1900 tagcontent.str() + "'");
1901
1902 // make sure that solver property is capitalised
1903 std::string solverPropertyUpper =
1904 boost::to_upper_copy(solverProperty);
1905
1906 // read the value
1907 ASSERTL0(solverInfo->Attribute("VALUE"),
1908 "Missing VALUE attribute in solver info "
1909 "XML element: \n\t'" +
1910 tagcontent.str() + "'");
1911 std::string solverValue = solverInfo->Attribute("VALUE");
1912 ASSERTL0(!solverValue.empty(),
1913 "VALUE attribute must be non-empty in XML "
1914 "element: \n\t'" +
1915 tagcontent.str() + "'");
1916
1917 // Set Variable
1918 m_solverInfo[solverPropertyUpper] = solverValue;
1919 solverInfo = solverInfo->NextSiblingElement("I");
1920 }
1921 }
1922
1923 if (m_comm && m_comm->GetRowComm()->GetSize() > 1)
1924 {
1925 ASSERTL0(
1926 m_solverInfo["GLOBALSYSSOLN"] == "IterativeFull" ||
1927 m_solverInfo["GLOBALSYSSOLN"] == "IterativeStaticCond" ||
1928 m_solverInfo["GLOBALSYSSOLN"] ==
1929 "IterativeMultiLevelStaticCond" ||
1930 m_solverInfo["GLOBALSYSSOLN"] == "XxtFull" ||
1931 m_solverInfo["GLOBALSYSSOLN"] == "XxtStaticCond" ||
1932 m_solverInfo["GLOBALSYSSOLN"] == "XxtMultiLevelStaticCond" ||
1933 m_solverInfo["GLOBALSYSSOLN"] == "PETScFull" ||
1934 m_solverInfo["GLOBALSYSSOLN"] == "PETScStaticCond" ||
1935 m_solverInfo["GLOBALSYSSOLN"] == "PETScMultiLevelStaticCond",
1936 "A parallel solver must be used when run in parallel.");
1937 }
1938}
1939
1940/**
1941 *
1942 */
1943void SessionReader::ReadGlobalSysSolnInfo(TiXmlElement *conditions)
1944{
1945 GetGloSysSolnList().clear();
1946
1947 if (!conditions)
1948 {
1949 return;
1950 }
1951
1952 TiXmlElement *GlobalSys =
1953 conditions->FirstChildElement("GLOBALSYSSOLNINFO");
1955
1956 if (!GlobalSys)
1957 {
1958 return;
1959 }
1960
1961 TiXmlElement *VarInfo = GlobalSys->FirstChildElement("V");
1962
1963 while (VarInfo)
1964 {
1965 std::stringstream tagcontent;
1966 tagcontent << *VarInfo;
1967
1968 ASSERTL0(VarInfo->Attribute("VAR"),
1969 "Missing VAR attribute in GobalSysSolnInfo XML "
1970 "element: \n\t'" +
1971 tagcontent.str() + "'");
1972 std::string VarList = VarInfo->Attribute("VAR");
1973 ASSERTL0(!VarList.empty(),
1974 "VAR attribute must be non-empty in XML element:\n\t'" +
1975 tagcontent.str() + "'");
1976
1977 // generate a list of variables.
1978 std::vector<std::string> varStrings;
1979 bool valid = ParseUtils::GenerateVector(VarList, varStrings);
1980
1981 ASSERTL0(valid, "Unable to process list of variable in XML "
1982 "element \n\t'" +
1983 tagcontent.str() + "'");
1984
1985 if (varStrings.size())
1986 {
1987 TiXmlElement *SysSolnInfo = VarInfo->FirstChildElement("I");
1988
1989 while (SysSolnInfo)
1990 {
1991 tagcontent.clear();
1992 tagcontent << *SysSolnInfo;
1993 // read the property name
1994 ASSERTL0(SysSolnInfo->Attribute("PROPERTY"),
1995 "Missing PROPERTY attribute in "
1996 "GlobalSysSolnInfo for variable(s) '" +
1997 VarList + "' in XML element: \n\t'" +
1998 tagcontent.str() + "'");
1999 std::string SysSolnProperty =
2000 SysSolnInfo->Attribute("PROPERTY");
2001 ASSERTL0(!SysSolnProperty.empty(),
2002 "GlobalSysSolnIno properties must have a "
2003 "non-empty name for variable(s) : '" +
2004 VarList + "' in XML element: \n\t'" +
2005 tagcontent.str() + "'");
2006
2007 // make sure that solver property is capitalised
2008 std::string SysSolnPropertyUpper =
2009 boost::to_upper_copy(SysSolnProperty);
2010
2011 // read the value
2012 ASSERTL0(SysSolnInfo->Attribute("VALUE"),
2013 "Missing VALUE attribute in GlobalSysSolnInfo "
2014 "for variable(s) '" +
2015 VarList + "' in XML element: \n\t" +
2016 tagcontent.str() + "'");
2017 std::string SysSolnValue = SysSolnInfo->Attribute("VALUE");
2018 ASSERTL0(!SysSolnValue.empty(),
2019 "GlobalSysSolnInfo properties must have a "
2020 "non-empty value for variable(s) '" +
2021 VarList + "' in XML element: \n\t'" +
2022 tagcontent.str() + "'");
2023
2024 // Store values under variable map.
2025 for (int i = 0; i < varStrings.size(); ++i)
2026 {
2027 auto x = GetGloSysSolnList().find(varStrings[i]);
2028 if (x == GetGloSysSolnList().end())
2029 {
2030 (GetGloSysSolnList()[varStrings[i]])
2031 [SysSolnPropertyUpper] = SysSolnValue;
2032 }
2033 else
2034 {
2035 x->second[SysSolnPropertyUpper] = SysSolnValue;
2036 }
2037 }
2038 SysSolnInfo = SysSolnInfo->NextSiblingElement("I");
2039 }
2040 VarInfo = VarInfo->NextSiblingElement("V");
2041 }
2042 }
2043
2044 if (m_verbose && GetGloSysSolnList().size() > 0 && m_comm)
2045 {
2046 if (m_comm->GetRank() == 0)
2047 {
2048 cout << "GlobalSysSoln Info:" << endl;
2049
2050 for (auto &x : GetGloSysSolnList())
2051 {
2052 cout << "\t Variable: " << x.first << endl;
2053
2054 for (auto &y : x.second)
2055 {
2056 cout << "\t\t " << y.first << " = " << y.second << endl;
2057 }
2058 }
2059 cout << endl;
2060 }
2061 }
2062}
2063
2064/**
2065 * @brief Read the time-integration scheme structure, if present.
2066 */
2067void SessionReader::ReadTimeIntScheme(TiXmlElement *conditions)
2068{
2069 if (!conditions)
2070 {
2071 return;
2072 }
2073
2074 TiXmlElement *timeInt =
2075 conditions->FirstChildElement("TIMEINTEGRATIONSCHEME");
2077
2078 if (!timeInt)
2079 {
2080 return;
2081 }
2082
2083 TiXmlElement *method = timeInt->FirstChildElement("METHOD");
2084 TiXmlElement *variant = timeInt->FirstChildElement("VARIANT");
2085 TiXmlElement *order = timeInt->FirstChildElement("ORDER");
2086 TiXmlElement *params = timeInt->FirstChildElement("FREEPARAMETERS");
2087
2088 // Only the method and order are required.
2089 ASSERTL0(method, "Missing METHOD tag inside "
2090 "TIMEINTEGRATIONSCHEME.");
2091 ASSERTL0(order, "Missing ORDER tag inside "
2092 "TIMEINTEGRATIONSCHEME.");
2093
2094 m_timeIntScheme.method = method->GetText();
2095
2096 std::string orderStr = order->GetText();
2097
2098 // Only the method and order are required.
2099 ASSERTL0(m_timeIntScheme.method.size() > 0,
2100 "Empty text inside METHOD tag in TIMEINTEGRATIONSCHEME.");
2101 ASSERTL0(orderStr.size() > 0,
2102 "Empty text inside ORDER tag in TIMEINTEGRATIONSCHEME.");
2103 try
2104 {
2105 m_timeIntScheme.order = std::stol(orderStr);
2106 }
2107 catch (...)
2108 {
2109 NEKERROR(ErrorUtil::efatal, "In ORDER tag, unable to convert "
2110 "string '" +
2111 orderStr + "' to an unsigned integer.");
2112 }
2113
2114 if (variant)
2115 {
2116 m_timeIntScheme.variant = variant->GetText();
2117 }
2118
2119 if (params)
2120 {
2121 std::string paramsStr = params->GetText();
2122 ASSERTL0(paramsStr.size() > 0,
2123 "Empty text inside FREEPARAMETERS tag in "
2124 "TIMEINTEGRATIONSCHEME.");
2125
2126 std::vector<std::string> pSplit;
2127 boost::split(pSplit, paramsStr, boost::is_any_of(" "));
2128
2129 m_timeIntScheme.freeParams.resize(pSplit.size());
2130 for (size_t i = 0; i < pSplit.size(); ++i)
2131 {
2132 try
2133 {
2134 m_timeIntScheme.freeParams[i] = std::stod(pSplit[i]);
2135 }
2136 catch (...)
2137 {
2138 NEKERROR(ErrorUtil::efatal, "In FREEPARAMETERS tag, "
2139 "unable to convert string '" +
2140 pSplit[i] +
2141 "' "
2142 "to a floating-point value.");
2143 }
2144 }
2145 }
2146
2147 if (m_verbose && m_comm)
2148 {
2149 if (m_comm->GetRank() == 0)
2150 {
2151 cout << "Trying to use time integration scheme:" << endl;
2152 cout << "\t Method : " << m_timeIntScheme.method << endl;
2153 cout << "\t Variant: " << m_timeIntScheme.variant << endl;
2154 cout << "\t Order : " << m_timeIntScheme.order << endl;
2155
2156 if (m_timeIntScheme.freeParams.size() > 0)
2157 {
2158 cout << "\t Params :";
2159 for (auto &x : m_timeIntScheme.freeParams)
2160 {
2161 cout << " " << x;
2162 }
2163 cout << endl;
2164 }
2165 }
2166 }
2167}
2168
2169/**
2170 *
2171 */
2172void SessionReader::ReadVariables(TiXmlElement *conditions)
2173{
2174 m_variables.clear();
2175
2176 if (!conditions)
2177 {
2178 return;
2179 }
2180
2181 TiXmlElement *variablesElement = conditions->FirstChildElement("VARIABLES");
2182 GetXMLElementTimeLevel(variablesElement, m_timeLevel);
2183
2184 // See if we have parameters defined. They are optional so we go on
2185 // if not.
2186 if (variablesElement)
2187 {
2188 TiXmlElement *varElement = variablesElement->FirstChildElement("V");
2189
2190 // Sequential counter for the composite numbers.
2191 int nextVariableNumber = -1;
2192
2193 while (varElement)
2194 {
2195 stringstream tagcontent;
2196 tagcontent << *varElement;
2197
2198 /// All elements are of the form: "<V ID="#"> name = value
2199 /// </V>", with ? being the element type.
2200 nextVariableNumber++;
2201
2202 int i;
2203 int err = varElement->QueryIntAttribute("ID", &i);
2204 ASSERTL0(err == TIXML_SUCCESS,
2205 "Variables must have a unique ID number attribute "
2206 "in XML element: \n\t'" +
2207 tagcontent.str() + "'");
2208 ASSERTL0(i == nextVariableNumber,
2209 "ID numbers for variables must begin with zero and"
2210 " be sequential in XML element: \n\t'" +
2211 tagcontent.str() + "'");
2212
2213 TiXmlNode *varChild = varElement->FirstChild();
2214 // This is primarily to skip comments that may be present.
2215 // Comments appear as nodes just like elements. We are
2216 // specifically looking for text in the body of the
2217 // definition.
2218 while (varChild && varChild->Type() != TiXmlNode::TINYXML_TEXT)
2219 {
2220 varChild = varChild->NextSibling();
2221 }
2222
2223 ASSERTL0(varChild, "Unable to read variable definition body for "
2224 "variable with ID " +
2225 std::to_string(i) +
2226 " in XML element: \n\t'" + tagcontent.str() +
2227 "'");
2228 std::string variableName = varChild->ToText()->ValueStr();
2229
2230 std::istringstream variableStrm(variableName);
2231 variableStrm >> variableName;
2232
2233 ASSERTL0(std::find(m_variables.begin(), m_variables.end(),
2234 variableName) == m_variables.end(),
2235 "Variable with ID " + std::to_string(i) +
2236 " in XML element \n\t'" + tagcontent.str() +
2237 "'\nhas already been defined.");
2238
2239 m_variables.push_back(variableName);
2240
2241 varElement = varElement->NextSiblingElement("V");
2242 }
2243
2244 ASSERTL0(nextVariableNumber > -1,
2245 "Number of variables must be greater than zero.");
2246 }
2247}
2248
2249/**
2250 *
2251 */
2252void SessionReader::ReadFunctions(TiXmlElement *conditions)
2253{
2254 m_functions.clear();
2255
2256 if (!conditions)
2257 {
2258 return;
2259 }
2260
2261 // Scan through conditions section looking for functions.
2262 TiXmlElement *function = conditions->FirstChildElement("FUNCTION");
2263
2264 while (function)
2265 {
2266 stringstream tagcontent;
2267 tagcontent << *function;
2268
2269 // Every function must have a NAME attribute
2270 ASSERTL0(function->Attribute("NAME"),
2271 "Functions must have a NAME attribute defined in XML "
2272 "element: \n\t'" +
2273 tagcontent.str() + "'");
2274 std::string functionStr = function->Attribute("NAME");
2275 ASSERTL0(!functionStr.empty(),
2276 "Functions must have a non-empty name in XML "
2277 "element: \n\t'" +
2278 tagcontent.str() + "'");
2279
2280 // Store function names in uppercase to remain case-insensitive.
2281 boost::to_upper(functionStr);
2282
2283 // Retrieve first entry (variable, or file)
2284 TiXmlElement *element = function;
2285 GetXMLElementTimeLevel(element, m_timeLevel, false);
2286 TiXmlElement *variable = element->FirstChildElement();
2287
2288 // Create new function structure with default type of none.
2289 FunctionVariableMap functionVarMap;
2290
2291 // Process all entries in the function block
2292 while (variable)
2293 {
2295 std::string conditionType = variable->Value();
2296
2297 // If no var is specified, assume wildcard
2298 std::string variableStr;
2299 if (!variable->Attribute("VAR"))
2300 {
2301 variableStr = "*";
2302 }
2303 else
2304 {
2305 variableStr = variable->Attribute("VAR");
2306 }
2307
2308 // Parse list of variables
2309 std::vector<std::string> variableList;
2310 ParseUtils::GenerateVector(variableStr, variableList);
2311
2312 // If no domain is specified, put to 0
2313 std::string domainStr;
2314 if (!variable->Attribute("DOMAIN"))
2315 {
2316 domainStr = "0";
2317 }
2318 else
2319 {
2320 domainStr = variable->Attribute("DOMAIN");
2321 }
2322
2323 // Parse list of domains
2324 std::vector<std::string> varSplit;
2325 std::vector<unsigned int> domainList;
2326 ParseUtils::GenerateSeqVector(domainStr, domainList);
2327
2328 // if no evars is specified, put "x y z t"
2329 std::string evarsStr = "x y z t";
2330 if (variable->Attribute("EVARS"))
2331 {
2332 evarsStr =
2333 evarsStr + std::string(" ") + variable->Attribute("EVARS");
2334 }
2335
2336 // Expressions are denoted by E
2337 if (conditionType == "E")
2338 {
2340
2341 // Expression must have a VALUE.
2342 ASSERTL0(variable->Attribute("VALUE"),
2343 "Attribute VALUE expected for function '" +
2344 functionStr + "'.");
2345 std::string fcnStr = variable->Attribute("VALUE");
2346 ASSERTL0(!fcnStr.empty(),
2347 (std::string("Expression for var: ") + variableStr +
2348 std::string(" must be specified."))
2349 .c_str());
2350
2351 // set expression
2352 funcDef.m_expression =
2354 m_interpreter, fcnStr, evarsStr);
2355 }
2356
2357 // Files are denoted by F
2358 else if (conditionType == "F")
2359 {
2360 // Check if transient or not
2361 if (variable->Attribute("TIMEDEPENDENT") &&
2362 boost::lexical_cast<bool>(
2363 variable->Attribute("TIMEDEPENDENT")))
2364 {
2366 }
2367 else
2368 {
2369 funcDef.m_type = eFunctionTypeFile;
2370 }
2371
2372 // File must have a FILE.
2373 ASSERTL0(variable->Attribute("FILE"),
2374 "Attribute FILE expected for function '" +
2375 functionStr + "'.");
2376 std::string filenameStr = variable->Attribute("FILE");
2377 ASSERTL0(!filenameStr.empty(),
2378 "A filename must be specified for the FILE "
2379 "attribute of function '" +
2380 functionStr + "'.");
2381
2382 std::vector<std::string> fSplit;
2383 boost::split(fSplit, filenameStr, boost::is_any_of(":"));
2384 ASSERTL0(fSplit.size() == 1 || fSplit.size() == 2,
2385 "Incorrect filename specification in function " +
2386 functionStr +
2387 "'. "
2388 "Specify variables inside file as: "
2389 "filename:var1,var2");
2390
2391 // set the filename
2392 fs::path fullpath = fSplit[0];
2393 fs::path ftype = fullpath.extension();
2394 if (fullpath.parent_path().extension() == ".pit")
2395 {
2396 string filename = fullpath.stem().string();
2397 fullpath = fullpath.parent_path();
2398 size_t start = filename.find_last_of("_") + 1;
2399 int index =
2400 atoi(filename.substr(start, filename.size()).c_str());
2401 fullpath /= filename.substr(0, start) +
2402 std::to_string(
2403 index + m_comm->GetTimeComm()->GetRank()) +
2404 ftype.string();
2405 }
2406 funcDef.m_filename = fullpath.string();
2407
2408 if (fSplit.size() == 2)
2409 {
2410 ASSERTL0(variableList[0] != "*",
2411 "Filename variable mapping not valid "
2412 "when using * as a variable inside "
2413 "function '" +
2414 functionStr + "'.");
2415
2416 boost::split(varSplit, fSplit[1], boost::is_any_of(","));
2417 ASSERTL0(varSplit.size() == variableList.size(),
2418 "Filename variables should contain the "
2419 "same number of variables defined in "
2420 "VAR in function " +
2421 functionStr + "'.");
2422 }
2423 }
2424
2425 // Nothing else supported so throw an error
2426 else
2427 {
2428 stringstream tagcontent;
2429 tagcontent << *variable;
2430
2432 "Identifier " + conditionType + " in function " +
2433 std::string(function->Attribute("NAME")) +
2434 " is not recognised in XML element: \n\t'" +
2435 tagcontent.str() + "'");
2436 }
2437
2438 // Add variables to function
2439 for (unsigned int i = 0; i < variableList.size(); ++i)
2440 {
2441 for (unsigned int j = 0; j < domainList.size(); ++j)
2442 {
2443 // Check it has not already been defined
2444 pair<std::string, int> key(variableList[i], domainList[j]);
2445 auto fcnsIter = functionVarMap.find(key);
2446 ASSERTL0(fcnsIter == functionVarMap.end(),
2447 "Error setting expression '" + variableList[i] +
2448 " in domain " + std::to_string(domainList[j]) +
2449 "' in function '" + functionStr +
2450 "'. "
2451 "Expression has already been defined.");
2452
2453 if (varSplit.size() > 0)
2454 {
2455 FunctionVariableDefinition funcDef2 = funcDef;
2456 funcDef2.m_fileVariable = varSplit[i];
2457 functionVarMap[key] = funcDef2;
2458 }
2459 else
2460 {
2461 functionVarMap[key] = funcDef;
2462 }
2463 }
2464 }
2465 variable = variable->NextSiblingElement();
2466 }
2467
2468 // Add function definition to map
2469 m_functions[functionStr] = functionVarMap;
2470 function = function->NextSiblingElement("FUNCTION");
2471 }
2472}
2473
2474/**
2475 *
2476 */
2477void SessionReader::ReadFilters(TiXmlElement *filters)
2478{
2479 if (!filters)
2480 {
2481 return;
2482 }
2483
2484 m_filters.clear();
2485
2486 TiXmlElement *filter = filters->FirstChildElement("FILTER");
2487
2488 while (filter)
2489 {
2490 ASSERTL0(filter->Attribute("TYPE"),
2491 "Missing attribute 'TYPE' for filter.");
2492 std::string typeStr = filter->Attribute("TYPE");
2493
2494 int domainID = -1;
2495 if (filter->Attribute("DOMAIN"))
2496 {
2497 // domainID = int(filter->Attribute("DOMAIN"));
2498 int err = filter->QueryIntAttribute("DOMAIN", &domainID);
2499 ASSERTL0(err == TIXML_SUCCESS,
2500 "Unable to read attribute DOMAIN in filter.");
2501 }
2502
2503 std::map<std::string, std::string> vParams;
2504
2505 TiXmlElement *element = filter;
2506 GetXMLElementTimeLevel(element, m_timeLevel, false);
2507 TiXmlElement *param = element->FirstChildElement("PARAM");
2508 while (param)
2509 {
2510 ASSERTL0(param->Attribute("NAME"),
2511 "Missing attribute 'NAME' for parameter in filter " +
2512 typeStr + "'.");
2513 std::string nameStr = param->Attribute("NAME");
2514
2515 ASSERTL0(param->GetText(), "Empty value string for param.");
2516 std::string valueStr = param->GetText();
2517
2518 vParams[nameStr] = valueStr;
2519
2520 param = param->NextSiblingElement("PARAM");
2521 }
2522
2523 FilterDefinition filterDef;
2524 filterDef.domain = domainID;
2525 filterDef.name = typeStr;
2526 filterDef.params = vParams;
2527 m_filters.push_back(filterDef);
2528
2529 filter = filter->NextSiblingElement("FILTER");
2530 }
2531}
2532
2533/**
2534 *
2535 */
2536void SessionReader::ParseEquals(const std::string &line, std::string &lhs,
2537 std::string &rhs)
2538{
2539 /// Pull out lhs and rhs and eliminate any spaces.
2540 size_t beg = line.find_first_not_of(" ");
2541 size_t end = line.find_first_of("=");
2542 // Check for no parameter name
2543 if (beg == end)
2544 {
2545 throw 1;
2546 }
2547 // Check for no parameter value
2548 if (end != line.find_last_of("="))
2549 {
2550 throw 1;
2551 }
2552 // Check for no equals sign
2553 if (end == std::string::npos)
2554 {
2555 throw 1;
2556 }
2557
2558 lhs = line.substr(line.find_first_not_of(" "), end - beg);
2559 lhs = lhs.substr(0, lhs.find_last_not_of(" ") + 1);
2560 rhs = line.substr(line.find_last_of("=") + 1);
2561 rhs = rhs.substr(rhs.find_first_not_of(" "));
2562 rhs = rhs.substr(0, rhs.find_last_not_of(" ") + 1);
2563}
2564
2565/**
2566 *
2567 */
2569{
2570 // Parse solver info overrides
2571 if (m_cmdLineOptions.count("solverinfo"))
2572 {
2573 std::vector<std::string> solverInfoList =
2574 m_cmdLineOptions["solverinfo"].as<std::vector<std::string>>();
2575
2576 for (size_t i = 0; i < solverInfoList.size(); ++i)
2577 {
2578 std::string lhs, rhs;
2579
2580 try
2581 {
2582 ParseEquals(solverInfoList[i], lhs, rhs);
2583 }
2584 catch (...)
2585 {
2586 NEKERROR(ErrorUtil::efatal, "Parse error with command line "
2587 "option: " +
2588 solverInfoList[i]);
2589 }
2590
2591 std::string lhsUpper = boost::to_upper_copy(lhs);
2592 m_solverInfo[lhsUpper] = rhs;
2593 }
2594 }
2595
2596 if (m_cmdLineOptions.count("parameter"))
2597 {
2598 std::vector<std::string> parametersList =
2599 m_cmdLineOptions["parameter"].as<std::vector<std::string>>();
2600
2601 for (size_t i = 0; i < parametersList.size(); ++i)
2602 {
2603 std::string lhs, rhs;
2604
2605 try
2606 {
2607 ParseEquals(parametersList[i], lhs, rhs);
2608 }
2609 catch (...)
2610 {
2611 NEKERROR(ErrorUtil::efatal, "Parse error with command line "
2612 "option: " +
2613 parametersList[i]);
2614 }
2615
2616 std::string lhsUpper = boost::to_upper_copy(lhs);
2617
2618 try
2619 {
2620 m_interpreter->SetParameter(lhs, std::stod(rhs));
2621 m_parameters[lhsUpper] = std::stod(rhs);
2622 }
2623 catch (...)
2624 {
2625 NEKERROR(ErrorUtil::efatal, "Unable to convert string: " + rhs +
2626 "to double value.");
2627 }
2628 }
2629 }
2630}
2631
2632/**
2633 *
2634 */
2636{
2637 for (auto &x : m_solverInfo)
2638 {
2639 std::string solverProperty = x.first;
2640 std::string solverValue = x.second;
2641
2642 auto propIt = GetSolverInfoEnums().find(solverProperty);
2643 if (propIt != GetSolverInfoEnums().end())
2644 {
2645 auto valIt = propIt->second.find(solverValue);
2646 ASSERTL0(valIt != propIt->second.end(), "Value '" + solverValue +
2647 "' is not valid for "
2648 "property '" +
2649 solverProperty + "'");
2650 }
2651 }
2652}
2653
2654/**
2655 *
2656 */
2661
2662/**
2663 * Helper function that gets a pointer to a child element, or throws an
2664 * exception if no such element exists
2665 */
2666TiXmlElement *GetChildElementOrThrow(const std::string &filename,
2667 std::string elementName,
2668 const TiXmlHandle &docHandle)
2669{
2670 TiXmlElement *element = docHandle.FirstChildElement(elementName).Element();
2671
2672 if (!element)
2673 {
2674 NEKERROR(ErrorUtil::efatal, "Unable to find '" + elementName +
2675 "' XML node in " + filename);
2676 }
2677
2678 return element;
2679}
2680
2681} // namespace Nektar::LibUtilities
#define NEKTAR_VERSION
#define ASSERTL0(condition, msg)
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
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.
bool DefinesFunction(const std::string &name) const
Checks if a specified function is defined in the XML document.
void SetGlobalSysSolnInfo(const std::string &variable, const std::string &property, const std::string &value)
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.
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 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.
static void GetXMLElementTimeLevel(TiXmlElement *&element, const size_t timeLevel, const bool enableCheck=true)
Get XML elment time level (Parallel-in-Time)
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.
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.
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 TimeIntScheme & GetTimeIntScheme() const
Returns the time integration scheme structure m_timeIntScheme from the session file.
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.
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.
std::shared_ptr< Interpreter > InterpreterSharedPtr
std::map< std::string, std::string > SolverInfoMap
std::map< std::string, GloSysInfoMap > GloSysSolnInfoList
std::map< std::pair< std::string, int >, FunctionVariableDefinition > FunctionVariableMap
std::map< std::string, NekDouble > ParameterMap
static std::string PortablePath(const fs::path &path)
create portable path on different platforms for std::filesystem path.
std::shared_ptr< Equation > EquationSharedPtr
Definition Equation.h:131
TiXmlElement * GetChildElementOrThrow(const std::string &filename, std::string elementName, const TiXmlHandle &docHandle)
std::map< std::string, EnumMap > EnumMapList
std::vector< FilterDefinition > FilterMap
CommFactory & GetCommFactory()
std::map< std::string, CmdLineArg > CmdLineArgMap
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition Comm.h:55
const std::string kGitBranch
Definition GitRevision.h:46
const std::string kGitSha1
Definition GitRevision.h:45
Definition sha1.cpp:72
STL namespace.
std::vector< NekDouble > freeParams