00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef MECHSYS_CAMCLAY_H
00023 #define MECHSYS_CAMCLAY_H
00024
00025 #ifdef HAVE_CONFIG_H
00026 #include "config.h"
00027 #else
00028 #ifndef REAL
00029 #define REAL double
00030 #endif
00031 #endif
00032
00033 #include "models/equilibmodel.h"
00034 #include "tensors/tensors.h"
00035 #include "tensors/operators.h"
00036 #include "tensors/functions.h"
00037 #include "util/util.h"
00038 #include "numerical/autostepme.h"
00039
00040 using Tensors::Tensor2;
00041 using Tensors::Tensor4;
00042 using Tensors::Stress_p_q;
00043 using Tensors::Reduce;
00044 using Tensors::AddScaled;
00045 using Tensors::GerX;
00046 using Tensors::Psd;
00047 using Tensors::IdyI;
00048 using Tensors::I;
00049
00050 class CamClay : public EquilibModel
00051 {
00052 public:
00053
00054 CamClay(Array<REAL> const & Prms, Array<REAL> const & IniData);
00055
00056
00057 String Name () const { return "CamClay"; }
00058 void TgStiffness (Tensors::Tensor4 & D) const;
00059 void StressUpdate (Tensors::Tensor2 const & DEps, Tensors::Tensor2 & DSig);
00060 void Actualize (Tensors::Tensor2 const & DSig, Tensors::Tensor2 & DEps);
00061 void BackupState ();
00062 void RestoreState ();
00063
00064
00065 Tensors::Tensor2 const & Sig() const { return _sig; }
00066 Tensors::Tensor2 const & Eps() const { return _eps; }
00067 int nInternalStateValues () const { return 2; }
00068 void InternalStateValues (Array<REAL> & IntStateVals ) const { IntStateVals .resize(2); IntStateVals[0]=_z0; IntStateVals[1]=_v; }
00069 void InternalStateNames (Array<String> & IntStateNames) const { IntStateNames.resize(2); IntStateNames[0]="z0"; IntStateNames[1]="v"; }
00070
00071 static size_t NPRMS;
00072 static size_t NIDAT;
00073
00074 private:
00075
00076 REAL _num_dLam;
00077 REAL _bkp_num_dLam;
00078
00079
00080 REAL _z0;
00081 REAL _v;
00082 REAL _z0_bkp;
00083 REAL _v_bkp;
00084
00085
00086 REAL _lam;
00087 REAL _kap;
00088 REAL _phics;
00089 REAL _G;
00090
00091
00092 REAL _Mcs;
00093
00094
00095 void _calc_dF_dSig(Tensor2 const & Sig, REAL const & z0, Tensor2 & V) const;
00096
00097 void _calc_grads_hards(REAL const & v ,
00098 Tensor2 const & Sig,
00099 REAL const & z0 ,
00100 Tensor2 & r ,
00101 Tensor2 & V ,
00102 REAL & y0 ,
00103 REAL & HH0,
00104 REAL & hp ) const;
00105
00106 void _calc_De(REAL const & v, Tensor2 const & Sig, Tensor4 & De) const;
00107 void _calc_Ce(REAL const & v, Tensor2 const & Sig, Tensor4 & Ce) const;
00108
00109 int _Dep_times_dEps(Tensor2 const & Eps,
00110 Tensor2 const & Sig,
00111 REAL const & z0,
00112 Tensor2 const & dEps,
00113 Tensor2 & dSig,
00114 REAL & dz0) const;
00115
00116 int _Cep_times_dSig(Tensor2 const & Sig,
00117 Tensor2 const & Eps,
00118 REAL const & z0,
00119 Tensor2 const & dSig,
00120 Tensor2 & dEps,
00121 REAL & dz0) const;
00122
00123 REAL _calc_yield_func(Tensor2 const & Sig, REAL const & z0) const;
00124
00125 REAL _find_intersection(Tensor2 const & Sig, Tensor2 const & DSig_tr, Tensor2 & Sig_int) const;
00126
00127 REAL _local_error(Tensor2 const & Ey ,
00128 Tensor2 const & y_high,
00129 REAL const & Ez0 ,
00130 REAL const & z0_high) const;
00131
00132 };
00133
00134 size_t CamClay::NPRMS = 4;
00135 size_t CamClay::NIDAT = 5;
00136
00138
00139
00140 inline CamClay::CamClay(Array<REAL> const & Prms, Array<REAL> const & IniData)
00141 : _num_dLam(-1.0)
00142 {
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153 const size_t n_prms = 4;
00154 if (Prms.size()!=n_prms)
00155 throw new Fatal(_("CamClay::Constructor: The number of parameters (%d) is incorrect. It must be equal to %d"), Prms.size(), n_prms);
00156
00157
00158 _lam = Prms[0];
00159 _kap = Prms[1];
00160 _phics = Prms[2];
00161 _G = Prms[3];
00162
00163
00164 REAL sin_phi = sin(Util::ToRad(_phics));
00165 _Mcs = 6.0*sin_phi/(3.0-sin_phi);
00166
00167
00168
00169
00170 if (IniData.size()!=5)
00171 throw new Fatal(_("CamClay::Constructor: The number of initial data is not sufficiet (it must be equal to 5). { SigX SigY SigZ vini OCR }"));
00172
00173
00174 REAL sig_x = IniData[0];
00175 REAL sig_y = IniData[1];
00176 REAL sig_z = IniData[2];
00177 _v = IniData[3];
00178 REAL OCR = IniData[4];
00179
00180
00181 _sig = sig_x, sig_y, sig_z, 0.0*Util::Sq2(), 0.0*Util::Sq2(), 0.0*Util::Sq2();
00182 _eps = 0.0,0.0,0.0,0.0*Util::Sq2(),0.0*Util::Sq2(),0.0*Util::Sq2();
00183
00184
00185 REAL p = (_sig(0)+_sig(1)+_sig(2))/3.0;
00186 _z0 = OCR*p;
00187
00188 }
00189
00190 inline void CamClay::TgStiffness(Tensors::Tensor4 & D) const
00191 {
00192 if (_num_dLam<0)
00193 {
00194 _calc_De(_v, _sig, D);
00195 }
00196 else
00197 {
00198
00199 Tensor2 r;
00200 Tensor2 V;
00201 REAL y0;
00202 REAL HH0;
00203 REAL hp;
00204 _calc_grads_hards(_v, _sig, _z0, r, V, y0, HH0, hp);
00205
00206
00207 Tensors::Tensor4 De;
00208 _calc_De(_v, _sig, De);
00209 REAL Phi = Reduce(V,De,r)+hp;
00210 Tensors::GerX(-1.0/Phi,De,r,V,De,De, D);
00211 }
00212
00213 }
00214
00215 inline void CamClay::Actualize(Tensors::Tensor2 const & DSig, Tensors::Tensor2 & DEps)
00216 {
00217
00218 Tensor2 eps_ini = _eps;
00219
00220
00221 Tensor2 dsig_tr = DSig;
00222 Tensor2 sig_tr; sig_tr=_sig+dsig_tr;
00223
00224
00225 REAL F = _calc_yield_func(_sig, _z0);
00226 REAL F_tr = _calc_yield_func(sig_tr,_z0);
00227
00228
00229 const REAL FTOL=1.0e-3;
00230 enum Situation {EL, EL_EPL, EPL};
00231 Situation sit;
00232 if (F<0.0)
00233 {
00234 if (F_tr<=0.0) sit=EL;
00235 else sit=EL_EPL;
00236 }
00237 else if (F>=0.0 && F/_z0<=FTOL)
00238 {
00239 if (F_tr<=0.0) sit=EL;
00240 else
00241 {
00242
00243 Tensor2 dF_dSig;
00244 _calc_dF_dSig(_sig, _z0, dF_dSig);
00245 REAL scalar = Tensors::Dot(dF_dSig,dsig_tr);
00246 if (scalar>=0.0) sit=EPL;
00247 else sit=EL_EPL;
00248 }
00249 }
00250 else
00251 throw new Fatal(_("CamClay::Actualize: F/z0 (=%e) >FTOL (%e)"),F/_z0,FTOL);
00252
00253
00254 if (sit==EL)
00255 {
00256
00257 Tensor4 Ce;
00258 _calc_Ce(_v, _sig, Ce);
00259
00260
00261 Tensor2 DEps;
00262 Tensors::Dot(Ce,DSig, DEps);
00263
00264
00265 _sig += DSig;
00266 _eps += DEps;
00267
00268 }
00269 else
00270 {
00271
00272 Tensor2 dsig = DSig;
00273
00274
00275 if (sit==EL_EPL)
00276 {
00277
00278
00279
00280 Tensor2 sig_int;
00281 _find_intersection(_sig,dsig_tr, sig_int);
00282
00283
00284 Tensor2 dsig_el,dsig_epl;
00285 dsig_el = sig_int - _sig;
00286 dsig_epl = dsig_tr - dsig_el;
00287
00288
00289 Tensor4 Ce;
00290 _calc_Ce(_v, _sig, Ce);
00291
00292
00293 Tensor2 DEps;
00294 Tensors::Dot(Ce,dsig_el, DEps);
00295
00296
00297 _sig += dsig_el;
00298 _eps += DEps;
00299
00300
00301
00302 dsig = dsig_epl;
00303 }
00304
00305
00306 int n_div=_isc.FE_ndiv();
00307 dsig = dsig/n_div;
00308 for (int i=0; i<n_div; ++i)
00309 {
00310 REAL dz0 = 0.0;
00311 _Cep_times_dSig(_sig, _eps, _z0, dsig, DEps, dz0);
00312 _sig += dsig;
00313 _eps += DEps;
00314 _z0 += dz0;
00315 }
00316 }
00317
00318
00319 DEps = _eps - eps_ini;
00320
00321
00322 _v += -(DEps(0)+DEps(1)+DEps(2))*_v;
00323
00324 }
00325
00326 inline void CamClay::StressUpdate(Tensors::Tensor2 const & DEps, Tensors::Tensor2 & DSig)
00327 {
00328
00329 Tensor2 sig_ini = _sig;
00330
00331
00332 Tensor4 De;
00333 _calc_De(_v,_sig, De);
00334
00335
00336 Tensor2 dsig_tr; Tensors::Dot(De,DEps, dsig_tr);
00337 Tensor2 sig_tr; sig_tr=_sig+dsig_tr;
00338
00339
00340 REAL F = _calc_yield_func(_sig, _z0);
00341 REAL F_tr = _calc_yield_func(sig_tr,_z0);
00342
00343
00344 const REAL FTOL=1.0e-1;
00345 enum Situation {EL, EL_EPL, EPL};
00346 Situation sit;
00347 if (F<0.0)
00348 {
00349 if (F_tr<=0.0) sit=EL;
00350 else sit=EL_EPL;
00351 }
00352 else if (F>=0.0 && F<=FTOL)
00353 {
00354 if (F_tr<=0.0) sit=EL;
00355 else
00356 {
00357
00358 Tensor2 V;
00359 _calc_dF_dSig(_sig,_z0, V);
00360 _num_dLam = Tensors::Dot(V,dsig_tr);
00361 if (_num_dLam>=0.0) sit=EPL;
00362 else sit=EL_EPL;
00363 }
00364 }
00365 else
00366 throw new Fatal("CamClay::StressUpdate: F>0.0");
00367
00368
00369 if (sit==EL)
00370 {
00371
00372 _num_dLam = -1.0;
00373
00374
00375 DSig = dsig_tr;
00376
00377
00378 _sig += DSig;
00379 _eps += DEps;
00380
00381 }
00382 else
00383 {
00384
00385 _num_dLam = +1.0;
00386
00387
00388 Tensor2 deps = DEps;
00389
00390
00391 if (sit==EL_EPL)
00392 {
00393
00394
00395
00396 Tensor2 sig_int;
00397 _find_intersection(_sig,dsig_tr, sig_int);
00398
00399
00400 Tensor4 Ce;
00401 _calc_Ce(_v,_sig, Ce);
00402
00403
00404 Tensor2 dsig_el = sig_int - _sig;
00405 Tensor2 deps_el;
00406 Tensors::Dot(Ce,dsig_el, deps_el);
00407
00408
00409 _sig += dsig_el;
00410 _eps += deps_el;
00411
00412
00413
00414 deps = DEps - deps_el;
00415 }
00416
00417
00418
00419 if (EquilibModel::_isc.Type()==IntegSchemesCtes::FE)
00420 {
00421
00422 int n_div=_isc.FE_ndiv();
00423 deps = deps/n_div;
00424 for (int i=0; i<n_div; ++i)
00425 {
00426 REAL dz0;
00427 _Dep_times_dEps(_eps, _sig, _z0, deps, DSig, dz0);
00428 _sig += DSig;
00429 _eps += deps;
00430 _z0 += dz0;
00431 }
00432 }
00433 else
00434 {
00435
00436 AutoStepME<Tensor2,Tensor2,REAL,CamClay> TI(EquilibModel::_isc);
00437
00438
00439 int nss = TI.Solve(this,
00440 &CamClay::_Dep_times_dEps,
00441 &CamClay::_local_error,
00442 _eps, _sig, _z0, deps);
00443
00444 if (nss==-1)
00445 throw new Fatal(_("CamClay::StressUpdate: (Loading) Number of max sub-steps (%d) was not sufficient for AutoStepME."), EquilibModel::_isc.ME_maxSS());
00446 }
00447 }
00448
00449
00450 DSig = _sig - sig_ini;
00451
00452
00453 _v += -(DEps(0)+DEps(1)+DEps(2))*_v;
00454
00455 }
00456
00457 inline void CamClay::_calc_dF_dSig(Tensor2 const & Sig, REAL const & z0, Tensor2 & V) const
00458 {
00459
00460 REAL p,q;
00461 Stress_p_q(Sig,p,q);
00462 Tensor2 S;
00463 S = Sig - p*I;
00464
00465
00466 REAL MM = _Mcs*_Mcs;
00467 V = (MM*(2.0*p-z0)/3.0)*I + 3.0*S;
00468 }
00469
00470 inline void CamClay::_calc_grads_hards(REAL const & v ,
00471 Tensor2 const & Sig,
00472 REAL const & z0 ,
00473 Tensor2 & r ,
00474 Tensor2 & V ,
00475 REAL & y0 ,
00476 REAL & HH0,
00477 REAL & hp ) const
00478 {
00479
00480 REAL p,q;
00481 Stress_p_q(Sig,p,q);
00482 Tensor2 S;
00483 S = Sig - p*I;
00484
00485
00486 REAL MM = _Mcs*_Mcs;
00487 V = (MM*(2.0*p-z0)/3.0)*I + 3.0*S;
00488 r = V;
00489 y0 = -MM*p;
00490
00491
00492 REAL tr_r = r(0)+r(1)+r(2);
00493 REAL chi = (_lam - _kap)/v;
00494 HH0 = z0*tr_r/chi;
00495
00496
00497 hp = -y0*HH0;
00498
00499 }
00500
00501 inline void CamClay::_calc_De(REAL const & v, Tensor2 const & Sig, Tensor4 & De) const
00502 {
00503
00504 REAL p = (Sig(0)+Sig(1)+Sig(2))/3.0;
00505
00506
00507 REAL K = p*v/_kap;
00508
00509
00510 Tensors::AddScaled(2.0*_G,Tensors::Psd, K,Tensors::IdyI, De);
00511
00512 }
00513
00514 inline void CamClay::_calc_Ce(REAL const & v, Tensor2 const & Sig, Tensor4 & Ce) const
00515 {
00516
00517 REAL p = (Sig(0)+Sig(1)+Sig(2))/3.0;
00518
00519
00520 REAL K = p*v/_kap;
00521
00522
00523 AddScaled(1.0/(2.0*_G), Psd, 1.0/(9.0*K), IdyI, Ce);
00524 }
00525
00526 inline int CamClay::_Dep_times_dEps(Tensor2 const & Eps,
00527 Tensor2 const & Sig,
00528 REAL const & z0,
00529 Tensor2 const & dEps,
00530 Tensor2 & dSig,
00531 REAL & dz0) const
00532 {
00533
00534 REAL v=_v;
00535 Tensor2 r;
00536 Tensor2 V;
00537 REAL y0;
00538 REAL HH0;
00539 REAL hp;
00540 _calc_grads_hards(v, Sig, z0, r, V, y0, HH0, hp);
00541
00542
00543 Tensors::Tensor4 De,Dep;
00544 _calc_De(v, Sig, De);
00545 REAL Phi = Reduce(V,De,r)+hp;
00546 Tensors::GerX(-1.0/Phi,De,r,V,De,De, Dep);
00547
00548
00549 Tensors::Dot(Dep, dEps, dSig);
00550 REAL dLam = Reduce(V,De,dEps)/Phi;
00551
00552
00553 dz0 = dLam * HH0;
00554
00555 return 0;
00556
00557 }
00558
00559 inline int CamClay::_Cep_times_dSig(Tensor2 const & Sig,
00560 Tensor2 const & Eps,
00561 REAL const & z0,
00562 Tensor2 const & dSig,
00563 Tensor2 & dEps,
00564 REAL & dz0) const
00565 {
00566
00567 REAL ev,ed;
00568 Tensors::Strain_Ev_Ed(Eps, ev,ed);
00569 if (ed>EquilibModel::_isc.EdMax()) return 1;
00570
00571
00572 REAL v=_v;
00573 Tensor2 r;
00574 Tensor2 V;
00575 REAL y0;
00576 REAL HH0;
00577 REAL hp;
00578 _calc_grads_hards(v, Sig, z0, r, V, y0, HH0, hp);
00579
00580
00581 Tensor4 Cep;
00582 _calc_Ce(v, Sig, Cep);
00583 Tensors::Ger(1.0/hp,r,V,Cep);
00584
00585
00586 Tensors::Dot(Cep, dSig, dEps);
00587 REAL dLam = Tensors::Dot(V,dSig)/hp;
00588
00589
00590 dz0 = dLam * HH0;
00591
00592 return 0;
00593
00594 }
00595
00596 inline REAL CamClay::_calc_yield_func(Tensor2 const & Sig, REAL const & z0) const
00597 {
00598 REAL p,q;
00599 Stress_p_q(Sig,p,q);
00600 REAL F = _Mcs*_Mcs*p*(p-z0)+q*q;
00601 return F/fabs(z0);
00602 }
00603
00604 inline REAL CamClay::_find_intersection(Tensor2 const & Sig, Tensor2 const & DSig_tr, Tensor2 & Sig_int) const
00605 {
00606 Tensor2 Sig_tr;
00607 Sig_tr = Sig + DSig_tr;
00608
00609 REAL F = _calc_yield_func(Sig, _z0);
00610 REAL F_tr = _calc_yield_func(Sig_tr, _z0);
00611 REAL alpha;
00612 REAL F_int;
00613
00614
00615
00616
00617
00618
00619 const int ITMAX=20;
00620 const REAL EPS=3.0e-8;
00621 const REAL tol=1.0e-5;
00622
00623 REAL a=0.0;
00624 REAL b=1.0;
00625 REAL c=1.0;
00626 REAL d=0,e=0,min1=0,min2=0;
00627 REAL fa=F;
00628 REAL fb=F_tr;
00629 REAL fc,p,q,r,s,tol1,xm;
00630 if ((fa > 0.0 && fb > 0.0) || (fa < 0.0 && fb < 0.0))
00631 {
00632 Sig_int = Sig;
00633 return 0.0;
00634
00635 }
00636 fc=fb;
00637 int iter;
00638 for (iter=1;iter<=ITMAX;iter++)
00639 {
00640 if ((fb > 0.0 && fc > 0.0) || (fb < 0.0 && fc < 0.0))
00641 {
00642 c=a;
00643 fc=fa;
00644 e=d=b-a;
00645 }
00646 if (fabs(fc) < fabs(fb))
00647 {
00648 a=b;
00649 b=c;
00650 c=a;
00651 fa=fb;
00652 fb=fc;
00653 fc=fa;
00654 }
00655 tol1=2.0*EPS*fabs(b)+0.5*tol;
00656 xm=0.5*(c-b);
00657 if (fabs(xm) <= tol1 || fb == 0.0)
00658 {
00659 alpha = b;
00660 Sig_int = Sig + alpha*DSig_tr;
00661 break;
00662 }
00663 if (fabs(e) >= tol1 && fabs(fa) > fabs(fb))
00664 {
00665 s=fb/fa;
00666 if (a == c)
00667 {
00668 p=2.0*xm*s;
00669 q=1.0-s;
00670 }
00671 else
00672 {
00673 q=fa/fc;
00674 r=fb/fc;
00675 p=s*(2.0*xm*q*(q-r)-(b-a)*(r-1.0));
00676 q=(q-1.0)*(r-1.0)*(s-1.0);
00677 }
00678 if (p > 0.0) q = -q;
00679 p=fabs(p);
00680 min1=3.0*xm*q-fabs(tol1*q);
00681 min2=fabs(e*q);
00682 if (2.0*p < (min1 < min2 ? min1 : min2))
00683 {
00684 e=d;
00685 d=p/q;
00686 }
00687 else
00688 {
00689 d=xm;
00690 e=d;
00691 }
00692 }
00693 else
00694 {
00695 d=xm;
00696 e=d;
00697 }
00698 a=b;
00699 fa=fb;
00700 if (fabs(d) > tol1)
00701 b += d;
00702 else
00703 b += Util::Sign(tol1,xm);
00704
00705
00706
00707
00708 alpha = b;
00709 Sig_int = Sig + alpha*DSig_tr;
00710 F_int = _calc_yield_func(Sig_int, _z0);
00711 fb = F_int;
00712 }
00713 if (iter>ITMAX)
00714 throw new Fatal("CamClay::_find_intersection: Maximum number of iterations exceeded in zbrent");
00715
00716 return alpha;
00717
00718 }
00719
00720 inline void CamClay::BackupState()
00721 {
00722 _sig_bkp = _sig;
00723 _eps_bkp = _eps;
00724 _v_bkp = _v;
00725 _z0_bkp = _z0;
00726 _bkp_num_dLam = _num_dLam;
00727 }
00728
00729 inline void CamClay::RestoreState()
00730 {
00731 _sig = _sig_bkp;
00732 _eps = _eps_bkp;
00733 _v = _v_bkp;
00734 _z0 = _z0_bkp;
00735 _num_dLam = _bkp_num_dLam;
00736 }
00737
00738 inline REAL CamClay::_local_error(Tensor2 const & Ey ,
00739 Tensor2 const & y_high,
00740 REAL const & Ez0 ,
00741 REAL const & z0_high) const
00742 {
00743 REAL Err_y = Tensors::Norm(Ey)/Tensors::Norm(y_high);
00744 REAL Err_z0 = fabs(Ez0)/fabs(z0_high);
00745 return (Err_y>Err_z0 ? Err_y : Err_z0);
00746 }
00747
00748
00750
00751
00752
00753 EquilibModel * CamClayMaker(Array<REAL> const & Prms, Array<REAL> const & IniData)
00754 {
00755 return new CamClay(Prms, IniData);
00756 }
00757
00758
00759 int CamClayRegister()
00760 {
00761 EquilibModelFactory["CamClay"] = CamClayMaker;
00762 return 0;
00763 }
00764
00765
00766 int __CamClay_dummy_int = CamClayRegister();
00767
00768 #endif // MECHSYS_CAMCLAY_H
00769
00770