From f18b551b449bcf5e351d943f783966ca8315cc0d Mon Sep 17 00:00:00 2001 From: Ana Dragos-Corneliu Date: Mon, 10 Aug 2026 17:35:23 +0200 Subject: [PATCH 1/7] Add LocalIntegrationInput: review integrated --- src/mat/4C_mat_inelastic_defgrad_factors.cpp | 293 ++++++++++-------- src/mat/4C_mat_inelastic_defgrad_factors.hpp | 134 ++++---- ..._mat_inelastic_defgrad_factors_service.cpp | 12 +- ..._mat_inelastic_defgrad_factors_service.hpp | 48 ++- ...inelastic_defgrad_factors_service_test.cpp | 30 +- .../mat/4C_inelastic_defgrad_factors_test.cpp | 84 +++-- 6 files changed, 341 insertions(+), 260 deletions(-) diff --git a/src/mat/4C_mat_inelastic_defgrad_factors.cpp b/src/mat/4C_mat_inelastic_defgrad_factors.cpp index 245f7804870..d8a58bad9a9 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors.cpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors.cpp @@ -1894,16 +1894,22 @@ void Mat::InelasticDefgradTransvIsotropElastViscoplast::calculate_gamma_delta( *--------------------------------------------------------------------*/ ViscoplastUtils::StateQuantities Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_state_quantities( - const Core::LinAlg::Matrix<3, 3>& CM, const double temperature, + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, const Core::LinAlg::Matrix<3, 3>& iFinM, const double plastic_strain, - ViscoplastUtils::ErrorType& err_status, const double dt, - const ViscoplastUtils::StateQuantityEvalType& eval_type) const + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status, + const InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantityEvalType& eval_type) const { ensure_error_free_evaluation(err_status); ViscoplastUtils::StateQuantities state_quantities{}; state_quantities.eval_type = eval_type; + // retrieve required data from the local integration input + const Core::LinAlg::Matrix<3, 3>& right_cg = local_integration_input.right_cg; + const double temperature = local_integration_input.temperature; + const double step = local_integration_input.step; + // auxiliaries Core::LinAlg::Matrix<1, 1> temp1x1(Core::LinAlg::Initialization::zero); @@ -1911,7 +1917,7 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_state_quantities( Core::LinAlg::Matrix<3, 3> temp3x3; // compute right elastic CG tensor - temp3x3.multiply_nn(1.0, CM, iFinM, 0.0); + temp3x3.multiply_nn(1.0, right_cg, iFinM, 0.0); state_quantities.curr_CeM.multiply_tn(1.0, iFinM, temp3x3, 0.0); Core::LinAlg::SymmetricTensor CeV = Core::LinAlg::assume_symmetry(Core::LinAlg::make_tensor(state_quantities.curr_CeM)); @@ -2037,7 +2043,7 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_state_quantities( // calculate equivalent plastic strain rate using the viscoplastic law state_quantities.curr_equiv_plastic_strain_rate = viscoplastic_law_->evaluate_plastic_strain_rate( - state_quantities.curr_equiv_stress, plastic_strain, dt, err_status, update_hist_var_); + state_quantities.curr_equiv_stress, plastic_strain, step, err_status, update_hist_var_); if (eval_type == ViscoplastUtils::StateQuantityEvalType::plastic_strain_rate_only) { @@ -2122,7 +2128,7 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_state_quantities( // calculate plastic update tensor (only required, and computed, for standard substepping) if (parameter()->timint_type() == ViscoplastUtils::TimIntType::standard) { - temp3x3.update(-dt, state_quantities.curr_lpM, 0.0); + temp3x3.update(-step, state_quantities.curr_lpM, 0.0); auto exp_err_status = Core::LinAlg::MatrixFunctErrorType::no_errors; state_quantities.curr_EpM = Core::LinAlg::matrix_exp(temp3x3, exp_err_status, parameter()->mat_exp_calc_method()); @@ -2152,10 +2158,12 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_state_quantities( *--------------------------------------------------------------------*/ ViscoplastUtils::StateQuantityDerivatives Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_state_quantity_derivatives( - const Core::LinAlg::Matrix<3, 3>& CM, const double temperature, + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, const Core::LinAlg::Matrix<3, 3>& iFinM, const double plastic_strain, - ViscoplastUtils::ErrorType& err_status, const double dt, - const ViscoplastUtils::StateQuantityDerivEvalType& eval_type, const bool eval_state) const + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status, + const InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantityDerivEvalType& eval_type, + const bool eval_state) const { ensure_error_free_evaluation(err_status); @@ -2163,6 +2171,11 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_state_quantity_deriv ViscoplastUtils::StateQuantityDerivatives state_quantity_derivatives{}; state_quantity_derivatives.eval_type = eval_type; + // retrieve required data from the local integration input + const Core::LinAlg::Matrix<3, 3>& right_cg = local_integration_input.right_cg; + const double step = local_integration_input.step; + + // auxiliaries Core::LinAlg::Matrix<3, 3> temp3x3(Core::LinAlg::Initialization::zero); Core::LinAlg::Matrix<6, 6> temp6x6(Core::LinAlg::Initialization::zero); @@ -2175,8 +2188,8 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_state_quantity_deriv ViscoplastUtils::StateQuantities relevant_state_quantities = state_quantities_; if (eval_state) { - relevant_state_quantities = evaluate_state_quantities(CM, temperature, iFinM, plastic_strain, - err_status, dt, ViscoplastUtils::StateQuantityEvalType::full_eval); + relevant_state_quantities = evaluate_state_quantities(local_integration_input, iFinM, + plastic_strain, err_status, ViscoplastUtils::StateQuantityEvalType::full_eval); } // get the state quantities @@ -2200,7 +2213,8 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_state_quantity_deriv Core::LinAlg::SymmetricTensor dCedC_tensor; Core::LinAlg::Tensor dCediFin_tensor; Mat::elast_hyper_get_derivs_of_elastic_right_cg_tensor(Core::LinAlg::make_tensor(iFinM), - Core::LinAlg::assume_symmetry(Core::LinAlg::make_tensor(CM)), dCedC_tensor, dCediFin_tensor); + Core::LinAlg::assume_symmetry(Core::LinAlg::make_tensor(right_cg)), dCedC_tensor, + dCediFin_tensor); state_quantity_derivatives.curr_dCedC = Core::LinAlg::make_6x6_voigt_matrix_from_tensor(dCedC_tensor); state_quantity_derivatives.curr_dCediFin = @@ -2235,16 +2249,16 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_state_quantity_deriv // calculate various other helper tensors required for subsequent computation Core::LinAlg::Matrix<3, 3> CiFinM(Core::LinAlg::Initialization::zero); - CiFinM.multiply_nn(1.0, CM, iFinM, 0.0); + CiFinM.multiply_nn(1.0, right_cg, iFinM, 0.0); Core::LinAlg::Matrix<9, 1> CiFinV(Core::LinAlg::Initialization::zero); Core::LinAlg::Voigt::matrix_3x3_to_9x1(CiFinM, CiFinV); Core::LinAlg::Matrix<3, 3> iFinTCM(Core::LinAlg::Initialization::zero); - iFinTCM.multiply_tn(1.0, iFinM, CM, 0.0); + iFinTCM.multiply_tn(1.0, iFinM, right_cg, 0.0); Core::LinAlg::Matrix<3, 3> CeiFinTCM(Core::LinAlg::Initialization::zero); temp3x3.multiply_nt(1.0, CeM, iFinM, 0.0); - CeiFinTCM.multiply_nn(1.0, temp3x3, CM, 0.0); + CeiFinTCM.multiply_nn(1.0, temp3x3, right_cg, 0.0); Core::LinAlg::Matrix<3, 3> CiFinCeM(Core::LinAlg::Initialization::zero); CiFinCeM.multiply_nn(1.0, CiFinM, CeM, 0.0); @@ -2265,13 +2279,13 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_state_quantity_deriv CeiFinTM.multiply_nn(1.0, CeM, iFinTM, 0.0); Core::LinAlg::Matrix<3, 3> iCinCiCinM(Core::LinAlg::Initialization::zero); - temp3x3.multiply_nn(1.0, CM, iCinM, 0.0); + temp3x3.multiply_nn(1.0, right_cg, iCinM, 0.0); iCinCiCinM.multiply_nn(1.0, iCinM, temp3x3, 0.0); Core::LinAlg::Matrix<6, 1> iCinCiCinV(Core::LinAlg::Initialization::zero); Core::LinAlg::Voigt::Stresses::matrix_to_vector(iCinCiCinM, iCinCiCinV); Core::LinAlg::Matrix<3, 3> iCM(Core::LinAlg::Initialization::zero); - iCM.invert(CM); + iCM.invert(right_cg); Core::LinAlg::Matrix<6, 1> iCV(Core::LinAlg::Initialization::zero); Core::LinAlg::Voigt::Stresses::matrix_to_vector(iCM, iCV); @@ -2505,7 +2519,7 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_state_quantity_deriv // compute the relevant derivatives of the plastic strain rate InelasticDefgradTransvIsotropElastViscoplastUtils::PlasticStrainRateDerivs evoEqFunctionDers = viscoplastic_law_->evaluate_derivatives_of_plastic_strain_rate( - equiv_stress, plastic_strain, dt, err_status); + equiv_stress, plastic_strain, step, err_status); // return if we get an error, all other calculations are useless since substepping is // triggered @@ -2625,7 +2639,7 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_state_quantity_deriv { // compute argument Core::LinAlg::Matrix<3, 3> min_dt_lpM(Core::LinAlg::Initialization::zero); - min_dt_lpM.update(-1.0 * dt, lpM, 0.0); + min_dt_lpM.update(-1.0 * step, lpM, 0.0); // compute derivative of exponential ... @@ -2641,19 +2655,19 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_state_quantity_deriv // ... w.r.t. inverse inelastic defgrad state_quantity_derivatives.curr_dEpdiFin.multiply_nn( - -dt, expderivV, state_quantity_derivatives.curr_dlpdiFin, 0.0); + -step, expderivV, state_quantity_derivatives.curr_dlpdiFin, 0.0); // ... w.r.t. right CG state_quantity_derivatives.curr_dEpdC.multiply_nn( - -dt, expderivV, state_quantity_derivatives.curr_dlpdC, 0.0); + -step, expderivV, state_quantity_derivatives.curr_dlpdC, 0.0); // ... w.r.t. plastic strain state_quantity_derivatives.curr_dEpdepsp.multiply_nn( - -dt, expderivV, state_quantity_derivatives.curr_dlpdepsp, 0.0); + -step, expderivV, state_quantity_derivatives.curr_dlpdepsp, 0.0); // ... w.r.t. temperature state_quantity_derivatives.curr_dEpdT.multiply_nn( - -dt, expderivV, state_quantity_derivatives.curr_dlpdT, 0.0); + -step, expderivV, state_quantity_derivatives.curr_dlpdT, 0.0); return state_quantity_derivatives; } @@ -2688,11 +2702,18 @@ void Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_additional_cmat return; } + auto local_integration_input = ViscoplastUtils::LocalIntegrationInput{{.defgrad = *defgrad, + .temperature = temperature, + .last_inv_inelastic_defgrad = time_step_quantities_.last_plastic_defgrad_inverse[gp_], + .last_plastic_strain = time_step_quantities_.last_plastic_strain[gp_], + .step = time_step_tracker_.dt}}; + + // declare error status (no errors) ViscoplastUtils::ErrorType err_status = ViscoplastUtils::ErrorType::no_errors; - const auto& diFinjdC = evaluate_history_variables_wrt_cauchy_green( - reduced_kinematics.right_cauchy_green, temperature, err_status) - .inv_plastic_defgrad_wrt_cauchy_green; + const auto& diFinjdC = + evaluate_history_variables_wrt_cauchy_green(local_integration_input, err_status) + .inv_plastic_defgrad_wrt_cauchy_green; FOUR_C_ASSERT_ALWAYS(err_status == ViscoplastUtils::ErrorType::no_errors, "Could not evaluate additional stiffness matrix: {}", @@ -2704,7 +2725,8 @@ void Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_additional_cmat ViscoplastUtils::HistoryVariablesDerivativesWrtTemperature Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_history_variables_wrt_temperature( - const Core::LinAlg::Matrix<3, 3>& CredM, const double temperature, + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) { if (thermo_mechanical_coupling_cache_.history_variables_wrt_temperature.is_evaluated(gp_)) @@ -2713,9 +2735,9 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_history_variables_wr return thermo_mechanical_coupling_cache_.history_variables_wrt_temperature.value(gp_); } - state_quantities_ = evaluate_state_quantities(CredM, temperature, + state_quantities_ = evaluate_state_quantities(local_integration_input, time_step_quantities_.current_plastic_defgrad_inverse[gp_], - time_step_quantities_.current_plastic_strain[gp_], err_status, time_step_tracker_.dt, + time_step_quantities_.current_plastic_strain[gp_], err_status, ViscoplastUtils::StateQuantityEvalType::full_eval); thermo_mechanical_coupling_cache_.state.set(gp_, {state_quantities_}); @@ -2731,9 +2753,7 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_history_variables_wr Core::LinAlg::Matrix<10, 10> jacMat(Core::LinAlg::Initialization::zero); viscoplastic_law_->pre_evaluate(params_, gp_); // set last_substep <- last_ - jacMat = evaluate_local_newton_jacobian(CredM, temperature, current_sol, - time_step_quantities_.last_plastic_strain[gp_], - time_step_quantities_.last_plastic_defgrad_inverse[gp_], time_step_tracker_.dt, err_status); + jacMat = evaluate_local_newton_jacobian(local_integration_input, current_sol, err_status); FOUR_C_ASSERT_ALWAYS( err_status == InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType::no_errors, "Could not evaluate Jacobian in off-diagonal stiffness evaluation!"); @@ -2842,10 +2862,16 @@ void Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_od_stiff_mat( return; } + auto local_integration_input = ViscoplastUtils::LocalIntegrationInput{{.defgrad = *defgrad, + .temperature = temperature, + .last_inv_inelastic_defgrad = time_step_quantities_.last_plastic_defgrad_inverse[gp_], + .last_plastic_strain = time_step_quantities_.last_plastic_strain[gp_], + .step = time_step_tracker_.dt}}; + ViscoplastUtils::ErrorType err_status = ViscoplastUtils::ErrorType::no_errors; - const auto& diFinjTV = evaluate_history_variables_wrt_temperature( - reduced_kinematics.right_cauchy_green, temperature, err_status) - .inv_plastic_defgrad_wrt_temperature; + const auto& diFinjTV = + evaluate_history_variables_wrt_temperature(local_integration_input, err_status) + .inv_plastic_defgrad_wrt_temperature; FOUR_C_ASSERT_ALWAYS(err_status == ViscoplastUtils::ErrorType::no_errors, "Could not evaluate off-diagonal stiffness matrix: {}", @@ -2894,30 +2920,35 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_taylor_quinney_heat_ constitutive_update(reduced_kinematics.defgrad, temperature); } + auto local_integration_input = ViscoplastUtils::LocalIntegrationInput{{.defgrad = *defgrad, + .temperature = temperature, + .last_inv_inelastic_defgrad = time_step_quantities_.last_plastic_defgrad_inverse[gp_], + .last_plastic_strain = time_step_quantities_.last_plastic_strain[gp_], + .step = time_step_tracker_.dt}}; + // evaluate the relevant linearizations, using cached values when available - const auto history_variables_wrt_cauchy_green = evaluate_history_variables_wrt_cauchy_green( - reduced_kinematics.right_cauchy_green, temperature, err_status); + const auto history_variables_wrt_cauchy_green = + evaluate_history_variables_wrt_cauchy_green(local_integration_input, err_status); FOUR_C_ASSERT_ALWAYS(err_status == ViscoplastUtils::ErrorType::no_errors, "Could not evaluate history variable derivatives for mechanical dissipation evaluation! " "Error: {}", ViscoplastUtils::get_detailed_error_message_for_error_type(err_status)); - const auto history_variables_wrt_temperature = evaluate_history_variables_wrt_temperature( - reduced_kinematics.right_cauchy_green, temperature, err_status); + const auto history_variables_wrt_temperature = + evaluate_history_variables_wrt_temperature(local_integration_input, err_status); FOUR_C_ASSERT_ALWAYS(err_status == ViscoplastUtils::ErrorType::no_errors, "Could not evaluate history variable derivatives for mechanical dissipation evaluation! " "Error: {}", ViscoplastUtils::get_detailed_error_message_for_error_type(err_status)); - const auto thermo_mechanical_coupling_state = evaluate_thermo_mechanical_coupling_state( - reduced_kinematics.right_cauchy_green, temperature, err_status); + const auto thermo_mechanical_coupling_state = + evaluate_thermo_mechanical_coupling_state(local_integration_input, err_status); FOUR_C_ASSERT_ALWAYS(err_status == ViscoplastUtils::ErrorType::no_errors, "Could not evaluate thermo-mechanical coupling state for mechanical dissipation evaluation! " "Error: {}", ViscoplastUtils::get_detailed_error_message_for_error_type(err_status)); const auto thermo_mechanical_coupling_state_derivatives = - evaluate_thermo_mechanical_coupling_state_derivatives( - reduced_kinematics.right_cauchy_green, temperature, err_status); + evaluate_thermo_mechanical_coupling_state_derivatives(local_integration_input, err_status); FOUR_C_ASSERT_ALWAYS(err_status == ViscoplastUtils::ErrorType::no_errors, "Could not evaluate thermo-mechanical coupling state derivatives for mechanical dissipation " "evaluation! Error: {}", @@ -2968,17 +2999,18 @@ void Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_inverse_inelast *--------------------------------------------------------------------*/ ViscoplastUtils::ThermoMechanicalCouplingState Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_thermo_mechanical_coupling_state( - const Core::LinAlg::Matrix<3, 3>& CredM, const double temperature, - ViscoplastUtils::ErrorType& err_status) + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) { if (thermo_mechanical_coupling_cache_.state.is_evaluated(gp_)) { return thermo_mechanical_coupling_cache_.state.value(gp_); } - const auto& state_quantities = evaluate_state_quantities(CredM, temperature, + const auto& state_quantities = evaluate_state_quantities(local_integration_input, time_step_quantities_.current_plastic_defgrad_inverse[gp_], - time_step_quantities_.current_plastic_strain[gp_], err_status, time_step_tracker_.dt, + time_step_quantities_.current_plastic_strain[gp_], err_status, ViscoplastUtils::StateQuantityEvalType::full_eval); if (err_status != ViscoplastUtils::ErrorType::no_errors) return {}; @@ -2991,17 +3023,19 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_thermo_mechanical_co *--------------------------------------------------------------------*/ ViscoplastUtils::ThermoMechanicalCouplingStateDerivatives Mat::InelasticDefgradTransvIsotropElastViscoplast:: - evaluate_thermo_mechanical_coupling_state_derivatives(const Core::LinAlg::Matrix<3, 3>& CredM, - const double temperature, ViscoplastUtils::ErrorType& err_status) + evaluate_thermo_mechanical_coupling_state_derivatives( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) { if (thermo_mechanical_coupling_cache_.state_derivatives.is_evaluated(gp_)) { return thermo_mechanical_coupling_cache_.state_derivatives.value(gp_); } - const auto& state_quantity_derivatives = evaluate_state_quantity_derivatives(CredM, temperature, - time_step_quantities_.current_plastic_defgrad_inverse[gp_], - time_step_quantities_.current_plastic_strain[gp_], err_status, time_step_tracker_.dt, + const auto& state_quantity_derivatives = evaluate_state_quantity_derivatives( + local_integration_input, time_step_quantities_.current_plastic_defgrad_inverse[gp_], + time_step_quantities_.current_plastic_strain[gp_], err_status, ViscoplastUtils::StateQuantityDerivEvalType::full_eval, true); if (err_status != ViscoplastUtils::ErrorType::no_errors) return {}; @@ -3015,8 +3049,9 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast:: ViscoplastUtils::HistoryVariablesDerivativesWrtCauchyGreen Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_history_variables_wrt_cauchy_green( - const Core::LinAlg::Matrix<3, 3>& CredM, const double temperature, - ViscoplastUtils::ErrorType& err_status) + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) { if (thermo_mechanical_coupling_cache_.history_variables_wrt_cauchy_green.is_evaluated(gp_)) { @@ -3028,9 +3063,9 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_history_variables_wr // auxiliaries Core::LinAlg::FourTensor<3> tempFourTensor(true); - state_quantities_ = evaluate_state_quantities(CredM, temperature, + state_quantities_ = evaluate_state_quantities(local_integration_input, time_step_quantities_.current_plastic_defgrad_inverse[gp_], - time_step_quantities_.current_plastic_strain[gp_], err_status, time_step_tracker_.dt, + time_step_quantities_.current_plastic_strain[gp_], err_status, ViscoplastUtils::StateQuantityEvalType::full_eval); thermo_mechanical_coupling_cache_.state.set(gp_, {state_quantities_}); @@ -3049,9 +3084,7 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_history_variables_wr Core::LinAlg::Matrix<10, 10> jacMat(Core::LinAlg::Initialization::zero); viscoplastic_law_->pre_evaluate(params_, gp_); // set last_substep <- last_ - jacMat = evaluate_local_newton_jacobian(CredM, temperature, current_sol, - time_step_quantities_.last_plastic_strain[gp_], - time_step_quantities_.last_plastic_defgrad_inverse[gp_], time_step_tracker_.dt, err_status); + jacMat = evaluate_local_newton_jacobian(local_integration_input, current_sol, err_status); // if we get singular Jacobian: throw exception -> go to FD-based linearization if (abs(jacMat.determinant()) < 1.0e-10) @@ -3138,8 +3171,12 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::constitutive_update( HistoryVariables result; // construct struct containing deformation tensors used for local integration - ViscoplastUtils::LocalIntegrationDeformationTensors deftensors( - FredM, time_step_quantities_.last_plastic_defgrad_inverse[gp_]); + auto local_integration_input = ViscoplastUtils::LocalIntegrationInput{{.defgrad = FredM, + .temperature = temperature, + .last_inv_inelastic_defgrad = time_step_quantities_.last_plastic_defgrad_inverse[gp_], + .last_plastic_strain = time_step_quantities_.last_plastic_strain[gp_], + .step = time_step_tracker_.dt}}; + // perform non-repeatable pre-evaluation tasks (non-repeatable: not // called in the redundant evaluate call, which is already handled -> direct return @@ -3155,13 +3192,12 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::constitutive_update( ViscoplastUtils::ErrorType err_status = ViscoplastUtils::ErrorType::no_errors; // set current defgrad and current right CG tensor - time_step_quantities_.current_defgrad[gp_] = deftensors.defgrad; - time_step_quantities_.current_rightCG[gp_] = deftensors.right_cg; + time_step_quantities_.current_defgrad[gp_] = local_integration_input.defgrad; + time_step_quantities_.current_rightCG[gp_] = local_integration_input.right_cg; time_step_quantities_.current_temperature[gp_] = temperature; thermo_mechanical_coupling_cache_.reset(gp_); // check whether the predictor is the solution (no plastic strain during this time step) - bool pred_is_sol = check_elastic_predictor( - deftensors.right_cg, temperature, iFinM_pred, plastic_strain_pred, err_status); + bool pred_is_sol = check_elastic_predictor(local_integration_input, err_status); if ((err_status == ViscoplastUtils::ErrorType::no_errors) && (pred_is_sol)) { // update inverse inelastic defgrad and plastic strain @@ -3173,7 +3209,7 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::constitutive_update( is_plastic_gp_[gp_] = true; err_status = ViscoplastUtils::ErrorType::no_errors; // perform local time integration - Core::LinAlg::Matrix<10, 1> sol = viscoplastic_correction(deftensors, temperature, err_status); + Core::LinAlg::Matrix<10, 1> sol = viscoplastic_correction(local_integration_input, err_status); // throw error if the Local Newton Loop cannot be evaluated with the given substepping // settings if (err_status != ViscoplastUtils::ErrorType::no_errors) @@ -3196,8 +3232,8 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::constitutive_update( time_step_quantities_.current_plastic_defgrad_inverse[gp_] = result.inv_plastic_defgrad; time_step_quantities_.current_plastic_strain[gp_] = result.plastic_strain; time_step_quantities_.current_equiv_stress[gp_] = state_quantities_.curr_equiv_stress; - time_step_quantities_.current_rightCG[gp_] = deftensors.right_cg; - time_step_quantities_.current_defgrad[gp_] = deftensors.defgrad; + time_step_quantities_.current_rightCG[gp_] = local_integration_input.right_cg; + time_step_quantities_.current_defgrad[gp_] = local_integration_input.defgrad; } return result; @@ -3332,13 +3368,20 @@ void Mat::InelasticDefgradTransvIsotropElastViscoplast::unpack_inelastic( *--------------------------------------------------------------------*/ Core::LinAlg::Matrix<10, 1> Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_local_newton_residual( - const Core::LinAlg::Matrix<3, 3>& CM, const double temperature, - const Core::LinAlg::Matrix<10, 1>& x, const double last_plastic_strain, - const Core::LinAlg::Matrix<3, 3>& last_iFinM, const double dt, - ViscoplastUtils::ErrorType& err_status) + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + const Core::LinAlg::Matrix<10, 1>& x, + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) { ensure_error_free_evaluation(err_status); + // retrieve required data from the local integration input + const Core::LinAlg::Matrix<3, 3>& last_iFinM = + local_integration_input.elastic_predictor_inverse_plastic_defgrad; + const double last_plastic_strain = local_integration_input.last_plastic_strain; + const double step = local_integration_input.step; + + // auxiliaries Core::LinAlg::Matrix<3, 3> temp3x3(Core::LinAlg::Initialization::zero); @@ -3347,8 +3390,8 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_local_newton_residua const double plastic_strain = x(9); // evaluate state variables - state_quantities_ = evaluate_state_quantities(CM, temperature, iFinM, plastic_strain, err_status, - dt, ViscoplastUtils::StateQuantityEvalType::full_eval); + state_quantities_ = evaluate_state_quantities(local_integration_input, iFinM, plastic_strain, + err_status, ViscoplastUtils::StateQuantityEvalType::full_eval); // declare residuals of the LNL Core::LinAlg::Matrix<3, 3> resFM(Core::LinAlg::Initialization::zero); @@ -3363,7 +3406,7 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_local_newton_residua // calculate residual of the equation for plastic strain resepsp = plastic_strain - last_plastic_strain - - dt * state_quantities_.curr_equiv_plastic_strain_rate; + step * state_quantities_.curr_equiv_plastic_strain_rate; } // compute residuals (logarithmic time integration) else if (parameter()->timint_type() == ViscoplastUtils::TimIntType::logarithmic) @@ -3399,11 +3442,11 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_local_newton_residua } // calculate residual of the equation for inelastic defgrad - resFM.update(1.0, logT, dt, state_quantities_.curr_lpM, 0.0); + resFM.update(1.0, logT, step, state_quantities_.curr_lpM, 0.0); // calculate residual of the equation for plastic strain resepsp = plastic_strain - last_plastic_strain - - dt * state_quantities_.curr_equiv_plastic_strain_rate; + step * state_quantities_.curr_equiv_plastic_strain_rate; } else { @@ -3432,13 +3475,17 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_local_newton_residua *--------------------------------------------------------------------*/ Core::LinAlg::Matrix<10, 10> Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_local_newton_jacobian( - const Core::LinAlg::Matrix<3, 3>& CM, const double temperature, - const Core::LinAlg::Matrix<10, 1>& x, const double last_plastic_strain, - const Core::LinAlg::Matrix<3, 3>& last_iFinM, const double dt, - ViscoplastUtils::ErrorType& err_status) + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + const Core::LinAlg::Matrix<10, 1>& x, + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) { ensure_error_free_evaluation(err_status); + // retrieve required data from the local integration input + const Core::LinAlg::Matrix<3, 3>& last_iFinM = + local_integration_input.elastic_predictor_inverse_plastic_defgrad; + const double step = local_integration_input.step; // auxiliaries Core::LinAlg::FourTensor<3> tempFourTensor(true); @@ -3450,8 +3497,8 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_local_newton_jacobia const double plastic_strain = x(9); // evaluate state derivatives - state_quantity_derivatives_ = evaluate_state_quantity_derivatives(CM, temperature, iFinM, - plastic_strain, err_status, dt, + state_quantity_derivatives_ = evaluate_state_quantity_derivatives(local_integration_input, iFinM, + plastic_strain, err_status, ViscoplastUtils::StateQuantityDerivEvalType::full_eval); // we do not reevaluate the state // quantities, this was done in the // residual computation already @@ -3494,12 +3541,12 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_local_newton_jacobia // compute 1x9 south-west component block of the Jacobian (derivative of residual for // plastic strain w.r.t. inelastic deformation gradient) - J_epsp_iFin.update(-dt * state_quantity_derivatives_.curr_dpsr_dequiv_stress, + J_epsp_iFin.update(-step * state_quantity_derivatives_.curr_dpsr_dequiv_stress, state_quantity_derivatives_.curr_dequiv_stress_diFin, 0.0); // compute south-east component of the Jacobian (derivative of residual for plastic // strain w.r.t. plastic strain) - J_epsp_epsp = 1.0 - dt * state_quantity_derivatives_.curr_dpsr_depsp; + J_epsp_epsp = 1.0 - step * state_quantity_derivatives_.curr_dpsr_depsp; } else if (parameter()->timint_type() == ViscoplastUtils::TimIntType::logarithmic) // logarithmic time integration @@ -3544,20 +3591,20 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_local_newton_jacobia 1.0, last_FinM, const_non_mat_tensors.id3x3, dTdiFin); Core::LinAlg::Matrix<9, 9> dlogTdiFin(Core::LinAlg::Initialization::zero); dlogTdiFin.multiply_nn(1.0, dlogTdT, dTdiFin, 0.0); - J_iFin_iFin.update(1.0, dlogTdiFin, dt, state_quantity_derivatives_.curr_dlpdiFin, 0.0); + J_iFin_iFin.update(1.0, dlogTdiFin, step, state_quantity_derivatives_.curr_dlpdiFin, 0.0); // compute 9x1 north-east component block of the Jacobian (derivative of residual for // inelastic deformation gradient w.r.t. plastic strain) - J_iFin_epsp.update(dt, state_quantity_derivatives_.curr_dlpdepsp, 0.0); + J_iFin_epsp.update(step, state_quantity_derivatives_.curr_dlpdepsp, 0.0); // compute 1x9 south-west component block of the Jacobian (derivative of residual for // plastic strain w.r.t. inelastic deformation gradient) - J_epsp_iFin.update(-dt * state_quantity_derivatives_.curr_dpsr_dequiv_stress, + J_epsp_iFin.update(-step * state_quantity_derivatives_.curr_dpsr_dequiv_stress, state_quantity_derivatives_.curr_dequiv_stress_diFin, 0.0); // compute south-east component of the Jacobian (derivative of residual for plastic // strain w.r.t. plastic strain) - J_epsp_epsp = 1.0 - dt * state_quantity_derivatives_.curr_dpsr_depsp; + J_epsp_epsp = 1.0 - step * state_quantity_derivatives_.curr_dpsr_depsp; } else { @@ -3574,9 +3621,9 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_local_newton_jacobia *--------------------------------------------------------------------*/ Core::LinAlg::Matrix<10, 1> Mat::InelasticDefgradTransvIsotropElastViscoplast::viscoplastic_correction( - const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationDeformationTensors& - deftensors, - const double temperature, ViscoplastUtils::ErrorType& err_status) + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + ViscoplastUtils::ErrorType& err_status) { ensure_error_free_evaluation(err_status); @@ -3608,7 +3655,7 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::viscoplastic_correction( // interpolate deformation gradient if we use local substepping, and calculate the right // Cauchy-Green deformation tensor accordingly curr_FM = tensor_interpolator_.get_interpolated_matrix( - {time_step_quantities_.last_defgrad[gp_], deftensors.defgrad}, {0.0, 1.0}, + {time_step_quantities_.last_defgrad[gp_], local_integration_input.defgrad}, {0.0, 1.0}, local_substepping_utils_.get_normalized_next_time_param(time_step_tracker_.dt), tensor_interp_err_status); if (tensor_interp_err_status != Core::LinAlg::TensorInterpolationErrorType::NoErrors) @@ -3617,18 +3664,23 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::viscoplastic_correction( "{}", get_error_warning_info(std::format("Tensor interpolation failed with err: {}", Core::LinAlg::make_error_message(tensor_interp_err_status)))); } - ViscoplastUtils::LocalIntegrationDeformationTensors curr_deftensors( - curr_FM, time_step_quantities_.last_substep_plastic_defgrad_inverse[gp_]); // interpolate temperature - curr_temp = std::lerp(time_step_quantities_.last_temperature[gp_], temperature, + curr_temp = std::lerp(time_step_quantities_.last_temperature[gp_], + local_integration_input.temperature, local_substepping_utils_.get_normalized_next_time_param(time_step_tracker_.dt)); + auto curr_local_integration_input = + ViscoplastUtils::LocalIntegrationInput{{.defgrad = curr_FM, + .temperature = curr_temp, + .last_inv_inelastic_defgrad = + time_step_quantities_.last_substep_plastic_defgrad_inverse[gp_], + .last_plastic_strain = time_step_quantities_.last_substep_plastic_strain[gp_], + .step = local_substepping_utils_.get_substep_size()}}; + // perform substep local Newton loop err_status = ViscoplastUtils::ErrorType::no_errors; - sol = local_newton_loop(curr_deftensors, curr_temp, - time_step_quantities_.last_substep_plastic_strain[gp_], - local_substepping_utils_.get_substep_size(), err_status); + sol = local_newton_loop(curr_local_integration_input, err_status); // update Local Newton quantities local_newton_manager_.update_after_local_newton(gp_); @@ -3649,7 +3701,8 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::viscoplastic_correction( else { // halve and prepare a new substep - bool halving_success = halve_and_prepare_new_substep(sol, curr_deftensors.right_cg); + bool halving_success = + halve_and_prepare_new_substep(sol, curr_local_integration_input.right_cg); // if the halving number was exceeded --> return with error if (!halving_success) { @@ -3666,8 +3719,7 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::viscoplastic_correction( { // perform local Newton loop - sol = local_newton_loop(deftensors, temperature, time_step_quantities_.last_plastic_strain[gp_], - time_step_tracker_.dt, err_status); + sol = local_newton_loop(local_integration_input, err_status); if (err_status != ViscoplastUtils::ErrorType::no_errors) { FOUR_C_THROW("{}", get_error_warning_info(std::format( @@ -3687,9 +3739,8 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::viscoplastic_correction( /*--------------------------------------------------------------------* *--------------------------------------------------------------------*/ Core::LinAlg::Matrix<10, 1> Mat::InelasticDefgradTransvIsotropElastViscoplast::local_newton_loop( - const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationDeformationTensors& - deftensors, - const double temperature, const double last_plastic_strain, const double dt, + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) { ensure_error_free_evaluation(err_status); @@ -3711,7 +3762,7 @@ Core::LinAlg::Matrix<10, 1> Mat::InelasticDefgradTransvIsotropElastViscoplast::l // initialize local Newton local_newton_manager_.reset_iter(); - temp10x1 = determine_local_newton_init_estimate(dt, deftensors, last_plastic_strain, err_status); + temp10x1 = determine_local_newton_init_estimate(local_integration_input, err_status); local_newton_manager_.save_init_estimate_and_reset_convergence_quantities(temp10x1); // handle eventual error in the initial estimate determination if (err_status != ViscoplastUtils::ErrorType::no_errors) @@ -3738,9 +3789,8 @@ Core::LinAlg::Matrix<10, 1> Mat::InelasticDefgradTransvIsotropElastViscoplast::l err_status = ViscoplastUtils::ErrorType::no_errors; // evaluate residual - residual = evaluate_local_newton_residual(deftensors.right_cg, temperature, - local_newton_manager_.sol(), last_plastic_strain, - deftensors.elastic_predictor_inverse_plastic_defgrad, dt, err_status); + residual = evaluate_local_newton_residual( + local_integration_input, local_newton_manager_.sol(), err_status); // error management after residual evaluation manage_evaluation(err_status, eval_action); @@ -3845,9 +3895,8 @@ Core::LinAlg::Matrix<10, 1> Mat::InelasticDefgradTransvIsotropElastViscoplast::l } // evaluate Jacobian - jacMat = evaluate_local_newton_jacobian(deftensors.right_cg, temperature, - local_newton_manager_.sol(), last_plastic_strain, - deftensors.elastic_predictor_inverse_plastic_defgrad, dt, err_status); + jacMat = evaluate_local_newton_jacobian( + local_integration_input, local_newton_manager_.sol(), err_status); // error management after Jacobian evaluation manage_evaluation(err_status, eval_action); @@ -4085,16 +4134,17 @@ bool Mat::InelasticDefgradTransvIsotropElastViscoplast::solve_local_newton_linea /*--------------------------------------------------------------------* *--------------------------------------------------------------------*/ bool Mat::InelasticDefgradTransvIsotropElastViscoplast::check_elastic_predictor( - const Core::LinAlg::Matrix<3, 3>& CM, const double temperature, - const Core::LinAlg::Matrix<3, 3>& iFinM_pred, const double plastic_strain_pred, - ViscoplastUtils::ErrorType& err_status) + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) { ensure_error_free_evaluation(err_status); // evaluate state with this elastic predictor and the minimum possible time step - state_quantities_ = evaluate_state_quantities(CM, temperature, iFinM_pred, plastic_strain_pred, - err_status, time_step_tracker_.min_dt, + state_quantities_ = evaluate_state_quantities(local_integration_input, + local_integration_input.elastic_predictor_inverse_plastic_defgrad, + local_integration_input.last_plastic_strain, err_status, ViscoplastUtils::StateQuantityEvalType::plastic_strain_rate_only); // check if the predicted plastic strain rate is 0 -> for flow rules with yield functions, @@ -4602,15 +4652,14 @@ bool Mat::InelasticDefgradTransvIsotropElastViscoplast::evaluate_output_data( *--------------------------------------------------------------------*/ Core::LinAlg::Matrix<10, 1> Mat::InelasticDefgradTransvIsotropElastViscoplast::determine_local_newton_init_estimate( - const double dt, - const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationDeformationTensors& - deftensors, - const double last_plastic_strain, + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, const InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) const { ensure_error_free_evaluation(err_status); // we use the elastic predictor - return wrap_unknowns(deftensors.elastic_predictor_inverse_plastic_defgrad, last_plastic_strain); + return wrap_unknowns(local_integration_input.elastic_predictor_inverse_plastic_defgrad, + local_integration_input.last_plastic_strain); } FOUR_C_NAMESPACE_CLOSE diff --git a/src/mat/4C_mat_inelastic_defgrad_factors.hpp b/src/mat/4C_mat_inelastic_defgrad_factors.hpp index b03151b9bcb..3d630181ad4 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors.hpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors.hpp @@ -1570,21 +1570,20 @@ namespace Mat * deformation tensor, given inverse plastic deformation gradient and given equivalent * plastic strain * - * @param[in] CM right Cauchy-Green deformation tensor \f[ \boldsymbol{C} \f] in matrix form - * @param[in] temperature absolute temperature + * @param[in] local_integration_input input for the local time integration * @param[in] iFinM inverse inelastic deformation gradient * \f[ \boldsymbol{F}_{\text{in}}^{-1} \f] in matrix form * @param[in] plastic_strain plastic strain \f$ \varepsilon_{\text{p}} \f$ * @param[out] err_status error status - * @param[in] dt time step (or substep) length used for time integration * @param[in] eval_type evaluation type: full evaluation or only * partial evaluation, e.g. stop once the plastic strain rate has * been evaluated */ InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantities evaluate_state_quantities( - const Core::LinAlg::Matrix<3, 3>& CM, const double temperature, + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, const Core::LinAlg::Matrix<3, 3>& iFinM, const double plastic_strain, - InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status, const double dt, + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status, const InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantityEvalType& eval_type) const; @@ -1592,14 +1591,11 @@ namespace Mat * Cauchy-Green deformation tensor, the inverse plastic deformation gradient and the equivalent * plastic strain (for a given/calculated state) * - * @param[in] CM right Cauchy-Green deformation tensor \f$ \boldsymbol{C} \f$ in matrix form - * @param[in] temperature absolute temperature + * @param[in] local_integration_input input for the local time integration * @param[in] iFinM inverse inelastic deformation gradient \f$ \boldsymbol{F}_{\text{in}}^{-1} * \f$ in matrix form * @param[in] plastic_strain plastic strain \f$ \varepsilon_{\text{p}} \f$ * @param[out] err_status error status - * @param[in] dt time step length \f$ \Delta t - * \f$ (used for the integration) * @param[in] eval_state boolean: do we want to also evaluate the current state first (true) * or is this already available from the * current state variables (false) @@ -1608,10 +1604,11 @@ namespace Mat * been evaluated */ InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantityDerivatives - evaluate_state_quantity_derivatives(const Core::LinAlg::Matrix<3, 3>& CM, - const double temperature, const Core::LinAlg::Matrix<3, 3>& iFinM, - const double plastic_strain, - InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status, const double dt, + evaluate_state_quantity_derivatives( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + const Core::LinAlg::Matrix<3, 3>& iFinM, const double plastic_strain, + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status, const InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantityDerivEvalType& eval_type, const bool eval_state = false) const; @@ -1714,17 +1711,13 @@ namespace Mat * i.e., the deformation in the current time step is purely elastic with no viscoplastic * contribution. * - * @param[in] CM right Cauchy_Green deformation tensor \f$ \boldsymbol{C} \f$ in matrix form - * @param[in] temperature absolute temperature - * @param[in] iFinM_pred predictor of the inverse inelastic deformation gradient \f$ - * \bm{F}_{\text{in, pred}} \f$ - * @param[in] plastic_strain_pred predictor of the plastic strain \f$ \varepsilon_{\text{p, - * pred}} \f$ + * @param[in] local_integration_input input for the local time integration * @param[out] err_status error status * @return boolean value: true (predictor = solution), or false (predictor != solution) */ - bool check_elastic_predictor(const Core::LinAlg::Matrix<3, 3>& CM, const double temperature, - const Core::LinAlg::Matrix<3, 3>& iFinM_pred, const double plastic_strain_pred, + bool check_elastic_predictor( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status); /*! @@ -1733,24 +1726,18 @@ namespace Mat * @note The state quantities (class variable) are updated in this method, since they * are used for the computation of the residual! * - * @param[in] CM right Cauchy_Green deformation tensor \f$ \boldsymbol{C} \f$ in matrix form - * @param[in] temperature absolute temperature + * @param[in] local_integration_input input for the local time integration * @param[in] x vector of Local Newton Loop unknowns, composed of the components of the * inverse inelastic deformation gradient \f$ \boldsymbol{F}_{\text{in}}^{-1} \f$ and plastic * strain \f$ \varepsilon_{\text{p}} \f$ - * @param[in] last_plastic_strain plastic strain \f$ \varepsilon_{\text{p}, n}\f$ at the - * previous time instant - * @param[in] last_iFinM last inverse inelastic deformation gradient - * \f$ \boldsymbol{F}_{\text{in}, n}^{-1} \f$ at the previous time instant - * in matrix form - * @param[in] dt time step (or substep) length used for time integration * @param[out] err_status error status * @return residual of the LNL equations */ - Core::LinAlg::Matrix<10, 1> evaluate_local_newton_residual(const Core::LinAlg::Matrix<3, 3>& CM, - const double temperature, const Core::LinAlg::Matrix<10, 1>& x, - const double last_plastic_strain, const Core::LinAlg::Matrix<3, 3>& last_iFinM, - const double dt, InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status); + Core::LinAlg::Matrix<10, 1> evaluate_local_newton_residual( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + const Core::LinAlg::Matrix<10, 1>& x, + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status); /*! * @brief After an unsuccessful convergence check and after the maximum number of local @@ -1787,25 +1774,18 @@ namespace Mat * They require the state quantities, which were evaluated and stored * previously when calculating the residual. * - * @param[in] CM right Cauchy_Green deformation tensor \f$ \boldsymbol{C} \f$ in matrix form - * @param[in] temperature absolute temperature + * @param[in] local_integration_input input for the local time integration * @param[in] x vector of Local Newton Loop unknowns, composed of the components of the * inverse inelastic deformation gradient \f$ \boldsymbol{F}_{\text{in}}^{-1} \f$ and plastic * strain \f$ \varepsilon_{\text{p}} \f$ - * @param[in] last_plastic_strain last plastic strain \f$ \varepsilon_{\text{p}, n}\f$ at the - * previous time instant - * @param[in] last_iFinM last inverse plastic deformation gradient - * \f$ \boldsymbol{F}_{\text{in}, n}^{-1} \f$ at the previous time instant - * in matrix form - * @param[in] dt time step (or substep) length used for time integration * @param[out] err_status error status * @return 10x10 jacobian matrix of the Local Newton Loop and of the linearization * \f$ \boldsymbol{J} \f$ */ Core::LinAlg::Matrix<10, 10> evaluate_local_newton_jacobian( - const Core::LinAlg::Matrix<3, 3>& CM, const double temperature, - const Core::LinAlg::Matrix<10, 1>& x, const double last_plastic_strain, - const Core::LinAlg::Matrix<3, 3>& last_iFinM, const double dt, + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + const Core::LinAlg::Matrix<10, 1>& x, InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status); /*! @@ -1814,17 +1794,15 @@ namespace Mat * @note Uses local substepping if specified so by the user; the current time step is halved if * problematic numerical states, marked with an error status, are encountered * - * @param[in] deftensors deformation tensors used for local time integration (reset if + * @param[in] local_integration_input input for the local time integration (reset if * substepping is used) - * @param[in] temperature absolute temperature * @param[out] err_status error status * @return solution vector of the Local Newton Loop, structured analogously to the initial guess * x */ Core::LinAlg::Matrix<10, 1> viscoplastic_correction( - const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationDeformationTensors& - deftensors, - const double temperature, + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status); /*! @@ -1834,17 +1812,13 @@ namespace Mat * @note The method does not perform local substepping internally, but only determines the * solution of a single substep in the substep loop. * - * @param[in] deftensors deformation tensors used for local time integration - * @param[in] temperature absolute temperature - * @param[in] last_plastic_strain plastic strain at the previous time instant - * @param[in] dt time step size to use for evaluation + * @param[in] local_integration_input input for the local time integration * @param[out] err_status error status * @return solution of the Local Newton Loop */ Core::LinAlg::Matrix<10, 1> local_newton_loop( - const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationDeformationTensors& - deftensors, - const double temperature, const double last_plastic_strain, const double dt, + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status); @@ -1894,14 +1868,14 @@ namespace Mat * Currently, analytical off-diagonal stiffness integration is implemented * only for logarithmic local time integration. * - * @param CredM Right Cauchy-Green deformation tensor. - * @param temperature Current temperature. - * @param err_status Error flag describing the evaluation status. + * @param[in] local_integration_input input for the local time integration + * @param[out] err_status Error flag describing the evaluation status. * @return derivatives of the history variables with respect to temperature */ InelasticDefgradTransvIsotropElastViscoplastUtils::HistoryVariablesDerivativesWrtTemperature - evaluate_history_variables_wrt_temperature(const Core::LinAlg::Matrix<3, 3>& CredM, - const double temperature, + evaluate_history_variables_wrt_temperature( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status); /** @@ -1916,16 +1890,16 @@ namespace Mat * a local linear system is assembled and solved * to determine the total Cauchy-Green derivatives of the history variables. * - * @param CredM Right Cauchy-Green deformation tensor. - * @param temperature Current temperature. - * @param err_status Error flag describing the evaluation status. + * @param[in] local_integration_input input for the local time integration + * @param[out] err_status Error flag describing the evaluation status. * * @return derivatives of the history variables with respect to the right Cauchy-Green * deformation tensor */ InelasticDefgradTransvIsotropElastViscoplastUtils::HistoryVariablesDerivativesWrtCauchyGreen - evaluate_history_variables_wrt_cauchy_green(const Core::LinAlg::Matrix<3, 3>& CredM, - const double temperature, + evaluate_history_variables_wrt_cauchy_green( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status); /*! @@ -1935,14 +1909,14 @@ namespace Mat * directly. Otherwise, this method evaluates the full state quantities for the current state * and fills the reduced coupling-state cache. * - * @param[in] CredM Right Cauchy-Green deformation tensor - * @param[in] temperature Current temperature + * @param[in] local_integration_input input for the local time integration * @param[out] err_status Error flag describing the evaluation status * @return thermo-mechanical coupling state */ InelasticDefgradTransvIsotropElastViscoplastUtils::ThermoMechanicalCouplingState - evaluate_thermo_mechanical_coupling_state(const Core::LinAlg::Matrix<3, 3>& CredM, - const double temperature, + evaluate_thermo_mechanical_coupling_state( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status); /*! @@ -1952,14 +1926,14 @@ namespace Mat * returned directly. Otherwise, this method evaluates the full state quantities and derivatives * for the current state and fills the reduced coupling-state cache. * - * @param[in] CredM Right Cauchy-Green deformation tensor - * @param[in] temperature Current temperature + * @param[in] local_integration_input input for the local time integration * @param[out] err_status Error flag describing the evaluation status * @return thermo-mechanical coupling state derivatives */ InelasticDefgradTransvIsotropElastViscoplastUtils::ThermoMechanicalCouplingStateDerivatives - evaluate_thermo_mechanical_coupling_state_derivatives(const Core::LinAlg::Matrix<3, 3>& CredM, - const double temperature, + evaluate_thermo_mechanical_coupling_state_derivatives( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status); @@ -2070,19 +2044,15 @@ namespace Mat * If adaptive estimate interpolation is used, this method also prepares everything for the * further re-estimations. * - * @param[in] dt time step / substep size - * @param[in] deftensors deformation tensors used for local time integration - * @param[in] last_plastic_strain equivalent plastic strain at the previously converged - * time instant + * @param[in] local_integration_input input for the local time integration * @param[in] err_status error status after the procedure * @return initial estimate containing the inverse inelastic defgrad (components 0 - 8), and * the equivalent plastic strain (component 9) for the Local Newton within this time step / * substep */ - [[nodiscard]] Core::LinAlg::Matrix<10, 1> determine_local_newton_init_estimate(const double dt, - const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationDeformationTensors& - deftensors, - const double last_plastic_strain, + [[nodiscard]] Core::LinAlg::Matrix<10, 1> determine_local_newton_init_estimate( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, const InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) const; }; } // namespace Mat diff --git a/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp b/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp index 997aacec9ad..4dd0c27031a 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp @@ -597,16 +597,18 @@ void Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalNewtonManager: /*--------------------------------------------------------------------* *--------------------------------------------------------------------*/ -Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationDeformationTensors:: - LocalIntegrationDeformationTensors( - const Core::LinAlg::Matrix<3, 3>& F, const Core::LinAlg::Matrix<3, 3>& last_iFp) +Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput:: + LocalIntegrationInput(const Config& cfg) { - defgrad = F; + defgrad = cfg.defgrad; inv_defgrad.invert(defgrad); right_cg.multiply_tn(1.0, defgrad, defgrad, 0.0); - elastic_predictor_inverse_plastic_defgrad = last_iFp; + elastic_predictor_inverse_plastic_defgrad = cfg.last_inv_inelastic_defgrad; elastic_predictor_elastic_defgrad.multiply( 1.0, defgrad, elastic_predictor_inverse_plastic_defgrad, 0.0); + temperature = cfg.temperature; + last_plastic_strain = cfg.last_plastic_strain; + step = cfg.step; } diff --git a/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp b/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp index a118b70345d..930c70e7c9d 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp @@ -1023,20 +1023,33 @@ namespace Mat bool resize_called_{false}; }; - //! helper struct containing deformation tensors passed as input - //! for the local time integration - struct LocalIntegrationDeformationTensors + //! helper struct containing relevant input for the local time integration via the Local + //! Newton-Raphson scheme + struct LocalIntegrationInput { - /*! - * @brief constructor - * - * @param[in] F deformation gradient \f$ \mathbf{F}_{n+1} \f$ - * @param[in] last_iFp previous inverse inelastic/plastic deformation gradient \f$ - \mathbf{F}_{\text{p},n}^{-1} \f$ - * - */ - LocalIntegrationDeformationTensors( - const Core::LinAlg::Matrix<3, 3>& F, const Core::LinAlg::Matrix<3, 3>& last_iFp); + //! configuration struct to be used for the construction of the integration input + struct Config + { + //! deformation gradient \f$ \boldsymbol{F}_{n+1} \f$ + Core::LinAlg::Matrix<3, 3> defgrad; + + //! absolute temperature \f$ T_{n+1} \f$ + double temperature; + + //! previous inverse inelastic/plastic deformation gradient \f$ \mathbf{F}_{\text{p},n}^{-1} + //! \f$ + Core::LinAlg::Matrix<3, 3> last_inv_inelastic_defgrad; + + //! previous plastic strain \f$ \varepsilon_{\text{p},n} \f$ + double last_plastic_strain; + + //! timestep / substep size \f$ \Delta t \f$ / \f$ \Delta \tilde{t} \f$ + double step; + }; + + LocalIntegrationInput() = delete; + //! constructor based on a given config + explicit LocalIntegrationInput(const Config& cfg); //! deformation gradient \f$ \mathbf{F}_{n+1} \f$ Core::LinAlg::Matrix<3, 3> defgrad; @@ -1054,6 +1067,15 @@ namespace Mat //! elastic deformation gradient within the elastic predictor \f$ //! \mathbf{F}_{\mathrm{e},n+1}^{(\mathrm{E})} \f$ Core::LinAlg::Matrix<3, 3> elastic_predictor_elastic_defgrad; + + //! absolute temperature \f$ T_{n+1} \f$ + double temperature; + + //! accumulated plastic strain at the previous time instant \f$ \varepsilon_{\mathrm{P},n} \f$ + double last_plastic_strain; + + //! timestep / substep size \f$ \Delta t \f$ / \f$ \Delta \tilde{t} \f$ + double step; }; } // namespace InelasticDefgradTransvIsotropElastViscoplastUtils diff --git a/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp b/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp index a74454452bb..ccbcc0d5a2f 100644 --- a/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp +++ b/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp @@ -28,9 +28,9 @@ namespace Core::Utils::SingletonOwnerRegistry::ScopeGuard guard; }; - /// tests the LocalIntegrationDeformationTensors of + /// tests the LocalIntegrationInput of /// InelasticDefgradTransvIsotropElastViscoplast - TEST_F(InelasticDefgradFactorsServiceTest, TestLocalIntegrationDeformationTensors) + TEST_F(InelasticDefgradFactorsServiceTest, TestLocalIntegrationInput) { // setup input Core::LinAlg::Matrix<3, 3> defgrad{Core::LinAlg::Initialization::zero}; @@ -107,15 +107,27 @@ namespace elastic_predictor_elastic_defgrad_ref(2, 1) = 0.7307524651000326; elastic_predictor_elastic_defgrad_ref(2, 2) = 0.5290836326068751; - // initialize LocalIntegrationDeformationTensors and perform checks for the saved quantities - ViscoplastUtils::LocalIntegrationDeformationTensors deftensors(defgrad, last_iFin); - FOUR_C_EXPECT_NEAR(deftensors.defgrad, defgrad, 1.0e-15); - FOUR_C_EXPECT_NEAR(deftensors.inv_defgrad, inv_defgrad_ref, 1.0e-15); - FOUR_C_EXPECT_NEAR(deftensors.right_cg, right_cg_ref, 1.0e-15); - FOUR_C_EXPECT_NEAR(deftensors.elastic_predictor_elastic_defgrad, + const double temperature = 293.15; + const double last_plastic_strain = 0.0; + const double timestep = 0.1; + + + // initialize LocalIntegrationInput and perform checks for the saved quantities + ViscoplastUtils::LocalIntegrationInput local_integration_input{{.defgrad = defgrad, + .temperature = temperature, + .last_inv_inelastic_defgrad = last_iFin, + .last_plastic_strain = last_plastic_strain, + .step = timestep}}; + FOUR_C_EXPECT_NEAR(local_integration_input.defgrad, defgrad, 1.0e-15); + FOUR_C_EXPECT_NEAR(local_integration_input.inv_defgrad, inv_defgrad_ref, 1.0e-15); + FOUR_C_EXPECT_NEAR(local_integration_input.right_cg, right_cg_ref, 1.0e-15); + FOUR_C_EXPECT_NEAR(local_integration_input.elastic_predictor_elastic_defgrad, elastic_predictor_elastic_defgrad_ref, 1.0e-15); - FOUR_C_EXPECT_NEAR(deftensors.elastic_predictor_inverse_plastic_defgrad, + FOUR_C_EXPECT_NEAR(local_integration_input.elastic_predictor_inverse_plastic_defgrad, elastic_predictor_inverse_plastic_defgrad_ref, 1.0e-15); + EXPECT_EQ(local_integration_input.temperature, temperature); + EXPECT_EQ(local_integration_input.last_plastic_strain, last_plastic_strain); + EXPECT_EQ(local_integration_input.step, timestep); } diff --git a/unittests/mat/4C_inelastic_defgrad_factors_test.cpp b/unittests/mat/4C_inelastic_defgrad_factors_test.cpp index 6b4fa61b4aa..69a34af2f85 100644 --- a/unittests/mat/4C_inelastic_defgrad_factors_test.cpp +++ b/unittests/mat/4C_inelastic_defgrad_factors_test.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -1738,9 +1739,16 @@ namespace // set reference solution for the state quantities set_up_state_quantities_solution(); - // compute right Cauchy-Green deformation tensor - Core::LinAlg::Matrix<3, 3> CM(Core::LinAlg::Initialization::zero); - CM.multiply_tn(1.0, FM_, FM_, 0.0); + // setup local integration input + Core::LinAlg::Matrix<3, 3> dummy_last_iFinM{Core::LinAlg::Initialization::zero}; + dummy_last_iFinM(0, 0) = dummy_last_iFinM(1, 1) = dummy_last_iFinM(2, 2) = 1.0; + const double dummy_last_plastic_strain = 0.0; + + auto local_integration_input = ViscoplastUtils::LocalIntegrationInput{{.defgrad = FM_, + .temperature = ref_temperature, + .last_inv_inelastic_defgrad = dummy_last_iFinM, + .last_plastic_strain = dummy_last_plastic_strain, + .step = time_step_size}}; // declare error status Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType err_status = @@ -1749,15 +1757,15 @@ namespace // compute StateQuantities objects Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantities computed_state_quantities_transv_isotrop = - transv_isotropic_material->evaluate_state_quantities(CM, ref_temperature, + transv_isotropic_material->evaluate_state_quantities(local_integration_input, iFin_transv_isotrop_vplast_refJC_solution_, - plastic_strain_transv_isotrop_vplast_refJC_solution_, err_status, 1.0, + plastic_strain_transv_isotrop_vplast_refJC_solution_, err_status, Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantityEvalType:: full_eval); Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantities - computed_state_quantities_isotrop = isotropic_material->evaluate_state_quantities(CM, - ref_temperature, iFin_transv_isotrop_vplast_refJC_solution_, - plastic_strain_transv_isotrop_vplast_refJC_solution_, err_status, 1.0, + computed_state_quantities_isotrop = isotropic_material->evaluate_state_quantities( + local_integration_input, iFin_transv_isotrop_vplast_refJC_solution_, + plastic_strain_transv_isotrop_vplast_refJC_solution_, err_status, Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantityEvalType:: full_eval); @@ -2334,9 +2342,16 @@ namespace set_up_state_quantity_derivatives_solution(); - // compute right Cauchy-Green deformation tensor - Core::LinAlg::Matrix<3, 3> CM(Core::LinAlg::Initialization::zero); - CM.multiply_tn(1.0, FM_, FM_, 0.0); + // setup local integration input + Core::LinAlg::Matrix<3, 3> dummy_last_iFinM{Core::LinAlg::Initialization::zero}; + dummy_last_iFinM(0, 0) = dummy_last_iFinM(1, 1) = dummy_last_iFinM(2, 2) = 1.0; + const double dummy_last_plastic_strain = 0.0; + + auto local_integration_input = ViscoplastUtils::LocalIntegrationInput{{.defgrad = FM_, + .temperature = ref_temperature, + .last_inv_inelastic_defgrad = dummy_last_iFinM, + .last_plastic_strain = dummy_last_plastic_strain, + .step = time_step_size}}; Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType err_status = Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType::no_errors; @@ -2344,18 +2359,18 @@ namespace // compute StateQuantityDerivatives objects Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantityDerivatives computed_state_quantity_derivatives_transv_isotrop = - transv_isotropic_material->evaluate_state_quantity_derivatives(CM, ref_temperature, + transv_isotropic_material->evaluate_state_quantity_derivatives(local_integration_input, iFin_transv_isotrop_vplast_refJC_solution_, - plastic_strain_transv_isotrop_vplast_refJC_solution_, err_status, 1.0, + plastic_strain_transv_isotrop_vplast_refJC_solution_, err_status, Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantityDerivEvalType:: full_eval, true); Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantityDerivatives computed_state_quantity_derivatives_isotrop = - isotropic_material->evaluate_state_quantity_derivatives(CM, ref_temperature, + isotropic_material->evaluate_state_quantity_derivatives(local_integration_input, iFin_transv_isotrop_vplast_refJC_solution_, - plastic_strain_transv_isotrop_vplast_refJC_solution_, err_status, 1.0, + plastic_strain_transv_isotrop_vplast_refJC_solution_, err_status, Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantityDerivEvalType:: full_eval, true); @@ -2436,16 +2451,16 @@ namespace //************************************************** const double current_temperature = 313.0; //************************************************** - Core::LinAlg::Matrix<3, 3> CM{Core::LinAlg::Initialization::zero}; - CM(0, 0) = 2.0000000000000000; - CM(0, 1) = 0.0000000000000000; - CM(0, 2) = 0.0000000000000000; - CM(1, 0) = 0.0000000000000000; - CM(1, 1) = 1.0000000000000000; - CM(1, 2) = 0.0000000000000000; - CM(2, 0) = 0.0000000000000000; - CM(2, 1) = 0.0000000000000000; - CM(2, 2) = 1.0000000000000000; + Core::LinAlg::Matrix<3, 3> FM{Core::LinAlg::Initialization::zero}; + FM(0, 0) = std::numbers::sqrt2; + FM(0, 1) = 0.0000000000000000; + FM(0, 2) = 0.0000000000000000; + FM(1, 0) = 0.0000000000000000; + FM(1, 1) = 1.0000000000000000; + FM(1, 2) = 0.0000000000000000; + FM(2, 0) = 0.0000000000000000; + FM(2, 1) = 0.0000000000000000; + FM(2, 2) = 1.0000000000000000; //************************************************** Core::LinAlg::Matrix<3, 3> iFinM{Core::LinAlg::Initialization::zero}; iFinM(0, 0) = 1.2771823873225885; @@ -2659,14 +2674,25 @@ namespace // call pre_evaluate material->pre_evaluate(param_list_thermo_vplast, context, 0, 0); + // setup local integration input + Core::LinAlg::Matrix<3, 3> dummy_last_iFinM{Core::LinAlg::Initialization::zero}; + dummy_last_iFinM(0, 0) = dummy_last_iFinM(1, 1) = dummy_last_iFinM(2, 2) = 1.0; + const double dummy_last_plastic_strain = 0.0; + + auto local_integration_input = ViscoplastUtils::LocalIntegrationInput{{.defgrad = FM, + .temperature = current_temperature, + .last_inv_inelastic_defgrad = dummy_last_iFinM, + .last_plastic_strain = dummy_last_plastic_strain, + .step = time_step_size}}; + Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType err_status{ FourC::Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType::no_errors}; // compute StateQuantities objects Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantities - computed_state_quantities = material->evaluate_state_quantities(CM, current_temperature, - iFinM, plastic_strain, err_status, 1.0, + computed_state_quantities = material->evaluate_state_quantities(local_integration_input, + iFinM, plastic_strain, err_status, Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantityEvalType:: full_eval); @@ -2681,8 +2707,8 @@ namespace // compute StateQuantityDerivatives objects Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantityDerivatives - computed_state_quantity_derivatives = material->evaluate_state_quantity_derivatives(CM, - current_temperature, iFinM, plastic_strain, err_status, 1.0, + computed_state_quantity_derivatives = material->evaluate_state_quantity_derivatives( + local_integration_input, iFinM, plastic_strain, err_status, Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::StateQuantityDerivEvalType:: full_eval, true); From 46858eea93a41597a0a73e6894e9f0b94d14fa76 Mon Sep 17 00:00:00 2001 From: Ana Dragos-Corneliu Date: Mon, 10 Aug 2026 18:06:24 +0200 Subject: [PATCH 2/7] Add AEI parameters: review integrated --- ...4C_global_legacy_module_validmaterials.cpp | 191 +++++++++++++++++- src/mat/4C_mat_inelastic_defgrad_factors.cpp | 6 +- src/mat/4C_mat_inelastic_defgrad_factors.hpp | 18 ++ ..._mat_inelastic_defgrad_factors_service.hpp | 163 +++++++++++++++ .../mat/4C_inelastic_defgrad_factors_test.cpp | 12 +- ...C_inelastic_defgrad_factors_test_utils.hpp | 66 ++++++ 6 files changed, 452 insertions(+), 4 deletions(-) create mode 100644 unittests/mat/4C_inelastic_defgrad_factors_test_utils.hpp diff --git a/src/global_legacy_module/4C_global_legacy_module_validmaterials.cpp b/src/global_legacy_module/4C_global_legacy_module_validmaterials.cpp index f55c72ae18b..25b9b2c6225 100644 --- a/src/global_legacy_module/4C_global_legacy_module_validmaterials.cpp +++ b/src/global_legacy_module/4C_global_legacy_module_validmaterials.cpp @@ -2875,7 +2875,8 @@ std::unordered_map Global::v { using namespace Core::IO::InputSpecBuilders::Validators; namespace ViscoplastUtils = Mat::InelasticDefgradTransvIsotropElastViscoplastUtils; - + namespace AEI = + Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::AdaptiveEstimateInterpolation; known_materials[Core::Materials::mfi_transv_isotrop_elast_viscoplast] = group( "MAT_InelasticDefgradTransvIsotropElastViscoplast", {parameter( @@ -3039,6 +3040,194 @@ std::unordered_map Global::v max_plastic_strain_deriv_incr)})}, {.description = "Settings for registering errors within the procedures used for " "constitutive update", + .required = false}), + group("ADAPTIVE_ESTIMATE_INTERPOLATION", + { + parameter("USE_ADAPTIVE_ESTIMATE_INTERPOLATION", + {.description = "use adaptive estimate interpolation?", + .default_value = true, + .store = + in_struct(&AEI::AEIParams::use_adaptive_estimate_interpolation)}), + parameter("ELASTIC_PREDICTOR_ZERO_COMPONENT_THRESHOLD", + {.description = "components of the elastic predictor (specifically: the " + "respective elastic deformation gradient) smaller than " + "this threshold are set to 0.0 to avoid " + "unnecessary, numerical rotations", + .default_value = 1.0e-13, + .validator = positive(), + .store = in_struct( + &AEI::AEIParams::elastic_predictor_zero_component_threshold)}), + group("PLASTIC_PREDICTOR_CONSTRUCTION", + { + parameter( + "ELASTIC_STRETCH_EIGENVAL_TYPE", + {.description = "elastic stretch eigenvalue specification for the " + "preliminary plastic predictor", + .default_value = AEI::PrelimPlasticPredictor:: + ElasticStretchEigenvalType::scale_unit, + .store = in_struct(&AEI::PlasticPredictorConstructionParams:: + elastic_stretch_eigenval_type)}), + parameter( + "ELASTIC_STRETCH_EIGENVECT_TYPE", + {.description = "elastic stretch eigenvector specification for the " + "preliminary plastic predictor", + .default_value = AEI::PrelimPlasticPredictor:: + ElasticStretchEigenvectType::from_elastic_predictor, + .store = in_struct(&AEI::PlasticPredictorConstructionParams:: + elastic_stretch_eigenvect_type)}), + parameter( + "ELASTIC_ROTATION_TYPE", + {.description = "elastic rotation specification for the " + "preliminary plastic predictor", + .default_value = AEI::PrelimPlasticPredictor:: + ElasticRotationType::from_elastic_predictor, + .store = in_struct(&AEI::PlasticPredictorConstructionParams:: + elastic_rotation_type)}), + parameter("MAX_ITER", + {.description = "maximum number of construction iterations $ " + "i_{\\text{C,max}} $", + .default_value = 50, + .validator = positive(), + .store = in_struct( + &AEI::PlasticPredictorConstructionParams::max_iter)}), + parameter("RELATIVE_UNDERSTRESS_TOL", + {.description = "relative understress tolerance $ \\kappa_{S} $ " + "used to determine the plastic predictor according " + "to $ 1 \\ge \\overline{\\sigma}^{(\\text{P})} / S " + "\\ge 1 - \\kappa_{S} $ ", + .default_value = 1.0e-6, + .validator = in_range(excl(0.), 1.0), + .store = in_struct(&AEI::PlasticPredictorConstructionParams:: + relative_understress_tol)}), + parameter("INTERVAL_SCANNING_PARAM", + {.description = + "interval scanning parameter $s$ for updating the " + "construction parameter $\\tau \\gets \\tau_{\\text{E}} + " + "s \\, \\left( \\tau_{\\hat{\\text{P}}} - " + "\\tau_{\\text{E}} \\right)$ (bisection: $ s = 1/2 $)", + .default_value = 0.5, + .validator = in_range(excl(0.), excl(1.)), + .store = in_struct(&AEI::PlasticPredictorConstructionParams:: + interval_scanning_param)}), + }, + { + .description = "Parameters used for the iterative construction of the " + "plastic predictor", + .required = false, + .store = in_struct(&AEI::AEIParams::plastic_predictor_construction), + }), + group("ESTIMATE_INTERPOLATION", + { + parameter("STARTING_POINT_TYPE", + {.description = "starting point type", + .default_value = AEI::StartingPointType::equiv_stress_history, + .store = in_struct( + &AEI::EstimateInterpolationParams::starting_point_type)}), + parameter("USER_SET_STARTING_POINT", + { + .description = + "specified starting point: for the constant starting point " + "strategy, this value is set at the beginning of each " + "local " + "integration; for the history-based starting point " + "strategy, " + "this value is used only for the first time step", + .default_value = 0.5, + .validator = in_range(0.0, 1.0), + .store = in_struct( + &AEI::EstimateInterpolationParams::user_set_starting_point), + }), + parameter("MAX_ITER", + { + .description = "maximum number of estimate interpolation " + "iterations " + "$i_{\\text{EI,max}}$", + .default_value = 50, + .validator = positive(), + .store = in_struct(&AEI::EstimateInterpolationParams::max_iter), + }), + parameter("INTERVAL_SCANNING_PARAM", + { + .description = + "interval scanning parameter $s$ for updating the " + "interpolation parameter $\\xi \\gets \\xi_{\\text{E}} + s " + "\\, \\left( \\xi_{\\text{P}} - \\xi_{\\text{E}} \\right) " + "(bisection: = $ s = 1/2 $)", + .default_value = 0.5, + .validator = in_range(excl(0.), excl(1.)), + .store = in_struct( + &AEI::EstimateInterpolationParams::interval_scanning_param), + }), + }, + {.description = + "Parameters used for the estimate interpolation between predictors", + .required = false, + .store = in_struct(&AEI::AEIParams::estimate_interpolation)}), + group("HARDENING_MANAGEMENT", + { + parameter("METHOD", + { + .description = "method to be used for handling hardening " + "variables " + "within the " + "adaptive estimate interpolation algorithm", + .default_value = AEI::HardeningManagementMethod:: + integrate_via_evolution_equations, + .store = in_struct(&AEI::HardeningParams::method), + + }), + parameter("MAX_ITER_INTEGRATION", + { + .description = + "maximum number of iterations for the integration of the " + "hardening variables via the evolution equations", + .default_value = 50, + .validator = positive(), + .store = in_struct(&AEI::HardeningParams::max_iter_integration), + }), + parameter("TOL_INTEGRATION", + { + .description = "tolerance for the integration of the hardening " + "variables via the evolution equations", + .default_value = 1.0e-8, + .validator = positive(), + .store = in_struct(&AEI::HardeningParams::tol_integration), + }), + + }, + {.description = "Parameters used for the management of hardening variables " + "during interpolation", + .required = false, + .store = in_struct(&AEI::AEIParams::hardening)}), + group("REESTIMATION", + { + parameter("MAX_NUM_REESTIMATIONS", + {.description = "maximum number of adaptive re-estimations allowed", + .default_value = 10, + .validator = positive_or_zero(), + .store = in_struct( + &AEI::ReestimationParams::max_num_reestimations)}), + parameter("INTERVAL_SCANNING_PARAM", + {.description = + "interval scanning parameter $s$ for determining " + "the intermediate parameter $ \\xi_{\\mathrm{I}} " + "\\gets \\xi_{\\mathrm{E}} + s \\, \\left( \\xi - " + "\\xi_{\\mathrm{E}}\\right) $ (bisection: $ s = 1/2 $)", + .default_value = 0.5, + .validator = in_range(excl(0.), excl(1.)), + .store = in_struct( + &AEI::ReestimationParams::interval_scanning_param)}), + }, + {.description = "Parameters used for the re-estimation procedures", + .required = false, + .store = in_struct(&AEI::AEIParams::reestimation)}), + + }, + {.description = "Parameters used in the Adaptive Estimate Interpolation for Local " + "Newton--Raphson estimates, as presented " + "in Ana, Schmidt, Wall: Adaptive Estimate Interpolation: " + "Accelerating Local Newton--Raphson Schemes in Computational " + "Plasticity / Viscoplasticity, Preprint", .required = false})}, {.description = "Versatile transversely isotropic (or isotropic) viscoplasticity model for " "finite deformations with isotropic hardening, using user-defined " diff --git a/src/mat/4C_mat_inelastic_defgrad_factors.cpp b/src/mat/4C_mat_inelastic_defgrad_factors.cpp index d8a58bad9a9..8647a197ec2 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors.cpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors.cpp @@ -55,6 +55,8 @@ FOUR_C_NAMESPACE_OPEN namespace { namespace ViscoplastUtils = Mat::InelasticDefgradTransvIsotropElastViscoplastUtils; + namespace AEI = + Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::AdaptiveEstimateInterpolation; // declare file-scope instance of the constant non-material tensors static ViscoplastUtils::ConstNonMatTensors const_non_mat_tensors = @@ -700,7 +702,9 @@ Mat::PAR::InelasticDefgradTransvIsotropElastViscoplast:: matdata.parameters.get("LOCAL_NEWTON")), error_registration_settings_( matdata.parameters.get( - "ERROR_REGISTRATION_SETTINGS")) + "ERROR_REGISTRATION_SETTINGS")), + adaptive_estimate_interpolation_params_( + matdata.parameters.get("ADAPTIVE_ESTIMATE_INTERPOLATION")) { // consistency check: yield parameters in case of transversely-isotropic behavior const bool all_yield_cond_param_specified = diff --git a/src/mat/4C_mat_inelastic_defgrad_factors.hpp b/src/mat/4C_mat_inelastic_defgrad_factors.hpp index 3d630181ad4..ebc6be3c30c 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors.hpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors.hpp @@ -414,6 +414,20 @@ namespace Mat return error_registration_settings_; } + //! is the Adaptive Estimate Interpolation used? + [[nodiscard]] bool use_adaptive_estimate_interpolation() const + { + return adaptive_estimate_interpolation_params_.use_adaptive_estimate_interpolation; + } + + //! get Adaptive Estimate Interpolation parameters + [[nodiscard]] const InelasticDefgradTransvIsotropElastViscoplastUtils:: + AdaptiveEstimateInterpolation::AEIParams& + adaptive_estimate_interpolation_params() const + { + return adaptive_estimate_interpolation_params_; + } + private: //! ID of the viscoplasticity law const int viscoplastic_law_id_; @@ -468,6 +482,10 @@ namespace Mat //! get error registration settings for the constitutive update const InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorRegistrationSettings error_registration_settings_; + + //! Adaptive Estimate Interpolation parameters + const InelasticDefgradTransvIsotropElastViscoplastUtils::AdaptiveEstimateInterpolation:: + AEIParams adaptive_estimate_interpolation_params_; }; } // namespace PAR diff --git a/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp b/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp index 930c70e7c9d..5c37f5b364a 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp @@ -15,6 +15,7 @@ #include "4C_mat_multiplicative_split_defgrad_elasthyper_service.hpp" #include "4C_utils_exceptions.hpp" +#include #include #include #include @@ -1078,6 +1079,168 @@ namespace Mat double step; }; + //! namespace containing utilities dedicated to the Adaptive Estimate Interpolation algorithm, + //! presented in Ana, Schmidt, Wall: Adaptive Estimate Interpolation: Accelerating Local + //! Newton-Raphson Schemes in Computational Plasticity and Viscoplasticity, Preprint + namespace AdaptiveEstimateInterpolation + { + + //! namespace containing specifications for the preliminary plastic predictor used within the + //! Adaptive Estimate Interpolation + namespace PrelimPlasticPredictor + { + //! strategy for choosing the elastic stretch eigenvalues \f$ \boldsymbol{\Lambda} \f$ + //! (other construction approaches for the preliminary plastic predictor will add to this + //! enum) + enum class ElasticStretchEigenvalType : std::uint8_t + { + scale_unit, ///< the unit tensor is scaled with the deformation gradient determinant to + ///< maintain plastic incompressibility: \f$ \boldsymbol{\Lambda} = + ///< \det(\boldsymbol{F}_{n+1})^{1/3} \boldsymbol{I} \f$ + }; + + //! strategy for choosing the elastic stretch eigenvectors \f$ \boldsymbol{Q} \f$ (other + //! construction approaches for the preliminary plastic predictor will add to this enum) + enum class ElasticStretchEigenvectType : std::uint8_t + { + from_elastic_predictor, ///< the elastic stretch eigenvectors are taken directly from the + ///< elastic predictor, which is a consistent assumption for + ///< isotropic material behavior + }; + + //! strategy for choosing the elastic stretch rotations \f$ \boldsymbol{R} \f$ (other + //! construction approaches for the preliminary plastic predictor will add to this enum) + enum class ElasticRotationType : std::uint8_t + { + from_elastic_predictor, ///< the elastic rotation is taken directly from the + ///< elastic predictor, which is a consistent assumption for + ///< isotropic material behavior + }; + } // namespace PrelimPlasticPredictor + + //! starting point type to be used for the estimate interpolation between predictors + enum class StartingPointType : std::uint8_t + { + constant, ///< user-set constant factor + equiv_stress_history ///< computes the interpolation factor based on the equivalent + ///< stress from the previous timestep with respect to its + ///< corresponding elastic and plastic predictors, see \emph{IH} + ///< strategy in the paper + }; + + //! enum class: method to be used for handling the hardening variables within the Adaptive + //! Estimate Interpolation procedures + enum class HardeningManagementMethod : std::uint8_t + { + use_previous, ///< use hardening variables from the previously converged time step + integrate_via_evolution_equations, ///< integrate the hardening variables via their + ///< dedicated evolution equations, using the + ///< interpolated elastic deformation gradient as input + ///< --> "smaller local Newton" + }; + + //! struct containing parameters for the iterative construction of the plastic predictor + struct PlasticPredictorConstructionParams + { + //! elastic stretch eigenvalue specification for the preliminary plastic predictor + PrelimPlasticPredictor::ElasticStretchEigenvalType elastic_stretch_eigenval_type; + + //! elastic stretch eigenvector specification for the preliminary plastic predictor + PrelimPlasticPredictor::ElasticStretchEigenvectType elastic_stretch_eigenvect_type; + + //! elastic rotation specification for the preliminary plastic predictor + PrelimPlasticPredictor::ElasticRotationType elastic_rotation_type; + + //! maximum number of construction iterations \f$ i_{\text{C,max}} \f$ + int max_iter; + + //! relative understress tolerance \f$ \kappa_{S} \f$ used to determine the + //! plastic predictor according to \f$ + //! 1 \ge \overline{\sigma}^{(\text{P})} / S \ge 1 - \kappa_{S} \f$ + double relative_understress_tol; + + //! interval scanning parameter \f$ s \f$ for updating the construction parameter \f$ \tau + //! \gets + //! \tau_{\text{E}} + s \, \left( \tau_{\hat{\text{P}}} - \tau_{\text{E}} \right) \f$ + //! (bisection: \f$ s = 1/2 \f$) + double interval_scanning_param; + }; + + + //! struct containing parameters for the estimate interpolation between the elastic and the + //! constructed plastic predictor + struct EstimateInterpolationParams + { + //! starting point type + StartingPointType starting_point_type; + + //! specified starting point: for the constant starting point strategy, this value is set at + //! the beginning of each local integration; for the history-based starting point strategy, + //! this value is used only for the first time step + double user_set_starting_point; + + //! maximum number of estimate interpolation iterations \f$ i_{\text{EI,max}} \f$ + int max_iter; + + //! interval scanning parameter \f$ s \f$ for updating the interpolation parameter \f$\xi + //! \gets + //! \xi_{\text{E}} + s \, \left( \xi_{\text{P}} - \xi_{\text{E}} \right) \f$ (bisection: \f$ + //! s= 1/2 \f$) + double interval_scanning_param; + }; + + + //! struct containing parameters dedicated to handling the hardening variables + struct HardeningParams + { //! method to use for handling / "interpolating" the hardening variables + HardeningManagementMethod method; + + //! maximum number of iterations for the integration of the hardening variables via the + //! evolution equations + int max_iter_integration; + + //! tolerance for the integration of the hardening variables via the evolution equations + double tol_integration; + }; + + + //! struct containing parameters for the re-estimation procedures + struct ReestimationParams + { + //! maximum number of adaptive re-estimations allowed + int max_num_reestimations; + + //! interval scanning parameter \f$ s \f$ for determining the intermediate parameter \f$ + //! \xi_{\mathrm{I}} \gets + //! \xi_{\mathrm{E}} + s \, \left( \xi - \xi_{\mathrm{E}}\right) \f$ (bisection: \f$ s = 1/2 + //! \f$) + double interval_scanning_param; + }; + + //! struct: parameters used for the AEI routines (main parameter set for the scheme) + struct AEIParams + { + //! is the Adaptive Estimate Interpolation used? + bool use_adaptive_estimate_interpolation; + + // components of the elastic predictor (specifically: the respective elastic deformation + // gradient) smaller than this threshold are set to 0.0 to avoid unnecessary, 'numerical' + // rotations + double elastic_predictor_zero_component_threshold; + + //! parameters for plastic predictor construction + PlasticPredictorConstructionParams plastic_predictor_construction; + + //! parameters for estimate interpolation between predictors + EstimateInterpolationParams estimate_interpolation; + + //! hardening parameters + HardeningParams hardening; + + //! re-estimation parameters + ReestimationParams reestimation; + }; + } // namespace AdaptiveEstimateInterpolation } // namespace InelasticDefgradTransvIsotropElastViscoplastUtils } // namespace Mat diff --git a/unittests/mat/4C_inelastic_defgrad_factors_test.cpp b/unittests/mat/4C_inelastic_defgrad_factors_test.cpp index 69a34af2f85..26aa9327399 100644 --- a/unittests/mat/4C_inelastic_defgrad_factors_test.cpp +++ b/unittests/mat/4C_inelastic_defgrad_factors_test.cpp @@ -8,6 +8,7 @@ #include #include "4C_global_data.hpp" +#include "4C_inelastic_defgrad_factors_test_utils.hpp" #include "4C_io_input_parameter_container.templates.hpp" #include "4C_linalg_fixedsizematrix.hpp" #include "4C_linalg_fixedsizematrix_generators.hpp" @@ -44,6 +45,9 @@ namespace { using namespace FourC; namespace ViscoplastUtils = Mat::InelasticDefgradTransvIsotropElastViscoplastUtils; + namespace AEI = + Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::AdaptiveEstimateInterpolation; + struct ReformulatedJohnsonCookParameters { @@ -71,6 +75,11 @@ namespace }; bool use_substepping = false; unsigned int max_substepping_halve_num = 0; + AEI::AEIParams adaptive_estimate_interp_params = + InelasticDefgradFactorsTestUtils::set_up_aei_params( + {.use_adaptive_estimate_interpolation = + false}); // no usage of AEI by default, must be explicitly enabled and + // configured in the subsequent tests ViscoplastUtils::LinearizationType linearization_type = ViscoplastUtils::LinearizationType::analytic; std::optional yield_cond_a = 1.0; @@ -187,8 +196,7 @@ namespace .register_plastic_strain_deriv_incr_overflow = false, .max_plastic_strain_deriv_incr = std::exp(30.0)}; material_data.add("ERROR_REGISTRATION_SETTINGS", error_registration_settings); - - + material_data.add("ADAPTIVE_ESTIMATE_INTERPOLATION", setup.adaptive_estimate_interp_params); auto material_params = std::dynamic_pointer_cast( diff --git a/unittests/mat/4C_inelastic_defgrad_factors_test_utils.hpp b/unittests/mat/4C_inelastic_defgrad_factors_test_utils.hpp new file mode 100644 index 00000000000..080deebf7e4 --- /dev/null +++ b/unittests/mat/4C_inelastic_defgrad_factors_test_utils.hpp @@ -0,0 +1,66 @@ +// This file is part of 4C multiphysics licensed under the +// GNU Lesser General Public License v3.0 or later. +// +// See the LICENSE.md file in the top-level for license information. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef FOUR_C_INELASTIC_DEFGRAD_FACTORS_TEST_UTILS_HPP +#define FOUR_C_INELASTIC_DEFGRAD_FACTORS_TEST_UTILS_HPP + +#include "4C_mat_inelastic_defgrad_factors_service.hpp" + +namespace FourC::InelasticDefgradFactorsTestUtils +{ + namespace AEI = + Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::AdaptiveEstimateInterpolation; + + /// default parameters for Adaptive Estimate Interpolation to be used in the tests + struct DefaultAEIParams + { + bool use_adaptive_estimate_interpolation = true; + double elastic_predictor_zero_component_threshold = 1.0e-13; + AEI::PlasticPredictorConstructionParams plastic_predictor_construction{ + .elastic_stretch_eigenval_type = + AEI::PrelimPlasticPredictor::ElasticStretchEigenvalType::scale_unit, + .elastic_stretch_eigenvect_type = + AEI::PrelimPlasticPredictor::ElasticStretchEigenvectType::from_elastic_predictor, + .elastic_rotation_type = + AEI::PrelimPlasticPredictor::ElasticRotationType::from_elastic_predictor, + .max_iter = 50, + .relative_understress_tol = 1.0e-6, + .interval_scanning_param = 0.5, + }; + AEI::EstimateInterpolationParams estimate_interpolation{ + .starting_point_type = AEI::StartingPointType::equiv_stress_history, + .user_set_starting_point = 0.5, + .max_iter = 50, + .interval_scanning_param = 0.5, + }; + AEI::HardeningParams hardening{ + .method = AEI::HardeningManagementMethod::integrate_via_evolution_equations, + .max_iter_integration = 50, + .tol_integration = 1.0e-8, + }; + AEI::ReestimationParams reestimation{ + .max_num_reestimations = 10, + .interval_scanning_param = 0.5, + }; + }; + + /// setup Adaptive Estimate Interpolation parameters using a config object + inline AEI::AEIParams set_up_aei_params(const DefaultAEIParams& default_params = {}) + { + return AEI::AEIParams{ + .use_adaptive_estimate_interpolation = default_params.use_adaptive_estimate_interpolation, + .elastic_predictor_zero_component_threshold = + default_params.elastic_predictor_zero_component_threshold, + .plastic_predictor_construction = default_params.plastic_predictor_construction, + .estimate_interpolation = default_params.estimate_interpolation, + .hardening = default_params.hardening, + .reestimation = default_params.reestimation, + }; + } + +} // namespace FourC::InelasticDefgradFactorsTestUtils +#endif From ede2f48315737ea73b712e60fa8229b293527d58 Mon Sep 17 00:00:00 2001 From: Ana Dragos-Corneliu Date: Mon, 10 Aug 2026 18:51:14 +0200 Subject: [PATCH 3/7] Add utils for AEI --- ...linalg_utils_quaternion_interpolation.cpp} | 4 +- ...linalg_utils_quaternion_interpolation.hpp} | 6 +- .../4C_linalg_utils_scalar_interpolation.cpp | 8 +- .../4C_linalg_utils_scalar_interpolation.hpp | 11 +- ...lg_utils_quaternion_interpolation_test.cpp | 5 +- ..._mat_inelastic_defgrad_factors_service.cpp | 468 ++++++++++++++++++ ..._mat_inelastic_defgrad_factors_service.hpp | 175 +++++++ ...inelastic_defgrad_factors_service_test.cpp | 366 ++++++++++++++ 8 files changed, 1028 insertions(+), 15 deletions(-) rename src/core/linalg/src/dense/{4C_linalg_utlis_quaternion_interpolation.cpp => 4C_linalg_utils_quaternion_interpolation.cpp} (99%) rename src/core/linalg/src/dense/{4C_linalg_utlis_quaternion_interpolation.hpp => 4C_linalg_utils_quaternion_interpolation.hpp} (98%) diff --git a/src/core/linalg/src/dense/4C_linalg_utlis_quaternion_interpolation.cpp b/src/core/linalg/src/dense/4C_linalg_utils_quaternion_interpolation.cpp similarity index 99% rename from src/core/linalg/src/dense/4C_linalg_utlis_quaternion_interpolation.cpp rename to src/core/linalg/src/dense/4C_linalg_utils_quaternion_interpolation.cpp index 6028656ae23..d7f0f056094 100644 --- a/src/core/linalg/src/dense/4C_linalg_utlis_quaternion_interpolation.cpp +++ b/src/core/linalg/src/dense/4C_linalg_utils_quaternion_interpolation.cpp @@ -7,7 +7,7 @@ #include "4C_config.hpp" -#include "4C_linalg_utlis_quaternion_interpolation.hpp" +#include "4C_linalg_utils_quaternion_interpolation.hpp" #include "4C_linalg_fixedsizematrix.hpp" #include "4C_linalg_utils_scalar_interpolation.hpp" @@ -563,4 +563,4 @@ void Core::LinAlg::GeneralizedSphericalLinearInterpolator::right_orthon template class Core::LinAlg::GeneralizedSphericalLinearInterpolator<1>; template class Core::LinAlg::GeneralizedSphericalLinearInterpolator<2>; template class Core::LinAlg::GeneralizedSphericalLinearInterpolator<3>; -FOUR_C_NAMESPACE_CLOSE \ No newline at end of file +FOUR_C_NAMESPACE_CLOSE diff --git a/src/core/linalg/src/dense/4C_linalg_utlis_quaternion_interpolation.hpp b/src/core/linalg/src/dense/4C_linalg_utils_quaternion_interpolation.hpp similarity index 98% rename from src/core/linalg/src/dense/4C_linalg_utlis_quaternion_interpolation.hpp rename to src/core/linalg/src/dense/4C_linalg_utils_quaternion_interpolation.hpp index d58bd0eb5c3..1acf8258ae0 100644 --- a/src/core/linalg/src/dense/4C_linalg_utlis_quaternion_interpolation.hpp +++ b/src/core/linalg/src/dense/4C_linalg_utils_quaternion_interpolation.hpp @@ -5,8 +5,8 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later -#ifndef FOUR_C_LINALG_UTLIS_QUATERNION_INTERPOLATION_HPP -#define FOUR_C_LINALG_UTLIS_QUATERNION_INTERPOLATION_HPP +#ifndef FOUR_C_LINALG_UTILS_QUATERNION_INTERPOLATION_HPP +#define FOUR_C_LINALG_UTILS_QUATERNION_INTERPOLATION_HPP #include "4C_config.hpp" @@ -220,4 +220,4 @@ namespace Core FOUR_C_NAMESPACE_CLOSE -#endif \ No newline at end of file +#endif diff --git a/src/core/linalg/src/dense/4C_linalg_utils_scalar_interpolation.cpp b/src/core/linalg/src/dense/4C_linalg_utils_scalar_interpolation.cpp index 2354a55c624..7e8b1ec2d56 100644 --- a/src/core/linalg/src/dense/4C_linalg_utils_scalar_interpolation.cpp +++ b/src/core/linalg/src/dense/4C_linalg_utils_scalar_interpolation.cpp @@ -304,7 +304,7 @@ template Core::LinAlg::ScalarInterpolator::logarithmic_weighted_average(const std::vector>& scalar_data, - const std::vector& weights) + const std::vector& weights) const { const size_t field_size = scalar_data[0].size(); std::vector log_sum(field_size, 0.0); @@ -336,7 +336,7 @@ std::vector Core::LinAlg::ScalarInterpolator::moving_least_square( const std::vector>& scalar_data, const std::vector>& ref_locs, - const Core::LinAlg::Matrix& interp_loc, const std::vector& weights) + const Core::LinAlg::Matrix& interp_loc, const std::vector& weights) const { const size_t field_size = scalar_data[0].size(); std::vector interp_scalar(field_size, 0.0); @@ -409,7 +409,7 @@ std::vector Core::LinAlg::ScalarInterpolator::logarithmic_moving_least_squares(const std::vector>& scalar_data, const std::vector>& ref_locs, - const Core::LinAlg::Matrix& interp_loc, const std::vector& weights) + const Core::LinAlg::Matrix& interp_loc, const std::vector& weights) const { std::vector interp_scalar(scalar_data[0].size(), 0.0); @@ -450,7 +450,7 @@ std::vector Core::LinAlg::ScalarInterpolator::get_interpolated_scalar( const std::vector>& scalar_data, const std::vector>& ref_locs, - const Core::LinAlg::Matrix& interp_loc) + const Core::LinAlg::Matrix& interp_loc) const { // Check for size consistency if (scalar_data.empty()) FOUR_C_THROW("Scalar data vector is empty."); diff --git a/src/core/linalg/src/dense/4C_linalg_utils_scalar_interpolation.hpp b/src/core/linalg/src/dense/4C_linalg_utils_scalar_interpolation.hpp index a02a23b3a0a..605024809de 100644 --- a/src/core/linalg/src/dense/4C_linalg_utils_scalar_interpolation.hpp +++ b/src/core/linalg/src/dense/4C_linalg_utils_scalar_interpolation.hpp @@ -159,7 +159,7 @@ namespace Core::LinAlg */ std::vector get_interpolated_scalar(const std::vector>& scalar_data, const std::vector>& ref_locs, - const Core::LinAlg::Matrix& interp_loc); + const Core::LinAlg::Matrix& interp_loc) const; private: /** @@ -179,7 +179,8 @@ namespace Core::LinAlg */ std::vector moving_least_square(const std::vector>& scalar_data, const std::vector>& ref_locs, - const Core::LinAlg::Matrix& interp_loc, const std::vector& weights); + const Core::LinAlg::Matrix& interp_loc, + const std::vector& weights) const; /** * @brief Computes the logarithmic interpolation of scalar data using the provided weights. @@ -193,7 +194,8 @@ namespace Core::LinAlg * @return A vector of doubles representing the logarithmic interpolation results. */ std::vector logarithmic_weighted_average( - const std::vector>& scalar_data, const std::vector& weights); + const std::vector>& scalar_data, + const std::vector& weights) const; /** * @brief Computes the log moving least squares interpolation for scalar data. @@ -213,7 +215,8 @@ namespace Core::LinAlg std::vector logarithmic_moving_least_squares( const std::vector>& scalar_data, const std::vector>& ref_locs, - const Core::LinAlg::Matrix& interp_loc, const std::vector& weights); + const Core::LinAlg::Matrix& interp_loc, + const std::vector& weights) const; const ScalarInterpolationType scalar_interp_type_; const ScalarInterpolationWeightingFunction weight_func_; diff --git a/src/core/linalg/tests/4C_linalg_utils_quaternion_interpolation_test.cpp b/src/core/linalg/tests/4C_linalg_utils_quaternion_interpolation_test.cpp index 3ae9086523a..e5ad76d440c 100644 --- a/src/core/linalg/tests/4C_linalg_utils_quaternion_interpolation_test.cpp +++ b/src/core/linalg/tests/4C_linalg_utils_quaternion_interpolation_test.cpp @@ -7,9 +7,10 @@ #include +#include "4C_linalg_utils_quaternion_interpolation.hpp" + #include "4C_linalg_fixedsizematrix.hpp" #include "4C_linalg_utils_scalar_interpolation.hpp" -#include "4C_linalg_utlis_quaternion_interpolation.hpp" #include "4C_unittest_utils_assertions_test.hpp" #include "4C_utils_exceptions.hpp" @@ -391,4 +392,4 @@ TEST(QuaternionInterpolationTest, SlerpWeighted_AnalyticalCheck) ASSERT_NEAR(result(3, 0), w_expected, 1e-12); // w } -FOUR_C_NAMESPACE_CLOSE \ No newline at end of file +FOUR_C_NAMESPACE_CLOSE diff --git a/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp b/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp index 4dd0c27031a..05bd48170c7 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp @@ -9,20 +9,132 @@ #include "4C_mat_inelastic_defgrad_factors_service.hpp" +#include "4C_fem_general_largerotations.hpp" #include "4C_linalg_fixedsizematrix.hpp" #include "4C_linalg_fixedsizematrix_tensor_products.hpp" #include "4C_linalg_fixedsizematrix_voigt_notation.hpp" #include "4C_linalg_four_tensor_generators.hpp" +#include "4C_linalg_utils_quaternion_interpolation.hpp" +#include "4C_linalg_utils_scalar_interpolation.hpp" +#include "4C_linalg_utils_tensor_interpolation.hpp" #include "4C_utils_enum.hpp" #include "4C_utils_exceptions.hpp" #include #include +#include FOUR_C_NAMESPACE_OPEN using namespace Mat::InelasticDefgradTransvIsotropElastViscoplastUtils; +namespace AEI = + Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::AdaptiveEstimateInterpolation; + + +namespace +{ + + // elastic and plastic predictor locations + constexpr double ELASTIC_PREDICTOR_LOCATION = 0.0; + constexpr double PLASTIC_PREDICTOR_LOCATION = 1.0; + const std::vector> ELASTIC_AND_PLASTIC_PREDICTOR_LOCATIONS = []() + { + Core::LinAlg::Matrix<1, 1> elast(Core::LinAlg::Initialization::zero); + Core::LinAlg::Matrix<1, 1> plast(Core::LinAlg::Initialization::zero); + elast(0, 0) = ELASTIC_PREDICTOR_LOCATION; + plast(0, 0) = PLASTIC_PREDICTOR_LOCATION; + return std::vector>{elast, plast}; + }(); + + + const Core::LinAlg::Matrix<4, 1> UNIT_QUATERNION = []() + { + Core::LinAlg::Matrix<4, 1> uq{Core::LinAlg::Initialization::zero}; + uq(3) = 1.0; + + return uq; + }(); + + // creates the eigenvalue interpolator used for the Adaptive Estimate Interpolation + Core::LinAlg::ScalarInterpolator<1> create_eigenvalue_interpolator() + { + Core::LinAlg::ScalarInterpolationType interp_type = + Core::LinAlg::ScalarInterpolationType::logarithmic_weighted_average; + Core::LinAlg::ScalarInterpolationWeightingFunction weight_func = + Core::LinAlg::ScalarInterpolationWeightingFunction::inverse_distance; + Core::LinAlg::ScalarInterpolationParams interp_params; + + return {interp_type, weight_func, interp_params}; + } + + + // Adaptive Estimate Interpolation: compute the elastic deformation gradient, using the + // interpolated eigenvalues and rotation contributions (quaternions) with respect to the elastic + // deformation gradient within the elastic predictor + Core::LinAlg::Matrix<3, 3> compute_elast_defgrad_wrt_elast_predictor( + const std::vector& interp_eigenval, + const Core::LinAlg::Matrix<3, 3>& eigenvect_rot_elast_pred, + const Core::LinAlg::Matrix<4, 1>& interp_rel_eigenvect_rot_quat, + const Core::LinAlg::Matrix<3, 3>& rot_elast_pred, + const Core::LinAlg::Matrix<4, 1>& interp_rel_rot_quat) + { + Core::LinAlg::Matrix<3, 3> out{Core::LinAlg::Initialization::zero}; + + // construct diagonal eigenvalue matrix + Core::LinAlg::Matrix<3, 3> eigenval_matrix{Core::LinAlg::Initialization::zero}; + for (unsigned int i = 0; i < 3; ++i) + { + eigenval_matrix(i, i) = interp_eigenval[i]; + } + + // construct eigenvector matrix + Core::LinAlg::Matrix<3, 3> rel_interp_eigenvect_matrix{Core::LinAlg::Initialization::zero}; + Core::LargeRotations::quaterniontotriad( + interp_rel_eigenvect_rot_quat, rel_interp_eigenvect_matrix); + Core::LinAlg::Matrix<3, 3> interp_eigenvect_matrix{Core::LinAlg::Initialization::zero}; + interp_eigenvect_matrix.multiply_nn( + 1.0, eigenvect_rot_elast_pred, rel_interp_eigenvect_matrix, 0.0); + + + // construct rotation matrix + Core::LinAlg::Matrix<3, 3> rel_interp_rot_matrix{Core::LinAlg::Initialization::zero}; + Core::LargeRotations::quaterniontotriad(interp_rel_rot_quat, rel_interp_rot_matrix); + Core::LinAlg::Matrix<3, 3> interp_rot_matrix{Core::LinAlg::Initialization::zero}; + interp_rot_matrix.multiply_nn(1.0, rot_elast_pred, rel_interp_rot_matrix, 0.0); + + + // multiply contributions + Core::LinAlg::Matrix<3, 3> LQ{Core::LinAlg::Initialization::zero}; + LQ.multiply(1.0, eigenval_matrix, interp_eigenvect_matrix, 0.0); + Core::LinAlg::Matrix<3, 3> QTLQ{Core::LinAlg::Initialization::zero}; + QTLQ.multiply_tn(1.0, interp_eigenvect_matrix, LQ, 0.0); + out.multiply(1.0, interp_rot_matrix, QTLQ, 0.0); + + return out; + } + + + // precondition matrix: absolute values smaller than a set tolerance are set to 0.0 + Core::LinAlg::Matrix<3, 3> precondition_matrix( + const Core::LinAlg::Matrix<3, 3>& matrix, const double tol) + { + Core::LinAlg::Matrix<3, 3> out_matrix{matrix}; + + for (unsigned i = 0; i < 3; ++i) + { + for (unsigned j = 0; j < 3; ++j) + { + if (std::abs(matrix(i, j)) < tol) + { + out_matrix(i, j) = 0.0; + } + } + } + return out_matrix; + } + +} // namespace void Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::ThermoMechanicalCouplingCache::resize( @@ -611,6 +723,362 @@ Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput:: step = cfg.step; } +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +AEI::PredictorInterpolator::PredictorInterpolator() + : ref_predictor_locs_(ELASTIC_AND_PLASTIC_PREDICTOR_LOCATIONS), + eigenval_interpolator_(create_eigenvalue_interpolator()) +{ + // auxiliaries + Core::LinAlg::Matrix<3, 3> unit_3x3{Core::LinAlg::Initialization::zero}; + for (unsigned int i = 0; i < 3; ++i) + { + unit_3x3(i, i) = 1.0; + } + std::vector> vector_of_ones(2, {1.0, 1.0, 1.0}); + + // initialize variables for a single Gauss point + eigenval_elast_pred_.resize(1, unit_3x3); + eigenval_plast_pred_.resize(1, unit_3x3); + scalar_interp_eigenval_.resize(1, vector_of_ones); + eigenvect_rot_elast_pred_.resize(1, unit_3x3); + rel_eigenvect_rot_plast_pred_.resize(1, UNIT_QUATERNION); + rot_elast_pred_.resize(1, unit_3x3); + rel_rot_plast_pred_.resize(1, UNIT_QUATERNION); +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::PredictorInterpolator::resize(const unsigned int numgp) +{ + FOUR_C_ASSERT(!resize_called_, + "You already called resize for the predictor interpolator! The number of current GP is {} " + "and " + "you attempt to set it to {}", + eigenval_elast_pred_.size(), numgp); + + eigenval_elast_pred_.resize(numgp, eigenval_elast_pred_[0]); + eigenval_plast_pred_.resize(numgp, eigenval_plast_pred_[0]); + scalar_interp_eigenval_.resize(numgp, scalar_interp_eigenval_[0]); + eigenvect_rot_elast_pred_.resize(numgp, eigenvect_rot_elast_pred_[0]); + rel_eigenvect_rot_plast_pred_.resize(numgp, rel_eigenvect_rot_plast_pred_[0]); + rot_elast_pred_.resize(numgp, rot_elast_pred_[0]); + rel_rot_plast_pred_.resize(numgp, rel_rot_plast_pred_[0]); + + resize_called_ = true; +} + + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::PredictorInterpolator::pack(Core::Communication::PackBuffer& data) const +{ + Core::Communication::add_to_pack(data, eigenval_elast_pred_); + Core::Communication::add_to_pack(data, eigenval_plast_pred_); + Core::Communication::add_to_pack(data, scalar_interp_eigenval_); + Core::Communication::add_to_pack(data, eigenvect_rot_elast_pred_); + Core::Communication::add_to_pack(data, rel_eigenvect_rot_plast_pred_); + Core::Communication::add_to_pack(data, rot_elast_pred_); + Core::Communication::add_to_pack(data, rel_rot_plast_pred_); + Core::Communication::add_to_pack(data, resize_called_); +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::PredictorInterpolator::unpack(Core::Communication::UnpackBuffer& buffer) +{ + Core::Communication::extract_from_pack(buffer, eigenval_elast_pred_); + Core::Communication::extract_from_pack(buffer, eigenval_plast_pred_); + Core::Communication::extract_from_pack(buffer, scalar_interp_eigenval_); + Core::Communication::extract_from_pack(buffer, eigenvect_rot_elast_pred_); + Core::Communication::extract_from_pack(buffer, rel_eigenvect_rot_plast_pred_); + Core::Communication::extract_from_pack(buffer, rot_elast_pred_); + Core::Communication::extract_from_pack(buffer, rel_rot_plast_pred_); + Core::Communication::extract_from_pack(buffer, resize_called_); +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::PredictorInterpolator::construct_prelim_plastic_pred(const unsigned int gp, + const Core::LinAlg::Matrix<3, 3>& elastic_defgrad_elastic_pred, + const double elastic_predictor_zero_component_threshold, + const PlasticPredictorConstructionParams& plastic_predictor_construction_params) +{ + // consistency checks + FOUR_C_ASSERT(gp < eigenval_elast_pred_.size(), + "Inconsistent Gauss point index {}, with set Gauss point size {}", gp, + eigenval_elast_pred_.size()); + + // get (preconditioned) elastic deformation gradient to be considered as elastic predictor + Core::LinAlg::Matrix<3, 3> precond_elastic_defgrad_elastic_pred{elastic_defgrad_elastic_pred}; + precond_elastic_defgrad_elastic_pred = + precondition_matrix(elastic_defgrad_elastic_pred, elastic_predictor_zero_component_threshold); + + // perform polar-spectral decomposition of elastic defgrad within elastic predictor + Core::LinAlg::Matrix<3, 3> material_stretch_elast_pred{Core::LinAlg::Initialization::zero}; + Core::LinAlg::Matrix<3, 3> eigenval_elast_pred_temp{ + Core::LinAlg::Initialization::zero}; // needed here for the function call, but we will grab + // the ordered eigenvalues from the spectral pairs + std::array>, 3> spectral_pairs_elast_pred; + Core::LinAlg::matrix_3x3_polar_decomposition(precond_elastic_defgrad_elastic_pred, + rot_elast_pred_[gp], material_stretch_elast_pred, eigenval_elast_pred_temp, + spectral_pairs_elast_pred); + for (int i = 0; i < 3; ++i) + { + FOUR_C_ASSERT_ALWAYS(spectral_pairs_elast_pred[i].first >= 1.0e-8, + "The eigenvalue {} of the elastic deformation gradient within the elastic predictor at GP " + "{} is {}, " + "such that its logarithm can not be computed!", + i, gp, spectral_pairs_elast_pred[i].first); + eigenval_elast_pred_[gp](i, i) = spectral_pairs_elast_pred[i].first; + for (int j = 0; j < 3; ++j) + { + eigenvect_rot_elast_pred_[gp](i, j) = spectral_pairs_elast_pred[i].second(j); + } + } + + // --> construct a preliminary plastic predictor based on the parameter specifications + + // elastic stretch eigenvectors + switch (plastic_predictor_construction_params.elastic_stretch_eigenvect_type) + { + case AEI::PrelimPlasticPredictor::ElasticStretchEigenvectType::from_elastic_predictor: + { + rel_eigenvect_rot_plast_pred_[gp].update(1.0, UNIT_QUATERNION, 0.0); + break; + } + default: + { + // other eigenvector rotation types not yet enabled; in case of multiple eigenvalues, a + // canonicalization approach for the related eigenvectors must be first implemented for the + // spectral decomposition to avoid artificial rotation contributions + FOUR_C_THROW( + "Elastic stretch eigenvector type {} not yet enabled for the preliminary plastic " + "predictor", + EnumTools::enum_name( + plastic_predictor_construction_params.elastic_stretch_eigenvect_type)); + } + } + + // elastic rotation + switch (plastic_predictor_construction_params.elastic_rotation_type) + { + case AEI::PrelimPlasticPredictor::ElasticRotationType::from_elastic_predictor: + { + rel_rot_plast_pred_[gp].update(1.0, UNIT_QUATERNION, 0.0); + break; + } + default: + { + // same as in the case of the elastic stretch eigenvectors + FOUR_C_THROW("Elastic rotation type {} not yet enabled for the plastic predictor!", + EnumTools::enum_name(plastic_predictor_construction_params.elastic_rotation_type)); + } + } + + // elastic stretch eigenvalues + const double detF = precond_elastic_defgrad_elastic_pred.determinant(); + FOUR_C_ASSERT_ALWAYS(detF > 1.0e-8, + "The determinant of the deformation gradient is {}, which is physically and numerically " + "invalid!", + detF); + + switch (plastic_predictor_construction_params.elastic_stretch_eigenval_type) + { + case AEI::PrelimPlasticPredictor::ElasticStretchEigenvalType::scale_unit: + { + const double scaled_detF = std::pow(detF, 1.0 / 3.0); + for (unsigned int i = 0; i < 3; ++i) + { + eigenval_plast_pred_[gp](i, i) = scaled_detF; + } + + break; + } + default: + { + FOUR_C_THROW("Elastic stretch eigenvalue type {} not yet enabled for the plastic predictor", + EnumTools::enum_name( + plastic_predictor_construction_params.elastic_stretch_eigenval_type)); + } + } + + // store eigenvalues such that they can be directly used within the scalar interpolator + scalar_interp_eigenval_[gp] = {{eigenval_elast_pred_[gp](0, 0), eigenval_elast_pred_[gp](1, 1), + eigenval_elast_pred_[gp](2, 2)}, + {eigenval_plast_pred_[gp](0, 0), eigenval_plast_pred_[gp](1, 1), + eigenval_plast_pred_[gp](2, 2)}}; +} + + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::PredictorInterpolator::interpolate_elastic_defgrad_contributions(const unsigned int gp, + const double interp_loc, Core::LinAlg::Matrix<4, 1>& interp_rel_rot_quat, + std::vector& interp_eigenval, + Core::LinAlg::Matrix<4, 1>& interp_rel_eigenvect_rot_quat) const +{ + // consistency checks + FOUR_C_ASSERT( + ELASTIC_PREDICTOR_LOCATION <= interp_loc && interp_loc <= PLASTIC_PREDICTOR_LOCATION, + "Interpolation is constrained to the interval between the elastic and the plastic " + "predictors! The current plastic predictor location " + "{} is out of these bounds: [{}, {}]", + interp_loc, ELASTIC_PREDICTOR_LOCATION, PLASTIC_PREDICTOR_LOCATION); + FOUR_C_ASSERT(gp < eigenval_elast_pred_.size(), + "Inconsistent Gauss point index {}, with set Gauss point size {}", gp, + eigenval_elast_pred_.size()); + + // auxiliaries + Core::LinAlg::Matrix<1, 1> matrix_interp_loc{Core::LinAlg::Initialization::zero}; + matrix_interp_loc(0) = interp_loc; + + // interpolate eigenvalues + interp_eigenval = eigenval_interpolator_.get_interpolated_scalar( + scalar_interp_eigenval_[gp], ref_predictor_locs_, matrix_interp_loc); + + // interpolate quaternions + interp_rel_eigenvect_rot_quat = Core::LinAlg::spherical_linear_interpolation( + UNIT_QUATERNION, rel_eigenvect_rot_plast_pred_[gp], interp_loc); + interp_rel_rot_quat = Core::LinAlg::spherical_linear_interpolation( + UNIT_QUATERNION, rel_rot_plast_pred_[gp], interp_loc); +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +Core::LinAlg::Matrix<3, 3> AEI::PredictorInterpolator::interpolate_elastic_defgrad( + const unsigned int gp, const double interp_loc) const +{ + // consistency checks + FOUR_C_ASSERT( + ELASTIC_PREDICTOR_LOCATION <= interp_loc && interp_loc <= PLASTIC_PREDICTOR_LOCATION, + "Interpolation is constrained to the interval between the elastic and the plastic " + "predictors! The current plastic predictor location " + "{} is out of these bounds: [{}, {}]", + interp_loc, ELASTIC_PREDICTOR_LOCATION, PLASTIC_PREDICTOR_LOCATION); + FOUR_C_ASSERT(gp < eigenval_elast_pred_.size(), + "Inconsistent Gauss point index {}, with set Gauss point size {}", gp, + eigenval_elast_pred_.size()); + + // interpolate contributions + Core::LinAlg::Matrix<4, 1> interp_rel_rot_quat{Core::LinAlg::Initialization::zero}; + std::vector interp_eigenval; + Core::LinAlg::Matrix<4, 1> interp_rel_eigenvect_rot_quat{Core::LinAlg::Initialization::zero}; + interpolate_elastic_defgrad_contributions( + gp, interp_loc, interp_rel_rot_quat, interp_eigenval, interp_rel_eigenvect_rot_quat); + + return compute_elast_defgrad_wrt_elast_predictor(interp_eigenval, eigenvect_rot_elast_pred_[gp], + interp_rel_eigenvect_rot_quat, rot_elast_pred_[gp], interp_rel_rot_quat); +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::PredictorInterpolator::set_plastic_predictor_after_construction_algo( + const unsigned int gp, const double plastic_pred_loc) +{ + // consistency checks + FOUR_C_ASSERT(ELASTIC_PREDICTOR_LOCATION <= plastic_pred_loc && + plastic_pred_loc <= PLASTIC_PREDICTOR_LOCATION, + "Interpolation constrained to the interval between the elastic and the plastic " + "predictors! The current plastic predictor location " + "{} is out of these bounds: [{}, {}]", + plastic_pred_loc, ELASTIC_PREDICTOR_LOCATION, PLASTIC_PREDICTOR_LOCATION); + FOUR_C_ASSERT(gp < eigenval_elast_pred_.size(), + "Inconsistent Gauss point index {}, with set Gauss point size {}", gp, + eigenval_elast_pred_.size()); + + // set all quantities relevant for the plastic predictor + std::vector interp_eigenval; + interpolate_elastic_defgrad_contributions(gp, plastic_pred_loc, rel_rot_plast_pred_[gp], + interp_eigenval, rel_eigenvect_rot_plast_pred_[gp]); + for (unsigned int i = 0; i < 3; ++i) + { + eigenval_plast_pred_[gp](i, i) = interp_eigenval[i]; + } + scalar_interp_eigenval_[gp] = {{eigenval_elast_pred_[gp](0, 0), eigenval_elast_pred_[gp](1, 1), + eigenval_elast_pred_[gp](2, 2)}, + {eigenval_plast_pred_[gp](0, 0), eigenval_plast_pred_[gp](1, 1), + eigenval_plast_pred_[gp](2, 2)}}; +} + +AEI::InterpolationPointContainer::InterpolationPointContainer( + const EstimateInterpolationParams& estimate_interpolation_params) +{ + lower_interp_bounds.resize(1, ELASTIC_PREDICTOR_LOCATION); + upper_interp_bounds.resize(1, PLASTIC_PREDICTOR_LOCATION); + switch (estimate_interpolation_params.starting_point_type) + { + case AEI::StartingPointType::constant: + { + FOUR_C_ASSERT(estimate_interpolation_params.user_set_starting_point.has_value(), + "The user-set starting point is not specified!"); + starting_points.resize(1, estimate_interpolation_params.user_set_starting_point.value()); + break; + } + default: + { + starting_points.resize(1, estimate_interpolation_params.interval_scanning_param); + break; + } + } + current_interp_points.resize(1, starting_points[0]); +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::InterpolationPointContainer::reset_bounds_and_current_interp_point(const unsigned int gp) +{ + // consistency checks + FOUR_C_ASSERT(gp < current_interp_points.size(), + "Inconsistent Gauss point index {}, with set Gauss point size {}", gp, + current_interp_points.size()); + + current_interp_points[gp] = starting_points[gp]; + lower_interp_bounds[gp] = ELASTIC_PREDICTOR_LOCATION; + upper_interp_bounds[gp] = PLASTIC_PREDICTOR_LOCATION; +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::InterpolationPointContainer::resize(const unsigned int numgp) +{ + FOUR_C_ASSERT(!resize_called, + "You already called resize for the interpolation point container! The number of " + "current GP is " + "{} and " + "you attempt to set it to {}", + current_interp_points.size(), numgp); + + current_interp_points.resize(numgp, current_interp_points[0]); + lower_interp_bounds.resize(numgp, lower_interp_bounds[0]); + upper_interp_bounds.resize(numgp, upper_interp_bounds[0]); + starting_points.resize(numgp, starting_points[0]); + + resize_called = true; +} + + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::InterpolationPointContainer::pack(Core::Communication::PackBuffer& data) const +{ + Core::Communication::add_to_pack(data, current_interp_points); + Core::Communication::add_to_pack(data, lower_interp_bounds); + Core::Communication::add_to_pack(data, upper_interp_bounds); + Core::Communication::add_to_pack(data, starting_points); + Core::Communication::add_to_pack(data, resize_called); +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::InterpolationPointContainer::unpack(Core::Communication::UnpackBuffer& buffer) +{ + Core::Communication::extract_from_pack(buffer, current_interp_points); + Core::Communication::extract_from_pack(buffer, lower_interp_bounds); + Core::Communication::extract_from_pack(buffer, upper_interp_bounds); + Core::Communication::extract_from_pack(buffer, starting_points); + Core::Communication::extract_from_pack(buffer, resize_called); +} FOUR_C_NAMESPACE_CLOSE diff --git a/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp b/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp index 5c37f5b364a..8e47a38dac4 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp @@ -12,6 +12,7 @@ #include "4C_comm_utils.hpp" #include "4C_linalg_fixedsizematrix.hpp" +#include "4C_linalg_utils_scalar_interpolation.hpp" #include "4C_mat_multiplicative_split_defgrad_elasthyper_service.hpp" #include "4C_utils_exceptions.hpp" @@ -1240,6 +1241,180 @@ namespace Mat //! re-estimation parameters ReestimationParams reestimation; }; + + //! Interpolator of elastic deformation gradients between the elastic and the plastic + //! predictors. This class stores the values of the involved quantities at + //! all Gauss points. + class PredictorInterpolator + { + public: + //! constructor + PredictorInterpolator(); + + //! resizing based on a given number of Gauss points + void resize(const unsigned int numgp); + + //! pack method + void pack(Core::Communication::PackBuffer& data) const; + + //! unpack method + void unpack(Core::Communication::UnpackBuffer& buffer); + + /*! + * @brief Constructs a preliminary plastic predictor given the elastic predictor and the + * specified AEI settings. + * + * + * @param[in] gp Gauss point index + * @param[in] elastic_defgrad_elastic_pred elastic deformation gradient within the elastic + * predictor + * @param[in] elastic_predictor_zero_component_threshold threshold for setting components of + * the elastic deformation gradient within the elastic predictor to 0.0 (in order to avoid + * numerical rotations) + * @param[in] plastic_predictor_construction_params parameters for plastic predictor + * construction + */ + void construct_prelim_plastic_pred(const unsigned int gp, + const Core::LinAlg::Matrix<3, 3>& elastic_defgrad_elastic_pred, + const double elastic_predictor_zero_component_threshold, + const PlasticPredictorConstructionParams& plastic_predictor_construction_params); + + /*! + * @brief Interpolates an elastic deformation gradient based on the stored predictor + * quantities. + * + * + * @param[in] gp Gauss point index + * @param[in] interp_loc location used for interpolation; either \f$ \tau \f$ (plastic + * predictor construction) or \f$ \xi \f$ (estimate interpolation) + */ + Core::LinAlg::Matrix<3, 3> interpolate_elastic_defgrad( + const unsigned int gp, const double interp_loc) const; + + /*! + * @brief After the plastic predictor construction algorithm has succeeded in finding the + * construction parameter \f$\tau \f$ associated with the plastic predictor, this function + * sets the determined plastic predictor (more specifically: all class variables + * associated with it). + * + * + * @param[in] gp Gauss point index + * @param[in] plastic_pred_loc location \f$ \tau \f$ determined in the plastic + * predictor construction + */ + void set_plastic_predictor_after_construction_algo( + const unsigned int gp, const double plastic_pred_loc); + + private: + /*! + * @brief Interpolates eigenvalues and rotational contributions based on the stored + * predictor quantities. + * + * + * @param[in] gp Gauss point index + * @param[in] interp_loc location used for interpolation; either \f$ \tau \f$ (plastic + * predictor construction) or \f$ \xi \f$ (estimate interpolation) + * @param[out] interp_rel_rot_quat interpolated relative elastic rotation quaternion + * @param[out] interp_eigenval interpolated elastic eigenvalues (stored in descending order) + * @param[out] interp_rel_eigenvect_rot_quat interpolated relative elastic eigenvector + * quaternion + */ + void interpolate_elastic_defgrad_contributions(const unsigned int gp, + const double interp_loc, Core::LinAlg::Matrix<4, 1>& interp_rel_rot_quat, + std::vector& interp_eigenval, + Core::LinAlg::Matrix<4, 1>& interp_rel_eigenvect_rot_quat) const; + + //! elastic predictor: elastic eigenvalue tensors \f$ + //! \boldsymbol{\Lambda}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{E})}} + //! \f$ of all Gauss points + std::vector> eigenval_elast_pred_; + //! plastic predictor: elastic eigenvalue tensors \f$ + //! \boldsymbol{\Lambda}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}} \f$ of all Gauss points + std::vector> eigenval_plast_pred_; + //! eigenvalue data storage to be directly used within the scalar interpolator; indexing: + //! - first dimension: Gauss point. + //! - second dimension: predictor type + //! (0 = elastic predictor, 1 = plastic predictor). + //! - third dimension: eigenvalues corresponding to the selected predictor, stored in + //! descending order. + std::vector>> scalar_interp_eigenval_; + //! interpolation locations for the elastic and plastic predictor, to be directly used + //! within the scalar interpolator; indexing: + //! - 0: elastic predictor location. + //! - 1: plastic predictor location. + const std::vector> ref_predictor_locs_; + //! elastic predictor: elastic stretch eigenvector tensors \f$ + //! \boldsymbol{Q}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{E})}} \f$ of all Gauss points + std::vector> eigenvect_rot_elast_pred_; + //! plastic predictor: relative elastic eigenvector quaternions \f$ + //! \boldsymbol{q}_{\boldsymbol{Q}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}}, \mathrm{rel}} + //! \f$ associated with \f$ + //! \boldsymbol{Q}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}, \mathrm{rel}} = + //! \boldsymbol{Q}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{E})}}^T + //! \boldsymbol{Q}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}} + //! \f$ of all Gauss points + std::vector> rel_eigenvect_rot_plast_pred_; + //! elastic predictor: elastic rotation tensors \f$ + //! \boldsymbol{R}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{E})}} \f$ of all Gauss points + std::vector> rot_elast_pred_; + //! plastic predictor: relative elastic rotation quaternions \f$ + //! \boldsymbol{r}_{\boldsymbol{R}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}, \mathrm{rel}}} + //! \f$ associated with \f$ \boldsymbol{R}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}, + //! \mathrm{rel}} = + //! \boldsymbol{R}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{E})}}^T + //! \boldsymbol{R}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}}\f$ of all Gauss points + std::vector> rel_rot_plast_pred_; + //! scalar eigenvalue interpolator + Core::LinAlg::ScalarInterpolator<1> eigenval_interpolator_; + //! tracks whether the resizing function has been called, to set the current number of Gauss + //! points exactly once! + bool resize_called_{false}; + }; + + //! Container for interpolation points / bounds used in the + //! Adaptive Estimate Interpolation. This class stores the values of the involved quantities + //! at all Gauss points. + struct InterpolationPointContainer + { + public: + /*! + * @brief Constructor + * + * @param[in] estimate_interpolation_params parameters for estimate interpolation between + * predictors + */ + explicit InterpolationPointContainer( + const EstimateInterpolationParams& estimate_interpolation_params); + + //! reset interpolation interval and set the current interpolation point to its saved + //! starting point at a given Gauss point + void reset_bounds_and_current_interp_point(const unsigned int gp); + + //! resizing based on the given number of Gauss points + void resize(const unsigned int numgp); + + //! pack method + void pack(Core::Communication::PackBuffer& data) const; + + //! unpack method + void unpack(Core::Communication::UnpackBuffer& buffer); + + //! current interpolation points \f$ \xi \f$ of all Gauss points + std::vector current_interp_points; + + //! lower interpolation bounds \f$ \xi_{\text{E}} \f$ of all Gauss points + std::vector lower_interp_bounds; + + //! upper interpolation bounds \f$ \xi_{\text{P}} \f$ of all Gauss points + std::vector upper_interp_bounds; + + //! starting points for interpolation \f$ \hat{\xi} \f$ of all Gauss points + std::vector starting_points; + + //! tracks whether the resizing function has been called, to set the current number of + //! Gauss points exactly once! + bool resize_called{false}; + }; } // namespace AdaptiveEstimateInterpolation } // namespace InelasticDefgradTransvIsotropElastViscoplastUtils diff --git a/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp b/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp index ccbcc0d5a2f..9550e619b06 100644 --- a/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp +++ b/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp @@ -7,17 +7,25 @@ #include +#include "4C_fem_general_largerotations.hpp" +#include "4C_inelastic_defgrad_factors_test_utils.hpp" #include "4C_linalg_fixedsizematrix.hpp" #include "4C_mat_inelastic_defgrad_factors_service.hpp" #include "4C_unittest_utils_assertions_test.hpp" #include "4C_utils_singleton_owner.hpp" +#include +#include +#include + namespace { using namespace FourC; namespace ViscoplastUtils = Mat::InelasticDefgradTransvIsotropElastViscoplastUtils; + namespace AEI = + Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::AdaptiveEstimateInterpolation; class InelasticDefgradFactorsServiceTest : public ::testing::Test { @@ -429,4 +437,362 @@ namespace EXPECT_FALSE(manager_res.is_local_newton_converged()); EXPECT_TRUE(manager_incr.is_local_newton_converged()); } + + /// Tests the plastic predictor construction, and the interpolation procedures associated with it + /// within the predictor interpolator used for the Adaptive Estimate Interpolation. + /// Note that the test only covers the already implemented specifications for the preliminary + /// plastic predictor, i.e., both rotations contributions are taken from the elastic predictor, + /// and therefore, only the eigenvalues are really interpolated. Further tests should be added + /// when other alternatives are implemented for the rotational contributions. + TEST_F(InelasticDefgradFactorsServiceTest, TestPredictorInterpolatorPlasticPredConstruction) + { + // construct predictor interpolator with a single Gauss point + AEI::PredictorInterpolator pred_interpolator{}; + const unsigned int gp = 0; + + // setup AEI parameters + AEI::AEIParams aei_params = InelasticDefgradFactorsTestUtils::set_up_aei_params(); + + // auxiliaries + Core::LinAlg::Matrix<3, 3> unit_3x3{Core::LinAlg::Initialization::zero}; + unit_3x3(0, 0) = unit_3x3(1, 1) = unit_3x3(2, 2) = 1.0; + + // setup dummy temperature, last plastic strain, and timestep + const double temperature = 293.15; + const double last_plastic_strain = 0.0; + const double timestep = 0.1; + + // setup previous inelastic defgrad: unit tensor + Core::LinAlg::Matrix<3, 3> last_inv_inelastic_defgrad{unit_3x3}; + + // setup deformation tensor components to be used subsequently + Core::LinAlg::Matrix<3, 3> lambda{ + Core::LinAlg::Initialization::zero}; // eigenvalue matrix \f$ \boldsymbol{Lambda} \f$ + Core::LinAlg::Matrix<3, 3> Q{ + Core::LinAlg::Initialization::zero}; // eigenvector rotation \f$ \boldsymbol{Q} \f$ + Core::LinAlg::Matrix<3, 3> R{ + Core::LinAlg::Initialization::zero}; // rotation \f$ \boldsymbol{R} \f$ + Core::LinAlg::Matrix<3, 3> ref_rotation{ + Core::LinAlg::Initialization::zero}; // reference rotation to test for: either \f$ + // \boldsymbol{Q}_{\mathrm{ref}} \f$ or \f$ + // \boldsymbol{R}_{\mathrm{ref}} \f$ + Core::LinAlg::Matrix<3, 3> defgrad{ + Core::LinAlg::Initialization::zero}; // full deformation gradient \f$ \boldsymbol{F} = + // \boldsymbol{R} \boldsymbol{Q}^T + // \boldsymbol{\Lambda} + // \boldsymbol{Q}\f$ + Core::LinAlg::Matrix<3, 3> ref_defgrad{ + Core::LinAlg::Initialization::zero}; // reference: full deformation gradient to test for: + // \f$ \boldsymbol{F}_{\text{ref}} \f$ + + auto get_rotation_matrix_from_rot_angle_around_z_axis = [](const double angle) + { + Core::LinAlg::Matrix<4, 1> rot_quat{Core::LinAlg::Initialization::zero}; + rot_quat(2) = std::sin(0.5 * angle); + rot_quat(3) = std::cos(0.5 * angle); + Core::LinAlg::Matrix<3, 3> rot_matrix{Core::LinAlg::Initialization::zero}; + Core::LargeRotations::quaterniontotriad(rot_quat, rot_matrix); + return rot_matrix; + }; + auto compute_full_defgrad = [](const Core::LinAlg::Matrix<3, 3>& R, + const Core::LinAlg::Matrix<3, 3>& Q, + const Core::LinAlg::Matrix<3, 3>& lambda) + { + Core::LinAlg::Matrix<3, 3> LQ{Core::LinAlg::Initialization::zero}; + LQ.multiply(1.0, lambda, Q, 0.0); + Core::LinAlg::Matrix<3, 3> QTLQ{Core::LinAlg::Initialization::zero}; + QTLQ.multiply_tn(1.0, Q, LQ, 0.0); + Core::LinAlg::Matrix<3, 3> defgrad{Core::LinAlg::Initialization::zero}; + defgrad.multiply(1.0, R, QTLQ, 0.0); + return defgrad; + }; + + + + // setup eigenvalues of the deformation gradient to be used within all subsequent tests, and + // already scale them for the plastic predictor + lambda.clear(); + lambda(0, 0) = 2.0; + lambda(1, 1) = 1.0; + lambda(2, 2) = 1.0; + Core::LinAlg::Matrix<3, 3> scaled_unit{unit_3x3}; + scaled_unit.scale(std::pow(lambda.determinant(), 1.0 / 3.0)); + + // --> first: test the construction and interpolation procedure for a diagonal deformation + // gradient + + // setup deformation gradient + Q = get_rotation_matrix_from_rot_angle_around_z_axis(0.0); + FOUR_C_EXPECT_NEAR(Q, unit_3x3, 1.0e-15); + R = get_rotation_matrix_from_rot_angle_around_z_axis(0.0); + FOUR_C_EXPECT_NEAR(R, unit_3x3, 1.0e-15); + defgrad = compute_full_defgrad(R, Q, lambda); + FOUR_C_EXPECT_NEAR(defgrad, lambda, 1.0e-15); + + // check the elastic predictor + ViscoplastUtils::LocalIntegrationInput local_integration_input{{.defgrad = defgrad, + .temperature = temperature, + .last_inv_inelastic_defgrad = last_inv_inelastic_defgrad, + .last_plastic_strain = last_plastic_strain, + .step = timestep}}; + FOUR_C_EXPECT_NEAR(local_integration_input.elastic_predictor_elastic_defgrad, defgrad, 1.0e-15); + + // construct preliminary plastic predictor + pred_interpolator.construct_prelim_plastic_pred(gp, + local_integration_input.elastic_predictor_elastic_defgrad, + aei_params.elastic_predictor_zero_component_threshold, + aei_params.plastic_predictor_construction); + + // verify whether both predictors are initialized consistently + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 0.0), + local_integration_input.elastic_predictor_elastic_defgrad, 1.0e-15); + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 1.0), + compute_full_defgrad(R, Q, scaled_unit), 1.0e-15); + + // now set the plastic predictor at the interpolation location 0.5 between the elastic and the + // preliminary plastic predictors + Core::LinAlg::Matrix<3, 3> lambda_plastic_pred_ref{Core::LinAlg::Initialization::zero}; + lambda_plastic_pred_ref(0, 0) = 1.5874010519681996; + lambda_plastic_pred_ref(1, 1) = 1.122462048309373; + lambda_plastic_pred_ref(2, 2) = 1.122462048309373; + pred_interpolator.set_plastic_predictor_after_construction_algo(gp, 0.5); + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 1.0), + compute_full_defgrad(R, Q, lambda_plastic_pred_ref), 1.0e-8); + + // --> repeat the procedure above with a deformation gradient additionally containing an + // eigenvector rotation of 45deg around the z-axis + + // setup deformation gradient + const double angle_Q = std::numbers::pi / 4.0; + Q = get_rotation_matrix_from_rot_angle_around_z_axis(angle_Q); + ref_rotation.clear(); + ref_rotation(0, 0) = ref_rotation(1, 1) = ref_rotation(1, 0) = 0.5 * std::numbers::sqrt2; + ref_rotation(0, 1) = -0.5 * std::numbers::sqrt2; + ref_rotation(2, 2) = 1.0; + FOUR_C_EXPECT_NEAR(Q, ref_rotation, 1.0e-15); + R = get_rotation_matrix_from_rot_angle_around_z_axis(0.0); + FOUR_C_EXPECT_NEAR(R, unit_3x3, 1.0e-15); + defgrad = compute_full_defgrad(R, Q, lambda); + ref_defgrad.clear(); + ref_defgrad(0, 0) = ref_defgrad(1, 1) = 1.5; + ref_defgrad(0, 1) = ref_defgrad(1, 0) = -0.5; + ref_defgrad(2, 2) = 1.0; + FOUR_C_EXPECT_NEAR(defgrad, ref_defgrad, 1.0e-15); + + // check elastic predictor + local_integration_input = ViscoplastUtils::LocalIntegrationInput{{.defgrad = defgrad, + .temperature = temperature, + .last_inv_inelastic_defgrad = last_inv_inelastic_defgrad, + .last_plastic_strain = last_plastic_strain, + .step = timestep}}; + FOUR_C_EXPECT_NEAR(local_integration_input.elastic_predictor_elastic_defgrad, defgrad, 1.0e-15); + + // construct preliminary plastic predictor + pred_interpolator.construct_prelim_plastic_pred(gp, + local_integration_input.elastic_predictor_elastic_defgrad, + aei_params.elastic_predictor_zero_component_threshold, + aei_params.plastic_predictor_construction); + + // verify whether both predictors are initialized consistently + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 0.0), + local_integration_input.elastic_predictor_elastic_defgrad, 1.0e-15); + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 1.0), + compute_full_defgrad(R, Q, scaled_unit), 1.0e-15); + + // now set the plastic predictor at the interpolation location 0.5 between the elastic and the + // preliminary plastic predictors + pred_interpolator.set_plastic_predictor_after_construction_algo(gp, 0.5); + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 1.0), + compute_full_defgrad(R, Q, lambda_plastic_pred_ref), 1.0e-8); + + + // --> finally, repeat the procedure above with a deformation gradient additionally containing + // an eigenvector rotation AND a rotation of 45deg around the z-axis + + // setup deformation gradient + FOUR_C_EXPECT_NEAR(Q, ref_rotation, 1.0e-15); // Q stays the same as above + R = get_rotation_matrix_from_rot_angle_around_z_axis(angle_Q); + FOUR_C_EXPECT_NEAR(R, ref_rotation, 1.0e-15); + defgrad = compute_full_defgrad(R, Q, lambda); + ref_defgrad.clear(); + ref_defgrad(0, 0) = std::numbers::sqrt2; + ref_defgrad(0, 1) = -std::numbers::sqrt2; + ref_defgrad(1, 0) = ref_defgrad(1, 1) = 0.5 * std::numbers::sqrt2; + ref_defgrad(2, 2) = 1.0; + FOUR_C_EXPECT_NEAR(defgrad, ref_defgrad, 1.0e-15); + + // check elastic predictor + local_integration_input = ViscoplastUtils::LocalIntegrationInput{{.defgrad = defgrad, + .temperature = temperature, + .last_inv_inelastic_defgrad = last_inv_inelastic_defgrad, + .last_plastic_strain = last_plastic_strain, + .step = timestep}}; + FOUR_C_EXPECT_NEAR(local_integration_input.elastic_predictor_elastic_defgrad, defgrad, 1.0e-15); + + // construct preliminary plastic predictor + pred_interpolator.construct_prelim_plastic_pred(gp, + local_integration_input.elastic_predictor_elastic_defgrad, + aei_params.elastic_predictor_zero_component_threshold, + aei_params.plastic_predictor_construction); + + // verify whether both predictors are initialized consistently + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 0.0), + local_integration_input.elastic_predictor_elastic_defgrad, 1.0e-15); + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 1.0), + compute_full_defgrad(R, Q, scaled_unit), 1.0e-15); + + // now set the plastic predictor at the interpolation location 0.5 between the elastic and the + // preliminary plastic predictors + pred_interpolator.set_plastic_predictor_after_construction_algo(gp, 0.5); + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 1.0), + compute_full_defgrad(R, Q, lambda_plastic_pred_ref), 1.0e-8); + } + + + /// Tests the preconditioning procedure for the elastic deformation gradient within the predictor + /// interpolator used for the Adaptive Estimate Interpolation, i.e., whether components smaller + /// than a set threshold are consistently set to 0 + TEST_F(InelasticDefgradFactorsServiceTest, TestPredictorInterpolatorPreconditioning) + { + // construct predictor interpolator with a single Gauss point + AEI::PredictorInterpolator pred_interpolator{}; + const unsigned int gp = 0; + + // initialize AEI parameters with and without preconditioning + AEI::AEIParams aei_params_preconditioning = InelasticDefgradFactorsTestUtils::set_up_aei_params( + {.elastic_predictor_zero_component_threshold = 1.0e-8}); + AEI::AEIParams aei_params_no_preconditioning = + InelasticDefgradFactorsTestUtils::set_up_aei_params( + {.elastic_predictor_zero_component_threshold = 0.0}); + + + // auxiliaries + Core::LinAlg::Matrix<3, 3> unit_3x3{Core::LinAlg::Initialization::zero}; + unit_3x3(0, 0) = unit_3x3(1, 1) = unit_3x3(2, 2) = 1.0; + + // setup previous inelastic defgrad, and deformation gradient + Core::LinAlg::Matrix<3, 3> last_inv_inelastic_defgrad{unit_3x3}; + Core::LinAlg::Matrix<3, 3> defgrad{Core::LinAlg::Initialization::zero}; + defgrad(0, 0) = 2.0; + defgrad(1, 1) = defgrad(2, 2) = 1.0; + defgrad(0, 1) = defgrad(1, 0) = 1.0e-9; + + // setup dummy temperature, last plastic strain, and timestep + const double temperature = 293.15; + const double last_plastic_strain = 0.0; + const double timestep = 0.1; + + // determine the elastic predictor + auto local_integration_input = ViscoplastUtils::LocalIntegrationInput{{.defgrad = defgrad, + .temperature = temperature, + .last_inv_inelastic_defgrad = last_inv_inelastic_defgrad, + .last_plastic_strain = last_plastic_strain, + .step = timestep}}; + + // construct preliminary plastic predictor and verify interpolated matrix at point 0.0 + + // for the case of no preconditioning, the exact elastic deformation gradient within the elastic + // predictor must be recovered + pred_interpolator.construct_prelim_plastic_pred(gp, + local_integration_input.elastic_predictor_elastic_defgrad, + aei_params_no_preconditioning.elastic_predictor_zero_component_threshold, + aei_params_no_preconditioning.plastic_predictor_construction); + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 0.0), + local_integration_input.elastic_predictor_elastic_defgrad, 1.0e-15); + + // for the case of preconditioning, the small off-diagonal elements must be 0 + Core::LinAlg::Matrix<3, 3> preconditioned_elastic_defgrad_elastic_predictor{ + local_integration_input.elastic_predictor_elastic_defgrad}; + preconditioned_elastic_defgrad_elastic_predictor(0, 1) = + preconditioned_elastic_defgrad_elastic_predictor(1, 0) = 0.0; + pred_interpolator.construct_prelim_plastic_pred(gp, + local_integration_input.elastic_predictor_elastic_defgrad, + aei_params_preconditioning.elastic_predictor_zero_component_threshold, + aei_params_preconditioning.plastic_predictor_construction); + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 0.0), + preconditioned_elastic_defgrad_elastic_predictor, 1.0e-15); + } + + /// Tests the resizing procedure for the predictor interpolator used for the Adaptive Estimate + /// Interpolation + TEST_F(InelasticDefgradFactorsServiceTest, TestPredictorInterpolatorResize) + { + AEI::PredictorInterpolator pred_interpolator{}; + constexpr unsigned int numgp = 3; + pred_interpolator.resize(numgp); + + AEI::AEIParams aei_params = InelasticDefgradFactorsTestUtils::set_up_aei_params(); + + // populate each GP with a different predictor + std::array, numgp> all_ref_elastic_pred{ + Core::LinAlg::Matrix<3, 3>{Core::LinAlg::Initialization::zero}, + Core::LinAlg::Matrix<3, 3>{Core::LinAlg::Initialization::zero}, + Core::LinAlg::Matrix<3, 3>{Core::LinAlg::Initialization::zero}}; + for (unsigned int gp = 0; gp < numgp; ++gp) + { + all_ref_elastic_pred[gp](0, 0) = 1.0 + 0.1 * gp; + all_ref_elastic_pred[gp](1, 1) = 1.0; + all_ref_elastic_pred[gp](2, 2) = 1.0; + + pred_interpolator.construct_prelim_plastic_pred(gp, all_ref_elastic_pred[gp], + aei_params.elastic_predictor_zero_component_threshold, + aei_params.plastic_predictor_construction); + } + + // verify that each GP retains its own state via the interpolated elastic predictor + for (unsigned int gp = 0; gp < numgp; ++gp) + { + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 0.0), + all_ref_elastic_pred[gp], 1.0e-12); + } + } + + /// Tests the initialization, the resizing and the reset procedure for the interpolation point + /// containers used within the Adaptive Estimate Interpolation + TEST_F(InelasticDefgradFactorsServiceTest, TestInterpolationPointContainer) + { + // setup Adaptive Estimate Interpolation parameters + AEI::AEIParams aei_params = InelasticDefgradFactorsTestUtils::set_up_aei_params(); + aei_params.estimate_interpolation.starting_point_type = AEI::StartingPointType::constant; + aei_params.estimate_interpolation.user_set_starting_point = 0.2; + + // construct interpolation point container with a single Gauss point + AEI::InterpolationPointContainer interp_point_container{aei_params.estimate_interpolation}; + const unsigned int gp = 0; + + // test consistent initialization + EXPECT_EQ(interp_point_container.lower_interp_bounds[gp], 0.0); + EXPECT_EQ(interp_point_container.upper_interp_bounds[gp], 1.0); + EXPECT_EQ( + interp_point_container.starting_points[gp], 0.2); // has to be the user-set starting point + EXPECT_EQ(interp_point_container.current_interp_points[gp], + interp_point_container.starting_points[gp]); + + // set some dummy values + interp_point_container.current_interp_points[gp] = 0.9; + interp_point_container.lower_interp_bounds[gp] = 0.7; + interp_point_container.upper_interp_bounds[gp] = 0.99; + const double dummy_starting_point = 0.34; + interp_point_container.starting_points[gp] = dummy_starting_point; + + + // reset and test consistency + interp_point_container.reset_bounds_and_current_interp_point(gp); + EXPECT_EQ(interp_point_container.starting_points[gp], dummy_starting_point); + EXPECT_EQ(interp_point_container.current_interp_points[gp], + interp_point_container.starting_points[gp]); + EXPECT_EQ(interp_point_container.lower_interp_bounds[gp], 0.0); + EXPECT_EQ(interp_point_container.upper_interp_bounds[gp], 1.0); + + // test resizing + interp_point_container.resize(3); + EXPECT_EQ(interp_point_container.current_interp_points[2], + interp_point_container.current_interp_points[0]); + EXPECT_EQ(interp_point_container.lower_interp_bounds[2], + interp_point_container.lower_interp_bounds[0]); + EXPECT_EQ(interp_point_container.upper_interp_bounds[2], + interp_point_container.upper_interp_bounds[0]); + EXPECT_EQ(interp_point_container.starting_points[2], interp_point_container.starting_points[0]); + } + } // namespace From 875de69b832caf87af1055a07d1ff57467c7fa6e Mon Sep 17 00:00:00 2001 From: Ana Dragos-Corneliu Date: Wed, 26 Aug 2026 15:30:41 +0200 Subject: [PATCH 4/7] Add utils for AEI: review --- ..._mat_inelastic_defgrad_factors_service.cpp | 323 +++++------------- ..._mat_inelastic_defgrad_factors_service.hpp | 165 ++++----- ...inelastic_defgrad_factors_service_test.cpp | 131 ++----- 3 files changed, 195 insertions(+), 424 deletions(-) diff --git a/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp b/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp index 05bd48170c7..b70cd6559f0 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp @@ -11,6 +11,7 @@ #include "4C_fem_general_largerotations.hpp" #include "4C_linalg_fixedsizematrix.hpp" +#include "4C_linalg_fixedsizematrix_generators.hpp" #include "4C_linalg_fixedsizematrix_tensor_products.hpp" #include "4C_linalg_fixedsizematrix_voigt_notation.hpp" #include "4C_linalg_four_tensor_generators.hpp" @@ -38,23 +39,13 @@ namespace // elastic and plastic predictor locations constexpr double ELASTIC_PREDICTOR_LOCATION = 0.0; constexpr double PLASTIC_PREDICTOR_LOCATION = 1.0; - const std::vector> ELASTIC_AND_PLASTIC_PREDICTOR_LOCATIONS = []() - { - Core::LinAlg::Matrix<1, 1> elast(Core::LinAlg::Initialization::zero); - Core::LinAlg::Matrix<1, 1> plast(Core::LinAlg::Initialization::zero); - elast(0, 0) = ELASTIC_PREDICTOR_LOCATION; - plast(0, 0) = PLASTIC_PREDICTOR_LOCATION; - return std::vector>{elast, plast}; - }(); - + const std::vector ELASTIC_AND_PLASTIC_PREDICTOR_LOCATIONS{ + Core::LinAlg::diagonal_matrix<1>(ELASTIC_PREDICTOR_LOCATION), + Core::LinAlg::diagonal_matrix<1>(PLASTIC_PREDICTOR_LOCATION), + }; - const Core::LinAlg::Matrix<4, 1> UNIT_QUATERNION = []() - { - Core::LinAlg::Matrix<4, 1> uq{Core::LinAlg::Initialization::zero}; - uq(3) = 1.0; - - return uq; - }(); + const auto UNIT_QUATERNION = + make_matrix(Core::LinAlg::Tensor({0.0, 0.0, 0.0, 1.0})); // creates the eigenvalue interpolator used for the Adaptive Estimate Interpolation Core::LinAlg::ScalarInterpolator<1> create_eigenvalue_interpolator() @@ -67,44 +58,74 @@ namespace return {interp_type, weight_func, interp_params}; } + const auto EIGENVAL_INTERPOLATOR_AEI = create_eigenvalue_interpolator(); + + // given the diagonal eigenvalue tensors of the elastic deformation gradients associated with the + // elastic and plastic predictors and an interpolation location between them, interpolate the + // eigenvalues using the defined eigenvalue interpolator + std::vector interpolate_eigenvalues( + const Core::LinAlg::Matrix<3, 3>& eigenvalues_elastic_predictor, + const Core::LinAlg::Matrix<3, 3>& eigenvalues_plastic_predictor, + const Core::LinAlg::Matrix<1, 1>& interpolation_location_1x1_matrix) + { + const std::vector> scalar_interp_eigenval = { + {eigenvalues_elastic_predictor(0, 0), eigenvalues_elastic_predictor(1, 1), + eigenvalues_elastic_predictor(2, 2)}, + {eigenvalues_plastic_predictor(0, 0), eigenvalues_plastic_predictor(1, 1), + eigenvalues_plastic_predictor(2, 2)}}; + + return EIGENVAL_INTERPOLATOR_AEI.get_interpolated_scalar(scalar_interp_eigenval, + ELASTIC_AND_PLASTIC_PREDICTOR_LOCATIONS, interpolation_location_1x1_matrix); + } // Adaptive Estimate Interpolation: compute the elastic deformation gradient, using the - // interpolated eigenvalues and rotation contributions (quaternions) with respect to the elastic - // deformation gradient within the elastic predictor - Core::LinAlg::Matrix<3, 3> compute_elast_defgrad_wrt_elast_predictor( - const std::vector& interp_eigenval, - const Core::LinAlg::Matrix<3, 3>& eigenvect_rot_elast_pred, - const Core::LinAlg::Matrix<4, 1>& interp_rel_eigenvect_rot_quat, - const Core::LinAlg::Matrix<3, 3>& rot_elast_pred, - const Core::LinAlg::Matrix<4, 1>& interp_rel_rot_quat) + // interpolated eigenvalues and the relative rotation contributions (quaternions) with respect to + // the elastic deformation gradient within the elastic predictor + Core::LinAlg::Matrix<3, 3> compute_elastic_defgrad_wrt_elastic_predictor( + const std::vector& interpolated_eigenvalues, + const Core::LinAlg::Matrix<3, 3>& eigenvector_rotation_elastic_predictor, + const Core::LinAlg::Matrix<4, 1>& interpolated_rel_eigenvector_rotation_quaternion, + const Core::LinAlg::Matrix<3, 3>& rotation_elastic_predictor, + const Core::LinAlg::Matrix<4, 1>& interpolated_rel_rotation_quaternion) { Core::LinAlg::Matrix<3, 3> out{Core::LinAlg::Initialization::zero}; - // construct diagonal eigenvalue matrix + // construct diagonal interpolated eigenvalue matrix Core::LinAlg::Matrix<3, 3> eigenval_matrix{Core::LinAlg::Initialization::zero}; for (unsigned int i = 0; i < 3; ++i) { - eigenval_matrix(i, i) = interp_eigenval[i]; + eigenval_matrix(i, i) = interpolated_eigenvalues[i]; } - // construct eigenvector matrix + // construct interpolated eigenvector matrix from its relative contribution with respect to the + // eigenvector matrix from the elastic predictor: + // \f$ \boldsymbol{Q}_{\boldsymbol{F}_{\mathrm{e,interp}}} = + // \boldsymbol{Q}_{\boldsymbol{F}_{\mathrm{e}}^{(\mathrm{E})}} + // \boldsymbol{Q}_{\boldsymbol{F}_{\mathrm{e,interp}},\mathrm{rel}} \f$ + // (the relative quaternion is transformed into an equivalent relative rotation matrix) Core::LinAlg::Matrix<3, 3> rel_interp_eigenvect_matrix{Core::LinAlg::Initialization::zero}; Core::LargeRotations::quaterniontotriad( - interp_rel_eigenvect_rot_quat, rel_interp_eigenvect_matrix); + interpolated_rel_eigenvector_rotation_quaternion, rel_interp_eigenvect_matrix); Core::LinAlg::Matrix<3, 3> interp_eigenvect_matrix{Core::LinAlg::Initialization::zero}; interp_eigenvect_matrix.multiply_nn( - 1.0, eigenvect_rot_elast_pred, rel_interp_eigenvect_matrix, 0.0); + 1.0, eigenvector_rotation_elastic_predictor, rel_interp_eigenvect_matrix, 0.0); - // construct rotation matrix + // construct interpolated rotation matrix from its relative contribution with respect to the + // rotation matrix from the elastic predictor: + // \f$ \boldsymbol{R}_{\boldsymbol{F}_{\mathrm{e,interp}}} = + // \boldsymbol{R}_{\boldsymbol{F}_{\mathrm{e}}^{(\mathrm{E})}} + // \boldsymbol{R}_{\boldsymbol{F}_{\mathrm{e,interp}},\mathrm{rel}} \f$ + // (the relative quaternion is transformed into an equivalent relative rotation matrix) Core::LinAlg::Matrix<3, 3> rel_interp_rot_matrix{Core::LinAlg::Initialization::zero}; - Core::LargeRotations::quaterniontotriad(interp_rel_rot_quat, rel_interp_rot_matrix); + Core::LargeRotations::quaterniontotriad( + interpolated_rel_rotation_quaternion, rel_interp_rot_matrix); Core::LinAlg::Matrix<3, 3> interp_rot_matrix{Core::LinAlg::Initialization::zero}; - interp_rot_matrix.multiply_nn(1.0, rot_elast_pred, rel_interp_rot_matrix, 0.0); + interp_rot_matrix.multiply_nn(1.0, rotation_elastic_predictor, rel_interp_rot_matrix, 0.0); - // multiply contributions + // multiply contributions to construct the final tensor Core::LinAlg::Matrix<3, 3> LQ{Core::LinAlg::Initialization::zero}; LQ.multiply(1.0, eigenval_matrix, interp_eigenvect_matrix, 0.0); Core::LinAlg::Matrix<3, 3> QTLQ{Core::LinAlg::Initialization::zero}; @@ -206,7 +227,7 @@ Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::ConstNonMatTensors::Cons // set constant non-material tensors // 3x3 identity - id3x3.update(1.0, unit3x3, 0.0); + id3x3 = unit3x3; // Voigt stress form of 3x3 identity Core::LinAlg::Voigt::VoigtUtils::matrix_to_vector( @@ -725,93 +746,13 @@ Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput:: /*--------------------------------------------------------------------* *--------------------------------------------------------------------*/ -AEI::PredictorInterpolator::PredictorInterpolator() - : ref_predictor_locs_(ELASTIC_AND_PLASTIC_PREDICTOR_LOCATIONS), - eigenval_interpolator_(create_eigenvalue_interpolator()) -{ - // auxiliaries - Core::LinAlg::Matrix<3, 3> unit_3x3{Core::LinAlg::Initialization::zero}; - for (unsigned int i = 0; i < 3; ++i) - { - unit_3x3(i, i) = 1.0; - } - std::vector> vector_of_ones(2, {1.0, 1.0, 1.0}); - - // initialize variables for a single Gauss point - eigenval_elast_pred_.resize(1, unit_3x3); - eigenval_plast_pred_.resize(1, unit_3x3); - scalar_interp_eigenval_.resize(1, vector_of_ones); - eigenvect_rot_elast_pred_.resize(1, unit_3x3); - rel_eigenvect_rot_plast_pred_.resize(1, UNIT_QUATERNION); - rot_elast_pred_.resize(1, unit_3x3); - rel_rot_plast_pred_.resize(1, UNIT_QUATERNION); -} - -/*--------------------------------------------------------------------* - *--------------------------------------------------------------------*/ -void AEI::PredictorInterpolator::resize(const unsigned int numgp) -{ - FOUR_C_ASSERT(!resize_called_, - "You already called resize for the predictor interpolator! The number of current GP is {} " - "and " - "you attempt to set it to {}", - eigenval_elast_pred_.size(), numgp); - - eigenval_elast_pred_.resize(numgp, eigenval_elast_pred_[0]); - eigenval_plast_pred_.resize(numgp, eigenval_plast_pred_[0]); - scalar_interp_eigenval_.resize(numgp, scalar_interp_eigenval_[0]); - eigenvect_rot_elast_pred_.resize(numgp, eigenvect_rot_elast_pred_[0]); - rel_eigenvect_rot_plast_pred_.resize(numgp, rel_eigenvect_rot_plast_pred_[0]); - rot_elast_pred_.resize(numgp, rot_elast_pred_[0]); - rel_rot_plast_pred_.resize(numgp, rel_rot_plast_pred_[0]); - - resize_called_ = true; -} - - -/*--------------------------------------------------------------------* - *--------------------------------------------------------------------*/ -void AEI::PredictorInterpolator::pack(Core::Communication::PackBuffer& data) const -{ - Core::Communication::add_to_pack(data, eigenval_elast_pred_); - Core::Communication::add_to_pack(data, eigenval_plast_pred_); - Core::Communication::add_to_pack(data, scalar_interp_eigenval_); - Core::Communication::add_to_pack(data, eigenvect_rot_elast_pred_); - Core::Communication::add_to_pack(data, rel_eigenvect_rot_plast_pred_); - Core::Communication::add_to_pack(data, rot_elast_pred_); - Core::Communication::add_to_pack(data, rel_rot_plast_pred_); - Core::Communication::add_to_pack(data, resize_called_); -} - -/*--------------------------------------------------------------------* - *--------------------------------------------------------------------*/ -void AEI::PredictorInterpolator::unpack(Core::Communication::UnpackBuffer& buffer) -{ - Core::Communication::extract_from_pack(buffer, eigenval_elast_pred_); - Core::Communication::extract_from_pack(buffer, eigenval_plast_pred_); - Core::Communication::extract_from_pack(buffer, scalar_interp_eigenval_); - Core::Communication::extract_from_pack(buffer, eigenvect_rot_elast_pred_); - Core::Communication::extract_from_pack(buffer, rel_eigenvect_rot_plast_pred_); - Core::Communication::extract_from_pack(buffer, rot_elast_pred_); - Core::Communication::extract_from_pack(buffer, rel_rot_plast_pred_); - Core::Communication::extract_from_pack(buffer, resize_called_); -} - -/*--------------------------------------------------------------------* - *--------------------------------------------------------------------*/ -void AEI::PredictorInterpolator::construct_prelim_plastic_pred(const unsigned int gp, +void AEI::PredictorInterpolator::construct_prelim_plastic_pred( const Core::LinAlg::Matrix<3, 3>& elastic_defgrad_elastic_pred, const double elastic_predictor_zero_component_threshold, const PlasticPredictorConstructionParams& plastic_predictor_construction_params) { - // consistency checks - FOUR_C_ASSERT(gp < eigenval_elast_pred_.size(), - "Inconsistent Gauss point index {}, with set Gauss point size {}", gp, - eigenval_elast_pred_.size()); - // get (preconditioned) elastic deformation gradient to be considered as elastic predictor - Core::LinAlg::Matrix<3, 3> precond_elastic_defgrad_elastic_pred{elastic_defgrad_elastic_pred}; - precond_elastic_defgrad_elastic_pred = + const auto precond_elastic_defgrad_elastic_pred = precondition_matrix(elastic_defgrad_elastic_pred, elastic_predictor_zero_component_threshold); // perform polar-spectral decomposition of elastic defgrad within elastic predictor @@ -821,19 +762,18 @@ void AEI::PredictorInterpolator::construct_prelim_plastic_pred(const unsigned in // the ordered eigenvalues from the spectral pairs std::array>, 3> spectral_pairs_elast_pred; Core::LinAlg::matrix_3x3_polar_decomposition(precond_elastic_defgrad_elastic_pred, - rot_elast_pred_[gp], material_stretch_elast_pred, eigenval_elast_pred_temp, + rot_elast_pred_, material_stretch_elast_pred, eigenval_elast_pred_temp, spectral_pairs_elast_pred); for (int i = 0; i < 3; ++i) { FOUR_C_ASSERT_ALWAYS(spectral_pairs_elast_pred[i].first >= 1.0e-8, - "The eigenvalue {} of the elastic deformation gradient within the elastic predictor at GP " - "{} is {}, " + "The eigenvalue {} of the elastic deformation gradient within the elastic predictor is {}, " "such that its logarithm can not be computed!", - i, gp, spectral_pairs_elast_pred[i].first); - eigenval_elast_pred_[gp](i, i) = spectral_pairs_elast_pred[i].first; + i, spectral_pairs_elast_pred[i].first); + eigenval_elast_pred_(i, i) = spectral_pairs_elast_pred[i].first; for (int j = 0; j < 3; ++j) { - eigenvect_rot_elast_pred_[gp](i, j) = spectral_pairs_elast_pred[i].second(j); + eigenvect_rot_elast_pred_(i, j) = spectral_pairs_elast_pred[i].second(j); } } @@ -844,7 +784,7 @@ void AEI::PredictorInterpolator::construct_prelim_plastic_pred(const unsigned in { case AEI::PrelimPlasticPredictor::ElasticStretchEigenvectType::from_elastic_predictor: { - rel_eigenvect_rot_plast_pred_[gp].update(1.0, UNIT_QUATERNION, 0.0); + rel_eigenvect_rot_plast_pred_ = UNIT_QUATERNION; break; } default: @@ -865,7 +805,7 @@ void AEI::PredictorInterpolator::construct_prelim_plastic_pred(const unsigned in { case AEI::PrelimPlasticPredictor::ElasticRotationType::from_elastic_predictor: { - rel_rot_plast_pred_[gp].update(1.0, UNIT_QUATERNION, 0.0); + rel_rot_plast_pred_ = UNIT_QUATERNION; break; } default: @@ -878,20 +818,11 @@ void AEI::PredictorInterpolator::construct_prelim_plastic_pred(const unsigned in // elastic stretch eigenvalues const double detF = precond_elastic_defgrad_elastic_pred.determinant(); - FOUR_C_ASSERT_ALWAYS(detF > 1.0e-8, - "The determinant of the deformation gradient is {}, which is physically and numerically " - "invalid!", - detF); - switch (plastic_predictor_construction_params.elastic_stretch_eigenval_type) { case AEI::PrelimPlasticPredictor::ElasticStretchEigenvalType::scale_unit: { - const double scaled_detF = std::pow(detF, 1.0 / 3.0); - for (unsigned int i = 0; i < 3; ++i) - { - eigenval_plast_pred_[gp](i, i) = scaled_detF; - } + eigenval_plast_pred_ = Core::LinAlg::diagonal_matrix<3>(std::cbrt(detF)); break; } @@ -902,20 +833,13 @@ void AEI::PredictorInterpolator::construct_prelim_plastic_pred(const unsigned in plastic_predictor_construction_params.elastic_stretch_eigenval_type)); } } - - // store eigenvalues such that they can be directly used within the scalar interpolator - scalar_interp_eigenval_[gp] = {{eigenval_elast_pred_[gp](0, 0), eigenval_elast_pred_[gp](1, 1), - eigenval_elast_pred_[gp](2, 2)}, - {eigenval_plast_pred_[gp](0, 0), eigenval_plast_pred_[gp](1, 1), - eigenval_plast_pred_[gp](2, 2)}}; } /*--------------------------------------------------------------------* *--------------------------------------------------------------------*/ -void AEI::PredictorInterpolator::interpolate_elastic_defgrad_contributions(const unsigned int gp, - const double interp_loc, Core::LinAlg::Matrix<4, 1>& interp_rel_rot_quat, - std::vector& interp_eigenval, +void AEI::PredictorInterpolator::interpolate_elastic_defgrad_contributions(const double interp_loc, + Core::LinAlg::Matrix<4, 1>& interp_rel_rot_quat, std::vector& interp_eigenval, Core::LinAlg::Matrix<4, 1>& interp_rel_eigenvect_rot_quat) const { // consistency checks @@ -925,29 +849,26 @@ void AEI::PredictorInterpolator::interpolate_elastic_defgrad_contributions(const "predictors! The current plastic predictor location " "{} is out of these bounds: [{}, {}]", interp_loc, ELASTIC_PREDICTOR_LOCATION, PLASTIC_PREDICTOR_LOCATION); - FOUR_C_ASSERT(gp < eigenval_elast_pred_.size(), - "Inconsistent Gauss point index {}, with set Gauss point size {}", gp, - eigenval_elast_pred_.size()); // auxiliaries Core::LinAlg::Matrix<1, 1> matrix_interp_loc{Core::LinAlg::Initialization::zero}; matrix_interp_loc(0) = interp_loc; - // interpolate eigenvalues - interp_eigenval = eigenval_interpolator_.get_interpolated_scalar( - scalar_interp_eigenval_[gp], ref_predictor_locs_, matrix_interp_loc); + // --> interpolate eigenvalues + interp_eigenval = + interpolate_eigenvalues(eigenval_elast_pred_, eigenval_plast_pred_, matrix_interp_loc); // interpolate quaternions interp_rel_eigenvect_rot_quat = Core::LinAlg::spherical_linear_interpolation( - UNIT_QUATERNION, rel_eigenvect_rot_plast_pred_[gp], interp_loc); + UNIT_QUATERNION, rel_eigenvect_rot_plast_pred_, interp_loc); interp_rel_rot_quat = Core::LinAlg::spherical_linear_interpolation( - UNIT_QUATERNION, rel_rot_plast_pred_[gp], interp_loc); + UNIT_QUATERNION, rel_rot_plast_pred_, interp_loc); } /*--------------------------------------------------------------------* *--------------------------------------------------------------------*/ Core::LinAlg::Matrix<3, 3> AEI::PredictorInterpolator::interpolate_elastic_defgrad( - const unsigned int gp, const double interp_loc) const + const double interp_loc) const { // consistency checks FOUR_C_ASSERT( @@ -956,25 +877,22 @@ Core::LinAlg::Matrix<3, 3> AEI::PredictorInterpolator::interpolate_elastic_defgr "predictors! The current plastic predictor location " "{} is out of these bounds: [{}, {}]", interp_loc, ELASTIC_PREDICTOR_LOCATION, PLASTIC_PREDICTOR_LOCATION); - FOUR_C_ASSERT(gp < eigenval_elast_pred_.size(), - "Inconsistent Gauss point index {}, with set Gauss point size {}", gp, - eigenval_elast_pred_.size()); // interpolate contributions Core::LinAlg::Matrix<4, 1> interp_rel_rot_quat{Core::LinAlg::Initialization::zero}; std::vector interp_eigenval; Core::LinAlg::Matrix<4, 1> interp_rel_eigenvect_rot_quat{Core::LinAlg::Initialization::zero}; interpolate_elastic_defgrad_contributions( - gp, interp_loc, interp_rel_rot_quat, interp_eigenval, interp_rel_eigenvect_rot_quat); + interp_loc, interp_rel_rot_quat, interp_eigenval, interp_rel_eigenvect_rot_quat); - return compute_elast_defgrad_wrt_elast_predictor(interp_eigenval, eigenvect_rot_elast_pred_[gp], - interp_rel_eigenvect_rot_quat, rot_elast_pred_[gp], interp_rel_rot_quat); + return compute_elastic_defgrad_wrt_elastic_predictor(interp_eigenval, eigenvect_rot_elast_pred_, + interp_rel_eigenvect_rot_quat, rot_elast_pred_, interp_rel_rot_quat); } /*--------------------------------------------------------------------* *--------------------------------------------------------------------*/ -void AEI::PredictorInterpolator::set_plastic_predictor_after_construction_algo( - const unsigned int gp, const double plastic_pred_loc) +void AEI::PredictorInterpolator::update_plastic_predictor_after_construction_algo( + const double plastic_pred_loc) { // consistency checks FOUR_C_ASSERT(ELASTIC_PREDICTOR_LOCATION <= plastic_pred_loc && @@ -983,102 +901,47 @@ void AEI::PredictorInterpolator::set_plastic_predictor_after_construction_algo( "predictors! The current plastic predictor location " "{} is out of these bounds: [{}, {}]", plastic_pred_loc, ELASTIC_PREDICTOR_LOCATION, PLASTIC_PREDICTOR_LOCATION); - FOUR_C_ASSERT(gp < eigenval_elast_pred_.size(), - "Inconsistent Gauss point index {}, with set Gauss point size {}", gp, - eigenval_elast_pred_.size()); // set all quantities relevant for the plastic predictor std::vector interp_eigenval; - interpolate_elastic_defgrad_contributions(gp, plastic_pred_loc, rel_rot_plast_pred_[gp], - interp_eigenval, rel_eigenvect_rot_plast_pred_[gp]); + interpolate_elastic_defgrad_contributions( + plastic_pred_loc, rel_rot_plast_pred_, interp_eigenval, rel_eigenvect_rot_plast_pred_); for (unsigned int i = 0; i < 3; ++i) { - eigenval_plast_pred_[gp](i, i) = interp_eigenval[i]; + eigenval_plast_pred_(i, i) = interp_eigenval[i]; } - scalar_interp_eigenval_[gp] = {{eigenval_elast_pred_[gp](0, 0), eigenval_elast_pred_[gp](1, 1), - eigenval_elast_pred_[gp](2, 2)}, - {eigenval_plast_pred_[gp](0, 0), eigenval_plast_pred_[gp](1, 1), - eigenval_plast_pred_[gp](2, 2)}}; } AEI::InterpolationPointContainer::InterpolationPointContainer( const EstimateInterpolationParams& estimate_interpolation_params) { - lower_interp_bounds.resize(1, ELASTIC_PREDICTOR_LOCATION); - upper_interp_bounds.resize(1, PLASTIC_PREDICTOR_LOCATION); + // set starting points for both constant starting points and the strategy based on the + // equivalent stress history (starting point will evolve for the latter based on the material + // evaluation of the subsequent timesteps) switch (estimate_interpolation_params.starting_point_type) { case AEI::StartingPointType::constant: + case AEI::StartingPointType::equiv_stress_history: { - FOUR_C_ASSERT(estimate_interpolation_params.user_set_starting_point.has_value(), - "The user-set starting point is not specified!"); - - starting_points.resize(1, estimate_interpolation_params.user_set_starting_point.value()); + starting_point = estimate_interpolation_params.user_set_starting_point; break; } default: { - starting_points.resize(1, estimate_interpolation_params.interval_scanning_param); - break; + FOUR_C_THROW( + "Interpolation point container initialization not supported for starting point type {}", + EnumTools::enum_name(estimate_interpolation_params.starting_point_type)); } } - current_interp_points.resize(1, starting_points[0]); -} - -/*--------------------------------------------------------------------* - *--------------------------------------------------------------------*/ -void AEI::InterpolationPointContainer::reset_bounds_and_current_interp_point(const unsigned int gp) -{ - // consistency checks - FOUR_C_ASSERT(gp < current_interp_points.size(), - "Inconsistent Gauss point index {}, with set Gauss point size {}", gp, - current_interp_points.size()); - - current_interp_points[gp] = starting_points[gp]; - lower_interp_bounds[gp] = ELASTIC_PREDICTOR_LOCATION; - upper_interp_bounds[gp] = PLASTIC_PREDICTOR_LOCATION; -} - -/*--------------------------------------------------------------------* - *--------------------------------------------------------------------*/ -void AEI::InterpolationPointContainer::resize(const unsigned int numgp) -{ - FOUR_C_ASSERT(!resize_called, - "You already called resize for the interpolation point container! The number of " - "current GP is " - "{} and " - "you attempt to set it to {}", - current_interp_points.size(), numgp); - - current_interp_points.resize(numgp, current_interp_points[0]); - lower_interp_bounds.resize(numgp, lower_interp_bounds[0]); - upper_interp_bounds.resize(numgp, upper_interp_bounds[0]); - starting_points.resize(numgp, starting_points[0]); - - resize_called = true; -} - - -/*--------------------------------------------------------------------* - *--------------------------------------------------------------------*/ -void AEI::InterpolationPointContainer::pack(Core::Communication::PackBuffer& data) const -{ - Core::Communication::add_to_pack(data, current_interp_points); - Core::Communication::add_to_pack(data, lower_interp_bounds); - Core::Communication::add_to_pack(data, upper_interp_bounds); - Core::Communication::add_to_pack(data, starting_points); - Core::Communication::add_to_pack(data, resize_called); } /*--------------------------------------------------------------------* *--------------------------------------------------------------------*/ -void AEI::InterpolationPointContainer::unpack(Core::Communication::UnpackBuffer& buffer) +void AEI::InterpolationPointContainer::reset_bounds_and_current_interp_point() { - Core::Communication::extract_from_pack(buffer, current_interp_points); - Core::Communication::extract_from_pack(buffer, lower_interp_bounds); - Core::Communication::extract_from_pack(buffer, upper_interp_bounds); - Core::Communication::extract_from_pack(buffer, starting_points); - Core::Communication::extract_from_pack(buffer, resize_called); + current_interp_point = starting_point; + lower_interp_bound = ELASTIC_PREDICTOR_LOCATION; + upper_interp_bound = PLASTIC_PREDICTOR_LOCATION; } FOUR_C_NAMESPACE_CLOSE diff --git a/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp b/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp index 8e47a38dac4..ac2eacd8f69 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp @@ -1080,9 +1080,9 @@ namespace Mat double step; }; - //! namespace containing utilities dedicated to the Adaptive Estimate Interpolation algorithm, - //! presented in Ana, Schmidt, Wall: Adaptive Estimate Interpolation: Accelerating Local - //! Newton-Raphson Schemes in Computational Plasticity and Viscoplasticity, Preprint + //! namespace containing utilities dedicated to the Adaptive Estimate Interpolation (AEI) + //! algorithm, presented in Ana, Schmidt, Wall: Adaptive Estimate Interpolation: Accelerating + //! Local Newton-Raphson Schemes in Computational Plasticity and Viscoplasticity, Preprint namespace AdaptiveEstimateInterpolation { @@ -1242,143 +1242,121 @@ namespace Mat ReestimationParams reestimation; }; - //! Interpolator of elastic deformation gradients between the elastic and the plastic - //! predictors. This class stores the values of the involved quantities at - //! all Gauss points. + //! Interpolator of elastic deformation gradients between two predictor states: between the + //! elastic predictor and the preliminary plastic predictor (during plastic predictor + //! construction), or between the elastic predictor and the plastic predictor (estimate + //! interpolation / reestimation). The elastic predictor itself never changes after calling + //! \ref PredictorInterpolator::construct_prelim_plastic_pred(); only the second predictor + //! state evolves, switching from the preliminary plastic predictor to the final plastic + //! predictor when + //! \ref PredictorInterpolator::update_plastic_predictor_after_construction_algo() is called. class PredictorInterpolator { public: - //! constructor - PredictorInterpolator(); - - //! resizing based on a given number of Gauss points - void resize(const unsigned int numgp); - - //! pack method - void pack(Core::Communication::PackBuffer& data) const; - - //! unpack method - void unpack(Core::Communication::UnpackBuffer& buffer); - /*! * @brief Constructs a preliminary plastic predictor given the elastic predictor and the * specified AEI settings. * + * @note This function also decomposes \p elastic_defgrad_elastic_pred and updates its + * components stored here as internal variables. + * * - * @param[in] gp Gauss point index * @param[in] elastic_defgrad_elastic_pred elastic deformation gradient within the elastic - * predictor + * predictor: \f$ \boldsymbol{F}_{\mathrm{e},n+1}^{(\mathrm{E})} = \boldsymbol{F}_{n+1} + * \boldsymbol{F}_{\mathrm{p},n}^{-1} \f$ * @param[in] elastic_predictor_zero_component_threshold threshold for setting components of - * the elastic deformation gradient within the elastic predictor to 0.0 (in order to avoid + * \p elastic_defgrad_elastic_pred to 0.0 (in order to avoid * numerical rotations) * @param[in] plastic_predictor_construction_params parameters for plastic predictor * construction */ - void construct_prelim_plastic_pred(const unsigned int gp, + void construct_prelim_plastic_pred( const Core::LinAlg::Matrix<3, 3>& elastic_defgrad_elastic_pred, - const double elastic_predictor_zero_component_threshold, + double elastic_predictor_zero_component_threshold, const PlasticPredictorConstructionParams& plastic_predictor_construction_params); /*! * @brief Interpolates an elastic deformation gradient based on the stored predictor - * quantities. + * quantities from the predictor extrema involved (elastic and preliminary plastic + * predictors / elastic and plastic predictors depending on the algorithmic component + * calling this function). * * - * @param[in] gp Gauss point index * @param[in] interp_loc location used for interpolation; either \f$ \tau \f$ (plastic - * predictor construction) or \f$ \xi \f$ (estimate interpolation) + * predictor construction) or \f$ \xi \f$ (estimate interpolation / reestimation) */ - Core::LinAlg::Matrix<3, 3> interpolate_elastic_defgrad( - const unsigned int gp, const double interp_loc) const; + [[nodiscard]] Core::LinAlg::Matrix<3, 3> interpolate_elastic_defgrad( + double interp_loc) const; /*! * @brief After the plastic predictor construction algorithm has succeeded in finding the * construction parameter \f$\tau \f$ associated with the plastic predictor, this function - * sets the determined plastic predictor (more specifically: all class variables - * associated with it). + * updates the determined plastic predictor (more specifically: all class variables + * currently associated with the preliminary plastic predictor are updated to the values of + * the determined plastic predictor). * * - * @param[in] gp Gauss point index * @param[in] plastic_pred_loc location \f$ \tau \f$ determined in the plastic * predictor construction */ - void set_plastic_predictor_after_construction_algo( - const unsigned int gp, const double plastic_pred_loc); + void update_plastic_predictor_after_construction_algo(double plastic_pred_loc); private: /*! * @brief Interpolates eigenvalues and rotational contributions based on the stored - * predictor quantities. + * predictor quantities from the predictor extrema involved (elastic and preliminary plastic + * predictors / elastic and plastic predictors depending on the algorithmic component + * calling this function). * * - * @param[in] gp Gauss point index * @param[in] interp_loc location used for interpolation; either \f$ \tau \f$ (plastic - * predictor construction) or \f$ \xi \f$ (estimate interpolation) + * predictor construction) or \f$ \xi \f$ (estimate interpolation / reestimation) * @param[out] interp_rel_rot_quat interpolated relative elastic rotation quaternion * @param[out] interp_eigenval interpolated elastic eigenvalues (stored in descending order) * @param[out] interp_rel_eigenvect_rot_quat interpolated relative elastic eigenvector * quaternion */ - void interpolate_elastic_defgrad_contributions(const unsigned int gp, - const double interp_loc, Core::LinAlg::Matrix<4, 1>& interp_rel_rot_quat, - std::vector& interp_eigenval, + void interpolate_elastic_defgrad_contributions(double interp_loc, + Core::LinAlg::Matrix<4, 1>& interp_rel_rot_quat, std::vector& interp_eigenval, Core::LinAlg::Matrix<4, 1>& interp_rel_eigenvect_rot_quat) const; - //! elastic predictor: elastic eigenvalue tensors \f$ + //! elastic predictor: elastic eigenvalue tensor \f$ //! \boldsymbol{\Lambda}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{E})}} - //! \f$ of all Gauss points - std::vector> eigenval_elast_pred_; - //! plastic predictor: elastic eigenvalue tensors \f$ - //! \boldsymbol{\Lambda}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}} \f$ of all Gauss points - std::vector> eigenval_plast_pred_; - //! eigenvalue data storage to be directly used within the scalar interpolator; indexing: - //! - first dimension: Gauss point. - //! - second dimension: predictor type - //! (0 = elastic predictor, 1 = plastic predictor). - //! - third dimension: eigenvalues corresponding to the selected predictor, stored in - //! descending order. - std::vector>> scalar_interp_eigenval_; - //! interpolation locations for the elastic and plastic predictor, to be directly used - //! within the scalar interpolator; indexing: - //! - 0: elastic predictor location. - //! - 1: plastic predictor location. - const std::vector> ref_predictor_locs_; - //! elastic predictor: elastic stretch eigenvector tensors \f$ - //! \boldsymbol{Q}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{E})}} \f$ of all Gauss points - std::vector> eigenvect_rot_elast_pred_; - //! plastic predictor: relative elastic eigenvector quaternions \f$ + //! \f$ + Core::LinAlg::Matrix<3, 3> eigenval_elast_pred_; + //! (preliminary) plastic predictor: elastic eigenvalue tensor \f$ + //! \boldsymbol{\Lambda}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}} \f$ + Core::LinAlg::Matrix<3, 3> eigenval_plast_pred_; + //! elastic predictor: elastic stretch eigenvector tensor \f$ + //! \boldsymbol{Q}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{E})}} \f$ + Core::LinAlg::Matrix<3, 3> eigenvect_rot_elast_pred_; + //! (preliminary) plastic predictor: relative elastic eigenvector quaternion \f$ //! \boldsymbol{q}_{\boldsymbol{Q}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}}, \mathrm{rel}} //! \f$ associated with \f$ //! \boldsymbol{Q}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}, \mathrm{rel}} = //! \boldsymbol{Q}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{E})}}^T //! \boldsymbol{Q}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}} - //! \f$ of all Gauss points - std::vector> rel_eigenvect_rot_plast_pred_; - //! elastic predictor: elastic rotation tensors \f$ - //! \boldsymbol{R}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{E})}} \f$ of all Gauss points - std::vector> rot_elast_pred_; - //! plastic predictor: relative elastic rotation quaternions \f$ + //! \f$ + Core::LinAlg::Matrix<4, 1> rel_eigenvect_rot_plast_pred_; + //! elastic predictor: elastic rotation tensor \f$ + //! \boldsymbol{R}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{E})}} \f$ + Core::LinAlg::Matrix<3, 3> rot_elast_pred_; + //! (preliminary) plastic predictor: relative elastic rotation quaternion \f$ //! \boldsymbol{r}_{\boldsymbol{R}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}, \mathrm{rel}}} //! \f$ associated with \f$ \boldsymbol{R}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}, //! \mathrm{rel}} = //! \boldsymbol{R}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{E})}}^T - //! \boldsymbol{R}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}}\f$ of all Gauss points - std::vector> rel_rot_plast_pred_; - //! scalar eigenvalue interpolator - Core::LinAlg::ScalarInterpolator<1> eigenval_interpolator_; - //! tracks whether the resizing function has been called, to set the current number of Gauss - //! points exactly once! - bool resize_called_{false}; + //! \boldsymbol{R}_{\boldsymbol{F}_{\text{e}}^{(\mathrm{P})}}\f$ + Core::LinAlg::Matrix<4, 1> rel_rot_plast_pred_; }; //! Container for interpolation points / bounds used in the - //! Adaptive Estimate Interpolation. This class stores the values of the involved quantities - //! at all Gauss points. + //! Adaptive Estimate Interpolation (AEI) scheme. struct InterpolationPointContainer { public: /*! - * @brief Constructor + * @brief Constructor setting the starting point based on the given parameters. * * @param[in] estimate_interpolation_params parameters for estimate interpolation between * predictors @@ -1387,33 +1365,20 @@ namespace Mat const EstimateInterpolationParams& estimate_interpolation_params); //! reset interpolation interval and set the current interpolation point to its saved - //! starting point at a given Gauss point - void reset_bounds_and_current_interp_point(const unsigned int gp); - - //! resizing based on the given number of Gauss points - void resize(const unsigned int numgp); - - //! pack method - void pack(Core::Communication::PackBuffer& data) const; - - //! unpack method - void unpack(Core::Communication::UnpackBuffer& buffer); - - //! current interpolation points \f$ \xi \f$ of all Gauss points - std::vector current_interp_points; + //! starting point + void reset_bounds_and_current_interp_point(); - //! lower interpolation bounds \f$ \xi_{\text{E}} \f$ of all Gauss points - std::vector lower_interp_bounds; + //! current interpolation point \f$ \xi \f$ + double current_interp_point; - //! upper interpolation bounds \f$ \xi_{\text{P}} \f$ of all Gauss points - std::vector upper_interp_bounds; + //! lower interpolation bound \f$ \xi_{\text{E}} \f$ + double lower_interp_bound; - //! starting points for interpolation \f$ \hat{\xi} \f$ of all Gauss points - std::vector starting_points; + //! upper interpolation bound \f$ \xi_{\text{P}} \f$ + double upper_interp_bound; - //! tracks whether the resizing function has been called, to set the current number of - //! Gauss points exactly once! - bool resize_called{false}; + //! starting point for interpolation \f$ \hat{\xi} \f$ + double starting_point; }; } // namespace AdaptiveEstimateInterpolation } // namespace InelasticDefgradTransvIsotropElastViscoplastUtils diff --git a/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp b/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp index 9550e619b06..8dfc1f6cc95 100644 --- a/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp +++ b/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp @@ -10,6 +10,7 @@ #include "4C_fem_general_largerotations.hpp" #include "4C_inelastic_defgrad_factors_test_utils.hpp" #include "4C_linalg_fixedsizematrix.hpp" +#include "4C_linalg_fixedsizematrix_generators.hpp" #include "4C_mat_inelastic_defgrad_factors_service.hpp" #include "4C_unittest_utils_assertions_test.hpp" #include "4C_utils_singleton_owner.hpp" @@ -446,16 +447,14 @@ namespace /// when other alternatives are implemented for the rotational contributions. TEST_F(InelasticDefgradFactorsServiceTest, TestPredictorInterpolatorPlasticPredConstruction) { - // construct predictor interpolator with a single Gauss point + // construct predictor interpolator AEI::PredictorInterpolator pred_interpolator{}; - const unsigned int gp = 0; // setup AEI parameters AEI::AEIParams aei_params = InelasticDefgradFactorsTestUtils::set_up_aei_params(); // auxiliaries - Core::LinAlg::Matrix<3, 3> unit_3x3{Core::LinAlg::Initialization::zero}; - unit_3x3(0, 0) = unit_3x3(1, 1) = unit_3x3(2, 2) = 1.0; + const auto unit_3x3 = Core::LinAlg::identity_matrix<3>(); // setup dummy temperature, last plastic strain, and timestep const double temperature = 293.15; @@ -507,8 +506,6 @@ namespace return defgrad; }; - - // setup eigenvalues of the deformation gradient to be used within all subsequent tests, and // already scale them for the plastic predictor lambda.clear(); @@ -538,15 +535,15 @@ namespace FOUR_C_EXPECT_NEAR(local_integration_input.elastic_predictor_elastic_defgrad, defgrad, 1.0e-15); // construct preliminary plastic predictor - pred_interpolator.construct_prelim_plastic_pred(gp, + pred_interpolator.construct_prelim_plastic_pred( local_integration_input.elastic_predictor_elastic_defgrad, aei_params.elastic_predictor_zero_component_threshold, aei_params.plastic_predictor_construction); // verify whether both predictors are initialized consistently - FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 0.0), + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(0.0), local_integration_input.elastic_predictor_elastic_defgrad, 1.0e-15); - FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 1.0), + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(1.0), compute_full_defgrad(R, Q, scaled_unit), 1.0e-15); // now set the plastic predictor at the interpolation location 0.5 between the elastic and the @@ -555,8 +552,8 @@ namespace lambda_plastic_pred_ref(0, 0) = 1.5874010519681996; lambda_plastic_pred_ref(1, 1) = 1.122462048309373; lambda_plastic_pred_ref(2, 2) = 1.122462048309373; - pred_interpolator.set_plastic_predictor_after_construction_algo(gp, 0.5); - FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 1.0), + pred_interpolator.update_plastic_predictor_after_construction_algo(0.5); + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(1.0), compute_full_defgrad(R, Q, lambda_plastic_pred_ref), 1.0e-8); // --> repeat the procedure above with a deformation gradient additionally containing an @@ -588,21 +585,21 @@ namespace FOUR_C_EXPECT_NEAR(local_integration_input.elastic_predictor_elastic_defgrad, defgrad, 1.0e-15); // construct preliminary plastic predictor - pred_interpolator.construct_prelim_plastic_pred(gp, + pred_interpolator.construct_prelim_plastic_pred( local_integration_input.elastic_predictor_elastic_defgrad, aei_params.elastic_predictor_zero_component_threshold, aei_params.plastic_predictor_construction); // verify whether both predictors are initialized consistently - FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 0.0), + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(0.0), local_integration_input.elastic_predictor_elastic_defgrad, 1.0e-15); - FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 1.0), + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(1.0), compute_full_defgrad(R, Q, scaled_unit), 1.0e-15); // now set the plastic predictor at the interpolation location 0.5 between the elastic and the // preliminary plastic predictors - pred_interpolator.set_plastic_predictor_after_construction_algo(gp, 0.5); - FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 1.0), + pred_interpolator.update_plastic_predictor_after_construction_algo(0.5); + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(1.0), compute_full_defgrad(R, Q, lambda_plastic_pred_ref), 1.0e-8); @@ -630,21 +627,21 @@ namespace FOUR_C_EXPECT_NEAR(local_integration_input.elastic_predictor_elastic_defgrad, defgrad, 1.0e-15); // construct preliminary plastic predictor - pred_interpolator.construct_prelim_plastic_pred(gp, + pred_interpolator.construct_prelim_plastic_pred( local_integration_input.elastic_predictor_elastic_defgrad, aei_params.elastic_predictor_zero_component_threshold, aei_params.plastic_predictor_construction); // verify whether both predictors are initialized consistently - FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 0.0), + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(0.0), local_integration_input.elastic_predictor_elastic_defgrad, 1.0e-15); - FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 1.0), + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(1.0), compute_full_defgrad(R, Q, scaled_unit), 1.0e-15); // now set the plastic predictor at the interpolation location 0.5 between the elastic and the // preliminary plastic predictors - pred_interpolator.set_plastic_predictor_after_construction_algo(gp, 0.5); - FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 1.0), + pred_interpolator.update_plastic_predictor_after_construction_algo(0.5); + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(1.0), compute_full_defgrad(R, Q, lambda_plastic_pred_ref), 1.0e-8); } @@ -654,9 +651,8 @@ namespace /// than a set threshold are consistently set to 0 TEST_F(InelasticDefgradFactorsServiceTest, TestPredictorInterpolatorPreconditioning) { - // construct predictor interpolator with a single Gauss point + // construct predictor interpolator AEI::PredictorInterpolator pred_interpolator{}; - const unsigned int gp = 0; // initialize AEI parameters with and without preconditioning AEI::AEIParams aei_params_preconditioning = InelasticDefgradFactorsTestUtils::set_up_aei_params( @@ -665,10 +661,8 @@ namespace InelasticDefgradFactorsTestUtils::set_up_aei_params( {.elastic_predictor_zero_component_threshold = 0.0}); - // auxiliaries - Core::LinAlg::Matrix<3, 3> unit_3x3{Core::LinAlg::Initialization::zero}; - unit_3x3(0, 0) = unit_3x3(1, 1) = unit_3x3(2, 2) = 1.0; + Core::LinAlg::Matrix<3, 3> unit_3x3 = Core::LinAlg::identity_matrix<3>(); // setup previous inelastic defgrad, and deformation gradient Core::LinAlg::Matrix<3, 3> last_inv_inelastic_defgrad{unit_3x3}; @@ -693,11 +687,11 @@ namespace // for the case of no preconditioning, the exact elastic deformation gradient within the elastic // predictor must be recovered - pred_interpolator.construct_prelim_plastic_pred(gp, + pred_interpolator.construct_prelim_plastic_pred( local_integration_input.elastic_predictor_elastic_defgrad, aei_params_no_preconditioning.elastic_predictor_zero_component_threshold, aei_params_no_preconditioning.plastic_predictor_construction); - FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 0.0), + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(0.0), local_integration_input.elastic_predictor_elastic_defgrad, 1.0e-15); // for the case of preconditioning, the small off-diagonal elements must be 0 @@ -705,49 +699,15 @@ namespace local_integration_input.elastic_predictor_elastic_defgrad}; preconditioned_elastic_defgrad_elastic_predictor(0, 1) = preconditioned_elastic_defgrad_elastic_predictor(1, 0) = 0.0; - pred_interpolator.construct_prelim_plastic_pred(gp, + pred_interpolator.construct_prelim_plastic_pred( local_integration_input.elastic_predictor_elastic_defgrad, aei_params_preconditioning.elastic_predictor_zero_component_threshold, aei_params_preconditioning.plastic_predictor_construction); - FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 0.0), + FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(0.0), preconditioned_elastic_defgrad_elastic_predictor, 1.0e-15); } - /// Tests the resizing procedure for the predictor interpolator used for the Adaptive Estimate - /// Interpolation - TEST_F(InelasticDefgradFactorsServiceTest, TestPredictorInterpolatorResize) - { - AEI::PredictorInterpolator pred_interpolator{}; - constexpr unsigned int numgp = 3; - pred_interpolator.resize(numgp); - - AEI::AEIParams aei_params = InelasticDefgradFactorsTestUtils::set_up_aei_params(); - - // populate each GP with a different predictor - std::array, numgp> all_ref_elastic_pred{ - Core::LinAlg::Matrix<3, 3>{Core::LinAlg::Initialization::zero}, - Core::LinAlg::Matrix<3, 3>{Core::LinAlg::Initialization::zero}, - Core::LinAlg::Matrix<3, 3>{Core::LinAlg::Initialization::zero}}; - for (unsigned int gp = 0; gp < numgp; ++gp) - { - all_ref_elastic_pred[gp](0, 0) = 1.0 + 0.1 * gp; - all_ref_elastic_pred[gp](1, 1) = 1.0; - all_ref_elastic_pred[gp](2, 2) = 1.0; - - pred_interpolator.construct_prelim_plastic_pred(gp, all_ref_elastic_pred[gp], - aei_params.elastic_predictor_zero_component_threshold, - aei_params.plastic_predictor_construction); - } - - // verify that each GP retains its own state via the interpolated elastic predictor - for (unsigned int gp = 0; gp < numgp; ++gp) - { - FOUR_C_EXPECT_NEAR(pred_interpolator.interpolate_elastic_defgrad(gp, 0.0), - all_ref_elastic_pred[gp], 1.0e-12); - } - } - - /// Tests the initialization, the resizing and the reset procedure for the interpolation point + /// Tests the initialization and the reset procedure for the interpolation point /// containers used within the Adaptive Estimate Interpolation TEST_F(InelasticDefgradFactorsServiceTest, TestInterpolationPointContainer) { @@ -756,43 +716,26 @@ namespace aei_params.estimate_interpolation.starting_point_type = AEI::StartingPointType::constant; aei_params.estimate_interpolation.user_set_starting_point = 0.2; - // construct interpolation point container with a single Gauss point + // construct interpolation point container AEI::InterpolationPointContainer interp_point_container{aei_params.estimate_interpolation}; - const unsigned int gp = 0; - // test consistent initialization - EXPECT_EQ(interp_point_container.lower_interp_bounds[gp], 0.0); - EXPECT_EQ(interp_point_container.upper_interp_bounds[gp], 1.0); - EXPECT_EQ( - interp_point_container.starting_points[gp], 0.2); // has to be the user-set starting point - EXPECT_EQ(interp_point_container.current_interp_points[gp], - interp_point_container.starting_points[gp]); + // test consistent initialization of the starting point + EXPECT_EQ(interp_point_container.starting_point, 0.2); // has to be the user-set starting point // set some dummy values - interp_point_container.current_interp_points[gp] = 0.9; - interp_point_container.lower_interp_bounds[gp] = 0.7; - interp_point_container.upper_interp_bounds[gp] = 0.99; + interp_point_container.current_interp_point = 0.9; + interp_point_container.lower_interp_bound = 0.7; + interp_point_container.upper_interp_bound = 0.99; const double dummy_starting_point = 0.34; - interp_point_container.starting_points[gp] = dummy_starting_point; + interp_point_container.starting_point = dummy_starting_point; // reset and test consistency - interp_point_container.reset_bounds_and_current_interp_point(gp); - EXPECT_EQ(interp_point_container.starting_points[gp], dummy_starting_point); - EXPECT_EQ(interp_point_container.current_interp_points[gp], - interp_point_container.starting_points[gp]); - EXPECT_EQ(interp_point_container.lower_interp_bounds[gp], 0.0); - EXPECT_EQ(interp_point_container.upper_interp_bounds[gp], 1.0); - - // test resizing - interp_point_container.resize(3); - EXPECT_EQ(interp_point_container.current_interp_points[2], - interp_point_container.current_interp_points[0]); - EXPECT_EQ(interp_point_container.lower_interp_bounds[2], - interp_point_container.lower_interp_bounds[0]); - EXPECT_EQ(interp_point_container.upper_interp_bounds[2], - interp_point_container.upper_interp_bounds[0]); - EXPECT_EQ(interp_point_container.starting_points[2], interp_point_container.starting_points[0]); + interp_point_container.reset_bounds_and_current_interp_point(); + EXPECT_EQ(interp_point_container.starting_point, dummy_starting_point); + EXPECT_EQ(interp_point_container.current_interp_point, interp_point_container.starting_point); + EXPECT_EQ(interp_point_container.lower_interp_bound, 0.0); + EXPECT_EQ(interp_point_container.upper_interp_bound, 1.0); } } // namespace From b08fc1c878e3d86545544317f7e5d6383f20b000 Mon Sep 17 00:00:00 2001 From: Ana Dragos-Corneliu Date: Mon, 10 Aug 2026 19:15:37 +0200 Subject: [PATCH 5/7] Add AEI manager --- src/mat/4C_mat_inelastic_defgrad_factors.cpp | 24 +- src/mat/4C_mat_inelastic_defgrad_factors.hpp | 6 + ..._mat_inelastic_defgrad_factors_service.cpp | 290 ++++++++++++++ ..._mat_inelastic_defgrad_factors_service.hpp | 271 +++++++++++++ ...inelastic_defgrad_factors_service_test.cpp | 356 ++++++++++++++++++ 5 files changed, 946 insertions(+), 1 deletion(-) diff --git a/src/mat/4C_mat_inelastic_defgrad_factors.cpp b/src/mat/4C_mat_inelastic_defgrad_factors.cpp index 8647a197ec2..fdde853187f 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors.cpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors.cpp @@ -1790,7 +1790,12 @@ Mat::InelasticDefgradTransvIsotropElastViscoplast::InelasticDefgradTransvIsotrop state_quantity_derivatives_(), tensor_interpolator_(init_tensor_interpolator()), local_substepping_utils_(0.0), - local_newton_manager_(parameter()->local_newton_params()) + local_newton_manager_(parameter()->local_newton_params()), + adaptive_estimate_interp_manager_( + parameter()->use_adaptive_estimate_interpolation() + ? std::make_optional( + AEI::AEIManager(parameter()->adaptive_estimate_interpolation_params())) + : std::nullopt) { // set time step size to 0.0 (this is set to the correct and current value in the // preevaluate method) @@ -3289,6 +3294,12 @@ void Mat::InelasticDefgradTransvIsotropElastViscoplast::setup(const int numgp, // resize plastic flow tracking vector with the correct number of Gauss points is_plastic_gp_.resize(numgp, is_plastic_gp_[0]); + // resize the data within the AEI manager + if (adaptive_estimate_interp_manager_.has_value()) + { + adaptive_estimate_interp_manager_->resize(numgp); + } + // read fiber and structural tensor in the case of transverse isotropy if (parameter()->mat_behavior() == ViscoplastUtils::MatBehavior::transv_isotropic) { @@ -3329,6 +3340,10 @@ void Mat::InelasticDefgradTransvIsotropElastViscoplast::pack_inelastic( // pack plastic flow tracking vector add_to_pack(data, is_plastic_gp_); + + // pack the adaptive estimate interpolation manager + if (adaptive_estimate_interp_manager_.has_value()) + adaptive_estimate_interp_manager_->pack(data); } } @@ -3353,6 +3368,9 @@ void Mat::InelasticDefgradTransvIsotropElastViscoplast::unpack_inelastic( local_newton_manager_.unpack(buffer); // unpack the plastic flow tracking vector extract_from_pack(buffer, is_plastic_gp_); + // unpack the adaptive estimate interpolation manager + if (adaptive_estimate_interp_manager_.has_value()) + adaptive_estimate_interp_manager_->unpack(buffer); } // set number of Gauss points manually, since the setup method is not called @@ -4481,6 +4499,10 @@ std::string Mat::InelasticDefgradTransvIsotropElastViscoplast::get_error_warning { extended_error_string += local_substepping_utils_.get_info(); } + if (adaptive_estimate_interp_manager_.has_value()) + { + extended_error_string += adaptive_estimate_interp_manager_->get_info(gp_); + } // get relevant error info extended_error_string += "BASE ERROR: \n"; diff --git a/src/mat/4C_mat_inelastic_defgrad_factors.hpp b/src/mat/4C_mat_inelastic_defgrad_factors.hpp index ebc6be3c30c..ef0d842a74a 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors.hpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors.hpp @@ -1711,6 +1711,12 @@ namespace Mat //! vector tracking whether there is plastic flow at each Gauss point std::vector is_plastic_gp_; + //! dedicated Adaptive Estimate Interpolation manager containing the fundamental logic of the + //! scheme + std::optional + adaptive_estimate_interp_manager_; + /*! * @brief Calculate the Holzapfel gamma and delta values of the isotropic elastic material * components diff --git a/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp b/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp index b70cd6559f0..beeac8da538 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors_service.cpp @@ -9,6 +9,7 @@ #include "4C_mat_inelastic_defgrad_factors_service.hpp" +#include "4C_comm_pack_helpers.hpp" #include "4C_fem_general_largerotations.hpp" #include "4C_linalg_fixedsizematrix.hpp" #include "4C_linalg_fixedsizematrix_generators.hpp" @@ -21,6 +22,8 @@ #include "4C_utils_enum.hpp" #include "4C_utils_exceptions.hpp" +#include +#include #include #include #include @@ -155,6 +158,40 @@ namespace return out_matrix; } + + //! calculates the starting point for the Adaptive Estimate Interpolation based on the equivalent + //! stress of the previous solution between its both predictors + double calculate_equiv_stress_starting_point( + const AEI::InputEquivStressStartingPoint& input_equiv_stress_starting_point) + { + // set to elastic predictor if the stress of the elastic predictor is numerically 0.0 -> + // this is theoretically + // possible for viscoplastic laws without yield surfaces, which may exhibit plastic flow + // even in this case; however, the determination of the starting point requires dividing + // over this stress value, which will not be possible in this specific case. + // Same goes for the case where the elastic predictor and the plastic predictor are + // associated with effectively the same stress value (e.g., during stress relaxation) -> set + // starting point as elastic predictor in these particular cases + if (input_equiv_stress_starting_point.equiv_stress_elast_pred <= 1.0e-12 || + std::abs(input_equiv_stress_starting_point.equiv_stress_plast_pred - + input_equiv_stress_starting_point.equiv_stress_elast_pred) / + input_equiv_stress_starting_point.equiv_stress_elast_pred < + 1.0e-8) + { + return ELASTIC_PREDICTOR_LOCATION; + } + + + // compute starting point based on the equivalent stress: we clamp between the elastic and + // plastic predictors because in some special cases such as stress relaxation, the starting + // point may be slightly out of this interval (machine precision) + return std::clamp((input_equiv_stress_starting_point.equiv_stress_solution - + input_equiv_stress_starting_point.equiv_stress_elast_pred) / + (input_equiv_stress_starting_point.equiv_stress_plast_pred - + input_equiv_stress_starting_point.equiv_stress_elast_pred), + ELASTIC_PREDICTOR_LOCATION, PLASTIC_PREDICTOR_LOCATION); + } + } // namespace @@ -944,4 +981,257 @@ void AEI::InterpolationPointContainer::reset_bounds_and_current_interp_point() upper_interp_bound = PLASTIC_PREDICTOR_LOCATION; } + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +AEI::AEIManager::AEIManager(const AEI::AEIParams& aei_params) : params_(aei_params) +{ + // initialize class variables + num_plastic_pred_construct_iters_ = 0; + num_estimate_interp_iters_ = 0; + num_reestimations_ = 0; + interpolation_point_containers_.resize( + 1, InterpolationPointContainer(aei_params.estimate_interpolation)); + predictor_interpolators_.resize(1); +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::AEIManager::resize(const unsigned int num_gp) +{ + FOUR_C_ASSERT(!resize_called_, + "You already called resize for the adaptive estimate interpolation manager! You attempt to " + "set it to {}", + num_gp); + + interpolation_point_containers_.resize(num_gp, interpolation_point_containers_[0]); + predictor_interpolators_.resize(num_gp, predictor_interpolators_[0]); + + resize_called_ = true; +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::AEIManager::reset_and_construct_prelim_plastic_pred( + const unsigned int gp, const LocalIntegrationInput& local_integration_input) +{ + // reset tracking variables + num_plastic_pred_construct_iters_ = 0; + num_estimate_interp_iters_ = 0; + num_reestimations_ = 0; + interpolation_point_containers_[gp].reset_bounds_and_current_interp_point(); + + // construct the preliminary predictor + predictor_interpolators_[gp].construct_prelim_plastic_pred( + local_integration_input.elastic_predictor_elastic_defgrad, + params_.elastic_predictor_zero_component_threshold, params_.plastic_predictor_construction); +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::AEIManager::pack(Core::Communication::PackBuffer& data) const +{ + // pack number of Gauss points + Core::Communication::add_to_pack(data, interpolation_point_containers_.size()); + + // pack starting points + for (const auto& interp_point_container : interpolation_point_containers_) + { + Core::Communication::add_to_pack(data, interp_point_container.starting_point); + } + Core::Communication::add_to_pack(data, resize_called_); +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::AEIManager::unpack(Core::Communication::UnpackBuffer& buffer) +{ + // unpack number of Gauss points + std::size_t num_gp; + Core::Communication::extract_from_pack(buffer, num_gp); + + // create interpolation point containers and predictor interpolators according to the number of + // Gauss points; for the interpolation point containers, also extract the respective starting + // point from the buffer + interpolation_point_containers_.resize( + num_gp, InterpolationPointContainer(params_.estimate_interpolation)); + predictor_interpolators_.resize(num_gp); + for (unsigned int gp = 0; gp < num_gp; ++gp) + { + Core::Communication::extract_from_pack( + buffer, interpolation_point_containers_[gp].starting_point); + } + Core::Communication::extract_from_pack(buffer, resize_called_); +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +Core::LinAlg::Matrix<3, 3> AEI::AEIManager::interpolate_inverse_inelastic_defgrad( + const unsigned int gp, const Core::LinAlg::Matrix<3, 3>& inv_defgrad) const +{ + Core::LinAlg::Matrix<3, 3> interp_elastic_defgrad = + predictor_interpolators_[gp].interpolate_elastic_defgrad( + interpolation_point_containers_[gp].current_interp_point); + + Core::LinAlg::Matrix<3, 3> inv_inelastic_defgrad{Core::LinAlg::Initialization::zero}; + inv_inelastic_defgrad.multiply(1.0, inv_defgrad, interp_elastic_defgrad); + + return inv_inelastic_defgrad; +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +Core::LinAlg::Matrix<3, 3> AEI::AEIManager::get_inverse_inelastic_defgrad_plastic_pred( + const unsigned int gp, const Core::LinAlg::Matrix<3, 3>& inv_defgrad) const +{ + // the plastic predictor lies at the location 1.0 + Core::LinAlg::Matrix<3, 3> interp_elastic_defgrad = + predictor_interpolators_[gp].interpolate_elastic_defgrad(1.0); + + Core::LinAlg::Matrix<3, 3> inv_inelastic_defgrad{Core::LinAlg::Initialization::zero}; + inv_inelastic_defgrad.multiply(1.0, inv_defgrad, interp_elastic_defgrad); + + return inv_inelastic_defgrad; +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::AEIManager::update_plastic_predictor_after_construction_algo(const unsigned int gp) +{ + // update the plastic predictor quantities + predictor_interpolators_[gp].update_plastic_predictor_after_construction_algo( + interpolation_point_containers_[gp].current_interp_point); + + // reset the interpolation point container + interpolation_point_containers_[gp].reset_bounds_and_current_interp_point(); +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::AEIManager::adapt_interpolation_interval( + const unsigned int gp, const InterpolationIntervalShift& interval_shift) +{ + switch (interval_shift) + { + case InterpolationIntervalShift::towards_elastic_pred: + { + interpolation_point_containers_[gp].upper_interp_bound = + interpolation_point_containers_[gp].current_interp_point; + break; + } + case InterpolationIntervalShift::towards_plastic_pred: + { + interpolation_point_containers_[gp].lower_interp_bound = + interpolation_point_containers_[gp].current_interp_point; + break; + } + default: + { + FOUR_C_THROW( + "You should not be here in the interpolation routine! The shift direction {} is not " + "supported!", + EnumTools::enum_name(interval_shift)); + } + } +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::AEIManager::set_current_interp_point( + const unsigned int gp, const CurrentInterpPointPreset preset) +{ + FOUR_C_ASSERT(gp < interpolation_point_containers_.size(), "GP index out of range"); + switch (preset) + { + case CurrentInterpPointPreset::plastic_pred_construct_update: + { + interpolation_point_containers_[gp].current_interp_point = + interpolation_point_containers_[gp].lower_interp_bound + + params_.plastic_predictor_construction.interval_scanning_param * + (interpolation_point_containers_[gp].upper_interp_bound - + interpolation_point_containers_[gp].lower_interp_bound); + return; + } + case CurrentInterpPointPreset::estimate_interpolation_update: + { + interpolation_point_containers_[gp].current_interp_point = + interpolation_point_containers_[gp].lower_interp_bound + + params_.estimate_interpolation.interval_scanning_param * + (interpolation_point_containers_[gp].upper_interp_bound - + interpolation_point_containers_[gp].lower_interp_bound); + return; + } + case CurrentInterpPointPreset::lower_interp_bound: + { + interpolation_point_containers_[gp].current_interp_point = + interpolation_point_containers_[gp].lower_interp_bound; + return; + } + case CurrentInterpPointPreset::upper_interp_bound: + { + interpolation_point_containers_[gp].current_interp_point = + interpolation_point_containers_[gp].upper_interp_bound; + return; + } + case CurrentInterpPointPreset::elastic_predictor: + { + interpolation_point_containers_[gp].current_interp_point = ELASTIC_PREDICTOR_LOCATION; + return; + } + case CurrentInterpPointPreset::plastic_predictor: + { + interpolation_point_containers_[gp].current_interp_point = PLASTIC_PREDICTOR_LOCATION; + return; + } + case CurrentInterpPointPreset::starting_point: + { + interpolation_point_containers_[gp].current_interp_point = + interpolation_point_containers_[gp].starting_point; + return; + } + case CurrentInterpPointPreset::intermediate_point: + { + interpolation_point_containers_[gp].current_interp_point = + interpolation_point_containers_[gp].lower_interp_bound + + params_.reestimation.interval_scanning_param * + (interpolation_point_containers_[gp].current_interp_point - + interpolation_point_containers_[gp].lower_interp_bound); + return; + } + default: + FOUR_C_THROW( + "Unsupported current interpolation point preset {}", EnumTools::enum_name(preset)); + } +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::AEIManager::set_user_starting_point(const unsigned gp) +{ + FOUR_C_ASSERT(gp < interpolation_point_containers_.size(), "GP index out of range"); + FOUR_C_ASSERT_ALWAYS( + params_.estimate_interpolation.starting_point_type == AEI::StartingPointType::constant, + "Setter should only be called for user-set starting points, not for {}", + EnumTools::enum_name(params_.estimate_interpolation.starting_point_type)); + + + interpolation_point_containers_[gp].starting_point = + params_.estimate_interpolation.user_set_starting_point; +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void AEI::AEIManager::set_stress_based_starting_point( + const unsigned gp, InputEquivStressStartingPoint input_equiv_stress_starting_point) +{ + FOUR_C_ASSERT(gp < interpolation_point_containers_.size(), "GP index out of range"); + FOUR_C_ASSERT_ALWAYS(params_.estimate_interpolation.starting_point_type == + AEI::StartingPointType::equiv_stress_history, + "Setter should only be called for stress-based starting points, not for {}", + EnumTools::enum_name(params_.estimate_interpolation.starting_point_type)); + + interpolation_point_containers_[gp].starting_point = + calculate_equiv_stress_starting_point(input_equiv_stress_starting_point); +} + FOUR_C_NAMESPACE_CLOSE diff --git a/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp b/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp index ac2eacd8f69..6fbf366f22c 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp @@ -1242,6 +1242,23 @@ namespace Mat ReestimationParams reestimation; }; + //! struct: input for the interpolation point determination based on the equivalent + //! stress of the previous solution between both predictors (I_HIST method from paper: + //! $\hat{\xi}_{n+1} = \text{min}[1, \text{max}(\frac{\overline{\sigma}_n - + //! \overline{\sigma}_n^{\text{E}}}{\overline{\sigma}_{n}^{\text{P}} - + //! \overline{\sigma}_{n}^{\text{E}}},0)]$) + struct InputEquivStressStartingPoint + { + //! equivalent stress of the solution: \f$ \overline{\sigma}_{n} \f$ + double equiv_stress_solution; + + //! equivalent stress of the elastic predictor: \f$ \overline{\sigma}_{n}^{\text{E}} \f$ + double equiv_stress_elast_pred; + + //! equivalent stress of the plastic predictor: \f$ \overline{\sigma}_{n}^{\text{P}} \f$ + double equiv_stress_plast_pred; + }; + //! Interpolator of elastic deformation gradients between two predictor states: between the //! elastic predictor and the preliminary plastic predictor (during plastic predictor //! construction), or between the elastic predictor and the plastic predictor (estimate @@ -1380,6 +1397,260 @@ namespace Mat //! starting point for interpolation \f$ \hat{\xi} \f$ double starting_point; }; + + //! Shift direction for the interpolation intervals + enum class InterpolationIntervalShift : std::uint8_t + { + towards_elastic_pred, ///< shift towards the elastic predictor (e.g., in case of + ///< vanishing plastic strain increments) + towards_plastic_pred, ///< shift towards the plastic predictor (e.g., in case of + ///< overflow errors due to high overstresses) + }; + + /// Types of interpolation points / bounds which can be used to set the current interpolation + /// point + enum class CurrentInterpPointPreset : std::uint8_t + { + plastic_pred_construct_update, ///< update current interpolation point between the lower + ///< and upper bound for the plastic predictor + ///< construction: + ///< (\f$ + ///< \tau \gets \tau_{\text{E}} + s \, \left( + ///< \tau_{\text{P}} - \tau_{\text{E}} + ///< \right) \f$) + estimate_interpolation_update, ///< update current interpolation point between the + ///< lower and upper bound for the estimate interpolation + ///< between predictors: + ///< (\f$ + ///< \xi \gets \xi_{\text{E}} + s \, \left( + ///< \xi_{\text{P}} - \xi_{\text{E}} + ///< \right) \f$) + lower_interp_bound, ///< shift towards elastic predictor (\f$ \xi \gets \xi_{\text{E}} \f$) + upper_interp_bound, ///< shift towards plastic predictor (\f$ \xi \gets \xi_{\text{P}} \f$) + elastic_predictor, ///< elastic predictor (\f$ \xi \gets 0.0 \f$) + plastic_predictor, ///< plastic predictor (\f$ \xi \gets 1.0 \f$) + starting_point, ///< starting point (\f$ \xi \gets \hat{\xi} \f$) + intermediate_point ///< intermediate point between lower bound and current interpolation + ///< point: + ///< (\f$ + ///< \xi \gets \xi_{\text{E}} + s \, \left( + ///< \xi - \xi_{\text{E}} + ///< \right) \f$) + }; + + //! class: manager for the Adaptive Estimate Interpolation (AEI) algorithm across all Gauss + //! points + class AEIManager + { + public: + AEIManager() = delete; + + /*! + * @brief Constructor + * + * @param[in] aei_params Adaptive Estimate Interpolation parameters + */ + explicit AEIManager(const AEIParams& aei_params); + + //! resize method: set the correct number of Gauss Points + void resize(unsigned int num_gp); + + //! get info as string + [[nodiscard]] std::string get_info(const unsigned int gp) const + { + std::string out; + out += "\nAdaptive estimate interpolation info: \n"; + out += std::format( + "number of plastic predictor construction iterations: {} / {}, number of estimate " + "interpolation iterations: {} / {}, number of re-estimations: {} / {}, interpolation " + "interval: [{}, {}], " + "current interpolation point: {} \n", + num_plastic_pred_construct_iters_, params_.plastic_predictor_construction.max_iter, + num_estimate_interp_iters_, params_.estimate_interpolation.max_iter, + num_reestimations_, params_.reestimation.max_num_reestimations, + lower_interp_bound(gp), upper_interp_bound(gp), current_interp_point(gp)); + return out; + }; + + + /*! + * @brief Verify whether plastic predictor construction is still possible, based on the set + * maximum number of iterations + * + * + */ + [[nodiscard]] bool is_plastic_pred_construct_possible() const + { + return ( + num_plastic_pred_construct_iters_ <= params_.plastic_predictor_construction.max_iter); + }; + + /*! + * @brief Verify whether estimate interpolation is still possible, based on the set maximum + * number of interpolation iterations + * + */ + [[nodiscard]] bool is_estimate_interp_possible() const + { + return (num_estimate_interp_iters_ <= params_.estimate_interpolation.max_iter); + }; + + /*! + * @brief Verify whether re-estimations are still possible, based on the + * set maximum number of re-estimations + * + */ + [[nodiscard]] bool is_reestimation_possible() const + { + return (num_reestimations_ <= params_.reestimation.max_num_reestimations); + }; + + /*! + * @brief Reset tasks and construction of the preliminary plastic + * predictor at a given Gauss point + * + * @param[in] gp Gauss point index + * @param[in] local_integration_input input data used for local time integration + */ + void reset_and_construct_prelim_plastic_pred( + unsigned int gp, const LocalIntegrationInput& local_integration_input); + + + //! pack method + void pack(Core::Communication::PackBuffer& data) const; + + //! unpack method + void unpack(Core::Communication::UnpackBuffer& buffer); + + /*! + * @brief Interpolate the inverse inelastic deformation gradient required by the + * viscoplastic material. + * + * @note The interpolation takes place between the elastic deformation gradients + * associated with the elastic and the plastic predictors at the current + * interpolation point saved internally. + * + * + * @param[in] gp Gauss point index + * @param[in] inv_defgrad inverse deformation gradient + */ + [[nodiscard]] Core::LinAlg::Matrix<3, 3> interpolate_inverse_inelastic_defgrad( + unsigned int gp, const Core::LinAlg::Matrix<3, 3>& inv_defgrad) const; + + /*! + * Retrieves the inverse inelastic deformation gradient associated with the plastic + * predictor, via interpolation using \f$ \xi = 1.0 \f$, at the specified Gauss point + * + * @param[in] gp Gauss point index + * @param[in] inv_defgrad inverse deformation gradient + */ + [[nodiscard]] Core::LinAlg::Matrix<3, 3> get_inverse_inelastic_defgrad_plastic_pred( + unsigned int gp, const Core::LinAlg::Matrix<3, 3>& inv_defgrad) const; + + /*! + * @brief Updates the plastic predictor quantities based on the current interpolation point; + * then resets the interpolation point container consistently, at the specified Gauss point + * + * @param[in] gp Gauss point + */ + void update_plastic_predictor_after_construction_algo(unsigned int gp); + + /*! + * @brief Adapt interpolation / construction intervals \f$ \left[\xi_{\mathrm{E}}, + * \xi_{\mathrm{P}} \right] \f$ based on evaluation error + * + * @param[in] gp Gauss point + * @param[in] interval_shift interval shift direction + */ + void adapt_interpolation_interval( + unsigned int gp, const InterpolationIntervalShift& interval_shift); + + //! get current interpolation point at a specified Gauss point + [[nodiscard]] double current_interp_point(unsigned int gp) const + { + FOUR_C_ASSERT(gp < interpolation_point_containers_.size(), "GP index out of range"); + return interpolation_point_containers_[gp].current_interp_point; + } + + //! set current interpolation point at the specified Gauss point using a given preset + void set_current_interp_point(unsigned int gp, CurrentInterpPointPreset preset); + + //! get lower interpolation bound at the specified Gauss point + [[nodiscard]] double lower_interp_bound(unsigned int gp) const + { + FOUR_C_ASSERT(gp < interpolation_point_containers_.size(), "GP index out of range"); + return interpolation_point_containers_[gp].lower_interp_bound; + } + + //! get upper interpolation bound at the specified Gauss point + [[nodiscard]] double upper_interp_bound(unsigned int gp) const + { + FOUR_C_ASSERT(gp < interpolation_point_containers_.size(), "GP index out of range"); + return interpolation_point_containers_[gp].upper_interp_bound; + } + + //! get starting point at the specified Gauss point + [[nodiscard]] double starting_point(unsigned int gp) const + { + FOUR_C_ASSERT(gp < interpolation_point_containers_.size(), "GP index out of range"); + return interpolation_point_containers_[gp].starting_point; + } + + //! set starting point at a specified Gauss point to the user-set value + void set_user_starting_point(unsigned int gp); + + //! set starting point at a specified Gauss point based on the equivalent stress from the + //! previous solution (see I_HIST method from the paper) + void set_stress_based_starting_point( + unsigned int gp, InputEquivStressStartingPoint input_equiv_stress_starting_point); + + //! increment number of re-estimations + void increment_num_reestimations() { ++num_reestimations_; } + + //! disable further re-estimations + void disable_further_reestimations() + { + num_reestimations_ = params_.reestimation.max_num_reestimations + 1; + } + + //! reset number of estimate interpolation iterations + void reset_num_estimate_interp_iters() { num_estimate_interp_iters_ = 0; } + + //! increment number of estimate interpolation iterations + void increment_num_estimate_interp_iters() { ++num_estimate_interp_iters_; } + + //! reset number of plastic predictor construction iterations + void reset_num_plastic_pred_construct_iters() { num_plastic_pred_construct_iters_ = 0; } + + //! increment number of plastic predictor construction iterations + void increment_num_plastic_pred_construct_iters() { ++num_plastic_pred_construct_iters_; } + + private: + //! Adaptive Estimate Interpolation parameters + const AEIParams params_; + + //! tracks whether the resizing function has been called, to set the current number of + //! Gauss points exactly once! + bool resize_called_{false}; + + //! current number of plastic predictor construction iterations at the currently evaluated + //! Gauss point + int num_plastic_pred_construct_iters_; + + //! current number of estimation interpolation iterations at the currently evaluated Gauss + //! point + int num_estimate_interp_iters_; + + //! current number of re-estimations at the currently evaluated Gauss point + int num_reestimations_; + + //! containers of interpolation points / bounds (vector over all Gauss points) + std::vector interpolation_point_containers_; + + //! predictor interpolators containing data and interpolation logic for the elastic and + //! plastic predictors (vector over all Gauss points) + std::vector predictor_interpolators_; + }; } // namespace AdaptiveEstimateInterpolation } // namespace InelasticDefgradTransvIsotropElastViscoplastUtils diff --git a/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp b/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp index 8dfc1f6cc95..ce62f8f3d65 100644 --- a/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp +++ b/unittests/mat/4C_inelastic_defgrad_factors_service_test.cpp @@ -738,4 +738,360 @@ namespace EXPECT_EQ(interp_point_container.upper_interp_bound, 1.0); } + /// tests the bookkeeping of iterations / re-estimations within the Adaptive Estimate + /// Interpolation manager + TEST_F(InelasticDefgradFactorsServiceTest, TestAdaptiveEstimateInterpolationManagerBookkeeping) + { + // consider a single Gauss point + const unsigned int gp = 0; + + // setup Adaptive Estimate Interpolation parameters + AEI::AEIParams aei_params = InelasticDefgradFactorsTestUtils::set_up_aei_params(); + aei_params.plastic_predictor_construction.max_iter = 1; + aei_params.estimate_interpolation.max_iter = 1; + aei_params.reestimation.max_num_reestimations = 1; + + // setup manager + AEI::AEIManager aei_manager(aei_params); + + // setup deformation tensors + Core::LinAlg::Matrix<3, 3> defgrad{Core::LinAlg::Initialization::zero}; + defgrad(0, 0) = 2.0; + defgrad(1, 1) = 1.0; + defgrad(2, 2) = 1.0; + Core::LinAlg::Matrix<3, 3> last_inv_inelastic_defgrad{Core::LinAlg::Initialization::zero}; + last_inv_inelastic_defgrad(0, 0) = 1.0; + last_inv_inelastic_defgrad(1, 1) = 1.0; + last_inv_inelastic_defgrad(2, 2) = 1.0; + // setup dummy temperature, last plastic strain and timestep + const double temperature = 293.15; + const double last_plastic_strain = 0.0; + const double timestep = 0.1; + + + // determine local integration input, in particular the elastic predictor + auto local_integration_input = ViscoplastUtils::LocalIntegrationInput{{.defgrad = defgrad, + .temperature = temperature, + .last_inv_inelastic_defgrad = last_inv_inelastic_defgrad, + .last_plastic_strain = last_plastic_strain, + .step = timestep}}; + + // test bookkeeping for plastic predictor construction iterations + aei_manager.reset_and_construct_prelim_plastic_pred(gp, local_integration_input); + EXPECT_TRUE(aei_manager.is_plastic_pred_construct_possible()); // 0 iterations -> true + aei_manager.increment_num_plastic_pred_construct_iters(); + EXPECT_TRUE(aei_manager.is_plastic_pred_construct_possible()); // 1 iterations -> true + aei_manager.increment_num_plastic_pred_construct_iters(); + EXPECT_FALSE(aei_manager.is_plastic_pred_construct_possible()); // 2 iterations -> false + + // test bookkeeping for estimate interpolation iterations + aei_manager.reset_and_construct_prelim_plastic_pred(gp, local_integration_input); + EXPECT_TRUE(aei_manager.is_estimate_interp_possible()); // 0 iterations -> true + aei_manager.increment_num_estimate_interp_iters(); + EXPECT_TRUE(aei_manager.is_estimate_interp_possible()); // 1 iterations -> true + aei_manager.increment_num_estimate_interp_iters(); + EXPECT_FALSE(aei_manager.is_estimate_interp_possible()); // 2 iterations -> false + + + // test bookkeeping for re-estimations + // 1. using the number of re-estimations + aei_manager.reset_and_construct_prelim_plastic_pred(gp, local_integration_input); + EXPECT_TRUE(aei_manager.is_reestimation_possible()); // 0 re-estimations -> true + aei_manager.increment_num_reestimations(); + EXPECT_TRUE(aei_manager.is_reestimation_possible()); // 1 re-estimation -> true + aei_manager.increment_num_reestimations(); + EXPECT_FALSE(aei_manager.is_reestimation_possible()); // 2 iterations -> false + + // 2. using the re-estimation disabling function + aei_manager.reset_and_construct_prelim_plastic_pred(gp, local_integration_input); + EXPECT_TRUE(aei_manager.is_reestimation_possible()); // 0 re-estimations -> true + aei_manager.disable_further_reestimations(); + EXPECT_FALSE(aei_manager.is_reestimation_possible()); // re-estimations disabled + } + + /// tests the plastic predictor construction and interpolation at different locations within the + /// Adaptive Estimate Interpolation manager + TEST_F(InelasticDefgradFactorsServiceTest, TestAdaptiveEstimateInterpolationManagerInterpolation) + { + // consider a single Gauss point + const unsigned int gp = 0; + + // setup Adaptive Estimate Interpolation parameters + manager + AEI::AEIParams aei_params = InelasticDefgradFactorsTestUtils::set_up_aei_params(); + aei_params.estimate_interpolation.starting_point_type = AEI::StartingPointType::constant; + aei_params.estimate_interpolation.user_set_starting_point = 0.1; + AEI::AEIManager aei_manager(aei_params); + + // setup deformation tensors (diagonal deformation gradient) + Core::LinAlg::Matrix<3, 3> defgrad{Core::LinAlg::Initialization::zero}; + defgrad(0, 0) = 2.0; + defgrad(1, 1) = 1.0; + defgrad(2, 2) = 1.0; + Core::LinAlg::Matrix<3, 3> last_inv_inelastic_defgrad{Core::LinAlg::Initialization::zero}; + last_inv_inelastic_defgrad(0, 0) = 1.0; + last_inv_inelastic_defgrad(1, 1) = 1.0; + last_inv_inelastic_defgrad(2, 2) = 1.0; + // setup dummy temperature, last plastic strain and timestep + const double temperature = 293.15; + const double last_plastic_strain = 0.0; + const double timestep = 0.1; + + auto local_integration_input = ViscoplastUtils::LocalIntegrationInput{{.defgrad = defgrad, + .temperature = temperature, + .last_inv_inelastic_defgrad = last_inv_inelastic_defgrad, + .last_plastic_strain = last_plastic_strain, + .step = timestep}}; + + + // construct preliminary plastic predictor, and verify endpoints + aei_manager.reset_and_construct_prelim_plastic_pred(gp, local_integration_input); + aei_manager.set_current_interp_point(gp, AEI::CurrentInterpPointPreset::elastic_predictor); + FOUR_C_EXPECT_NEAR( + aei_manager.interpolate_inverse_inelastic_defgrad(gp, local_integration_input.inv_defgrad), + last_inv_inelastic_defgrad, 1.0e-15); + + aei_manager.set_current_interp_point(gp, AEI::CurrentInterpPointPreset::plastic_predictor); + Core::LinAlg::Matrix<3, 3> elastic_defgrad_plastic_pred{Core::LinAlg::Initialization::zero}; + elastic_defgrad_plastic_pred(0, 0) = elastic_defgrad_plastic_pred(1, 1) = + elastic_defgrad_plastic_pred(2, 2) = std::pow(defgrad.determinant(), 1.0 / 3.0); + Core::LinAlg::Matrix<3, 3> inv_inelastic_defgrad_plastic_pred_ref{ + Core::LinAlg::Initialization::zero}; + inv_inelastic_defgrad_plastic_pred_ref.multiply( + 1.0, local_integration_input.inv_defgrad, elastic_defgrad_plastic_pred, 0.0); + FOUR_C_EXPECT_NEAR( + aei_manager.interpolate_inverse_inelastic_defgrad(gp, local_integration_input.inv_defgrad), + inv_inelastic_defgrad_plastic_pred_ref, + 1.0e-15); // check using the saved current interpolation point + FOUR_C_EXPECT_NEAR(aei_manager.get_inverse_inelastic_defgrad_plastic_pred( + gp, local_integration_input.inv_defgrad), + inv_inelastic_defgrad_plastic_pred_ref, + 1.0e-15); // check using the dedicated plastic predictor recovery method + + + // construct the plastic predictor between the elastic predictor and the preliminary plastic + // predictor (here: exactly in the middle based on the set interval scanning parameter: 0.5), + // and repeat the checks + aei_manager.set_current_interp_point(gp, + AEI::CurrentInterpPointPreset:: + plastic_pred_construct_update); // right in the middle of the elastic predictor and the + // preliminary plastic predictor + aei_manager.update_plastic_predictor_after_construction_algo(gp); + + aei_manager.set_current_interp_point(gp, AEI::CurrentInterpPointPreset::elastic_predictor); + FOUR_C_EXPECT_NEAR( + aei_manager.interpolate_inverse_inelastic_defgrad(gp, local_integration_input.inv_defgrad), + last_inv_inelastic_defgrad, 1.0e-15); + + aei_manager.set_current_interp_point(gp, AEI::CurrentInterpPointPreset::plastic_predictor); + elastic_defgrad_plastic_pred.clear(); + elastic_defgrad_plastic_pred(0, 0) = 1.5874010519681996; + elastic_defgrad_plastic_pred(1, 1) = 1.122462048309373; + elastic_defgrad_plastic_pred(2, 2) = 1.122462048309373; + inv_inelastic_defgrad_plastic_pred_ref.multiply( + 1.0, local_integration_input.inv_defgrad, elastic_defgrad_plastic_pred, 0.0); + FOUR_C_EXPECT_NEAR( + aei_manager.interpolate_inverse_inelastic_defgrad(gp, local_integration_input.inv_defgrad), + inv_inelastic_defgrad_plastic_pred_ref, + 1.0e-15); // check using the saved current interpolation point + FOUR_C_EXPECT_NEAR(aei_manager.get_inverse_inelastic_defgrad_plastic_pred( + gp, local_integration_input.inv_defgrad), + inv_inelastic_defgrad_plastic_pred_ref, + 1.0e-15); // check using the dedicated plastic predictor recovery method + + + // --> test further setter options for the current interpolation point + Core::LinAlg::Matrix<3, 3> interp_elastic_defgrad_ref{Core::LinAlg::Initialization::zero}; + Core::LinAlg::Matrix<3, 3> interp_inv_inelastic_defgrad_ref{Core::LinAlg::Initialization::zero}; + + + // update preset for plastic predictor construction: specified with the interval scanning + // parameter internally, based on the current interpolation bounds (here: \f$ \tau = 0.5 \f$, + // pristine bounds \f$ \tau_{\text{E}} = 0.0 \f$ and \f$ \tau_{\text{P}} = 1.0 \f$) + aei_manager.set_current_interp_point( + gp, AEI::CurrentInterpPointPreset::plastic_pred_construct_update); + interp_elastic_defgrad_ref(0, 0) = 1.7817974362806785; + interp_elastic_defgrad_ref(1, 1) = 1.0594630943592953; + interp_elastic_defgrad_ref(2, 2) = 1.0594630943592953; + interp_inv_inelastic_defgrad_ref.multiply( + 1.0, local_integration_input.inv_defgrad, interp_elastic_defgrad_ref, 0.0); + FOUR_C_EXPECT_NEAR( + aei_manager.interpolate_inverse_inelastic_defgrad(gp, local_integration_input.inv_defgrad), + interp_inv_inelastic_defgrad_ref, + 1.0e-15); // check using the saved current interpolation point + + + // update preset for estimate interpolation: specified with the interval scanning parameter + // internally, based on the current interpolation bounds (here: \f$ \xi = 0.5 \f$, pristine + // bounds \f$ \xi_{\text{E}} = 0.0 \f$ and \f$ \xi_{\text{P}} = 1.0 \f$) + aei_manager.set_current_interp_point( + gp, AEI::CurrentInterpPointPreset::estimate_interpolation_update); + interp_elastic_defgrad_ref(0, 0) = 1.7817974362806785; + interp_elastic_defgrad_ref(1, 1) = 1.0594630943592953; + interp_elastic_defgrad_ref(2, 2) = 1.0594630943592953; + interp_inv_inelastic_defgrad_ref.multiply( + 1.0, local_integration_input.inv_defgrad, interp_elastic_defgrad_ref, 0.0); + FOUR_C_EXPECT_NEAR( + aei_manager.interpolate_inverse_inelastic_defgrad(gp, local_integration_input.inv_defgrad), + interp_inv_inelastic_defgrad_ref, + 1.0e-15); // check using the saved current interpolation point + + // user-set starting point (here: \f$ \xi = 0.1 \f$) + aei_manager.set_user_starting_point(gp); + aei_manager.set_current_interp_point(gp, AEI::CurrentInterpPointPreset::starting_point); + interp_elastic_defgrad_ref(0, 0) = 1.9543199368684918; + interp_elastic_defgrad_ref(1, 1) = 1.0116194403019225; + interp_elastic_defgrad_ref(2, 2) = 1.0116194403019225; + interp_inv_inelastic_defgrad_ref.multiply( + 1.0, local_integration_input.inv_defgrad, interp_elastic_defgrad_ref, 0.0); + FOUR_C_EXPECT_NEAR( + aei_manager.interpolate_inverse_inelastic_defgrad(gp, local_integration_input.inv_defgrad), + interp_inv_inelastic_defgrad_ref, + 1.0e-15); // check using the saved current interpolation point + + // intermediate point between the lower bound (here \f$ \xi_{\text{E}} = 0.0 \f$), and the + // current interpolation point (here \f$ \xi = 0.1 \f$) because of the user-set starting + // point --> here: \f$ \xi_{\text{I}} = 0.05 \f$ + aei_manager.set_current_interp_point(gp, AEI::CurrentInterpPointPreset::intermediate_point); + interp_elastic_defgrad_ref(0, 0) = 1.9770280407057923; + interp_elastic_defgrad_ref(1, 1) = 1.0057929410678534; + interp_elastic_defgrad_ref(2, 2) = 1.0057929410678534; + interp_inv_inelastic_defgrad_ref.multiply( + 1.0, local_integration_input.inv_defgrad, interp_elastic_defgrad_ref, 0.0); + FOUR_C_EXPECT_NEAR( + aei_manager.interpolate_inverse_inelastic_defgrad(gp, local_integration_input.inv_defgrad), + interp_inv_inelastic_defgrad_ref, + 1.0e-15); // check using the saved current interpolation point + + + // we now shift towards the plastic predictor, i.e, set the lower bound as the current + // interpolation point, i.e., \f$ \xi_{\text{E}} = + // \xi_{\text{I}} = 0.05 \f$; and redo the estimate interpolation update, \f$ \xi = 0.5 \left( + // 0.05 + 1.0 \right) = 0.525 \f$ + aei_manager.adapt_interpolation_interval( + gp, AEI::InterpolationIntervalShift::towards_plastic_pred); + aei_manager.set_current_interp_point( + gp, AEI::CurrentInterpPointPreset::estimate_interpolation_update); + interp_elastic_defgrad_ref(0, 0) = 1.7715350382047212; + interp_elastic_defgrad_ref(1, 1) = 1.0625273666151527; + interp_elastic_defgrad_ref(2, 2) = 1.0625273666151527; + interp_inv_inelastic_defgrad_ref.multiply( + 1.0, local_integration_input.inv_defgrad, interp_elastic_defgrad_ref, 0.0); + FOUR_C_EXPECT_NEAR( + aei_manager.interpolate_inverse_inelastic_defgrad(gp, local_integration_input.inv_defgrad), + interp_inv_inelastic_defgrad_ref, + 1.0e-15); // check using the saved current interpolation point + + // we now shift towards the elastic predictor, i.e., set the upper bound as the current + // interpolation point: $\xi_{\text{P}} = 0.525$ and redo the estimate interpolation update, \f$ + // \xi = 0.5 \left( 0.05 + 0.525 \right) = 0.2875 \f$ + aei_manager.adapt_interpolation_interval( + gp, AEI::InterpolationIntervalShift::towards_elastic_pred); + aei_manager.set_current_interp_point( + gp, AEI::CurrentInterpPointPreset::estimate_interpolation_update); + interp_elastic_defgrad_ref(0, 0) = 1.8714631830798973; + interp_elastic_defgrad_ref(1, 1) = 1.033771021567608; + interp_elastic_defgrad_ref(2, 2) = 1.033771021567608; + interp_inv_inelastic_defgrad_ref.multiply( + 1.0, local_integration_input.inv_defgrad, interp_elastic_defgrad_ref, 0.0); + FOUR_C_EXPECT_NEAR( + aei_manager.interpolate_inverse_inelastic_defgrad(gp, local_integration_input.inv_defgrad), + interp_inv_inelastic_defgrad_ref, + 1.0e-15); // check using the saved current interpolation point + } + + + /// tests the starting point update routines of the Adaptive Estimate Interpolation manager + TEST_F(InelasticDefgradFactorsServiceTest, TestAdaptiveEstimateInterpolationManagerStartingPoints) + { + // consider a single Gauss point + const unsigned int gp = 0; + + // function: setup plastic predictor for a given aei manager, and set its current interpolation + // point <- starting point + auto construct_plastic_predictor_and_init_curr_interp_point = + [](AEI::AEIManager& input_aei_manager) + { + // setup deformation tensors (diagonal deformation gradient) + Core::LinAlg::Matrix<3, 3> defgrad{Core::LinAlg::Initialization::zero}; + defgrad(0, 0) = 2.0; + defgrad(1, 1) = 1.0; + defgrad(2, 2) = 1.0; + Core::LinAlg::Matrix<3, 3> last_inv_inelastic_defgrad{Core::LinAlg::Initialization::zero}; + last_inv_inelastic_defgrad(0, 0) = 1.0; + last_inv_inelastic_defgrad(1, 1) = 1.0; + last_inv_inelastic_defgrad(2, 2) = 1.0; + + // setup dummy temperature, last plastic strain and timestep + const double temperature = 293.15; + const double last_plastic_strain = 0.0; + const double timestep = 0.1; + + + // determine the elastic predictor via the local integration input + auto local_integration_input = ViscoplastUtils::LocalIntegrationInput{{.defgrad = defgrad, + .temperature = temperature, + .last_inv_inelastic_defgrad = last_inv_inelastic_defgrad, + .last_plastic_strain = last_plastic_strain, + .step = timestep}}; + + + // reset all interpolation points (also sets the starting point) and construct plastic + // predictor + input_aei_manager.reset_and_construct_prelim_plastic_pred(gp, local_integration_input); + }; + + // create AEI manager with set starting point + AEI::AEIParams aei_params_user_set = InelasticDefgradFactorsTestUtils::set_up_aei_params(); + aei_params_user_set.estimate_interpolation.starting_point_type = + AEI::StartingPointType::constant; + aei_params_user_set.estimate_interpolation.user_set_starting_point = 0.1; + AEI::AEIManager aei_manager_user_set(aei_params_user_set); + construct_plastic_predictor_and_init_curr_interp_point(aei_manager_user_set); + + EXPECT_EQ(aei_manager_user_set.current_interp_point(gp), 0.1); // user set starting point + aei_manager_user_set.set_user_starting_point(gp); // starting point: 0.1 + EXPECT_EQ(aei_manager_user_set.starting_point(gp), 0.1); + + + // create AEI manager with a starting point based on the evolution of the equivalent stress + AEI::AEIParams aei_params_equiv_stress_starting_point = + InelasticDefgradFactorsTestUtils::set_up_aei_params(); + aei_params_equiv_stress_starting_point.estimate_interpolation.starting_point_type = + AEI::StartingPointType::equiv_stress_history; + AEI::AEIManager aei_manager_equiv_stress_starting_point(aei_params_equiv_stress_starting_point); + construct_plastic_predictor_and_init_curr_interp_point(aei_manager_equiv_stress_starting_point); + + // test initialization of starting point at the interval scanning parameter, since no + // stress-based update has taken place yet + EXPECT_EQ(aei_manager_equiv_stress_starting_point.starting_point(gp), 0.5); + EXPECT_EQ(aei_manager_equiv_stress_starting_point.current_interp_point(gp), 0.5); + + // set starting point using stress input, and see whether this also translates to + // the current interpolation point upon initialization: first specify the stress as the + // predictor values, then an arbitrary value + aei_manager_equiv_stress_starting_point.set_stress_based_starting_point( + gp, AEI::InputEquivStressStartingPoint{.equiv_stress_solution = 10.0, + .equiv_stress_elast_pred = 10.0, + .equiv_stress_plast_pred = 0.0}); + construct_plastic_predictor_and_init_curr_interp_point(aei_manager_equiv_stress_starting_point); + EXPECT_EQ(aei_manager_equiv_stress_starting_point.starting_point(gp), 0.0); + EXPECT_EQ(aei_manager_equiv_stress_starting_point.current_interp_point(gp), 0.0); + + aei_manager_equiv_stress_starting_point.set_stress_based_starting_point( + gp, AEI::InputEquivStressStartingPoint{.equiv_stress_solution = 0.0, + .equiv_stress_elast_pred = 10.0, + .equiv_stress_plast_pred = 0.0}); + construct_plastic_predictor_and_init_curr_interp_point(aei_manager_equiv_stress_starting_point); + EXPECT_EQ(aei_manager_equiv_stress_starting_point.starting_point(gp), 1.0); + EXPECT_EQ(aei_manager_equiv_stress_starting_point.current_interp_point(gp), 1.0); + + aei_manager_equiv_stress_starting_point.set_stress_based_starting_point( + gp, AEI::InputEquivStressStartingPoint{.equiv_stress_solution = 2.5, + .equiv_stress_elast_pred = 10.0, + .equiv_stress_plast_pred = 0.0}); + construct_plastic_predictor_and_init_curr_interp_point(aei_manager_equiv_stress_starting_point); + EXPECT_EQ(aei_manager_equiv_stress_starting_point.starting_point(gp), 0.75); + EXPECT_EQ(aei_manager_equiv_stress_starting_point.current_interp_point(gp), 0.75); + } + } // namespace From d852e4cdbf8b2d46fc5d3617ec4958f4eebed5b7 Mon Sep 17 00:00:00 2001 From: Ana Dragos-Corneliu Date: Mon, 10 Aug 2026 19:21:00 +0200 Subject: [PATCH 6/7] Wire AEI to vplast. material --- src/mat/4C_mat_inelastic_defgrad_factors.cpp | 862 +++++++++++++++++- src/mat/4C_mat_inelastic_defgrad_factors.hpp | 135 ++- ..._mat_inelastic_defgrad_factors_service.hpp | 15 + .../mat/4C_inelastic_defgrad_factors_test.cpp | 283 ++++++ 4 files changed, 1278 insertions(+), 17 deletions(-) diff --git a/src/mat/4C_mat_inelastic_defgrad_factors.cpp b/src/mat/4C_mat_inelastic_defgrad_factors.cpp index fdde853187f..7b18c9172c1 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors.cpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors.cpp @@ -3255,6 +3255,13 @@ void Mat::InelasticDefgradTransvIsotropElastViscoplast::update() { for (unsigned int gp = 0; gp < num_gp_; ++gp) { + // set starting points for the following time step in the adaptive estimate interpolation, + // prior to updating the time step quantities + if (is_plastic_gp_[gp] && adaptive_estimate_interp_manager_.has_value()) + { + update_aei_starting_point(gp); + } + // update history variables for the next time step time_step_quantities_.update(gp); // reset saved number of iterations at each Gauss point within Local Newton-Raphson manager @@ -3815,7 +3822,7 @@ Core::LinAlg::Matrix<10, 1> Mat::InelasticDefgradTransvIsotropElastViscoplast::l local_integration_input, local_newton_manager_.sol(), err_status); // error management after residual evaluation - manage_evaluation(err_status, eval_action); + manage_evaluation(err_status, local_integration_input, eval_action); switch (eval_action) { case (ViscoplastUtils::EvaluationAction::continue_current_iteration): @@ -3884,7 +3891,7 @@ Core::LinAlg::Matrix<10, 1> Mat::InelasticDefgradTransvIsotropElastViscoplast::l // error management routine after the 'stuck' verification err_status = InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType:: no_convergence_local_newton; - manage_evaluation(err_status, eval_action); + manage_evaluation(err_status, local_integration_input, eval_action); switch (eval_action) { case (ViscoplastUtils::EvaluationAction::continue_current_iteration): @@ -3921,7 +3928,7 @@ Core::LinAlg::Matrix<10, 1> Mat::InelasticDefgradTransvIsotropElastViscoplast::l local_integration_input, local_newton_manager_.sol(), err_status); // error management after Jacobian evaluation - manage_evaluation(err_status, eval_action); + manage_evaluation(err_status, local_integration_input, eval_action); switch (eval_action) { @@ -3958,7 +3965,7 @@ Core::LinAlg::Matrix<10, 1> Mat::InelasticDefgradTransvIsotropElastViscoplast::l { err_status = ViscoplastUtils::ErrorType::failed_solution_linear_system_lnl; // error management after linear system solution - manage_evaluation(err_status, eval_action); + manage_evaluation(err_status, local_integration_input, eval_action); switch (eval_action) { case (ViscoplastUtils::EvaluationAction::continue_current_iteration): @@ -4171,8 +4178,9 @@ bool Mat::InelasticDefgradTransvIsotropElastViscoplast::check_elastic_predictor( // check if the predicted plastic strain rate is 0 -> for flow rules with yield functions, // this means that the predictor is correct - return (state_quantities_.curr_equiv_plastic_strain_rate * time_step_tracker_.dt <= - ViscoplastUtils::zero_plastic_strain_increment); + return (err_status == ViscoplastUtils::ErrorType::no_errors) && + (state_quantities_.curr_equiv_plastic_strain_rate * time_step_tracker_.dt <= + ViscoplastUtils::zero_plastic_strain_increment); } bool Mat::InelasticDefgradTransvIsotropElastViscoplast::halve_and_prepare_new_substep( @@ -4448,7 +4456,9 @@ Mat::HeatSource Mat::InelasticDefgradTransvIsotropElastViscoplast:: *--------------------------------------------------------------------*/ void Mat::InelasticDefgradTransvIsotropElastViscoplast::manage_evaluation( const InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status, - InelasticDefgradTransvIsotropElastViscoplastUtils::EvaluationAction& eval_action) const + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + InelasticDefgradTransvIsotropElastViscoplastUtils::EvaluationAction& eval_action) { // default evaluation action: continue iteration eval_action = InelasticDefgradTransvIsotropElastViscoplastUtils::EvaluationAction:: @@ -4461,9 +4471,39 @@ void Mat::InelasticDefgradTransvIsotropElastViscoplast::manage_evaluation( } else { - // ERROR MANAGEMENT STRATEGY 1: substepping -> just exit, and see if a new halved - // substep size is feasible - if (parameter()->use_local_substepping()) + // default strategy: re-estimation (for both one-step and substepping integration) + if (adaptive_estimate_interp_manager_.has_value()) + { + // determine updated estimate + Core::LinAlg::Matrix<10, 1> updated_estimate = + reestimate_to_restart_local_newton(local_integration_input, eval_action); + if (eval_action == ViscoplastUtils::EvaluationAction::exit_with_error) + { + // substepping as an alternative error management strategy if re-estimation does not work + if (parameter()->use_local_substepping()) + { + return; + } + // throw error + FOUR_C_THROW( + "{}", get_error_warning_info(std::format( + "The re-estimation procedure has failed! Error status: {}", err_status))); + } + + // determine increment mapping the current solution vector to the updated estimate + Core::LinAlg::Matrix<10, 1> increment_wrt_current_sol{Core::LinAlg::Initialization::zero}; + increment_wrt_current_sol.update( + 1.0, updated_estimate, -1.0, local_newton_manager_.sol(), 0.0); + + // "artificial reset" of the Local Newton--Raphson: the solution vector is set to the updated + // estimate, and the iteration counter is incremented to proceed with the next iteration + local_newton_manager_.increment_solution_vector(increment_wrt_current_sol); + local_newton_manager_.increment_iter(); + + return; + } + // in case of substepping without AEI: exit with error, and halve the substep is possible + else if (parameter()->use_local_substepping()) { eval_action = ViscoplastUtils::EvaluationAction::exit_with_error; return; @@ -4680,12 +4720,806 @@ Core::LinAlg::Matrix<10, 1> Mat::InelasticDefgradTransvIsotropElastViscoplast::determine_local_newton_init_estimate( const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& local_integration_input, - const InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) const + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) { ensure_error_free_evaluation(err_status); - // we use the elastic predictor - return wrap_unknowns(local_integration_input.elastic_predictor_inverse_plastic_defgrad, - local_integration_input.last_plastic_strain); + if (adaptive_estimate_interp_manager_.has_value()) + { + // pre-evaluate Adaptive Estimate Interpolation: importantly, reset and + // determine the preliminary plastic predictor + adaptive_estimate_interp_manager_->reset_and_construct_prelim_plastic_pred( + gp_, local_integration_input); + + // construct the plastic predictor such that its stress state lies numerically "on" the yield + // surface (slightly "under" within a given numerical tolerance) (only for yield-surface-based + // viscoplasticity formulations; for no-yield-surface formulations, we currently accept the + // preliminary plastic predictor as the plastic predictor) + if (viscoplastic_law_->uses_yield_surface()) + { + construct_plastic_predictor(local_integration_input, err_status); + + // return directly in case of error + if (err_status != ViscoplastUtils::ErrorType::no_errors) + { + return Core::LinAlg::Matrix<10, 1>{Core::LinAlg::Initialization::zero}; + } + } + + // interpolate initial estimate + return interpolate_estimate(local_integration_input, err_status); + } + else + { + // we use the elastic predictor + return wrap_unknowns(local_integration_input.elastic_predictor_inverse_plastic_defgrad, + local_integration_input.last_plastic_strain); + } +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +bool Mat::InelasticDefgradTransvIsotropElastViscoplast::exhibits_plastic_flow( + const double curr_equiv_stress, const double last_plastic_strain) const +{ + // numerical tolerance for stresses = 0.0 + const double numerical_tol = 1.0e-12; + + if (viscoplastic_law_->uses_yield_surface()) + { + return ( + viscoplastic_law_->evaluate_stress_ratio(curr_equiv_stress, last_plastic_strain) >= 1.0); + } + else + { + return (viscoplastic_law_->evaluate_stress_ratio(curr_equiv_stress, last_plastic_strain) >= + numerical_tol); + } +} + + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void Mat::InelasticDefgradTransvIsotropElastViscoplast::assert_predictor_stress_consistency( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + const double invS) const +{ + ViscoplastUtils::ErrorType err_status{ViscoplastUtils::ErrorType::no_errors}; + + // retrieve required data from the local integration input + const Core::LinAlg::Matrix<3, 3>& elastic_predictor_inverse_plastic_defgrad = + local_integration_input.elastic_predictor_inverse_plastic_defgrad; + const Core::LinAlg::Matrix<3, 3>& inv_defgrad = local_integration_input.inv_defgrad; + + + // dummy plastic strain to be used in the subsequent stress-only evaluations + const double dummy_plastic_strain = -1.0; + + // compute the relative overstress associated with the elastic predictor + ViscoplastUtils::StateQuantities state_quantities_elastic_pred = evaluate_state_quantities( + local_integration_input, elastic_predictor_inverse_plastic_defgrad, dummy_plastic_strain, + err_status, ViscoplastUtils::StateQuantityEvalType::equiv_stress_only); + // note that the evaluation may fail if large stresses are involved, but this is ok since the + // elastic predictor is assumed to have a high stress; we only perform further verifications for + // the case where this is computable + if (err_status == ViscoplastUtils::ErrorType::no_errors) + { + // ensure that the elastic predictor does not exhibit "understress" with respect to the + // specified lowest meaningful stress bound + const double relative_overstress_elastic_pred = + state_quantities_elastic_pred.curr_equiv_stress * invS - 1.0; + FOUR_C_ASSERT_ALWAYS(relative_overstress_elastic_pred >= 0.0, "{}", + get_error_warning_info( + std::format("Your elastic predictor is under the lowest meaningful threshold, " + "relative understress: " + "{}! This indicates an inconsistent lowest meaningful bound!", + relative_overstress_elastic_pred))); + } + + // compute the relative overstress (should be understress! < 0) associated with the preliminary + // plastic predictor (at this stage stored as the "plastic predictor" within the AEI manager) + err_status = InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType::no_errors; + ViscoplastUtils::StateQuantities state_quantities_prelim_plastic_pred = evaluate_state_quantities( + local_integration_input, + adaptive_estimate_interp_manager_->get_inverse_inelastic_defgrad_plastic_pred( + gp_, inv_defgrad), + dummy_plastic_strain, err_status, ViscoplastUtils::StateQuantityEvalType::equiv_stress_only); + FOUR_C_ASSERT_ALWAYS(err_status == ViscoplastUtils::ErrorType::no_errors, "{}", + get_error_warning_info("Inconsistent preliminary plastic predictor stress!" + "This should always be computable for " + "the interpolation to work")); + + // for isotropic materials, we use the von Mises equivalent stress; hence, we already know + // that the preliminary plastic predictor with scale_unit eigenvalues must exhibit \f$ + // \overline{\sigma}^{\hat{\text{P}}} = 0.0 \f$! + if (parameter()->mat_behavior() == ViscoplastUtils::MatBehavior::isotropic && + parameter() + ->adaptive_estimate_interpolation_params() + .plastic_predictor_construction.elastic_stretch_eigenval_type == + AEI::PrelimPlasticPredictor::ElasticStretchEigenvalType::scale_unit) + { + FOUR_C_ASSERT_ALWAYS(state_quantities_prelim_plastic_pred.curr_equiv_stress < 1.0e-8, "{}", + get_error_warning_info(std::format( + "You have specified isotropic material behavior and a unit scaling for the " + "eigenvalues, " + "but have received a von Mises equivalent stress of {}! This is inconsistent " + "since the " + "stress has to be 0 in this case!", + state_quantities_prelim_plastic_pred.curr_equiv_stress))); + } + else + { + const double relative_overstress_prelim_plastic_pred = + state_quantities_prelim_plastic_pred.curr_equiv_stress * invS - 1.0; + FOUR_C_ASSERT_ALWAYS(relative_overstress_prelim_plastic_pred <= 0.0, "{}", + get_error_warning_info( + std::format("Your preliminary plastic predictor is over the lowest meaningful " + "threshold, relative overstress: " + "{}! This indicates an inconsistent lowest meaningful bound!", + relative_overstress_prelim_plastic_pred))); + } +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void Mat::InelasticDefgradTransvIsotropElastViscoplast::construct_plastic_predictor( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + ViscoplastUtils::ErrorType& err_status) +{ + ensure_error_free_evaluation(err_status); + FOUR_C_ASSERT(adaptive_estimate_interp_manager_.has_value(), "{}", + get_error_warning_info(std::format("This method should not be called without initializing " + "the manager for adaptive estimate interpolation!"))); + + // determine lowest meaningful threshold $S$ (yield stress at previous timestep) + const double S = + viscoplastic_law_->compute_flow_resistance(time_step_quantities_.last_equiv_stress[gp_], + local_integration_input.last_plastic_strain, err_status); + if (err_status != ViscoplastUtils::ErrorType::no_errors) + { + // early return with error, managed eventually by substepping strategy + return; + } + FOUR_C_ASSERT_ALWAYS(std::abs(S) > 1.0e-15, + "The lowest meaningful bound stress bound should be larger than 0.0, it is currently {}", S); + const double invS = 1.0 / S; + +#ifdef FOUR_C_ENABLE_ASSERTIONS + assert_predictor_stress_consistency(local_integration_input, invS); +#endif + + // --> iterative procedure to determine the plastic predictor from the elastic and the preliminary + // plastic predictors + + // declare interpolated inverse inelastic defgrad + Core::LinAlg::Matrix<3, 3> interp_inverse_inelastic_defgrad{Core::LinAlg::Initialization::zero}; + + // procedure starts with the preliminary plastic predictor (which is currently stored as the + // "plastic predictor" for the AEI manager, internally) + adaptive_estimate_interp_manager_->set_current_interp_point( + gp_, AEI::CurrentInterpPointPreset::plastic_predictor); + + // set dummy plastic strain to be used when evaluating the interpolated stresses via + // StateQuantities + const double dummy_plastic_strain = -1.0; + + // iterative procedure to determine the plastic predictor based on the preliminary plastic + // predictor + while (true) + { + adaptive_estimate_interp_manager_->increment_num_plastic_pred_construct_iters(); + err_status = ViscoplastUtils::ErrorType::no_errors; + + // check whether iterative procedure is still possible based on the number of iterations + FOUR_C_ASSERT_ALWAYS(adaptive_estimate_interp_manager_->is_plastic_pred_construct_possible(), + "{}", + get_error_warning_info( + std::format("Plastic predictor construction has failed after {} iterations", + parameter() + ->adaptive_estimate_interpolation_params() + .plastic_predictor_construction.max_iter))); + + // interpolate inverse inelastic defgrad and compute the associated stress state + interp_inverse_inelastic_defgrad = + adaptive_estimate_interp_manager_->interpolate_inverse_inelastic_defgrad( + gp_, local_integration_input.inv_defgrad); + ViscoplastUtils::StateQuantities interp_state_quantities = evaluate_state_quantities( + local_integration_input, interp_inverse_inelastic_defgrad, dummy_plastic_strain, err_status, + ViscoplastUtils::StateQuantityEvalType::equiv_stress_only); + if (err_status == InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType::no_errors) + { + // compute and verify relative overstress + const double relative_overstress_interp = + interp_state_quantities.curr_equiv_stress * invS - 1.0; + + // we only break out if the plastic predictor stress condition is fulfilled + if (relative_overstress_interp <= 0.0 && + -parameter() + ->adaptive_estimate_interpolation_params() + .plastic_predictor_construction.relative_understress_tol <= + relative_overstress_interp) + { + // we update the plastic predictor now and break out of the loop + adaptive_estimate_interp_manager_->update_plastic_predictor_after_construction_algo(gp_); + + break; + } + else if (relative_overstress_interp < + -parameter() + ->adaptive_estimate_interpolation_params() + .plastic_predictor_construction.relative_understress_tol) + { + // we shift towards the elastic predictor + adaptive_estimate_interp_manager_->adapt_interpolation_interval( + gp_, AEI::InterpolationIntervalShift::towards_elastic_pred); + adaptive_estimate_interp_manager_->set_current_interp_point( + gp_, AEI::CurrentInterpPointPreset::plastic_pred_construct_update); + } + else + { + // we shift towards the preliminary plastic predictor + adaptive_estimate_interp_manager_->adapt_interpolation_interval( + gp_, AEI::InterpolationIntervalShift::towards_plastic_pred); + adaptive_estimate_interp_manager_->set_current_interp_point( + gp_, AEI::CurrentInterpPointPreset::plastic_pred_construct_update); + } + } + else + { + // ensure that this can only be an overflow error, because we have only evaluated the stress + // and not the plastic strain rate at this stage + FOUR_C_ASSERT(err_status == ViscoplastUtils::ErrorType::overflow_error, + "This should not be an {} error, but an overflow error!", err_status); + + // shift interpolation interval towards the plastic predictor; update current interpolation + // point + adaptive_estimate_interp_manager_->adapt_interpolation_interval( + gp_, AEI::InterpolationIntervalShift::towards_plastic_pred); + adaptive_estimate_interp_manager_->set_current_interp_point( + gp_, AEI::CurrentInterpPointPreset::plastic_pred_construct_update); + } + } +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +double Mat::InelasticDefgradTransvIsotropElastViscoplast::integrate_plastic_strain( + const AEI::InputHardeningIntegration& integration_input, + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) const +{ + ensure_error_free_evaluation(err_status); + FOUR_C_ASSERT(adaptive_estimate_interp_manager_.has_value(), "{}", + get_error_warning_info(std::format("This method should not be called without initializing " + "the manager for adaptive estimate interpolation"))); + + const AEI::HardeningParams& hardening_params = + parameter()->adaptive_estimate_interpolation_params().hardening; + + FOUR_C_ASSERT( + hardening_params.method == AEI::HardeningManagementMethod::integrate_via_evolution_equations, + "{}", + get_error_warning_info( + std::format("This method should only be called if the hardening integration method is " + "'integrate_via_evol_eqs'! The current method is {}", + parameter()->adaptive_estimate_interpolation_params().hardening.method))); + + + // auxiliaries + InelasticDefgradTransvIsotropElastViscoplastUtils::PlasticStrainRateDerivs + plastic_strain_rate_derivs; + + // set initial estimate as the previous plastic strain + double plastic_strain = integration_input.last_plastic_strain; + + // initialize iteration counter + int iter = 0; + + // initialize quantities involved in the hardening integration with dummy values + double plastic_strain_rate = 1.0e10; + double deriv_plastic_strain_rate = 1.0e10; + double residual = 1.0e10; + double jacobian = 1.0e10; + + // Newton-Raphson loop for hardening integration + while (true) + { + // increment iterations + ++iter; + + + // check whether the maximum number of iterations was exceeded + if (iter > parameter()->adaptive_estimate_interpolation_params().hardening.max_iter_integration) + { + // mark artificially with "overflow_error", we want to shift + // towards the plastic predictor in the next estimate interpolation iteration (although in the + // current implementation it does not really matter what type of error we set here, the shift + // will happen anyway) + err_status = ViscoplastUtils::ErrorType::overflow_error; + return -1; + } + + // compute plastic strain rate from the viscoplasticity law + plastic_strain_rate = viscoplastic_law_->evaluate_plastic_strain_rate( + integration_input.interp_equiv_stress, plastic_strain, integration_input.step, err_status); + // return directly when encountering error -> this will be handled by the estimate + // interpolation procedure + if (err_status != ViscoplastUtils::ErrorType::no_errors) return -1; + + // compute residual + residual = plastic_strain - integration_input.last_plastic_strain - + integration_input.step * plastic_strain_rate; + + // return solution if converged + if (std::abs(residual) <= hardening_params.tol_integration) + { + return plastic_strain; + } + + // compute derivative of the plastic strain rate w.r.t. plastic + // strain + plastic_strain_rate_derivs = viscoplastic_law_->evaluate_derivatives_of_plastic_strain_rate( + integration_input.interp_equiv_stress, plastic_strain, integration_input.step, err_status); + deriv_plastic_strain_rate = plastic_strain_rate_derivs.deriv_plastic_strain; + + // return directly when encountering overflow error -> this will be handled by the estimate + // interpolation directly + if (err_status != ViscoplastUtils::ErrorType::no_errors) return -1; + + // compute jacobian and verify that it is non-zero + jacobian = 1.0 - integration_input.step * deriv_plastic_strain_rate; + if (std::abs(jacobian) <= 1.0e-12) + { + // mark artificially with "overflow_error", we want to shift + // towards the plastic predictor in the next estimate interpolation iteration (although in the + // current implementation it does not really matter what type of error we set here, the shift + // will happen anyway) + err_status = ViscoplastUtils::ErrorType::overflow_error; + return -1; + } + + // update solution + plastic_strain -= residual / jacobian; + } +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +ViscoplastUtils::ErrorType +Mat::InelasticDefgradTransvIsotropElastViscoplast::verify_estimate_candidate( + const Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + const Core::LinAlg::Matrix<3, 3>& iFin_candidate, const double plastic_strain_candidate) +{ + // initialize output + ViscoplastUtils::ErrorType err_status{ViscoplastUtils::ErrorType::no_errors}; + + // evaluate the candidate state + state_quantities_ = evaluate_state_quantities(local_integration_input, iFin_candidate, + plastic_strain_candidate, err_status, ViscoplastUtils::StateQuantityEvalType::full_eval); + if (err_status != ViscoplastUtils::ErrorType::no_errors) return err_status; + + // evaluate the candidate state linearization + state_quantity_derivatives_ = evaluate_state_quantity_derivatives(local_integration_input, + iFin_candidate, plastic_strain_candidate, err_status, + ViscoplastUtils::StateQuantityDerivEvalType::full_eval, false); + + return err_status; +} + + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +Core::LinAlg::Matrix<10, 1> Mat::InelasticDefgradTransvIsotropElastViscoplast::interpolate_estimate( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) +{ + ensure_error_free_evaluation(err_status); + FOUR_C_ASSERT(adaptive_estimate_interp_manager_.has_value(), "{}", + get_error_warning_info(std::format("This method should not be called without initializing " + "the manager for adaptive estimate interpolation!"))); + + // retrieve required data from the local integration input + const Core::LinAlg::Matrix<3, 3>& elastic_predictor_inverse_plastic_defgrad = + local_integration_input.elastic_predictor_inverse_plastic_defgrad; + const Core::LinAlg::Matrix<3, 3>& inv_defgrad = local_integration_input.inv_defgrad; + const double last_plastic_strain = local_integration_input.last_plastic_strain; + const double step = local_integration_input.step; + + // set numerical threshold for verifying numerical 0.0 + const double numerical_tol = 1.0e-10; + + // declare interpolated estimate components for the inverse plastic defgrad and + // the plastic strain + Core::LinAlg::Matrix<3, 3> interp_iFin{Core::LinAlg::Initialization::zero}; + double interp_plastic_strain{0.0}; + + // loop until the interpolated estimate candidate is also a valid Local Newton estimate + while (true) + { + adaptive_estimate_interp_manager_->increment_num_estimate_interp_iters(); + + // check whether estimate interpolation is still possible + FOUR_C_ASSERT_ALWAYS(adaptive_estimate_interp_manager_->is_estimate_interp_possible(), "{}", + get_error_warning_info(std::format( + "Could not interpolate initial / updated estimate according to the Adaptive Estimate " + "Interpolation algorithm: {}", + err_status))); + err_status = ViscoplastUtils::ErrorType::no_errors; + + // interpolate inverse plastic deformation gradient with the current interpolation point + // saved within the dedicated manager + if (adaptive_estimate_interp_manager_->current_interp_point(gp_) < numerical_tol) + { + interp_iFin = + elastic_predictor_inverse_plastic_defgrad; // return exactly the elastic predictor, + // since interpolating with + // preconditioned matrices can lead to + // (slight) deviations from the elastic + // predictor -> could also lead to the + // "interpolated elastic predictor" not + // exhibiting plastic flow during stress + // relaxation, for example! + } + else + { + interp_iFin = adaptive_estimate_interp_manager_->interpolate_inverse_inelastic_defgrad( + gp_, inv_defgrad); + } + + // compute equivalent stress related to the interpolated inverse plastic deformation + // gradient + ViscoplastUtils::StateQuantities state_quantities_stress_only = + evaluate_state_quantities(local_integration_input, interp_iFin, -1.0, err_status, + ViscoplastUtils::StateQuantityEvalType::equiv_stress_only); + if (err_status == ViscoplastUtils::ErrorType::no_errors) + { + // detect possible "under the yield surface" error state, and shift interpolation accordingly + // towards the elastic predictor + if (!exhibits_plastic_flow( + state_quantities_stress_only.curr_equiv_stress, last_plastic_strain)) + { + adaptive_estimate_interp_manager_->adapt_interpolation_interval( + gp_, AEI::InterpolationIntervalShift::towards_elastic_pred); + adaptive_estimate_interp_manager_->set_current_interp_point( + gp_, AEI::CurrentInterpPointPreset::estimate_interpolation_update); + continue; + } + } + else + { + // shift towards plastic predictor if error is encountered + adaptive_estimate_interp_manager_->adapt_interpolation_interval( + gp_, AEI::InterpolationIntervalShift::towards_plastic_pred); + adaptive_estimate_interp_manager_->set_current_interp_point( + gp_, AEI::CurrentInterpPointPreset::estimate_interpolation_update); + continue; + } + + // get plastic strain for estimate candidate + switch (parameter()->adaptive_estimate_interpolation_params().hardening.method) + { + case AEI::HardeningManagementMethod::use_previous: + { + interp_plastic_strain = last_plastic_strain; + break; + } + case AEI::HardeningManagementMethod::integrate_via_evolution_equations: + { + interp_plastic_strain = integrate_plastic_strain( + AEI::InputHardeningIntegration{ + .interp_equiv_stress = state_quantities_stress_only.curr_equiv_stress, + .last_plastic_strain = last_plastic_strain, + .step = step}, + err_status); + + // shift towards the plastic predictor if integration fails + if (err_status != InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType::no_errors) + { + adaptive_estimate_interp_manager_->adapt_interpolation_interval( + gp_, AEI::InterpolationIntervalShift::towards_plastic_pred); + adaptive_estimate_interp_manager_->set_current_interp_point( + gp_, AEI::CurrentInterpPointPreset::estimate_interpolation_update); + continue; + } + + break; + } + default: + { + FOUR_C_THROW("{}", + get_error_warning_info( + std::format("Unsupported hardening method {} for adaptive estimate interpolation!", + parameter()->adaptive_estimate_interpolation_params().hardening.method))); + } + } + + // if we have reached this point, then we have a viable estimate candidate; we now verify it + err_status = + verify_estimate_candidate(local_integration_input, interp_iFin, interp_plastic_strain); + if (err_status == ViscoplastUtils::ErrorType::no_errors) + { + // reset dedicated counter and return solution + adaptive_estimate_interp_manager_->reset_num_estimate_interp_iters(); + return wrap_unknowns(interp_iFin, interp_plastic_strain); + } + else + { + // shift towards plastic predictor + adaptive_estimate_interp_manager_->adapt_interpolation_interval( + gp_, AEI::InterpolationIntervalShift::towards_plastic_pred); + adaptive_estimate_interp_manager_->set_current_interp_point( + gp_, AEI::CurrentInterpPointPreset::estimate_interpolation_update); + + + // if the interpolation interval has narrowed down to essentially [0, 0] -> try evaluating + // the standard elastic predictor as a last resort, i.e., return it directly, and do not + // allow for re-estimations which are anyway not possible anymore based on the given + // interval + if (adaptive_estimate_interp_manager_->upper_interp_bound(gp_) < numerical_tol) + { + err_status = ViscoplastUtils::ErrorType::no_errors; + adaptive_estimate_interp_manager_->disable_further_reestimations(); + adaptive_estimate_interp_manager_->reset_num_estimate_interp_iters(); + return wrap_unknowns(elastic_predictor_inverse_plastic_defgrad, last_plastic_strain); + } + } + } + + FOUR_C_THROW("{}", + get_error_warning_info( + "You should not be here! We should have either returned or thrown before reaching this " + "point " + "in the estimate interpolation!")); +} + + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +Core::LinAlg::Matrix<10, 1> +Mat::InelasticDefgradTransvIsotropElastViscoplast::reinterpolate_with_updated_bounds( + const Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + InelasticDefgradTransvIsotropElastViscoplastUtils::EvaluationAction& eval_action) +{ + FOUR_C_ASSERT(adaptive_estimate_interp_manager_.has_value(), "{}", + get_error_warning_info(std::format("This method should not be called without initializing " + "the manager for adaptive estimate interpolation!"))); + + adaptive_estimate_interp_manager_->set_current_interp_point( + gp_, AEI::CurrentInterpPointPreset::estimate_interpolation_update); + ViscoplastUtils::ErrorType err_status{ViscoplastUtils::ErrorType::no_errors}; + Core::LinAlg::Matrix<10, 1> updated_estimate = + interpolate_estimate(local_integration_input, err_status); + + // decide based on the evaluation error status whether to continue with the Local Newton or + // exit with error + if (err_status == ViscoplastUtils::ErrorType::no_errors) + { + eval_action = ViscoplastUtils::EvaluationAction::continue_with_next_iteration; + return updated_estimate; + } + else + { + eval_action = ViscoplastUtils::EvaluationAction::exit_with_error; + return Core::LinAlg::Matrix<10, 1>{Core::LinAlg::Initialization::zero}; + } +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +Core::LinAlg::Matrix<10, 1> +Mat::InelasticDefgradTransvIsotropElastViscoplast::reestimate_to_restart_local_newton( + const Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + ViscoplastUtils::EvaluationAction& eval_action) +{ + FOUR_C_ASSERT(adaptive_estimate_interp_manager_.has_value(), "{}", + get_error_warning_info(std::format("This method should not be called without initializing " + "the manager for adaptive estimate interpolation!"))); + + // retrieve required data from the local integration input + const Core::LinAlg::Matrix<3, 3>& inv_defgrad = local_integration_input.inv_defgrad; + const double last_plastic_strain = local_integration_input.last_plastic_strain; + const double step = local_integration_input.step; + + // increment number of re-estimations + adaptive_estimate_interp_manager_->increment_num_reestimations(); + if (!adaptive_estimate_interp_manager_->is_reestimation_possible()) + { + // exit with error, since nothing else can be done here + eval_action = ViscoplastUtils::EvaluationAction::exit_with_error; + return Core::LinAlg::Matrix<10, 1>{Core::LinAlg::Initialization::zero}; + } + + // set current interpolation point <- intermediate interpolation point + adaptive_estimate_interp_manager_->set_current_interp_point( + gp_, AEI::CurrentInterpPointPreset::intermediate_point); + + // compute equivalent stress associated with the intermediate interpolation point + Core::LinAlg::Matrix<3, 3> interp_iFin = + adaptive_estimate_interp_manager_->interpolate_inverse_inelastic_defgrad(gp_, inv_defgrad); + ViscoplastUtils::ErrorType err_status{ViscoplastUtils::ErrorType::no_errors}; + const double dummy_plastic_strain = -1.0; + ViscoplastUtils::StateQuantities interp_state_quantities = + evaluate_state_quantities(local_integration_input, interp_iFin, dummy_plastic_strain, + err_status, ViscoplastUtils::StateQuantityEvalType::equiv_stress_only); + + // if the state could not be computed -> shift toward plastic predictor + if (err_status != ViscoplastUtils::ErrorType::no_errors) + { + // ensure that this can only be an overflow error, because we have only evaluated the stress + // and not the plastic strain rate at this stage + FOUR_C_ASSERT(err_status == ViscoplastUtils::ErrorType::overflow_error, + "This should not be an {} error, but an overflow error!", err_status); + adaptive_estimate_interp_manager_->adapt_interpolation_interval( + gp_, AEI::InterpolationIntervalShift::towards_plastic_pred); + return reinterpolate_with_updated_bounds(local_integration_input, eval_action); + } + + // if no plastic flow is exhibited, i.e., the equivalent stress is "under the previous yield + // surface" -> set upper bound to intermediate point, i.e., shift interpolation towards the + // elastic predictor and work with this updated interval + if (!exhibits_plastic_flow(interp_state_quantities.curr_equiv_stress, last_plastic_strain)) + { + adaptive_estimate_interp_manager_->adapt_interpolation_interval( + gp_, AEI::InterpolationIntervalShift::towards_elastic_pred); + return reinterpolate_with_updated_bounds(local_integration_input, eval_action); + } + + // integrate plastic strain + double interp_plastic_strain = -1.0; + switch (parameter()->adaptive_estimate_interpolation_params().hardening.method) + { + case AEI::HardeningManagementMethod::use_previous: + { + interp_plastic_strain = last_plastic_strain; + break; + } + case AEI::HardeningManagementMethod::integrate_via_evolution_equations: + { + interp_plastic_strain = integrate_plastic_strain( + AEI::InputHardeningIntegration{ + .interp_equiv_stress = interp_state_quantities.curr_equiv_stress, + .last_plastic_strain = last_plastic_strain, + .step = step}, + err_status); + + // shift towards plastic predictor if integration fails + if (err_status != InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType::no_errors) + { + adaptive_estimate_interp_manager_->adapt_interpolation_interval( + gp_, AEI::InterpolationIntervalShift::towards_plastic_pred); + return reinterpolate_with_updated_bounds(local_integration_input, eval_action); + } + break; + } + default: + { + FOUR_C_THROW("{}", + get_error_warning_info( + std::format("Unsupported hardening method {} for adaptive estimate interpolation!", + parameter()->adaptive_estimate_interpolation_params().hardening.method))); + } + } + + // if we have reached this point, then we have a viable estimate candidate; we now verify + // it + err_status = + verify_estimate_candidate(local_integration_input, interp_iFin, interp_plastic_strain); + if (err_status == InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType::no_errors) + { + eval_action = ViscoplastUtils::EvaluationAction::continue_with_next_iteration; + return wrap_unknowns(interp_iFin, interp_plastic_strain); + } + else + { + // inadmissible estimate -> shift towards plastic predictor and reinterpolate with updated + // bounds + adaptive_estimate_interp_manager_->adapt_interpolation_interval( + gp_, AEI::InterpolationIntervalShift::towards_plastic_pred); + + return reinterpolate_with_updated_bounds(local_integration_input, eval_action); + } +} + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +void Mat::InelasticDefgradTransvIsotropElastViscoplast::update_aei_starting_point( + const unsigned int gp) +{ + FOUR_C_ASSERT(adaptive_estimate_interp_manager_.has_value(), "{}", + get_error_warning_info("This method should not be called without enabling " + "adaptive estimate interpolation!")); + const AEI::AEIParams& aei_params = parameter()->adaptive_estimate_interpolation_params(); + + // starting points are set based on the specified method + switch (aei_params.estimate_interpolation.starting_point_type) + { + case AEI::StartingPointType::constant: + { + adaptive_estimate_interp_manager_->set_user_starting_point(gp); + break; + } + case AEI::StartingPointType::equiv_stress_history: + { + adaptive_estimate_interp_manager_->set_stress_based_starting_point( + gp, get_input_equiv_stress_starting_point(gp)); + break; + } + default: + FOUR_C_THROW("{}", get_error_warning_info(std::format("Starting point type {} unsupported!", + aei_params.estimate_interpolation.starting_point_type))); + } +} + + +/*--------------------------------------------------------------------* + *--------------------------------------------------------------------*/ +AEI::InputEquivStressStartingPoint +Mat::InelasticDefgradTransvIsotropElastViscoplast::get_input_equiv_stress_starting_point( + const unsigned int gp) const +{ + // get deformation gradient components + auto local_integration_input = + ViscoplastUtils::LocalIntegrationInput{{.defgrad = time_step_quantities_.current_defgrad[gp], + .temperature = time_step_quantities_.current_temperature[gp], + .last_inv_inelastic_defgrad = time_step_quantities_.last_plastic_defgrad_inverse[gp], + .last_plastic_strain = time_step_quantities_.last_plastic_strain[gp], + .step = time_step_tracker_.dt}}; + ViscoplastUtils::ErrorType err_status{ViscoplastUtils::ErrorType::no_errors}; + + // compute solution stress at the considered Gauss point + ViscoplastUtils::StateQuantities state_quantities_sol = evaluate_state_quantities( + local_integration_input, time_step_quantities_.current_plastic_defgrad_inverse[gp], -1.0, + err_status, ViscoplastUtils::StateQuantityEvalType::equiv_stress_only); + if (err_status != ViscoplastUtils::ErrorType::no_errors) + { + FOUR_C_THROW( + "{}", get_error_warning_info(std::format("Could not evaluate solution stress! This " + "is definitely impossible! Error status: {}", + err_status))); + } + + // compute stress related to the elastic and plastic predictors at the considered Gauss + // point + ViscoplastUtils::StateQuantities state_quantities_elast_pred = evaluate_state_quantities( + local_integration_input, time_step_quantities_.last_plastic_defgrad_inverse[gp], -1.0, + err_status, ViscoplastUtils::StateQuantityEvalType::equiv_stress_only); + + if (err_status != ViscoplastUtils::ErrorType::no_errors) + { + FOUR_C_THROW( + "{}", get_error_warning_info(std::format( + "Could not even evaluate the stress of the elastic predictor when attempting to " + "update " + "the starting points of the adaptive estimate interpolation using the " + "optimal_equiv_stress strategy! Error status: {}", + err_status))); + } + + Core::LinAlg::Matrix<3, 3> iFin_plastic_pred = + adaptive_estimate_interp_manager_->get_inverse_inelastic_defgrad_plastic_pred( + gp, local_integration_input.inv_defgrad); + ViscoplastUtils::StateQuantities state_quantities_plast_pred = + evaluate_state_quantities(local_integration_input, iFin_plastic_pred, -1.0, err_status, + ViscoplastUtils::StateQuantityEvalType::equiv_stress_only); + + if (err_status != ViscoplastUtils::ErrorType::no_errors) + { + FOUR_C_THROW( + "{}", get_error_warning_info(std::format( + "Could not even evaluate the stress of the plastic predictor when attempting to " + "update " + "the starting points of the adaptive estimate interpolation using the " + "optimal_equiv_stress strategy! \n {}", + err_status))); + } + + return {.equiv_stress_solution = state_quantities_sol.curr_equiv_stress, + .equiv_stress_elast_pred = state_quantities_elast_pred.curr_equiv_stress, + .equiv_stress_plast_pred = state_quantities_plast_pred.curr_equiv_stress}; } FOUR_C_NAMESPACE_CLOSE diff --git a/src/mat/4C_mat_inelastic_defgrad_factors.hpp b/src/mat/4C_mat_inelastic_defgrad_factors.hpp index ef0d842a74a..971f23bb473 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors.hpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors.hpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -1986,11 +1987,14 @@ namespace Mat * * * @param[in] err_status error status + * @param[in] local_integration_input input required for the local time integration * @param[out] eval_action action to be performed subsequently in the local Newton Loop */ void manage_evaluation( const InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status, - InelasticDefgradTransvIsotropElastViscoplastUtils::EvaluationAction& eval_action) const; + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + InelasticDefgradTransvIsotropElastViscoplastUtils::EvaluationAction& eval_action); /*! * @brief Evaluate the additional cmat stiffness tensor using a perturbation-based approach, if @@ -2069,7 +2073,7 @@ namespace Mat * further re-estimations. * * @param[in] local_integration_input input for the local time integration - * @param[in] err_status error status after the procedure + * @param[out] err_status error status after the procedure * @return initial estimate containing the inverse inelastic defgrad (components 0 - 8), and * the equivalent plastic strain (component 9) for the Local Newton within this time step / * substep @@ -2077,7 +2081,132 @@ namespace Mat [[nodiscard]] Core::LinAlg::Matrix<10, 1> determine_local_newton_init_estimate( const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& local_integration_input, - const InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) const; + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status); + + //! verify whether plastic flow is exhibited based on the current value for the equivalent + //! stress \f$ \overline{\sigma}_{n+1} \f$, and the plastic strain at the previous time instant + //! \f$ \varepsilon_{\text{p},n} \f$ -> Note that this function includes both viscoplastic flow + //! rules with, and without yield surfaces, whereby we assume for the latter that plastic flow + //! is exhibited whenever the equivalent stress exceeds numerical 0.0 + [[nodiscard]] bool exhibits_plastic_flow( + const double curr_equiv_stress, const double last_plastic_strain) const; + + /*! + * @brief Asserts whether the elastic and the preliminary plastic predictors (AEI) exhibit + * suitable stress values with respect to the lowest meaningful bound \f$ S \f$, prior to the + * iterative construction of the plastic predictor + * + * @param[in] local_integration_input input for the local time integration + * @param[in] invS inverse lowest meaningful bound \f$ 1 / S \f$ + */ + void assert_predictor_stress_consistency( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + double invS) const; + + /*! + * @brief Construct the plastic predictor for the Adaptive Estimate Interpolation algorithm + via the dedicated manager and its utilities. + * + * @param[in] local_integration_input input for the local time integration + * @param[out] err_status error status after the procedure + */ + void construct_plastic_predictor( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status); + + /*! + * @brief Interpolates initial / updated estimates for the Local Newton loop between the + * elastic and plastic predictors according to the Adaptive Estimate Interpolation algorithm + * + * @param[in] local_integration_input input for the local time integration + * @param[out] err_status error status after the procedure + * @return initial / updated estimate to be used within the Local Newton + */ + [[nodiscard]] Core::LinAlg::Matrix<10, 1> interpolate_estimate( + const InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status); + + /*! + * @brief Integrates the equivalent plastic strain based on its evolution equation; relevant + * for the plastic strain update / "interpolation" within the Adaptive Estimate Interpolation + * procedures + * + * @param[in] integration_input struct containing variables required for hardening integration + * @param[out] err_status error status after the procedure + */ + [[nodiscard]] double integrate_plastic_strain( + const InelasticDefgradTransvIsotropElastViscoplastUtils::AdaptiveEstimateInterpolation:: + InputHardeningIntegration& integration_input, + InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType& err_status) const; + + /*! + * @brief Verifies whether the specified estimate candidate is a valid Local Newton estimate, + i.e., whether it is numerically admissible, meaning that Local Newton residual and Jacobian can + be evaluated + * without triggering overflow. + * Note: the verification that plastic flow is exhibited should happen beforehand, this function + does not verify this, as is also the case in Algorithm 2 of the paper (Ana, Schmidt, Wall: + Adaptive Estimate Interpolation: Accelerating Local Newton-Raphson Schemes in Computational + Plasticity and Viscoplasticity, Preprint). + * + * @param[in] local_integration_input input for the local time integration + * @param[in] iFin_candidate estimate candidate: inverse inelastic deformation gradient + * @param[in] plastic_strain_candidate estimate candidate: equivalent plastic strain + * @return error status; no_errors means that this is a valid estimate for the Local Newton + * scheme + */ + [[nodiscard]] InelasticDefgradTransvIsotropElastViscoplastUtils::ErrorType + verify_estimate_candidate( + const Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + const Core::LinAlg::Matrix<3, 3>& iFin_candidate, const double plastic_strain_candidate); + + + /*! + * @brief Perform the re-estimation procedure of the Adaptive Estimate Interpolation + * algorithm, to effectively restart the Local Newton loop + * + * @param[in] local_integration_input input for the local time integration + * @param[out] eval_action action to be performed subsequently in the Local Newton scheme + * @return updated estimate for the Local Newton scheme + */ + [[nodiscard]] Core::LinAlg::Matrix<10, 1> reestimate_to_restart_local_newton( + const Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + InelasticDefgradTransvIsotropElastViscoplastUtils::EvaluationAction& eval_action); + + + /*! + * @brief Reinterpolates an updated estimate using the updated interpolation interval + * + * @note Helper function to be called within the re-estimation procedure of the Adaptive + * Estimate Interpolation + * + * @param[in] local_integration_input input for the local time integration + * @param[out] eval_action action to be performed subsequently in the Local Newton scheme + * @return updated estimate for the Local Newton scheme + */ + [[nodiscard]] Core::LinAlg::Matrix<10, 1> reinterpolate_with_updated_bounds( + const Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalIntegrationInput& + local_integration_input, + InelasticDefgradTransvIsotropElastViscoplastUtils::EvaluationAction& eval_action); + + //! updates the starting point used at a given Gauss point within the Adaptive Estimate + //! Interpolation algorithm for the next time step + void update_aei_starting_point(unsigned int gp); + + //! get the input needed for determining the interpolation starting point (Adaptive Estimate + //! Interpolation) based on the equivalent stress of the previous solution, between the elastic + //! and the plastic predictors (see I_HIST method within the paper) -> Note that this input is + //! determined based on the current_ values of local integration variables for the NEXT + //! timestep, so the function should be called before updating last_ <- current_ in the update + //! method + [[nodiscard]] InelasticDefgradTransvIsotropElastViscoplastUtils::AdaptiveEstimateInterpolation:: + InputEquivStressStartingPoint + get_input_equiv_stress_starting_point(unsigned int gp) const; }; } // namespace Mat diff --git a/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp b/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp index 6fbf366f22c..c4cf51c4b5c 100644 --- a/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp +++ b/src/mat/4C_mat_inelastic_defgrad_factors_service.hpp @@ -1242,6 +1242,21 @@ namespace Mat ReestimationParams reestimation; }; + //! struct containing information required for integrating the hardening variables according + //! to their evolution equations (currently only the equivalent plastic strain assumed as an + //! internal variable) + struct InputHardeningIntegration + { + //! interpolated equivalent stress \f$ \overline{\sigma}(\xi) \f$ + double interp_equiv_stress; + + //! previous plastic strain \f$ \varepsilon_{\text{p},n} \f$ + double last_plastic_strain; + + //! integration timestep / substep \f$ \Delta t \f$ / \f$ \Delta \tilde{t} \f$ + double step; + }; + //! struct: input for the interpolation point determination based on the equivalent //! stress of the previous solution between both predictors (I_HIST method from paper: //! $\hat{\xi}_{n+1} = \text{min}[1, \text{max}(\frac{\overline{\sigma}_n - diff --git a/unittests/mat/4C_inelastic_defgrad_factors_test.cpp b/unittests/mat/4C_inelastic_defgrad_factors_test.cpp index 26aa9327399..71d705c9ebc 100644 --- a/unittests/mat/4C_inelastic_defgrad_factors_test.cpp +++ b/unittests/mat/4C_inelastic_defgrad_factors_test.cpp @@ -2323,6 +2323,289 @@ namespace } + /// Tests a challenging local integration scenario, where using the elastic predictor to + /// initialize the Local Newton-Raphson scheme does not converge, whilst using the Adaptive + /// Estimate Interpolation (AEI) with hardening integration does (but only when the re-estimation + /// mechanism is enabled!) + TEST_F(InelasticDefgradFactorsTest, TestElasticPredictorAgainstAdaptiveEstimateInterpolation) + { + // setup common material parameters to be used + Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalNewtonParams local_newton_params{ + .res_tol = 1.0e-8, + .incr_tol = 1.0e-8, + .conv_check = Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalNewtonConvCheck:: + residual_and_increment_ratio, + .diver_cont = + Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalNewtonDiverCont::stop, + .max_iter = 100, + .max_exceedance_fact_res_tol = 0.0, + .max_exceedance_fact_incr_tol = 0.0, + }; + ReformulatedJohnsonCookParameters ref_jc_params = {.strain_rate_prefac = 1.0, + .strain_rate_exp_fac = 0.014, + .init_yield_strength = 792.0, + .isotrop_harden_prefac = 510.0, + .isotrop_harden_exp = 0.26, + .ref_temperature = 293.0, + .melt_temperature = 1000.0, + .temperature_sens = 0.1}; + + // setup the general test settings + Teuchos::ParameterList params_list; + double total_time = 1.0e0; + double time_step_size = 1.0e0; + Mat::EvaluationContext<3> context{.total_time = &total_time, + .time_step_size = &time_step_size, + .xi = {}, + .ref_coords = nullptr}; + + Core::LinAlg::Matrix<3, 3> unit_3x3 = Core::LinAlg::identity_matrix<3>(); + Core::LinAlg::Matrix<3, 3> iFin_other(unit_3x3); + + Core::LinAlg::Matrix<3, 3> FM(Core::LinAlg::Initialization::zero); + FM(0, 0) = 3.0; + FM(1, 1) = 1.0; + FM(2, 2) = 1.0; + + Core::LinAlg::Matrix<3, 3> iFin_result(Core::LinAlg::Initialization::zero); + + // setup the material using the elastic predictor + auto material_elastic_pred = + set_up_viscoplastic_material({.local_newton_params = local_newton_params, + .use_substepping = false, + .viscoplastic_law_params = ref_jc_params}) + .material; + // the use of the elastic predictor fails to converge + material_elastic_pred->pre_evaluate(params_list, context, 0, 0); + FOUR_C_EXPECT_THROW_WITH_MESSAGE( + material_elastic_pred->evaluate_inverse_inelastic_def_grad(&FM, iFin_other, iFin_result), + Core::Exception, + "Local Newton evaluation has failed and there is no evaluation management strategy"); + + // setup the material using the AEI with hardening integration + reestimation + AEI::AEIParams aei_params_with_reestim = + InelasticDefgradFactorsTestUtils::set_up_aei_params(); // default: hardening integration + auto material_aei_with_reestim = + set_up_viscoplastic_material({.local_newton_params = local_newton_params, + .use_substepping = false, + .adaptive_estimate_interp_params = aei_params_with_reestim, + .viscoplastic_law_params = ref_jc_params}) + .material; + + + // setup the material using the AEI with hardening integration, but without the reestimation + // mechanism + AEI::AEIParams aei_params_no_reestim = + InelasticDefgradFactorsTestUtils::set_up_aei_params(); // default: hardening integration + aei_params_no_reestim.reestimation.max_num_reestimations = 0; // disable reestimations + auto material_aei_no_reestim = + set_up_viscoplastic_material({.local_newton_params = local_newton_params, + .use_substepping = false, + .adaptive_estimate_interp_params = aei_params_no_reestim, + .viscoplastic_law_params = ref_jc_params}) + .material; + + // the use of the AEI converges only when re-estimations are enabled + Core::LinAlg::Matrix<3, 3> iFin_result_ref{Core::LinAlg::Initialization::zero}; + iFin_result_ref(0, 0) = 0.48201356865; + iFin_result_ref(1, 1) = 1.44035773137; + iFin_result_ref(2, 2) = 1.44035773137; + material_aei_with_reestim->pre_evaluate(params_list, context, 0, 0); + material_aei_with_reestim->evaluate_inverse_inelastic_def_grad(&FM, iFin_other, iFin_result); + FOUR_C_EXPECT_NEAR(iFin_result, iFin_result_ref, 1.0e-10); + + material_aei_no_reestim->pre_evaluate(params_list, context, 0, 0); + FOUR_C_EXPECT_THROW_WITH_MESSAGE( + material_aei_no_reestim->evaluate_inverse_inelastic_def_grad(&FM, iFin_other, iFin_result), + Core::Exception, "The re-estimation procedure has failed!"); + } + + /// Tests two challenging local integration scenarios using the Adaptive Estimate Interpolation + /// algorithm. In the first, numerically more tractable scenario, both hardening strategies + /// converge: fixing the plastic state and performing consistent integration based on the + /// interpolated equivalent stress. + /// In the second, more numerically challenging scenario, only the + /// consistent hardening integration converges. + TEST_F(InelasticDefgradFactorsTest, TestHardeningManagementAdaptiveEstimateInterpolation) + { + // setup common material parameters to be used + Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalNewtonParams local_newton_params{ + .res_tol = 1.0e-8, + .incr_tol = 1.0e-8, + .conv_check = Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalNewtonConvCheck:: + residual_and_increment_ratio, + .diver_cont = + Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalNewtonDiverCont::stop, + .max_iter = 50, + .max_exceedance_fact_res_tol = 0.0, + .max_exceedance_fact_incr_tol = 0.0, + }; + + + // setup the general test settings + Teuchos::ParameterList params_list; + double total_time = 1.0; + double time_step_size = 1.0; + Mat::EvaluationContext<3> context{.total_time = &total_time, + .time_step_size = &time_step_size, + .xi = {}, + .ref_coords = nullptr}; + + Core::LinAlg::Matrix<3, 3> unit_3x3 = Core::LinAlg::identity_matrix<3>(); + Core::LinAlg::Matrix<3, 3> iFin_other(unit_3x3); + + Core::LinAlg::Matrix<3, 3> iFin_result(Core::LinAlg::Initialization::zero); + + + // setup material using AEI with hardening integration + AEI::AEIParams aei_params_hardening_integration = + InelasticDefgradFactorsTestUtils::set_up_aei_params(); // default: hardening integration + auto material_aei_hardening_integration = set_up_viscoplastic_material( + { + .local_newton_params = local_newton_params, + .use_substepping = false, + .adaptive_estimate_interp_params = aei_params_hardening_integration, + }) + .material; + + // setup material using AEI with fixed plastic state / hardening + AEI::AEIParams aei_params_fixed_hardening = InelasticDefgradFactorsTestUtils::set_up_aei_params( + {.hardening = {.method = AEI::HardeningManagementMethod::use_previous, + .max_iter_integration = 0, + .tol_integration = 0.0}}); + auto material_aei_fixed_hardening = set_up_viscoplastic_material( + { + .local_newton_params = local_newton_params, + .use_substepping = false, + .adaptive_estimate_interp_params = aei_params_fixed_hardening, + }) + .material; + + // first deformation scenario: both hardening strategies converge + Core::LinAlg::Matrix<3, 3> FM(Core::LinAlg::Initialization::zero); + FM(0, 0) = 1.1; + FM(1, 1) = 0.9; + FM(2, 2) = 0.9; + Core::LinAlg::Matrix<3, 3> iFin_result_ref{Core::LinAlg::Initialization::zero}; + iFin_result_ref(0, 0) = 0.96637623335; + iFin_result_ref(1, 1) = 1.01724808212; + iFin_result_ref(2, 2) = 1.01724808212; + + material_aei_hardening_integration->pre_evaluate(params_list, context, 0, 0); + material_aei_hardening_integration->evaluate_inverse_inelastic_def_grad( + &FM, iFin_other, iFin_result); + FOUR_C_EXPECT_NEAR(iFin_result, iFin_result_ref, 1.0e-10); + material_aei_fixed_hardening->pre_evaluate(params_list, context, 0, 0); + material_aei_fixed_hardening->evaluate_inverse_inelastic_def_grad(&FM, iFin_other, iFin_result); + FOUR_C_EXPECT_NEAR(iFin_result, iFin_result_ref, 1.0e-10); + + // second deformation scenario: repeat the tests with a more numerically complex state, such + // that only the use of hardening integration converges + FM.clear(); + FM(0, 0) = 1.5; + FM(1, 1) = 0.75; + FM(2, 2) = 0.75; + iFin_result_ref.clear(); + iFin_result_ref(0, 0) = 0.70480335583; + iFin_result_ref(1, 1) = 1.19114880226; + iFin_result_ref(2, 2) = 1.19114880226; + + material_aei_hardening_integration->pre_evaluate(params_list, context, 0, 0); + material_aei_hardening_integration->evaluate_inverse_inelastic_def_grad( + &FM, iFin_other, iFin_result); + FOUR_C_EXPECT_NEAR(iFin_result, iFin_result_ref, 1.0e-10); + + material_aei_fixed_hardening->pre_evaluate(params_list, context, 0, 0); + FOUR_C_EXPECT_THROW_WITH_MESSAGE( + material_aei_fixed_hardening->evaluate_inverse_inelastic_def_grad( + &FM, iFin_other, iFin_result), + Core::Exception, "The re-estimation procedure has failed!"); + } + + + /// Tests a challenging local integration scenario where the use of Adaptive Estimate + /// Interpolation alone does not converge (re-estimation disabled), but including substepping as a + /// fallback strategy does + TEST_F(InelasticDefgradFactorsTest, TestAdaptiveEstimateInterpolationWithSubstepping) + { + // setup common material parameters to be used + Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalNewtonParams local_newton_params{ + .res_tol = 1.0e-8, + .incr_tol = 1.0e-8, + .conv_check = Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalNewtonConvCheck:: + residual_and_increment_ratio, + .diver_cont = + Mat::InelasticDefgradTransvIsotropElastViscoplastUtils::LocalNewtonDiverCont::stop, + .max_iter = 50, + .max_exceedance_fact_res_tol = 0.0, + .max_exceedance_fact_incr_tol = 0.0, + }; + ReformulatedJohnsonCookParameters ref_jc_params = {.strain_rate_prefac = 1.0, + .strain_rate_exp_fac = 0.014, + .init_yield_strength = 792.0, + .isotrop_harden_prefac = 510.0, + .isotrop_harden_exp = 0.26, + .ref_temperature = 293.0, + .melt_temperature = 1000.0, + .temperature_sens = 0.1}; + + + // setup the general test settings + Teuchos::ParameterList params_list; + double total_time = 1.0; + double time_step_size = 1.0; + Mat::EvaluationContext<3> context{.total_time = &total_time, + .time_step_size = &time_step_size, + .xi = {}, + .ref_coords = nullptr}; + + Core::LinAlg::Matrix<3, 3> unit_3x3 = Core::LinAlg::identity_matrix<3>(); + Core::LinAlg::Matrix<3, 3> iFin_other(unit_3x3); + + Core::LinAlg::Matrix<3, 3> iFin_result(Core::LinAlg::Initialization::zero); + + + // setup the material using AEI without substepping (and without re-estimation) + AEI::AEIParams aei_params = + InelasticDefgradFactorsTestUtils::set_up_aei_params(); // default: hardening integration + aei_params.reestimation.max_num_reestimations = 0; // disable reestimations + auto material_aei_no_substepping = + set_up_viscoplastic_material({.local_newton_params = local_newton_params, + .use_substepping = false, + .adaptive_estimate_interp_params = aei_params, + .viscoplastic_law_params = ref_jc_params}) + .material; + + // setup the material using AEI with substepping + auto material_aei_with_substepping = + set_up_viscoplastic_material({.local_newton_params = local_newton_params, + .use_substepping = true, + .max_substepping_halve_num = 10, + .adaptive_estimate_interp_params = aei_params, + .viscoplastic_law_params = ref_jc_params}) + .material; + + // complex deformation scenario: only the additional use of substepping converges + Core::LinAlg::Matrix<3, 3> FM(Core::LinAlg::Initialization::zero); + FM(0, 0) = 5.5; + FM(1, 1) = 1.0; + FM(2, 2) = 1.0; + Core::LinAlg::Matrix<3, 3> iFin_result_ref{Core::LinAlg::Initialization::zero}; + iFin_result_ref(0, 0) = 0.32153119143; + iFin_result_ref(1, 1) = 1.76355271195; + iFin_result_ref(2, 2) = 1.76355271195; + + material_aei_no_substepping->pre_evaluate(params_list, context, 0, 0); + FOUR_C_EXPECT_THROW_WITH_MESSAGE( + material_aei_no_substepping->evaluate_inverse_inelastic_def_grad( + &FM, iFin_other, iFin_result), + Core::Exception, "The re-estimation procedure has failed!"); + + material_aei_with_substepping->pre_evaluate(params_list, context, 0, 0); + material_aei_with_substepping->evaluate_inverse_inelastic_def_grad( + &FM, iFin_other, iFin_result); + FOUR_C_EXPECT_NEAR(iFin_result, iFin_result_ref, 1.0e-10); + } TEST_F(InelasticDefgradFactorsTest, TestEvaluateStateQuantityDerivatives) { From 7ba2efe25ee5cfbccb1a7aeb1c5140ae76dedef0 Mon Sep 17 00:00:00 2001 From: Ana Dragos-Corneliu Date: Mon, 10 Aug 2026 19:23:13 +0200 Subject: [PATCH 7/7] Add framework tests --- ...st_refJC_log_timint_tsi_monolithic.4C.yaml | 2 + ...t_refJC_log_timint_tsi_partitioned.4C.yaml | 2 + ...at_iso_viscoplast_refJC_log_timint.4C.yaml | 6 +- ...rp_equiv_stress_history_no_restart.4C.yaml | 206 +++++++++++++++++ ..._equiv_stress_history_with_restart.4C.yaml | 208 ++++++++++++++++++ ...user_set_starting_point_no_restart.4C.yaml | 201 +++++++++++++++++ ...er_set_starting_point_with_restart.4C.yaml | 203 +++++++++++++++++ ...plast_refJC_log_timint_substepping.4C.yaml | 6 +- ...nsviso_viscoplast_refJC_log_timint.4C.yaml | 7 +- ...o_viscoplast_refJC_standard_timint.4C.yaml | 7 +- tests/list_of_tests.cmake | 6 + 11 files changed, 848 insertions(+), 6 deletions(-) create mode 100644 tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_equiv_stress_history_no_restart.4C.yaml create mode 100644 tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_equiv_stress_history_with_restart.4C.yaml create mode 100644 tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_user_set_starting_point_no_restart.4C.yaml create mode 100644 tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_user_set_starting_point_with_restart.4C.yaml diff --git a/tests/input_files/mat_iso_thermoviscoplast_refJC_log_timint_tsi_monolithic.4C.yaml b/tests/input_files/mat_iso_thermoviscoplast_refJC_log_timint_tsi_monolithic.4C.yaml index e64328eb8dc..20f5b00fd82 100644 --- a/tests/input_files/mat_iso_thermoviscoplast_refJC_log_timint_tsi_monolithic.4C.yaml +++ b/tests/input_files/mat_iso_thermoviscoplast_refJC_log_timint_tsi_monolithic.4C.yaml @@ -80,6 +80,8 @@ MATERIALS: MAX_EXCEEDANCE_FACT_RES_TOL: 10 MAX_EXCEEDANCE_FACT_INCR_TOL: 10 DIVER_CONT: stop + ADAPTIVE_ESTIMATE_INTERPOLATION: + USE_ADAPTIVE_ESTIMATE_INTERPOLATION: false - MAT: 4 MAT_ViscoplasticLawReformulatedJohnsonCook: STRAIN_RATE_PREFAC: 1 # [1/s] diff --git a/tests/input_files/mat_iso_thermoviscoplast_refJC_log_timint_tsi_partitioned.4C.yaml b/tests/input_files/mat_iso_thermoviscoplast_refJC_log_timint_tsi_partitioned.4C.yaml index 08b66316a04..6fb6dcc1cb1 100644 --- a/tests/input_files/mat_iso_thermoviscoplast_refJC_log_timint_tsi_partitioned.4C.yaml +++ b/tests/input_files/mat_iso_thermoviscoplast_refJC_log_timint_tsi_partitioned.4C.yaml @@ -83,6 +83,8 @@ MATERIALS: MAX_EXCEEDANCE_FACT_RES_TOL: 10 MAX_EXCEEDANCE_FACT_INCR_TOL: 10 DIVER_CONT: stop + ADAPTIVE_ESTIMATE_INTERPOLATION: + USE_ADAPTIVE_ESTIMATE_INTERPOLATION: false - MAT: 4 MAT_ViscoplasticLawReformulatedJohnsonCook: STRAIN_RATE_PREFAC: 1 # [1/s] diff --git a/tests/input_files/mat_iso_viscoplast_refJC_log_timint.4C.yaml b/tests/input_files/mat_iso_viscoplast_refJC_log_timint.4C.yaml index b0171450079..a6379aad5d2 100644 --- a/tests/input_files/mat_iso_viscoplast_refJC_log_timint.4C.yaml +++ b/tests/input_files/mat_iso_viscoplast_refJC_log_timint.4C.yaml @@ -10,7 +10,9 @@ TITLE: - "- time integration of internal variables using logarithmic substepping, as shown in:" - "Ana: Continuum Modeling and Calibration of Viscoplasticity in the Context" - "of the Lithium Anode in Solid-State Batteries" - - "(Master's Thesis, Institute for Computational Mechanics, TU Munich, 2024)" + - "(Master's Thesis, Institute for Computational Mechanics, TU Munich, 2024)." + - "The Adaptive Estimate Interpolation algorithm presented in Ana, Schmidt, Wall: Accelerating Local + Newton--Raphson Schemes in Computational Plasticity / Viscoplasticity is not used in this test." PROBLEM TYPE: PROBLEMTYPE: "Structure" IO: @@ -64,6 +66,8 @@ MATERIALS: MAX_PLASTIC_STRAIN_INCR: 10686474581524.463 REGISTER_PLASTIC_STRAIN_DERIV_INCR_OVERFLOW: false MAX_PLASTIC_STRAIN_DERIV_INCR: 10686474581524.463 + ADAPTIVE_ESTIMATE_INTERPOLATION: + USE_ADAPTIVE_ESTIMATE_INTERPOLATION: false - MAT: 4 MAT_ViscoplasticLawReformulatedJohnsonCook: STRAIN_RATE_PREFAC: 1 diff --git a/tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_equiv_stress_history_no_restart.4C.yaml b/tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_equiv_stress_history_no_restart.4C.yaml new file mode 100644 index 00000000000..65373dd8609 --- /dev/null +++ b/tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_equiv_stress_history_no_restart.4C.yaml @@ -0,0 +1,206 @@ +TITLE: + - "Simulation of a viscoplastic HEX8 element under uniaxial tension with a constant strain rate of $1 + \\ \\mathrm{s}^{-1}$, as shown in Ana, Schmidt, Wall: Accelerating Local Newton--Raphson Schemes in + Computational Plasticity / Viscoplasticity." + - "The Adaptive Estimate Interpolation scheme is used for local time integration, in order to determine + efficient initial and updated estimates (due to re-estimations) for the Local Newton--Raphson procedure." + - "The accumulated plastic strain of the estimates is integrated according to its evolution equation, + consistent with the interpolated elastic deformation gradient." + - "The starting point of the adaptive estimate interpolation procedure for the next timestep is set + using the solution equivalent stress, in relation to the elastic and plastic predictors (I_HIST variant + in the paper)." +PROBLEM TYPE: + PROBLEMTYPE: "Structure" +IO: + STRUCT_STRESS: "Cauchy" + STRUCT_STRAIN: "log" + STDOUTEVERY: 1 + VERBOSITY: minimal +IO/RUNTIME VTK OUTPUT/STRUCTURE: + OUTPUT_STRUCTURE: true + DISPLACEMENT: true + STRESS_STRAIN: true + GAUSS_POINT_DATA_OUTPUT_TYPE: gauss_points +IO/RUNTIME VTK OUTPUT: + EVERY_ITERATION: false + INTERVAL_STEPS: 1 +STRUCTURAL DYNAMIC: + INT_STRATEGY: "Standard" + DYNAMICTYPE: "Statics" + RESTARTEVERY: 1 + TIMESTEP: 1 + NUMSTEP: 5000000 + MAXTIME: 1.0 + TOLDISP: 1e-06 + NORM_DISP: Abs + TOLRES: 1e-06 + NORM_RESF: Abs + NEGLECTINERTIA: true + LINEAR_SOLVER: 1 +SOLVER 1: + SOLVER: "UMFPACK" +FUNCT1: + - COMPONENT: 0 + SYMBOLIC_FUNCTION_OF_SPACE_TIME: "a" + - VARIABLE: 0 + NAME: "a" + TYPE: "multifunction" + NUMPOINTS: 2 + TIMES: [0.0, 1.6e+16] + DESCRIPTION: ["exp(1.0 * t) - 1.0"] +MATERIALS: + - MAT: 1 + MAT_MultiplicativeSplitDefgradElastHyper: + NUMMATEL: 1 + MATIDSEL: [2] + NUMFACINEL: 1 + INELDEFGRADFACIDS: [3] + DENS: 7830 + - MAT: 2 + ELAST_CoupSVK: + YOUNG: 2.0e5 + NUE: 0.29 + - MAT: 3 + MAT_InelasticDefgradTransvIsotropElastViscoplast: + VISCOPLAST_LAW_ID: 4 + FIBER_READER_ID: 5 + MAT_BEHAVIOR: "isotropic" + TIME_INTEGRATION_HIST_VARS: logarithmic + LOCAL_NEWTON: + CONV_CHECK: residual_and_increment_ratio + MAX_ITER: 100 + RES_TOL: 1.0e-10 + INCR_TOL: 1.0e-10 + DIVER_CONT: stop + ERROR_REGISTRATION_SETTINGS: + MAX_PLASTIC_STRAIN_INCR: 1.0e12 + ADAPTIVE_ESTIMATE_INTERPOLATION: + USE_ADAPTIVE_ESTIMATE_INTERPOLATION: true + ELASTIC_PREDICTOR_ZERO_COMPONENT_THRESHOLD: 1e-13 + PLASTIC_PREDICTOR_CONSTRUCTION: + ELASTIC_STRETCH_EIGENVAL_TYPE: scale_unit + ELASTIC_STRETCH_EIGENVECT_TYPE: from_elastic_predictor + ELASTIC_ROTATION_TYPE: from_elastic_predictor + MAX_ITER: 50 + RELATIVE_UNDERSTRESS_TOL: 0.000001 + INTERVAL_SCANNING_PARAM: 0.5 + ESTIMATE_INTERPOLATION: + STARTING_POINT_TYPE: equiv_stress_history + MAX_ITER: 50 + INTERVAL_SCANNING_PARAM: 0.5 + HARDENING_MANAGEMENT: + METHOD: integrate_via_evolution_equations + MAX_ITER_INTEGRATION: 50 + TOL_INTEGRATION: 1e-8 + REESTIMATION: + MAX_NUM_REESTIMATIONS: 10 + INTERVAL_SCANNING_PARAM: 0.5 + - MAT: 4 + MAT_ViscoplasticLawReformulatedJohnsonCook: + STRAIN_RATE_PREFAC: 1 + STRAIN_RATE_EXP_FAC: 0.014 + INIT_YIELD_STRENGTH: 792.0 + ISOTROP_HARDEN_PREFAC: 510.0 + ISOTROP_HARDEN_EXP: 0.26 + REF_TEMPERATURE: 293 + MELT_TEMPERATURE: 1000 + TEMPERATURE_SENS: 0.1 + - MAT: 5 + ELAST_CoupTransverselyIsotropic: + ALPHA: 1 + BETA: 1 + GAMMA: 1 + ANGLE: 0 + STR_TENS_ID: 100 + - MAT: 100 + ELAST_StructuralTensor: + STRATEGY: "Standard" +DESIGN POINT DIRICH CONDITIONS: + - E: 1 + NUMDOF: 3 + ONOFF: [1, 1, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] + - E: 2 + NUMDOF: 3 + ONOFF: [1, 1, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 3 + NUMDOF: 3 + ONOFF: [1, 0, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 4 + NUMDOF: 3 + ONOFF: [1, 0, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] + - E: 5 + NUMDOF: 3 + ONOFF: [0, 1, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] + - E: 6 + NUMDOF: 3 + ONOFF: [0, 1, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 7 + NUMDOF: 3 + ONOFF: [0, 0, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 8 + NUMDOF: 3 + ONOFF: [0, 0, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] +DNODE-NODE TOPOLOGY: + - NODE 1 DNODE 1 + - NODE 2 DNODE 2 + - NODE 3 DNODE 3 + - NODE 4 DNODE 4 + - NODE 5 DNODE 5 + - NODE 6 DNODE 6 + - NODE 7 DNODE 7 + - NODE 8 DNODE 8 +DLINE-NODE TOPOLOGY: + - NODE 1 DLINE 1 + - NODE 4 DLINE 1 + - NODE 1 DLINE 2 + - NODE 5 DLINE 2 + - NODE 1 DLINE 3 + - NODE 2 DLINE 3 + - NODE 2 DLINE 4 + - NODE 3 DLINE 4 + - NODE 2 DLINE 5 + - NODE 6 DLINE 5 +DSURF-NODE TOPOLOGY: + - NODE 1 DSURFACE 1 + - NODE 4 DSURFACE 1 + - NODE 5 DSURFACE 1 + - NODE 8 DSURFACE 1 + - NODE 2 DSURFACE 2 + - NODE 3 DSURFACE 2 + - NODE 6 DSURFACE 2 + - NODE 7 DSURFACE 2 + - NODE 1 DSURFACE 3 + - NODE 2 DSURFACE 3 + - NODE 3 DSURFACE 3 + - NODE 4 DSURFACE 3 + - NODE 1 DSURFACE 4 + - NODE 2 DSURFACE 4 + - NODE 5 DSURFACE 4 + - NODE 6 DSURFACE 4 +NODE COORDS: + - NODE 1 COORD -5.0000000000000000e-01 -5.0000000000000000e-01 5.0000000000000000e-01 + - NODE 2 COORD -5.0000000000000000e-01 -5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 3 COORD -5.0000000000000000e-01 5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 4 COORD -5.0000000000000000e-01 5.0000000000000000e-01 5.0000000000000000e-01 + - NODE 5 COORD 5.0000000000000000e-01 -5.0000000000000000e-01 5.0000000000000000e-01 + - NODE 6 COORD 5.0000000000000000e-01 -5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 7 COORD 5.0000000000000000e-01 5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 8 COORD 5.0000000000000000e-01 5.0000000000000000e-01 5.0000000000000000e-01 +STRUCTURE ELEMENTS: + - 1 SOLID HEX8 1 2 3 4 5 6 7 8 MAT 1 KINEM nonlinear FIBER1 0 0 1.0 diff --git a/tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_equiv_stress_history_with_restart.4C.yaml b/tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_equiv_stress_history_with_restart.4C.yaml new file mode 100644 index 00000000000..8e1c22556df --- /dev/null +++ b/tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_equiv_stress_history_with_restart.4C.yaml @@ -0,0 +1,208 @@ +TITLE: + - "Simulation of a viscoplastic HEX8 element under uniaxial tension with a constant strain rate of $1 + \\ \\mathrm{s}^{-1}$, as shown in Ana, Schmidt, Wall: Accelerating Local Newton--Raphson Schemes in + Computational Plasticity / Viscoplasticity." + - "The Adaptive Estimate Interpolation scheme is used for local time integration, in order to determine + efficient initial and updated estimates (due to re-estimations) for the Local Newton--Raphson procedure." + - "The accumulated plastic strain of the estimates is integrated according to its evolution equation, + consistent with the interpolated elastic deformation gradient." + - "The starting point of the adaptive estimate interpolation procedure for the next timestep is set + using the solution equivalent stress, in relation to the elastic and plastic predictors (I_HIST variant + in the paper)." + - "A smaller timestep is used compared to the referenced publication, to also test restarts using the + Adaptive Estimate Interpolation." +PROBLEM TYPE: + PROBLEMTYPE: "Structure" +IO: + STRUCT_STRESS: "Cauchy" + STRUCT_STRAIN: "log" + STDOUTEVERY: 1 + VERBOSITY: minimal +IO/RUNTIME VTK OUTPUT/STRUCTURE: + OUTPUT_STRUCTURE: true + DISPLACEMENT: true + STRESS_STRAIN: true + GAUSS_POINT_DATA_OUTPUT_TYPE: gauss_points +IO/RUNTIME VTK OUTPUT: + EVERY_ITERATION: false + INTERVAL_STEPS: 1 +STRUCTURAL DYNAMIC: + INT_STRATEGY: "Standard" + DYNAMICTYPE: "Statics" + RESTARTEVERY: 1 + TIMESTEP: 0.1 + NUMSTEP: 5000000 + MAXTIME: 1.0 + TOLDISP: 1e-06 + NORM_DISP: Abs + TOLRES: 1e-06 + NORM_RESF: Abs + NEGLECTINERTIA: true + LINEAR_SOLVER: 1 +SOLVER 1: + SOLVER: "UMFPACK" +FUNCT1: + - COMPONENT: 0 + SYMBOLIC_FUNCTION_OF_SPACE_TIME: "a" + - VARIABLE: 0 + NAME: "a" + TYPE: "multifunction" + NUMPOINTS: 2 + TIMES: [0.0, 1.6e+16] + DESCRIPTION: ["exp(1.0 * t) - 1.0"] +MATERIALS: + - MAT: 1 + MAT_MultiplicativeSplitDefgradElastHyper: + NUMMATEL: 1 + MATIDSEL: [2] + NUMFACINEL: 1 + INELDEFGRADFACIDS: [3] + DENS: 7830 + - MAT: 2 + ELAST_CoupSVK: + YOUNG: 2.0e5 + NUE: 0.29 + - MAT: 3 + MAT_InelasticDefgradTransvIsotropElastViscoplast: + VISCOPLAST_LAW_ID: 4 + FIBER_READER_ID: 5 + MAT_BEHAVIOR: "isotropic" + TIME_INTEGRATION_HIST_VARS: logarithmic + LOCAL_NEWTON: + CONV_CHECK: residual_and_increment_ratio + MAX_ITER: 100 + RES_TOL: 1.0e-10 + INCR_TOL: 1.0e-10 + DIVER_CONT: stop + ERROR_REGISTRATION_SETTINGS: + MAX_PLASTIC_STRAIN_INCR: 1.0e12 + ADAPTIVE_ESTIMATE_INTERPOLATION: + USE_ADAPTIVE_ESTIMATE_INTERPOLATION: true + ELASTIC_PREDICTOR_ZERO_COMPONENT_THRESHOLD: 1e-13 + PLASTIC_PREDICTOR_CONSTRUCTION: + ELASTIC_STRETCH_EIGENVAL_TYPE: scale_unit + ELASTIC_STRETCH_EIGENVECT_TYPE: from_elastic_predictor + ELASTIC_ROTATION_TYPE: from_elastic_predictor + MAX_ITER: 50 + RELATIVE_UNDERSTRESS_TOL: 0.000001 + INTERVAL_SCANNING_PARAM: 0.5 + ESTIMATE_INTERPOLATION: + STARTING_POINT_TYPE: equiv_stress_history + MAX_ITER: 50 + INTERVAL_SCANNING_PARAM: 0.5 + HARDENING_MANAGEMENT: + METHOD: integrate_via_evolution_equations + MAX_ITER_INTEGRATION: 50 + TOL_INTEGRATION: 1e-8 + REESTIMATION: + MAX_NUM_REESTIMATIONS: 10 + INTERVAL_SCANNING_PARAM: 0.5 + - MAT: 4 + MAT_ViscoplasticLawReformulatedJohnsonCook: + STRAIN_RATE_PREFAC: 1 + STRAIN_RATE_EXP_FAC: 0.014 + INIT_YIELD_STRENGTH: 792.0 + ISOTROP_HARDEN_PREFAC: 510.0 + ISOTROP_HARDEN_EXP: 0.26 + REF_TEMPERATURE: 293 + MELT_TEMPERATURE: 1000 + TEMPERATURE_SENS: 0.1 + - MAT: 5 + ELAST_CoupTransverselyIsotropic: + ALPHA: 1 + BETA: 1 + GAMMA: 1 + ANGLE: 0 + STR_TENS_ID: 100 + - MAT: 100 + ELAST_StructuralTensor: + STRATEGY: "Standard" +DESIGN POINT DIRICH CONDITIONS: + - E: 1 + NUMDOF: 3 + ONOFF: [1, 1, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] + - E: 2 + NUMDOF: 3 + ONOFF: [1, 1, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 3 + NUMDOF: 3 + ONOFF: [1, 0, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 4 + NUMDOF: 3 + ONOFF: [1, 0, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] + - E: 5 + NUMDOF: 3 + ONOFF: [0, 1, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] + - E: 6 + NUMDOF: 3 + ONOFF: [0, 1, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 7 + NUMDOF: 3 + ONOFF: [0, 0, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 8 + NUMDOF: 3 + ONOFF: [0, 0, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] +DNODE-NODE TOPOLOGY: + - NODE 1 DNODE 1 + - NODE 2 DNODE 2 + - NODE 3 DNODE 3 + - NODE 4 DNODE 4 + - NODE 5 DNODE 5 + - NODE 6 DNODE 6 + - NODE 7 DNODE 7 + - NODE 8 DNODE 8 +DLINE-NODE TOPOLOGY: + - NODE 1 DLINE 1 + - NODE 4 DLINE 1 + - NODE 1 DLINE 2 + - NODE 5 DLINE 2 + - NODE 1 DLINE 3 + - NODE 2 DLINE 3 + - NODE 2 DLINE 4 + - NODE 3 DLINE 4 + - NODE 2 DLINE 5 + - NODE 6 DLINE 5 +DSURF-NODE TOPOLOGY: + - NODE 1 DSURFACE 1 + - NODE 4 DSURFACE 1 + - NODE 5 DSURFACE 1 + - NODE 8 DSURFACE 1 + - NODE 2 DSURFACE 2 + - NODE 3 DSURFACE 2 + - NODE 6 DSURFACE 2 + - NODE 7 DSURFACE 2 + - NODE 1 DSURFACE 3 + - NODE 2 DSURFACE 3 + - NODE 3 DSURFACE 3 + - NODE 4 DSURFACE 3 + - NODE 1 DSURFACE 4 + - NODE 2 DSURFACE 4 + - NODE 5 DSURFACE 4 + - NODE 6 DSURFACE 4 +NODE COORDS: + - NODE 1 COORD -5.0000000000000000e-01 -5.0000000000000000e-01 5.0000000000000000e-01 + - NODE 2 COORD -5.0000000000000000e-01 -5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 3 COORD -5.0000000000000000e-01 5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 4 COORD -5.0000000000000000e-01 5.0000000000000000e-01 5.0000000000000000e-01 + - NODE 5 COORD 5.0000000000000000e-01 -5.0000000000000000e-01 5.0000000000000000e-01 + - NODE 6 COORD 5.0000000000000000e-01 -5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 7 COORD 5.0000000000000000e-01 5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 8 COORD 5.0000000000000000e-01 5.0000000000000000e-01 5.0000000000000000e-01 +STRUCTURE ELEMENTS: + - 1 SOLID HEX8 1 2 3 4 5 6 7 8 MAT 1 KINEM nonlinear FIBER1 0 0 1.0 diff --git a/tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_user_set_starting_point_no_restart.4C.yaml b/tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_user_set_starting_point_no_restart.4C.yaml new file mode 100644 index 00000000000..4e07c2e8a6a --- /dev/null +++ b/tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_user_set_starting_point_no_restart.4C.yaml @@ -0,0 +1,201 @@ +TITLE: + - "Simulation of a viscoplastic HEX8 element under uniaxial tension with a constant strain rate of $1 + \\ \\mathrm{s}^{-1}$, as shown in Ana, Schmidt, Wall: Accelerating Local Newton--Raphson Schemes in + Computational Plasticity / Viscoplasticity." + - "The Adaptive Estimate Interpolation scheme is used for local time integration, in order to determine + efficient initial and updated estimates (due to re-estimations) for the Local Newton--Raphson procedure." + - "The accumulated plastic strain of the estimates is integrated according to its evolution equation, + consistent with the interpolated elastic deformation gradient." + - "The starting point of the Adaptive Estimate Interpolation procedure is user-set as 0.5, in the center + between both predictors (I_CONST variant in the paper)." +PROBLEM TYPE: + PROBLEMTYPE: "Structure" +IO: + STRUCT_STRESS: "Cauchy" + STRUCT_STRAIN: "LOG" +IO/RUNTIME VTK OUTPUT/STRUCTURE: + OUTPUT_STRUCTURE: true + DISPLACEMENT: true + STRESS_STRAIN: true +IO/RUNTIME VTK OUTPUT: + INTERVAL_STEPS: 1 +STRUCTURAL DYNAMIC: + DYNAMICTYPE: "Statics" + RESTARTEVERY: 1 + TIMESTEP: 1 + NUMSTEP: 5000000 + MAXTIME: 1.0 + TOLDISP: 1e-06 + NORM_DISP: Abs + TOLRES: 1e-06 + NORM_RESF: Abs + NEGLECTINERTIA: true + LINEAR_SOLVER: 1 +SOLVER 1: + SOLVER: "UMFPACK" +FUNCT1: + - COMPONENT: 0 + SYMBOLIC_FUNCTION_OF_SPACE_TIME: "a" + - VARIABLE: 0 + NAME: "a" + TYPE: "multifunction" + NUMPOINTS: 2 + TIMES: [0.0, 1.6e+16] + DESCRIPTION: ["exp(1.0 * t) - 1.0"] +MATERIALS: + - MAT: 1 + MAT_MultiplicativeSplitDefgradElastHyper: + NUMMATEL: 1 + MATIDSEL: [2] + NUMFACINEL: 1 + INELDEFGRADFACIDS: [3] + DENS: 7830 + - MAT: 2 + ELAST_CoupSVK: + YOUNG: 2.0e5 + NUE: 0.29 + - MAT: 3 + MAT_InelasticDefgradTransvIsotropElastViscoplast: + VISCOPLAST_LAW_ID: 4 + FIBER_READER_ID: 5 + MAT_BEHAVIOR: "isotropic" + TIME_INTEGRATION_HIST_VARS: logarithmic + LOCAL_NEWTON: + CONV_CHECK: residual_and_increment_ratio + MAX_ITER: 100 + RES_TOL: 1.0e-10 + INCR_TOL: 1.0e-10 + DIVER_CONT: stop + ERROR_REGISTRATION_SETTINGS: + MAX_PLASTIC_STRAIN_INCR: 1.0e12 + ADAPTIVE_ESTIMATE_INTERPOLATION: + USE_ADAPTIVE_ESTIMATE_INTERPOLATION: true + ELASTIC_PREDICTOR_ZERO_COMPONENT_THRESHOLD: 1e-13 + PLASTIC_PREDICTOR_CONSTRUCTION: + ELASTIC_STRETCH_EIGENVAL_TYPE: scale_unit + ELASTIC_STRETCH_EIGENVECT_TYPE: from_elastic_predictor + ELASTIC_ROTATION_TYPE: from_elastic_predictor + MAX_ITER: 50 + RELATIVE_UNDERSTRESS_TOL: 0.000001 + INTERVAL_SCANNING_PARAM: 0.5 + ESTIMATE_INTERPOLATION: + STARTING_POINT_TYPE: constant + USER_SET_STARTING_POINT: 0.5 + MAX_ITER: 50 + INTERVAL_SCANNING_PARAM: 0.5 + HARDENING_MANAGEMENT: + METHOD: integrate_via_evolution_equations + MAX_ITER_INTEGRATION: 50 + TOL_INTEGRATION: 1e-8 + REESTIMATION: + MAX_NUM_REESTIMATIONS: 10 + INTERVAL_SCANNING_PARAM: 0.5 + - MAT: 4 + MAT_ViscoplasticLawReformulatedJohnsonCook: + STRAIN_RATE_PREFAC: 1 + STRAIN_RATE_EXP_FAC: 0.014 + INIT_YIELD_STRENGTH: 792.0 + ISOTROP_HARDEN_PREFAC: 510.0 + ISOTROP_HARDEN_EXP: 0.26 + REF_TEMPERATURE: 293 + MELT_TEMPERATURE: 1000 + TEMPERATURE_SENS: 0.1 + - MAT: 5 + ELAST_CoupTransverselyIsotropic: + ALPHA: 1 + BETA: 1 + GAMMA: 1 + ANGLE: 0 + STR_TENS_ID: 100 + - MAT: 100 + ELAST_StructuralTensor: + STRATEGY: "Standard" +DESIGN POINT DIRICH CONDITIONS: + - E: 1 + NUMDOF: 3 + ONOFF: [1, 1, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] + - E: 2 + NUMDOF: 3 + ONOFF: [1, 1, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 3 + NUMDOF: 3 + ONOFF: [1, 0, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 4 + NUMDOF: 3 + ONOFF: [1, 0, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] + - E: 5 + NUMDOF: 3 + ONOFF: [0, 1, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] + - E: 6 + NUMDOF: 3 + ONOFF: [0, 1, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 7 + NUMDOF: 3 + ONOFF: [0, 0, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 8 + NUMDOF: 3 + ONOFF: [0, 0, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] +DNODE-NODE TOPOLOGY: + - NODE 1 DNODE 1 + - NODE 2 DNODE 2 + - NODE 3 DNODE 3 + - NODE 4 DNODE 4 + - NODE 5 DNODE 5 + - NODE 6 DNODE 6 + - NODE 7 DNODE 7 + - NODE 8 DNODE 8 +DLINE-NODE TOPOLOGY: + - NODE 1 DLINE 1 + - NODE 4 DLINE 1 + - NODE 1 DLINE 2 + - NODE 5 DLINE 2 + - NODE 1 DLINE 3 + - NODE 2 DLINE 3 + - NODE 2 DLINE 4 + - NODE 3 DLINE 4 + - NODE 2 DLINE 5 + - NODE 6 DLINE 5 +DSURF-NODE TOPOLOGY: + - NODE 1 DSURFACE 1 + - NODE 4 DSURFACE 1 + - NODE 5 DSURFACE 1 + - NODE 8 DSURFACE 1 + - NODE 2 DSURFACE 2 + - NODE 3 DSURFACE 2 + - NODE 6 DSURFACE 2 + - NODE 7 DSURFACE 2 + - NODE 1 DSURFACE 3 + - NODE 2 DSURFACE 3 + - NODE 3 DSURFACE 3 + - NODE 4 DSURFACE 3 + - NODE 1 DSURFACE 4 + - NODE 2 DSURFACE 4 + - NODE 5 DSURFACE 4 + - NODE 6 DSURFACE 4 +NODE COORDS: + - NODE 1 COORD -5.0000000000000000e-01 -5.0000000000000000e-01 5.0000000000000000e-01 + - NODE 2 COORD -5.0000000000000000e-01 -5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 3 COORD -5.0000000000000000e-01 5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 4 COORD -5.0000000000000000e-01 5.0000000000000000e-01 5.0000000000000000e-01 + - NODE 5 COORD 5.0000000000000000e-01 -5.0000000000000000e-01 5.0000000000000000e-01 + - NODE 6 COORD 5.0000000000000000e-01 -5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 7 COORD 5.0000000000000000e-01 5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 8 COORD 5.0000000000000000e-01 5.0000000000000000e-01 5.0000000000000000e-01 +STRUCTURE ELEMENTS: + - 1 SOLID HEX8 1 2 3 4 5 6 7 8 MAT 1 KINEM nonlinear FIBER1 0 0 1.0 diff --git a/tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_user_set_starting_point_with_restart.4C.yaml b/tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_user_set_starting_point_with_restart.4C.yaml new file mode 100644 index 00000000000..ddaf2765bb6 --- /dev/null +++ b/tests/input_files/mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_user_set_starting_point_with_restart.4C.yaml @@ -0,0 +1,203 @@ +TITLE: + - "Simulation of a viscoplastic HEX8 element under uniaxial tension with a constant strain rate of $1 + \\ \\mathrm{s}^{-1}$, as shown in Ana, Schmidt, Wall: Accelerating Local Newton--Raphson Schemes in + Computational Plasticity / Viscoplasticity." + - "The Adaptive Estimate Interpolation scheme is used for local time integration, in order to determine + efficient initial and updated estimates (due to re-estimations) for the Local Newton--Raphson procedure." + - "The accumulated plastic strain of the estimates is integrated according to its evolution equation, + consistent with the interpolated elastic deformation gradient." + - "The starting point of the Adaptive Estimate Interpolation procedure is user-set as 0.5, in the center + between both predictors (I_CONST variant in the paper)." + - "A smaller timestep is used compared to the referenced publication, to also test restarts using the + Adaptive Estimate Interpolation." +PROBLEM TYPE: + PROBLEMTYPE: "Structure" +IO: + STRUCT_STRESS: "Cauchy" + STRUCT_STRAIN: "LOG" +IO/RUNTIME VTK OUTPUT/STRUCTURE: + OUTPUT_STRUCTURE: true + DISPLACEMENT: true + STRESS_STRAIN: true +IO/RUNTIME VTK OUTPUT: + INTERVAL_STEPS: 1 +STRUCTURAL DYNAMIC: + DYNAMICTYPE: "Statics" + RESTARTEVERY: 1 + TIMESTEP: 0.1 + NUMSTEP: 5000000 + MAXTIME: 1.0 + TOLDISP: 1e-06 + NORM_DISP: Abs + TOLRES: 1e-06 + NORM_RESF: Abs + NEGLECTINERTIA: true + LINEAR_SOLVER: 1 +SOLVER 1: + SOLVER: "UMFPACK" +FUNCT1: + - COMPONENT: 0 + SYMBOLIC_FUNCTION_OF_SPACE_TIME: "a" + - VARIABLE: 0 + NAME: "a" + TYPE: "multifunction" + NUMPOINTS: 2 + TIMES: [0.0, 1.6e+16] + DESCRIPTION: ["exp(1.0 * t) - 1.0"] +MATERIALS: + - MAT: 1 + MAT_MultiplicativeSplitDefgradElastHyper: + NUMMATEL: 1 + MATIDSEL: [2] + NUMFACINEL: 1 + INELDEFGRADFACIDS: [3] + DENS: 7830 + - MAT: 2 + ELAST_CoupSVK: + YOUNG: 2.0e5 + NUE: 0.29 + - MAT: 3 + MAT_InelasticDefgradTransvIsotropElastViscoplast: + VISCOPLAST_LAW_ID: 4 + FIBER_READER_ID: 5 + MAT_BEHAVIOR: "isotropic" + TIME_INTEGRATION_HIST_VARS: logarithmic + LOCAL_NEWTON: + CONV_CHECK: residual_and_increment_ratio + MAX_ITER: 100 + RES_TOL: 1.0e-10 + INCR_TOL: 1.0e-10 + DIVER_CONT: stop + ERROR_REGISTRATION_SETTINGS: + MAX_PLASTIC_STRAIN_INCR: 1.0e12 + ADAPTIVE_ESTIMATE_INTERPOLATION: + USE_ADAPTIVE_ESTIMATE_INTERPOLATION: true + ELASTIC_PREDICTOR_ZERO_COMPONENT_THRESHOLD: 1e-13 + PLASTIC_PREDICTOR_CONSTRUCTION: + ELASTIC_STRETCH_EIGENVAL_TYPE: scale_unit + ELASTIC_STRETCH_EIGENVECT_TYPE: from_elastic_predictor + ELASTIC_ROTATION_TYPE: from_elastic_predictor + MAX_ITER: 50 + RELATIVE_UNDERSTRESS_TOL: 0.000001 + INTERVAL_SCANNING_PARAM: 0.5 + ESTIMATE_INTERPOLATION: + STARTING_POINT_TYPE: constant + USER_SET_STARTING_POINT: 0.5 + MAX_ITER: 50 + INTERVAL_SCANNING_PARAM: 0.5 + HARDENING_MANAGEMENT: + METHOD: integrate_via_evolution_equations + MAX_ITER_INTEGRATION: 50 + TOL_INTEGRATION: 1e-8 + REESTIMATION: + MAX_NUM_REESTIMATIONS: 10 + INTERVAL_SCANNING_PARAM: 0.5 + - MAT: 4 + MAT_ViscoplasticLawReformulatedJohnsonCook: + STRAIN_RATE_PREFAC: 1 + STRAIN_RATE_EXP_FAC: 0.014 + INIT_YIELD_STRENGTH: 792.0 + ISOTROP_HARDEN_PREFAC: 510.0 + ISOTROP_HARDEN_EXP: 0.26 + REF_TEMPERATURE: 293 + MELT_TEMPERATURE: 1000 + TEMPERATURE_SENS: 0.1 + - MAT: 5 + ELAST_CoupTransverselyIsotropic: + ALPHA: 1 + BETA: 1 + GAMMA: 1 + ANGLE: 0 + STR_TENS_ID: 100 + - MAT: 100 + ELAST_StructuralTensor: + STRATEGY: "Standard" +DESIGN POINT DIRICH CONDITIONS: + - E: 1 + NUMDOF: 3 + ONOFF: [1, 1, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] + - E: 2 + NUMDOF: 3 + ONOFF: [1, 1, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 3 + NUMDOF: 3 + ONOFF: [1, 0, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 4 + NUMDOF: 3 + ONOFF: [1, 0, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] + - E: 5 + NUMDOF: 3 + ONOFF: [0, 1, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] + - E: 6 + NUMDOF: 3 + ONOFF: [0, 1, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 7 + NUMDOF: 3 + ONOFF: [0, 0, 1] + VAL: [0, 0, 0] + FUNCT: [null, null, null] + - E: 8 + NUMDOF: 3 + ONOFF: [0, 0, 1] + VAL: [0, 0, 1] + FUNCT: [null, null, 1] +DNODE-NODE TOPOLOGY: + - NODE 1 DNODE 1 + - NODE 2 DNODE 2 + - NODE 3 DNODE 3 + - NODE 4 DNODE 4 + - NODE 5 DNODE 5 + - NODE 6 DNODE 6 + - NODE 7 DNODE 7 + - NODE 8 DNODE 8 +DLINE-NODE TOPOLOGY: + - NODE 1 DLINE 1 + - NODE 4 DLINE 1 + - NODE 1 DLINE 2 + - NODE 5 DLINE 2 + - NODE 1 DLINE 3 + - NODE 2 DLINE 3 + - NODE 2 DLINE 4 + - NODE 3 DLINE 4 + - NODE 2 DLINE 5 + - NODE 6 DLINE 5 +DSURF-NODE TOPOLOGY: + - NODE 1 DSURFACE 1 + - NODE 4 DSURFACE 1 + - NODE 5 DSURFACE 1 + - NODE 8 DSURFACE 1 + - NODE 2 DSURFACE 2 + - NODE 3 DSURFACE 2 + - NODE 6 DSURFACE 2 + - NODE 7 DSURFACE 2 + - NODE 1 DSURFACE 3 + - NODE 2 DSURFACE 3 + - NODE 3 DSURFACE 3 + - NODE 4 DSURFACE 3 + - NODE 1 DSURFACE 4 + - NODE 2 DSURFACE 4 + - NODE 5 DSURFACE 4 + - NODE 6 DSURFACE 4 +NODE COORDS: + - NODE 1 COORD -5.0000000000000000e-01 -5.0000000000000000e-01 5.0000000000000000e-01 + - NODE 2 COORD -5.0000000000000000e-01 -5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 3 COORD -5.0000000000000000e-01 5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 4 COORD -5.0000000000000000e-01 5.0000000000000000e-01 5.0000000000000000e-01 + - NODE 5 COORD 5.0000000000000000e-01 -5.0000000000000000e-01 5.0000000000000000e-01 + - NODE 6 COORD 5.0000000000000000e-01 -5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 7 COORD 5.0000000000000000e-01 5.0000000000000000e-01 -5.0000000000000000e-01 + - NODE 8 COORD 5.0000000000000000e-01 5.0000000000000000e-01 5.0000000000000000e-01 +STRUCTURE ELEMENTS: + - 1 SOLID HEX8 1 2 3 4 5 6 7 8 MAT 1 KINEM nonlinear FIBER1 0 0 1.0 diff --git a/tests/input_files/mat_iso_viscoplast_refJC_log_timint_substepping.4C.yaml b/tests/input_files/mat_iso_viscoplast_refJC_log_timint_substepping.4C.yaml index 7a2a3b78b26..1849510eec7 100644 --- a/tests/input_files/mat_iso_viscoplast_refJC_log_timint_substepping.4C.yaml +++ b/tests/input_files/mat_iso_viscoplast_refJC_log_timint_substepping.4C.yaml @@ -10,7 +10,9 @@ TITLE: - "- time integration of internal variables using logarithmic substepping, as shown in:" - "Ana: Continuum Modeling and Calibration of Viscoplasticity in the Context" - "of the Lithium Anode in Solid-State Batteries" - - "(Master's Thesis, Institute for Computational Mechanics, TU Munich, 2024)" + - "(Master's Thesis, Institute for Computational Mechanics, TU Munich, 2024)." + - "The Adaptive Estimate Interpolation algorithm presented in Ana, Schmidt, Wall: Accelerating Local + Newton--Raphson Schemes in Computational Plasticity / Viscoplasticity is not used in this test." PROBLEM TYPE: PROBLEMTYPE: "Structure" IO: @@ -62,6 +64,8 @@ MATERIALS: MAX_EXCEEDANCE_FACT_RES_TOL: 10 MAX_EXCEEDANCE_FACT_INCR_TOL: 10 DIVER_CONT: stop + ADAPTIVE_ESTIMATE_INTERPOLATION: + USE_ADAPTIVE_ESTIMATE_INTERPOLATION: false - MAT: 4 MAT_ViscoplasticLawReformulatedJohnsonCook: STRAIN_RATE_PREFAC: 1 diff --git a/tests/input_files/mat_transviso_viscoplast_refJC_log_timint.4C.yaml b/tests/input_files/mat_transviso_viscoplast_refJC_log_timint.4C.yaml index 83fd47d7f5c..aff614da775 100644 --- a/tests/input_files/mat_transviso_viscoplast_refJC_log_timint.4C.yaml +++ b/tests/input_files/mat_transviso_viscoplast_refJC_log_timint.4C.yaml @@ -10,7 +10,9 @@ TITLE: - "- time integration of internal variables using logarithmic substepping, as shown in:" - "Ana: Continuum Modeling and Calibration of Viscoplasticity in the Context" - "of the Lithium Anode in Solid-State Batteries" - - "(Master's Thesis, Institute for Computational Mechanics, TU Munich, 2024)" + - "(Master's Thesis, Institute for Computational Mechanics, TU Munich, 2024)." + - "The Adaptive Estimate Interpolation algorithm presented in Ana, Schmidt, Wall: Accelerating Local + Newton--Raphson Schemes in Computational Plasticity / Viscoplasticity is not used in this test." PROBLEM TYPE: PROBLEMTYPE: "Structure" IO: @@ -62,7 +64,8 @@ MATERIALS: MAX_EXCEEDANCE_FACT_RES_TOL: 10 MAX_EXCEEDANCE_FACT_INCR_TOL: 10 DIVER_CONT: stop - + ADAPTIVE_ESTIMATE_INTERPOLATION: + USE_ADAPTIVE_ESTIMATE_INTERPOLATION: false - MAT: 4 MAT_ViscoplasticLawReformulatedJohnsonCook: STRAIN_RATE_PREFAC: 1 diff --git a/tests/input_files/mat_transviso_viscoplast_refJC_standard_timint.4C.yaml b/tests/input_files/mat_transviso_viscoplast_refJC_standard_timint.4C.yaml index e3faee50ebd..7e9680c8b7a 100644 --- a/tests/input_files/mat_transviso_viscoplast_refJC_standard_timint.4C.yaml +++ b/tests/input_files/mat_transviso_viscoplast_refJC_standard_timint.4C.yaml @@ -10,7 +10,9 @@ TITLE: - "- time integration of internal variables using standard substepping, as shown in:" - "Ana: Continuum Modeling and Calibration of Viscoplasticity in the Context" - "of the Lithium Anode in Solid-State Batteries" - - "(Master's Thesis, Institute for Computational Mechanics, TU Munich, 2024)" + - "(Master's Thesis, Institute for Computational Mechanics, TU Munich, 2024)." + - "The Adaptive Estimate Interpolation algorithm presented in Ana, Schmidt, Wall: Accelerating Local + Newton--Raphson Schemes in Computational Plasticity / Viscoplasticity is not used in this test." PROBLEM TYPE: PROBLEMTYPE: "Structure" IO: @@ -62,7 +64,8 @@ MATERIALS: MAX_EXCEEDANCE_FACT_RES_TOL: 10 MAX_EXCEEDANCE_FACT_INCR_TOL: 10 DIVER_CONT: stop - + ADAPTIVE_ESTIMATE_INTERPOLATION: + USE_ADAPTIVE_ESTIMATE_INTERPOLATION: false - MAT: 4 MAT_ViscoplasticLawReformulatedJohnsonCook: STRAIN_RATE_PREFAC: 1 diff --git a/tests/list_of_tests.cmake b/tests/list_of_tests.cmake index c11df3231cc..bc572881fa7 100644 --- a/tests/list_of_tests.cmake +++ b/tests/list_of_tests.cmake @@ -915,6 +915,12 @@ four_c_test(TEST_FILE mat_iso_thermoviscoplast_refJC_log_timint_tsi_monolithic.4 __four_c_test_restart(BASED_ON ${current} SAME_FILE RESTART_STEP 90) four_c_test(TEST_FILE mat_iso_thermoviscoplast_refJC_log_timint_tsi_partitioned.4C.yaml RETURN_AS current) __four_c_test_restart(BASED_ON ${current} SAME_FILE RESTART_STEP 90) +four_c_test(TEST_FILE mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_equiv_stress_history_no_restart.4C.yaml RETURN_AS current) +four_c_test(TEST_FILE mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_equiv_stress_history_with_restart.4C.yaml NP 2 RETURN_AS current) +__four_c_test_restart(BASED_ON ${current} SAME_FILE NP 2 RESTART_STEP 9) +four_c_test(TEST_FILE mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_user_set_starting_point_no_restart.4C.yaml RETURN_AS current) +four_c_test(TEST_FILE mat_iso_viscoplast_refJC_log_timint_adaptive_estimate_interp_user_set_starting_point_with_restart.4C.yaml NP 2 RETURN_AS current) +__four_c_test_restart(BASED_ON ${current} SAME_FILE NP 2 RESTART_STEP 9) four_c_test(TEST_FILE mat_muscle_combo_hex.4C.yaml NP 2 RETURN_AS current) __four_c_test_restart(BASED_ON ${current} SAME_FILE NP 2 RESTART_STEP 140) four_c_test(TEST_FILE mat_muscle_combo_hex_act_map_every_timestep.4C.yaml NP 2 RETURN_AS current)