150 std::vector<double>
const& local_x,
151 std::vector<double>
const& local_x_prev,
152 std::vector<double>& local_rhs_data,
153 std::vector<double>& local_Jac_data)
156 assert(local_x.size() == local_matrix_dim);
158 auto const T = Eigen::Map<
typename ShapeMatricesType::template VectorType<
161 auto const p_L = Eigen::Map<
162 typename ShapeMatricesType::template VectorType<pressure_size>
const>(
166 Eigen::Map<
typename ShapeMatricesType::template VectorType<
169 auto const p_L_prev = Eigen::Map<
170 typename ShapeMatricesType::template VectorType<pressure_size>
const>(
174 typename ShapeMatricesType::template MatrixType<local_matrix_dim,
176 local_Jac_data, local_matrix_dim, local_matrix_dim);
179 typename ShapeMatricesType::template VectorType<local_matrix_dim>>(
180 local_rhs_data, local_matrix_dim);
215 auto const& liquid_phase = medium.phase(
"AqueousLiquid");
216 auto const& solid_phase = medium.phase(
"Solid");
218 medium.hasPhase(
"Gas") ? &medium.phase(
"Gas") :
nullptr;
222 unsigned const n_integration_points =
224 for (
unsigned ip = 0; ip < n_integration_points; ip++)
226 auto const& w =
_ip_data[ip].integration_weight;
229 auto const& dNdx =
_ip_data[ip].dNdx;
243 double p_cap_prev_ip;
253 auto& S_L =
_ip_data[ip].saturation;
254 auto const S_L_prev =
_ip_data[ip].saturation_prev;
257 variables, x_position, t, dt);
259 auto& solid_elasticity = *
_process_data.simplified_elasticity;
263 solid_elasticity.bulkCompressibilityFromYoungsModulus(
264 solid_phase, variables, x_position, t, dt);
265 auto const beta_SR = (1 - alpha) * beta_S;
270 variables, x_position, t, dt);
274 double const drho_LR_dp =
278 auto const beta_LR = drho_LR_dp / rho_LR;
281 variables, x_position, t, dt);
286 double const dS_L_dp_cap =
292 double const DeltaS_L_Deltap_cap =
293 (p_cap_ip == p_cap_prev_ip)
295 : (S_L - S_L_prev) / (p_cap_ip - p_cap_prev_ip);
298 auto chi_S_L_prev = S_L_prev;
299 auto dchi_dS_L = 1.0;
302 auto const chi = [&medium, x_position, t, dt](
double const S_L)
307 .template value<double>(variables, x_position, t, dt);
310 chi_S_L_prev = chi(S_L_prev);
313 .template dValue<double>(
330 variables, variables_prev, x_position, t, dt);
337 "ThermoRichardsFlow: Biot-coefficient {} is smaller than "
338 "porosity {} in element/integration point {}/{}.",
344 .template value<double>(variables, x_position, t, dt);
347 variables, x_position, t, dt);
356 auto const K_pT_thermal_osmosis =
357 (solid_phase.hasProperty(
362 .value(variables, x_position, t, dt))
363 : Eigen::MatrixXd::Zero(GlobalDim, GlobalDim));
368 Eigen::Matrix<double, 3, 3>
const
369 solid_linear_thermal_expansion_coefficient =
373 .value(variables, x_position, t, dt));
377 variables, x_position, t, dt);
382 laplace_p.noalias() +=
383 dNdx.transpose() * k_rel * rho_Ki_over_mu * dNdx * w;
384 laplace_T.noalias() +=
385 dNdx.transpose() * rho_LR * K_pT_thermal_osmosis * dNdx * w;
386 const double alphaB_minus_phi = alpha - phi;
387 double const a0 = alphaB_minus_phi * beta_SR;
388 double const specific_storage_a_p =
389 S_L * (phi * beta_LR + S_L * a0 +
390 chi_S_L * alpha * alpha *
391 solid_elasticity.storageContribution(
392 solid_phase, variables, x_position, t, dt));
393 double const specific_storage_a_S = phi - p_cap_ip * S_L * a0;
395 double const dspecific_storage_a_p_dp_cap =
396 dS_L_dp_cap * (phi * beta_LR + 2 * S_L * a0 +
398 solid_elasticity.storageContribution(
399 solid_phase, variables, x_position, t, dt) *
400 (chi_S_L + dchi_dS_L * S_L));
401 double const dspecific_storage_a_S_dp_cap =
402 -a0 * (S_L + p_cap_ip * dS_L_dp_cap);
404 storage_p_a_p.noalias() +=
405 N.transpose() * rho_LR * specific_storage_a_p * N * w;
407 storage_p_a_S.noalias() -= N.transpose() * rho_LR *
408 specific_storage_a_S * DeltaS_L_Deltap_cap *
414 .noalias() += N.transpose() * (p_cap_ip - p_cap_prev_ip) / dt *
415 rho_LR * dspecific_storage_a_p_dp_cap * N * w;
417 storage_p_a_S_Jpp.noalias() -=
418 N.transpose() * rho_LR *
419 ((S_L - S_L_prev) * dspecific_storage_a_S_dp_cap +
420 specific_storage_a_S * dS_L_dp_cap) /
423 double const dk_rel_dS_L =
425 .template dValue<double>(variables,
432 .noalias() += dNdx.transpose() * rho_Ki_over_mu * grad_p_cap *
433 dk_rel_dS_L * dS_L_dp_cap * N * w;
438 .noalias() += dNdx.transpose() * rho_LR * rho_Ki_over_mu * b *
439 dk_rel_dS_L * dS_L_dp_cap * N * w;
441 local_rhs.template segment<pressure_size>(
pressure_index).noalias() +=
442 dNdx.transpose() * rho_LR * k_rel * rho_Ki_over_mu * b * w;
447 double const fluid_volumetric_thermal_expansion_coefficient =
450 const double eff_thermal_expansion =
451 S_L * (alphaB_minus_phi *
452 solid_linear_thermal_expansion_coefficient.trace() +
453 phi * fluid_volumetric_thermal_expansion_coefficient +
454 alpha * solid_elasticity.thermalExpansivityContribution(
455 solid_linear_thermal_expansion_coefficient,
456 solid_phase, variables, x_position, t, dt));
458 N.transpose() * rho_LR * eff_thermal_expansion * N * w;
464 auto const specific_heat_capacity_fluid =
466 .template value<double>(variables, x_position, t, dt);
468 auto const specific_heat_capacity_solid =
471 .template value<double>(variables, x_position, t, dt);
475 (rho_SR * specific_heat_capacity_solid * (1 - phi) +
476 (S_L * rho_LR * specific_heat_capacity_fluid) * phi) *
479 auto const thermal_conductivity =
482 thermal_conductivity]
483 .value(variables, x_position, t, dt));
486 -Ki_over_mu * k_rel * (dNdx * p_L - rho_LR * b) -
487 K_pT_thermal_osmosis * dNdx * T);
489 K_TT.noalias() += (dNdx.transpose() * thermal_conductivity * dNdx +
490 N.transpose() * velocity_L.transpose() * dNdx *
491 rho_LR * specific_heat_capacity_fluid) *
498 dNdx.transpose() * T_ip * K_pT_thermal_osmosis * dNdx * w;
499 dK_TT_dp.noalias() -= rho_LR * specific_heat_capacity_fluid *
500 N.transpose() * (dNdx * T).transpose() *
501 k_rel * Ki_over_mu * dNdx * w;
503 dK_TT_dp.noalias() -= rho_LR * specific_heat_capacity_fluid *
504 N.transpose() * velocity_L.dot(dNdx * T) /
505 k_rel * dk_rel_dS_L * dS_L_dp_cap * N * w;
507 if (gas_phase && S_L < 1.0)
511 double const rho_wv =
513 .template value<double>(variables, x_position, t, dt);
515 double const drho_wv_dT =
517 .template dValue<double>(variables,
520 double const drho_wv_dp =
522 .template dValue<double>(
529 .template value<double>(variables, x_position, t, dt);
532 auto const tortuosity =
534 .template value<double>(variables, x_position, t, dt);
536 phi * (1.0 - S_L) * tortuosity *
538 .template value<double>(variables, x_position, t, dt);
540 double const f_Tv_D_Tv = f_Tv * D_v * drho_wv_dT;
541 double const D_pv = D_v * drho_wv_dp;
545 -(f_Tv_D_Tv * grad_T - D_pv * grad_p_cap);
546 double const specific_heat_capacity_vapour =
548 .template value<double>(variables, x_position, t, dt);
551 w * (rho_wv * specific_heat_capacity_vapour * (1 - S_L) * phi) *
554 K_TT.noalias() += N.transpose() * vapour_flux.transpose() * dNdx *
555 specific_heat_capacity_vapour * w;
557 double const storage_coefficient_by_water_vapor =
558 phi * (rho_wv * dS_L_dp_cap + (1 - S_L) * drho_wv_dp);
560 storage_p_a_p.noalias() +=
561 N.transpose() * storage_coefficient_by_water_vapor * N * w;
563 double const vapor_expansion_factor = phi * (1 - S_L) * drho_wv_dT;
564 M_pT.noalias() += N.transpose() * vapor_expansion_factor * N * w;
567 .template block<pressure_size, temperature_size>(
569 .noalias() += dNdx.transpose() * f_Tv_D_Tv * dNdx * w;
572 .noalias() -= f_Tv_D_Tv * dNdx.transpose() * (dNdx * T) * w;
574 laplace_p.noalias() += dNdx.transpose() * D_pv * dNdx * w;
581 double const factor = phi * (1 - S_L) / rho_LR;
585 .template value<double>(variables, x_position, t, dt) *
588 double const drho_LR_dT =
590 .template dValue<double>(variables,
594 double const rho_wv_over_rho_L = rho_wv / rho_LR;
597 (drho_wv_dT - rho_wv_over_rho_L * drho_LR_dT) *
598 N.transpose() * N * w;
602 (drho_wv_dp - rho_wv_over_rho_L * drho_LR_dp) +
603 L0 * phi * rho_wv_over_rho_L * dS_L_dp_cap) *
604 N.transpose() * N * w;
608 L0 * f_Tv_D_Tv * dNdx.transpose() * dNdx * w / rho_LR;
611 L0 * D_pv * dNdx.transpose() * dNdx * w / rho_LR;
618 storage_p_a_p = storage_p_a_p.colwise().sum().eval().asDiagonal();
619 storage_p_a_S = storage_p_a_S.colwise().sum().eval().asDiagonal();
621 storage_p_a_S_Jpp.colwise().sum().eval().asDiagonal();
631 .noalias() += M_TT / dt + K_TT;
636 .noalias() += K_Tp + dK_TT_dp;
642 .noalias() += laplace_p + storage_p_a_p / dt + storage_p_a_S_Jpp;
648 .noalias() += M_pT / dt + laplace_T;
655 M_TT * (T - T_prev) / dt + K_TT * T;
660 local_rhs.template segment<pressure_size>(
pressure_index).noalias() -=
661 laplace_p * p_L + laplace_T * T +
662 (storage_p_a_p + storage_p_a_S) * (p_L - p_L_prev) / dt +
663 M_pT * (T - T_prev) / dt;
670 .template block<temperature_size, pressure_size>(
672 .noalias() += M_Tp / dt;
675 .noalias() -= M_Tp * (p_L - p_L_prev) / dt;
682 double const t,
double const dt, std::vector<double>
const& local_x,
683 std::vector<double>
const& local_x_prev, std::vector<double>& local_M_data,
684 std::vector<double>& local_K_data, std::vector<double>& local_rhs_data)
687 assert(local_x.size() == local_matrix_dim);
689 auto const T = Eigen::Map<
typename ShapeMatricesType::template VectorType<
692 auto const p_L = Eigen::Map<
693 typename ShapeMatricesType::template VectorType<pressure_size>
const>(
696 auto const p_L_prev = Eigen::Map<
697 typename ShapeMatricesType::template VectorType<pressure_size>
const>(
701 typename ShapeMatricesType::template MatrixType<local_matrix_dim,
703 local_K_data, local_matrix_dim, local_matrix_dim);
706 typename ShapeMatricesType::template MatrixType<local_matrix_dim,
708 local_M_data, local_matrix_dim, local_matrix_dim);
711 typename ShapeMatricesType::template VectorType<local_matrix_dim>>(
712 local_rhs_data, local_matrix_dim);
715 auto const& liquid_phase = medium.phase(
"AqueousLiquid");
716 auto const& solid_phase = medium.phase(
"Solid");
718 medium.hasPhase(
"Gas") ? &medium.phase(
"Gas") :
nullptr;
722 unsigned const n_integration_points =
724 for (
unsigned ip = 0; ip < n_integration_points; ip++)
726 auto const& w =
_ip_data[ip].integration_weight;
729 auto const& dNdx =
_ip_data[ip].dNdx;
743 double p_cap_prev_ip;
753 auto& S_L =
_ip_data[ip].saturation;
754 auto const S_L_prev =
_ip_data[ip].saturation_prev;
757 variables, x_position, t, dt);
759 auto& solid_elasticity = *
_process_data.simplified_elasticity;
763 solid_elasticity.bulkCompressibilityFromYoungsModulus(
764 solid_phase, variables, x_position, t, dt);
765 auto const beta_SR = (1 - alpha) * beta_S;
770 variables, x_position, t, dt);
773 double const drho_LR_dp =
777 auto const beta_LR = drho_LR_dp / rho_LR;
780 variables, x_position, t, dt);
785 double const dS_L_dp_cap =
791 double const DeltaS_L_Deltap_cap =
792 (p_cap_ip == p_cap_prev_ip)
794 : (S_L - S_L_prev) / (p_cap_ip - p_cap_prev_ip);
797 auto chi_S_L_prev = S_L_prev;
800 auto const chi = [&medium, x_position, t, dt](
double const S_L)
805 .template value<double>(variables, x_position, t, dt);
808 chi_S_L_prev = chi(S_L_prev);
823 variables, variables_prev, x_position, t, dt);
830 "ThermoRichardsFlow: Biot-coefficient {} is smaller than "
831 "porosity {} in element/integration point {}/{}.",
835 auto const K_pT_thermal_osmosis =
836 (solid_phase.hasProperty(
841 .value(variables, x_position, t, dt))
842 : Eigen::MatrixXd::Zero(GlobalDim, GlobalDim));
846 .template value<double>(variables, x_position, t, dt);
849 variables, x_position, t, dt);
861 Eigen::Matrix<double, 3, 3>
const
862 solid_linear_thermal_expansion_coefficient =
866 .value(variables, x_position, t, dt));
870 variables, x_position, t, dt);
878 .noalias() += dNdx.transpose() * k_rel * rho_Ki_over_mu * dNdx * w;
880 const double alphaB_minus_phi = alpha - phi;
881 double const a0 = alphaB_minus_phi * beta_SR;
882 double const specific_storage_a_p =
883 S_L * (phi * beta_LR + S_L * a0 +
884 chi_S_L * alpha * alpha *
885 solid_elasticity.storageContribution(
886 solid_phase, variables, x_position, t, dt));
887 double const specific_storage_a_S = phi - p_cap_ip * S_L * a0;
892 .noalias() += N.transpose() * rho_LR *
893 (specific_storage_a_p -
894 specific_storage_a_S * DeltaS_L_Deltap_cap) *
897 local_rhs.template segment<pressure_size>(
pressure_index).noalias() +=
898 dNdx.transpose() * rho_LR * k_rel * rho_Ki_over_mu * b * w;
903 double const fluid_volumetric_thermal_expansion_coefficient =
906 const double eff_thermal_expansion =
907 S_L * (alphaB_minus_phi *
908 solid_linear_thermal_expansion_coefficient.trace() +
909 phi * fluid_volumetric_thermal_expansion_coefficient +
910 alpha * solid_elasticity.thermalExpansivityContribution(
911 solid_linear_thermal_expansion_coefficient,
912 solid_phase, variables, x_position, t, dt));
918 dNdx.transpose() * rho_LR * K_pT_thermal_osmosis * dNdx * w;
924 N.transpose() * rho_LR * eff_thermal_expansion * N * w;
930 auto const specific_heat_capacity_fluid =
932 .template value<double>(variables, x_position, t, dt);
934 auto const specific_heat_capacity_solid =
937 .template value<double>(variables, x_position, t, dt);
940 .template block<temperature_size, temperature_size>(
944 (rho_SR * specific_heat_capacity_solid * (1 - phi) +
945 (S_L * rho_LR * specific_heat_capacity_fluid) * phi) *
948 auto const thermal_conductivity =
951 thermal_conductivity]
952 .value(variables, x_position, t, dt));
955 -Ki_over_mu * k_rel * (dNdx * p_L - rho_LR * b) -
956 K_pT_thermal_osmosis * dNdx * T);
959 .template block<temperature_size, temperature_size>(
961 .noalias() += (dNdx.transpose() * thermal_conductivity * dNdx +
962 N.transpose() * velocity_L.transpose() * dNdx *
963 rho_LR * specific_heat_capacity_fluid) *
966 .template block<temperature_size, pressure_size>(
969 dNdx.transpose() * T_ip * K_pT_thermal_osmosis * dNdx * w;
971 if (gas_phase && S_L < 1.0)
975 double const rho_wv =
977 .template value<double>(variables, x_position, t, dt);
979 double const drho_wv_dT =
981 .template dValue<double>(variables,
984 double const drho_wv_dp =
986 .template dValue<double>(
993 .template value<double>(variables, x_position, t, dt);
996 auto const tortuosity =
998 .template value<double>(variables, x_position, t, dt);
1000 phi * (1.0 - S_L) * tortuosity *
1002 .template value<double>(variables, x_position, t, dt);
1004 double const f_Tv_D_Tv = f_Tv * D_v * drho_wv_dT;
1005 double const D_pv = D_v * drho_wv_dp;
1010 -(f_Tv_D_Tv * grad_T - D_pv * grad_p_cap);
1011 double const specific_heat_capacity_vapour =
1013 .template value<double>(variables, x_position, t, dt);
1016 .template block<temperature_size, temperature_size>(
1019 w * (rho_wv * specific_heat_capacity_vapour * (1 - S_L) * phi) *
1023 .template block<temperature_size, temperature_size>(
1025 .noalias() += N.transpose() * vapour_flux.transpose() * dNdx *
1026 specific_heat_capacity_vapour * w;
1028 double const storage_coefficient_by_water_vapor =
1029 phi * (rho_wv * dS_L_dp_cap + (1 - S_L) * drho_wv_dp);
1034 N.transpose() * storage_coefficient_by_water_vapor * N * w;
1036 double const vapor_expansion_factor = phi * (1 - S_L) * drho_wv_dT;
1038 .template block<pressure_size, temperature_size>(
1040 .noalias() += N.transpose() * vapor_expansion_factor * N * w;
1043 .noalias() -= f_Tv_D_Tv * dNdx.transpose() * (dNdx * T) * w;
1048 .noalias() += dNdx.transpose() * D_pv * dNdx * w;
1055 double const factor = phi * (1 - S_L) / rho_LR;
1059 .template value<double>(variables, x_position, t, dt) *
1062 double const drho_LR_dT =
1064 .template dValue<double>(variables,
1068 double const rho_wv_over_rho_L = rho_wv / rho_LR;
1070 .template block<temperature_size, temperature_size>(
1074 (drho_wv_dT - rho_wv_over_rho_L * drho_LR_dT) *
1075 N.transpose() * N * w;
1078 .template block<temperature_size, pressure_size>(
1082 (drho_wv_dp - rho_wv_over_rho_L * drho_LR_dp) +
1083 L0 * phi * rho_wv_over_rho_L * dS_L_dp_cap) *
1084 N.transpose() * N * w;
1088 .template block<temperature_size, temperature_size>(
1091 L0 * f_Tv_D_Tv * dNdx.transpose() * dNdx * w / rho_LR;
1094 .template block<temperature_size, pressure_size>(
1097 L0 * D_pv * dNdx.transpose() * dNdx * w / rho_LR;
1104 auto Mpp = local_M.template block<pressure_size, pressure_size>(
1106 Mpp = Mpp.colwise().sum().eval().asDiagonal();
1193 Eigen::VectorXd
const& local_x,
1194 Eigen::VectorXd
const& local_x_prev)
1199 auto const p_L = local_x.template segment<pressure_size>(
pressure_index);
1205 auto const& liquid_phase = medium.phase(
"AqueousLiquid");
1206 auto const& solid_phase = medium.phase(
"Solid");
1210 unsigned const n_integration_points =
1213 double saturation_avg = 0;
1214 double porosity_avg = 0;
1216 for (
unsigned ip = 0; ip < n_integration_points; ip++)
1232 double p_cap_prev_ip;
1243 auto& S_L =
_ip_data[ip].saturation;
1244 auto const S_L_prev =
_ip_data[ip].saturation_prev;
1246 variables, x_position, t, dt);
1251 auto chi_S_L_prev = S_L_prev;
1254 auto const chi = [&medium, x_position, t, dt](
double const S_L)
1259 .template value<double>(variables, x_position, t, dt);
1262 chi_S_L_prev = chi(S_L_prev);
1269 variables, x_position, t, dt);
1271 auto& solid_elasticity = *
_process_data.simplified_elasticity;
1273 solid_elasticity.bulkCompressibilityFromYoungsModulus(
1274 solid_phase, variables, x_position, t, dt);
1275 auto const beta_SR = (1 - alpha) * beta_S;
1282 variables, variables_prev, x_position, t, dt);
1288 variables, x_position, t, dt);
1291 variables, x_position, t, dt);
1297 double const k_rel =
1299 .template value<double>(variables, x_position, t, dt);
1305 variables, x_position, t, dt);
1306 _ip_data[ip].dry_density_solid = (1 - phi) * rho_SR;
1310 auto const K_pT_thermal_osmosis =
1311 (solid_phase.hasProperty(
1316 .value(variables, x_position, t, dt))
1317 : Eigen::MatrixXd::Zero(GlobalDim, GlobalDim));
1320 auto const& dNdx =
_ip_data[ip].dNdx;
1321 _ip_data[ip].v_darcy.noalias() = -K_over_mu * dNdx * p_L -
1322 K_pT_thermal_osmosis * dNdx * T +
1323 rho_LR * K_over_mu * b;
1325 saturation_avg += S_L;
1326 porosity_avg += phi;
1328 saturation_avg /= n_integration_points;
1329 porosity_avg /= n_integration_points;