00001
00002
00003
00004
00005
00006
00007 #include <Intrepid_MiniTensor.h>
00008 #include "Teuchos_TestForException.hpp"
00009 #include "Phalanx_DataLayout.hpp"
00010
00011 #include "LocalNonlinearSolver.hpp"
00012
00013 namespace LCM
00014 {
00015
00016
00017 template<typename EvalT, typename Traits>
00018 GursonHMRModel<EvalT, Traits>::
00019 GursonHMRModel(Teuchos::ParameterList* p,
00020 const Teuchos::RCP<Albany::Layouts>& dl) :
00021 LCM::ConstitutiveModel<EvalT, Traits>(p, dl),
00022 sat_mod_(p->get<RealType>("Saturation Modulus", 0.0)),
00023 sat_exp_(p->get<RealType>("Saturation Exponent", 0.0)),
00024 f0_(p->get<RealType>("Initial Void Volume", 0.0)),
00025 kw_(p->get<RealType>("Shear Damage Parameter", 0.0)),
00026 eN_(p->get<RealType>("Void Nucleation Parameter eN", 0.0)),
00027 sN_(p->get<RealType>("Void Nucleation Parameter sN", 0.1)),
00028 fN_(p->get<RealType>("Void Nucleation Parameter fN", 0.0)),
00029 fc_(p->get<RealType>("Critical Void Volume", 1.0)),
00030 ff_(p->get<RealType>("Failure Void Volume", 1.0)),
00031 q1_(p->get<RealType>("Yield Parameter q1", 1.0)),
00032 q2_(p->get<RealType>("Yield Parameter q2", 1.0)),
00033 q3_(p->get<RealType>("Yield Parameter q3", 1.0))
00034 {
00035
00036 this->dep_field_map_.insert(std::make_pair("F", dl->qp_tensor));
00037 this->dep_field_map_.insert(std::make_pair("J", dl->qp_scalar));
00038 this->dep_field_map_.insert(std::make_pair("Poissons Ratio", dl->qp_scalar));
00039 this->dep_field_map_.insert(std::make_pair("Elastic Modulus", dl->qp_scalar));
00040 this->dep_field_map_.insert(std::make_pair("Yield Strength", dl->qp_scalar));
00041 this->dep_field_map_.insert(
00042 std::make_pair("Hardening Modulus", dl->qp_scalar));
00043 this->dep_field_map_.insert(
00044 std::make_pair("Recovery Modulus", dl->qp_scalar));
00045
00046
00047 std::string cauchy_string = (*field_name_map_)["Cauchy_Stress"];
00048 std::string Fp_string = (*field_name_map_)["Fp"];
00049 std::string eqps_string = (*field_name_map_)["eqps"];
00050 std::string ess_string = (*field_name_map_)["ess"];
00051 std::string isoHardening_string = (*field_name_map_)["isoHardening"];
00052 std::string void_string = (*field_name_map_)["Void_Volume"];
00053
00054
00055 this->eval_field_map_.insert(std::make_pair(cauchy_string, dl->qp_tensor));
00056 this->eval_field_map_.insert(std::make_pair(Fp_string, dl->qp_tensor));
00057 this->eval_field_map_.insert(std::make_pair(eqps_string, dl->qp_scalar));
00058 this->eval_field_map_.insert(std::make_pair(ess_string, dl->qp_scalar));
00059 this->eval_field_map_.insert(
00060 std::make_pair(isoHardening_string, dl->qp_scalar));
00061 this->eval_field_map_.insert(std::make_pair(void_string, dl->qp_scalar));
00062
00063
00064
00065
00066 this->num_state_variables_++;
00067 this->state_var_names_.push_back(cauchy_string);
00068 this->state_var_layouts_.push_back(dl->qp_tensor);
00069 this->state_var_init_types_.push_back("scalar");
00070 this->state_var_init_values_.push_back(0.0);
00071 this->state_var_old_state_flags_.push_back(false);
00072 this->state_var_output_flags_.push_back(true);
00073
00074
00075 this->num_state_variables_++;
00076 this->state_var_names_.push_back(Fp_string);
00077 this->state_var_layouts_.push_back(dl->qp_tensor);
00078 this->state_var_init_types_.push_back("identity");
00079 this->state_var_init_values_.push_back(1.0);
00080 this->state_var_old_state_flags_.push_back(true);
00081 this->state_var_output_flags_.push_back(false);
00082
00083
00084 this->num_state_variables_++;
00085 this->state_var_names_.push_back(eqps_string);
00086 this->state_var_layouts_.push_back(dl->qp_scalar);
00087 this->state_var_init_types_.push_back("scalar");
00088 this->state_var_init_values_.push_back(0.0);
00089 this->state_var_old_state_flags_.push_back(true);
00090 this->state_var_output_flags_.push_back(true);
00091
00092
00093 this->num_state_variables_++;
00094 this->state_var_names_.push_back(ess_string);
00095 this->state_var_layouts_.push_back(dl->qp_scalar);
00096 this->state_var_init_types_.push_back("scalar");
00097 this->state_var_init_values_.push_back(0.0);
00098 this->state_var_old_state_flags_.push_back(true);
00099 this->state_var_output_flags_.push_back(true);
00100
00101
00102 this->num_state_variables_++;
00103 this->state_var_names_.push_back(isoHardening_string);
00104 this->state_var_layouts_.push_back(dl->qp_scalar);
00105 this->state_var_init_types_.push_back("scalar");
00106 this->state_var_init_values_.push_back(0.0);
00107 this->state_var_old_state_flags_.push_back(true);
00108 this->state_var_output_flags_.push_back(true);
00109
00110
00111 this->num_state_variables_++;
00112 this->state_var_names_.push_back(void_string);
00113 this->state_var_layouts_.push_back(dl->qp_scalar);
00114 this->state_var_init_types_.push_back("scalar");
00115 this->state_var_init_values_.push_back(f0_);
00116 this->state_var_old_state_flags_.push_back(true);
00117 this->state_var_output_flags_.push_back(true);
00118 }
00119
00120 template<typename EvalT, typename Traits>
00121 void GursonHMRModel<EvalT, Traits>::
00122 computeState(typename Traits::EvalData workset,
00123 std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > dep_fields,
00124 std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > eval_fields)
00125 {
00126
00127 PHX::MDField<ScalarT> def_grad = *dep_fields["F"];
00128 PHX::MDField<ScalarT> J = *dep_fields["J"];
00129 PHX::MDField<ScalarT> poissons_ratio = *dep_fields["Poissons Ratio"];
00130 PHX::MDField<ScalarT> elastic_modulus = *dep_fields["Elastic Modulus"];
00131 PHX::MDField<ScalarT> yield_strength = *dep_fields["Yield Strength"];
00132 PHX::MDField<ScalarT> hardening_modulus = *dep_fields["Hardening Modulus"];
00133 PHX::MDField<ScalarT> recovery_modulus = *dep_fields["Recovery Modulus"];
00134
00135
00136 std::string cauchy_string = (*field_name_map_)["Cauchy_Stress"];
00137 std::string Fp_string = (*field_name_map_)["Fp"];
00138 std::string eqps_string = (*field_name_map_)["eqps"];
00139 std::string ess_string = (*field_name_map_)["ess"];
00140 std::string isoHardening_string = (*field_name_map_)["isoHardening"];
00141 std::string void_string = (*field_name_map_)["Void_Volume"];
00142
00143
00144 PHX::MDField<ScalarT> stress = *eval_fields[cauchy_string];
00145 PHX::MDField<ScalarT> Fp = *eval_fields[Fp_string];
00146 PHX::MDField<ScalarT> eqps = *eval_fields[eqps_string];
00147 PHX::MDField<ScalarT> ess = *eval_fields[ess_string];
00148 PHX::MDField<ScalarT> isoHardening = *eval_fields[isoHardening_string];
00149 PHX::MDField<ScalarT> void_volume = *eval_fields[void_string];
00150
00151
00152 Albany::MDArray Fp_old =
00153 (*workset.stateArrayPtr)[Fp_string + "_old"];
00154 Albany::MDArray eqps_old =
00155 (*workset.stateArrayPtr)[eqps_string + "_old"];
00156 Albany::MDArray ess_old =
00157 (*workset.stateArrayPtr)[ess_string + "_old"];
00158 Albany::MDArray isoHardening_old =
00159 (*workset.stateArrayPtr)[isoHardening_string + "_old"];
00160 Albany::MDArray void_volume_old =
00161 (*workset.stateArrayPtr)[void_string + "_old"];
00162
00163 Intrepid::Tensor<ScalarT> F(num_dims_), be(num_dims_), logbe(num_dims_);
00164 Intrepid::Tensor<ScalarT> s(num_dims_), sigma(num_dims_), N(num_dims_);
00165 Intrepid::Tensor<ScalarT> A(num_dims_), expA(num_dims_), Fpnew(num_dims_);
00166 Intrepid::Tensor<ScalarT> Fpn(num_dims_), Fpinv(num_dims_), Cpinv(num_dims_);
00167 Intrepid::Tensor<ScalarT> dPhi(num_dims_);
00168 Intrepid::Tensor<ScalarT> I(Intrepid::eye<ScalarT>(num_dims_));
00169
00170 ScalarT kappa, mu, H, Y, Rd;
00171 ScalarT p, trlogbeby3, detbe;
00172 ScalarT fvoid, eq, es, isoH, Phi, dgam, Ybar;
00173
00174
00175 std::vector<ScalarT> X(4);
00176 std::vector<ScalarT> R(4);
00177 std::vector<ScalarT> dRdX(16);
00178 ScalarT norm_residual0(0.0), norm_residual(0.0), relative_residual(0.0);
00179 LocalNonlinearSolver<EvalT, Traits> solver;
00180
00181 for (std::size_t cell(0); cell < workset.numCells; ++cell) {
00182 for (std::size_t pt(0); pt < num_pts_; ++pt) {
00183 kappa = elastic_modulus(cell, pt)
00184 / (3.0 * (1.0 - 2.0 * poissons_ratio(cell, pt)));
00185 mu = elastic_modulus(cell, pt)
00186 / (2.0 * (1.0 + poissons_ratio(cell, pt)));
00187 H = hardening_modulus(cell, pt);
00188 Y = yield_strength(cell, pt);
00189 Rd = recovery_modulus(cell, pt);
00190
00191
00192 F.fill(&def_grad(cell, pt, 0, 0));
00193
00194 for (std::size_t i(0); i < num_dims_; ++i) {
00195 for (std::size_t j(0); j < num_dims_; ++j) {
00196 Fpn(i, j) = static_cast<ScalarT>(Fp_old(cell, pt, i, j));
00197 }
00198 }
00199
00200
00201 Fpinv = Intrepid::inverse(Fpn);
00202 Cpinv = Fpinv * Intrepid::transpose(Fpinv);
00203 be = F * Cpinv * Intrepid::transpose(F);
00204 logbe = Intrepid::log_sym<ScalarT>(be);
00205 trlogbeby3 = Intrepid::trace(logbe) / 3.0;
00206 detbe = Intrepid::det<ScalarT>(be);
00207 s = mu * (logbe - trlogbeby3 * I);
00208 p = 0.5 * kappa * std::log(detbe);
00209 fvoid = void_volume_old(cell, pt);
00210 eq = eqps_old(cell, pt);
00211 es = ess_old(cell, pt);
00212 isoH = isoHardening_old(cell, pt);
00213
00214
00215 Phi = YieldFunction(s, p, fvoid, Y, isoH, J(cell, pt));
00216
00217 dgam = 0.0;
00218 if (Phi > 0.0) {
00219
00220
00221 X[0] = dgam;
00222 X[1] = p;
00223 X[2] = fvoid;
00224 X[3] = es;
00225
00226 int iter = 0;
00227 norm_residual0 = 0.0;
00228 norm_residual = 0.0;
00229 relative_residual = 0.0;
00230
00231
00232 while (true) {
00233
00234 ResidualJacobian(X, R, dRdX, p, fvoid, es, s, mu, kappa, H, Y,
00235 Rd, J(cell, pt));
00236
00237 norm_residual = 0.0;
00238 for (int i = 0; i < 4; i++)
00239 norm_residual += R[i] * R[i];
00240
00241 norm_residual = std::sqrt(norm_residual);
00242
00243 if (iter == 0)
00244 norm_residual0 = norm_residual;
00245
00246 if (norm_residual0 != 0)
00247 relative_residual = norm_residual / norm_residual0;
00248 else
00249 relative_residual = norm_residual0;
00250
00251
00252
00253
00254 if (relative_residual < 1.0e-11 || norm_residual < 1.0e-11)
00255 break;
00256
00257 if (iter > 20)
00258 break;
00259
00260
00261 solver.solve(dRdX, X, R);
00262
00263 iter++;
00264 }
00265
00266
00267
00268 solver.computeFadInfo(dRdX, X, R);
00269
00270
00271 dgam = X[0];
00272 p = X[1];
00273 fvoid = X[2];
00274 es = X[3];
00275
00276 isoH = 2.0 * mu * es;
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292 s = (1.0 / (1.0 + 2.0 * mu * dgam)) * s;
00293
00294
00295 Ybar = Y + isoH;
00296
00297
00298
00299
00300
00301 ScalarT tmp = 1.5 * q2_ * p / Ybar;
00302 ScalarT deq = dgam / Ybar / (1.0 - fvoid)
00303 * (Intrepid::dotdot(s, s)
00304 + q1_ * q2_ * p * Ybar * fvoid * std::sinh(tmp));
00305 eq = eq + deq;
00306
00307 dPhi =
00308 s + 1.0 / 3.0 * q1_ * q2_ * Ybar * fvoid * std::sinh(tmp) * I;
00309
00310 expA = Intrepid::exp(dgam * dPhi);
00311
00312 for (std::size_t i(0); i < num_dims_; ++i) {
00313 for (std::size_t j(0); j < num_dims_; ++j) {
00314 Fp(cell, pt, i, j) = 0.0;
00315 for (std::size_t k(0); k < num_dims_; ++k) {
00316 Fp(cell, pt, i, j) += expA(i, k) * Fpn(k, j);
00317 }
00318 }
00319 }
00320
00321 eqps(cell, pt) = eq;
00322 ess(cell, pt) = es;
00323 isoHardening(cell, pt) = isoH;
00324 void_volume(cell, pt) = fvoid;
00325
00326 }
00327 else {
00328
00329 eqps(cell, pt) = eqps_old(cell, pt);
00330 ess(cell, pt) = ess_old(cell, pt);
00331 isoHardening(cell, pt) = isoHardening_old(cell, pt);
00332 void_volume(cell, pt) = void_volume_old(cell, pt);
00333
00334 for (std::size_t i(0); i < num_dims_; ++i) {
00335 for (std::size_t j(0); j < num_dims_; ++j) {
00336 Fp(cell, pt, i, j) = Fp_old(cell, pt, i, j);
00337 }
00338 }
00339
00340 }
00341
00342
00343
00344
00345 for (std::size_t i(0); i < num_dims_; ++i) {
00346 for (std::size_t j(0); j < num_dims_; ++j) {
00347 stress(cell, pt, i, j) = s(i, j) / J(cell, pt);
00348 }
00349 stress(cell, pt, i, i) += p / J(cell, pt);
00350 }
00351
00352 }
00353 }
00354
00355 }
00356
00357
00358
00359 template<typename EvalT, typename Traits>
00360 typename EvalT::ScalarT
00361 GursonHMRModel<EvalT, Traits>::YieldFunction(
00362 Intrepid::Tensor<ScalarT> const & s,
00363 ScalarT const & p,
00364 ScalarT const & fvoid,
00365 ScalarT const & Y,
00366 ScalarT const & isoH,
00367 ScalarT const & jacobian)
00368 {
00369
00370 ScalarT Ybar = Y + isoH;
00371
00372
00373
00374
00375 ScalarT tmp = 1.5 * q2_ * p / Ybar;
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393 ScalarT psi = 1.0 + q3_ * fvoid * fvoid - 2.0 * q1_ * fvoid * std::cosh(tmp);
00394
00395
00396 ScalarT Phi = 0.5 * Intrepid::dotdot(s, s) - psi * Ybar * Ybar / 3.0;
00397
00398
00399
00400
00401
00402
00403
00404 return Phi;
00405 }
00406
00407 template<typename EvalT, typename Traits>
00408 void
00409 GursonHMRModel<EvalT, Traits>::ResidualJacobian(std::vector<ScalarT> & X,
00410 std::vector<ScalarT> & R, std::vector<ScalarT> & dRdX, const ScalarT & p,
00411 const ScalarT & fvoid, const ScalarT & es, Intrepid::Tensor<ScalarT> & s,
00412 const ScalarT & mu, const ScalarT & kappa, const ScalarT & H,
00413 const ScalarT & Y, const ScalarT & Rd, const ScalarT & jacobian)
00414 {
00415 ScalarT sq32 = std::sqrt(3.0 / 2.0);
00416 ScalarT sq23 = std::sqrt(2.0 / 3.0);
00417 std::vector<DFadType> Rfad(4);
00418 std::vector<DFadType> Xfad(4);
00419
00420
00421
00422
00423
00424 std::vector<ScalarT> Xval(4);
00425 for (std::size_t i = 0; i < 4; ++i) {
00426 Xval[i] = Sacado::ScalarValue<ScalarT>::eval(X[i]);
00427 Xfad[i] = DFadType(4, i, Xval[i]);
00428 }
00429
00430 DFadType dgam = Xfad[0];
00431 DFadType pFad = Xfad[1];
00432 DFadType fvoidFad = Xfad[2];
00433 DFadType esFad = Xfad[3];
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450 DFadType Ybar;
00451 Ybar = mu * esFad;
00452 Ybar = Y + 2.0 * Ybar;
00453
00454
00455
00456
00457 DFadType tmp = 1.5 * q2_ * pFad / Ybar;
00458
00459 DFadType psi =
00460 1.0 + q3_ * fvoidFad * fvoidFad
00461 - 2.0 * q1_ * fvoidFad * std::cosh(tmp);
00462
00463 DFadType factor = 1.0 / (1.0 + (2.0 * (mu * dgam)));
00464
00465
00466 Intrepid::Tensor<DFadType> sfad(num_dims_);
00467 for (std::size_t i = 0; i < num_dims_; ++i) {
00468 for (std::size_t j = 0; j < num_dims_; ++j) {
00469 sfad(i, j) = factor * s(i, j);
00470 }
00471 }
00472
00473
00474
00475
00476
00477 DFadType omega(0.0), J3(0.0), taue(0.0), smag2, smag;
00478 J3 = Intrepid::det(sfad);
00479 smag2 = Intrepid::dotdot(sfad, sfad);
00480 if (smag2 > 0.0) {
00481 smag = std::sqrt(smag2);
00482 taue = sq32 * smag;
00483 }
00484
00485 if (taue > 0.0)
00486 omega = 1.0
00487 - (27.0 * J3 / 2.0 / taue / taue / taue)
00488 * (27.0 * J3 / 2.0 / taue / taue / taue);
00489
00490 DFadType deq(0.0);
00491 if (smag != 0.0) {
00492 deq = dgam
00493 * (smag2 + q1_ * q2_ * pFad * Ybar * fvoidFad * std::sinh(tmp))
00494 / (1.0 - fvoidFad) / Ybar;
00495 }
00496 else {
00497 deq = dgam * (q1_ * q2_ * pFad * Ybar * fvoidFad * std::sinh(tmp))
00498 / (1.0 - fvoidFad) / Ybar;
00499 }
00500
00501 DFadType des = (H - Rd * esFad) * deq;
00502
00503
00504 DFadType dfn(0.0);
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516 DFadType dfg(0.0);
00517 if (taue > 0.0) {
00518 dfg = dgam * q1_ * q2_ * (1.0 - fvoidFad) * fvoidFad * Ybar
00519 * std::sinh(tmp) + sq23 * dgam * kw_ * fvoidFad * omega * smag;
00520 }
00521 else {
00522 dfg = dgam * q1_ * q2_ * (1.0 - fvoidFad)
00523 * fvoidFad * Ybar * std::sinh(tmp);
00524 }
00525
00526 DFadType Phi;
00527 Phi = 0.5 * smag2 - psi * Ybar * Ybar / 3.0;
00528
00529
00530 Rfad[0] = Phi;
00531 Rfad[1] = pFad - p
00532 + dgam * q1_ * q2_ * kappa * Ybar * fvoidFad * std::sinh(tmp);
00533 Rfad[2] = fvoidFad - fvoid - dfg - dfn;
00534 Rfad[3] = esFad - es - des;
00535
00536
00537 for (int i = 0; i < 4; i++)
00538 R[i] = Rfad[i].val();
00539
00540
00541 for (int i = 0; i < 4; i++)
00542 for (int j = 0; j < 4; j++)
00543 dRdX[i + 4 * j] = Rfad[i].dx(j);
00544
00545 }
00546
00547 }
00548