diff --git a/Documentation/ProjectFile/prj/process_variables/process_variable/boundary_conditions/boundary_condition/PhaseFieldIrreversibleDamageOracleBoundaryCondition/c_PhaseFieldIrreversibleDamageOracleBoundaryCondition.md b/Documentation/ProjectFile/prj/process_variables/process_variable/boundary_conditions/boundary_condition/PhaseFieldIrreversibleDamageOracleBoundaryCondition/c_PhaseFieldIrreversibleDamageOracleBoundaryCondition.md new file mode 100644 index 0000000000000000000000000000000000000000..24deec36a1cd164d6ca9d648e1dabb1308a20ce8 --- /dev/null +++ b/Documentation/ProjectFile/prj/process_variables/process_variable/boundary_conditions/boundary_condition/PhaseFieldIrreversibleDamageOracleBoundaryCondition/c_PhaseFieldIrreversibleDamageOracleBoundaryCondition.md @@ -0,0 +1 @@ +Phase field irreversibility is set. When its value becomes smaller than 0.05, it will be set to 0 in dirichlet boundary condition. diff --git a/Documentation/ProjectFile/prj/processes/process/PHASE_FIELD/t_hydro_crack_scheme.md b/Documentation/ProjectFile/prj/processes/process/PHASE_FIELD/t_hydro_crack_scheme.md new file mode 100644 index 0000000000000000000000000000000000000000..e938d33adaba54df328d623ca8c11f732bf1902b --- /dev/null +++ b/Documentation/ProjectFile/prj/processes/process/PHASE_FIELD/t_hydro_crack_scheme.md @@ -0,0 +1 @@ +In case of static, pressure is set to 1.0. For propagating crack, evolution of pressure is found through enforcing the crack volume balance. diff --git a/MaterialLib/SolidModels/LinearElasticIsotropicPhaseField.h b/MaterialLib/SolidModels/LinearElasticIsotropicPhaseField.h index 7bce42d01c2ff387bba59e81a4b69526b6baa00a..7314b1130fd3755cf758b056817d43e975eaa148 100644 --- a/MaterialLib/SolidModels/LinearElasticIsotropicPhaseField.h +++ b/MaterialLib/SolidModels/LinearElasticIsotropicPhaseField.h @@ -94,7 +94,8 @@ public: KelvinMatrix& C_tensile, KelvinMatrix& C_compressive, KelvinVector& sigma_real, - double const degradation) const override + double const degradation, + double& elastic_energy) const override { using Invariants = MathLib::KelvinVector::Invariants<KelvinVectorSize>; // calculation of deviatoric parts @@ -120,6 +121,7 @@ public: sigma_compressive.noalias() = KelvinVector::Zero(); C_tensile.template topLeftCorner<3, 3>().setConstant(K); C_tensile.noalias() += 2 * mu * P_dev * KelvinMatrix::Identity(); + elastic_energy = degradation * strain_energy_tensile; } else { @@ -129,6 +131,8 @@ public: K * eps_curr_trace * Invariants::identity2; C_tensile.noalias() = 2 * mu * P_dev * KelvinMatrix::Identity(); C_compressive.template topLeftCorner<3, 3>().setConstant(K); + elastic_energy = K / 2 * eps_curr_trace * eps_curr_trace + + mu * epsd_curr.transpose() * epsd_curr; } sigma_real.noalias() = degradation * sigma_tensile + sigma_compressive; diff --git a/MaterialLib/SolidModels/PhaseFieldExtension.h b/MaterialLib/SolidModels/PhaseFieldExtension.h index 4ef4dbfea6272bfaecdd6b7e6a000adfec33754c..425da16cf2b6ad27b77d878dd100da01705007d6 100644 --- a/MaterialLib/SolidModels/PhaseFieldExtension.h +++ b/MaterialLib/SolidModels/PhaseFieldExtension.h @@ -32,7 +32,8 @@ struct PhaseFieldExtension : public MechanicsBase<DisplacementDim> KelvinMatrix& C_tensile, KelvinMatrix& C_compressive, KelvinVector& sigma_real, - double const degradation) const = 0; + double const degradation, + double& elastic_energy) const = 0; /// Dynamic size Kelvin vector and matrix wrapper for the polymorphic /// constitutive relation compute function. @@ -48,7 +49,8 @@ struct PhaseFieldExtension : public MechanicsBase<DisplacementDim> Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>& C_compressive, Eigen::Matrix<double, Eigen::Dynamic, 1>& sigma_real, - double const degradation) const + double const degradation, + double& elastic_energy) const { // TODO Avoid copies of data: // Using MatrixBase<Derived> not possible because template functions @@ -71,7 +73,8 @@ struct PhaseFieldExtension : public MechanicsBase<DisplacementDim> C_tensile_, C_compressive_, sigma_real_, - degradation); + degradation, + elastic_energy); sigma_tensile = sigma_tensile_; sigma_compressive = sigma_compressive_; diff --git a/ProcessLib/BoundaryCondition/BoundaryCondition.cpp b/ProcessLib/BoundaryCondition/BoundaryCondition.cpp index 64a633bfc0d69d172f59c91e8efe11062b80ad0f..ead1f9bbc2bf9820a653d60844c20dd91bc45737 100644 --- a/ProcessLib/BoundaryCondition/BoundaryCondition.cpp +++ b/ProcessLib/BoundaryCondition/BoundaryCondition.cpp @@ -18,6 +18,7 @@ #include "NonuniformDirichletBoundaryCondition.h" #include "NonuniformNeumannBoundaryCondition.h" #include "NormalTractionBoundaryCondition.h" +#include "PhaseFieldIrreversibleDamageOracleBoundaryCondition.h" #include "RobinBoundaryCondition.h" namespace ProcessLib @@ -62,7 +63,6 @@ BoundaryConditionBuilder::createBoundaryCondition( config, dof_table, mesh, variable_id, integration_order, shapefunction_order); } - // // Special boundary conditions // @@ -72,6 +72,12 @@ BoundaryConditionBuilder::createBoundaryCondition( config, dof_table, mesh, variable_id, integration_order, shapefunction_order, parameters); } + if (type == "PhaseFieldIrreversibleDamageOracleBoundaryCondition") + { + return createPhaseFieldIrreversibleDamageOracleBoundaryCondition( + config, dof_table, mesh, variable_id, integration_order, + shapefunction_order, parameters); + } OGS_FATAL("Unknown boundary condition type: `%s'.", type.c_str()); } @@ -230,6 +236,21 @@ BoundaryConditionBuilder::createNormalTractionBoundaryCondition( parameters); } +std::unique_ptr<BoundaryCondition> BoundaryConditionBuilder:: + createPhaseFieldIrreversibleDamageOracleBoundaryCondition( + const BoundaryConditionConfig& config, + const NumLib::LocalToGlobalIndexMap& dof_table, + const MeshLib::Mesh& mesh, const int variable_id, + const unsigned /*integration_order*/, + const unsigned /*shapefunction_order*/, + const std::vector< + std::unique_ptr<ProcessLib::ParameterBase>>& /*parameters*/) +{ + return ProcessLib:: + createPhaseFieldIrreversibleDamageOracleBoundaryCondition( + config.config, dof_table, mesh, variable_id, *config.component_id); +} + std::vector<MeshLib::Element*> BoundaryConditionBuilder::getClonedElements( MeshGeoToolsLib::BoundaryElementsSearcher& boundary_element_searcher, GeoLib::GeoObject const& geometry) diff --git a/ProcessLib/BoundaryCondition/BoundaryCondition.h b/ProcessLib/BoundaryCondition/BoundaryCondition.h index 6f02c9ae29e159f00418d4e53c72a11febdcae89..a654c57659168f5c3447bae767c4e3c55e3f0cda 100644 --- a/ProcessLib/BoundaryCondition/BoundaryCondition.h +++ b/ProcessLib/BoundaryCondition/BoundaryCondition.h @@ -62,6 +62,11 @@ public: // Therefore there is nothing to do here. } + virtual void preTimestep(const double /*t*/, GlobalVector const& /*x*/) + { + // A hook added for solution dependent dirichlet + } + virtual ~BoundaryCondition() = default; }; @@ -127,6 +132,16 @@ protected: const std::vector<std::unique_ptr<ProcessLib::ParameterBase>>& parameters); + virtual std::unique_ptr<BoundaryCondition> + createPhaseFieldIrreversibleDamageOracleBoundaryCondition( + const BoundaryConditionConfig& config, + const NumLib::LocalToGlobalIndexMap& dof_table, + const MeshLib::Mesh& mesh, const int variable_id, + const unsigned /*integration_order*/, + const unsigned /*shapefunction_order*/, + const std::vector< + std::unique_ptr<ProcessLib::ParameterBase>>& /*parameters*/); + static std::vector<MeshLib::Element*> getClonedElements( MeshGeoToolsLib::BoundaryElementsSearcher& boundary_element_searcher, GeoLib::GeoObject const& geometry); diff --git a/ProcessLib/BoundaryCondition/BoundaryConditionCollection.h b/ProcessLib/BoundaryCondition/BoundaryConditionCollection.h index 42aec640e3fdd9072e9d1216b5a16705586f2d1c..679f76579600208e9c06ea9d56425fb3bfa7ce2d 100644 --- a/ProcessLib/BoundaryCondition/BoundaryConditionCollection.h +++ b/ProcessLib/BoundaryCondition/BoundaryConditionCollection.h @@ -44,6 +44,14 @@ public: NumLib::LocalToGlobalIndexMap const& dof_table, unsigned const integration_order); + void preTimestep(const double t, GlobalVector const& x) + { + for (auto const& bc_ptr : _boundary_conditions) + { + bc_ptr->preTimestep(t, x); + } + } + private: mutable std::vector<NumLib::IndexValueVector<GlobalIndexType>> _dirichlet_bcs; std::vector<std::unique_ptr<BoundaryCondition>> _boundary_conditions; diff --git a/ProcessLib/BoundaryCondition/PhaseFieldIrreversibleDamageOracleBoundaryCondition.cpp b/ProcessLib/BoundaryCondition/PhaseFieldIrreversibleDamageOracleBoundaryCondition.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bc72d5b47334e51860f4ee502c9b6b6797c7312e --- /dev/null +++ b/ProcessLib/BoundaryCondition/PhaseFieldIrreversibleDamageOracleBoundaryCondition.cpp @@ -0,0 +1,85 @@ +/** + * \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 "PhaseFieldIrreversibleDamageOracleBoundaryCondition.h" + +#include <algorithm> +#include <logog/include/logog.hpp> +#include <vector> +#include "ProcessLib/Utils/ProcessUtils.h" + +namespace ProcessLib +{ +void PhaseFieldIrreversibleDamageOracleBoundaryCondition::getEssentialBCValues( + const double /*t*/, + NumLib::IndexValueVector<GlobalIndexType>& bc_values) const +{ + SpatialPosition pos; + + bc_values.ids.clear(); + bc_values.values.clear(); + + // convert mesh node ids to global index for the given component + bc_values.ids.reserve(bc_values.ids.size() + _bc_values.ids.size()); + bc_values.values.reserve(bc_values.values.size() + + _bc_values.values.size()); + + std::copy(_bc_values.ids.begin(), _bc_values.ids.end(), + std::back_inserter(bc_values.ids)); + std::copy(_bc_values.values.begin(), _bc_values.values.end(), + std::back_inserter(bc_values.values)); +} + +// update new values and corresponding indices. +void PhaseFieldIrreversibleDamageOracleBoundaryCondition::preTimestep( + const double /*t*/, const GlobalVector& x) +{ + // phase-field variable is considered irreversible if it loses more than 95% + // of the stiffness, which is a widely used threshold. + double irreversibleDamage = 0.05; + + _bc_values.ids.clear(); + _bc_values.values.clear(); + + auto const mesh_id = _mesh.getID(); + auto const& nodes = _mesh.getNodes(); + for (auto const* n : nodes) + { + std::size_t node_id = n->getID(); + MeshLib::Location l(mesh_id, MeshLib::MeshItemType::Node, node_id); + const auto g_idx = + _dof_table.getGlobalIndex(l, _variable_id, _component_id); + + if (x[node_id] <= irreversibleDamage) + { + _bc_values.ids.emplace_back(g_idx); + _bc_values.values.emplace_back(0.0); + } + } +} + +std::unique_ptr<PhaseFieldIrreversibleDamageOracleBoundaryCondition> +createPhaseFieldIrreversibleDamageOracleBoundaryCondition( + BaseLib::ConfigTree const& config, + NumLib::LocalToGlobalIndexMap const& dof_table, MeshLib::Mesh const& mesh, + int const variable_id, int const component_id) +{ + DBUG( + "Constructing PhaseFieldIrreversibleDamageOracleBoundaryCondition from " + "config."); + //! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__type} + config.checkConfigParameter( + "type", "PhaseFieldIrreversibleDamageOracleBoundaryCondition"); + + return std::make_unique< + PhaseFieldIrreversibleDamageOracleBoundaryCondition>( + dof_table, mesh, variable_id, component_id); +} + +} // namespace ProcessLib diff --git a/ProcessLib/BoundaryCondition/PhaseFieldIrreversibleDamageOracleBoundaryCondition.h b/ProcessLib/BoundaryCondition/PhaseFieldIrreversibleDamageOracleBoundaryCondition.h new file mode 100644 index 0000000000000000000000000000000000000000..9afa9f2426c3ceeb3016736c3ea7f5538cf87788 --- /dev/null +++ b/ProcessLib/BoundaryCondition/PhaseFieldIrreversibleDamageOracleBoundaryCondition.h @@ -0,0 +1,66 @@ +/** + * \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 "BoundaryCondition.h" +#include "NumLib/DOF/LocalToGlobalIndexMap.h" +#include "NumLib/IndexValueVector.h" +#include "ProcessLib/Parameter/Parameter.h" + +namespace ProcessLib +{ +class PhaseFieldIrreversibleDamageOracleBoundaryCondition final + : public BoundaryCondition +{ +public: + PhaseFieldIrreversibleDamageOracleBoundaryCondition( + NumLib::LocalToGlobalIndexMap const& dof_table, + MeshLib::Mesh const& mesh, int const variable_id, + int const component_id) + : _dof_table(dof_table), + _mesh(mesh), + _variable_id(variable_id), + _component_id(component_id) + { + if (variable_id >= static_cast<int>(dof_table.getNumberOfVariables()) || + component_id >= + dof_table.getNumberOfVariableComponents(variable_id)) + { + OGS_FATAL( + "Variable id or component id too high. Actual values: (%d, " + "%d), " + "maximum values: (%d, %d).", + variable_id, component_id, dof_table.getNumberOfVariables(), + dof_table.getNumberOfVariableComponents(variable_id)); + } + } + + void getEssentialBCValues( + const double t, + NumLib::IndexValueVector<GlobalIndexType>& bc_values) const override; + + void preTimestep(const double t, const GlobalVector& x) override; + +private: + NumLib::LocalToGlobalIndexMap const& _dof_table; + MeshLib::Mesh const& _mesh; + int const _variable_id; + int const _component_id; + + NumLib::IndexValueVector<GlobalIndexType> _bc_values; +}; + +std::unique_ptr<PhaseFieldIrreversibleDamageOracleBoundaryCondition> +createPhaseFieldIrreversibleDamageOracleBoundaryCondition( + BaseLib::ConfigTree const& config, + NumLib::LocalToGlobalIndexMap const& dof_table, MeshLib::Mesh const& mesh, + int const variable_id, int const component_id); + +} // namespace ProcessLib diff --git a/ProcessLib/PhaseField/CreatePhaseFieldProcess.cpp b/ProcessLib/PhaseField/CreatePhaseFieldProcess.cpp index 8116905574936e1471daebded5a895bc4545687b..674bb831fa55c0baada25f33375e133cdd087fbc 100644 --- a/ProcessLib/PhaseField/CreatePhaseFieldProcess.cpp +++ b/ProcessLib/PhaseField/CreatePhaseFieldProcess.cpp @@ -22,7 +22,6 @@ namespace ProcessLib { namespace PhaseField { - template <int DisplacementDim> std::unique_ptr<Process> createPhaseFieldProcess( MeshLib::Mesh& mesh, @@ -56,9 +55,9 @@ std::unique_ptr<Process> createPhaseFieldProcess( auto per_process_variables = findProcessVariables( variables, pv_config, {//! \ogs_file_param_special{prj__processes__process__PHASE_FIELD__process_variables__phasefield} - "phasefield", + "phasefield", //! \ogs_file_param_special{prj__processes__process__PHASE_FIELD__process_variables__displacement} - "displacement"}); + "displacement"}); variable_ph = &per_process_variables[0].get(); variable_u = &per_process_variables[1].get(); process_variables.push_back(std::move(per_process_variables)); @@ -66,14 +65,14 @@ std::unique_ptr<Process> createPhaseFieldProcess( else // staggered scheme. { using namespace std::string_literals; - for (auto const& variable_name : {"phasefield"s, "displacement"s}) + for (auto const& variable_name : {"displacement"s, "phasefield"s}) { auto per_process_variables = findProcessVariables(variables, pv_config, {variable_name}); process_variables.push_back(std::move(per_process_variables)); } - variable_ph = &process_variables[0][0].get(); - variable_u = &process_variables[1][0].get(); + variable_u = &process_variables[0][0].get(); + variable_ph = &process_variables[1][0].get(); } DBUG("Associate displacement with process variable \'%s\'.", @@ -94,7 +93,7 @@ std::unique_ptr<Process> createPhaseFieldProcess( if (variable_ph->getNumberOfComponents() != 1) { OGS_FATAL( - "Pressure process variable '%s' is not a scalar variable but has " + "Phasefield process variable '%s' is not a scalar variable but has " "%d components.", variable_ph->getName().c_str(), variable_ph->getNumberOfComponents()); @@ -118,11 +117,13 @@ std::unique_ptr<Process> createPhaseFieldProcess( material = nullptr; if (type == "LinearElasticIsotropic") { - auto elastic_model = MaterialLib::Solids::createLinearElasticIsotropic< - DisplacementDim>(parameters, constitutive_relation_config); - material = - std::make_unique<MaterialLib::Solids::LinearElasticIsotropicPhaseField< - DisplacementDim>>(std::move(elastic_model->getMaterialProperties())); + auto elastic_model = + MaterialLib::Solids::createLinearElasticIsotropic<DisplacementDim>( + parameters, constitutive_relation_config); + material = std::make_unique< + MaterialLib::Solids::LinearElasticIsotropicPhaseField< + DisplacementDim>>( + std::move(elastic_model->getMaterialProperties())); } else { @@ -191,10 +192,29 @@ std::unique_ptr<Process> createPhaseFieldProcess( std::copy_n(b.data(), b.size(), specific_body_force.data()); } + auto const crack_scheme = + //! \ogs_file_param{prj__processes__process__PHASE_FIELD__hydro_crack_scheme} + config.getConfigParameterOptional<std::string>("hydro_crack_scheme"); + if (crack_scheme && + ((*crack_scheme != "propagating") && (*crack_scheme != "static"))) + { + OGS_FATAL( + "hydro_crack_scheme must be \"propagating\" or \"static\" but " + "\"%s\" was given", + crack_scheme->c_str()); + } + + const bool propagating_crack = + (crack_scheme && (*crack_scheme == "propagating")); + const bool crack_pressure = + (crack_scheme && + ((*crack_scheme == "propagating") || (*crack_scheme == "static"))); + PhaseFieldProcessData<DisplacementDim> process_data{ std::move(material), residual_stiffness, crack_resistance, crack_length_scale, kinetic_coefficient, solid_density, - history_field, specific_body_force}; + history_field, specific_body_force, propagating_crack, + crack_pressure}; SecondaryVariableCollection secondary_variables; @@ -205,10 +225,10 @@ std::unique_ptr<Process> createPhaseFieldProcess( named_function_caller); return std::make_unique<PhaseFieldProcess<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); + 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> createPhaseFieldProcess<2>( diff --git a/ProcessLib/PhaseField/LocalAssemblerInterface.h b/ProcessLib/PhaseField/LocalAssemblerInterface.h index 72d970218ebd0f1f2a9ba77e4152147b6124c1d9..b0953d7ab36aa04e7d28d31ebee4b9fd76a9598c 100644 --- a/ProcessLib/PhaseField/LocalAssemblerInterface.h +++ b/ProcessLib/PhaseField/LocalAssemblerInterface.h @@ -18,82 +18,40 @@ namespace ProcessLib { namespace PhaseField { - struct PhaseFieldLocalAssemblerInterface : public ProcessLib::LocalAssemblerInterface, public NumLib::ExtrapolatableElement { - virtual std::vector<double> const& getIntPtSigmaXX( + 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& getIntPtSigmaYY( + 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& getIntPtSigmaZZ( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const = 0; - - virtual std::vector<double> const& getIntPtSigmaXY( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const = 0; - - virtual std::vector<double> const& getIntPtSigmaXZ( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const = 0; - - virtual std::vector<double> const& getIntPtSigmaYZ( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const = 0; - - virtual std::vector<double> const& getIntPtEpsilonXX( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const = 0; + virtual void computeCrackIntegral( + std::size_t mesh_item_id, + std::vector< + std::reference_wrapper<NumLib::LocalToGlobalIndexMap>> const& + dof_tables, + GlobalVector const& x, double const t, double& crack_volume, + bool const use_monolithic_scheme, + CoupledSolutionsForStaggeredScheme const* const cpl_xs) = 0; - virtual std::vector<double> const& getIntPtEpsilonYY( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const = 0; - - virtual std::vector<double> const& getIntPtEpsilonZZ( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const = 0; - - virtual std::vector<double> const& getIntPtEpsilonXY( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const = 0; - - virtual std::vector<double> const& getIntPtEpsilonXZ( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const = 0; - - virtual std::vector<double> const& getIntPtEpsilonYZ( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const = 0; + virtual void computeEnergy( + std::size_t mesh_item_id, + std::vector< + std::reference_wrapper<NumLib::LocalToGlobalIndexMap>> const& + dof_tables, + GlobalVector const& x, double const t, double& elastic_energy, + double& surface_energy, double& pressure_work, + bool const use_monolithic_scheme, + CoupledSolutionsForStaggeredScheme const* const cpl_xs) = 0; }; } // namespace PhaseField diff --git a/ProcessLib/PhaseField/PhaseFieldFEM-impl.h b/ProcessLib/PhaseField/PhaseFieldFEM-impl.h new file mode 100644 index 0000000000000000000000000000000000000000..e44074d184cc413d46ce14689df25e55cc978218 --- /dev/null +++ b/ProcessLib/PhaseField/PhaseFieldFEM-impl.h @@ -0,0 +1,585 @@ +/** + * \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 PhaseFieldFEM-impl.h + * Created on January 8, 2018, 3:00 PM + */ +#pragma once + +#include "NumLib/DOF/DOFTableUtil.h" +#include "ProcessLib/CoupledSolutionsForStaggeredScheme.h" + +namespace ProcessLib +{ +namespace PhaseField +{ +template <typename ShapeFunction, typename IntegrationMethod, + int DisplacementDim> +void PhaseFieldLocalAssembler<ShapeFunction, 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) +{ + using RhsVector = + typename ShapeMatricesType::template VectorType<phasefield_size + + displacement_size>; + using JacobianMatrix = typename ShapeMatricesType::template MatrixType< + phasefield_size + displacement_size, + phasefield_size + displacement_size>; + + auto const local_matrix_size = local_x.size(); + assert(local_matrix_size == phasefield_size + displacement_size); + + auto d = Eigen::Map< + typename ShapeMatricesType::template VectorType<phasefield_size> const>( + local_x.data() + phasefield_index, phasefield_size); + + auto u = Eigen::Map<typename ShapeMatricesType::template VectorType< + displacement_size> const>(local_x.data() + displacement_index, + displacement_size); + + auto d_dot = Eigen::Map< + typename ShapeMatricesType::template VectorType<phasefield_size> const>( + local_xdot.data() + phasefield_index, phasefield_size); + + auto local_Jac = MathLib::createZeroedMatrix<JacobianMatrix>( + local_Jac_data, local_matrix_size, local_matrix_size); + + auto local_rhs = MathLib::createZeroedVector<RhsVector>(local_rhs_data, + local_matrix_size); + + typename ShapeMatricesType::template MatrixType<displacement_size, + phasefield_size> + Kud; + Kud.setZero(displacement_size, phasefield_size); + + typename ShapeMatricesType::template MatrixType<phasefield_size, + displacement_size> + Kdu; + Kdu.setZero(phasefield_size, displacement_size); + + typename ShapeMatricesType::NodalMatrixType Kdd; + Kdd.setZero(phasefield_size, phasefield_size); + + typename ShapeMatricesType::NodalMatrixType Ddd; + Ddd.setZero(phasefield_size, phasefield_size); + + double const& dt = _process_data.dt; + + 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 = _ip_data[ip].N; + auto const& dNdx = _ip_data[ip].dNdx; + + auto const x_coord = + interpolateXCoordinate<ShapeFunction, ShapeMatricesType>(_element, + N); + auto const& B = + LinearBMatrix::computeBMatrix<DisplacementDim, + ShapeFunction::NPOINTS, + typename BMatricesType::BMatrixType>( + dNdx, N, x_coord, _is_axially_symmetric); + + auto const& C_tensile = _ip_data[ip].C_tensile; + auto const& C_compressive = _ip_data[ip].C_compressive; + + auto& eps = _ip_data[ip].eps; + auto const& strain_energy_tensile = _ip_data[ip].strain_energy_tensile; + auto const& sigma_tensile = _ip_data[ip].sigma_tensile; + + auto& history_variable = _ip_data[ip].history_variable; + auto& history_variable_prev = _ip_data[ip].history_variable_prev; + + auto const& sigma_real = _ip_data[ip].sigma_real; + + // Kdd_1 defines one term which both used in Kdd and local_rhs for + // phase field + double const gc = _process_data.crack_resistance(t, x_position)[0]; + double const ls = _process_data.crack_length_scale(t, x_position)[0]; + typename ShapeMatricesType::NodalMatrixType const Kdd_1 = + dNdx.transpose() * 2 * gc * ls * dNdx; + + // + // displacement equation, displacement part + // + double const k = _process_data.residual_stiffness(t, x_position)[0]; + double const d_ip = N.dot(d); + double const degradation = d_ip * d_ip * (1 - k) + k; + eps.noalias() = B * u; + _ip_data[ip].updateConstitutiveRelation(t, x_position, dt, u, + degradation); + + local_Jac + .template block<displacement_size, displacement_size>( + displacement_index, displacement_index) + .noalias() += + B.transpose() * (degradation * C_tensile + C_compressive) * B * w; + + typename ShapeMatricesType::template MatrixType<DisplacementDim, + displacement_size> + N_u = ShapeMatricesType::template MatrixType< + DisplacementDim, displacement_size>::Zero(DisplacementDim, + displacement_size); + + for (int i = 0; i < DisplacementDim; ++i) + N_u.template block<1, displacement_size / DisplacementDim>( + i, i * displacement_size / DisplacementDim) + .noalias() = N; + + auto const rho_sr = _process_data.solid_density(t, x_position)[0]; + auto const& b = _process_data.specific_body_force; + local_rhs.template block<displacement_size, 1>(displacement_index, 0) + .noalias() -= + (B.transpose() * sigma_real - N_u.transpose() * rho_sr * b) * w; + + // + // displacement equation, phasefield part + // + + // Temporary storage used in the Kud and for potential reuse in the + // Kdu matrix. + auto const Kud_ip_contribution = + (B.transpose() * 2 * d_ip * sigma_tensile * N * w).eval(); + + Kud.noalias() += Kud_ip_contribution; + + if (history_variable_prev < strain_energy_tensile) + { + history_variable = strain_energy_tensile; + Kdu.noalias() += Kud_ip_contribution.transpose(); + } + else + { + history_variable = history_variable_prev; + } + + // + // phasefield equation, phasefield part. + // + Kdd.noalias() += (Kdd_1 + N.transpose() * 2 * history_variable * N + + N.transpose() * 0.5 * gc / ls * N) * + w; + double const M = _process_data.kinetic_coefficient(t, x_position)[0]; + double const d_dot_ip = N.dot(d_dot); + + local_rhs.template segment<phasefield_size>(phasefield_index) + .noalias() -= (N.transpose() * d_dot_ip / M + Kdd_1 * d + + N.transpose() * d_ip * 2 * history_variable - + N.transpose() * 0.5 * gc / ls * (1 - d_ip)) * + w; + + Ddd.noalias() += N.transpose() / M * N * w; + } + // displacement equation, phasefield part + local_Jac + .template block<displacement_size, phasefield_size>(displacement_index, + phasefield_index) + .noalias() += Kud; + + // phasefield equation, phasefield part. + local_Jac + .template block<phasefield_size, phasefield_size>(phasefield_index, + phasefield_index) + .noalias() += Kdd + Ddd / dt; + + // phasefield equation, displacement part. + local_Jac + .template block<phasefield_size, displacement_size>(phasefield_index, + displacement_index) + .noalias() += Kdu; +} + +template <typename ShapeFunction, typename IntegrationMethod, + int DisplacementDim> +void PhaseFieldLocalAssembler<ShapeFunction, IntegrationMethod, + DisplacementDim>:: + 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) +{ + // For the equations with phase field. + if (local_coupled_solutions.process_id == 1) + { + assembleWithJacobianPhaseFiledEquations( + 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 ShapeFunction, typename IntegrationMethod, + int DisplacementDim> +void PhaseFieldLocalAssembler<ShapeFunction, IntegrationMethod, + DisplacementDim>:: + 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) +{ + using DeformationVector = + typename ShapeMatricesType::template VectorType<displacement_size>; + using DeformationMatrix = + typename ShapeMatricesType::template MatrixType<displacement_size, + displacement_size>; + using PhaseFieldVector = + typename ShapeMatricesType::template VectorType<phasefield_size>; + + auto const& local_u = local_coupled_solutions.local_coupled_xs[0]; + auto const& local_d = local_coupled_solutions.local_coupled_xs[1]; + assert(local_u.size() == displacement_size); + assert(local_d.size() == phasefield_size); + + auto const local_matrix_size = local_u.size(); + auto d = + Eigen::Map<PhaseFieldVector const>(local_d.data(), phasefield_size); + + auto u = + Eigen::Map<DeformationVector const>(local_u.data(), displacement_size); + + auto local_Jac = MathLib::createZeroedMatrix<DeformationMatrix>( + local_Jac_data, local_matrix_size, local_matrix_size); + + auto local_rhs = MathLib::createZeroedVector<DeformationVector>( + local_b_data, local_matrix_size); + + SpatialPosition x_position; + x_position.setElementID(_element.getID()); + double const& dt = _process_data.dt; + + auto local_pressure = 0.0; + if (_process_data.crack_pressure) + local_pressure = _process_data.unity_pressure; + + int const n_integration_points = _integration_method.getNumberOfPoints(); + for (int ip = 0; ip < n_integration_points; ip++) + { + x_position.setIntegrationPoint(ip); + auto const& w = _ip_data[ip].integration_weight; + auto const& N = _ip_data[ip].N; + auto const& dNdx = _ip_data[ip].dNdx; + + auto const x_coord = + interpolateXCoordinate<ShapeFunction, ShapeMatricesType>(_element, + N); + + auto const& B = + LinearBMatrix::computeBMatrix<DisplacementDim, + ShapeFunction::NPOINTS, + typename BMatricesType::BMatrixType>( + dNdx, N, x_coord, _is_axially_symmetric); + + auto& eps = _ip_data[ip].eps; + eps.noalias() = B * u; + double const k = _process_data.residual_stiffness(t, x_position)[0]; + double const d_ip = N.dot(d); + double const degradation = d_ip * d_ip * (1 - k) + k; + _ip_data[ip].updateConstitutiveRelation(t, x_position, dt, u, + degradation); + + auto& sigma_real = _ip_data[ip].sigma_real; + auto const& C_tensile = _ip_data[ip].C_tensile; + auto const& C_compressive = _ip_data[ip].C_compressive; + + typename ShapeMatricesType::template MatrixType<DisplacementDim, + displacement_size> + N_u = ShapeMatricesType::template MatrixType< + DisplacementDim, displacement_size>::Zero(DisplacementDim, + displacement_size); + + for (int i = 0; i < DisplacementDim; ++i) + N_u.template block<1, displacement_size / DisplacementDim>( + i, i * displacement_size / DisplacementDim) + .noalias() = N; + + auto const rho_sr = _process_data.solid_density(t, x_position)[0]; + auto const& b = _process_data.specific_body_force; + + local_rhs.noalias() -= + (B.transpose() * sigma_real - N_u.transpose() * rho_sr * b - + local_pressure * N_u.transpose() * dNdx * d) * + w; + + local_Jac.noalias() += + B.transpose() * (degradation * C_tensile + C_compressive) * B * w; + } +} + +template <typename ShapeFunction, typename IntegrationMethod, + int DisplacementDim> +void PhaseFieldLocalAssembler<ShapeFunction, IntegrationMethod, + DisplacementDim>:: + assembleWithJacobianPhaseFiledEquations( + 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) +{ + using DeformationVector = + typename ShapeMatricesType::template VectorType<displacement_size>; + using PhaseFieldVector = + typename ShapeMatricesType::template VectorType<phasefield_size>; + using PhaseFieldMatrix = + typename ShapeMatricesType::template MatrixType<phasefield_size, + phasefield_size>; + + auto const& local_u = local_coupled_solutions.local_coupled_xs[0]; + auto const& local_d = local_coupled_solutions.local_coupled_xs[1]; + assert(local_u.size() == displacement_size); + assert(local_d.size() == phasefield_size); + + auto const local_matrix_size = local_d.size(); + auto d = + Eigen::Map<PhaseFieldVector const>(local_d.data(), phasefield_size); + auto u = + Eigen::Map<DeformationVector const>(local_u.data(), displacement_size); + + auto local_Jac = MathLib::createZeroedMatrix<PhaseFieldMatrix>( + local_Jac_data, local_matrix_size, local_matrix_size); + auto local_rhs = MathLib::createZeroedVector<PhaseFieldVector>( + local_b_data, local_matrix_size); + + SpatialPosition x_position; + x_position.setElementID(_element.getID()); + double const& dt = _process_data.dt; + + auto local_pressure = 0.0; + if (_process_data.crack_pressure) + local_pressure = _process_data.unity_pressure; + else if (_process_data.propagating_crack) + local_pressure = _process_data.pressure; + + int const n_integration_points = _integration_method.getNumberOfPoints(); + for (int ip = 0; ip < n_integration_points; ip++) + { + x_position.setIntegrationPoint(ip); + auto const& w = _ip_data[ip].integration_weight; + auto const& N = _ip_data[ip].N; + auto const& dNdx = _ip_data[ip].dNdx; + + double const gc = _process_data.crack_resistance(t, x_position)[0]; + double const ls = _process_data.crack_length_scale(t, x_position)[0]; + + // for propagating crack, u is rescaled. + if (_process_data.propagating_crack) + { + double const k = _process_data.residual_stiffness(t, x_position)[0]; + double const d_ip = N.dot(d); + double const degradation = d_ip * d_ip * (1 - k) + k; + auto const x_coord = + interpolateXCoordinate<ShapeFunction, ShapeMatricesType>( + _element, N); + auto const& B = LinearBMatrix::computeBMatrix< + DisplacementDim, ShapeFunction::NPOINTS, + typename BMatricesType::BMatrixType>(dNdx, N, x_coord, + _is_axially_symmetric); + + auto& eps = _ip_data[ip].eps; + eps.noalias() = B * u; + _ip_data[ip].updateConstitutiveRelation(t, x_position, dt, u, + degradation); + } + + auto const& strain_energy_tensile = _ip_data[ip].strain_energy_tensile; + + auto& ip_data = _ip_data[ip]; + ip_data.strain_energy_tensile = strain_energy_tensile; + + typename ShapeMatricesType::template MatrixType<DisplacementDim, + displacement_size> + N_u = ShapeMatricesType::template MatrixType< + DisplacementDim, displacement_size>::Zero(DisplacementDim, + displacement_size); + + for (int i = 0; i < DisplacementDim; ++i) + N_u.template block<1, displacement_size / DisplacementDim>( + i, i * displacement_size / DisplacementDim) + .noalias() = N; + + local_Jac.noalias() += + (2 * N.transpose() * N * strain_energy_tensile + + gc * (N.transpose() * N / ls + dNdx.transpose() * dNdx * ls)) * + w; + + local_rhs.noalias() -= + (N.transpose() * N * d * 2 * strain_energy_tensile + + gc * ((N.transpose() * N / ls + dNdx.transpose() * dNdx * ls) * d - + N.transpose() / ls) - + local_pressure * dNdx.transpose() * N_u * u) * + w; + } +} + +template <typename ShapeFunction, typename IntegrationMethod, + int DisplacementDim> +void PhaseFieldLocalAssembler<ShapeFunction, IntegrationMethod, + DisplacementDim>:: + computeCrackIntegral(std::size_t mesh_item_id, + std::vector<std::reference_wrapper< + NumLib::LocalToGlobalIndexMap>> const& dof_tables, + GlobalVector const& /*x*/, double const /*t*/, + double& crack_volume, + bool const /*use_monolithic_scheme*/, + CoupledSolutionsForStaggeredScheme const* const cpl_xs) +{ + assert(cpl_xs != nullptr); + + std::vector<std::vector<GlobalIndexType>> indices_of_processes; + indices_of_processes.reserve(dof_tables.size()); + std::transform(dof_tables.begin(), dof_tables.end(), + std::back_inserter(indices_of_processes), + [&](NumLib::LocalToGlobalIndexMap const& dof_table) { + return NumLib::getIndices(mesh_item_id, dof_table); + }); + + auto local_coupled_xs = + getCurrentLocalSolutions(*cpl_xs, indices_of_processes); + assert(local_coupled_xs.size() == 2); + + auto const& local_u = local_coupled_xs[0]; + auto const& local_d = local_coupled_xs[1]; + + assert(local_u.size() == displacement_size); + assert(local_d.size() == phasefield_size); + + auto d = Eigen::Map< + typename ShapeMatricesType::template VectorType<phasefield_size> const>( + local_d.data(), phasefield_size); + + auto u = Eigen::Map<typename ShapeMatricesType::template VectorType< + displacement_size> const>(local_u.data(), displacement_size); + + 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& w = _ip_data[ip].integration_weight; + auto const& N = _ip_data[ip].N; + auto const& dNdx = _ip_data[ip].dNdx; + + typename ShapeMatricesType::template MatrixType<DisplacementDim, + displacement_size> + N_u = ShapeMatricesType::template MatrixType< + DisplacementDim, displacement_size>::Zero(DisplacementDim, + displacement_size); + + for (int i = 0; i < DisplacementDim; ++i) + N_u.template block<1, displacement_size / DisplacementDim>( + i, i * displacement_size / DisplacementDim) + .noalias() = N; + + crack_volume += (N_u * u).dot(dNdx * d) * w; + } +} + +template <typename ShapeFunction, typename IntegrationMethod, + int DisplacementDim> +void PhaseFieldLocalAssembler<ShapeFunction, IntegrationMethod, + DisplacementDim>:: + computeEnergy(std::size_t mesh_item_id, + std::vector<std::reference_wrapper< + NumLib::LocalToGlobalIndexMap>> const& dof_tables, + GlobalVector const& /*x*/, double const t, + double& elastic_energy, double& surface_energy, + double& pressure_work, bool const /*use_monolithic_scheme*/, + CoupledSolutionsForStaggeredScheme const* const cpl_xs) +{ + assert(cpl_xs != nullptr); + + std::vector<std::vector<GlobalIndexType>> indices_of_processes; + indices_of_processes.reserve(dof_tables.size()); + std::transform(dof_tables.begin(), dof_tables.end(), + std::back_inserter(indices_of_processes), + [&](NumLib::LocalToGlobalIndexMap const& dof_table) { + return NumLib::getIndices(mesh_item_id, dof_table); + }); + + auto local_coupled_xs = + getCurrentLocalSolutions(*cpl_xs, indices_of_processes); + assert(local_coupled_xs.size() == 2); + + auto const& local_u = local_coupled_xs[0]; + auto const& local_d = local_coupled_xs[1]; + + assert(local_u.size() == displacement_size); + assert(local_d.size() == phasefield_size); + + auto d = Eigen::Map< + typename ShapeMatricesType::template VectorType<phasefield_size> const>( + local_d.data(), phasefield_size); + + auto u = Eigen::Map<typename ShapeMatricesType::template VectorType< + displacement_size> const>(local_u.data(), displacement_size); + + 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& w = _ip_data[ip].integration_weight; + auto const& N = _ip_data[ip].N; + auto const& dNdx = _ip_data[ip].dNdx; + double const d_ip = N.dot(d); + auto pressure_ip = _process_data.pressure; + auto u_corrected = pressure_ip * u; + double const gc = _process_data.crack_resistance(t, x_position)[0]; + double const ls = _process_data.crack_length_scale(t, x_position)[0]; + + typename ShapeMatricesType::template MatrixType<DisplacementDim, + displacement_size> + N_u = ShapeMatricesType::template MatrixType< + DisplacementDim, displacement_size>::Zero(DisplacementDim, + displacement_size); + + for (int i = 0; i < DisplacementDim; ++i) + N_u.template block<1, displacement_size / DisplacementDim>( + i, i * displacement_size / DisplacementDim) + .noalias() = N; + + elastic_energy += _ip_data[ip].elastic_energy * w; + + surface_energy += + 0.5 * gc * + ((1 - d_ip) * (1 - d_ip) / ls + (dNdx * d).dot((dNdx * d)) * ls) * + w; + + if (_process_data.crack_pressure) + pressure_work += + pressure_ip * (N_u * u_corrected).dot(dNdx * d) * w; + } +} +} // namespace PhaseField +} // namespace ProcessLib diff --git a/ProcessLib/PhaseField/PhaseFieldFEM.h b/ProcessLib/PhaseField/PhaseFieldFEM.h index c9bde13feaba2385cff617d1b59af6ecdcf7bce7..c168e0f8089fe25feed65af7c57f6f056d6fbc65 100644 --- a/ProcessLib/PhaseField/PhaseFieldFEM.h +++ b/ProcessLib/PhaseField/PhaseFieldFEM.h @@ -46,7 +46,7 @@ struct IntegrationPointData final typename BMatricesType::KelvinVectorType sigma_tensile, sigma_compressive, sigma_real_prev, sigma_real; - double strain_energy_tensile; + double strain_energy_tensile, elastic_energy; MaterialLib::Solids::MechanicsBase<DisplacementDim>& solid_material; std::unique_ptr<typename MaterialLib::Solids::MechanicsBase< @@ -81,7 +81,7 @@ struct IntegrationPointData final .calculateDegradedStress(t, x_position, eps, strain_energy_tensile, sigma_tensile, sigma_compressive, C_tensile, C_compressive, sigma_real, - degradation); + degradation, elastic_energy); } EIGEN_MAKE_ALIGNED_OPERATOR_NEW; }; @@ -101,18 +101,12 @@ class PhaseFieldLocalAssembler : public PhaseFieldLocalAssemblerInterface public: using ShapeMatricesType = ShapeMatrixPolicyType<ShapeFunction, DisplacementDim>; - // Types for displacement. // (Higher order elements = ShapeFunction). using ShapeMatrices = typename ShapeMatricesType::ShapeMatrices; using BMatricesType = BMatrixPolicyType<ShapeFunction, DisplacementDim>; using NodalForceVectorType = typename BMatricesType::NodalForceVectorType; - using RhsVector = typename ShapeMatricesType::template VectorType< - ShapeFunction::NPOINTS + ShapeFunction::NPOINTS * DisplacementDim>; - using JacobianMatrix = typename ShapeMatricesType::template MatrixType< - ShapeFunction::NPOINTS + ShapeFunction::NPOINTS * DisplacementDim, - ShapeFunction::NPOINTS + ShapeFunction::NPOINTS * DisplacementDim>; PhaseFieldLocalAssembler(PhaseFieldLocalAssembler const&) = delete; PhaseFieldLocalAssembler(PhaseFieldLocalAssembler&&) = delete; @@ -166,6 +160,8 @@ public: ip_data.history_variable_prev = _process_data.history_field(0, x_position)[0]; ip_data.sigma_real.setZero(kelvin_vector_size); + ip_data.strain_energy_tensile = 0.0; + ip_data.elastic_energy = 0.0; ip_data.N = shape_matrices[ip].N; ip_data.dNdx = shape_matrices[ip].dNdx; @@ -191,180 +187,14 @@ public: 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 - { - auto const local_matrix_size = local_x.size(); - assert(local_matrix_size == phasefield_size + displacement_size); - - auto d = Eigen::Map<typename ShapeMatricesType::template VectorType< - phasefield_size> const>(local_x.data() + phasefield_index, - phasefield_size); - - auto u = Eigen::Map<typename ShapeMatricesType::template VectorType< - displacement_size> const>(local_x.data() + displacement_index, - displacement_size); - - auto d_dot = Eigen::Map<typename ShapeMatricesType::template VectorType< - phasefield_size> const>(local_xdot.data() + phasefield_index, - phasefield_size); - - auto local_Jac = MathLib::createZeroedMatrix<JacobianMatrix>( - local_Jac_data, local_matrix_size, local_matrix_size); - - auto local_rhs = MathLib::createZeroedVector<RhsVector>( - local_rhs_data, local_matrix_size); + std::vector<double>& local_Jac_data) override; - typename ShapeMatricesType::template MatrixType<displacement_size, - phasefield_size> - Kud; - Kud.setZero(displacement_size, phasefield_size); - - typename ShapeMatricesType::template MatrixType<phasefield_size, - displacement_size> - Kdu; - Kdu.setZero(phasefield_size, displacement_size); - - typename ShapeMatricesType::NodalMatrixType Kdd; - Kdd.setZero(phasefield_size, phasefield_size); - - typename ShapeMatricesType::NodalMatrixType Ddd; - Ddd.setZero(phasefield_size, phasefield_size); - - double const& dt = _process_data.dt; - - 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 = _ip_data[ip].N; - auto const& dNdx = _ip_data[ip].dNdx; - - auto const x_coord = - interpolateXCoordinate<ShapeFunction, ShapeMatricesType>( - _element, N); - auto const& B = LinearBMatrix::computeBMatrix< - DisplacementDim, ShapeFunction::NPOINTS, - typename BMatricesType::BMatrixType>(dNdx, N, x_coord, - _is_axially_symmetric); - - auto const& C_tensile = _ip_data[ip].C_tensile; - auto const& C_compressive = _ip_data[ip].C_compressive; - - auto& eps = _ip_data[ip].eps; - auto const& strain_energy_tensile = - _ip_data[ip].strain_energy_tensile; - auto const& sigma_tensile = _ip_data[ip].sigma_tensile; - - auto& history_variable = _ip_data[ip].history_variable; - auto& history_variable_prev = _ip_data[ip].history_variable_prev; - - auto const& sigma_real = _ip_data[ip].sigma_real; - - // Kdd_1 defines one term which both used in Kdd and local_rhs for - // phase field - double const gc = _process_data.crack_resistance(t, x_position)[0]; - double const ls = - _process_data.crack_length_scale(t, x_position)[0]; - typename ShapeMatricesType::NodalMatrixType const Kdd_1 = - dNdx.transpose() * 2 * gc * ls * dNdx; - - // - // displacement equation, displacement part - // - double const k = _process_data.residual_stiffness(t, x_position)[0]; - double const d_ip = N.dot(d); - double const degradation = d_ip * d_ip * (1 - k) + k; - eps.noalias() = B * u; - _ip_data[ip].updateConstitutiveRelation(t, x_position, dt, u, - degradation); - - local_Jac - .template block<displacement_size, displacement_size>( - displacement_index, displacement_index) - .noalias() += B.transpose() * - (degradation * C_tensile + C_compressive) * B * w; - - typename ShapeMatricesType::template MatrixType<DisplacementDim, - displacement_size> - N_u = ShapeMatricesType::template MatrixType< - DisplacementDim, - displacement_size>::Zero(DisplacementDim, - displacement_size); - - for (int i = 0; i < DisplacementDim; ++i) - N_u.template block<1, displacement_size / DisplacementDim>( - i, i * displacement_size / DisplacementDim) - .noalias() = N; - - auto const rho_sr = _process_data.solid_density(t, x_position)[0]; - auto const& b = _process_data.specific_body_force; - local_rhs - .template block<displacement_size, 1>(displacement_index, 0) - .noalias() -= - (B.transpose() * sigma_real - N_u.transpose() * rho_sr * b) * w; - - // - // displacement equation, phasefield part - // - - // Temporary storage used in the Kud and for potential reuse in the - // Kdu matrix. - auto const Kud_ip_contribution = - (B.transpose() * 2 * d_ip * sigma_tensile * N * w).eval(); - - Kud.noalias() += Kud_ip_contribution; - - if (history_variable_prev < strain_energy_tensile) - { - history_variable = strain_energy_tensile; - Kdu.noalias() += Kud_ip_contribution.transpose(); - } - else - { - history_variable = history_variable_prev; - } - - // - // phasefield equation, phasefield part. - // - Kdd.noalias() += (Kdd_1 + N.transpose() * 2 * history_variable * N + - N.transpose() * 0.5 * gc / ls * N) * - w; - double const M = - _process_data.kinetic_coefficient(t, x_position)[0]; - double const d_dot_ip = N.dot(d_dot); - - local_rhs.template segment<phasefield_size>(phasefield_index) - .noalias() -= (N.transpose() * d_dot_ip / M + Kdd_1 * d + - N.transpose() * d_ip * 2 * history_variable - - N.transpose() * 0.5 * gc / ls * (1 - d_ip)) * - w; - - Ddd.noalias() += N.transpose() / M * N * w; - } - // displacement equation, phasefield part - local_Jac - .template block<displacement_size, phasefield_size>( - displacement_index, phasefield_index) - .noalias() += Kud; - - // phasefield equation, phasefield part. - local_Jac - .template block<phasefield_size, phasefield_size>(phasefield_index, - phasefield_index) - .noalias() += Kdd + Ddd / dt; - - // phasefield equation, displacement part. - local_Jac - .template block<phasefield_size, displacement_size>( - phasefield_index, displacement_index) - .noalias() += Kdu; - } + 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*/, @@ -379,6 +209,25 @@ public: } } + void computeCrackIntegral( + std::size_t mesh_item_id, + std::vector< + std::reference_wrapper<NumLib::LocalToGlobalIndexMap>> const& + dof_tables, + GlobalVector const& x, double const t, double& crack_volume, + bool const use_monolithic_scheme, + CoupledSolutionsForStaggeredScheme const* const cpl_xs) override; + + void computeEnergy( + std::size_t mesh_item_id, + std::vector< + std::reference_wrapper<NumLib::LocalToGlobalIndexMap>> const& + dof_tables, + GlobalVector const& x, double const t, double& elastic_energy, + double& surface_energy, double& pressure_work, + bool const use_monolithic_scheme, + CoupledSolutionsForStaggeredScheme const* const cpl_xs) override; + Eigen::Map<const Eigen::RowVectorXd> getShapeMatrix( const unsigned integration_point) const override { @@ -388,152 +237,72 @@ public: return Eigen::Map<const Eigen::RowVectorXd>(N.data(), N.size()); } - std::vector<double> const& getIntPtSigmaXX( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const override - { - return getIntPtSigma(cache, 0); - } - - std::vector<double> const& getIntPtSigmaYY( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const override - { - return getIntPtSigma(cache, 1); - } - - std::vector<double> const& getIntPtSigmaZZ( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const override - { - return getIntPtSigma(cache, 2); - } - - std::vector<double> const& getIntPtSigmaXY( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const override - { - return getIntPtSigma(cache, 3); - } - - std::vector<double> const& getIntPtSigmaYZ( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const override - { - assert(DisplacementDim == 3); - return getIntPtSigma(cache, 4); - } - - std::vector<double> const& getIntPtSigmaXZ( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const override - { - assert(DisplacementDim == 3); - return getIntPtSigma(cache, 5); - } - - std::vector<double> const& getIntPtEpsilonXX( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const override - { - return getIntPtEpsilon(cache, 0); - } - - std::vector<double> const& getIntPtEpsilonYY( +private: + std::vector<double> const& getIntPtSigma( const double /*t*/, GlobalVector const& /*current_solution*/, NumLib::LocalToGlobalIndexMap const& /*dof_table*/, std::vector<double>& cache) const override { - return getIntPtEpsilon(cache, 1); - } + static const int kelvin_vector_size = + MathLib::KelvinVector::KelvinVectorDimensions< + DisplacementDim>::value; + auto const num_intpts = _ip_data.size(); - std::vector<double> const& getIntPtEpsilonZZ( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const override - { - return getIntPtEpsilon(cache, 2); - } + cache.clear(); + auto cache_mat = MathLib::createZeroedMatrix<Eigen::Matrix< + double, kelvin_vector_size, Eigen::Dynamic, Eigen::RowMajor>>( + cache, kelvin_vector_size, num_intpts); - std::vector<double> const& getIntPtEpsilonXY( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const override - { - return getIntPtEpsilon(cache, 3); - } + for (unsigned ip = 0; ip < num_intpts; ++ip) + { + auto const& sigma = _ip_data[ip].sigma_real; + cache_mat.col(ip) = + MathLib::KelvinVector::kelvinVectorToSymmetricTensor(sigma); + } - std::vector<double> const& getIntPtEpsilonYZ( - const double /*t*/, - GlobalVector const& /*current_solution*/, - NumLib::LocalToGlobalIndexMap const& /*dof_table*/, - std::vector<double>& cache) const override - { - assert(DisplacementDim == 3); - return getIntPtEpsilon(cache, 4); + return cache; } - std::vector<double> const& getIntPtEpsilonXZ( + virtual std::vector<double> const& getIntPtEpsilon( const double /*t*/, GlobalVector const& /*current_solution*/, NumLib::LocalToGlobalIndexMap const& /*dof_table*/, std::vector<double>& cache) const override { - assert(DisplacementDim == 3); - return getIntPtEpsilon(cache, 5); - } + auto const kelvin_vector_size = + MathLib::KelvinVector::KelvinVectorDimensions< + DisplacementDim>::value; + auto const num_intpts = _ip_data.size(); -private: - std::vector<double> const& getIntPtSigma(std::vector<double>& cache, - std::size_t const component) const - { cache.clear(); - cache.reserve(_ip_data.size()); + auto cache_mat = MathLib::createZeroedMatrix<Eigen::Matrix< + double, kelvin_vector_size, Eigen::Dynamic, Eigen::RowMajor>>( + cache, kelvin_vector_size, num_intpts); - for (auto const& ip_data : _ip_data) + for (unsigned ip = 0; ip < num_intpts; ++ip) { - if (component < 3) // xx, yy, zz components - cache.push_back(ip_data.sigma_real[component]); - else // mixed xy, yz, xz components - cache.push_back(ip_data.sigma_real[component] / std::sqrt(2)); + auto const& eps = _ip_data[ip].eps; + cache_mat.col(ip) = + MathLib::KelvinVector::kelvinVectorToSymmetricTensor(eps); } return cache; } - std::vector<double> const& getIntPtEpsilon( - std::vector<double>& cache, std::size_t const component) const - { - cache.clear(); - cache.reserve(_ip_data.size()); + void assembleWithJacobianPhaseFiledEquations( + 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); - for (auto const& ip_data : _ip_data) - { - if (component < 3) // xx, yy, zz components - cache.push_back(ip_data.eps[component]); - else // mixed xy, yz, xz components - cache.push_back(ip_data.eps[component] / std::sqrt(2)); - } - - return cache; - } + 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); PhaseFieldProcessData<DisplacementDim>& _process_data; @@ -557,3 +326,5 @@ private: } // namespace PhaseField } // namespace ProcessLib + +#include "PhaseFieldFEM-impl.h" diff --git a/ProcessLib/PhaseField/PhaseFieldProcess-impl.h b/ProcessLib/PhaseField/PhaseFieldProcess-impl.h index eedd3abc08af808b1f93005b477cc099cb09354a..1f49952126b504ec14a73f1c2fe86bf13be79838 100644 --- a/ProcessLib/PhaseField/PhaseFieldProcess-impl.h +++ b/ProcessLib/PhaseField/PhaseFieldProcess-impl.h @@ -11,6 +11,8 @@ #include <cassert> +#include "NumLib/DOF/ComputeSparsityPattern.h" + #include "ProcessLib/Process.h" #include "ProcessLib/SmallDeformation/CreateLocalAssemblers.h" @@ -38,6 +40,12 @@ PhaseFieldProcess<DisplacementDim>::PhaseFieldProcess( use_monolithic_scheme), _process_data(std::move(process_data)) { + // Disable nodal forces for monolithic scheme. + if (!_use_monolithic_scheme) + { + _nodal_forces = MeshLib::getOrCreateMeshProperty<double>( + mesh, "NodalForces", MeshLib::MeshItemType::Node, DisplacementDim); + } } template <int DisplacementDim> @@ -47,18 +55,49 @@ bool PhaseFieldProcess<DisplacementDim>::isLinear() const } template <int DisplacementDim> -void PhaseFieldProcess<DisplacementDim>::initializeConcreteProcess( - NumLib::LocalToGlobalIndexMap const& dof_table, - MeshLib::Mesh const& mesh, - unsigned const integration_order) +MathLib::MatrixSpecifications +PhaseFieldProcess<DisplacementDim>::getMatrixSpecifications( + const int process_id) const { - ProcessLib::SmallDeformation::createLocalAssemblers< - DisplacementDim, PhaseFieldLocalAssembler>( - mesh.getElements(), dof_table, _local_assemblers, - mesh.isAxiallySymmetric(), integration_order, _process_data); + // For the monolithic scheme or the M process (deformation) in the staggered + // scheme. + if (_use_monolithic_scheme || process_id == 0) + { + auto const& l = *_local_to_global_index_map; + return {l.dofSizeWithoutGhosts(), l.dofSizeWithoutGhosts(), + &l.getGhostIndices(), &this->_sparsity_pattern}; + } + + // For staggered scheme and phase field process. + auto const& l = *_local_to_global_index_map_single_component; + return {l.dofSizeWithoutGhosts(), l.dofSizeWithoutGhosts(), + &l.getGhostIndices(), &_sparsity_pattern_with_single_component}; +} + +template <int DisplacementDim> +NumLib::LocalToGlobalIndexMap const& +PhaseFieldProcess<DisplacementDim>::getDOFTable(const int process_id) const +{ + // If monolithic scheme is used or the equation of deformation is solved in + // the staggered scheme. + if (_use_monolithic_scheme || process_id == 0) + { + return *_local_to_global_index_map; + } + + // For the equation of phasefield + return *_local_to_global_index_map_single_component; +} + +template <int DisplacementDim> +void PhaseFieldProcess<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()); // TODO move the two data members somewhere else. - // for extrapolation of secondary variables + // for extrapolation of secondary variables of stress or strain std::vector<MeshLib::MeshSubsets> all_mesh_subsets_single_component; all_mesh_subsets_single_component.emplace_back( _mesh_subset_all_nodes.get()); @@ -68,71 +107,94 @@ void PhaseFieldProcess<DisplacementDim>::initializeConcreteProcess( // by location order is needed for output NumLib::ComponentOrder::BY_LOCATION); - Base::_secondary_variables.addSecondaryVariable( - "sigma_xx", - makeExtrapolator(1, getExtrapolator(), _local_assemblers, - &LocalAssemblerInterface::getIntPtSigmaXX)); + assert(_local_to_global_index_map_single_component); - Base::_secondary_variables.addSecondaryVariable( - "sigma_yy", - makeExtrapolator(1, getExtrapolator(), _local_assemblers, - &LocalAssemblerInterface::getIntPtSigmaYY)); + if (_use_monolithic_scheme) + { + const int process_id = 0; // Only one process in the monolithic scheme. + std::vector<MeshLib::MeshSubsets> all_mesh_subsets; + std::generate_n( + std::back_inserter(all_mesh_subsets), + getProcessVariables(process_id)[1].get().getNumberOfComponents() + + 1, + [&]() { + return MeshLib::MeshSubsets{_mesh_subset_all_nodes.get()}; + }); - Base::_secondary_variables.addSecondaryVariable( - "sigma_zz", - makeExtrapolator(1, getExtrapolator(), _local_assemblers, - &LocalAssemblerInterface::getIntPtSigmaZZ)); + 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 = 0; + std::vector<MeshLib::MeshSubsets> all_mesh_subsets; + std::generate_n( + std::back_inserter(all_mesh_subsets), + getProcessVariables(process_id)[0].get().getNumberOfComponents(), + [&]() { + return MeshLib::MeshSubsets{_mesh_subset_all_nodes.get()}; + }); - Base::_secondary_variables.addSecondaryVariable( - "sigma_xy", - makeExtrapolator(1, getExtrapolator(), _local_assemblers, - &LocalAssemblerInterface::getIntPtSigmaXY)); + 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); - if (DisplacementDim == 3) - { - Base::_secondary_variables.addSecondaryVariable( - "sigma_xz", - makeExtrapolator(1, getExtrapolator(), _local_assemblers, - &LocalAssemblerInterface::getIntPtSigmaXZ)); - - Base::_secondary_variables.addSecondaryVariable( - "sigma_yz", - makeExtrapolator(1, getExtrapolator(), _local_assemblers, - &LocalAssemblerInterface::getIntPtSigmaYZ)); + // For phase field equation. + _sparsity_pattern_with_single_component = + NumLib::computeSparsityPattern( + *_local_to_global_index_map_single_component, _mesh); } +} - Base::_secondary_variables.addSecondaryVariable( - "epsilon_xx", - makeExtrapolator(1, getExtrapolator(), _local_assemblers, - &LocalAssemblerInterface::getIntPtEpsilonXX)); - - Base::_secondary_variables.addSecondaryVariable( - "epsilon_yy", - makeExtrapolator(1, getExtrapolator(), _local_assemblers, - &LocalAssemblerInterface::getIntPtEpsilonYY)); +template <int DisplacementDim> +void PhaseFieldProcess<DisplacementDim>::initializeConcreteProcess( + NumLib::LocalToGlobalIndexMap const& dof_table, + MeshLib::Mesh const& mesh, + unsigned const integration_order) +{ + ProcessLib::SmallDeformation::createLocalAssemblers< + DisplacementDim, PhaseFieldLocalAssembler>( + mesh.getElements(), dof_table, _local_assemblers, + mesh.isAxiallySymmetric(), integration_order, _process_data); Base::_secondary_variables.addSecondaryVariable( - "epsilon_zz", + "sigma", makeExtrapolator(1, getExtrapolator(), _local_assemblers, - &LocalAssemblerInterface::getIntPtEpsilonZZ)); + &LocalAssemblerInterface::getIntPtSigma)); Base::_secondary_variables.addSecondaryVariable( - "epsilon_xy", + "epsilon", makeExtrapolator(1, getExtrapolator(), _local_assemblers, - &LocalAssemblerInterface::getIntPtEpsilonXY)); + &LocalAssemblerInterface::getIntPtEpsilon)); +} - if (DisplacementDim == 3) +template <int DisplacementDim> +void PhaseFieldProcess<DisplacementDim>::initializeBoundaryConditions() +{ + if (_use_monolithic_scheme) { - Base::_secondary_variables.addSecondaryVariable( - "epsilon_yz", - makeExtrapolator(1, getExtrapolator(), _local_assemblers, - &LocalAssemblerInterface::getIntPtEpsilonYZ)); - - Base::_secondary_variables.addSecondaryVariable( - "epsilon_xz", - makeExtrapolator(1, getExtrapolator(), _local_assemblers, - &LocalAssemblerInterface::getIntPtEpsilonXZ)); + const int process_id_of_phasefieldmechanics = 0; + initializeProcessBoundaryConditionsAndSourceTerms( + *_local_to_global_index_map, process_id_of_phasefieldmechanics); + return; } + + // Staggered scheme: + // for the equations of deformation. + const int mechanical_process_id = 0; + initializeProcessBoundaryConditionsAndSourceTerms( + *_local_to_global_index_map, mechanical_process_id); + // for the phase field + const int phasefield_process_id = 1; + initializeProcessBoundaryConditionsAndSourceTerms( + *_local_to_global_index_map_single_component, phasefield_process_id); } template <int DisplacementDim> @@ -143,7 +205,33 @@ void PhaseFieldProcess<DisplacementDim>::assembleConcreteProcess( DBUG("Assemble PhaseFieldProcess."); std::vector<std::reference_wrapper<NumLib::LocalToGlobalIndexMap>> - dof_tables = {std::ref(*_local_to_global_index_map)}; + dof_tables; + + // For the monolithic scheme + if (_use_monolithic_scheme) + { + DBUG("Assemble PhaseFieldProcess for the monolithic scheme."); + dof_tables.emplace_back(*_local_to_global_index_map); + } + else + { + // For the staggered scheme + if (_coupled_solutions->process_id == 1) + { + DBUG( + "Assemble the equations of phase field in " + "PhaseFieldProcess for the staggered scheme."); + } + else + { + DBUG( + "Assemble the equations of deformation in " + "PhaseFieldProcess for the staggered scheme."); + } + dof_tables.emplace_back(*_local_to_global_index_map_single_component); + dof_tables.emplace_back(*_local_to_global_index_map); + } + // Call global assembler for each local assembly item. GlobalExecutor::executeMemberDereferenced( _global_assembler, &VectorMatrixAssembler::assemble, _local_assemblers, @@ -156,42 +244,144 @@ void PhaseFieldProcess<DisplacementDim>::assembleWithJacobianConcreteProcess( const double dxdot_dx, const double dx_dx, GlobalMatrix& M, GlobalMatrix& K, GlobalVector& b, GlobalMatrix& Jac) { - // DBUG("AssembleJacobian PhaseFieldProcess."); - std::vector<std::reference_wrapper<NumLib::LocalToGlobalIndexMap>> - dof_tables = {std::ref(*_local_to_global_index_map)}; + dof_tables; + + // For the monolithic scheme + if (_use_monolithic_scheme) + { + DBUG("AssembleJacobian PhaseFieldProcess for the monolithic scheme."); + dof_tables.emplace_back(*_local_to_global_index_map); + } + else + { + // For the staggered scheme + if (_coupled_solutions->process_id == 1) + { + DBUG( + "Assemble the Jacobian equations of phase field in " + "PhaseFieldProcess for the staggered scheme."); + } + else + { + DBUG( + "Assemble the Jacobian equations of deformation in " + "PhaseFieldProcess for the staggered scheme."); + } + dof_tables.emplace_back(*_local_to_global_index_map); + dof_tables.emplace_back(*_local_to_global_index_map_single_component); + } // Call global assembler for each local assembly item. + GlobalExecutor::executeMemberDereferenced( _global_assembler, &VectorMatrixAssembler::assembleWithJacobian, - _local_assemblers, dof_tables, t, x, xdot, dxdot_dx, - dx_dx, M, K, b, Jac, _coupled_solutions); + _local_assemblers, dof_tables, t, x, xdot, dxdot_dx, dx_dx, M, K, b, + Jac, _coupled_solutions); + + if (!_use_monolithic_scheme && (_coupled_solutions->process_id == 0)) + { + b.copyValues(*_nodal_forces); + std::transform(_nodal_forces->begin(), _nodal_forces->end(), + _nodal_forces->begin(), [](double val) { return -val; }); + } } template <int DisplacementDim> void PhaseFieldProcess<DisplacementDim>::preTimestepConcreteProcess( GlobalVector const& x, double const t, double const dt, - const int /*process_id*/) + const int process_id) { - DBUG("PreTimestep PhaseFieldProcess."); + DBUG("PreTimestep PhaseFieldProcess %d.", process_id); _process_data.dt = dt; _process_data.t = t; + _process_data.injected_volume = _process_data.t; GlobalExecutor::executeMemberOnDereferenced( &LocalAssemblerInterface::preTimestep, _local_assemblers, - *_local_to_global_index_map, x, t, dt); + getDOFTable(process_id), x, t, dt); } template <int DisplacementDim> void PhaseFieldProcess<DisplacementDim>::postTimestepConcreteProcess( - GlobalVector const& x, int const /*process_id*/) + GlobalVector const& x, int const process_id) { - DBUG("PostTimestep PhaseFieldProcess."); + if (isPhaseFieldProcess(process_id)) + { + DBUG("PostTimestep PhaseFieldProcess."); - GlobalExecutor::executeMemberOnDereferenced( - &LocalAssemblerInterface::postTimestep, _local_assemblers, - *_local_to_global_index_map, x); + _process_data.elastic_energy = 0.0; + _process_data.surface_energy = 0.0; + _process_data.pressure_work = 0.0; + + std::vector<std::reference_wrapper<NumLib::LocalToGlobalIndexMap>> + dof_tables; + + dof_tables.emplace_back(*_local_to_global_index_map); + dof_tables.emplace_back(*_local_to_global_index_map_single_component); + + GlobalExecutor::executeMemberOnDereferenced( + &LocalAssemblerInterface::computeEnergy, _local_assemblers, + dof_tables, x, _process_data.t, _process_data.elastic_energy, + _process_data.surface_energy, _process_data.pressure_work, + _use_monolithic_scheme, _coupled_solutions); + + INFO("Elastic energy: %g Surface energy: %g Pressure work: %g ", + _process_data.elastic_energy, _process_data.surface_energy, + _process_data.pressure_work); + } } +template <int DisplacementDim> +void PhaseFieldProcess<DisplacementDim>::postNonLinearSolverConcreteProcess( + GlobalVector const& x, const double t, const int process_id) +{ + if (_use_monolithic_scheme) + return; + + _process_data.crack_volume = 0.0; + + if (!isPhaseFieldProcess(process_id)) + { + std::vector<std::reference_wrapper<NumLib::LocalToGlobalIndexMap>> + dof_tables; + + dof_tables.emplace_back(*_local_to_global_index_map); + dof_tables.emplace_back(*_local_to_global_index_map_single_component); + + DBUG("PostNonLinearSolver crack volume computation."); + + GlobalExecutor::executeMemberOnDereferenced( + &LocalAssemblerInterface::computeCrackIntegral, _local_assemblers, + dof_tables, x, t, _process_data.crack_volume, + _use_monolithic_scheme, _coupled_solutions); + + INFO("Integral of crack: %g", _process_data.crack_volume); + + if (_process_data.propagating_crack) + { + _process_data.pressure_old = _process_data.pressure; + _process_data.pressure = + _process_data.injected_volume / _process_data.crack_volume; + _process_data.pressure_error = + abs(_process_data.pressure_old - _process_data.pressure) / + _process_data.pressure; + INFO("Internal pressure: %g and Pressure error: %.4e", + _process_data.pressure, _process_data.pressure_error); + auto& u = _coupled_solutions->coupled_xs[0].get(); + MathLib::LinAlg::scale(const_cast<GlobalVector&>(u), + _process_data.pressure); + } + } + else + { + if (_process_data.propagating_crack) + { + auto& u = _coupled_solutions->coupled_xs[0].get(); + MathLib::LinAlg::scale(const_cast<GlobalVector&>(u), + 1 / _process_data.pressure); + } + } +} } // namespace PhaseField } // namespace ProcessLib diff --git a/ProcessLib/PhaseField/PhaseFieldProcess.h b/ProcessLib/PhaseField/PhaseFieldProcess.h index efdc9d2b5954ae0b7a5b8be02edc726979a1c798..b0bdfaf9995d947ffa1a577c784c777dbd97202f 100644 --- a/ProcessLib/PhaseField/PhaseFieldProcess.h +++ b/ProcessLib/PhaseField/PhaseFieldProcess.h @@ -18,7 +18,6 @@ namespace ProcessLib { namespace PhaseField { - /** * \brief A class to simulate mechanical fracturing process * using phase-field approach in solids described by @@ -69,30 +68,44 @@ public: bool isLinear() const override; //! @} + MathLib::MatrixSpecifications getMatrixSpecifications( + const int process_id) const override; + + NumLib::LocalToGlobalIndexMap const& getDOFTable( + const int process_id) const override; + private: using LocalAssemblerInterface = PhaseFieldLocalAssemblerInterface; + void constructDofTable() override; + + void initializeBoundaryConditions() override; + void initializeConcreteProcess( NumLib::LocalToGlobalIndexMap const& dof_table, MeshLib::Mesh const& mesh, unsigned const integration_order) override; - void assembleConcreteProcess( - const double t, GlobalVector const& x, GlobalMatrix& M, GlobalMatrix& K, - GlobalVector& b) 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 preTimestepConcreteProcess(GlobalVector const& x, double const t, + double const dt, + const int process_id) override; void postTimestepConcreteProcess(GlobalVector const& x, int const process_id) override; + void postNonLinearSolverConcreteProcess(GlobalVector const& x, + const double t, + int const process_id) override; + private: PhaseFieldProcessData<DisplacementDim> _process_data; @@ -100,6 +113,20 @@ private: std::unique_ptr<NumLib::LocalToGlobalIndexMap> _local_to_global_index_map_single_component; + + MeshLib::PropertyVector<double>* _nodal_forces = nullptr; + + /// Sparsity pattern for the phase field equation, and it is initialized + /// only if the staggered scheme is used. + GlobalSparsityPattern _sparsity_pattern_with_single_component; + + /// Check whether the process represented by \c process_id is/has + /// mechanical process. In the present implementation, the mechanical + /// process has process_id == 0 in the staggered scheme. + bool isPhaseFieldProcess(int const process_id) const + { + return !_use_monolithic_scheme && process_id == 1; + } }; extern template class PhaseFieldProcess<2>; diff --git a/ProcessLib/PhaseField/PhaseFieldProcessData.h b/ProcessLib/PhaseField/PhaseFieldProcessData.h index 7184f64298b4c091e92e005d3fc42b423484360e..75fdace07173ad99b6c67235b9c3a0bae855f470 100644 --- a/ProcessLib/PhaseField/PhaseFieldProcessData.h +++ b/ProcessLib/PhaseField/PhaseFieldProcessData.h @@ -21,7 +21,7 @@ namespace Solids template <int DisplacementDim> struct MechanicsBase; } -} +} // namespace MaterialLib namespace ProcessLib { template <typename T> @@ -41,7 +41,8 @@ struct PhaseFieldProcessData Parameter<double> const& kinetic_coefficient_, Parameter<double> const& solid_density_, Parameter<double>& history_field_, - Eigen::Matrix<double, DisplacementDim, 1> const& specific_body_force_) + Eigen::Matrix<double, DisplacementDim, 1> const& specific_body_force_, + bool propagating_crack_, bool crack_pressure_) : material{std::move(material_)}, residual_stiffness(residual_stiffness_), crack_resistance(crack_resistance_), @@ -49,7 +50,9 @@ struct PhaseFieldProcessData kinetic_coefficient(kinetic_coefficient_), solid_density(solid_density_), history_field(history_field_), - specific_body_force(specific_body_force_) + specific_body_force(specific_body_force_), + propagating_crack(propagating_crack_), + crack_pressure(crack_pressure_) { } @@ -63,7 +66,9 @@ struct PhaseFieldProcessData history_field(other.history_field), specific_body_force(other.specific_body_force), dt(other.dt), - t(other.t) + t(other.t), + propagating_crack(other.propagating_crack), + crack_pressure(other.crack_pressure) { } @@ -87,6 +92,17 @@ struct PhaseFieldProcessData Eigen::Matrix<double, DisplacementDim, 1> const specific_body_force; double dt = 0.0; double t = 0.0; + double const unity_pressure = 1.0; + double pressure = 0.0; + double pressure_old = 0.0; + double pressure_error = 0.0; + double injected_volume = 0.0; + double crack_volume = 0.0; + double elastic_energy = 0.0; + double surface_energy = 0.0; + double pressure_work = 0.0; + bool propagating_crack = false; + bool crack_pressure = false; }; } // namespace PhaseField diff --git a/ProcessLib/PhaseField/Tests.cmake b/ProcessLib/PhaseField/Tests.cmake index 29c3a780e48a70d7e00e759b590cc699177a4f0d..b7a8a39025b91538779cdcb582d6be52065d72f8 100644 --- a/ProcessLib/PhaseField/Tests.cmake +++ b/ProcessLib/PhaseField/Tests.cmake @@ -10,3 +10,56 @@ AddTest( expected_cube_1e0_pcs_0_ts_10000_t_1.000000.vtu cube_1e0_pcs_0_ts_10000_t_1.000000.vtu displacement displacement 1e-6 1e-6 expected_cube_1e0_pcs_0_ts_10000_t_1.000000.vtu cube_1e0_pcs_0_ts_10000_t_1.000000.vtu phasefield phasefield 1e-6 1e-6 ) + +AddTest( + NAME PhaseField_2D_StaticHydraulicFracture + PATH PhaseField + EXECUTABLE ogs + EXECUTABLE_ARGS 2D_static.prj + WRAPPER time + TESTER vtkdiff + REQUIREMENTS NOT (OGS_USE_LIS OR OGS_USE_MPI) + DIFF_DATA + expected_2D_StaticCrack_pcs_1_ts_1_t_1.000000.vtu 2D_StaticCrack_pcs_1_ts_1_t_1.000000.vtu displacement displacement 1e-15 1e-15 + expected_2D_StaticCrack_pcs_1_ts_1_t_1.000000.vtu 2D_StaticCrack_pcs_1_ts_1_t_1.000000.vtu phasefield phasefield 1e-15 1e-15 + ) + +AddTest( + NAME PhaseField_3D_beam_LARGE + PATH PhaseField + EXECUTABLE ogs + EXECUTABLE_ARGS beam3d_stag_1pcs.prj + WRAPPER time + TESTER vtkdiff + REQUIREMENTS NOT (OGS_USE_LIS OR OGS_USE_MPI) + DIFF_DATA + expected_beam3_stag1pcsAT2_pcs_1_ts_10_t_1.000000.vtu beam3_stag1pcsAT2_pcs_1_ts_10_t_1.000000.vtu displacement displacement 1e-5 0 + expected_beam3_stag1pcsAT2_pcs_1_ts_10_t_1.000000.vtu beam3_stag1pcsAT2_pcs_1_ts_10_t_1.000000.vtu phasefield phasefield 1e-6 0 + ) + + +AddTest( + NAME LARGE_PhaseField_Staggered_square_line + PATH PhaseField + EXECUTABLE ogs + EXECUTABLE_ARGS square_line_h_400.prj + WRAPPER time + TESTER vtkdiff + REQUIREMENTS NOT (OGS_USE_LIS OR OGS_USE_MPI) + DIFF_DATA + square_line_h_400_pcs_0_ts_400000_t_400.000000.vtu square_line_h_400_pcs_0_ts_400000_t_400.000000.vtu displacement displacement 1e-16 0 + square_line_h_400_pcs_0_ts_400000_t_400.000000.vtu square_line_h_400_pcs_0_ts_400000_t_400.000000.vtu phasefield phasefield 1e-16 0 + ) + +AddTest( + NAME LARGE_PhaseField_Staggered_square_shear + PATH PhaseField + EXECUTABLE ogs + EXECUTABLE_ARGS square_shear_h_400.prj + WRAPPER time + TESTER vtkdiff + REQUIREMENTS NOT (OGS_USE_LIS OR OGS_USE_MPI) + DIFF_DATA + square_shear_h_400_pcs_0_ts_30000_t_300.000000.vtu square_shear_h_400_pcs_0_ts_30000_t_300.000000.vtu displacement displacement 1e-16 0 + square_shear_h_400_pcs_0_ts_30000_t_300.000000.vtu square_shear_h_400_pcs_0_ts_30000_t_300.000000.vtu phasefield phasefield 1e-16 0 + ) diff --git a/ProcessLib/Process.cpp b/ProcessLib/Process.cpp index 4647714e169eeeb86e119c127b63cbc16e60408a..9e9d9ab2e7e2b2c6edfcfcc10f40f6fadc56c780 100644 --- a/ProcessLib/Process.cpp +++ b/ProcessLib/Process.cpp @@ -346,6 +346,8 @@ void Process::preTimestep(GlobalVector const& x, const double t, MathLib::LinAlg::setLocalAccessibleVector(x); preTimestepConcreteProcess(x, t, delta_t, process_id); + + _boundary_conditions[process_id].preTimestep(t, x); } void Process::postTimestep(GlobalVector const& x, int const process_id) diff --git a/ProcessLib/ProcessVariable.cpp b/ProcessLib/ProcessVariable.cpp index 93474a224f8c1238941233ec4bb69fb3ee696933..48d45cd23714ee5b1fe49743e6610847ae032155 100644 --- a/ProcessLib/ProcessVariable.cpp +++ b/ProcessLib/ProcessVariable.cpp @@ -165,11 +165,15 @@ ProcessVariable::createBoundaryConditions( std::vector<std::unique_ptr<ParameterBase>> const& parameters) { std::vector<std::unique_ptr<BoundaryCondition>> bcs; + bcs.reserve(_bc_configs.size()); for (auto& config : _bc_configs) - bcs.emplace_back(_bc_builder->createBoundaryCondition( + { + auto bc = _bc_builder->createBoundaryCondition( config, dof_table, _mesh, variable_id, integration_order, - _shapefunction_order, parameters)); + _shapefunction_order, parameters); + bcs.push_back(std::move(bc)); + } return bcs; } diff --git a/Tests/Data/PhaseField/2D_static.prj b/Tests/Data/PhaseField/2D_static.prj new file mode 100644 index 0000000000000000000000000000000000000000..d848c5d108aa41c773cb4bc6bed248f52c6a6429 --- /dev/null +++ b/Tests/Data/PhaseField/2D_static.prj @@ -0,0 +1,307 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<OpenGeoSysProject> + <mesh>cracked_medium_ic.vtu</mesh> + <geometry>bar.gml</geometry> + <processes> + <process> + <name>PhaseField</name> + <type>PHASE_FIELD</type> + <coupling_scheme>staggered</coupling_scheme> + <hydro_crack_scheme>static</hydro_crack_scheme> + <integration_order>2</integration_order> + <constitutive_relation> + <type>LinearElasticIsotropic</type> + <youngs_modulus>E</youngs_modulus> + <poissons_ratio>nu</poissons_ratio> + </constitutive_relation> + <phasefield_parameters> + <residual_stiffness>k</residual_stiffness> + <crack_resistance>gc</crack_resistance> + <crack_length_scale>ls</crack_length_scale> + <kinetic_coefficient>M</kinetic_coefficient> + <history_field>H</history_field> + </phasefield_parameters> + <solid_density>rho_sr</solid_density> + <process_variables> + <phasefield>phasefield</phasefield> + <displacement>displacement</displacement> + </process_variables> + <specific_body_force>0 0 </specific_body_force> + </process> + </processes> + <time_loop> + <global_process_coupling> + <max_iter> 1000 </max_iter> + <convergence_criteria> + <!-- convergence criterion for the first process --> + <convergence_criterion> + <type>DeltaX</type> + <norm_type>INFINITY_N</norm_type> + <abstol>1.e-1</abstol> + <reltol>1.e-1</reltol> + </convergence_criterion> + <!-- convergence criterion for the second process --> + <convergence_criterion> + <type>DeltaX</type> + <norm_type>INFINITY_N</norm_type> + <abstol>1.e-4</abstol> + <reltol>1.e-10</reltol> + </convergence_criterion> + </convergence_criteria> + </global_process_coupling> + <processes> + <process ref="PhaseField"> + <nonlinear_solver>basic_newton_u</nonlinear_solver> + <convergence_criterion> + <type>DeltaX</type> + <norm_type>NORM2</norm_type> + <reltol>1.e-14</reltol> + </convergence_criterion> + <time_discretization> + <type>BackwardEuler</type> + </time_discretization> + <output> + <variables> + <variable>displacement</variable> + </variables> + </output> + <time_stepping> + <type>FixedTimeStepping</type> + <t_initial>0</t_initial> + <t_end>1</t_end> + <timesteps> + <pair> + <repeat>2</repeat> + <delta_t>1.0</delta_t> + </pair> + </timesteps> + </time_stepping> + </process> + <process ref="PhaseField"> + <nonlinear_solver>basic_newton_d</nonlinear_solver> + <convergence_criterion> + <type>DeltaX</type> + <norm_type>NORM2</norm_type> + <reltol>1.e-14</reltol> + </convergence_criterion> + <time_discretization> + <type>BackwardEuler</type> + </time_discretization> + <output> + <variables> + <variable>phasefield</variable> + </variables> + </output> + <time_stepping> + <type>FixedTimeStepping</type> + <t_initial>0</t_initial> + <t_end>1</t_end> + <timesteps> + <pair> + <repeat>2</repeat> + <delta_t>1.0</delta_t> + </pair> + </timesteps> + </time_stepping> + </process> + </processes> + <output> + <type>VTK</type> + <prefix>2D_StaticCrack</prefix> + <timesteps> + <pair> + <repeat>10</repeat> + <each_steps>1</each_steps> + </pair> + <pair> + <repeat>10</repeat> + <each_steps>1</each_steps> + </pair> + <!--<pair><repeat>50</repeat><each_steps>100</each_steps></pair>--> + </timesteps> + </output> + </time_loop> + <parameters> + <!-- Mechanics --> + <parameter> + <name>E</name> + <type>Constant</type> + <value>1.0</value> + </parameter> + <parameter> + <name>nu</name> + <type>Constant</type> + <value>0.15</value> + </parameter> + <parameter> + <name>k</name> + <type>Constant</type> + <value>1e-8</value> + </parameter> + <parameter> + <name>gc</name> + <type>Constant</type> + <value>1.0</value> + </parameter> + <parameter> + <name>ls</name> + <type>Constant</type> + <value>0.02</value> + </parameter> + <parameter> + <name>H</name> + <type>Constant</type> + <value>0.0</value> + </parameter> + <parameter> + <name>rho_sr</name> + <type>Constant</type> + <value>0.0</value> + </parameter> + <parameter> + <name>displacement0</name> + <type>Constant</type> + <values>0 0</values> + </parameter> + <parameter> + <name>phasefield_ic</name> + <type>MeshNode</type> + <field_name>phase-field</field_name> + <!--type>Constant</type> + <value>1</value>--> + </parameter> + <parameter> + <name>phasefield_bc</name> + <type>Constant</type> + <value>1</value> + </parameter> + <parameter> + <name>dirichlet0</name> + <type>Constant</type> + <value>0</value> + </parameter> + <parameter> + <name>M</name> + <type>Constant</type> + <value>0.0</value> + </parameter> + <parameter> + <name>Dirichlet_load</name> + <type>Constant</type> + <value>1</value> + </parameter> + <parameter> + <name>Dirichlet_top_y</name> + <type>CurveScaled</type> + <curve>Dirichlet_top_time</curve> + <parameter>Dirichlet_load</parameter> + </parameter> + </parameters> + <curves> + <curve> + <name>Dirichlet_top_time</name> + <coords>0 1</coords> + <values>0 1.0</values> + </curve> + </curves> + <process_variables> + <process_variable> + <name>displacement</name> + <components>2</components> + <order>1</order> + <initial_condition>displacement0</initial_condition> + <boundary_conditions> + <boundary_condition> + <geometrical_set>bar</geometrical_set> + <geometry>bottom</geometry> + <type>Dirichlet</type> + <component>1</component> + <parameter>dirichlet0</parameter> + </boundary_condition> + <boundary_condition> + <geometrical_set>bar</geometrical_set> + <geometry>top</geometry> + <type>Dirichlet</type> + <component>1</component> + <parameter>dirichlet0</parameter> + </boundary_condition> + <boundary_condition> + <geometrical_set>bar</geometrical_set> + <geometry>left</geometry> + <type>Dirichlet</type> + <component>0</component> + <parameter>dirichlet0</parameter> + </boundary_condition> + <boundary_condition> + <geometrical_set>bar</geometrical_set> + <geometry>right</geometry> + <type>Dirichlet</type> + <component>0</component> + <parameter>dirichlet0</parameter> + </boundary_condition> + </boundary_conditions> + </process_variable> + <process_variable> + <name>phasefield</name> + <components>1</components> + <order>1</order> + <initial_condition>phasefield_ic</initial_condition> + <boundary_conditions> + <boundary_condition> + <geometrical_set>bar</geometrical_set> + <geometry>left</geometry> + <type>Dirichlet</type> + <component>0</component> + <parameter>phasefield_bc</parameter> + </boundary_condition> + <boundary_condition> + <geometrical_set>bar</geometrical_set> + <geometry>right</geometry> + <type>Dirichlet</type> + <component>0</component> + <parameter>phasefield_bc</parameter> + </boundary_condition> + <boundary_condition> + <geometrical_set>bar</geometrical_set> + <geometry>right</geometry> + <type>PhaseFieldIrreversibleDamageOracleBoundaryCondition</type> + <component>0</component> + </boundary_condition> + </boundary_conditions> + </process_variable> + </process_variables> + <nonlinear_solvers> + <nonlinear_solver> + <name>basic_newton_d</name> + <type>Newton</type> + <max_iter>50</max_iter> + <linear_solver>linear_solver_d</linear_solver> + </nonlinear_solver> + <nonlinear_solver> + <name>basic_newton_u</name> + <type>Newton</type> + <max_iter>50</max_iter> + <linear_solver>linear_solver_u</linear_solver> + </nonlinear_solver> + </nonlinear_solvers> + <linear_solvers> + <linear_solver> + <name>linear_solver_d</name> + <eigen> + <solver_type>BiCGSTAB</solver_type> + <precon_type>ILUT</precon_type> + <max_iteration_step>10000</max_iteration_step> + <error_tolerance>1e-16</error_tolerance> + </eigen> + </linear_solver> + <linear_solver> + <name>linear_solver_u</name> + <eigen> + <solver_type>BiCGSTAB</solver_type> + <precon_type>ILUT</precon_type> + <max_iteration_step>10000</max_iteration_step> + <error_tolerance>1e-16</error_tolerance> + </eigen> + </linear_solver> + </linear_solvers> +</OpenGeoSysProject> diff --git a/Tests/Data/PhaseField/bar.gml b/Tests/Data/PhaseField/bar.gml new file mode 100644 index 0000000000000000000000000000000000000000..d226fe62c21fdde3fde76e6d94cd2b29f34016c2 --- /dev/null +++ b/Tests/Data/PhaseField/bar.gml @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19c58dced67204b13be71364487e0f0591191151b6162d19bc29db839471c1fa +size 910 diff --git a/Tests/Data/PhaseField/beam3d.prj b/Tests/Data/PhaseField/beam3d.prj index ee6df112f292188cb8fa905f4c443e614e444169..e41182aa564c32769a806bf5f5ee3a3864508a36 100644 --- a/Tests/Data/PhaseField/beam3d.prj +++ b/Tests/Data/PhaseField/beam3d.prj @@ -25,14 +25,8 @@ <phasefield>phasefield</phasefield> </process_variables> <secondary_variables> - <secondary_variable type="static" internal_name="sigma_xx" output_name="sigma_xx"/> - <secondary_variable type="static" internal_name="sigma_yy" output_name="sigma_yy"/> - <secondary_variable type="static" internal_name="sigma_zz" output_name="sigma_zz"/> - <secondary_variable type="static" internal_name="sigma_xy" output_name="sigma_xy"/> - <secondary_variable type="static" internal_name="epsilon_xx" output_name="epsilon_xx"/> - <secondary_variable type="static" internal_name="epsilon_yy" output_name="epsilon_yy"/> - <secondary_variable type="static" internal_name="epsilon_zz" output_name="epsilon_zz"/> - <secondary_variable type="static" internal_name="epsilon_xy" output_name="epsilon_xy"/> + <secondary_variable type="static" internal_name="sigma" output_name="sigma"/> + <secondary_variable type="static" internal_name="epsilon" output_name="epsilon"/> </secondary_variables> <specific_body_force>0 0 0</specific_body_force> </process> @@ -53,14 +47,8 @@ <variables> <variable>displacement</variable> <variable>phasefield</variable> - <variable>sigma_xx</variable> - <variable>sigma_yy</variable> - <variable>sigma_zz</variable> - <variable>sigma_xy</variable> - <variable>epsilon_xx</variable> - <variable>epsilon_yy</variable> - <variable>epsilon_zz</variable> - <variable>epsilon_xy</variable> + <variable>sigma</variable> + <variable>epsilon</variable> </variables> </output> <time_stepping> diff --git a/Tests/Data/PhaseField/beam3d_stag_1pcs.prj b/Tests/Data/PhaseField/beam3d_stag_1pcs.prj new file mode 100644 index 0000000000000000000000000000000000000000..2d71e978074adec4655b7c873e065d8573e157c2 --- /dev/null +++ b/Tests/Data/PhaseField/beam3d_stag_1pcs.prj @@ -0,0 +1,322 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<OpenGeoSysProject> + <mesh>beam3d.vtu</mesh> + <geometry>beam3d.gml</geometry> + <processes> + <process> + <name>PhaseField</name> + <type>PHASE_FIELD</type> + <coupling_scheme>staggered</coupling_scheme> + <integration_order>2</integration_order> + <constitutive_relation> + <type>LinearElasticIsotropic</type> + <youngs_modulus>E</youngs_modulus> + <poissons_ratio>nu</poissons_ratio> + </constitutive_relation> + <phasefield_parameters> + <residual_stiffness>k</residual_stiffness> + <crack_resistance>gc</crack_resistance> + <crack_length_scale>ls</crack_length_scale> + <kinetic_coefficient>M</kinetic_coefficient> + <history_field>H</history_field> + </phasefield_parameters> + <solid_density>rho_sr</solid_density> + <process_variables> + <phasefield>phasefield</phasefield> + <displacement>displacement</displacement> + </process_variables> + <specific_body_force>0 0 0</specific_body_force> + </process> + </processes> + <time_loop> + <global_process_coupling> + <max_iter> 1000 </max_iter> + <convergence_criteria> + <!-- convergence criterion for the first process --> + <convergence_criterion> + <type>DeltaX</type> + <norm_type>INFINITY_N</norm_type> + <abstol>1.e-1</abstol> + <reltol>1.e-1</reltol> + </convergence_criterion> + <!-- convergence criterion for the second process --> + <convergence_criterion> + <type>DeltaX</type> + <norm_type>INFINITY_N</norm_type> + <abstol>1.e-4</abstol> + <reltol>1.e-10</reltol> + </convergence_criterion> + </convergence_criteria> + </global_process_coupling> + <processes> + <process ref="PhaseField"> + <nonlinear_solver>basic_newton_u</nonlinear_solver> + <convergence_criterion> + <type>DeltaX</type> + <norm_type>NORM2</norm_type> + <reltol>1.e-14</reltol> + </convergence_criterion> + <time_discretization> + <type>BackwardEuler</type> + </time_discretization> + <output> + <variables> + <variable>displacement</variable> + </variables> + </output> + <time_stepping> + <type>FixedTimeStepping</type> + <t_initial>0</t_initial> + <t_end>1</t_end> + <timesteps> + <pair> + <repeat>10</repeat> + <delta_t>1e-1</delta_t> + </pair> + </timesteps> + </time_stepping> + </process> + <process ref="PhaseField"> + <nonlinear_solver>basic_newton_d</nonlinear_solver> + <convergence_criterion> + <type>DeltaX</type> + <norm_type>NORM2</norm_type> + <reltol>1.e-14</reltol> + </convergence_criterion> + <time_discretization> + <type>BackwardEuler</type> + </time_discretization> + <output> + <variables> + <variable>phasefield</variable> + </variables> + </output> + <time_stepping> + <type>FixedTimeStepping</type> + <t_initial>0</t_initial> + <t_end>1</t_end> + <timesteps> + <pair> + <repeat>10</repeat> + <delta_t>1e-1</delta_t> + </pair> + </timesteps> + </time_stepping> + </process> + </processes> + <output> + <type>VTK</type> + <prefix>beam3_stag1pcsAT2</prefix> + <timesteps> + <pair> + <repeat>10</repeat> + <each_steps>1</each_steps> + </pair> + <pair> + <repeat>10</repeat> + <each_steps>1</each_steps> + </pair> + </timesteps> + </output> + </time_loop> + <parameters> + <!-- Mechanics --> + <parameter> + <name>E</name> + <type>Constant</type> + <value>2.1e5</value> + </parameter> + <parameter> + <name>nu</name> + <type>Constant</type> + <value>0.3</value> + </parameter> + <parameter> + <name>k</name> + <type>Constant</type> + <value>1e-8</value> + </parameter> + <parameter> + <name>gc</name> + <type>Constant</type> + <value>2.7</value> + </parameter> + <parameter> + <name>ls</name> + <type>Constant</type> + <value>0.02</value> + </parameter> + <parameter> + <name>H</name> + <type>Constant</type> + <value>0.0</value> + </parameter> + <parameter> + <name>rho_sr</name> + <type>Constant</type> + <value>0.0</value> + </parameter> + <parameter> + <name>displacement0</name> + <type>Constant</type> + <values>0 0 0</values> + </parameter> + <parameter> + <name>phasefield_ic</name> + <type>Constant</type> + <value>1</value> + </parameter> + <parameter> + <name>phasefield_bc</name> + <type>Constant</type> + <value>1</value> + </parameter> + <parameter> + <name>dirichlet0</name> + <type>Constant</type> + <value>0</value> + </parameter> + <parameter> + <name>Dirichlet_spatial</name> + <type>Constant</type> + <value>1</value> + </parameter> + <parameter> + <name>dirichlet1</name> + <type>CurveScaled</type> + <curve>Dirichlet_temporal</curve> + <parameter>Dirichlet_spatial</parameter> + </parameter> + <parameter> + <name>dirichlet2</name> + <type>CurveScaled</type> + <curve>Dirichlet_temporal_left</curve> + <parameter>Dirichlet_spatial</parameter> + </parameter> + <parameter> + <name>M</name> + <type>Constant</type> + <value>0.0</value> + </parameter> + </parameters> + <curves> + <curve> + <name>Dirichlet_temporal</name> + <coords>0 1</coords> + <values>0 0.013</values> + </curve> + <curve> + <name>Dirichlet_temporal_left</name> + <coords>0 1</coords> + <values>0 -0.013</values> + </curve> + </curves> + <process_variables> + <process_variable> + <name>phasefield</name> + <components>1</components> + <order>1</order> + <initial_condition>phasefield_ic</initial_condition> + <boundary_conditions> + <boundary_condition> + <geometrical_set>beam3d_geometry</geometrical_set> + <geometry>left</geometry> + <type>Dirichlet</type> + <component>0</component> + <parameter>phasefield_bc</parameter> + </boundary_condition> + <boundary_condition> + <geometrical_set>beam3d_geometry</geometrical_set> + <geometry>right</geometry> + <type>Dirichlet</type> + <component>0</component> + <parameter>phasefield_bc</parameter> + </boundary_condition> + </boundary_conditions> + </process_variable> + <process_variable> + <name>displacement</name> + <components>3</components> + <order>1</order> + <initial_condition>displacement0</initial_condition> + <boundary_conditions> + <boundary_condition> + <geometrical_set>beam3d_geometry</geometrical_set> + <geometry>bottom</geometry> + <type>Dirichlet</type> + <component>1</component> + <parameter>dirichlet0</parameter> + </boundary_condition> + <boundary_condition> + <geometrical_set>beam3d_geometry</geometrical_set> + <geometry>top</geometry> + <type>Dirichlet</type> + <component>1</component> + <parameter>dirichlet0</parameter> + </boundary_condition> + <boundary_condition> + <geometrical_set>beam3d_geometry</geometrical_set> + <geometry>back</geometry> + <type>Dirichlet</type> + <component>2</component> + <parameter>dirichlet0</parameter> + </boundary_condition> + <boundary_condition> + <geometrical_set>beam3d_geometry</geometrical_set> + <geometry>front</geometry> + <type>Dirichlet</type> + <component>2</component> + <parameter>dirichlet0</parameter> + </boundary_condition> + <boundary_condition> + <geometrical_set>beam3d_geometry</geometrical_set> + <geometry>left</geometry> + <type>Dirichlet</type> + <component>0</component> + <parameter>dirichlet2</parameter> + </boundary_condition> + <boundary_condition> + <geometrical_set>beam3d_geometry</geometrical_set> + <geometry>right</geometry> + <type>Dirichlet</type> + <component>0</component> + <parameter>dirichlet1</parameter> + </boundary_condition> + </boundary_conditions> + </process_variable> + </process_variables> + <nonlinear_solvers> + <nonlinear_solver> + <name>basic_newton_d</name> + <type>Newton</type> + <max_iter>50</max_iter> + <linear_solver>linear_solver_d</linear_solver> + </nonlinear_solver> + <nonlinear_solver> + <name>basic_newton_u</name> + <type>Newton</type> + <max_iter>50</max_iter> + <linear_solver>linear_solver_u</linear_solver> + </nonlinear_solver> + </nonlinear_solvers> + <linear_solvers> + <linear_solver> + <name>linear_solver_d</name> + <eigen> + <solver_type>BiCGSTAB</solver_type> + <precon_type>ILUT</precon_type> + <max_iteration_step>10000</max_iteration_step> + <error_tolerance>1e-16</error_tolerance> + </eigen> + </linear_solver> + <linear_solver> + <name>linear_solver_u</name> + <eigen> + <solver_type>BiCGSTAB</solver_type> + <precon_type>ILUT</precon_type> + <max_iteration_step>10000</max_iteration_step> + <error_tolerance>1e-16</error_tolerance> + </eigen> + </linear_solver> + </linear_solvers> +</OpenGeoSysProject> diff --git a/Tests/Data/PhaseField/cracked_medium_ic.vtu b/Tests/Data/PhaseField/cracked_medium_ic.vtu new file mode 100644 index 0000000000000000000000000000000000000000..18ffcbda95817f483abb18ee1e691c407c898bc6 --- /dev/null +++ b/Tests/Data/PhaseField/cracked_medium_ic.vtu @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f22a75eb26ee0fcd85f30edb7536f8fd3bb41a20fc3a6465674fbbeec760b4e4 +size 608625 diff --git a/Tests/Data/PhaseField/cube_1e0.prj b/Tests/Data/PhaseField/cube_1e0.prj index 9c65f5f238e0286e0967c07f1481a6e13634ced8..015d7d44df0c9276317cdd3260440e04b38e555c 100644 --- a/Tests/Data/PhaseField/cube_1e0.prj +++ b/Tests/Data/PhaseField/cube_1e0.prj @@ -25,14 +25,8 @@ <phasefield>phasefield</phasefield> </process_variables> <secondary_variables> - <secondary_variable type="static" internal_name="sigma_xx" output_name="sigma_xx"/> - <secondary_variable type="static" internal_name="sigma_yy" output_name="sigma_yy"/> - <secondary_variable type="static" internal_name="sigma_zz" output_name="sigma_zz"/> - <secondary_variable type="static" internal_name="sigma_xy" output_name="sigma_xy"/> - <secondary_variable type="static" internal_name="epsilon_xx" output_name="epsilon_xx"/> - <secondary_variable type="static" internal_name="epsilon_yy" output_name="epsilon_yy"/> - <secondary_variable type="static" internal_name="epsilon_zz" output_name="epsilon_zz"/> - <secondary_variable type="static" internal_name="epsilon_xy" output_name="epsilon_xy"/> + <secondary_variable type="static" internal_name="sigma" output_name="sigma"/> + <secondary_variable type="static" internal_name="epsilon" output_name="epsilon"/> </secondary_variables> <specific_body_force>0 0 0</specific_body_force> </process> @@ -53,14 +47,8 @@ <variables> <variable>displacement</variable> <variable>phasefield</variable> - <variable>sigma_xx</variable> - <variable>sigma_yy</variable> - <variable>sigma_zz</variable> - <variable>sigma_xy</variable> - <variable>epsilon_xx</variable> - <variable>epsilon_yy</variable> - <variable>epsilon_zz</variable> - <variable>epsilon_xy</variable> + <variable>sigma</variable> + <variable>epsilon</variable> </variables> </output> <time_stepping> diff --git a/Tests/Data/PhaseField/expected_2D_StaticCrack_pcs_1_ts_1_t_1.000000.vtu b/Tests/Data/PhaseField/expected_2D_StaticCrack_pcs_1_ts_1_t_1.000000.vtu new file mode 100644 index 0000000000000000000000000000000000000000..4c094b9b19beb756be46e249969967ed79a4955b --- /dev/null +++ b/Tests/Data/PhaseField/expected_2D_StaticCrack_pcs_1_ts_1_t_1.000000.vtu @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7242128dbc6adc0dc37c92f9e962c53d5218b32d5ce51fb46aac600ca32fec82 +size 350563 diff --git a/Tests/Data/PhaseField/expected_beam3_stag1pcsAT2_pcs_1_ts_10_t_1.000000.vtu b/Tests/Data/PhaseField/expected_beam3_stag1pcsAT2_pcs_1_ts_10_t_1.000000.vtu new file mode 100644 index 0000000000000000000000000000000000000000..8a9eff31f2ccb1c087d6c187cd4f4317a2ae12e5 --- /dev/null +++ b/Tests/Data/PhaseField/expected_beam3_stag1pcsAT2_pcs_1_ts_10_t_1.000000.vtu @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ec0d3b7e9c65734abcc0f7bcfb6014c04ace62f4a0658d13f3704d5a8c31528 +size 42664 diff --git a/Tests/Data/PhaseField/square_line_h_400.prj b/Tests/Data/PhaseField/square_line_h_400.prj index d6b2a4d726404d5f4f0923615dedb8aaa52a17d2..ce3f93e05d02278d891165085513f19dd654eb4c 100644 --- a/Tests/Data/PhaseField/square_line_h_400.prj +++ b/Tests/Data/PhaseField/square_line_h_400.prj @@ -25,14 +25,8 @@ <phasefield>phasefield</phasefield> </process_variables> <secondary_variables> - <secondary_variable type="static" internal_name="sigma_xx" output_name="sigma_xx"/> - <secondary_variable type="static" internal_name="sigma_yy" output_name="sigma_yy"/> - <secondary_variable type="static" internal_name="sigma_zz" output_name="sigma_zz"/> - <secondary_variable type="static" internal_name="sigma_xy" output_name="sigma_xy"/> - <secondary_variable type="static" internal_name="epsilon_xx" output_name="epsilon_xx"/> - <secondary_variable type="static" internal_name="epsilon_yy" output_name="epsilon_yy"/> - <secondary_variable type="static" internal_name="epsilon_zz" output_name="epsilon_zz"/> - <secondary_variable type="static" internal_name="epsilon_xy" output_name="epsilon_xy"/> + <secondary_variable type="static" internal_name="sigma" output_name="sigma"/> + <secondary_variable type="static" internal_name="epsilon" output_name="epsilon"/> </secondary_variables> <specific_body_force>0 0</specific_body_force> </process> @@ -53,14 +47,8 @@ <variables> <variable>displacement</variable> <variable>phasefield</variable> - <variable>sigma_xx</variable> - <variable>sigma_yy</variable> - <variable>sigma_zz</variable> - <variable>sigma_xy</variable> - <variable>epsilon_xx</variable> - <variable>epsilon_yy</variable> - <variable>epsilon_zz</variable> - <variable>epsilon_xy</variable> + <variable>sigma</variable> + <variable>epsilon</variable> </variables> </output> <time_stepping> diff --git a/Tests/Data/PhaseField/square_shear_h_400.prj b/Tests/Data/PhaseField/square_shear_h_400.prj index 6eaabc34a16a38ca55662b41aeb7b680d2663b6f..5b569530e298f3fe6128fa8400032ff4f8aa7dbb 100644 --- a/Tests/Data/PhaseField/square_shear_h_400.prj +++ b/Tests/Data/PhaseField/square_shear_h_400.prj @@ -25,14 +25,8 @@ <phasefield>phasefield</phasefield> </process_variables> <secondary_variables> - <secondary_variable type="static" internal_name="sigma_xx" output_name="sigma_xx"/> - <secondary_variable type="static" internal_name="sigma_yy" output_name="sigma_yy"/> - <secondary_variable type="static" internal_name="sigma_zz" output_name="sigma_zz"/> - <secondary_variable type="static" internal_name="sigma_xy" output_name="sigma_xy"/> - <secondary_variable type="static" internal_name="epsilon_xx" output_name="epsilon_xx"/> - <secondary_variable type="static" internal_name="epsilon_yy" output_name="epsilon_yy"/> - <secondary_variable type="static" internal_name="epsilon_zz" output_name="epsilon_zz"/> - <secondary_variable type="static" internal_name="epsilon_xy" output_name="epsilon_xy"/> + <secondary_variable type="static" internal_name="sigma" output_name="sigma"/> + <secondary_variable type="static" internal_name="epsilon" output_name="epsilon"/> </secondary_variables> <specific_body_force>0 0</specific_body_force> </process> @@ -53,14 +47,8 @@ <variables> <variable>displacement</variable> <variable>phasefield</variable> - <variable>sigma_xx</variable> - <variable>sigma_yy</variable> - <variable>sigma_zz</variable> - <variable>sigma_xy</variable> - <variable>epsilon_xx</variable> - <variable>epsilon_yy</variable> - <variable>epsilon_zz</variable> - <variable>epsilon_xy</variable> + <variable>sigma</variable> + <variable>epsilon</variable> </variables> </output> <time_stepping>