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