![]() |
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_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