Real
volumetricStrain(const SymmTensor & symm_strain)
{
  Real value = symm_strain.trace();
  value += symm_strain.xx() * symm_strain.yy() + symm_strain.yy() * symm_strain.zz() +
           symm_strain.zz() * symm_strain.xx() +
           symm_strain.xx() * symm_strain.yy() * symm_strain.zz();
  return value;
}
void
CardiacHolzapfel2009Material::computeQpStressProperties(const SymmTensor &C, const SymmTensor & /*E*/)
{
  const SymmTensor CC(square(C));
  // invariants (We will not need all of them. However, defining them avoids to forget any.)
  const Real I1(C.trace());
  /*const Real I2(0.5*(I1*I1-CC.trace()));*/
  /*const Real I3(_J[_qp]);               */
  const Real I4f(_Ef[_qp]*(C*_Ef[_qp]));
  const Real I4s(_Es[_qp]*(C*_Es[_qp]));
  /*const Real I4n(_En[_qp]*(C*_En[_qp])); */
  /*const Real I5f(_Ef[_qp]*(CC*_Ef[_qp]));*/
  /*const Real I5s(_Es[_qp]*(CC*_Es[_qp]));*/
  /*const Real I5n(_En[_qp]*(CC*_En[_qp]));*/
  const Real I8fs(_Ef[_qp]*(C*_Es[_qp]));
  /*const Real I8fn(_Ef[_qp]*(C*_En[_qp]));*/
  /*const Real I8sn(_Es[_qp]*(C*_En[_qp]));*/

  // the following will be needed in the stress as well as in the energy and stress_derivative
  const Real  i_term(   _p[A1 ]*std::exp(_p[B1 ]*(I1 -3)        ) );
  const Real  f_term( 2*_p[Af ]*std::exp(_p[Bf ]*(I4f-1)*(I4f-1)) );
  const Real  s_term( 2*_p[As ]*std::exp(_p[Bs ]*(I4s-1)*(I4s-1)) );
  const Real fs_term(   _p[Afs]*std::exp(_p[Bfs]* I8fs  * I8fs  ) );

  // elastic energy contribution
  _W[_qp] =  i_term             /(2*_p[B1 ])
         + ( f_term - 2*_p[Af ])/(2*_p[Bf ])
         + ( s_term - 2*_p[As ])/(2*_p[Bs ])
         + (fs_term - 2*_p[Afs])/(2*_p[Bfs]);

  // tensors for constructing stress and stress_derivative
  const SymmTensor EfEf(kron(_Ef[_qp]));
  const SymmTensor EsEs(kron(_Es[_qp]));
  const SymmTensor EfEs(kronSym(_Ef[_qp],_Es[_qp]));

  // stress
  _stress[_qp] = scaledID(i_term) + EfEf*(I4f-1)*f_term + EsEs*(I4s-1)*s_term + EfEs*I8fs*fs_term;

  // stress derivative                          /* fancy lambda function syntax makes things much easier here */
  _stress_derivative[_qp].fill_from_minor_iter( [&](const unsigned int M,
                                                    const unsigned int N,
                                                    const unsigned int P,
                                                    const unsigned int Q) -> Real { return                          _p[B1 ]  *  i_term *  _id(M,N)  * _id(P,Q)
                                                                                           + (1 + (I4f-1)*(I4f-1)*2*_p[Bf ]) *  f_term * EfEf(M,N) * EfEf(P,Q)
                                                                                           + (1 + (I4f-1)*(I4f-1)*2*_p[Bf ]) *  s_term * EsEs(M,N) * EsEs(P,Q)
                                                                                           + (1 +  I8fs          *2*_p[Bfs]) * fs_term * EfEs(M,N) * EfEs(P,Q); } );
}
Beispiel #3
0
void
PLC_LSH::computeLSH( const SymmTensor & strain_increment,
                     SymmTensor & plastic_strain_increment,
                     SymmTensor & stress_new )
{

  // compute deviatoric trial stress
  SymmTensor dev_trial_stress(stress_new);
  dev_trial_stress.addDiag( -stress_new.trace()/3 );

  // effective trial stress
  Real dts_squared = dev_trial_stress.doubleContraction(dev_trial_stress);
  Real effective_trial_stress = std::sqrt(1.5 * dts_squared);

  // determine if yield condition is satisfied
  Real yield_condition = effective_trial_stress - _hardening_variable_old[_qp] - _yield_stress;

  _hardening_variable[_qp] = _hardening_variable_old[_qp];
  _plastic_strain[_qp] = _plastic_strain_old[_qp];

  if (yield_condition > 0)  // then use newton iteration to determine effective plastic strain increment
  {
    unsigned int it = 0;
    Real plastic_residual = 0;
    Real norm_plas_residual = 10;
    Real first_norm_plas_residual = 10;
    Real scalar_plastic_strain_increment = 0;

    while (it < _max_its &&
          norm_plas_residual > _absolute_tolerance &&
          (norm_plas_residual/first_norm_plas_residual) > _relative_tolerance)
    {
      plastic_residual = effective_trial_stress - (3. * _shear_modulus * scalar_plastic_strain_increment) -
        _hardening_variable[_qp] - _yield_stress;
      norm_plas_residual = std::abs(plastic_residual);
      if (it == 0)
      {
        first_norm_plas_residual = norm_plas_residual;
      }

      scalar_plastic_strain_increment += plastic_residual / (3. * _shear_modulus + _hardening_constant);

      _hardening_variable[_qp] = _hardening_variable_old[_qp] + (_hardening_constant * scalar_plastic_strain_increment);

      if (_output_iteration_info == true)
      {
        _console
          << "pls_it="    << it
          << " trl_strs=" << effective_trial_stress
          << " del_p="    << scalar_plastic_strain_increment
          << " harden="   << _hardening_variable[_qp]
          << " rel_res="  << norm_plas_residual/first_norm_plas_residual
          << " rel_tol="  << _relative_tolerance
          << " abs_res="  << norm_plas_residual
          << " abs_tol="  << _absolute_tolerance
          << std::endl;
      }

      ++it;

    }

    if (it == _max_its &&
       norm_plas_residual > _absolute_tolerance &&
       (norm_plas_residual/first_norm_plas_residual) > _relative_tolerance)
    {
      mooseError("Max sub-newton iteration hit during plasticity increment solve!");
    }

    if (effective_trial_stress < 0.01)
    {
      effective_trial_stress = 0.01;
    }
    plastic_strain_increment = dev_trial_stress;
    plastic_strain_increment *= (1.5*scalar_plastic_strain_increment/effective_trial_stress);

    SymmTensor elastic_strain_increment(strain_increment);
    elastic_strain_increment -= plastic_strain_increment;

    // compute stress increment
    stress_new = *elasticityTensor() * elastic_strain_increment;

    // update stress and plastic strain
    stress_new += _stress_old;
    _plastic_strain[_qp] += plastic_strain_increment;

  } // end of if statement

}
Beispiel #4
0
void
ReturnMappingModel::computeStress(const Elem & /*current_elem*/,
                                  const SymmElasticityTensor & elasticityTensor,
                                  const SymmTensor & stress_old,
                                  SymmTensor & strain_increment,
                                  SymmTensor & stress_new,
                                  SymmTensor & inelastic_strain_increment)
{
  // compute deviatoric trial stress
  SymmTensor dev_trial_stress(stress_new);
  dev_trial_stress.addDiag(-dev_trial_stress.trace() / 3.0);

  // compute effective trial stress
  Real dts_squared = dev_trial_stress.doubleContraction(dev_trial_stress);
  Real effective_trial_stress = std::sqrt(1.5 * dts_squared);

  // compute effective strain increment
  SymmTensor dev_strain_increment(strain_increment);
  dev_strain_increment.addDiag(-strain_increment.trace() / 3.0);
  _effective_strain_increment = dev_strain_increment.doubleContraction(dev_strain_increment);
  _effective_strain_increment = std::sqrt(2.0 / 3.0 * _effective_strain_increment);

  const SymmIsotropicElasticityTensor * iso_e_t =
      dynamic_cast<const SymmIsotropicElasticityTensor *>(&elasticityTensor);
  if (!iso_e_t)
    mooseError("Models derived from ReturnMappingModel require a SymmIsotropicElasticityTensor");
  _three_shear_modulus = 3.0 * iso_e_t->shearModulus();

  computeStressInitialize(effective_trial_stress, elasticityTensor);

  Real scalar;
  returnMappingSolve(effective_trial_stress, scalar, _console);

  // compute inelastic and elastic strain increments
  if (_legacy_return_mapping)
  {
    if (effective_trial_stress < 0.01)
      effective_trial_stress = 0.01;

    inelastic_strain_increment = dev_trial_stress;
    inelastic_strain_increment *= (1.5 * scalar / effective_trial_stress);
  }
  else
  {
    if (scalar != 0.0)
      inelastic_strain_increment = dev_trial_stress * (1.5 * scalar / effective_trial_stress);
    else
      inelastic_strain_increment = 0.0;
  }

  strain_increment -= inelastic_strain_increment;
  _effective_inelastic_strain[_qp] = _effective_inelastic_strain_old[_qp] + scalar;

  // compute stress increment
  stress_new = elasticityTensor * strain_increment;

  // update stress
  stress_new += stress_old;

  computeStressFinalize(inelastic_strain_increment);
}
bool FractureElasticityVoigt::evalStress (double lambda, double mu, double Gc,
                                          const SymmTensor& epsil, double* Phi,
                                          SymmTensor* sigma, Matrix* dSdE,
                                          bool postProc, bool printElm) const
{
  PROFILE3("FractureEl::evalStress");

  unsigned short int a = 0, b = 0;

  // Define a Lambda-function to set up the isotropic constitutive matrix
  auto&& setIsotropic = [this,a,b](Matrix& C, double lambda, double mu) mutable
  {
    for (a = 1; a <= C.rows(); a++)
      if (a > nsd)
        C(a,a) = mu;
      else
      {
        C(a,a) = 2.0*mu;
        for (b = 1; b <= nsd; b++)
          C(a,b) += lambda;
      }
  };

  // Define some material constants
  double trEps = epsil.trace();
  double C0 = trEps >= -epsZ ? Gc*lambda : lambda;
  double Cp = Gc*mu;

  if (trEps >= -epsZ && trEps <= epsZ)
  {
    // No strains, stress free configuration
    Phi[0] = 0.0;
    if (postProc)
      Phi[1] = Phi[2] = Phi[3] = 0.0;
    if (sigma)
      *sigma = 0.0;
    if (dSdE)
      setIsotropic(*dSdE,C0,Cp);
    return true;
  }

  // Calculate principal strains and the associated directions
  Vec3 eps;
  std::vector<SymmTensor> M(nsd,SymmTensor(nsd));
  {
    PROFILE4("Tensor::principal");
    if (!epsil.principal(eps,M.data()))
      return false;
  }

  // Split the strain tensor into positive and negative parts
  SymmTensor ePos(nsd), eNeg(nsd);
  for (a = 0; a < nsd; a++)
    if (eps[a] > 0.0)
      ePos += eps[a]*M[a];
    else if (eps[a] < 0.0)
      eNeg += eps[a]*M[a];

  if (sigma)
  {
    // Evaluate the stress tensor
    *sigma = C0*trEps;
    *sigma += 2.0*mu*(Gc*ePos + eNeg);
  }

  // Evaluate the tensile energy
  Phi[0] = mu*(ePos*ePos).trace();
  if (trEps > 0.0) Phi[0] += 0.5*lambda*trEps*trEps;
  if (postProc)
  {
    // Evaluate the compressive energy
    Phi[1] = mu*(eNeg*eNeg).trace();
    if (trEps < 0.0) Phi[1] += 0.5*lambda*trEps*trEps;
    // Evaluate the total strain energy
    Phi[2] = Gc*Phi[0] + Phi[1];
    // Evaluate the bulk energy
    Phi[3] = Gc*(Phi[0] + Phi[1]);
  }
  else if (sigmaC > 0.0) // Evaluate the crack driving function
    Phi[0] = this->MieheCrit56(eps,lambda,mu);

#if INT_DEBUG > 4
  std::cout <<"eps_p = "<< eps <<"\n";
  for (a = 0; a < nsd; a++)
    std::cout <<"M("<< 1+a <<") =\n"<< M[a];
  std::cout <<"ePos =\n"<< ePos <<"eNeg =\n"<< eNeg;
  if (sigma) std::cout <<"sigma =\n"<< *sigma;
  std::cout <<"Phi = "<< Phi[0];
  if (postProc) std::cout <<" "<< Phi[1] <<" "<< Phi[2] <<" "<< Phi[3];
  std::cout << std::endl;
#else
  if (printElm)
  {
    std::cout <<"g(c) = "<< Gc
              <<"\nepsilon =\n"<< epsil <<"eps_p = "<< eps
              <<"\nePos =\n"<< ePos <<"eNeg =\n"<< eNeg;
    if (sigma) std::cout <<"sigma =\n"<< *sigma;
    std::cout <<"Phi = "<< Phi[0];
    if (postProc) std::cout <<" "<< Phi[1] <<" "<< Phi[2] <<" "<< Phi[3];
    std::cout << std::endl;
  }
#endif

  if (!dSdE)
    return true;
  else if (eps[0] == eps[nsd-1])
  {
    // Hydrostatic pressure
    setIsotropic(*dSdE, C0, eps.x > 0.0 ? Cp : mu);
    return true;
  }

  typedef unsigned short int s_ind; // Convenience type definition

  // Define a Lambda-function to calculate (lower triangle of) the matrix Qa
  auto&& getQ = [this](Matrix& Q, const SymmTensor& Ma, double C)
  {
    if (C == 0.0) return;

    auto&& Mult = [Ma](s_ind i, s_ind j, s_ind k, s_ind l)
    {
      return Ma(i,j)*Ma(k,l);
    };

    s_ind i, j, k, l, is, js;

    // Normal stresses and strains
    for (i = 1; i <= nsd; i++)
      for (j = 1; j <= i; j++)
        Q(i,j) += C*Mult(i,i,j,j);

    is = nsd+1;
    for (i = 1; i < nsd; i++)
      for (j = i+1; j <= nsd; j++, is++)
      {
        // Shear stress coupled to normal strain
        for (k = 1; k <= nsd; k++)
          Q(is,k) += C*Mult(i,j,k,k);

        // Shear stress coupled to shear strain
        js = nsd+1;
        for (k = 1; k < nsd; k++)
          for (l = k+1; js <= is; l++, js++)
            Q(is,js) += C*Mult(i,j,k,l);
      }
  };

  // Define a Lambda-function to calculate (lower triangle of) the matrix Gab
  auto&& getG = [this](Matrix& G, const SymmTensor& Ma,
                       const SymmTensor& Mb, double C)
  {
    if (C == 0.0) return;

    auto&& Mult = [Ma,Mb](s_ind i, s_ind j, s_ind k, s_ind l)
    {
      return Ma(i,k)*Mb(j,l) + Ma(i,l)*Mb(j,k) +
             Mb(i,k)*Ma(j,l) + Mb(i,l)*Ma(j,k);
    };

    s_ind i, j, k, l, is, js;

    // Normal stresses and strains
    for (i = 1; i <= nsd; i++)
      for (j = 1; j <= i; j++)
        G(i,j) += C*Mult(i,i,j,j);

    is = nsd+1;
    for (i = 1; i < nsd; i++)
      for (j = i+1; j <= nsd; j++, is++)
      {
        // Shear stress coupled to normal strain
        for (k = 1; k <= nsd; k++)
          G(is,k) += C*Mult(i,j,k,k);

        // Shear stress coupled to shear strain
        js = nsd+1;
        for (k = 1; k < nsd; k++)
          for (l = k+1; js <= is; l++, js++)
            G(is,js) += C*Mult(i,j,k,l);
      }
  };

  // Evaluate the stress tangent assuming Voigt notation and symmetry
  for (a = 1; a <= nsd; a++)
    for (b = 1; b <= a; b++)
      (*dSdE)(a,b) = C0;

  for (a = 0; a < nsd; a++)
  {
    double C1 = eps[a] >= 0.0 ? Cp : mu;
    getQ(*dSdE, M[a], 2.0*C1);
    if (eps[a] != 0.0)
      for (b = 0; b < nsd; b++)
        if (a != b && eps[a] != eps[b])
          getG(*dSdE,M[a],M[b],C1/(1.0-eps[b]/eps[a]));
  }

  // Account for symmetry
  for (b = 2; b <= dSdE->rows(); b++)
    for (a = 1; a < b; a++)
      (*dSdE)(a,b) = (*dSdE)(b,a);

  return true;
}
Beispiel #6
0
void
Linear::computeStrain( const unsigned qp,
                       const SymmTensor & total_strain_old,
                       SymmTensor & total_strain_new,
                       SymmTensor & strain_increment )
{
  strain_increment.xx( _grad_disp_x[qp](0) );
  strain_increment.yy( _grad_disp_y[qp](1) );
  strain_increment.zz( _grad_disp_z[qp](2) );
  strain_increment.xy( 0.5*(_grad_disp_x[qp](1)+_grad_disp_y[qp](0)) );
  strain_increment.yz( 0.5*(_grad_disp_y[qp](2)+_grad_disp_z[qp](1)) );
  strain_increment.zx( 0.5*(_grad_disp_z[qp](0)+_grad_disp_x[qp](2)) );
  if (_large_strain)
  {
    strain_increment.xx() += 0.5*(_grad_disp_x[qp](0)*_grad_disp_x[qp](0) +
                                  _grad_disp_y[qp](0)*_grad_disp_y[qp](0) +
                                  _grad_disp_z[qp](0)*_grad_disp_z[qp](0));
    strain_increment.yy() += 0.5*(_grad_disp_x[qp](1)*_grad_disp_x[qp](1) +
                                  _grad_disp_y[qp](1)*_grad_disp_y[qp](1) +
                                  _grad_disp_z[qp](1)*_grad_disp_z[qp](1));
    strain_increment.zz() += 0.5*(_grad_disp_x[qp](2)*_grad_disp_x[qp](2) +
                                  _grad_disp_y[qp](2)*_grad_disp_y[qp](2) +
                                  _grad_disp_z[qp](2)*_grad_disp_z[qp](2));
    strain_increment.xy() += 0.5*(_grad_disp_x[qp](0)*_grad_disp_x[qp](1) +
                                  _grad_disp_y[qp](0)*_grad_disp_y[qp](1) +
                                  _grad_disp_z[qp](0)*_grad_disp_z[qp](1));
    strain_increment.yz() += 0.5*(_grad_disp_x[qp](1)*_grad_disp_x[qp](2) +
                                  _grad_disp_y[qp](1)*_grad_disp_y[qp](2) +
                                  _grad_disp_z[qp](1)*_grad_disp_z[qp](2));
    strain_increment.zx() += 0.5*(_grad_disp_x[qp](2)*_grad_disp_x[qp](0) +
                                  _grad_disp_y[qp](2)*_grad_disp_y[qp](0) +
                                  _grad_disp_z[qp](2)*_grad_disp_z[qp](0));
  }

  if (_volumetric_locking_correction)
  {
    // volumetric locking correction - averaging the volumertic strain over the element
    Real volumetric_strain = 0.0;
    Real volume = 0.0;
    for (unsigned int qp_loop = 0; qp_loop < _solid_model.qrule()->n_points(); ++qp_loop)
    {
      volumetric_strain += (_grad_disp_x[qp_loop](0) + _grad_disp_y[qp_loop](1) + _grad_disp_z[qp_loop](2)) / 3.0 * _solid_model.JxW(qp_loop);

      volume += _solid_model.JxW(qp_loop);

      if (_large_strain)
      {
        volumetric_strain += 0.5 * (_grad_disp_x[qp](0) * _grad_disp_x[qp](0) +
                                    _grad_disp_y[qp](0) * _grad_disp_y[qp](0) +
                                    _grad_disp_z[qp](0) * _grad_disp_z[qp](0)) / 3.0 * _solid_model.JxW(qp_loop);
        volumetric_strain += 0.5 * (_grad_disp_x[qp](1) * _grad_disp_x[qp](1) +
                                    _grad_disp_y[qp](1) * _grad_disp_y[qp](1) +
                                    _grad_disp_z[qp](1) * _grad_disp_z[qp](1)) / 3.0 * _solid_model.JxW(qp_loop);
        volumetric_strain += 0.5 * (_grad_disp_x[qp](2) * _grad_disp_x[qp](2) +
                                    _grad_disp_y[qp](2) * _grad_disp_y[qp](2) +
                                    _grad_disp_z[qp](2) * _grad_disp_z[qp](2)) / 3.0 * _solid_model.JxW(qp_loop);
      }
    }

    volumetric_strain /= volume; // average volumetric strain

    // strain increment at _qp
    Real trace = strain_increment.trace();
    strain_increment.xx() += volumetric_strain - trace / 3.0;
    strain_increment.yy() += volumetric_strain - trace / 3.0;
    strain_increment.zz() += volumetric_strain - trace / 3.0;
  }

  total_strain_new = strain_increment;
  strain_increment -= total_strain_old;
}
Real
firstInvariant(const SymmTensor & symm_tensor)
{
    return symm_tensor.trace();
}
Real
hydrostatic(const SymmTensor & symm_tensor)
{
    return symm_tensor.trace() / 3.0;
}
Beispiel #9
0
void
PlaneStrain::computeStrain( const unsigned qp,
                               const SymmTensor & total_strain_old,
                               SymmTensor & total_strain_new,
                               SymmTensor & strain_increment )
{
  strain_increment.xx() = _grad_disp_x[qp](0);
  strain_increment.yy() = _grad_disp_y[qp](1);

  if (_have_strain_zz)
    strain_increment.zz() = _strain_zz[qp];
  else if (_have_scalar_strain_zz && _scalar_strain_zz.size()>0)
    strain_increment.zz() = _scalar_strain_zz[0];
  else
    strain_increment.zz() = 0;

  strain_increment.xy() = 0.5*(_grad_disp_x[qp](1) + _grad_disp_y[qp](0));
  strain_increment.yz() = 0;
  strain_increment.zx() = 0;
  if (_large_strain)
  {
    strain_increment.xx() += 0.5*(_grad_disp_x[qp](0)*_grad_disp_x[qp](0) +
                                  _grad_disp_y[qp](0)*_grad_disp_y[qp](0));
    strain_increment.yy() += 0.5*(_grad_disp_x[qp](1)*_grad_disp_x[qp](1) +
                                  _grad_disp_y[qp](1)*_grad_disp_y[qp](1));
    strain_increment.xy() += 0.5*(_grad_disp_x[qp](0)*_grad_disp_x[qp](1) +
                                  _grad_disp_y[qp](0)*_grad_disp_y[qp](1));
  }

  if (_volumetric_locking_correction)
  {
    // volumetric locking correction
    Real volumetric_strain = 0.0;
    Real volume = 0.0;
    Real dim = 3.0;
    for (unsigned int qp_loop = 0; qp_loop < _solid_model.qrule()->n_points(); ++qp_loop)
    {
      if (_have_strain_zz)
        volumetric_strain += (_grad_disp_x[qp_loop](0) + _grad_disp_y[qp_loop](1) + _strain_zz[qp_loop]) / dim * _solid_model.JxW(qp_loop);
      else if (_have_scalar_strain_zz && _scalar_strain_zz.size() > 0)
        volumetric_strain += (_grad_disp_x[qp_loop](0) + _grad_disp_y[qp_loop](1) + _scalar_strain_zz[0]) / dim * _solid_model.JxW(qp_loop);
      else
        volumetric_strain += (_grad_disp_x[qp_loop](0) + _grad_disp_y[qp_loop](1)) / dim * _solid_model.JxW(qp_loop);

      volume += _solid_model.JxW(qp_loop);

      if (_large_strain)
      {
        volumetric_strain += 0.5 * (_grad_disp_x[qp_loop](0) * _grad_disp_x[qp_loop](0) +
                                    _grad_disp_y[qp_loop](0) * _grad_disp_y[qp_loop](0)) / dim * _solid_model.JxW(qp_loop);
        volumetric_strain += 0.5 * (_grad_disp_x[qp_loop](1) * _grad_disp_x[qp_loop](1) +
                                    _grad_disp_y[qp_loop](1) * _grad_disp_y[qp_loop](1)) / dim * _solid_model.JxW(qp_loop);
      }
    }

    volumetric_strain /= volume; // average volumetric strain

    // strain increment at _qp
    Real trace = strain_increment.trace();
    strain_increment.xx() += volumetric_strain - trace / dim;
    strain_increment.yy() += volumetric_strain - trace / dim;
    strain_increment.zz() += volumetric_strain - trace / dim;
  }

  total_strain_new = strain_increment;

  strain_increment -= total_strain_old;
}
Beispiel #10
0
void
ReturnMappingModel::computeStress(const Elem & /*current_elem*/, unsigned qp,
                                  const SymmElasticityTensor & elasticityTensor,
                                  const SymmTensor & stress_old,
                                  SymmTensor & strain_increment,
                                  SymmTensor & stress_new,
                                  SymmTensor & inelastic_strain_increment)
{
  // compute deviatoric trial stress
  SymmTensor dev_trial_stress(stress_new);
  dev_trial_stress.addDiag(-dev_trial_stress.trace()/3.0);

  // compute effective trial stress
  Real dts_squared = dev_trial_stress.doubleContraction(dev_trial_stress);
  Real effective_trial_stress = std::sqrt(1.5 * dts_squared);

  // compute effective strain increment
  SymmTensor dev_strain_increment(strain_increment);
  dev_strain_increment.addDiag(-strain_increment.trace()/3.0);
  _effective_strain_increment = dev_strain_increment.doubleContraction(dev_strain_increment);
  _effective_strain_increment = std::sqrt(2.0/3.0 * _effective_strain_increment);

  computeStressInitialize(qp, effective_trial_stress, elasticityTensor);

  // Use Newton sub-iteration to determine inelastic strain increment

  Real scalar = 0;
  unsigned int it = 0;
  Real residual = 10;
  Real norm_residual = 10;
  Real first_norm_residual = 10;

  std::string iter_output;

  while (it < _max_its &&
        norm_residual > _absolute_tolerance &&
        (norm_residual/first_norm_residual) > _relative_tolerance)
  {
    iterationInitialize(qp, scalar);

    residual = computeResidual(qp, effective_trial_stress, scalar);
    norm_residual = std::abs(residual);
    if (it == 0)
    {
      first_norm_residual = norm_residual;
      if (first_norm_residual == 0)
      {
        first_norm_residual = 1;
      }
    }

    scalar -= residual / computeDerivative(qp, effective_trial_stress, scalar);

    if (_output_iteration_info == true ||
        _output_iteration_info_on_error == true)
    {
        iter_output = "In the element " + Moose::stringify(_current_elem->id()) +
                         + " and the qp point " + Moose::stringify(qp) + ": \n" +
                         + " iteration = " + Moose::stringify(it ) + "\n" +
                         + " effective trial stress = " + Moose::stringify(effective_trial_stress) + "\n" +
                         + " scalar effective inelastic strain = " + Moose::stringify(scalar) +"\n" +
                         + " relative residual = " + Moose::stringify(norm_residual/first_norm_residual) + "\n" +
                         + " relative tolerance = " + Moose::stringify(_relative_tolerance) + "\n" +
                         + " absolute residual = " + Moose::stringify(norm_residual) + "\n" +
                         + " absolute tolerance = " + Moose::stringify(_absolute_tolerance) + "\n";
      }
    iterationFinalize(qp, scalar);
    ++it;
  }

  if (_output_iteration_info)
    _console << iter_output;

  if (it == _max_its &&
     norm_residual > _absolute_tolerance &&
     (norm_residual/first_norm_residual) > _relative_tolerance)
  {
    if (_output_iteration_info_on_error)
    {
      Moose::err << iter_output;
    }
    mooseError("Exceeded maximum iterations in ReturnMappingModel solve for material: " << _name << ".  Rerun with  'output_iteration_info_on_error = true' for more information.");
  }

  // compute inelastic and elastic strain increments (avoid potential divide by zero - how should this be done)?
  if (effective_trial_stress < 0.01)
  {
    effective_trial_stress = 0.01;
  }

  inelastic_strain_increment = dev_trial_stress;
  inelastic_strain_increment *= (1.5*scalar/effective_trial_stress);

  strain_increment -= inelastic_strain_increment;

  // compute stress increment
  stress_new = elasticityTensor * strain_increment;

  // update stress
  stress_new += stress_old;

  computeStressFinalize(qp, inelastic_strain_increment);
}
Beispiel #11
0
void
ReturnMappingModel::computeStress( const Elem & /*current_elem*/, unsigned qp,
                                   const SymmElasticityTensor & elasticityTensor,
                                   const SymmTensor & stress_old,
                                   SymmTensor & strain_increment,
                                   SymmTensor & stress_new,
                                   SymmTensor & inelastic_strain_increment )
{

  // compute deviatoric trial stress
  SymmTensor dev_trial_stress(stress_new);
  dev_trial_stress.addDiag( -dev_trial_stress.trace()/3.0 );

  // compute effective trial stress
  Real dts_squared = dev_trial_stress.doubleContraction(dev_trial_stress);
  Real effective_trial_stress = std::sqrt(1.5 * dts_squared);

  // compute effective strain increment
  SymmTensor dev_strain_increment(strain_increment);
  dev_strain_increment.addDiag( -strain_increment.trace()/3.0);
  _effective_strain_increment = dev_strain_increment.doubleContraction(dev_strain_increment);
  _effective_strain_increment = std::sqrt(2.0/3.0 * _effective_strain_increment);

  computeStressInitialize(qp, effective_trial_stress, elasticityTensor);

  // Use Newton sub-iteration to determine inelastic strain increment

  Real scalar = 0;
  unsigned int it = 0;
  Real residual = 10;
  Real norm_residual = 10;
  Real first_norm_residual = 10;

  std::stringstream iter_output;

  while (it < _max_its &&
        norm_residual > _absolute_tolerance &&
        (norm_residual/first_norm_residual) > _relative_tolerance)
  {
    iterationInitialize( qp, scalar );

    residual = computeResidual(qp, effective_trial_stress, scalar);
    norm_residual = std::abs(residual);
    if (it == 0)
    {
      first_norm_residual = norm_residual;
      if (first_norm_residual == 0)
      {
        first_norm_residual = 1;
      }
    }

    scalar -= residual / computeDerivative(qp, effective_trial_stress, scalar);

    if (_output_iteration_info == true ||
        _output_iteration_info_on_error == true)
    {
      iter_output
        << " it="       << it
        << " trl_strs=" << effective_trial_stress
        << " scalar="   << scalar
        << " rel_res="  << norm_residual/first_norm_residual
        << " rel_tol="  << _relative_tolerance
        << " abs_res="  << norm_residual
        << " abs_tol="  << _absolute_tolerance
        << std::endl;
    }

    iterationFinalize( qp, scalar );

    ++it;
  }

  if (_output_iteration_info)
    _console << iter_output.str();


  if (it == _max_its &&
     norm_residual > _absolute_tolerance &&
     (norm_residual/first_norm_residual) > _relative_tolerance)
  {
    if (_output_iteration_info_on_error)
    {
      Moose::err << iter_output.str();
    }
    mooseError("Max sub-newton iteration hit during nonlinear constitutive model solve! (" << _name << ")");
  }

  // compute inelastic and elastic strain increments (avoid potential divide by zero - how should this be done)?
  if (effective_trial_stress < 0.01)
  {
    effective_trial_stress = 0.01;
  }

  inelastic_strain_increment = dev_trial_stress;
  inelastic_strain_increment *= (1.5*scalar/effective_trial_stress);

  strain_increment -= inelastic_strain_increment;

  // compute stress increment
  stress_new = elasticityTensor * strain_increment;

  // update stress
  stress_new += stress_old;

  computeStressFinalize(qp, inelastic_strain_increment);

}
Beispiel #12
0
Real
MaterialTensorAux::getTensorQuantity(const SymmTensor & tensor,
                                     const MTA_ENUM quantity,
                                     const MooseEnum & quantity_moose_enum,
                                     const int index,
                                     const Point * curr_point,
                                     const Point * p1,
                                     const Point * p2)
{
  Real value(0);
  if (quantity == MTA_COMPONENT)
  {
    value = tensor.component(index);
  }
  else if ( quantity == MTA_VONMISES )
  {
    value = std::sqrt(0.5*(
                           std::pow(tensor.xx() - tensor.yy(), 2) +
                           std::pow(tensor.yy() - tensor.zz(), 2) +
                           std::pow(tensor.zz() - tensor.xx(), 2) + 6 * (
                           std::pow(tensor.xy(), 2) +
                           std::pow(tensor.yz(), 2) +
                           std::pow(tensor.zx(), 2))));
  }
  else if ( quantity == MTA_PLASTICSTRAINMAG )
  {
    value = std::sqrt(2.0/3.0 * tensor.doubleContraction(tensor));
  }
  else if ( quantity == MTA_HYDROSTATIC )
  {
    value = tensor.trace()/3.0;
  }
  else if ( quantity == MTA_HOOP )
  {
    // This is the location of the stress.  A vector from the cylindrical axis to this point will define the x' axis.
    Point p0( *curr_point );

    // The vector p1 + t*(p2-p1) defines the cylindrical axis.  The point along this
    // axis closest to p0 is found by the following for t:
    const Point p2p1( *p2 - *p1 );
    const Point p2p0( *p2 - p0 );
    const Point p1p0( *p1 - p0 );
    const Real t( -(p1p0*p2p1)/p2p1.size_sq() );
    // The nearest point on the cylindrical axis to p0 is p.
    const Point p( *p1 + t * p2p1 );
    Point xp( p0 - p );
    xp /= xp.size();
    Point yp( p2p1/p2p1.size() );
    Point zp( xp.cross( yp ));
    //
    // The following works but does more than we need
    //
//    // Rotation matrix R
//    ColumnMajorMatrix R(3,3);
//    // Fill with direction cosines
//    R(0,0) = xp(0);
//    R(1,0) = xp(1);
//    R(2,0) = xp(2);
//    R(0,1) = yp(0);
//    R(1,1) = yp(1);
//    R(2,1) = yp(2);
//    R(0,2) = zp(0);
//    R(1,2) = zp(1);
//    R(2,2) = zp(2);
//    // Rotate
//    ColumnMajorMatrix tensor( _tensor[_qp].columnMajorMatrix() );
//    ColumnMajorMatrix tensorp( R.transpose() * ( tensor * R ));
//    // Hoop stress is the zz stress
//    value = tensorp(2,2);
    //
    // Instead, tensorp(2,2) = R^T(2,:)*tensor*R(:,2)
    //
    const Real zp0( zp(0) );
    const Real zp1( zp(1) );
    const Real zp2( zp(2) );
    value = (zp0*tensor(0,0)+zp1*tensor(1,0)+zp2*tensor(2,0))*zp0 +
            (zp0*tensor(0,1)+zp1*tensor(1,1)+zp2*tensor(2,1))*zp1 +
            (zp0*tensor(0,2)+zp1*tensor(1,2)+zp2*tensor(2,2))*zp2;
  }
  else if ( quantity == MTA_RADIAL )
  {
    // This is the location of the stress.  A vector from the cylindrical axis to this point will define the x' axis
    // which is the radial direction in which we want the stress.
    Point p0( *curr_point );

    // The vector p1 + t*(p2-p1) defines the cylindrical axis.  The point along this
    // axis closest to p0 is found by the following for t:
    const Point p2p1( *p2 - *p1 );
    const Point p2p0( *p2 - p0 );
    const Point p1p0( *p1 - p0 );
    const Real t( -(p1p0*p2p1)/p2p1.size_sq() );
    // The nearest point on the cylindrical axis to p0 is p.
    const Point p( *p1 + t * p2p1 );
    Point xp( p0 - p );
    xp /= xp.size();
    const Real xp0( xp(0) );
    const Real xp1( xp(1) );
    const Real xp2( xp(2) );
    value = (xp0*tensor(0,0)+xp1*tensor(1,0)+xp2*tensor(2,0))*xp0 +
            (xp0*tensor(0,1)+xp1*tensor(1,1)+xp2*tensor(2,1))*xp1 +
            (xp0*tensor(0,2)+xp1*tensor(1,2)+xp2*tensor(2,2))*xp2;
  }
  else if ( quantity == MTA_AXIAL )
  {
    // The vector p2p1=(p2-p1) defines the axis, which is the direction in which we want the stress.
    Point p2p1( *p2 - *p1 );
    p2p1 /= p2p1.size();

    const Real axis0( p2p1(0) );
    const Real axis1( p2p1(1) );
    const Real axis2( p2p1(2) );
    value = (axis0*tensor(0,0)+axis1*tensor(1,0)+axis2*tensor(2,0))*axis0 +
            (axis0*tensor(0,1)+axis1*tensor(1,1)+axis2*tensor(2,1))*axis1 +
            (axis0*tensor(0,2)+axis1*tensor(1,2)+axis2*tensor(2,2))*axis2;
  }
  else if ( quantity == MTA_MAXPRINCIPAL )
  {
    value = principalValue( tensor, 0 );
  }
  else if ( quantity == MTA_MEDPRINCIPAL )
  {
    value = principalValue( tensor, 1 );
  }
  else if ( quantity == MTA_MINPRINCIPAL )
  {
    value = principalValue( tensor, 2 );
  }
  else if ( quantity == MTA_FIRSTINVARIANT )
  {
    value = tensor.trace();
  }
  else if ( quantity == MTA_SECONDINVARIANT )
  {
    value =
      tensor.xx()*tensor.yy() +
      tensor.yy()*tensor.zz() +
      tensor.zz()*tensor.xx() -
      tensor.xy()*tensor.xy() -
      tensor.yz()*tensor.yz() -
      tensor.zx()*tensor.zx();
  }
  else if ( quantity == MTA_THIRDINVARIANT )
  {
    value =
      tensor.xx()*tensor.yy()*tensor.zz() -
      tensor.xx()*tensor.yz()*tensor.yz() +
      tensor.xy()*tensor.zx()*tensor.yz() -
      tensor.xy()*tensor.xy()*tensor.zz() +
      tensor.zx()*tensor.xy()*tensor.yz() -
      tensor.zx()*tensor.zx()*tensor.yy();
  }
  else if ( quantity == MTA_TRIAXIALITY )
  {
    Real hydrostatic = tensor.trace()/3.0;
    Real von_mises = std::sqrt(0.5*(
                                 std::pow(tensor.xx() - tensor.yy(), 2) +
                                 std::pow(tensor.yy() - tensor.zz(), 2) +
                                 std::pow(tensor.zz() - tensor.xx(), 2) + 6 * (
                                   std::pow(tensor.xy(), 2) +
                                   std::pow(tensor.yz(), 2) +
                                   std::pow(tensor.zx(), 2))));

    value = std::abs(hydrostatic / von_mises);
  }
  else if ( quantity == MTA_VOLUMETRICSTRAIN )
  {
    value =
      tensor.trace() +
      tensor.xx()*tensor.yy() +
      tensor.yy()*tensor.zz() +
      tensor.zz()*tensor.xx() +
      tensor.xx()*tensor.yy()*tensor.zz();
  }
  else
  {
    mooseError("Unknown quantity in MaterialTensorAux: " + quantity_moose_enum.operator std::string());
  }
  return value;
}