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
00029 #ifndef ABSTRACTCARDIACMECHANICSSOLVER_HPP_
00030 #define ABSTRACTCARDIACMECHANICSSOLVER_HPP_
00031
00032 #include "IncompressibleNonlinearElasticitySolver.hpp"
00033 #include "CompressibleNonlinearElasticitySolver.hpp"
00034 #include "QuadraticBasisFunction.hpp"
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:
00166 AbstractCardiacMechanicsSolver(QuadraticMesh<DIM>& rQuadMesh,
00167 SolidMechanicsProblemDefinition<DIM>& rProblemDefinition,
00168 std::string outputDirectory);
00169
00173 ~AbstractCardiacMechanicsSolver();
00174
00175
00177 unsigned GetTotalNumQuadPoints()
00178 {
00179 return mTotalQuadPoints;
00180 }
00181
00183 virtual GaussianQuadratureRule<DIM>* GetQuadratureRule()
00184 {
00185 return this->mpQuadratureRule;
00186 }
00187
00188
00195 void SetConstantFibreSheetDirections(const c_matrix<double,DIM,DIM>& rFibreSheetMatrix);
00196
00208 void SetVariableFibreSheetDirections(std::string orthoFile, bool definedPerQuadraturePoint);
00209
00210
00211
00224 void SetCalciumAndVoltage(std::vector<double>& rCalciumConcentrations,
00225 std::vector<double>& rVoltages);
00226
00234 virtual void Solve(double time, double nextTime, double odeTimestep)=0;
00235
00236
00237
00257 void ComputeDeformationGradientAndStretchInEachElement(std::vector<c_matrix<double,DIM,DIM> >& rDeformationGradients,
00258 std::vector<double>& rStretches);
00259 };
00260
00261
00262 template<class ELASTICITY_SOLVER,unsigned DIM>
00263 AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::AbstractCardiacMechanicsSolver(QuadraticMesh<DIM>& rQuadMesh,
00264 SolidMechanicsProblemDefinition<DIM>& rProblemDefinition,
00265 std::string outputDirectory)
00266 : ELASTICITY_SOLVER(rQuadMesh,
00267 rProblemDefinition,
00268 outputDirectory),
00269 mCurrentTime(DBL_MAX),
00270 mNextTime(DBL_MAX),
00271 mOdeTimestep(DBL_MAX)
00272 {
00273
00274 mTotalQuadPoints = rQuadMesh.GetNumElements()*this->mpQuadratureRule->GetNumQuadPoints();
00275
00276
00277 mStretches.resize(mTotalQuadPoints, 1.0);
00278
00279
00280 mConstantFibreSheetDirections = zero_matrix<double>(DIM,DIM);
00281 for(unsigned i=0; i<DIM; i++)
00282 {
00283 mConstantFibreSheetDirections(i,i) = 1.0;
00284 }
00285
00286 mpVariableFibreSheetDirections = NULL;
00287 }
00288
00289
00290 template<class ELASTICITY_SOLVER,unsigned DIM>
00291 AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::~AbstractCardiacMechanicsSolver()
00292 {
00293 if(mpVariableFibreSheetDirections)
00294 {
00295 delete mpVariableFibreSheetDirections;
00296 }
00297 }
00298
00299
00300
00301 template<class ELASTICITY_SOLVER,unsigned DIM>
00302 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::SetCalciumAndVoltage(std::vector<double>& rCalciumConcentrations,
00303 std::vector<double>& rVoltages)
00304
00305 {
00306 assert(rCalciumConcentrations.size() == this->mTotalQuadPoints);
00307 assert(rVoltages.size() == this->mTotalQuadPoints);
00308
00309 ContractionModelInputParameters input_parameters;
00310
00311 for(unsigned i=0; i<rCalciumConcentrations.size(); i++)
00312 {
00313 input_parameters.intracellularCalciumConcentration = rCalciumConcentrations[i];
00314 input_parameters.voltage = rVoltages[i];
00315
00316 mContractionModelSystems[i]->SetInputParameters(input_parameters);
00317 }
00318 }
00319
00320 template<class ELASTICITY_SOLVER,unsigned DIM>
00321 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::ComputeStressAndStressDerivative(AbstractMaterialLaw<DIM>* pMaterialLaw,
00322 c_matrix<double,DIM,DIM>& rC,
00323 c_matrix<double,DIM,DIM>& rInvC,
00324 double pressure,
00325 unsigned elementIndex,
00326 unsigned currentQuadPointGlobalIndex,
00327 c_matrix<double,DIM,DIM>& rT,
00328 FourthOrderTensor<DIM,DIM,DIM,DIM>& rDTdE,
00329 bool assembleJacobian)
00330 {
00331 if(!mpVariableFibreSheetDirections)
00332 {
00333 mpCurrentElementFibreSheetMatrix = &mConstantFibreSheetDirections;
00334 }
00335 else if(!mFibreSheetDirectionsDefinedByQuadraturePoint)
00336 {
00337 mpCurrentElementFibreSheetMatrix = &(*mpVariableFibreSheetDirections)[elementIndex];
00338 }
00339 else
00340 {
00341 mpCurrentElementFibreSheetMatrix = &(*mpVariableFibreSheetDirections)[currentQuadPointGlobalIndex];
00342 }
00343
00344 for(unsigned i=0; i<DIM; i++)
00345 {
00346 mCurrentElementFibreDirection(i) = (*mpCurrentElementFibreSheetMatrix)(i,0);
00347 }
00348
00349
00350 pMaterialLaw->SetChangeOfBasisMatrix(*mpCurrentElementFibreSheetMatrix);
00351 pMaterialLaw->ComputeStressAndStressDerivative(rC,rInvC,pressure,rT,rDTdE,assembleJacobian);
00352
00353
00354 double I4 = inner_prod(mCurrentElementFibreDirection, prod(rC, mCurrentElementFibreDirection));
00355 double lambda = sqrt(I4);
00356
00357 double active_tension = 0;
00358 double d_act_tension_dlam = 0.0;
00359 double d_act_tension_d_dlamdt = 0.0;
00360
00361 GetActiveTensionAndTensionDerivs(lambda, currentQuadPointGlobalIndex, assembleJacobian,
00362 active_tension, d_act_tension_dlam, d_act_tension_d_dlamdt);
00363
00364
00365 double dTdE_coeff = -2*active_tension/(I4*I4);
00366 if(IsImplicitSolver())
00367 {
00368 double dt = mNextTime-mCurrentTime;
00369 dTdE_coeff += (d_act_tension_dlam + d_act_tension_d_dlamdt/dt)/(lambda*I4);
00370 }
00371
00372 rT += (active_tension/I4)*outer_prod(mCurrentElementFibreDirection,mCurrentElementFibreDirection);
00373
00374 if(assembleJacobian)
00375 {
00376 for (unsigned M=0; M<DIM; M++)
00377 {
00378 for (unsigned N=0; N<DIM; N++)
00379 {
00380 for (unsigned P=0; P<DIM; P++)
00381 {
00382 for (unsigned Q=0; Q<DIM; Q++)
00383 {
00384 rDTdE(M,N,P,Q) += dTdE_coeff * mCurrentElementFibreDirection(M)
00385 * mCurrentElementFibreDirection(N)
00386 * mCurrentElementFibreDirection(P)
00387 * mCurrentElementFibreDirection(Q);
00388 }
00389 }
00390 }
00391 }
00392 }
00393 }
00394
00395
00396
00397
00398 template<class ELASTICITY_SOLVER,unsigned DIM>
00399 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::ComputeDeformationGradientAndStretchInEachElement(
00400 std::vector<c_matrix<double,DIM,DIM> >& rDeformationGradients,
00401 std::vector<double>& rStretches)
00402 {
00403 assert(rStretches.size()==this->mrQuadMesh.GetNumElements());
00404
00405
00406 assert(!mpVariableFibreSheetDirections || !mFibreSheetDirectionsDefinedByQuadraturePoint);
00407
00408 static c_matrix<double,DIM,NUM_VERTICES_PER_ELEMENT> element_current_displacements;
00409 static c_matrix<double,DIM,NUM_VERTICES_PER_ELEMENT> grad_lin_phi;
00410 static c_matrix<double,DIM,DIM> F;
00411
00412 static c_matrix<double,DIM,DIM> jacobian;
00413 static c_matrix<double,DIM,DIM> inverse_jacobian;
00414 double jacobian_determinant;
00415 ChastePoint<DIM> quadrature_point;
00416
00417
00418 for(unsigned elem_index=0; elem_index<this->mrQuadMesh.GetNumElements(); elem_index++)
00419 {
00420 Element<DIM,DIM>* p_elem = this->mrQuadMesh.GetElement(elem_index);
00421
00422
00423 mpCurrentElementFibreSheetMatrix = mpVariableFibreSheetDirections ? &(*mpVariableFibreSheetDirections)[elem_index] : &mConstantFibreSheetDirections;
00424 for(unsigned i=0; i<DIM; i++)
00425 {
00426 mCurrentElementFibreDirection(i) = (*mpCurrentElementFibreSheetMatrix)(i,0);
00427 }
00428
00429
00430 for (unsigned II=0; II<NUM_VERTICES_PER_ELEMENT; II++)
00431 {
00432 for (unsigned JJ=0; JJ<DIM; JJ++)
00433 {
00434 element_current_displacements(JJ,II) = this->mCurrentSolution[DIM*p_elem->GetNodeGlobalIndex(II) + JJ];
00435 }
00436 }
00437
00438
00439 this->mrQuadMesh.GetInverseJacobianForElement(elem_index, jacobian, jacobian_determinant, inverse_jacobian);
00440 LinearBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(quadrature_point, inverse_jacobian, grad_lin_phi);
00441
00442 F = identity_matrix<double>(DIM,DIM);
00443
00444
00445
00446 for (unsigned node_index=0; node_index<NUM_VERTICES_PER_ELEMENT; node_index++)
00447 {
00448 for (unsigned i=0; i<DIM; i++)
00449 {
00450 for (unsigned M=0; M<DIM; M++)
00451 {
00452 F(i,M) += grad_lin_phi(M,node_index)*element_current_displacements(i,node_index);
00453 }
00454 }
00455 }
00456
00457 rDeformationGradients[elem_index] = F;
00458
00459
00460 c_vector<double,DIM> deformed_fibre = prod(F, mCurrentElementFibreDirection);
00461 rStretches[elem_index] = norm_2(deformed_fibre);
00462 }
00463 }
00464
00465
00466
00467
00468 template<class ELASTICITY_SOLVER,unsigned DIM>
00469 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::SetVariableFibreSheetDirections(std::string orthoFile, bool definedPerQuadraturePoint)
00470 {
00471 mFibreSheetDirectionsDefinedByQuadraturePoint = definedPerQuadraturePoint;
00472
00473 FileFinder finder(orthoFile, RelativeTo::ChasteSourceRoot);
00474 FibreReader<DIM> reader(finder, ORTHO);
00475
00476 unsigned num_entries = reader.GetNumLinesOfData();
00477
00478 if(!mFibreSheetDirectionsDefinedByQuadraturePoint && (num_entries!=this->mrQuadMesh.GetNumElements()) )
00479 {
00480 EXCEPTION("Number of entries defined at top of file " << orthoFile << " does not match number of elements in the mesh, "
00481 << "found " << num_entries << ", expected " << this->mrQuadMesh.GetNumElements());
00482 }
00483
00484 if(mFibreSheetDirectionsDefinedByQuadraturePoint && (num_entries!=mTotalQuadPoints) )
00485 {
00486 EXCEPTION("Number of entries defined at top of file " << orthoFile << " does not match number of quadrature points defined, "
00487 << "found " << num_entries << ", expected " << mTotalQuadPoints);
00488 }
00489
00490 mpVariableFibreSheetDirections = new std::vector<c_matrix<double,DIM,DIM> >(num_entries, zero_matrix<double>(DIM,DIM));
00491 for(unsigned index=0; index<num_entries; index++)
00492 {
00493 reader.GetNextFibreSheetAndNormalMatrix( (*mpVariableFibreSheetDirections)[index] );
00494 }
00495 }
00496
00497
00498
00499 template<class ELASTICITY_SOLVER,unsigned DIM>
00500 void AbstractCardiacMechanicsSolver<ELASTICITY_SOLVER,DIM>::SetConstantFibreSheetDirections(const c_matrix<double,DIM,DIM>& rFibreSheetMatrix)
00501 {
00502 mConstantFibreSheetDirections = rFibreSheetMatrix;
00503
00504 c_matrix<double,DIM,DIM> temp = prod(trans(rFibreSheetMatrix),rFibreSheetMatrix);
00505 for(unsigned i=0; i<DIM; i++)
00506 {
00507 for(unsigned j=0; j<DIM; j++)
00508 {
00509 double val = (i==j ? 1.0 : 0.0);
00510 if(fabs(temp(i,j)-val)>1e-4)
00511 {
00512 EXCEPTION("The given fibre-sheet matrix, " << rFibreSheetMatrix << ", is not orthogonal");
00513 }
00514 }
00515 }
00516 }
00517
00518
00519 #endif