diff --git a/src/MGroup.Constitutive.Structural/Continuum/VonMisesMaterial3D.cs b/src/MGroup.Constitutive.Structural/Continuum/VonMisesMaterial3D.cs
index 0ad5be4..6a4006d 100644
--- a/src/MGroup.Constitutive.Structural/Continuum/VonMisesMaterial3D.cs
+++ b/src/MGroup.Constitutive.Structural/Continuum/VonMisesMaterial3D.cs
@@ -20,7 +20,12 @@ namespace MGroup.Constitutive.Structural.Continuum
/// Wikipedia -Von Mises yield criterion
public class VonMisesMaterial3D : IIsotropicContinuumMaterial3D
{
- private const string PLASTIC_STRAIN = "Plastic strain";
+ ///
+ /// Identity second order tensor written in vector form.
+ ///
+ private static readonly double[] IdentityVector = new[] { 1.0, 1.0, 1.0, 0, 0, 0 };
+ private const string EQUIVALENT_PLASTIC_STRAIN = "Equivalent plastic strain";
+ private const string YIELD_STRESS = "Yield stress";
private const string STRESS_X = "Stress X";
private const string STRESS_Y = "Stress Y";
private const string STRESS_Z = "Stress Z";
@@ -45,18 +50,31 @@ public class VonMisesMaterial3D : IIsotropicContinuumMaterial3D
private const int TotalStresses = TotalStrains;
///
- /// An array needed for the formulation of the consistent constitutive matrix.
+ /// Array for projecting a tensor on its deviatoric part.
///
- private static readonly double[,] SupportiveMatrixForConsistentConstitutiveMatrix = new[,]
+ private static readonly double[,] DeviatoricProjection = new[,]
{
- { 0, -1, -1, 0, 0, 0 },
- { -1, 0, -1, 0, 0, 0 },
- { -1, -1, 0, 0, 0, 0 },
- { 0, 0, 0, 0.5, 0, 0 },
- { 0, 0, 0, 0, 0.5, 0 },
- { 0, 0, 0, 0, 0, 0.5 }
+ { 2.0/3.0, -1.0/3.0, -1.0/3.0, 0, 0, 0 },
+ { -1.0/3.0, 2.0/3.0, -1.0/3.0, 0, 0, 0 },
+ { -1.0/3.0, -1.0/3.0, 2.0/3.0, 0, 0, 0 },
+ { 0, 0, 0, 1.0, 0, 0 },
+ { 0, 0, 0, 0, 1.0, 0 },
+ { 0, 0, 0, 0, 0, 1.0 }
};
+ ///
+ /// Array for projecting a tensor on its volumetric part.
+ ///
+ private static readonly double[,] VolumetricProjection = new[,]
+ {
+ { 1.0, 1.0, 1.0, 0, 0, 0 },
+ { 1.0, 1.0, 1.0, 0, 0, 0 },
+ { 1.0, 1.0, 1.0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0}
+ };
+
///
/// The constitutive matrix of the material while still in the elastic region.
///
@@ -84,13 +102,30 @@ public class VonMisesMaterial3D : IIsotropicContinuumMaterial3D
private readonly double shearModulus;
///
- /// The yields stress.
+ /// The bulk modulus.
+ ///
+ ///
+ /// Wikipedia - Bulk Modulus
+ ///
+ private readonly double bulkModulus;
+
+ ///
+ /// The initial yield stress.
///
///
/// Yield (engineering)
/// The yield strength or yield point of a material is defined in engineering and materials science as the stress at which a material begins to deform plastically.
///
- private readonly double yieldStress;
+ private readonly double initialYieldStress;
+
+ ///
+ /// The current yield stress.
+ ///
+ ///
+ /// Yield (engineering)
+ /// The yield strength or yield point of a material is defined in engineering and materials science as the stress at which a material begins to deform plastically.
+ ///
+ private double yieldStress;
///
/// The young modulus.
@@ -119,25 +154,52 @@ public class VonMisesMaterial3D : IIsotropicContinuumMaterial3D
private bool modified;
///
- /// The current plastic strain.
+ /// The current strain vector.
+ ///
+ private double[] strains = new double[6];
+
+ ///
+ /// The previously converged elastic strain vector.
+ ///
+ private double[] strainsElasticPrev;
+
+ ///
+ /// The current elastic strain vector.
+ ///
+ private double[] strainsElastic = new double[6];
+
+ ///
+ /// The previously converged plastic strain vector.
///
- private double plasticStrain;
+ private double[] strainsPlasticPrev;
///
- /// The new plastic strain.
+ /// The current plastic strain vector.
///
- private double plasticStrainNew;
+ private double[] strainsPlastic = new double[6];
///
- /// The array of stresses.
+ /// The previously converged equivalent/accumulated plastic strain vector.
+ ///
+ private double strainsEquivalentPrev;
+
+ ///
+ /// The current equivalent/accumulated plastic strain vector.
+ ///
+ private double strainsEquivalent;
+
+ ///
+ /// The current increment stress vector.
///
private double[] stresses = new double[6];
///
- /// The array of new stresses.
+ /// The current iteration stress vector.
///
private double[] stressesNew = new double[6];
+ private bool matrices_not_initialized = true;
+
///
/// Initializes a new instance of the class.
///
@@ -165,38 +227,25 @@ public VonMisesMaterial3D(double youngModulus, double poissonRatio, double yield
}
this.poissonRatio = poissonRatio;
- this.yieldStress = yieldStress;
+ this.initialYieldStress = yieldStress;
this.hardeningRatio = hardeningRatio;
this.shearModulus = this.YoungModulus / (2 * (1 + this.PoissonRatio));
+ this.bulkModulus = this.YoungModulus / (3 * (1 - 2 * this.PoissonRatio));
double lamda = (youngModulus * poissonRatio) / ((1 + poissonRatio) * (1 - (2 * poissonRatio)));
double mi = youngModulus / (2 * (1 + poissonRatio));
double value1 = (2 * mi) + lamda;
- this.elasticConstitutiveMatrix = Matrix.CreateZero(6, 6);
- this.elasticConstitutiveMatrix[0, 0] = value1;
- this.elasticConstitutiveMatrix[0, 1] = lamda;
- this.elasticConstitutiveMatrix[0, 2] = lamda;
- this.elasticConstitutiveMatrix[1, 0] = lamda;
- this.elasticConstitutiveMatrix[1, 1] = value1;
- this.elasticConstitutiveMatrix[1, 2] = lamda;
- this.elasticConstitutiveMatrix[2, 0] = lamda;
- this.elasticConstitutiveMatrix[2, 1] = lamda;
- this.elasticConstitutiveMatrix[2, 2] = value1;
- this.elasticConstitutiveMatrix[3, 3] = mi;
- this.elasticConstitutiveMatrix[4, 4] = mi;
- this.elasticConstitutiveMatrix[5, 5] = mi;
+ elasticConstitutiveMatrix = GetConstitutiveMatrix();
+ InitializeMatrices();
+ }
- currentState = new GenericConstitutiveLawState(this, new[]
- {
- (PLASTIC_STRAIN, 0d),
- (STRESS_X, 0d),
- (STRESS_Y, 0d),
- (STRESS_Z, 0d),
- (STRESS_XY, 0d),
- (STRESS_XZ, 0d),
- (STRESS_YZ, 0d),
- });
+ public void InitializeMatrices()
+ {
+ strainsElasticPrev = new double[6];
+ strainsPlasticPrev = new double[6];
+ strainsEquivalentPrev = 0;
+ matrices_not_initialized = false;
}
public double[] Coordinates { get; set; }
@@ -211,12 +260,7 @@ public IMatrixView ConstitutiveMatrix
{
get
{
- if (this.constitutiveMatrix == null)
- {
- UpdateConstitutiveMatrixAndEvaluateResponse(new double[6]);
- this.constitutiveMatrix.MatrixSymmetry = LinearAlgebra.Providers.MatrixSymmetry.Symmetric;
- }
-
+ if (this.constitutiveMatrix == null) UpdateConstitutiveMatrixAndEvaluateResponse(new double[6]);
return constitutiveMatrix;
}
}
@@ -241,7 +285,7 @@ public IMatrixView ConstitutiveMatrix
public double[] IncrementalStrains => this.incrementalStrains;
///
- /// Gets a value indicating whether this is modified.
+ /// Gets a value indicating whether this is modified.
///
///
/// true if modified; otherwise, false.
@@ -252,9 +296,9 @@ public IMatrixView ConstitutiveMatrix
/// Gets the plastic strain.
///
///
- /// The plastic strain.
+ /// The plastic strain vector.
///
- public double PlasticStrain => this.plasticStrain;
+ public double[] StrainsPlastic => this.strainsPlastic;
///
/// Gets the Poisson ratio.
@@ -311,20 +355,16 @@ public double YoungModulus
///
public object Clone()
{
- return new VonMisesMaterial3D(this.youngModulus, this.poissonRatio, this.yieldStress, this.hardeningRatio)
+ return new VonMisesMaterial3D(this.youngModulus, this.poissonRatio, this.initialYieldStress, this.hardeningRatio)
{
modified = this.IsCurrentStateDifferent(),
- plasticStrain = this.plasticStrain,
+ strainsEquivalent = this.strainsEquivalent,
+ strainsEquivalentPrev = this.strainsEquivalentPrev,
incrementalStrains = incrementalStrains.Copy(),
stresses = stresses.Copy()
};
}
- ///
- /// Resets the indicator of whether the material is modified.
- ///
- public void ResetModified() => this.modified = false;
-
///
/// Clears the stresses of the element's material.
///
@@ -337,24 +377,33 @@ public void ClearStresses()
public void ClearState()
{
modified = false;
- constitutiveMatrix.Clear();
incrementalStrains.Clear();
stresses.Clear();
stressesNew.Clear();
- plasticStrain = 0;
- plasticStrainNew = 0;
+ strains.Clear();
+ incrementalStrains.Clear();
+ strainsElasticPrev.Clear();
+ strainsElastic.Clear();
+ strainsPlasticPrev.Clear();
+ strainsPlastic.Clear();
+ strainsEquivalent = 0;
+ strainsEquivalentPrev = 0;
+ constitutiveMatrix = GetConstitutiveMatrix();
}
///
- /// Saves the state of the element's material.
+ /// Saves the state of the element's material.
///
public GenericConstitutiveLawState CreateState()
{
- this.plasticStrain = this.plasticStrainNew;
stresses.CopyFrom(stressesNew);
+ strainsElasticPrev.CopyFrom(strainsElastic);
+ strainsPlasticPrev.CopyFrom(strainsPlastic);
+ strainsEquivalentPrev = strainsEquivalent;
currentState = new GenericConstitutiveLawState(this, new[]
{
- (PLASTIC_STRAIN, plasticStrain),
+ (EQUIVALENT_PLASTIC_STRAIN, strainsEquivalent),
+ (YIELD_STRESS, yieldStress),
(STRESS_X, stresses[0]),
(STRESS_Y, stresses[1]),
(STRESS_Z, stresses[2]),
@@ -372,7 +421,8 @@ public GenericConstitutiveLawState CurrentState
set
{
currentState = value;
- plasticStrain = currentState.StateValues[PLASTIC_STRAIN];
+ strainsEquivalent = currentState.StateValues[EQUIVALENT_PLASTIC_STRAIN];
+ yieldStress = currentState.StateValues[YIELD_STRESS];
stresses[0] = currentState.StateValues[STRESS_X];
stresses[1] = currentState.StateValues[STRESS_Y];
stresses[2] = currentState.StateValues[STRESS_Z];
@@ -382,15 +432,35 @@ public GenericConstitutiveLawState CurrentState
}
}
+ ///
+ /// Resets the indicator of whether the material is modified.
+ ///
+ public void ResetModified() => this.modified = false;
+
+
///
/// Updates the element's material with the provided incremental strains.
///
/// The incremental strains to use for the next step.
public double[] UpdateConstitutiveMatrixAndEvaluateResponse(double[] strainsIncrement)
{
+ if (matrices_not_initialized)
+ { this.InitializeMatrices(); }
incrementalStrains.CopyFrom(strainsIncrement);
this.CalculateNextStressStrainPoint();
+ currentState = new GenericConstitutiveLawState(this, new[]
+{
+ (EQUIVALENT_PLASTIC_STRAIN, strainsEquivalent),
+ (YIELD_STRESS, yieldStress),
+ (STRESS_X, stresses[0]),
+ (STRESS_Y, stresses[1]),
+ (STRESS_Z, stresses[2]),
+ (STRESS_XY, stresses[3]),
+ (STRESS_XZ, stresses[4]),
+ (STRESS_YZ, stresses[5]),
+ });
+
return stressesNew;
}
@@ -399,32 +469,45 @@ public double[] UpdateConstitutiveMatrixAndEvaluateResponse(double[] strainsIncr
///
/// This is a constant already calculated in the calling method.
///
- /// We need an additional constant here equal to: 2*G*G*deltaPlasticStrain*sqrt(3/J2elastic)
- /// Since value1 is already calculated, the additional constant can be calculated through it:
- /// value3 = 2 * G * value1;
+ /// Refer to chapter 7.6.6 page 262 in Souza Neto.
///
- private void BuildConsistentTangentialConstitutiveMatrix(double value1)
+ private Matrix BuildConsistentTangentialConstitutiveMatrix(double vonMisesStress, double[] unityvector)
{
- this.constitutiveMatrix = Matrix.CreateZero(TotalStresses, TotalStrains);
- this.constitutiveMatrix.MatrixSymmetry = LinearAlgebra.Providers.MatrixSymmetry.Symmetric;
- double invariantJ2New = this.GetDeviatorSecondStressInvariant(stressesNew);
-
- double value2 = (3 * this.shearModulus * this.shearModulus) /
- ((this.hardeningRatio + (3 * this.shearModulus)) * invariantJ2New);
-
- double value3 = 2 * this.shearModulus * value1;
- double value4 = 0.5 / invariantJ2New;
+ Matrix consistenttangent = Matrix.CreateZero(TotalStresses, TotalStrains);
+ double dgamma = this.strainsEquivalent - this.strainsEquivalentPrev;
+ double v1 = -dgamma * 6 * Math.Pow(this.shearModulus, 2) / vonMisesStress;
+ double Hk = 0;
+ double Hi = this.hardeningRatio;
+ double v2 = (dgamma / vonMisesStress - 1 / (3 * this.shearModulus + Hk + Hi)) * 6 * Math.Pow(this.shearModulus, 2);
+ for (int i = 0; i < 6; i++)
+ {
+ for (int j = 0; j < 6; j++)
+ {
+ consistenttangent[i, j] = this.elasticConstitutiveMatrix[i, j] + v1 * DeviatoricProjection[i, j] + v2 * unityvector[i] * unityvector[j];
+ }
+ }
+ return consistenttangent;
+ }
- var stressDeviator = this.GetStressDeviator(stressesNew);
- for (int k1 = 0; k1 < TotalStresses; k1++)
+ ///
+ /// Builds the consistent tangential constitutive matrix.
+ ///
+ ///
+ /// Refer to chapter 7.6.6 page 262 in Souza Neto.
+ ///
+ private void BuildConsistentTangentialConstitutiveMatrix(double[] strainDeviatoricTrial, double normStrainDeviatoricTrial, double deltastrainsEquivalent, double vonMisesStress)
+ {
+ var N = new double[incrementalStrains.Length];
+ for (int i = 0; i < incrementalStrains.Length; i++)
{
- for (int k2 = 0; k2 < TotalStresses; k2++)
+ N[i] = strainDeviatoricTrial[i] / normStrainDeviatoricTrial;
+ }
+ for (int i = 0; i < incrementalStrains.Length; i++)
+ {
+ for (int j = 0; j < incrementalStrains.Length; j++)
{
- this.constitutiveMatrix[k2, k1] = this.elasticConstitutiveMatrix[k2, k1] -
- (value2 * stressDeviator[k2] * stressDeviator[k1]) -
- (value3 *
- (SupportiveMatrixForConsistentConstitutiveMatrix[k2, k1] -
- (value4 * stressDeviator[k2] * stressDeviator[k1])));
+ constitutiveMatrix[i, j] = 2 * shearModulus * (1 - (3 * shearModulus * deltastrainsEquivalent) / vonMisesStress) * DeviatoricProjection[i, j] +
+ 6 * shearModulus * shearModulus * (deltastrainsEquivalent / vonMisesStress - 1 / (3 * shearModulus + hardeningRatio)) * (N[i] * N[j]) + bulkModulus * VolumetricProjection[i, j];
}
}
}
@@ -457,49 +540,87 @@ private void BuildTangentialConstitutiveMatrix()
/// When the new plastic strain is less than the previous one.
private void CalculateNextStressStrainPoint()
{
- var stressesElastic = new double[6];
- for (int i = 0; i < 6; i++)
+ //calculate trial variables
+ var strainTrial = new double[incrementalStrains.Length];
+ var stressTrial = new double[incrementalStrains.Length];
+ var strainDeviatoricTrial = new double[incrementalStrains.Length];
+ var stressVolumetricTrial = new double[incrementalStrains.Length];
+ var stressDeviatoricTrial = new double[incrementalStrains.Length];
+ var normStrainDeviatoricTrial = new double();
+ for (int i = 0; i < incrementalStrains.Length; i++)
+ strainTrial[i] = strainsElasticPrev[i] + incrementalStrains[i];
+ for (int i = 0; i < incrementalStrains.Length; i++)
{
- stressesElastic[i] = this.stresses[i];
- for (int j = 0; j < 6; j++)
- stressesElastic[i] += this.elasticConstitutiveMatrix[i, j] * this.incrementalStrains[j];
+ for (int j = 0; j < incrementalStrains.Length; j++)
+ {
+ strainDeviatoricTrial[i] = strainDeviatoricTrial[i] + DeviatoricProjection[i, j] * strainTrial[j];
+ if (i >= 0 && i <= 2)
+ stressTrial[i] += (2 * shearModulus * DeviatoricProjection[i, j] * strainTrial[j] + bulkModulus * VolumetricProjection[i, j] * strainTrial[j]);
+ else
+ stressTrial[i] += 0.5 * (2 * shearModulus * DeviatoricProjection[i, j] * strainTrial[j] + bulkModulus * VolumetricProjection[i, j] * strainTrial[j]);
+ }
}
-
- double invariantJ2Elastic = this.GetDeviatorSecondStressInvariant(stressesElastic);
- double vonMisesStress = Math.Sqrt(3 * invariantJ2Elastic);
+ for (int i = 0; i < incrementalStrains.Length; i++)
+ {
+ for (int j = 0; j < incrementalStrains.Length; j++)
+ {
+ stressVolumetricTrial[i] += (double)1 / 3 * VolumetricProjection[i, j] * stressTrial[j];
+ stressDeviatoricTrial[i] += DeviatoricProjection[i, j] * stressTrial[j];
+ }
+ normStrainDeviatoricTrial += strainDeviatoricTrial[i] * strainDeviatoricTrial[i];
+ }
+ normStrainDeviatoricTrial = Math.Sqrt(normStrainDeviatoricTrial);
+ var J2 = GetDeviatorSecondStressInvariant(stressTrial);
+ double vonMisesStress = Math.Sqrt(3 * J2);
double vonMisesStressMinusYieldStress = vonMisesStress -
- (this.yieldStress + (this.hardeningRatio * this.plasticStrain));
+ (this.initialYieldStress + (this.hardeningRatio * this.strainsEquivalentPrev));
+ yieldStress = this.initialYieldStress + (this.hardeningRatio * this.strainsEquivalentPrev);
bool materialIsInElasticRegion = vonMisesStressMinusYieldStress <= 0;
+ var stressVolumetric = new double[incrementalStrains.Length];
+ var stressDeviatoric = new double[incrementalStrains.Length];
if (materialIsInElasticRegion)
{
- this.stressesNew = stressesElastic;
- this.constitutiveMatrix = this.elasticConstitutiveMatrix;
- this.plasticStrainNew = this.plasticStrain;
+ stressesNew.CopyFrom(stressTrial);
+ stressVolumetric.CopyFrom(stressVolumetricTrial);
+ stressDeviatoric.CopyFrom(stressDeviatoricTrial);
+ strainsEquivalent = strainsEquivalentPrev;
+ constitutiveMatrix = elasticConstitutiveMatrix.CopyToFullMatrix();
}
else
{
- double deltaPlasticStrain = vonMisesStressMinusYieldStress /
+ double deltastrainsEquivalent = vonMisesStressMinusYieldStress /
((3 * this.shearModulus) + this.hardeningRatio);
- this.plasticStrainNew = this.plasticStrain + deltaPlasticStrain;
+ this.strainsEquivalent = this.strainsEquivalentPrev + deltastrainsEquivalent;
- // 2.0 and 1/2 cancel out
- double value1 = this.shearModulus * deltaPlasticStrain * Math.Sqrt(3 / invariantJ2Elastic);
- var stressDeviatorElastic = this.GetStressDeviator(stressesElastic);
- for (int i = 0; i < 6; i++)
- this.stressesNew[i] = stressesElastic[i] - (value1 * stressDeviatorElastic[i]);
-
- //this.BuildConsistentTangentialConstitutiveMatrix(value1);
- this.BuildTangentialConstitutiveMatrix();
+ for (int i = 0; i < incrementalStrains.Length; i++)
+ {
+ stressVolumetric[i] = stressVolumetricTrial[i];
+ stressDeviatoric[i] = (1 - (3 * shearModulus * deltastrainsEquivalent) / vonMisesStress) * stressDeviatoricTrial[i];
+ stressesNew[i] = stressVolumetric[i] + stressDeviatoric[i];
+ }
+ BuildConsistentTangentialConstitutiveMatrix(strainDeviatoricTrial, normStrainDeviatoricTrial, deltastrainsEquivalent, vonMisesStress);
+ //this.BuildTangentialConstitutiveMatrix();
}
- if (Math.Abs(this.plasticStrainNew) < Math.Abs(this.plasticStrain))
+ if (Math.Abs(this.strainsEquivalent) < Math.Abs(this.strainsEquivalentPrev))
{
throw new InvalidOperationException("Plastic strain cannot decrease.");
}
- this.modified = this.plasticStrainNew != this.plasticStrain;
+ this.modified = this.strainsEquivalent != this.strainsEquivalentPrev;
+
+ for (int i = 0; i < incrementalStrains.Length; i++)
+ {
+ if (i >= 0 && i <= 2)
+ strainsElastic[i] = 1 / (2 * shearModulus) * stressDeviatoric[i] + 1 / (3 * bulkModulus) * stressVolumetric[i];
+ else
+ strainsElastic[i] = 2 * (1 / (2 * shearModulus) * stressDeviatoric[i] + 1 / (3 * bulkModulus) * stressVolumetric[i]);
+ if (vonMisesStress > 0)
+ strainsPlastic[i] = strainsPlasticPrev[i] + strainTrial[i] - strainsElastic[i];
+ strains[i] = strainsElastic[i] + strainsPlastic[i];
+ }
}
///
@@ -518,8 +639,8 @@ private void CalculateNextStressStrainPoint()
/// Calculates and returns the second stress invariant (I2).
///
/// The second stress invariant (I2).
- public double GetSecondStressInvariant(double[] stresses)
- => (stresses[0] * stresses[1]) + (stresses[1] * stresses[2]) + (stresses[0] * stresses[2])
+ public double GetSecondStressInvariant(double[] stresses)
+ => (stresses[0] * stresses[1]) + (stresses[1] * stresses[2]) + (stresses[0] * stresses[2])
- Math.Pow(stresses[5], 2) - Math.Pow(stresses[3], 2) - Math.Pow(stresses[4], 2);
///
@@ -546,9 +667,9 @@ public double[] GetStressDeviator(double[] stresses)
/// Calculates and returns the third stress invariant (I3).
///
/// The third stress invariant (I3).
- public double GetThirdStressInvariant(double[] stresses)
- => (stresses[0] * stresses[1] * stresses[2]) + (2 * stresses[5] * stresses[3] * stresses[4])
- - (Math.Pow(stresses[5], 2) * stresses[2]) -(Math.Pow(stresses[3], 2) * stresses[0])
+ public double GetThirdStressInvariant(double[] stresses)
+ => (stresses[0] * stresses[1] * stresses[2]) + (2 * stresses[5] * stresses[3] * stresses[4])
+ - (Math.Pow(stresses[5], 2) * stresses[2]) - (Math.Pow(stresses[3], 2) * stresses[0])
- (Math.Pow(stresses[4], 2) * stresses[1]);
///
@@ -584,5 +705,28 @@ public double GetDeviatorThirdStressInvariant(double[] stresses)
return j3;
}
+ private Matrix GetConstitutiveMatrix()
+ {
+ double fE1 = YoungModulus / (double)(1 + PoissonRatio);
+ double fE2 = fE1 * PoissonRatio / (double)(1 - 2 * PoissonRatio);
+ double fE3 = fE1 + fE2;
+ double fE4 = fE1 * 0.5;
+ var afE = Matrix.CreateZero(6, 6);
+ afE[0, 0] = fE3;
+ afE[0, 1] = fE2;
+ afE[0, 2] = fE2;
+ afE[1, 0] = fE2;
+ afE[1, 1] = fE3;
+ afE[1, 2] = fE2;
+ afE[2, 0] = fE2;
+ afE[2, 1] = fE2;
+ afE[2, 2] = fE3;
+ afE[3, 3] = fE4;
+ afE[4, 4] = fE4;
+ afE[5, 5] = fE4;
+
+ return afE;
+ }
+
}
}
diff --git a/src/MGroup.Constitutive.Structural/Continuum/VonMisesMaterial3DFunctionalHardening.cs b/src/MGroup.Constitutive.Structural/Continuum/VonMisesMaterial3DFunctionalHardening.cs
new file mode 100644
index 0000000..15e7f9c
--- /dev/null
+++ b/src/MGroup.Constitutive.Structural/Continuum/VonMisesMaterial3DFunctionalHardening.cs
@@ -0,0 +1,733 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// To be decided
+//
+//
+// Class for 3D Von Mises materials.
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+using System;
+using MGroup.LinearAlgebra.Matrices;
+using MGroup.MSolve.Constitutive;
+using MGroup.MSolve.DataStructures;
+
+namespace MGroup.Constitutive.Structural.Continuum
+{
+ ///
+ /// Class for 3D Von Mises materials.
+ ///
+ /// Wikipedia -Von Mises yield criterion
+ public class VonMisesMaterial3DFunctionalHardening : IIsotropicContinuumMaterial3D
+ {
+ ///
+ /// Identity second order tensor written in vector form.
+ ///
+ private static readonly double[] IdentityVector = new[] { 1.0, 1.0, 1.0, 0, 0, 0 };
+ private const string EQUIVALENT_PLASTIC_STRAIN = "Equivalent plastic strain";
+ private const string STRESS_X = "Stress X";
+ private const string STRESS_Y = "Stress Y";
+ private const string STRESS_Z = "Stress Z";
+ private const string STRESS_XY = "Stress XY";
+ private const string STRESS_XZ = "Stress XZ";
+ private const string STRESS_YZ = "Stress YZ";
+ private GenericConstitutiveLawState currentState;
+
+ ///
+ /// The Poisson ratio value of an incompressible solid.
+ ///
+ private const double PoissonRatioForIncompressibleSolid = 0.5;
+
+ ///
+ /// The total number of strains.
+ ///
+ private const int TotalStrains = 6;
+
+ ///
+ /// The total number of stresses.
+ ///
+ private const int TotalStresses = TotalStrains;
+
+ ///
+ /// Array for projecting a tensor on its deviatoric part.
+ ///
+ private static readonly double[,] DeviatoricProjection = new[,]
+ {
+ { 2.0/3.0, -1.0/3.0, -1.0/3.0, 0, 0, 0 },
+ { -1.0/3.0, 2.0/3.0, -1.0/3.0, 0, 0, 0 },
+ { -1.0/3.0, -1.0/3.0, 2.0/3.0, 0, 0, 0 },
+ { 0, 0, 0, 1.0, 0, 0 },
+ { 0, 0, 0, 0, 1.0, 0 },
+ { 0, 0, 0, 0, 0, 1.0 }
+ };
+
+ ///
+ /// Array for projecting a tensor on its volumetric part.
+ ///
+ private static readonly double[,] VolumetricProjection = new[,]
+ {
+ { 1.0, 1.0, 1.0, 0, 0, 0 },
+ { 1.0, 1.0, 1.0, 0, 0, 0 },
+ { 1.0, 1.0, 1.0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0}
+ };
+
+ ///
+ /// The constitutive matrix of the material while still in the elastic region.
+ ///
+ private readonly Matrix elasticConstitutiveMatrix;
+
+ ///
+ /// Hardening modulus for linear hardening.
+ ///
+ private readonly Func hardeningFunc;
+
+ private double hardeningGrad;
+
+ ///
+ /// Hardening modulus for linear hardening.
+ ///
+ private double hardeningModulus;
+
+ ///
+ /// The Poisson ratio.
+ ///
+ ///
+ /// Wikipedia - Poisson's Ratio
+ ///
+ private double poissonRatio;
+
+ ///
+ /// The shear modulus.
+ ///
+ ///
+ /// Wikipedia - Shear Modulus
+ ///
+ private readonly double shearModulus;
+
+ ///
+ /// The bulk modulus.
+ ///
+ ///
+ /// Wikipedia - Bulk Modulus
+ ///
+ private readonly double bulkModulus;
+
+ ///
+ /// The yields stress.
+ ///
+ ///
+ /// Yield (engineering)
+ /// The yield strength or yield point of a material is defined in engineering and materials science as the stress at which a material begins to deform plastically.
+ ///
+ private readonly double yieldStress;
+
+ ///
+ /// The young modulus.
+ ///
+ ///
+ /// Wikipedia - Young's Modulus
+ ///
+ private double youngModulus;
+
+ ///
+ /// The constitutive matrix of the material.
+ ///
+ private Matrix constitutiveMatrix;
+
+ ///
+ /// The array of incremental strains.
+ ///
+ ///
+ /// Deformation (engineering)
+ ///
+ private double[] incrementalStrains = new double[6];
+
+ ///
+ /// Indicates whether this is modified.
+ ///
+ private bool modified;
+
+ ///
+ /// The current strain vector.
+ ///
+ private double[] strains = new double[6];
+
+ ///
+ /// The previously converged elastic strain vector.
+ ///
+ private double[] strainsElasticPrev;
+
+ ///
+ /// The current elastic strain vector.
+ ///
+ private double[] strainsElastic = new double[6];
+
+ ///
+ /// The previously converged plastic strain vector.
+ ///
+ private double[] strainsPlasticPrev;
+
+ ///
+ /// The current plastic strain vector.
+ ///
+ private double[] strainsPlastic = new double[6];
+
+ ///
+ /// The previously converged equivalent/accumulated plastic strain vector.
+ ///
+ private double strainsEquivalentPrev;
+
+ ///
+ /// The current equivalent/accumulated plastic strain vector.
+ ///
+ private double strainsEquivalent;
+
+ ///
+ /// The current increment stress vector.
+ ///
+ private double[] stresses = new double[6];
+
+ ///
+ /// The current iteration stress vector.
+ ///
+ private double[] stressesNew = new double[6];
+
+ private bool matrices_not_initialized = true;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The young modulus.
+ ///
+ ///
+ /// The Poisson ratio.
+ ///
+ ///
+ /// The yield stress.
+ ///
+ ///
+ /// The hardening function.
+ ///
+ /// When Poisson ratio is equal to 0.5.
+ public VonMisesMaterial3DFunctionalHardening(double youngModulus, double poissonRatio, double yieldStress, Func hardeningFunc)
+ {
+ this.youngModulus = youngModulus;
+
+ if (poissonRatio == PoissonRatioForIncompressibleSolid)
+ {
+ throw new ArgumentException(
+ "Poisson ratio cannot be" + PoissonRatioForIncompressibleSolid + "(incompressible solid)");
+ }
+
+ this.poissonRatio = poissonRatio;
+ this.yieldStress = yieldStress;
+ this.hardeningFunc = hardeningFunc;
+
+ this.shearModulus = this.YoungModulus / (2 * (1 + this.PoissonRatio));
+ this.bulkModulus = this.YoungModulus / (3 * (1 - 2 * this.PoissonRatio));
+ double lamda = (youngModulus * poissonRatio) / ((1 + poissonRatio) * (1 - (2 * poissonRatio)));
+ double mi = youngModulus / (2 * (1 + poissonRatio));
+ double value1 = (2 * mi) + lamda;
+
+ elasticConstitutiveMatrix = GetConstitutiveMatrix();
+ InitializeMatrices();
+ }
+
+ public void InitializeMatrices()
+ {
+ strainsElasticPrev = new double[6];
+ strainsPlasticPrev = new double[6];
+ strainsEquivalentPrev = 0;
+ matrices_not_initialized = false;
+ }
+
+ public double[] Coordinates { get; set; }
+
+ ///
+ /// Gets the constitutive matrix.
+ ///
+ ///
+ /// The constitutive matrix.
+ ///
+ public IMatrixView ConstitutiveMatrix
+ {
+ get
+ {
+ if (this.constitutiveMatrix == null) UpdateConstitutiveMatrixAndEvaluateResponse(new double[6]);
+ return constitutiveMatrix;
+ }
+ }
+
+ ///
+ /// Gets the ID of the material.
+ ///
+ ///
+ /// The id.
+ ///
+ public int ID => 1;
+
+ ///
+ /// Gets the incremental strains of the finite element's material.
+ ///
+ ///
+ /// The incremental strains.
+ ///
+ ///
+ /// Deformation (engineering)
+ ///
+ public double[] IncrementalStrains => this.incrementalStrains;
+
+ ///
+ /// Gets a value indicating whether this is modified.
+ ///
+ ///
+ /// true if modified; otherwise, false.
+ ///
+ public bool IsCurrentStateDifferent() => modified;
+
+ ///
+ /// Gets the plastic strain.
+ ///
+ ///
+ /// The plastic strain vector.
+ ///
+ public double[] StrainsPlastic => this.strainsPlastic;
+
+ ///
+ /// Gets the Poisson ratio.
+ ///
+ ///
+ /// The Poisson ratio.
+ ///
+ ///
+ /// Wikipedia - Poisson's Ratio
+ ///
+ public double PoissonRatio
+ {
+ get
+ {
+ return this.poissonRatio;
+ }
+ set
+ {
+ this.poissonRatio = value;
+ }
+ }
+
+ ///
+ /// Gets the stresses of the finite element's material.
+ ///
+ ///
+ /// The stresses.
+ ///
+ ///
+ /// Stress (mechanics)
+ ///
+ public double[] Stresses => this.stressesNew;
+
+ ///
+ /// Gets the Young's Modulus.
+ ///
+ ///
+ /// The young modulus.
+ ///
+ ///
+ /// Wikipedia - Young's Modulus
+ ///
+ public double YoungModulus
+ {
+ get => this.youngModulus;
+ set => this.youngModulus = value;
+ }
+
+ ///
+ /// Creates a new object that is a copy of the current instance.
+ ///
+ ///
+ /// A new object that is a copy of this instance.
+ ///
+ public object Clone()
+ {
+ return new VonMisesMaterial3DFunctionalHardening(this.youngModulus, this.poissonRatio, this.yieldStress, this.hardeningFunc)
+ {
+ modified = this.IsCurrentStateDifferent(),
+ strainsEquivalent = this.strainsEquivalent,
+ strainsEquivalentPrev = this.strainsEquivalentPrev,
+ incrementalStrains = incrementalStrains.Copy(),
+ stresses = stresses.Copy()
+ };
+ }
+
+ ///
+ /// Clears the stresses of the element's material.
+ ///
+ public void ClearStresses()
+ {
+ stresses.Clear();
+ stressesNew.Clear();
+ }
+
+ public void ClearState()
+ {
+ modified = false;
+ incrementalStrains.Clear();
+ stresses.Clear();
+ stressesNew.Clear();
+ strains.Clear();
+ incrementalStrains.Clear();
+ strainsElasticPrev.Clear();
+ strainsElastic.Clear();
+ strainsPlasticPrev.Clear();
+ strainsPlastic.Clear();
+ strainsEquivalent = 0;
+ strainsEquivalentPrev = 0;
+ constitutiveMatrix = GetConstitutiveMatrix();
+ }
+
+ ///
+ /// Saves the state of the element's material.
+ ///
+ public GenericConstitutiveLawState CreateState()
+ {
+ stresses.CopyFrom(stressesNew);
+ strainsElasticPrev.CopyFrom(strainsElastic);
+ strainsPlasticPrev.CopyFrom(strainsPlastic);
+ strainsEquivalentPrev = strainsEquivalent;
+ currentState = new GenericConstitutiveLawState(this, new[]
+ {
+ (EQUIVALENT_PLASTIC_STRAIN, strainsEquivalent),
+ (STRESS_X, stresses[0]),
+ (STRESS_Y, stresses[1]),
+ (STRESS_Z, stresses[2]),
+ (STRESS_XY, stresses[3]),
+ (STRESS_XZ, stresses[4]),
+ (STRESS_YZ, stresses[5]),
+ });
+
+ return currentState;
+ }
+ IHaveState ICreateState.CreateState() => CreateState();
+ public GenericConstitutiveLawState CurrentState
+ {
+ get => currentState;
+ set
+ {
+ currentState = value;
+ strainsEquivalent = currentState.StateValues[EQUIVALENT_PLASTIC_STRAIN];
+ stresses[0] = currentState.StateValues[STRESS_X];
+ stresses[1] = currentState.StateValues[STRESS_Y];
+ stresses[2] = currentState.StateValues[STRESS_Z];
+ stresses[3] = currentState.StateValues[STRESS_XY];
+ stresses[4] = currentState.StateValues[STRESS_XZ];
+ stresses[5] = currentState.StateValues[STRESS_YZ];
+ }
+ }
+
+ ///
+ /// Resets the indicator of whether the material is modified.
+ ///
+ public void ResetModified() => this.modified = false;
+
+
+ ///
+ /// Updates the element's material with the provided incremental strains.
+ ///
+ /// The incremental strains to use for the next step.
+ public double[] UpdateConstitutiveMatrixAndEvaluateResponse(double[] strainsIncrement)
+ {
+ if (matrices_not_initialized)
+ { this.InitializeMatrices(); }
+ incrementalStrains.CopyFrom(strainsIncrement);
+ this.CalculateNextStressStrainPoint();
+
+ currentState = new GenericConstitutiveLawState(this, new[]
+{
+ (EQUIVALENT_PLASTIC_STRAIN, strainsEquivalent),
+ (STRESS_X, stresses[0]),
+ (STRESS_Y, stresses[1]),
+ (STRESS_Z, stresses[2]),
+ (STRESS_XY, stresses[3]),
+ (STRESS_XZ, stresses[4]),
+ (STRESS_YZ, stresses[5]),
+ });
+
+ return stressesNew;
+ }
+
+ /////
+ ///// Builds the consistent tangential constitutive matrix.
+ /////
+ ///// This is a constant already calculated in the calling method.
+ /////
+ ///// Refer to chapter 7.6.6 page 262 in Souza Neto.
+ /////
+ //private Matrix BuildConsistentTangentialConstitutiveMatrix(double vonMisesStress, double[] unityvector)
+ //{
+ // Matrix consistenttangent = Matrix.CreateZero(TotalStresses, TotalStrains);
+ // double dgamma = this.strainsEquivalent - this.strainsEquivalentPrev;
+ // double v1 = -dgamma * 6 * Math.Pow(this.shearModulus, 2) / vonMisesStress;
+ // double Hk = 0;
+ // double Hi = this.hardeningRatio;
+ // double v2 = (dgamma / vonMisesStress - 1 / (3 * this.shearModulus + Hk + Hi)) * 6 * Math.Pow(this.shearModulus, 2);
+ // for (int i = 0; i < 6; i++)
+ // {
+ // for (int j = 0; j < 6; j++)
+ // {
+ // consistenttangent[i, j] = this.elasticConstitutiveMatrix[i, j] + v1 * DeviatoricProjection[i, j] + v2 * unityvector[i] * unityvector[j];
+ // }
+ // }
+ // return consistenttangent;
+ //}
+
+ ///
+ /// Builds the consistent tangential constitutive matrix.
+ ///
+ ///
+ /// Refer to chapter 7.6.6 page 262 in Souza Neto.
+ ///
+ private void BuildConsistentTangentialConstitutiveMatrix(double[] strainDeviatoricTrial, double normStrainDeviatoricTrial, double vonMisesStress, double deltastrainsEquivalent)
+ {
+ var N = new double[incrementalStrains.Length];
+ for (int i = 0; i < incrementalStrains.Length; i++)
+ {
+ N[i] = strainDeviatoricTrial[i] / normStrainDeviatoricTrial;
+ }
+ for (int i = 0; i < incrementalStrains.Length; i++)
+ {
+ for (int j = 0; j < incrementalStrains.Length; j++)
+ {
+ constitutiveMatrix[i, j] = 2 * shearModulus * (1 - (3 * shearModulus * vonMisesStress) / deltastrainsEquivalent) * DeviatoricProjection[i, j] +
+ 6 * shearModulus * shearModulus * (vonMisesStress / deltastrainsEquivalent - 1 / (3 * shearModulus + hardeningModulus)) * (N[i] * N[j]) + bulkModulus * VolumetricProjection[i, j];
+ }
+ }
+ }
+
+ /////
+ ///// Builds the tangential constitutive matrix.
+ /////
+ //private void BuildTangentialConstitutiveMatrix()
+ //{
+ // this.constitutiveMatrix = Matrix.CreateZero(TotalStresses, TotalStrains);
+ // double invariantJ2New = this.GetDeviatorSecondStressInvariant(stressesNew);
+
+ // double value2 = (3 * this.shearModulus * this.shearModulus) /
+ // ((this.hardeningRatio + (3 * this.shearModulus)) * invariantJ2New);
+
+ // var stressDeviator = this.GetStressDeviator(stressesNew);
+ // for (int k1 = 0; k1 < TotalStresses; k1++)
+ // {
+ // for (int k2 = 0; k2 < TotalStresses; k2++)
+ // {
+ // this.constitutiveMatrix[k2, k1] = this.elasticConstitutiveMatrix[k2, k1] -
+ // (value2 * stressDeviator[k2] * stressDeviator[k1]);
+ // }
+ // }
+ //}
+
+ ///
+ /// Calculates the next stress-strain point.
+ ///
+ /// When the new plastic strain is less than the previous one.
+ private void CalculateNextStressStrainPoint()
+ {
+ //calculate trial variables
+ var strainTrial = new double[incrementalStrains.Length];
+ var stressTrial = new double[incrementalStrains.Length];
+ var strainDeviatoricTrial = new double[incrementalStrains.Length];
+ var stressVolumetricTrial = new double[incrementalStrains.Length];
+ var stressDeviatoricTrial = new double[incrementalStrains.Length];
+ var normStrainDeviatoricTrial = new double();
+ for (int i = 0; i < incrementalStrains.Length; i++)
+ strainTrial[i] = strainsElasticPrev[i] + incrementalStrains[i];
+ for (int i = 0; i < incrementalStrains.Length; i++)
+ {
+ for (int j = 0; j < incrementalStrains.Length; j++)
+ {
+ strainDeviatoricTrial[i] = strainDeviatoricTrial[i] + DeviatoricProjection[i, j] * strainTrial[j];
+ if (i >= 0 && i <= 2)
+ stressTrial[i] += (2 * shearModulus * DeviatoricProjection[i, j] * strainTrial[j] + bulkModulus * VolumetricProjection[i, j] * strainTrial[j]);
+ else
+ stressTrial[i] += 0.5 * (2 * shearModulus * DeviatoricProjection[i, j] * strainTrial[j] + bulkModulus * VolumetricProjection[i, j] * strainTrial[j]);
+ }
+ }
+ for (int i = 0; i < incrementalStrains.Length; i++)
+ {
+ for (int j = 0; j < incrementalStrains.Length; j++)
+ {
+ stressVolumetricTrial[i] += (double)1 / 3 * VolumetricProjection[i, j] * stressTrial[j];
+ stressDeviatoricTrial[i] += DeviatoricProjection[i, j] * stressTrial[j];
+ }
+ normStrainDeviatoricTrial += strainDeviatoricTrial[i] * strainDeviatoricTrial[i];
+ }
+ normStrainDeviatoricTrial = Math.Sqrt(normStrainDeviatoricTrial);
+ var J2 = GetDeviatorSecondStressInvariant(stressTrial);
+ double vonMisesStress = Math.Sqrt(3 * J2);
+ double vonMisesStressMinusYieldStress = vonMisesStress - hardeningFunc(strainsEquivalentPrev);
+
+ bool materialIsInElasticRegion = vonMisesStressMinusYieldStress <= 0;
+ var stressVolumetric = new double[incrementalStrains.Length];
+ var stressDeviatoric = new double[incrementalStrains.Length];
+ double deltastrainsEquivalent = 0;
+ if (materialIsInElasticRegion)
+ {
+ stressesNew.CopyFrom(stressTrial);
+ stressVolumetric.CopyFrom(stressVolumetricTrial);
+ stressDeviatoric.CopyFrom(stressDeviatoricTrial);
+ strainsEquivalent = strainsEquivalentPrev;
+ constitutiveMatrix = elasticConstitutiveMatrix.CopyToFullMatrix();
+ }
+ else
+ {
+ strainsEquivalent = strainsEquivalentPrev;
+ var yieldFunc = Math.Sqrt(3*J2) - hardeningFunc(strainsEquivalent);
+ hardeningModulus = CalculateHardeningGradient(strainsEquivalent);
+ while (Math.Abs(yieldFunc) >= 1e-6)
+ {
+ deltastrainsEquivalent += yieldFunc / (3 * shearModulus + hardeningModulus);
+ strainsEquivalent = strainsEquivalentPrev + deltastrainsEquivalent;
+ yieldFunc = Math.Sqrt(3 * J2) - 3 * shearModulus * deltastrainsEquivalent - hardeningFunc(strainsEquivalent);
+ hardeningModulus = CalculateHardeningGradient(strainsEquivalent);
+ }
+
+ for (int i = 0; i < incrementalStrains.Length; i++)
+ {
+ stressVolumetric[i] = stressVolumetricTrial[i];
+ stressDeviatoric[i] = (1 - (3 * shearModulus * deltastrainsEquivalent) / vonMisesStress) * stressDeviatoricTrial[i];
+ stressesNew[i] = stressVolumetric[i] + stressDeviatoric[i];
+ }
+ BuildConsistentTangentialConstitutiveMatrix(strainDeviatoricTrial, normStrainDeviatoricTrial, deltastrainsEquivalent, vonMisesStress);
+ //this.BuildTangentialConstitutiveMatrix();
+ }
+
+ if (Math.Abs(this.strainsEquivalent) < Math.Abs(this.strainsEquivalentPrev))
+ {
+ throw new InvalidOperationException("Plastic strain cannot decrease.");
+ }
+
+ this.modified = this.strainsEquivalent != this.strainsEquivalentPrev;
+
+ for (int i = 0; i < incrementalStrains.Length; i++)
+ {
+ if (i >= 0 && i <= 2)
+ strainsElastic[i] = 1 / (2 * shearModulus) * stressDeviatoric[i] + 1 / (3 * bulkModulus) * stressVolumetric[i];
+ else
+ strainsElastic[i] = 2 * (1 / (2 * shearModulus) * stressDeviatoric[i] + 1 / (3 * bulkModulus) * stressVolumetric[i]);
+ if (vonMisesStress > 0)
+ strainsPlastic[i] = strainsPlasticPrev[i] + strainTrial[i] - strainsElastic[i];
+ strains[i] = strainsElastic[i] + strainsPlastic[i];
+ }
+ }
+
+ private double CalculateHardeningGradient(double strain_eq) => hardeningGrad = (hardeningFunc(strain_eq + 1e-8) - hardeningFunc(strain_eq)) / 1e-8;
+
+ ///
+ /// Calculates and returns the first stress invariant (I1).
+ ///
+ /// The first stress invariant (I1).
+ public double GetFirstStressInvariant(double[] stresses) => stresses[0] + stresses[1] + stresses[2];
+
+ ///
+ /// Calculates and returns the mean hydrostatic stress.
+ ///
+ /// The mean hydrostatic stress.
+ public double GetMeanStress(double[] stresses) => GetFirstStressInvariant(stresses) / 3.0;
+
+ ///
+ /// Calculates and returns the second stress invariant (I2).
+ ///
+ /// The second stress invariant (I2).
+ public double GetSecondStressInvariant(double[] stresses)
+ => (stresses[0] * stresses[1]) + (stresses[1] * stresses[2]) + (stresses[0] * stresses[2])
+ - Math.Pow(stresses[5], 2) - Math.Pow(stresses[3], 2) - Math.Pow(stresses[4], 2);
+
+ ///
+ /// Calculates and returns the stress deviator tensor in vector form.
+ ///
+ /// The stress deviator tensor in vector form.
+ public double[] GetStressDeviator(double[] stresses)
+ {
+ var hydrostaticStress = this.GetMeanStress(stresses);
+ var stressDeviator = new double[]
+ {
+ stresses[0] - hydrostaticStress,
+ stresses[1] - hydrostaticStress,
+ stresses[2] - hydrostaticStress,
+ stresses[3],
+ stresses[4],
+ stresses[5]
+ };
+
+ return stressDeviator;
+ }
+
+ ///
+ /// Calculates and returns the third stress invariant (I3).
+ ///
+ /// The third stress invariant (I3).
+ public double GetThirdStressInvariant(double[] stresses)
+ => (stresses[0] * stresses[1] * stresses[2]) + (2 * stresses[5] * stresses[3] * stresses[4])
+ - (Math.Pow(stresses[5], 2) * stresses[2]) - (Math.Pow(stresses[3], 2) * stresses[0])
+ - (Math.Pow(stresses[4], 2) * stresses[1]);
+
+ ///
+ /// Returns the first stress invariant of the stress deviator tensor (J1), which is zero.
+ ///
+ /// The first stress invariant of the stress deviator tensor (J1).
+ public double GetDeviatorFirstStressInvariant(double[] stresses) => 0;
+
+ ///
+ /// Calculates and returns the second stress invariant of the stress deviator tensor (J2).
+ ///
+ /// The second stress invariant of the stress deviator tensor (J2).
+ public double GetDeviatorSecondStressInvariant(double[] stresses)
+ {
+ double i1 = this.GetFirstStressInvariant(stresses);
+ double i2 = this.GetSecondStressInvariant(stresses);
+
+ double j2 = (1 / 3d * Math.Pow(i1, 2)) - i2;
+ return j2;
+ }
+
+ ///
+ /// Calculates and returns the third stress invariant of the stress deviator tensor (J3).
+ ///
+ /// The third deviator stress invariant (J3).
+ public double GetDeviatorThirdStressInvariant(double[] stresses)
+ {
+ double i1 = this.GetFirstStressInvariant(stresses);
+ double i2 = this.GetSecondStressInvariant(stresses);
+ double i3 = this.GetThirdStressInvariant(stresses);
+
+ double j3 = (2 / 27 * Math.Pow(i1, 3)) - (1 / 3 * i1 * i2) + i3;
+ return j3;
+ }
+
+ private Matrix GetConstitutiveMatrix()
+ {
+ double fE1 = YoungModulus / (double)(1 + PoissonRatio);
+ double fE2 = fE1 * PoissonRatio / (double)(1 - 2 * PoissonRatio);
+ double fE3 = fE1 + fE2;
+ double fE4 = fE1 * 0.5;
+ var afE = Matrix.CreateZero(6, 6);
+ afE[0, 0] = fE3;
+ afE[0, 1] = fE2;
+ afE[0, 2] = fE2;
+ afE[1, 0] = fE2;
+ afE[1, 1] = fE3;
+ afE[1, 2] = fE2;
+ afE[2, 0] = fE2;
+ afE[2, 1] = fE2;
+ afE[2, 2] = fE3;
+ afE[3, 3] = fE4;
+ afE[4, 4] = fE4;
+ afE[5, 5] = fE4;
+
+ return afE;
+ }
+
+ }
+}