void ComputeSmearedCrackingStress::computeCrackStrainAndOrientation( RealVectorValue & strain_in_crack_dir) { // The rotation tensor is ordered such that directions for pre-existing cracks appear first // in the list of columns. For example, if there is one existing crack, its direction is in the // first column in the rotation tensor. const unsigned int num_known_dirs = getNumKnownCrackDirs(); if (num_known_dirs == 0) { std::vector<Real> eigval(3, 0.0); RankTwoTensor eigvec; _elastic_strain[_qp].symmetricEigenvaluesEigenvectors(eigval, eigvec); // If the elastic strain is beyond the cracking strain, save the eigen vectors as // the rotation tensor. Reverse their order so that the third principal strain // (most tensile) will correspond to the first crack. _crack_rotation[_qp].fillColumn(0, eigvec.column(2)); _crack_rotation[_qp].fillColumn(1, eigvec.column(1)); _crack_rotation[_qp].fillColumn(2, eigvec.column(0)); strain_in_crack_dir(0) = eigval[2]; strain_in_crack_dir(1) = eigval[1]; strain_in_crack_dir(2) = eigval[0]; } else if (num_known_dirs == 1) { // This is easily the most complicated case. // 1. Rotate the elastic strain to the orientation associated with the known // crack. // 2. Extract the lower 2x2 block into a separate tensor. // 3. Run the eigen solver on the result. // 4. Update the rotation tensor to reflect the effect of the 2 eigenvectors. // 1. const RankTwoTensor & R = _crack_rotation[_qp]; RankTwoTensor ePrime(_elastic_strain[_qp]); ePrime.rotate(R.transpose()); // elastic strain in crack coordinates // 2. ColumnMajorMatrix e2x2(2, 2); e2x2(0, 0) = ePrime(1, 1); e2x2(1, 0) = ePrime(2, 1); e2x2(0, 1) = ePrime(1, 2); e2x2(1, 1) = ePrime(2, 2); // 3. ColumnMajorMatrix e_val2x1(2, 1); ColumnMajorMatrix e_vec2x2(2, 2); e2x2.eigen(e_val2x1, e_vec2x2); // 4. RankTwoTensor eigvec( 1.0, 0.0, 0.0, 0.0, e_vec2x2(0, 1), e_vec2x2(1, 1), 0.0, e_vec2x2(0, 0), e_vec2x2(1, 0)); _crack_rotation[_qp] = _crack_rotation_old[_qp] * eigvec; // Roe implementation strain_in_crack_dir(0) = ePrime(0, 0); strain_in_crack_dir(1) = e_val2x1(1, 0); strain_in_crack_dir(2) = e_val2x1(0, 0); } else if (num_known_dirs == 2 || num_known_dirs == 3) { // Rotate to cracked orientation and pick off the strains in the rotated // coordinate directions. const RankTwoTensor & R = _crack_rotation[_qp]; RankTwoTensor ePrime(_elastic_strain[_qp]); ePrime.rotate(R.transpose()); // elastic strain in crack coordinates strain_in_crack_dir(0) = ePrime(0, 0); strain_in_crack_dir(1) = ePrime(1, 1); strain_in_crack_dir(2) = ePrime(2, 2); } else mooseError("Invalid number of known crack directions"); }
void HyperElasticPhaseFieldIsoDamage::computeDamageStress() { Real lambda = _elasticity_tensor[_qp](0, 0, 1, 1); Real mu = _elasticity_tensor[_qp](0, 1, 0, 1); Real c = _c[_qp]; Real xfac = Utility::pow<2>(1.0 - c) + _kdamage; std::vector<Real> eigval; RankTwoTensor evec; _ee.symmetricEigenvaluesEigenvectors(eigval, evec); for (unsigned int i = 0; i < LIBMESH_DIM; ++i) _etens[i].vectorOuterProduct(evec.column(i), evec.column(i)); Real etr = 0.0; for (unsigned int i = 0; i < LIBMESH_DIM; ++i) etr += eigval[i]; Real etrpos = (std::abs(etr) + etr) / 2.0; Real etrneg = (std::abs(etr) - etr) / 2.0; RankTwoTensor pk2pos, pk2neg; for (unsigned int i = 0; i < LIBMESH_DIM; ++i) { pk2pos += _etens[i] * (lambda * etrpos + 2.0 * mu * (std::abs(eigval[i]) + eigval[i]) / 2.0); pk2neg += _etens[i] * (lambda * etrneg + 2.0 * mu * (std::abs(eigval[i]) - eigval[i]) / 2.0); } _pk2_tmp = pk2pos * xfac - pk2neg; if (_save_state) { std::vector<Real> epos(LIBMESH_DIM), eneg(LIBMESH_DIM); for (unsigned int i = 0; i < LIBMESH_DIM; ++i) { epos[i] = (std::abs(eigval[i]) + eigval[i]) / 2.0; eneg[i] = (std::abs(eigval[i]) - eigval[i]) / 2.0; } // sum squares of epos and eneg Real pval(0.0), nval(0.0); for (unsigned int i = 0; i < LIBMESH_DIM; ++i) { pval += epos[i] * epos[i]; nval += eneg[i] * eneg[i]; } // Energy with positive principal strains const Real G0_pos = lambda * etrpos * etrpos / 2.0 + mu * pval; const Real G0_neg = lambda * etrneg * etrneg / 2.0 + mu * nval; // Assign history variable and derivative if (G0_pos > _hist_old[_qp]) _hist[_qp] = G0_pos; else _hist[_qp] = _hist_old[_qp]; Real hist_variable = _hist_old[_qp]; if (_use_current_hist) hist_variable = _hist[_qp]; // Elastic free energy density _F[_qp] = hist_variable * xfac - G0_neg + _gc[_qp] / (2 * _l[_qp]) * c * c; // derivative of elastic free energy density wrt c _dFdc[_qp] = -hist_variable * 2.0 * (1.0 - c) * (1 - _kdamage) + _gc[_qp] / _l[_qp] * c; // 2nd derivative of elastic free energy density wrt c _d2Fdc2[_qp] = hist_variable * 2.0 * (1 - _kdamage) + _gc[_qp] / _l[_qp]; _dG0_dee = pk2pos; _dpk2_dc = -pk2pos * 2.0 * (1.0 - c); } }