void
ComputeMultipleInelasticStress::updateQpState(RankTwoTensor & elastic_strain_increment,
                                              RankTwoTensor & combined_inelastic_strain_increment)
{
  if (_output_iteration_info == true)
  {
    _console << std::endl
             << "iteration output for ComputeMultipleInelasticStress solve:"
             << " time=" << _t << " int_pt=" << _qp << std::endl;
  }
  Real l2norm_delta_stress;
  Real first_l2norm_delta_stress = 1.0;
  unsigned int counter = 0;

  std::vector<RankTwoTensor> inelastic_strain_increment;
  inelastic_strain_increment.resize(_num_models);

  for (unsigned i_rmm = 0; i_rmm < _models.size(); ++i_rmm)
    inelastic_strain_increment[i_rmm].zero();

  RankTwoTensor stress_max, stress_min;

  do
  {
    for (unsigned i_rmm = 0; i_rmm < _num_models; ++i_rmm)
    {
      _models[i_rmm]->setQp(_qp);

      // initially assume the strain is completely elastic
      elastic_strain_increment = _strain_increment[_qp];
      // and subtract off all inelastic strain increments calculated so far
      // except the one that we're about to calculate
      for (unsigned j_rmm = 0; j_rmm < _num_models; ++j_rmm)
        if (i_rmm != j_rmm)
          elastic_strain_increment -= inelastic_strain_increment[j_rmm];

      // form the trial stress, with the check for changed elasticity constants
      if (_is_elasticity_tensor_guaranteed_isotropic || !_perform_finite_strain_rotations)
      {
        _stress[_qp] =
            _elasticity_tensor[_qp] * (_elastic_strain_old[_qp] + elastic_strain_increment);
        // InitialStress Deprecation: remove these lines
        if (_perform_finite_strain_rotations)
          rotateQpInitialStress();
        addQpInitialStress();
      }
      else
        _stress[_qp] = _stress_old[_qp] + _elasticity_tensor[_qp] * elastic_strain_increment;

      // given a trial stress (_stress[_qp]) and a strain increment (elastic_strain_increment)
      // let the i^th model produce an admissible stress (as _stress[_qp]), and decompose
      // the strain increment into an elastic part (elastic_strain_increment) and an
      // inelastic part (inelastic_strain_increment[i_rmm])
      computeAdmissibleState(i_rmm,
                             elastic_strain_increment,
                             inelastic_strain_increment[i_rmm],
                             _consistent_tangent_operator[i_rmm]);

      if (i_rmm == 0)
      {
        stress_max = _stress[_qp];
        stress_min = _stress[_qp];
      }
      else
      {
        for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
        {
          for (unsigned int j = 0; j < LIBMESH_DIM; ++j)
          {
            if (_stress[_qp](i, j) > stress_max(i, j))
              stress_max(i, j) = _stress[_qp](i, j);
            else if (stress_min(i, j) > _stress[_qp](i, j))
              stress_min(i, j) = _stress[_qp](i, j);
          }
        }
      }
    }

    // now check convergence in the stress:
    // once the change in stress is within tolerance after each recompute material
    // consider the stress to be converged
    l2norm_delta_stress = (stress_max - stress_min).L2norm();
    if (counter == 0 && l2norm_delta_stress > 0.0)
      first_l2norm_delta_stress = l2norm_delta_stress;

    if (_output_iteration_info == true)
    {
      _console << "stress iteration number = " << counter << "\n"
               << " relative l2 norm delta stress = "
               << (0 == first_l2norm_delta_stress ? 0
                                                  : l2norm_delta_stress / first_l2norm_delta_stress)
               << "\n"
               << " stress convergence relative tolerance = " << _relative_tolerance << "\n"
               << " absolute l2 norm delta stress = " << l2norm_delta_stress << "\n"
               << " stress convergence absolute tolerance = " << _absolute_tolerance << std::endl;
    }
    ++counter;
  } while (counter < _max_iterations && l2norm_delta_stress > _absolute_tolerance &&
           (l2norm_delta_stress / first_l2norm_delta_stress) > _relative_tolerance &&
           _num_models != 1);

  if (counter == _max_iterations && l2norm_delta_stress > _absolute_tolerance &&
      (l2norm_delta_stress / first_l2norm_delta_stress) > _relative_tolerance)
    throw MooseException("Max stress iteration hit during ComputeMultipleInelasticStress solve!");

  combined_inelastic_strain_increment.zero();
  for (unsigned i_rmm = 0; i_rmm < _num_models; ++i_rmm)
    combined_inelastic_strain_increment +=
        _inelastic_weights[i_rmm] * inelastic_strain_increment[i_rmm];

  if (_fe_problem.currentlyComputingJacobian())
    computeQpJacobianMult();

  _matl_timestep_limit[_qp] = 0.0;
  for (unsigned i_rmm = 0; i_rmm < _num_models; ++i_rmm)
    _matl_timestep_limit[_qp] += 1.0 / _models[i_rmm]->computeTimeStepLimit();

  if (MooseUtils::absoluteFuzzyEqual(_matl_timestep_limit[_qp], 0.0))
  {
    _matl_timestep_limit[_qp] = std::numeric_limits<Real>::max();
  }
  else
  {
    _matl_timestep_limit[_qp] = 1.0 / _matl_timestep_limit[_qp];
  }
}
void
ComputeReturnMappingStress::updateQpStress(RankTwoTensor & strain_increment,
                                          RankTwoTensor & stress_new)
{
  if (_output_iteration_info == true)
  {
    _console
      << std::endl
      << "iteration output for ComputeReturnMappingStress solve:"
      << " time=" <<_t
      << " int_pt=" << _qp
      << std::endl;
  }

  RankTwoTensor elastic_strain_increment;

  Real l2norm_delta_stress, first_l2norm_delta_stress;
  unsigned int counter = 0;

  std::vector<RankTwoTensor> inelastic_strain_increment;
  inelastic_strain_increment.resize(_models.size());

  for (unsigned i_rmm = 0; i_rmm < _models.size(); ++i_rmm)
    inelastic_strain_increment[i_rmm].zero();

  RankTwoTensor stress_max, stress_min;

  do
  {
    for (unsigned i_rmm = 0; i_rmm < _models.size(); ++i_rmm)
    {
      _models[i_rmm]->setQp(_qp);

      elastic_strain_increment = strain_increment;

      for (unsigned j_rmm = 0; j_rmm < _models.size(); ++j_rmm)
        if (i_rmm != j_rmm)
          elastic_strain_increment -= inelastic_strain_increment[j_rmm];

      stress_new = _elasticity_tensor[_qp] * (elastic_strain_increment + _elastic_strain_old[_qp]);

      _models[i_rmm]->updateStress(elastic_strain_increment,
                                   inelastic_strain_increment[i_rmm],
                                   stress_new);

      if (i_rmm == 0)
      {
        stress_max = stress_new;
        stress_min = stress_new;
      }
      else
      {
        for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
        {
          for (unsigned int j = 0; j < LIBMESH_DIM; ++j)
          {
            if (stress_new(i,j) > stress_max(i,j))
              stress_max(i,j) = stress_new(i,j);
            else if (stress_min(i,j) > stress_new(i,j))
              stress_min(i,j) = stress_new(i,j);
          }
        }
      }

    }

    // now check convergence in the stress:
    // once the change in stress is within tolerance after each recompute material
    // consider the stress to be converged
    RankTwoTensor delta_stress(stress_max - stress_min);
    l2norm_delta_stress = delta_stress.L2norm();
    if (counter == 0)
      first_l2norm_delta_stress = l2norm_delta_stress;

    if (_output_iteration_info == true)
    {
      _console
        << "stress iteration number = " << counter << "\n"
        << " relative l2 norm delta stress = " << (0 == first_l2norm_delta_stress ? 0 : l2norm_delta_stress/first_l2norm_delta_stress) << "\n"
        << " stress convergence relative tolerance = "  << _relative_tolerance <<"\n"
        << " absolute l2 norm delta stress = " << l2norm_delta_stress << "\n"
        << " stress converengen absolute tolerance = "  << _absolute_tolerance
        << std::endl;
    }
    ++counter;
  }
  while (counter < _max_its &&
          l2norm_delta_stress > _absolute_tolerance &&
          (l2norm_delta_stress / first_l2norm_delta_stress) > _relative_tolerance &&
          _models.size() != 1);

  if (counter == _max_its &&
      l2norm_delta_stress > _absolute_tolerance &&
      (l2norm_delta_stress / first_l2norm_delta_stress) > _relative_tolerance)
    mooseError("Max stress iteration hit during ComputeReturnMappingStress solve!");

  strain_increment = elastic_strain_increment;
}