void InteractionIntegral::computeTFields(RankTwoTensor & aux_stress, RankTwoTensor & grad_disp) { Real t = _theta; Real st = std::sin(t); Real ct = std::cos(t); Real stsq = Utility::pow<2>(st); Real ctsq = Utility::pow<2>(ct); Real ctcu = Utility::pow<3>(ct); Real oneOverPiR = 1.0 / (libMesh::pi * _r); aux_stress.zero(); aux_stress(0, 0) = -oneOverPiR * ctcu; aux_stress(0, 1) = -oneOverPiR * st * ctsq; aux_stress(1, 0) = -oneOverPiR * st * ctsq; aux_stress(1, 1) = -oneOverPiR * ct * stsq; aux_stress(2, 2) = -oneOverPiR * _poissons_ratio * (ctcu + ct * stsq); grad_disp.zero(); grad_disp(0, 0) = oneOverPiR / (4.0 * _youngs_modulus) * (ct * (4.0 * Utility::pow<2>(_poissons_ratio) - 3.0 + _poissons_ratio) - std::cos(3.0 * t) * (1.0 + _poissons_ratio)); grad_disp(0, 1) = -oneOverPiR / (4.0 * _youngs_modulus) * (st * (4.0 * Utility::pow<2>(_poissons_ratio) - 3.0 + _poissons_ratio) + std::sin(3.0 * t) * (1.0 + _poissons_ratio)); }
bool stznewHEVPFlowRatePowerLawJ2::computeDirection(unsigned int qp, RankTwoTensor & val) const { RankTwoTensor pk2_dev = computePK2Deviatoric(_pk2[qp], _ce[qp]); // Real s_xx = _tensor[qp](0,0); // Real s_yy = _tensor[qp](1,1); // Real tau_xy= _tensor[qp](0,1); // Real s_mean = 1.0/3.0*(s_xx+s_yy); // Real PI = 3.1415926; // Real tau_max = std::pow((s_xx-s_yy)/2*(s_xx-s_yy)/2+tau_xy*tau_xy,0.5); // Real eqv_stress = tau_max; // RankTwoTensor pk2_dev = computePK2Deviatoric(_pk2[qp], _ce[qp]); Real eqv_stress = computeEqvStress(pk2_dev, _ce[qp]); RankTwoTensor dirnew ; Real anglec; Real angles; Real PI= 3.1415926; Real theta= 0.25*PI+0.5*(_phiangle/180.0*PI); anglec = std::cos(theta); angles = std::sin(theta); dirnew.zero(); dirnew(0,0)=2.0*anglec*angles; dirnew(1,1)=-2.0*anglec*angles; val.zero(); if (eqv_stress > _strength[qp]) { val = 1.5/eqv_stress * _ce[qp] * pk2_dev * _ce[qp]; //val = 1.5/eqv_stress*pk2_dev*_ce[qp]; // val = dirnew; // // } return true; }
Real PorousFlowDispersiveFlux::computeQpResidual() { RealVectorValue flux = 0.0; RealVectorValue velocity; Real velocity_abs; RankTwoTensor v2; RankTwoTensor dispersion; dispersion.zero(); Real diffusion; for (unsigned int ph = 0; ph < _num_phases; ++ph) { // Diffusive component diffusion = _porosity_qp[_qp] * _tortuosity[_qp][ph] * _diffusion_coeff[_qp][ph][_fluid_component]; // Calculate Darcy velocity velocity = (_permeability[_qp] * (_grad_p[_qp][ph] - _fluid_density_qp[_qp][ph] * _gravity) * _relative_permeability[_qp][ph] / _fluid_viscosity[_qp][ph]); velocity_abs = std::sqrt(velocity * velocity); if (velocity_abs > 0.0) { v2.vectorOuterProduct(velocity, velocity); // Add longitudinal dispersion to diffusive component diffusion += _disp_trans[ph] * velocity_abs; dispersion = (_disp_long[ph] - _disp_trans[ph]) * v2 / velocity_abs; } flux += _fluid_density_qp[_qp][ph] * (diffusion * _identity_tensor + dispersion) * _grad_mass_frac[_qp][ph][_fluid_component]; } return _grad_test[_i][_qp] * flux; }
bool HEVPFlowRatePowerLawJ2::computeDirection(unsigned int qp, RankTwoTensor & val) const { RankTwoTensor pk2_dev = computePK2Deviatoric(_pk2[qp], _ce[qp]); Real eqv_stress = computeEqvStress(pk2_dev, _ce[qp]); val.zero(); if (eqv_stress > 0.0) val = 1.5 / eqv_stress * _ce[qp] * pk2_dev * _ce[qp]; return true; }
bool FlowRateModel::computeFlowDirection(RankTwoTensor & flow_dirn, const RankTwoTensor & pk2, const RankTwoTensor & ce, const std::vector<Real> & /*internal_var*/, const unsigned int /*start_index*/, const unsigned int /*size*/) const { RankTwoTensor pk2_dev = computePK2Deviatoric(pk2, ce); Real eqv_stress = computeEqvStress(pk2_dev, ce); flow_dirn.zero(); if (eqv_stress > 0.0) flow_dirn = 3.0/(2.0 * eqv_stress) * ce * pk2_dev * ce; return true; }
bool stzRHEVPFlowRatePowerLawJ2::computeTensorDerivative(unsigned int qp, const std::string & coupled_var_name, RankTwoTensor & val) const { val.zero(); if (_pk2_prop_name == coupled_var_name) { RankTwoTensor pk2_dev = computePK2Deviatoric(_pk2[qp], _ce[qp]); Real eqv_stress = computeEqvStress(pk2_dev, _ce[qp]); Real dflowrate_dseqv; if (eqv_stress>_strength[qp]) // dflowrate_dseqv = 1/_t_tau*std::exp(-1/_chiv[qp])*std::exp(eqv_stress/_grain_pressure/_chiv[qp])* \ (1.0/(_grain_pressure*_chiv[qp])*(1.0-_strength[qp]/eqv_stress)+_strength[qp]/(eqv_stress*eqv_stress)); dflowrate_dseqv = _v*std::exp(-1/_chiv[qp])*(1.0-1.0/(eqv_stress*eqv_stress)); RankTwoTensor tau = pk2_dev * _ce[qp]; RankTwoTensor dseqv_dpk2dev; dseqv_dpk2dev.zero(); if (eqv_stress > _strength[qp]) dseqv_dpk2dev = 1.5/eqv_stress * tau * _ce[qp]; RankTwoTensor ce_inv = _ce[qp].inverse(); RankFourTensor dpk2dev_dpk2; for (unsigned int i = 0; i < LIBMESH_DIM; ++i) for (unsigned int j = 0; j < LIBMESH_DIM; ++j) for (unsigned int k = 0; k < LIBMESH_DIM; ++k) for (unsigned int l = 0; l < LIBMESH_DIM; ++l) { dpk2dev_dpk2(i, j, k, l) = 0.0; if (i==k && j==l) dpk2dev_dpk2(i, j, k, l) = 1.0; dpk2dev_dpk2(i, j, k, l) -= ce_inv(i, j) * _ce[qp](k, l)/3.0; } val = dflowrate_dseqv * dpk2dev_dpk2.transposeMajor() * dseqv_dpk2dev; } return true; }
bool HEVPFlowRatePowerLawJ2::computeTensorDerivative(unsigned int qp, const std::string & coupled_var_name, RankTwoTensor & val) const { val.zero(); if (_pk2_prop_name == coupled_var_name) { RankTwoTensor pk2_dev = computePK2Deviatoric(_pk2[qp], _ce[qp]); Real eqv_stress = computeEqvStress(pk2_dev, _ce[qp]); Real dflowrate_dseqv = _ref_flow_rate * _flow_rate_exponent * std::pow(eqv_stress / _strength[qp], _flow_rate_exponent - 1.0) / _strength[qp]; RankTwoTensor tau = pk2_dev * _ce[qp]; RankTwoTensor dseqv_dpk2dev; dseqv_dpk2dev.zero(); if (eqv_stress > 0.0) dseqv_dpk2dev = 1.5 / eqv_stress * tau * _ce[qp]; RankTwoTensor ce_inv = _ce[qp].inverse(); RankFourTensor dpk2dev_dpk2; for (unsigned int i = 0; i < LIBMESH_DIM; ++i) for (unsigned int j = 0; j < LIBMESH_DIM; ++j) for (unsigned int k = 0; k < LIBMESH_DIM; ++k) for (unsigned int l = 0; l < LIBMESH_DIM; ++l) { dpk2dev_dpk2(i, j, k, l) = 0.0; if (i == k && j == l) dpk2dev_dpk2(i, j, k, l) = 1.0; dpk2dev_dpk2(i, j, k, l) -= ce_inv(i, j) * _ce[qp](k, l) / 3.0; } val = dflowrate_dseqv * dpk2dev_dpk2.transposeMajor() * dseqv_dpk2dev; } return true; }
void RecomputeRadialReturn::computeStress(RankTwoTensor & strain_increment, RankTwoTensor & inelastic_strain_increment, RankTwoTensor & stress_new) { // Given the stretching, update the inelastic strain // Compute the stress in the intermediate configuration while retaining the stress history // compute the deviatoric trial stress and trial strain from the current intermediate configuration RankTwoTensor deviatoric_trial_stress = stress_new.deviatoric(); // compute the effective trial stress Real dev_trial_stress_squared = deviatoric_trial_stress.doubleContraction(deviatoric_trial_stress); Real effective_trial_stress = std::sqrt(3.0 / 2.0 * dev_trial_stress_squared); //If the effective trial stress is zero, so should the inelastic strain increment be zero //In that case skip the entire iteration if the effective trial stress is zero if (effective_trial_stress != 0.0) { computeStressInitialize(effective_trial_stress); // Use Newton sub-iteration to determine the scalar effective inelastic strain increment Real scalar_effective_inelastic_strain = 0; unsigned int iteration = 0; Real residual = 10; // use a large number here to guarantee at least one loop through while Real norm_residual = 10; Real first_norm_residual = 10; // create an output string with iteration information when errors occur std::string iteration_output; while (iteration < _max_its && norm_residual > _absolute_tolerance && (norm_residual/first_norm_residual) > _relative_tolerance) { iterationInitialize(scalar_effective_inelastic_strain); residual = computeResidual(effective_trial_stress, scalar_effective_inelastic_strain); norm_residual = std::abs(residual); if (iteration == 0) { first_norm_residual = norm_residual; if (first_norm_residual == 0) first_norm_residual = 1; } Real derivative = computeDerivative(effective_trial_stress, scalar_effective_inelastic_strain); scalar_effective_inelastic_strain -= residual / derivative; if (_output_iteration_info || _output_iteration_info_on_error) { iteration_output = "In the element " + Moose::stringify(_current_elem->id()) + + " and the qp point " + Moose::stringify(_qp) + ": \n" + + " iteration = " + Moose::stringify(iteration ) + "\n" + + " effective trial stress = " + Moose::stringify(effective_trial_stress) + "\n" + + " scalar effective inelastic strain = " + Moose::stringify(scalar_effective_inelastic_strain) +"\n" + + " relative residual = " + Moose::stringify(norm_residual/first_norm_residual) + "\n" + + " relative tolerance = " + Moose::stringify(_relative_tolerance) + "\n" + + " absolute residual = " + Moose::stringify(norm_residual) + "\n" + + " absolute tolerance = " + Moose::stringify(_absolute_tolerance) + "\n"; } iterationFinalize(scalar_effective_inelastic_strain); ++iteration; } if (_output_iteration_info) _console << iteration_output << std::endl; if (iteration == _max_its && norm_residual > _absolute_tolerance && (norm_residual/first_norm_residual) > _relative_tolerance) { if (_output_iteration_info_on_error) Moose::err << iteration_output; mooseError("Exceeded maximum iterations in RecomputeRadialReturn solve for material: " << _name << ". Rerun with 'output_iteration_info_on_error = true' for more information."); } // compute inelastic strain increments while avoiding a potential divide by zero inelastic_strain_increment = deviatoric_trial_stress; inelastic_strain_increment *= (3.0 / 2.0 * scalar_effective_inelastic_strain / effective_trial_stress); } else inelastic_strain_increment.zero(); strain_increment -= inelastic_strain_increment; stress_new = _elasticity_tensor[_qp] * (strain_increment + _elastic_strain_old[_qp]); computeStressFinalize(inelastic_strain_increment); }
void mooseSetToZero<RankTwoTensor>(RankTwoTensor & v) { v.zero(); }
bool TensorMechanicsPlasticTensileMulti::doReturnMap(const RankTwoTensor & trial_stress, const 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() == 3, "TensorMechanicsPlasticTensileMulti size of dpm should be 3 but it is " << dpm.size()); std::vector<Real> eigvals; RankTwoTensor eigvecs; trial_stress.symmetricEigenvaluesEigenvectors(eigvals, eigvecs); eigvals[0] += _shift; eigvals[2] -= _shift; Real str = tensile_strength(intnl_old); yf.resize(3); yf[0] = eigvals[0] - str; yf[1] = eigvals[1] - str; yf[2] = eigvals[2] - str; if (yf[0] <= _f_tol && yf[1] <= _f_tol && yf[2] <= _f_tol) { // purely elastic (trial_stress, intnl_old) trial_stress_inadmissible = false; return true; } trial_stress_inadmissible = true; delta_dp.zero(); returned_stress.zero(); // In the following i often assume that E_ijkl is // for an isotropic situation. This reduces FLOPS // substantially which is important since the returnMap // is potentially the most compute-intensive function // of a simulation. // In many comments i write the general expression, and // i hope that might guide future coders if they are // generalising to a non-istropic E_ijkl // n[alpha] = E_ijkl*r[alpha]_kl expressed in principal stress space // (alpha = 0, 1, 2, corresponding to the three surfaces) // Note that in principal stress space, the flow // directions are, expressed in 'vector' form, // r[0] = (1,0,0), r[1] = (0,1,0), r[2] = (0,0,1). // Similar for _n: // so _n[0] = E_ij00*r[0], _n[1] = E_ij11*r[1], _n[2] = E_ij22*r[2] // In the following I assume that the E_ijkl is // for an isotropic situation. // In the anisotropic situation, we couldn't express // the flow directions as vectors in the same principal // stress space as the stress: they'd be full rank-2 tensors std::vector<std::vector<Real> > n(3); for (unsigned i = 0 ; i < 3 ; ++i) n[i].resize(3); n[0][0] = E_ijkl(0,0,0,0); n[0][1] = E_ijkl(1,1,0,0); n[0][2] = E_ijkl(2,2,0,0); n[1][0] = E_ijkl(0,0,1,1); n[1][1] = E_ijkl(1,1,1,1); n[1][2] = E_ijkl(2,2,1,1); n[2][0] = E_ijkl(0,0,2,2); n[2][1] = E_ijkl(1,1,2,2); n[2][2] = E_ijkl(2,2,2,2); // 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 is correct for zero // Poisson's ratio and no hardening, and at least // gives a not-completely-stupid guess in the // more general case. // 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 std::vector<int> trial_order(3); if (yf[0] > 0) // all the yield functions are positive, since eigvals are ordered eigvals[0] <= eigvals[1] <= eigvals[2] { trial_order[0] = tip; trial_order[1] = edge; trial_order[2] = plane; } else if (yf[1] > 0) // two yield functions are positive { trial_order[0] = edge; trial_order[1] = tip; trial_order[2] = plane; } else { trial_order[0] = plane; trial_order[1] = edge; trial_order[2] = tip; } unsigned trial; bool nr_converged; for (trial = 0 ; trial < 3 ; ++trial) { switch (trial_order[trial]) { case tip: nr_converged = returnTip(eigvals, n, dpm, returned_stress, intnl_old, 0); break; case edge: nr_converged = returnEdge(eigvals, n, dpm, returned_stress, intnl_old, 0); break; case plane: nr_converged = returnPlane(eigvals, n, dpm, returned_stress, intnl_old, 0); break; } str = tensile_strength(intnl_old + dpm[0] + dpm[1] + dpm[2]); if (nr_converged && KuhnTuckerOK(returned_stress, dpm, str)) break; } if (trial == 3) { Moose::err << "Trial stress = \n"; trial_stress.print(Moose::err); Moose::err << "Internal parameter = " << intnl_old << "\n"; mooseError("TensorMechanicsPlasticTensileMulti: FAILURE! You probably need to implement a line search\n"); // failure - must place yield function values at trial stress into yf str = tensile_strength(intnl_old); yf[0] = eigvals[0] - str; yf[1] = eigvals[1] - str; yf[2] = eigvals[2] - str; return false; } // success returned_intnl = intnl_old; for (unsigned i = 0 ; i < 3 ; ++i) { yf[i] = returned_stress(i, i) - str; delta_dp(i, i) = dpm[i]; returned_intnl += dpm[i]; } returned_stress = eigvecs*returned_stress*(eigvecs.transpose()); delta_dp = eigvecs*delta_dp*(eigvecs.transpose()); return true; }
bool stznewHEVPFlowRatePowerLawJ2::computeTensorDerivative(unsigned int qp, const std::string & coupled_var_name, RankTwoTensor & val) const { val.zero(); if (_pk2_prop_name == coupled_var_name) { RankTwoTensor pk2_dev = computePK2Deviatoric(_pk2[qp], _ce[qp]); // Real s_xx = _tensor[qp](0,0); // Real s_yy = _tensor[qp](1,1); // Real tau_xy= _tensor[qp](0,1); // Real s_mean = 1.0/3.0*(s_xx+s_yy); // Real PI = 3.1415926; // Real tau_max = std::pow((s_xx-s_yy)/2*(s_xx-s_yy)/2+tau_xy*tau_xy,0.5); // Real eqv_stress = tau_max ; Real eqv_stress = computeEqvStress(pk2_dev, _ce[qp]); Real _pressure_eff=_grain_pressure-_biot*_pf[qp]; // Real _t_taunew = _agrain[qp]/std::sqrt(_grain_pressure/_rho); Real _t_taunew = _agrain[qp]/std::sqrt(_pressure_eff/_rho); // Real dflowrate_dseqv = _ref_flow_rate * _flow_rate_exponent * std::pow(eqv_stress/_strength[qp],_flow_rate_exponent-1.0)/_strength[qp]; // stz // Real dflowrate_dseqv = 1/_t_tau*std::exp(-1/_chiv[qp])*std::exp(eqv_stress/_grain_pressure/_chiv[qp])* \ // (1/(_grain_pressure*_chiv[qp])*(1-_strength[qp]/eqv_stress)+_strength[qp]/(eqv_stress*eqv_stress))*(eqv_stress>_strength[qp]); // Real dflowrate_dseqv; if (eqv_stress>_strength[qp]) // dflowrate_dseqv = 1/_t_tau*std::exp(-1/_chiv[qp])*std::exp(eqv_stress/_grain_pressure/_chiv[qp])* \ (1.0/(_grain_pressure*_chiv[qp])*(1.0-_strength[qp]/eqv_stress)+_strength[qp]/(eqv_stress*eqv_stress)); // Original Stuff { dflowrate_dseqv = 1/_t_taunew*std::exp(-1/_chiv[qp])*std::exp(eqv_stress/_pressure_eff/_chiv[qp])* \ (1.0/(_pressure_eff*_chiv[qp])*(1.0-_strength[qp]/eqv_stress)+_strength[qp]/(eqv_stress*eqv_stress)); } // Modified // { //dflowrate_dseqv = 1.0/_t_taunew*std::exp(-1.0/_chiv[qp])*(-1.0*_strength[qp])/(eqv_stress*eqv_stress); // } // dflowrate_dseqv = 1/_t_tau*std::exp(-1/_chi)*std::exp(eqv_stress/_grain_pressure/_chi)* \ // (1.0/(_grain_pressure*_chi)*(1.0-_strength[qp]/eqv_stress)+_strength[qp]/(eqv_stress*eqv_stress)); RankTwoTensor tau = pk2_dev * _ce[qp]; RankTwoTensor dseqv_dpk2dev; dseqv_dpk2dev.zero(); if (eqv_stress > _strength[qp]) dseqv_dpk2dev = 1.5/eqv_stress * tau * _ce[qp]; RankTwoTensor ce_inv = _ce[qp].inverse(); RankFourTensor dpk2dev_dpk2; for (unsigned int i = 0; i < LIBMESH_DIM; ++i) for (unsigned int j = 0; j < LIBMESH_DIM; ++j) for (unsigned int k = 0; k < LIBMESH_DIM; ++k) for (unsigned int l = 0; l < LIBMESH_DIM; ++l) { dpk2dev_dpk2(i, j, k, l) = 0.0; if (i==k && j==l) dpk2dev_dpk2(i, j, k, l) = 1.0; dpk2dev_dpk2(i, j, k, l) -= ce_inv(i, j) * _ce[qp](k, l)/3.0; } val = dflowrate_dseqv * dpk2dev_dpk2.transposeMajor() * dseqv_dpk2dev; } return true; }
void InteractionIntegral::computeAuxFields(RankTwoTensor & aux_stress, RankTwoTensor & grad_disp) { RealVectorValue k(0.0); if (_sif_mode == SifMethod::KI) k(0) = 1.0; else if (_sif_mode == SifMethod::KII) k(1) = 1.0; else if (_sif_mode == SifMethod::KIII) k(2) = 1.0; Real t = _theta; Real t2 = _theta / 2.0; Real tt2 = 3.0 * _theta / 2.0; Real st = std::sin(t); Real ct = std::cos(t); Real st2 = std::sin(t2); Real ct2 = std::cos(t2); Real stt2 = std::sin(tt2); Real ctt2 = std::cos(tt2); Real ct2sq = Utility::pow<2>(ct2); Real ct2cu = Utility::pow<3>(ct2); Real sqrt2PiR = std::sqrt(2.0 * libMesh::pi * _r); // Calculate auxiliary stress tensor aux_stress.zero(); aux_stress(0, 0) = 1.0 / sqrt2PiR * (k(0) * ct2 * (1.0 - st2 * stt2) - k(1) * st2 * (2.0 + ct2 * ctt2)); aux_stress(1, 1) = 1.0 / sqrt2PiR * (k(0) * ct2 * (1.0 + st2 * stt2) + k(1) * st2 * ct2 * ctt2); aux_stress(0, 1) = 1.0 / sqrt2PiR * (k(0) * ct2 * st2 * ctt2 + k(1) * ct2 * (1.0 - st2 * stt2)); aux_stress(0, 2) = -1.0 / sqrt2PiR * k(2) * st2; aux_stress(1, 2) = 1.0 / sqrt2PiR * k(2) * ct2; // plane stress // Real s33 = 0; // plane strain aux_stress(2, 2) = _poissons_ratio * (aux_stress(0, 0) + aux_stress(1, 1)); aux_stress(1, 0) = aux_stress(0, 1); aux_stress(2, 0) = aux_stress(0, 2); aux_stress(2, 1) = aux_stress(1, 2); // Calculate x1 derivative of auxiliary displacements grad_disp.zero(); grad_disp(0, 0) = k(0) / (4.0 * _shear_modulus * sqrt2PiR) * (ct * ct2 * _kappa + ct * ct2 - 2.0 * ct * ct2cu + st * st2 * _kappa + st * st2 - 6.0 * st * st2 * ct2sq) + k(1) / (4.0 * _shear_modulus * sqrt2PiR) * (ct * st2 * _kappa + ct * st2 + 2.0 * ct * st2 * ct2sq - st * ct2 * _kappa + 3.0 * st * ct2 - 6.0 * st * ct2cu); grad_disp(0, 1) = k(0) / (4.0 * _shear_modulus * sqrt2PiR) * (ct * st2 * _kappa + ct * st2 - 2.0 * ct * st2 * ct2sq - st * ct2 * _kappa - 5.0 * st * ct2 + 6.0 * st * ct2cu) + k(1) / (4.0 * _shear_modulus * sqrt2PiR) * (-ct * ct2 * _kappa + 3.0 * ct * ct2 - 2.0 * ct * ct2cu - st * st2 * _kappa + 3.0 * st * st2 - 6.0 * st * st2 * ct2sq); grad_disp(0, 2) = k(2) / (_shear_modulus * sqrt2PiR) * (st2 * ct - ct2 * st); }
void ComputeMultipleInelasticStress::updateQpState(RankTwoTensor & elastic_strain_increment, RankTwoTensor & combined_inelastic_strain_increment) { if (_output_iteration_info == true) { _console << std::endl << "iteration output for ComputeMultipleInelasticStress solve:" << " time=" << _t << " int_pt=" << _qp << std::endl; } Real l2norm_delta_stress; Real first_l2norm_delta_stress = 1.0; unsigned int counter = 0; std::vector<RankTwoTensor> inelastic_strain_increment; inelastic_strain_increment.resize(_num_models); for (unsigned i_rmm = 0; i_rmm < _models.size(); ++i_rmm) inelastic_strain_increment[i_rmm].zero(); RankTwoTensor stress_max, stress_min; do { for (unsigned i_rmm = 0; i_rmm < _num_models; ++i_rmm) { _models[i_rmm]->setQp(_qp); // initially assume the strain is completely elastic elastic_strain_increment = _strain_increment[_qp]; // and subtract off all inelastic strain increments calculated so far // except the one that we're about to calculate for (unsigned j_rmm = 0; j_rmm < _num_models; ++j_rmm) if (i_rmm != j_rmm) elastic_strain_increment -= inelastic_strain_increment[j_rmm]; // form the trial stress, with the check for changed elasticity constants if (_is_elasticity_tensor_guaranteed_isotropic || !_perform_finite_strain_rotations) { _stress[_qp] = _elasticity_tensor[_qp] * (_elastic_strain_old[_qp] + elastic_strain_increment); // InitialStress Deprecation: remove these lines if (_perform_finite_strain_rotations) rotateQpInitialStress(); addQpInitialStress(); } else _stress[_qp] = _stress_old[_qp] + _elasticity_tensor[_qp] * elastic_strain_increment; // given a trial stress (_stress[_qp]) and a strain increment (elastic_strain_increment) // let the i^th model produce an admissible stress (as _stress[_qp]), and decompose // the strain increment into an elastic part (elastic_strain_increment) and an // inelastic part (inelastic_strain_increment[i_rmm]) computeAdmissibleState(i_rmm, elastic_strain_increment, inelastic_strain_increment[i_rmm], _consistent_tangent_operator[i_rmm]); if (i_rmm == 0) { stress_max = _stress[_qp]; stress_min = _stress[_qp]; } else { for (unsigned int i = 0; i < LIBMESH_DIM; ++i) { for (unsigned int j = 0; j < LIBMESH_DIM; ++j) { if (_stress[_qp](i, j) > stress_max(i, j)) stress_max(i, j) = _stress[_qp](i, j); else if (stress_min(i, j) > _stress[_qp](i, j)) stress_min(i, j) = _stress[_qp](i, j); } } } } // now check convergence in the stress: // once the change in stress is within tolerance after each recompute material // consider the stress to be converged l2norm_delta_stress = (stress_max - stress_min).L2norm(); if (counter == 0 && l2norm_delta_stress > 0.0) first_l2norm_delta_stress = l2norm_delta_stress; if (_output_iteration_info == true) { _console << "stress iteration number = " << counter << "\n" << " relative l2 norm delta stress = " << (0 == first_l2norm_delta_stress ? 0 : l2norm_delta_stress / first_l2norm_delta_stress) << "\n" << " stress convergence relative tolerance = " << _relative_tolerance << "\n" << " absolute l2 norm delta stress = " << l2norm_delta_stress << "\n" << " stress convergence absolute tolerance = " << _absolute_tolerance << std::endl; } ++counter; } while (counter < _max_iterations && l2norm_delta_stress > _absolute_tolerance && (l2norm_delta_stress / first_l2norm_delta_stress) > _relative_tolerance && _num_models != 1); if (counter == _max_iterations && l2norm_delta_stress > _absolute_tolerance && (l2norm_delta_stress / first_l2norm_delta_stress) > _relative_tolerance) throw MooseException("Max stress iteration hit during ComputeMultipleInelasticStress solve!"); combined_inelastic_strain_increment.zero(); for (unsigned i_rmm = 0; i_rmm < _num_models; ++i_rmm) combined_inelastic_strain_increment += _inelastic_weights[i_rmm] * inelastic_strain_increment[i_rmm]; if (_fe_problem.currentlyComputingJacobian()) computeQpJacobianMult(); _matl_timestep_limit[_qp] = 0.0; for (unsigned i_rmm = 0; i_rmm < _num_models; ++i_rmm) _matl_timestep_limit[_qp] += 1.0 / _models[i_rmm]->computeTimeStepLimit(); if (MooseUtils::absoluteFuzzyEqual(_matl_timestep_limit[_qp], 0.0)) { _matl_timestep_limit[_qp] = std::numeric_limits<Real>::max(); } else { _matl_timestep_limit[_qp] = 1.0 / _matl_timestep_limit[_qp]; } }
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; }
Real PorousFlowDispersiveFlux::computeQpJac(unsigned int jvar) const { // If the variable is not a valid PorousFlow variable, set the Jacobian to 0 if (_dictator.notPorousFlowVariable(jvar)) return 0.0; const unsigned int pvar = _dictator.porousFlowVariableNum(jvar); RealVectorValue velocity; Real velocity_abs; RankTwoTensor v2; RankTwoTensor dispersion; dispersion.zero(); Real diffusion; RealVectorValue flux = 0.0; RealVectorValue dflux = 0.0; for (unsigned int ph = 0; ph < _num_phases; ++ph) { // Diffusive component diffusion = _porosity_qp[_qp] * _tortuosity[_qp][ph] * _diffusion_coeff[_qp][ph][_fluid_component]; // Calculate Darcy velocity velocity = (_permeability[_qp] * (_grad_p[_qp][ph] - _fluid_density_qp[_qp][ph] * _gravity) * _relative_permeability[_qp][ph] / _fluid_viscosity[_qp][ph]); velocity_abs = std::sqrt(velocity * velocity); if (velocity_abs > 0.0) { v2.vectorOuterProduct(velocity, velocity); // Add longitudinal dispersion to diffusive component diffusion += _disp_trans[ph] * velocity_abs; dispersion = (_disp_long[ph] - _disp_trans[ph]) * v2 / velocity_abs; } // Derivative of Darcy velocity RealVectorValue dvelocity = _dpermeability_dvar[_qp][pvar] * _phi[_j][_qp] * (_grad_p[_qp][ph] - _fluid_density_qp[_qp][ph]*_gravity); for (unsigned i = 0; i < LIBMESH_DIM; ++i) dvelocity += _dpermeability_dgradvar[_qp][i][pvar] * _grad_phi[_j][_qp](i) * (_grad_p[_qp][ph] - _fluid_density_qp[_qp][ph] * _gravity); dvelocity += _permeability[_qp] * (_grad_phi[_j][_qp] * _dgrad_p_dgrad_var[_qp][ph][pvar] - _phi[_j][_qp] * _dfluid_density_qp_dvar[_qp][ph][pvar] * _gravity); dvelocity += _permeability[_qp] * (_dgrad_p_dvar[_qp][ph][pvar] * _phi[_j][_qp]); Real dvelocity_abs = 0.0; if (velocity_abs > 0.0) dvelocity_abs = velocity * dvelocity / velocity_abs; // Derivative of diffusion term (note: dispersivity is assumed constant) Real ddiffusion = _phi[_j][_qp] * _dporosity_qp_dvar[_qp][pvar] * _tortuosity[_qp][ph] * _diffusion_coeff[_qp][ph][_fluid_component]; ddiffusion += _phi[_j][_qp] * _porosity_qp[_qp] * _dtortuosity_dvar[_qp][ph][pvar] * _diffusion_coeff[_qp][ph][_fluid_component]; ddiffusion += _phi[_j][_qp] * _porosity_qp[_qp] * _tortuosity[_qp][ph] * _ddiffusion_coeff_dvar[_qp][ph][_fluid_component][pvar]; ddiffusion += _disp_trans[ph] * dvelocity_abs; // Derivative of dispersion term (note: dispersivity is assumed constant) RankTwoTensor ddispersion; ddispersion.zero(); if (velocity_abs > 0.0) { RankTwoTensor dv2a, dv2b; dv2a.vectorOuterProduct(velocity, dvelocity); dv2b.vectorOuterProduct(dvelocity, velocity); ddispersion = (_disp_long[ph] - _disp_trans[ph]) * (dv2a + dv2b) / velocity_abs; ddispersion -= (_disp_long[ph] - _disp_trans[ph]) * v2 * dvelocity_abs / velocity_abs / velocity_abs; } dflux += _phi[_j][_qp] * _dfluid_density_qp_dvar[_qp][ph][pvar] * (diffusion * _identity_tensor + dispersion) * _grad_mass_frac[_qp][ph][_fluid_component]; dflux += _fluid_density_qp[_qp][ph] * (ddiffusion * _identity_tensor + ddispersion) * _grad_mass_frac[_qp][ph][_fluid_component]; dflux += _fluid_density_qp[_qp][ph] * (diffusion * _identity_tensor + dispersion) * _dmass_frac_dvar[_qp][ph][_fluid_component][pvar] * _grad_phi[_j][_qp]; } return _grad_test[_i][_qp] * dflux; }