コード例 #1
0
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;
}
コード例 #2
0
void
TensorMechanicsPlasticMohrCoulombMulti::activeConstraints(const std::vector<Real> & /*f*/, const RankTwoTensor & stress, const Real & intnl, std::vector<bool> & act) const
{
  act.assign(6, false);

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

  Real sinphi = std::sin(phi(intnl));
  Real cosphi = std::cos(phi(intnl));
  Real coh = cohesion(intnl);
  Real cohcot = coh*cosphi/sinphi;

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

  // naively there are lots of different combinations
  // to try.  Eg, there are 6 yield surfaces, and so
  // for returning-to-the-tip, there are 6*5*4 possible
  // combinations of 3 yield functions that we could try.
  // However, with the constraint v0<=v1<=v2, and symmetry,
  // the following combinations of act are checked:
  // 110100 (tip) (about 43%)
  // 010101 (tip) (about 1%)
  // 010100 (edge) (about 22%)
  // 000101 (edge) (about 22%)
  // 000100 (plane) (about 12%)
  // Some other "tip" combinations are tried by
  // FiniteStrainMultiPlasticity, in about 0.001% of cases,
  // but these are not work checking.

  // these are the normals to the 6 yield surfaces (flow directions)
  std::vector<std::vector<Real> > n(6);
  Real sinpsi = std::sin(psi(intnl));
  Real oneminus = 1 - sinpsi;
  Real oneplus = 1 + sinpsi;
  n[0].resize(3);
  n[0][0] = oneplus ; n[0][1] = -oneminus ; n[0][2] = 0;
  n[1].resize(3);
  n[1][0] = -oneminus ; n[1][1] = oneplus ; n[1][2] = 0;
  n[2].resize(3);
  n[2][0] = oneplus ; n[2][1] = 0 ; n[2][2] = -oneminus;
  n[3].resize(3);
  n[3][0] = -oneminus ; n[3][1] = 0 ; n[3][2] = oneplus;
  n[4].resize(3);
  n[4][0] = 0 ; n[4][1] = oneplus ; n[4][2] = -oneminus;
  n[5].resize(3);
  n[5][0] = 0 ; n[5][1] = -oneminus ; n[5][2] = oneplus;

  // Check for return to the tip.
  // For tip-return to satisfy Kuhn-Tucker we need
  // v = a*n[a] + b*n[b] + c*n[c]
  // with a, b, and c all being non-negative (they are
  // the plasticity multipliers)

  Real denom;

  // 110100 (tip)
  denom = triple(n[0], n[1], n[3]);
  if (triple(v, n[0], n[1])/denom >= 0 && triple(v, n[1], n[3])/denom >= 0 && triple(v, n[3], n[0])/denom >= 0)
  {
    act[0] = act[1] = act[3] = true;
    return;
  }

  // 010101 (tip)
  denom = triple(n[1], n[3], n[5]);
  if (triple(v, n[1], n[3])/denom >= 0 && triple(v, n[3], n[5])/denom >= 0 && triple(v, n[5], n[1])/denom >= 0)
  {
    act[1] = act[3] = act[5] = true;
    return;
  }

  // the following are tangents to the 1, 3, and 5 yield surfaces
  // used below.
  std::vector<Real> t1(3);
  t1[0] = oneplus ; t1[1] = oneminus ; t1[2] = 0;
  std::vector<Real> t3(3);
  t3[0] = oneplus ; t3[1] = 0 ; t3[2] = oneminus;
  std::vector<Real> t5(3);
  t5[0] = 0 ; t5[1] = oneplus ; t5[2] = oneminus;


  // 010100 (edge)
  std::vector<Real> n1xn3(3);
  n1xn3[0] = oneplus ; n1xn3[1] = oneminus ; n1xn3[2] = oneminus;
  // work out the point to which we would return, "a".  It is defined by
  // f1 = 0 = f3, and that (p - a).(n1 x n3) = 0, where "p" is the
  // starting position (p = eigvals).
  // In the following a = (lam0, lam2, lam2)
  Real pdotn1xn3 = dot(eigvals, n1xn3);
  Real lam0 = pdotn1xn3 - 4*coh*cosphi*oneminus/(1 + sinphi);
  lam0 /= oneplus + 2*oneminus*(1 - sinphi)/(1 + sinphi);
  Real lam1 = lam0*(1 - sinphi)/(1 + sinphi) + 2*coh*cosphi/(1 + sinphi);
  std::vector<Real> pminusa(3);
  pminusa[0] = eigvals[0] - lam0;
  pminusa[1] = eigvals[1] - lam1;
  pminusa[2] = eigvals[2] - lam1;
  if (dot(pminusa, t3)/dot(n[1], t3) >= 0 && dot(pminusa, t1)/dot(n[3], t1) >= 0)
  {
    act[1] = act[3] = true;
    return;
  }

  // 000101 (edge)
  std::vector<Real> n3xn5(3);
  n3xn5[0] = oneplus ; n3xn5[1] = oneplus ; n3xn5[2] = oneminus;
  // work out the point to which we would return, "a".  It is defined by
  // f3 = 0 = f5, and that (p - a).(n3 x n5) = 0, where "p" is the
  // starting position (p = eigvals).
  // In the following a = (lam0, lam2, lam2)
  Real pdotn3xn5 = dot(eigvals, n3xn5);
  Real lam2 = pdotn3xn5 + 4*coh*cosphi*oneplus/(1 - sinphi);
  lam2 /= oneminus + 2*oneplus*(1 + sinphi)/(1 - sinphi);
  lam1 = lam2*(1 + sinphi)/(1 - sinphi) - 2*coh*cosphi/(1 - sinphi);
  pminusa[0] = eigvals[0] - lam1;
  pminusa[1] = eigvals[1] - lam1;
  pminusa[2] = eigvals[2] - lam2;
  if (dot(pminusa, t5)/dot(n[3], t5) >= 0 && dot(pminusa, t3)/dot(n[5], t3) >= 0)
  {
    act[3] = act[5] = true;
    return;
  }

  // 000100 (plane)
  act[3] = true;
  return;
}