Forked from
ogs / ogs
792 commits behind the upstream repository.
-
Dmitri Naumov authored
... with shared pointers. There is a generalization for arbitrary types of map values and should be usable also in the constitutive relations map for solids and BHEs.
Dmitri Naumov authored... with shared pointers. There is a generalization for arbitrary types of map values and should be usable also in the constitutive relations map for solids and BHEs.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ProjectData.cpp 56.26 KiB
/**
* \file
* \author Karsten Rink
* \date 2010-08-25
* \brief Implementation of the project data class.
*
* \copyright
* Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
* Distributed under a Modified BSD License.
* See accompanying file LICENSE.txt or
* http://www.opengeosys.org/project/license
*
*/
#include "ProjectData.h"
#include <pybind11/eval.h>
#include <algorithm>
#include <boost/algorithm/string/predicate.hpp>
#include <cctype>
#include <range/v3/action/sort.hpp>
#include <range/v3/action/unique.hpp>
#include <range/v3/algorithm/contains.hpp>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/adjacent_remove_if.hpp>
#include <set>
#include "BaseLib/Algorithm.h"
#include "BaseLib/ConfigTree.h"
#include "BaseLib/FileTools.h"
#include "BaseLib/Logging.h"
#include "BaseLib/StringTools.h"
#include "GeoLib/GEOObjects.h"
#include "GeoLib/IO/AsciiRasterInterface.h"
#include "GeoLib/IO/NetCDFRasterReader.h"
#include "GeoLib/Raster.h"
#include "InfoLib/CMakeInfo.h"
#include "MaterialLib/MPL/CreateMedium.h"
#include "MathLib/Curve/CreatePiecewiseLinearCurve.h"
#if defined(USE_LIS)
#include "MathLib/LinAlg/EigenLis/LinearSolverOptionsParser.h"
#elif defined(USE_PETSC)
#include "MathLib/LinAlg/PETSc/LinearSolverOptionsParser.h"
#else
#include "MathLib/LinAlg/Eigen/LinearSolverOptionsParser.h"
#endif
#include "MeshGeoToolsLib/ConstructMeshesFromGeometries.h"
#include "MeshGeoToolsLib/CreateSearchLength.h"
#include "MeshGeoToolsLib/SearchLength.h"
#include "MeshLib/Mesh.h"
#include "MeshLib/Utils/SetMeshSpaceDimension.h"
#include "MeshToolsLib/ZeroMeshFieldDataByMaterialIDs.h"
#include "NumLib/ODESolver/ConvergenceCriterion.h"
#include "ProcessLib/CreateJacobianAssembler.h"
#include "ProcessLib/DeactivatedSubdomain.h"
// FileIO
#include "GeoLib/IO/XmlIO/Boost/BoostXmlGmlInterface.h"
#include "MeshLib/IO/readMeshFromFile.h"
#include "ParameterLib/ConstantParameter.h"
#include "ParameterLib/CreateCoordinateSystem.h"
#include "ParameterLib/Utils.h"
#include "ProcessLib/CreateTimeLoop.h"
#include "ProcessLib/TimeLoop.h"
#ifdef OGS_EMBED_PYTHON_INTERPRETER
#include "Applications/CLI/ogs_embedded_python.h"
#endif
#ifdef OGS_BUILD_PROCESS_COMPONENTTRANSPORT
#include "ChemistryLib/CreateChemicalSolverInterface.h"
#include "ProcessLib/ComponentTransport/CreateComponentTransportProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_STEADYSTATEDIFFUSION
#include "ProcessLib/SteadyStateDiffusion/CreateSteadyStateDiffusion.h"
#endif
#ifdef OGS_BUILD_PROCESS_HT
#include "ProcessLib/HT/CreateHTProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_HEATCONDUCTION
#include "ProcessLib/HeatConduction/CreateHeatConductionProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_HEATTRANSPORTBHE
#include "ProcessLib/HeatTransportBHE/CreateHeatTransportBHEProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_WELLBORESIMULATOR
#include "ProcessLib/WellboreSimulator/CreateWellboreSimulatorProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_HYDROMECHANICS
#include "ProcessLib/HydroMechanics/CreateHydroMechanicsProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_LARGEDEFORMATION
#include "ProcessLib/LargeDeformation/CreateLargeDeformationProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_LIE
#include "ProcessLib/LIE/HydroMechanics/CreateHydroMechanicsProcess.h"
#include "ProcessLib/LIE/SmallDeformation/CreateSmallDeformationProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_LIQUIDFLOW
#include "ProcessLib/LiquidFlow/CreateLiquidFlowProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_STOKESFLOW
#include "ProcessLib/StokesFlow/CreateStokesFlowProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_THERMORICHARDSMECHANICS
#include "ProcessLib/ThermoRichardsMechanics/CreateThermoRichardsMechanicsProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_PHASEFIELD
#include "ProcessLib/PhaseField/CreatePhaseFieldProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_RICHARDSCOMPONENTTRANSPORT
#include "ProcessLib/RichardsComponentTransport/CreateRichardsComponentTransportProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_RICHARDSFLOW
#include "ProcessLib/RichardsFlow/CreateRichardsFlowProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_RICHARDSMECHANICS
#include "ProcessLib/RichardsMechanics/CreateRichardsMechanicsProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_SMALLDEFORMATION
#include "ProcessLib/SmallDeformation/CreateSmallDeformationProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_SMALLDEFORMATIONNONLOCAL
#include "ProcessLib/SmallDeformationNonlocal/CreateSmallDeformationNonlocalProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_TES
#include "ProcessLib/TES/CreateTESProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_TH2M
#include "ProcessLib/TH2M/CreateTH2MProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_THERMALTWOPHASEFLOWWITHPP
#include "ProcessLib/ThermalTwoPhaseFlowWithPP/CreateThermalTwoPhaseFlowWithPPProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_THERMOHYDROMECHANICS
#include "ProcessLib/ThermoHydroMechanics/CreateThermoHydroMechanicsProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_THERMOMECHANICALPHASEFIELD
#include "ProcessLib/ThermoMechanicalPhaseField/CreateThermoMechanicalPhaseFieldProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_THERMOMECHANICS
#include "ProcessLib/ThermoMechanics/CreateThermoMechanicsProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_THERMORICHARDSFLOW
#include "ProcessLib/ThermoRichardsFlow/CreateThermoRichardsFlowProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_TWOPHASEFLOWWITHPP
#include "ProcessLib/TwoPhaseFlowWithPP/CreateTwoPhaseFlowWithPPProcess.h"
#endif
#ifdef OGS_BUILD_PROCESS_TWOPHASEFLOWWITHPRHO
#include "ProcessLib/TwoPhaseFlowWithPrho/CreateTwoPhaseFlowWithPrhoProcess.h"
#endif
namespace
{
void readGeometry(std::string const& fname, GeoLib::GEOObjects& geo_objects,
std::string const& dir_first, std::string const& dir_second)
{
DBUG("Reading geometry file '{:s}'.", fname);
GeoLib::IO::BoostXmlGmlInterface gml_reader(geo_objects);
std::string geometry_file = BaseLib::joinPaths(dir_first, fname);
if (!BaseLib::IsFileExisting(geometry_file))
{
// Fallback to reading gml from prj-file directory
geometry_file = BaseLib::joinPaths(dir_second, fname);
WARN("File {:s} not found in {:s}! Trying reading from {:s}.", fname,
dir_first, dir_second);
if (!BaseLib::IsFileExisting(geometry_file))
{
OGS_FATAL("Could not read geometry file {:s} in {:s}.", fname,
dir_second);
}
}
gml_reader.readFile(geometry_file);
}
std::unique_ptr<MeshLib::Mesh> readSingleMesh(
BaseLib::ConfigTree const& mesh_config_parameter,
std::string const& directory)
{
std::string const mesh_file = BaseLib::joinPaths(
directory, mesh_config_parameter.getValue<std::string>());
DBUG("Reading mesh file '{:s}'.", mesh_file);
auto mesh = std::unique_ptr<MeshLib::Mesh>(MeshLib::IO::readMeshFromFile(
mesh_file, true /* compute_element_neighbors */));
if (!mesh)
{
std::filesystem::path abspath{mesh_file};
try
{
abspath = std::filesystem::absolute(mesh_file);
}
catch (std::filesystem::filesystem_error const& e)
{
ERR("Determining the absolute path of '{}' failed: {}", mesh_file,
e.what());
}
OGS_FATAL("Could not read mesh from '{:s}' file. No mesh added.",
abspath.string());
}
#ifdef DOXYGEN_DOCU_ONLY
//! \ogs_file_attr{prj__meshes__mesh__axially_symmetric}
mesh_config_parameter.getConfigAttributeOptional<bool>("axially_symmetric");
#endif // DOXYGEN_DOCU_ONLY
if (auto const axially_symmetric =
//! \ogs_file_attr{prj__mesh__axially_symmetric}
mesh_config_parameter.getConfigAttributeOptional<bool>(
"axially_symmetric"))
{
mesh->setAxiallySymmetric(*axially_symmetric);
if (mesh->getDimension() == 3 && mesh->isAxiallySymmetric())
{
OGS_FATAL("3D mesh cannot be axially symmetric.");
}
}
return mesh;
}
std::vector<std::unique_ptr<MeshLib::Mesh>> readMeshes(
BaseLib::ConfigTree const& config, std::string const& directory,
std::string const& project_directory)
{
std::vector<std::unique_ptr<MeshLib::Mesh>> meshes;
GeoLib::GEOObjects geoObjects;
//! \ogs_file_param{prj__meshes}
auto optional_meshes = config.getConfigSubtreeOptional("meshes");
if (optional_meshes)
{
DBUG("Reading multiple meshes.");
//! \ogs_file_param{prj__meshes__mesh}
auto const configs = optional_meshes->getConfigParameterList("mesh");
std::transform(configs.begin(), configs.end(),
std::back_inserter(meshes),
[&directory](auto const& mesh_config)
{ return readSingleMesh(mesh_config, directory); });
if (auto const geometry_file_name =
//! \ogs_file_param{prj__geometry}
config.getConfigParameterOptional<std::string>("geometry"))
{
readGeometry(*geometry_file_name, geoObjects, directory,
project_directory);
}
}
else
{ // Read single mesh with geometry.
meshes.push_back(
//! \ogs_file_param{prj__mesh}
readSingleMesh(config.getConfigParameter("mesh"), directory));
auto const geometry_file_name =
//! \ogs_file_param{prj__geometry}
config.getConfigParameter<std::string>("geometry");
readGeometry(geometry_file_name, geoObjects, directory,
project_directory);
}
{ // generate meshes from geometries
std::unique_ptr<MeshGeoToolsLib::SearchLength> search_length_algorithm =
MeshGeoToolsLib::createSearchLengthAlgorithm(config, *meshes[0]);
bool const multiple_nodes_allowed = false;
auto additional_meshes =
MeshGeoToolsLib::constructAdditionalMeshesFromGeoObjects(
geoObjects, *meshes[0], std::move(search_length_algorithm),
multiple_nodes_allowed);
std::move(begin(additional_meshes), end(additional_meshes),
std::back_inserter(meshes));
}
auto mesh_names = MeshLib::views::names | ranges::to<std::vector>() |
ranges::actions::sort;
auto const sorted_names = meshes | mesh_names;
auto const unique_names = meshes | mesh_names | ranges::actions::unique;
if (unique_names.size() < sorted_names.size())
{
WARN(
"Mesh names aren't unique. From project file read mesh names are:");
for (auto const& name : meshes | MeshLib::views::names)
{
INFO("- {}", name);
}
}
auto const zero_mesh_field_data_by_material_ids =
//! \ogs_file_param{prj__zero_mesh_field_data_by_material_ids}
config.getConfigParameterOptional<std::vector<int>>(
"zero_mesh_field_data_by_material_ids");
if (zero_mesh_field_data_by_material_ids)
{
WARN(
"Tag 'zero_mesh_field_data_by_material_ids` is experimental. Its "
"name may be changed, or it may be removed due to its "
"corresponding feature becomes a single tool. Please use it with "
"care!");
MeshToolsLib::zeroMeshFieldDataByMaterialIDs(
*meshes[0], *zero_mesh_field_data_by_material_ids);
}
MeshLib::setMeshSpaceDimension(meshes);
return meshes;
}
std::vector<GeoLib::NamedRaster> readRasters(
BaseLib::ConfigTree const& config, std::string const& raster_directory,
GeoLib::MinMaxPoints const& min_max_points)
{
INFO("readRasters ...");
std::vector<GeoLib::NamedRaster> named_rasters;
//! \ogs_file_param{prj__rasters}
auto optional_rasters = config.getConfigSubtreeOptional("rasters");
if (optional_rasters)
{
//! \ogs_file_param{prj__rasters__raster}
auto const configs = optional_rasters->getConfigSubtreeList("raster");
std::transform(
configs.begin(), configs.end(), std::back_inserter(named_rasters),
[&raster_directory, &min_max_points](auto const& raster_config)
{
return GeoLib::IO::readRaster(raster_config, raster_directory,
min_max_points);
});
}
INFO("readRasters done");
return named_rasters;
}
// for debugging raster reading implementation
// void writeRasters(std::vector<GeoLib::NamedRaster> const& named_rasters,
// std::string const& output_directory)
//{
// for (auto const& named_raster : named_rasters)
// {
// #if defined(USE_PETSC)
// int my_mpi_rank;
// MPI_Comm_rank(MPI_COMM_WORLD, &my_mpi_rank);
// #endif
// FileIO::AsciiRasterInterface::writeRasterAsASC(
// named_raster.raster, output_directory + "/" +
// named_raster.raster_name +
// #if defined(USE_PETSC)
// "_" + std::to_string(my_mpi_rank) +
// #endif
// ".asc");
// }
//}
std::vector<int> parseMaterialIdString(
std::string const& material_id_string,
MeshLib::PropertyVector<int> const* const material_ids)
{
if (material_id_string == "*")
{
if (material_ids == nullptr)
{
OGS_FATAL(
"MaterialIDs property is not defined in the mesh but it is "
"required to parse '*' definition.");
}
std::vector<int> material_ids_of_this_medium =
*material_ids |
ranges::views::adjacent_remove_if(std::equal_to<>()) |
ranges::to_vector;
BaseLib::makeVectorUnique(material_ids_of_this_medium);
DBUG("Catch all medium definition for material ids {}.",
fmt::join(material_ids_of_this_medium, ", "));
return material_ids_of_this_medium;
}
// Usual case of ids separated by comma.
return BaseLib::splitMaterialIdString(material_id_string);
}
template <typename T, typename CreateMedium>
requires std::convertible_to<decltype(std::declval<CreateMedium>()(
std::declval<int>())),
std::shared_ptr<T>>
void createMediumForId(int const id,
std::map<int, std::shared_ptr<T>>& _media,
std::vector<int> const& material_ids_of_this_medium,
CreateMedium&& create_medium)
{
if (_media.find(id) != end(_media))
{
OGS_FATAL(
"Multiple media were specified for the same material id "
"'{:d}'. Keep in mind, that if no material id is "
"specified, it is assumed to be 0 by default.",
id);
}
if (id == material_ids_of_this_medium[0])
{
_media[id] = create_medium(id);
}
else
{
_media[id] = _media[material_ids_of_this_medium[0]];
}
}
} // namespace
ProjectData::ProjectData() = default;
ProjectData::ProjectData(BaseLib::ConfigTree const& project_config,
std::string const& project_directory,
std::string const& output_directory,
std::string const& mesh_directory,
[[maybe_unused]] std::string const& script_directory)
: _mesh_vec(readMeshes(project_config, mesh_directory, project_directory)),
_named_rasters(readRasters(project_config, project_directory,
GeoLib::AABB(_mesh_vec[0]->getNodes().begin(),
_mesh_vec[0]->getNodes().end())
.getMinMaxPoints()))
{
// for debugging raster reading implementation
// writeRasters(_named_rasters, output_directory);
if (auto const python_script =
//! \ogs_file_param{prj__python_script}
project_config.getConfigParameterOptional<std::string>("python_script"))
{
namespace py = pybind11;
#ifdef OGS_EMBED_PYTHON_INTERPRETER
_py_scoped_interpreter.emplace(ApplicationsLib::setupEmbeddedPython());
#endif
// Append to python's module search path
auto py_path = py::module::import("sys").attr("path");
py_path.attr("append")(script_directory); // .prj or -s directory
auto const script_path =
BaseLib::joinPaths(script_directory, *python_script);
// Evaluate in scope of main module
py::object scope = py::module::import("__main__").attr("__dict__");
// add (global) variables
auto globals = py::dict(scope);
globals["ogs_prj_directory"] = project_directory;
globals["ogs_mesh_directory"] = mesh_directory;
globals["ogs_script_directory"] = script_directory;
try
{
py::eval_file(script_path, scope);
}
catch (py::error_already_set const& e)
{
OGS_FATAL("Error evaluating python script {}: {}", script_path,
e.what());
}
}
//! \ogs_file_param{prj__curves}
parseCurves(project_config.getConfigSubtreeOptional("curves"));
auto parameter_names_for_transformation =
//! \ogs_file_param{prj__parameters}
parseParameters(project_config.getConfigSubtree("parameters"));
_local_coordinate_system = ParameterLib::createCoordinateSystem(
//! \ogs_file_param{prj__local_coordinate_system}
project_config.getConfigSubtreeOptional("local_coordinate_system"),
_parameters);
for (auto& parameter : _parameters)
{
if (std::find(begin(parameter_names_for_transformation),
end(parameter_names_for_transformation),
parameter->name) !=
end(parameter_names_for_transformation))
{
if (!_local_coordinate_system)
{
OGS_FATAL(
"The parameter '{:s}' is using the local coordinate system "
"but no local coordinate system was provided.",
parameter->name);
}
parameter->setCoordinateSystem(*_local_coordinate_system);
}
parameter->initialize(_parameters);
}
//! \ogs_file_param{prj__process_variables}
parseProcessVariables(project_config.getConfigSubtree("process_variables"));
//! \ogs_file_param{prj__media}
parseMedia(project_config.getConfigSubtreeOptional("media"));
//! \ogs_file_param{prj__linear_solvers}
parseLinearSolvers(project_config.getConfigSubtree("linear_solvers"));
auto chemical_solver_interface = parseChemicalSolverInterface(
//! \ogs_file_param{prj__chemical_system}
project_config.getConfigSubtreeOptional("chemical_system"),
output_directory);
//! \ogs_file_param{prj__processes}
parseProcesses(project_config.getConfigSubtree("processes"),
project_directory, output_directory,
std::move(chemical_solver_interface));
//! \ogs_file_param{prj__nonlinear_solvers}
parseNonlinearSolvers(project_config.getConfigSubtree("nonlinear_solvers"));
//! \ogs_file_param{prj__time_loop}
parseTimeLoop(project_config.getConfigSubtree("time_loop"),
output_directory);
}
void ProjectData::parseProcessVariables(
BaseLib::ConfigTree const& process_variables_config)
{
DBUG("Parse process variables:");
std::set<std::string> names;
for (auto var_config
//! \ogs_file_param{prj__process_variables__process_variable}
: process_variables_config.getConfigSubtreeList("process_variable"))
{
// Either the mesh name is given, or the first mesh's name will be
// taken. Taking the first mesh's value is deprecated.
auto const mesh_name =
//! \ogs_file_param{prj__process_variables__process_variable__mesh}
var_config.getConfigParameter<std::string>("mesh",
_mesh_vec[0]->getName());
auto& mesh = MeshLib::findMeshByName(_mesh_vec, mesh_name);
auto pv = ProcessLib::ProcessVariable{var_config, mesh, _mesh_vec,
_parameters, _curves};
if (!names.insert(pv.getName()).second)
{
OGS_FATAL("A process variable with name `{:s}' already exists.",
pv.getName());
}
_process_variables.push_back(std::move(pv));
}
}
std::vector<std::string> ProjectData::parseParameters(
BaseLib::ConfigTree const& parameters_config)
{
using namespace ProcessLib;
std::set<std::string> names;
std::vector<std::string> parameter_names_for_transformation;
DBUG("Reading parameters:");
for (auto parameter_config :
//! \ogs_file_param{prj__parameters__parameter}
parameters_config.getConfigSubtreeList("parameter"))
{
auto p = ParameterLib::createParameter(parameter_config, _mesh_vec,
_named_rasters, _curves);
if (!names.insert(p->name).second)
{
OGS_FATAL("A parameter with name `{:s}' already exists.", p->name);
}
auto const use_local_coordinate_system =
//! \ogs_file_param{prj__parameters__parameter__use_local_coordinate_system}
parameter_config.getConfigParameterOptional<bool>(
"use_local_coordinate_system");
if (!!use_local_coordinate_system && *use_local_coordinate_system)
{
parameter_names_for_transformation.push_back(p->name);
}
_parameters.push_back(std::move(p));
}
_parameters.push_back(
std::make_unique<ParameterLib::ConstantParameter<double>>(
ProcessLib::DeactivatedSubdomain::zero_parameter_name, 0.0));
_parameters.push_back(
std::make_unique<ParameterLib::ConstantParameter<double>>(
ProcessLib::Process::constant_one_parameter_name, 1.0));
return parameter_names_for_transformation;
}
void ProjectData::parseMedia(
std::optional<BaseLib::ConfigTree> const& media_config)
{
if (!media_config)
{
return;
}
DBUG("Reading media:");
if (_mesh_vec.empty() || _mesh_vec[0] == nullptr)
{
ERR("A mesh is required to define medium materials.");
return;
}
for (auto const& medium_config :
//! \ogs_file_param{prj__media__medium}
media_config->getConfigSubtreeList("medium"))
{
auto create_medium = [dim = _mesh_vec[0]->getDimension(),
&medium_config, this](int const id)
{
return MaterialPropertyLib::createMedium(
id, _mesh_vec[0]->getDimension(), medium_config, _parameters,
_local_coordinate_system ? &*_local_coordinate_system : nullptr,
_curves);
};
auto const material_id_string =
//! \ogs_file_attr{prj__media__medium__id}
medium_config.getConfigAttribute<std::string>("id", "0");
std::vector<int> const material_ids_of_this_medium =
parseMaterialIdString(material_id_string,
materialIDs(*_mesh_vec[0]));
for (auto const& id : material_ids_of_this_medium)
{
createMediumForId(id, _media, material_ids_of_this_medium,
create_medium);
}
}
if (_media.empty())
{
OGS_FATAL("No entity is found inside <media>.");
}
}
std::unique_ptr<ChemistryLib::ChemicalSolverInterface>
ProjectData::parseChemicalSolverInterface(
std::optional<BaseLib::ConfigTree> const& config,
std::string const& output_directory)
{
if (!config)
{
return nullptr;
}
std::unique_ptr<ChemistryLib::ChemicalSolverInterface>
chemical_solver_interface;
#ifdef OGS_BUILD_PROCESS_COMPONENTTRANSPORT
INFO(
"Ready for initializing interface to a chemical solver for water "
"chemistry calculation.");
auto const chemical_solver =
//! \ogs_file_attr{prj__chemical_system__chemical_solver}
config->getConfigAttribute<std::string>("chemical_solver");
if (boost::iequals(chemical_solver, "Phreeqc"))
{
INFO(
"Configuring phreeqc interface for water chemistry calculation "
"using file-based approach.");
chemical_solver_interface = ChemistryLib::createChemicalSolverInterface<
ChemistryLib::ChemicalSolver::Phreeqc>(_mesh_vec, _linear_solvers,
*config, output_directory);
}
else if (boost::iequals(chemical_solver, "PhreeqcKernel"))
{
OGS_FATAL(
"The chemical solver option of PhreeqcKernel is not accessible for "
"the time being. Please set 'Phreeqc'' as the chemical solver for "
"reactive transport modeling.");
}
else if (boost::iequals(chemical_solver, "SelfContained"))
{
INFO(
"Use self-contained chemical solver for water chemistry "
"calculation.");
chemical_solver_interface = ChemistryLib::createChemicalSolverInterface<
ChemistryLib::ChemicalSolver::SelfContained>(
_mesh_vec, _linear_solvers, *config, output_directory);
}
else
{
OGS_FATAL(
"Unknown chemical solver. Please specify either Phreeqc or "
"PhreeqcKernel as the solver for water chemistry calculation "
"instead.");
}
#else
(void)output_directory;
OGS_FATAL(
"Found the type of the process to be solved is not component transport "
"process. Please specify the process type to ComponentTransport. At "
"the present, water chemistry calculation is only available for "
"component transport process.");
#endif
return chemical_solver_interface;
}
void ProjectData::parseProcesses(
BaseLib::ConfigTree const& processes_config,
std::string const& project_directory,
std::string const& output_directory,
[[maybe_unused]] std::unique_ptr<ChemistryLib::ChemicalSolverInterface>&&
chemical_solver_interface)
{
(void)project_directory; // to avoid compilation warning
(void)output_directory; // to avoid compilation warning
DBUG("Reading processes:");
//! \ogs_file_param{prj__processes__process}
for (auto process_config : processes_config.getConfigSubtreeList("process"))
{
auto const type =
//! \ogs_file_param{prj__processes__process__type}
process_config.peekConfigParameter<std::string>("type");
auto const name =
//! \ogs_file_param{prj__processes__process__name}
process_config.getConfigParameter<std::string>("name");
[[maybe_unused]] auto const integration_order =
//! \ogs_file_param{prj__processes__process__integration_order}
process_config.getConfigParameter<int>("integration_order");
std::unique_ptr<ProcessLib::Process> process;
auto jacobian_assembler = ProcessLib::createJacobianAssembler(
//! \ogs_file_param{prj__processes__process__jacobian_assembler}
process_config.getConfigSubtreeOptional("jacobian_assembler"));
#ifdef OGS_BUILD_PROCESS_STEADYSTATEDIFFUSION
if (type == "STEADY_STATE_DIFFUSION")
{
// The existence check of the in the configuration referenced
// process variables is checked in the physical process.
// TODO at the moment we have only one mesh, later there can be
// several meshes. Then we have to assign the referenced mesh
// here.
process =
ProcessLib::SteadyStateDiffusion::createSteadyStateDiffusion(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config, _mesh_vec, _media);
}
else
#endif
#ifdef OGS_BUILD_PROCESS_LIQUIDFLOW
if (type == "LIQUID_FLOW")
{
process = ProcessLib::LiquidFlow::createLiquidFlowProcess(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config, _mesh_vec, _media);
}
else
#endif
#ifdef OGS_BUILD_PROCESS_STOKESFLOW
if (type == "StokesFlow")
{
WARN(
"The StokesFlow process is deprecated and will be removed in "
"OGS-6.5.5.");
switch (_mesh_vec[0]->getDimension())
{
case 2:
process =
ProcessLib::StokesFlow::createStokesFlowProcess<2>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config, _media);
break;
default:
OGS_FATAL(
"StokesFlow process does not support given "
"dimension {:d}",
_mesh_vec[0]->getDimension());
}
}
else
#endif
#ifdef OGS_BUILD_PROCESS_TES
if (type == "TES")
{
WARN(
"The TES process is deprecated and will be removed in "
"OGS-6.5.5.");
process = ProcessLib::TES::createTESProcess(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config);
}
else
#endif
#ifdef OGS_BUILD_PROCESS_TH2M
if (type == "TH2M")
{
switch (_mesh_vec[0]->getDimension())
{
case 2:
process = ProcessLib::TH2M::createTH2MProcess<2>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
case 3:
process = ProcessLib::TH2M::createTH2MProcess<3>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
default:
OGS_FATAL("TH2M process does not support given dimension");
}
}
else
#endif
#ifdef OGS_BUILD_PROCESS_HEATCONDUCTION
if (type == "HEAT_CONDUCTION")
{
process = ProcessLib::HeatConduction::createHeatConductionProcess(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config, _media);
}
else
#endif
#ifdef OGS_BUILD_PROCESS_HEATTRANSPORTBHE
if (type == "HEAT_TRANSPORT_BHE")
{
if (_mesh_vec[0]->getDimension() != 3)
{
OGS_FATAL(
"HEAT_TRANSPORT_BHE can only work with a 3-dimensional "
"mesh! ");
}
process =
ProcessLib::HeatTransportBHE::createHeatTransportBHEProcess(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config, _curves, _media);
}
else
#endif
#ifdef OGS_BUILD_PROCESS_WELLBORESIMULATOR
if (type == "WELLBORE_SIMULATOR")
{
if (_mesh_vec[0]->getDimension() != 1)
{
OGS_FATAL(
"WELLBORE_SIMULATOR can only work with a 1-dimensional "
"mesh!");
}
process =
ProcessLib::WellboreSimulator::createWellboreSimulatorProcess(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config, _media);
}
else
#endif
#ifdef OGS_BUILD_PROCESS_HYDROMECHANICS
if (type == "HYDRO_MECHANICS")
{
if ( //! \ogs_file_param{prj__processes__process__HYDRO_MECHANICS__dimension}
process_config.getConfigParameterOptional<int>("dimension"))
{
OGS_FATAL(
"The 'dimension' tag has been removed in the merge-request "
"!4766."
"The dimension is now taken from the main mesh and the tag "
"must be"
"removed. There is a python script in the merge-request "
"description"
"for automatic conversion.");
}
switch (_mesh_vec[0]->getDimension())
{
case 2:
process =
ProcessLib::HydroMechanics::createHydroMechanicsProcess<
2>(name, *_mesh_vec[0],
std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
case 3:
process =
ProcessLib::HydroMechanics::createHydroMechanicsProcess<
3>(name, *_mesh_vec[0],
std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
default:
OGS_FATAL(
"HYDRO_MECHANICS process does not support given "
"dimension");
}
}
else
#endif
#ifdef OGS_BUILD_PROCESS_LARGEDEFORMATION
if (type == "LARGE_DEFORMATION")
{
switch (_mesh_vec[0]->getDimension())
{
case 2:
process = ProcessLib::LargeDeformation::
createLargeDeformationProcess<2>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
case 3:
process = ProcessLib::LargeDeformation::
createLargeDeformationProcess<3>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
default:
OGS_FATAL(
"LARGE_DEFORMATION process does not support given "
"dimension");
}
}
else
#endif
#ifdef OGS_BUILD_PROCESS_LIE
if (type == "HYDRO_MECHANICS_WITH_LIE")
{
if ( //! \ogs_file_param{prj__processes__process__HYDRO_MECHANICS_WITH_LIE__dimension}
process_config.getConfigParameterOptional<int>("dimension"))
{
OGS_FATAL(
"The 'dimension' tag has been removed in the merge-request "
"!4766."
"The dimension is now taken from the main mesh and the tag "
"must be"
"removed. There is a python script in the merge-request "
"description"
"for automatic conversion.");
}
switch (_mesh_vec[0]->getDimension())
{
case 2:
process = ProcessLib::LIE::HydroMechanics::
createHydroMechanicsProcess<2>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config);
break;
case 3:
process = ProcessLib::LIE::HydroMechanics::
createHydroMechanicsProcess<3>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config);
break;
default:
OGS_FATAL(
"HYDRO_MECHANICS_WITH_LIE process does not support "
"given dimension");
}
}
else
#endif
#ifdef OGS_BUILD_PROCESS_HT
if (type == "HT")
{
process = ProcessLib::HT::createHTProcess(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config, _mesh_vec, _media);
}
else
#endif
#ifdef OGS_BUILD_PROCESS_COMPONENTTRANSPORT
if (type == "ComponentTransport")
{
process =
ProcessLib::ComponentTransport::createComponentTransportProcess(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config, _mesh_vec, _media,
std::move(chemical_solver_interface));
}
else
#endif
#ifdef OGS_BUILD_PROCESS_PHASEFIELD
if (type == "PHASE_FIELD")
{
switch (_mesh_vec[0]->getDimension())
{
case 2:
process =
ProcessLib::PhaseField::createPhaseFieldProcess<2>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config);
break;
case 3:
process =
ProcessLib::PhaseField::createPhaseFieldProcess<3>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config);
break;
}
}
else
#endif
#ifdef OGS_BUILD_PROCESS_RICHARDSCOMPONENTTRANSPORT
if (type == "RichardsComponentTransport")
{
process = ProcessLib::RichardsComponentTransport::
createRichardsComponentTransportProcess(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config, _media);
}
else
#endif
#ifdef OGS_BUILD_PROCESS_SMALLDEFORMATION
if (type == "SMALL_DEFORMATION")
{
switch (_mesh_vec[0]->getDimension())
{
case 2:
process = ProcessLib::SmallDeformation::
createSmallDeformationProcess<2>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
case 3:
process = ProcessLib::SmallDeformation::
createSmallDeformationProcess<3>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
default:
OGS_FATAL(
"SMALL_DEFORMATION process does not support given "
"dimension");
}
}
else
#endif
#ifdef OGS_BUILD_PROCESS_SMALLDEFORMATIONNONLOCAL
if (type == "SMALL_DEFORMATION_NONLOCAL")
{
WARN(
"The SMALL_DEFORMATION_NONLOCAL process is deprecated and will "
"be removed in OGS-6.5.5.");
switch (_mesh_vec[0]->getDimension())
{
case 2:
process = ProcessLib::SmallDeformationNonlocal::
createSmallDeformationNonlocalProcess<2>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config);
break;
case 3:
process = ProcessLib::SmallDeformationNonlocal::
createSmallDeformationNonlocalProcess<3>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config);
break;
default:
OGS_FATAL(
"SMALL_DEFORMATION_NONLOCAL process does not support "
"given dimension {:d}",
_mesh_vec[0]->getDimension());
}
}
else
#endif
#ifdef OGS_BUILD_PROCESS_LIE
if (type == "SMALL_DEFORMATION_WITH_LIE")
{
if ( //! \ogs_file_param{prj__processes__process__SMALL_DEFORMATION_WITH_LIE__dimension}
process_config.getConfigParameterOptional<int>("dimension"))
{
OGS_FATAL(
"The 'dimension' tag has been removed in the merge-request "
"!4766."
"The dimension is now taken from the main mesh and the tag "
"must be"
"removed. There is a python script in the merge-request "
"description"
"for automatic conversion.");
}
switch (_mesh_vec[0]->getDimension())
{
case 2:
process = ProcessLib::LIE::SmallDeformation::
createSmallDeformationProcess<2>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config);
break;
case 3:
process = ProcessLib::LIE::SmallDeformation::
createSmallDeformationProcess<3>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config);
break;
default:
OGS_FATAL(
"SMALL_DEFORMATION_WITH_LIE process does not support "
"given dimension");
}
}
else
#endif
#ifdef OGS_BUILD_PROCESS_THERMOHYDROMECHANICS
if (type == "THERMO_HYDRO_MECHANICS")
{
if ( //! \ogs_file_param{prj__processes__process__THERMO_HYDRO_MECHANICS__dimension}
process_config.getConfigParameterOptional<int>("dimension"))
{
OGS_FATAL(
"The 'dimension' tag has been removed in the merge-request "
"!4766."
"The dimension is now taken from the main mesh and the tag "
"must be"
"removed. There is a python script in the merge-request "
"description"
"for automatic conversion.");
}
switch (_mesh_vec[0]->getDimension())
{
case 2:
process = ProcessLib::ThermoHydroMechanics::
createThermoHydroMechanicsProcess<2>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
case 3:
process = ProcessLib::ThermoHydroMechanics::
createThermoHydroMechanicsProcess<3>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
default:
OGS_FATAL(
"THERMO_HYDRO_MECHANICS process does not support given "
"dimension");
}
}
else
#endif
#ifdef OGS_BUILD_PROCESS_THERMOMECHANICALPHASEFIELD
if (type == "THERMO_MECHANICAL_PHASE_FIELD")
{
WARN(
"The THERMO_MECHANICAL_PHASE_FIELD process is deprecated and "
"will be removed in OGS-6.5.5.");
switch (_mesh_vec[0]->getDimension())
{
case 2:
process = ProcessLib::ThermoMechanicalPhaseField::
createThermoMechanicalPhaseFieldProcess<2>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config);
break;
case 3:
process = ProcessLib::ThermoMechanicalPhaseField::
createThermoMechanicalPhaseFieldProcess<3>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config);
break;
}
}
else
#endif
#ifdef OGS_BUILD_PROCESS_THERMOMECHANICS
if (type == "THERMO_MECHANICS")
{
switch (_mesh_vec[0]->getDimension())
{
case 2:
process = ProcessLib::ThermoMechanics::
createThermoMechanicsProcess<2>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
case 3:
process = ProcessLib::ThermoMechanics::
createThermoMechanicsProcess<3>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
}
}
else
#endif
#ifdef OGS_BUILD_PROCESS_RICHARDSFLOW
if (type == "RICHARDS_FLOW")
{
process = ProcessLib::RichardsFlow::createRichardsFlowProcess(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config, _media);
}
else
#endif
#ifdef OGS_BUILD_PROCESS_RICHARDSMECHANICS
if (type == "RICHARDS_MECHANICS")
{
if ( //! \ogs_file_param{prj__processes__process__RICHARDS_MECHANICS__dimension}
process_config.getConfigParameterOptional<int>("dimension"))
{
OGS_FATAL(
"The 'dimension' tag has been removed in the merge-request "
"!4766."
"The dimension is now taken from the main mesh and the tag "
"must be"
"removed. There is a python script in the merge-request "
"description"
"for automatic conversion.");
}
switch (_mesh_vec[0]->getDimension())
{
case 2:
process = ProcessLib::RichardsMechanics::
createRichardsMechanicsProcess<2>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
case 3:
process = ProcessLib::RichardsMechanics::
createRichardsMechanicsProcess<3>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
}
}
else
#endif
#ifdef OGS_BUILD_PROCESS_THERMORICHARDSFLOW
if (type == "THERMO_RICHARDS_FLOW")
{
process =
ProcessLib::ThermoRichardsFlow::createThermoRichardsFlowProcess(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config, _media);
}
else
#endif
#ifdef OGS_BUILD_PROCESS_THERMORICHARDSMECHANICS
if (type == "THERMO_RICHARDS_MECHANICS")
{
switch (_mesh_vec[0]->getDimension())
{
case 2:
process = ProcessLib::ThermoRichardsMechanics::
createThermoRichardsMechanicsProcess<2>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
case 3:
process = ProcessLib::ThermoRichardsMechanics::
createThermoRichardsMechanicsProcess<3>(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters,
_local_coordinate_system, integration_order,
process_config, _media);
break;
}
}
else
#endif
#ifdef OGS_BUILD_PROCESS_TWOPHASEFLOWWITHPP
if (type == "TWOPHASE_FLOW_PP")
{
process =
ProcessLib::TwoPhaseFlowWithPP::createTwoPhaseFlowWithPPProcess(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config, _media);
}
else
#endif
#ifdef OGS_BUILD_PROCESS_TWOPHASEFLOWWITHPRHO
if (type == "TWOPHASE_FLOW_PRHO")
{
WARN(
"The TWOPHASE_FLOW_PRHO process is deprecated and will be "
"removed in OGS-6.5.5.");
process = ProcessLib::TwoPhaseFlowWithPrho::
createTwoPhaseFlowWithPrhoProcess(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config, _media);
}
else
#endif
#ifdef OGS_BUILD_PROCESS_THERMALTWOPHASEFLOWWITHPP
if (type == "THERMAL_TWOPHASE_WITH_PP")
{
process = ProcessLib::ThermalTwoPhaseFlowWithPP::
createThermalTwoPhaseFlowWithPPProcess(
name, *_mesh_vec[0], std::move(jacobian_assembler),
_process_variables, _parameters, integration_order,
process_config, _media);
}
else
#endif
{
OGS_FATAL("Unknown process type: {:s}", type);
}
if (ranges::contains(_processes, name,
[](std::unique_ptr<ProcessLib::Process> const& p)
{ return p->name; }))
{
OGS_FATAL("The process name '{:s}' is not unique.", name);
}
_processes.push_back(std::move(process));
}
}
void ProjectData::parseTimeLoop(BaseLib::ConfigTree const& config,
std::string const& output_directory)
{
DBUG("Reading time loop configuration.");
bool const compensate_non_equilibrium_initial_residuum = std::any_of(
std::begin(_process_variables),
std::end(_process_variables),
[](auto const& process_variable)
{ return process_variable.compensateNonEquilibriumInitialResiduum(); });
_time_loop = ProcessLib::createTimeLoop(
config, output_directory, _processes, _nonlinear_solvers, _mesh_vec,
compensate_non_equilibrium_initial_residuum);
if (!_time_loop)
{
OGS_FATAL("Initialization of time loop failed.");
}
}
void ProjectData::parseLinearSolvers(BaseLib::ConfigTree const& config)
{
DBUG("Reading linear solver configuration.");
//! \ogs_file_param{prj__linear_solvers__linear_solver}
for (auto conf : config.getConfigSubtreeList("linear_solver"))
{
//! \ogs_file_param{prj__linear_solvers__linear_solver__name}
auto const name = conf.getConfigParameter<std::string>("name");
auto const linear_solver_parser =
MathLib::LinearSolverOptionsParser<GlobalLinearSolver>{};
auto const solver_options =
linear_solver_parser.parseNameAndOptions("", &conf);
BaseLib::insertIfKeyUniqueElseError(
_linear_solvers,
name,
std::make_unique<GlobalLinearSolver>(std::get<0>(solver_options),
std::get<1>(solver_options)),
"The linear solver name is not unique");
}
}
void ProjectData::parseNonlinearSolvers(BaseLib::ConfigTree const& config)
{
DBUG("Reading non-linear solver configuration.");
//! \ogs_file_param{prj__nonlinear_solvers__nonlinear_solver}
for (auto conf : config.getConfigSubtreeList("nonlinear_solver"))
{
auto const ls_name =
//! \ogs_file_param{prj__nonlinear_solvers__nonlinear_solver__linear_solver}
conf.getConfigParameter<std::string>("linear_solver");
auto const& linear_solver = BaseLib::getOrError(
_linear_solvers, ls_name,
"A linear solver with the given name does not exist.");
//! \ogs_file_param{prj__nonlinear_solvers__nonlinear_solver__name}
auto const name = conf.getConfigParameter<std::string>("name");
BaseLib::insertIfKeyUniqueElseError(
_nonlinear_solvers,
name,
NumLib::createNonlinearSolver(*linear_solver, conf).first,
"The nonlinear solver name is not unique");
}
}
void ProjectData::parseCurves(std::optional<BaseLib::ConfigTree> const& config)
{
if (!config)
{
return;
}
DBUG("Reading curves configuration.");
//! \ogs_file_param{prj__curves__curve}
for (auto conf : config->getConfigSubtreeList("curve"))
{
//! \ogs_file_param{prj__curves__curve__name}
auto const name = conf.getConfigParameter<std::string>("name");
BaseLib::insertIfKeyUniqueElseError(
_curves,
name,
MathLib::createPiecewiseLinearCurve<
MathLib::PiecewiseLinearInterpolation>(conf),
"The curve name is not unique.");
}
}
MeshLib::Mesh& ProjectData::getMesh(std::string const& mesh_name) const
{
return MeshLib::findMeshByName(_mesh_vec, mesh_name);
}