Skip to content

Only require old stresses for elasticity if necessary#7007

Open
gassmoeller wants to merge 3 commits into
geodynamics:mainfrom
gassmoeller:only_use_as_many_fields_as_necessary
Open

Only require old stresses for elasticity if necessary#7007
gassmoeller wants to merge 3 commits into
geodynamics:mainfrom
gassmoeller:only_use_as_many_fields_as_necessary

Conversation

@gassmoeller

Copy link
Copy Markdown
Member

@anne-glerum as discussed this is a rebased version of anne-glerum#20. Can you give this a proper review? I am missing a changelog entry, I will need to write that as well.

Summary of PR: Our elasticity implementation under certain conditions needs two sets of stress tensors, one for the current time step, and one for the old time step partially modified into the current time (advected with the flow, but not rotated according to it). However, this is only necessary under certain conditions (see: https://github.com/geodynamics/aspect/compare/main...gassmoeller:aspect:only_use_as_many_fields_as_necessary?expand=1#diff-06e3c0241f4cd5f26a2dd149ee3e25bf3217d99aafcff84d02a98fe32629db6bR806). If these conditions are not met, we can get away with one advected stress tensor, which significantly reduces the compute time and memory requirements.

We will also have to look into all the elasticity benchmarks and tests to see which ones need to be modified. And we should decide if it should be allowed to specify two stress tensors (current and old) even if the old one is not needed. We could allow it for backward compatibility (and to make it easier to switch between the two approaches). I havent actually thought about if my current implementation allows both or not.

@tiannh7

tiannh7 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Hi @gassmoeller ,

Thank you for working on this. I think this is a very useful improvement.

I have run into a similar issue in my recent 3-D viscoelastic models. In my tests, requiring the old stress fields did not seem to provide a noticeable improvement in accuracy for the cases I examined, but it did have a large impact on computational cost. The additional stress fields significantly affect memory use, advection cost, matrix assembly, and overall solve time in large 3-D calculations.

In my local setup, I have been using an option similar to use old stress = false. I have tested this with several benchmarks and model comparisons, and so far I have not found a significant difference in the results for the cases where the old unrotated stress is not required by the time-stepping scheme.

I had been planning to discuss this after finishing my current project, so I am very glad to see this issue being addressed in this PR. This looks like a very helpful change for large 3-D viscoelastic models.

@anne-glerum anne-glerum left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @gassmoeller, this is going to be a great speed-up, thank you! I have a few tiny comments, and think that the logic in solver_schemes.cc needs to be changed.


// Compute the total stress at time t.
const SymmetricTensor<2, dim>
// Compute the total stress at time $t+\Delta t_c$.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this PR doesn't change when the reactions are computed/applied, this is still computing the total stress at time t, at the beginning of the next timestep $t+\Delta t_c$.

Suggested change
// Compute the total stress at time $t+\Delta t_c$.
// Compute the total stress at time $t$.

Comment on lines +317 to +319
const std::shared_ptr<MaterialModel::ReactionRateOutputs<dim>> reaction_rate_outputs
= material_outputs.template get_additional_output_object<MaterialModel::ReactionRateOutputs<dim>>();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These lines are not needed in this PR, probably a leftover from anne-glerum#19.

Comment thread source/simulator/solver_schemes.cc Outdated
Comment on lines +429 to +430
for (auto &c : stress_field_indices)
stress_initial_residual += system_rhs.block(introspection.block_indices.compositional_fields[c]).l2_norm() / n_stress_fields;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be restricted to the current fields ve_stress*, not the current and old fields. n_stress_fields could be 2*n_independent_components here, and we don't want to average the residual over both tensors.

Comment thread source/simulator/solver_schemes.cc Outdated

// Overwrite the initial residual
for (auto &c : stress_indices)
if (c<SymmetricTensor<2,dim>::n_independent_components)

@anne-glerum anne-glerum Jun 19, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stresses don't need to be listed as the first fields, so their compositional field indexes aren't necessarily <n_independent_components. The index of each stress field within stress_indices would be for the first/current set of stresses.

Comment thread source/simulator/solver_schemes.cc
@anne-glerum

anne-glerum commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

We will also have to look into all the elasticity benchmarks and tests to see which ones need to be modified. And we should decide if it should be allowed to specify two stress tensors (current and old) even if the old one is not needed. We could allow it for backward compatibility (and to make it easier to switch between the two approaches). I havent actually thought about if my current implementation allows both or not.

At the moment, in some places decisions are based on the number of fields of type stress (e.g. in the particle property). Keeping the old stress fields even though they are not used, would need some changes to that logic. Perhaps calling the material model for require_unrotated_viscoelastic_stress should be the actual check everywhere.

@gassmoeller gassmoeller force-pushed the only_use_as_many_fields_as_necessary branch from a390921 to 85e1b98 Compare June 22, 2026 14:15

@anne-glerum anne-glerum left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Rene, thanks for going through all the prm files! The ones that have changed so far look good. I think some comments in the material model and one more thing in the solver_scheme still needs to be changed.

// second set of n_independent_components fields, e.g. in 2D on field 3, 4 and 5.
// The old stress was advected into the current timestep, but not rotated.
// Below we update it to full stress of the current timestep after using it to
// compute the full stress.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 3 lines were changed, but the old version was correct. In this PR the reaction rates are still used at the beginning of the current timestep to compute the full stress of the previous timestep.

Comment on lines +786 to +789
// Also update the second set of stresses, stress_old, with the newly computed stress,
// which in the next timestep will serve as the old stress advected but not rotated
// into the current timestep. For fields, this function fill_reaction_rates is only
// called at the end of the timestep, and so this update only happens once.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment has also been changed, but for the current PR the reaction rates are still used at the beginning of the timpestep to update the stress of the previous timestep.

old_stress_indices.push_back(introspection.compositional_index_for_name("ve_stress_yz_old"));
}

for (unsigned int c=0; c<SymmetricTensor<2,dim>::n_independent_components; ++c)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the stress fields do not have to be the first fields, looping over field 0 to n_independent_components is not necessarily correct. The loop will have to be over the first n_independent_components of stress_field_indices.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants