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
Add derivatives to visco plastic material model #2030
Add derivatives to visco plastic material model #2030
Conversation
@MFraters - Great! Given that there will likely be a few more material models added that use the Newton solver, perhaps it would be worth moving the finite difference section higher up as you suggested? Regardless, I'll take go through this today or tomorrow. |
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.
In general I like the changes a lot, and think that they will be helpful for a number of other material models as well. However, I have a few technical issues with the changes. There are some pieces I do not quite understand and that need to be better documented. Moreover, I do not like to add checks that are only important, because of the way we test this material model. Is it possible to remove these get_simulator
tests and still be able to test the model? Or would that be very complicated?
@@ -182,7 +183,7 @@ namespace aspect | |||
// The first time this function is called (first iteration of first time step) | |||
// a specified "reference" strain rate is used as the returned value would | |||
// otherwise be zero. | |||
const double edot_ii = ( (this->get_timestep_number() == 0 && strain_rate.norm() <= std::numeric_limits<double>::min()) | |||
const double edot_ii = ( (&(this->get_simulator()) != nullptr && this->get_timestep_number() == 0 && strain_rate.norm() <= std::numeric_limits<double>::min()) |
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.
Why is this necessary? I was under the impression that we should never get here without a simulator object. Is this just something for the tests?
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, during the test of this material model, there is no simulator. So this is to make sure that the test actually works.
MaterialModel::MaterialModelDerivatives<dim> *derivatives; | ||
derivatives = out.template get_additional_output<MaterialModel::MaterialModelDerivatives<dim> >(); | ||
|
||
const double derivative_scaling_factor = &(this->get_simulator()) != nullptr ? (this->get_parameters().nonlinear_solver == Parameters<dim>::NonlinearSolver::Newton_Stokes ? this->get_newton_handler().get_newton_derivative_scaling_factor() : 0) : 1; |
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 complicated to read, could you spell that out in actual if-else-loops. Again, why do we need to test for the simulator pointer?
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.
If I remove the const I can spell it out in if-else statements. I could also add a comment explaining the line. Something like: If there is no simulator, it is a test environment and we want to enable the derivatives, so we set this variable to one. If we do not use the Newton solver, we do not need the derivatives, so we set this variable to zero. Otherwise, we use the value from the newton handler.
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.
If having the const
leads to code that is hard to read, then get rid of it. The comment sounds good to me!
// compute derivatives if nessesary | ||
if (derivative_scaling_factor != 0 && derivatives != NULL) | ||
{ | ||
const double finite_difference_accuracy = 1e-7; |
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 parts needs significantly more explanation. Why do you split up the components of the strain rate? I would prefer if we can move a lot of this into a separate function (either private in this material model or in aspect::Utilities
). Is this currently only implemented for 2D (you only access elements 0 or 1)? What happens if strain_rate is close to zero?
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.
Good point. I have moved the splitting of the components into a separate function, which allows for much less code :) It works now both in 2d and 3d. I also added more comments in the code.
@@ -544,6 +666,14 @@ namespace aspect | |||
void | |||
ViscoPlastic<dim>::declare_parameters (ParameterHandler &prm) | |||
{ | |||
prm.enter_subsection("Compositional fields"); |
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 do not need to declare a parameter again, this just needs to be done by the plugin owning this parameter.
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.
So this, and the next comment are the same problem as above, the this->n_compositional_fields()
is not available in when it is being tested.
@@ -730,7 +860,13 @@ namespace aspect | |||
ViscoPlastic<dim>::parse_parameters (ParameterHandler &prm) | |||
{ | |||
// increment by one for background: | |||
const unsigned int n_fields = this->n_compositional_fields() + 1; | |||
unsigned int n_fields = 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.
Why does the above not work? In theory you should have access to that variable already.
It will be difficult to check the things I would like to check in a way where there is a simulator. We can of course discuss to see if there is a way to do it. |
@gassmoeller I guess I will have to make different tests for them after all, because I can't change the material model member variable
Or do you know a way around this? |
Check by my office some time today, I am sure we can find a solution to this. |
a71f80c
to
e657541
Compare
@gassmoeller I think that I have addressed all your comments. |
@gassmoeller -- are you working this through with @MFraters or do you want me to also take a look? |
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.
Much better, though I still have a number of comments. I also feel like the two loops over the compositions (separate for strain rate and pressure) in the evaluate
function should be mergeable into a single one (with one inner loop for the strain rate components), but I can only see that clearly when my current comments are addressed. @bangerth: I have marked two questions for you, I can handle the rest.
include/aspect/utilities.h
Outdated
* Create matrix with unit at independent indices | ||
*/ | ||
template <int dim> | ||
SymmetricTensor<2,dim> symmetric_independent_component_matrix (const unsigned int k); |
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 would name this function differently, though I am not sure if there is a convention for this. Maybe index_selector
? It is something that has only zeroes as entries, except for a one in the k
th index (or two 1/2 for the symmetric case). @bangerth: Do you have a good name for this?
The documentation could be the following: "A function that returns a SymmetricTensor, which entries are zero, except for the k'th component, which is set to one. If k is not on the main diagonal the resulting tensor is symmetrized."
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.
For the text, it should be "...WHOSE entries are zero..."
Fundamentally, this function returns the elements of a basis for the set of symmetric tensors since every tensor can be written as a linear combination of the tensors returned by this function. So maybe something like nth_basis_for_symmetric_tensors()
?
const double finite_difference_accuracy = 1e-7; | ||
|
||
// For each independent component, compute the derivative. | ||
for (unsigned int independent_component_k = 0; independent_component_k < SymmetricTensor<2,dim>::n_independent_components; independent_component_k++) |
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.
Lets rename the index to component
, that makes it shorter, and the k
is really not necessary if the name already explains what it is.
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.
Also ++component
instead of component++
for good style
for (unsigned int independent_component_k = 0; independent_component_k < SymmetricTensor<2,dim>::n_independent_components; independent_component_k++) | ||
{ | ||
const TableIndices<2> indices_ij = SymmetricTensor<2,dim>::unrolled_to_component_indices (independent_component_k); | ||
SymmetricTensor<2,dim> strain_rate_component = strain_rate + std::max(std::fabs(strain_rate[indices_ij]), min_strain_rate) * finite_difference_accuracy |
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.
lets call this strain_rate_difference
to stay consistent with the pressure_difference
below.
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.
also can this be const
?
std::vector<double> eta_component = calculate_isostrain_viscosities(volume_fractions, pressure, temperature, composition, strain_rate_component,viscous_flow_law,yield_mechanism); | ||
|
||
// For each composition of the independent component, compute the derivative. | ||
for (unsigned int composition_i = 0; composition_i < eta_component.size(); composition_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.
call this composition_index
and do ++composition_index
if (derivative_component != 0) | ||
{ | ||
// when the difference is non-zero, divide by the difference. | ||
derivative_component /= std::max(std::fabs(strain_rate_component[indices_ij]), min_strain_rate) * finite_difference_accuracy; |
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.
How is the term on the right hand side different from what you add in line 431? If it is the same: Give it a name and define it in line 430.
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.
one uses the strain-rate and the other one uses the strain-rate plus the finite difference of the strain-rate.
// For each independent component, compute the derivative. | ||
for (unsigned int independent_component_k = 0; independent_component_k < SymmetricTensor<2,dim>::n_independent_components; independent_component_k++) | ||
{ | ||
const TableIndices<2> indices_ij = SymmetricTensor<2,dim>::unrolled_to_component_indices (independent_component_k); |
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.
rename this to strain_rate_indices
/** | ||
* Now compute the derivative of the viscosity to the pressure | ||
*/ | ||
double pressure_difference = in.pressure[i] + (std::fabs(in.pressure[i]) * finite_difference_accuracy); |
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.
const
*/ | ||
double pressure_difference = in.pressure[i] + (std::fabs(in.pressure[i]) * finite_difference_accuracy); | ||
|
||
std::vector<double> pressure_difference_eta = calculate_isostrain_viscosities(volume_fractions, pressure_difference, temperature, composition, strain_rate,viscous_flow_law,yield_mechanism); |
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.
viscosity_difference
and const
?
|
||
for (unsigned int composition_i = 0; composition_i < pressure_difference_eta.size(); composition_i++) | ||
{ | ||
double deriv_pressure = pressure_difference_eta[composition_i] - composition_viscosities[composition_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.
rename to viscosity_derivative
source/utilities.cc
Outdated
symmetric_independent_component_matrix (const unsigned int k) | ||
{ | ||
// somehow I need this, because otherwise it complains that I am passing 3 arguments and it only takes 2... | ||
const bool boolian = k < SymmetricTensor<2,dim>::n_independent_components; |
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.
@bangerth: I have tested this and found the same strange behavior. The following code does not work with deal.II 8.5, although it should:
const unsigned int k=0;
Assert(k< SymmetricTensor<2,dim>::n_independent_components,ExcMessage(""))
The compiler error message is:
/home/rengas/Software/Aspect-Versionen/aspect/source/material_model/visco_plastic.cc:815:80: error: macro "Assert" passed 3 arguments, but takes just 2
Assert(k< SymmetricTensor<2,dim>::n_independent_components,ExcMessage(""));
^
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.
As discussed on the way to lunch, you'll have to put a set of (parentheses) around the condition or the preprocessor is going to interpret the comma in 2,dim
as one that separates macro arguments.
It is ready for an new round of reviews :) |
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 have only a couple small comments. Please address and squash your patches. Hopefully your testcase of today then becomes simpler to look at as well!
// otherwise set it to zero. | ||
double derivative_scaling_factor = 0.0; | ||
if (this->get_parameters().nonlinear_solver == Parameters<dim>::NonlinearSolver::Newton_Stokes) | ||
derivative_scaling_factor = this->get_newton_handler().get_newton_derivative_scaling_factor(); |
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.
Hm, why do you actually need this in the material model? Shouldn't the scaling factor be applied only at the one or two places in the assembly where we compute the Newton matrix? If that were the case, you wouldn't have to deal with it in every single material model.
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.
So the factor itself is actually not used to compute something here. It is only used to determine wheter the derivatives should be computed. Because when this scaling factor is zero, which may happen even when derivatives != NULL
, there is no use in computing the derivatives.
@@ -396,14 +408,83 @@ namespace aspect | |||
// TODO: This is only consistent with viscosity averaging if the arithmetic averaging | |||
// scheme is chosen. It would be useful to have a function to calculate isostress viscosities. | |||
const std::vector<double> composition_viscosities = | |||
calculate_isostrain_viscosities(volume_fractions, pressure, temperature, composition, in.strain_rate[i],viscous_flow_law,yield_mechanism); | |||
calculate_isostrain_viscosities(volume_fractions, pressure, temperature, composition, strain_rate,viscous_flow_law,yield_mechanism); |
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.
while you're here, break the line into shorter ones around 80 characters of length, and put a space after every comma separating the arguments
/** | ||
* Now compute the derivative of the viscosity to the pressure | ||
*/ | ||
const double pressure_difference = in.pressure[i] + (std::fabs(in.pressure[i]) * finite_difference_accuracy); |
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.
there are several long lines here. can you break them as well?
source/utilities.cc
Outdated
{ | ||
// somehow I need this, because otherwise it complains that I am passing 3 arguments and it only takes 2... | ||
const bool boolian = k < SymmetricTensor<2,dim>::n_independent_components; | ||
Assert(boolian, ExcMessage("The component is larger then the amount of independent components in the matrix.") ); |
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 write this as
Assert((k < SymmetricTensor<2,dim>::n_independent_components),
ExcMessage("The component is larger then the amount of independent components in the matrix.") );
This has the advantage that the violated condition appears in the screen output.
(Unrelated: The correct spelling is "boolean" because it is named after Mr. Boole.)
f4866c7
to
4539f3c
Compare
4539f3c
to
56c55b6
Compare
About the derivative scaling factor, as I mentioned yesterday my preference would be if the assembly loop simply didn't ask about information it doesn't need, rather than every material model separately trying to figure out whether the information it is being asked to deliver is actually used. |
We convinced ourselves that the code is correct as is. So I'll merge. |
Adding finite difference derivatives to the visco-plastic material model, so it can be used with the Newton solver. With this finite difference model, it should be relatively easy to add derivatives to other material models.
The finite difference could actually be done somewhere higher up or abstracted into a single function.