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_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
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,
00074 LinAlg::Vector<REAL> const & DF_ext ,
00075 LinAlg::Vector<REAL> const & DU_ext ,
00076 LinAlg::Matrix<REAL> & K ,
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 _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 };
00100
00101
00103
00104
00105 inline void AutoME::_do_solve_for_an_increment(int const increment,
00106 LinAlg::Vector<REAL> const & DF_ext ,
00107 LinAlg::Vector<REAL> const & DU_ext ,
00108 LinAlg::Matrix<REAL> & K ,
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
00134
00135
00136
00137
00138
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
00146 LinAlg::CopyScal(dT,dF_ext, _dF_1);
00147 LinAlg::CopyScal(dT,dU_ext, _dU_1);
00148 LinAlg::CopyScal(dT,dF_ext, _dF_2);
00149 LinAlg::CopyScal(dT,dU_ext, _dU_2);
00150
00151
00152 _backup_nodes_and_elements_state();
00153
00154
00155 _assemb_K(K);
00156 _inv_K_times_X(K, false, _dF_1, _dU_1);
00157
00158
00159
00160
00161
00162
00163 _update_nodes_and_elements_state(_dU_1, dF_int);
00164
00165
00166 _assemb_K(K);
00167 _inv_K_times_X(K, false, _dF_2, _dU_2);
00168
00169
00170 REAL normU = _norm_essential_vector();
00171 REAL normF = _norm_natural_vector();
00172
00173
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);
00176 LinAlg::AddScaled(0.5,_dF_2, -0.5,_dF_1, _Err_F);
00177 REAL Rerr_U = LinAlg::Norm(_Err_U)/(1.0+normU);
00178 REAL Rerr_F = LinAlg::Norm(_Err_F)/normF;
00179 REAL Rerr = (Rerr_U>Rerr_F ? Rerr_U : Rerr_F);
00180 REAL m = _mCoef*sqrt(_STOL/Rerr);
00181
00182
00183 _restore_nodes_and_elements_state();
00184
00185 if (Rerr<=_STOL)
00186 {
00187
00188 LinAlg::AddScaled(0.5,_dU_1, 0.5,_dU_2, _dU_ME);
00189
00190
00191 _update_nodes_and_elements_state(_dU_ME, dF_int);
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206 T = T + dT;
00207 if (m>_mMax) m=_mMax;
00208 }
00209 else
00210 if (m<_mMin) m=_mMin;
00211
00212
00213 dT = m*dT;
00214 if (dT>1.0-T) dT=1.0-T;
00215
00216
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
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
00235 int AutoMERegister()
00236 {
00237 SolverFactory["AutoME"] = AutoMEMaker;
00238 return 0;
00239 }
00240
00241
00242 int __AutoME_dummy_int = AutoMERegister();
00243
00244 };
00245
00246 #endif // MECHSYS_FEM_AUTOME_H
00247
00248