autome.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_AUTOME_H
00023 #define MECHSYS_FEM_AUTOME_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 // MechSys
00034 #include "util/string.h"
00035 #include "util/lineparser.h"
00036 #include "fem/solver/solver.h"
00037 
00038 namespace FEM
00039 {
00040 
00041 class AutoME : public Solver
00042 {
00043 public:
00044     AutoME(Array<String> const & SolverCtes, FEM::InputData const & ID, FEM::Data & data, FEM::Output & output)
00045         : Solver (ID, data, output),
00046           _maxSS (200)   ,
00047           _STOL  (1.0e-2),
00048           _dTini (0.001) ,
00049           _mMin  (0.01)  ,
00050           _mMax  (10)    ,
00051           _mCoef (0.7)   ,
00052           _ZTOL  (1e-3)  ,
00053           _unbal_correction  (false),
00054           _check_convergence (true)
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=="maxSS") LP>>_maxSS;
00062             else if (key=="STOL")  LP>>_STOL;
00063             else if (key=="dTini") LP>>_dTini;
00064             else if (key=="mMin")  LP>>_mMin;
00065             else if (key=="mMax")  LP>>_mMax;
00066             else if (key=="mCoef") LP>>_mCoef;
00067             else if (key=="ZTOL")  LP>>_ZTOL;
00068             else if (key=="unbcor") LP>>_unbal_correction;
00069             else if (key=="checkConvergence") LP>>_check_convergence;
00070             else throw new Fatal(_("AutoME::AutoME: < %s > is invalid "), key.c_str());
00071         }
00072     }
00073     void _do_solve_for_an_increment(int                  const   increment,  // In
00074                                     LinAlg::Vector<REAL> const & DF_ext   ,  // In
00075                                     LinAlg::Vector<REAL> const & DU_ext   ,  // In
00076                                     LinAlg::Matrix<REAL>       & K        ,  // (no needed outside)
00077                                     LinAlg::Vector<REAL>       & dF_int   ,  // (no needed outside)
00078                                     LinAlg::Vector<REAL>       & Rinternal,  // (no needed outside)
00079                                     IntSolverData              & ISD      ); // Out
00080 private:
00081     int  _maxSS;
00082     REAL _STOL;
00083     REAL _dTini;
00084     REAL _mMin;
00085     REAL _mMax;
00086     REAL _mCoef;
00087     REAL _ZTOL;
00088     bool _unbal_correction;
00089     bool _check_convergence;
00090 
00091     LinAlg::Vector<REAL> _dF_1;
00092     LinAlg::Vector<REAL> _dU_1;
00093     LinAlg::Vector<REAL> _dF_2;
00094     LinAlg::Vector<REAL> _dU_2;
00095     LinAlg::Vector<REAL> _dU_ME;
00096     LinAlg::Vector<REAL> _Err_U;
00097     LinAlg::Vector<REAL> _Err_F;
00098     LinAlg::Vector<REAL> _dU_unb;
00099 }; // class AutoME
00100 
00101 
00103 
00104 
00105 inline void AutoME::_do_solve_for_an_increment(int                  const   increment, // In // {{{
00106                                                LinAlg::Vector<REAL> const & DF_ext   , // In
00107                                                LinAlg::Vector<REAL> const & DU_ext   , // In
00108                                                LinAlg::Matrix<REAL>       & K        , // (no needed outside)
00109                                                LinAlg::Vector<REAL>       & dF_int   , // (no needed outside)
00110                                                LinAlg::Vector<REAL>       & Rinternal, // (no needed outside)
00111                                                IntSolverData              & ISD      ) // Out
00112 {
00113     // Allocate and fill dF_ext and dU_ext
00114     int n_tot_dof = DF_ext.Size();
00115     LinAlg::Vector<REAL> dF_ext; dF_ext.Resize(n_tot_dof);
00116     LinAlg::Vector<REAL> dU_ext; dU_ext.Resize(n_tot_dof);
00117     LinAlg::Copy(DF_ext, dF_ext);
00118     LinAlg::Copy(DU_ext, dU_ext);
00119 
00120     // Allocate auxiliar vectors
00121     if (increment==0)
00122     {
00123         _dF_1 .Resize(n_tot_dof);
00124         _dU_1 .Resize(n_tot_dof);
00125         _dF_2 .Resize(n_tot_dof);
00126         _dU_2 .Resize(n_tot_dof);
00127         _dU_ME.Resize(n_tot_dof);
00128         _Err_U.Resize(n_tot_dof);
00129         _Err_F.Resize(n_tot_dof);
00130         //if (_unbal_correction)
00131             //_dU_unb.Resize(n_tot_dof);
00132     }
00133     
00134     // Initialize unbalanced forces array
00135     //if (_unbal_correction)
00136         //_dU_unb.SetValues(0.0);
00137 
00138     // Start substeps
00139     REAL  T = 0.0;
00140     REAL dT = _dTini;
00141     for (int k=0; k<_maxSS; ++k)
00142     {
00143         if (T>=1.0) return;
00144 
00145         // Calculate scaled increment vectors for this sub-step
00146         LinAlg::CopyScal(dT,dF_ext, _dF_1); // _dF_1 <- dT*dF_ext
00147         LinAlg::CopyScal(dT,dU_ext, _dU_1); // _dU_1 <- dT*dU_ext;
00148         LinAlg::CopyScal(dT,dF_ext, _dF_2); // _dF_2 <- dT*dF_ext
00149         LinAlg::CopyScal(dT,dU_ext, _dU_2); // _dU_2 <- dT*dU_ext;
00150 
00151         // Backup element state (needed when updating disp. state for a ME increment)
00152         _backup_nodes_and_elements_state();
00153 
00154         // Forward-Euler: Assemble K matrix and calculate _dU_1
00155         _assemb_K(K);
00156         _inv_K_times_X(K, false, _dF_1, _dU_1);
00157 
00158         // Add unbalanced displacements
00159         //if (_unbal_correction)
00160             //LinAlg::Axpy(1.0,_dU_unb, _dU_1); // _dU_1 <- _dU_1 + _dU_unb
00161 
00162         // Forward-Euler: update nodes and elements state
00163         _update_nodes_and_elements_state(_dU_1, dF_int);
00164 
00165         // Modified-Euler: Assemble K matrix and calculate dU_2
00166         _assemb_K(K);
00167         _inv_K_times_X(K, false, _dF_2, _dU_2);
00168 
00169         // Save the norm of essential and natural vectors
00170         REAL normU = _norm_essential_vector(); // (%)
00171         REAL normF = _norm_natural_vector();
00172 
00173         // Calculate local error
00174         if (normF<=_ZTOL) throw new Message(_("AutoME::_do_solve_for_an_increment: k=%d: normF=%e cannot be equal to zero (%e)"),k,normF,_ZTOL);
00175         LinAlg::AddScaled(0.5,_dU_2, -0.5,_dU_1, _Err_U); // Error on U (%)
00176         LinAlg::AddScaled(0.5,_dF_2, -0.5,_dF_1, _Err_F); // Error on F
00177         REAL Rerr_U = LinAlg::Norm(_Err_U)/(1.0+normU);   // (R)elative error on U
00178         REAL Rerr_F = LinAlg::Norm(_Err_F)/normF;         // (R)elative error on F
00179         REAL   Rerr = (Rerr_U>Rerr_F ? Rerr_U : Rerr_F);  // (R)elative error
00180         REAL      m = _mCoef*sqrt(_STOL/Rerr);
00181 
00182         // Restore nodes and element for initial disp. state given at the start of the increment
00183         _restore_nodes_and_elements_state();
00184 
00185         if (Rerr<=_STOL)
00186         {
00187             // Calculate Modified-Euler displacement increment vector
00188             LinAlg::AddScaled(0.5,_dU_1, 0.5,_dU_2, _dU_ME);
00189 
00190             // Update nodes and elements state for a Modified-Euler evaluation of displacements
00191             _update_nodes_and_elements_state(_dU_ME, dF_int);
00192 
00193             /*
00194             // Calculate residual (internal)
00195             LinAlg::AddScaled (1.0,_dF_2, -1.0,dF_int, Rinternal); // Rinternal <- dF_ext - dF_int
00196             REAL denom = 0.0;                                       // Normalizer
00197             for (int i=0; i<Rinternal.Size(); i++) denom += pow((dF_ext(i)+dF_int(i))/2.0, 2.0);
00198             ISD.ME_resid(LinAlg::Norm(Rinternal)/sqrt(denom));
00199             */
00200 
00201             // Calculate unbalanced displacements
00202             //if (_unbal_correction)
00203                 //_inv_K_times_X(K, false, Rinternal, _dU_unb);
00204 
00205             // Next pseudo time
00206             T = T + dT;
00207             if (m>_mMax) m=_mMax;
00208         }
00209         else
00210             if (m<_mMin) m=_mMin;
00211 
00212         // Next substep size
00213         dT = m*dT;
00214         if (dT>1.0-T) dT=1.0-T;
00215 
00216         // IntSolverData
00217         ISD.ME_Rerr(Rerr).ME_T(T).ME_dT(dT).ME_m(m);
00218     }
00219     if (_check_convergence)
00220         throw new Fatal(_("AutoME::_do_solve_for_an_increment: did not converge for %d substeps"), _maxSS);
00221 
00222 } // }}}
00223 
00224 
00226 
00227 
00228 // Allocate a new AutoME solver
00229 Solver * AutoMEMaker(Array<String> const & SolverCtes, FEM::InputData const & ID, FEM::Data & data, FEM::Output & output) // {{{
00230 {
00231     return new AutoME(SolverCtes, ID, data, output);
00232 } // }}}
00233 
00234 // Register an AutoME solver into SolverFactory array map
00235 int AutoMERegister() // {{{
00236 {
00237     SolverFactory["AutoME"] = AutoMEMaker;
00238     return 0;
00239 } // }}}
00240 
00241 // Execute the autoregistration
00242 int __AutoME_dummy_int = AutoMERegister();
00243 
00244 }; // namespace FEM
00245 
00246 #endif // MECHSYS_FEM_AUTOME_H
00247 
00248 // vim:fdm=marker

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