From 2fa3356c73af3a7c43aa751a18935d069acfb745 Mon Sep 17 00:00:00 2001 From: Dmitrij Naumov <dmitrij@naumov.de> Date: Wed, 27 Jun 2018 17:45:09 +0200 Subject: [PATCH] [PL] Implementation of RichardsMechanics process. --- Applications/ApplicationsLib/ProjectData.cpp | 27 + CMakeLists.txt | 1 + ProcessLib/RichardsMechanics/CMakeLists.txt | 6 + .../RichardsMechanics/CreateLocalAssemblers.h | 87 ++ .../CreateRichardsMechanicsProcess.cpp | 239 +++++ .../CreateRichardsMechanicsProcess.h | 65 ++ .../RichardsMechanics/IntegrationPointData.h | 96 ++ .../LocalAssemblerInterface.h | 48 + .../RichardsMechanics/LocalDataInitializer.h | 289 ++++++ .../RichardsMechanicsFEM-impl.h | 833 ++++++++++++++++++ .../RichardsMechanics/RichardsMechanicsFEM.h | 237 +++++ .../RichardsMechanicsProcess.cpp | 381 ++++++++ .../RichardsMechanicsProcess.h | 140 +++ .../RichardsMechanicsProcessData.h | 104 +++ 14 files changed, 2553 insertions(+) create mode 100644 ProcessLib/RichardsMechanics/CMakeLists.txt create mode 100644 ProcessLib/RichardsMechanics/CreateLocalAssemblers.h create mode 100644 ProcessLib/RichardsMechanics/CreateRichardsMechanicsProcess.cpp create mode 100644 ProcessLib/RichardsMechanics/CreateRichardsMechanicsProcess.h create mode 100644 ProcessLib/RichardsMechanics/IntegrationPointData.h create mode 100644 ProcessLib/RichardsMechanics/LocalAssemblerInterface.h create mode 100644 ProcessLib/RichardsMechanics/LocalDataInitializer.h create mode 100644 ProcessLib/RichardsMechanics/RichardsMechanicsFEM-impl.h create mode 100644 ProcessLib/RichardsMechanics/RichardsMechanicsFEM.h create mode 100644 ProcessLib/RichardsMechanics/RichardsMechanicsProcess.cpp create mode 100644 ProcessLib/RichardsMechanics/RichardsMechanicsProcess.h create mode 100644 ProcessLib/RichardsMechanics/RichardsMechanicsProcessData.h diff --git a/Applications/ApplicationsLib/ProjectData.cpp b/Applications/ApplicationsLib/ProjectData.cpp index d3d07d07bd6..10b42a97ca4 100644 --- a/Applications/ApplicationsLib/ProjectData.cpp +++ b/Applications/ApplicationsLib/ProjectData.cpp @@ -72,6 +72,9 @@ #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 @@ -554,6 +557,30 @@ void ProjectData::parseProcesses(BaseLib::ConfigTree const& processes_config, } else #endif +#ifdef OGS_BUILD_PROCESS_RICHARDSMECHANICS + if (type == "RICHARDS_MECHANICS") + { + //! \ogs_file_param{prj__processes__process__RICHARDS_MECHANICS__dimension} + switch (process_config.getConfigParameter<int>("dimension")) + { + case 2: + process = ProcessLib::RichardsMechanics:: + createRichardsMechanicsProcess<2>( + *_mesh_vec[0], std::move(jacobian_assembler), + _process_variables, _parameters, integration_order, + process_config); + break; + case 3: + process = ProcessLib::RichardsMechanics:: + createRichardsMechanicsProcess<3>( + *_mesh_vec[0], std::move(jacobian_assembler), + _process_variables, _parameters, integration_order, + process_config); + break; + } + } + else +#endif #ifdef OGS_BUILD_PROCESS_TWOPHASEFLOWWITHPP if (type == "TWOPHASE_FLOW_PP") { diff --git a/CMakeLists.txt b/CMakeLists.txt index add4d4668f4..ddd5670df00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,7 @@ set(ProcessesList PhaseField RichardsComponentTransport RichardsFlow + RichardsMechanics SmallDeformation TES ThermalTwoPhaseFlowWithPP diff --git a/ProcessLib/RichardsMechanics/CMakeLists.txt b/ProcessLib/RichardsMechanics/CMakeLists.txt new file mode 100644 index 00000000000..6e124260816 --- /dev/null +++ b/ProcessLib/RichardsMechanics/CMakeLists.txt @@ -0,0 +1,6 @@ +APPEND_SOURCE_FILES(SOURCES) + +add_library(RichardsMechanics ${SOURCES}) +target_link_libraries(RichardsMechanics PUBLIC ProcessLib RichardsFlow) + +include(Tests.cmake) diff --git a/ProcessLib/RichardsMechanics/CreateLocalAssemblers.h b/ProcessLib/RichardsMechanics/CreateLocalAssemblers.h new file mode 100644 index 00000000000..7a7c825cfc0 --- /dev/null +++ b/ProcessLib/RichardsMechanics/CreateLocalAssemblers.h @@ -0,0 +1,87 @@ +/** + * \copyright + * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + */ + +#pragma once + +#include <vector> + +#include <logog/include/logog.hpp> + +#include "NumLib/DOF/LocalToGlobalIndexMap.h" + +#include "LocalDataInitializer.h" + +namespace ProcessLib +{ +namespace RichardsMechanics +{ +namespace detail +{ +template <int GlobalDim, + template <typename, typename, typename, int> + class LocalAssemblerImplementation, + typename LocalAssemblerInterface, typename... ExtraCtorArgs> +void createLocalAssemblers( + NumLib::LocalToGlobalIndexMap const& dof_table, + const unsigned shapefunction_order, + std::vector<MeshLib::Element*> const& mesh_elements, + std::vector<std::unique_ptr<LocalAssemblerInterface>>& local_assemblers, + ExtraCtorArgs&&... extra_ctor_args) +{ + // Shape matrices initializer + using LocalDataInitializer = + LocalDataInitializer<LocalAssemblerInterface, + LocalAssemblerImplementation, GlobalDim, + ExtraCtorArgs...>; + + DBUG("Create local assemblers."); + // Populate the vector of local assemblers. + local_assemblers.resize(mesh_elements.size()); + + LocalDataInitializer initializer(dof_table, shapefunction_order); + + DBUG("Calling local assembler builder for all mesh elements."); + GlobalExecutor::transformDereferenced( + initializer, mesh_elements, local_assemblers, + std::forward<ExtraCtorArgs>(extra_ctor_args)...); +} + +} // namespace detail + +/*! Creates local assemblers for each element of the given \c mesh. + * + * \tparam LocalAssemblerImplementation the individual local assembler type + * \tparam LocalAssemblerInterface the general local assembler interface + * \tparam ExtraCtorArgs types of additional constructor arguments. + * Those arguments will be passed to the constructor of + * \c LocalAssemblerImplementation. + * + * The first two template parameters cannot be deduced from the arguments. + * Therefore they always have to be provided manually. + */ +template <int GlobalDim, + template <typename, typename, typename, int> + class LocalAssemblerImplementation, + typename LocalAssemblerInterface, typename... ExtraCtorArgs> +void createLocalAssemblers( + const unsigned /*dimension*/, + std::vector<MeshLib::Element*> const& mesh_elements, + NumLib::LocalToGlobalIndexMap const& dof_table, + const unsigned shapefunction_order, + std::vector<std::unique_ptr<LocalAssemblerInterface>>& local_assemblers, + ExtraCtorArgs&&... extra_ctor_args) +{ + DBUG("Create local assemblers."); + + detail::createLocalAssemblers<GlobalDim, LocalAssemblerImplementation>( + dof_table, shapefunction_order, mesh_elements, local_assemblers, + std::forward<ExtraCtorArgs>(extra_ctor_args)...); +} +} // namespace RichardsMechanics + +} // namespace ProcessLib diff --git a/ProcessLib/RichardsMechanics/CreateRichardsMechanicsProcess.cpp b/ProcessLib/RichardsMechanics/CreateRichardsMechanicsProcess.cpp new file mode 100644 index 00000000000..d901fb3f40a --- /dev/null +++ b/ProcessLib/RichardsMechanics/CreateRichardsMechanicsProcess.cpp @@ -0,0 +1,239 @@ +/** + * \copyright + * Copyright (c) 2012-2018, 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 "CreateRichardsMechanicsProcess.h" + +#include <cassert> + +#include "MaterialLib/SolidModels/CreateConstitutiveRelation.h" +#include "MaterialLib/SolidModels/MechanicsBase.h" +#include "ProcessLib/Output/CreateSecondaryVariables.h" +#include "ProcessLib/RichardsFlow/CreateRichardsFlowMaterialProperties.h" +#include "ProcessLib/Utils/ProcessUtils.h" + +#include "RichardsMechanicsProcess.h" +#include "RichardsMechanicsProcessData.h" + +namespace ProcessLib +{ +namespace RichardsMechanics +{ +template <int DisplacementDim> +std::unique_ptr<Process> createRichardsMechanicsProcess( + MeshLib::Mesh& mesh, + std::unique_ptr<ProcessLib::AbstractJacobianAssembler>&& jacobian_assembler, + std::vector<ProcessVariable> const& variables, + std::vector<std::unique_ptr<ParameterBase>> const& parameters, + unsigned const integration_order, + BaseLib::ConfigTree const& config) +{ + //! \ogs_file_param{prj__processes__process__type} + config.checkConfigParameter("type", "RICHARDS_MECHANICS"); + DBUG("Create RichardsMechanicsProcess."); + + auto const staggered_scheme = + //! \ogs_file_param{prj__processes__process__RICHARDS_MECHANICS__coupling_scheme} + config.getConfigParameterOptional<std::string>("coupling_scheme"); + const bool use_monolithic_scheme = + !(staggered_scheme && (*staggered_scheme == "staggered")); + + // Process variable. + + //! \ogs_file_param{prj__processes__process__RICHARDS_MECHANICS__process_variables} + auto const pv_config = config.getConfigSubtree("process_variables"); + + ProcessVariable* variable_p; + ProcessVariable* variable_u; + std::vector<std::vector<std::reference_wrapper<ProcessVariable>>> + process_variables; + if (use_monolithic_scheme) // monolithic scheme. + { + auto per_process_variables = findProcessVariables( + variables, pv_config, + {//! \ogs_file_param_special{prj__processes__process__RICHARDS_MECHANICS__process_variables__pressure} + "pressure", + //! \ogs_file_param_special{prj__processes__process__RICHARDS_MECHANICS__process_variables__displacement} + "displacement"}); + variable_p = &per_process_variables[0].get(); + variable_u = &per_process_variables[1].get(); + process_variables.push_back(std::move(per_process_variables)); + } + else // staggered scheme. + { + using namespace std::string_literals; + for (auto const& variable_name : {"pressure"s, "displacement"s}) + { + auto per_process_variables = + findProcessVariables(variables, pv_config, {variable_name}); + process_variables.push_back(std::move(per_process_variables)); + } + variable_p = &process_variables[0][0].get(); + variable_u = &process_variables[1][0].get(); + } + + DBUG("Associate displacement with process variable \'%s\'.", + variable_u->getName().c_str()); + + if (variable_u->getNumberOfComponents() != DisplacementDim) + { + OGS_FATAL( + "Number of components of the process variable '%s' is different " + "from the displacement dimension: got %d, expected %d", + variable_u->getName().c_str(), + variable_u->getNumberOfComponents(), + DisplacementDim); + } + + DBUG("Associate pressure with process variable \'%s\'.", + variable_p->getName().c_str()); + if (variable_p->getNumberOfComponents() != 1) + { + OGS_FATAL( + "Pressure process variable '%s' is not a scalar variable but has " + "%d components.", + variable_p->getName().c_str(), + variable_p->getNumberOfComponents()); + } + + // Constitutive relation. + auto solid_material = + MaterialLib::Solids::createConstitutiveRelation<DisplacementDim>( + parameters, config); + + // Intrinsic permeability + auto& intrinsic_permeability = findParameter<double>( + config, + //! \ogs_file_param_special{prj__processes__process__RICHARDS_MECHANICS__intrinsic_permeability} + "intrinsic_permeability", parameters, 1); + + DBUG("Use \'%s\' as intrinsic conductivity parameter.", + intrinsic_permeability.name.c_str()); + + // Fluid bulk modulus + auto& fluid_bulk_modulus = findParameter<double>( + config, + //! \ogs_file_param_special{prj__processes__process__RICHARDS_MECHANICS__fluid_bulk_modulus} + "fluid_bulk_modulus", parameters, 1); + DBUG("Use \'%s\' as fluid bulk modulus parameter.", + fluid_bulk_modulus.name.c_str()); + + // Biot coefficient + auto& biot_coefficient = findParameter<double>( + config, + //! \ogs_file_param_special{prj__processes__process__RICHARDS_MECHANICS__biot_coefficient} + "biot_coefficient", parameters, 1); + DBUG("Use \'%s\' as Biot coefficient parameter.", + biot_coefficient.name.c_str()); + + // Solid density + auto& solid_density = findParameter<double>( + config, + //! \ogs_file_param_special{prj__processes__process__RICHARDS_MECHANICS__solid_density} + "solid_density", parameters, 1); + DBUG("Use \'%s\' as solid density parameter.", solid_density.name.c_str()); + + // Solid bulk modulus + auto& solid_bulk_modulus = findParameter<double>( + config, + //! \ogs_file_param_special{prj__processes__process__RICHARDS_MECHANICS__solid_bulk_modulus} + "solid_bulk_modulus", parameters, 1); + DBUG("Use \'%s\' as solid bulk modulus parameter.", + solid_bulk_modulus.name.c_str()); + + // Specific body force + Eigen::Matrix<double, DisplacementDim, 1> specific_body_force; + { + std::vector<double> const b = + //! \ogs_file_param{prj__processes__process__RICHARDS_MECHANICS__specific_body_force} + config.getConfigParameter<std::vector<double>>( + "specific_body_force"); + if (b.size() != DisplacementDim) + { + OGS_FATAL( + "The size of the specific body force vector does not match the " + "displacement dimension. Vector size is %d, displacement " + "dimension is %d", + b.size(), DisplacementDim); + } + + std::copy_n(b.data(), b.size(), specific_body_force.data()); + } + + auto& temperature = findParameter<double>( + config, + //! \ogs_file_param_special{prj__processes__process__RICHARDS_MECHANICS__temperature} + "temperature", parameters, 1); + + auto const& flow_material_config = + //! \ogs_file_param{prj__processes__process__RICHARDS_MECHANICS__material_property} + config.getConfigSubtree("material_property"); + + boost::optional<MeshLib::PropertyVector<int> const&> material_ids; + if (mesh.getProperties().existsPropertyVector<int>("MaterialIDs")) + { + INFO( + "MaterialIDs vector found; the Richards flow is in heterogeneous " + "porous media."); + material_ids = + *mesh.getProperties().getPropertyVector<int>("MaterialIDs"); + } + else + { + INFO( + "MaterialIDs vector not found; the Richards flow is in homogeneous " + "porous media."); + } + auto flow_material = + ProcessLib::RichardsFlow::createRichardsFlowMaterialProperties( + flow_material_config, material_ids, parameters); + + RichardsMechanicsProcessData<DisplacementDim> process_data{ + std::move(flow_material), + std::move(solid_material), + intrinsic_permeability, + fluid_bulk_modulus, + biot_coefficient, + solid_density, + solid_bulk_modulus, + temperature, + specific_body_force}; + + SecondaryVariableCollection secondary_variables; + + NumLib::NamedFunctionCaller named_function_caller( + {"RichardsMechanics_displacement"}); + + ProcessLib::createSecondaryVariables(config, secondary_variables, + named_function_caller); + + return std::make_unique<RichardsMechanicsProcess<DisplacementDim>>( + mesh, std::move(jacobian_assembler), parameters, integration_order, + std::move(process_variables), std::move(process_data), + std::move(secondary_variables), std::move(named_function_caller), + use_monolithic_scheme); +} + +template std::unique_ptr<Process> createRichardsMechanicsProcess<2>( + MeshLib::Mesh& mesh, + std::unique_ptr<ProcessLib::AbstractJacobianAssembler>&& jacobian_assembler, + std::vector<ProcessVariable> const& variables, + std::vector<std::unique_ptr<ParameterBase>> const& parameters, + unsigned const integration_order, + BaseLib::ConfigTree const& config); + +template std::unique_ptr<Process> createRichardsMechanicsProcess<3>( + MeshLib::Mesh& mesh, + std::unique_ptr<ProcessLib::AbstractJacobianAssembler>&& jacobian_assembler, + std::vector<ProcessVariable> const& variables, + std::vector<std::unique_ptr<ParameterBase>> const& parameters, + unsigned const integration_order, + BaseLib::ConfigTree const& config); + +} // namespace RichardsMechanics +} // namespace ProcessLib diff --git a/ProcessLib/RichardsMechanics/CreateRichardsMechanicsProcess.h b/ProcessLib/RichardsMechanics/CreateRichardsMechanicsProcess.h new file mode 100644 index 00000000000..45c28c1b9a5 --- /dev/null +++ b/ProcessLib/RichardsMechanics/CreateRichardsMechanicsProcess.h @@ -0,0 +1,65 @@ +/** + * \copyright + * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#pragma once + +#include <map> +#include <memory> +#include <vector> + +namespace BaseLib +{ +class ConfigTree; +} +namespace MeshLib +{ +class Mesh; +} +namespace MathLib +{ +class PiecewiseLinearInterpolation; +} +namespace ProcessLib +{ +class AbstractJacobianAssembler; +struct ParameterBase; +class Process; +class ProcessVariable; +} // namespace ProcessLib + +namespace ProcessLib +{ +namespace RichardsMechanics +{ +template <int DisplacementDim> +std::unique_ptr<Process> createRichardsMechanicsProcess( + MeshLib::Mesh& mesh, + std::unique_ptr<ProcessLib::AbstractJacobianAssembler>&& jacobian_assembler, + std::vector<ProcessVariable> const& variables, + std::vector<std::unique_ptr<ParameterBase>> const& parameters, + unsigned const integration_order, + BaseLib::ConfigTree const& config); + +extern template std::unique_ptr<Process> createRichardsMechanicsProcess<2>( + MeshLib::Mesh& mesh, + std::unique_ptr<ProcessLib::AbstractJacobianAssembler>&& jacobian_assembler, + std::vector<ProcessVariable> const& variables, + std::vector<std::unique_ptr<ParameterBase>> const& parameters, + unsigned const integration_order, + BaseLib::ConfigTree const& config); + +extern template std::unique_ptr<Process> createRichardsMechanicsProcess<3>( + MeshLib::Mesh& mesh, + std::unique_ptr<ProcessLib::AbstractJacobianAssembler>&& jacobian_assembler, + std::vector<ProcessVariable> const& variables, + std::vector<std::unique_ptr<ParameterBase>> const& parameters, + unsigned const integration_order, + BaseLib::ConfigTree const& config); +} // namespace RichardsMechanics +} // namespace ProcessLib diff --git a/ProcessLib/RichardsMechanics/IntegrationPointData.h b/ProcessLib/RichardsMechanics/IntegrationPointData.h new file mode 100644 index 00000000000..cc03455f711 --- /dev/null +++ b/ProcessLib/RichardsMechanics/IntegrationPointData.h @@ -0,0 +1,96 @@ +/** + * \copyright + * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#pragma once + +#include <memory> + +#include "MaterialLib/SolidModels/LinearElasticIsotropic.h" +#include "MathLib/KelvinVector.h" +#include "MathLib/LinAlg/Eigen/EigenMapTools.h" + +namespace ProcessLib +{ +namespace RichardsMechanics +{ +template <typename BMatricesType, typename ShapeMatrixTypeDisplacement, + typename ShapeMatricesTypePressure, int DisplacementDim, int NPoints> +struct IntegrationPointData final +{ + explicit IntegrationPointData( + MaterialLib::Solids::MechanicsBase<DisplacementDim>& solid_material) + : solid_material(solid_material), + material_state_variables( + solid_material.createMaterialStateVariables()) + { + // Initialize current time step values + static const int kelvin_vector_size = + MathLib::KelvinVector::KelvinVectorDimensions< + DisplacementDim>::value; + sigma_eff.setZero(kelvin_vector_size); + eps.setZero(kelvin_vector_size); + + // Previous time step values are not initialized and are set later. + eps_prev.resize(kelvin_vector_size); + sigma_eff_prev.resize(kelvin_vector_size); + } + + typename ShapeMatrixTypeDisplacement::template MatrixType< + DisplacementDim, NPoints * DisplacementDim> + N_u_op; + typename BMatricesType::KelvinVectorType sigma_eff, sigma_eff_prev; + typename BMatricesType::KelvinVectorType eps, eps_prev; + + typename ShapeMatrixTypeDisplacement::NodalRowVectorType N_u; + typename ShapeMatrixTypeDisplacement::GlobalDimNodalMatrixType dNdx_u; + + typename ShapeMatricesTypePressure::NodalRowVectorType N_p; + typename ShapeMatricesTypePressure::GlobalDimNodalMatrixType dNdx_p; + + double saturation; + + MaterialLib::Solids::MechanicsBase<DisplacementDim>& solid_material; + std::unique_ptr<typename MaterialLib::Solids::MechanicsBase< + DisplacementDim>::MaterialStateVariables> + material_state_variables; + double integration_weight; + + void pushBackState() + { + eps_prev = eps; + sigma_eff_prev = sigma_eff; + material_state_variables->pushBackState(); + } + + template <typename DisplacementVectorType> + typename BMatricesType::KelvinMatrixType updateConstitutiveRelation( + double const t, + SpatialPosition const& x_position, + double const dt, + DisplacementVectorType const& /*u*/, + double const temperature) + { + auto&& solution = solid_material.integrateStress( + t, x_position, dt, eps_prev, eps, sigma_eff_prev, + *material_state_variables, temperature); + + if (!solution) + OGS_FATAL("Computation of local constitutive relation failed."); + + MathLib::KelvinVector::KelvinMatrixType<DisplacementDim> C; + std::tie(sigma_eff, material_state_variables, C) = std::move(*solution); + + return C; + } + + EIGEN_MAKE_ALIGNED_OPERATOR_NEW; +}; + +} // namespace RichardsMechanics +} // namespace ProcessLib diff --git a/ProcessLib/RichardsMechanics/LocalAssemblerInterface.h b/ProcessLib/RichardsMechanics/LocalAssemblerInterface.h new file mode 100644 index 00000000000..d16c6081a3e --- /dev/null +++ b/ProcessLib/RichardsMechanics/LocalAssemblerInterface.h @@ -0,0 +1,48 @@ +/** + * \copyright + * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#pragma once + +#include "NumLib/Extrapolation/ExtrapolatableElement.h" +#include "ProcessLib/LocalAssemblerInterface.h" + +namespace ProcessLib +{ +namespace RichardsMechanics +{ +struct LocalAssemblerInterface : public ProcessLib::LocalAssemblerInterface, + public NumLib::ExtrapolatableElement +{ + virtual std::vector<double> const& getIntPtSigma( + const double /*t*/, + GlobalVector const& /*current_solution*/, + NumLib::LocalToGlobalIndexMap const& /*dof_table*/, + std::vector<double>& cache) const = 0; + + virtual std::vector<double> const& getIntPtEpsilon( + const double /*t*/, + GlobalVector const& /*current_solution*/, + NumLib::LocalToGlobalIndexMap const& /*dof_table*/, + std::vector<double>& cache) const = 0; + + virtual std::vector<double> const& getIntPtDarcyVelocity( + const double /*t*/, + GlobalVector const& /*current_solution*/, + NumLib::LocalToGlobalIndexMap const& /*dof_table*/, + std::vector<double>& cache) const = 0; + + virtual std::vector<double> const& getIntPtSaturation( + const double /*t*/, + GlobalVector const& /*current_solution*/, + NumLib::LocalToGlobalIndexMap const& /*dof_table*/, + std::vector<double>& cache) const = 0; +}; + +} // namespace RichardsMechanics +} // namespace ProcessLib diff --git a/ProcessLib/RichardsMechanics/LocalDataInitializer.h b/ProcessLib/RichardsMechanics/LocalDataInitializer.h new file mode 100644 index 00000000000..f7cfc1dee1c --- /dev/null +++ b/ProcessLib/RichardsMechanics/LocalDataInitializer.h @@ -0,0 +1,289 @@ +/** + * \copyright + * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#pragma once + +#include <functional> +#include <memory> +#include <type_traits> +#include <typeindex> +#include <typeinfo> +#include <unordered_map> + +#include "MeshLib/Elements/Elements.h" +#include "NumLib/DOF/LocalToGlobalIndexMap.h" +#include "NumLib/Fem/FiniteElement/LowerDimShapeTable.h" +#include "NumLib/Fem/Integration/GaussLegendreIntegrationPolicy.h" + +#ifndef OGS_MAX_ELEMENT_DIM +static_assert(false, "The macro OGS_MAX_ELEMENT_DIM is undefined."); +#endif + +#ifndef OGS_MAX_ELEMENT_ORDER +static_assert(false, "The macro OGS_MAX_ELEMENT_ORDER is undefined."); +#endif + +// The following macros decide which element types will be compiled, i.e. +// which element types will be available for use in simulations. + +#ifdef OGS_ENABLE_ELEMENT_SIMPLEX +#define ENABLED_ELEMENT_TYPE_SIMPLEX 1u +#else +#define ENABLED_ELEMENT_TYPE_SIMPLEX 0u +#endif + +#ifdef OGS_ENABLE_ELEMENT_CUBOID +#define ENABLED_ELEMENT_TYPE_CUBOID 1u << 1 +#else +#define ENABLED_ELEMENT_TYPE_CUBOID 0u +#endif + +#ifdef OGS_ENABLE_ELEMENT_PRISM +#define ENABLED_ELEMENT_TYPE_PRISM 1u << 2 +#else +#define ENABLED_ELEMENT_TYPE_PRISM 0u +#endif + +#ifdef OGS_ENABLE_ELEMENT_PYRAMID +#define ENABLED_ELEMENT_TYPE_PYRAMID 1u << 3 +#else +#define ENABLED_ELEMENT_TYPE_PYRAMID 0u +#endif + +// Dependent element types. +// Faces of tets, pyramids and prisms are triangles +#define ENABLED_ELEMENT_TYPE_TRI \ + ((ENABLED_ELEMENT_TYPE_SIMPLEX) | (ENABLED_ELEMENT_TYPE_PYRAMID) | \ + (ENABLED_ELEMENT_TYPE_PRISM)) +// Faces of hexes, pyramids and prisms are quads +#define ENABLED_ELEMENT_TYPE_QUAD \ + ((ENABLED_ELEMENT_TYPE_CUBOID) | (ENABLED_ELEMENT_TYPE_PYRAMID) | \ + (ENABLED_ELEMENT_TYPE_PRISM)) + +// All enabled element types +#define OGS_ENABLED_ELEMENTS \ + ((ENABLED_ELEMENT_TYPE_SIMPLEX) | (ENABLED_ELEMENT_TYPE_CUBOID) | \ + (ENABLED_ELEMENT_TYPE_PYRAMID) | (ENABLED_ELEMENT_TYPE_PRISM)) + +// Include only what is needed (Well, the conditions are not sharp). +#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_SIMPLEX) != 0 +#include "NumLib/Fem/ShapeFunction/ShapeTet10.h" +#include "NumLib/Fem/ShapeFunction/ShapeTet4.h" +#endif + +#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_TRI) != 0 +#include "NumLib/Fem/ShapeFunction/ShapeTri3.h" +#include "NumLib/Fem/ShapeFunction/ShapeTri6.h" +#endif + +#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_CUBOID) != 0 +#include "NumLib/Fem/ShapeFunction/ShapeHex20.h" +#include "NumLib/Fem/ShapeFunction/ShapeHex8.h" +#endif + +#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_QUAD) != 0 +#include "NumLib/Fem/ShapeFunction/ShapeQuad4.h" +#include "NumLib/Fem/ShapeFunction/ShapeQuad8.h" +#include "NumLib/Fem/ShapeFunction/ShapeQuad9.h" +#endif + +#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_PRISM) != 0 +#include "NumLib/Fem/ShapeFunction/ShapePrism15.h" +#include "NumLib/Fem/ShapeFunction/ShapePrism6.h" +#endif + +#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_PYRAMID) != 0 +#include "NumLib/Fem/ShapeFunction/ShapePyra13.h" +#include "NumLib/Fem/ShapeFunction/ShapePyra5.h" +#endif + +namespace ProcessLib +{ +namespace RichardsMechanics +{ +/// The LocalDataInitializer is a functor creating a local assembler data with +/// corresponding to the mesh element type shape functions and calling +/// initialization of the new local assembler data. +/// For example for MeshLib::Quad a local assembler data with template argument +/// NumLib::ShapeQuad4 is created. +/// +/// \attention This is modified version of the ProcessLib::LocalDataInitializer +/// class which does not include line elements, allows only shapefunction of +/// order 2. +template <typename LocalAssemblerInterface, + template <typename, typename, typename, int> + class RichardsMechanicsLocalAssembler, + int GlobalDim, typename... ConstructorArgs> +class LocalDataInitializer final +{ +public: + using LADataIntfPtr = std::unique_ptr<LocalAssemblerInterface>; + + LocalDataInitializer(NumLib::LocalToGlobalIndexMap const& dof_table, + const unsigned shapefunction_order) + : _dof_table(dof_table) + { + if (shapefunction_order != 2) + OGS_FATAL( + "The given shape function order %d is not supported.\nOnly " + "shape functions of order 2 are supported.", + shapefunction_order); + // /// Quads and Hexahedra /////////////////////////////////// + +#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_QUAD) != 0 && \ + OGS_MAX_ELEMENT_DIM >= 2 && OGS_MAX_ELEMENT_ORDER >= 2 + _builder[std::type_index(typeid(MeshLib::Quad8))] = + makeLocalAssemblerBuilder<NumLib::ShapeQuad8>(); + _builder[std::type_index(typeid(MeshLib::Quad9))] = + makeLocalAssemblerBuilder<NumLib::ShapeQuad9>(); +#endif + +#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_CUBOID) != 0 && \ + OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 2 + _builder[std::type_index(typeid(MeshLib::Hex20))] = + makeLocalAssemblerBuilder<NumLib::ShapeHex20>(); +#endif + + // /// Simplices //////////////////////////////////////////////// + +#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_TRI) != 0 && \ + OGS_MAX_ELEMENT_DIM >= 2 && OGS_MAX_ELEMENT_ORDER >= 2 + _builder[std::type_index(typeid(MeshLib::Tri6))] = + makeLocalAssemblerBuilder<NumLib::ShapeTri6>(); +#endif + +#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_SIMPLEX) != 0 && \ + OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 2 + _builder[std::type_index(typeid(MeshLib::Tet10))] = + makeLocalAssemblerBuilder<NumLib::ShapeTet10>(); +#endif + + // /// Prisms //////////////////////////////////////////////////// + +#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_PRISM) != 0 && \ + OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 2 + _builder[std::type_index(typeid(MeshLib::Prism15))] = + makeLocalAssemblerBuilder<NumLib::ShapePrism15>(); +#endif + + // /// Pyramids ////////////////////////////////////////////////// + +#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_PYRAMID) != 0 && \ + OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 2 + _builder[std::type_index(typeid(MeshLib::Pyramid13))] = + makeLocalAssemblerBuilder<NumLib::ShapePyra13>(); +#endif + } + + /// Sets the provided \c data_ptr to the newly created local assembler data. + /// + /// \attention + /// The index \c id is not necessarily the mesh item's id. Especially when + /// having multiple meshes it will differ from the latter. + void operator()(std::size_t const id, + MeshLib::Element const& mesh_item, + LADataIntfPtr& data_ptr, + ConstructorArgs&&... args) const + { + auto const type_idx = std::type_index(typeid(mesh_item)); + auto const it = _builder.find(type_idx); + + if (it != _builder.end()) + { + auto const num_local_dof = _dof_table.getNumberOfElementDOF(id); + data_ptr = it->second(mesh_item, num_local_dof, + std::forward<ConstructorArgs>(args)...); + } + else + { + OGS_FATAL( + "You are trying to build a local assembler for an unknown mesh " + "element type (%s)." + " Maybe you have disabled this mesh element type in your build " + "configuration or this process requires higher order elements.", + type_idx.name()); + } + } + +private: + using LADataBuilder = + std::function<LADataIntfPtr(MeshLib::Element const& e, + std::size_t const local_matrix_size, + ConstructorArgs&&...)>; + + template <typename ShapeFunctionDisplacement> + using IntegrationMethod = typename NumLib::GaussLegendreIntegrationPolicy< + typename ShapeFunctionDisplacement::MeshElement>::IntegrationMethod; + + template <typename ShapeFunctionDisplacement, + typename ShapeFunctionPressure> + using LAData = RichardsMechanicsLocalAssembler< + ShapeFunctionDisplacement, ShapeFunctionPressure, + IntegrationMethod<ShapeFunctionDisplacement>, GlobalDim>; + + /// A helper forwarding to the correct version of makeLocalAssemblerBuilder + /// depending whether the global dimension is less than the shape function's + /// dimension or not. + template <typename ShapeFunctionDisplacement> + static LADataBuilder makeLocalAssemblerBuilder() + { + return makeLocalAssemblerBuilder<ShapeFunctionDisplacement>( + static_cast<std::integral_constant< + bool, (GlobalDim >= ShapeFunctionDisplacement::DIM)>*>( + nullptr)); + } + + /// Mapping of element types to local assembler constructors. + std::unordered_map<std::type_index, LADataBuilder> _builder; + + NumLib::LocalToGlobalIndexMap const& _dof_table; + + // local assembler builder implementations. +private: + /// Generates a function that creates a new LocalAssembler of type + /// LAData<ShapeFunctionDisplacement>. Only functions with shape function's + /// dimension less or equal to the global dimension are instantiated, e.g. + /// following combinations of shape functions and global dimensions: (Line2, + /// 1), + /// (Line2, 2), (Line2, 3), (Hex20, 3) but not (Hex20, 2) or (Hex20, 1). + template <typename ShapeFunctionDisplacement> + static LADataBuilder makeLocalAssemblerBuilder(std::true_type*) + { + // (Lower order elements = Order(ShapeFunctionDisplacement) - 1). + using ShapeFunctionPressure = + typename NumLib::LowerDim<ShapeFunctionDisplacement>::type; + return [](MeshLib::Element const& e, + std::size_t const local_matrix_size, + ConstructorArgs&&... args) { + return LADataIntfPtr{ + new LAData<ShapeFunctionDisplacement, ShapeFunctionPressure>{ + e, local_matrix_size, + std::forward<ConstructorArgs>(args)...}}; + }; + } + + /// Returns nullptr for shape functions whose dimensions are less than the + /// global dimension. + template <typename ShapeFunctionDisplacement> + static LADataBuilder makeLocalAssemblerBuilder(std::false_type*) + { + return nullptr; + } +}; + +} // namespace RichardsMechanics +} // namespace ProcessLib + +#undef ENABLED_ELEMENT_TYPE_SIMPLEX +#undef ENABLED_ELEMENT_TYPE_CUBOID +#undef ENABLED_ELEMENT_TYPE_PYRAMID +#undef ENABLED_ELEMENT_TYPE_PRISM +#undef ENABLED_ELEMENT_TYPE_TRI +#undef ENABLED_ELEMENT_TYPE_QUAD +#undef OGS_ENABLED_ELEMENTS diff --git a/ProcessLib/RichardsMechanics/RichardsMechanicsFEM-impl.h b/ProcessLib/RichardsMechanics/RichardsMechanicsFEM-impl.h new file mode 100644 index 00000000000..5d6f227360b --- /dev/null +++ b/ProcessLib/RichardsMechanics/RichardsMechanicsFEM-impl.h @@ -0,0 +1,833 @@ +/** + * \copyright + * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + * \file RichardsMechanicsFEM-impl.h + * Created on November 29, 2017, 2:03 PM + */ + +#pragma once + +#include "RichardsMechanicsFEM.h" + +#include "MathLib/KelvinVector.h" +#include "NumLib/Function/Interpolation.h" +#include "ProcessLib/CoupledSolutionsForStaggeredScheme.h" + +namespace ProcessLib +{ +namespace RichardsMechanics +{ +template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, + typename IntegrationMethod, int DisplacementDim> +RichardsMechanicsLocalAssembler<ShapeFunctionDisplacement, + ShapeFunctionPressure, IntegrationMethod, + DisplacementDim>:: + RichardsMechanicsLocalAssembler( + MeshLib::Element const& e, + std::size_t const /*local_matrix_size*/, + bool const is_axially_symmetric, + unsigned const integration_order, + RichardsMechanicsProcessData<DisplacementDim>& process_data) + : _process_data(process_data), + _integration_method(integration_order), + _element(e), + _is_axially_symmetric(is_axially_symmetric) +{ + unsigned const n_integration_points = + _integration_method.getNumberOfPoints(); + + _ip_data.reserve(n_integration_points); + _secondary_data.N_u.resize(n_integration_points); + + auto const shape_matrices_u = + initShapeMatrices<ShapeFunctionDisplacement, + ShapeMatricesTypeDisplacement, IntegrationMethod, + DisplacementDim>(e, is_axially_symmetric, + _integration_method); + + auto const shape_matrices_p = + initShapeMatrices<ShapeFunctionPressure, ShapeMatricesTypePressure, + IntegrationMethod, DisplacementDim>( + e, is_axially_symmetric, _integration_method); + + for (unsigned ip = 0; ip < n_integration_points; ip++) + { + // displacement (subscript u) + _ip_data.emplace_back(*_process_data.solid_material); + auto& ip_data = _ip_data[ip]; + auto const& sm_u = shape_matrices_u[ip]; + _ip_data[ip].integration_weight = + _integration_method.getWeightedPoint(ip).getWeight() * + sm_u.integralMeasure * sm_u.detJ; + + ip_data.N_u_op = ShapeMatricesTypeDisplacement::template MatrixType< + DisplacementDim, displacement_size>::Zero(DisplacementDim, + displacement_size); + for (int i = 0; i < DisplacementDim; ++i) + ip_data.N_u_op + .template block<1, displacement_size / DisplacementDim>( + i, i * displacement_size / DisplacementDim) + .noalias() = sm_u.N; + + ip_data.N_u = sm_u.N; + ip_data.dNdx_u = sm_u.dNdx; + + ip_data.N_p = shape_matrices_p[ip].N; + ip_data.dNdx_p = shape_matrices_p[ip].dNdx; + + _secondary_data.N_u[ip] = shape_matrices_u[ip].N; + } +} + +template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, + typename IntegrationMethod, int DisplacementDim> +void RichardsMechanicsLocalAssembler< + ShapeFunctionDisplacement, ShapeFunctionPressure, IntegrationMethod, + DisplacementDim>::assemble(double const t, + std::vector<double> const& local_x, + std::vector<double>& local_M_data, + std::vector<double>& local_K_data, + std::vector<double>& local_rhs_data) +{ + assert(local_x.size() == pressure_size + displacement_size); + + auto p_L = + Eigen::Map<typename ShapeMatricesTypePressure::template VectorType< + pressure_size> const>(local_x.data() + pressure_index, + pressure_size); + + auto u = + Eigen::Map<typename ShapeMatricesTypeDisplacement::template VectorType< + displacement_size> const>(local_x.data() + displacement_index, + displacement_size); + + auto K = MathLib::createZeroedMatrix< + typename ShapeMatricesTypeDisplacement::template MatrixType< + displacement_size + pressure_size, + displacement_size + pressure_size>>( + local_K_data, displacement_size + pressure_size, + displacement_size + pressure_size); + + auto M = MathLib::createZeroedMatrix< + typename ShapeMatricesTypeDisplacement::template MatrixType< + displacement_size + pressure_size, + displacement_size + pressure_size>>( + local_M_data, displacement_size + pressure_size, + displacement_size + pressure_size); + + auto rhs = MathLib::createZeroedVector< + typename ShapeMatricesTypeDisplacement::template VectorType< + displacement_size + pressure_size>>( + local_rhs_data, displacement_size + pressure_size); + + double const& dt = _process_data.dt; + auto const material_id = + _process_data.flow_material->getMaterialID(_element.getID()); + + SpatialPosition x_position; + x_position.setElementID(_element.getID()); + + unsigned const n_integration_points = + _integration_method.getNumberOfPoints(); + for (unsigned ip = 0; ip < n_integration_points; ip++) + { + x_position.setIntegrationPoint(ip); + auto const& w = _ip_data[ip].integration_weight; + + auto const& N_u_op = _ip_data[ip].N_u_op; + + auto const& N_u = _ip_data[ip].N_u; + auto const& dNdx_u = _ip_data[ip].dNdx_u; + + auto const& N_p = _ip_data[ip].N_p; + auto const& dNdx_p = _ip_data[ip].dNdx_p; + + auto const x_coord = + interpolateXCoordinate<ShapeFunctionDisplacement, + ShapeMatricesTypeDisplacement>(_element, + N_u); + auto const B = + LinearBMatrix::computeBMatrix<DisplacementDim, + ShapeFunctionDisplacement::NPOINTS, + typename BMatricesType::BMatrixType>( + dNdx_u, N_u, x_coord, _is_axially_symmetric); + + double p_cap_ip; + NumLib::shapeFunctionInterpolate(-p_L, N_p, p_cap_ip); + + auto& eps = _ip_data[ip].eps; + auto& S_L = _ip_data[ip].saturation; + + auto const alpha = _process_data.biot_coefficient(t, x_position)[0]; + auto const rho_SR = _process_data.solid_density(t, x_position)[0]; + auto const K_SR = _process_data.solid_bulk_modulus(t, x_position)[0]; + auto const K_LR = _process_data.fluid_bulk_modulus(t, x_position)[0]; + auto const temperature = _process_data.temperature(t, x_position)[0]; + auto const porosity = _process_data.flow_material->getPorosity( + material_id, t, x_position, -p_cap_ip, temperature, p_cap_ip); + auto const rho_LR = _process_data.flow_material->getFluidDensity( + -p_cap_ip, temperature); + auto const& b = _process_data.specific_body_force; + auto const& identity2 = MathLib::KelvinVector::Invariants< + MathLib::KelvinVector::KelvinVectorDimensions< + DisplacementDim>::value>::identity2; + + S_L = _process_data.flow_material->getSaturation( + material_id, t, x_position, -p_cap_ip, temperature, p_cap_ip); + + double const dS_L_dp_cap = + _process_data.flow_material->getSaturationDerivative( + material_id, t, x_position, -p_cap_ip, temperature, S_L); + + double const k_rel = + _process_data.flow_material->getRelativePermeability( + t, x_position, -p_cap_ip, temperature, S_L); + auto const mu = _process_data.flow_material->getFluidViscosity( + -p_cap_ip, temperature); + + double const K_intrinsic = + _process_data.intrinsic_permeability(t, x_position)[0]; + double const K_over_mu = K_intrinsic / mu; + + // + // displacement equation, displacement part + // + eps.noalias() = B * u; + + auto C = _ip_data[ip].updateConstitutiveRelation(t, x_position, dt, u, + temperature); + + // + // displacement equation, displacement part + // + K.template block<displacement_size, displacement_size>( + displacement_index, displacement_index) + .noalias() += B.transpose() * C * B * w; + + double const rho = rho_SR * (1 - porosity) + porosity * rho_LR; + rhs.template segment<displacement_size>(displacement_index).noalias() += + N_u_op.transpose() * rho * b * w; + + // + // pressure equation, pressure part. + // + double const a0 = S_L * (alpha - porosity) / K_SR; + // Volumetric average specific storage of the solid and fluid phases. + double const specific_storage = + dS_L_dp_cap * (p_cap_ip * a0 - porosity) + + S_L * (porosity / K_LR + a0); + M.template block<pressure_size, pressure_size>(pressure_index, + pressure_index) + .noalias() += N_p.transpose() * rho_LR * specific_storage * N_p * w; + + K.template block<pressure_size, pressure_size>(pressure_index, + pressure_index) + .noalias() += + dNdx_p.transpose() * rho_LR * k_rel * K_over_mu * dNdx_p * w; + + rhs.template segment<pressure_size>(pressure_index).noalias() += + dNdx_p.transpose() * rho_LR * rho_LR * k_rel * K_over_mu * b * w; + + // + // displacement equation, pressure part + // + K.template block<displacement_size, pressure_size>(displacement_index, + pressure_index) + .noalias() -= B.transpose() * alpha * S_L * identity2 * N_p * w; + + // + // pressure equation, displacement part. + // + M.template block<pressure_size, displacement_size>(pressure_index, + displacement_index) + .noalias() += N_p.transpose() * S_L * rho_LR * alpha * + identity2.transpose() * B * w; + } +} + +template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, + typename IntegrationMethod, int DisplacementDim> +void RichardsMechanicsLocalAssembler<ShapeFunctionDisplacement, + ShapeFunctionPressure, IntegrationMethod, + DisplacementDim>:: + assembleWithJacobian(double const t, std::vector<double> const& local_x, + std::vector<double> const& local_xdot, + const double /*dxdot_dx*/, const double /*dx_dx*/, + std::vector<double>& /*local_M_data*/, + std::vector<double>& /*local_K_data*/, + std::vector<double>& local_rhs_data, + std::vector<double>& local_Jac_data) +{ + assert(local_x.size() == pressure_size + displacement_size); + + auto p_L = + Eigen::Map<typename ShapeMatricesTypePressure::template VectorType< + pressure_size> const>(local_x.data() + pressure_index, + pressure_size); + + auto u = + Eigen::Map<typename ShapeMatricesTypeDisplacement::template VectorType< + displacement_size> const>(local_x.data() + displacement_index, + displacement_size); + + auto p_L_dot = + Eigen::Map<typename ShapeMatricesTypePressure::template VectorType< + pressure_size> const>(local_xdot.data() + pressure_index, + pressure_size); + auto u_dot = + Eigen::Map<typename ShapeMatricesTypeDisplacement::template VectorType< + displacement_size> const>(local_xdot.data() + displacement_index, + displacement_size); + + auto local_Jac = MathLib::createZeroedMatrix< + typename ShapeMatricesTypeDisplacement::template MatrixType< + displacement_size + pressure_size, + displacement_size + pressure_size>>( + local_Jac_data, displacement_size + pressure_size, + displacement_size + pressure_size); + + auto local_rhs = MathLib::createZeroedVector< + typename ShapeMatricesTypeDisplacement::template VectorType< + displacement_size + pressure_size>>( + local_rhs_data, displacement_size + pressure_size); + + typename ShapeMatricesTypePressure::NodalMatrixType laplace_p = + ShapeMatricesTypePressure::NodalMatrixType::Zero(pressure_size, + pressure_size); + + typename ShapeMatricesTypePressure::NodalMatrixType storage_p = + ShapeMatricesTypePressure::NodalMatrixType::Zero(pressure_size, + pressure_size); + + typename ShapeMatricesTypeDisplacement::template MatrixType< + displacement_size, pressure_size> + Kup = ShapeMatricesTypeDisplacement::template MatrixType< + displacement_size, pressure_size>::Zero(displacement_size, + pressure_size); + + typename ShapeMatricesTypeDisplacement::template MatrixType< + pressure_size, displacement_size> + Kpu = ShapeMatricesTypeDisplacement::template MatrixType< + pressure_size, displacement_size>::Zero(pressure_size, + displacement_size); + + double const& dt = _process_data.dt; + auto const material_id = + _process_data.flow_material->getMaterialID(_element.getID()); + + SpatialPosition x_position; + x_position.setElementID(_element.getID()); + + unsigned const n_integration_points = + _integration_method.getNumberOfPoints(); + for (unsigned ip = 0; ip < n_integration_points; ip++) + { + x_position.setIntegrationPoint(ip); + auto const& w = _ip_data[ip].integration_weight; + + auto const& N_u_op = _ip_data[ip].N_u_op; + + auto const& N_u = _ip_data[ip].N_u; + auto const& dNdx_u = _ip_data[ip].dNdx_u; + + auto const& N_p = _ip_data[ip].N_p; + auto const& dNdx_p = _ip_data[ip].dNdx_p; + + auto const x_coord = + interpolateXCoordinate<ShapeFunctionDisplacement, + ShapeMatricesTypeDisplacement>(_element, + N_u); + auto const B = + LinearBMatrix::computeBMatrix<DisplacementDim, + ShapeFunctionDisplacement::NPOINTS, + typename BMatricesType::BMatrixType>( + dNdx_u, N_u, x_coord, _is_axially_symmetric); + + double p_cap_ip; + NumLib::shapeFunctionInterpolate(-p_L, N_p, p_cap_ip); + + double p_cap_dot_ip; + NumLib::shapeFunctionInterpolate(-p_L_dot, N_p, p_cap_dot_ip); + + typename ShapeMatricesTypeDisplacement::GlobalDimVectorType u_ip( + DisplacementDim); + for (int i = 0; i < u_ip.size(); ++i) + { + NumLib::shapeFunctionInterpolate( + u.segment(i * ShapeFunctionDisplacement::NPOINTS, + ShapeFunctionDisplacement::NPOINTS), + N_u, u_ip.coeffRef(i)); + } + + auto& eps = _ip_data[ip].eps; + auto& S_L = _ip_data[ip].saturation; + auto const& sigma_eff = _ip_data[ip].sigma_eff; + + auto const alpha = _process_data.biot_coefficient(t, x_position)[0]; + auto const rho_SR = _process_data.solid_density(t, x_position)[0]; + auto const K_SR = _process_data.solid_bulk_modulus(t, x_position)[0]; + auto const K_LR = _process_data.fluid_bulk_modulus(t, x_position)[0]; + auto const temperature = _process_data.temperature(t, x_position)[0]; + + auto const porosity = _process_data.flow_material->getPorosity( + material_id, t, x_position, -p_cap_ip, temperature, p_cap_ip); + auto const rho_LR = _process_data.flow_material->getFluidDensity( + -p_cap_ip, temperature); + auto const& b = _process_data.specific_body_force; + auto const& identity2 = MathLib::KelvinVector::Invariants< + MathLib::KelvinVector::KelvinVectorDimensions< + DisplacementDim>::value>::identity2; + + S_L = _process_data.flow_material->getSaturation( + material_id, t, x_position, -p_cap_ip, temperature, p_cap_ip); + + double const dS_L_dp_cap = + _process_data.flow_material->getSaturationDerivative( + material_id, t, x_position, -p_cap_ip, temperature, S_L); + + double const d2S_L_dp_cap_2 = + _process_data.flow_material->getSaturationDerivative2( + material_id, t, x_position, -p_cap_ip, temperature, S_L); + + double const k_rel = + _process_data.flow_material->getRelativePermeability( + t, x_position, -p_cap_ip, temperature, S_L); + auto const mu = _process_data.flow_material->getFluidViscosity( + -p_cap_ip, temperature); + + double const K_intrinsic = + _process_data.intrinsic_permeability(t, x_position)[0]; + double const K_over_mu = K_intrinsic / mu; + // + // displacement equation, displacement part + // + eps.noalias() = B * u; + + auto C = _ip_data[ip].updateConstitutiveRelation(t, x_position, dt, u, + temperature); + + local_Jac + .template block<displacement_size, displacement_size>( + displacement_index, displacement_index) + .noalias() += B.transpose() * C * B * w; + + double const rho = rho_SR * (1 - porosity) + porosity * rho_LR; + local_rhs.template segment<displacement_size>(displacement_index) + .noalias() -= + (B.transpose() * sigma_eff - N_u_op.transpose() * rho * b) * w; + + // + // displacement equation, pressure part + // + Kup.noalias() += B.transpose() * alpha * S_L * identity2 * N_p * w; + + /* For future implementation including swelling. + double const dsigma_eff_dp_cap = -K_intrinsic * m_swell * n * + std::pow(S_L, n - 1) * dS_L_dp_cap * + identity2; + local_Jac + .template block<displacement_size, pressure_size>( + displacement_index, pressure_index) + .noalias() -= B.transpose() * dsigma_eff_dp_cap * N_p * w; + */ + + local_Jac + .template block<displacement_size, pressure_size>( + displacement_index, pressure_index) + .noalias() -= B.transpose() * alpha * + (S_L + p_cap_ip * dS_L_dp_cap) * identity2 * N_p * w; + + local_Jac + .template block<displacement_size, pressure_size>( + displacement_index, pressure_index) + .noalias() += + N_u_op.transpose() * porosity * rho_LR * dS_L_dp_cap * b * N_p * w; + // + // pressure equation, displacement part. + // + Kpu.noalias() += N_p.transpose() * S_L * rho_LR * alpha * + identity2.transpose() * B * w; + + // + // pressure equation, pressure part. + // + laplace_p.noalias() += + dNdx_p.transpose() * rho_LR * k_rel * K_over_mu * dNdx_p * w; + + double const a0 = (alpha - porosity) / K_SR; + double const specific_storage = + dS_L_dp_cap * (p_cap_ip * S_L * a0 - porosity) + + S_L * (porosity / K_LR + S_L * a0); + + double const dspecific_storage_dp_cap = + d2S_L_dp_cap_2 * (p_cap_ip * S_L * a0 - porosity) + + dS_L_dp_cap * + (porosity / K_LR + a0 * 3 * S_L + dS_L_dp_cap * p_cap_ip * a0); + + storage_p.noalias() += + N_p.transpose() * rho_LR * specific_storage * N_p * w; + + local_Jac + .template block<pressure_size, pressure_size>(pressure_index, + pressure_index) + .noalias() += N_p.transpose() * rho_LR * p_cap_dot_ip * + dspecific_storage_dp_cap * N_p * w; + + /* In the derivation there is a div(du/dt) term in the Jacobian, but + * this implementation increases the total runtime by 1%. Maybe a very + * large step is needed to see the increase of efficiency. + double div_u_dot = 0; + for (int i = 0; i < DisplacementDim; ++i) + { + div_u_dot += + (dNdx_u * + u_dot.template segment<ShapeFunctionDisplacement::NPOINTS>( + i * ShapeFunctionDisplacement::NPOINTS))[i]; + } + local_Jac + .template block<pressure_size, pressure_size>(pressure_index, + pressure_index) + .noalias() -= N_p.transpose() * rho_LR * dS_L_dp_cap * alpha * + div_u_dot * N_p * w; + */ + + double const dk_rel_dS_l = + _process_data.flow_material->getRelativePermeabilityDerivative( + t, x_position, -p_cap_ip, temperature, S_L); + typename ShapeMatricesTypeDisplacement::GlobalDimVectorType const + grad_p_cap = -dNdx_p * p_L; + local_Jac + .template block<pressure_size, pressure_size>(pressure_index, + pressure_index) + .noalias() += dNdx_p.transpose() * rho_LR * K_over_mu * grad_p_cap * + dk_rel_dS_l * dS_L_dp_cap * N_p * w; + + local_Jac + .template block<pressure_size, pressure_size>(pressure_index, + pressure_index) + .noalias() += dNdx_p.transpose() * rho_LR * rho_LR * K_over_mu * b * + dk_rel_dS_l * dS_L_dp_cap * N_p * w; + + local_rhs.template segment<pressure_size>(pressure_index).noalias() += + dNdx_p.transpose() * rho_LR * rho_LR * k_rel * K_over_mu * b * w; + } + + // pressure equation, pressure part. + local_Jac + .template block<pressure_size, pressure_size>(pressure_index, + pressure_index) + .noalias() += laplace_p + storage_p / dt; + + // pressure equation, displacement part. + local_Jac + .template block<pressure_size, displacement_size>(pressure_index, + displacement_index) + .noalias() = Kpu / dt; + + // pressure equation + local_rhs.template segment<pressure_size>(pressure_index).noalias() -= + laplace_p * p_L + storage_p * p_L_dot + Kpu * u_dot; + + // displacement equation + local_rhs.template segment<displacement_size>(displacement_index) + .noalias() += Kup * p_L; +} + +template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, + typename IntegrationMethod, int DisplacementDim> +std::vector<double> const& RichardsMechanicsLocalAssembler< + ShapeFunctionDisplacement, ShapeFunctionPressure, IntegrationMethod, + DisplacementDim>:: + getIntPtSigma(const double /*t*/, + GlobalVector const& /*current_solution*/, + NumLib::LocalToGlobalIndexMap const& /*dof_table*/, + std::vector<double>& cache) const +{ + static const int kelvin_vector_size = + MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; + auto const num_intpts = _ip_data.size(); + + cache.clear(); + auto cache_mat = MathLib::createZeroedMatrix<Eigen::Matrix< + double, kelvin_vector_size, Eigen::Dynamic, Eigen::RowMajor>>( + cache, kelvin_vector_size, num_intpts); + + for (unsigned ip = 0; ip < num_intpts; ++ip) + { + auto const& sigma = _ip_data[ip].sigma_eff; + cache_mat.col(ip) = + MathLib::KelvinVector::kelvinVectorToSymmetricTensor(sigma); + } + + return cache; +} + +template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, + typename IntegrationMethod, int DisplacementDim> +std::vector<double> const& RichardsMechanicsLocalAssembler< + ShapeFunctionDisplacement, ShapeFunctionPressure, IntegrationMethod, + DisplacementDim>:: + getIntPtEpsilon(const double /*t*/, + GlobalVector const& /*current_solution*/, + NumLib::LocalToGlobalIndexMap const& /*dof_table*/, + std::vector<double>& cache) const +{ + auto const kelvin_vector_size = + MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; + auto const num_intpts = _ip_data.size(); + + cache.clear(); + auto cache_mat = MathLib::createZeroedMatrix<Eigen::Matrix< + double, kelvin_vector_size, Eigen::Dynamic, Eigen::RowMajor>>( + cache, kelvin_vector_size, num_intpts); + + for (unsigned ip = 0; ip < num_intpts; ++ip) + { + auto const& eps = _ip_data[ip].eps; + cache_mat.col(ip) = + MathLib::KelvinVector::kelvinVectorToSymmetricTensor(eps); + } + + return cache; +} +template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, + typename IntegrationMethod, int DisplacementDim> +std::vector<double> const& RichardsMechanicsLocalAssembler< + ShapeFunctionDisplacement, ShapeFunctionPressure, IntegrationMethod, + DisplacementDim>::getIntPtDarcyVelocity(const double t, + GlobalVector const& + current_solution, + NumLib::LocalToGlobalIndexMap const& + dof_table, + std::vector<double>& cache) const +{ + auto const num_intpts = _ip_data.size(); + + auto const indices = NumLib::getIndices(_element.getID(), dof_table); + assert(!indices.empty()); + auto const local_x = current_solution.get(indices); + + cache.clear(); + auto cache_matrix = MathLib::createZeroedMatrix<Eigen::Matrix< + double, DisplacementDim, Eigen::Dynamic, Eigen::RowMajor>>( + cache, DisplacementDim, num_intpts); + + auto p_L = + Eigen::Map<typename ShapeMatricesTypePressure::template VectorType< + pressure_size> const>(local_x.data() + pressure_index, + pressure_size); + + unsigned const n_integration_points = + _integration_method.getNumberOfPoints(); + + SpatialPosition x_position; + x_position.setElementID(_element.getID()); + for (unsigned ip = 0; ip < n_integration_points; ip++) + { + x_position.setIntegrationPoint(ip); + auto const& N_p = _ip_data[ip].N_p; + + double p_cap_ip; + NumLib::shapeFunctionInterpolate(-p_L, N_p, p_cap_ip); + + auto const temperature = _process_data.temperature(t, x_position)[0]; + auto const mu = _process_data.flow_material->getFluidViscosity( + -p_cap_ip, temperature); + double const K_over_mu = + _process_data.intrinsic_permeability(t, x_position)[0] / mu; + auto const rho_LR = _process_data.flow_material->getFluidDensity( + -p_cap_ip, temperature); + auto const& b = _process_data.specific_body_force; + + // Compute the velocity + auto const& dNdx_p = _ip_data[ip].dNdx_p; + cache_matrix.col(ip).noalias() = + -K_over_mu * dNdx_p * p_L - K_over_mu * rho_LR * b; + } + + return cache; +} + +template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, + typename IntegrationMethod, int DisplacementDim> +std::vector<double> const& RichardsMechanicsLocalAssembler< + ShapeFunctionDisplacement, ShapeFunctionPressure, IntegrationMethod, + DisplacementDim>:: + getIntPtSaturation(const double /*t*/, + GlobalVector const& /*current_solution*/, + NumLib::LocalToGlobalIndexMap const& /*dof_table*/, + std::vector<double>& cache) const +{ + auto const num_intpts = _ip_data.size(); + + cache.clear(); + auto cache_mat = MathLib::createZeroedMatrix< + Eigen::Matrix<double, 1, Eigen::Dynamic, Eigen::RowMajor>>(cache, 1, + num_intpts); + + for (unsigned ip = 0; ip < num_intpts; ++ip) + { + cache_mat[ip] = _ip_data[ip].saturation; + } + + return cache; +} + +template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, + typename IntegrationMethod, int DisplacementDim> +void RichardsMechanicsLocalAssembler<ShapeFunctionDisplacement, + ShapeFunctionPressure, IntegrationMethod, + DisplacementDim>:: + assembleWithJacobianForPressureEquations( + const double /*t*/, const std::vector<double>& /*local_xdot*/, + const double /*dxdot_dx*/, const double /*dx_dx*/, + std::vector<double>& /*local_M_data*/, + std::vector<double>& /*local_K_data*/, + std::vector<double>& /*local_b_data*/, + std::vector<double>& /*local_Jac_data*/, + const LocalCoupledSolutions& /*local_coupled_solutions*/) +{ + OGS_FATAL("RichardsMechanics; The staggered scheme is not implemented."); +} + +template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, + typename IntegrationMethod, int DisplacementDim> +void RichardsMechanicsLocalAssembler<ShapeFunctionDisplacement, + ShapeFunctionPressure, IntegrationMethod, + DisplacementDim>:: + assembleWithJacobianForDeformationEquations( + const double /*t*/, const std::vector<double>& /*local_xdot*/, + const double /*dxdot_dx*/, const double /*dx_dx*/, + std::vector<double>& /*local_M_data*/, + std::vector<double>& /*local_K_data*/, + std::vector<double>& /*local_b_data*/, + std::vector<double>& /*local_Jac_data*/, + const LocalCoupledSolutions& /*local_coupled_solutions*/) +{ + OGS_FATAL("RichardsMechanics; The staggered scheme is not implemented."); +} + +template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, + typename IntegrationMethod, int DisplacementDim> +void RichardsMechanicsLocalAssembler<ShapeFunctionDisplacement, + ShapeFunctionPressure, IntegrationMethod, + DisplacementDim>:: + assembleWithJacobianForStaggeredScheme( + const double t, + const std::vector<double>& local_xdot, + const double dxdot_dx, + const double dx_dx, + std::vector<double>& local_M_data, + std::vector<double>& local_K_data, + std::vector<double>& local_b_data, + std::vector<double>& local_Jac_data, + const LocalCoupledSolutions& local_coupled_solutions) +{ + // For the equations with pressure + if (local_coupled_solutions.process_id == 0) + { + assembleWithJacobianForPressureEquations( + t, local_xdot, dxdot_dx, dx_dx, local_M_data, local_K_data, + local_b_data, local_Jac_data, local_coupled_solutions); + return; + } + + // For the equations with deformation + assembleWithJacobianForDeformationEquations( + t, local_xdot, dxdot_dx, dx_dx, local_M_data, local_K_data, + local_b_data, local_Jac_data, local_coupled_solutions); +} + +template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, + typename IntegrationMethod, int DisplacementDim> +void RichardsMechanicsLocalAssembler<ShapeFunctionDisplacement, + ShapeFunctionPressure, IntegrationMethod, + DisplacementDim>:: + postNonLinearSolverConcrete(std::vector<double> const& local_x, + double const t, + bool const use_monolithic_scheme) +{ + const int displacement_offset = + use_monolithic_scheme ? displacement_index : 0; + + auto u = + Eigen::Map<typename ShapeMatricesTypeDisplacement::template VectorType< + displacement_size> const>(local_x.data() + displacement_offset, + displacement_size); + double const& dt = _process_data.dt; + SpatialPosition x_position; + x_position.setElementID(_element.getID()); + + int const n_integration_points = _integration_method.getNumberOfPoints(); + for (int ip = 0; ip < n_integration_points; ip++) + { + x_position.setIntegrationPoint(ip); + auto const& N_u = _ip_data[ip].N_u; + auto const& dNdx_u = _ip_data[ip].dNdx_u; + auto const temperature = _process_data.temperature(t, x_position)[0]; + + auto const x_coord = + interpolateXCoordinate<ShapeFunctionDisplacement, + ShapeMatricesTypeDisplacement>(_element, + N_u); + auto const B = + LinearBMatrix::computeBMatrix<DisplacementDim, + ShapeFunctionDisplacement::NPOINTS, + typename BMatricesType::BMatrixType>( + dNdx_u, N_u, x_coord, _is_axially_symmetric); + + auto& eps = _ip_data[ip].eps; + eps.noalias() = B * u; + + _ip_data[ip].updateConstitutiveRelation(t, x_position, dt, u, + temperature); + } +} + +template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, + typename IntegrationMethod, int DisplacementDim> +void RichardsMechanicsLocalAssembler<ShapeFunctionDisplacement, + ShapeFunctionPressure, IntegrationMethod, + DisplacementDim>:: + computeSecondaryVariableConcrete(double const t, + std::vector<double> const& local_x) +{ + auto p_L = + Eigen::Map<typename ShapeMatricesTypePressure::template VectorType< + pressure_size> const>(local_x.data() + pressure_index, + pressure_size); + auto const material_id = + _process_data.flow_material->getMaterialID(_element.getID()); + + SpatialPosition x_position; + x_position.setElementID(_element.getID()); + + unsigned const n_integration_points = + _integration_method.getNumberOfPoints(); + + double saturation_avg = 0; + + for (unsigned ip = 0; ip < n_integration_points; ip++) + { + x_position.setIntegrationPoint(ip); + auto const& N_p = _ip_data[ip].N_p; + auto const temperature = _process_data.temperature(t, x_position)[0]; + + double p_cap_ip; + NumLib::shapeFunctionInterpolate(-p_L, N_p, p_cap_ip); + auto& S_L = _ip_data[ip].saturation; + S_L = _process_data.flow_material->getSaturation( + material_id, t, x_position, -p_cap_ip, temperature, p_cap_ip); + saturation_avg += S_L; + } + saturation_avg /= n_integration_points; + + (*_process_data.element_saturation)[_element.getID()] = saturation_avg; +} + +} // namespace RichardsMechanics +} // namespace ProcessLib diff --git a/ProcessLib/RichardsMechanics/RichardsMechanicsFEM.h b/ProcessLib/RichardsMechanics/RichardsMechanicsFEM.h new file mode 100644 index 00000000000..ca91e763e88 --- /dev/null +++ b/ProcessLib/RichardsMechanics/RichardsMechanicsFEM.h @@ -0,0 +1,237 @@ +/** + * \copyright + * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#pragma once + +#include <memory> +#include <vector> + +#include "MaterialLib/SolidModels/LinearElasticIsotropic.h" +#include "MathLib/KelvinVector.h" +#include "MathLib/LinAlg/Eigen/EigenMapTools.h" +#include "NumLib/DOF/DOFTableUtil.h" +#include "NumLib/Fem/ShapeMatrixPolicy.h" +#include "ProcessLib/Deformation/BMatrixPolicy.h" +#include "ProcessLib/Deformation/LinearBMatrix.h" +#include "ProcessLib/LocalAssemblerTraits.h" +#include "ProcessLib/Parameter/Parameter.h" +#include "ProcessLib/Utils/InitShapeMatrices.h" + +#include "IntegrationPointData.h" +#include "LocalAssemblerInterface.h" +#include "RichardsMechanicsProcessData.h" + +namespace ProcessLib +{ +namespace RichardsMechanics +{ +/// Used by for extrapolation of the integration point values. It is ordered +/// (and stored) by integration points. +template <typename ShapeMatrixType> +struct SecondaryData +{ + std::vector<ShapeMatrixType, Eigen::aligned_allocator<ShapeMatrixType>> N_u; +}; + +template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, + typename IntegrationMethod, int DisplacementDim> +class RichardsMechanicsLocalAssembler : public LocalAssemblerInterface +{ +public: + using ShapeMatricesTypeDisplacement = + ShapeMatrixPolicyType<ShapeFunctionDisplacement, DisplacementDim>; + using ShapeMatricesTypePressure = + ShapeMatrixPolicyType<ShapeFunctionPressure, DisplacementDim>; + + static int const KelvinVectorSize = + MathLib::KelvinVector::KelvinVectorDimensions<DisplacementDim>::value; + using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; + + RichardsMechanicsLocalAssembler(RichardsMechanicsLocalAssembler const&) = + delete; + RichardsMechanicsLocalAssembler(RichardsMechanicsLocalAssembler&&) = delete; + + RichardsMechanicsLocalAssembler( + MeshLib::Element const& e, + std::size_t const /*local_matrix_size*/, + bool const is_axially_symmetric, + unsigned const integration_order, + RichardsMechanicsProcessData<DisplacementDim>& process_data); + + void assemble(double const t, std::vector<double> const& local_x, + std::vector<double>& local_M_data, + std::vector<double>& local_K_data, + std::vector<double>& local_rhs_data) override; + + void assembleWithJacobian(double const t, + std::vector<double> const& local_x, + std::vector<double> const& local_xdot, + const double /*dxdot_dx*/, const double /*dx_dx*/, + std::vector<double>& /*local_M_data*/, + std::vector<double>& /*local_K_data*/, + std::vector<double>& local_rhs_data, + std::vector<double>& local_Jac_data) override; + + void assembleWithJacobianForStaggeredScheme( + double const t, std::vector<double> const& local_xdot, + const double dxdot_dx, const double dx_dx, + std::vector<double>& local_M_data, std::vector<double>& local_K_data, + std::vector<double>& local_b_data, std::vector<double>& local_Jac_data, + LocalCoupledSolutions const& local_coupled_solutions) override; + + void preTimestepConcrete(std::vector<double> const& /*local_x*/, + double const /*t*/, + double const /*delta_t*/) override + { + unsigned const n_integration_points = + _integration_method.getNumberOfPoints(); + + for (unsigned ip = 0; ip < n_integration_points; ip++) + { + _ip_data[ip].pushBackState(); + } + } + + void computeSecondaryVariableConcrete( + double const t, std::vector<double> const& local_x) override; + + void postNonLinearSolverConcrete(std::vector<double> const& local_x, + double const t, + bool const use_monolithic_scheme) override; + + Eigen::Map<const Eigen::RowVectorXd> getShapeMatrix( + const unsigned integration_point) const override + { + auto const& N_u = _secondary_data.N_u[integration_point]; + + // assumes N is stored contiguously in memory + return Eigen::Map<const Eigen::RowVectorXd>(N_u.data(), N_u.size()); + } + + std::vector<double> const& getIntPtDarcyVelocity( + const double t, + GlobalVector const& current_solution, + NumLib::LocalToGlobalIndexMap const& dof_table, + std::vector<double>& cache) const override; + + std::vector<double> const& getIntPtSaturation( + const double /*t*/, + GlobalVector const& /*current_solution*/, + NumLib::LocalToGlobalIndexMap const& /*dof_table*/, + std::vector<double>& /*cache*/) const override; + + std::vector<double> const& getIntPtSigma( + const double /*t*/, + GlobalVector const& /*current_solution*/, + NumLib::LocalToGlobalIndexMap const& /*dof_table*/, + std::vector<double>& cache) const override; + + std::vector<double> const& getIntPtEpsilon( + const double /*t*/, + GlobalVector const& /*current_solution*/, + NumLib::LocalToGlobalIndexMap const& /*dof_table*/, + std::vector<double>& cache) const override; + +private: + /** + * Assemble local matrices and vectors arise from the linearized discretized + * weak form of the residual of the momentum balance equation, + * \f[ + * \nabla (\sigma - \alpha_b p \mathrm{I}) = f + * \f] + * where \f$ \sigma\f$ is the effective stress tensor, \f$p\f$ is the pore + * pressure, \f$\alpha_b\f$ is the Biot constant, \f$\mathrm{I}\f$ is the + * identity tensor, and \f$f\f$ is the body force. + * + * @param t Time + * @param local_xdot Nodal values of \f$\dot{x}\f$ of an element. + * @param dxdot_dx Value of \f$\dot{x} \cdot dx\f$. + * @param dx_dx Value of \f$ x \cdot dx\f$. + * @param local_M_data Mass matrix of an element, which takes the form of + * \f$ \inta N^T N\mathrm{d}\Omega\f$. Not used. + * @param local_K_data Laplacian matrix of an element, which takes the + * form of \f$ \int (\nabla N)^T K \nabla N\mathrm{d}\Omega\f$. + * Not used. + * @param local_b_data Right hand side vector of an element. + * @param local_Jac_data Element Jacobian matrix for the Newton-Raphson + * method. + * @param local_coupled_solutions Nodal values of solutions of the coupled + * processes of an element. + */ + void assembleWithJacobianForDeformationEquations( + double const t, std::vector<double> const& local_xdot, + const double dxdot_dx, const double dx_dx, + std::vector<double>& local_M_data, std::vector<double>& local_K_data, + std::vector<double>& local_b_data, std::vector<double>& local_Jac_data, + LocalCoupledSolutions const& local_coupled_solutions); + + /** + * Assemble local matrices and vectors arise from the linearized discretized + * weak form of the residual of the mass balance equation of single phase + * flow, + * \f[ + * \alpha \cdot{p} - \nabla (K (\nabla p + \rho g \nabla z) + + * \alpha_b \nabla \cdot \dot{u} = Q + * \f] + * where \f$ alpha\f$ is a coefficient may depend on storage or the fluid + * density change, \f$ \rho\f$ is the fluid density, \f$\g\f$ is the + * gravitational acceleration, \f$z\f$ is the vertical coordinate, \f$u\f$ + * is the displacement, and \f$Q\f$ is the source/sink term. + * + * @param t Time + * @param local_xdot Nodal values of \f$\dot{x}\f$ of an element. + * @param dxdot_dx Value of \f$\dot{x} \cdot dx\f$. + * @param dx_dx Value of \f$ x \cdot dx\f$. + * @param local_M_data Mass matrix of an element, which takes the form of + * \f$ \inta N^T N\mathrm{d}\Omega\f$. Not used. + * @param local_K_data Laplacian matrix of an element, which takes the + * form of \f$ \int (\nabla N)^T K \nabla N\mathrm{d}\Omega\f$. + * Not used. + * @param local_b_data Right hand side vector of an element. + * @param local_Jac_data Element Jacobian matrix for the Newton-Raphson + * method. + * @param local_coupled_solutions Nodal values of solutions of the coupled + * processes of an element. + */ + void assembleWithJacobianForPressureEquations( + double const t, std::vector<double> const& local_xdot, + const double dxdot_dx, const double dx_dx, + std::vector<double>& local_M_data, std::vector<double>& local_K_data, + std::vector<double>& local_b_data, std::vector<double>& local_Jac_data, + LocalCoupledSolutions const& local_coupled_solutions); + +private: + RichardsMechanicsProcessData<DisplacementDim>& _process_data; + + using BMatricesType = + BMatrixPolicyType<ShapeFunctionDisplacement, DisplacementDim>; + using IpData = + IntegrationPointData<BMatricesType, ShapeMatricesTypeDisplacement, + ShapeMatricesTypePressure, DisplacementDim, + ShapeFunctionDisplacement::NPOINTS>; + std::vector<IpData, Eigen::aligned_allocator<IpData>> _ip_data; + + IntegrationMethod _integration_method; + MeshLib::Element const& _element; + bool const _is_axially_symmetric; + SecondaryData< + typename ShapeMatricesTypeDisplacement::ShapeMatrices::ShapeType> + _secondary_data; + + static const int pressure_index = 0; + static const int pressure_size = ShapeFunctionPressure::NPOINTS; + static const int displacement_index = ShapeFunctionPressure::NPOINTS; + static const int displacement_size = + ShapeFunctionDisplacement::NPOINTS * DisplacementDim; +}; + +} // namespace RichardsMechanics +} // namespace ProcessLib + +#include "RichardsMechanicsFEM-impl.h" diff --git a/ProcessLib/RichardsMechanics/RichardsMechanicsProcess.cpp b/ProcessLib/RichardsMechanics/RichardsMechanicsProcess.cpp new file mode 100644 index 00000000000..d1ef1a3cd66 --- /dev/null +++ b/ProcessLib/RichardsMechanics/RichardsMechanicsProcess.cpp @@ -0,0 +1,381 @@ +/** + * \copyright + * Copyright (c) 2012-2018, 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 "RichardsMechanicsProcess.h" + +#include <cassert> + +#include "MeshLib/Elements/Utils.h" +#include "NumLib/DOF/ComputeSparsityPattern.h" +#include "ProcessLib/Process.h" +#include "ProcessLib/RichardsMechanics/CreateLocalAssemblers.h" + +#include "RichardsMechanicsFEM.h" +#include "RichardsMechanicsProcessData.h" + +namespace ProcessLib +{ +namespace RichardsMechanics +{ +template <int DisplacementDim> +RichardsMechanicsProcess<DisplacementDim>::RichardsMechanicsProcess( + MeshLib::Mesh& mesh, + std::unique_ptr<ProcessLib::AbstractJacobianAssembler>&& jacobian_assembler, + std::vector<std::unique_ptr<ParameterBase>> const& parameters, + unsigned const integration_order, + std::vector<std::vector<std::reference_wrapper<ProcessVariable>>>&& + process_variables, + RichardsMechanicsProcessData<DisplacementDim>&& process_data, + SecondaryVariableCollection&& secondary_variables, + NumLib::NamedFunctionCaller&& named_function_caller, + bool const use_monolithic_scheme) + : Process(mesh, std::move(jacobian_assembler), parameters, + integration_order, std::move(process_variables), + std::move(secondary_variables), std::move(named_function_caller), + use_monolithic_scheme), + _process_data(std::move(process_data)) +{ + _nodal_forces = MeshLib::getOrCreateMeshProperty<double>( + mesh, "NodalForces", MeshLib::MeshItemType::Node, DisplacementDim); + + _hydraulic_flow = MeshLib::getOrCreateMeshProperty<double>( + mesh, "HydraulicFlow", MeshLib::MeshItemType::Node, 1); +} + +template <int DisplacementDim> +bool RichardsMechanicsProcess<DisplacementDim>::isLinear() const +{ + return false; +} + +template <int DisplacementDim> +MathLib::MatrixSpecifications +RichardsMechanicsProcess<DisplacementDim>::getMatrixSpecifications( + const int process_id) const +{ + // For the monolithic scheme or the M process (deformation) in the staggered + // scheme. + if (_use_monolithic_scheme || process_id == 1) + { + auto const& l = *_local_to_global_index_map; + return {l.dofSizeWithoutGhosts(), l.dofSizeWithoutGhosts(), + &l.getGhostIndices(), &this->_sparsity_pattern}; + } + + // For staggered scheme and H process (pressure). + auto const& l = *_local_to_global_index_map_with_base_nodes; + return {l.dofSizeWithoutGhosts(), l.dofSizeWithoutGhosts(), + &l.getGhostIndices(), &_sparsity_pattern_with_linear_element}; +} + +template <int DisplacementDim> +void RichardsMechanicsProcess<DisplacementDim>::constructDofTable() +{ + // Create single component dof in every of the mesh's nodes. + _mesh_subset_all_nodes = + std::make_unique<MeshLib::MeshSubset>(_mesh, _mesh.getNodes()); + // Create single component dof in the mesh's base nodes. + _base_nodes = MeshLib::getBaseNodes(_mesh.getElements()); + _mesh_subset_base_nodes = + std::make_unique<MeshLib::MeshSubset>(_mesh, _base_nodes); + + // TODO move the two data members somewhere else. + // for extrapolation of secondary variables of stress or strain + std::vector<MeshLib::MeshSubset> all_mesh_subsets_single_component{ + *_mesh_subset_all_nodes}; + _local_to_global_index_map_single_component = + std::make_unique<NumLib::LocalToGlobalIndexMap>( + std::move(all_mesh_subsets_single_component), + // by location order is needed for output + NumLib::ComponentOrder::BY_LOCATION); + + if (_use_monolithic_scheme) + { + // For pressure, which is the first + std::vector<MeshLib::MeshSubset> all_mesh_subsets{ + *_mesh_subset_base_nodes}; + + // For displacement. + const int monolithic_process_id = 0; + std::generate_n(std::back_inserter(all_mesh_subsets), + getProcessVariables(monolithic_process_id)[1] + .get() + .getNumberOfComponents(), + [&]() { return *_mesh_subset_all_nodes; }); + + std::vector<int> const vec_n_components{1, DisplacementDim}; + _local_to_global_index_map = + std::make_unique<NumLib::LocalToGlobalIndexMap>( + std::move(all_mesh_subsets), vec_n_components, + NumLib::ComponentOrder::BY_LOCATION); + assert(_local_to_global_index_map); + } + else + { + // For displacement equation. + const int process_id = 1; + std::vector<MeshLib::MeshSubset> all_mesh_subsets; + std::generate_n( + std::back_inserter(all_mesh_subsets), + getProcessVariables(process_id)[0].get().getNumberOfComponents(), + [&]() { return *_mesh_subset_all_nodes; }); + + std::vector<int> const vec_n_components{DisplacementDim}; + _local_to_global_index_map = + std::make_unique<NumLib::LocalToGlobalIndexMap>( + std::move(all_mesh_subsets), vec_n_components, + NumLib::ComponentOrder::BY_LOCATION); + + // For pressure equation. + // Collect the mesh subsets with base nodes in a vector. + std::vector<MeshLib::MeshSubset> all_mesh_subsets_base_nodes{ + *_mesh_subset_base_nodes}; + _local_to_global_index_map_with_base_nodes = + std::make_unique<NumLib::LocalToGlobalIndexMap>( + std::move(all_mesh_subsets_base_nodes), + // by location order is needed for output + NumLib::ComponentOrder::BY_LOCATION); + + _sparsity_pattern_with_linear_element = NumLib::computeSparsityPattern( + *_local_to_global_index_map_with_base_nodes, _mesh); + + assert(_local_to_global_index_map); + assert(_local_to_global_index_map_with_base_nodes); + } +} + +template <int DisplacementDim> +void RichardsMechanicsProcess<DisplacementDim>::initializeConcreteProcess( + NumLib::LocalToGlobalIndexMap const& dof_table, + MeshLib::Mesh const& mesh, + unsigned const integration_order) +{ + const int mechanical_process_id = _use_monolithic_scheme ? 0 : 1; + const int deformation_variable_id = _use_monolithic_scheme ? 1 : 0; + ProcessLib::RichardsMechanics::createLocalAssemblers< + DisplacementDim, RichardsMechanicsLocalAssembler>( + mesh.getDimension(), mesh.getElements(), dof_table, + // use displacement process variable to set shape function order + getProcessVariables(mechanical_process_id)[deformation_variable_id] + .get() + .getShapeFunctionOrder(), + _local_assemblers, mesh.isAxiallySymmetric(), integration_order, + _process_data); + + _secondary_variables.addSecondaryVariable( + "sigma", + makeExtrapolator(MathLib::KelvinVector::KelvinVectorType< + DisplacementDim>::RowsAtCompileTime, + getExtrapolator(), _local_assemblers, + &LocalAssemblerInterface::getIntPtSigma)); + + _secondary_variables.addSecondaryVariable( + "epsilon", + makeExtrapolator(MathLib::KelvinVector::KelvinVectorType< + DisplacementDim>::RowsAtCompileTime, + getExtrapolator(), _local_assemblers, + &LocalAssemblerInterface::getIntPtEpsilon)); + + _secondary_variables.addSecondaryVariable( + "velocity", + makeExtrapolator(DisplacementDim, getExtrapolator(), _local_assemblers, + &LocalAssemblerInterface::getIntPtDarcyVelocity)); + + _secondary_variables.addSecondaryVariable( + "saturation", + makeExtrapolator(1, getExtrapolator(), _local_assemblers, + &LocalAssemblerInterface::getIntPtSaturation)); + + _process_data.element_saturation = MeshLib::getOrCreateMeshProperty<double>( + const_cast<MeshLib::Mesh&>(mesh), "saturation_avg", + MeshLib::MeshItemType::Cell, 1); +} + +template <int DisplacementDim> +void RichardsMechanicsProcess<DisplacementDim>::initializeBoundaryConditions() +{ + if (_use_monolithic_scheme) + { + const int monolithic_process_id = 0; + initializeProcessBoundaryConditionsAndSourceTerms( + *_local_to_global_index_map, monolithic_process_id); + return; + } + + // Staggered scheme: + // for the equations of pressure + const int hydraulic_process_id = 0; + initializeProcessBoundaryConditionsAndSourceTerms( + *_local_to_global_index_map_with_base_nodes, hydraulic_process_id); + + // for the equations of deformation. + const int mechanical_process_id = 1; + initializeProcessBoundaryConditionsAndSourceTerms( + *_local_to_global_index_map, mechanical_process_id); +} + +template <int DisplacementDim> +void RichardsMechanicsProcess<DisplacementDim>::assembleConcreteProcess( + const double t, GlobalVector const& x, GlobalMatrix& M, GlobalMatrix& K, + GlobalVector& b) +{ + DBUG("Assemble the equations for RichardsMechanics"); + + // Note: This assembly function is for the Picard nonlinear solver. Since + // only the Newton-Raphson method is employed to simulate coupled HM + // processes in this class, this function is actually not used so far. + + std::vector<std::reference_wrapper<NumLib::LocalToGlobalIndexMap>> + dof_table = {std::ref(*_local_to_global_index_map)}; + // Call global assembler for each local assembly item. + GlobalExecutor::executeMemberDereferenced( + _global_assembler, &VectorMatrixAssembler::assemble, _local_assemblers, + dof_table, t, x, M, K, b, _coupled_solutions); +} + +template <int DisplacementDim> +void RichardsMechanicsProcess<DisplacementDim>:: + assembleWithJacobianConcreteProcess(const double t, GlobalVector const& x, + GlobalVector const& xdot, + const double dxdot_dx, + const double dx_dx, GlobalMatrix& M, + GlobalMatrix& K, GlobalVector& b, + GlobalMatrix& Jac) +{ + std::vector<std::reference_wrapper<NumLib::LocalToGlobalIndexMap>> + dof_tables; + // For the monolithic scheme + if (_use_monolithic_scheme) + { + DBUG( + "Assemble the Jacobian of RichardsMechanics for the monolithic" + " scheme."); + dof_tables.emplace_back(*_local_to_global_index_map); + } + else + { + // For the staggered scheme + if (_coupled_solutions->process_id == 0) + { + DBUG( + "Assemble the Jacobian equations of liquid fluid process in " + "RichardsMechanics for the staggered scheme."); + } + else + { + DBUG( + "Assemble the Jacobian equations of mechanical process in " + "RichardsMechanics for the staggered scheme."); + } + dof_tables.emplace_back(*_local_to_global_index_map_with_base_nodes); + dof_tables.emplace_back(*_local_to_global_index_map); + } + + GlobalExecutor::executeMemberDereferenced( + _global_assembler, &VectorMatrixAssembler::assembleWithJacobian, + _local_assemblers, dof_tables, t, x, xdot, dxdot_dx, dx_dx, M, K, b, + Jac, _coupled_solutions); + + auto copyRhs = [&](int const variable_id, auto& output_vector) { + if (_use_monolithic_scheme) + { + transformVariableFromGlobalVector(b, variable_id, dof_tables[0], + output_vector, + std::negate<double>()); + } + else + { + transformVariableFromGlobalVector( + b, 0, dof_tables[_coupled_solutions->process_id], output_vector, + std::negate<double>()); + } + }; + if (_use_monolithic_scheme || _coupled_solutions->process_id == 0) + { + copyRhs(0, *_hydraulic_flow); + } + if (_use_monolithic_scheme || _coupled_solutions->process_id == 1) + { + copyRhs(1, *_nodal_forces); + } +} + +template <int DisplacementDim> +void RichardsMechanicsProcess<DisplacementDim>::preTimestepConcreteProcess( + GlobalVector const& x, double const t, double const dt, + const int process_id) +{ + DBUG("PreTimestep RichardsMechanicsProcess."); + + _process_data.dt = dt; + _process_data.t = t; + + if (hasMechanicalProcess(process_id)) + GlobalExecutor::executeMemberOnDereferenced( + &LocalAssemblerInterface::preTimestep, _local_assemblers, + *_local_to_global_index_map, x, t, dt); +} + +template <int DisplacementDim> +void RichardsMechanicsProcess< + DisplacementDim>::postNonLinearSolverConcreteProcess(GlobalVector const& x, + const double t, + const int process_id) +{ + if (!hasMechanicalProcess(process_id)) + { + return; + } + + DBUG("PostNonLinearSolver RichardsMechanicsProcess."); + // Calculate strain, stress or other internal variables of mechanics. + GlobalExecutor::executeMemberOnDereferenced( + &LocalAssemblerInterface::postNonLinearSolver, _local_assemblers, + getDOFTable(process_id), x, t, _use_monolithic_scheme); +} + +template <int DisplacementDim> +void RichardsMechanicsProcess< + DisplacementDim>::computeSecondaryVariableConcrete(const double t, + GlobalVector const& x) +{ + DBUG("Compute the secondary variables for RichardsMechanicsProcess."); + GlobalExecutor::executeMemberOnDereferenced( + &LocalAssemblerInterface::computeSecondaryVariable, _local_assemblers, + *_local_to_global_index_map, t, x, _coupled_solutions); +} + +template <int DisplacementDim> +std::tuple<NumLib::LocalToGlobalIndexMap*, bool> RichardsMechanicsProcess< + DisplacementDim>::getDOFTableForExtrapolatorData() const +{ + const bool manage_storage = false; + return std::make_tuple(_local_to_global_index_map_single_component.get(), + manage_storage); +} + +template <int DisplacementDim> +NumLib::LocalToGlobalIndexMap const& +RichardsMechanicsProcess<DisplacementDim>::getDOFTable( + const int process_id) const +{ + if (hasMechanicalProcess(process_id)) + { + return *_local_to_global_index_map; + } + + // For the equation of pressure + return *_local_to_global_index_map_with_base_nodes; +} + +template class RichardsMechanicsProcess<2>; +template class RichardsMechanicsProcess<3>; + +} // namespace RichardsMechanics +} // namespace ProcessLib diff --git a/ProcessLib/RichardsMechanics/RichardsMechanicsProcess.h b/ProcessLib/RichardsMechanics/RichardsMechanicsProcess.h new file mode 100644 index 00000000000..fe176bd3e3d --- /dev/null +++ b/ProcessLib/RichardsMechanics/RichardsMechanicsProcess.h @@ -0,0 +1,140 @@ +/** + * \copyright + * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#pragma once + +#include "LocalAssemblerInterface.h" +#include "ProcessLib/Process.h" +#include "RichardsMechanicsProcessData.h" + +namespace ProcessLib +{ +namespace RichardsMechanics +{ +struct LocalAssemblerInterface; + +/// Linear kinematics poro-mechanical/biphasic (fluid-solid mixture) model. +/// +/// The mixture momentum balance and the mixture mass balance are solved under +/// fully saturated conditions. +template <int DisplacementDim> +class RichardsMechanicsProcess final : public Process +{ +public: + RichardsMechanicsProcess( + MeshLib::Mesh& mesh, + std::unique_ptr<ProcessLib::AbstractJacobianAssembler>&& + jacobian_assembler, + std::vector<std::unique_ptr<ParameterBase>> const& parameters, + unsigned const integration_order, + std::vector<std::vector<std::reference_wrapper<ProcessVariable>>>&& + process_variables, + RichardsMechanicsProcessData<DisplacementDim>&& process_data, + SecondaryVariableCollection&& secondary_variables, + NumLib::NamedFunctionCaller&& named_function_caller, + bool const use_monolithic_scheme); + + //! \name ODESystem interface + //! @{ + + bool isLinear() const override; + //! @} + + /** + * Get the size and the sparse pattern of the global matrix in order to + * create the global matrices and vectors for the system equations of this + * process. + * + * @param process_id Process ID. If the monolithic scheme is applied, + * process_id = 0. For the staggered scheme, + * process_id = 0 represents the + * hydraulic (H) process, while process_id = 1 + * represents the mechanical (M) process. + * @return Matrix specifications including size and sparse pattern. + */ + MathLib::MatrixSpecifications getMatrixSpecifications( + const int process_id) const override; + +private: + void constructDofTable() override; + + void initializeConcreteProcess( + NumLib::LocalToGlobalIndexMap const& dof_table, + MeshLib::Mesh const& mesh, + unsigned const integration_order) override; + + void initializeBoundaryConditions() override; + + void assembleConcreteProcess(const double t, GlobalVector const& x, + GlobalMatrix& M, GlobalMatrix& K, + GlobalVector& b) override; + + void assembleWithJacobianConcreteProcess( + const double t, GlobalVector const& x, GlobalVector const& xdot, + const double dxdot_dx, const double dx_dx, GlobalMatrix& M, + GlobalMatrix& K, GlobalVector& b, GlobalMatrix& Jac) override; + + void preTimestepConcreteProcess(GlobalVector const& x, double const t, + double const dt, + const int process_id) override; + + void postNonLinearSolverConcreteProcess(GlobalVector const& x, + const double t, + int const process_id) override; + + NumLib::LocalToGlobalIndexMap const& getDOFTable( + const int process_id) const override; + +private: + std::vector<MeshLib::Node*> _base_nodes; + std::unique_ptr<MeshLib::MeshSubset const> _mesh_subset_base_nodes; + RichardsMechanicsProcessData<DisplacementDim> _process_data; + + std::vector<std::unique_ptr<LocalAssemblerInterface>> _local_assemblers; + + std::unique_ptr<NumLib::LocalToGlobalIndexMap> + _local_to_global_index_map_single_component; + + /// Local to global index mapping for base nodes, which is used for linear + /// interpolation for pressure in the staggered scheme. + std::unique_ptr<NumLib::LocalToGlobalIndexMap> + _local_to_global_index_map_with_base_nodes; + + /// Sparsity pattern for the flow equation, and it is initialized only if + /// the staggered scheme is used. + GlobalSparsityPattern _sparsity_pattern_with_linear_element; + + /// Solutions of the previous time step + std::array<std::unique_ptr<GlobalVector>, 2> _xs_previous_timestep; + + void computeSecondaryVariableConcrete(const double t, + GlobalVector const& x) override; + /** + * @copydoc ProcessLib::Process::getDOFTableForExtrapolatorData() + */ + std::tuple<NumLib::LocalToGlobalIndexMap*, bool> + getDOFTableForExtrapolatorData() const override; + + /// Check whether the process represented by \c process_id is/has + /// mechanical process. In the present implementation, the mechanical + /// process has process_id == 1 in the staggered scheme. + bool hasMechanicalProcess(int const process_id) const + { + return _use_monolithic_scheme || process_id == 1; + } + + MeshLib::PropertyVector<double>* _nodal_forces = nullptr; + MeshLib::PropertyVector<double>* _hydraulic_flow = nullptr; +}; + +extern template class RichardsMechanicsProcess<2>; +extern template class RichardsMechanicsProcess<3>; + +} // namespace RichardsMechanics +} // namespace ProcessLib diff --git a/ProcessLib/RichardsMechanics/RichardsMechanicsProcessData.h b/ProcessLib/RichardsMechanics/RichardsMechanicsProcessData.h new file mode 100644 index 00000000000..df5a6edf8d0 --- /dev/null +++ b/ProcessLib/RichardsMechanics/RichardsMechanicsProcessData.h @@ -0,0 +1,104 @@ +/** + * \copyright + * Copyright (c) 2012-2018, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#pragma once + +#include "ProcessLib/Parameter/Parameter.h" + +#include <memory> +#include <utility> + +#include <Eigen/Dense> + +#include "ProcessLib/RichardsFlow/RichardsFlowMaterialProperties.h" + +namespace MaterialLib +{ +namespace Solids +{ +template <int DisplacementDim> +struct MechanicsBase; +} +} // namespace MaterialLib +namespace ProcessLib +{ +namespace RichardsMechanics +{ +template <int DisplacementDim> +struct RichardsMechanicsProcessData +{ + RichardsMechanicsProcessData( + std::unique_ptr< + ProcessLib::RichardsFlow::RichardsFlowMaterialProperties>&& + flow_material_, + std::unique_ptr<MaterialLib::Solids::MechanicsBase<DisplacementDim>>&& + solid_material_, + Parameter<double> const& intrinsic_permeability_, + Parameter<double> const& fluid_bulk_modulus_, + Parameter<double> const& biot_coefficient_, + Parameter<double> const& solid_density_, + Parameter<double> const& solid_bulk_modulus_, + Parameter<double> const& temperature_, + Eigen::Matrix<double, DisplacementDim, 1> + specific_body_force_) + : flow_material{std::move(flow_material_)}, + solid_material{std::move(solid_material_)}, + intrinsic_permeability(intrinsic_permeability_), + fluid_bulk_modulus(fluid_bulk_modulus_), + biot_coefficient(biot_coefficient_), + solid_density(solid_density_), + solid_bulk_modulus(solid_bulk_modulus_), + temperature(temperature_), + specific_body_force(std::move(specific_body_force_)) + { + } + + RichardsMechanicsProcessData(RichardsMechanicsProcessData&& other) = + default; + + //! Copies are forbidden. + RichardsMechanicsProcessData(RichardsMechanicsProcessData const&) = delete; + + //! Assignments are not needed. + void operator=(RichardsMechanicsProcessData const&) = delete; + void operator=(RichardsMechanicsProcessData&&) = delete; + + std::unique_ptr<ProcessLib::RichardsFlow::RichardsFlowMaterialProperties> + flow_material; + + /// The constitutive relation for the mechanical part. + std::unique_ptr<MaterialLib::Solids::MechanicsBase<DisplacementDim>> + solid_material; + /// Permeability of the solid. A scalar quantity, Parameter<double>. + Parameter<double> const& intrinsic_permeability; + /// Fluid's bulk modulus. A scalar quantity, Parameter<double>. + Parameter<double> const& fluid_bulk_modulus; + /// Biot coefficient. A scalar quantity, Parameter<double>. + Parameter<double> const& biot_coefficient; + /// Density of the solid. A scalar quantity, Parameter<double>. + Parameter<double> const& solid_density; + /// Solid's bulk modulus. A scalar quantity, Parameter<double>. + Parameter<double> const& solid_bulk_modulus; + /// Reference temperature for material properties. A scalar quantity, + /// Parameter<double>. + Parameter<double> const& temperature; + /// Specific body forces applied to solid and fluid. + /// It is usually used to apply gravitational forces. + /// A vector of displacement dimension's length. + Eigen::Matrix<double, DisplacementDim, 1> const specific_body_force; + double dt = 0.0; + double t = 0.0; + + MeshLib::PropertyVector<double>* element_saturation = nullptr; + + EIGEN_MAKE_ALIGNED_OPERATOR_NEW; +}; + +} // namespace RichardsMechanics +} // namespace ProcessLib -- GitLab