AbstractCardiacMechanicsSolver.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #ifndef ABSTRACTCARDIACMECHANICSSOLVER_HPP_
00030 #define ABSTRACTCARDIACMECHANICSSOLVER_HPP_
00031 
00032 #include "NonlinearElasticitySolver.hpp"
00033 #include "NashHunterPoleZeroLaw.hpp"
00034 #include "QuadraticBasisFunction.hpp" // not included in NonlinearElasticitySolver.hpp, just the cpp
00035 #include "LinearBasisFunction.hpp"
00036 #include "AbstractContractionModel.hpp"
00037 #include "FibreReader.hpp"
00038 
00039 #include "AbstractCardiacMechanicsSolverInterface.hpp"
00040 
00053 template<class ELASTICITY_SOLVER, unsigned DIM>
00054 class AbstractCardiacMechanicsSolver : public ELASTICITY_SOLVER, public AbstractCardiacMechanicsSolverInterface<DIM>
00055 {
00056 protected:
00057     static const unsigned NUM_VERTICES_PER_ELEMENT = ELASTICITY_SOLVER::NUM_VERTICES_PER_ELEMENT; 
00064     std::vector<AbstractContractionModel*> mContractionModelSystems;
00065 
00071     std::vector<double> mStretches;
00072 
00074     unsigned mTotalQuadPoints;
00075 
00077     double mCurrentTime;
00079     double mNextTime;
00081     double mOdeTimestep;
00082 
00084     c_matrix<double,DIM,DIM> mConstantFibreSheetDirections;
00085 
00090     std::vector<c_matrix<double,DIM,DIM> >* mpVariableFibreSheetDirections;
00091     
00096     bool mFibreSheetDirectionsDefinedByQuadraturePoint;
00097 
00099     c_matrix<double,DIM,DIM>* mpCurrentElementFibreSheetMatrix;
00101     c_vector<double,DIM> mCurrentElementFibreDirection;
00102 
00107     virtual bool IsImplicitSolver()=0;
00108 
00127     void ComputeStressAndStressDerivative(AbstractMaterialLaw<DIM>* pMaterialLaw,
00128                                           c_matrix<double,DIM,DIM>& rC, 
00129                                           c_matrix<double,DIM,DIM>& rInvC, 
00130                                           double pressure,
00131                                           unsigned elementIndex,
00132                                           unsigned currentQuadPointGlobalIndex,
00133                                           c_matrix<double,DIM,DIM>& rT,
00134                                           FourthOrderTensor<DIM,DIM,DIM,DIM>& rDTdE,
00135                                           bool computeDTdE);
00136     
00137 
00138 
00139 
00152     virtual void GetActiveTensionAndTensionDerivs(double currentFibreStretch,
00153                                                   unsigned currentQuadPointGlobalIndex,
00154                                                   bool assembleJacobian,
00155                                                   double& rActiveTension,
00156                                                   double& rDerivActiveTensionWrtLambda,
00157                                                   double& rDerivActiveTensionWrtDLambdaDt)=0;
00158 public:
00168     AbstractCardiacMechanicsSolver(QuadraticMesh<DIM>* pQuadMesh,
00169                                    std::string outputDirectory,
00170                                    std::vector<unsigned>& rFixedNodes,
00171                                    AbstractMaterialLaw<DIM>* pMaterialLaw);
00172 
00173 
00177     ~AbstractCardiacMechanicsSolver();
00178     
00179     
00181     unsigned GetTotalNumQuadPoints()
00182     {
00183         return mTotalQuadPoints;
00184     }
00185 
00187     virtual GaussianQuadratureRule<DIM>* GetQuadratureRule()
00188     {
00189         return this->mpQuadratureRule;
00190     }
00191 
00192 
00199     void SetConstantFibreSheetDirections(const c_matrix<double,DIM,DIM>& rFibreSheetMatrix);
00200 
00212     void SetVariableFibreSheetDirections(std::string orthoFile, bool definedPerQuadraturePoint);
00213 
00214 
00215 
00228     void SetCalciumAndVoltage(std::vector<double>& rCalciumConcentrations,
00229                               std::vector<double>& rVoltages);
00230 
00238     virtual void Solve(double time, double nextTime, double odeTimestep)=0;
00239     
00240     
00241 
00261     void ComputeDeformationGradientAndStretchInEachElement(std::vector<c_matrix<double,DIM,DIM> >& rDeformationGradients,
00262                                                            std::vector<double>& rStretches);
00263 };
00264 
00265 
00266 template<class ELASTICITY_SOLVER,unsigned DIM>
00267 AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::AbstractCardiacMechanicsSolver(QuadraticMesh<DIM>* pQuadMesh,
00268                                                                                       std::string outputDirectory,
00269                                                                                       std::vector<unsigned>& rFixedNodes,
00270                                                                                       AbstractMaterialLaw<DIM>* pMaterialLaw)
00271    : ELASTICITY_SOLVER(pQuadMesh,
00272                        pMaterialLaw,
00273                        zero_vector<double>(DIM),
00274                        DOUBLE_UNSET,
00275                        outputDirectory,
00276                        rFixedNodes),
00277      mCurrentTime(DBL_MAX),
00278      mNextTime(DBL_MAX),
00279      mOdeTimestep(DBL_MAX)
00280 {
00281     // compute total num quad points
00282     mTotalQuadPoints = pQuadMesh->GetNumElements()*this->mpQuadratureRule->GetNumQuadPoints();
00283 
00284     // initialise the store of fibre stretches
00285     mStretches.resize(mTotalQuadPoints, 1.0);
00286 
00287     // initialise fibre/sheet direction matrix to be the identity, fibres in X-direction, and sheet in XY-plane
00288     mConstantFibreSheetDirections = zero_matrix<double>(DIM,DIM);
00289     for(unsigned i=0; i<DIM; i++)
00290     {
00291         mConstantFibreSheetDirections(i,i) = 1.0;
00292     }
00293 
00294     mpVariableFibreSheetDirections = NULL;
00295 }
00296 
00297 
00298 template<class ELASTICITY_SOLVER,unsigned DIM>
00299 AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::~AbstractCardiacMechanicsSolver()
00300 {
00301     if(mpVariableFibreSheetDirections)
00302     {
00303         delete mpVariableFibreSheetDirections;
00304     }
00305 }
00306 
00307 
00308 
00309 template<class ELASTICITY_SOLVER,unsigned DIM>
00310 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::SetCalciumAndVoltage(std::vector<double>& rCalciumConcentrations,
00311                                                                                  std::vector<double>& rVoltages)
00312 
00313 {
00314     assert(rCalciumConcentrations.size() == this->mTotalQuadPoints);
00315     assert(rVoltages.size() == this->mTotalQuadPoints);
00316 
00317     ContractionModelInputParameters input_parameters;
00318 
00319     for(unsigned i=0; i<rCalciumConcentrations.size(); i++)
00320     {
00321         input_parameters.intracellularCalciumConcentration = rCalciumConcentrations[i];
00322         input_parameters.voltage = rVoltages[i];
00323 
00324         mContractionModelSystems[i]->SetInputParameters(input_parameters);
00325     }
00326 }
00327 
00328 template<class ELASTICITY_SOLVER,unsigned DIM>
00329 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::ComputeStressAndStressDerivative(AbstractMaterialLaw<DIM>* pMaterialLaw,
00330                                                                                              c_matrix<double,DIM,DIM>& rC,
00331                                                                                              c_matrix<double,DIM,DIM>& rInvC,
00332                                                                                              double pressure,
00333                                                                                              unsigned elementIndex,
00334                                                                                              unsigned currentQuadPointGlobalIndex,
00335                                                                                              c_matrix<double,DIM,DIM>& rT,
00336                                                                                              FourthOrderTensor<DIM,DIM,DIM,DIM>& rDTdE,
00337                                                                                              bool assembleJacobian)
00338 {
00339     if(!mpVariableFibreSheetDirections) // constant fibre directions
00340     {
00341         mpCurrentElementFibreSheetMatrix = &mConstantFibreSheetDirections;
00342     }
00343     else if(!mFibreSheetDirectionsDefinedByQuadraturePoint) // fibre directions defined for each mechanics mesh element
00344     {
00345         mpCurrentElementFibreSheetMatrix = &(*mpVariableFibreSheetDirections)[elementIndex];
00346     }
00347     else // fibre directions defined for each mechanics mesh quadrature point
00348     {
00349         mpCurrentElementFibreSheetMatrix = &(*mpVariableFibreSheetDirections)[currentQuadPointGlobalIndex];
00350     }
00351         
00352     for(unsigned i=0; i<DIM; i++)
00353     {
00354         mCurrentElementFibreDirection(i) = (*mpCurrentElementFibreSheetMatrix)(i,0);
00355     }
00356 
00357     // 1. Compute T and dTdE for the PASSIVE part of the strain energy.
00358     pMaterialLaw->SetChangeOfBasisMatrix(*mpCurrentElementFibreSheetMatrix);
00359     pMaterialLaw->ComputeStressAndStressDerivative(rC,rInvC,pressure,rT,rDTdE,assembleJacobian);
00360 
00361     // 2. Compute the active tension and add to the stress and stress-derivative
00362     double I4 = inner_prod(mCurrentElementFibreDirection, prod(rC, mCurrentElementFibreDirection));
00363     double lambda = sqrt(I4);
00364 
00365     double active_tension = 0;
00366     double d_act_tension_dlam = 0.0;     // Set and used if assembleJacobian==true
00367     double d_act_tension_d_dlamdt = 0.0; // Set and used if assembleJacobian==true
00368 
00369     GetActiveTensionAndTensionDerivs(lambda, currentQuadPointGlobalIndex, assembleJacobian,
00370                                      active_tension, d_act_tension_dlam, d_act_tension_d_dlamdt);
00371 
00372     // amend the stress and dTdE using the active tension
00373     double dTdE_coeff = -2*active_tension/(I4*I4); // note: I4*I4 = lam^4
00374     if(IsImplicitSolver())
00375     {
00376         double dt = mNextTime-mCurrentTime;
00377         dTdE_coeff += (d_act_tension_dlam + d_act_tension_d_dlamdt/dt)/(lambda*I4); // note: I4*lam = lam^3
00378     }
00379 
00380     rT += (active_tension/I4)*outer_prod(mCurrentElementFibreDirection,mCurrentElementFibreDirection);
00381 
00382     if(assembleJacobian)
00383     {
00384         for (unsigned M=0; M<DIM; M++)
00385         {
00386             for (unsigned N=0; N<DIM; N++)
00387             {
00388                 for (unsigned P=0; P<DIM; P++)
00389                 {
00390                     for (unsigned Q=0; Q<DIM; Q++)
00391                     {
00392                         rDTdE(M,N,P,Q) +=  dTdE_coeff * mCurrentElementFibreDirection(M)
00393                                                       * mCurrentElementFibreDirection(N)
00394                                                       * mCurrentElementFibreDirection(P)
00395                                                       * mCurrentElementFibreDirection(Q);
00396                     }
00397                 }
00398             }
00399         }
00400     }
00401 }
00402 
00403 
00404 
00405 
00406 template<class ELASTICITY_SOLVER,unsigned DIM>
00407 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::ComputeDeformationGradientAndStretchInEachElement(
00408     std::vector<c_matrix<double,DIM,DIM> >& rDeformationGradients,
00409     std::vector<double>& rStretches)
00410 {
00411     assert(rStretches.size()==this->mpQuadMesh->GetNumElements());
00412     
00413     // this will only work currently if the coarse mesh fibre info is defined per element, not per quad point 
00414     assert(!mpVariableFibreSheetDirections || !mFibreSheetDirectionsDefinedByQuadraturePoint);
00415    
00416     static c_matrix<double,DIM,NUM_VERTICES_PER_ELEMENT> element_current_displacements;
00417     static c_matrix<double,DIM,NUM_VERTICES_PER_ELEMENT> grad_lin_phi;
00418     static c_matrix<double,DIM,DIM> F;      // the deformation gradient, F = dx/dX, F_{iM} = dx_i/dX_M
00419 
00420     static c_matrix<double,DIM,DIM> jacobian;
00421     static c_matrix<double,DIM,DIM> inverse_jacobian;
00422     double jacobian_determinant;
00423     ChastePoint<DIM> quadrature_point; // not needed, but has to be passed in  
00424     
00425     // loop over all the elements
00426     for(unsigned elem_index=0; elem_index<this->mpQuadMesh->GetNumElements(); elem_index++)
00427     {
00428         Element<DIM,DIM>* p_elem = this->mpQuadMesh->GetElement(elem_index);
00429 
00430         // get the fibre direction for this element
00431         mpCurrentElementFibreSheetMatrix = mpVariableFibreSheetDirections ? &(*mpVariableFibreSheetDirections)[elem_index] : &mConstantFibreSheetDirections;
00432         for(unsigned i=0; i<DIM; i++)
00433         {
00434             mCurrentElementFibreDirection(i) = (*mpCurrentElementFibreSheetMatrix)(i,0);
00435         }
00436         
00437         // get the displacement at this element
00438         for (unsigned II=0; II<NUM_VERTICES_PER_ELEMENT; II++)
00439         {
00440             for (unsigned JJ=0; JJ<DIM; JJ++)
00441             {
00442                 element_current_displacements(JJ,II) = this->mCurrentSolution[DIM*p_elem->GetNodeGlobalIndex(II) + JJ];
00443             }
00444         }
00445 
00446         // set up the linear basis functions
00447         this->mpQuadMesh->GetInverseJacobianForElement(elem_index, jacobian, jacobian_determinant, inverse_jacobian);
00448         LinearBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(quadrature_point, inverse_jacobian, grad_lin_phi);
00449         
00450         F = identity_matrix<double>(DIM,DIM); 
00451 
00452         // loop over the vertices and interpolate F, the deformation gradient
00453         // (note: could use matrix-mult if this becomes inefficient
00454         for (unsigned node_index=0; node_index<NUM_VERTICES_PER_ELEMENT; node_index++)
00455         {
00456             for (unsigned i=0; i<DIM; i++)
00457             {
00458                 for (unsigned M=0; M<DIM; M++)
00459                 {
00460                     F(i,M) += grad_lin_phi(M,node_index)*element_current_displacements(i,node_index);
00461                 }
00462             }
00463         }
00464 
00465         rDeformationGradients[elem_index] = F;
00466         
00467         // compute and save the stretch: m^T C m = ||Fm||
00468         c_vector<double,DIM> deformed_fibre = prod(F, mCurrentElementFibreDirection);
00469         rStretches[elem_index] = norm_2(deformed_fibre);
00470     }
00471 }
00472 
00473 
00474 
00475 
00476 template<class ELASTICITY_SOLVER,unsigned DIM>
00477 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::SetVariableFibreSheetDirections(std::string orthoFile, bool definedPerQuadraturePoint)
00478 {
00479     mFibreSheetDirectionsDefinedByQuadraturePoint = definedPerQuadraturePoint;
00480     
00481     FileFinder finder(orthoFile, RelativeTo::ChasteSourceRoot);
00482     FibreReader<DIM> reader(finder, ORTHO);
00483     
00484     unsigned num_entries = reader.GetNumLinesOfData();
00485 
00486     if(!mFibreSheetDirectionsDefinedByQuadraturePoint && (num_entries!=this->mpQuadMesh->GetNumElements()) )
00487     {
00488         std::stringstream ss;
00489         ss << "Number of entries defined at top of file " << orthoFile << " does not match number of elements in the mesh, "
00490            << "found " <<  num_entries << ", expected " << this->mpQuadMesh->GetNumElements();
00491         EXCEPTION(ss.str());
00492     }
00493 
00494     if(mFibreSheetDirectionsDefinedByQuadraturePoint && (num_entries!=mTotalQuadPoints) )
00495     {
00496         std::stringstream ss;
00497         ss << "Number of entries defined at top of file " << orthoFile << " does not match number of quadrature points defined, "
00498            << "found " <<  num_entries << ", expected " << mTotalQuadPoints;
00499         EXCEPTION(ss.str());
00500     }
00501     
00502     mpVariableFibreSheetDirections = new std::vector<c_matrix<double,DIM,DIM> >(num_entries, zero_matrix<double>(DIM,DIM));
00503     for(unsigned index=0; index<num_entries; index++)
00504     {
00505         reader.GetNextFibreSheetAndNormalMatrix( (*mpVariableFibreSheetDirections)[index] );
00506     }
00507 }
00508 
00509 
00510 
00511 template<class ELASTICITY_SOLVER,unsigned DIM>
00512 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::SetConstantFibreSheetDirections(const c_matrix<double,DIM,DIM>& rFibreSheetMatrix)
00513 {
00514     mConstantFibreSheetDirections = rFibreSheetMatrix;
00515     // check orthogonality
00516     c_matrix<double,DIM,DIM>  temp = prod(trans(rFibreSheetMatrix),rFibreSheetMatrix);
00517     for(unsigned i=0; i<DIM; i++)
00518     {
00519         for(unsigned j=0; j<DIM; j++)
00520         {
00521             double val = (i==j ? 1.0 : 0.0);
00522             if(fabs(temp(i,j)-val)>1e-4)
00523             {
00524                 std::stringstream string_stream;
00525                 string_stream << "The given fibre-sheet matrix, " << rFibreSheetMatrix << ", is not orthogonal";
00526                 EXCEPTION(string_stream.str());
00527             }
00528         }
00529     }
00530 }
00531 
00532 
00533 #endif /*ABSTRACTCARDIACMECHANICSSOLVER_HPP_*/

Generated on Tue May 31 14:31:42 2011 for Chaste by  doxygen 1.5.5