コード例 #1
0
/**
 * Implements the return-map algorithm via a Newton-Raphson process.
 * This idea is fully explained in Simo and Hughes "Computational
 * Inelasticity" Springer 1997, for instance, as well as many other
 * books on plasticity.
 * The basic idea is as follows.
 * Given: sig_old - the stress at the start of the "time step"
 *        plastic_strain_old - the plastic strain at the start of the "time step"
 *        eqvpstrain_old - equivalent plastic strain at the start of the "time step"
 *                         (In general we would be given some number of internal
 *                         parameters that the yield function depends upon.)
 *        delta_d - the prescribed strain increment for this "time step"
 * we want to determine the following parameters at the end of this "time step":
 *        sig - the stress
 *        plastic_strain - the plastic strain
 *        eqvpstrain - the equivalent plastic strain (again, in general, we would
 *                     have an arbitrary number of internal parameters).
 *
 * To determine these parameters, introduce
 *    the "yield function", f
 *    the "consistency parameter", flow_incr
 *    the "flow potential", flow_dirn_ij
 *    the "internal potential", internalPotential (in general there are as many internalPotential
 *        functions as there are internal parameters).
 * All three of f, flow_dirn_ij, and internalPotential, are functions of
 * sig and eqvpstrain.
 * To find sig, plastic_strain and eqvpstrain, we need to solve the following
 *   resid_ij = 0
 *   f = 0
 *   rep = 0
 * This is done by using Newton-Raphson.
 * There are 8 equations here: six from resid_ij=0 (more generally there are nine
 * but in this case resid is symmetric); one from f=0; one from rep=0 (more generally, for N
 * internal parameters there are N of these equations).
 *
 * resid_ij = flow_incr*flow_dirn_ij - (plastic_strain - plastic_strain_old)_ij
 *          = flow_incr*flow_dirn_ij - (E^{-1}(trial_stress - sig))_ij
 * Here trial_stress = E*(strain - plastic_strain_old)
 *      sig = E*(strain - plastic_strain)
 * Note: flow_dirn_ij is evaluated at sig and eqvpstrain (not the old values).
 *
 * f is the yield function, evaluated at sig and eqvpstrain
 *
 * rep = -flow_incr*internalPotential - (eqvpstrain - eqvpstrain_old)
 * Here internalPotential are evaluated at sig and eqvpstrain (not the old values).
 *
 * The Newton-Raphson procedure has sig, flow_incr, and eqvpstrain as its
 * variables.  Therefore we need the derivatives of resid_ij, f, and rep
 * with respect to these parameters
 *
 * In this associative J2 with isotropic hardening, things are a little more specialised.
 * (1) f = sqrt(3*s_ij*s_ij/2) - K(eqvpstrain)    (this is called "isotropic hardening")
 * (2) associativity means that flow_dirn_ij = df/d(sig_ij) = s_ij*sqrt(3/2/(s_ij*s_ij)), and
 *     this means that flow_dirn_ij*flow_dirn_ij = 3/2, so when resid_ij=0, we get
 *     (plastic_strain_dot)_ij*(plastic_strain_dot)_ij = (3/2)*flow_incr^2, where
 *     plastic_strain_dot = plastic_strain - plastic_strain_old
 * (3) The definition of equivalent plastic strain is through
 *     eqvpstrain_dot = sqrt(2*plastic_strain_dot_ij*plastic_strain_dot_ij/3), so
 *     using (2), we obtain eqvpstrain_dot = flow_incr, and this yields
 *     internalPotential = -1 in the "rep" equation.
 */
void
FiniteStrainPlasticMaterial::returnMap(const RankTwoTensor & sig_old,
                                       const Real eqvpstrain_old,
                                       const RankTwoTensor & plastic_strain_old,
                                       const RankTwoTensor & delta_d,
                                       const RankFourTensor & E_ijkl,
                                       RankTwoTensor & sig,
                                       Real & eqvpstrain,
                                       RankTwoTensor & plastic_strain)
{
  // the yield function, must be non-positive
  // Newton-Raphson sets this to zero if trial stress enters inadmissible region
  Real f;

  // the consistency parameter, must be non-negative
  // change in plastic strain in this timestep = flow_incr*flow_potential
  Real flow_incr = 0.0;

  // direction of flow defined by the potential
  RankTwoTensor flow_dirn;

  // Newton-Raphson sets this zero
  // resid_ij = flow_incr*flow_dirn_ij - (plastic_strain - plastic_strain_old)
  RankTwoTensor resid;

  // Newton-Raphson sets this zero
  // rep = -flow_incr*internalPotential - (eqvpstrain - eqvpstrain_old)
  Real rep;

  // change in the stress (sig) in a Newton-Raphson iteration
  RankTwoTensor ddsig;

  // change in the consistency parameter in a Newton-Raphson iteration
  Real dflow_incr = 0.0;

  // change in equivalent plastic strain in one Newton-Raphson iteration
  Real deqvpstrain = 0.0;

  // convenience variable that holds the change in plastic strain incurred during the return
  // delta_dp = plastic_strain - plastic_strain_old
  // delta_dp = E^{-1}*(trial_stress - sig), where trial_stress = E*(strain - plastic_strain_old)
  RankTwoTensor delta_dp;

  // d(yieldFunction)/d(stress)
  RankTwoTensor df_dsig;

  // d(resid_ij)/d(sigma_kl)
  RankFourTensor dr_dsig;

  // dr_dsig_inv_ijkl*dr_dsig_klmn = 0.5*(de_ij de_jn + de_ij + de_jm), where de_ij = 1 if i=j, but
  // zero otherwise
  RankFourTensor dr_dsig_inv;

  // d(yieldFunction)/d(eqvpstrain)
  Real fq;

  // yield stress at the start of this "time step" (ie, evaluated with
  // eqvpstrain_old).  It is held fixed during the Newton-Raphson return,
  // even if eqvpstrain != eqvpstrain_old.
  Real yield_stress;

  // measures of whether the Newton-Raphson process has converged
  Real err1, err2, err3;

  // number of Newton-Raphson iterations performed
  unsigned int iter = 0;

  // maximum number of Newton-Raphson iterations allowed
  unsigned int maxiter = 100;

  // plastic loading occurs if yieldFunction > toly
  Real toly = 1.0e-8;

  // Assume this strain increment does not induce any plasticity
  // This is the elastic-predictor
  sig = sig_old + E_ijkl * delta_d; // the trial stress
  eqvpstrain = eqvpstrain_old;
  plastic_strain = plastic_strain_old;

  yield_stress = getYieldStress(eqvpstrain); // yield stress at this equivalent plastic strain
  if (yieldFunction(sig, yield_stress) > toly)
  {
    // the sig just calculated is inadmissable.  We must return to the yield surface.
    // This is done iteratively, using a Newton-Raphson process.

    delta_dp.zero();

    sig = sig_old + E_ijkl * delta_d; // this is the elastic predictor

    flow_dirn = flowPotential(sig);

    resid = flow_dirn * flow_incr - delta_dp; // Residual 1 - refer Hughes Simo
    f = yieldFunction(sig, yield_stress);
    rep = -eqvpstrain + eqvpstrain_old - flow_incr * internalPotential(); // Residual 3 rep=0

    err1 = resid.L2norm();
    err2 = std::abs(f);
    err3 = std::abs(rep);

    while ((err1 > _rtol || err2 > _ftol || err3 > _eptol) &&
           iter < maxiter) // Stress update iteration (hardness fixed)
    {
      iter++;

      df_dsig = dyieldFunction_dstress(sig);
      getJac(sig, E_ijkl, flow_incr, dr_dsig);   // gets dr_dsig = d(resid_ij)/d(sig_kl)
      fq = dyieldFunction_dinternal(eqvpstrain); // d(f)/d(eqvpstrain)

      /**
       * The linear system is
       *   ( dr_dsig  flow_dirn  0  )( ddsig       )   ( - resid )
       *   ( df_dsig     0       fq )( dflow_incr  ) = ( - f     )
       *   (   0         1       -1 )( deqvpstrain )   ( - rep   )
       * The zeroes are: d(resid_ij)/d(eqvpstrain) = flow_dirn*d(df/d(sig_ij))/d(eqvpstrain) = 0
       * and df/d(flow_dirn) = 0  (this is always true, even for general hardening and
       * non-associative)
       * and d(rep)/d(sig_ij) = -flow_incr*d(internalPotential)/d(sig_ij) = 0
       */

      dr_dsig_inv = dr_dsig.invSymm();

      /**
       * Because of the zeroes and ones, the linear system is not impossible to
       * solve by hand.
       * NOTE: andy believes there was originally a sign-error in the next line.  The
       *       next line is unchanged, however andy's definition of fq is negative of
       *       the original definition of fq.  andy can't see any difference in any tests!
       */
      dflow_incr = (f - df_dsig.doubleContraction(dr_dsig_inv * resid) + fq * rep) /
                   (df_dsig.doubleContraction(dr_dsig_inv * flow_dirn) - fq);
      ddsig =
          dr_dsig_inv *
          (-resid -
           flow_dirn * dflow_incr); // from solving the top row of linear system, given dflow_incr
      deqvpstrain =
          rep + dflow_incr; // from solving the bottom row of linear system, given dflow_incr

      // update the variables
      flow_incr += dflow_incr;
      delta_dp -= E_ijkl.invSymm() * ddsig;
      sig += ddsig;
      eqvpstrain += deqvpstrain;

      // evaluate the RHS equations ready for next Newton-Raphson iteration
      flow_dirn = flowPotential(sig);
      resid = flow_dirn * flow_incr - delta_dp;
      f = yieldFunction(sig, yield_stress);
      rep = -eqvpstrain + eqvpstrain_old - flow_incr * internalPotential();

      err1 = resid.L2norm();
      err2 = std::abs(f);
      err3 = std::abs(rep);
    }

    if (iter >= maxiter)
      mooseError("Constitutive failure");

    plastic_strain += delta_dp;
  }
}
コード例 #2
0
  void SundialsInterface::init(const Dict& opts) {
    // Call the base class method
    Integrator::init(opts);

    // Default options
    abstol_ = 1e-8;
    reltol_ = 1e-6;
    exact_jacobian_ = true;
    max_num_steps_ = 10000;
    finite_difference_fsens_ = false;
    stop_at_end_ = true;
    use_preconditioner_ = false;
    max_krylov_ = 10;
    string linear_solver_type = "dense";
    string iterative_solver = "gmres";
    string pretype = "none";
    string linear_solver;
    Dict linear_solver_options;
    upper_bandwidth_ = -1;
    lower_bandwidth_ = -1;
    upper_bandwidthB_ = -1;
    lower_bandwidthB_ = -1;
    quad_err_con_ = false;
    interpolation_type_ = "hermite";
    steps_per_checkpoint_ = 20;
    disable_internal_warnings_ = false;
    max_multistep_order_ = 5;

    // Read options
    for (auto&& op : opts) {
      if (op.first=="abstol") {
        abstol_ = op.second;
      } else if (op.first=="reltol") {
        reltol_ = op.second;
      } else if (op.first=="exact_jacobian") {
        exact_jacobian_ = op.second;
      } else if (op.first=="max_num_steps") {
        max_num_steps_ = op.second;
      } else if (op.first=="finite_difference_fsens") {
        finite_difference_fsens_ = op.second;
      } else if (op.first=="stop_at_end") {
        stop_at_end_ = op.second;
      } else if (op.first=="use_preconditioner") {
        use_preconditioner_ = op.second;
      } else if (op.first=="max_krylov") {
        max_krylov_ = op.second;
      } else if (op.first=="linear_solver_type") {
        linear_solver_type = op.second.to_string();
      } else if (op.first=="iterative_solver") {
        iterative_solver = op.second.to_string();
      } else if (op.first=="pretype") {
        pretype = op.second.to_string();
      } else if (op.first=="linear_solver") {
        linear_solver = op.second.to_string();
      } else if (op.first=="linear_solver_options") {
        linear_solver_options = op.second;
      } else if (op.first=="upper_bandwidth") {
        upper_bandwidth_ = op.second;
      } else if (op.first=="lower_bandwidth") {
        lower_bandwidth_ = op.second;
      } else if (op.first=="upper_bandwidthB") {
        upper_bandwidthB_ = op.second;
      } else if (op.first=="lower_bandwidthB") {
        lower_bandwidthB_ = op.second;
      } else if (op.first=="quad_err_con") {
        quad_err_con_ = op.second;
      } else if (op.first=="interpolation_type") {
        interpolation_type_ = op.second.to_string();
      } else if (op.first=="steps_per_checkpoint") {
        steps_per_checkpoint_ = op.second;
      } else if (op.first=="disable_internal_warnings") {
        disable_internal_warnings_ = op.second;
      } else if (op.first=="max_multistep_order") {
        max_multistep_order_ = op.second;
      }
    }

    // Default dependent options
    exact_jacobianB_ = exact_jacobian_;
    fsens_abstol_ = abstol_;
    fsens_reltol_ = reltol_;
    abstolB_ = abstol_;
    reltolB_ = reltol_;
    use_preconditionerB_ = use_preconditioner_;
    max_krylovB_ = max_krylov_;
    std::string linear_solver_typeB = linear_solver_type;
    std::string iterative_solverB = iterative_solver;
    std::string pretypeB = pretype;
    string linear_solverB = linear_solver;
    Dict linear_solver_optionsB = linear_solver_options;

    // Read options again
    for (auto&& op : opts) {
      if (op.first=="exact_jacobianB") {
        exact_jacobianB_ = op.second;
      } else if (op.first=="fsens_abstol") {
        fsens_abstol_ = op.second;
      } else if (op.first=="fsens_reltol") {
        fsens_reltol_ = op.second;
      } else if (op.first=="abstolB") {
        abstolB_ = op.second;
      } else if (op.first=="reltolB") {
        reltolB_ = op.second;
      } else if (op.first=="use_preconditionerB") {
        use_preconditionerB_ = op.second;
      } else if (op.first=="max_krylovB") {
        max_krylovB_ = op.second;
      } else if (op.first=="linear_solver_typeB") {
        linear_solver_typeB = op.second.to_string();
      } else if (op.first=="iterative_solverB") {
        iterative_solverB = op.second.to_string();
      } else if (op.first=="pretypeB") {
        pretypeB = op.second.to_string();
      } else if (op.first=="linear_solverB") {
        linear_solverB = op.second.to_string();
      } else if (op.first=="linear_solver_optionsB") {
        linear_solver_optionsB = op.second;
      }
    }

    // No Jacobian of g if g doesn't exist
    if (g_.is_null()) {
      exact_jacobianB_ = false;
    }

    // Linear solver for forward integration
    if (linear_solver_type=="dense") {
      linsol_f_ = SD_DENSE;
    } else if (linear_solver_type=="banded") {
      linsol_f_ = SD_BANDED;
    } else if (linear_solver_type=="iterative") {
      linsol_f_ = SD_ITERATIVE;

      // Iterative solver
      if (iterative_solver=="gmres") {
        itsol_f_ = SD_GMRES;
      } else if (iterative_solver=="bcgstab") {
        itsol_f_ = SD_BCGSTAB;
      } else if (iterative_solver=="tfqmr") {
        itsol_f_ = SD_TFQMR;
      } else {
        casadi_error("Unknown iterative solver for forward integration: " + iterative_solver);
      }

      // Preconditioning type
      if (pretype=="none") {
        pretype_f_ = PREC_NONE;
      } else if (pretype=="left") {
        pretype_f_ = PREC_LEFT;
      } else if (pretype=="right") {
        pretype_f_ = PREC_RIGHT;
      } else if (pretype=="both") {
        pretype_f_ = PREC_BOTH;
      } else {
        casadi_error("Unknown preconditioning type for forward integration: " + pretype);
      }
    } else if (linear_solver_type=="user_defined") {
      linsol_f_ = SD_USER_DEFINED;
    } else {
      casadi_error("Unknown linear solver for forward integration: " + linear_solver_type);
    }

    // Linear solver for backward integration
    if (linear_solver_typeB=="dense") {
      linsol_g_ = SD_DENSE;
    } else if (linear_solver_typeB=="banded") {
      linsol_g_ = SD_BANDED;
    } else if (linear_solver_typeB=="iterative") {
      linsol_g_ = SD_ITERATIVE;

      // Iterative solver
      if (iterative_solverB=="gmres") {
        itsol_g_ = SD_GMRES;
      } else if (iterative_solverB=="bcgstab") {
        itsol_g_ = SD_BCGSTAB;
      } else if (iterative_solverB=="tfqmr") {
        itsol_g_ = SD_TFQMR;
      } else {
        casadi_error("Unknown sparse solver for backward integration: " + iterative_solverB);
      }

      // Preconditioning type
      if (pretypeB=="none") {
        pretype_g_ = PREC_NONE;
      } else if (pretypeB=="left") {
        pretype_g_ = PREC_LEFT;
      } else if (pretypeB=="right") {
        pretype_g_ = PREC_RIGHT;
      } else if (pretypeB=="both") {
        pretype_g_ = PREC_BOTH;
      } else {
        casadi_error("Unknown preconditioning type for backward integration: " + pretypeB);
      }
    } else if (linear_solver_typeB=="user_defined") {
      linsol_g_ = SD_USER_DEFINED;
    } else {
      casadi_error("Unknown linear solver for backward integration: " + iterative_solverB);
    }

    // Create a Jacobian if requested
    if (exact_jacobian_) {
      jac_ = getJac();
      alloc(jac_);
      alloc_w(jac_.nnz_out(0), true);
    }

    if (!jac_.is_null()) {
      casadi_assert_message(jac_.size2_out(0)==jac_.size1_out(0),
                            "SundialsInterface::init: the jacobian of the forward problem must "
                            "be square but got " << jac_.sparsity_out(0).dim());

      casadi_assert_message(!jac_.sparsity_out(0).is_singular(),
                            "SundialsInterface::init: singularity - the jacobian of the forward "
                            "problem is structurally rank-deficient. sprank(J)="
                            << sprank(jac_.sparsity_out(0)) << " (in stead of "<< jac_.size2_out(0)
                            << ")");
    }

    // Create a backwards Jacobian if requested
    if (exact_jacobianB_ && !g_.is_null()) jacB_ = getJacB();

    if (!jacB_.is_null()) {
      alloc(jacB_);
      alloc_w(jacB_.nnz_out(0), true);
      casadi_assert_message(jacB_.size2_out(0)==jacB_.size1_out(0),
                            "SundialsInterface::init: the jacobian of the backward problem must be "
                            "square but got " << jacB_.sparsity_out(0).dim());

      casadi_assert_message(!jacB_.sparsity_out(0).is_singular(),
                            "SundialsInterface::init: singularity - the jacobian of the backward"
                            " problem is structurally rank-deficient. sprank(J)="
                            << sprank(jacB_.sparsity_out(0)) << " (instead of "
                            << jacB_.size2_out(0) << ")");
    }

    // Create a linear solver
    if (!linear_solver.empty() && !jac_.is_null()) {
      linsol_ = linsol("linsol", linear_solver, jac_.sparsity_out(0),
                       1, linear_solver_options);
      alloc(linsol_);
    }

    // Create a linear solver
    if (!linear_solverB.empty() && !jacB_.is_null()) {
      linsolB_ = linsol("linsolB", linear_solverB, jacB_.sparsity_out(0),
                        1, linear_solver_optionsB);
      alloc(linsolB_);
    }

    // Allocate temporary memory
    //alloc_w(np_, true); // p_
    //alloc_w(nrp_, true); // rp_
  }
コード例 #3
0
/*
 *Solves for incremental plastic rate of deformation tensor and stress in unrotated frame.
 *Input: Strain incrment, 4th order elasticity tensor, stress tensor in previous incrmenent and
 *plastic rate of deformation tensor gradient.
 */
void
FiniteStrainPlasticMaterial::solveStressResid(RankTwoTensor sig_old,RankTwoTensor delta_d,RankFourTensor E_ijkl, RankTwoTensor *dp, RankTwoTensor *sig)
{

  RankTwoTensor sig_new,delta_dp,dpn;
  RankTwoTensor flow_tensor, flow_dirn;
  RankTwoTensor resid,ddsig;
  RankFourTensor dr_dsig,dr_dsig_inv;
  Real /*sig_eqv,*/flow_incr,f,dflow_incr;
  Real err1,err2,err3;
  unsigned int plastic_flag;
  unsigned int iter,maxiter=100;
  Real eqvpstrain,eqvpstrain_old,deqvpstrain,fq,rep;
  Real yield_stress;


  sig_new=sig_old+E_ijkl*delta_d;
  eqvpstrain_old=eqvpstrain=_eqv_plastic_strain_old[_qp];
  yield_stress=getYieldStress(eqvpstrain);
  plastic_flag=isPlastic(sig_new,yield_stress);//Check of plasticity for elastic predictor

  if (plastic_flag==1)
  {

    iter=0;

    dflow_incr=0.0;
    flow_incr=0.0;
    delta_dp.zero();
    deqvpstrain=0.0;

    sig_new=sig_old+E_ijkl*delta_d;

    getFlowTensor(sig_new,&flow_tensor);
    flow_dirn=flow_tensor;


    resid=flow_dirn*flow_incr-delta_dp;//Residual 1 - refer Hughes Simo
    f=getSigEqv(sig_new)-yield_stress;//Residual 2 - f=0
    rep=-eqvpstrain+eqvpstrain_old+flow_incr;//Residual 3 rep=0

    err1=resid.L2norm();
    err2=fabs(f);
    err3=fabs(rep);


    while ((err1 > _rtol || err2 > _ftol || err3 > _eptol) && iter < maxiter )//Stress update iteration (hardness fixed)
    {


      iter++;

      getJac(sig_new,E_ijkl,flow_incr,&dr_dsig);//Jacobian
      dr_dsig_inv=dr_dsig.invSymm();
      fq=getdYieldStressdPlasticStrain(eqvpstrain);

      dflow_incr=(f-flow_tensor.doubleContraction(dr_dsig_inv*resid)+fq*rep)/(flow_tensor.doubleContraction(dr_dsig_inv*flow_dirn)-fq);
      ddsig=dr_dsig_inv*(-resid-flow_dirn*dflow_incr);

      flow_incr+=dflow_incr;
      delta_dp-=E_ijkl.invSymm()*ddsig;
      sig_new+=ddsig;
      deqvpstrain=rep+dflow_incr;
      eqvpstrain+=deqvpstrain;

      getFlowTensor(sig_new,&flow_tensor);
      flow_dirn=flow_tensor;

      resid=flow_dirn*flow_incr-delta_dp;
      f=getSigEqv(sig_new)-yield_stress;
      rep=-eqvpstrain+eqvpstrain_old+flow_incr;

      err1=resid.L2norm();
      err2=fabs(f);
      err3=fabs(rep);

    }

    if (iter>=maxiter)
    {
      _stress[_qp](2,2)=1e6;
      printf("Constitutive Error: Too many iterations %f %f %f \n",err1,err2, err3);//Convergence failure
      return;
    }

    dpn=*dp+delta_dp;

  }

  *dp=dpn;//Plastic strain in unrotated configuration
  *sig=sig_new;
  _eqv_plastic_strain[_qp]=eqvpstrain;
}
コード例 #4
0
/*
 *Solves for incremental plastic rate of deformation tensor and stress in unrotated frame.
 *Input: Strain incrment, 4th order elasticity tensor, stress tensor in previous incrmenent and
 *plastic rate of deformation tensor.
 */
void
FiniteStrainRatePlasticMaterial::returnMap(const RankTwoTensor & sig_old, const RankTwoTensor & delta_d, const RankFourTensor & E_ijkl, RankTwoTensor & dp, RankTwoTensor & sig)
{
  RankTwoTensor sig_new, delta_dp, dpn;
  RankTwoTensor flow_tensor, flow_dirn;
  RankTwoTensor resid,ddsig;
  RankFourTensor dr_dsig, dr_dsig_inv;
  Real flow_incr, flow_incr_tmp;
  Real err1, err3, tol1, tol3;
  unsigned int iterisohard, iter, maxiterisohard = 20, maxiter = 50;
  Real eqvpstrain;
  Real yield_stress, yield_stress_prev;

  tol1 = 1e-10;
  tol3 = 1e-6;

  iterisohard = 0;
  eqvpstrain = std::pow(2.0/3.0,0.5) * dp.L2norm();
  yield_stress = getYieldStress(eqvpstrain);

  err3 = 1.1 * tol3;

  while (err3 > tol3 && iterisohard < maxiterisohard) //Hardness update iteration
  {
    iterisohard++;
    iter = 0;
    delta_dp.zero();

    sig_new = sig_old + E_ijkl * delta_d;
    flow_incr=_ref_pe_rate*_dt * std::pow(macaulayBracket(getSigEqv(sig_new) / yield_stress - 1.0), _exponent);

    getFlowTensor(sig_new, yield_stress, flow_tensor);
    flow_dirn = flow_tensor;

    resid = flow_dirn * flow_incr - delta_dp;
    err1 = resid.L2norm();

    while (err1 > tol1  && iter < maxiter) //Stress update iteration (hardness fixed)
    {
      iter++;

      getJac(sig_new, E_ijkl, flow_incr, yield_stress, dr_dsig); //Jacobian
      dr_dsig_inv = dr_dsig.invSymm();

      ddsig = -dr_dsig_inv * resid;

      sig_new += ddsig; //Update stress
      delta_dp -= E_ijkl.invSymm() * ddsig; //Update plastic rate of deformation tensor

      flow_incr_tmp = _ref_pe_rate * _dt * std::pow(macaulayBracket(getSigEqv(sig_new) / yield_stress - 1.0), _exponent);

      if (flow_incr_tmp < 0.0) //negative flow increment not allowed
        mooseError("Constitutive Error-Negative flow increment: Reduce time increment.");

      flow_incr = flow_incr_tmp;

      getFlowTensor(sig_new, yield_stress, flow_tensor);
      flow_dirn = flow_tensor;

      resid = flow_dirn * flow_incr - delta_dp; //Residual

      err1=resid.L2norm();
    }

    if (iter>=maxiter)//Convergence failure
      mooseError("Constitutive Error-Too many iterations: Reduce time increment.\n"); //Convergence failure

    dpn = dp + delta_dp;
    eqvpstrain = std::pow(2.0/3.0, 0.5) * dpn.L2norm();

    yield_stress_prev = yield_stress;
    yield_stress = getYieldStress(eqvpstrain);

    err3 = std::abs(yield_stress-yield_stress_prev);
  }

  if (iterisohard>=maxiterisohard)
    mooseError("Constitutive Error-Too many iterations in Hardness Update:Reduce time increment.\n"); //Convergence failure

  dp = dpn; //Plastic rate of deformation tensor in unrotated configuration
  sig = sig_new;
}