Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
@@ -0,0 +1,72 @@
# ComputeMultipleInelasticStressSmallStrain

!syntax description /Materials/ComputeMultipleInelasticStressSmallStrain

## Description

`ComputeMultipleInelasticStressSmallStrain` computes the stress and decomposition of strain into elastic and inelastic components for materials with multiple inelastic models (e.g., plasticity, creep) using a **small strain formulation**. This class is analogous to [ComputeMultipleInelasticStress](ComputeMultipleInelasticStress.md) but uses total strains instead of strain increments and does not include finite strain rotation effects.

### Small Strain vs Finite Strain

The key differences between this class and `ComputeMultipleInelasticStress` are:

- **Strain Formulation**: Uses total small strains $\boldsymbol{\varepsilon} = \frac{1}{2}(\nabla \mathbf{u} + \nabla \mathbf{u}^T)$ instead of logarithmic strain increments
- **No Rotations**: Does not perform finite strain rotations or use rotation increment tensors
- **Parent Class**: Inherits from [ComputeStressBase](ComputeStressBase.md) instead of [ComputeFiniteStrainElasticStress](ComputeFiniteStrainElasticStress.md)
- **Total Formulation**: Works with total strains rather than incremental formulation

### Iterative Solution Procedure

The material uses an iterative return mapping algorithm to find the admissible stress state that satisfies all inelastic models simultaneously:

1. For each iteration:
- Loop over all inelastic models
- For each model, compute the current elastic strain by subtracting inelastic strains from other models
- Form trial stress: $\boldsymbol{\sigma}^{trial} = \mathbf{C} : \boldsymbol{\varepsilon}^{elastic}$
- Call the model's `updateState` method to compute admissible stress and inelastic strain increment
- Track min/max stress for convergence checking

2. Check convergence based on the L2 norm of stress differences between models
3. If not converged and iterations remain, repeat

4. Once converged:
- Combine inelastic strains from all models using specified weights
- Compute final elastic strain: $\boldsymbol{\varepsilon}^{elastic} = \boldsymbol{\varepsilon}^{total} - \boldsymbol{\varepsilon}^{inelastic}$
- Compute Jacobian (tangent operator) if needed

### Strain Decomposition

The mechanical strain is decomposed as:

\begin{equation}
\boldsymbol{\varepsilon}^{mechanical} = \boldsymbol{\varepsilon}^{elastic} + \boldsymbol{\varepsilon}^{inelastic}
\end{equation}

where the combined inelastic strain is a weighted sum:

\begin{equation}
\boldsymbol{\varepsilon}^{inelastic} = \sum_i w_i \boldsymbol{\varepsilon}^{inelastic}_i
\end{equation}

## Usage Notes

- This material should be paired with a small strain calculator such as [ComputeSmallStrain](ComputeSmallStrain.md)
- Do NOT use with incremental strain formulations (e.g., `ComputeFiniteStrain`)
- Inelastic models should be listed with creep models first, plasticity models last
- The `perform_finite_strain_rotations` parameter from the finite strain version is not needed here

## Example Input File Syntax

!listing modules/solid_mechanics/test/tests/multiple_inelastic_stress_small_strain/two_models.i block=Materials/stress

!syntax parameters /Materials/ComputeMultipleInelasticStressSmallStrain

!syntax inputs /Materials/ComputeMultipleInelasticStressSmallStrain

!syntax children /Materials/ComputeMultipleInelasticStressSmallStrain

## See Also

- [ComputeMultipleInelasticStress](ComputeMultipleInelasticStress.md) - Finite strain version
- [ComputeSmallStrain](ComputeSmallStrain.md) - Small strain calculator to pair with this class
- [StressUpdateBase](StressUpdateBase.md) - Base class for inelastic models
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//* This file is part of the MOOSE framework
//* https://mooseframework.inl.gov
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#pragma once

#include "ComputeMultipleInelasticStressSmallStrainBase.h"

/**
* ComputeMultipleInelasticStressSmallStrain computes the stress, the consistent tangent
* operator (or an approximation to it), and a decomposition of the strain
* into elastic and inelastic parts using small strain formulation.
*
* The elastic strain is calculated by subtracting the computed inelastic strain
* from the mechanical strain tensor. Mechanical strain is considered as the sum
* of the elastic and inelastic (plastic, creep, etc) strains.
*
* This material is used to call the recompute iterative materials of a number
* of specified inelastic models that inherit from StressUpdateBase. It iterates
* over the specified inelastic models until the change in stress is within
* a user-specified tolerance, in order to produce the stress, the consistent
* tangent operator and the elastic and inelastic strains for the time increment.
*/

class ComputeMultipleInelasticStressSmallStrain : public ComputeMultipleInelasticStressSmallStrainBase
{
public:
static InputParameters validParams();

ComputeMultipleInelasticStressSmallStrain(const InputParameters & parameters);

protected:
virtual std::vector<MaterialName> getInelasticModelNames() override;

virtual void updateQpState(RankTwoTensor & elastic_strain,
RankTwoTensor & inelastic_strain) override;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
//* This file is part of the MOOSE framework
//* https://mooseframework.inl.gov
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#pragma once

#include "ComputeStressBase.h"
#include "GuaranteeConsumer.h"
#include "DamageBase.h"
#include "StressUpdateBase.h"
#include "MultipleInelasticStressHelper.h"

/**
* ComputeMultipleInelasticStressSmallStrainBase computes the stress, the consistent tangent
* operator (or an approximation to it), and a decomposition of the strain
* into elastic and inelastic parts using small strain formulation.
*
* The elastic strain is calculated by subtracting the computed inelastic strain
* from the mechanical strain tensor. Mechanical strain is considered as the sum
* of the elastic and inelastic (plastic, creep, etc) strains.
*
* This material is used to call the recompute iterative materials of a number
* of specified inelastic models that inherit from StressUpdateBase. It iterates
* over the specified inelastic models until the change in stress is within
* a user-specified tolerance, in order to produce the stress, the consistent
* tangent operator and the elastic and inelastic strains for the time increment.
*
* This class uses small strain (total) formulation, in contrast to
* ComputeMultipleInelasticStressBase which uses finite strain (incremental) formulation.
*/

class ComputeMultipleInelasticStressSmallStrainBase : public ComputeStressBase,
public GuaranteeConsumer
{
public:
static InputParameters validParams();

ComputeMultipleInelasticStressSmallStrainBase(const InputParameters & parameters);

virtual void initialSetup() override;

protected:
virtual std::vector<MaterialName> getInelasticModelNames() = 0;

virtual void initQpStatefulProperties() override;

virtual void computeQpStress() override;

/**
* Given the current strain, iterate over all of the user-specified
* recompute materials in order to find an admissible stress (which is placed
* into _stress[_qp]) and set of inelastic strains, as well as the tangent operator
* (which is placed into _Jacobian_mult[_qp]).
* @param elastic_strain The elastic strain after the iterative process has converged
* @param inelastic_strain The inelastic strain after the iterative process has converged
*/
virtual void updateQpState(RankTwoTensor & elastic_strain, RankTwoTensor & inelastic_strain) = 0;

/**
* An optimised version of updateQpState that gets used when the number
* of plastic models is unity, or when we're cycling through models
* Given the current strain, find an admissible stress (which is
* put into _stress[_qp]) and inelastic strain, as well as the tangent operator
* (which is placed into _Jacobian_mult[_qp])
* @param model_number Use this model number
* @param elastic_strain The elastic strain
* @param inelastic_strain The inelastic strain
*/
virtual void updateQpStateSingleModel(unsigned model_number,
RankTwoTensor & elastic_strain,
RankTwoTensor & inelastic_strain);

/**
* Using _elasticity_tensor[_qp] and the consistent tangent operators,
* _consistent_tangent_operator[...] computed by the inelastic models,
* compute _Jacobian_mult[_qp]
*/
virtual void computeQpJacobianMult();

/**
* Given a trial stress (_stress[_qp]) and the current mechanical strain
* let the model_number model produce an admissible stress (gets placed back
* in _stress[_qp]), and compute the elastic and inelastic strains,
* as well as the consistent_tangent_operator
* @param model_number The inelastic model to use
* @param elastic_strain The elastic strain (computed)
* @param inelastic_strain The inelastic strain (computed)
* @param consistent_tangent_operator The consistent tangent operator
*/
virtual void computeAdmissibleState(unsigned model_number,
RankTwoTensor & elastic_strain,
RankTwoTensor & inelastic_strain,
RankFourTensor & consistent_tangent_operator);

///@{Input parameters associated with the recompute iteration to return the stress state to the yield surface
const unsigned int _max_iterations;
const Real _relative_tolerance;
const Real _absolute_tolerance;
const bool _internal_solve_full_iteration_history;
///@}

/// Name of the elasticity tensor material property
const std::string _elasticity_tensor_name;
/// Elasticity tensor material property
const MaterialProperty<RankFourTensor> & _elasticity_tensor;

/// Old value of mechanical strain
const MaterialProperty<RankTwoTensor> & _mechanical_strain_old;

/// The sum of the inelastic strains that come from the plastic models
MaterialProperty<RankTwoTensor> & _inelastic_strain;

/// old value of inelastic strain
const MaterialProperty<RankTwoTensor> & _inelastic_strain_old;

/// Old value of stress
const MaterialProperty<RankTwoTensor> & _stress_old;

/// what sort of Tangent operator to calculate
const enum class TangentOperatorEnum { elastic, nonlinear } _tangent_operator_type;

/// number of plastic models
unsigned _num_models;

/// Flags to compute tangent during updateState call
std::vector<bool> _tangent_computation_flag;

/// Calculation method for the tangent modulus
TangentCalculationMethod _tangent_calculation_method;

/// _inelastic_strain = sum_i (_inelastic_weights_i * inelastic_strain_from_model_i)
std::vector<Real> _inelastic_weights;

/// the consistent tangent operators computed by each plastic model
std::vector<RankFourTensor> _consistent_tangent_operator;

/// whether to cycle through the models, using only one model per timestep
const bool _cycle_models;

MaterialProperty<Real> & _material_timestep_limit;

/**
* Rank four symmetric identity tensor
*/
const RankFourTensor _identity_symmetric_four;

/**
* The user supplied list of inelastic models to use in the simulation
*
* Users should take care to list creep models first and plasticity
* models last to allow for the case when a creep model relaxes the stress state
* inside of the yield surface in an iteration.
*/
std::vector<StressUpdateBase *> _models;

/// is the elasticity tensor guaranteed to be isotropic?
bool _is_elasticity_tensor_guaranteed_isotropic;

/// are all inelastic models inherently isotropic? (not the case for e.g. weak plane plasticity models)
bool _all_models_isotropic;

/// Pointer to the damage model
DamageBaseTempl<false> * _damage_model;

RankTwoTensor _undamaged_stress_old;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//* This file is part of the MOOSE framework
//* https://mooseframework.inl.gov
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#pragma once

#include "RankTwoTensor.h"
#include "RankFourTensor.h"
#include "StressUpdateBase.h"

/**
* Helper class containing shared logic for multiple inelastic stress calculations.
* This allows code reuse between finite strain and small strain formulations.
*/
class MultipleInelasticStressHelper
{
public:
/**
* Compute the Jacobian multiplier using the elasticity tensor and consistent tangent operators
* @param tangent_calculation_method The method for computing the tangent
* @param elasticity_tensor The elasticity tensor
* @param consistent_tangent_operator Vector of consistent tangent operators from each model
* @param num_models Number of inelastic models
* @param identity_symmetric_four The rank-4 symmetric identity tensor
* @return The computed Jacobian multiplier
*/
static RankFourTensor computeJacobianMult(
TangentCalculationMethod tangent_calculation_method,
const RankFourTensor & elasticity_tensor,
const std::vector<RankFourTensor> & consistent_tangent_operator,
unsigned int num_models,
const RankFourTensor & identity_symmetric_four);

/**
* Compute the combined inelastic strain increment from individual model contributions
* @param inelastic_strain_increment Vector of inelastic strain increments from each model
* @param inelastic_weights Weights for combining the inelastic strains
* @param num_models Number of inelastic models
* @return The weighted sum of inelastic strain increments
*/
static RankTwoTensor computeCombinedInelasticStrainIncrement(
const std::vector<RankTwoTensor> & inelastic_strain_increment,
const std::vector<Real> & inelastic_weights,
unsigned int num_models);

/**
* Compute material timestep limit from all models
* @param models Vector of stress update models
* @param num_models Number of inelastic models
* @return The computed timestep limit
*/
static Real computeMaterialTimestepLimit(const std::vector<StressUpdateBase *> & models,
unsigned int num_models);

/**
* Check convergence of the stress iteration
* @param stress_max Maximum stress from current iteration
* @param stress_min Minimum stress from current iteration
* @param counter Current iteration number
* @param max_iterations Maximum allowed iterations
* @param relative_tolerance Relative convergence tolerance
* @param absolute_tolerance Absolute convergence tolerance
* @param first_l2norm_delta_stress L2 norm from first iteration (for relative check)
* @param num_models Number of models (if 1, always converged)
* @return true if converged, false otherwise
*/
static bool checkConvergence(const RankTwoTensor & stress_max,
const RankTwoTensor & stress_min,
unsigned int counter,
unsigned int max_iterations,
Real relative_tolerance,
Real absolute_tolerance,
Real first_l2norm_delta_stress,
unsigned int num_models);

/**
* Update stress min/max for convergence checking
* @param stress Current stress state
* @param stress_max Maximum stress (updated in place)
* @param stress_min Minimum stress (updated in place)
* @param is_first_model True if this is the first model in the iteration
*/
static void updateStressMinMax(const RankTwoTensor & stress,
RankTwoTensor & stress_max,
RankTwoTensor & stress_min,
bool is_first_model);

/**
* Compute the L2 norm of the stress difference for convergence checking
* @param stress_max Maximum stress
* @param stress_min Minimum stress
* @return L2 norm of the difference
*/
static Real computeStressDifferenceNorm(const RankTwoTensor & stress_max,
const RankTwoTensor & stress_min);
};
Loading