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