CardiacNewtonSolver.hpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifndef CARDIACNEWTONSOLVER_HPP_
00029 #define CARDIACNEWTONSOLVER_HPP_
00030
00031 #include <cmath>
00032 #include "IsNan.hpp"
00033 #include "UblasCustomFunctions.hpp"
00034 #include "AbstractBackwardEulerCardiacCell.hpp"
00035 #include "Warnings.hpp"
00036
00049 template<unsigned SIZE, typename CELLTYPE>
00050 class CardiacNewtonSolver
00051 {
00052 public:
00058 static CardiacNewtonSolver<SIZE, CELLTYPE>* Instance()
00059 {
00060 static CardiacNewtonSolver<SIZE, CELLTYPE> inst;
00061 return &inst;
00062 }
00063
00071 void Solve(CELLTYPE &rCell,
00072 double time,
00073 double rCurrentGuess[SIZE])
00074 {
00075 unsigned counter = 0;
00076 const double eps = 1e-6;
00077
00078
00079 rCell.ComputeResidual(time, rCurrentGuess, mResidual.data());
00080 double norm_of_residual = norm_inf(mResidual);
00081 assert(!std::isnan(norm_of_residual));
00082 double norm_of_update = 0.0;
00083 do
00084 {
00085
00086 rCell.ComputeJacobian(time, rCurrentGuess, mJacobian);
00087
00088
00089 SolveLinearSystem();
00090
00091
00092 norm_of_update = norm_inf(mUpdate);
00093
00094
00095 for (unsigned i=0; i<SIZE; i++)
00096 {
00097 rCurrentGuess[i] -= mUpdate[i];
00098 }
00099 double norm_of_previous_residual = norm_of_residual;
00100 rCell.ComputeResidual(time, rCurrentGuess, mResidual.data());
00101 norm_of_residual = norm_inf(mResidual);
00102 if (norm_of_residual > norm_of_previous_residual && norm_of_update > eps)
00103 {
00104
00105
00106
00107
00108
00109
00110 double relative_change_max = 0.0;
00111 unsigned relative_change_direction = 0;
00112 for (unsigned i=0; i<SIZE; i++)
00113 {
00114 double relative_change = fabs(mUpdate[i]/rCurrentGuess[i]);
00115 if (relative_change > relative_change_max)
00116 {
00117 relative_change_max = relative_change;
00118 relative_change_direction = i;
00119 }
00120 }
00121
00122 if (relative_change_max > 1.0)
00123 {
00124
00125 rCurrentGuess[relative_change_direction] += 0.8*mUpdate[relative_change_direction];
00126 rCell.ComputeResidual(time, rCurrentGuess, mResidual.data());
00127 norm_of_residual = norm_inf(mResidual);
00128 WARNING("Residual increasing and one direction changing radically - back tracking in that direction");
00129 }
00130 }
00131 counter++;
00132
00133
00134 if (counter > 15)
00135 {
00136 #define COVERAGE_IGNORE
00137 EXCEPTION("Newton method diverged in CardiacNewtonSolver::Solve()");
00138 #undef COVERAGE_IGNORE
00139 }
00140 }
00141 while (norm_of_update > eps);
00142
00143 #define COVERAGE_IGNORE
00144 #ifndef NDEBUG
00145 if (norm_of_residual > 2e-10)
00146 {
00147 WARN_ONCE_ONLY("Newton iteration terminated because update vector norm is small, but residual norm is not small.");
00148 }
00149 #endif // NDEBUG
00150 #undef COVERAGE_IGNORE
00151 }
00152
00153 protected:
00155 CardiacNewtonSolver()
00156 {}
00158 CardiacNewtonSolver(const CardiacNewtonSolver<SIZE, CELLTYPE>&);
00160 CardiacNewtonSolver<SIZE, CELLTYPE>& operator= (const CardiacNewtonSolver<SIZE, CELLTYPE>&);
00161
00171 void SolveLinearSystem()
00172 {
00173 for (unsigned i=0; i<SIZE; i++)
00174 {
00175 for (unsigned ii=i+1; ii<SIZE; ii++)
00176 {
00177 double fact = mJacobian[ii][i]/mJacobian[i][i];
00178 for (unsigned j=i; j<SIZE; j++)
00179 {
00180 mJacobian[ii][j] -= fact*mJacobian[i][j];
00181 }
00182 mResidual[ii] -= fact*mResidual[i];
00183 }
00184 }
00185 for (unsigned i=SIZE; i-- > 0; )
00186 {
00187 mUpdate[i] = mResidual[i];
00188 for (unsigned j=i+1; j<SIZE; j++)
00189 {
00190 mUpdate[i] -= mJacobian[i][j]*mUpdate[j];
00191 }
00192 mUpdate[i] /= mJacobian[i][i];
00193 }
00194 }
00195
00196 private:
00198 c_vector<double, SIZE> mResidual;
00200 double mJacobian[SIZE][SIZE];
00202 c_vector<double, SIZE> mUpdate;
00203 };
00204
00205 #endif