void StVenantKirchhoffModel<EvalT, Traits>:: computeState(typename Traits::EvalData workset, std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > dep_fields, std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > eval_fields) { // extract dependent MDFields PHX::MDField<ScalarT> def_grad = *dep_fields["F"]; PHX::MDField<ScalarT> J = *dep_fields["J"]; PHX::MDField<ScalarT> poissons_ratio = *dep_fields["Poissons Ratio"]; PHX::MDField<ScalarT> elastic_modulus = *dep_fields["Elastic Modulus"]; // extract evaluated MDFields std::string cauchy = (*field_name_map_)["Cauchy_Stress"]; PHX::MDField<ScalarT> stress = *eval_fields[cauchy]; ScalarT lambda; ScalarT mu; Intrepid::Tensor<ScalarT> F(num_dims_), C(num_dims_), sigma(num_dims_); Intrepid::Tensor<ScalarT> I(Intrepid::eye<ScalarT>(num_dims_)); Intrepid::Tensor<ScalarT> S(num_dims_), E(num_dims_); for (int cell(0); cell < workset.numCells; ++cell) { for (int pt(0); pt < num_pts_; ++pt) { lambda = (elastic_modulus(cell, pt) * poissons_ratio(cell, pt)) / (1. + poissons_ratio(cell, pt)) / (1 - 2 * poissons_ratio(cell, pt)); mu = elastic_modulus(cell, pt) / (2. * (1. + poissons_ratio(cell, pt))); F.fill(def_grad,cell, pt,0,0); C = F * transpose(F); E = 0.5 * ( C - I ); S = lambda * Intrepid::trace(E) * I + 2.0 * mu * E; sigma = (1.0 / Intrepid::det(F) ) * F * S * Intrepid::transpose(F); 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 HyperelasticDamageModel<EvalT, Traits>:: computeState(typename Traits::EvalData workset, std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > dep_fields, std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > eval_fields) { // extract dependent MDFields PHX::MDField<ScalarT> def_grad = *dep_fields["F"]; PHX::MDField<ScalarT> J = *dep_fields["J"]; PHX::MDField<ScalarT> poissons_ratio = *dep_fields["Poissons Ratio"]; PHX::MDField<ScalarT> elastic_modulus = *dep_fields["Elastic Modulus"]; PHX::MDField<ScalarT> delta_time = *dep_fields["Delta Time"]; // extract evaluated MDFields std::string cauchy = (*field_name_map_)["Cauchy_Stress"]; PHX::MDField<ScalarT> stress = *eval_fields[cauchy]; PHX::MDField<ScalarT> alpha = *eval_fields["alpha"]; PHX::MDField<ScalarT> damage; if (!have_damage_) { damage = *eval_fields["local damage"]; } PHX::MDField<ScalarT> source = *eval_fields["Damage_Source"]; //get state variables Albany::MDArray alpha_old = (*workset.stateArrayPtr)["alpha_old"]; ScalarT kappa; ScalarT mu, mubar; ScalarT Jm53, Jm23; ScalarT smag; ScalarT energy; ScalarT dt = delta_time(0); Intrepid::Tensor<ScalarT> F(num_dims_), b(num_dims_), sigma(num_dims_); Intrepid::Tensor<ScalarT> I(Intrepid::eye<ScalarT>(num_dims_)); Intrepid::Tensor<ScalarT> s(num_dims_), n(num_dims_); for (int cell(0); cell < workset.numCells; ++cell) { for (int pt(0); pt < num_pts_; ++pt) { kappa = elastic_modulus(cell, pt) / (3. * (1. - 2. * poissons_ratio(cell, pt))); mu = elastic_modulus(cell, pt) / (2. * (1. + poissons_ratio(cell, pt))); Jm53 = std::pow(J(cell, pt), -5. / 3.); Jm23 = Jm53 * J(cell, pt); F.fill(def_grad,cell, pt,0,0); b = F * transpose(F); mubar = (1.0 / 3.0) * mu * Jm23 * Intrepid::trace(b); sigma = 0.5 * kappa * (J(cell, pt) - 1. / J(cell, pt)) * I + mu * Jm53 * Intrepid::dev(b); energy = 0.5 * kappa * (0.5 * (J(cell, pt) * J(cell, pt) - 1.0) - std::log(J(cell, pt))) + 0.5 * mu * (Jm23 * Intrepid::trace(b) - 3.0); if (have_temperature_) { ScalarT delta_temp = temperature_(cell, pt) - ref_temperature_; energy += heat_capacity_ * ((delta_temp) - temperature_(cell, pt) * std::log(temperature_(cell, pt) / ref_temperature_)) - 3.0 * expansion_coeff_ * (J(cell, pt) - 1.0 / J(cell, pt)) * delta_temp; sigma -= expansion_coeff_ * (1.0 + 1.0 / (J(cell, pt) * J(cell, pt))) * delta_temp * I; } alpha(cell, pt) = std::max((ScalarT) alpha_old(cell, pt), energy); source(cell, pt) = (max_damage_ / damage_saturation_) * std::exp(-alpha(cell, pt) / damage_saturation_) * (alpha(cell, pt) - alpha_old(cell, pt)) / dt; if (!have_damage_) { damage(cell, pt) = max_damage_ * (1.0 - std::exp(-alpha(cell, pt) / damage_saturation_)); } for (int i = 0; i < num_dims_; ++i) { for (int j = 0; j < num_dims_; ++j) { stress(cell, pt, i, j) = (1.0 - damage(cell, pt)) * sigma(i, j); } } } } }
void DruckerPragerModel<EvalT, Traits>:: computeState(typename Traits::EvalData workset, std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > dep_fields, std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > eval_fields) { // extract dependent MDFields PHX::MDField<ScalarT> strain = *dep_fields["Strain"]; PHX::MDField<ScalarT> poissons_ratio = *dep_fields["Poissons Ratio"]; PHX::MDField<ScalarT> elastic_modulus = *dep_fields["Elastic Modulus"]; // retrieve appropriate field name strings std::string cauchy_string = (*field_name_map_)["Cauchy_Stress"]; std::string strain_string = (*field_name_map_)["Strain"]; std::string eqps_string = (*field_name_map_)["eqps"]; std::string friction_string = (*field_name_map_)["Friction_Parameter"]; // extract evaluated MDFields PHX::MDField<ScalarT> stress = *eval_fields[cauchy_string]; PHX::MDField<ScalarT> eqps = *eval_fields[eqps_string]; PHX::MDField<ScalarT> friction = *eval_fields[friction_string]; PHX::MDField<ScalarT> tangent = *eval_fields["Material Tangent"]; // get State Variables Albany::MDArray strainold = (*workset.stateArrayPtr)[strain_string + "_old"]; Albany::MDArray stressold = (*workset.stateArrayPtr)[cauchy_string + "_old"]; Albany::MDArray eqpsold = (*workset.stateArrayPtr)[eqps_string + "_old"]; Albany::MDArray frictionold = (*workset.stateArrayPtr)[friction_string + "_old"]; Intrepid::Tensor<ScalarT> id(Intrepid::eye<ScalarT>(num_dims_)); Intrepid::Tensor4<ScalarT> id1(Intrepid::identity_1<ScalarT>(num_dims_)); Intrepid::Tensor4<ScalarT> id2(Intrepid::identity_2<ScalarT>(num_dims_)); Intrepid::Tensor4<ScalarT> id3(Intrepid::identity_3<ScalarT>(num_dims_)); Intrepid::Tensor4<ScalarT> Celastic (num_dims_); Intrepid::Tensor<ScalarT> sigma(num_dims_), sigmaN(num_dims_), s(num_dims_); Intrepid::Tensor<ScalarT> epsilon(num_dims_), epsilonN(num_dims_); Intrepid::Tensor<ScalarT> depsilon(num_dims_); Intrepid::Tensor<ScalarT> nhat(num_dims_); ScalarT lambda, mu, kappa; ScalarT alpha, alphaN; ScalarT p, q, ptr, qtr; ScalarT eq, eqN, deq; ScalarT snorm; ScalarT Phi; //local unknowns and residual vectors std::vector<ScalarT> X(4); std::vector<ScalarT> R(4); std::vector<ScalarT> dRdX(16); for (std::size_t cell(0); cell < workset.numCells; ++cell) { for (std::size_t pt(0); pt < num_pts_; ++pt) { lambda = ( elastic_modulus(cell,pt) * poissons_ratio(cell,pt) ) / ( ( 1 + poissons_ratio(cell,pt) ) * ( 1 - 2 * poissons_ratio(cell,pt) ) ); mu = elastic_modulus(cell,pt) / ( 2 * ( 1 + poissons_ratio(cell,pt) ) ); kappa = lambda + 2.0 * mu / 3.0; // 4-th order elasticity tensor Celastic = lambda * id3 + mu * (id1 + id2); // previous state (the fill doesn't work for state virable) //sigmaN.fill( &stressold(cell,pt,0,0) ); //epsilonN.fill( &strainold(cell,pt,0,0) ); for (std::size_t i(0); i < num_dims_; ++i) { for (std::size_t j(0); j < num_dims_; ++j) { sigmaN(i, j) = stressold(cell, pt, i, j); epsilonN(i, j) = strainold(cell, pt, i, j); //epsilon(i,j) = strain(cell,pt,i,j); } } epsilon.fill( &strain(cell,pt,0,0) ); depsilon = epsilon - epsilonN; alphaN = frictionold(cell,pt); eqN = eqpsold(cell,pt); // trial state sigma = sigmaN + Intrepid::dotdot(Celastic,depsilon); ptr = Intrepid::trace(sigma) / 3.0; s = sigma - ptr * id; snorm = Intrepid::dotdot(s,s); if(snorm > 0) snorm = std::sqrt(snorm); qtr = sqrt(3.0/2.0) * snorm; // unit deviatoric tensor if (snorm > 0){ nhat = s / snorm; } else{ nhat = id; } // check yielding Phi = qtr + alphaN * ptr - Cf_; alpha = alphaN; p = ptr; q = qtr; deq = 0.0; if(Phi > 1.0e-12) {// plastic yielding // initialize local unknown vector X[0] = ptr; X[1] = qtr; X[2] = alpha; X[3] = deq; LocalNonlinearSolver<EvalT, Traits> solver; int iter = 0; ScalarT norm_residual0(0.0), norm_residual(0.0), relative_residual(0.0); // local N-R loop while (true) { ResidualJacobian(X, R, dRdX, ptr, qtr, eqN, mu, kappa); norm_residual = 0.0; for (int i = 0; i < 4; i++) norm_residual += R[i] * R[i]; norm_residual = std::sqrt(norm_residual); if (iter == 0) norm_residual0 = norm_residual; if (norm_residual0 != 0) relative_residual = norm_residual / norm_residual0; else relative_residual = norm_residual0; //std::cout << iter << " " //<< Sacado::ScalarValue<ScalarT>::eval(norm_residual) //<< " " << Sacado::ScalarValue<ScalarT>::eval(relative_residual) //<< std::endl; if (relative_residual < 1.0e-11 || norm_residual < 1.0e-11) break; if (iter > 20) break; // call local nonlinear solver solver.solve(dRdX, X, R); iter++; } // end of local N-R loop // compute sensitivity information w.r.t. system parameters // and pack the sensitivity back to X solver.computeFadInfo(dRdX, X, R); // update p = X[0]; q = X[1]; alpha = X[2]; deq = X[3]; }//end plastic yielding eq = eqN + deq; s = sqrt(2.0/3.0) * q * nhat; sigma = s + p * id; eqps(cell, pt) = eq; friction(cell,pt) = alpha; 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) = sigma(i, j); } } }// end loop over pt } // end loop over cell }
void ElasticDamageModel<EvalT, Traits>:: computeState(typename Traits::EvalData workset, std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT>>> dep_fields, std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT>>> eval_fields) { //bool print = false; //if (typeid(ScalarT) == typeid(RealType)) print = true; //cout.precision(15); // extract dependent MDFields PHX::MDField<ScalarT> strain = *dep_fields["Strain"]; PHX::MDField<ScalarT> poissons_ratio = *dep_fields["Poissons Ratio"]; PHX::MDField<ScalarT> elastic_modulus = *dep_fields["Elastic Modulus"]; // retrieve appropriate field name strings std::string cauchy_string = (*field_name_map_)["Cauchy_Stress"]; std::string energy_string = (*field_name_map_)["Matrix_Energy"]; std::string damage_string = (*field_name_map_)["Matrix_Damage"]; std::string tangent_string = (*field_name_map_)["Material Tangent"]; // extract evaluated MDFields PHX::MDField<ScalarT> stress = *eval_fields[cauchy_string]; PHX::MDField<ScalarT> energy = *eval_fields[energy_string]; PHX::MDField<ScalarT> damage = *eval_fields[damage_string]; PHX::MDField<ScalarT> tangent; if(compute_tangent_) { tangent = *eval_fields[tangent_string]; } // previous state Albany::MDArray energy_old = (*workset.stateArrayPtr)[energy_string + "_old"]; ScalarT mu, lame; ScalarT alpha, damage_deriv; // Define some tensors for use Intrepid::Tensor<ScalarT> I(Intrepid::eye<ScalarT>(num_dims_)); Intrepid::Tensor<ScalarT> epsilon(num_dims_), sigma(num_dims_); Intrepid::Tensor4<ScalarT> Ce(num_dims_); Intrepid::Tensor4<ScalarT> id4(num_dims_); Intrepid::Tensor4<ScalarT> id3(Intrepid::identity_3<ScalarT>(num_dims_)); id4 = 0.5 * (Intrepid::identity_1<ScalarT>(num_dims_) + Intrepid::identity_2<ScalarT>(num_dims_)); for (int cell = 0; cell < workset.numCells; ++cell) { for (int pt = 0; pt < num_pts_; ++pt) { // local parameters mu = elastic_modulus(cell, pt) / (2.0 * (1.0 + poissons_ratio(cell, pt))); lame = elastic_modulus(cell, pt) * poissons_ratio(cell, pt) / (1.0 + poissons_ratio(cell, pt)) / (1.0 - 2.0 * poissons_ratio(cell, pt)); // small strain tensor epsilon.fill(strain,cell, pt,0,0); // undamaged elasticity tensor Ce = lame * id3 + 2.0 * mu * id4; // undamaged energy energy(cell, pt) = 0.5 * Intrepid::dotdot(Intrepid::dotdot(epsilon, Ce), epsilon); // undamaged Cauchy stress sigma = Intrepid::dotdot(Ce, epsilon); // maximum thermodynamic force alpha = energy_old(cell, pt); if (energy(cell, pt) > alpha) alpha = energy(cell, pt); // damage term damage(cell, pt) = max_damage_ * (1 - std::exp(-alpha / saturation_)); // derivative of damage w.r.t alpha damage_deriv = max_damage_ / saturation_ * std::exp(-alpha / saturation_); // tangent for matrix considering damage if(compute_tangent_) { Ce = (1.0 - damage(cell, pt)) * Ce - damage_deriv * Intrepid::tensor(sigma, sigma); } // total Cauchy stress for (int i(0); i < num_dims_; ++i) { for (int j(0); j < num_dims_; ++j) { stress(cell, pt, i, j) = (1.0 - damage(cell, pt)) * sigma(i, j); } } // total tangent if(compute_tangent_) { for (int i(0); i < num_dims_; ++i) { for (int j(0); j < num_dims_; ++j) { for (int k(0); k < num_dims_; ++k) { for (int l(0); l < num_dims_; ++l) { tangent(cell, pt, i, j, k, l) = Ce(i, j, k, l); } } } } }// compute_tangent_ } // pt } // cell }
void AnisotropicHyperelasticDamageModel<EvalT, Traits>:: computeState(typename Traits::EvalData workset, std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT>>> dep_fields, std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT>>> eval_fields) { bool print = false; //if (typeid(ScalarT) == typeid(RealType)) print = true; //cout.precision(15); // retrive appropriate field name strings std::string F_string = (*field_name_map_)["F"]; std::string J_string = (*field_name_map_)["J"]; std::string cauchy_string = (*field_name_map_)["Cauchy_Stress"]; std::string matrix_energy_string = (*field_name_map_)["Matrix_Energy"]; std::string f1_energy_string = (*field_name_map_)["F1_Energy"]; std::string f2_energy_string = (*field_name_map_)["F2_Energy"]; std::string matrix_damage_string = (*field_name_map_)["Matrix_Damage"]; std::string f1_damage_string = (*field_name_map_)["F1_Damage"]; std::string f2_damage_string = (*field_name_map_)["F2_Damage"]; // extract dependent MDFields PHX::MDField<ScalarT> def_grad = *dep_fields[F_string]; PHX::MDField<ScalarT> J = *dep_fields[J_string]; PHX::MDField<ScalarT> poissons_ratio = *dep_fields["Poissons Ratio"]; PHX::MDField<ScalarT> elastic_modulus = *dep_fields["Elastic Modulus"]; // extract evaluated MDFields PHX::MDField<ScalarT> stress = *eval_fields[cauchy_string]; PHX::MDField<ScalarT> energy_m = *eval_fields[matrix_energy_string]; PHX::MDField<ScalarT> energy_f1 = *eval_fields[f1_energy_string]; PHX::MDField<ScalarT> energy_f2 = *eval_fields[f2_energy_string]; PHX::MDField<ScalarT> damage_m = *eval_fields[matrix_damage_string]; PHX::MDField<ScalarT> damage_f1 = *eval_fields[f1_damage_string]; PHX::MDField<ScalarT> damage_f2 = *eval_fields[f2_damage_string]; // previous state Albany::MDArray energy_m_old = (*workset.stateArrayPtr)[matrix_energy_string + "_old"]; Albany::MDArray energy_f1_old = (*workset.stateArrayPtr)[f1_energy_string + "_old"]; Albany::MDArray energy_f2_old = (*workset.stateArrayPtr)[f2_energy_string + "_old"]; ScalarT kappa, mu, Jm53, Jm23, p, I4_f1, I4_f2; ScalarT alpha_f1, alpha_f2, alpha_m; // Define some tensors for use Intrepid::Tensor<ScalarT> I(Intrepid::eye<ScalarT>(num_dims_)); Intrepid::Tensor<ScalarT> F(num_dims_), s(num_dims_), b(num_dims_), C( num_dims_); Intrepid::Tensor<ScalarT> sigma_m(num_dims_), sigma_f1(num_dims_), sigma_f2( num_dims_); Intrepid::Tensor<ScalarT> M1dyadM1(num_dims_), M2dyadM2(num_dims_); Intrepid::Tensor<ScalarT> S0_f1(num_dims_), S0_f2(num_dims_); Intrepid::Vector<ScalarT> M1(num_dims_), M2(num_dims_); for (int cell = 0; cell < workset.numCells; ++cell) { for (int pt = 0; pt < num_pts_; ++pt) { // local parameters kappa = elastic_modulus(cell, pt) / (3. * (1. - 2. * poissons_ratio(cell, pt))); mu = elastic_modulus(cell, pt) / (2. * (1. + poissons_ratio(cell, pt))); Jm53 = std::pow(J(cell, pt), -5. / 3.); Jm23 = std::pow(J(cell, pt), -2. / 3.); F.fill(def_grad,cell, pt,0,0); // compute deviatoric stress b = F * Intrepid::transpose(F); s = mu * Jm53 * Intrepid::dev(b); // compute pressure p = 0.5 * kappa * (J(cell, pt) - 1. / (J(cell, pt))); sigma_m = s + p * I; // compute energy for M energy_m(cell, pt) = 0.5 * kappa * (0.5 * (J(cell, pt) * J(cell, pt) - 1.0) - std::log(J(cell, pt))) + 0.5 * mu * (Jm23 * Intrepid::trace(b) - 3.0); // damage term in M alpha_m = energy_m_old(cell, pt); if (energy_m(cell, pt) > alpha_m) alpha_m = energy_m(cell, pt); damage_m(cell, pt) = max_damage_m_ * (1 - std::exp(-alpha_m / saturation_m_)); //-----------compute stress in Fibers // Right Cauchy-Green Tensor C = F^{T} * F C = Intrepid::transpose(F) * F; // Fiber orientation vectors // // fiber 1 for (int i = 0; i < num_dims_; ++i) { M1(i) = direction_f1_[i]; } M1 = M1 / norm(M1); // fiber 2 for (int i = 0; i < num_dims_; ++i) { M2(i) = direction_f2_[i]; } M2 = M2 / norm(M2); // Anisotropic invariants I4 = M_{i} * C * M_{i} I4_f1 = Intrepid::dot(M1, Intrepid::dot(C, M1)); I4_f2 = Intrepid::dot(M2, Intrepid::dot(C, M2)); M1dyadM1 = Intrepid::dyad(M1, M1); M2dyadM2 = Intrepid::dyad(M2, M2); // undamaged stress (2nd PK stress) S0_f1 = (4.0 * k_f1_ * (I4_f1 - 1.0) * std::exp(q_f1_ * (I4_f1 - 1) * (I4_f1 - 1))) * M1dyadM1; S0_f2 = (4.0 * k_f2_ * (I4_f2 - 1.0) * std::exp(q_f2_ * (I4_f2 - 1) * (I4_f2 - 1))) * M2dyadM2; // compute energy for fibers energy_f1(cell, pt) = k_f1_ * (std::exp(q_f1_ * (I4_f1 - 1) * (I4_f1 - 1)) - 1) / q_f1_; energy_f2(cell, pt) = k_f2_ * (std::exp(q_f2_ * (I4_f2 - 1) * (I4_f2 - 1)) - 1) / q_f2_; // Fiber Cauchy stress sigma_f1 = (1.0 / J(cell, pt)) * Intrepid::dot(F, Intrepid::dot(S0_f1, Intrepid::transpose(F))); sigma_f2 = (1.0 / J(cell, pt)) * Intrepid::dot(F, Intrepid::dot(S0_f2, Intrepid::transpose(F))); // maximum thermodynamic forces alpha_f1 = energy_f1_old(cell, pt); alpha_f2 = energy_f2_old(cell, pt); if (energy_f1(cell, pt) > alpha_f1) alpha_f1 = energy_f1(cell, pt); if (energy_f2(cell, pt) > alpha_f2) alpha_f2 = energy_f2(cell, pt); // damage term in fibers damage_f1(cell, pt) = max_damage_f1_ * (1 - std::exp(-alpha_f1 / saturation_f1_)); damage_f2(cell, pt) = max_damage_f2_ * (1 - std::exp(-alpha_f2 / saturation_f2_)); // total Cauchy stress (M, Fibers) for (int i(0); i < num_dims_; ++i) { for (int j(0); j < num_dims_; ++j) { stress(cell, pt, i, j) = volume_fraction_m_ * (1 - damage_m(cell, pt)) * sigma_m(i, j) + volume_fraction_f1_ * (1 - damage_f1(cell, pt)) * sigma_f1(i, j) + volume_fraction_f2_ * (1 - damage_f2(cell, pt)) * sigma_f2(i, j); } } if (print) { std::cout << " matrix damage: " << damage_m(cell, pt) << std::endl; std::cout << " matrix energy: " << energy_m(cell, pt) << std::endl; std::cout << " fiber1 damage: " << damage_f1(cell, pt) << std::endl; std::cout << " fiber1 energy: " << energy_f1(cell, pt) << std::endl; std::cout << " fiber2 damage: " << damage_f2(cell, pt) << std::endl; std::cout << " fiber2 energy: " << energy_f2(cell, pt) << std::endl; } } // pt } // cell }
void ElastoViscoplasticModel<EvalT, Traits>:: computeState(typename Traits::EvalData workset, std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > dep_fields, std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > eval_fields) { std::string cauchy_string = (*field_name_map_)["Cauchy_Stress"]; std::string Fp_string = (*field_name_map_)["Fp"]; std::string eqps_string = (*field_name_map_)["eqps"]; std::string eps_ss_string = (*field_name_map_)["eps_ss"]; std::string kappa_string = (*field_name_map_)["isotropic_hardening"]; std::string source_string = (*field_name_map_)["Mechanical_Source"]; std::string F_string = (*field_name_map_)["F"]; std::string J_string = (*field_name_map_)["J"]; // extract dependent MDFields PHX::MDField<ScalarT> def_grad_field = *dep_fields[F_string]; PHX::MDField<ScalarT> J = *dep_fields[J_string]; PHX::MDField<ScalarT> poissons_ratio = *dep_fields["Poissons Ratio"]; PHX::MDField<ScalarT> elastic_modulus = *dep_fields["Elastic Modulus"]; PHX::MDField<ScalarT> yield_strength = *dep_fields["Yield Strength"]; PHX::MDField<ScalarT> hardening_modulus = *dep_fields["Hardening Modulus"]; PHX::MDField<ScalarT> recovery_modulus = *dep_fields["Recovery Modulus"]; PHX::MDField<ScalarT> flow_exp = *dep_fields["Flow Rule Exponent"]; PHX::MDField<ScalarT> flow_coeff = *dep_fields["Flow Rule Coefficient"]; PHX::MDField<ScalarT> delta_time = *dep_fields["Delta Time"]; // extract evaluated MDFields PHX::MDField<ScalarT> stress_field = *eval_fields[cauchy_string]; PHX::MDField<ScalarT> Fp_field = *eval_fields[Fp_string]; PHX::MDField<ScalarT> eqps_field = *eval_fields[eqps_string]; PHX::MDField<ScalarT> eps_ss_field = *eval_fields[eps_ss_string]; PHX::MDField<ScalarT> kappa_field = *eval_fields[kappa_string]; PHX::MDField<ScalarT> source_field; if (have_temperature_) { source_field = *eval_fields[source_string]; } // get State Variables Albany::MDArray Fp_field_old = (*workset.stateArrayPtr)[Fp_string + "_old"]; Albany::MDArray eqps_field_old = (*workset.stateArrayPtr)[eqps_string + "_old"]; Albany::MDArray eps_ss_field_old = (*workset.stateArrayPtr)[eps_ss_string + "_old"]; Albany::MDArray kappa_field_old = (*workset.stateArrayPtr)[kappa_string + "_old"]; // define constants RealType sq23(std::sqrt(2. / 3.)); RealType sq32(std::sqrt(3. / 2.)); // pre-define some tensors that will be re-used below Intrepid::Tensor<ScalarT> F(num_dims_), be(num_dims_); Intrepid::Tensor<ScalarT> s(num_dims_), sigma(num_dims_); Intrepid::Tensor<ScalarT> N(num_dims_), A(num_dims_); Intrepid::Tensor<ScalarT> expA(num_dims_), Fpnew(num_dims_); Intrepid::Tensor<ScalarT> I(Intrepid::eye<ScalarT>(num_dims_)); Intrepid::Tensor<ScalarT> Fpn(num_dims_), Cpinv(num_dims_), Fpinv(num_dims_); for (std::size_t cell(0); cell < workset.numCells; ++cell) { for (std::size_t pt(0); pt < num_pts_; ++pt) { ScalarT bulk = elastic_modulus(cell, pt) / (3. * (1. - 2. * poissons_ratio(cell, pt))); ScalarT mu = elastic_modulus(cell, pt) / (2. * (1. + poissons_ratio(cell, pt))); ScalarT Y = yield_strength(cell, pt); ScalarT Jm23 = std::pow(J(cell, pt), -2. / 3.); // assign local state variables // //ScalarT kappa = kappa_field(cell,pt); ScalarT kappa_old = kappa_field_old(cell,pt); ScalarT eps_ss = eps_ss_field(cell,pt); ScalarT eps_ss_old = eps_ss_field_old(cell,pt); ScalarT eqps_old = eqps_field_old(cell,pt); // fill local tensors // F.fill(&def_grad_field(cell, pt, 0, 0)); for (std::size_t i(0); i < num_dims_; ++i) { for (std::size_t j(0); j < num_dims_; ++j) { Fpn(i, j) = ScalarT(Fp_field_old(cell, pt, i, j)); } } // compute trial state // compute the Kirchhoff stress in the current configuration // Cpinv = Intrepid::inverse(Fpn) * Intrepid::transpose(Intrepid::inverse(Fpn)); be = Jm23 * F * Cpinv * Intrepid::transpose(F); s = mu * Intrepid::dev(be); ScalarT smag = Intrepid::norm(s); ScalarT mubar = Intrepid::trace(be) * mu / (num_dims_); // check yield condition // ScalarT Phi = sq32 * smag - ( Y + kappa_old ); std::cout << "======== Phi: " << Phi << std::endl; std::cout << "======== eps: " << std::numeric_limits<RealType>::epsilon() << std::endl; if (Phi > std::numeric_limits<RealType>::epsilon()) { // return mapping algorithm // bool converged = false; int iter = 0; RealType max_norm = std::numeric_limits<RealType>::min(); // hardening and recovery parameters // ScalarT H = hardening_modulus(cell, pt); ScalarT Rd = recovery_modulus(cell, pt); // flow rule temperature dependent parameters // ScalarT f = flow_coeff(cell,pt); ScalarT n = flow_exp(cell,pt); // This solver deals with Sacado type info // LocalNonlinearSolver<EvalT, Traits> solver; // create some vectors to store solver data // std::vector<ScalarT> R(2); std::vector<ScalarT> dRdX(4); std::vector<ScalarT> X(2); // initial guess X[0] = 0.0; X[1] = eps_ss_old; // create a copy of be as a Fad Intrepid::Tensor<Fad> beF(num_dims_); for (std::size_t i = 0; i < num_dims_; ++i) { for (std::size_t j = 0; j < num_dims_; ++j) { beF(i, j) = be(i, j); } } Fad two_mubarF = 2.0 * Intrepid::trace(beF) * mu / (num_dims_); //Fad sq32F = std::sqrt(3.0/2.0); // FIXME this seems to be necessary to get PhiF to compile below // need to look into this more, it appears to be a conflict // between the Intrepid::norm and FadType operations // Fad smagF = smag; while (!converged) { // set up data types // std::vector<Fad> XFad(2); std::vector<Fad> RFad(2); std::vector<ScalarT> Xval(2); for (std::size_t i = 0; i < 2; ++i) { Xval[i] = Sacado::ScalarValue<ScalarT>::eval(X[i]); XFad[i] = Fad(2, i, Xval[i]); } // get solution vars // Fad dgamF = XFad[0]; Fad eps_ssF = XFad[1]; // compute yield function // Fad eqps_rateF = 0.0; if (delta_time(0) > 0) eqps_rateF = sq23 * dgamF / delta_time(0); Fad rate_termF = 1.0 + std::asinh( std::pow(eqps_rateF / f, n)); Fad kappaF = two_mubarF * eps_ssF; Fad PhiF = sq32 * (smagF - two_mubarF * dgamF) - ( Y + kappaF ) * rate_termF; // compute the hardening residual // Fad eps_resF = eps_ssF - eps_ss_old - (H - Rd*eps_ssF) * dgamF; // for convenience put the residuals into a container // RFad[0] = PhiF; RFad[1] = eps_resF; // extract the values of the residuals // for (int i = 0; i < 2; ++i) R[i] = RFad[i].val(); // extract the sensitivities of the residuals // for (int i = 0; i < 2; ++i) for (int j = 0; j < 2; ++j) dRdX[i + 2 * j] = RFad[i].dx(j); // this call invokes the solver and updates the solution in X // solver.solve(dRdX, X, R); // compute the norm of the residual // RealType R0 = Sacado::ScalarValue<ScalarT>::eval(R[0]); RealType R1 = Sacado::ScalarValue<ScalarT>::eval(R[1]); RealType norm_res = std::sqrt(R0*R0 + R1*R1); max_norm = std::max(norm_res, max_norm); // check against too many inerations // TEUCHOS_TEST_FOR_EXCEPTION(iter == 30, std::runtime_error, std::endl << "Error in ElastoViscoplastic return mapping\n" << "iter count = " << iter << "\n" << std::endl); // check for a sufficiently small residual // std::cout << "======== norm_res : " << norm_res << std::endl; if ( (norm_res/max_norm < 1.e-12) || (norm_res < 1.e-12) ) converged = true; // increment the iteratio counter // iter++; } solver.computeFadInfo(dRdX, X, R); ScalarT dgam = X[0]; ScalarT eps_ss = X[1]; ScalarT kappa = 2.0 * mubar * eps_ss; std::cout << "======== dgam : " << dgam << std::endl; std::cout << "======== e_ss : " << eps_ss << std::endl; std::cout << "======== kapp : " << kappa << std::endl; // plastic direction N = (1 / smag) * s; // update s s -= 2 * mubar * dgam * N; // update state variables eps_ss_field(cell, pt) = eps_ss; eqps_field(cell,pt) = eqps_old + sq23 * dgam; kappa_field(cell,pt) = kappa; // mechanical source // FIXME this is not correct, just a placeholder // if (have_temperature_ && delta_time(0) > 0) { source_field(cell, pt) = (sq23 * dgam / delta_time(0)) * (Y + kappa) / (density_ * heat_capacity_); } // exponential map to get Fpnew // A = dgam * N; expA = Intrepid::exp(A); Fpnew = expA * Fpn; for (std::size_t i(0); i < num_dims_; ++i) { for (std::size_t j(0); j < num_dims_; ++j) { Fp_field(cell, pt, i, j) = Fpnew(i, j); } } } else { // we are not yielding, variables do not evolve // eps_ss_field(cell, pt) = eps_ss_old; eqps_field(cell,pt) = eqps_old; kappa_field(cell,pt) = kappa_old; if (have_temperature_) source_field(cell, pt) = 0.0; for (std::size_t i(0); i < num_dims_; ++i) { for (std::size_t j(0); j < num_dims_; ++j) { Fp_field(cell, pt, i, j) = Fpn(i, j); } } } // compute pressure ScalarT p = 0.5 * bulk * (J(cell, pt) - 1. / (J(cell, pt))); // compute stress sigma = p * I + s / J(cell, pt); for (std::size_t i(0); i < num_dims_; ++i) { for (std::size_t j(0); j < num_dims_; ++j) { stress_field(cell, pt, i, j) = sigma(i, j); } } } } if (have_temperature_) { for (std::size_t cell(0); cell < workset.numCells; ++cell) { for (std::size_t pt(0); pt < num_pts_; ++pt) { F.fill(&def_grad_field(cell,pt,0,0)); ScalarT J = Intrepid::det(F); sigma.fill(&stress_field(cell,pt,0,0)); sigma -= 3.0 * expansion_coeff_ * (1.0 + 1.0 / (J*J)) * (temperature_(cell,pt) - ref_temperature_) * I; for (std::size_t i = 0; i < num_dims_; ++i) { for (std::size_t j = 0; j < num_dims_; ++j) { stress_field(cell, pt, i, j) = sigma(i, j); } } } } } }