Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
18d02d5
set hardening with the recent structure
mnabideltares Nov 6, 2025
193f999
Fixes, and clang format
mnabideltares Nov 6, 2025
a337918
restructured and added unit tests
mnabideltares Nov 11, 2025
7b2fa35
Merge remote-tracking branch 'origin/master' into geo/13826-use-new-s…
mnabideltares Nov 12, 2025
bad8482
Modifications based on review
mnabideltares Nov 16, 2025
31b63a1
Bug is fixed, unit tests are fixed
mnabideltares Nov 17, 2025
9b064e0
Added keywords to material parameters
mnabideltares Nov 17, 2025
4e72305
Made two member functions `const`
avdg81 Nov 19, 2025
35f0ad1
Removed unused `#include`
avdg81 Nov 19, 2025
78e86fc
Made `CalculateCornerPoint` a member of class `CoulombWithTensionCutO…
avdg81 Nov 19, 2025
c15c117
Made `IsStressAtTensionApexReturnZone` a member of class `CoulombWith…
avdg81 Nov 19, 2025
d01e531
Made `IsStressAtTensionCutoffReturnZone` a member of class `CoulombWi…
avdg81 Nov 19, 2025
163654c
Made `IsStressAtCornerReturnZone` a member of class `CoulombWithTensi…
avdg81 Nov 19, 2025
a5bde4b
Made `ReturnStressAtTensionApexReturnZone` a member of class `Coulomb…
avdg81 Nov 19, 2025
3f502fd
Made `ReturnStressAtTensionCutoffReturnZone` a member of class `Coulo…
avdg81 Nov 19, 2025
e5da12e
Made `ReturnStressAtRegularFailureZone` a member of class `CoulombWit…
avdg81 Nov 19, 2025
cbae902
When calculating the equivalent plastic strain, calculate the plastic…
avdg81 Nov 19, 2025
064546b
Got rid of a local variable
avdg81 Nov 19, 2025
58d7c68
Rewrote the calculation of the equivalent plastic strain increment
avdg81 Nov 19, 2025
5345b79
Make a truly linear function when you ask for it
avdg81 Nov 19, 2025
4f973a4
Moved the plastic tolerance and maximum number of iterations from the…
avdg81 Nov 19, 2025
1b2c0fc
Renamed two Geo variables and changed the type of one of them
avdg81 Nov 19, 2025
5439346
Added check for material properties in Coulomb yield surface
mnabideltares Nov 26, 2025
f0ba844
Fixes
mnabideltares Nov 26, 2025
277c5a0
resetting of kappa is applied
mnabideltares Nov 27, 2025
051834a
Some minor suggestions
avdg81 Nov 28, 2025
5c28601
Adopt a different mechanism to restore kappa when needed
avdg81 Nov 28, 2025
9d0845c
Added unittests
mnabideltares Dec 2, 2025
c7a7088
Fixed unittests
mnabideltares Dec 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,131 +15,136 @@

#include "custom_constitutive/coulomb_with_tension_cut_off_impl.h"
#include "custom_utilities/constitutive_law_utilities.h"
#include "custom_utilities/ublas_utilities.h"
#include "geo_mechanics_application_variables.h"
#include "includes/properties.h"
#include "includes/serializer.h"

namespace
namespace Kratos
{

using namespace Kratos;

double CalculateApex(double FrictionAngleInRadians, double Cohesion)
CoulombWithTensionCutOffImpl::CoulombWithTensionCutOffImpl(const Properties& rMaterialProperties)
: mCoulombYieldSurface{rMaterialProperties}, mTensionCutOff{rMaterialProperties[GEO_TENSILE_STRENGTH]}
{
return Cohesion / std::tan(FrictionAngleInRadians);
if (rMaterialProperties.Has(GEO_ABS_YIELD_FUNCTION_TOLERANCE)) {
mAbsoluteYieldFunctionValueTolerance = rMaterialProperties[GEO_ABS_YIELD_FUNCTION_TOLERANCE];
}

if (rMaterialProperties.Has(GEO_MAX_PLASTIC_ITERATIONS)) {
mMaxNumberOfPlasticIterations = rMaterialProperties[GEO_MAX_PLASTIC_ITERATIONS];
}
}

Vector CalculateCornerPoint(double FrictionAngleInRadians, double Cohesion, double TensileStrength)
bool CoulombWithTensionCutOffImpl::IsAdmissibleSigmaTau(const Vector& rTrialSigmaTau) const
{
// Check whether the tension cut-off lies beyond the apex
auto result = Vector{ZeroVector(2)};
result[0] = CalculateApex(FrictionAngleInRadians, Cohesion);
if (TensileStrength > result[0]) return result;

result[0] = (TensileStrength - Cohesion * std::cos(FrictionAngleInRadians)) /
(1.0 - std::sin(FrictionAngleInRadians));
result[1] = (Cohesion * std::cos(FrictionAngleInRadians) - TensileStrength * std::sin(FrictionAngleInRadians)) /
(1.0 - std::sin(FrictionAngleInRadians));
return result;
const auto coulomb_yield_function_value = mCoulombYieldSurface.YieldFunctionValue(rTrialSigmaTau);
const auto tension_yield_function_value = mTensionCutOff.YieldFunctionValue(rTrialSigmaTau);
constexpr auto tolerance = 1.0e-10;
const auto coulomb_tolerance = tolerance * (1.0 + std::abs(coulomb_yield_function_value));
const auto tension_tolerance = tolerance * (1.0 + std::abs(tension_yield_function_value));
return coulomb_yield_function_value < coulomb_tolerance && tension_yield_function_value < tension_tolerance;
}

bool IsStressAtTensionApexReturnZone(const Vector& rTrialSigmaTau, double TensileStrength, double Apex)
Vector CoulombWithTensionCutOffImpl::DoReturnMapping(const Vector& rTrialSigmaTau,
CoulombYieldSurface::CoulombAveragingType AveragingType)
{
return TensileStrength < Apex && rTrialSigmaTau[0] - rTrialSigmaTau[1] - TensileStrength > 0.0;
Vector result = ZeroVector(2);

auto kappa_start = mCoulombYieldSurface.GetKappa();
for (auto counter = std::size_t{0}; counter < mMaxNumberOfPlasticIterations; ++counter) {
if (IsStressAtTensionApexReturnZone(rTrialSigmaTau)) {
return ReturnStressAtTensionApexReturnZone();
}

if (IsStressAtTensionCutoffReturnZone(rTrialSigmaTau)) {
return ReturnStressAtTensionCutoffReturnZone(rTrialSigmaTau);
}

if (IsStressAtCornerReturnZone(rTrialSigmaTau, AveragingType)) {
result = CalculateCornerPoint();
} else { // Regular failure region
result = ReturnStressAtRegularFailureZone(rTrialSigmaTau, AveragingType);
}

const auto kappa = kappa_start + mCoulombYieldSurface.CalculateEquivalentPlasticStrainIncrement(
rTrialSigmaTau, AveragingType);
mCoulombYieldSurface.SetKappa(kappa);

if (std::abs(mCoulombYieldSurface.YieldFunctionValue(result)) < mAbsoluteYieldFunctionValueTolerance) {
break;
}
}
return result;
}

bool IsStressAtTensionCutoffReturnZone(const Vector& rTrialSigmaTau, double TensileStrength, double Apex, const Vector& rCornerPoint)
void CoulombWithTensionCutOffImpl::SaveKappaOfCoulombYieldSurface()
{
return TensileStrength < Apex &&
rCornerPoint[1] - rTrialSigmaTau[1] - rCornerPoint[0] + rTrialSigmaTau[0] > 0.0;
mSavedKappaOfCoulombYieldSurface = mCoulombYieldSurface.GetKappa();
}

bool IsStressAtCornerReturnZone(const Vector& rTrialSigmaTau,
const Vector& rDerivativeOfFlowFunction,
const Vector& rCornerPoint)
void CoulombWithTensionCutOffImpl::RestoreKappaOfCoulombYieldSurface()
{
return (rTrialSigmaTau[0] - rCornerPoint[0]) * rDerivativeOfFlowFunction[1] -
(rTrialSigmaTau[1] - rCornerPoint[1]) * rDerivativeOfFlowFunction[0] >=
0.0;
mCoulombYieldSurface.SetKappa(mSavedKappaOfCoulombYieldSurface);
}

Vector ReturnStressAtTensionApexReturnZone(double TensileStrength)
Vector CoulombWithTensionCutOffImpl::CalculateCornerPoint() const
{
auto result = Vector{ZeroVector{2}};
result[0] = TensileStrength;
return result;
const auto tensile_strength = mTensionCutOff.GetTensileStrength();
if (const auto apex = mCoulombYieldSurface.CalculateApex(); tensile_strength > apex)
return UblasUtilities::CreateVector({apex, 0.0});

const auto cohesion = mCoulombYieldSurface.GetCohesion();
const auto sin_phi = std::sin(mCoulombYieldSurface.GetFrictionAngleInRadians());
const auto cos_phi = std::cos(mCoulombYieldSurface.GetFrictionAngleInRadians());
return UblasUtilities::CreateVector({(tensile_strength - cohesion * cos_phi) / (1.0 - sin_phi),
(cohesion * cos_phi - tensile_strength * sin_phi) / (1.0 - sin_phi)});
}

Vector ReturnStressAtTensionCutoffReturnZone(const Vector& rSigmaTau,
const Vector& rDerivativeOfFlowFunction,
double TensileStrength)
bool CoulombWithTensionCutOffImpl::IsStressAtTensionApexReturnZone(const Vector& rTrialSigmaTau) const
{
const auto lambda = (TensileStrength - rSigmaTau[0] - rSigmaTau[1]) /
(rDerivativeOfFlowFunction[0] + rDerivativeOfFlowFunction[1]);
return rSigmaTau + lambda * rDerivativeOfFlowFunction;
const auto tensile_strength = mTensionCutOff.GetTensileStrength();
return tensile_strength < mCoulombYieldSurface.CalculateApex() &&
rTrialSigmaTau[0] - rTrialSigmaTau[1] - tensile_strength > 0.0;
}

Vector ReturnStressAtRegularFailureZone(const Vector& rSigmaTau,
const Vector& rDerivativeOfFlowFunction,
double FrictionAngleInRadians,
double Cohesion)
bool CoulombWithTensionCutOffImpl::IsStressAtTensionCutoffReturnZone(const Vector& rTrialSigmaTau) const
{
const auto sin_phi = std::sin(FrictionAngleInRadians);
const auto numerator = sin_phi * rDerivativeOfFlowFunction[0] + rDerivativeOfFlowFunction[1];
const auto lambda =
(Cohesion * std::cos(FrictionAngleInRadians) - rSigmaTau[0] * sin_phi - rSigmaTau[1]) / numerator;
return rSigmaTau + lambda * rDerivativeOfFlowFunction;
const auto corner_point = CalculateCornerPoint();
return mTensionCutOff.GetTensileStrength() < mCoulombYieldSurface.CalculateApex() &&
corner_point[1] - rTrialSigmaTau[1] - corner_point[0] + rTrialSigmaTau[0] > 0.0;
}

} // namespace

namespace Kratos
bool CoulombWithTensionCutOffImpl::IsStressAtCornerReturnZone(const Vector& rTrialSigmaTau,
CoulombYieldSurface::CoulombAveragingType AveragingType) const
{
const auto corner_point = CalculateCornerPoint();
const auto derivative_of_flow_function =
mCoulombYieldSurface.DerivativeOfFlowFunction(rTrialSigmaTau, AveragingType);
return (rTrialSigmaTau[0] - corner_point[0]) * derivative_of_flow_function[1] -
(rTrialSigmaTau[1] - corner_point[1]) * derivative_of_flow_function[0] >=
0.0;
}

CoulombWithTensionCutOffImpl::CoulombWithTensionCutOffImpl(const Properties& rMaterialProperties)
: mCoulombYieldSurface{rMaterialProperties}, mTensionCutOff{rMaterialProperties[GEO_TENSILE_STRENGTH]}
Vector CoulombWithTensionCutOffImpl::ReturnStressAtTensionApexReturnZone() const
{
return UblasUtilities::CreateVector({mTensionCutOff.GetTensileStrength(), 0.0});
}

bool CoulombWithTensionCutOffImpl::IsAdmissibleSigmaTau(const Vector& rTrialSigmaTau) const
Vector CoulombWithTensionCutOffImpl::ReturnStressAtTensionCutoffReturnZone(const Vector& rSigmaTau) const
{
const auto coulomb_yield_function_value = mCoulombYieldSurface.YieldFunctionValue(rTrialSigmaTau);
const auto tension_yield_function_value = mTensionCutOff.YieldFunctionValue(rTrialSigmaTau);
constexpr auto tolerance = 1.0e-10;
const auto coulomb_tolerance = tolerance * (1.0 + std::abs(coulomb_yield_function_value));
const auto tension_tolerance = tolerance * (1.0 + std::abs(tension_yield_function_value));
return coulomb_yield_function_value < coulomb_tolerance && tension_yield_function_value < tension_tolerance;
const auto derivative_of_flow_function = mTensionCutOff.DerivativeOfFlowFunction(rSigmaTau);
const auto lambda_tc = (mTensionCutOff.GetTensileStrength() - rSigmaTau[0] - rSigmaTau[1]) /
(derivative_of_flow_function[0] + derivative_of_flow_function[1]);
return rSigmaTau + lambda_tc * derivative_of_flow_function;
}

Vector CoulombWithTensionCutOffImpl::DoReturnMapping(const Vector& rTrialSigmaTau,
CoulombYieldSurface::CoulombAveragingType AveragingType) const
Vector CoulombWithTensionCutOffImpl::ReturnStressAtRegularFailureZone(const Vector& rSigmaTau,
CoulombYieldSurface::CoulombAveragingType AveragingType) const
{
const auto apex = CalculateApex(mCoulombYieldSurface.GetFrictionAngleInRadians(),
mCoulombYieldSurface.GetCohesion());

if (IsStressAtTensionApexReturnZone(rTrialSigmaTau, mTensionCutOff.GetTensileStrength(), apex)) {
return ReturnStressAtTensionApexReturnZone(mTensionCutOff.GetTensileStrength());
}

const auto corner_point =
CalculateCornerPoint(mCoulombYieldSurface.GetFrictionAngleInRadians(),
mCoulombYieldSurface.GetCohesion(), mTensionCutOff.GetTensileStrength());
if (IsStressAtTensionCutoffReturnZone(rTrialSigmaTau, mTensionCutOff.GetTensileStrength(), apex, corner_point)) {
return ReturnStressAtTensionCutoffReturnZone(
rTrialSigmaTau, mTensionCutOff.DerivativeOfFlowFunction(rTrialSigmaTau),
mTensionCutOff.GetTensileStrength());
}

if (IsStressAtCornerReturnZone(
rTrialSigmaTau, mCoulombYieldSurface.DerivativeOfFlowFunction(rTrialSigmaTau, AveragingType),
corner_point)) {
return corner_point;
}

// Regular failure region
return ReturnStressAtRegularFailureZone(
rTrialSigmaTau, mCoulombYieldSurface.DerivativeOfFlowFunction(rTrialSigmaTau, AveragingType),
mCoulombYieldSurface.GetFrictionAngleInRadians(), mCoulombYieldSurface.GetCohesion());
const auto derivative_of_flow_function =
mCoulombYieldSurface.DerivativeOfFlowFunction(rSigmaTau, AveragingType);
const auto lambda = mCoulombYieldSurface.CalculatePlasticMultiplier(rSigmaTau, derivative_of_flow_function);
return rSigmaTau + lambda * derivative_of_flow_function;
}

void CoulombWithTensionCutOffImpl::save(Serializer& rSerializer) const
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,28 @@ class CoulombWithTensionCutOffImpl
explicit CoulombWithTensionCutOffImpl(const Properties& rMaterialProperties);

[[nodiscard]] bool IsAdmissibleSigmaTau(const Vector& rTrialSigmaTau) const;
[[nodiscard]] Vector DoReturnMapping(const Vector& rTrialSigmaTau,
CoulombYieldSurface::CoulombAveragingType AveragingType) const;
[[nodiscard]] Vector DoReturnMapping(const Vector& rTrialSigmaTau,
CoulombYieldSurface::CoulombAveragingType AveragingType);

void SaveKappaOfCoulombYieldSurface();
void RestoreKappaOfCoulombYieldSurface();

private:
CoulombYieldSurface mCoulombYieldSurface;
TensionCutoff mTensionCutOff;
double mSavedKappaOfCoulombYieldSurface{0.0};
double mAbsoluteYieldFunctionValueTolerance{1.0e-8};
std::size_t mMaxNumberOfPlasticIterations{100};

[[nodiscard]] Vector CalculateCornerPoint() const;
[[nodiscard]] bool IsStressAtTensionApexReturnZone(const Vector& rTrialSigmaTau) const;
[[nodiscard]] bool IsStressAtTensionCutoffReturnZone(const Vector& rTrialSigmaTau) const;
[[nodiscard]] bool IsStressAtCornerReturnZone(const Vector& rTrialSigmaTau,
CoulombYieldSurface::CoulombAveragingType AveragingType) const;
[[nodiscard]] Vector ReturnStressAtTensionApexReturnZone() const;
[[nodiscard]] Vector ReturnStressAtTensionCutoffReturnZone(const Vector& rSigmaTau) const;
[[nodiscard]] Vector ReturnStressAtRegularFailureZone(const Vector& rSigmaTau,
CoulombYieldSurface::CoulombAveragingType AveragingType) const;

friend class Serializer;
void save(Serializer& rSerializer) const;
Expand Down
Loading
Loading