Skip to content

Commit

Permalink
Merge pull request #5671 from bangerth/hack-spd-correction
Browse files Browse the repository at this point in the history
Better (and correctly) document the SPD correction factor.
  • Loading branch information
gassmoeller authored May 31, 2024
2 parents 3abee03 + 386f41f commit b8d1177
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 9 deletions.
25 changes: 19 additions & 6 deletions include/aspect/utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -816,17 +816,30 @@ namespace aspect
*
* The goal of this function is to find a factor $\alpha$ so that
* $2\eta(\varepsilon(\mathbf u)) I \otimes I + \alpha\left[a \otimes b + b \otimes a\right]$ remains a
* positive definite matrix. Here, $a=\varepsilon(\mathbf u)$ is the @p strain_rate
* positive definite rank-4 tensor (i.e., a positive definite operator mapping
* rank-2 tensors to rank-2 tensors). By definition, the whole operator
* is symmetric. In the definition above, $a=\varepsilon(\mathbf u)$ is the @p strain_rate
* and $b=\frac{\partial\eta(\varepsilon(\mathbf u),p)}{\partial \varepsilon}$ is the derivative of the viscosity
* with respect to the strain rate and is given by @p dviscosities_dstrain_rate. Since the viscosity $\eta$
* must be positive, there is always a value of $\alpha$ (possibly small) so that the result is a positive
* definite matrix. In the best case, we want to choose $\alpha=1$ because that corresponds to the full Newton step,
* definite operator. In the best case, we want to choose $\alpha=1$ because that corresponds to the full Newton step,
* and so the function never returns anything larger than one.
*
* The factor is defined by:
* $\frac{2\eta(\varepsilon(\mathbf u))}{\left[1-\frac{b:a}{\|a\| \|b\|} \right]^2\|a\|\|b\|}$. Alpha is
* reset to a maximum of one, and if it is smaller then one, a safety_factor scales the alpha to make
* sure that the 1-alpha won't get to close to zero.
* One can do some algebra to determine what the optimal factor is. We did
* this in the Newton paper (Fraters et al., Geophysical Journal
* International, 2019) where we derived a factor of
* $\frac{2\eta(\varepsilon(\mathbf u))}{\left[1-\frac{b:a}{\|a\| \|b\|} \right]^2\|a\|\|b\|}$,
* which we reset to a maximum of one, and if it is smaller then one,
* a safety_factor scales the value to make sure that 1-alpha won't get to
* close to zero. However, as later pointed out by Yimin Jin, the computation
* is wrong, see https://github.com/geodynamics/aspect/issues/5555. Instead,
* the function now computes the factor as
* $(2 \eta) / (a:b + b:a)$, again capped at a maximal value of 1,
* and using a safety factor from below.
*
* In practice, $a$ and $b$ are almost always parallel to each other,
* and $a:b + b:a = 2a:b$, in which case one can drop the factor
* of $2$ everywhere in the computations.
*/
template <int dim>
double compute_spd_factor(const double eta,
Expand Down
14 changes: 11 additions & 3 deletions source/utilities.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2521,11 +2521,19 @@ namespace aspect
if ((strain_rate.norm() == 0) || (dviscosities_dstrain_rate.norm() == 0))
return 1;

const double E = strain_rate * dviscosities_dstrain_rate;
if (E >= -eta * SPD_safety_factor)
// If the correction a:b+b:a is smaller than 2*eta (by at least
// the safety factor), then we are on the safe side and can
// use the optimal value 1. (We are here assuming the common case
// where a is parallel to b, so a:b+b:a = 2a*b and we can drop
// the factor of 2 on both sides
const double a_colon_b = strain_rate * dviscosities_dstrain_rate;
if (a_colon_b < eta * SPD_safety_factor)
return 1.0;
else
return SPD_safety_factor * std::abs(eta / E);
// Otherwise we have that the correction a:b+b:a=2a*b is
// too large and we have to return a factor smaller than
// one.
return SPD_safety_factor * std::abs(eta / a_colon_b);
}


Expand Down

0 comments on commit b8d1177

Please sign in to comment.