From 0854da74892c07442eb17f51311fb7ef3ca84d7c Mon Sep 17 00:00:00 2001 From: Dmitri Naumov <github@naumov.de> Date: Tue, 31 Aug 2021 12:24:31 +0200 Subject: [PATCH] [PL/TH2M] Partially implement analytical Jacobian. --- ProcessLib/TH2M/ConstitutiveVariables.h | 50 + ProcessLib/TH2M/IntegrationPointData.h | 1 + .../PhaseTransitionModel.h | 26 + .../PhaseTransitionNone.cpp | 50 + ProcessLib/TH2M/TH2MFEM-impl.h | 978 +++++++++++++++++- 5 files changed, 1095 insertions(+), 10 deletions(-) diff --git a/ProcessLib/TH2M/ConstitutiveVariables.h b/ProcessLib/TH2M/ConstitutiveVariables.h index b8d6276fc7d..c4c9496095e 100644 --- a/ProcessLib/TH2M/ConstitutiveVariables.h +++ b/ProcessLib/TH2M/ConstitutiveVariables.h @@ -20,9 +20,59 @@ struct ConstitutiveVariables { using KelvinMatrixType = MathLib::KelvinVector::KelvinMatrixType<DisplacementDim>; + using DisplacementDimVector = Eigen::Matrix<double, DisplacementDim, 1>; + using DisplacementDimMatrix = + Eigen::Matrix<double, DisplacementDim, DisplacementDim>; KelvinMatrixType C; + DisplacementDimMatrix dlambda_dp_GR; + DisplacementDimMatrix dlambda_dp_cap; + DisplacementDimMatrix dlambda_dT; + DisplacementDimVector drho_GR_h_w_eff_dp_GR_Npart; + DisplacementDimMatrix drho_GR_h_w_eff_dp_GR_gradNpart; + DisplacementDimVector drho_LR_h_w_eff_dp_cap_Npart; + DisplacementDimMatrix drho_LR_h_w_eff_dp_cap_gradNpart; + DisplacementDimVector drho_GR_h_w_eff_dT; + DisplacementDimMatrix dfW_4a_dp_GR; + DisplacementDimMatrix dfW_4a_dp_cap; + DisplacementDimMatrix dfW_4a_dT; + DisplacementDimMatrix dfW_4d_dp_GR; + DisplacementDimMatrix dfW_4d_dp_cap; + DisplacementDimMatrix dfW_4d_dT; + DisplacementDimMatrix dfC_4_LCpG_dT; + DisplacementDimMatrix dadvection_C_dp_GR; + double drho_LR_dT = std::numeric_limits<double>::quiet_NaN(); + double drho_SR_dT = std::numeric_limits<double>::quiet_NaN(); + double drho_u_eff_dT = std::numeric_limits<double>::quiet_NaN(); + double drho_u_eff_dp_GR = std::numeric_limits<double>::quiet_NaN(); + double drho_u_eff_dp_cap = std::numeric_limits<double>::quiet_NaN(); + double drho_h_eff_dT = std::numeric_limits<double>::quiet_NaN(); + double drho_h_eff_dp_GR = std::numeric_limits<double>::quiet_NaN(); + double drho_h_eff_dp_cap = std::numeric_limits<double>::quiet_NaN(); + double dh_G_dT = std::numeric_limits<double>::quiet_NaN(); + double dh_L_dT = std::numeric_limits<double>::quiet_NaN(); + double dfC_4_MCpG_dp_GR = std::numeric_limits<double>::quiet_NaN(); + double dfC_4_MCpG_dT = std::numeric_limits<double>::quiet_NaN(); + double dfC_4_MCT_dT = std::numeric_limits<double>::quiet_NaN(); + double dfC_4_MCu_dT = std::numeric_limits<double>::quiet_NaN(); + double dfC_3a_dp_GR = std::numeric_limits<double>::quiet_NaN(); + double dfC_3a_dp_cap = std::numeric_limits<double>::quiet_NaN(); + double dfC_3a_dT = std::numeric_limits<double>::quiet_NaN(); + double dfC_2a_dp_GR = std::numeric_limits<double>::quiet_NaN(); + double dfC_2a_dp_cap = std::numeric_limits<double>::quiet_NaN(); + double dfC_2a_dT = std::numeric_limits<double>::quiet_NaN(); + double dfW_2a_dp_GR = std::numeric_limits<double>::quiet_NaN(); + double dfW_2b_dp_GR = std::numeric_limits<double>::quiet_NaN(); + double dfW_2a_dp_cap = std::numeric_limits<double>::quiet_NaN(); + double dfW_2b_dp_cap = std::numeric_limits<double>::quiet_NaN(); + double dfW_2a_dT = std::numeric_limits<double>::quiet_NaN(); + double dfW_2b_dT = std::numeric_limits<double>::quiet_NaN(); + double dfW_3a_dp_GR = std::numeric_limits<double>::quiet_NaN(); + double dfW_3a_dp_cap = std::numeric_limits<double>::quiet_NaN(); + double dfW_3a_dT = std::numeric_limits<double>::quiet_NaN(); + double ds_L_dp_cap = std::numeric_limits<double>::quiet_NaN(); + EIGEN_MAKE_ALIGNED_OPERATOR_NEW; }; diff --git a/ProcessLib/TH2M/IntegrationPointData.h b/ProcessLib/TH2M/IntegrationPointData.h index 67100620ddd..2e959a1da3a 100644 --- a/ProcessLib/TH2M/IntegrationPointData.h +++ b/ProcessLib/TH2M/IntegrationPointData.h @@ -122,6 +122,7 @@ struct IntegrationPointData final // porosity double phi = std::numeric_limits<double>::quiet_NaN(); + double dphi_dT = std::numeric_limits<double>::quiet_NaN(); double muGR = std::numeric_limits<double>::quiet_NaN(); double muLR = std::numeric_limits<double>::quiet_NaN(); diff --git a/ProcessLib/TH2M/PhaseTransitionModels/PhaseTransitionModel.h b/ProcessLib/TH2M/PhaseTransitionModels/PhaseTransitionModel.h index 54654ccbb04..b172d3f45d1 100644 --- a/ProcessLib/TH2M/PhaseTransitionModels/PhaseTransitionModel.h +++ b/ProcessLib/TH2M/PhaseTransitionModels/PhaseTransitionModel.h @@ -24,6 +24,23 @@ struct PhaseTransitionModelVariables double rhoCGR = 0.; double rhoWGR = 0.; + double drho_GR_dp_GR = 0.; + double drho_GR_dT = 0.; + double drho_C_GR_dp_GR = 0.; + double drho_C_GR_dT = 0.; + double drho_LR_dp_GR = 0.; + double drho_LR_dp_LR = 0.; + double drho_C_LR_dp_GR = 0.; + double drho_C_LR_dp_LR = 0.; + double drho_C_LR_dT = 0.; + + double drho_W_LR_dp_LR = 0.; + double drho_W_LR_dp_GR = 0.; + double drho_W_GR_dT = 0.; + double drho_W_LR_dT = 0.; + double drho_W_GR_dp_GR = 0.; + double drho_W_GR_dp_cap = 0.; + // liquid phase density double rhoLR = 0.; double rhoWLR = 0.; @@ -71,9 +88,18 @@ struct PhaseTransitionModelVariables double hWG = 0; double hL = 0; + double dh_G_dT = 0; + double dh_L_dT = 0; + // specific inner energies double uG = 0; double uL = 0; + + double du_G_dT = 0; + double du_L_dT = 0; + double du_G_dp_GR = 0; + double du_L_dp_GR = 0; + double du_L_dp_cap = 0; }; struct PhaseTransitionModel diff --git a/ProcessLib/TH2M/PhaseTransitionModels/PhaseTransitionNone.cpp b/ProcessLib/TH2M/PhaseTransitionModels/PhaseTransitionNone.cpp index def1a73daf3..9ce4254b4fe 100644 --- a/ProcessLib/TH2M/PhaseTransitionModels/PhaseTransitionNone.cpp +++ b/ProcessLib/TH2M/PhaseTransitionModels/PhaseTransitionNone.cpp @@ -107,11 +107,61 @@ PhaseTransitionModelVariables PhaseTransitionNone::updateConstitutiveVariables( // specific phase enthalpies cv.hG = cpG * T; cv.hL = cpL * T; + cv.dh_G_dT = cpG; + cv.dh_L_dT = cpL; // specific inner energies cv.uG = cv.hG - pGR / cv.rhoGR; cv.uL = cv.hL; + auto const drho_GR_dT = + gas_phase[MaterialPropertyLib::PropertyType::density] + .template dValue<double>(variables, + MaterialPropertyLib::Variable::temperature, + pos, t, dt); + cv.du_G_dT = cpG + pGR * drho_GR_dT / cv.rhoGR / cv.rhoGR; + + cv.du_L_dT = cpL; + + cv.drho_GR_dp_GR = + gas_phase.property(MaterialPropertyLib::PropertyType::density) + .template dValue<double>( + variables, MaterialPropertyLib::Variable::phase_pressure, pos, + t, dt); + cv.drho_LR_dp_LR = + liquid_phase[MaterialPropertyLib::PropertyType::density] + .template dValue<double>( + variables, MaterialPropertyLib::Variable::liquid_phase_pressure, + pos, t, dt); + cv.drho_LR_dp_GR = cv.drho_LR_dp_LR; + + cv.du_G_dp_GR = + -1 / cv.rhoGR + pGR * cv.drho_GR_dp_GR / cv.rhoGR / cv.rhoGR; + + cv.drho_C_GR_dp_GR = cv.drho_GR_dp_GR; + cv.drho_C_LR_dp_LR = 0; + cv.drho_C_LR_dp_GR = 0; + cv.drho_C_GR_dT = drho_GR_dT; + + auto const drho_LR_dT = + liquid_phase[MaterialPropertyLib::PropertyType::density] + .template dValue<double>(variables, + MaterialPropertyLib::Variable::temperature, + pos, t, dt); + cv.drho_C_LR_dT = 0; + + cv.du_L_dp_GR = 0; + cv.du_L_dp_cap = 0; + /* TODO update to the following when uL has same structure as the uG: + +-1 / cv.rhoLR + pLR * cv.drho_LR_dp_cap / cv.rhoLR / cv.rhoLR; + */ + + cv.drho_W_LR_dp_LR = cv.drho_LR_dp_LR; + cv.drho_W_LR_dp_GR = cv.drho_LR_dp_GR; + cv.drho_W_LR_dT = drho_LR_dT; + cv.drho_W_GR_dT = 0; + cv.drho_W_GR_dp_GR = 0; + cv.drho_W_GR_dp_cap = 0; return cv; } } // namespace TH2M diff --git a/ProcessLib/TH2M/TH2MFEM-impl.h b/ProcessLib/TH2M/TH2MFEM-impl.h index 9f4f9471951..d7763bb9713 100644 --- a/ProcessLib/TH2M/TH2MFEM-impl.h +++ b/ProcessLib/TH2M/TH2MFEM-impl.h @@ -125,6 +125,8 @@ TH2MLocalAssembler<ShapeFunctionDisplacement, ShapeFunctionPressure, pos.setElementID(_element.getID()); auto const& medium = *_process_data.media_map->getMedium(_element.getID()); + auto const& gas_phase = medium.phase("Gas"); + auto const& liquid_phase = medium.phase("AqueousLiquid"); auto const& solid_phase = medium.phase("Solid"); unsigned const n_integration_points = @@ -143,7 +145,7 @@ TH2MLocalAssembler<ShapeFunctionDisplacement, ShapeFunctionPressure, auto const& NT = Np; auto const& Nu = ip_data.N_u; auto const& gradNu = ip_data.dNdx_u; - + auto const& gradNp = ip_data.dNdx_p; auto const x_coord = NumLib::interpolateXCoordinate<ShapeFunctionDisplacement, ShapeMatricesTypeDisplacement>( @@ -153,6 +155,8 @@ TH2MLocalAssembler<ShapeFunctionDisplacement, ShapeFunctionPressure, double const pGR = Np.dot(gas_pressure); double const pCap = Np.dot(capillary_pressure); double const pLR = pGR - pCap; + GlobalDimVectorType const gradpGR = gradNp * gas_pressure; + GlobalDimVectorType const gradpCap = gradNp * capillary_pressure; MPL::VariableArray vars; vars[static_cast<int>(MPL::Variable::temperature)] = T; @@ -293,7 +297,7 @@ TH2MLocalAssembler<ShapeFunctionDisplacement, ShapeFunctionPressure, auto const lambdaGR = MPL::formEigenTensor<DisplacementDim>(c.lambdaGR); auto const lambdaLR = MPL::formEigenTensor<DisplacementDim>(c.lambdaLR); - ip_data.lambda = phi_S * lambdaSR + phi_L * lambdaLR + phi_G * lambdaGR; + ip_data.lambda = phi_G * lambdaGR + phi_L * lambdaLR + phi_S * lambdaSR; auto const cpS = solid_phase.property(MPL::PropertyType::specific_heat_capacity) @@ -340,6 +344,275 @@ TH2MLocalAssembler<ShapeFunctionDisplacement, ShapeFunctionPressure, ip_data.h_G = c.hG; ip_data.h_L = c.hL; ip_data.pWGR = c.pWGR; + + // --------------------------------------------------------------------- + // Derivatives for Jacobian + // --------------------------------------------------------------------- + ip_cv.drho_LR_dT = + liquid_phase.property(MPL::PropertyType::density) + .template dValue<double>(vars, MPL::Variable::temperature, pos, + t, dt); + ip_cv.drho_SR_dT = + solid_phase.property(MPL::PropertyType::density) + .template dValue<double>(vars, MPL::Variable::temperature, + pos, t, dt) +#ifdef NON_CONSTANT_SOLID_PHASE_VOLUME_FRACTION + * (1. - ip_data.thermal_volume_strain + + (ip_data.alpha_B - 1.) * div_u) - + rho_ref_SR * ip_data.beta_T_SR +#endif + ; + + // porosity + auto const dphi_0_dT = + medium[MPL::PropertyType::porosity].template dValue<double>( + vars, MPL::Variable::temperature, pos, t, dt); + + auto const dphi_S_0_dT = -dphi_0_dT; + const double dphi_S_dT = dphi_S_0_dT +#ifdef NON_CONSTANT_SOLID_PHASE_VOLUME_FRACTION + * (1. + ip_data.thermal_volume_strain - + ip_data.alpha_B * div_u) + + phi_S_0 * ip_data.beta_T_SR +#endif + ; + + ip_cv.drho_u_eff_dT = + phi_G * c.drho_GR_dT * c.uG + phi_G * c.rhoGR * c.du_G_dT + + phi_L * ip_cv.drho_LR_dT * c.uL + phi_L * c.rhoLR * c.du_L_dT + + phi_S * ip_cv.drho_SR_dT * u_S + phi_S * rhoSR * cpS + + dphi_S_dT * rhoSR * u_S; + + ip_cv.ds_L_dp_cap = + medium[MPL::PropertyType::saturation].template dValue<double>( + vars, MPL::Variable::capillary_pressure, pos, t, dt); + // TODO (naumov) Extend for partially saturated media. + constexpr double ds_L_dp_GR = 0; + double const ds_G_dp_GR = -ds_L_dp_GR; + double const ds_G_dp_cap = -ip_cv.ds_L_dp_cap; + + double const dphi_G_dp_GR = -ds_L_dp_GR * ip_data.phi; + double const dphi_G_dp_cap = -ip_cv.ds_L_dp_cap * ip_data.phi; + double const dphi_L_dp_GR = ds_L_dp_GR * ip_data.phi; + double const dphi_L_dp_cap = ip_cv.ds_L_dp_cap * ip_data.phi; + + auto const dlambda_GR_dT = MPL::formEigenTensor<DisplacementDim>( + gas_phase[MPL::PropertyType::thermal_conductivity].dValue( + vars, MPL::Variable::temperature, pos, t, dt)); + auto const dlambda_LR_dT = MPL::formEigenTensor<DisplacementDim>( + liquid_phase[MPL::PropertyType::thermal_conductivity].dValue( + vars, MPL::Variable::temperature, pos, t, dt)); + auto const dlambda_SR_dT = MPL::formEigenTensor<DisplacementDim>( + solid_phase[MPL::PropertyType::thermal_conductivity].dValue( + vars, MPL::Variable::temperature, pos, t, dt)); + + ip_cv.dlambda_dp_GR = dphi_G_dp_GR * lambdaGR + dphi_L_dp_GR * lambdaLR; + + ip_cv.dlambda_dp_cap = + dphi_G_dp_cap * lambdaGR + dphi_L_dp_cap * lambdaLR; + + ip_cv.dlambda_dT = phi_G * dlambda_GR_dT + phi_L * dlambda_LR_dT + + phi_S * dlambda_SR_dT + dphi_S_dT * lambdaSR; + + // From p_LR = p_GR - p_cap it follows for + // drho_LR/dp_GR = drho_LR/dp_LR * dp_LR/dp_GR + // = drho_LR/dp_LR * (dp_GR/dp_GR - dp_cap/dp_GR) + // = drho_LR/dp_LR * (1 - 0) + double const drho_LR_dp_GR = c.drho_LR_dp_LR; + double const drho_LR_dp_cap = -c.drho_LR_dp_LR; + // And also for drho_GR/dp_LR = drho_GR/dp_GR * dp_GR/dp_LR: + double const drho_GR_dp_cap = 0; + + ip_cv.drho_h_eff_dp_GR = + dphi_G_dp_GR * c.rhoGR * c.hG + phi_G * c.drho_GR_dp_GR * c.hG + + dphi_L_dp_GR * c.rhoLR * c.hL + phi_L * drho_LR_dp_GR * c.hL; + ip_cv.drho_h_eff_dp_cap = + dphi_G_dp_cap * c.rhoGR * c.hG + phi_G * drho_GR_dp_cap * c.hG + + dphi_L_dp_cap * c.rhoLR * c.hL + phi_L * drho_LR_dp_cap * c.hL; + + // TODO (naumov) Extend for temperature dependent porosities. + constexpr double dphi_G_dT = 0; + constexpr double dphi_L_dT = 0; + ip_cv.drho_h_eff_dT = + dphi_G_dT * c.rhoGR * c.hG + phi_G * c.drho_GR_dT * c.hG + + phi_G * c.rhoGR * c.dh_G_dT + dphi_L_dT * c.rhoLR * c.hL + + phi_L * ip_cv.drho_LR_dT * c.hL + phi_L * c.rhoLR * c.dh_L_dT + + dphi_S_dT * rhoSR * ip_data.h_S + + phi_S * ip_cv.drho_SR_dT * ip_data.h_S + phi_S * rhoSR * cpS; + + ip_cv.drho_u_eff_dp_GR = + dphi_G_dp_GR * c.rhoGR * c.uG + phi_G * c.drho_GR_dp_GR * c.uG + + phi_G * c.rhoGR * c.du_G_dp_GR + dphi_L_dp_GR * c.rhoLR * c.uL + + phi_L * drho_LR_dp_GR * c.uL + phi_L * c.rhoLR * c.du_L_dp_GR; + + ip_cv.drho_u_eff_dp_cap = + dphi_G_dp_cap * c.rhoGR * c.uG + phi_G * drho_GR_dp_cap * c.uG + + dphi_L_dp_cap * c.rhoLR * c.uL + phi_L * drho_LR_dp_cap * c.uL + + phi_L * c.rhoLR * c.du_L_dp_cap; + + auto const& b = _process_data.specific_body_force; + auto const k_over_mu_G = + (ip_data.k_S * ip_data.k_rel_G / ip_data.muGR).eval(); + auto const k_over_mu_L = + (ip_data.k_S * ip_data.k_rel_L / ip_data.muLR).eval(); + GlobalDimVectorType const w_GS = + k_over_mu_G * c.rhoGR * b - k_over_mu_G * gradpGR; + GlobalDimVectorType const w_LS = k_over_mu_L * gradpCap + + k_over_mu_L * c.rhoLR * b - + k_over_mu_L * gradpGR; + + ip_cv.drho_GR_h_w_eff_dp_GR_Npart = + c.drho_GR_dp_GR * c.hG * w_GS + + c.rhoGR * c.hG * k_over_mu_G * c.drho_GR_dp_GR * b; + ip_cv.drho_GR_h_w_eff_dp_GR_gradNpart = + -c.rhoGR * c.hG * k_over_mu_G - c.rhoLR * c.hL * k_over_mu_L; + + ip_cv.drho_LR_h_w_eff_dp_cap_Npart = + -drho_LR_dp_cap * c.hL * w_LS - + c.rhoLR * c.hL * k_over_mu_L * drho_LR_dp_cap * b; + ip_cv.drho_LR_h_w_eff_dp_cap_gradNpart = + // TODO (naumov) why the minus sign?????? + -c.rhoLR * c.hL * k_over_mu_L; + + ip_cv.drho_GR_h_w_eff_dT = + c.drho_GR_dT * c.hG * w_GS + c.rhoGR * c.dh_G_dT * w_GS + + ip_cv.drho_LR_dT * c.hL * w_LS + c.rhoLR * c.dh_L_dT * w_LS; + // TODO (naumov) + k_over_mu_G * drho_GR_dT * b + k_over_mu_L * + // drho_LR_dT * b + + // Derivatives of s_G * rho_C_GR_dot + s_L * rho_C_LR_dot abbreviated + // here with S_rho_C_eff. + double const s_L = ip_data.s_L; + double const s_G = 1. - ip_data.s_L; + double const rho_C_GR_dot = (ip_data.rhoCGR - ip_data.rhoCGR_prev) / dt; + double const rho_C_LR_dot = (ip_data.rhoCLR - ip_data.rhoCLR_prev) / dt; + double const rho_C_FR = s_G * ip_data.rhoCGR + s_L * ip_data.rhoCLR; + double const rho_W_FR = s_G * ip_data.rhoWGR + s_L * ip_data.rhoWLR; + // TODO (naumov) Extend for partially saturated media. + constexpr double drho_C_GR_dp_cap = 0; + ip_cv.dfC_3a_dp_GR = + ds_G_dp_GR * rho_C_GR_dot + s_G * c.drho_C_GR_dp_GR / dt + + ds_L_dp_GR * rho_C_LR_dot + s_L * c.drho_C_LR_dp_GR / dt; + ip_cv.dfC_3a_dp_cap = + ds_G_dp_cap * rho_C_GR_dot + s_G * drho_C_GR_dp_cap / dt + + ip_cv.ds_L_dp_cap * rho_C_LR_dot - s_L * c.drho_C_LR_dp_LR / dt; + ip_cv.dfC_3a_dT = s_G * c.drho_C_GR_dT / dt + s_L * c.drho_C_LR_dT / dt; + + double const drho_C_FR_dp_GR = + ds_G_dp_GR * ip_data.rhoCGR + s_G * c.drho_C_GR_dp_GR + + ds_L_dp_GR * ip_data.rhoCLR + s_L * c.drho_C_LR_dp_GR; + ip_cv.dfC_4_MCpG_dp_GR = drho_C_FR_dp_GR * + (ip_data.alpha_B - ip_data.phi) * + ip_data.beta_p_SR; + + double const drho_C_FR_dT = s_G * c.drho_C_GR_dT + s_L * c.drho_C_LR_dT; + ip_cv.dfC_4_MCpG_dT = + drho_C_FR_dT * (ip_data.alpha_B - ip_data.phi) * ip_data.beta_p_SR +#ifdef NON_CONSTANT_SOLID_PHASE_VOLUME_FRACTION + - rho_C_FR * ip_data.dphi_dT * ip_data.beta_p_SR +#endif + ; + + ip_cv.dfC_4_MCT_dT = + drho_C_FR_dT * (ip_data.alpha_B - ip_data.phi) * ip_data.beta_T_SR +#ifdef NON_CONSTANT_SOLID_PHASE_VOLUME_FRACTION + + rho_C_FR * (ip_data.alpha_B - ip_data.dphi_dT) * ip_data.beta_T_SR +#endif + ; + + ip_cv.dfC_4_MCu_dT = drho_C_FR_dT * ip_data.alpha_B; + + ip_cv.dfC_2a_dp_GR = -ip_data.phi * c.drho_C_GR_dp_GR - + drho_C_FR_dp_GR * pCap * + (ip_data.alpha_B - ip_data.phi) * + ip_data.beta_p_SR; + + double const drho_C_FR_dp_cap = + ds_G_dp_cap * ip_data.rhoCGR + s_G * drho_C_GR_dp_cap + + ip_cv.ds_L_dp_cap * ip_data.rhoCLR - s_L * c.drho_C_LR_dp_LR; + + ip_cv.dfC_2a_dp_cap = + ip_data.phi * (-c.drho_C_LR_dp_LR - drho_C_GR_dp_cap) - + drho_C_FR_dp_cap * pCap * (ip_data.alpha_B - ip_data.phi) * + ip_data.beta_p_SR + + rho_C_FR * (ip_data.alpha_B - ip_data.phi) * ip_data.beta_p_SR; + + ip_cv.dfC_2a_dT = +#ifdef NON_CONSTANT_SOLID_PHASE_VOLUME_FRACTION + ip_data.dphi_dT * (ip_data.rhoCLR - ip_data.rhoCGR) + +#endif + ip_data.phi * (c.drho_C_LR_dT - c.drho_C_GR_dT) - + drho_C_FR_dT * pCap * (ip_data.alpha_B - ip_data.phi) * + ip_data.beta_p_SR +#ifdef NON_CONSTANT_SOLID_PHASE_VOLUME_FRACTION + + rho_C_FR * pCap * ip_data.dphi_dT * ip_data.beta_p_SR +#endif + ; + + ip_cv.dadvection_C_dp_GR = + c.drho_C_GR_dp_GR * k_over_mu_G + c.drho_C_LR_dp_GR * k_over_mu_L; + + ip_cv.dfC_4_LCpG_dT = + c.drho_C_GR_dT * k_over_mu_G + c.drho_C_LR_dT * k_over_mu_L + // + ip_cv.ddiffusion_C_p_dT TODO (naumov) + ; + + double const drho_W_FR_dp_GR = + ds_G_dp_GR * ip_data.rhoWGR + s_G * c.drho_W_GR_dp_GR + + ds_L_dp_GR * ip_data.rhoWLR + s_L * c.drho_W_LR_dp_GR; + double const drho_W_FR_dp_cap = + ds_G_dp_cap * ip_data.rhoWGR + s_G * c.drho_W_GR_dp_cap + + ip_cv.ds_L_dp_cap * ip_data.rhoWLR - s_L * c.drho_W_LR_dp_LR; + double const drho_W_FR_dT = s_G * c.drho_W_GR_dT + s_L * c.drho_W_LR_dT; + + ip_cv.dfW_2a_dp_GR = + ip_data.phi * (c.drho_W_LR_dp_GR - c.drho_W_GR_dp_GR); + ip_cv.dfW_2b_dp_GR = drho_W_FR_dp_GR * pCap * + (ip_data.alpha_B - ip_data.phi) * + ip_data.beta_p_SR; + ip_cv.dfW_2a_dp_cap = + ip_data.phi * (-c.drho_W_LR_dp_LR - c.drho_W_GR_dp_cap); + ip_cv.dfW_2b_dp_cap = + drho_W_FR_dp_cap * pCap * (ip_data.alpha_B - ip_data.phi) * + ip_data.beta_p_SR + + rho_W_FR * (ip_data.alpha_B - ip_data.phi) * ip_data.beta_p_SR; + + ip_cv.dfW_2a_dT = +#ifdef NON_CONSTANT_SOLID_PHASE_VOLUME_FRACTION + ip_data.dphi_dT * (ip_data.rhoWLR - ip_data.rhoWGR) + +#endif + ip_data.phi * (c.drho_W_LR_dT - c.drho_W_GR_dT); + ip_cv.dfW_2b_dT = + drho_W_FR_dT * pCap * (ip_data.alpha_B - ip_data.phi) * + ip_data.beta_p_SR +#ifdef NON_CONSTANT_SOLID_PHASE_VOLUME_FRACTION + - rho_W_FR * pCap * ip_data.dphi_dT * ip_data.beta_p_SR +#endif + ; + + double const rho_W_GR_dot = (ip_data.rhoWGR - ip_data.rhoWGR_prev) / dt; + double const rho_W_LR_dot = (ip_data.rhoWLR - ip_data.rhoWLR_prev) / dt; + + ip_cv.dfW_3a_dp_GR = + ds_G_dp_GR * rho_W_GR_dot + s_G * c.drho_W_GR_dp_GR / dt + + ds_L_dp_GR * rho_W_LR_dot + s_L * c.drho_W_LR_dp_GR / dt; + ip_cv.dfW_3a_dp_cap = + ds_G_dp_cap * rho_W_GR_dot + s_G * c.drho_W_GR_dp_cap / dt + + ip_cv.ds_L_dp_cap * rho_W_LR_dot - s_L * c.drho_W_LR_dp_LR / dt; + ip_cv.dfW_3a_dT = s_G * c.drho_W_GR_dT / dt + s_L * c.drho_W_LR_dT / dt; + + ip_cv.dfW_4a_dp_GR = c.drho_W_GR_dp_GR * k_over_mu_G; + ip_cv.dfW_4a_dp_cap = -c.drho_W_LR_dp_LR * k_over_mu_L; + ip_cv.dfW_4a_dT = + c.drho_W_GR_dT * k_over_mu_G + c.drho_W_LR_dT * k_over_mu_L; + + // TODO (naumov) for dxmW*/d* != 0 + ip_cv.dfW_4d_dp_GR = + Eigen::Matrix<double, DisplacementDim, DisplacementDim>::Zero(); + ip_cv.dfW_4d_dp_cap = + Eigen::Matrix<double, DisplacementDim, DisplacementDim>::Zero(); + ip_cv.dfW_4d_dT = + Eigen::Matrix<double, DisplacementDim, DisplacementDim>::Zero(); } return ip_constitutive_variables; @@ -807,18 +1080,703 @@ template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, typename IntegrationMethod, int DisplacementDim> void TH2MLocalAssembler<ShapeFunctionDisplacement, ShapeFunctionPressure, IntegrationMethod, DisplacementDim>:: - assembleWithJacobian(double const /*t*/, double const /*dt*/, - std::vector<double> const& /*local_x*/, - std::vector<double> const& /*local_xdot*/, + assembleWithJacobian(double const t, double const dt, + std::vector<double> const& local_x, + std::vector<double> const& local_xdot, const double /*dxdot_dx*/, const double /*dx_dx*/, std::vector<double>& /*local_M_data*/, std::vector<double>& /*local_K_data*/, - std::vector<double>& /*local_rhs_data*/, - std::vector<double>& /*local_Jac_data*/) + std::vector<double>& local_rhs_data, + std::vector<double>& local_Jac_data) { - OGS_FATAL( - "TH2MLocalAssembler:assembleWithJacobian is currently not " - "implemented."); + auto const matrix_size = gas_pressure_size + capillary_pressure_size + + temperature_size + displacement_size; + assert(local_x.size() == matrix_size); + + auto const temperature = Eigen::Map<VectorType<temperature_size> const>( + local_x.data() + temperature_index, temperature_size); + + auto const gas_pressure = Eigen::Map<VectorType<gas_pressure_size> const>( + local_x.data() + gas_pressure_index, gas_pressure_size); + + auto const capillary_pressure = + Eigen::Map<VectorType<capillary_pressure_size> const>( + local_x.data() + capillary_pressure_index, capillary_pressure_size); + + auto const gas_pressure_dot = + Eigen::Map<VectorType<gas_pressure_size> const>( + local_xdot.data() + gas_pressure_index, gas_pressure_size); + + auto const capillary_pressure_dot = + Eigen::Map<VectorType<capillary_pressure_size> const>( + local_xdot.data() + capillary_pressure_index, + capillary_pressure_size); + + auto const temperature_dot = Eigen::Map<VectorType<temperature_size> const>( + local_xdot.data() + temperature_index, temperature_size); + + auto const displacement_dot = + Eigen::Map<VectorType<displacement_size> const>( + local_xdot.data() + displacement_index, displacement_size); + + auto local_Jac = + MathLib::createZeroedMatrix<MatrixType<matrix_size, matrix_size>>( + local_Jac_data, matrix_size, matrix_size); + + auto local_f = MathLib::createZeroedVector<VectorType<matrix_size>>( + local_rhs_data, matrix_size); + + // component-formulation + // W - liquid phase main component + // C - gas phase main component + + // C component equation matrices + MatrixType<C_size, gas_pressure_size> MCpG = + MatrixType<C_size, gas_pressure_size>::Zero(C_size, gas_pressure_size); + MatrixType<C_size, capillary_pressure_size> MCpC = + MatrixType<C_size, capillary_pressure_size>::Zero( + C_size, capillary_pressure_size); + MatrixType<C_size, temperature_size> MCT = + MatrixType<C_size, temperature_size>::Zero(C_size, temperature_size); + MatrixType<C_size, displacement_size> MCu = + MatrixType<C_size, displacement_size>::Zero(C_size, displacement_size); + + MatrixType<C_size, gas_pressure_size> LCpG = + MatrixType<C_size, gas_pressure_size>::Zero(C_size, gas_pressure_size); + MatrixType<C_size, capillary_pressure_size> LCpC = + MatrixType<C_size, capillary_pressure_size>::Zero( + C_size, capillary_pressure_size); + MatrixType<C_size, temperature_size> LCT = + MatrixType<C_size, temperature_size>::Zero(C_size, temperature_size); + + // mass matrix - W component equation + MatrixType<W_size, gas_pressure_size> MWpG = + MatrixType<W_size, gas_pressure_size>::Zero(W_size, gas_pressure_size); + MatrixType<W_size, capillary_pressure_size> MWpC = + MatrixType<W_size, capillary_pressure_size>::Zero( + W_size, capillary_pressure_size); + MatrixType<W_size, temperature_size> MWT = + MatrixType<W_size, temperature_size>::Zero(W_size, temperature_size); + MatrixType<W_size, displacement_size> MWu = + MatrixType<W_size, displacement_size>::Zero(W_size, displacement_size); + + // stiffness matrix - W component equation + MatrixType<W_size, gas_pressure_size> LWpG = + MatrixType<W_size, gas_pressure_size>::Zero(W_size, gas_pressure_size); + MatrixType<W_size, capillary_pressure_size> LWpC = + MatrixType<W_size, capillary_pressure_size>::Zero( + W_size, capillary_pressure_size); + MatrixType<W_size, temperature_size> LWT = + MatrixType<W_size, temperature_size>::Zero(W_size, temperature_size); + + // mass matrix - temperature equation + MatrixType<temperature_size, displacement_size> MTu = + MatrixType<temperature_size, displacement_size>::Zero( + temperature_size, displacement_size); + + // stiffness matrix - temperature equation + MatrixType<temperature_size, temperature_size> KTT = + MatrixType<temperature_size, temperature_size>::Zero(temperature_size, + temperature_size); + + // stiffness matrices - displacement equation coupling into pressures + MatrixType<displacement_size, gas_pressure_size> KUpG = + MatrixType<displacement_size, gas_pressure_size>::Zero( + displacement_size, gas_pressure_size); + MatrixType<displacement_size, capillary_pressure_size> KUpC = + MatrixType<displacement_size, capillary_pressure_size>::Zero( + displacement_size, capillary_pressure_size); + + // pointer-vectors to the right hand side terms - C-component equation + auto fC = local_f.template segment<C_size>(C_index); + // pointer-vectors to the right hand side terms - W-component equation + auto fW = local_f.template segment<W_size>(W_index); + // pointer-vectors to the right hand side terms - temperature equation + auto fT = local_f.template segment<temperature_size>(temperature_index); + // pointer-vectors to the right hand side terms - displacement equation + auto fU = local_f.template segment<displacement_size>(displacement_index); + + ParameterLib::SpatialPosition pos; + pos.setElementID(_element.getID()); + + unsigned const n_integration_points = + _integration_method.getNumberOfPoints(); + + auto const ip_constitutive_variables = updateConstitutiveVariables( + Eigen::Map<Eigen::VectorXd const>(local_x.data(), local_x.size()), + Eigen::Map<Eigen::VectorXd const>(local_xdot.data(), local_xdot.size()), + t, dt); + + for (unsigned int_point = 0; int_point < n_integration_points; int_point++) + { + pos.setIntegrationPoint(int_point); + auto& ip = _ip_data[int_point]; + auto& ip_cv = ip_constitutive_variables[int_point]; + + auto const& Np = ip.N_p; + auto const& NT = Np; + auto const& Nu = ip.N_u; + + auto const& NpT = Np.transpose().eval(); + auto const& NTT = NT.transpose().eval(); + + auto const& gradNp = ip.dNdx_p; + auto const& gradNT = gradNp; + auto const& gradNu = ip.dNdx_u; + + auto const& gradNpT = gradNp.transpose().eval(); + auto const& gradNTT = gradNT.transpose().eval(); + + auto const& Nu_op = ip.N_u_op; + auto const& w = ip.integration_weight; + + auto const& m = Invariants::identity2; + auto const mT = m.transpose().eval(); + + auto const x_coord = + NumLib::interpolateXCoordinate<ShapeFunctionDisplacement, + ShapeMatricesTypeDisplacement>( + _element, Nu); + + auto const Bu = + LinearBMatrix::computeBMatrix<DisplacementDim, + ShapeFunctionDisplacement::NPOINTS, + typename BMatricesType::BMatrixType>( + gradNu, Nu, x_coord, _is_axially_symmetric); + + auto const BuT = Bu.transpose().eval(); + + double const div_u_dot = Invariants::trace(Bu * displacement_dot); + + double const pCap = Np.dot(capillary_pressure); + + GlobalDimVectorType const gradpGR = gradNp * gas_pressure; + GlobalDimVectorType const gradpCap = gradNp * capillary_pressure; + GlobalDimVectorType const gradT = gradNT * temperature; + + double const pGR_dot = Np.dot(gas_pressure_dot); + double const pCap_dot = Np.dot(capillary_pressure_dot); + double const T_dot = NT.dot(temperature_dot); + auto& beta_T_SR = ip.beta_T_SR; + + auto const I = + Eigen::Matrix<double, DisplacementDim, DisplacementDim>::Identity(); + + const double sD_G = ip.diffusion_coefficient_vapour; + const double sD_L = ip.diffusion_coefficient_solvate; + + auto const D_C_G = (sD_G * I).eval(); + auto const D_W_G = (sD_G * I).eval(); + auto const D_C_L = (sD_L * I).eval(); + auto const D_W_L = (sD_L * I).eval(); + + auto& k_S = ip.k_S; + + auto& s_L = ip.s_L; + auto const s_G = 1. - s_L; + auto const s_L_dot = (s_L - ip.s_L_prev) / dt; + + auto& alpha_B = ip.alpha_B; + auto& beta_p_SR = ip.beta_p_SR; + + auto const& b = _process_data.specific_body_force; + + // porosity + auto& phi = ip.phi; + + // volume fraction + auto const phi_G = s_G * phi; + auto const phi_L = s_L * phi; + auto const phi_S = 1. - phi; + + // solid phase density + auto& rho_SR = ip.rhoSR; + // effective density + auto const rho = phi_G * ip.rhoGR + phi_L * ip.rhoLR + phi_S * rho_SR; + + // abbreviations + const double rho_C_FR = s_G * ip.rhoCGR + s_L * ip.rhoCLR; + const double rho_W_FR = s_G * ip.rhoWGR + s_L * ip.rhoWLR; + + // phase specific enthalpies + auto& h_G = ip.h_G; + auto& h_L = ip.h_L; + + auto const rho_C_GR_dot = (ip.rhoCGR - ip.rhoCGR_prev) / dt; + auto const rho_C_LR_dot = (ip.rhoCLR - ip.rhoCLR_prev) / dt; + auto const rho_W_GR_dot = (ip.rhoWGR - ip.rhoWGR_prev) / dt; + auto const rho_W_LR_dot = (ip.rhoWLR - ip.rhoWLR_prev) / dt; + + auto const rho_h_eff = ip.rho_G_h_G + ip.rho_L_h_L + ip.rho_S_h_S; + + auto const rho_u_eff_dot = (ip.rho_u_eff - ip.rho_u_eff_prev) / dt; + + auto const k_over_mu_G = (k_S * ip.k_rel_G / ip.muGR).eval(); + auto const k_over_mu_L = (k_S * ip.k_rel_L / ip.muLR).eval(); + + GlobalDimVectorType const w_GS = + k_over_mu_G * ip.rhoGR * b - k_over_mu_G * gradpGR; + + GlobalDimVectorType const w_LS = k_over_mu_L * gradpCap + + k_over_mu_L * ip.rhoLR * b - + k_over_mu_L * gradpGR; + + // --------------------------------------------------------------------- + // C-component equation + // --------------------------------------------------------------------- + + MCpG.noalias() += NpT * rho_C_FR * (alpha_B - phi) * beta_p_SR * Np * w; + MCpC.noalias() -= + NpT * rho_C_FR * (alpha_B - phi) * beta_p_SR * s_L * Np * w; + + if (_process_data.apply_mass_lumping) + { + if (pCap_dot != 0.) // avoid division by Zero + { + MCpC.noalias() += + NpT * + (phi * (ip.rhoCLR - ip.rhoCGR) - + rho_C_FR * pCap * (alpha_B - phi) * beta_p_SR) * + s_L_dot / pCap_dot * Np * w; + } + } + + MCT.noalias() -= NpT * rho_C_FR * (alpha_B - phi) * beta_T_SR * Np * w; + // d (fC_4_MCT * T_dot)/d T + local_Jac + .template block<C_size, temperature_size>(C_index, + temperature_index) + .noalias() += NpT * ip_cv.dfC_4_MCT_dT * T_dot * NT * w; + + MCu.noalias() += NpT * rho_C_FR * alpha_B * mT * Bu * w; + // d (fC_4_MCu * u_dot)/d T + local_Jac + .template block<C_size, temperature_size>(C_index, + temperature_index) + .noalias() += NpT * ip_cv.dfC_4_MCu_dT * div_u_dot * NT * w; + + auto const advection_C_G = (ip.rhoCGR * k_over_mu_G).eval(); + auto const advection_C_L = (ip.rhoCLR * k_over_mu_L).eval(); + auto const diffusion_C_G_p = + (phi_G * ip.rhoGR * D_C_G * ip.dxmCG_dpGR).eval(); + auto const diffusion_C_L_p = + (phi_L * ip.rhoLR * D_C_L * ip.dxmCL_dpLR).eval(); + auto const diffusion_C_G_T = + (phi_G * ip.rhoGR * D_C_G * ip.dxmCG_dT).eval(); + auto const diffusion_C_L_T = + (phi_L * ip.rhoLR * D_C_L * ip.dxmCL_dT).eval(); + + auto const advection_C = (advection_C_G + advection_C_L).eval(); + auto const diffusion_C_p = (diffusion_C_G_p + diffusion_C_L_p).eval(); + auto const diffusion_C_T = (diffusion_C_G_T + diffusion_C_L_T).eval(); + + LCpG.noalias() += gradNpT * (advection_C + diffusion_C_p) * gradNp * w; + + // d (fC_4_LCpG * grad p_GR)/d p_GR + local_Jac.template block<C_size, C_size>(C_index, C_index).noalias() += + gradNpT * + (ip_cv.dadvection_C_dp_GR + // + ip_cv.ddiffusion_C_p_dp_GR TODO (naumov) + ) * + gradpGR * Np * w; + + // d (fC_4_LCpG * grad p_GR)/d T + local_Jac + .template block<C_size, temperature_size>(C_index, + temperature_index) + .noalias() += gradNpT * ip_cv.dfC_4_LCpG_dT * gradpGR * NT * w; + + // d (fC_4_MCpG * p_GR_dot)/d p_GR + local_Jac.template block<C_size, C_size>(C_index, C_index).noalias() += + NpT * ip_cv.dfC_4_MCpG_dp_GR * pGR_dot * Np * w; + + // d (fC_4_MCpG * p_GR_dot)/d T + local_Jac + .template block<C_size, temperature_size>(C_index, + temperature_index) + .noalias() += NpT * ip_cv.dfC_4_MCpG_dT * pGR_dot * NT * w; + + LCpC.noalias() -= + gradNpT * (advection_C_L + diffusion_C_L_p) * gradNp * w; + + LCT.noalias() += gradNpT * diffusion_C_T * gradNp * w; + + // fC_1 + fC.noalias() += gradNpT * + (advection_C_G * ip.rhoGR + advection_C_L * ip.rhoLR) * + b * w; + + if (!_process_data.apply_mass_lumping) + { + // fC_2 = \int a * s_L_dot + auto const a = phi * (ip.rhoCLR - ip.rhoCGR) - + rho_C_FR * pCap * (alpha_B - phi) * beta_p_SR; + fC.noalias() -= NpT * a * s_L_dot * w; + + // TODO (naumov) Extend for partially saturated media. + constexpr double ds_L_dp_GR = 0; + local_Jac.template block<C_size, C_size>(C_index, C_index) + .noalias() += + NpT * (ip_cv.dfC_2a_dp_GR * s_L_dot - a * ds_L_dp_GR / dt) * + Np * w; + + local_Jac.template block<C_size, W_size>(C_index, W_index) + .noalias() += + NpT * + (ip_cv.dfC_2a_dp_cap * s_L_dot + a * ip_cv.ds_L_dp_cap / dt) * + Np * w; + + local_Jac + .template block<C_size, temperature_size>(C_index, + temperature_index) + .noalias() += NpT * ip_cv.dfC_2a_dT * s_L_dot * NT * w; + } + { + // fC_3 = \int phi * a + double const a = s_G * rho_C_GR_dot + s_L * rho_C_LR_dot; + fC.noalias() -= NpT * phi * a * w; + + local_Jac.template block<C_size, C_size>(C_index, C_index) + .noalias() += NpT * phi * ip_cv.dfC_3a_dp_GR * Np * w; + + local_Jac.template block<C_size, W_size>(C_index, W_index) + .noalias() += NpT * phi * ip_cv.dfC_3a_dp_cap * Np * w; + + local_Jac + .template block<C_size, temperature_size>(C_index, + temperature_index) + .noalias() += NpT * + ( +#ifdef NON_CONSTANT_SOLID_PHASE_VOLUME_FRACTION + ip.dphi_dT * a + +#endif // NON_CONSTANT_SOLID_PHASE_VOLUME_FRACTION + phi * ip_cv.dfC_3a_dT) * + NT * w; + } + // --------------------------------------------------------------------- + // W-component equation + // --------------------------------------------------------------------- + + MWpG.noalias() += NpT * rho_W_FR * (alpha_B - phi) * beta_p_SR * Np * w; + MWpC.noalias() -= + NpT * rho_W_FR * (alpha_B - phi) * beta_p_SR * s_L * Np * w; + + if (_process_data.apply_mass_lumping) + { + if (pCap_dot != 0.) // avoid division by Zero + { + MWpC.noalias() += + NpT * + (phi * (ip.rhoWLR - ip.rhoWGR) - + rho_W_FR * pCap * (alpha_B - phi) * beta_p_SR) * + s_L_dot / pCap_dot * Np * w; + } + } + + MWT.noalias() -= NpT * rho_W_FR * (alpha_B - phi) * beta_T_SR * Np * w; + + MWu.noalias() += NpT * rho_W_FR * alpha_B * mT * Bu * w; + + auto const advection_W_G = (ip.rhoWGR * k_over_mu_G).eval(); + auto const advection_W_L = (ip.rhoWLR * k_over_mu_L).eval(); + auto const diffusion_W_G_p = phi_G * ip.rhoGR * D_W_G * ip.dxmWG_dpGR; + auto const diffusion_W_L_p = phi_L * ip.rhoLR * D_W_L * ip.dxmWL_dpLR; + auto const diffusion_W_G_T = phi_G * ip.rhoGR * D_W_G * ip.dxmWG_dT; + auto const diffusion_W_L_T = phi_L * ip.rhoLR * D_W_L * ip.dxmWL_dT; + + auto const advection_W = advection_W_G + advection_W_L; + auto const diffusion_W_p = diffusion_W_G_p + diffusion_W_L_p; + auto const diffusion_W_T = diffusion_W_G_T + diffusion_W_L_T; + + LWpG.noalias() += gradNpT * (advection_W + diffusion_W_p) * gradNp * w; + + // fW_4 LWpG' parts; LWpG = \int grad (a + d) grad + local_Jac.template block<W_size, C_size>(W_index, C_index).noalias() -= + gradNpT * (ip_cv.dfW_4a_dp_GR + ip_cv.dfW_4d_dp_GR) * gradpGR * Np * + w; + + local_Jac.template block<W_size, W_size>(W_index, W_index).noalias() -= + gradNpT * (ip_cv.dfW_4a_dp_cap + ip_cv.dfW_4d_dp_cap) * gradpGR * + Np * w; + + local_Jac + .template block<W_size, temperature_size>(W_index, + temperature_index) + .noalias() -= + gradNpT * (ip_cv.dfW_4a_dT + ip_cv.dfW_4d_dT) * gradpGR * NT * w; + + LWpC.noalias() -= + gradNpT * (advection_W_L + diffusion_W_L_p) * gradNp * w; + + LWT.noalias() += gradNpT * (diffusion_W_T)*gradNp * w; + + // fW_1 + fW.noalias() += gradNpT * + (advection_W_G * ip.rhoGR + advection_W_L * ip.rhoLR) * + b * w; + + // fW_2 = \int (f - g) * s_L_dot + if (!_process_data.apply_mass_lumping) + { + double const f = phi * (ip.rhoWLR - ip.rhoWGR); + double const g = rho_W_FR * pCap * (alpha_B - phi) * beta_p_SR; + + fW.noalias() -= NpT * (f - g) * s_L_dot * w; + + local_Jac.template block<W_size, C_size>(W_index, C_index) + .noalias() += NpT * (ip_cv.dfW_2a_dp_GR - ip_cv.dfW_2b_dp_GR) * + s_L_dot * Np * w; + + // sign negated because of dp_cap = -dp_LR + // TODO (naumov) Had to change the sign to get equal Jacobian WW + // blocks in A2 Test. Where is the error? + local_Jac.template block<W_size, W_size>(W_index, W_index) + .noalias() += + NpT * + ((ip_cv.dfW_2a_dp_cap - ip_cv.dfW_2b_dp_cap) * s_L_dot + + (f - g) * ip_cv.ds_L_dp_cap / dt) * + Np * w; + + local_Jac + .template block<W_size, temperature_size>(W_index, + temperature_index) + .noalias() += + NpT * (ip_cv.dfW_2a_dT - ip_cv.dfW_2b_dT) * s_L_dot * Np * w; + } + + // fW_3 = \int phi * a + fW.noalias() -= + NpT * phi * (s_G * rho_W_GR_dot + s_L * rho_W_LR_dot) * w; + + local_Jac.template block<W_size, C_size>(W_index, C_index).noalias() += + NpT * phi * ip_cv.dfW_3a_dp_GR * Np * w; + + local_Jac.template block<W_size, W_size>(W_index, W_index).noalias() += + NpT * phi * ip_cv.dfW_3a_dp_cap * Np * w; + + local_Jac + .template block<W_size, temperature_size>(W_index, + temperature_index) + .noalias() += + NpT * + ( +#ifdef NON_CONSTANT_SOLID_PHASE_VOLUME_FRACTION + ip.dphi_dT * (s_G * rho_W_GR_dot + s_L * rho_W_LR_dot) + +#endif // NON_CONSTANT_SOLID_PHASE_VOLUME_FRACTION + phi * ip_cv.dfW_3a_dT) * + NT * w; + + // --------------------------------------------------------------------- + // - temperature equation + // --------------------------------------------------------------------- + + MTu.noalias() += NTT * rho_h_eff * mT * Bu * w; + + // dfT_4/dp_GR + // d (MTu * u_dot)/dp_GR + local_Jac + .template block<temperature_size, C_size>(temperature_index, + C_index) + .noalias() += NTT * ip_cv.drho_h_eff_dp_GR * div_u_dot * NT * w; + + // dfT_4/dp_cap + // d (MTu * u_dot)/dp_cap + local_Jac + .template block<temperature_size, W_size>(temperature_index, + W_index) + .noalias() -= NTT * ip_cv.drho_h_eff_dp_cap * div_u_dot * NT * w; + + // dfT_4/dT + // d (MTu * u_dot)/dT + local_Jac + .template block<temperature_size, temperature_size>( + temperature_index, temperature_index) + .noalias() += NTT * ip_cv.drho_h_eff_dT * div_u_dot * NT * w; + + KTT.noalias() += gradNTT * ip.lambda * gradNT * w; + + // d KTT/dp_GR * T + local_Jac + .template block<temperature_size, C_size>(temperature_index, + C_index) + .noalias() += gradNTT * ip_cv.dlambda_dp_GR * gradT * Np * w; + + // d KTT/dp_cap * T + local_Jac + .template block<temperature_size, W_size>(temperature_index, + W_index) + .noalias() += gradNTT * ip_cv.dlambda_dp_cap * gradT * Np * w; + + // d KTT/dT * T + local_Jac + .template block<temperature_size, temperature_size>( + temperature_index, temperature_index) + .noalias() += gradNTT * ip_cv.dlambda_dT * gradT * NT * w; + + // fT_1 + fT.noalias() -= NTT * rho_u_eff_dot * w; + + // dfT_1/dp_GR + local_Jac + .template block<temperature_size, C_size>(temperature_index, + C_index) + .noalias() += NpT / dt * ip_cv.drho_u_eff_dp_GR * Np * w; + + // dfT_1/dp_cap + local_Jac + .template block<temperature_size, W_size>(temperature_index, + W_index) + .noalias() += NpT / dt * ip_cv.drho_u_eff_dp_cap * Np * w; + + // dfT_1/dT + // MTT + local_Jac + .template block<temperature_size, temperature_size>( + temperature_index, temperature_index) + .noalias() += NTT * ip_cv.drho_u_eff_dT / dt * NT * w; + + // fT_2 + fT.noalias() += + gradNTT * (ip.rhoGR * h_G * w_GS + ip.rhoLR * h_L * w_LS) * w; + + // dfT_2/dp_GR + local_Jac + .template block<temperature_size, C_size>(temperature_index, + C_index) + .noalias() -= + // dfT_2/dp_GR first part + gradNTT * ip_cv.drho_GR_h_w_eff_dp_GR_Npart * Np * w + + // dfT_2/dp_GR second part + gradNTT * ip_cv.drho_GR_h_w_eff_dp_GR_gradNpart * gradNp * w; + + // dfT_2/dp_cap + local_Jac + .template block<temperature_size, W_size>(temperature_index, + W_index) + .noalias() -= + // first part of dfT_2/dp_cap + gradNTT * (-ip_cv.drho_LR_h_w_eff_dp_cap_Npart) * Np * w + + // second part of dfT_2/dp_cap + gradNTT * (-ip_cv.drho_LR_h_w_eff_dp_cap_gradNpart) * gradNp * w; + + // dfT_2/dT + local_Jac + .template block<temperature_size, temperature_size>( + temperature_index, temperature_index) + .noalias() -= gradNTT * ip_cv.drho_GR_h_w_eff_dT * NT * w; + + // fT_3 + fT.noalias() += + NTT * (ip.rhoGR * w_GS.transpose() + ip.rhoLR * w_LS.transpose()) * + b * w; + + // --------------------------------------------------------------------- + // - displacement equation + // --------------------------------------------------------------------- + + KUpG.noalias() -= (BuT * alpha_B * m * Np) * w; + + // dfU_2/dp_GR part i.e. part of the d(KUpG*p_GR)/dp_GR derivative is + // dKUpG/dp_GR + KUpG. The former is zero, the latter is handled below. + + KUpC.noalias() += (BuT * alpha_B * s_L * m * Np) * w; + + // dfU_2/dp_LR part i.e. part of the d(KUpC*p_cap)/dp_LR derivative is + // dKUpC/dp_LR + KUpC. The latter is handled below, the former here: + local_Jac + .template block<displacement_size, W_size>(displacement_index, + W_index) + .noalias() += BuT * alpha_B * ip_cv.ds_L_dp_cap * pCap * m * Np * w; + + local_Jac + .template block<displacement_size, displacement_size>( + displacement_index, displacement_index) + .noalias() += BuT * ip_cv.C * Bu * w; + + // fU_1 + fU.noalias() -= (BuT * ip.sigma_eff - Nu_op.transpose() * rho * b) * w; + + // KuT + local_Jac + .template block<displacement_size, temperature_size>( + displacement_index, temperature_index) + .noalias() -= BuT * (ip_cv.C * ip.alpha_T_SR) * NT * w; + + /* TODO (naumov) Test with gravity needed to check this Jacobian part. + local_Jac + .template block<displacement_size, temperature_size>( + displacement_index, temperature_index) + .noalias() += Nu_op.transpose() * ip_cv.drho_dT * b * Nu_op * w; + */ + + if (_process_data.apply_mass_lumping) + { + MCpG = MCpG.colwise().sum().eval().asDiagonal(); + MCpC = MCpC.colwise().sum().eval().asDiagonal(); + MWpG = MWpG.colwise().sum().eval().asDiagonal(); + MWpC = MWpC.colwise().sum().eval().asDiagonal(); + } + } // int_point-loop + + // --- Gas --- + // fC_4 + fC.noalias() -= LCpG * gas_pressure + LCpC * capillary_pressure + + LCT * temperature + MCpG * gas_pressure_dot + + MCpC * capillary_pressure_dot + MCT * temperature_dot + + MCu * displacement_dot; + + local_Jac.template block<C_size, C_size>(C_index, C_index).noalias() += + LCpG + MCpG / dt; + local_Jac.template block<C_size, W_size>(C_index, W_index).noalias() += + LCpC + MCpC / dt; + local_Jac + .template block<C_size, temperature_size>(C_index, temperature_index) + .noalias() += LCT + MCT / dt; + local_Jac + .template block<C_size, displacement_size>(C_index, displacement_index) + .noalias() += MCu / dt; + + // --- Capillary pressure --- + // fW_4 + fW.noalias() -= LWpG * gas_pressure + LWpC * capillary_pressure + + LWT * temperature + MWpG * gas_pressure_dot + + MWpC * capillary_pressure_dot + MWT * temperature_dot + + MWu * displacement_dot; + + local_Jac.template block<W_size, W_size>(W_index, W_index).noalias() += + LWpC + MWpC / dt; + local_Jac.template block<W_size, C_size>(W_index, C_index).noalias() += + LWpG + MWpG / dt; + local_Jac + .template block<W_size, temperature_size>(W_index, temperature_index) + .noalias() += LWT + MWT / dt; + local_Jac + .template block<W_size, displacement_size>(W_index, displacement_index) + .noalias() += MWu / dt; + + // --- Temperature --- + // fT_4 + fT.noalias() -= KTT * temperature + MTu * displacement_dot; + + local_Jac + .template block<temperature_size, temperature_size>(temperature_index, + temperature_index) + .noalias() += KTT; + local_Jac + .template block<temperature_size, displacement_size>(temperature_index, + displacement_index) + .noalias() += MTu / dt; + + // --- Displacement --- + // fU_2 + fU.noalias() -= KUpG * gas_pressure + KUpC * capillary_pressure; + + local_Jac + .template block<displacement_size, C_size>(displacement_index, C_index) + .noalias() += KUpG; + local_Jac + .template block<displacement_size, W_size>(displacement_index, W_index) + .noalias() += KUpC; } template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure, -- GitLab