AbstractCardiacMechanicsSolver.cpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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 "AbstractCardiacMechanicsSolver.hpp"
00037 #include "AbstractContractionCellFactory.hpp"
00038 #include "FakeBathContractionModel.hpp"
00039 
00040 template<class ELASTICITY_SOLVER,unsigned DIM>
00041 AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::AbstractCardiacMechanicsSolver(QuadraticMesh<DIM>& rQuadMesh,
00042                                                                                       ElectroMechanicsProblemDefinition<DIM>& rProblemDefinition,
00043                                                                                       std::string outputDirectory)
00044    : ELASTICITY_SOLVER(rQuadMesh,
00045                        rProblemDefinition,
00046                        outputDirectory),
00047      mpMeshPair(NULL),
00048      mCurrentTime(DBL_MAX),
00049      mNextTime(DBL_MAX),
00050      mOdeTimestep(DBL_MAX),
00051      mrElectroMechanicsProblemDefinition(rProblemDefinition)
00052 {
00053 }
00054 
00055 template<class ELASTICITY_SOLVER,unsigned DIM>
00056 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::Initialise()
00057 {
00058     // compute total num quad points
00059     unsigned num_quad_pts_per_element = this->mpQuadratureRule->GetNumQuadPoints();
00060     mTotalQuadPoints = this->mrQuadMesh.GetNumElements()*num_quad_pts_per_element;
00061 
00062     std::vector<ElementAndWeights<DIM> > fine_elements = mpMeshPair->rGetElementsAndWeights();
00063     assert(fine_elements.size()==mTotalQuadPoints);
00064     assert(mpMeshPair!=NULL);
00065 
00066     AbstractContractionCellFactory<DIM>* p_factory = mrElectroMechanicsProblemDefinition.GetContractionCellFactory();
00067 
00068     for (typename AbstractTetrahedralMesh<DIM, DIM>::ElementIterator iter = this->mrQuadMesh.GetElementIteratorBegin();
00069          iter != this->mrQuadMesh.GetElementIteratorEnd();
00070          ++iter)
00071     {
00072         Element<DIM, DIM>& element = *iter;
00073 
00074         if (element.GetOwnership() == true)
00075         {
00076             for(unsigned j=0; j<num_quad_pts_per_element; j++)
00077             {
00078                 unsigned quad_pt_global_index = element.GetIndex()*num_quad_pts_per_element + j;
00079 
00080                 // We construct a set of data to be assigned to each quadrature point
00081                 // this includes a contraction cell model set as bath or by the contraction
00082                 // cell factory.
00083                 DataAtQuadraturePoint data_at_quad_point;
00084                 data_at_quad_point.Stretch = 1.0;
00085                 data_at_quad_point.StretchLastTimeStep = 1.0;
00086 
00087                 if ( mpMeshPair->GetFineMesh().GetElement(fine_elements[quad_pt_global_index].ElementNum)
00088                         ->GetUnsignedAttribute() == HeartRegionCode::GetValidBathId() )
00089                 {
00090                     // Bath
00091                     data_at_quad_point.ContractionModel = new FakeBathContractionModel;
00092                 }
00093                 else
00094                 {
00095                     // Tissue
00096                     data_at_quad_point.ContractionModel = p_factory->CreateContractionCellForElement( &element );
00097                 }
00098                 mQuadPointToDataAtQuadPointMap[quad_pt_global_index] = data_at_quad_point;
00099             }
00100         }
00101     }
00102 
00103     // initialise the iterator to point at the beginning
00104     mMapIterator = mQuadPointToDataAtQuadPointMap.begin();
00105 
00106     // initialise fibre/sheet direction matrix to be the identity, fibres in X-direction, and sheet in XY-plane
00107     mConstantFibreSheetDirections = zero_matrix<double>(DIM,DIM);
00108     for(unsigned i=0; i<DIM; i++)
00109     {
00110         mConstantFibreSheetDirections(i,i) = 1.0;
00111     }
00112 
00113     mpVariableFibreSheetDirections = NULL;
00114 
00115     // Check that we are using the right kind of solver.
00116     for(std::map<unsigned,DataAtQuadraturePoint>::iterator iter = this->mQuadPointToDataAtQuadPointMap.begin();
00117             iter != this->mQuadPointToDataAtQuadPointMap.end();
00118             iter++)
00119     {
00120         if (!IsImplicitSolver() && (*iter).second.ContractionModel->IsStretchRateDependent())
00121         {
00122             EXCEPTION("stretch-rate-dependent contraction model requires an IMPLICIT cardiac mechanics solver.");
00123         }
00124 
00125         if (!IsImplicitSolver() && (*iter).second.ContractionModel->IsStretchDependent())
00126         {
00127             WARN_ONCE_ONLY("stretch-dependent contraction model may require an IMPLICIT cardiac mechanics solver.");
00128         }
00129     }
00130 }
00131 
00132 
00133 template<class ELASTICITY_SOLVER,unsigned DIM>
00134 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::SetFineCoarseMeshPair(FineCoarseMeshPair<DIM>* pMeshPair)
00135 {
00136     assert(pMeshPair!=NULL);
00137     if (pMeshPair->GetCoarseMesh().GetNumElements() != this->mrQuadMesh.GetNumElements())
00138     {
00139         EXCEPTION("When setting a mesh pair into the solver, the coarse mesh of the mesh pair must be the same as the quadratic mesh");
00140     }
00141     mpMeshPair = pMeshPair;
00142 }
00143 
00144 template<class ELASTICITY_SOLVER,unsigned DIM>
00145 AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::~AbstractCardiacMechanicsSolver()
00146 {
00147     for(mMapIterator = mQuadPointToDataAtQuadPointMap.begin();
00148         mMapIterator != mQuadPointToDataAtQuadPointMap.end();
00149         ++mMapIterator)
00150     {
00151         AbstractContractionModel* p_model = mMapIterator->second.ContractionModel;
00152         if (p_model)
00153         {
00154             delete p_model;
00155         }
00156     }
00157 
00158     if(mpVariableFibreSheetDirections)
00159     {
00160         delete mpVariableFibreSheetDirections;
00161     }
00162 }
00163 
00164 
00165 
00166 template<class ELASTICITY_SOLVER,unsigned DIM>
00167 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::SetCalciumAndVoltage(std::vector<double>& rCalciumConcentrations,
00168                                                                                  std::vector<double>& rVoltages)
00169 
00170 {
00171     assert(rCalciumConcentrations.size() == mTotalQuadPoints);
00172     assert(rVoltages.size() == mTotalQuadPoints);
00173 
00174     ContractionModelInputParameters input_parameters;
00175 
00176     for(unsigned i=0; i<rCalciumConcentrations.size(); i++)
00177     {
00178         input_parameters.intracellularCalciumConcentration = rCalciumConcentrations[i];
00179         input_parameters.voltage = rVoltages[i];
00180 
00182         std::map<unsigned,DataAtQuadraturePoint>::iterator iter = mQuadPointToDataAtQuadPointMap.find(i);
00183         if(iter != mQuadPointToDataAtQuadPointMap.end())
00184         {
00185             iter->second.ContractionModel->SetInputParameters(input_parameters);
00186         }
00187     }
00188 }
00189 
00190 
00191 template<class ELASTICITY_SOLVER,unsigned DIM>
00192 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::SetupChangeOfBasisMatrix(unsigned elementIndex,
00193                                                                                      unsigned currentQuadPointGlobalIndex)
00194 {
00195     if(!mpVariableFibreSheetDirections) // constant fibre directions
00196     {
00197         this->mChangeOfBasisMatrix = mConstantFibreSheetDirections;
00198     }
00199     else if(!mFibreSheetDirectionsDefinedByQuadraturePoint) // fibre directions defined for each mechanics mesh element
00200     {
00201         this->mChangeOfBasisMatrix = (*mpVariableFibreSheetDirections)[elementIndex];
00202     }
00203     else // fibre directions defined for each mechanics mesh quadrature point
00204     {
00205         this->mChangeOfBasisMatrix = (*mpVariableFibreSheetDirections)[currentQuadPointGlobalIndex];
00206     }
00207 }
00208 
00209 
00210 
00211 template<class ELASTICITY_SOLVER,unsigned DIM>
00212 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::AddActiveStressAndStressDerivative(c_matrix<double,DIM,DIM>& rC,
00213                                                                                                unsigned elementIndex,
00214                                                                                                unsigned currentQuadPointGlobalIndex,
00215                                                                                                c_matrix<double,DIM,DIM>& rT,
00216                                                                                                FourthOrderTensor<DIM,DIM,DIM,DIM>& rDTdE,
00217                                                                                                bool addToDTdE)
00218 {
00219     for(unsigned i=0; i<DIM; i++)
00220     {
00221         mCurrentElementFibreDirection(i) = this->mChangeOfBasisMatrix(i,0);
00222     }
00223 
00224     //Compute the active tension and add to the stress and stress-derivative
00225     double I4_fibre = inner_prod(mCurrentElementFibreDirection, prod(rC, mCurrentElementFibreDirection));
00226     double lambda_fibre = sqrt(I4_fibre);
00227 
00228     double active_tension = 0;
00229     double d_act_tension_dlam = 0.0;     // Set and used if assembleJacobian==true
00230     double d_act_tension_d_dlamdt = 0.0; // Set and used if assembleJacobian==true
00231 
00232     GetActiveTensionAndTensionDerivs(lambda_fibre, currentQuadPointGlobalIndex, addToDTdE,
00233                                      active_tension, d_act_tension_dlam, d_act_tension_d_dlamdt);
00234 
00235 
00236     double detF = sqrt(Determinant(rC));
00237     rT += (active_tension*detF/I4_fibre)*outer_prod(mCurrentElementFibreDirection,mCurrentElementFibreDirection);
00238 
00239     // amend the stress and dTdE using the active tension
00240     double dTdE_coeff1 = -2*active_tension*detF/(I4_fibre*I4_fibre); // note: I4_fibre*I4_fibre = lam^4
00241     double dTdE_coeff2 = active_tension*detF/I4_fibre;
00242     double dTdE_coeff_s1 = 0.0; // only set non-zero if we apply cross fibre tension (in 2/3D)
00243     double dTdE_coeff_s2 = 0.0; // only set non-zero if we apply cross fibre tension (in 2/3D)
00244     double dTdE_coeff_s3 = 0.0; // only set non-zero if we apply cross fibre tension and implicit (in 2/3D)
00245     double dTdE_coeff_n1 = 0.0; // only set non-zero if we apply cross fibre tension in 3D
00246     double dTdE_coeff_n2 = 0.0; // only set non-zero if we apply cross fibre tension in 3D
00247     double dTdE_coeff_n3 = 0.0; // only set non-zero if we apply cross fibre tension in 3D and implicit
00248 
00249     if(IsImplicitSolver())
00250     {
00251         double dt = mNextTime-mCurrentTime;
00252         //std::cout << "d sigma / d lamda = " << d_act_tension_dlam << ", d sigma / d lamdat = " << d_act_tension_d_dlamdt << "\n" << std::flush;
00253         dTdE_coeff1 += (d_act_tension_dlam + d_act_tension_d_dlamdt/dt)*detF/(lambda_fibre*I4_fibre); // note: I4_fibre*lam = lam^3
00254     }
00255 
00256     bool apply_cross_fibre_tension = (this->mrElectroMechanicsProblemDefinition.GetApplyCrossFibreTension()) && (DIM > 1);
00257     if(apply_cross_fibre_tension)
00258     {
00259         double sheet_cross_fraction = mrElectroMechanicsProblemDefinition.GetSheetTensionFraction();
00260 
00261         for(unsigned i=0; i<DIM; i++)
00262         {
00263             mCurrentElementSheetDirection(i) = this->mChangeOfBasisMatrix(i,1);
00264         }
00265 
00266         double I4_sheet = inner_prod(mCurrentElementSheetDirection, prod(rC, mCurrentElementSheetDirection));
00267 
00268         // amend the stress and dTdE using the active tension
00269         dTdE_coeff_s1 = -2*sheet_cross_fraction*detF*active_tension/(I4_sheet*I4_sheet); // note: I4*I4 = lam^4
00270 
00271         if(IsImplicitSolver())
00272         {
00273             double dt = mNextTime-mCurrentTime;
00274             dTdE_coeff_s3 = sheet_cross_fraction*(d_act_tension_dlam + d_act_tension_d_dlamdt/dt)*detF/(lambda_fibre*I4_sheet); // note: I4*lam = lam^3
00275         }
00276 
00277         rT += sheet_cross_fraction*(active_tension*detF/I4_sheet)*outer_prod(mCurrentElementSheetDirection,mCurrentElementSheetDirection);
00278 
00279         dTdE_coeff_s2 = active_tension*sheet_cross_fraction*detF/I4_sheet;
00280 
00281         if (DIM>2)
00282         {
00283             double sheet_normal_cross_fraction = mrElectroMechanicsProblemDefinition.GetSheetNormalTensionFraction();
00284             for(unsigned i=0; i<DIM; i++)
00285             {
00286                 mCurrentElementSheetNormalDirection(i) = this->mChangeOfBasisMatrix(i,2);
00287             }
00288 
00289             double I4_sheet_normal = inner_prod(mCurrentElementSheetNormalDirection, prod(rC, mCurrentElementSheetNormalDirection));
00290 
00291             dTdE_coeff_n1 =-2*sheet_normal_cross_fraction*detF*active_tension/(I4_sheet_normal*I4_sheet_normal); // note: I4*I4 = lam^4
00292 
00293             rT += sheet_normal_cross_fraction*(active_tension*detF/I4_sheet_normal)*outer_prod(mCurrentElementSheetNormalDirection,mCurrentElementSheetNormalDirection);
00294 
00295             dTdE_coeff_n2 = active_tension*sheet_normal_cross_fraction*detF/I4_sheet_normal;
00296             if(IsImplicitSolver())
00297             {
00298                 double dt = mNextTime-mCurrentTime;
00299                 dTdE_coeff_n3 = sheet_normal_cross_fraction*(d_act_tension_dlam + d_act_tension_d_dlamdt/dt)*detF/(lambda_fibre*I4_sheet_normal); // note: I4*lam = lam^3
00300             }
00301         }
00302     }
00303 
00304 
00305     if(addToDTdE)
00306     {
00307         c_matrix<double,DIM,DIM> invC = Inverse(rC);
00308 
00309         for (unsigned M=0; M<DIM; M++)
00310         {
00311             for (unsigned N=0; N<DIM; N++)
00312             {
00313                 for (unsigned P=0; P<DIM; P++)
00314                 {
00315                     for (unsigned Q=0; Q<DIM; Q++)
00316                     {
00317                         rDTdE(M,N,P,Q) +=   dTdE_coeff1 * mCurrentElementFibreDirection(M)
00318                                                         * mCurrentElementFibreDirection(N)
00319                                                         * mCurrentElementFibreDirection(P)
00320                                                         * mCurrentElementFibreDirection(Q)
00321 
00322                                          +  dTdE_coeff2 * mCurrentElementFibreDirection(M)
00323                                                         * mCurrentElementFibreDirection(N)
00324                                                         * invC(P,Q);
00325                         if(apply_cross_fibre_tension)
00326                         {
00327                             rDTdE(M,N,P,Q) += dTdE_coeff_s1 * mCurrentElementSheetDirection(M)
00328                                                             * mCurrentElementSheetDirection(N)
00329                                                             * mCurrentElementSheetDirection(P)
00330                                                             * mCurrentElementSheetDirection(Q)
00331 
00332                                            +  dTdE_coeff_s2 * mCurrentElementSheetDirection(M)
00333                                                             * mCurrentElementSheetDirection(N)
00334                                                             * invC(P,Q)
00335 
00336                                            + dTdE_coeff_s3 * mCurrentElementSheetDirection(M)
00337                                                            * mCurrentElementSheetDirection(N)
00338                                                            * mCurrentElementFibreDirection(P)
00339                                                            * mCurrentElementFibreDirection(Q);
00340                             if (DIM>2)
00341                             {
00342                                 rDTdE(M,N,P,Q) += dTdE_coeff_n1 * mCurrentElementSheetNormalDirection(M)
00343                                                                 * mCurrentElementSheetNormalDirection(N)
00344                                                                 * mCurrentElementSheetNormalDirection(P)
00345                                                                 * mCurrentElementSheetNormalDirection(Q)
00346 
00347                                                 + dTdE_coeff_n2 * mCurrentElementSheetNormalDirection(M)
00348                                                                 * mCurrentElementSheetNormalDirection(N)
00349                                                                 * invC(P,Q)
00350 
00351                                                 + dTdE_coeff_n3 * mCurrentElementSheetNormalDirection(M)
00352                                                                 * mCurrentElementSheetNormalDirection(N)
00353                                                                 * mCurrentElementFibreDirection(P)
00354                                                                 * mCurrentElementFibreDirection(Q);
00355                             }
00356                         }
00357                     }
00358                 }
00359             }
00360         }
00361     }
00362 
00363 //    ///\todo #2180 The code below applies a cross fibre tension in the 2D case. Things that need doing:
00364 //    // * Refactor the common code between the block below and the block above to avoid duplication.
00365 //    // * Handle the 3D case.
00366 //    if(this->mrElectroMechanicsProblemDefinition.GetApplyCrossFibreTension() && DIM > 1)
00367 //    {
00368 //        double sheet_cross_fraction = mrElectroMechanicsProblemDefinition.GetSheetTensionFraction();
00369 //
00370 //        for(unsigned i=0; i<DIM; i++)
00371 //        {
00372 //            mCurrentElementSheetDirection(i) = this->mChangeOfBasisMatrix(i,1);
00373 //        }
00374 //
00375 //        double I4_sheet = inner_prod(mCurrentElementSheetDirection, prod(rC, mCurrentElementSheetDirection));
00376 //
00377 //        // amend the stress and dTdE using the active tension
00378 //        double dTdE_coeff_s1 = -2*sheet_cross_fraction*detF*active_tension/(I4_sheet*I4_sheet); // note: I4*I4 = lam^4
00379 //
00380 //        ///\todo #2180 The code below is specific to the implicit cardiac mechanics solver. Currently
00381 //        // the cross-fibre code is only tested using the explicit solver so the code below fails coverage.
00382 //        // This will need to be added back in once an implicit test is in place.
00383 //        double lambda_sheet = sqrt(I4_sheet);
00384 //        if(IsImplicitSolver())
00385 //        {
00386 //           double dt = mNextTime-mCurrentTime;
00387 //           dTdE_coeff_s1 += (d_act_tension_dlam + d_act_tension_d_dlamdt/dt)/(lambda_sheet*I4_sheet); // note: I4*lam = lam^3
00388 //        }
00389 //
00390 //        rT += sheet_cross_fraction*(active_tension*detF/I4_sheet)*outer_prod(mCurrentElementSheetDirection,mCurrentElementSheetDirection);
00391 //
00392 //        double dTdE_coeff_s2 = active_tension*detF/I4_sheet;
00393 //        if(addToDTdE)
00394 //        {
00395 //           for (unsigned M=0; M<DIM; M++)
00396 //           {
00397 //               for (unsigned N=0; N<DIM; N++)
00398 //               {
00399 //                   for (unsigned P=0; P<DIM; P++)
00400 //                   {
00401 //                       for (unsigned Q=0; Q<DIM; Q++)
00402 //                       {
00403 //                           rDTdE(M,N,P,Q) +=  dTdE_coeff_s1 * mCurrentElementSheetDirection(M)
00404 //                                                            * mCurrentElementSheetDirection(N)
00405 //                                                            * mCurrentElementSheetDirection(P)
00406 //                                                            * mCurrentElementSheetDirection(Q)
00407 //
00408 //                                           +  dTdE_coeff_s2 * mCurrentElementFibreDirection(M)
00409 //                                                            * mCurrentElementFibreDirection(N)
00410 //                                                            * invC(P,Q);
00411 //
00412 //                       }
00413 //                   }
00414 //               }
00415 //           }
00416 //        }
00417 //    }
00418 }
00419 
00420 
00421 template<class ELASTICITY_SOLVER,unsigned DIM>
00422 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::ComputeDeformationGradientAndStretchInEachElement(
00423     std::vector<c_matrix<double,DIM,DIM> >& rDeformationGradients,
00424     std::vector<double>& rStretches)
00425 {
00426     assert(rStretches.size()==this->mrQuadMesh.GetNumElements());
00427 
00428     // this will only work currently if the coarse mesh fibre info is defined per element, not per quad point
00429     assert(!mpVariableFibreSheetDirections || !mFibreSheetDirectionsDefinedByQuadraturePoint);
00430 
00431     static c_matrix<double,DIM,NUM_VERTICES_PER_ELEMENT> element_current_displacements;
00432     static c_matrix<double,DIM,NUM_VERTICES_PER_ELEMENT> grad_lin_phi;
00433     static c_matrix<double,DIM,DIM> F;      // the deformation gradient, F = dx/dX, F_{iM} = dx_i/dX_M
00434 
00435     static c_matrix<double,DIM,DIM> jacobian;
00436     static c_matrix<double,DIM,DIM> inverse_jacobian;
00437     double jacobian_determinant;
00438     ChastePoint<DIM> quadrature_point; // not needed, but has to be passed in
00439 
00440     // loop over all the elements
00441     for(unsigned elem_index=0; elem_index<this->mrQuadMesh.GetNumElements(); elem_index++)
00442     {
00443         Element<DIM,DIM>* p_elem = this->mrQuadMesh.GetElement(elem_index);
00444 
00445         // get the fibre direction for this element
00446         SetupChangeOfBasisMatrix(elem_index, 0); // 0 is quad index, and doesn't matter as checked that fibres not defined by quad pt above.
00447         for(unsigned i=0; i<DIM; i++)
00448         {
00449             mCurrentElementFibreDirection(i) = this->mChangeOfBasisMatrix(i,0);
00450         }
00451 
00452         // get the displacement at this element
00453         for (unsigned II=0; II<NUM_VERTICES_PER_ELEMENT; II++)
00454         {
00455             for (unsigned JJ=0; JJ<DIM; JJ++)
00456             {
00457                 // mProblemDimension = DIM for compressible elasticity and DIM+1 for incompressible elasticity
00458                 element_current_displacements(JJ,II) = this->mCurrentSolution[this->mProblemDimension*p_elem->GetNodeGlobalIndex(II) + JJ];
00459             }
00460         }
00461 
00462         // set up the linear basis functions
00463         this->mrQuadMesh.GetInverseJacobianForElement(elem_index, jacobian, jacobian_determinant, inverse_jacobian);
00464         LinearBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(quadrature_point, inverse_jacobian, grad_lin_phi);
00465 
00466         F = identity_matrix<double>(DIM,DIM);
00467 
00468         // loop over the vertices and interpolate F, the deformation gradient
00469         // (note: could use matrix-mult if this becomes inefficient
00470         for (unsigned node_index=0; node_index<NUM_VERTICES_PER_ELEMENT; node_index++)
00471         {
00472             for (unsigned i=0; i<DIM; i++)
00473             {
00474                 for (unsigned M=0; M<DIM; M++)
00475                 {
00476                     F(i,M) += grad_lin_phi(M,node_index)*element_current_displacements(i,node_index);
00477                 }
00478             }
00479         }
00480 
00481         rDeformationGradients[elem_index] = F;
00482 
00483         // compute and save the stretch: m^T C m = ||Fm||
00484         c_vector<double,DIM> deformed_fibre = prod(F, mCurrentElementFibreDirection);
00485         rStretches[elem_index] = norm_2(deformed_fibre);
00486     }
00487 }
00488 
00489 
00490 template<class ELASTICITY_SOLVER,unsigned DIM>
00491 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::SetVariableFibreSheetDirections(const FileFinder& rOrthoFile, bool definedPerQuadraturePoint)
00492 {
00493     mFibreSheetDirectionsDefinedByQuadraturePoint = definedPerQuadraturePoint;
00494 
00495     FibreReader<DIM> reader(rOrthoFile, ORTHO);
00496 
00497     unsigned num_entries = reader.GetNumLinesOfData();
00498 
00499     if (!mFibreSheetDirectionsDefinedByQuadraturePoint && (num_entries!=this->mrQuadMesh.GetNumElements()) )
00500     {
00501         EXCEPTION("Number of entries defined at top of file " << rOrthoFile.GetAbsolutePath() <<
00502                   " does not match number of elements in the mesh, " << "found " <<  num_entries <<
00503                   ", expected " << this->mrQuadMesh.GetNumElements());
00504     }
00505 
00506     if (mFibreSheetDirectionsDefinedByQuadraturePoint && (num_entries!=mTotalQuadPoints) )
00507     {
00508         EXCEPTION("Number of entries defined at top of file " << rOrthoFile.GetAbsolutePath() <<
00509                   " does not match number of quadrature points defined, " << "found " <<  num_entries <<
00510                   ", expected " << mTotalQuadPoints);
00511     }
00512 
00513     mpVariableFibreSheetDirections = new std::vector<c_matrix<double,DIM,DIM> >(num_entries, zero_matrix<double>(DIM,DIM));
00514     for(unsigned index=0; index<num_entries; index++)
00515     {
00516         reader.GetFibreSheetAndNormalMatrix(index, (*mpVariableFibreSheetDirections)[index] );
00517     }
00518 }
00519 
00520 template<class ELASTICITY_SOLVER,unsigned DIM>
00521 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::SetConstantFibreSheetDirections(const c_matrix<double,DIM,DIM>& rFibreSheetMatrix)
00522 {
00523     mConstantFibreSheetDirections = rFibreSheetMatrix;
00524     // check orthogonality
00525     c_matrix<double,DIM,DIM>  temp = prod(trans(rFibreSheetMatrix),rFibreSheetMatrix);
00526     for(unsigned i=0; i<DIM; i++)
00527     {
00528         for(unsigned j=0; j<DIM; j++)
00529         {
00530             double val = (i==j ? 1.0 : 0.0);
00531             if(fabs(temp(i,j)-val)>1e-4)
00532             {
00533                 EXCEPTION("The given fibre-sheet matrix, " << rFibreSheetMatrix << ", is not orthogonal");
00534             }
00535         }
00536     }
00537 }
00538 
00539 template class AbstractCardiacMechanicsSolver<IncompressibleNonlinearElasticitySolver<2>,2>;
00540 template class AbstractCardiacMechanicsSolver<IncompressibleNonlinearElasticitySolver<3>,3>;
00541 template class AbstractCardiacMechanicsSolver<CompressibleNonlinearElasticitySolver<2>,2>;
00542 template class AbstractCardiacMechanicsSolver<CompressibleNonlinearElasticitySolver<3>,3>;
00543 
00544 

Generated by  doxygen 1.6.2