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(); }
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); }
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; } }
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; } }
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(); }
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)); }
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; } } }
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()); }
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(); }
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(); }
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; } } }
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(); }
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(); }