[GeoMechanicsApplication] Improve the Coulomb model framework#14187
[GeoMechanicsApplication] Improve the Coulomb model framework#14187
Conversation
The new name makes clearer what it returns.
This resolves an issue found by SonarQube.
Also renamed some variables and made a few ones `const`.
…he-coulomb-model-framework
WPK4FEM
left a comment
There was a problem hiding this comment.
Hi Anne,
In retrospect, my review comments are more about the future use than about the current state. I think the PR is a step in a good direction.
Regards, Wijtze Pieter
| #include "custom_constitutive/geo_sigma_tau.hpp" | ||
| #include "custom_constitutive/principal_stresses.hpp" |
There was a problem hiding this comment.
At first glance the naming is not consistent. Why geo_ preceding sigma_tau and omitting geo_ before principal_stresses in the names of the hpp files.
There was a problem hiding this comment.
Well, both classes were prepared by two different developers who adopted different naming schemes. After a brief discussion with you, @rfaasse and myself, we decided to remove the geo_ prefix from geo_sigma_tau.{cpp,hpp}.
| Geo::SigmaTau CoulombWithTensionCutOffImpl::ReturnStressAtTensionCutoffReturnZone(const Geo::SigmaTau& rSigmaTau) const | ||
| { | ||
| const auto derivative_of_flow_function = mTensionCutOff.DerivativeOfFlowFunction(rSigmaTau); | ||
| const auto lambda_tc = (mTensionCutOff.GetTensileStrength() - rSigmaTau[0] - rSigmaTau[1]) / | ||
| const auto lambda_tc = (mTensionCutOff.GetTensileStrength() - rSigmaTau.Sigma() - rSigmaTau.Tau()) / | ||
| (derivative_of_flow_function[0] + derivative_of_flow_function[1]); | ||
| return rSigmaTau + lambda_tc * derivative_of_flow_function; | ||
| return Geo::SigmaTau{rSigmaTau.Values() + lambda_tc * derivative_of_flow_function}; | ||
| } |
There was a problem hiding this comment.
now the lambda computation only depends on the content of the tension cutoff yield surface, but we will need a correction that includes the elastic constitutive tensor. After that correction should this lambda computation be here or a part of the tension cut off yield surface. The latter would make it necessary to know about the elastic constitutive tensor in the yield surfaces.
There was a problem hiding this comment.
I would say that the answer depends on what is conceptually most natural. When the elastic constitutive tensor is naturally associated with the yield surface, the tensor can be part of it. If it's more of a case where the yield surface just uses the elastic constitutive tensor, we may simply pass it through the argument list. What do you think is most natural?
There was a problem hiding this comment.
Pass it through the argument list, otherwise the yield surface may need to know about non-linear elasticity.
|
|
||
| Geo::SigmaTau CoulombWithTensionCutOffImpl::ReturnStressAtRegularFailureZone( | ||
| const Geo::SigmaTau& rSigmaTau, CoulombYieldSurface::CoulombAveragingType AveragingType) const | ||
| { |
There was a problem hiding this comment.
Also this lambda computation will need to know about the elastic constitutive tensor.
| Vector mTractionVector; | ||
| Vector mTractionVectorFinalized; |
There was a problem hiding this comment.
Should we change these to Geo::SigmaTau?
There was a problem hiding this comment.
Over time, yes. But for now, no. The reason I'm against doing it now, is simply scope creep. When we change these data members, we are also forced to make class Geo::SigmaTau serializable (i.e. we need to implement and test load and save functions), or else the serialization of InterfaceCoulombWithTensionCutOff will be broken. All of this is doable, but not with just a few extra lines. Is it okay for you if I add a backlog issue for this suggestion, just so we can pick it up later?
rfaasse
left a comment
There was a problem hiding this comment.
Thanks for implementing this improvement to the framework! I have some conceptual questions and some minor suggestions for improvements, but I don't expect anything major will come out of it!
| CoulombYieldSurface::CoulombAveragingType AveragingType) | ||
| { | ||
| auto sigma_tau_to_sigma_tau = [](const Geo::SigmaTau& rSigmaTau) { return rSigmaTau; }; | ||
| return DoReturnMapping<>(rTrialSigmaTau, sigma_tau_to_sigma_tau, AveragingType); |
There was a problem hiding this comment.
When seeing it like this, it feels a bit weird to pass this trivial conversion function. Would it be possible to have the conversion function as an optional? Then we just skip the conversion if it's not passed
There was a problem hiding this comment.
Hmm, I'm not sure. We cannot really skip the conversion, unless we're willing to assume that when no conversion function is supplied, the given stress state is to be taken as a
There was a problem hiding this comment.
When first reading, my reaction was the same as Richards. Still I would keep the explicit passing of a trivial conversion. We probably will encounter other sets of stress invariants, the name of the convertor is then helping to make explicit from which to which perception of stress we are moving.
| [[nodiscard]] bool IsAdmissibleSigmaTau(const Vector& rTrialSigmaTau) const; | ||
| [[nodiscard]] Vector DoReturnMapping(const Vector& rTrialSigmaTau, | ||
| CoulombYieldSurface::CoulombAveragingType AveragingType); | ||
| [[nodiscard]] bool IsAdmissibleStressState(const Geo::SigmaTau& rTrialSigmaTau) const; |
There was a problem hiding this comment.
You could argue that the name of this argument doesn't need to repeat 'sigma tau' in the name, because it's already it's type (which would also result in code that has a bit less repetition, e.g. rTrialStress.Sigma() instead of rTrialSigmaTau.Sigma()). I'm find with both ways, but am slightly in favour of not repeating the type in variable/argument names.
There was a problem hiding this comment.
In a separate conversation Anne asked me about this. The use of sigma and tau here refers to the tractions on a chosen plane ( which also is the description we choose in an interface element ). Therefore I would find the following natural:
Geo::SigmaTau rTrialTraction
and for selecting the components of this variable you then get rTrialTraction.sigma and rTrialTracion.tau
There was a problem hiding this comment.
Then I will rename the objects of type Geo::SigmaTau to something with "traction" in their names. 👍
| #include "custom_constitutive/sigma_tau.hpp" | ||
| #include "custom_utilities/constitutive_law_utilities.h" | ||
| #include "custom_utilities/stress_strain_utilities.h" | ||
| #include "custom_utilities/ublas_utilities.h" |
There was a problem hiding this comment.
Due to the changes ublas_utilities.h became redundant as an include here.
There was a problem hiding this comment.
Good catch! Removed the now redundant #include.
| return YieldFunctionValue(StressStrainUtilities::TransformPrincipalStressesToSigmaTau(rPrincipalStresses)); | ||
| } | ||
|
|
||
| Vector CoulombYieldSurface::DerivativeOfFlowFunction(const Vector& rSigmaTau) const |
There was a problem hiding this comment.
Probably the same holds here (we only keep it for now, but remove it after the PQ stress state is added?)
There was a problem hiding this comment.
No, I think we will continue to use this specific one. It is being called from CoulombWithTensionCutOffImpl::IsAdmissibleStressState, which accepts either a principal stress state or a MohrCoulombWithTensionCutOff::CalculateMaterialResponseCauchy which calls this check is most naturally expressed in terms of principal stresses, so I wouldn't want to move the conversion from principal stresses to
|
|
||
| void CoulombYieldSurface::SetKappa(double kappa) { mKappa = kappa; } | ||
|
|
||
| // At some point in time we would like to get rid of this API. For now, just forward the request. |
There was a problem hiding this comment.
Just to validate my understanding: is this only kept for now because we don't have the PQ stress state yet (and so have to implement the Vector version to keep supporting building the CompressionCap)?
There was a problem hiding this comment.
It's only there because we have one more yield surface that doesn't use specific stress states yet (i.e. the compression cap). Since all yield surfaces still derive from YieldSurface, we must implement this interface (since they are pure virtual functions). However, the Coulomb yield surface and the tension cut-off no longer use this API (as you can see from the code coverage analysis). As soon as we have expressed the compression cap in terms of YieldSurface interface, and these overrides can be removed. That was what I was trying to say with the comment "At some point in time we would like to get rid of this API. For now, just forward the request.".
| StressStrainUtilities::CalculatePrincipalStresses( | ||
| trial_stress_vector, principal_trial_stress_vector, rotation_matrix); | ||
|
|
||
| if (auto trial_sigma_tau = StressStrainUtilities::TransformPrincipalStressesToSigmaTau(principal_trial_stress_vector); |
There was a problem hiding this comment.
Nice that the conversion is no longer the callers responsibility!
| // Note that we attempt to calculate the principal stress vector (which consists of three values) from the given | ||
| // sigma and tau (two values). As a result, the second principal stress cannot be uniquely determined. | ||
| const auto principal_stress_vector = Geo::PrincipalStresses{}; | ||
| return YieldFunctionValue(StressStrainUtilities::TransformSigmaTauToPrincipalStresses( |
There was a problem hiding this comment.
This means that the second component of the 'new' principal stress would be a 0.0. I don't know enough to determine whether that would lead to a problem or not, so I leave the question here without knowing if it's a redundant one (I see that it's the same as before, with an extra comment, so the situation certainly didn't get worse, just trying to understand).
| auto eigen_vectors = Matrix{}; | ||
| CalculatePrincipalStresses(rStressVector, principal_stresses, eigen_vectors); | ||
|
|
||
| return std::make_pair(Geo::PrincipalStresses{principal_stresses}, eigen_vectors); |
There was a problem hiding this comment.
It's good to keep in mind we create an extra new object here (the PrincipalStresses object from the Vector), so it might impact performance (since this function is probably called for every integration point in a simulation). We don't need to change anything now, since we first want to get it working, but it's something to keep in mind
| ::testing::Values(std::make_tuple(Geo::PrincipalStresses{3.0, 2.0, 1.0}, 1.0), | ||
| std::make_tuple(Geo::PrincipalStresses{1.7071067811865475, 1.0, 0.2928932188134525}, 0.0), | ||
| std::make_tuple(Geo::PrincipalStresses{0.1715728752538099, -1.0, -1.8284271247461901}, -1.0))); |
| auto p_coulomb_yield_surface = | ||
| std::unique_ptr<YieldSurface>{std::make_unique<CoulombYieldSurface>(material_properties)}; | ||
| auto serializer = StreamSerializer{}; | ||
| const auto coulomb_yield_surface = CoulombYieldSurface{material_properties}; |
There was a problem hiding this comment.
I think this test tests a bit less now (we test saving a concrete implementation, instead of saving a pointer to an abstract base with a concrete implementation behind it). I think this could be fine, since saving unique pointers is tested in core (probably?), just wanted to double-check if this was indeed your intention.
There was a problem hiding this comment.
Or does it have to do with the idea to move to something less 'inheritance-based' in the future?
📝 Description
The Coulomb model now accepts principal stresses as well as sigma and tau. This also applies to the tension cut-off.
When these changes are in place, we can start to fix the incorrect return mapping of the tension cut-off as well as include the effect of the elastic constitutive tensor.