MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/models/stressupdate.h
Go to the documentation of this file.
00001 /************************************************************************
00002  * MechSys - Open Library for Mechanical Systems                        *
00003  * Copyright (C) 2005 Dorival M. Pedroso, Raul Durand                   *
00004  * Copyright (C) 2009 Sergio Galindo                                    *
00005  *                                                                      *
00006  * This program is free software: you can redistribute it and/or modify *
00007  * it under the terms of the GNU General Public License as published by *
00008  * the Free Software Foundation, either version 3 of the License, or    *
00009  * any later version.                                                   *
00010  *                                                                      *
00011  * This program is distributed in the hope that it will be useful,      *
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         *
00014  * GNU General Public License for more details.                         *
00015  *                                                                      *
00016  * You should have received a copy of the GNU General Public License    *
00017  * along with this program. If not, see <http://www.gnu.org/licenses/>  *
00018  ************************************************************************/
00019 
00020 #ifdef STRESSUPDATE_DECLARE
00021 
00022 class StressUpdate
00023 {
00024 public:
00025     // callbacks
00026     typedef void (*pDbgFun) (StressUpdate const & SU, void * UserData); 
00027 
00028     // enum
00029     enum Scheme_t { ME_t, SingleFE_t, RK_t }; 
00030 
00031     // Constructor & Destructor
00032      StressUpdate ();
00033     ~StressUpdate () { if (ODE!=NULL) delete ODE;  if (sta_1!=NULL) delete sta_1;  if (sta_ME!=NULL) delete sta_ME; }
00034 
00035     // Methods
00036     void   SetModel  (Model const * TheMdl);
00037     void   SetScheme (String const & Name);
00038     void   Update    (Vec_t const & DEps, State * Sta, Vec_t & DSig);
00039     double Update    (double Dt, ATensor2 const & L, ATensor2 & F, State * Sta); 
00040     void   GetInfo   (std::ostream & os, bool Header=false) const;
00041 
00042     // Data
00043     Model const * Mdl;
00044     pDbgFun       DbgFun;
00045     void        * DbgDat;
00046 
00047     // ODE solver (if sheme==RK)
00048     Numerical::ODESolver<StressUpdate> * ODE;
00049 
00050     // Constants for integration
00051     Scheme_t       Scheme; 
00052     double         STOL;
00053     double         dTini;
00054     double         mMin;
00055     double         mMax;
00056     size_t         MaxSS;
00057     bool           CDrift; 
00058     double         Error;
00059     String         RKScheme;
00060     double         T;
00061     double         dT;
00062     size_t         SS;     
00063     size_t         SSs;    
00064     size_t         DCit;   
00065     size_t         DCitEl; 
00066     size_t         ncp;    
00067     size_t         niv;    
00068     size_t         neq;    
00069     Vec_t          dsig;
00070     Vec_t          deps;
00071     Vec_t          divs;
00072     Vec_t          eps0;
00073     EquilibState * sta;
00074 
00075     // auxiliary variables
00076     EquilibState * sta_1;         // intermediate state
00077     EquilibState * sta_ME;        // Modified-Euler state
00078     Vec_t deps_1, dsig_1, divs_1; // intermediate increments
00079     Vec_t dsig_2, divs_2;         // ME increments
00080     Vec_t sig_dif;                // ME - FE stress difference
00081 
00082     // auxiliary variables for large deformation update
00083     ATensor2 mF;         
00084     ATensor2 Ia;         
00085     ATensor2 DtL;        
00086     ATensor2 dtL;        
00087     ATensor2 dtL_1;      
00088     Vec_t    sig_tmp;    
00089     Vec_t    DEps_in;    
00090     Vec_t    dsig_out;   
00091     bool     CorrectObj; 
00092     EquilibState * sta_in;
00093 
00094     // auxiliary methods
00095     size_t GetMax (size_t PrevMax, size_t NewMax)
00096     {
00097         if (NewMax>PrevMax) return NewMax;
00098         else                return PrevMax;
00099     }
00100 
00101 private:
00102     // Auxiliary methods
00103     int  _RK_fun    (double t, double const Y[], double dYdt[]);
00104     void _RK_up_fun (double t, double Y[]);
00105 };
00106 
00107 #endif // STRESSUPDATE_DECLARE
00108 
00109 
00111 
00112 
00113 #ifdef STRESSUPDATE_IMPLEMENT
00114 
00115 #include <mechsys/numerical/odesolver.h>
00116 
00117 inline Model::StressUpdate::StressUpdate ()
00118     : Mdl      (NULL),
00119       DbgFun   (NULL),
00120       DbgDat   (NULL),
00121       ODE      (NULL),
00122       Scheme   (ME_t),
00123       STOL     (1.0e-5),
00124       dTini    (1.0),
00125       mMin     (0.1),
00126       mMax     (10.0),
00127       MaxSS    (2000),
00128       CDrift   (true),
00129       Error    (0.0),
00130       RKScheme ("ME"),
00131       T        (0.0),
00132       dT       (dTini),
00133       SS       (0),
00134       SSs      (0),
00135       DCit     (0),
00136       DCitEl   (0),
00137       sta      (NULL),
00138       CorrectObj (false)
00139 {
00140     Ia = 1.0,1.0,1.0, 0.0,0.0,0.0, 0.0,0.0,0.0;
00141 }
00142 
00143 inline void Model::StressUpdate::SetModel (Model const * TheMdl)
00144 {
00145     Mdl = TheMdl;
00146     ncp = Mdl->NCps;
00147     niv = Mdl->NIvs;
00148     neq = ncp + niv;
00149     ODE = new Numerical::ODESolver<StressUpdate> (this, &StressUpdate::_RK_fun, neq, "ME", STOL, dTini);
00150     ODE->UpFun = &StressUpdate::_RK_up_fun;
00151     ODE->mMin  = mMin;
00152     ODE->mMax  = mMax;
00153 
00154     // auxiliary variables
00155     dsig.change_dim (ncp);
00156     deps.change_dim (ncp);
00157     divs.change_dim (niv);
00158 
00159     // ME variables
00160     sta_1  = new EquilibState (Mdl->NDim);
00161     sta_ME = new EquilibState (Mdl->NDim);
00162     deps_1.change_dim(ncp);  dsig_1.change_dim(ncp);  divs_1.change_dim(niv);
00163     dsig_2.change_dim(ncp);  divs_2.change_dim(niv);
00164     sig_dif.change_dim(ncp);
00165 }
00166 
00167 inline void Model::StressUpdate::SetScheme (String const & Name)
00168 {
00169     if      (Name=="ME")       Scheme = ME_t;
00170     else if (Name=="SingleFE") Scheme = SingleFE_t;
00171     else if (Name=="RK")       Scheme = RK_t;
00172     else throw new Fatal("StressUpdate::SetScheme: Scheme named %s is invalid",Name.CStr());
00173 }
00174 
00175 inline void Model::StressUpdate::Update (Vec_t const & DEps, State * Sta, Vec_t & DSig)
00176 {
00177     // check
00178     if (Mdl==NULL) throw new Fatal("Model::StressUpdate::Update: SetModel must be called before calling this method");
00179 
00180     // scheme
00181     if (Mdl->Prms.HasKey("newsu")) { if ((int)Mdl->Prms("newsu")) Scheme = RK_t; }
00182 
00183     // current state
00184     sta  = static_cast<EquilibState*>(Sta);
00185     DSig = sta->Sig; // temporary copy to calculate increment later
00186 
00187     if (Scheme==SingleFE_t) // without intersection detection (should be used for linear elasticity only)
00188     {
00189         throw new Fatal("Model::StressUpdate::Update: SingleFE_t is deactivated");
00190         deps = DEps;
00191         Mdl->TgIncs (sta, deps, dsig, divs);
00192         if (CorrectObj)
00193         {
00194             AddSkewTimesOp1 (DtL, sta->Sig, dsig);
00195             //printf("Model::StressUpdate::Update: Correcting objective stress increment\n");
00196         }
00197         sta->Eps += deps;
00198         sta->Sig += dsig;
00199         sta->Ivs += divs;
00200         if (DbgFun!=NULL) (*DbgFun) ((*this), DbgDat);
00201     }
00202     else if (Scheme==ME_t)
00203     {
00204         // loading-unloading ?
00205         double aint = -1.0; // no intersection
00206         bool   ldg  = Mdl->LoadCond (sta, DEps, aint);
00207 
00208         // set loading flag
00209         sta    -> Ldg = ldg;
00210         sta_1  -> Ldg = ldg;
00211         sta_ME -> Ldg = ldg;
00212 
00213         // with intersection ?
00214         if (aint>0.0 && aint<1.0)
00215         {
00216             // update to intersection
00217             deps = aint*DEps;
00218             Mdl->TgIncs (sta, deps, dsig, divs);
00219             if (CorrectObj) { dtL=aint*DtL;  AddSkewTimesOp1 (dtL, sta->Sig, dsig); }
00220             sta->Eps += deps;
00221             sta->Sig += dsig;
00222             sta->Ivs += divs;
00223             deps = fabs(1.0-aint)*DEps; // remaining of DEps to be applied
00224             if (CorrectObj) dtL = fabs(1.0-aint)*DtL;
00225 
00226             // change loading flag
00227             ldg           = true;
00228             sta    -> Ldg = ldg;
00229             sta_1  -> Ldg = ldg;
00230             sta_ME -> Ldg = ldg;
00231 
00232             // drift correction
00233             //if (DbgFun!=NULL) (*DbgFun) ((*this), DbgDat);
00234             if (CDrift) DCitEl = GetMax (DCitEl, Mdl->CorrectDrift(sta));
00235 
00236             // debug
00237             if (DbgFun!=NULL) (*DbgFun) ((*this), DbgDat);
00238         }
00239         else
00240         {
00241             deps = DEps; // update with full DEps
00242             if (CorrectObj) dtL = DtL;
00243         }
00244 
00245         // for each pseudo time T
00246         T      = 0.0;
00247         dT     = dTini;
00248         SS     = 0;
00249         SSs    = 0;
00250         DCitEl = 0;
00251         DCit   = 0;
00252         for (SS=0; SS<MaxSS; ++SS)
00253         {
00254             // exit point
00255             if (T>=1.0) break;
00256 
00257             // FE and ME increments
00258             deps_1 = dT*deps;
00259             Mdl->TgIncs (sta, deps_1, dsig_1, divs_1);
00260             if (CorrectObj) { dtL_1=dT*dtL;  AddSkewTimesOp1 (dtL_1, sta->Sig, dsig_1); }
00261             sta_1->Eps  = sta->Eps + deps_1;
00262             sta_1->Sig  = sta->Sig + dsig_1;
00263             sta_1->Ivs  = sta->Ivs + divs_1;
00264             Mdl->TgIncs (sta_1, deps_1, dsig_2, divs_2);
00265             if (CorrectObj) AddSkewTimesOp1 (dtL_1, sta_1->Sig, dsig_2);
00266             sta_ME->Sig = sta->Sig + 0.5*(dsig_1+dsig_2);
00267             sta_ME->Ivs = sta->Ivs + 0.5*(divs_1+divs_2);
00268 
00269             // local error estimate
00270             sig_dif = sta_ME->Sig - sta_1->Sig;
00271             double sig_err = Norm(sig_dif)/(1.0+Norm(sta_ME->Sig));
00272             double ivs_err = 0.0;
00273             for (size_t i=0; i<niv; ++i) ivs_err += fabs(sta_ME->Ivs(i)-sta_1->Ivs(i))/(1.0+fabs(sta_ME->Ivs(i)));
00274             Error = sig_err + ivs_err;
00275 
00276             // step multiplier
00277             double m = (Error>0.0 ? 0.9*sqrt(STOL/Error) : mMax);
00278 
00279             // update
00280             if (Error<STOL)
00281             {
00282                 // update state
00283                 SSs++;
00284                 T += dT;
00285                 sta->Eps = sta_1  -> Eps;
00286                 sta->Sig = sta_ME -> Sig;
00287                 sta->Ivs = sta_ME -> Ivs;
00288 
00289                 // drift correction
00290                 //if (DbgFun!=NULL) (*DbgFun) ((*this), DbgDat);
00291                 if (CDrift) DCit = GetMax (DCit, Mdl->CorrectDrift (sta));
00292 
00293                 // update stress path in model
00294                 Mdl->UpdatePath (sta, deps_1, Vec_t(0.5*(dsig_1+dsig_2)));
00295 
00296                 // limit change on stepsize
00297                 if (m>mMax) m = mMax;
00298 
00299                 // debug
00300                 if (DbgFun!=NULL) (*DbgFun) ((*this), DbgDat);
00301             }
00302             else if (m<mMin) m = mMin;
00303 
00304             // change next step size
00305             dT = m * dT;
00306 
00307             // check for last increment
00308             if (dT>1.0-T) dT = 1.0-T;
00309         }
00310         if (SS>=MaxSS) throw new Fatal("StressUpdate::Update: Modified-Euler (local) did not converge after %d substeps",SS);
00311     }
00312     else if (Scheme==RK_t)
00313     {
00314         // initial strain and increment
00315         eps0 = sta->Eps;
00316         deps = DEps;
00317 
00318         // loading condition
00319         double aint;
00320         sta->Ldg = Mdl->LoadCond (sta, deps, aint);
00321 
00322         // initial state
00323         ODE->t = 0.0;
00324         for (size_t i=0; i<ncp; ++i) ODE->Y[    i] = sta->Sig(i);
00325         for (size_t i=0; i<niv; ++i) ODE->Y[ncp+i] = sta->Ivs(i);
00326 
00327         // evolve
00328         ODE->Evolve (1.0);
00329 
00330         // final state
00331         for (size_t i=0; i<ncp; ++i) sta->Sig(i) = ODE->Y[    i];
00332         for (size_t i=0; i<niv; ++i) sta->Ivs(i) = ODE->Y[ncp+i];
00333         sta->Eps = eps0 + deps;
00334     }
00335     else throw new Fatal("StressUpdate::Update: Scheme is not available yet");
00336 
00337     // return total stress increment
00338     DSig = sta->Sig - DSig;
00339 
00340     // debug
00341     if (DbgFun!=NULL) (*DbgFun) ((*this), DbgDat);
00342 }
00343 
00344 inline double Model::StressUpdate::Update (double Dt, ATensor2 const & L, ATensor2 & F, State * Sta)
00345 {
00346     // update deformation gradient
00347     mF = Ia + L*Dt;
00348     Dot (mF, F,  F); // F = mF*F
00349 
00350     // compute strain increment == rate of deformation D*Dt, in which D = Sym(L)
00351     Sym (Dt, L, ncp, DEps_in); // DEps_in = Dt*sym(L)
00352 
00353     // stress update
00354     sta_in  = static_cast<EquilibState*>(Sta); // cannot use sta_1 or else, because the other Update will re-assign these
00355     sig_tmp = sta_in->Sig;
00356     if (Mdl->UseUpdateSta)
00357     {
00358         Mdl->UpdateSta (F, sta_in);
00359     }
00360     else
00361     {
00362         DtL        = Dt*L;
00363         CorrectObj = true;
00364         Update (DEps_in, sta_in, dsig_out);
00365         CorrectObj = false;
00366     }
00367 
00368     // Strain energy
00369     return 0.0;//0.5*Dot(sig_tmp+sta_in->Sig, DEps_in); // strain energy / volume
00370 }
00371 
00372 inline void Model::StressUpdate::GetInfo (std::ostream & os, bool Header) const
00373 {
00374     String buf;
00375     if (Scheme==ME_t)
00376     {
00377         if (Header)
00378         {
00379             os << "\n" << TERM_BLACK_WHITE << "----------------------------- StressUpdate/Scheme: ME ------------------------------" << TERM_RST << "\n\n";
00380             os << "STOL   = " << STOL   << std::endl;
00381             os << "dTini  = " << dTini  << std::endl;
00382             os << "mMin   = " << mMin   << std::endl;
00383             os << "mMax   = " << mMax   << std::endl;
00384             os << "MaxSS  = " << MaxSS  << std::endl;
00385             os << "CDrift = " << CDrift << std::endl;
00386             buf.Printf("\n%6s %6s %6s %6s %6s %12s %12s %16s\n", "Scheme", "SS", "SSs", "DCitEl", "DCit", "T", "dT", "Error");
00387             os << buf;
00388         }
00389         buf.Printf("%6s %6zd %6zd %6zd %6zd %12.8f %12.8f %16.8e\n", "ME", SS, SSs, DCitEl, DCit, T, dT, Error);
00390         os << buf;
00391     }
00392     else if (Scheme==SingleFE_t)
00393     {
00394         if (Header) os << "\n" << TERM_BLACK_WHITE << "----------------------------- StressUpdate/Scheme: SingleFE ------------------------" << TERM_RST << "\n\n";
00395     }
00396     else if (Scheme==RK_t)
00397     {
00398         if (Header)
00399         {
00400             if (ODE==NULL)
00401             {
00402                 os << "\n" << TERM_BLACK_WHITE << "----------------------------- StressUpdate/Scheme: RK ----------------------------" << TERM_RST << "\n\n";
00403                 return;
00404             }
00405             os << "\n" << TERM_BLACK_WHITE << "----------------------------- StressUpdate/Scheme: RK(" << ODE->Scheme << ") ----------------------------" << TERM_RST << "\n\n";
00406             os << "STOL   = " << ODE->STOL   << std::endl;
00407             os << "dTini  = " << ODE->dTini  << std::endl;
00408             os << "mMin   = " << ODE->mMin   << std::endl;
00409             os << "mMax   = " << ODE->mMax   << std::endl;
00410             os << "MaxSS  = " << ODE->MaxSS  << std::endl;
00411             os << "CDrift = " << CDrift      << std::endl;
00412             buf.Printf("\n%6s %6s %6s %6s %12s %12s\n", "Scheme", "SS", "SSs", "DCit", "T", "dT");
00413             os << buf;
00414         }
00415         if (ODE==NULL) return;
00416         buf.Printf("%6s %6zd %6zd %6zd %12.8f %12.8f\n", "ME", ODE->SS, ODE->SSs, DCit, ODE->T, ODE->dT);
00417         os << buf;
00418     }
00419 }
00420 
00421 inline int Model::StressUpdate::_RK_fun (double t, double const Y[], double dYdt[])
00422 {
00423     // current strain, stress, and internal values
00424     sta->Eps = eps0 + t*deps;
00425     for (size_t i=0; i<ncp; ++i) sta->Sig(i) = Y[    i];
00426     for (size_t i=0; i<niv; ++i) sta->Ivs(i) = Y[ncp+i];
00427 
00428     // tangent increments
00429     Mdl->TgIncs (sta, deps, dsig, divs);
00430     for (size_t i=0; i<ncp; ++i) dYdt[    i] = dsig(i);
00431     for (size_t i=0; i<niv; ++i) dYdt[ncp+i] = divs(i);
00432 
00433     // return success
00434     return GSL_SUCCESS;
00435 }
00436 
00437 inline void Model::StressUpdate::_RK_up_fun (double t, double Y[])
00438 {
00439     // current strain, stress, and internal values
00440     sta->Eps = eps0 + t*deps;
00441     for (size_t i=0; i<ncp; ++i) sta->Sig(i) = Y[    i];
00442     for (size_t i=0; i<niv; ++i) sta->Ivs(i) = Y[ncp+i];
00443 
00444     // correct drift
00445     if (CDrift)
00446     {
00447         DCit = GetMax (DCit, Mdl->CorrectDrift (sta));
00448         for (size_t i=0; i<ncp; ++i) Y[    i] = sta->Sig(i);
00449         for (size_t i=0; i<niv; ++i) Y[ncp+i] = sta->Ivs(i);
00450     }
00451 
00452     // debug function
00453     if (DbgFun!=NULL) (*DbgFun) ((*this), DbgDat);
00454 }
00455 
00456 #endif // STRESSUPDATE_IMPLEMENT
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines