camclay.h

00001 /*************************************************************************************
00002  * MechSys - A C++ library to simulate (Continuum) Mechanical Systems                *
00003  * Copyright (C) 2005 Dorival de Moraes Pedroso <dorival.pedroso at gmail.com>       *
00004  * Copyright (C) 2005 Raul Dario Durand Farfan  <raul.durand at gmail.com>           *
00005  *                                                                                   *
00006  * This file is part of MechSys.                                                     *
00007  *                                                                                   *
00008  * MechSys is free software; you can redistribute it and/or modify it under the      *
00009  * terms of the GNU General Public License as published by the Free Software         *
00010  * Foundation; either version 2 of the License, or (at your option) any later        *
00011  * version.                                                                          *
00012  *                                                                                   *
00013  * MechSys is distributed in the hope that it will be useful, but WITHOUT ANY        *
00014  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A   *
00015  * PARTICULAR PURPOSE. See the GNU General Public License for more details.          *
00016  *                                                                                   *
00017  * You should have received a copy of the GNU General Public License along with      *
00018  * MechSys; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, *
00019  * Fifth Floor, Boston, MA 02110-1301, USA                                           *
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; // Mean and deviatoric Cambridge stress invariants
00043 using Tensors::Reduce;     // Used in: Phi <- V:De:r - y0*HH0  and  dLam <- V:De:dEps/Phi
00044 using Tensors::AddScaled;  // Z = a*X + b*Y
00045 using Tensors::GerX;       // Used in: Dep <- (-1/Phi)(De:r)dy(V:De) + De
00046 using Tensors::Psd;        // P symmetric deviatoric
00047 using Tensors::IdyI;       // I dyadic I
00048 using Tensors::I;          // Second order identity tensor
00049 
00050 class CamClay : public EquilibModel
00051 {
00052 public:
00053     // Constructor
00054     CamClay(Array<REAL> const & Prms, Array<REAL> const & IniData);
00055 
00056     // Derived Methods
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     // Access Methods
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     // Numerator of dLam
00076     REAL _num_dLam;
00077     REAL _bkp_num_dLam;
00078 
00079     // Internal State Values
00080     REAL _z0;
00081     REAL _v;
00082     REAL _z0_bkp;
00083     REAL _v_bkp;
00084 
00085     // Parameters
00086     REAL _lam;
00087     REAL _kap;
00088     REAL _phics;
00089     REAL _G;
00090 
00091     // Derived constants
00092     REAL _Mcs;
00093 
00094     // Private methods
00095     void _calc_dF_dSig(Tensor2 const & Sig, REAL const & z0, Tensor2 & V) const;
00096 
00097     void _calc_grads_hards(REAL    const & v  ,        // In:  Specific volume
00098                            Tensor2 const & Sig,        // In:  Stress tensor
00099                            REAL    const & z0 ,        // In:  Internal variable
00100                            Tensor2       & r  ,        // Out: Plastic strain direction
00101                            Tensor2       & V  ,        // Out: Derivative of f ("loading" surface) w.r.t Sig (df_dSig)
00102                            REAL          & y0 ,        // Out: Derivative of f ("loading" surface) w.r.t z
00103                            REAL          & HH0,        // Out: Hardening modulae
00104                            REAL          & hp ) const; // Out: Plastic coeficient
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,        // In: (actual) stress tensor
00110                         Tensor2 const & Sig,        // In: (actual) strain tensor
00111                         REAL    const & z0,         // In: (actual) internal variables
00112                         Tensor2 const & dEps,       // In: Stress increment
00113                         Tensor2       & dSig,       // Out: Strain increment
00114                         REAL          & dz0) const; // Out: Internal variables increment
00115 
00116     int _Cep_times_dSig(Tensor2 const & Sig,        // In: (actual) stress tensor
00117                         Tensor2 const & Eps,        // In: (actual) strain tensor
00118                         REAL    const & z0,         // In: (actual) internal variables
00119                         Tensor2 const & dSig,       // In: Stress increment
00120                         Tensor2       & dEps,       // Out: Strain increment
00121                         REAL          & dz0) const; // Out: Internal variables increment
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    ,         // In: Stress or Strain error between low and high order evaluation (FE and ME)
00128                       Tensor2 const & y_high,         // In: Stress or Strain high order evaluation - "correct" (ME)
00129                       REAL    const & Ez0   ,         // In: Error on internal variables
00130                       REAL    const & z0_high) const; // In: Higher evaluation of internal variables
00131 
00132 }; // class CamClay
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/*elastic*/) // deve ser negativo, pois no inicio Dep eh indeterminado
00142 {
00143     // ##################################################################### Setup Parameters
00144 
00145     /* example.mat
00146      * #-------------------------------
00147      * #            0      1     2   3
00148      * #          lam    kap phics   G
00149      * CamClay 0.0891 0.0196  31.6 200
00150      */
00151 
00152     // Check number of parameters
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     // Parameters
00158     _lam   = Prms[0];
00159     _kap   = Prms[1];
00160     _phics = Prms[2];
00161     _G     = Prms[3];
00162 
00163     // Derived constants
00164     REAL sin_phi = sin(Util::ToRad(_phics));
00165     _Mcs = 6.0*sin_phi/(3.0-sin_phi);
00166     
00167     // ##################################################################### Setup Initial State
00168 
00169     // Check number of initial data
00170     if (IniData.size()!=5) // Layered analysis
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     // Read initial data
00174     REAL sig_x = IniData[0]; // X stress component
00175     REAL sig_y = IniData[1]; // Y stress component
00176     REAL sig_z = IniData[2]; // Z stress component
00177             _v = IniData[3]; // Initial specific volume
00178     REAL   OCR = IniData[4]; // Over consolidation rate (not used here)
00179 
00180     // Fill stress and strain tensors
00181     _sig = sig_x, sig_y, sig_z, 0.0*Util::Sq2(), 0.0*Util::Sq2(), 0.0*Util::Sq2(); // Mandel representation
00182     _eps = 0.0,0.0,0.0,0.0*Util::Sq2(),0.0*Util::Sq2(),0.0*Util::Sq2();
00183 
00184     // Calculate internal variables
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) // Elastic tangent stiffness
00193     {
00194         _calc_De(_v, _sig, D); // D <- De
00195     }
00196     else // Elastoplastic tangent stiffness
00197     {
00198         // Gradients and Hardening
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         // Dep and Phi
00207         Tensors::Tensor4 De;
00208         _calc_De(_v, _sig, De);
00209         REAL Phi = Reduce(V,De,r)+hp;   // Phi = V:De:r - y0*HH0
00210         Tensors::GerX(-1.0/Phi,De,r,V,De,De, D); // D <- Dep = (-1/Phi) * (De:r)dy(V:De) + De
00211     }
00212     
00213 } // }}}
00214 
00215 inline void CamClay::Actualize(Tensors::Tensor2 const & DSig, Tensors::Tensor2 & DEps) // P{{{
00216 {
00217     // Initial _eps
00218     Tensor2 eps_ini = _eps;
00219 
00220     // Stress invariants of the increment of stress
00221     Tensor2 dsig_tr = DSig;
00222     Tensor2  sig_tr; sig_tr=_sig+dsig_tr;
00223 
00224     // Yield function values
00225     REAL F    = _calc_yield_func(_sig,  _z0);
00226     REAL F_tr = _calc_yield_func(sig_tr,_z0);
00227 
00228     // Check loading condition
00229     const REAL FTOL=1.0e-3;
00230     enum Situation {EL, EL_EPL, EPL}; // EL: Elastic-Loading
00231     Situation sit;                    // EL_EPL: Elastic-Loading + ElastoPlastic-Loading
00232     if (F<0.0)                        // EPL :ElastoPlastic-Loading
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             // Gradients
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 // F>FTOL
00251         throw new Fatal(_("CamClay::Actualize: F/z0 (=%e) >FTOL (%e)"),F/_z0,FTOL);
00252 
00253     // Elastic loading
00254     if (sit==EL)
00255     {
00256         // Elastic tensors
00257         Tensor4 Ce;
00258         _calc_Ce(_v, _sig, Ce);
00259 
00260         // DEps
00261         Tensor2 DEps;
00262         Tensors::Dot(Ce,DSig, DEps);
00263 
00264         // Actualize
00265         _sig += DSig;
00266         _eps += DEps;
00267         // _z stay unchanged
00268     }
00269     else // sit==EL_EPL || sit==EPL
00270     {
00271         // Auxiliar tensor
00272         Tensor2 dsig = DSig;
00273 
00274         // Find interpolation
00275         if (sit==EL_EPL)
00276         {
00277             //std::cout << "(Actualize): F = " << F << ", F_tr = " << F_tr << std::endl;
00278 
00279             // Find intersection
00280             Tensor2 sig_int;
00281             _find_intersection(_sig,dsig_tr, sig_int);
00282 
00283             // Elastic and Elastoplastic parts of stress
00284             Tensor2 dsig_el,dsig_epl;
00285              dsig_el = sig_int - _sig;
00286             dsig_epl = dsig_tr - dsig_el;
00287 
00288             // Elastic tensors
00289             Tensor4 Ce;
00290             _calc_Ce(_v, _sig, Ce);
00291 
00292             // DEps
00293             Tensor2 DEps;
00294             Tensors::Dot(Ce,dsig_el, DEps);
00295 
00296             // Actualize
00297             _sig += dsig_el;
00298             _eps += DEps;
00299             // _z stay unchanged
00300 
00301             // Continue with elastoplastic part (fill augmented vectors)
00302             dsig = dsig_epl;
00303         }
00304 
00305         // Forward-Euler
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     // Calculate the total (secant) increment of strain
00319     DEps = _eps - eps_ini;
00320 
00321     // Update internal state (secant)
00322     _v += -(DEps(0)+DEps(1)+DEps(2))*_v; // dv=-dEv*v
00323 
00324 } // }}}
00325 
00326 inline void CamClay::StressUpdate(Tensors::Tensor2 const & DEps, Tensors::Tensor2 & DSig) // P{{{
00327 {
00328     // Initial _sig
00329     Tensor2 sig_ini = _sig;
00330 
00331     // De
00332     Tensor4 De;
00333     _calc_De(_v,_sig, De);
00334 
00335     // Trial state
00336     Tensor2 dsig_tr; Tensors::Dot(De,DEps, dsig_tr);
00337     Tensor2  sig_tr; sig_tr=_sig+dsig_tr;
00338 
00339     // Yield function values
00340     REAL F    = _calc_yield_func(_sig,  _z0);
00341     REAL F_tr = _calc_yield_func(sig_tr,_z0);
00342 
00343     // Check loading condition
00344     const REAL FTOL=1.0e-1;
00345     enum Situation {EL, EL_EPL, EPL}; // EL: Elastic-Loading
00346     Situation sit;                    // EL_EPL: Elastic-Loading + ElastoPlastic-Loading
00347     if (F<0.0)                        // EPL :ElastoPlastic-Loading
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             // Calculate the numerator of dLam
00358             Tensor2 V; // df_dsig
00359             _calc_dF_dSig(_sig,_z0, V);
00360             _num_dLam = Tensors::Dot(V,dsig_tr); // dLam = (V:De:deps)/Phi
00361             if (_num_dLam>=0.0) sit=EPL;
00362             else                sit=EL_EPL;
00363         }
00364     }
00365     else // F>FTOL
00366         throw new Fatal("CamClay::StressUpdate: F>0.0");
00367 
00368     // Elastic loading
00369     if (sit==EL)
00370     {
00371         // Set the numerator of dLam so that it may be used in TgStiffness
00372         _num_dLam = -1.0;
00373 
00374         // DSig
00375         DSig = dsig_tr;
00376 
00377         // Actualize
00378         _sig += DSig;
00379         _eps += DEps;
00380         // _z stay unchanged
00381     }
00382     else // sit==EL_EPL || sit==EPL
00383     {
00384         // Set the numerator of dLam so that it may be used in TgStiffness
00385         _num_dLam = +1.0;
00386 
00387         // Auxiliar tensor
00388         Tensor2 deps = DEps;
00389 
00390         // Find interpolation
00391         if (sit==EL_EPL)
00392         {
00393             //std::cout << "(StressUpdate): F = " << F << ", F_tr = " << F_tr << std::endl;
00394 
00395             // Find intersection
00396             Tensor2 sig_int;
00397             _find_intersection(_sig,dsig_tr, sig_int);
00398 
00399             // Ce
00400             Tensor4 Ce;
00401             _calc_Ce(_v,_sig, Ce);
00402 
00403             // Elastic and Elastoplastic parts of stress ans strain
00404             Tensor2 dsig_el = sig_int - _sig;
00405             Tensor2 deps_el;
00406             Tensors::Dot(Ce,dsig_el, deps_el);
00407 
00408             // Actualize
00409             _sig += dsig_el;
00410             _eps += deps_el;
00411             // _z stay unchanged
00412 
00413             // Continue with elastoplastic part
00414             deps = DEps - deps_el;
00415         }
00416 
00417 
00418 
00419         if (EquilibModel::_isc.Type()==IntegSchemesCtes::FE)
00420         {
00421             // Forward-Euler - Update (Elastoplastic)
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             // TimeInteg
00436             AutoStepME<Tensor2,Tensor2,REAL,CamClay> TI(EquilibModel::_isc);
00437 
00438             // Update stress (_sig), internal variables (_z) and strain (_eps) state
00439             int nss = TI.Solve(this,                      // Address of this instance of GenericEP class
00440                                &CamClay::_Dep_times_dEps, // Pointer to a function that calculates {dSig}=[Dep]:{dEps}
00441                                &CamClay::_local_error,    // Pointer to a function that calculates local error on dEps
00442                                _eps, _sig, _z0, deps);
00443             // Check num_sub_steps
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     // Calculate the total (secant) increment of stress
00450     DSig = _sig - sig_ini;
00451 
00452     // Update internal state
00453     _v += -(DEps(0)+DEps(1)+DEps(2))*_v; // dv=-dEv*v
00454 
00455 } // }}}
00456 
00457 inline void CamClay::_calc_dF_dSig(Tensor2 const & Sig, REAL const & z0, Tensor2 & V) const // {{{
00458 {
00459     // Invariants
00460     REAL p,q;
00461     Stress_p_q(Sig,p,q);
00462     Tensor2 S;
00463     S = Sig - p*I;
00464 
00465     // Gradients
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  ,       // In:  Specific volume // {{{
00471                                        Tensor2 const & Sig,       // In:  Stress tensor
00472                                        REAL    const & z0 ,       // In:  Internal variable
00473                                        Tensor2       & r  ,       // Out: Plastic strain direction
00474                                        Tensor2       & V  ,       // Out: Derivative of f ("loading" surface) w.r.t Sig (df_dSig)
00475                                        REAL          & y0 ,       // Out: Derivative of f ("loading" surface) w.r.t z
00476                                        REAL          & HH0,       // Out: Hardening modulae
00477                                        REAL          & hp ) const // Out: Plastic coeficient
00478 {
00479     // Invariants
00480     REAL p,q;
00481     Stress_p_q(Sig,p,q);
00482     Tensor2 S;
00483     S = Sig - p*I;
00484 
00485     // Gradients
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     // Hardening
00492     REAL tr_r = r(0)+r(1)+r(2);
00493     REAL  chi = (_lam - _kap)/v;
00494           HH0 = z0*tr_r/chi;
00495 
00496     // Plastic coefficient
00497     hp = -y0*HH0;
00498 
00499 } // }}}
00500 
00501 inline void CamClay::_calc_De(REAL const & v, Tensor2 const & Sig, Tensor4 & De) const // {{{
00502 {
00503     // Invariants
00504     REAL p = (Sig(0)+Sig(1)+Sig(2))/3.0;
00505 
00506     // Calculate Bulk modulus
00507     REAL K = p*v/_kap;
00508 
00509     // Calc De
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     // Invariants
00517     REAL p = (Sig(0)+Sig(1)+Sig(2))/3.0;
00518 
00519     // Calculate Bulk modulus
00520     REAL K = p*v/_kap;
00521 
00522     // Calc Ce
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,       // In: (actual) stress tensor {{{
00527                                     Tensor2 const & Sig,       // In: (actual) strain tensor
00528                                     REAL    const & z0,        // In: (actual) internal variables
00529                                     Tensor2 const & dEps,      // In: Stress increment
00530                                     Tensor2       & dSig,      // Out: Strain increment
00531                                     REAL          & dz0) const // Out: Internal variables increment
00532 {
00533     // Gradients and Hardening
00534     REAL    v=_v; // using (constant) current specific volume
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     // Dep and Phi
00543     Tensors::Tensor4 De,Dep;
00544     _calc_De(v, Sig, De);
00545     REAL Phi = Reduce(V,De,r)+hp;              // Phi = V:De:r - y0*HH0
00546     Tensors::GerX(-1.0/Phi,De,r,V,De,De, Dep); // Dep = (-1/Phi) * (De:r)dy(V:De) + De
00547 
00548     // dSig and dLam
00549     Tensors::Dot(Dep, dEps, dSig);     // dSig = Dep:dEps
00550     REAL dLam = Reduce(V,De,dEps)/Phi; // dLam = V:De:dEps/Phi
00551 
00552     // dz0
00553     dz0 = dLam * HH0;
00554 
00555     return 0;
00556 
00557 } // }}}
00558 
00559 inline int CamClay::_Cep_times_dSig(Tensor2 const & Sig,       // In: (actual) stress tensor {{{
00560                                     Tensor2 const & Eps,       // In: (actual) strain tensor
00561                                     REAL    const & z0,        // In: (actual) internal variables
00562                                     Tensor2 const & dSig,      // In: Stress increment
00563                                     Tensor2       & dEps,      // Out: Strain increment
00564                                     REAL          & dz0) const // Out: Internal variables increment
00565 {
00566     // Stop if excessive deviatoric strains
00567     REAL ev,ed;
00568     Tensors::Strain_Ev_Ed(Eps, ev,ed);
00569     if (ed>EquilibModel::_isc.EdMax()) return 1; // -1 => failed;  0 => continue;  1 => stop
00570 
00571     // Gradients and Hardening
00572     REAL    v=_v; // using (constant) current specific volume
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     // Cep
00581     Tensor4 Cep;
00582     _calc_Ce(v, Sig, Cep);        // Cep <- Ce
00583     Tensors::Ger(1.0/hp,r,V,Cep); // Cep <- (1/cp)*(r dyadic V) + Ce
00584 
00585     // dEps and dLam
00586     Tensors::Dot(Cep, dSig, dEps);       // dEps <- Cep:dSig
00587     REAL dLam = Tensors::Dot(V,dSig)/hp; // dLam <- V:dSig/cp
00588 
00589     // dz0
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     // Find alpha for intersection and the intersection (Sig_int) itself
00615 
00616     //Using Brent’s method, find the root of a function func known to lie between x1 and x2. The
00617     //root, returned as zbrent, will be refined until its accuracy is tol.
00618 
00619     const int  ITMAX=20;   // Maximum allowed number of iterations.
00620     const REAL EPS=3.0e-8; // Machine REALing-point precision.
00621     const REAL tol=1.0e-5;
00622 
00623     REAL a=0.0; // x1
00624     REAL b=1.0; // x2
00625     REAL c=1.0; // x2
00626     REAL d=0,e=0,min1=0,min2=0;
00627     REAL fa=F;    //(*func)(a);
00628     REAL fb=F_tr; //(*func)(b);
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         //throw new Fatal("CamClay::_find_intersection: Root must be bracketed in zbrent");
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;   //Rename a, b, c and adjust bounding interval
00643             fc=fa; // d.
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; // Convergence check.
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; // Attempt inverse quadratic interpolation.
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; // Check whether in bounds.
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; // Accept interpolation.
00685                 d=p/q;
00686             }
00687             else
00688             {
00689                 d=xm; // Interpolation failed, use bisection.
00690                 e=d;
00691             }
00692         }
00693         else
00694         { // Bounds decreasing too slowly, use bisection.
00695             d=xm;
00696             e=d;
00697         }
00698         a=b; // Move last best guess to a.
00699         fa=fb;
00700         if (fabs(d) > tol1) // Evaluate new trial root.
00701             b += d;
00702         else
00703             b += Util::Sign(tol1,xm);
00704 
00705         // Calculate function value at intersection
00706         //fb=(*func)(b);
00707         // Trial Intersection
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    ,         // In: Stress or Strain error between low and high order evaluation (FE and ME) {{{
00739                                   Tensor2 const & y_high,         // In: Stress or Strain high order evaluation - "correct" (ME)
00740                                   REAL    const & Ez0   ,         // In: Error on internal variables
00741                                   REAL    const & z0_high) const  // In: Higher evaluation of internal variables
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 // Allocate a new CamClay model
00753 EquilibModel * CamClayMaker(Array<REAL> const & Prms, Array<REAL> const & IniData) // {{{
00754 {
00755     return new CamClay(Prms, IniData);
00756 } // }}}
00757 
00758 // Register an CamClay model into ModelFactory array map
00759 int CamClayRegister() // {{{
00760 {
00761     EquilibModelFactory["CamClay"] = CamClayMaker;
00762     return 0;
00763 } // }}}
00764 
00765 // Execute the autoregistration
00766 int __CamClay_dummy_int = CamClayRegister();
00767 
00768 #endif // MECHSYS_CAMCLAY_H
00769 
00770 // vim:fdm=marker

Generated on Wed Jan 24 15:56:27 2007 for MechSys by  doxygen 1.4.7