KOKKOS_INLINE_FUNCTION void J2MiniKernel<EvalT, Traits>::operator()(int cell, int pt) const { constexpr minitensor::Index MAX_DIM{3}; using Tensor = minitensor::Tensor<ScalarT, MAX_DIM>; Tensor F(num_dims_); Tensor const I(minitensor::eye<ScalarT, MAX_DIM>(num_dims_)); Tensor sigma(num_dims_); ScalarT const E = elastic_modulus_(cell, pt); ScalarT const nu = poissons_ratio_(cell, pt); ScalarT const kappa = E / (3.0 * (1.0 - 2.0 * nu)); ScalarT const mu = E / (2.0 * (1.0 + nu)); ScalarT const K = hardening_modulus_(cell, pt); ScalarT const Y = yield_strength_(cell, pt); ScalarT const J1 = J_(cell, pt); ScalarT const Jm23 = 1.0 / std::cbrt(J1 * J1); // fill local tensors F.fill(def_grad_, cell, pt, 0, 0); // Mechanical deformation gradient auto Fm = Tensor(F); if (have_temperature_) { // Compute the mechanical deformation gradient Fm based on the // multiplicative decomposition of the deformation gradient // // F = Fm.Ft => Fm = F.inv(Ft) // // where Ft is the thermal part of F, given as // // Ft = Le * I = exp(alpha * dtemp) * I // // Le = exp(alpha*dtemp) is the thermal stretch and alpha the // coefficient of thermal expansion. ScalarT dtemp = temperature_(cell, pt) - ref_temperature_; ScalarT thermal_stretch = std::exp(expansion_coeff_ * dtemp); Fm /= thermal_stretch; } Tensor Fpn(num_dims_); for (int i{0}; i < num_dims_; ++i) { for (int j{0}; j < num_dims_; ++j) { Fpn(i, j) = ScalarT(Fp_old_(cell, pt, i, j)); } } // compute trial state Tensor const Fpinv = minitensor::inverse(Fpn); Tensor const Cpinv = Fpinv * minitensor::transpose(Fpinv); Tensor const be = Jm23 * Fm * Cpinv * minitensor::transpose(Fm); Tensor s = mu * minitensor::dev(be); ScalarT const mubar = minitensor::trace(be) * mu / (num_dims_); // check yield condition ScalarT const smag = minitensor::norm(s); ScalarT const f = smag - SQ23 * (Y + K * eqps_old_(cell, pt) + sat_mod_ * (1.0 - std::exp(-sat_exp_ * eqps_old_(cell, pt)))); RealType constexpr yield_tolerance = 1.0e-12; if (f > yield_tolerance) { // Use minimization equivalent to return mapping using ValueT = typename Sacado::ValueType<ScalarT>::type; using NLS = J2NLS<EvalT>; constexpr minitensor::Index nls_dim{NLS::DIMENSION}; using MIN = minitensor::Minimizer<ValueT, nls_dim>; using STEP = minitensor::NewtonStep<NLS, ValueT, nls_dim>; MIN minimizer; STEP step; NLS j2nls(sat_mod_, sat_exp_, eqps_old_(cell, pt), K, smag, mubar, Y); minitensor::Vector<ScalarT, nls_dim> x; x(0) = 0.0; LCM::MiniSolver<MIN, STEP, NLS, EvalT, nls_dim> mini_solver( minimizer, step, j2nls, x); ScalarT const alpha = eqps_old_(cell, pt) + SQ23 * x(0); ScalarT const H = K * alpha + sat_mod_ * (1.0 - exp(-sat_exp_ * alpha)); ScalarT const dgam = x(0); // plastic direction Tensor const N = (1 / smag) * s; // update s s -= 2 * mubar * dgam * N; // update eqps eqps_(cell, pt) = alpha; // mechanical source if (have_temperature_ == true && delta_time_(0) > 0) { source_(cell, pt) = (SQ23 * dgam / delta_time_(0) * (Y + H + temperature_(cell, pt))) / (density_ * heat_capacity_); } // exponential map to get Fpnew Tensor const A = dgam * N; Tensor const expA = minitensor::exp(A); Tensor const Fpnew = expA * Fpn; for (int i{0}; i < num_dims_; ++i) { for (int j{0}; j < num_dims_; ++j) { Fp_(cell, pt, i, j) = Fpnew(i, j); } } } else { eqps_(cell, pt) = eqps_old_(cell, pt); if (have_temperature_ == true) source_(cell, pt) = 0.0; for (int i{0}; i < num_dims_; ++i) { for (int j{0}; j < num_dims_; ++j) { Fp_(cell, pt, i, j) = Fpn(i, j); } } } // update yield surface yield_surf_(cell, pt) = Y + K * eqps_(cell, pt) + sat_mod_ * (1. - std::exp(-sat_exp_ * eqps_(cell, pt))); // compute pressure ScalarT const p = 0.5 * kappa * (J_(cell, pt) - 1. / (J_(cell, pt))); // compute stress sigma = p * I + s / J_(cell, pt); for (int i(0); i < num_dims_; ++i) { for (int j(0); j < num_dims_; ++j) { stress_(cell, pt, i, j) = sigma(i, j); } } }
void MechanicsResidual<EvalT, Traits>:: evaluateFields(typename Traits::EvalData workset) { std::cout.precision(15); // initilize Tensors Intrepid::Tensor<ScalarT> F(num_dims_), P(num_dims_), sig(num_dims_); Intrepid::Tensor<ScalarT> I(Intrepid::eye<ScalarT>(num_dims_)); if (have_pore_pressure_) { for (std::size_t cell=0; cell < workset.numCells; ++cell) { for (std::size_t pt=0; pt < num_pts_; ++pt) { // Effective Stress theory sig.fill( &stress_(cell,pt,0,0) ); sig -= biot_coeff_(cell,pt) * pore_pressure_(cell,pt) * I; for (std::size_t i=0; i<num_dims_; i++) { for (std::size_t j=0; j<num_dims_; j++) { stress_(cell,pt,i,j) = sig(i,j); } } } } } // initialize residual if(have_strain_){ // for small deformation, use Cauchy stress for (std::size_t cell=0; cell < workset.numCells; ++cell) { for (std::size_t node=0; node < num_nodes_; ++node) { for (std::size_t dim=0; dim<num_dims_; ++dim) { residual_(cell,node,dim)=0.0; } } for (std::size_t pt=0; pt < num_pts_; ++pt) { //F.fill( &def_grad_(cell,pt,0,0) ); sig.fill( &stress_(cell,pt,0,0) ); for (std::size_t node=0; node < num_nodes_; ++node) { for (std::size_t i=0; i<num_dims_; ++i) { for (std::size_t j=0; j<num_dims_; ++j) { residual_(cell,node,i) += sig(i, j) * w_grad_bf_(cell, node, pt, j); } } } } } } else { // for large deformation, map Cauchy stress to 1st PK stress for (std::size_t cell=0; cell < workset.numCells; ++cell) { for (std::size_t node=0; node < num_nodes_; ++node) { for (std::size_t dim=0; dim<num_dims_; ++dim) { residual_(cell,node,dim)=0.0; } } for (std::size_t pt=0; pt < num_pts_; ++pt) { F.fill( &def_grad_(cell,pt,0,0) ); sig.fill( &stress_(cell,pt,0,0) ); // map Cauchy stress to 1st PK P = Intrepid::piola(F,sig); for (std::size_t node=0; node < num_nodes_; ++node) { for (std::size_t i=0; i<num_dims_; ++i) { for (std::size_t j=0; j<num_dims_; ++j) { residual_(cell,node,i) += P(i, j) * w_grad_bf_(cell, node, pt, j); } } } } } } // optional body force if (have_body_force_) { for (std::size_t cell=0; cell < workset.numCells; ++cell) { for (std::size_t node=0; node < num_nodes_; ++node) { for (std::size_t pt=0; pt < num_pts_; ++pt) { for (std::size_t dim=0; dim<num_dims_; ++dim) { residual_(cell,node,dim) += w_bf_(cell,node,pt) * body_force_(cell,pt,dim); } } } } } }