MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/fem/solvers/stdsolver.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 #ifndef MECHSYS_FEM_STDSOLVER_H
00021 #define MECHSYS_FEM_STDSOLVER_H
00022 
00023 // MechSys
00024 #include <mechsys/fem/solver.h>
00025 
00026 namespace FEM
00027 {
00028 
00029 class STDSolver : public Solver
00030 {
00031 public:
00032     // enum
00033     enum Scheme_t  { FE_t, ME_t, NR_t };             
00034     enum TScheme_t { TH_t };                         
00035     enum DScheme_t { GN22_t, RK_t };                 
00036     enum Damping_t { None_t, Rayleigh_t, HMCoup_t }; 
00037 
00038     // Constructor
00039     STDSolver (Domain & Dom, SDPair const & Flags, pOutFun OutFun=NULL, void * OutDat=NULL,
00040                                                    pOutFun DbgFun=NULL, void * DbgDat=NULL); 
00041 
00042     // Methods
00043     String Name           () const { return "STDSolver"; }
00044     void   Solve          (size_t NInc=1, char const * FileKey=NULL);                      
00045     void   TransSolve     (double tf, double dt, double dtOut, char const * FileKey=NULL); 
00046     void   DynSolve       (double tf, double dt, double dtOut, char const * FileKey=NULL); 
00047     void   AssembleKA     ();                                                              
00048     void   AssembleKMA    (double Coef1, double Coef2);                                    
00049     void   AssembleKCMA   (double Coef1, double Coef2, double Coef3);                      
00050     void   TgIncs         (double dT, Vec_t & dU, Vec_t & dF);                             
00051     void   UpdateNodes    (bool Transient=false);                                          
00052     void   UpdateElements (Vec_t const & dU, bool CalcFint);                               
00053     void   Initialize     (bool Transient=false);                                          
00054     void   SetIncsW       (size_t NInc, bool NonLinWei=false);                             
00055     bool   ResidOK        () const;                                                        
00056 
00057     // Data (read-only)
00058     size_t        Inc;      
00059     size_t        Stp;      
00060     size_t        It;       
00061     size_t        NEq;      
00062     size_t        NIv;      
00063     size_t        NLag;     
00064     Array<long>   pEQ;      
00065     Array<long>   pEQproc;  
00066     Array<bool>   pU;       
00067     double        NormR;    
00068     double        MaxNormF; 
00069 
00070     // Data (read-write)
00071     Scheme_t      Scheme;   
00072     bool          CalcWork; 
00073     size_t        nSS;      
00074     double        STOL;     
00075     double        dTini;    
00076     double        dTlast;   
00077     double        mMin;     
00078     double        mMax;     
00079     size_t        MaxSS;    
00080     bool          SSOut;    
00081     bool          CteTg;    
00082     bool          ModNR;    
00083     double        TolR;     
00084     bool          CorR;     
00085     size_t        MaxIt;    
00086     TScheme_t     TScheme;  
00087     double        TransTh;  
00088     DScheme_t     DScheme;  
00089     Damping_t     DampTy;   
00090     double        DampAm;   
00091     double        DampAk;   
00092     double        DynTh1;   
00093     double        DynTh2;   
00094     Array<double> IncsW;    
00095     bool          WithInfo; 
00096     bool          WarnRes;  
00097     double        WrnTol;   
00098     String        RKScheme; 
00099     double        RKSTOL;   
00100     SDPair        NLSteps;  
00101 
00102     // Triplets and sparse matrices
00103     Sparse::Triplet<double,int> K11,K12,K21,K22; 
00104     Sparse::Triplet<double,int> C11,C12,C21,C22; 
00105     Sparse::Triplet<double,int> M11,M12,M21,M22; 
00106     Sparse::Triplet<double,int> A11;             
00107 
00108     // Vectors
00109     Vec_t R;            
00110     Vec_t F0;           
00111     Vec_t F, F_int;     
00112     Vec_t W, U;         
00113     Vec_t V, A;         
00114     Vec_t dU, dF;       
00115     Vec_t Us, Vs;       
00116     Vec_t TmpVec;       
00117 
00118     void DebugPrintMatrices (bool Stop=true); 
00119 
00120 private:
00121     void   _aug_and_set_A ();                          
00122     void   _wrn_resid     ();                          
00123     void   _cal_resid     ();                          
00124     void   _cor_resid     (Vec_t & dU, Vec_t & dF);    
00125     void   _FE_update     (double tf);                 
00126     void   _ME_update     (double tf, char const*FNK); 
00127     void   _NR_update     (double tf);                 
00128     void   _TH_update     (double tf, double dt);      
00129     void   _GN22_update   (double tf, double dt);      
00130     void   _time_print    (char const * Comment=NULL); 
00131     void   _VUIV_to_Y     (double Y[]);
00132     void   _Y_to_VUIV     (double const Y[]);
00133     int    _RK_func       (double t, double const Y[], double dYdt[]);
00134     void   _RK_update     (double tf, double dt);      
00135 };
00136 
00137 
00139 
00140 
00141 inline STDSolver::STDSolver (Domain & Dom, SDPair const & Flags, pOutFun OutFun, void * OutDat, pOutFun DbgFun, void * DbgDat)
00142     : Solver   (Dom, Flags, OutFun, OutDat, DbgFun, DbgDat),
00143       Inc      (0),
00144       Stp      (0),
00145       It       (0),
00146       Scheme   (ME_t),
00147       CalcWork (false),
00148       nSS      (1),
00149       STOL     (1.0e-5),
00150       dTini    (1.0),
00151       dTlast   (-1.0),
00152       mMin     (0.1),
00153       mMax     (10.0),
00154       MaxSS    (2000),
00155       SSOut    (false),
00156       CteTg    (false),
00157       ModNR    (false),
00158       TolR     (1.0e-7),
00159       CorR     (true),
00160       MaxIt    (20),
00161       TScheme  (TH_t),
00162       TransTh  (1./2.),
00163       DScheme  (GN22_t),
00164       DampTy   (None_t),
00165       DampAm   (0.005),
00166       DampAk   (0.5),
00167       DynTh1   (0.5),
00168       DynTh2   (0.5),
00169       WithInfo (true),
00170       WarnRes  (false),
00171       WrnTol   (1.0e-7),
00172       RKScheme ("RK4I"),
00173       RKSTOL   (1.0e-2)
00174 {
00175 #if HAS_MPI
00176     if (FEM::Domain::PARA && MPI::COMM_WORLD.Get_rank()!=0) WithInfo = false;
00177 #endif
00178 
00179     if (Flags.HasKey("fe"       )) Scheme   = (static_cast<int>(Flags("fe"))>0 ? FE_t : Scheme);
00180     if (Flags.HasKey("me"       )) Scheme   = (static_cast<int>(Flags("me"))>0 ? ME_t : Scheme);
00181     if (Flags.HasKey("nr"       )) Scheme   = (static_cast<int>(Flags("nr"))>0 ? NR_t : Scheme);
00182     if (Flags.HasKey("calcwork" )) CalcWork = (static_cast<int>(Flags("calcwork"))>0);
00183     if (Flags.HasKey("nss"      )) nSS      = (static_cast<int>(Flags("nss"     ))>0);
00184     if (Flags.HasKey("ssout"    )) SSOut    = (static_cast<int>(Flags("ssout"   ))>0);
00185     if (Flags.HasKey("ctetg"    )) CteTg    = (static_cast<int>(Flags("ctetg"   ))>0);
00186     if (Flags.HasKey("modnr"    )) ModNR    = (static_cast<int>(Flags("modnr"   ))>0);
00187     if (Flags.HasKey("hm"       )) DampTy   = (static_cast<int>(Flags("hm")      )>0 ? HMCoup_t   : DampTy );
00188     if (Flags.HasKey("ray"      )) DampTy   = (static_cast<int>(Flags("ray")     )>0 ? Rayleigh_t : DampTy );
00189     if (Flags.HasKey("rk"       )) DScheme  = (static_cast<int>(Flags("rk")      )>0 ? RK_t       : DScheme);
00190     if (Flags.HasKey("am"       )) DampAm   = Flags("am");
00191     if (Flags.HasKey("ak"       )) DampAk   = Flags("ak");
00192     if (Flags.HasKey("maxit"    )) MaxIt    = static_cast<int>(Flags("maxit"));
00193     if (Flags.HasKey("tolr"     )) TolR     = Flags("tolr");
00194     if (Flags.HasKey("rkstol"   )) RKSTOL   = Flags("rkstol");
00195     if (Flags.HasKey("nldt_nsml")) NLSteps.Set("nsml", Flags("nldt_nsml"));
00196     if (Flags.HasKey("nldt_nn"  )) NLSteps.Set("nn"  , Flags("nldt_nn"  ));
00197     if (Flags.HasKey("nldt_n"   )) NLSteps.Set("n"   , Flags("nldt_n"   ));
00198     if (Flags.HasKey("nldt_ll"  )) NLSteps.Set("ll"  , Flags("nldt_ll"  ));
00199     if (Flags.HasKey("nldt_sch" )) NLSteps.Set("sch" , Flags("nldt_sch" ));
00200     if (Flags.HasKey("nldt_m"   )) NLSteps.Set("m"   , Flags("nldt_m"   ));
00201 
00202     //if (rkscheme!="") Sol.RKScheme = rkscheme;
00203 }
00204 
00205 inline void STDSolver::Solve (size_t NInc, char const * FileKey)
00206 {
00207     // info
00208     Util::Stopwatch stopwatch(/*activated*/WithInfo);
00209 
00210     // initialize global matrices and vectors
00211     Initialize ();
00212 
00213     // output initial state
00214     if (WithInfo)
00215     {
00216         if      (Scheme==FE_t) _time_print ("Quasi-static --- FE");
00217         else if (Scheme==ME_t) _time_print ("Quasi-static --- ME");
00218         else if (Scheme==NR_t) _time_print ("Quasi-static --- NR");
00219     }
00220     if (Dom.IdxOut==0)
00221     {
00222         Dom.OutResults (FileKey);
00223         if (OutFun!=NULL) (*OutFun) (this, OutDat);
00224         if (DbgFun!=NULL) (*DbgFun) (this, DbgDat);
00225     }
00226 
00227     // weights
00228     if (IncsW.Size()!=NInc) SetIncsW (NInc);
00229 
00230     // solve
00231     double t0 = Dom.Time; // current time
00232     double tf = t0 + 1.0; // final time
00233     double Dt = tf - t0;  // total time increment
00234     double dt, tout;      // timestep and time for output
00235     for (Inc=0; Inc<NInc; ++Inc)
00236     {
00237         // timestep
00238         dt   = IncsW[Inc]*Dt; // timestep
00239         tout = Dom.Time + dt; // time for output
00240 
00241         // update U, F, Time and elements to tout
00242         if      (Scheme==FE_t) _FE_update (tout);
00243         else if (Scheme==ME_t) _ME_update (tout, FileKey);
00244         else if (Scheme==NR_t) _NR_update (tout);
00245 
00246         // update nodes to tout
00247         UpdateNodes ();
00248 
00249         // output
00250         if (WithInfo) _time_print ();
00251         if (Scheme!=ME_t) Dom.OutResults (FileKey);
00252         else if (!SSOut)  Dom.OutResults (FileKey);
00253         if (OutFun!=NULL) (*OutFun) (this, OutDat);
00254 
00255         // next tout
00256         tout = Dom.Time + dt;
00257     }
00258 }
00259 
00260 inline void STDSolver::TransSolve (double tf, double dt, double DtOut, char const * FileKey)
00261 {
00262     // info
00263     Util::Stopwatch stopwatch(/*activated*/WithInfo);
00264 
00265     // initialize global matrices and vectors
00266     Initialize (/*Transient*/true);
00267 
00268     // output initial state
00269     if (WithInfo)
00270     {
00271         if (TScheme==TH_t) _time_print ("Transient ------ TH(theta)");
00272     }
00273     if (Dom.IdxOut==0)
00274     {
00275         Dom.OutResults (FileKey);
00276         if (OutFun!=NULL) (*OutFun) (this, OutDat);
00277         if (DbgFun!=NULL) (*DbgFun) (this, DbgDat);
00278     }
00279 
00280     // time for output
00281     double dtOut = DtOut;
00282     double tout  = Dom.Time + dtOut;
00283 
00284     // nonlinear timesteps
00285     int    nl_nsml = 7;     // number fo small timestep __sets__
00286     int    nl_sch  = 0;     // scheme for larger timesteps
00287     double nl_ll   = 100.0; // denominator
00288     double nl_m    = 2.0;   // multiplier for larger timesteps in sch==1
00289     int    nl_n    = 10;    // number of timesteps per __set__
00290     int    nl_i    = 0;     // timestep set index
00291     int    nl_k    = 0;     // current accumulated timesteps
00292     int    nl_K    = 0;     // current total number of timesteps
00293     bool   nl_stp  = false; // use nonlinear timesteps ?
00294     if (NLSteps.Keys.Size()>0)
00295     {
00296         nl_nsml = static_cast<int>(NLSteps("nsml"));
00297         nl_n    = static_cast<int>(NLSteps("n"));
00298         if (NLSteps.HasKey("sch")) nl_sch = static_cast<int>(NLSteps("sch"));
00299         if (NLSteps.HasKey("ll" )) nl_ll  = NLSteps("ll");
00300         if (NLSteps.HasKey("m"  )) nl_m   = NLSteps("m");
00301         nl_stp  = true;
00302         dt      = Timestep (nl_i, nl_nsml, nl_ll, nl_sch, nl_m);
00303         dtOut   = (dtOut<dt ? dt : dtOut);
00304     }
00305 
00306     // solve
00307     if (TScheme==TH_t)
00308     {
00309         while (Dom.Time<tf)
00310         {
00311             // update U, F, Time and elements to tout
00312             _TH_update (tout,dt);
00313 
00314             // update nodes to tout
00315             UpdateNodes (true);
00316 
00317             // output
00318             if (WithInfo) _time_print ();
00319             Dom.OutResults (FileKey);
00320             if (OutFun!=NULL) (*OutFun) (this, OutDat);
00321 
00322             // next tout
00323             tout = Dom.Time + dtOut;
00324 
00325             // next timestep set
00326             if (nl_stp)
00327             {
00328                 nl_K++;
00329                 nl_k++;
00330                 if (nl_k==nl_n)
00331                 {
00332                     nl_k = 0;
00333                     nl_i++;
00334                     dt    = Timestep (nl_i, nl_nsml, nl_ll, nl_sch, nl_m);
00335                     dtOut = (dtOut<dt ? dt : dtOut);
00336                 }
00337             }
00338         }
00339     }
00340 }
00341 
00342 inline void STDSolver::DynSolve (double tf, double dt, double DtOut, char const * FileKey)
00343 {
00344     // info
00345     Util::Stopwatch stopwatch(/*activated*/WithInfo);
00346 
00347     // initialize global matrices and vectors
00348     Initialize (/*Transient*/true);
00349 
00350     // output initial state
00351     if (WithInfo)
00352     {
00353         if      (DScheme==GN22_t) _time_print ("Dynamic ------ GN22");
00354         else if (DScheme==RK_t)
00355         {
00356             String buf("Dynamic ------ "); buf.append(RKScheme);
00357             _time_print (buf.CStr());
00358         }
00359     }
00360     if (Dom.IdxOut==0)
00361     {
00362         Dom.OutResults (FileKey);
00363         if (OutFun!=NULL) (*OutFun) (this, OutDat);
00364         if (DbgFun!=NULL) (*DbgFun) (this, DbgDat);
00365     }
00366 
00367     // time for output
00368     double dtOut = DtOut;
00369     double tout  = Dom.Time + dtOut;
00370 
00371     // nonlinear timesteps
00372     int    nl_nsml = 7;     // number fo small timestep __sets__
00373     int    nl_sch  = 0;     // scheme for larger timesteps
00374     double nl_ll   = 100.0; // denominator
00375     double nl_m    = 2.0;   // multiplier for larger timesteps in sch==1
00376     int    nl_n    = 10;    // number of timesteps per __set__
00377     int    nl_i    = 0;     // timestep set index
00378     int    nl_k    = 0;     // current accumulated timesteps
00379     int    nl_K    = 0;     // current total number of timesteps
00380     bool   nl_stp  = false; // use nonlinear timesteps ?
00381     if (NLSteps.Keys.Size()>0)
00382     {
00383         nl_nsml = static_cast<int>(NLSteps("nsml"));
00384         nl_n    = static_cast<int>(NLSteps("n"));
00385         if (NLSteps.HasKey("sch")) nl_sch = static_cast<int>(NLSteps("sch"));
00386         if (NLSteps.HasKey("ll" )) nl_ll  = NLSteps("ll");
00387         if (NLSteps.HasKey("m"  )) nl_m   = NLSteps("m");
00388         nl_stp  = true;
00389         dt      = Timestep (nl_i, nl_nsml, nl_ll, nl_sch, nl_m);
00390         dtOut   = (dtOut<dt ? dt : dtOut);
00391     }
00392 
00393     // solve
00394     if (DScheme==GN22_t)
00395     {
00396         double small = 1.0e-10;
00397         while (Dom.Time<tf)
00398         {
00399             // update U, F, Time and elements to tout
00400             _GN22_update (tout,dt);
00401 
00402             // update nodes to tout
00403             UpdateNodes (true);
00404 
00405             // output
00406             if (WithInfo) _time_print ();
00407             Dom.OutResults (FileKey);
00408             if (OutFun!=NULL) (*OutFun) (this, OutDat);
00409 
00410             // next tout
00411             tout = Dom.Time + dtOut;
00412 
00413             // next timestep set
00414             if (nl_stp)
00415             {
00416                 nl_K++;
00417                 nl_k++;
00418                 if (nl_k==nl_n)
00419                 {
00420                     nl_k = 0;
00421                     nl_i++;
00422                     dt    = Timestep (nl_i, nl_nsml, nl_ll, nl_sch, nl_m);
00423                     dtOut = (dtOut<dt ? dt : dtOut);
00424                 }
00425             }
00426 
00427             // last dt and tout
00428             if (Dom.Time + dt > tf) dt = tf - Dom.Time;
00429             if (tout>tf) tout = tf;
00430             if (dt<small) break; // finished
00431         }
00432     }
00433     else if (DScheme==RK_t)
00434     {
00435         // ODE
00436         if (CteTg) NIv = 0;
00437         size_t nvars = 2*NEq + NIv;
00438         Numerical::ODESolver<STDSolver> ode(this, &STDSolver::_RK_func, nvars, RKScheme.CStr(), RKSTOL, dt);
00439 
00440         // set initial state
00441         ode.t = Dom.Time;
00442         _VUIV_to_Y (ode.Y);
00443 
00444         // solve
00445         while (Dom.Time<tf)
00446         {
00447             // evolve from Time to tout
00448             ode.Evolve (tout);
00449 
00450             // update V, U and elements (if not CteTg)
00451             _Y_to_VUIV (ode.Y);
00452 
00453             // update elements if not already updated by _Y_to_VUIV
00454             if (CteTg)
00455             {
00456                 double Dt = ode.t - Dom.Time;
00457                 for (size_t i=0; i<Dom.ActEles.Size(); ++i)
00458                 {
00459                     size_t niv = Dom.ActEles[i]->NIVs();
00460                     if (niv>0)
00461                     {
00462                         Vec_t rate;
00463                         Dom.ActEles[i]->CalcIVRate (Dom.Time, U, V, rate);
00464                         for (size_t j=0; j<niv; ++j) Dom.ActEles[i]->SetIV (j, rate(j)*Dt);
00465                     }
00466                 }
00467             }
00468 
00469             // update nodes to tout
00470             UpdateNodes (true);
00471 
00472             // new time
00473             Dom.Time = ode.t;
00474 
00475             // output
00476             if (WithInfo) _time_print ();
00477             Dom.OutResults (FileKey);
00478             if (OutFun!=NULL) (*OutFun) (this, OutDat);
00479 
00480             // next tout
00481             tout = Dom.Time + dtOut;
00482         }
00483     }
00484 }
00485 
00486 inline void STDSolver::AssembleKA ()
00487 {
00488     if (CteTg && A11.Top()>0) return; // constant tangent matrices => linear problems
00489     A11.ResetTop(); // reset top (position to insert new values) => clear triplet
00490     K12.ResetTop();
00491     K21.ResetTop();
00492     K22.ResetTop();
00493     for (size_t k=0; k<Dom.ActEles.Size(); ++k)
00494     {
00495         Mat_t         K;   // K matrix
00496         Array<size_t> loc; // location array
00497         Dom.ActEles[k]->CalcK  (K);
00498         Dom.ActEles[k]->GetLoc (loc);
00499         for (size_t i=0; i<loc.Size(); ++i)
00500         {
00501             for (size_t j=0; j<loc.Size(); ++j)
00502             {
00503                      if (!pU[loc[i]] && !pU[loc[j]]) A11.PushEntry (loc[i], loc[j], K(i,j));
00504                 else if (!pU[loc[i]] &&  pU[loc[j]]) K12.PushEntry (loc[i], loc[j], K(i,j));
00505                 else if ( pU[loc[i]] && !pU[loc[j]]) K21.PushEntry (loc[i], loc[j], K(i,j));
00506                 else if ( pU[loc[i]] &&  pU[loc[j]]) K22.PushEntry (loc[i], loc[j], K(i,j));
00507             }
00508         }
00509     }
00510 
00511     // augment A matrix and set Lagrange multipliers (if any)
00512     _aug_and_set_A();
00513 }
00514 
00515 inline void STDSolver::AssembleKMA (double C1, double C2)
00516 {
00517     if (CteTg && A11.Top()>0) return; // constant tangent matrices => linear problems
00518     K11.ResetTop(); // reset top (position to insert new values) => clear triplet
00519     K12.ResetTop();
00520     K21.ResetTop();
00521     K22.ResetTop();
00522     M11.ResetTop(); // reset top (position to insert new values) => clear triplet
00523     M12.ResetTop();
00524     M21.ResetTop();
00525     M22.ResetTop();
00526     A11.ResetTop(); // reset top (position to insert new values) => clear triplet
00527     for (size_t k=0; k<Dom.ActEles.Size(); ++k)
00528     {
00529         Mat_t         K, M; // matrices
00530         Array<size_t> loc;  // location array
00531         Dom.ActEles[k]->CalcK  (K);
00532         Dom.ActEles[k]->CalcM  (M);
00533         Dom.ActEles[k]->GetLoc (loc);
00534         for (size_t i=0; i<loc.Size(); ++i)
00535         {
00536             for (size_t j=0; j<loc.Size(); ++j)
00537             {
00538                      if (!pU[loc[i]] && !pU[loc[j]]) { A11.PushEntry (loc[i], loc[j], C1*M(i,j) + C2*K(i,j));
00539                                                        K11.PushEntry (loc[i], loc[j], K(i,j));  M11.PushEntry (loc[i], loc[j], M(i,j)); }
00540                 else if (!pU[loc[i]] &&  pU[loc[j]]) { K12.PushEntry (loc[i], loc[j], K(i,j));  M12.PushEntry (loc[i], loc[j], M(i,j)); }
00541                 else if ( pU[loc[i]] && !pU[loc[j]]) { K21.PushEntry (loc[i], loc[j], K(i,j));  M21.PushEntry (loc[i], loc[j], M(i,j)); }
00542                 else if ( pU[loc[i]] &&  pU[loc[j]]) { K22.PushEntry (loc[i], loc[j], K(i,j));  M22.PushEntry (loc[i], loc[j], M(i,j)); }
00543             }
00544         }
00545     }
00546 
00547     // augment A matrix and set Lagrange multipliers (if any)
00548     _aug_and_set_A();
00549 }
00550 
00551 inline void STDSolver::AssembleKCMA (double C1, double C2, double C3)
00552 {
00553     if (CteTg && A11.Top()>0) return; // constant tangent matrices => linear problems
00554     K11.ResetTop(); // reset top (position to insert new values) => clear triplet
00555     K12.ResetTop();
00556     K21.ResetTop();
00557     K22.ResetTop();
00558     C11.ResetTop(); // reset top (position to insert new values) => clear triplet
00559     C12.ResetTop();
00560     C21.ResetTop();
00561     C22.ResetTop();
00562     M11.ResetTop(); // reset top (position to insert new values) => clear triplet
00563     M12.ResetTop();
00564     M21.ResetTop();
00565     M22.ResetTop();
00566     A11.ResetTop(); // reset top (position to insert new values) => clear triplet
00567     for (size_t k=0; k<Dom.ActEles.Size(); ++k)
00568     {
00569         // matrices
00570         Mat_t M, C, K;
00571         if      (DampTy==HMCoup_t) Dom.ActEles[k]->CalcKCM (K, C, M);
00572         else if (DampTy==Rayleigh_t)
00573         {
00574             Dom.ActEles[k]->CalcK (K);
00575             Dom.ActEles[k]->CalcM (M);
00576             C = DampAm*M + DampAk*K;
00577         }
00578         // set K, C, M, and A matrices
00579         Array<size_t> loc;
00580         Dom.ActEles[k]->GetLoc (loc);
00581         for (size_t i=0; i<loc.Size(); ++i)
00582         {
00583             for (size_t j=0; j<loc.Size(); ++j)
00584             {
00585                      if (!pU[loc[i]] && !pU[loc[j]]) { A11.PushEntry (loc[i], loc[j], C1*M(i,j) + C2*C(i,j) + C3*K(i,j));
00586                                                        K11.PushEntry (loc[i], loc[j], K(i,j));  C11.PushEntry (loc[i], loc[j], C(i,j));  M11.PushEntry (loc[i], loc[j], M(i,j)); }
00587                 else if (!pU[loc[i]] &&  pU[loc[j]]) { K12.PushEntry (loc[i], loc[j], K(i,j));  C12.PushEntry (loc[i], loc[j], C(i,j));  M12.PushEntry (loc[i], loc[j], M(i,j)); }
00588                 else if ( pU[loc[i]] && !pU[loc[j]]) { K21.PushEntry (loc[i], loc[j], K(i,j));  C21.PushEntry (loc[i], loc[j], C(i,j));  M21.PushEntry (loc[i], loc[j], M(i,j)); }
00589                 else if ( pU[loc[i]] &&  pU[loc[j]]) { K22.PushEntry (loc[i], loc[j], K(i,j));  C22.PushEntry (loc[i], loc[j], C(i,j));  M22.PushEntry (loc[i], loc[j], M(i,j)); }
00590             }
00591         }
00592     }
00593 
00594     // augment A matrix and set Lagrange multipliers (if any)
00595     _aug_and_set_A();
00596 }
00597 
00598 inline void STDSolver::TgIncs (double dT, Vec_t & dU, Vec_t & dF)
00599 {
00600     // assemble global K matrix
00601     AssembleKA ();
00602 
00603     // set prescribed dF
00604     set_to_zero (dF);
00605     set_to_zero (W);
00606     for (size_t i=0; i<Dom.NodsWithPF.Size(); ++i)
00607     {
00608         Node * const nod = Dom.NodsWithPF[i];
00609         for (size_t j=0; j<nod->NPF(); ++j)
00610         {
00611             int eq = nod->EqPF(j);
00612             if (!pU[eq]) // set dF for unknown variables only
00613             {
00614                 dF(eq) = dT*nod->PF(j, /*time*/0);
00615                 W (eq) = dF(eq); // set W1 equal to dF1
00616             }
00617         }
00618     }
00619 
00620     // set prescribed dU
00621     set_to_zero (dU);
00622     for (size_t i=0; i<Dom.NodsWithPU.Size(); ++i)
00623     {
00624         Node * const nod = Dom.NodsWithPU[i];
00625         for (size_t j=0; j<nod->NPU(); ++j)
00626         {
00627             int eq = nod->EqPU(j);
00628             if (FEM::Domain::PARA)
00629             {
00630 #ifdef HAS_MPI
00631                 if (nod->Vert.PartIDs.TheMin()==MPI::COMM_WORLD.Get_rank())
00632                     W(eq) = dT*nod->PU(j, /*time*/0); // set W2 equal to dU2
00633 #endif
00634             }
00635             else W(eq) = dT*nod->PU(j, /*time*/0);
00636             dU(eq) = dT*nod->PU(j, /*time*/0);
00637         }
00638     }
00639 
00640     // correct W
00641     Sparse::SubMult (K12, dU, W); // W1 -= K12*dU2
00642 
00643     // calc dU and dF
00644     if (FEM::Domain::PARA) MUMPS  ::Solve (A11, W, dU); // dU = inv(A11)*W
00645     else                   UMFPACK::Solve (A11, W, dU); // dU = inv(A11)*W
00646 
00647     // calc dF2
00648     Sparse::AddMult (K21, dU, dF); // dF2 += K21*dU1
00649     Sparse::AddMult (K22, dU, dF); // dF2 += K22*dU2
00650 
00651 #ifdef HAS_MPI
00652     if (FEM::Domain::PARA)
00653     {
00654         // join dF
00655         MPI::COMM_WORLD.Allreduce (dF.data, TmpVec.data, NEq, MPI::DOUBLE, MPI::SUM);
00656         dF = TmpVec;
00657     }
00658 #endif
00659 }
00660 
00661 inline void STDSolver::UpdateNodes (bool Transient)
00662 {
00663     if (Transient)
00664     {
00665         for (size_t i=0; i<Dom.ActNods.Size(); ++i) Dom.ActNods[i]->SetUVF (U,V,F);
00666     }
00667     else
00668     {
00669         for (size_t i=0; i<Dom.ActNods.Size(); ++i) Dom.ActNods[i]->SetUF (U,F);
00670     }
00671 }
00672 
00673 inline void STDSolver::UpdateElements (Vec_t const & dU, bool CalcFint)
00674 {
00675     if (CalcFint)
00676     {
00677         if (FEM::Domain::PARA)
00678         {
00679 #ifdef HAS_MPI
00680             Vec_t dFint(NEq), dFint_tmp(NEq);
00681             set_to_zero (dFint);
00682             for (size_t i=0; i<Dom.ActEles.Size(); ++i) Dom.ActEles[i]->UpdateState (dU, &dFint);
00683             MPI::COMM_WORLD.Allreduce (dFint.data, dFint_tmp.data, NEq, MPI::DOUBLE, MPI::SUM);
00684             F_int += dFint_tmp;
00685 #endif
00686         }
00687         else
00688         {
00689             for (size_t i=0; i<Dom.ActEles.Size(); ++i) Dom.ActEles[i]->UpdateState (dU, &F_int);
00690         }
00691     }
00692     else
00693     {
00694         for (size_t i=0; i<Dom.ActEles.Size(); ++i) Dom.ActEles[i]->UpdateState (dU);
00695     }
00696 }
00697 
00698 inline void STDSolver::Initialize (bool Transient)
00699 {
00700     // info
00701     Util::Stopwatch stopwatch(/*activated*/WithInfo);
00702     if (WithInfo) printf("\n%s--- STDSolver --- initializing --------------------------------------------------------%s\n",TERM_CLR1,TERM_RST);
00703 
00704     if (FEM::Domain::PARA)
00705     {
00706 #ifdef HAS_MPI
00707         int my_id  = MPI::COMM_WORLD.Get_rank();
00708         int nprocs = MPI::COMM_WORLD.Get_size();
00709 
00710         // compute equation numbers corresponding to local DOFs of elements
00711         NEq = 0;
00712         for (size_t i=0; i<Dom.ActEles.Size(); ++i) Dom.ActEles[i]->IncNLocDOF (NEq);
00713 
00714         // compute equation numbers
00715         for (size_t i=0; i<Dom.ActNods.Size(); ++i)
00716         {
00717             for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00718             {
00719                 // only the domain with smallest ID will set EQ number
00720                 int min_part_id = Dom.ActNods[i]->Vert.PartIDs.TheMin();
00721                 if (min_part_id==my_id) NEq++;
00722             }
00723         }
00724 
00725         // communicate the number of DOFs numbered
00726         Array<int> send_alloc_dofs(nprocs); // number of dofs just allocated in this processor
00727         Array<int> recv_alloc_dofs(nprocs); // number of dofs just allocated in this processor
00728         send_alloc_dofs.SetValues (0);
00729         send_alloc_dofs[my_id] = NEq;
00730         MPI::COMM_WORLD.Scan (send_alloc_dofs.GetPtr(), recv_alloc_dofs.GetPtr(), nprocs, MPI::INT, MPI::SUM);
00731 
00732         // correct equation numbers
00733         NEq = 0;
00734         if (my_id>0)
00735         {
00736             for (int i=0; i<my_id; ++i) NEq += recv_alloc_dofs[i];
00737         }
00738 
00739         // assign equation numbers corresponding to local DOFs of elements
00740         for (size_t i=0; i<Dom.ActEles.Size(); ++i) Dom.ActEles[i]->IncNLocDOF (NEq);
00741 
00742         // assign equation numbers
00743         for (size_t i=0; i<Dom.ActNods.Size(); ++i)
00744         {
00745             for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00746             {
00747                 int min_part_id = Dom.ActNods[i]->Vert.PartIDs.TheMin();
00748                 if (min_part_id==my_id) // only the domain with smallest ID will set EQ number
00749                 {
00750                     Dom.ActNods[i]->Eq(j) = NEq;
00751                     NEq++;
00752                 }
00753             }
00754         }
00755 
00756         // post messages
00757         const int TAG_SENT_EQ = 1000;
00758         for (int i=my_id+1; i<nprocs; ++i)
00759         {
00760             Array<int> inter_eq; // equation of interface DOFs
00761             for (size_t j=0; j<Dom.InterNodes.Size(); ++j)
00762             {
00763                 int  min_part_id       =  Dom.InterNodes[j]->Vert.PartIDs.TheMin(); // the smallest proc is the one supposed to send always
00764                 bool do_send_to_proc_i = (Dom.InterNodes[j]->Vert.PartIDs.Find(i)>=0); // found processor on the interface and has higher id than me
00765                 if (my_id==min_part_id && do_send_to_proc_i)
00766                 {
00767                     for (size_t k=0; k<Dom.InterNodes[j]->NDOF(); ++k)
00768                         inter_eq.Push (Dom.InterNodes[j]->Eq(k));
00769                 }
00770             }
00771             MPI::Request req_send = MPI::COMM_WORLD.Isend (inter_eq.GetPtr(), inter_eq.Size(), MPI::INT, i, TAG_SENT_EQ);
00772             req_send.Wait ();
00773         }
00774 
00775         // receive messages
00776         MPI::Status status;
00777 #ifdef PARALLEL_DEBUG
00778         Array<int> assigned_equations;
00779 #endif
00780         for (int i=0; i<my_id; ++i)
00781         {
00782             MPI::COMM_WORLD.Probe (MPI::ANY_SOURCE, TAG_SENT_EQ, status);
00783             int source = status.Get_source();
00784             int count  = status.Get_count(MPI::INT);
00785             Array<int> inter_eq(count); // equation of interface DOFs
00786             MPI::COMM_WORLD.Recv (inter_eq.GetPtr(), count, MPI::INT, source, TAG_SENT_EQ);
00787 
00788             int m = 0;
00789             for (size_t j=0; j<Dom.InterNodes.Size(); ++j)
00790             {
00791                 int min_part_id = Dom.InterNodes[j]->Vert.PartIDs.TheMin(); // the smallest proc is the one supposed to send always
00792                 if (source==min_part_id)
00793                 {
00794                     for (size_t k=0; k<Dom.InterNodes[j]->NDOF(); ++k)
00795                     {
00796 #ifdef PARALLEL_DEBUG
00797                         if (assigned_equations.Find(inter_eq[m])>=0) throw new Fatal("problem during assignment: Node # %d, iDOF=%zd, eq=%d. Proc # %d got message from proc # %d",Dom.InterNodes[j]->Vert.ID,k,inter_eq[m],my_id,source);
00798                         assigned_equations.Push(inter_eq[m]);
00799 #endif
00800                         Dom.InterNodes[j]->Eq(k) = inter_eq[m];
00801                         m++;
00802                     }
00803                 }
00804             }
00805         }
00806 
00807         // set NEq in all procs  
00808         if (my_id==nprocs-1) // I'm the last processor and the only one who knows the total num equations
00809         {
00810             NEq = 0;
00811             for (int i=0; i<nprocs; ++i) NEq += recv_alloc_dofs[i];
00812         }
00813         MPI::COMM_WORLD.Bcast (&NEq, 1, MPI::INT, /*from*/nprocs-1); // last processor will broadcast to everyone else
00814 #else
00815         throw new Fatal("STDSolver::Initialize: Parallel code is not available (not compiled)");
00816 #endif
00817     }
00818     else
00819     {
00820         // assign equation numbers corresponding to local DOFs of elements
00821         NEq = 0;
00822         for (size_t i=0; i<Dom.ActEles.Size(); ++i) Dom.ActEles[i]->IncNLocDOF (NEq);
00823 
00824         // assign equation numbers
00825         for (size_t i=0; i<Dom.ActNods.Size(); ++i)
00826         {
00827             for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00828             {
00829                 Dom.ActNods[i]->Eq(j) = NEq;
00830                 NEq++;
00831             }
00832         }
00833     }
00834 
00835     // prescribed equations and prescribed U
00836     pEQ    .Resize    (0);
00837     pU     .Resize    (NEq);
00838     pU     .SetValues (false);
00839     pEQproc.Resize    (0);
00840     for (size_t i=0; i<Dom.NodsWithPU.Size(); ++i)
00841     {
00842         Node const * nod = Dom.NodsWithPU[i];
00843         for (size_t j=0; j<nod->NPU(); ++j)
00844         {
00845             int eq = nod->EqPU(j);
00846             pU[eq] = true;
00847             pEQ.Push (eq);
00848 #ifdef HAS_MPI
00849             if (FEM::Domain::PARA) pEQproc.Push (nod->Vert.PartIDs.TheMin());
00850 #endif
00851         }
00852     }
00853 
00854     // number of Lagrange multipliers
00855     size_t nlag_pins = Dom.NodsPins.Size()*Dom.NDim; // number of Lag mult due to pins
00856     size_t nlag_insu = Dom.NodsIncSup.Size();        // number of Lag mult due to inclined supports
00857     NLag = nlag_pins + nlag_insu;                    // total number of Lagrange multipliers
00858     NEq += NLag;
00859 
00860     // number of extra non-zero values due to Lagrange multipliers
00861     size_t nzlag = nlag_pins*2*Dom.NDim + nlag_insu*2*Dom.NDim;
00862 
00863     // find total number of non-zero entries, including duplicates
00864     NIv = 0; // total number of internal variables of elements
00865     size_t K11_size = 0;
00866     size_t K12_size = 0;
00867     size_t K21_size = 0;
00868     size_t K22_size = 0;
00869     for (size_t k=0; k<Dom.ActEles.Size(); ++k)
00870     {
00871         Array<size_t> loc; // location array
00872         Dom.ActEles[k]->GetLoc (loc);
00873         for (size_t i=0; i<loc.Size(); ++i)
00874         for (size_t j=0; j<loc.Size(); ++j)
00875         {
00876                  if (!pU[loc[i]] && !pU[loc[j]]) K11_size++;
00877             else if (!pU[loc[i]] &&  pU[loc[j]]) K12_size++;
00878             else if ( pU[loc[i]] && !pU[loc[j]]) K21_size++;
00879             else if ( pU[loc[i]] &&  pU[loc[j]]) K22_size++;
00880         }
00881         NIv += Dom.ActEles[k]->NIVs();
00882     }
00883 
00884     // allocate triplets
00885     A11.AllocSpace (NEq,NEq,K11_size+pEQ.Size()+nzlag); // augmented
00886     K12.AllocSpace (NEq,NEq,K12_size);
00887     K21.AllocSpace (NEq,NEq,K21_size);
00888     K22.AllocSpace (NEq,NEq,K22_size);
00889     if (Transient)
00890     {
00891         K11.AllocSpace (NEq,NEq,K11_size);
00892         M11.AllocSpace (NEq,NEq,K11_size);
00893         M12.AllocSpace (NEq,NEq,K12_size);
00894         M21.AllocSpace (NEq,NEq,K21_size);
00895         M22.AllocSpace (NEq,NEq,K22_size);
00896         if (DampTy!=None_t)
00897         {
00898             C11.AllocSpace (NEq,NEq,K11_size);
00899             C12.AllocSpace (NEq,NEq,K12_size);
00900             C21.AllocSpace (NEq,NEq,K21_size);
00901             C22.AllocSpace (NEq,NEq,K22_size);
00902         }
00903     }
00904 
00905     // initialize variables
00906     R     .change_dim (NEq);  set_to_zero (R);
00907     F     .change_dim (NEq);  set_to_zero (F);
00908     F_int .change_dim (NEq);  set_to_zero (F_int);
00909     F0    .change_dim (NEq);  set_to_zero (F0);
00910     W     .change_dim (NEq);  set_to_zero (W);
00911     U     .change_dim (NEq);  set_to_zero (U);
00912     dU    .change_dim (NEq);  set_to_zero (dU);
00913     dF    .change_dim (NEq);  set_to_zero (dF);
00914     TmpVec.change_dim (NEq);  set_to_zero (TmpVec);
00915     if (Transient)
00916     {
00917         V .change_dim (NEq);  set_to_zero (V);
00918         A .change_dim (NEq);  set_to_zero (A);
00919         Us.change_dim (NEq);  set_to_zero (Us);
00920         Vs.change_dim (NEq);  set_to_zero (Vs);
00921     }
00922 
00923     // set variables
00924     for (size_t i=0; i<Dom.ActNods.Size(); ++i) Dom.ActNods[i]->GetUF (U,F);
00925     F_int = F;
00926     F0    = F;
00927 
00928     // calc residual
00929     _cal_resid ();
00930 
00931     // info
00932     if (WithInfo)
00933     {
00934         printf("%s  Num of DOFs (NEq)  = %zd%s\n", TERM_CLR2, NEq, TERM_RST);
00935         printf("%s  Num of non-zeros   = %zd%s\n", TERM_CLR2, K11_size+pEQ.Size()+nzlag, TERM_RST);
00936     }
00937 }
00938 
00939 inline void STDSolver::SetIncsW (size_t NInc, bool NonLinWei)
00940 {
00941     IncsW.Resize (NInc);
00942     if (NonLinWei)
00943     {
00944         double delx = 1.0/NInc;
00945         for (size_t i=0; i<NInc; ++i)
00946         {
00947             double xi = 1.0-delx*i;
00948             double xj = 1.0-delx*(i+1);
00949             double yi = pow(xi,3.0);
00950             double yj = pow(xj,3.0);
00951             IncsW[i] = yi-yj;
00952         }
00953     }
00954     else
00955     {
00956         for (size_t i=0; i<NInc; ++i) IncsW[i] = 1.0/NInc;
00957     }
00958 }
00959 
00960 inline bool STDSolver::ResidOK () const
00961 {
00962     if (MaxNormF<1.0e-8) // particular case when MaxNormF is very small
00963     {
00964         return (NormR<TolR);
00965     }
00966     else return (NormR<TolR*MaxNormF);
00967 }
00968 
00969 inline void STDSolver::_aug_and_set_A ()
00970 {
00971     // augment A11
00972     if (FEM::Domain::PARA)
00973     {
00974 #ifdef HAS_MPI
00975         for (size_t i=0; i<pEQ.Size(); ++i)
00976         {
00977             if (pEQproc[i]==MPI::COMM_WORLD.Get_rank()) A11.PushEntry (pEQ[i],pEQ[i], 1.0);
00978         }
00979 #endif
00980     }
00981     else
00982     {
00983         for (size_t i=0; i<pEQ.Size(); ++i) A11.PushEntry (pEQ[i],pEQ[i], 1.0);
00984     }
00985 
00986     // set equations corresponding to Lagrange multipliers
00987     int eqlag = NEq - NLag;
00988 
00989     // pins and inclined supports
00990     for (size_t i=0; i<Dom.NodsPins  .Size(); ++i) Dom.NodsPins  [i]->SetLagPin    (eqlag, A11);
00991     for (size_t i=0; i<Dom.NodsIncSup.Size(); ++i) Dom.NodsIncSup[i]->SetLagIncSup (eqlag, A11);
00992 }
00993 
00994 inline void STDSolver::_wrn_resid ()
00995 {
00996     for (size_t eq=0; eq<NEq; ++eq)
00997     {
00998         if (fabs(R(eq))>WrnTol)
00999         {
01000             for (size_t i=0; i<Dom.ActNods.Size();     ++i)
01001             for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
01002                 if (Dom.ActNods[i]->Eq(j)==static_cast<int>(eq))
01003                     printf("%sWarning: Problem with residual: Vert # %4zd, eq=%6zd, F=%15.6e, F_int=%15.6e, R=%15.6e\n%s", TERM_RED, Dom.ActNods[i]->Vert.ID, eq, F(eq), F_int(eq), R(eq),TERM_RST);
01004                     //throw new Fatal("%sWarning: Problem with residual: Vert # %4ld, eq=%6zd, F=%15.6e, F_int=%15.6e, R=%15.6e\n%s", TERM_RED, Dom.ActNods[i]->Vert.ID, eq, F(eq), F_int(eq), R(eq),TERM_RST);
01005         }
01006     }
01007 }
01008 
01009 inline void STDSolver::_cal_resid ()
01010 {
01011     // calculate residual
01012     R = F - F_int;
01013 
01014     //printf("\n######################################   Before   ####################################\n");
01015 #ifdef DO_DEBUG
01016     _wrn_resid ();
01017 #endif
01018     
01019     // number of the first equation corresponding to Lagrange multipliers
01020     int eqlag = NEq - NLag;
01021 
01022     // clear forces due to pins and inclined supports
01023     for (size_t i=0; i<Dom.NodsPins  .Size(); ++i) Dom.NodsPins  [i]->ClrRPin    (eqlag, R);
01024     for (size_t i=0; i<Dom.NodsIncSup.Size(); ++i) Dom.NodsIncSup[i]->ClrRIncSup (eqlag, R);
01025 
01026     // clear forces due to supports
01027     //for (size_t i=0; i<pEQ.Size(); ++i) R(pEQ[i]) = 0.0;
01028 
01029     //printf("\n######################################   After   #####################################\n");
01030     if (WarnRes) _wrn_resid ();
01031 
01032     NormR    = Norm(R);
01033     MaxNormF = Util::Max (Norm(F), Norm(F_int));
01034 }
01035 
01036 inline void STDSolver::_cor_resid (Vec_t & dU, Vec_t & dF)
01037 {
01038     if (!CorR) return;
01039 
01040     // iterations
01041     size_t it = 0;
01042     while (!ResidOK() && it<MaxIt)
01043     {
01044         // debug
01045         if (DbgFun!=NULL) (*DbgFun) (this, DbgDat);
01046 
01047         // assemble global K matrix
01048         if (!ModNR) AssembleKA ();
01049 
01050         if (FEM::Domain::PARA)
01051         {
01052 #ifdef HAS_MPI
01053             // set workspace: R
01054             set_to_zero (dF);
01055             for (size_t i=0; i<pEQ.Size(); ++i)
01056             {
01057                 dF(pEQ[i]) = -R(pEQ[i]); // dF2 = -R2
01058             }
01059 
01060             if (FEM::Domain::PARA && MPI::COMM_WORLD.Get_rank()>0) R = 1.0;
01061 
01062             // set workspace: R
01063             for (size_t i=0; i<pEQ.Size(); ++i)
01064             {
01065                 R (pEQ[i]) = 0.0;        // R2  = 0
01066             }
01067 
01068             for (size_t i=0; i<Dom.InterNodes.Size(); ++i)
01069             {
01070                 for (size_t j=0; j<Dom.InterNodes[i]->NDOF(); ++j)
01071                 {
01072                     long   eq   = Dom.InterNodes[i]->Eq(j);
01073                     size_t nint = Dom.InterNodes[i]->Vert.PartIDs.Size();
01074                     dF(eq) /= static_cast<double>(nint);
01075                 }
01076             }
01077 
01078             // solve
01079             MUMPS::Solve (A11, R,  dU, /*Prod*/true); // dU1 = inv(A11)*R1
01080 
01081             // calc dF
01082             Sparse::AddMult (K21, dU, dF); // dF2 += K21*dU1  =>  dF2 = K21*dU1 - R2
01083 
01084             // join dF
01085             MPI::COMM_WORLD.Allreduce (dF.data, TmpVec.data, NEq, MPI::DOUBLE, MPI::SUM);
01086             dF = TmpVec;
01087 #endif
01088         }
01089         else
01090         {
01091             // calc corrector dU
01092             set_to_zero (dF);
01093             for (size_t i=0; i<pEQ.Size(); ++i)
01094             {
01095                 dF(pEQ[i]) = -R(pEQ[i]); // dF2 = -R2
01096                 R (pEQ[i]) = 0.0;        // R2  = 0
01097             }
01098 
01099             // solve
01100             UMFPACK::Solve (A11, R,  dU); // dU1 = inv(A11)*R1
01101 
01102             // calc dF
01103             Sparse::AddMult (K21, dU, dF); // dF2 += K21*dU1  =>  dF2 = K21*dU1 - R2
01104         }
01105 
01106         //std::cout << "Norm(dU) = " << Util::_8s << Norm(dU)    << std::endl;
01107         //std::cout << "Norm(R)  = " << Util::_8s << Norm(R)     << std::endl;
01108         //std::cout << "Norm(F)  = " << Util::_8s << Norm(F)     << std::endl;
01109         //std::cout << "Norm(Fi) = " << Util::_8s << Norm(F_int) << std::endl;
01110 
01111         // update
01112         UpdateElements (dU, /*CalcFint*/true);
01113         U += dU;
01114         F += dF;
01115 
01116         // residual
01117         _cal_resid ();
01118 
01119         // next iteration
01120         it++;
01121     }
01122     if (it>=MaxIt) throw new Fatal("STDSolver::_cor_resid: Residual correction did not converge after %d iterations.\n\t(%e>=%e)  (NormR>=TolR*MaxNormF).\n\tNormR         = %g\n\tMaxNormF      = %g\n\tTolR          = %e\n\tTolR*MaxNormF = %e",it,NormR,TolR*MaxNormF,NormR,MaxNormF,TolR,TolR*MaxNormF);
01123     if (it>It) It = it;
01124 }
01125 
01126 inline void STDSolver::_FE_update (double tf)
01127 {
01128     double dt = (tf-Dom.Time)/nSS;
01129     for (Stp=0; Stp<nSS; ++Stp)
01130     {
01131         // calculate tangent increments
01132         TgIncs (dt, dU, dF);
01133 
01134         // update elements
01135         UpdateElements (dU, /*CalcFint*/true);
01136 
01137         // update U, F, and Time
01138         U        += dU;
01139         F        += dF;
01140         Dom.Time += dt;
01141 
01142         // debug
01143         if (DbgFun!=NULL) (*DbgFun) (this, DbgDat);
01144     }
01145 
01146     // residual
01147     _cal_resid ();
01148 }
01149 
01150 inline void STDSolver::_ME_update (double tf, char const * FNK)
01151 {
01152     // auxiliar vectors
01153     Vec_t dU_fe(NEq), dU_tm(NEq), dU_me(NEq), U_me(NEq), U_dif(NEq);
01154     Vec_t dF_fe(NEq), dF_tm(NEq), dF_me(NEq), F_me(NEq), F_dif(NEq);
01155 
01156     // for each pseudo time T
01157     double T   = 0.0;
01158     double dT  = (dTlast>0.0 ? dTlast : dTini);
01159     double Dt  = tf-Dom.Time;
01160     for (Stp=0; Stp<MaxSS; ++Stp)
01161     {
01162         // exit point
01163         if (T>=1.0) break;
01164 
01165         // backup state of elements
01166         for (size_t i=0; i<Dom.ActEles.Size(); ++i) Dom.ActEles[i]->BackupState ();
01167 
01168         // time increment
01169         double dt = Dt*dT;
01170 
01171         // FE state
01172         TgIncs (dt, dU_fe, dF_fe);
01173         UpdateElements (dU_fe, /*CalcFint*/false);
01174 
01175         // ME state
01176         TgIncs (dt, dU_tm, dF_tm);
01177         dU_me = 0.5*(dU_fe + dU_tm);
01178         dF_me = 0.5*(dF_fe + dF_tm);
01179         U_me  = U + dU_me;
01180         F_me  = F + dF_me;
01181 
01182         // local error
01183         U_dif = 0.5*(dU_tm - dU_fe);
01184         F_dif = 0.5*(dF_tm - dF_fe);
01185         for (size_t i=NEq-NLag; i<NEq; ++i) { U_dif(i)=0.0; F_dif(i)=0.0; } // ignore equations corresponding to Lagrange multipliers
01186         double U_err = Norm(U_dif)/(1.0+Norm(U_me));
01187         double F_err = Norm(F_dif)/(1.0+Norm(F_me));
01188         double error = U_err + F_err;
01189 
01190         // step multiplier
01191         double m = (error>0.0 ? 0.9*sqrt(STOL/error) : mMax);
01192 
01193         // restore state of elements
01194         for (size_t i=0; i<Dom.ActEles.Size(); ++i) Dom.ActEles[i]->RestoreState ();
01195 
01196         // update
01197         if (error<STOL)
01198         {
01199             UpdateElements (dU_me, /*CalcFint*/true);
01200             T        += dT;
01201             U         = U_me;
01202             F         = F_me;
01203             Dom.Time += dt;
01204             //_cal_resid ();
01205             //_cor_resid (dU_me, dF_me);
01206             if (m>mMax) m = mMax;
01207             if (SSOut || (DbgFun!=NULL)) UpdateNodes ();
01208             if (DbgFun!=NULL) (*DbgFun) (this, DbgDat);
01209             if (SSOut) Dom.OutResults (FNK);
01210         }
01211         else if (m<mMin) m = mMin;
01212 
01213         // change next step size
01214         dT = m * dT;
01215 
01216         // check for last increment
01217         if (dT>1.0-T) dT = 1.0-T;
01218         else dTlast = dT;
01219     }
01220     if (Stp>=MaxSS) throw new Fatal("STDSolver:_ME_update: Modified-Euler (global integration) did not converge for %d steps",Stp);
01221 
01222     // correct residual
01223     _cal_resid ();
01224     _cor_resid (dU_me, dF_me);
01225 }
01226 
01227 inline void STDSolver::_NR_update (double tf)
01228 {
01229     It = 0;
01230     double dt = (tf-Dom.Time)/nSS;
01231     for (Stp=0; Stp<nSS; ++Stp)
01232     {
01233         // calculate tangent increments
01234         TgIncs (dt, dU, dF);
01235 
01236         // update elements
01237         UpdateElements (dU, /*CalcFint*/true);
01238 
01239         // update U, F, and Time
01240         U        += dU;
01241         F        += dF;
01242         Dom.Time += dt;
01243 
01244         // residual
01245         _cal_resid ();
01246         _cor_resid (dU, dF);
01247 
01248         // debug
01249         if (DbgFun!=NULL) (*DbgFun) (this, DbgDat);
01250     }
01251 }
01252 
01253 inline void STDSolver::_TH_update (double tf, double Dt)
01254 {
01255     // timestep
01256     double dt = (Dom.Time+Dt>tf ? tf-Dom.Time : Dt);
01257 
01258     while (Dom.Time<tf)
01259     {
01260         // calculate W1 and F1
01261         set_to_zero (W);
01262         double t0 = Dom.Time;
01263         double t1 = Dom.Time + dt;
01264         for (size_t i=0; i<Dom.NodsWithPF.Size(); ++i)
01265         {
01266             Node * const nod = Dom.NodsWithPF[i];
01267             for (size_t j=0; j<nod->NPF(); ++j)
01268             {
01269                 int eq = nod->EqPF(j);
01270                 if (!pU[eq])
01271                 {
01272                     W(eq) = (F0(eq) + nod->PF(j,t1)*TransTh + nod->PF(j,t0)*(1.0-TransTh)) * dt;
01273                 }
01274             }
01275         }
01276 
01277         // set W2 with prescribed DeltaU = U(n+1) - U(n)
01278         for (size_t i=0; i<Dom.NodsWithPU.Size(); ++i)
01279         {
01280             Node * const nod = Dom.NodsWithPU[i];
01281             for (size_t j=0; j<nod->NPU(); ++j)
01282             {
01283                 int eq = nod->EqPU(j);
01284                 W(eq) = nod->PU(j, t1) - U(eq);
01285             }
01286         }
01287 
01288         // solve
01289         double c1 = dt*TransTh;
01290         AssembleKMA     (1.0, c1);         // A11 = M + dt*th*K
01291         Sparse::SubMult (dt, K11, U, W);   // W1 -=    dt*K11*U1(n)
01292         Sparse::SubMult (dt, K12, U, W);   // W1 -=    dt*K12*U2(n)
01293         Sparse::SubMult (    M12, W, W);   // W1 -=       M12*W2
01294         Sparse::SubMult (c1, K12, W, W);   // W1 -= dt*th*K12*W2
01295         UMFPACK::Solve  (A11, W, dU);      // dU  = inv(A11)*W
01296         UpdateElements  (dU, /*CalcFint*/false);
01297 
01298         // update
01299         U += dU;
01300 
01301         // next time step
01302         dt = (Dom.Time+dt>tf ? tf-Dom.Time : dt);
01303         Dom.Time += dt;
01304 
01305         // debug
01306         if (DbgFun!=NULL) (*DbgFun) (this, DbgDat);
01307     }
01308 }
01309 
01310 inline void STDSolver::_GN22_update (double tf, double Dt)
01311 {
01312     // timestep
01313     double dt = Dt;
01314 
01315     // constants
01316     const double c1 = dt*dt*(1.0-DynTh2)/2.0;
01317     const double c2 = dt*(1.0-DynTh1);
01318     const double c3 = 2.0/(dt*dt*DynTh2);
01319     const double c4 = 2.0*DynTh1/(dt*DynTh2);
01320 
01321     while (Dom.Time<tf)
01322     {
01323         // set prescribed F
01324         F = F0;
01325         double tb = Dom.Time+DynTh1*dt;
01326         for (size_t i=0; i<Dom.NodsWithPF.Size(); ++i)
01327         {
01328             Node * const nod = Dom.NodsWithPF[i];
01329             for (size_t j=0; j<nod->NPF(); ++j)
01330             {
01331                 int eq = nod->EqPF(j);
01332                 if (!pU[eq]) F(eq) = F0(eq) + nod->PF(j, tb);
01333             }
01334         }
01335         for (size_t i=0; i<Dom.ActEles.Size(); ++i) Dom.ActEles[i]->AddToF (tb, F);
01336         double normF = Norm(F);
01337 
01338         // predictor
01339         Us = U + dt*V + c1*A;
01340         Vs = V + c2*A;
01341         A  = c3*(U - Us);
01342         V  = Vs + (DynTh1*dt)*A;
01343 
01344         // iterations
01345         for (It=0; It<MaxIt; ++It)
01346         {
01347             // residual
01348             R = F - F_int;
01349             for (size_t i=0; i<pEQ.Size(); ++i)
01350             {
01351                 F(pEQ[i]) = 0.0; // F2 = 0
01352                 R(pEQ[i]) = 0.0; // R2 = 0   clear residual corresponding to supports
01353             }
01354 
01355             // assemble Amat
01356             if (DampTy==None_t) AssembleKMA  (c3,     1.0);  // A = c3*M        + K
01357             else                AssembleKCMA (c3, c4, 1.0);  // A = c3*M + c4*C + K
01358 
01359             // solve for dU
01360             Sparse::SubMult (M11, A, R);  if (DampTy!=None_t)  // R -= M11*A
01361             Sparse::SubMult (C11, V, R);                       // R -= C11*V
01362             UMFPACK::Solve  (A11, R, dU);                      // dU = inv(A11)*R
01363 
01364             // set prescribed dU
01365             for (size_t i=0; i<Dom.NodsWithPU.Size(); ++i)
01366             {
01367                 Node * const nod = Dom.NodsWithPU[i];
01368                 for (size_t j=0; j<nod->NPU(); ++j)
01369                 {
01370                     int eq = nod->EqPU(j);
01371                     dU(eq) = nod->PU(j,tb) - U(eq);
01372                 }
01373             }
01374 
01375 #ifdef DO_DEBUG
01376             double normdU = Norm(dU);
01377             if (Util::IsNan(normdU)) throw new Fatal("STDSolver::_GN22_update: normdU is NaN");
01378 #endif
01379 
01380             // update elements
01381             UpdateElements (dU, /*CalcFint*/true);
01382 
01383 #ifdef DO_DEBUG
01384             double normFint = Norm(F_int);
01385             if (Util::IsNan(normFint)) throw new Fatal("STDSolver::_GN22_update: normFint is NaN");
01386 #endif
01387 
01388             // update state
01389             U += dU;
01390             A  = c3*(U - Us);
01391             V  = Vs + (DynTh1*dt)*A;
01392 
01393             // set prescribed U, V and A
01394             for (size_t i=0; i<Dom.NodsWithPU.Size(); ++i)
01395             {
01396                 Node * const nod = Dom.NodsWithPU[i];
01397                 for (size_t j=0; j<nod->NPU(); ++j)
01398                 {
01399                     int eq = nod->EqPU(j);
01400                     U(eq) = nod->PU(j, tb);
01401                     V(eq) = nod->PV(j, tb);
01402                     A(eq) = nod->PA(j, tb);
01403                 }
01404             }
01405 
01406             // calculate F2
01407             Sparse::AddMult (M21, A, F);                        // F2 += M21*A1
01408             Sparse::AddMult (M22, A, F);  if (DampTy!=None_t) { // F2 += M22*A2
01409             Sparse::AddMult (C21, V, F);                        // F2 += C21*V1
01410             Sparse::AddMult (C22, V, F); }                      // F2 += C22*V2
01411             Sparse::AddMult (K21, U, F);                        // F2 += K21*V1
01412             Sparse::AddMult (K22, U, F);                        // F2 += K22*V2
01413 
01414             // check convergence
01415             NormR    = Norm(R);
01416             MaxNormF = Util::Max (normF, Norm(F_int));
01417 #ifdef DO_DEBUG
01418             if (Util::IsNan(NormR)) throw new Fatal("STDSolver::_GN22_update: NormR is NaN");
01419             printf("NormR = %g\n",NormR);
01420 #endif
01421             if (ResidOK()) break;
01422         }
01423         if (It>=MaxIt) throw new Fatal("STDSolver::_GN22_update: Generalized-Newmark (GN22) did not converge after %d iterations (TolR=%g).\nTolR*NormR=%g, NormR=%g, Time=%g, Dt=%g, dt=%g",It,TolR,TolR*NormR,NormR,Dom.Time,Dt,dt);
01424 
01425         // next time step
01426         dt = (Dom.Time+dt>tf ? tf-Dom.Time : dt);
01427         Dom.Time += dt;
01428 
01429         // debug
01430         if (DbgFun!=NULL) (*DbgFun) (this, DbgDat);
01431     }
01432 }
01433 
01434 inline void STDSolver::_time_print (char const * Comment)
01435 {
01436     if (Comment!=NULL)
01437     {
01438         printf("\n%s--- Stage solution --- %s -----------------------------------------%s\n",TERM_CLR1,Comment,TERM_RST);
01439         printf("%s%10s  %12s  %4s  %4s%s\n",TERM_CLR2,"Time","Norm(R)","NSS","NIT",TERM_RST);
01440     }
01441     printf("%10.6f  %s%8e%s  %4zd  %4zd\n",Dom.Time,(ResidOK()?TERM_GREEN:TERM_RED),NormR,TERM_RST,Stp,It);
01442 }
01443 
01444 inline void STDSolver::_VUIV_to_Y (double Y[])
01445 {
01446     for (size_t i=0; i<NEq; ++i)
01447     {
01448         Y[i]     = V(i);
01449         Y[NEq+i] = U(i);
01450     }
01451     if (!CteTg)
01452     {
01453         for (size_t i=0; i<Dom.ActEles.Size();     ++i)
01454         for (size_t j=0; j<Dom.ActEles[i]->NIVs(); ++j)
01455             Y[2*NEq+j] = Dom.ActEles[i]->GetIV (j);
01456     }
01457 }
01458 
01459 inline void STDSolver::_Y_to_VUIV (double const Y[])
01460 {
01461     for (size_t i=0; i<NEq; ++i)
01462     {
01463         V(i) = Y[i];
01464         U(i) = Y[NEq+i];
01465     }
01466     if (!CteTg)
01467     {
01468         for (size_t i=0; i<Dom.ActEles.Size(); ++i)
01469         for (size_t j=0; j<Dom.ActEles[i]->NIVs(); ++j)
01470             Dom.ActEles[i]->SetIV (j, Y[2*NEq+j]);
01471     }
01472 }
01473 
01474 inline int STDSolver::_RK_func (double t, double const Y[], double dYdt[])
01475 {
01476     // get current U and V and set elements with current IVs (needs to be before the assembly)
01477     _Y_to_VUIV (Y);
01478 
01479     // prescribed U, V, and A
01480     set_to_zero (A);
01481     for (size_t i=0; i<Dom.NodsWithPU.Size(); ++i)
01482     {
01483         Node * const nod = Dom.NodsWithPU[i];
01484         for (size_t j=0; j<nod->NPU(); ++j)
01485         {
01486             int eq = nod->EqPU(j);
01487             U(eq) = nod->PU(j, t);
01488             V(eq) = nod->PV(j, t);
01489             A(eq) = nod->PA(j, t);
01490         }
01491     }
01492 
01493     // prescribed F
01494     F = F0;
01495     for (size_t i=0; i<Dom.NodsWithPF.Size(); ++i)
01496     {
01497         Node * const nod = Dom.NodsWithPF[i];
01498         for (size_t j=0; j<nod->NPF(); ++j)
01499         {
01500             int eq = nod->EqPF(j);
01501             if (!pU[eq]) F(eq) = F0(eq) + nod->PF(j, t);
01502         }
01503     }
01504     for (size_t i=0; i<Dom.ActEles.Size(); ++i) Dom.ActEles[i]->AddToF (t, F);
01505 
01506     // assembly
01507     if (DampTy==None_t) AssembleKMA  (1.0, 0.0);      // A11 = M11
01508     else                AssembleKCMA (1.0, 0.0, 0.0); // A11 = M11
01509 
01510     // set A(t) and V(t)
01511     // F = F1 - p1 - c1 - M12*A2
01512     //   = F1 - K11*U1 - K12*U2 - C11*V1 - C12*V2 - M12*A2
01513     Sparse::SubMult (K11, U, F);                               // F -= K11*U1
01514     Sparse::SubMult (K12, U, F);  if (DampTy!=None_t) {        // F -= K12*U2
01515     Sparse::SubMult (C11, V, F);                               // F -= C11*V1
01516     Sparse::SubMult (C12, V, F); }                             // F -= C12*V2
01517     Sparse::SubMult (M12, A, F);                               // F -= M12*A2
01518     for (size_t i=0; i<pEQ.Size(); ++i) F(pEQ[i]) = A(pEQ[i]); // F2 = A2
01519     UMFPACK::Solve (A11, F, A);                                // A = inv(M11)*F
01520 
01521     // set dYdt
01522     for (size_t i=0; i<NEq; ++i)
01523     {
01524         dYdt[i]     = A(i); // dVdt
01525         dYdt[NEq+i] = V(i); // dUdt
01526     }
01527     if (!CteTg)
01528     {
01529         for (size_t i=0; i<Dom.ActEles.Size(); ++i)
01530         {
01531             size_t niv = Dom.ActEles[i]->NIVs();
01532             if (niv>0)
01533             {
01534                 Vec_t rate;
01535                 Dom.ActEles[i]->CalcIVRate (t, U, V, rate);
01536                 for (size_t j=0; j<niv; ++j) dYdt[2*NEq+j] = rate(j);
01537             }
01538         }
01539     }
01540 
01541     return GSL_SUCCESS;
01542 }
01543 
01544 inline void STDSolver::DebugPrintMatrices (bool Stop)
01545 {
01546     Sparse::Matrix<double,int> MM11(M11), MM12(M12), MM21(M21), MM22(M22);
01547     Sparse::Matrix<double,int> KK11(K11), KK12(K12), KK21(K21), KK22(K22);
01548     Mat_t mm11, mm12, mm21, mm22, mm;
01549     Mat_t kk11, kk12, kk21, kk22, kk;
01550     MM11.GetDense(mm11); MM12.GetDense(mm12); MM21.GetDense(mm21); MM22.GetDense(mm22);
01551     KK11.GetDense(kk11); KK12.GetDense(kk12); KK21.GetDense(kk21); KK22.GetDense(kk22);
01552     mm = mm11 + mm12 + mm21 + mm22;
01553     kk = kk11 + kk12 + kk21 + kk22;
01554     A11.WriteSMAT("A11");
01555     WriteSMAT    (mm,"M");
01556     WriteSMAT    (kk,"K");
01557     std::cout << std::endl << std::endl;
01558     printf("det(A11) = %g\n", UMFPACK::Det(A11));
01559     printf("det(M)   = %g\n", Det(mm));
01560     printf("det(K)   = %g\n", Det(kk));
01561     if (DampTy!=None_t)
01562     {
01563         Sparse::Matrix<double,int> CC11(C11), CC12(C12), CC21(C21), CC22(C22);
01564         Mat_t cc11, cc12, cc21, cc22, cc;
01565         CC11.GetDense(cc11); CC12.GetDense(cc12); CC21.GetDense(cc21); CC22.GetDense(cc22);
01566         cc = cc11 + cc12 + cc21 + cc22;
01567         printf("det(C)   = %g\n", Det(cc));
01568         WriteSMAT(cc,"C");  printf("Matrix <%sC.smat%s> written\n",TERM_CLR_BLUE_H,TERM_RST);
01569     }
01570     printf("Matrix <%sA11.smat%s> written\n",TERM_CLR_BLUE_H,TERM_RST);
01571     printf("Matrix <%sM.smat%s> written\n",TERM_CLR_BLUE_H,TERM_RST);
01572     printf("Matrix <%sK.smat%s> written\n",TERM_CLR_BLUE_H,TERM_RST);
01573     std::cout << std::endl;
01574     if (Stop) throw new Fatal("STDSolver::DebugPrintMatrices   STOP");
01575 }
01576 
01577 
01579 
01580 
01581 Solver * STDSolverMaker(Domain & Dom, SDPair const & Flags, Solver::pOutFun OutFun, void * OutDat, Solver::pOutFun DbgFun, void * DbgDat)
01582 {
01583     return new STDSolver (Dom, Flags, OutFun, OutDat, DbgFun, DbgDat);
01584 }
01585 
01586 int STDSolverRegister()
01587 {
01588     SolverFactory["STDSolver"] = STDSolverMaker;
01589     return 0;
01590 }
01591 
01592 int __STDSolver_dummy_int  = STDSolverRegister();
01593 
01594 
01595 }; // namespace FEM
01596 
01597 #endif // MECHSYS_FEM_STDSOLVER_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines