![]() |
MechSys
1.0
Computing library for simulations in continuum and discrete mechanics
|
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