Chaste Release::3.1
ImplicitCardiacMechanicsSolver.cpp
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 
00036 #include "ImplicitCardiacMechanicsSolver.hpp"
00037 #include "Kerchoffs2003ContractionModel.hpp"
00038 #include "NhsModelWithBackwardSolver.hpp"
00039 #include "NonPhysiologicalContractionModel.hpp"
00040 #include "FakeBathContractionModel.hpp"
00041 
00042 template<class ELASTICITY_SOLVER,unsigned DIM>
00043 ImplicitCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::ImplicitCardiacMechanicsSolver(
00044                                   ContractionModelName contractionModelName,
00045                                   QuadraticMesh<DIM>& rQuadMesh,
00046                                   ElectroMechanicsProblemDefinition<DIM>& rProblemDefinition,
00047                                   std::string outputDirectory)
00048     : AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>(rQuadMesh,
00049                                                             contractionModelName,
00050                                                             rProblemDefinition,
00051                                                             outputDirectory)
00052 {
00053 
00054 }
00055 
00056 
00057 template<class ELASTICITY_SOLVER,unsigned DIM>
00058 void ImplicitCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::InitialiseContractionModels(ContractionModelName contractionModelName)
00059 {
00060     for(std::map<unsigned,DataAtQuadraturePoint>::iterator iter = this->mQuadPointToDataAtQuadPointMap.begin();
00061         iter != this->mQuadPointToDataAtQuadPointMap.end();
00062         iter++)
00063     {
00064         AbstractContractionModel* p_contraction_model;
00065         if (iter->second.Active == true)
00066         {
00067             switch(contractionModelName)
00068             {
00069                 case NONPHYSIOL1:
00070                 case NONPHYSIOL2:
00071                 case NONPHYSIOL3:
00072                 {
00073                     unsigned option = (contractionModelName==NONPHYSIOL1 ? 1 : (contractionModelName==NONPHYSIOL2? 2 : 3));
00074                     p_contraction_model = new NonPhysiologicalContractionModel(option);
00075                     break;
00076                 }
00077                 case NHS:
00078                 {
00079                     p_contraction_model = new NhsModelWithBackwardSolver;
00080                     break;
00081                 }
00082                 case KERCHOFFS2003: //stretch dependent
00083                 {
00084                     p_contraction_model = new Kerchoffs2003ContractionModel;
00085                     break;
00086                 }
00087                 default:
00088                 {
00089                     #define COVERAGE_IGNORE
00090                     EXCEPTION("Unknown or disallowed contraction model");
00091                     #undef COVERAGE_IGNORE
00092                 }
00093             }
00094             iter->second.ContractionModel = p_contraction_model;
00095         }
00096         else
00097         {
00098                //bath
00099                p_contraction_model = new FakeBathContractionModel;
00100                iter->second.ContractionModel = p_contraction_model;
00101         }
00102     }
00103 }
00104 
00105 template<class ELASTICITY_SOLVER,unsigned DIM>
00106 ImplicitCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::~ImplicitCardiacMechanicsSolver()
00107 {
00108 }
00109 
00110 
00111 template<class ELASTICITY_SOLVER,unsigned DIM>
00112 void ImplicitCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::Solve(double time, double nextTime, double odeTimestep)
00113 {
00114     // set the times, which are used in AssembleOnElement
00115     assert(time < nextTime);
00116     this->mCurrentTime = time;
00117     this->mNextTime = nextTime;
00118     this->mOdeTimestep = odeTimestep;
00119 
00120     // solve
00121     ELASTICITY_SOLVER::Solve();
00122 
00123     // assemble residual again (to solve the cell models implicitly again
00124     // using the correct value of the deformation x (in case this wasn't the
00125     // last thing that was done
00126     if(this->GetNumNewtonIterations() > 0)
00127     {
00128         this->AssembleSystem(true,false);
00129     }
00130 
00131     // now update state variables, and set lambda at last timestep. Note
00132     // stretches were set in AssembleOnElement
00133     for(std::map<unsigned,DataAtQuadraturePoint>::iterator iter = this->mQuadPointToDataAtQuadPointMap.begin();
00134         iter != this->mQuadPointToDataAtQuadPointMap.end();
00135         iter++)
00136     {
00137         AbstractContractionModel* p_contraction_model = iter->second.ContractionModel;
00138         iter->second.StretchLastTimeStep = iter->second.Stretch;
00139         p_contraction_model->UpdateStateVariables();
00140     }
00141 
00142 }
00143 
00144 
00145 
00146 template<class ELASTICITY_SOLVER,unsigned DIM>
00147 void ImplicitCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::GetActiveTensionAndTensionDerivs(double currentFibreStretch,
00148                                                                                              unsigned currentQuadPointGlobalIndex,
00149                                                                                              bool assembleJacobian,
00150                                                                                              double& rActiveTension,
00151                                                                                              double& rDerivActiveTensionWrtLambda,
00152                                                                                              double& rDerivActiveTensionWrtDLambdaDt)
00153 {
00154     // The iterator should be pointing to the right place (note: it is incremented at the end of this method)
00155     // This iterator is used so that we don't have to search the map
00156     assert(this->mMapIterator->first==currentQuadPointGlobalIndex);
00157 
00158     DataAtQuadraturePoint& r_data_at_quad_point = this->mMapIterator->second;
00159 
00160     // save this fibre stretch
00161     r_data_at_quad_point.Stretch = currentFibreStretch;
00162 
00163     // compute dlam/dt
00164     double dlam_dt = (currentFibreStretch-r_data_at_quad_point.StretchLastTimeStep)/(this->mNextTime-this->mCurrentTime);
00165 
00166     // Set this stretch and stretch rate on contraction model
00167     AbstractContractionModel* p_contraction_model = r_data_at_quad_point.ContractionModel;
00168     p_contraction_model->SetStretchAndStretchRate(currentFibreStretch, dlam_dt);
00169 
00170     // Call RunDoNotUpdate() on the contraction model to solve it using this stretch, and get the active tension
00171     try
00172     {
00173         p_contraction_model->RunDoNotUpdate(this->mCurrentTime,this->mNextTime,this->mOdeTimestep);
00174         rActiveTension = p_contraction_model->GetNextActiveTension();
00175     }
00176     catch (Exception& e)
00177     {
00178         #define COVERAGE_IGNORE
00179         // if this failed during assembling the Jacobian this is a fatal error.
00180         if(assembleJacobian)
00181         {
00182             // probably shouldn't be able to get here
00183             EXCEPTION("Failure in solving contraction models using current stretches for assembling Jacobian");
00184         }
00185         // if this failed during assembling the residual, the stretches are too large, so we just
00186         // set the active tension to infinity so that the residual will be infinite
00187         rActiveTension = DBL_MAX;
00188         std::cout << "WARNING: could not solve contraction model with this stretch and stretch rate. "
00189                   << "Setting active tension to infinity (DBL_MAX) so that the residual(-norm) is also infinite\n" << std::flush;
00190         assert(0); // just to see if we ever get here, can be removed..
00191         return;
00192         #undef COVERAGE_IGNORE
00193     }
00194 
00195     // if assembling the Jacobian, numerically evaluate dTa/dlam & dTa/d(lamdot)
00196     if(assembleJacobian)
00197     {
00198         // get active tension for (lam+h,dlamdt)
00199         double h1 = std::max(1e-6, currentFibreStretch/100);
00200         p_contraction_model->SetStretchAndStretchRate(currentFibreStretch+h1, dlam_dt);
00201         p_contraction_model->RunDoNotUpdate(this->mCurrentTime,this->mNextTime,this->mOdeTimestep);
00202         double active_tension_at_lam_plus_h = p_contraction_model->GetNextActiveTension();
00203 
00204         // get active tension for (lam,dlamdt+h)
00205         double h2 = std::max(1e-6, dlam_dt/100);
00206         p_contraction_model->SetStretchAndStretchRate(currentFibreStretch, dlam_dt+h2);
00207         p_contraction_model->RunDoNotUpdate(this->mCurrentTime,this->mNextTime,this->mOdeTimestep);
00208         double active_tension_at_dlamdt_plus_h = p_contraction_model->GetNextActiveTension();
00209 
00210         rDerivActiveTensionWrtLambda = (active_tension_at_lam_plus_h - rActiveTension)/h1;
00211         rDerivActiveTensionWrtDLambdaDt = (active_tension_at_dlamdt_plus_h - rActiveTension)/h2;
00212     }
00213 
00214     // increment the iterator
00215     this->mMapIterator++;
00216     if(this->mMapIterator==this->mQuadPointToDataAtQuadPointMap.end())
00217     {
00218         this->mMapIterator = this->mQuadPointToDataAtQuadPointMap.begin();
00219     }
00220 
00221 }
00222 
00223 
00224 
00225 template class ImplicitCardiacMechanicsSolver<IncompressibleNonlinearElasticitySolver<2>,2>;
00226 template class ImplicitCardiacMechanicsSolver<IncompressibleNonlinearElasticitySolver<3>,3>;
00227 template class ImplicitCardiacMechanicsSolver<CompressibleNonlinearElasticitySolver<2>,2>;
00228 template class ImplicitCardiacMechanicsSolver<CompressibleNonlinearElasticitySolver<3>,3>;
00229 
00230