23
23
#include < aspect/material_model/utilities.h>
24
24
#include < aspect/utilities.h>
25
25
26
- #include < deal.II/sundials/kinsol.h>
27
26
#include < deal.II/base/signaling_nan.h>
28
27
#include < deal.II/base/parameter_handler.h>
29
28
@@ -55,14 +54,16 @@ namespace aspect
55
54
const double edot_ii = std::max (std::sqrt (std::max (-second_invariant (deviator (strain_rate)), 0 .)),
56
55
min_strain_rate);
57
56
const double log_edot_ii = std::log (edot_ii);
58
- double log_strain_rate_deriv;
59
57
60
58
// Find effective viscosities for each of the individual phases
61
59
// Viscosities should have the same number of entries as compositional fields
62
60
std::vector<double > composition_viscosities (n_chemical_composition_fields);
63
61
for (unsigned int j=0 ; j < n_chemical_composition_fields; ++j)
64
62
{
65
- // Power law creep equation
63
+ // Because the ratios of the diffusion and dislocation strain rates are not known, stress is also unknown
64
+ // We use KINSOL to find the second invariant of the stress tensor that satisfies the total strain rate.
65
+
66
+ // The power law creep equation is
66
67
// edot_ii_i = A_i * stress_ii_i^{n_i} * d^{-m} \exp\left(-\frac{E_i^\ast + PV_i^\ast}{n_iRT}\right)
67
68
// where ii indicates the square root of the second invariant and
68
69
// i corresponds to diffusion or dislocation creep
@@ -73,22 +74,9 @@ namespace aspect
73
74
// For dislocation creep, viscosity is grain size independent (m=0)
74
75
const Rheology::DislocationCreepParameters dislocation_creep_parameters = dislocation_creep.compute_creep_parameters (j);
75
76
76
- // For diffusion creep, viscosity is grain size dependent
77
- const double prefactor_stress_diffusion = diffusion_creep_parameters.prefactor *
78
- std::pow (grain_size, -diffusion_creep_parameters.grain_size_exponent ) *
79
- std::exp (-(std::max (diffusion_creep_parameters.activation_energy + pressure*diffusion_creep_parameters.activation_volume ,0.0 ))/
80
- (constants::gas_constant*temperature));
81
-
82
- // Because the ratios of the diffusion and dislocation strain rates are not known, stress is also unknown
83
- // We use KINSOL to find the second invariant of the stress tensor that satisfies the total strain rate.
84
- SUNDIALS::KINSOL<Vector<double >>::AdditionalData additional_data;
85
- additional_data.strategy = dealii::SUNDIALS::KINSOL<>::AdditionalData::newton;
86
- additional_data.function_tolerance = log_strain_rate_residual_threshold;
87
- additional_data.maximum_non_linear_iterations = stress_max_iteration_number;
88
- additional_data.maximum_setup_calls = 1 ;
89
-
90
- SUNDIALS::KINSOL<Vector<double >> nonlinear_solver (additional_data);
91
77
78
+ SUNDIALS::KINSOL<Vector<double >> nonlinear_solver (kinsol_settings);
79
+ double log_strain_rate_deriv;
92
80
nonlinear_solver.reinit_vector = [&](Vector<double > &x)
93
81
{
94
82
x.reinit (1 );
@@ -98,7 +86,9 @@ namespace aspect
98
86
[&](const Vector<double > ¤t_log_stress_ii,
99
87
Vector<double > &residual)
100
88
{
101
- std::tie (residual (0 ), log_strain_rate_deriv) = compute_log_strain_rate_residual_and_derivative (current_log_stress_ii[0 ], pressure, temperature, diffusion_creep_parameters, dislocation_creep_parameters, log_edot_ii);
89
+ std::tie (residual (0 ), log_strain_rate_deriv) = compute_log_strain_rate_residual_and_derivative (
90
+ current_log_stress_ii[0 ], pressure, temperature, diffusion_creep_parameters, dislocation_creep_parameters, log_edot_ii
91
+ );
102
92
};
103
93
104
94
nonlinear_solver.setup_jacobian =
@@ -115,14 +105,23 @@ namespace aspect
115
105
solution (0 ) = residual (0 ) / log_strain_rate_deriv;
116
106
};
117
107
118
- // Start with the assumption that all strain is accommodated by diffusion creep:
119
- // If the diffusion creep prefactor is very small, that means that the diffusion viscosity is very large.
120
- // In this case, use the maximum viscosity instead to compute the starting guess.
121
- double stress_ii = (prefactor_stress_diffusion > (0.5 / maximum_viscosity)
122
- ?
123
- edot_ii/prefactor_stress_diffusion
124
- :
125
- 0.5 / maximum_viscosity);
108
+
109
+ // Our starting guess for the stress assumes that all strain is
110
+ // accommodated by either diffusion creep, dislocation creep,
111
+ // or by the maximum viscosity limiter.
112
+ const double prefactor_stress_diffusion = diffusion_creep_parameters.prefactor *
113
+ std::pow (grain_size, -diffusion_creep_parameters.grain_size_exponent ) *
114
+ std::exp (-(std::max (diffusion_creep_parameters.activation_energy + pressure*diffusion_creep_parameters.activation_volume ,0.0 ))/
115
+ (constants::gas_constant*temperature));
116
+
117
+ const double prefactor_stress_dislocation = dislocation_creep_parameters.prefactor *
118
+ std::exp (-(std::max (dislocation_creep_parameters.activation_energy + pressure*dislocation_creep_parameters.activation_volume ,0.0 ))/
119
+ (constants::gas_constant*temperature));
120
+
121
+ double stress_ii = std::min ({
122
+ std::pow (edot_ii/prefactor_stress_diffusion, 1 ./diffusion_creep_parameters.stress_exponent ),
123
+ std::pow (edot_ii/prefactor_stress_dislocation, 1 ./dislocation_creep_parameters.stress_exponent ),
124
+ 0.5 / maximum_viscosity});
126
125
127
126
// KINSOL works on vectors and so the scalar (log) stress is inserted into
128
127
// a vector of length 1
@@ -142,8 +141,8 @@ namespace aspect
142
141
const double current_log_stress_ii,
143
142
const double pressure,
144
143
const double temperature,
145
- const Rheology::DiffusionCreepParameters diffusion_creep_parameters,
146
- const Rheology::DislocationCreepParameters dislocation_creep_parameters,
144
+ const Rheology::DiffusionCreepParameters & diffusion_creep_parameters,
145
+ const Rheology::DislocationCreepParameters & dislocation_creep_parameters,
147
146
const double log_edot_ii) const
148
147
{
149
148
const std::pair<double , double > log_diff_edot_and_deriv = diffusion_creep.compute_log_strain_rate_and_derivative (current_log_stress_ii, pressure, temperature, diffusion_creep_parameters);
@@ -339,6 +338,11 @@ namespace aspect
339
338
dislocation_creep.initialize_simulator (this ->get_simulator ());
340
339
dislocation_creep.parse_parameters (prm, std::make_unique<std::vector<unsigned int >>(n_chemical_composition_fields));
341
340
341
+ // KINSOL settings
342
+ kinsol_settings.strategy = dealii::SUNDIALS::KINSOL<>::AdditionalData::newton;
343
+ kinsol_settings.function_tolerance = log_strain_rate_residual_threshold;
344
+ kinsol_settings.maximum_non_linear_iterations = stress_max_iteration_number;
345
+ kinsol_settings.maximum_setup_calls = 1 ;
342
346
}
343
347
}
344
348
}
0 commit comments