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_CAUTOME_H
00023 #define MECHSYS_FEM_CAUTOME_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
00034 #include "util/string.h"
00035 #include "util/lineparser.h"
00036 #include "fem/solver/csolver.h"
00037
00038 namespace FEM
00039 {
00040
00041 class CAutoME: public CSolver
00042 {
00043 public:
00044 CAutoME(Array<String> const & CSolverCtes, FEM::InputData const & ID, FEM::Data & data, FEM::Output & output)
00045 : CSolver (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-5) ,
00053 _check_convergence (true)
00054 {
00055 for (size_t i=0; i<CSolverCtes.size(); ++i)
00056 {
00057 LineParser LP(CSolverCtes[i]);
00058 LP.ReplaceAllChars('=',' ');
00059 String key; LP>>key;
00060 if (key=="maxSS") LP>>_maxSS;
00061 else if (key=="STOL") LP>>_STOL;
00062 else if (key=="dTini") LP>>_dTini;
00063 else if (key=="mMin") LP>>_mMin;
00064 else if (key=="mMax") LP>>_mMax;
00065 else if (key=="mCoef") LP>>_mCoef;
00066 else if (key=="ZTOL") LP>>_ZTOL;
00067 else if (key=="checkConvergence") LP>>_check_convergence;
00068 else throw new Fatal(_("CAutoME::CAutoME: < %s > is invalid "), key.c_str());
00069 }
00070 }
00071 void _do_solve_for_an_increment(int const increment,
00072 LinAlg::Vector<REAL> const & DF_ext ,
00073 LinAlg::Vector<REAL> const & DU_ext ,
00074 REAL const dTime ,
00075 LinAlg::Matrix<REAL> & G ,
00076 LinAlg::Vector<REAL> & hKUn ,
00077 LinAlg::Vector<REAL> & dF_int ,
00078 LinAlg::Vector<REAL> & Rinternal,
00079 IntSolverData & ISD );
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 _check_convergence;
00089
00090 LinAlg::Vector<REAL> _dF_1;
00091 LinAlg::Vector<REAL> _dU_1;
00092 LinAlg::Vector<REAL> _dF_2;
00093 LinAlg::Vector<REAL> _dU_2;
00094 LinAlg::Vector<REAL> _dU_ME;
00095 LinAlg::Vector<REAL> _Err_U;
00096 LinAlg::Vector<REAL> _Err_F;
00097 };
00098
00099
00101
00102
00103 inline void CAutoME::_do_solve_for_an_increment(int const increment,
00104 LinAlg::Vector<REAL> const & DF_ext ,
00105 LinAlg::Vector<REAL> const & DU_ext ,
00106 REAL const dTime ,
00107 LinAlg::Matrix<REAL> & G ,
00108 LinAlg::Vector<REAL> & hKUn ,
00109 LinAlg::Vector<REAL> & dF_int ,
00110 LinAlg::Vector<REAL> & Rinternal,
00111 IntSolverData & ISD )
00112 {
00113
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
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 }
00131
00132
00133 REAL T = 0.0;
00134 REAL dT = _dTini;
00135 for (int k=0; k<_maxSS; ++k)
00136 {
00137 if (T>=1.0) return;
00138
00139
00140 REAL h = dT*dTime;
00141
00142
00143 LinAlg::CopyScal(dT,dF_ext, _dF_1);
00144 LinAlg::CopyScal(dT,dU_ext, _dU_1);
00145 LinAlg::CopyScal(dT,dF_ext, _dF_2);
00146 LinAlg::CopyScal(dT,dU_ext, _dU_2);
00147
00148
00149 _backup_nodes_and_elements_state();
00150
00151
00152 _assemb_G (G, hKUn, h);
00153 LinAlg::Axpy (-1.0,hKUn, _dF_1);
00154 _inv_K_times_X (G, false, _dF_1, _dU_1);
00155
00156
00157 _update_nodes_and_elements_state(_dU_1, dF_int, h);
00158
00159
00160 _assemb_G (G, hKUn, h);
00161 LinAlg::Axpy (-1.0,hKUn, _dF_2);
00162 _inv_K_times_X (G, false, _dF_2, _dU_2);
00163
00164
00165 REAL normU = _norm_essential_vector();
00166 REAL normF = _norm_natural_vector();
00167
00168
00169 if (normF<=_ZTOL) throw new Message(_("CAutoME::_do_solve_for_an_increment: k=%d: normF=%e cannot be equal to ZTOL (%e)"),k,normF,_ZTOL);
00170 LinAlg::AddScaled(0.5,_dU_2, -0.5,_dU_1, _Err_U);
00171 LinAlg::AddScaled(0.5,_dF_2, -0.5,_dF_1, _Err_F);
00172 REAL Rerr_U = LinAlg::Norm(_Err_U)/(1.0+normU);
00173 REAL Rerr_F = LinAlg::Norm(_Err_F)/normF;
00174 REAL Rerr = (Rerr_U>Rerr_F ? Rerr_U : Rerr_F);
00175 REAL m = _mCoef*sqrt(_STOL/Rerr);
00176
00177
00178 _restore_nodes_and_elements_state();
00179
00180 if (Rerr<=_STOL)
00181 {
00182
00183 LinAlg::AddScaled(0.5,_dU_1, 0.5,_dU_2, _dU_ME);
00184
00185
00186 _update_nodes_and_elements_state(_dU_ME, dF_int, h);
00187
00188
00189 T = T + dT;
00190 if (m>_mMax) m=_mMax;
00191 }
00192 else
00193 if (m<_mMin) m=_mMin;
00194
00195
00196 dT = m*dT;
00197 if (dT>1.0-T) dT=1.0-T;
00198
00199
00200 ISD.ME_Rerr(Rerr).ME_T(T).ME_dT(dT).ME_m(m);
00201 }
00202 if (_check_convergence)
00203 throw new Fatal(_("CAutoME::_do_solve_for_an_increment: did not converge for %d substeps"), _maxSS);
00204
00205 }
00206
00207
00209
00210
00211
00212 CSolver * CAutoMEMaker(Array<String> const & CSolverCtes, FEM::InputData const & ID, FEM::Data & data, FEM::Output & output)
00213 {
00214 return new CAutoME(CSolverCtes, ID, data, output);
00215 }
00216
00217
00218 int CAutoMERegister()
00219 {
00220 CSolverFactory["CAutoME"] = CAutoMEMaker;
00221 return 0;
00222 }
00223
00224
00225 int __CAutoME_dummy_int = CAutoMERegister();
00226
00227 };
00228
00229 #endif // MECHSYS_FEM_CAUTOME_H
00230
00231