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 "NonlinearElasticitySolver.hpp"
00033 #include "NashHunterPoleZeroLaw.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:
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
00282 mTotalQuadPoints = pQuadMesh->GetNumElements()*this->mpQuadratureRule->GetNumQuadPoints();
00283
00284
00285 mStretches.resize(mTotalQuadPoints, 1.0);
00286
00287
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)
00340 {
00341 mpCurrentElementFibreSheetMatrix = &mConstantFibreSheetDirections;
00342 }
00343 else if(!mFibreSheetDirectionsDefinedByQuadraturePoint)
00344 {
00345 mpCurrentElementFibreSheetMatrix = &(*mpVariableFibreSheetDirections)[elementIndex];
00346 }
00347 else
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
00358 pMaterialLaw->SetChangeOfBasisMatrix(*mpCurrentElementFibreSheetMatrix);
00359 pMaterialLaw->ComputeStressAndStressDerivative(rC,rInvC,pressure,rT,rDTdE,assembleJacobian);
00360
00361
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;
00367 double d_act_tension_d_dlamdt = 0.0;
00368
00369 GetActiveTensionAndTensionDerivs(lambda, currentQuadPointGlobalIndex, assembleJacobian,
00370 active_tension, d_act_tension_dlam, d_act_tension_d_dlamdt);
00371
00372
00373 double dTdE_coeff = -2*active_tension/(I4*I4);
00374 if(IsImplicitSolver())
00375 {
00376 double dt = mNextTime-mCurrentTime;
00377 dTdE_coeff += (d_act_tension_dlam + d_act_tension_d_dlamdt/dt)/(lambda*I4);
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
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;
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;
00424
00425
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
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
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
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
00453
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
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
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