MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/fem/solvers/rksolver.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_RKSOLVER_H
00021 #define MECHSYS_FEM_RKSOLVER_H
00022 
00023 // Std Lib
00024 #include <cstring>  // for strcmp
00025 #include <iostream> // for cout
00026 
00027 // Blitz++
00028 #include <blitz/tinyvec-et.h>
00029 
00030 // MPI
00031 #ifdef HAS_MPI
00032   #include <mpi.h>
00033 #endif
00034 
00035 // MechSys
00036 #include <mechsys/fem/node.h>
00037 #include <mechsys/fem/element.h>
00038 #include <mechsys/fem/domain.h>
00039 #include <mechsys/linalg/sparse_triplet.h>
00040 #include <mechsys/linalg/sparse_matrix.h>
00041 #include <mechsys/linalg/umfpack.h>
00042 #include <mechsys/linalg/mumps.h>
00043 #include <mechsys/util/stopwatch.h>
00044 #include <mechsys/numerical/odesolver.h>
00045 
00046 namespace FEM
00047 {
00048 
00049 class RKSolver
00050 {
00051 public:
00052     // enum
00053     enum Damping_t { None_t, Rayleigh_t, HMCoup_t }; 
00054 
00055     // Constructor & Destructor
00056      RKSolver (Domain & dom);
00057     ~RKSolver () { if (USys!=NULL) delete USys; }
00058 
00059     // Methods
00060     void SteadySolve (int NInc=1,                         char const * FKey=NULL);
00061     void TransSolve  (double tf, double dt, double dtOut, char const * FKey=NULL);
00062     void DynSolve    (double tf, double dt, double dtOut, char const * FKey=NULL);
00063     void VWPSolve    (double tf, double dt, double dtOut, char const * FKey=NULL);
00064 
00065     void DebugPrintMatrices (bool Stop=true); 
00066 
00067     // Data (read/write)
00068     bool          WithInfo; 
00069     bool          LinProb;  
00070     Damping_t     DampTy;   
00071     double        DampAm;   
00072     double        DampAk;   
00073     String        Scheme;   
00074     double        STOL;     
00075     bool          DynCteM;  
00076 
00077     // Data (read-only)
00078     Domain      & Dom;      
00079     size_t        NEq;      
00080     size_t        NIv;      
00081     size_t        NNu;      
00082     size_t        NLag;     
00083     size_t        NnzLag;   
00084     Array<int>    pEQ;      
00085     Array<bool>   pU;       
00086 
00087     // Auxiliary data
00088     Array<int>    Eq1_to_V1;
00089     Array<int>    Eq1_to_U1;
00090     Vec_t         A,V,U,F,Fi;
00091 
00092     // Triplets
00093     size_t K11_size, K12_size, K21_size, K22_size; 
00094     Sparse::Triplet<double,int> K11,K12,K21,K22;   
00095     Sparse::Triplet<double,int> C11,C12,C21,C22;   
00096     Sparse::Triplet<double,int> M11,M12,M21,M22;   
00097     UMFPACK::Sys              * USys;              
00098 
00099     // Internal methods
00100     int  SteadyFunc     (double t, double const Y[], double dYdt[]); 
00101     int  TransFunc      (double t, double const Y[], double dYdt[]); 
00102     int  DynFunc        (double t, double const Y[], double dYdt[]); 
00103     void DynUpFunc      (double t, double Y[]);                      
00104     int  VWPFunc        (double t, double const Y[], double dYdt[]); 
00105     void Initialize     ();                                          
00106     void AssembleK      ();                                          
00107     void AssembleKM     ();                                          
00108     void AssembleMC     ();                                          
00109     void AugMatrix      (Sparse::Triplet<double,int> & A11);         
00110 };
00111 
00112 
00114 
00115 
00116 inline RKSolver::RKSolver (Domain & dom)
00117     : WithInfo (true),
00118       LinProb  (false),
00119       DampTy   (None_t),
00120       DampAm   (0.01),
00121       DampAk   (0.01),
00122       Scheme   ("ME"),
00123       STOL     (1.0e-3),
00124       DynCteM  (true),
00125       Dom      (dom),
00126       USys     (NULL)
00127 {
00128 }
00129 
00130 inline void RKSolver::SteadySolve (int NInc, char const * FKey)
00131 {
00132     // initialize 
00133     Initialize ();
00134 
00135     // allocate triplets and vectors
00136     V  .change_dim (NEq);
00137     U  .change_dim (NEq);
00138     F  .change_dim (NEq);
00139     K11.AllocSpace (NEq,NEq,K11_size+pEQ.Size()+NnzLag); // augmented
00140     K12.AllocSpace (NEq,NEq,K12_size);
00141     K21.AllocSpace (NEq,NEq,K21_size);
00142     K22.AllocSpace (NEq,NEq,K22_size);
00143 
00144     // allocate ode solver
00145     NNu = NEq-pEQ.Size(); // number of nodal unknowns
00146     Numerical::ODESolver<RKSolver> ode(this, &RKSolver::SteadyFunc, NNu, Scheme.CStr(), STOL, 1.0/NInc);
00147 
00148     // set initial values
00149     ode.t    = 0.0; // pseudo-time (0 <= ode.t <= 1)
00150     int rkeq = 0;
00151     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00152     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00153     {
00154         int eq = Dom.ActNods[i]->Eq(j);
00155         if (!Dom.ActNods[i]->pU(j))
00156         {
00157             Eq1_to_U1[eq]        = rkeq++;
00158             ode.Y[Eq1_to_U1[eq]] = Dom.ActNods[i]->U(j); // U1
00159         }
00160         // fill vectors with initial values
00161         U(eq) = Dom.ActNods[i]->U(j);
00162         F(eq) = Dom.ActNods[i]->F(j);
00163     }
00164 
00165     // first output
00166     printf("\n%s--- Stage solution --- Steady ---------------------------------%s\n",TERM_CLR1,TERM_RST);
00167     printf("%s%10s%s\n",TERM_CLR2,"Time",TERM_RST);
00168 
00169     // solve
00170     double Time0 = Dom.Time;
00171     double tout  = 1.0/NInc;
00172     while (ode.t<1.0)
00173     {
00174         // evolve
00175         ode.Evolve (tout);
00176         Dom.Time = Time0 + ode.t;
00177 
00178         // collect results into U,F and update nodes
00179         for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00180         for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00181         {
00182             int eq = Dom.ActNods[i]->Eq(j);
00183             if (!Dom.ActNods[i]->pU(j))
00184             {
00185                 // fill vectors
00186                 U(eq)  = ode.Y[Eq1_to_U1[eq]];                // U1
00187                 F(eq) += ode.t*Dom.ActNods[i]->PFOrZero(j,0); // F1
00188                 // set node
00189                 Dom.ActNods[i]->U(j) = U(eq); // U1
00190                 Dom.ActNods[i]->F(j) = F(eq); // F1
00191             }
00192             else
00193             {
00194                 // fill vectors
00195                 U(eq) += ode.t*Dom.ActNods[i]->PUIdxDOF(j,0); // U2
00196                 F(eq)  = 0.0;                                 // F2
00197                 // set node
00198                 Dom.ActNods[i]->U(j) = U(eq); // U2
00199             }
00200         }
00201 
00202         // calculate F2
00203         AssembleK       ();
00204         Sparse::AddMult (K21, U, F); // F2 += K21*U1
00205         Sparse::AddMult (K22, U, F); // F2 += K22*U2
00206 
00207         // update F2 in nodes
00208         for (size_t i=0; i<Dom.NodsWithPU.Size();     ++i)
00209         for (size_t j=0; j<Dom.NodsWithPU[i]->NDOF(); ++j)
00210         {
00211             if (Dom.NodsWithPU[i]->pU(j))
00212             {
00213                 int eq = Dom.NodsWithPU[i]->Eq(j);
00214                 Dom.NodsWithPU[i]->F(j) = F(eq); // F2
00215             }
00216         }
00217 
00218         // output
00219         if (WithInfo) printf("%10.6f\n",Dom.Time);
00220         Dom.OutResults (FKey);
00221         tout += 1.0/NInc;
00222         if (tout>1.0) tout = 1.0;
00223     }
00224 }
00225 
00226 inline int RKSolver::SteadyFunc (double t, double const Y[], double dYdt[])
00227 {
00228     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00229     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00230     {
00231         int eq = Dom.ActNods[i]->Eq(j);
00232         if (!Dom.ActNods[i]->pU(j))
00233         {
00234             U(eq) = Y[Eq1_to_U1[eq]];              // U1
00235             F(eq) = Dom.ActNods[i]->PFOrZero(j,0); // DF1
00236             V(eq) = 0.0;                           // dU1dT
00237         }
00238         else U(eq) = Dom.ActNods[i]->PUIdxDOF(j,0); // DU2
00239     }
00240 
00241     AssembleK       ();
00242     Sparse::SubMult (K12, U, F);  // DF1 -= K12*DU2
00243     UMFPACK::Solve  (K11, F, V);  // V1   = inv(K11)*DF1 == dU1dT
00244 
00245     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00246     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00247     {
00248         if (!Dom.ActNods[i]->pU(j))
00249         {
00250             int eq = Dom.ActNods[i]->Eq(j);
00251             dYdt[Eq1_to_U1[eq]] = V(eq); // dU1dT
00252         }
00253     }
00254 
00255     return GSL_SUCCESS;
00256 }
00257 
00258 inline void RKSolver::TransSolve (double tf, double dt, double dtOut, char const * FKey)
00259 {
00260     // initialize 
00261     Initialize ();
00262 
00263     // allocate triplets and vectors
00264     V  .change_dim (NEq);
00265     U  .change_dim (NEq);
00266     F  .change_dim (NEq);
00267     K11.AllocSpace (NEq,NEq,K11_size);
00268     K12.AllocSpace (NEq,NEq,K12_size);
00269     K21.AllocSpace (NEq,NEq,K21_size);
00270     K22.AllocSpace (NEq,NEq,K22_size);
00271     M11.AllocSpace (NEq,NEq,K11_size+pEQ.Size()+NnzLag); // augmented
00272     M12.AllocSpace (NEq,NEq,K12_size);
00273     M21.AllocSpace (NEq,NEq,K21_size);
00274     M22.AllocSpace (NEq,NEq,K22_size);
00275 
00276     // allocate ode solver
00277     NNu = NEq-pEQ.Size(); // number of nodal unknowns
00278     Numerical::ODESolver<RKSolver> ode(this, &RKSolver::TransFunc, NNu, Scheme.CStr(), STOL, dt);
00279 
00280     // set initial values
00281     ode.t    = Dom.Time;
00282     int rkeq = 0;
00283     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00284     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00285     {
00286         if (!Dom.ActNods[i]->pU(j))
00287         {
00288             int eq = Dom.ActNods[i]->Eq(j);
00289             Eq1_to_U1[eq]        = rkeq++;
00290             ode.Y[Eq1_to_U1[eq]] = Dom.ActNods[i]->U(j); // U1
00291         }
00292     }
00293 
00294     // first output
00295     printf("\n%s--- Stage solution --- Transient ------------------------------%s\n",TERM_CLR1,TERM_RST);
00296     printf("%s%10s%s\n",TERM_CLR2,"Time",TERM_RST);
00297 
00298     // solve
00299     double tout = Dom.Time + dtOut;
00300     while (ode.t<tf)
00301     {
00302         // evolve
00303         ode.Evolve (tout);
00304         Dom.Time = ode.t;
00305 
00306         // collect results into V,U,F and update nodes
00307         for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00308         for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00309         {
00310             int eq = Dom.ActNods[i]->Eq(j);
00311             if (!Dom.ActNods[i]->pU(j))
00312             {
00313                 // fill vectors
00314                 U(eq) = ode.Y[Eq1_to_U1[eq]];              // U1
00315                 F(eq) = Dom.ActNods[i]->PFOrZero(j,ode.t); // F1
00316                 // set node
00317                 Dom.ActNods[i]->U(j) = U(eq); // U1
00318                 Dom.ActNods[i]->F(j) = F(eq); // F1
00319             }
00320             else
00321             {
00322                 // fill vectors
00323                 V(eq) = Dom.ActNods[i]->PVIdxDOF(j,ode.t); // V2
00324                 U(eq) = Dom.ActNods[i]->PUIdxDOF(j,ode.t); // U2
00325                 F(eq) = 0.0;                               // F2
00326                 // set node
00327                 Dom.ActNods[i]->U(j) = U(eq); // U2
00328             }
00329         }
00330 
00331         // calculate F2 TODO: should calculate V1 here
00332         AssembleKM      ();
00333         Sparse::AddMult (M21, V, F);  // F2 += M21*V1
00334         Sparse::AddMult (M22, V, F);  // F2 += M22*V2
00335         Sparse::AddMult (K21, U, F);  // F2 += K21*U1
00336         Sparse::AddMult (K22, U, F);  // F2 += K22*U2
00337 
00338         // update F2 in nodes
00339         for (size_t i=0; i<Dom.NodsWithPU.Size();     ++i)
00340         for (size_t j=0; j<Dom.NodsWithPU[i]->NDOF(); ++j)
00341         {
00342             if (Dom.NodsWithPU[i]->pU(j))
00343             {
00344                 int eq = Dom.NodsWithPU[i]->Eq(j);
00345                 Dom.NodsWithPU[i]->F(j) = F(eq); // F2
00346             }
00347         }
00348 
00349         // output
00350         if (WithInfo) printf("%10.6f\n",Dom.Time);
00351         Dom.OutResults (FKey);
00352         tout += dtOut;
00353         if (tout>tf) tout = tf;
00354     }
00355 }
00356 
00357 inline int RKSolver::TransFunc (double t, double const Y[], double dYdt[])
00358 {
00359     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00360     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00361     {
00362         int eq = Dom.ActNods[i]->Eq(j);
00363         if (!Dom.ActNods[i]->pU(j))
00364         {
00365             U(eq) = Y[Eq1_to_U1[eq]];              // U1
00366             F(eq) = Dom.ActNods[i]->PFOrZero(j,t); // F1
00367         }
00368         else
00369         {
00370             V(eq) = Dom.ActNods[i]->PVIdxDOF(j,t); // V2
00371             U(eq) = Dom.ActNods[i]->PUIdxDOF(j,t); // U2
00372         }
00373     }
00374 
00375     AssembleKM      ();
00376     Sparse::SubMult (M12, V, F);  // F1 -= M12*V2
00377     Sparse::SubMult (K11, U, F);  // F1 -= K11*U1
00378     Sparse::SubMult (K12, U, F);  // F1 -= K12*U2
00379     UMFPACK::Solve  (M11, F, V);  // V1  = inv(M11)*F1
00380 
00381     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00382     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00383     {
00384         if (!Dom.ActNods[i]->pU(j))
00385         {
00386             int eq = Dom.ActNods[i]->Eq(j);
00387             dYdt[Eq1_to_U1[eq]] = V(eq); // V1
00388         }
00389     }
00390 
00391     return GSL_SUCCESS;
00392 }
00393 
00394 inline void RKSolver::DynSolve (double tf, double dt, double dtOut, char const * FKey)
00395 {
00396     // initialize 
00397     Initialize ();
00398 
00399     // allocate triplets and vectors
00400     A  .change_dim (NEq);
00401     V  .change_dim (NEq);
00402     U  .change_dim (NEq);
00403     F  .change_dim (NEq);
00404     Fi .change_dim (NEq);
00405     M11.AllocSpace (NEq,NEq,K11_size+pEQ.Size()+NnzLag); // augmented
00406     M12.AllocSpace (NEq,NEq,K12_size);
00407     M21.AllocSpace (NEq,NEq,K21_size);
00408     M22.AllocSpace (NEq,NEq,K22_size);
00409     if (DampTy!=None_t)
00410     {
00411         C11.AllocSpace (NEq,NEq,K11_size);
00412         C12.AllocSpace (NEq,NEq,K12_size);
00413         C21.AllocSpace (NEq,NEq,K21_size);
00414         C22.AllocSpace (NEq,NEq,K22_size);
00415     }
00416 
00417     // allocate ode solver
00418     NNu = 2*(NEq-pEQ.Size()); // number of nodal unknowns
00419     Numerical::ODESolver<RKSolver> ode(this, &RKSolver::DynFunc, NNu+NIv, Scheme.CStr(), STOL, dt);
00420     //ode.UpFun = &RKSolver::DynUpFunc;
00421     //if (Scheme!="ME") throw new Fatal("RKSolver::DynSolve: This method works only with 'ME' at this time. Scheme==%s is not available yet",Scheme.CStr());
00422 
00423     // set initial values
00424     ode.t    = Dom.Time;
00425     int rkeq = 0;
00426     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00427     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00428     {
00429         if (!Dom.ActNods[i]->pU(j))
00430         {
00431             ode.Y[rkeq++] = Dom.ActNods[i]->V(j); // V1
00432             ode.Y[rkeq++] = Dom.ActNods[i]->U(j); // U1
00433         }
00434     }
00435     for (size_t i=0; i<Dom.ActEles.Size();     ++i)
00436     for (size_t j=0; j<Dom.ActEles[i]->NIVs(); ++j)
00437     {
00438         ode.Y[rkeq++] = Dom.ActEles[i]->GetIV(j);
00439     }
00440 
00441     // first output
00442     printf("\n%s--- Stage solution --- Dynamic --------------------------------%s\n",TERM_CLR1,TERM_RST);
00443     printf("%s%10s%s\n",TERM_CLR2,"Time",TERM_RST);
00444     Dom.OutResults (FKey);
00445 
00446     // solve
00447     double tout = Dom.Time + dtOut;
00448     while (Dom.Time<tf)
00449     {
00450         // evolve
00451         ode.Evolve (tout);
00452         Dom.Time = ode.t;
00453 
00454         // update
00455         size_t rkeq = 0;
00456         for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00457         for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00458         {
00459             if (!Dom.ActNods[i]->pU(j))
00460             {
00461                 Dom.ActNods[i]->V(j) = ode.Y[rkeq++];                     // V1
00462                 Dom.ActNods[i]->U(j) = ode.Y[rkeq++];                     // U1
00463                 Dom.ActNods[i]->F(j) = Dom.ActNods[i]->PFOrZero(j,ode.t); // F1
00464             }
00465             else
00466             {
00467                 Dom.ActNods[i]->V(j) = Dom.ActNods[i]->PVIdxDOF(j,ode.t); // V2
00468                 Dom.ActNods[i]->U(j) = Dom.ActNods[i]->PUIdxDOF(j,ode.t); // U2
00469             }
00470         }
00471         for (size_t i=0; i<Dom.ActEles.Size(); ++i)
00472         {
00473             size_t niv = Dom.ActEles[i]->NIVs();
00474             for (size_t j=0; j<niv; ++j) Dom.ActEles[i]->SetIV (j, ode.Y[rkeq++]);
00475         }
00476 
00477         // output
00478         if (WithInfo) printf("%10.6f\n",Dom.Time);
00479         Dom.OutResults (FKey);
00480         tout += dtOut;
00481         if (tout>tf) tout = tf;
00482     }
00483 }
00484 
00485 inline int RKSolver::DynFunc (double t, double const Y[], double dYdt[])
00486 {
00487     int rkeq = 0;
00488     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00489     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00490     {
00491         int eq = Dom.ActNods[i]->Eq(j);
00492         if (!Dom.ActNods[i]->pU(j))
00493         {
00494             V(eq) = Y[rkeq++];                     // V1
00495             U(eq) = Y[rkeq++];                     // U1
00496             F(eq) = Dom.ActNods[i]->PFOrZero(j,t); // F1
00497         }
00498         else
00499         {
00500             A(eq) = Dom.ActNods[i]->PAIdxDOF(j,t); // A2
00501             V(eq) = Dom.ActNods[i]->PVIdxDOF(j,t); // V2
00502             U(eq) = Dom.ActNods[i]->PUIdxDOF(j,t); // U2
00503         }
00504     }
00505     set_to_zero (Fi);
00506     for (size_t i=0; i<Dom.ActEles.Size(); ++i)
00507     {
00508         for (size_t j=0; j<Dom.ActEles[i]->NIVs(); ++j) Dom.ActEles[i]->SetIV (j, Y[rkeq++]);
00509         Dom.ActEles[i]->CorrectIVs ();
00510         Dom.ActEles[i]->SetFint (&Fi);
00511     }
00512 
00513     F -= Fi; // F = F - Fi
00514     //for (size_t i=0; i<pEQ.Size(); ++i) F(pEQ[i]) = A(pEQ[i]); // F2 = A2
00515     if (DynCteM)
00516     {
00517         if (USys==NULL)
00518         {
00519             AssembleMC ();
00520             USys = new UMFPACK::Sys (M11);
00521         }
00522     }
00523     else AssembleMC ();
00524     Sparse::SubMult (M12, A, F); if (DampTy!=None_t) { // F1 -= M12*A2
00525     Sparse::SubMult (C11, V, F);                       // F1 -= C11*V1
00526     Sparse::SubMult (C12, V, F); }                     // F1 -= C12*V2
00527     if (DynCteM) USys->Solve         (F, A);           // A1  = inv(M11)*F1
00528     else         UMFPACK::Solve (M11, F, A);           // A1  = inv(M11)*F1
00529 
00530     rkeq = 0;
00531     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00532     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00533     {
00534         if (!Dom.ActNods[i]->pU(j))
00535         {
00536             int eq = Dom.ActNods[i]->Eq(j);
00537             dYdt[rkeq++] = A(eq); // A1
00538             dYdt[rkeq++] = V(eq); // V1
00539         }
00540     }
00541     if (NIv>0)
00542     {
00543         for (size_t i=0; i<Dom.ActEles.Size(); ++i)
00544         {
00545             Vec_t dIVdt;
00546             Dom.ActEles[i]->CalcIVRate (t, U, V, dIVdt);
00547             for (size_t j=0; j<Dom.ActEles[i]->NIVs(); ++j) dYdt[rkeq++] = dIVdt(j);
00548         }
00549     }
00550 
00551     return GSL_SUCCESS;
00552 }
00553 
00554 inline void RKSolver::DynUpFunc (double t, double Y[])
00555 {
00556     size_t rkeq = 0;
00557     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00558     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00559     {
00560         if (!Dom.ActNods[i]->pU(j))
00561         {
00562             Dom.ActNods[i]->V(j) = Y[rkeq++];                     // V1
00563             Dom.ActNods[i]->U(j) = Y[rkeq++];                     // U1
00564             Dom.ActNods[i]->F(j) = Dom.ActNods[i]->PFOrZero(j,t); // F1
00565         }
00566         else
00567         {
00568             Dom.ActNods[i]->V(j) = Dom.ActNods[i]->PVIdxDOF(j,t); // V2
00569             Dom.ActNods[i]->U(j) = Dom.ActNods[i]->PUIdxDOF(j,t); // U2
00570         }
00571     }
00572     for (size_t i=0; i<Dom.ActEles.Size(); ++i)
00573     {
00574         size_t niv = Dom.ActEles[i]->NIVs();
00575         for (size_t j=0; j<niv; ++j) Dom.ActEles[i]->SetIV (j, Y[rkeq++]);
00576         Dom.ActEles[i]->CorrectIVs ();
00577         rkeq -= niv;
00578         for (size_t j=0; j<niv; ++j) Y[rkeq++] = Dom.ActEles[i]->GetIV (j);
00579     }
00580 }
00581 
00582 inline void RKSolver::VWPSolve (double tf, double dt, double dtOut, char const * FKey)
00583 {
00584     // initialize 
00585     Initialize ();
00586 
00587     // allocate triplets and vectors
00588     A  .change_dim (NEq);
00589     V  .change_dim (NEq);
00590     U  .change_dim (NEq);
00591     F  .change_dim (NEq);
00592     Fi .change_dim (NEq);
00593     M11.AllocSpace (NEq,NEq,K11_size+pEQ.Size()+NnzLag); // augmented
00594     M12.AllocSpace (NEq,NEq,K12_size);
00595     M21.AllocSpace (NEq,NEq,K21_size);
00596     M22.AllocSpace (NEq,NEq,K22_size);
00597     if (DampTy!=None_t)
00598     {
00599         C11.AllocSpace (NEq,NEq,K11_size);
00600         C12.AllocSpace (NEq,NEq,K12_size);
00601         C21.AllocSpace (NEq,NEq,K21_size);
00602         C22.AllocSpace (NEq,NEq,K22_size);
00603     }
00604 
00605     // allocate ode solver
00606     NNu = 2*(NEq-pEQ.Size()); // number of nodal unknowns
00607     Numerical::ODESolver<RKSolver> ode(this, &RKSolver::DynFunc, NNu+NIv, Scheme.CStr(), STOL, dt);
00608     //ode.UpFun = &RKSolver::DynUpFunc;
00609     //if (Scheme!="ME") throw new Fatal("RKSolver::DynSolve: This method works only with 'ME' at this time. Scheme==%s is not available yet",Scheme.CStr());
00610 
00611     // set initial values
00612     ode.t    = Dom.Time;
00613     int rkeq = 0;
00614     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00615     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00616     {
00617         if (!Dom.ActNods[i]->pU(j))
00618         {
00619             ode.Y[rkeq++] = Dom.ActNods[i]->V(j); // V1
00620             ode.Y[rkeq++] = Dom.ActNods[i]->U(j); // U1
00621         }
00622     }
00623     for (size_t i=0; i<Dom.ActEles.Size();     ++i)
00624     for (size_t j=0; j<Dom.ActEles[i]->NIVs(); ++j)
00625     {
00626         ode.Y[rkeq++] = Dom.ActEles[i]->GetIV(j);
00627     }
00628 
00629     // first output
00630     printf("\n%s--- Stage solution --- Dynamic --------------------------------%s\n",TERM_CLR1,TERM_RST);
00631     printf("%s%10s%s\n",TERM_CLR2,"Time",TERM_RST);
00632     Dom.OutResults (FKey);
00633 
00634     // solve
00635     double tout = Dom.Time + dtOut;
00636     while (Dom.Time<tf)
00637     {
00638         // evolve
00639         ode.Evolve (tout);
00640         Dom.Time = ode.t;
00641 
00642         // update
00643         size_t rkeq = 0;
00644         for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00645         for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00646         {
00647             if (!Dom.ActNods[i]->pU(j))
00648             {
00649                 Dom.ActNods[i]->V(j) = ode.Y[rkeq++];                     // V1
00650                 Dom.ActNods[i]->U(j) = ode.Y[rkeq++];                     // U1
00651                 Dom.ActNods[i]->F(j) = Dom.ActNods[i]->PFOrZero(j,ode.t); // F1
00652             }
00653             else
00654             {
00655                 Dom.ActNods[i]->V(j) = Dom.ActNods[i]->PVIdxDOF(j,ode.t); // V2
00656                 Dom.ActNods[i]->U(j) = Dom.ActNods[i]->PUIdxDOF(j,ode.t); // U2
00657             }
00658         }
00659         for (size_t i=0; i<Dom.ActEles.Size(); ++i)
00660         {
00661             size_t niv = Dom.ActEles[i]->NIVs();
00662             for (size_t j=0; j<niv; ++j) Dom.ActEles[i]->SetIV (j, ode.Y[rkeq++]);
00663         }
00664 
00665         // output
00666         if (WithInfo) printf("%10.6f\n",Dom.Time);
00667         Dom.OutResults (FKey);
00668         tout += dtOut;
00669         if (tout>tf) tout = tf;
00670     }
00671 }
00672 
00673 inline int RKSolver::VWPFunc (double t, double const Y[], double dYdt[])
00674 {
00675     int rkeq = 0;
00676     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00677     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00678     {
00679         int eq = Dom.ActNods[i]->Eq(j);
00680         if (!Dom.ActNods[i]->pU(j))
00681         {
00682             V(eq) = Y[rkeq++];                     // V1
00683             U(eq) = Y[rkeq++];                     // U1
00684             F(eq) = Dom.ActNods[i]->PFOrZero(j,t); // F1
00685         }
00686         else
00687         {
00688             A(eq) = Dom.ActNods[i]->PAIdxDOF(j,t); // A2
00689             V(eq) = Dom.ActNods[i]->PVIdxDOF(j,t); // V2
00690             U(eq) = Dom.ActNods[i]->PUIdxDOF(j,t); // U2
00691         }
00692     }
00693     set_to_zero (Fi);
00694     for (size_t i=0; i<Dom.ActEles.Size(); ++i)
00695     {
00696         for (size_t j=0; j<Dom.ActEles[i]->NIVs(); ++j) Dom.ActEles[i]->SetIV (j, Y[rkeq++]);
00697         Dom.ActEles[i]->CorrectIVs ();
00698         Dom.ActEles[i]->SetFint (&Fi);
00699     }
00700 
00701     F -= Fi; // F = F - Fi
00702     //for (size_t i=0; i<pEQ.Size(); ++i) F(pEQ[i]) = A(pEQ[i]); // F2 = A2
00703     if (DynCteM)
00704     {
00705         if (USys==NULL)
00706         {
00707             AssembleMC ();
00708             USys = new UMFPACK::Sys (M11);
00709         }
00710     }
00711     else AssembleMC ();
00712     Sparse::SubMult (M12, A, F); if (DampTy!=None_t) { // F1 -= M12*A2
00713     Sparse::SubMult (C11, V, F);                       // F1 -= C11*V1
00714     Sparse::SubMult (C12, V, F); }                     // F1 -= C12*V2
00715     if (DynCteM) USys->Solve         (F, A);           // A1  = inv(M11)*F1
00716     else         UMFPACK::Solve (M11, F, A);           // A1  = inv(M11)*F1
00717 
00718     rkeq = 0;
00719     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00720     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00721     {
00722         if (!Dom.ActNods[i]->pU(j))
00723         {
00724             int eq = Dom.ActNods[i]->Eq(j);
00725             dYdt[rkeq++] = A(eq); // A1
00726             dYdt[rkeq++] = V(eq); // V1
00727         }
00728     }
00729     if (NIv>0)
00730     {
00731         for (size_t i=0; i<Dom.ActEles.Size(); ++i)
00732         {
00733             Vec_t dIVdt;
00734             Dom.ActEles[i]->CalcIVRate (t, U, V, dIVdt);
00735             for (size_t j=0; j<Dom.ActEles[i]->NIVs(); ++j) dYdt[rkeq++] = dIVdt(j);
00736         }
00737     }
00738 
00739     return GSL_SUCCESS;
00740 }
00741 
00742 inline void RKSolver::Initialize ()
00743 {
00744     // assign equation numbers corresponding to local DOFs of elements
00745     NEq = 0;
00746     //for (size_t i=0; i<Dom.ActEles.Size(); ++i) Dom.ActEles[i]->IncNLocDOF (NEq);
00747 
00748     // assign equation numbers
00749     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00750     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00751     {
00752         Dom.ActNods[i]->Eq(j) = NEq;
00753         NEq++;
00754     }
00755 
00756     // prescribed equations and prescribed U
00757     pEQ.Resize    (0);
00758     pU .Resize    (NEq);
00759     pU .SetValues (false);
00760     for (size_t i=0; i<Dom.NodsWithPU.Size(); ++i)
00761     {
00762         Node const * nod = Dom.NodsWithPU[i];
00763         for (size_t j=0; j<nod->NPU(); ++j)
00764         {
00765             int eq = nod->EqPU(j);
00766             pU[eq] = true;
00767             pEQ.Push (eq);
00768         }
00769     }
00770 
00771     // number of Lagrange multipliers
00772     size_t nlag_pins = Dom.NodsPins.Size()*Dom.NDim; // number of Lag mult due to pins
00773     size_t nlag_insu = Dom.NodsIncSup.Size();        // number of Lag mult due to inclined supports
00774     NLag = nlag_pins + nlag_insu;                    // total number of Lagrange multipliers
00775     NEq += NLag;
00776 
00777     // number of extra non-zero values due to Lagrange multipliers
00778     NnzLag = nlag_pins*2*Dom.NDim + nlag_insu*2*Dom.NDim;
00779 
00780     // find total number of non-zero entries, including duplicates
00781     NIv      = 0; // total number of internal variables of elements
00782     K11_size = 0;
00783     K12_size = 0;
00784     K21_size = 0;
00785     K22_size = 0;
00786     for (size_t k=0; k<Dom.ActEles.Size(); ++k)
00787     {
00788         Array<size_t> loc; // location array
00789         Dom.ActEles[k]->GetLoc (loc);
00790         for (size_t i=0; i<loc.Size(); ++i)
00791         for (size_t j=0; j<loc.Size(); ++j)
00792         {
00793                  if (!pU[loc[i]] && !pU[loc[j]]) K11_size++;
00794             else if (!pU[loc[i]] &&  pU[loc[j]]) K12_size++;
00795             else if ( pU[loc[i]] && !pU[loc[j]]) K21_size++;
00796             else if ( pU[loc[i]] &&  pU[loc[j]]) K22_size++;
00797         }
00798         NIv += Dom.ActEles[k]->NIVs();
00799     }
00800 
00801     // RK maps
00802     Eq1_to_V1.Resize (NEq);   Eq1_to_V1.SetValues (-1);
00803     Eq1_to_U1.Resize (NEq);   Eq1_to_U1.SetValues (-1);
00804 
00805     // info
00806     if (WithInfo)
00807     {
00808         printf("%s  Num of DOFs (NEq)     = %zd%s\n", TERM_CLR2, NEq, TERM_RST);
00809         printf("%s  Num of non-zeros      = %zd%s\n", TERM_CLR2, K11_size+pEQ.Size()+NnzLag, TERM_RST);
00810         printf("%s  Num of Int vals (NIV) = %zd%s\n", TERM_CLR2, NIv, TERM_RST);
00811     }
00812 }
00813 
00814 inline void RKSolver::AssembleK ()
00815 {
00816     if (LinProb && K11.Top()>0) return;
00817     K11.ResetTop();
00818     K12.ResetTop();
00819     K21.ResetTop();
00820     K22.ResetTop();
00821     for (size_t k=0; k<Dom.ActEles.Size(); ++k)
00822     {
00823         Mat_t         K;
00824         Array<size_t> loc;
00825         Dom.ActEles[k]->CalcK  (K);
00826         Dom.ActEles[k]->GetLoc (loc);
00827         for (size_t i=0; i<loc.Size(); ++i)
00828         for (size_t j=0; j<loc.Size(); ++j)
00829         {
00830             if      (!pU[loc[i]] && !pU[loc[j]]) { K11.PushEntry(loc[i], loc[j], K(i,j)); }
00831             else if (!pU[loc[i]] &&  pU[loc[j]]) { K12.PushEntry(loc[i], loc[j], K(i,j)); }
00832             else if ( pU[loc[i]] && !pU[loc[j]]) { K21.PushEntry(loc[i], loc[j], K(i,j)); }
00833             else if ( pU[loc[i]] &&  pU[loc[j]]) { K22.PushEntry(loc[i], loc[j], K(i,j)); }
00834         }
00835     }
00836     AugMatrix (K11);
00837 }
00838 
00839 inline void RKSolver::AssembleKM ()
00840 {
00841     if (LinProb && M11.Top()>0) return;
00842     K11.ResetTop();   M11.ResetTop();
00843     K12.ResetTop();   M12.ResetTop();
00844     K21.ResetTop();   M21.ResetTop();
00845     K22.ResetTop();   M22.ResetTop();
00846     for (size_t k=0; k<Dom.ActEles.Size(); ++k)
00847     {
00848         Mat_t         K, M;
00849         Array<size_t> loc;
00850         Dom.ActEles[k]->CalcK  (K);
00851         Dom.ActEles[k]->CalcM  (M);
00852         Dom.ActEles[k]->GetLoc (loc);
00853         for (size_t i=0; i<loc.Size(); ++i)
00854         for (size_t j=0; j<loc.Size(); ++j)
00855         {
00856             if      (!pU[loc[i]] && !pU[loc[j]]) { K11.PushEntry(loc[i], loc[j], K(i,j));  M11.PushEntry(loc[i], loc[j], M(i,j)); }
00857             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)); }
00858             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)); }
00859             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)); }
00860         }
00861     }
00862     AugMatrix (M11);
00863 }
00864 
00865 inline void RKSolver::AssembleMC ()
00866 {
00867     if (LinProb && M11.Top()>0) return;
00868     M11.ResetTop();
00869     M12.ResetTop();
00870     M21.ResetTop();
00871     M22.ResetTop();
00872     if (DampTy!=None_t)
00873     {
00874         C11.ResetTop();
00875         C12.ResetTop();
00876         C21.ResetTop();
00877         C22.ResetTop();
00878     }
00879     for (size_t k=0; k<Dom.ActEles.Size(); ++k)
00880     {
00881         Mat_t         C, M;
00882         Array<size_t> loc;
00883         Dom.ActEles[k]->CalcM  (M);
00884         Dom.ActEles[k]->GetLoc (loc);
00885         if (DampTy==Rayleigh_t)
00886         {
00887             Mat_t K;
00888             Dom.ActEles[k]->CalcK (K);
00889             C = DampAm*M + DampAk*K;
00890         }
00891         for (size_t i=0; i<loc.Size(); ++i)
00892         for (size_t j=0; j<loc.Size(); ++j)
00893         {
00894             if      (!pU[loc[i]] && !pU[loc[j]]) { M11.PushEntry(loc[i], loc[j], M(i,j));  if (DampTy!=None_t) { C11.PushEntry(loc[i], loc[j], C(i,j)); } }
00895             else if (!pU[loc[i]] &&  pU[loc[j]]) { M12.PushEntry(loc[i], loc[j], M(i,j));  if (DampTy!=None_t) { C12.PushEntry(loc[i], loc[j], C(i,j)); } }
00896             else if ( pU[loc[i]] && !pU[loc[j]]) { M21.PushEntry(loc[i], loc[j], M(i,j));  if (DampTy!=None_t) { C21.PushEntry(loc[i], loc[j], C(i,j)); } }
00897             else if ( pU[loc[i]] &&  pU[loc[j]]) { M22.PushEntry(loc[i], loc[j], M(i,j));  if (DampTy!=None_t) { C22.PushEntry(loc[i], loc[j], C(i,j)); } }
00898         }
00899     }
00900     AugMatrix (M11);
00901 }
00902 
00903 inline void RKSolver::AugMatrix (Sparse::Triplet<double,int> & A11)
00904 {
00905     // augment A11 matrix and set Lagrange multipliers (if any)
00906     for (size_t i=0; i<pEQ.Size(); ++i) A11.PushEntry (pEQ[i],pEQ[i], 1.0);
00907 
00908     // set equations corresponding to Lagrange multipliers
00909     int eqlag = NEq - NLag;
00910 
00911     // pins and inclined supports
00912     for (size_t i=0; i<Dom.NodsPins  .Size(); ++i) Dom.NodsPins  [i]->SetLagPin    (eqlag, A11);
00913     for (size_t i=0; i<Dom.NodsIncSup.Size(); ++i) Dom.NodsIncSup[i]->SetLagIncSup (eqlag, A11);
00914 }
00915 
00916 inline void RKSolver::DebugPrintMatrices (bool Stop)
00917 {
00918     K11.AllocSpace (NEq,NEq,K11_size);
00919     K12.AllocSpace (NEq,NEq,K12_size);
00920     K21.AllocSpace (NEq,NEq,K21_size);
00921     K22.AllocSpace (NEq,NEq,K22_size);
00922     AssembleKM();
00923     Sparse::Matrix<double,int> MM11(M11), MM12(M12), MM21(M21), MM22(M22);
00924     Sparse::Matrix<double,int> KK11(K11), KK12(K12), KK21(K21), KK22(K22);
00925     Mat_t mm11, mm12, mm21, mm22, mm;
00926     Mat_t kk11, kk12, kk21, kk22, kk;
00927     MM11.GetDense(mm11); MM12.GetDense(mm12); MM21.GetDense(mm21); MM22.GetDense(mm22);
00928     KK11.GetDense(kk11); KK12.GetDense(kk12); KK21.GetDense(kk21); KK22.GetDense(kk22);
00929     mm = mm11 + mm12 + mm21 + mm22;
00930     kk = kk11 + kk12 + kk21 + kk22;
00931     WriteSMAT (mm,"M");
00932     WriteSMAT (kk,"K");
00933     std::cout << std::endl << std::endl;
00934     printf("det(M) = %g\n", Det(mm));
00935     printf("det(K) = %g\n", Det(kk));
00936     printf("Matrix <%sM.smat%s> written\n",TERM_CLR_BLUE_H,TERM_RST);
00937     printf("Matrix <%sK.smat%s> written\n",TERM_CLR_BLUE_H,TERM_RST);
00938     std::cout << std::endl;
00939     if (Stop) throw new Fatal("STDSolver::DebugPrintMatrices   STOP");
00940 }
00941 
00942 }; // namespace FEM
00943 
00944 #endif // MECHSYS_FEM_RKSOLVER_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines