-
Notifications
You must be signed in to change notification settings - Fork 237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Use correct stresses in visco-elasto-plastic rheology #4370
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@anne-glerum - Thanks for starting this discussion! I've added comments under most of your discussion points, but will wait to add further comments until @bobmyhill and @dansand have a chance to chime in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More thoughts about where we might need to use different stress values.
d544685
to
c255d55
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@anne-glerum - Partial review at the end of the today. Bravo for getting this all implemented and particularly the comments, which very succinctly and clearly outlines the "old versus new" issue in the context of ASPECTs solvers (+ how things are being updated)! 👏 Independent of elasticity, the comments are an excellent resource for anyone trying to understand the solver schemes and solution updates!
MaterialModel::MaterialModelOutputs<dim> &out) const | ||
{ | ||
if (in.current_cell.state() == IteratorState::valid && this->get_timestep_number() > 0 && in.requests_property(MaterialProperties::reaction_terms)) | ||
// TODO: also evaluate at t = 0? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I initially thought we would want to do this at t=0, but now I'm not sure it makes sense to do so if we have not actually computed a numerical time step yet? However, I think we would still definitely want to add the force term to the RHS of the momentum equation at t=0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the moment, we use the fixed_elastic_timestep when no numerical timestep is available yet, so that's probably fine. If the initial fields are zero, the reaction terms will be zero. Thinking about it again, I think the reaction terms should be computed at t0 just in case the initial stresses on the fields are not zero.
The force terms are already added at t0.
// old stress have been incorrectly switched. In Eq. (8) of the same supplement, | ||
// the advected stress history tensor is used, but this tensor is only advected during | ||
// the advection solve for which we are computing the reaction terms here (in case of fields). | ||
// TODO Change: delete these lines. Move to somewhere else? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these lines should be removed from the code, but the key points added into the ASPECT manual when we put in a section for the VEP rheology.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain again why these lines are not needed anymore? If they are unnecessary or wrong, they should be deleted (no need to keep them). If they are a feature that is unsupported with the new way we do elastic stressses, we could keep a note about this (which feature, which PR it was removed), but still remove the code to avoid outdated code and confusion (we can always get it back from the git history).
// $\tau^{t}_T = 2 \eta^{t}_effcreep (\dot{\varepsilon}^{t}_T + \frac{\tau^{t}_{0adv}}{2 G \Delta te}$. | ||
// Compute difference $\tau^{t}_T - \tau^{t}_{0adv}$. | ||
// Multiply with previous timestep, divide by current timestep. | ||
// Can we Assert here that $tau^{t+\Delta te} == \eta_{eff} D^{t+\Delta te}_{eff}$? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what the Assert here would be checking. Can you elaborate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still confused about what this assert would be checking.
Anne: @bobmyhill do you remember?
Thanks for the comments @naliboff , I've addressed them where possible. Maybe @bobmyhill , @jdannberg or @gassmoeller can also give this a look? |
b331551
to
932635c
Compare
f376adc
to
78939f0
Compare
6298741
to
0efcbec
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@anne-glerum - I added a few more suggestions and questions to the PR, nearly entirely just regarding documentation. Overall, the PR is in great shape and really well documented (thank you!). I did not get through the full PR, but did review the key updates to elasticity.cc, etc.
A few additional general questions:
- Can the stress_component_statistics still be removed, per a comment in the .cc file? If it does need to be included, I will review that as well.
- Are the updates to stress.cc implementing the same changes as proposed in fixed stress visualization for elastic materials #4375?
// the advected stress history tensor is used, but this tensor is only advected during | ||
// the advection solve for which we are computing the reaction terms here (in case of fields). | ||
// TODO Change: delete these lines. Move to somewhere else? | ||
//if (use_stress_averaging == true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe uncomment these lines for now, but add in a comment above saying that this operation will never be done due to an assert (or something to this effect)?
// $\tau^{t}_T = 2 \eta^{t}_effcreep (\dot{\varepsilon}^{t}_T + \frac{\tau^{t}_{0adv}}{2 G \Delta te}$. | ||
// Compute difference $\tau^{t}_T - \tau^{t}_{0adv}$. | ||
// Multiply with previous timestep, divide by current timestep. | ||
// Can we Assert here that $tau^{t+\Delta te} == \eta_{eff} D^{t+\Delta te}_{eff}$? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still confused about what this assert would be checking.
Anne: @bobmyhill do you remember?
I think the statistics postprocessor could still be useful, as it gives the statistics of the full stress at time t, instead of the the rotated and advected, but not updated, stress at time t. I've changed the comments to reflect this.
No. The changes in #4375 are valid for the VEP implementation in main, the changes in stress.cc are for the VEP implementation in this PR. |
f02d6d6
to
30a7ab5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will need to finish this later, but I have a number of small items and questions at this stage.
@@ -121,7 +121,7 @@ namespace aspect | |||
this->get_material_model().evaluate (material_inputs,material_outputs); | |||
|
|||
for (unsigned int i = 0; i < SymmetricTensor<2,dim>::n_independent_components ; ++i) | |||
particle->get_properties()[data_position + i] += material_outputs.reaction_terms[0][i]; | |||
particle->get_properties()[data_position + i] = material_inputs.composition[0][i] + material_outputs.reaction_terms[0][i]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is potentially a problem. By first interpolating the particle property to the field and then assigning back to the particle we introduce a lot of numerical diffusion. Why does the approach above not work? Because of the nonlinear solver?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think my reasoning was as follows:
- In the operator splitting step, we update the solution (the stress compositional fields) of the previous timestep.
- After that we advance the particles and evaluate the updated solution at their location
- We then update the particle properties, in this case the stress. If we use the stress values on the particles, then these do not include the operator splitting update. If we instead use the stress values that were updated and interpolated to the particle locations, then we include the operator splitting update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update: now we use two particle properties, composition
and elastic_stress
. composition
updates the particle properties with the new field solutions that include the operator splitting step. elastic_stress
then applies the reaction term. So now we can stick with
particle->get_properties()[data_position + i] += material_outputs.reaction_terms[0][i];
// old stress have been incorrectly switched. In Eq. (8) of the same supplement, | ||
// the advected stress history tensor is used, but this tensor is only advected during | ||
// the advection solve for which we are computing the reaction terms here (in case of fields). | ||
// TODO Change: delete these lines. Move to somewhere else? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain again why these lines are not needed anymore? If they are unnecessary or wrong, they should be deleted (no need to keep them). If they are a feature that is unsupported with the new way we do elastic stressses, we could keep a note about this (which feature, which PR it was removed), but still remove the code to avoid outdated code and confusion (we can always get it back from the git history).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few more comments. Let me know if I should take a look at the postprocessors as well.
@anne-glerum I tried to have a look at this PR, but you have a lot of unrelated changes in your branch (see https://github.com/geodynamics/aspect/pull/4370/files). It looks like you may have merged the 2.4.0 release branch, or some other changes. Can you rebase and try to remove the unrelated changes from your branch? |
Hi @gassmoeller , yes I can see that makes reviewing very complicated. I rebased to the release because that is the version we wanted to use for the paper. I can make a copy of this branch (based on the release) and then rebase this PR to main. Would it be okay if I squash my commits before I rebase? I remember rebasing to the release being very laborious because of a multitude of commits giving merge conflicts. Alternatively, I update the copy of this branch I still have from before the rebase to the release with the changes I have made in the meantime and then rebase that to main. I'd then still prefer to squash the commits first. I'm not sure what is preferable or whether it makes a difference. |
Yes, I think that is the best approach. Keep a copy based on the release (for reference in the paper), but rebase to main so that we can merge it. Squashing the commits is fine. |
Okay, thanks. I will do that and let you know when I'm done :) |
7fb8ec2
to
f8dde02
Compare
Hi @gassmoeller, I have rebased to main. I also ran the third benchmark (2D square under simple shear for half of the model time) again; I summarize the results below. Maybe you could keep the issues listed below in mind when going through the code.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I started a review, but didnt get through the important part yet, I will continue tomorrow or Wednesday. Just some comments for now.
Hi @anne-glerum, I think I understand the problem (after about 2 hours of reconstructing the order of operations 😄) and have an idea for a fix, but it is a bit complex:
Each solution is a bit tricky, but i think we need one of them. I prefer 2 or 3, because they also add additional functionality to ASPECT, and are not limited to our current problem. Maybe something we need to work on during the hackathon? Could you try the problematic benchmark with |
Ohhh brilliant @gassmoeller! Thank you for taking the time to figure this out! Concerning option 3, we would need access to the It seems a bit like duplicating functionality (having an operator splitting for fields and for particles), but completely storing and computing stresses on the particles is a clean option. And, like you say, it's an update to a property value, it doesn't need the additional functionality of solving the ODEs over multiple timesteps. Maybe we can discuss it tomorrow. And yes, this does sound like a hack project.
Using |
3d50613
to
44fb0f6
Compare
44fb0f6
to
e63b401
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A first batch of comments, I have to split this into several reviews because of the length of the PR.
heating_model_outputs.heating_source_terms[q] = stress * deviatoric_strain_rate; | ||
|
||
// If elasticity is used, the stress should include the elastic stresses | ||
// and only the visco-plastic (non-elastic) strain rate should contribute. | ||
if (this->get_parameters().enable_elasticity == true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please include the first line in the if-else as in:
if (this->get_parameters().enable_elasticity == false)
heating_model_outputs.heating_source_terms[q] = stress * deviatoric_strain_rate;
else
{
...
}
double dtc = this->get_timestep(); | ||
if (!this->simulator_is_past_initialization() || | ||
(this->get_timestep_number() == 0 && this->get_timestep() == 0)) | ||
dtc = std::min(std::min(this->get_parameters().maximum_time_step, this->get_parameters().maximum_first_time_step), elastic_timestep()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth to have this complicated estimate instead of just returning 1.0
(= elastic_timestep() / elastic_timestep()
)? It will likely only matter for the zeroeth timestep in models that set a maximum time step. But we should not accumulate any elastic stresses in time step 0 anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit complicated, but in all our benchmarks we set the maximum timestep to either equal the elastic timestep or to be a specific factor smaller than the elastic timestep. If the initial stress is nonzero, the timestep ratio matters for the force term and viscous dissipaton, and the timestep ratio also feeds into the elastic viscosity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Next batch of comments mostly concerning the particle property and the postprocessors.
for (unsigned int n = 0; n < this->n_compositional_fields(); ++n) | ||
material_inputs.composition[0][n] = old_solution[this->introspection().component_indices.compositional_fields[n]]; | ||
for (unsigned int n = 0; n < 2*SymmetricTensor<2,dim>::n_independent_components; ++n) | ||
material_inputs.composition[0][n] = particle->get_properties()[data_position + n]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not understand this part. Is it equivalent to:
for (n=0; n<2*n_independent_components)
composition[n] = particle_property[data_position + n];
for (n=2*n_independent_components; n<n_compositional_fields)
composition[n] = old_solution[compositional_index[n]];
If so, maybe it is easier to write it that way (e.g. flip the order of the loops and do not overwrite entries that have just been set).
Also just because I see it here: The code assumes that all stress fields are the first fields listed, is this correct? I thought I saw somewhere that we try to move away from that restriction and only require that stress fields are contiguous (but not necessarily the first compositional fields). We can discuss if that is necessary for this PR or something for later, but I feel uncomfortable introducing more features that require a certain position of compositional fields now that we have the compositional_field_type
infrastructure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I've started to move away from the stress fields having to be the first fields. I'll make sure that is consistently done everywhere.
I now only fill the non-stress fields with the old_solution, so there is no overwriting with the particle values anymore.
// Visco-elastic stresses are stored on the fields | ||
SymmetricTensor<2, dim> stress_0, stress_old; | ||
stress_0[0][0] = in.composition[q][this->introspection().compositional_index_for_name("ve_stress_xx")]; | ||
stress_0[1][1] = in.composition[q][this->introspection().compositional_index_for_name("ve_stress_yy")]; | ||
stress_0[0][1] = in.composition[q][this->introspection().compositional_index_for_name("ve_stress_xy")]; | ||
|
||
stress_old[0][0] = in.composition[q][this->introspection().compositional_index_for_name("ve_stress_xx_old")]; | ||
stress_old[1][1] = in.composition[q][this->introspection().compositional_index_for_name("ve_stress_yy_old")]; | ||
stress_old[0][1] = in.composition[q][this->introspection().compositional_index_for_name("ve_stress_xy_old")]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I vaguely remember that this was discussed somewhere, but please remind me. The reason the sign is flipped between the elastic and non-elastic case is that the stress stored in the ve_stress
fields already has the correct sign convention? Maybe add this to the comment in line 139.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation in main takes the stress directly from the stored fields and multiplies it with -1 to get the right sign convention. This branch's implementation builds the full shear stress from the fields stress_0 and stress_old (not negating them) and then multiplies the whole shear stress with -1. So the signs are the same?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Next batch of comments, this time mostly for the material models.
const std::vector<unsigned int> stress_field_indices = this->introspection().get_indices_for_fields_of_type(CompositionalFieldDescription::stress); | ||
for (auto it = stress_field_indices.begin(); it != stress_field_indices.end(); ++it) | ||
composition_mask.set(*it, false); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With #5643 you can simplify this code to:
const std::vector<unsigned int> stress_field_indices = this->introspection().get_indices_for_fields_of_type(CompositionalFieldDescription::stress); | |
for (auto it = stress_field_indices.begin(); it != stress_field_indices.end(); ++it) | |
composition_mask.set(*it, false); | |
} | |
const std::vector<unsigned int> &stress_field_indices = this->introspection().get_indices_for_fields_of_type(CompositionalFieldDescription::stress); | |
for (unsigned int field_index: stress_field_indices) | |
composition_mask.set(field_index, false); | |
} |
But one additional question: The comment says to set a mask representing the viscoelastic stress tensor components, but to me it looks like the code is doing the opposite, it sets a mask that excludes all the stress tensor components. Do I misunderstand the code or does the comment need an update?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The strain rheology mask function above starts with true
s and for each strain field sets the true
to false
. The corresponding stress tensor components are also set to false
here. I'll make the comment more clear.
This whole function is actually no longer used since
#5542 and could be removed, also from main.
// Only fill them if operator splitting is used for fields or when the particles track | ||
// the visco-elastic stresses. | ||
if (this->get_parameters().use_operator_splitting || | ||
((this->get_parameters().mapped_particle_properties).count(this->introspection().compositional_index_for_name("ve_stress_xx")))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This condition could use an update to the compositional type machinery: this->introspection().composition_type_exists(CompositionalFieldDescription::stress)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the check can be removed. If elasticity is used with the VE or VP material model, we already do this check in parse_parameters in elasticity.cc. I did add the check in.requests_property(MaterialProperties::reaction_rates))
in fill_reaction_rates.
// timestep to the advected and rotated stress computed in the previous timestep ($\tau^{0adv}$) | ||
// to obtain $\tau^{t}$. | ||
if (this->get_parameters().use_operator_splitting || | ||
((this->get_parameters().mapped_particle_properties).count(this->introspection().compositional_index_for_name("ve_stress_xx")))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use the introspection
to ask for material type here (see my comment in visco_plastic).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, I've removed this check.
d8453d1
to
74a042e
Compare
af20e85
to
8352252
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didnt make it through all files, but here are some smaller suggestions. I think this is getting quite close to merge. Let's talk a bit more about the field duplication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work. A few very minor suggestions, but this looks almost good to go.
benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up_particles.prm
Show resolved
Hide resolved
benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up_yield_particles.prm
Show resolved
Hide resolved
// Assemble current and old stress tensor if elastic behavior is enabled | ||
SymmetricTensor<2, dim> stress_0_advected = numbers::signaling_nan<SymmetricTensor<2, dim>>(); | ||
SymmetricTensor<2, dim> stress_old = numbers::signaling_nan<SymmetricTensor<2, dim>>(); | ||
double elastic_shear_modulus = numbers::signaling_nan<double>(); | ||
if (this->get_parameters().enable_elasticity) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can all of the code in this if statement be moved into elasticity.cc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be, but the stress tensors are used in a later if statement to compute the effective strain rate. That function call could get the MaterialInputs in
and unwrap the tensors from the fields itself. It would do it for each volume fraction though.
// (different rotations, different stress changes), but this is inconsistent with storing only one stress tensor. | ||
// The averaging used is the same as for the viscosity. | ||
const std::vector<double> &elastic_shear_moduli = elastic_rheology.get_elastic_shear_moduli(); | ||
elastic_shear_modulus = MaterialUtilities::average_value(volume_fractions, elastic_shear_moduli, viscosity_averaging); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might we want to have a separate shear_modulus_averaging
parameter declared in the elastic rheology module?
@anne-glerum let us know when you want us to take another look at this. |
@gassmoeller I will, I want to test it again first on our cluster. |
7b0f92e
to
ced787e
Compare
98aee95
to
64988eb
Compare
64988eb
to
ad2dfce
Compare
This PR is at the moment for discussing with everybody interested the changes to the elasticy and visco-plastic plugins that @bobmyhill, @naliboff and I discussed yesterday. @dansand, your input would be great to have!
FYI @EstherHeck
For all pull requests:
For new features/models or changes of existing features: