RankTwoTensor
TensorMechanicsPlasticMeanCapTC::dhardPotential_dstress(const RankTwoTensor & stress, Real intnl) const
{
  const Real tr = stress.trace();
  const Real t_str = tensile_strength(intnl);
  if (tr >= t_str)
    return RankTwoTensor();
  const Real c_str = compressive_strength(intnl);
  if (tr <= c_str)
    return RankTwoTensor();
  return - std::sin(M_PI * (tr - c_str) / (t_str - c_str)) * M_PI / (t_str - c_str) * stress.dtrace();
}
示例#2
0
void
RankTwoTensorTest::rotateTest()
{
  Real sqrt2 = 0.707106781187;
  RealTensorValue rtv0(sqrt2, -sqrt2, 0, sqrt2, sqrt2, 0, 0, 0, 1); // rotation about "0" axis
  RealTensorValue rtv1(sqrt2, 0, -sqrt2, 0, 1, 0, sqrt2, 0, sqrt2); // rotation about "1" axis
  RealTensorValue rtv2(1, 0, 0, 0, sqrt2, -sqrt2, 0, sqrt2, sqrt2); // rotation about "2" axis

  RankTwoTensor rot0(rtv0);
  RankTwoTensor rot0T = rot0.transpose();
  RankTwoTensor rot1(rtv1);
  RankTwoTensor rot1T = rot1.transpose();
  RankTwoTensor rot2(rtv2);
  RankTwoTensor rot2T = rot2.transpose();
  RankTwoTensor rot = rot0*rot1*rot2;

  RankTwoTensor answer;
  RankTwoTensor m3;

  // the following "answer"s come from mathematica of course!

  // rotate about "0" axis with RealTensorValue, then back again with RankTwoTensor
  m3 = _m3;
  answer = RankTwoTensor(-4, 3, 6.363961, 3, 0, -2.1213403, 6.363961, -2.1213403, 9);
  m3.rotate(rtv0);
  CPPUNIT_ASSERT_DOUBLES_EQUAL(0, (m3 - answer).L2norm(), 0.0001);
  m3.rotate(rot0T);
  CPPUNIT_ASSERT_DOUBLES_EQUAL(0, (m3 - _m3).L2norm(), 0.0001);

  // rotate about "1" axis with RealTensorValue, then back again with RankTwoTensor
  m3 = _m3;
  answer = RankTwoTensor(2, 5.656854, -4, 5.656854, -5, -2.828427, -4, -2.828427, 8);
  m3.rotate(rtv1);
  CPPUNIT_ASSERT_DOUBLES_EQUAL(0, (m3 - answer).L2norm(), 0.0001);
  m3.rotate(rot1T);
  CPPUNIT_ASSERT_DOUBLES_EQUAL(0, (m3 - _m3).L2norm(), 0.0001);

  // rotate about "2" axis with RealTensorValue, then back again with RankTwoTensor
  m3 = _m3;
  answer = RankTwoTensor(1, -sqrt2, 3.5355339, -sqrt2, 8, -7, 3.5355339, -7, -4);
  m3.rotate(rtv2);
  CPPUNIT_ASSERT_DOUBLES_EQUAL(0, (m3 - answer).L2norm(), 0.0001);
  m3.rotate(rot2T);
  CPPUNIT_ASSERT_DOUBLES_EQUAL(0, (m3 - _m3).L2norm(), 0.0001);

  // rotate with "rot"
  m3 = _m3;
  answer = RankTwoTensor(-2.9675144, -6.51776695, 5.6213203, -6.51776695, 5.9319805, -2.0857864, 5.6213203, -2.0857864, 2.0355339);
  m3.rotate(rot);
  CPPUNIT_ASSERT_DOUBLES_EQUAL(0, (m3 - answer).L2norm(), 0.0001);
}
RankTwoTensor
TensorMechanicsPlasticMeanCapTC::dflowPotential_dintnl(const RankTwoTensor & stress, Real intnl) const
{
  const Real tr = stress.trace();
  const Real t_str = tensile_strength(intnl);
  if (tr >= t_str)
    return RankTwoTensor();
  const Real c_str = compressive_strength(intnl);
  if (tr <= c_str)
    return RankTwoTensor();
  const Real dt = dtensile_strength(intnl);
  const Real dc = dcompressive_strength(intnl);
  return std::sin(M_PI * (tr - c_str) / (t_str - c_str)) * stress.dtrace() * M_PI / std::pow(t_str - c_str, 2) * ((tr - t_str) * dc - (tr - c_str) * dt);
}
示例#4
0
RankTwoEigenRoutinesTest::RankTwoEigenRoutinesTest()
{
  _m0 = RankTwoTensor(0, 0, 0, 0, 0, 0, 0, 0, 0);
  _m1 = RankTwoTensor(1, 0, 0, 0, 1, 0, 0, 0, 1);
  _m2 = RankTwoTensor(1, 0, 0, 0, 2, 0, 0, 0, 3);
  _m3 = RankTwoTensor(1, 2, 3, 2, -5, -6, 3, -6, 9);
  _m4 = RankTwoTensor(1, 0, 0, 0, 3, 0, 0, 0, 2);
  _m5 = RankTwoTensor(1, 0, 0, 0, 1, 0, 0, 0, 2);
  _m6 = RankTwoTensor(1, 0, 0, 0, 2, 0, 0, 0, 1);
  _m7 = RankTwoTensor(1, 0, 0, 0, 2, 0, 0, 0, 2);
  _m8 = RankTwoTensor(1, 1, 0, 1, 1, 0, 0, 0, 2); // has eigenvalues 0, 2 and 2
}
void
MultiPlasticityDebugger::fddyieldFunction_dstress(const RankTwoTensor & stress,
                                                  const std::vector<Real> & intnl,
                                                  std::vector<RankTwoTensor> & df_dstress)
{
  df_dstress.assign(_num_surfaces, RankTwoTensor());

  std::vector<bool> act;
  act.assign(_num_surfaces, true);

  Real ep = _fspb_debug_stress_change;
  RankTwoTensor stressep;
  std::vector<Real> fep, fep_minus;
  for (unsigned i = 0; i < 3; ++i)
    for (unsigned j = 0; j < 3; ++j)
    {
      stressep = stress;
      // do a central difference to attempt to capture discontinuities
      // such as those encountered in tensile and Mohr-Coulomb
      stressep(i, j) += ep / 2.0;
      yieldFunction(stressep, intnl, act, fep);
      stressep(i, j) -= ep;
      yieldFunction(stressep, intnl, act, fep_minus);
      for (unsigned surface = 0; surface < _num_surfaces; ++surface)
        df_dstress[surface](i, j) = (fep[surface] - fep_minus[surface]) / ep;
    }
}
示例#6
0
void
FiniteStrainPlasticBase::fddflowPotential_dintnl(const RankTwoTensor & stress, const std::vector<Real> & intnl, std::vector<std::vector<RankTwoTensor> > & dr_dintnl)
{
  dr_dintnl.resize(numberOfYieldFunctions());
  for (unsigned alpha = 0 ; alpha < numberOfYieldFunctions() ; ++alpha)
    dr_dintnl[alpha].assign(numberOfInternalParameters(), RankTwoTensor());

  std::vector<RankTwoTensor> origr;
  flowPotential(stress, intnl, origr);

  std::vector<Real> intnlep;
  intnlep.resize(numberOfInternalParameters());
  for (unsigned a = 0 ; a < numberOfInternalParameters() ; ++a)
    intnlep[a] = intnl[a];
  Real ep;
  std::vector<RankTwoTensor> rep;
  for (unsigned a = 0 ; a < numberOfInternalParameters() ; ++a)
  {
    ep = _fspb_debug_intnl_change[a];
    intnlep[a] += ep;
    flowPotential(stress, intnlep, rep);
    for (unsigned alpha = 0 ; alpha < numberOfYieldFunctions() ; ++alpha)
      dr_dintnl[alpha][a] = (rep[alpha] - origr[alpha])/ep;
    intnlep[a] -= ep;
  }
}
示例#7
0
void
FiniteStrainPlasticBase::calculateConstraints(const RankTwoTensor & stress, const std::vector<Real> & intnl_old, const std::vector<Real> & intnl, const std::vector<Real> & pm, const RankTwoTensor & delta_dp, std::vector<Real> & f, RankTwoTensor & epp, std::vector<Real> & ic)
{
  // yield functions
  yieldFunction(stress, intnl, f);


  // flow direction
  std::vector<RankTwoTensor> r;
  flowPotential(stress, intnl, r);

  epp = RankTwoTensor();
  for (unsigned alpha = 0 ; alpha < numberOfYieldFunctions() ; ++alpha)
    epp += pm[alpha]*r[alpha];
  epp -= delta_dp;


  // internal constraints
  std::vector<std::vector<Real> > h;
  hardPotential(stress, intnl, h);

  ic.resize(numberOfInternalParameters());
  for (unsigned a = 0 ; a < numberOfInternalParameters() ; ++a)
  {
    ic[a] = intnl[a] - intnl_old[a];
    for (unsigned alpha = 0 ; alpha < numberOfYieldFunctions() ; ++alpha)
      ic[a] += pm[alpha]*h[a][alpha];
  }
}
void
MultiPlasticityLinearSystem::calculateConstraints(const RankTwoTensor & stress,
                                                  const std::vector<Real> & intnl_old,
                                                  const std::vector<Real> & intnl,
                                                  const std::vector<Real> & pm,
                                                  const RankTwoTensor & delta_dp,
                                                  std::vector<Real> & f,
                                                  std::vector<RankTwoTensor> & r,
                                                  RankTwoTensor & epp,
                                                  std::vector<Real> & ic,
                                                  const std::vector<bool> & active)
{
  // see comments at the start of .h file

  mooseAssert(intnl_old.size() == _num_models,
              "Size of intnl_old is " << intnl_old.size()
                                      << " which is incorrect in calculateConstraints");
  mooseAssert(intnl.size() == _num_models,
              "Size of intnl is " << intnl.size() << " which is incorrect in calculateConstraints");
  mooseAssert(pm.size() == _num_surfaces,
              "Size of pm is " << pm.size() << " which is incorrect in calculateConstraints");
  mooseAssert(active.size() == _num_surfaces,
              "Size of active is " << active.size()
                                   << " which is incorrect in calculateConstraints");

  // yield functions
  yieldFunction(stress, intnl, active, f);

  // flow directions and "epp"
  flowPotential(stress, intnl, active, r);
  epp = RankTwoTensor();
  unsigned ind = 0;
  for (unsigned surface = 0; surface < _num_surfaces; ++surface)
    if (active[surface])
      epp += pm[surface] * r[ind++]; // note, even the deactivated_due_to_ld must get added in
  epp -= delta_dp;

  // internal constraints
  std::vector<Real> h;
  hardPotential(stress, intnl, active, h);
  ic.resize(0);
  ind = 0;
  std::vector<unsigned int> active_surfaces;
  std::vector<unsigned int>::iterator active_surface;
  for (unsigned model = 0; model < _num_models; ++model)
  {
    activeSurfaces(model, active, active_surfaces);
    if (active_surfaces.size() > 0)
    {
      // some surfaces are active in this model, so must form an internal constraint
      ic.push_back(intnl[model] - intnl_old[model]);
      for (active_surface = active_surfaces.begin(); active_surface != active_surfaces.end();
           ++active_surface)
        ic[ic.size() - 1] += pm[*active_surface] * h[ind++]; // we know the correct one is h[ind]
                                                             // since it was constructed in the same
                                                             // manner
    }
  }
}
RankTwoTensor
TensorMechanicsPlasticJ2::dyieldFunction_dstress(const RankTwoTensor & stress, Real /*intnl*/) const
{
  Real sII = stress.secondInvariant();
  if (sII == 0.0)
    return RankTwoTensor();
  else
    return 0.5 * std::sqrt(3.0 / sII) * stress.dsecondInvariant();
}
示例#10
0
RankTwoTensor
RankTwoTensor::dsin3Lode(const Real r0) const
{
  Real bar = secondInvariant();
  if (bar <= r0)
    return RankTwoTensor();
  else
    return -1.5 * std::sqrt(3.0) * (dthirdInvariant() / std::pow(bar, 1.5) - 1.5 * dsecondInvariant() * thirdInvariant() / std::pow(bar, 2.5));
}
示例#11
0
void
GolemMaterialH::computeQpProperties()
{
  _scaling_factor[_qp] = computeQpScaling();
  _fluid_density[_qp] = _fluid_density_uo->computeDensity(0.0, 0.0, _rho0_f);
  _fluid_viscosity[_qp] = _fluid_viscosity_uo->computeViscosity(0.0, 0.0, _mu0);
  _porosity[_qp] = _porosity_uo->computePorosity(_phi0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
  _permeability[_qp] =
      _permeability_uo->computePermeability(_k0, _phi0, _porosity[_qp], _scaling_factor[_qp]);
  GolemPropertiesH();
  if (_has_disp)
  {
    // Declare some property when this material is used for fractures or faults in a HM simulation
    (*_dH_kernel_dev)[_qp] = RankTwoTensor();
    (*_dH_kernel_dpf)[_qp] = RankTwoTensor();
    if (_fe_problem.isTransient())
    {
      (*_dH_kernel_time_dev)[_qp] = 0.0;
      (*_dH_kernel_time_dpf)[_qp] = 0.0;
    }
  }
}
示例#12
0
RankTwoTensorTest::RankTwoTensorTest()
{
  _m0 = RankTwoTensor(0, 0, 0, 0, 0, 0, 0, 0, 0);
  _m1 = RankTwoTensor(1, 0, 0, 0, 1, 0, 0, 0, 1);
  _m2 = RankTwoTensor(1, 0, 0, 0, 2, 0, 0, 0, 3);
  _m3 = RankTwoTensor(1, 2, 3, 2, -5, -6, 3, -6, 9);
  _unsymmetric0 = RankTwoTensor(1, 2, 3, -4, -5, -6, 7, 8, 9);
  _unsymmetric1 = RankTwoTensor(1, 2, 3, -4, -5, -6, 7, 8, 10);
}
void
CosseratLinearElasticMaterial::computeQpStrain()
{
    RankTwoTensor strain(_grad_disp_x[_qp], _grad_disp_y[_qp], _grad_disp_z[_qp]);
    RealVectorValue wc_vector((*_wc[0])[_qp], (*_wc[1])[_qp], (*_wc[2])[_qp]);

    for (unsigned i = 0; i < LIBMESH_DIM; ++i)
        for (unsigned j = 0; j < LIBMESH_DIM; ++j)
            for (unsigned k = 0; k < LIBMESH_DIM; ++k)
                strain(i, j) += PermutationTensor::eps(i, j, k) * wc_vector(k);

    _elastic_strain[_qp] = strain;

    _curvature[_qp] = RankTwoTensor((*_grad_wc[0])[_qp], (*_grad_wc[1])[_qp], (*_grad_wc[2])[_qp]);
}
RankTwoTensor
ComputeCappedWeakPlaneCosseratStress::dqdstress(const RankTwoTensor & stress) const
{
  RankTwoTensor deriv = RankTwoTensor();
  const Real q = std::sqrt(Utility::pow<2>(stress(0, 2)) + Utility::pow<2>(stress(1, 2)));
  if (q > 0.0)
  {
    deriv(0, 2) = stress(0, 2) / q;
    deriv(1, 2) = stress(1, 2) / q;
  }
  else
  {
    // derivative is not defined here.  For now i'll set:
    deriv(0, 2) = 1.0;
    deriv(1, 2) = 1.0;
  }
  return deriv;
}
TensorMechanicsPlasticWeakPlaneTensileN::TensorMechanicsPlasticWeakPlaneTensileN(const InputParameters & parameters) :
    TensorMechanicsPlasticWeakPlaneTensile(parameters),
    _input_n(getParam<RealVectorValue>("normal_vector")),
    _df_dsig(RankTwoTensor())
{
  // cannot check the following for all values of strength, but this is a start
  if (_strength.value(0) < 0)
    mooseError("Weak plane tensile strength must not be negative");
  if (_input_n.size() == 0)
     mooseError("Weak-plane normal vector must not have zero length");
   else
     _input_n /= _input_n.size();
  _rot = RotationMatrix::rotVecToZ(_input_n);

  for (unsigned i = 0 ; i < 3 ; ++i)
    for (unsigned j = 0 ; j < 3 ; ++j)
      _df_dsig(i, j) = _rot(2, i)*_rot(2, j);
}
void
ComputeCosseratSmallStrain::computeQpProperties()
{
  RankTwoTensor strain((*_grad_disp[0])[_qp], (*_grad_disp[1])[_qp], (*_grad_disp[2])[_qp]);
  RealVectorValue wc_vector((*_wc[0])[_qp], (*_wc[1])[_qp], (*_wc[2])[_qp]);

  for (unsigned i = 0; i < LIBMESH_DIM; ++i)
    for (unsigned j = 0; j < LIBMESH_DIM; ++j)
      for (unsigned k = 0; k < LIBMESH_DIM; ++k)
        strain(i, j) += PermutationTensor::eps(i, j, k) * wc_vector(k);

  _total_strain[_qp] = strain;

  _mechanical_strain[_qp] = strain;
  for (auto es : _eigenstrains)
    _mechanical_strain[_qp] -= (*es)[_qp];

  _curvature[_qp] = RankTwoTensor((*_grad_wc[0])[_qp], (*_grad_wc[1])[_qp], (*_grad_wc[2])[_qp]);
}
void
CappedDruckerPragerCosseratStressUpdate::setStressAfterReturn(const RankTwoTensor & stress_trial,
                                                              Real p_ok,
                                                              Real q_ok,
                                                              Real /*gaE*/,
                                                              const std::vector<Real> & /*intnl*/,
                                                              const yieldAndFlow & /*smoothed_q*/,
                                                              const RankFourTensor & /*Eijkl*/,
                                                              RankTwoTensor & stress) const
{
  // symm_stress is the symmetric part of the stress tensor.
  // symm_stress = (s_ij+s_ji)/2 + de_ij tr(stress) / 3
  //             = q / q_trial * (s_ij^trial+s_ji^trial)/2 + de_ij p / 3
  //             = q / q_trial * (symm_stress_ij^trial - de_ij tr(stress^trial) / 3) + de_ij p / 3
  const Real p_trial = stress_trial.trace();
  RankTwoTensor symm_stress = RankTwoTensor(RankTwoTensor::initIdentity) / 3.0 *
                              (p_ok - (_in_q_trial == 0.0 ? 0.0 : p_trial * q_ok / _in_q_trial));
  if (_in_q_trial > 0)
    symm_stress += q_ok / _in_q_trial * 0.5 * (stress_trial + stress_trial.transpose());
  stress = symm_stress + 0.5 * (stress_trial - stress_trial.transpose());
}
示例#18
0
void
FiniteStrainPlasticBase::fddyieldFunction_dstress(const RankTwoTensor & stress, const std::vector<Real> & intnl, std::vector<RankTwoTensor> & df_dstress)
{
  df_dstress.assign(numberOfYieldFunctions(), RankTwoTensor());

  Real ep = _fspb_debug_stress_change;
  RankTwoTensor stressep;
  std::vector<Real> fep, fep_minus;
  for (unsigned i = 0 ; i < 3 ; ++i)
    for (unsigned j = 0 ; j < 3 ; ++j)
    {
      stressep = stress;
      // do a central difference to attempt to capture discontinuities
      // such as those encountered in tensile and Mohr-Coulomb
      stressep(i, j) += ep/2.0;
      yieldFunction(stressep, intnl, fep);
      stressep(i, j) -= ep;
      yieldFunction(stressep, intnl, fep_minus);
      for (unsigned alpha = 0 ; alpha < numberOfYieldFunctions() ; ++alpha)
        df_dstress[alpha](i, j) = (fep[alpha] - fep_minus[alpha])/ep;
    }
}
RankTwoTensor
TensorMechanicsPlasticTensile::dflowPotential_dintnl(const RankTwoTensor & /*stress*/,
                                                     Real /*intnl*/) const
{
  return RankTwoTensor();
}
示例#20
0
RankTwoTensor
TensorMechanicsPlasticModel::dhardPotential_dstress(const RankTwoTensor & /*stress*/, Real /*intnl*/) const
{
  return RankTwoTensor();
}
bool
TensorMechanicsPlasticMohrCoulombMulti::doReturnMap(const RankTwoTensor & trial_stress, Real intnl_old, const RankFourTensor & E_ijkl,
                                                    Real ep_plastic_tolerance, RankTwoTensor & returned_stress, Real & returned_intnl,
                                                    std::vector<Real> & dpm, RankTwoTensor & delta_dp, std::vector<Real> & yf,
                                                    bool & trial_stress_inadmissible) const
{
  mooseAssert(dpm.size() == 6, "TensorMechanicsPlasticMohrCoulombMulti size of dpm should be 6 but it is " << dpm.size());

  std::vector<Real> eigvals;
  RankTwoTensor eigvecs;
  trial_stress.symmetricEigenvaluesEigenvectors(eigvals, eigvecs);
  eigvals[0] += _shift;
  eigvals[2] -= _shift;

  Real sinphi = std::sin(phi(intnl_old));
  Real cosphi = std::cos(phi(intnl_old));
  Real coh = cohesion(intnl_old);
  Real cohcos = coh*cosphi;

  yieldFunctionEigvals(eigvals[0], eigvals[1], eigvals[2], sinphi, cohcos, yf);

  if (yf[0] <= _f_tol && yf[1] <= _f_tol && yf[2] <= _f_tol && yf[3] <= _f_tol && yf[4] <= _f_tol && yf[5] <= _f_tol)
  {
    // purely elastic (trial_stress, intnl_old)
    trial_stress_inadmissible = false;
    return true;
  }

  trial_stress_inadmissible = true;
  delta_dp.zero();
  returned_stress = RankTwoTensor();

  // these are the normals to the 6 yield surfaces, which are const because of the assumption of no psi hardening
  std::vector<RealVectorValue> norm(6);
  const Real sinpsi = std::sin(psi(intnl_old));
  const Real oneminus = 0.5*(1 - sinpsi);
  const Real oneplus = 0.5*(1 + sinpsi);
  norm[0](0) = oneplus; norm[0](1) = -oneminus; norm[0](2) = 0;
  norm[1](0) = -oneminus; norm[1](1) = oneplus; norm[1](2) = 0;
  norm[2](0) = oneplus; norm[2](1) = 0; norm[2](2) = -oneminus;
  norm[3](0) = -oneminus; norm[3](1) = 0; norm[3](2) = oneplus;
  norm[4](0) = 0; norm[4](1) = oneplus; norm[4](2) = -oneminus;
  norm[5](0) = 0; norm[5](1) = -oneminus; norm[5](2) = oneplus;

  // the flow directions are these norm multiplied by Eijkl.
  // I call the flow directions "n".
  // In the following I assume that the Eijkl is
  // for an isotropic situation.  Then I don't have to
  // rotate to the principal-stress frame, and i don't
  // have to worry about strange off-diagonal things
  std::vector<RealVectorValue> n(6);
  for (unsigned ys = 0; ys < 6; ++ys)
    for (unsigned i = 0; i < 3; ++i)
      for (unsigned j = 0; j < 3; ++j)
        n[ys](i) += E_ijkl(i,i,j,j)*norm[ys](j);
  const Real mag_E = E_ijkl(0, 0, 0, 0);

  // With non-zero Poisson's ratio and hardening
  // it is not computationally cheap to know whether
  // the trial stress will return to the tip, edge,
  // or plane.  The following at least
  // gives a not-completely-stupid guess
  // trial_order[0] = type of return to try first
  // trial_order[1] = type of return to try second
  // trial_order[2] = type of return to try third
  // trial_order[3] = type of return to try fourth
  // trial_order[4] = type of return to try fifth
  // In the following the "binary" stuff indicates the
  // deactive (0) and active (1) surfaces, eg
  // 110100 means that surfaces 0, 1 and 3 are active
  // and 2, 4 and 5 are deactive
  const unsigned int number_of_return_paths = 5;
  std::vector<int> trial_order(number_of_return_paths);
  if (yf[1] > _f_tol && yf[3] > _f_tol && yf[5] > _f_tol)
  {
    trial_order[0] = tip110100;
    trial_order[1] = edge010100;
    trial_order[2] = plane000100;
    trial_order[3] = edge000101;
    trial_order[4] = tip010101;
  }
  else if (yf[1] <= _f_tol && yf[3] > _f_tol && yf[5] > _f_tol)
  {
    trial_order[0] = edge000101;
    trial_order[1] = plane000100;
    trial_order[2] = tip110100;
    trial_order[3] = tip010101;
    trial_order[4] = edge010100;
  }
  else if (yf[1] <= _f_tol && yf[3] > _f_tol && yf[5] <= _f_tol)
  {
    trial_order[0] = plane000100;
    trial_order[1] = edge000101;
    trial_order[2] = edge010100;
    trial_order[3] = tip110100;
    trial_order[4] = tip010101;
  }
  else
  {
    trial_order[0] = edge010100;
    trial_order[1] = plane000100;
    trial_order[2] = edge000101;
    trial_order[3] = tip110100;
    trial_order[4] = tip010101;
  }

  unsigned trial;
  bool nr_converged = false;
  bool kt_success = false;
  std::vector<RealVectorValue> ntip(3);
  std::vector<Real> dpmtip(3);

  for (trial = 0; trial < number_of_return_paths; ++trial)
  {
    switch (trial_order[trial])
    {
      case tip110100:
        for (unsigned int i = 0; i < 3; ++i)
        {
          ntip[0](i) = n[0](i);
          ntip[1](i) = n[1](i);
          ntip[2](i) = n[3](i);
        }
        kt_success = returnTip(eigvals, ntip, dpmtip, returned_stress, intnl_old, sinphi, cohcos, 0, nr_converged, ep_plastic_tolerance, yf);
        if (nr_converged && kt_success)
        {
          dpm[0] = dpmtip[0];
          dpm[1] = dpmtip[1];
          dpm[3] = dpmtip[2];
          dpm[2] = dpm[4] = dpm[5] = 0;
        }
        break;

      case tip010101:
        for (unsigned int i = 0; i < 3; ++i)
        {
          ntip[0](i) = n[1](i);
          ntip[1](i) = n[3](i);
          ntip[2](i) = n[5](i);
        }
        kt_success = returnTip(eigvals, ntip, dpmtip, returned_stress, intnl_old, sinphi, cohcos, 0, nr_converged, ep_plastic_tolerance, yf);
        if (nr_converged && kt_success)
        {
          dpm[1] = dpmtip[0];
          dpm[3] = dpmtip[1];
          dpm[5] = dpmtip[2];
          dpm[0] = dpm[2] = dpm[4] = 0;
        }
        break;

      case edge000101:
        kt_success = returnEdge000101(eigvals, n, dpm, returned_stress, intnl_old, sinphi, cohcos, 0, mag_E, nr_converged, ep_plastic_tolerance, yf);
        break;

      case edge010100:
        kt_success = returnEdge010100(eigvals, n, dpm, returned_stress, intnl_old, sinphi, cohcos, 0, mag_E, nr_converged, ep_plastic_tolerance, yf);
        break;

      case plane000100:
        kt_success = returnPlane(eigvals, n, dpm, returned_stress, intnl_old, sinphi, cohcos, 0, nr_converged, ep_plastic_tolerance, yf);
        break;
    }

    if (nr_converged && kt_success)
      break;
  }

  if (trial == number_of_return_paths)
  {
    sinphi = std::sin(phi(intnl_old));
    cosphi = std::cos(phi(intnl_old));
    coh = cohesion(intnl_old);
    cohcos = coh*cosphi;
    yieldFunctionEigvals(eigvals[0], eigvals[1], eigvals[2], sinphi, cohcos, yf);
    Moose::err << "Trial stress = \n";
    trial_stress.print(Moose::err);
    Moose::err << "which has eigenvalues = " << eigvals[0] << " " << eigvals[1] << " " << eigvals[2] << "\n";
    Moose::err << "and yield functions = " << yf[0] << " " << yf[1] << " " << yf[2] << " " << yf[3] << " " << yf[4] << " " << yf[5] << "\n";
    Moose::err << "Internal parameter = " << intnl_old << "\n";
    mooseError("TensorMechanicsPlasticMohrCoulombMulti: FAILURE!  You probably need to implement a line search if your hardening is too severe, or you need to tune your tolerances (eg, yield_function_tolerance should be a little smaller than (young modulus)*ep_plastic_tolerance).\n");
    return false;
  }

  // success

  returned_intnl = intnl_old;
  for (unsigned i = 0; i < 6; ++i)
    returned_intnl += dpm[i];
  for (unsigned i = 0; i < 6; ++i)
    for (unsigned j = 0; j < 3; ++j)
      delta_dp(j, j) += dpm[i]*norm[i](j);
  returned_stress = eigvecs*returned_stress*(eigvecs.transpose());
  delta_dp = eigvecs*delta_dp*(eigvecs.transpose());
  return true;
}
void
CappedDruckerPragerCosseratStressUpdate::consistentTangentOperator(
    const RankTwoTensor & /*stress_trial*/,
    Real /*p_trial*/,
    Real /*q_trial*/,
    const RankTwoTensor & stress,
    Real /*p*/,
    Real q,
    Real gaE,
    const yieldAndFlow & smoothed_q,
    const RankFourTensor & Eijkl,
    bool compute_full_tangent_operator,
    RankFourTensor & cto) const
{
  if (!compute_full_tangent_operator)
  {
    cto = Eijkl;
    return;
  }

  RankFourTensor EAijkl;
  for (unsigned i = 0; i < _tensor_dimensionality; ++i)
    for (unsigned j = 0; j < _tensor_dimensionality; ++j)
      for (unsigned k = 0; k < _tensor_dimensionality; ++k)
        for (unsigned l = 0; l < _tensor_dimensionality; ++l)
        {
          cto(i, j, k, l) = 0.5 * (Eijkl(i, j, k, l) + Eijkl(j, i, k, l));
          EAijkl(i, j, k, l) = 0.5 * (Eijkl(i, j, k, l) - Eijkl(j, i, k, l));
        }

  const RankTwoTensor s_over_q =
      (q == 0.0 ? RankTwoTensor()
                : (0.5 * (stress + stress.transpose()) -
                   stress.trace() * RankTwoTensor(RankTwoTensor::initIdentity) / 3.0) /
                      q);
  const RankTwoTensor E_s_over_q = Eijkl.innerProductTranspose(s_over_q); // not symmetric in kl
  const RankTwoTensor Ekl =
      RankTwoTensor(RankTwoTensor::initIdentity).initialContraction(Eijkl); // symmetric in kl

  for (unsigned i = 0; i < _tensor_dimensionality; ++i)
    for (unsigned j = 0; j < _tensor_dimensionality; ++j)
      for (unsigned k = 0; k < _tensor_dimensionality; ++k)
        for (unsigned l = 0; l < _tensor_dimensionality; ++l)
        {
          cto(i, j, k, l) -= (i == j) * (1.0 / 3.0) *
                             (Ekl(k, l) * (1.0 - _dp_dpt) + 0.5 * E_s_over_q(k, l) * (-_dp_dqt));
          cto(i, j, k, l) -=
              s_over_q(i, j) * (Ekl(k, l) * (-_dq_dpt) + 0.5 * E_s_over_q(k, l) * (1.0 - _dq_dqt));
        }

  if (smoothed_q.dg[1] != 0.0)
  {
    const RankFourTensor Tijab = _Ehost * (gaE / _Epp) * smoothed_q.dg[1] * d2qdstress2(stress);
    RankFourTensor inv = RankFourTensor(RankFourTensor::initIdentitySymmetricFour) + Tijab;
    try
    {
      inv = inv.transposeMajor().invSymm();
    }
    catch (const MooseException & e)
    {
      // Cannot form the inverse, so probably at some degenerate place in stress space.
      // Just return with the "best estimate" of the cto.
      mooseWarning("CappedDruckerPragerCosseratStressUpdate: Cannot invert 1+T in consistent "
                   "tangent operator computation at quadpoint ",
                   _qp,
                   " of element ",
                   _current_elem->id());
      return;
    }
    cto = (cto.transposeMajor() * inv).transposeMajor();
  }
  cto += EAijkl;
}
void
TensorMechanicsPlasticTensileMulti::dflowPotential_dintnlV(const RankTwoTensor & /*stress*/, const Real & /*intnl*/, std::vector<RankTwoTensor> & dr_dintnl) const
{
  dr_dintnl.assign(3, RankTwoTensor());
}
void
TensorMechanicsPlasticTensileMulti::activeConstraints(const std::vector<Real> & f, const RankTwoTensor & stress, const Real & intnl, const RankFourTensor & Eijkl, std::vector<bool> & act, RankTwoTensor & returned_stress) const
{
  act.assign(3, false);

  if (f[0] <= _f_tol && f[1] <= _f_tol && f[2] <= _f_tol)
  {
    returned_stress = stress;
    return;
  }

  returned_stress = RankTwoTensor();

  std::vector<Real> eigvals;
  RankTwoTensor eigvecs;
  stress.symmetricEigenvaluesEigenvectors(eigvals, eigvecs);
  eigvals[0] += _shift;
  eigvals[2] -= _shift;

  Real str = tensile_strength(intnl);
  std::vector<Real> v(3);
  v[0] = eigvals[0] - str;
  v[1] = eigvals[1] - str;
  v[2] = eigvals[2] - str;

  // these are the normals to the 3 yield surfaces
  std::vector<std::vector<Real> > n(3);
  n[0].resize(3);
  n[0][0] = 1 ; n[0][1] = 0 ; n[0][2] = 0;
  n[1].resize(3);
  n[1][0] = 0 ; n[1][1] = 1 ; n[1][2] = 0;
  n[2].resize(3);
  n[2][0] = 0 ; n[2][1] = 0 ; n[2][2] = 1;

  // the flow directions are these n multiplied by Eijkl.
  // I re-use the name "n" for the flow directions
  // In the following I assume that the Eijkl is
  // for an isotropic situation.  This is the most
  // common when using TensileMulti, and remember
  // that the returned_stress need not be perfect
  // anyway.
  // I divide by E(0,0,0,0) so the n remain of order 1
  Real ratio = Eijkl(1,1,0,0)/Eijkl(0,0,0,0);
  n[0][1] = n[0][2] = ratio;
  n[1][0] = n[1][2] = ratio;
  n[2][0] = n[2][1] = ratio;


  // 111 (tip)
  // For tip-return to satisfy Kuhn-Tucker, we need
  // v = alpha*n[0] + beta*n[1] * gamma*n[2]
  // with alpha, beta, and gamma all being non-negative (they are
  // the plasticity multipliers)
  Real denom = triple(n[0], n[1], n[2]);
  if (triple(v, n[0], n[1])/denom >= 0 && triple(v, n[1], n[2])/denom >= 0 && triple(v, n[2], n[0])/denom >= 0)
  {
    act[0] = act[1] = act[2] = true;
    returned_stress(0, 0) = returned_stress(1, 1) = returned_stress(2, 2) = str;
    returned_stress = eigvecs*returned_stress*(eigvecs.transpose());
    return;
  }

  // 011 (edge)
  std::vector<Real> n1xn2(3);
  n1xn2[0] = n[1][1]*n[2][2] - n[1][2]*n[2][1];
  n1xn2[1] = n[1][2]*n[2][0] - n[1][0]*n[2][2];
  n1xn2[2] = n[1][0]*n[2][1] - n[1][1]*n[2][0];
  // work out the point to which we would return, "a".  It is defined by
  // f1 = 0 = f2, and that (p - a).(n1 x n2) = 0, where "p" is the
  // starting position (p = eigvals).
  // In the following a = (a0, str, str)
  Real pdotn1xn2 = dot(eigvals, n1xn2);
  Real a0 = (-str*n1xn2[1] - str*n1xn2[2] + pdotn1xn2)/n1xn2[0];
  // we need p - a = alpha*n1 + beta*n2, where alpha and beta are non-negative
  // for Kuhn-Tucker to be satisfied
  std::vector<Real> pminusa(3);
  pminusa[0] = eigvals[0] - a0;
  pminusa[1] = v[1];
  pminusa[2] = v[2];
  if ((pminusa[2] - pminusa[0])/(1.0 - ratio) >= 0 && (pminusa[1] - pminusa[0])/(1.0 - ratio) >= 0)
  {
    returned_stress(0, 0) = a0;
    returned_stress(1, 1) = str;
    returned_stress(2, 2) = str;
    returned_stress = eigvecs*returned_stress*(eigvecs.transpose());
    act[1] = act[2] = true;
    return;
  }

  // 001 (plane)
  // the returned point, "a", is defined by f2=0 and
  // a = p - alpha*n2
  Real alpha = (eigvals[2] - str)/n[2][2];
  act[2] = true;
  returned_stress(0, 0) = eigvals[0] - alpha*n[2][0];
  returned_stress(1, 1) = eigvals[1] - alpha*n[2][1];
  returned_stress(2, 2) = str;
  returned_stress = eigvecs*returned_stress*(eigvecs.transpose());
  return;
}
RankTwoTensor
TensorMechanicsPlasticSimpleTester::dflowPotential_dintnl(const RankTwoTensor & /*stress*/, const Real & /*intnl*/) const
{
  return RankTwoTensor();
}
示例#26
0
void
GolemMaterialTH::computeQpProperties()
{
  if (_has_lumped_mass_matrix)
  {
    (*_node_number)[_qp] = nearest();
    (*_nodal_temp)[_qp] = (*_nodal_temp_var)[(*_node_number)[_qp]];
    (*_nodal_temp_old)[_qp] = (*_nodal_temp_var_old)[(*_node_number)[_qp]];
    (*_nodal_pf)[_qp] = (*_nodal_pf_var)[(*_node_number)[_qp]];
    if (_has_boussinesq)
      (*_nodal_pf_old)[_qp] = (*_nodal_pf_var_old)[(*_node_number)[_qp]];
  }
  _scaling_factor[_qp] = computeQpScaling();
  computeDensity();
  computeViscosity();
  _porosity[_qp] = _porosity_uo->computePorosity(_phi0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
  _permeability[_qp] =
      _permeability_uo->computePermeability(_k0, _phi0, _porosity[_qp], _scaling_factor[_qp]);
  // GolemKernelT related properties
  _T_kernel_diff[_qp] = _porosity[_qp] * _lambda_f + (1.0 - _porosity[_qp]) * _lambda_s;
  if (_has_T_source_sink)
    (*_T_kernel_source)[_qp] = -1.0 * _T_source_sink;
  // GolemKernelH related properties
  GolemPropertiesH();
  // GolemkernelTH related poperties
  _TH_kernel[_qp] = -_H_kernel[_qp] * _fluid_density[_qp] * _c_f;
  if (_fe_problem.isTransient())
  {
    // Correct H_kernel_time
    if (_drho_dpf[_qp] != 0.0)
      (*_H_kernel_time)[_qp] = (_porosity[_qp] * _drho_dpf[_qp]) / _fluid_density[_qp];
    (*_T_kernel_time)[_qp] =
        _porosity[_qp] * _fluid_density[_qp] * _c_f + (1.0 - _porosity[_qp]) * _rho0_s * _c_s;
  }
  // Properties derivatives
  // H_kernel derivatives
  (*_dH_kernel_dpf)[_qp] = -_H_kernel[_qp] * _dmu_dpf[_qp] / _fluid_viscosity[_qp];
  _dH_kernel_dT[_qp] = -_H_kernel[_qp] * _dmu_dT[_qp] / _fluid_viscosity[_qp];
  // H_kernel_grav derivatives
  _dH_kernel_grav_dpf[_qp] = -_drho_dpf[_qp] * _gravity;
  _dH_kernel_grav_dT[_qp] = -_drho_dT[_qp] * _gravity;
  if (_fe_problem.isTransient())
  {
    // T_kernel_time
    (*_dT_kernel_time_dpf)[_qp] = _drho_dpf[_qp] * _porosity[_qp] * _c_f;
    (*_dT_kernel_time_dT)[_qp] = _drho_dT[_qp] * _porosity[_qp] * _c_f;
  }
  // TH_kernel derivatives
  _dTH_kernel_dpf[_qp] = -(_fluid_density[_qp] * _c_f * (*_dH_kernel_dpf)[_qp] +
                           _H_kernel[_qp] * _c_f * _drho_dpf[_qp]);
  _dTH_kernel_dT[_qp] =
      -(_fluid_density[_qp] * _c_f * _dH_kernel_dT[_qp] + _H_kernel[_qp] * _c_f * _drho_dT[_qp]);
  if (_has_SUPG_upwind)
    computeQpSUPG();
  if (_has_disp)
  {
    // Declare some property when this material is used for fractures or faults in a THM simulation
    (*_dH_kernel_dev)[_qp] = RankTwoTensor();
    (*_dT_kernel_diff_dev)[_qp] = 0.0;
    (*_dT_kernel_diff_dpf)[_qp] = 0.0;
    (*_dT_kernel_diff_dT)[_qp] = 0.0;
    if (_fe_problem.isTransient())
    {
      (*_dT_kernel_time_dev)[_qp] = 0.0;
      (*_dH_kernel_time_dev)[_qp] = 0.0;
      (*_dH_kernel_time_dpf)[_qp] = 0.0;
      (*_dH_kernel_time_dT)[_qp] = 0.0;
    }
  }
}
示例#27
0
RankTwoTensor
RankTwoTensor::dtrace() const
{
  return RankTwoTensor(1, 0, 0, 0, 1, 0, 0, 0, 1);
}
RankTwoTensor
TensorMechanicsPlasticModel::dyieldFunction_dstress(const RankTwoTensor & /*stress*/, const Real & /*intnl*/) const
{
  return RankTwoTensor();
}
示例#29
0
void
MultiPlasticityLinearSystem::calculateJacobian(const RankTwoTensor & stress, const std::vector<Real> & intnl, const std::vector<Real> & pm, const RankFourTensor & E_inv, const std::vector<bool> & active, const std::vector<bool> & deactivated_due_to_ld, std::vector<std::vector<Real> > & jac)
{
  // see comments at the start of .h file

  mooseAssert(intnl.size() == _num_models, "Size of intnl is " << intnl.size() << " which is incorrect in calculateJacobian");
  mooseAssert(pm.size() == _num_surfaces, "Size of pm is " << pm.size() << " which is incorrect in calculateJacobian");
  mooseAssert(active.size() == _num_surfaces, "Size of active is " << active.size() << " which is incorrect in calculateJacobian");
  mooseAssert(deactivated_due_to_ld.size() == _num_surfaces, "Size of deactivated_due_to_ld is " << deactivated_due_to_ld.size() << " which is incorrect in calculateJacobian");


  unsigned ind = 0;
  unsigned active_surface_ind = 0;


  std::vector<bool> active_surface(_num_surfaces); // active and not deactivated_due_to_ld
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
    active_surface[surface] = (active[surface] && !deactivated_due_to_ld[surface]);
  unsigned num_active_surface = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
    if (active_surface[surface])
      num_active_surface++;

  std::vector<bool> active_model(_num_models); // whether a model has surfaces that are active and not deactivated_due_to_ld
  for (unsigned model = 0 ; model < _num_models ; ++model)
    active_model[model] = anyActiveSurfaces(model, active_surface);

  unsigned num_active_model = 0;
  for (unsigned model = 0 ; model < _num_models ; ++model)
    if (active_model[model])
      num_active_model++;

  ind = 0;
  std::vector<unsigned int> active_model_index(_num_models);
  for (unsigned model = 0 ; model < _num_models ; ++model)
    if (active_model[model])
      active_model_index[model] = ind++;
    else
      active_model_index[model] = _num_models+1; // just a dummy, that will probably cause a crash if something goes wrong



  std::vector<RankTwoTensor> df_dstress;
  dyieldFunction_dstress(stress, intnl, active_surface, df_dstress);

  std::vector<Real> df_dintnl;
  dyieldFunction_dintnl(stress, intnl, active_surface, df_dintnl);

  std::vector<RankTwoTensor> r;
  flowPotential(stress, intnl, active, r);

  std::vector<RankFourTensor> dr_dstress;
  dflowPotential_dstress(stress, intnl, active, dr_dstress);

  std::vector<RankTwoTensor> dr_dintnl;
  dflowPotential_dintnl(stress, intnl, active, dr_dintnl);

  std::vector<Real> h;
  hardPotential(stress, intnl, active, h);

  std::vector<RankTwoTensor> dh_dstress;
  dhardPotential_dstress(stress, intnl, active, dh_dstress);

  std::vector<Real> dh_dintnl;
  dhardPotential_dintnl(stress, intnl, active, dh_dintnl);




  // d(epp)/dstress = sum_{active alpha} pm[alpha]*dr_dstress
  RankFourTensor depp_dstress;
  ind = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
    if (active[surface]) // includes deactivated_due_to_ld
      depp_dstress += pm[surface]*dr_dstress[ind++];
  depp_dstress += E_inv;

  // d(epp)/dpm_{active_surface_index} = r_{active_surface_index}
  std::vector<RankTwoTensor> depp_dpm;
  depp_dpm.resize(num_active_surface);
  ind = 0;
  active_surface_ind = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
  {
    if (active[surface])
    {
      if (active_surface[surface]) // do not include the deactived_due_to_ld, since their pm are not dofs in the NR
        depp_dpm[active_surface_ind++] = r[ind];
      ind++;
    }
  }

  // d(epp)/dintnl_{active_model_index} = sum(pm[asdf]*dr_dintnl[fdsa])
  std::vector<RankTwoTensor> depp_dintnl;
  depp_dintnl.assign(num_active_model, RankTwoTensor());
  ind = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
  {
    if (active[surface])
    {
      unsigned int model_num = modelNumber(surface);
      if (active_model[model_num]) // only include models with surfaces which are still active after deactivated_due_to_ld
        depp_dintnl[active_model_index[model_num]] += pm[surface]*dr_dintnl[ind];
      ind++;
    }
  }


  // df_dstress has been calculated above
  // df_dpm is always zero
  // df_dintnl has been calculated above, but only the active_surface+active_model stuff needs to be included in Jacobian: see below

  std::vector<RankTwoTensor> dic_dstress;
  dic_dstress.assign(num_active_model, RankTwoTensor());
  ind = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
  {
    if (active[surface])
    {
      unsigned int model_num = modelNumber(surface);
      if (active_model[model_num]) // only include ic for models with active_surface (ie, if model only contains deactivated_due_to_ld don't include it)
        dic_dstress[active_model_index[model_num]] += pm[surface]*dh_dstress[ind];
      ind++;
    }
  }


  std::vector<std::vector<Real> > dic_dpm;
  dic_dpm.resize(num_active_model);
  ind = 0;
  active_surface_ind = 0;
  for (unsigned model = 0 ; model < num_active_model ; ++model)
    dic_dpm[model].assign(num_active_surface, 0);
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
  {
    if (active[surface])
    {
      if (active_surface[surface]) // only take derivs wrt active-but-not-deactivated_due_to_ld pm
      {
        unsigned int model_num = modelNumber(surface);
        // if (active_model[model_num]) // do not need this check as if the surface has active_surface, the model must be deemed active!
          dic_dpm[active_model_index[model_num]][active_surface_ind] = h[ind];
        active_surface_ind++;
      }
      ind++;
    }
  }


  std::vector<std::vector<Real> > dic_dintnl;
  dic_dintnl.resize(num_active_model);
  for (unsigned model = 0 ; model < num_active_model ; ++model)
  {
    dic_dintnl[model].assign(num_active_model, 0);
    dic_dintnl[model][model] = 1; // deriv wrt internal parameter
  }
  ind = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
  {
    if (active[surface])
    {
      unsigned int model_num = modelNumber(surface);
      if (active_model[model_num]) // only the models that contain surfaces that are still active after deactivation_due_to_ld
        dic_dintnl[active_model_index[model_num]][active_model_index[model_num]] += pm[surface]*dh_dintnl[ind];
      ind++;
    }
  }



  unsigned int dim = 3;
  unsigned int system_size = 6 + num_active_surface + num_active_model; // "6" comes from symmeterizing epp
  jac.resize(system_size);
  for (unsigned i = 0 ; i < system_size ; ++i)
    jac[i].assign(system_size, 0);

  unsigned int row_num = 0;
  unsigned int col_num = 0;
  for (unsigned i = 0 ; i < dim ; ++i)
    for (unsigned j = 0 ; j <= i ; ++j)
    {
      for (unsigned k = 0 ; k < dim ; ++k)
        for (unsigned l = 0 ; l <= k ; ++l)
          jac[col_num][row_num++] = depp_dstress(i, j, k, l) + (k != l ? depp_dstress(i, j, l, k) : 0); // extra part is needed because i assume dstress(i, j) = dstress(j, i)
      for (unsigned surface = 0 ; surface < num_active_surface ; ++surface)
        jac[col_num][row_num++] = depp_dpm[surface](i, j);
      for (unsigned a = 0 ; a < num_active_model ; ++a)
        jac[col_num][row_num++] = depp_dintnl[a](i, j);
      row_num = 0;
      col_num++;
    }

  ind = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
    if (active_surface[surface])
    {
      for (unsigned k = 0 ; k < dim ; ++k)
        for (unsigned l = 0 ; l <= k ; ++l)
        jac[col_num][row_num++] = df_dstress[ind](k, l) + (k != l ? df_dstress[ind](l, k) : 0); // extra part is needed because i assume dstress(i, j) = dstress(j, i)
      for (unsigned beta = 0 ; beta < num_active_surface ; ++beta)
        jac[col_num][row_num++] = 0; // df_dpm
      for (unsigned model = 0 ; model < _num_models ; ++model)
        if (active_model[model]) // only use df_dintnl for models in active_model
        {
          if (modelNumber(surface) == model)
            jac[col_num][row_num++] = df_dintnl[ind];
          else
            jac[col_num][row_num++] = 0;
        }
      ind++;
      row_num = 0;
      col_num++;
    }

  for (unsigned a = 0 ; a < num_active_model ; ++a)
  {
    for (unsigned k = 0 ; k < dim ; ++k)
      for (unsigned l = 0 ; l <= k ; ++l)
        jac[col_num][row_num++] = dic_dstress[a](k, l) + (k != l ? dic_dstress[a](l, k) : 0); // extra part is needed because i assume dstress(i, j) = dstress(j, i)
    for (unsigned alpha = 0 ; alpha < num_active_surface ; ++alpha)
      jac[col_num][row_num++] = dic_dpm[a][alpha];
    for (unsigned b = 0 ; b < num_active_model ; ++b)
      jac[col_num][row_num++] = dic_dintnl[a][b];
    row_num = 0;
    col_num++;
  }

  mooseAssert(col_num == system_size, "Incorrect filling of cols in Jacobian");
}
RankTwoTensor
TensorMechanicsPlasticModel::flowPotential(const RankTwoTensor & /*stress*/, const Real & /*intnl*/) const
{
  return RankTwoTensor();
}