Skip to content

Commit

Permalink
generalize the SPD factor
Browse files Browse the repository at this point in the history
  • Loading branch information
Yimin Jin committed Jun 3, 2024
1 parent 41c3b29 commit ebc873f
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 20 deletions.
10 changes: 3 additions & 7 deletions include/aspect/utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -841,17 +841,13 @@ namespace aspect
* 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,
* which we reset to a maximum of one, and if it is smaller than 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.
* $\frac{2\eta(\varepsilon(\mathbf u))}{\left[1-\frac{b:a}{\|a\| \|b\|} \right]\|a\|\|b\|}$,
* again capped at a maximal value of 1, and using a safety factor from below.
*/
template <int dim>
double compute_spd_factor(const double eta,
Expand Down
23 changes: 10 additions & 13 deletions source/utilities.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2546,28 +2546,25 @@ namespace aspect

// The factor in the Newton matrix is going to be of the form
// 2*eta I + (a \otimes b + b \otimes a)
// where a=strain_rate and b=dviscosities_dstrain_rate.
//
// If a,b are parallel, this simplifies to
// [2*eta + 2 a:b] I = 2 [eta + a:b] I
// where a=strain_rate and b=dviscosities_dstrain_rate,
// and we need to make sure that
// [eta + alpha a:b] > (1-safety_factor)*eta
// eta + alpha (a:b - |a||b|) / 2 >= (1-safety_factor)*eta
// by choosing alpha appropriately.

// So, first check: If
// [eta + a:b] > (1-safety_factor)*eta
// alpha (|a||b| - a:b) <= 2*safety_factor*eta
// is already satisfied, then we can choose alpha=1
const double a_colon_b = strain_rate * dviscosities_dstrain_rate;
if (eta + a_colon_b > eta * (1. - SPD_safety_factor))
const double norm_a_b = std::sqrt((strain_rate * strain_rate) * (dviscosities_dstrain_rate * dviscosities_dstrain_rate));
const double contract_a_b = strain_rate * dviscosities_dstrain_rate;
const double denominator = norm_a_b - contract_a_b;

if (denominator <= 2.0 * SPD_safety_factor * eta)
return 1.0;
else
{
// Otherwise solve the equation above for alpha, which yields
// a:b = -safety_factor*eta / a:b
// This can only ever happen if a:b < 0, so we get
// a:b = safety_factor * abs(eta / a:b)
Assert (a_colon_b < 0, ExcInternalError());
return SPD_safety_factor * std::abs(eta / a_colon_b);
// alpha = 2*safety_factor*eta / (|a||b| - a:b)
return 2.0 * SPD_safety_factor * eta / denominator;
}
}

Expand Down

0 comments on commit ebc873f

Please sign in to comment.