OGS
Simulation.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "Simulation.h"
5
6#include <spdlog/spdlog.h>
7
13#include "BaseLib/DateTools.h"
14#include "BaseLib/FileTools.h"
15#include "BaseLib/MPI.h"
17#include "BaseLib/RunTime.h"
18#include "MeshLib/Mesh.h"
20#include "ProcessLib/TimeLoop.h"
21
22Simulation::Simulation(int argc, char* argv[])
23 : linear_solver_library_setup{ApplicationsLib::LinearSolverLibrarySetup::
24 create(argc, argv)},
25#if defined(USE_PETSC)
26 controller(vtkSmartPointer<vtkMPIController>::New()),
27#endif
28 test_definition{std::nullopt}
29{
30#if defined(USE_PETSC)
31 controller->Initialize(&argc, &argv, 1);
32 vtkMPIController::SetGlobalController(controller);
33#endif
34}
35
37 std::string const& project,
38 std::vector<std::string> const& xml_patch_file_names,
39 bool const reference_path_is_set, std::string const& reference_path,
40 bool const nonfatal, std::string const& outdir, std::string const& mesh_dir,
41 std::string const& script_dir, bool const write_prj)
42{
43 INFO("Reading project file {}.",
44 std::filesystem::relative(project).string());
45 DBUG("Project file: {}.", std::filesystem::absolute(project).string());
46 DBUG("Working directory: {}.", std::filesystem::current_path().string());
47
48 std::stringstream prj_stream;
49 BaseLib::prepareProjectFile(prj_stream, project, xml_patch_file_names,
50 write_prj, outdir);
51 auto project_config = BaseLib::makeConfigTree(
52 project, !nonfatal, "OpenGeoSysProject", prj_stream);
53
54 if (!reference_path_is_set)
55 { // Ignore the test_definition section.
56 project_config.ignoreConfigParameter("test_definition");
57 }
58 else
59 {
62 project_config.getConfigSubtree("test_definition"), reference_path,
63 outdir);
64 if (test_definition->numberOfTests() == 0)
65 {
67 "No tests were constructed from the test definitions, "
68 "but reference solutions path was given.");
69 }
70
71 INFO("Cleanup possible output files before running ogs.");
72 BaseLib::removeFiles(test_definition->getOutputFiles());
73 }
74#ifdef OGS_USE_INSITU
76 if (auto t = project_config.getConfigSubtreeOptional("insitu"))
77 {
80 t->getConfigSubtree("scripts"),
81 BaseLib::extractPath(project));
82 isInsituConfigured = true;
83 }
84#else
85 project_config.ignoreConfigParameter("insitu");
86#endif
87
88 project_data = std::make_unique<ProjectData>(project_config, outdir,
89 mesh_dir, script_dir);
90
91 INFO("Initialize processes.");
92 for (auto& p : project_data->getProcesses())
93 {
94 p->initialize(project_data->getMedia());
95 }
96
97 // Check intermediately that config parsing went fine.
98 checkAndInvalidate(project_config);
100
101 auto& time_loop = project_data->getTimeLoop();
102 auto time_value = time_loop.currentTime()();
103 INFO("Time step #0 started. Time: {}. Step size: 0.", time_value);
104
105 BaseLib::RunTime init_timer;
106 init_timer.start();
107 time_loop.initialize();
108 INFO("Time step #0 took {:g} s.", init_timer.elapsed());
109}
110
112{
113 auto const& time_loop = project_data->getTimeLoop();
114 return time_loop.currentTime()();
115}
116
118{
119 auto const& time_loop = project_data->getTimeLoop();
120 return time_loop.endTime()();
121}
122
124{
125 auto& time_loop = project_data->getTimeLoop();
126 if (time_loop.currentTime() < time_loop.endTime())
127 {
128 auto const result = time_loop.executeTimeStep();
129 time_loop.calculateNextTimeStep();
130 return result;
131 }
132 return false;
133}
134
135MeshLib::Mesh& Simulation::getMesh(std::string const& name)
136{
137 return project_data->getMesh(name);
138}
139
140std::vector<std::string> Simulation::getMeshNames() const
141{
142 return project_data->getMeshNames();
143}
144
145static std::atomic<int> gSignalThatStoppedMe{-1};
146
147extern "C" void signalHandler(int signum)
148{
149 gSignalThatStoppedMe.store(signum);
150}
151
153{
154 INFO("Solve processes.");
155 auto& time_loop = project_data->getTimeLoop();
156 while (time_loop.currentTime() < time_loop.endTime())
157 {
158 time_loop.executeTimeStep();
159 if (!time_loop.calculateNextTimeStep())
160 {
161 break;
162 }
163 }
164
165 return time_loop.successful_time_step;
166}
167
169{
170 auto const& time_loop = project_data->getTimeLoop();
171 time_loop.outputLastTimeStep();
172}
173
174std::optional<ApplicationsLib::TestDefinition> Simulation::getTestDefinition()
175 const
176{
177 return test_definition;
178}
179
181{
182#ifdef OGS_USE_INSITU
184 {
186 }
187#endif
188#if defined(USE_PETSC)
189 controller->Finalize(1);
190#endif
191}
192
194 std::optional<ApplicationsLib::TestDefinition>& test_definition)
195{
196 // In serial builds, run the complete test definition normally. In PETSc
197 // builds, xdmfdiff tests compare global XDMF/HDF5 output files and must run
198 // only once on rank 0 after all ranks have finished simulation.
199 // The rank 0 result is broadcast so every rank exits with the same status.
200 if (!test_definition)
201 {
202 auto const end_time = std::chrono::system_clock::now();
203 auto const time_str = BaseLib::formatDate(end_time);
204 DBUG("No test definition was found. No tests will be executed.");
205 INFO("OGS completed on {:s}.", time_str);
206 return EXIT_SUCCESS;
207 }
208
209#if defined(USE_PETSC)
210 bool const has_xdmfdiff_tests = test_definition->hasTests("xdmfdiff");
212 bool const run_all_tests = !has_xdmfdiff_tests;
213 bool const run_xdmfdiff_tests = has_xdmfdiff_tests && mpi.rank == 0;
214#else
215 bool constexpr run_all_tests = true;
216 bool constexpr run_xdmfdiff_tests = false;
217#endif
218
219 auto const log_tests_header = []
220 {
221 INFO("");
222 INFO("##########################################");
223 INFO("# Running tests #");
224 INFO("##########################################");
225 INFO("");
226 };
227
228 auto tests_succeeded = true;
229 if (run_all_tests)
230 {
231 log_tests_header();
232 tests_succeeded = test_definition->runTests();
233 }
234 else
235 {
236 tests_succeeded = test_definition->runTestsExcluding("xdmfdiff");
237 }
238
239#if defined(USE_PETSC)
240 if (has_xdmfdiff_tests)
241 {
242 // Need to wait until all ranks have written their output.
243 MPI_Barrier(mpi.communicator);
244 auto xdmfdiff_status = EXIT_SUCCESS;
245 if (run_xdmfdiff_tests)
246 {
247 log_tests_header();
248 xdmfdiff_status = test_definition->runTests("xdmfdiff")
249 ? EXIT_SUCCESS
250 : EXIT_FAILURE;
251 }
252 MPI_Bcast(&xdmfdiff_status, 1, MPI_INT, 0, mpi.communicator);
253
254 tests_succeeded = tests_succeeded && xdmfdiff_status == EXIT_SUCCESS;
255 tests_succeeded = BaseLib::MPI::allOf(tests_succeeded, mpi);
256 }
257#endif
258
259 if (run_all_tests || run_xdmfdiff_tests)
260 {
261 auto const end_time = std::chrono::system_clock::now();
262 auto const time_str = BaseLib::formatDate(end_time);
263 if (tests_succeeded)
264 {
265 INFO("OGS completed on {:s}.", time_str);
266 }
267 else
268 {
269 ERR("OGS terminated on {:s}. One of the tests failed.", time_str);
270 }
271 }
272 return tests_succeeded ? EXIT_SUCCESS : EXIT_FAILURE;
273}
#define OGS_FATAL(...)
Definition Error.h:10
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:22
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
void signalHandler(int signum)
static std::atomic< int > gSignalThatStoppedMe
static void assertNoSwallowedErrors()
Asserts that there have not been any errors reported in the destructor.
Count the running time.
Definition RunTime.h:18
double elapsed() const
Get the elapsed time in seconds.
Definition RunTime.h:31
void start()
Start the timer.
Definition RunTime.h:21
OGS_EXPORT_SYMBOL double currentTime() const
std::shared_ptr< ApplicationsLib::LinearSolverLibrarySetup > linear_solver_library_setup
Definition Simulation.h:50
OGS_EXPORT_SYMBOL bool executeSimulation()
OGS_EXPORT_SYMBOL std::optional< ApplicationsLib::TestDefinition > getTestDefinition() const
std::unique_ptr< ProjectData > project_data
Definition Simulation.h:54
bool isInsituConfigured
Definition Simulation.h:57
static OGS_EXPORT_SYMBOL int runTestDefinitions(std::optional< ApplicationsLib::TestDefinition > &test_definition)
std::optional< ApplicationsLib::TestDefinition > test_definition
Definition Simulation.h:55
OGS_EXPORT_SYMBOL MeshLib::Mesh & getMesh(std::string const &name)
OGS_EXPORT_SYMBOL double endTime() const
OGS_EXPORT_SYMBOL ~Simulation()
OGS_EXPORT_SYMBOL void initializeDataStructures(std::string const &project, std::vector< std::string > const &xml_patch_file_names, bool reference_path_is_set, std::string const &reference_path, bool nonfatal, std::string const &outdir, std::string const &mesh_dir, std::string const &script_dir, bool write_prj)
OGS_EXPORT_SYMBOL bool executeTimeStep()
vtkSmartPointer< vtkMPIController > controller
Definition Simulation.h:52
OGS_EXPORT_SYMBOL void outputLastTimeStep() const
OGS_EXPORT_SYMBOL Simulation(int argc, char *argv[])
OGS_EXPORT_SYMBOL std::vector< std::string > getMeshNames() const
static bool allOf(bool const val, Mpi const &mpi=Mpi{OGS_COMM_WORLD})
Definition MPI.h:190
void prepareProjectFile(std::stringstream &prj_stream, const std::string &filepath, const std::vector< std::string > &patch_files, bool write_prj, const std::string &out_directory)
Applies includes and patch files to project file.
std::string extractPath(std::string const &pathname)
ConfigTree makeConfigTree(const std::string &filepath, const bool be_ruthless, const std::string &toplevel_tag, std::stringstream &prj_stream)
std::string formatDate(std::chrono::time_point< std::chrono::system_clock > const &time)
void removeFiles(std::vector< std::string > const &files)
void Initialize(BaseLib::ConfigTree const &scripts_config, std::string const &path)
Definition Adaptor.cpp:23
void Finalize()
Definition Adaptor.cpp:55
MPI_Comm communicator
Definition MPI.h:47