00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef MECHSYS_FEM_SOLVER_H
00023 #define MECHSYS_FEM_SOLVER_H
00024
00025 #ifdef HAVE_CONFIG_H
00026 #include "config.h"
00027 #else
00028 #ifndef REAL
00029 #define REAL double
00030 #endif
00031 #endif
00032
00033 #include "fem/solver/intsolverdata.h"
00034 #include "util/string.h"
00035 #include "fem/data.h"
00036 #include "fem/output.h"
00037 #include "fem/node.h"
00038 #include "fem/ele/element.h"
00039 #include "linalg/vector.h"
00040 #include "linalg/matrix.h"
00041 #include "linalg/lawrap.h"
00042
00043 namespace FEM
00044 {
00045
00047
00052 class Solver
00053 {
00054 public:
00055
00056 Solver(FEM::InputData const & ID, FEM::Data & data, FEM::Output & output);
00057
00058 virtual ~Solver() {}
00059
00060 void Solve(int iStage);
00061 protected:
00062
00063 FEM::InputData const & _idat;
00064 FEM::Data & _data;
00065 FEM::Output & _output;
00066 Array<FEM::Node::DOFVarsStruct*> _a_udofs;
00067 Array<FEM::Node::DOFVarsStruct*> _a_pdofs;
00068 LinAlg::Vector<REAL> _DF_ext;
00069 LinAlg::Vector<REAL> _DU_ext;
00070
00071
00072 void _realloc_and_setup_dof_vectors();
00073 void _assemb_natural_stage_inc();
00074 void _assemb_essential_stage_inc();
00075 void _assemb_K(LinAlg::Matrix<REAL> & K);
00076
00077 void _inv_K_times_X(LinAlg::Matrix<REAL> & K ,
00078 bool DoPreserveK ,
00079 LinAlg::Vector<REAL> & X ,
00080 LinAlg::Vector<REAL> & Y );
00081 int _n_tot_dof() const { return _a_udofs.size() + _a_pdofs.size(); }
00082
00083 void _backup_nodes_and_elements_state();
00084 void _update_nodes_and_elements_state(LinAlg::Vector<REAL> const & dU, LinAlg::Vector<REAL> & dF_int);
00085 void _restore_nodes_and_elements_state();
00086
00087 REAL _norm_essential_vector();
00088 REAL _norm_natural_vector();
00089
00090
00091 virtual void _do_solve_for_an_increment(int const increment,
00092 LinAlg::Vector<REAL> const & dF_ext ,
00093 LinAlg::Vector<REAL> const & dU_ext ,
00094 LinAlg::Matrix<REAL> & K ,
00095 LinAlg::Vector<REAL> & dF_int ,
00096 LinAlg::Vector<REAL> & Rinternal,
00097 IntSolverData & ISD ) =0;
00098 private:
00099 LinAlg::Vector<REAL> _U_bkp;
00100 LinAlg::Vector<REAL> _F_bkp;
00101
00102 void _do_scatter(LinAlg::Matrix<REAL> const & K,
00103 LinAlg::Vector<REAL> const & X,
00104 LinAlg::Vector<REAL> const & Y,
00105 LinAlg::Matrix<REAL> & K11,
00106 LinAlg::Matrix<REAL> & K12,
00107 LinAlg::Matrix<REAL> & K21,
00108 LinAlg::Matrix<REAL> & K22,
00109 LinAlg::Vector<REAL> & Y2,
00110 LinAlg::Vector<REAL> & X1);
00111
00112 void _do_gather(LinAlg::Vector<REAL> const & Y1,
00113 LinAlg::Vector<REAL> const & Y2,
00114 LinAlg::Vector<REAL> const & X1,
00115 LinAlg::Vector<REAL> const & X2,
00116 LinAlg::Vector<REAL> & Y ,
00117 LinAlg::Vector<REAL> & X);
00118 };
00119
00120
00122
00123
00124 inline Solver::Solver(FEM::InputData const & ID, FEM::Data & data, FEM::Output & output)
00125 : _idat (ID),
00126 _data (data),
00127 _output (output)
00128 {
00129 }
00130
00131 inline void Solver::Solve(int iStage)
00132 {
00133
00134
00135 _realloc_and_setup_dof_vectors();
00136
00137
00138 _U_bkp.Resize(_n_tot_dof());
00139 _F_bkp.Resize(_n_tot_dof());
00140
00141
00142 _assemb_natural_stage_inc();
00143
00144
00145 _assemb_essential_stage_inc();
00146
00147
00148
00149
00150 int n_tot_dof = _n_tot_dof();
00151
00152
00153 int num_div = _idat.nDIV[iStage];
00154
00155
00156 REAL lam=1.0/num_div;
00157 LinAlg::Scal(lam, _DF_ext);
00158 LinAlg::Scal(lam, _DU_ext);
00159
00160
00161 LinAlg::Matrix<REAL> K(n_tot_dof, n_tot_dof);
00162
00163
00164 LinAlg::Vector<REAL> dF_int (n_tot_dof);
00165 LinAlg::Vector<REAL> Rinternal(n_tot_dof);
00166
00167
00168 if (iStage==0) _output.OutputIncrement(iStage, -1);
00169
00170
00171 for (int increment=0; increment<num_div; ++increment)
00172 {
00173
00174 IntSolverData isd;
00175
00176
00177 _do_solve_for_an_increment(increment, _DF_ext, _DU_ext, K, dF_int, Rinternal, isd);
00178
00179
00180 _output.OutputIncrement(iStage, increment, isd);
00181 }
00182
00183
00184 _output.OutputStage(iStage);
00185
00186 }
00187
00188 inline void Solver::_realloc_and_setup_dof_vectors()
00189 {
00190
00191 int eq_id=0;
00192
00193
00194 _a_udofs.resize(0);
00195 _a_pdofs.resize(0);
00196
00197
00198 for (size_t i=0; i<_data.Nodes.size(); ++i)
00199 {
00200
00201 Array<FEM::Node::DOFVarsStruct> & dofs = _data.Nodes[i].DOFVars();
00202
00203
00204 for (size_t j=0; j<dofs.size(); ++j)
00205 {
00206
00207 if (dofs[j].IsEssenPresc) _a_pdofs.push_back(&dofs[j]);
00208 else _a_udofs.push_back(&dofs[j]);
00209
00210
00211 dofs[j].EqID = eq_id;
00212 eq_id++;
00213 }
00214 }
00215 }
00216
00217 inline void Solver::_assemb_natural_stage_inc()
00218 {
00219
00220 int n_tot_dof = _n_tot_dof();
00221
00222
00223 _DF_ext.Resize(n_tot_dof);
00224
00225
00226 for (size_t iu=0; iu<_a_udofs.size(); ++iu)
00227 _DF_ext(_a_udofs[iu]->EqID) = _a_udofs[iu]->NaturalBry;
00228
00229
00230 for (size_t ip=0; ip<_a_pdofs.size(); ++ip)
00231 _DF_ext(_a_pdofs[ip]->EqID) = _a_pdofs[ip]->NaturalBry;
00232 }
00233
00234 inline void Solver::_assemb_essential_stage_inc()
00235 {
00236
00237 int n_tot_dof = _n_tot_dof();
00238
00239
00240 _DU_ext.Resize(n_tot_dof);
00241
00242
00243 for (size_t iu=0; iu<_a_udofs.size(); ++iu)
00244 _DU_ext(_a_udofs[iu]->EqID) = _a_udofs[iu]->EssentialBry;
00245
00246
00247 for (size_t ip=0; ip<_a_pdofs.size(); ++ip)
00248 _DU_ext(_a_pdofs[ip]->EqID) = _a_pdofs[ip]->EssentialBry;
00249 }
00250
00251 inline void Solver::_assemb_K(LinAlg::Matrix<REAL> & K)
00252 {
00253
00254 K.SetValues(0.0);
00255
00256
00257 for (size_t i_ele=0; i_ele<_data.Elements.size(); ++i_ele)
00258 {
00259
00260 FEM::EquilibElem const * const E = dynamic_cast<FEM::EquilibElem *>(_data.Elements[i_ele]);
00261 if (!E) throw new Fatal(_("FEM::Solver: This solver only works for equilibrium type elements"));
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281 if (E->IsActive())
00282 {
00283
00284 LinAlg::Matrix<REAL> Ke;
00285 Array<size_t> a_map_Ke_to_K_pos;
00286 E->Stiffness(Ke, a_map_Ke_to_K_pos);
00287
00288
00289
00290
00291 for (int i_row_Ke=0; i_row_Ke<Ke.Rows(); ++i_row_Ke)
00292 for (int j_col_Ke=0; j_col_Ke<Ke.Rows(); ++j_col_Ke)
00293 K(a_map_Ke_to_K_pos[i_row_Ke], a_map_Ke_to_K_pos[j_col_Ke]) += Ke(i_row_Ke, j_col_Ke);
00294 }
00295 }
00296 }
00297
00298 inline void Solver::_inv_K_times_X(LinAlg::Matrix<REAL> & K ,
00299 bool DoPreserveK ,
00300 LinAlg::Vector<REAL> & X ,
00301 LinAlg::Vector<REAL> & Y )
00302 {
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 LinAlg::Matrix<REAL> K11,K12;
00322 LinAlg::Matrix<REAL> K21,K22;
00323 LinAlg::Vector<REAL> Y2;
00324 LinAlg::Vector<REAL> X1;
00325
00326
00327 _do_scatter(K,X,Y, K11,K12,K21,K22, Y2, X1);
00328
00329
00330 LinAlg::Vector<REAL> TMP(X1);
00331 LinAlg::Gemv(-1.0,K12,Y2,1.0,TMP);
00332
00333
00334 if (_idat.linSOLVER==InputData::lsLAPACK)
00335 {
00336 #if defined (USE_LAPACK) || defined (USE_GOTOBLAS)
00337 LinAlg::Gesv(K11, TMP);
00338 #else
00339 throw new Fatal(_("Solver::_inv_K_times_X: LAPACK (or GOTOBLAS) is not available (USE_LAPACK=false, or USE_GOTOBLAS=false)"));
00340 #endif
00341 }
00342 else if (_idat.linSOLVER==InputData::lsUMFPACK)
00343 {
00344 throw new Fatal(_("Solver::_inv_K_times_X: UMFPACK is not working yet"));
00345 }
00346 else if (_idat.linSOLVER==InputData::lsSUPERLU)
00347 {
00348 throw new Fatal(_("Solver::_inv_K_times_X: SUPERLU is not working yet"));
00349 }
00350 else throw new Fatal(_("Solver::_inv_K_times_X: linSOLVER is invalid"));
00351
00352 LinAlg::Vector<REAL> & Y1 = TMP;
00353 LinAlg::Vector<REAL> X2(Y2.Size());
00354 LinAlg::Gemvpmv(1.0,K21,Y1, 1.0,K22,Y2, X2);
00355
00356
00357 _do_gather(Y1,Y2, X1,X2, Y,X);
00358
00359
00360
00361
00362
00363
00364
00365
00366 }
00367
00368 inline void Solver::_do_scatter(LinAlg::Matrix<REAL> const & K,
00369 LinAlg::Vector<REAL> const & X,
00370 LinAlg::Vector<REAL> const & Y,
00371 LinAlg::Matrix<REAL> & K11,
00372 LinAlg::Matrix<REAL> & K12,
00373 LinAlg::Matrix<REAL> & K21,
00374 LinAlg::Matrix<REAL> & K22,
00375 LinAlg::Vector<REAL> & Y2,
00376 LinAlg::Vector<REAL> & X1)
00377 {
00378
00379
00380 int us = _a_udofs.size();
00381 int ps = _a_pdofs.size();
00382
00383
00384 K11.Resize(us,us);
00385 K12.Resize(us,ps);
00386 K21.Resize(ps,us);
00387 K22.Resize(ps,ps);
00388 Y2.Resize(ps);
00389 X1.Resize(us);
00390
00391 for (int ip=0; ip<ps; ++ip)
00392
00393
00394 for (int iu=0; iu<us; ++iu)
00395 {
00396
00397 for (int ju=0; ju<us; ++ju)
00398 K11(iu,ju) = K(_a_udofs[iu]->EqID, _a_udofs[ju]->EqID);
00399
00400
00401 for (int jp=0; jp<ps; ++jp)
00402 K12(iu,jp) = K(_a_udofs[iu]->EqID, _a_pdofs[jp]->EqID);
00403
00404
00405 X1(iu) = X(_a_udofs[iu]->EqID);
00406 }
00407
00408
00409 for (int ip=0; ip<ps; ++ip)
00410 {
00411
00412 for (int ju=0; ju<us; ++ju)
00413 K21(ip,ju) = K(_a_pdofs[ip]->EqID, _a_udofs[ju]->EqID);
00414
00415
00416 for (int jp=0; jp<ps; ++jp)
00417 K22(ip,jp) = K(_a_pdofs[ip]->EqID, _a_pdofs[jp]->EqID);
00418
00419
00420 Y2(ip) = Y(_a_pdofs[ip]->EqID);
00421 }
00422 }
00423
00424 inline void Solver::_do_gather(LinAlg::Vector<REAL> const & Y1,
00425 LinAlg::Vector<REAL> const & Y2,
00426 LinAlg::Vector<REAL> const & X1,
00427 LinAlg::Vector<REAL> const & X2,
00428 LinAlg::Vector<REAL> & Y ,
00429 LinAlg::Vector<REAL> & X)
00430 {
00431
00432
00433 int us = _a_udofs.size();
00434 int ps = _a_pdofs.size();
00435
00436
00437 for (int iu=0; iu<us; ++iu)
00438 {
00439
00440 Y(_a_udofs[iu]->EqID) = Y1(iu);
00441
00442
00443 X(_a_udofs[iu]->EqID) = X1(iu);
00444 }
00445
00446
00447 for (int ip=0; ip<ps; ++ip)
00448 {
00449
00450 Y(_a_pdofs[ip]->EqID) = Y2(ip);
00451
00452
00453 X(_a_pdofs[ip]->EqID) = X2(ip);
00454 }
00455 }
00456
00457 inline void Solver::_backup_nodes_and_elements_state()
00458 {
00459
00460
00461
00462 for (size_t iu=0; iu<_a_udofs.size(); ++iu)
00463 {
00464 _U_bkp(_a_udofs[iu]->EqID) = _a_udofs[iu]->EssentialVal;
00465 _F_bkp(_a_udofs[iu]->EqID) = _a_udofs[iu]->NaturalVal;
00466 }
00467
00468
00469 for (size_t ip=0; ip<_a_pdofs.size(); ++ip)
00470 {
00471 _U_bkp(_a_pdofs[ip]->EqID) = _a_pdofs[ip]->EssentialVal;
00472 _F_bkp(_a_pdofs[ip]->EqID) = _a_pdofs[ip]->NaturalVal;
00473 }
00474
00475
00476
00477
00478 for (size_t i=0; i<_data.Elements.size(); ++i)
00479 _data.Elements[i]->BackupState();
00480
00481
00482 }
00483
00484 inline void Solver::_update_nodes_and_elements_state(LinAlg::Vector<REAL> const & dU, LinAlg::Vector<REAL> & dF_int)
00485 {
00486
00487
00488
00489 for (size_t iu=0; iu<_a_udofs.size(); ++iu)
00490 _a_udofs[iu]->EssentialVal += dU(_a_udofs[iu]->EqID);
00491
00492
00493 for (size_t ip=0; ip<_a_pdofs.size(); ++ip)
00494 _a_pdofs[ip]->EssentialVal += dU(_a_pdofs[ip]->EqID);
00495
00496
00497
00498
00499
00500
00501 for (size_t iu=0; iu<_a_udofs.size(); ++iu)
00502 {
00503 _a_udofs[iu]->_IncEssenVal = dU(_a_udofs[iu]->EqID);
00504 _a_udofs[iu]->_IncNaturVal = 0.0;
00505 }
00506
00507
00508 for (size_t ip=0; ip<_a_pdofs.size(); ++ip)
00509 {
00510 _a_pdofs[ip]->_IncEssenVal = dU(_a_pdofs[ip]->EqID);
00511 _a_pdofs[ip]->_IncNaturVal = 0.0;
00512 }
00513
00514
00515
00516
00517 for (size_t i=0; i<_data.Elements.size(); ++i)
00518 _data.Elements[i]->UpdateState();
00519
00520
00521
00522
00523 for (size_t iu=0; iu<_a_udofs.size(); ++iu)
00524 dF_int(_a_udofs[iu]->EqID) = _a_udofs[iu]->_IncNaturVal;
00525
00526
00527 for (size_t ip=0; ip<_a_pdofs.size(); ++ip)
00528 dF_int(_a_pdofs[ip]->EqID) = _a_pdofs[ip]->_IncNaturVal;
00529
00530
00531 }
00532
00533 inline void Solver::_restore_nodes_and_elements_state()
00534 {
00535
00536
00537
00538 for (size_t iu=0; iu<_a_udofs.size(); ++iu)
00539 {
00540 _a_udofs[iu]->EssentialVal = _U_bkp(_a_udofs[iu]->EqID);
00541 _a_udofs[iu]->NaturalVal = _F_bkp(_a_udofs[iu]->EqID);
00542 }
00543
00544
00545 for (size_t ip=0; ip<_a_pdofs.size(); ++ip)
00546 {
00547 _a_pdofs[ip]->EssentialVal = _U_bkp(_a_pdofs[ip]->EqID);
00548 _a_pdofs[ip]->NaturalVal = _F_bkp(_a_pdofs[ip]->EqID);
00549 }
00550
00551
00552
00553
00554 for (size_t i=0; i<_data.Elements.size(); ++i)
00555 _data.Elements[i]->RestoreState();
00556
00557
00558 }
00559
00560 inline REAL Solver::_norm_essential_vector()
00561 {
00562 REAL tmp=0.0;
00563
00564 for (size_t iu=0; iu<_a_udofs.size(); ++iu)
00565 tmp += pow(_a_udofs[iu]->EssentialVal,2.0);
00566
00567
00568 for (size_t ip=0; ip<_a_pdofs.size(); ++ip)
00569 tmp += pow(_a_pdofs[ip]->EssentialVal,2.0);
00570
00571 return sqrt(tmp);
00572 }
00573
00574 inline REAL Solver::_norm_natural_vector()
00575 {
00576 REAL tmp=0.0;
00577
00578 for (size_t iu=0; iu<_a_udofs.size(); ++iu)
00579 tmp += pow(_a_udofs[iu]->NaturalVal,2.0);
00580
00581
00582 for (size_t ip=0; ip<_a_pdofs.size(); ++ip)
00583 tmp += pow(_a_pdofs[ip]->NaturalVal,2.0);
00584
00585 return sqrt(tmp);
00586 }
00587
00589
00590
00591
00592 typedef Solver * (*SolverMakerPtr)(Array<String> const & SolverCtes, FEM::InputData const & ID, FEM::Data & data, FEM::Output & output);
00593
00594
00595 typedef std::map<String, SolverMakerPtr, std::less<String> > SolverFactory_t;
00596
00597
00598 SolverFactory_t SolverFactory;
00599
00600
00601 Solver * AllocSolver(String const & SolverName, Array<String> const & SolverCtes, FEM::InputData const & ID, FEM::Data & data, FEM::Output & output)
00602 {
00603 SolverMakerPtr ptr=NULL;
00604 ptr = SolverFactory[SolverName];
00605 if (ptr==NULL)
00606 throw new Fatal(_("FEM::AllocSolver: There is no < %s > solver implemented in this library"), SolverName.c_str());
00607 return (*ptr)(SolverCtes, ID, data, output);
00608 }
00609
00610 };
00611
00612 #endif // MECHSYS_FEM_SOLVER_H
00613
00614