Chaste Release::3.1
|
00001 /* 00002 00003 Copyright (c) 2005-2012, University of Oxford. 00004 All rights reserved. 00005 00006 University of Oxford means the Chancellor, Masters and Scholars of the 00007 University of Oxford, having an administrative office at Wellington 00008 Square, Oxford OX1 2JD, UK. 00009 00010 This file is part of Chaste. 00011 00012 Redistribution and use in source and binary forms, with or without 00013 modification, are permitted provided that the following conditions are met: 00014 * Redistributions of source code must retain the above copyright notice, 00015 this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright notice, 00017 this list of conditions and the following disclaimer in the documentation 00018 and/or other materials provided with the distribution. 00019 * Neither the name of the University of Oxford nor the names of its 00020 contributors may be used to endorse or promote products derived from this 00021 software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 */ 00035 #ifndef CARDIACNEWTONSOLVER_HPP_ 00036 #define CARDIACNEWTONSOLVER_HPP_ 00037 00038 #include <cmath> 00039 #include "IsNan.hpp" 00040 #include "UblasCustomFunctions.hpp" 00041 #include "AbstractBackwardEulerCardiacCell.hpp" 00042 #include "Warnings.hpp" 00043 00056 template<unsigned SIZE, typename CELLTYPE> 00057 class CardiacNewtonSolver 00058 { 00059 public: 00065 static CardiacNewtonSolver<SIZE, CELLTYPE>* Instance() 00066 { 00067 static CardiacNewtonSolver<SIZE, CELLTYPE> inst; 00068 return &inst; 00069 } 00070 00078 void Solve(CELLTYPE &rCell, 00079 double time, 00080 double rCurrentGuess[SIZE]) 00081 { 00082 unsigned counter = 0; 00083 const double eps = 1e-6; // JonW tolerance 00084 00085 // check that the initial guess that was given gives a valid residual 00086 rCell.ComputeResidual(time, rCurrentGuess, mResidual.data()); 00087 double norm_of_residual = norm_inf(mResidual); 00088 assert(!std::isnan(norm_of_residual)); 00089 double norm_of_update = 0.0; //Properly initialised in the loop 00090 do 00091 { 00092 // Calculate Jacobian for current guess 00093 rCell.ComputeJacobian(time, rCurrentGuess, mJacobian); 00094 00095 // Solve Newton linear system for mUpdate, given mJacobian and mResidual 00096 SolveLinearSystem(); 00097 00098 // Update norm (JonW style) 00099 norm_of_update = norm_inf(mUpdate); 00100 00101 // Update current guess and recalculate residual 00102 for (unsigned i=0; i<SIZE; i++) 00103 { 00104 rCurrentGuess[i] -= mUpdate[i]; 00105 } 00106 double norm_of_previous_residual = norm_of_residual; 00107 rCell.ComputeResidual(time, rCurrentGuess, mResidual.data()); 00108 norm_of_residual = norm_inf(mResidual); 00109 if (norm_of_residual > norm_of_previous_residual && norm_of_update > eps) 00110 { 00111 //Second part of guard: 00112 //Note that if norm_of_update < eps (converged) then it's 00113 //likely that both the residual and the previous residual were 00114 //close to the root. 00115 00116 //Work out where the biggest change in the guess has happened. 00117 double relative_change_max = 0.0; 00118 unsigned relative_change_direction = 0; 00119 for (unsigned i=0; i<SIZE; i++) 00120 { 00121 double relative_change = fabs(mUpdate[i]/rCurrentGuess[i]); 00122 if (relative_change > relative_change_max) 00123 { 00124 relative_change_max = relative_change; 00125 relative_change_direction = i; 00126 } 00127 } 00128 00129 if (relative_change_max > 1.0) 00130 { 00131 //Only walk 0.2 of the way in that direction (put back 0.8) 00132 rCurrentGuess[relative_change_direction] += 0.8*mUpdate[relative_change_direction]; 00133 rCell.ComputeResidual(time, rCurrentGuess, mResidual.data()); 00134 norm_of_residual = norm_inf(mResidual); 00135 WARNING("Residual increasing and one direction changing radically - back tracking in that direction"); 00136 } 00137 } 00138 counter++; 00139 00140 // avoid infinite loops 00141 if (counter > 15) 00142 { 00143 #define COVERAGE_IGNORE 00144 EXCEPTION("Newton method diverged in CardiacNewtonSolver::Solve()"); 00145 #undef COVERAGE_IGNORE 00146 } 00147 } 00148 while (norm_of_update > eps); 00149 00150 #define COVERAGE_IGNORE 00151 #ifndef NDEBUG 00152 if (norm_of_residual > 2e-10) 00153 { //This line is for correlation - in case we use norm_of_residual as convergence criterion 00154 WARN_ONCE_ONLY("Newton iteration terminated because update vector norm is small, but residual norm is not small."); 00155 } 00156 #endif // NDEBUG 00157 #undef COVERAGE_IGNORE 00158 } 00159 00160 protected: 00162 CardiacNewtonSolver() 00163 {} 00165 CardiacNewtonSolver(const CardiacNewtonSolver<SIZE, CELLTYPE>&); 00167 CardiacNewtonSolver<SIZE, CELLTYPE>& operator= (const CardiacNewtonSolver<SIZE, CELLTYPE>&); 00168 00178 void SolveLinearSystem() 00179 { 00180 for (unsigned i=0; i<SIZE; i++) 00181 { 00182 for (unsigned ii=i+1; ii<SIZE; ii++) 00183 { 00184 double fact = mJacobian[ii][i]/mJacobian[i][i]; 00185 for (unsigned j=i; j<SIZE; j++) 00186 { 00187 mJacobian[ii][j] -= fact*mJacobian[i][j]; 00188 } 00189 mResidual[ii] -= fact*mResidual[i]; 00190 } 00191 } 00192 for (unsigned i=SIZE; i-- > 0; ) 00193 { 00194 mUpdate[i] = mResidual[i]; 00195 for (unsigned j=i+1; j<SIZE; j++) 00196 { 00197 mUpdate[i] -= mJacobian[i][j]*mUpdate[j]; 00198 } 00199 mUpdate[i] /= mJacobian[i][i]; 00200 } 00201 } 00202 00203 private: 00205 c_vector<double, SIZE> mResidual; 00207 double mJacobian[SIZE][SIZE]; 00209 c_vector<double, SIZE> mUpdate; 00210 }; 00211 00212 #endif /*CARDIACNEWTONSOLVER_HPP_*/