autoincme.h

00001 /*************************************************************************************
00002  * MechSys - A C++ library to simulate (Continuum) Mechanical Systems                *
00003  * Copyright (C) 2005 Dorival de Moraes Pedroso <dorival.pedroso at gmail.com>       *
00004  * Copyright (C) 2005 Raul Dario Durand Farfan  <raul.durand at gmail.com>           *
00005  *                                                                                   *
00006  * This file is part of MechSys.                                                     *
00007  *                                                                                   *
00008  * MechSys is free software; you can redistribute it and/or modify it under the      *
00009  * terms of the GNU General Public License as published by the Free Software         *
00010  * Foundation; either version 2 of the License, or (at your option) any later        *
00011  * version.                                                                          *
00012  *                                                                                   *
00013  * MechSys is distributed in the hope that it will be useful, but WITHOUT ANY        *
00014  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A   *
00015  * PARTICULAR PURPOSE. See the GNU General Public License for more details.          *
00016  *                                                                                   *
00017  * You should have received a copy of the GNU General Public License along with      *
00018  * MechSys; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, *
00019  * Fifth Floor, Boston, MA 02110-1301, USA                                           *
00020  *************************************************************************************/
00021 
00022 #ifndef MECHSYS_FEM_AUTOINCME_H
00023 #define MECHSYS_FEM_AUTOINCME_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 "util/string.h"
00034 #include "fem/solver/solver.h"
00035 #include "util/lineparser.h"
00036 #ifdef DO_DEBUG
00037   #include "util/numstreams.h"
00038 #endif
00039 
00040 namespace FEM
00041 {
00042 
00043 class AutoIncME : public Solver
00044 {
00045 public:
00046     AutoIncME(Array<String> const & SolverCtes, FEM::Data & data, FEM::Output & output, Array<int> & nDiv)
00047         : Solver             (data, output, nDiv) ,
00048           _dT_ini            (0.001)  ,
00049           _m_min             (0.01)   ,
00050           _m_max             (10)     ,
00051           _m_sf              (0.7)    ,
00052           _max_sub_steps     (200)    ,
00053           _dtol              (1.0e-4) ,
00054           _use_resid_correct (false)  
00055     {
00056         for (size_t i=0; i<SolverCtes.size(); ++i)
00057         {
00058             LineParser LP(SolverCtes[i]);
00059             LP.ReplaceAllChars('=',' ');
00060             String key;                    LP>>key;
00061                  if (key=="dTini")         LP>>_dT_ini;
00062             else if (key=="mMin")          LP>>_m_min;
00063             else if (key=="mMax")          LP>>_m_max;
00064             else if (key=="mSF")           LP>>_m_sf;
00065             else if (key=="maxSSteps")     LP>>_max_sub_steps;
00066             else if (key=="DTOL")          LP>>_dtol;
00067             else if (key=="correctResid")  LP>>_use_resid_correct;
00068         }
00069     }
00070     void _do_solve_for_an_increment(int                  const   increment   ,  // In
00071                                     LinAlg::Vector<REAL>       & dF_ext      ,  // In/Out
00072                                     LinAlg::Vector<REAL>       & dU_ext      ,  // In/Out
00073                                     REAL                 const   norm_dF_ext ,  // In
00074                                     LinAlg::Matrix<REAL>       & K           ,  // Out
00075                                     LinAlg::Vector<REAL>       & dF_int      ,  // Out
00076                                     LinAlg::Vector<REAL>       & R           ,  // Out
00077                                     REAL                       & resid       ); // Out
00078 private:
00079     REAL _dT_ini;
00080     REAL _m_min;
00081     REAL _m_max;
00082     REAL _m_sf; // sf: safety factor
00083     int  _max_sub_steps;
00084     REAL _dtol;
00085     bool _use_resid_correct;
00086     LinAlg::Vector<REAL> _df_ext;
00087     LinAlg::Vector<REAL> _du_ext;
00088     LinAlg::Vector<REAL> _df_int;
00089     LinAlg::Vector<REAL>   _df_1;
00090     LinAlg::Vector<REAL>   _df_2;
00091     LinAlg::Vector<REAL>   _du_1;
00092     LinAlg::Vector<REAL>   _du_2;
00093     LinAlg::Vector<REAL>  _du_ME;
00094     LinAlg::Vector<REAL>  _Err_f;
00095     LinAlg::Vector<REAL>  _Err_u;
00096 }; // class AutoIncME
00097 
00098 
00100 
00101 
00102 inline void AutoIncME::_do_solve_for_an_increment(int                  const   increment   , // In // {{{
00103                                                   LinAlg::Vector<REAL>       & dF_ext      , // In/Out
00104                                                   LinAlg::Vector<REAL>       & dU_ext      , // In/Out
00105                                                   REAL                 const   norm_dF_ext , // In
00106                                                   LinAlg::Matrix<REAL>       & K           , // Out
00107                                                   LinAlg::Vector<REAL>       & dF_int      , // Out
00108                                                   LinAlg::Vector<REAL>       & R           , // Out
00109                                                   REAL                       & resid       ) // Out
00110 {
00111 #ifdef DO_DEBUG // {{{
00112     std::cout << "AutoIncME: Increment # " << increment+1 << std::endl;
00113 #endif // }}}
00114 
00115     if (increment==0)
00116     {
00117         // Allocate temporary vectors
00118         int n_tot_dof = dF_ext.Size();
00119         _df_ext.Resize(n_tot_dof);
00120         _du_ext.Resize(n_tot_dof);
00121         _df_int.Resize(n_tot_dof);
00122           _df_1.Resize(n_tot_dof);
00123           _df_2.Resize(n_tot_dof);
00124           _du_1.Resize(n_tot_dof);
00125           _du_2.Resize(n_tot_dof);
00126          _du_ME.Resize(n_tot_dof);
00127          _Err_f.Resize(n_tot_dof);
00128          _Err_u.Resize(n_tot_dof);
00129 
00130 #ifdef DO_DEBUG // {{{
00131            std::cout << "Sub-step" << _8s()<< "resid" << "Accep/Reject" << _8s()<< "T" << _8s()<< "m" << _8s()<< "dT" << std::endl;
00132 #endif // }}}
00133     }
00134 
00135     // Auxiliar "pseudo-time" variables
00136     REAL  T = 0.0;
00137     REAL dT = _dT_ini;
00138     REAL m;
00139 
00140     // Loop along sub-steps (0<k<NumSubSteps(?))
00141     bool DidFinish=false;
00142     for (int k_sub_step=0; k_sub_step<_max_sub_steps; ++k_sub_step)
00143     {
00144         // Check for convergence
00145         if (T>=1.0) { DidFinish=true; std::cout << std::endl; break; }
00146         
00147         // Calculate scaled increment vectors for this sub-step
00148         LinAlg::CopyScal(dT,dF_ext, _df_ext); // _df_ext <- dT*dF_ext
00149         LinAlg::CopyScal(dT,dU_ext, _du_ext); // _du_ext <- dT*dU_ext;
00150 
00151         // Setup temporary force vectors
00152         LinAlg::Copy(_df_ext, _df_1); // _df_1 <- _df_ext
00153         LinAlg::Copy(_df_ext, _df_2); // _df_2 <- _df_ext;
00154 
00155         // Setup temporary displacement vectors
00156         LinAlg::Copy(_du_ext, _du_1); // _du_1 <- _du_ext;
00157         LinAlg::Copy(_du_ext, _du_2); // _du_2 <- _du_ext;
00158 
00159         // Backup element state
00160         _backup_nodes_and_elements_state(); // _U_bkp<-Node.U; Elem->BackupState();
00161 
00162         // Assemble K matrix and calculate dU_ext
00163         _assemb_K(K);
00164         //_inv_K_times_X(K, false, _df_ext, _du_1); // -------------- First evaluation
00165         _inv_K_times_X(K, false, _df_1, _du_1); // -------------- First evaluation
00166 
00167         // Update nodes and elements state for a Forward-Euler evaluation of displacements
00168         _update_nodes_and_elements_state(_du_1, _df_int); // Node.U<-Node.U+_du_1; Elem->StressUpdate(_du_1);
00169 
00170         //if (_use_resid_correct) {{{
00171         //{
00172             // Calculate residual and its (Euclidian) norm
00173             //LinAlg::Copy(dF_ext, R);      // R <- dF_ext
00174             //LinAlg::Axpy(-1.0,dF_int, R); // R <- -1*dF_int+R == R-dF_int (for the first iteration: R<-dF_ext-dF_int)
00175 
00176             //LinAlg::Copy(dU_ext, dU_unb);
00177             //LinAlg::Axpy(-1.0,dU_1, dU_unb); // ???  dU_unb <- dU_ext - dU_1;
00178 
00179             // Calculate unbalanced displacements
00180             //_inv_K_times_X(K, false, R, dU_unb); // In=R,U; Out=dU  =>  dU=inv[K(U)]*R
00181 
00182             // Update all elements state
00183             //_update_elements_state(dU_unb, dF_int);
00184         //} }}}
00185 
00186         // Assemble K matrix and calculate dU_ext
00187         _assemb_K(K);
00188         //_inv_K_times_X(K, false, _df_ext, _du_2); // -------------- Second evaluation
00189         _inv_K_times_X(K, false, _df_2, _du_2); // -------------- Second evaluation
00190 
00191         // Calculate Modified-Euler displacement increment vector
00192         LinAlg::AddScaled(0.5,_du_1, 0.5,_du_2, _du_ME); // _du_ME <- 0.5*_du_1 + 0.5*_du_2
00193 
00194         // Calculate local error estimative
00195         //LinAlg::AddScaled(0.5,_du_2, -0.5,_du_1, _Err); // _Err <- 0.5*_du_2 - 0.5*_du_1
00196         //REAL norm_Err = sqrt(LinAlg::Dot(_Err,_Err));
00197         //REAL      err = norm_Err/_norm_essential_vector();
00198         LinAlg::AddScaled(0.5,_df_2, -0.5,_df_1, _Err_f); // _Err <- 0.5*_du_2 - 0.5*_du_1
00199         LinAlg::AddScaled(0.5,_du_2, -0.5,_du_1, _Err_u); // _Err <- 0.5*_du_2 - 0.5*_du_1
00200         REAL norm_Err_f = sqrt(LinAlg::Dot(_Err_f,_Err_f))/sqrt(LinAlg::Dot(_df_2,_df_2));
00201         REAL norm_Err_u = sqrt(LinAlg::Dot(_Err_u,_Err_u))/sqrt(LinAlg::Dot(_du_2,_du_2));
00202         REAL err = (norm_Err_f>norm_Err_u ? norm_Err_f : norm_Err_u);
00203 
00204         // Multiplier for the size of next sub-increment
00205         m = _m_sf*sqrt(_dtol/err);
00206 
00207         // Restore all elements state (useful both if sstep accepted or not)
00208         _restore_nodes_and_elements_state(); // Node.U<-_U_bkp; Elem->RestoreState();
00209 
00210         // Check if this sub-step can be accepted
00211         if (err<=_dtol) // sub-step accepted
00212         {
00213             // Actualize "pseudo-time"
00214             T = T + dT;
00215 
00216             // Update nodes and elements state for a Modified-Euler evaluation of displacements
00217             _update_nodes_and_elements_state(_du_ME, _df_int); // Node.U<-Node.U+_du_ME; Elem->StressUpdate(_du_ME);
00218 
00219             // Calculate residual and its (Euclidian) norm
00220             LinAlg::AddScaled(1.0,_df_ext, -1.0,_df_int, R); // R <- dF_ext-dF_int
00221             resid = sqrt(LinAlg::Dot(R,R))/norm_dF_ext;      // normalized measure of the residual
00222 
00223             // Check upper bound of step size
00224             if (m>_m_max) m=_m_max;
00225 #ifdef DO_DEBUG // {{{
00226             std::cout << k_sub_step << _8s()<< resid << "Accepted";
00227 #endif // }}}
00228         }
00229         else // sub-step rejected
00230         {
00231             if (m<_m_min) m=_m_min; // Check lower bound of step size
00232 #ifdef DO_DEBUG // {{{
00233             std::cout << k_sub_step << -1 << "Rejected";
00234 #endif // }}}
00235         }
00236 
00237         // Next sub-step
00238         dT = m*dT;
00239         if (dT>1.0-T) dT=1.0-T;
00240 //#ifdef DO_DEBUG // {{{
00241         std::cout << _8s()<< T << _8s()<< m << _8s()<< dT << std::endl;
00242         //std::cout << _6()<< T <<  m <<  dT << std::endl;
00243 //#endif // }}}
00244     }
00245     if (!DidFinish)
00246         throw new Fatal(_("AutoIncME::_do_solve did not finish with T=1. k_sub_step=<%d>"),_max_sub_steps);
00247 } // }}}
00248 
00249 
00251 
00252 
00253 // Allocate a new AutoIncME solver
00254 Solver * AutoIncMEMaker(Array<String> const & SolverCtes, FEM::Data & data, FEM::Output & output, Array<int> & nDiv) // {{{
00255 {
00256     return new AutoIncME(SolverCtes, data, output, nDiv);
00257 } // }}}
00258 
00259 // Register an AutoIncME solver into SolverFactory array map
00260 int AutoIncMERegister() // {{{
00261 {
00262     SolverFactory["AutoIncME"] = AutoIncMEMaker;
00263     return 0;
00264 } // }}}
00265 
00266 // Execute the autoregistration
00267 int __AutoIncME_dummy_int = AutoIncMERegister();
00268 
00269 }; // namespace FEM
00270 
00271 #endif // MECHSYS_FEM_AUTOINCME_H
00272 
00273 // vim:fdm=marker

Generated on Wed Jan 24 15:56:25 2007 for MechSys by  doxygen 1.4.7