36 #include "AbstractCardiacMechanicsSolver.hpp"
37 #include "AbstractContractionCellFactory.hpp"
38 #include "FakeBathContractionModel.hpp"
40 template<
class ELASTICITY_SOLVER,
unsigned DIM>
43 std::string outputDirectory)
48 mCurrentTime(DBL_MAX),
50 mOdeTimestep(DBL_MAX),
51 mrElectroMechanicsProblemDefinition(rProblemDefinition)
55 template<
class ELASTICITY_SOLVER,
unsigned DIM>
59 unsigned num_quad_pts_per_element = this->mpQuadratureRule->GetNumQuadPoints();
60 mTotalQuadPoints = this->mrQuadMesh.GetNumElements()*num_quad_pts_per_element;
62 std::vector<ElementAndWeights<DIM> > fine_elements = mpMeshPair->rGetElementsAndWeights();
63 assert(fine_elements.size()==mTotalQuadPoints);
64 assert(mpMeshPair!=NULL);
69 iter != this->mrQuadMesh.GetElementIteratorEnd();
76 for (
unsigned j=0; j<num_quad_pts_per_element; j++)
78 unsigned quad_pt_global_index = element.
GetIndex()*num_quad_pts_per_element + j;
84 data_at_quad_point.
Stretch = 1.0;
87 if (mpMeshPair->GetFineMesh().GetElement(fine_elements[quad_pt_global_index].ElementNum)
98 mQuadPointToDataAtQuadPointMap[quad_pt_global_index] = data_at_quad_point;
104 mMapIterator = mQuadPointToDataAtQuadPointMap.begin();
107 mConstantFibreSheetDirections = zero_matrix<double>(DIM,DIM);
108 for (
unsigned i=0; i<DIM; i++)
110 mConstantFibreSheetDirections(i,i) = 1.0;
113 mpVariableFibreSheetDirections = NULL;
116 for (std::map<unsigned,DataAtQuadraturePoint>::iterator iter = this->mQuadPointToDataAtQuadPointMap.begin();
117 iter != this->mQuadPointToDataAtQuadPointMap.end();
120 if (!IsImplicitSolver() && (*iter).second.ContractionModel->IsStretchRateDependent())
122 EXCEPTION(
"stretch-rate-dependent contraction model requires an IMPLICIT cardiac mechanics solver.");
125 if (!IsImplicitSolver() && (*iter).second.ContractionModel->IsStretchDependent())
127 WARN_ONCE_ONLY(
"stretch-dependent contraction model may require an IMPLICIT cardiac mechanics solver.");
133 template<
class ELASTICITY_SOLVER,
unsigned DIM>
136 assert(pMeshPair!=NULL);
139 EXCEPTION(
"When setting a mesh pair into the solver, the coarse mesh of the mesh pair must be the same as the quadratic mesh");
141 mpMeshPair = pMeshPair;
144 template<
class ELASTICITY_SOLVER,
unsigned DIM>
147 for (mMapIterator = mQuadPointToDataAtQuadPointMap.begin();
148 mMapIterator != mQuadPointToDataAtQuadPointMap.end();
158 if (mpVariableFibreSheetDirections)
160 delete mpVariableFibreSheetDirections;
164 template<
class ELASTICITY_SOLVER,
unsigned DIM>
166 std::vector<double>& rVoltages)
169 assert(rCalciumConcentrations.size() == mTotalQuadPoints);
170 assert(rVoltages.size() == mTotalQuadPoints);
174 for (
unsigned i=0; i<rCalciumConcentrations.size(); i++)
177 input_parameters.voltage = rVoltages[i];
180 std::map<unsigned,DataAtQuadraturePoint>::iterator iter = mQuadPointToDataAtQuadPointMap.find(i);
181 if (iter != mQuadPointToDataAtQuadPointMap.end())
183 iter->second.ContractionModel->SetInputParameters(input_parameters);
189 template<
class ELASTICITY_SOLVER,
unsigned DIM>
191 unsigned currentQuadPointGlobalIndex)
193 if (!mpVariableFibreSheetDirections)
195 this->mChangeOfBasisMatrix = mConstantFibreSheetDirections;
197 else if (!mFibreSheetDirectionsDefinedByQuadraturePoint)
199 this->mChangeOfBasisMatrix = (*mpVariableFibreSheetDirections)[elementIndex];
203 this->mChangeOfBasisMatrix = (*mpVariableFibreSheetDirections)[currentQuadPointGlobalIndex];
207 template<
class ELASTICITY_SOLVER,
unsigned DIM>
209 unsigned elementIndex,
210 unsigned currentQuadPointGlobalIndex,
211 c_matrix<double,DIM,DIM>& rT,
215 for (
unsigned i=0; i<DIM; i++)
217 mCurrentElementFibreDirection(i) = this->mChangeOfBasisMatrix(i,0);
221 double I4_fibre = inner_prod(mCurrentElementFibreDirection, prod(rC, mCurrentElementFibreDirection));
222 double lambda_fibre = sqrt(I4_fibre);
224 double active_tension = 0;
225 double d_act_tension_dlam = 0.0;
226 double d_act_tension_d_dlamdt = 0.0;
228 GetActiveTensionAndTensionDerivs(lambda_fibre, currentQuadPointGlobalIndex, addToDTdE,
229 active_tension, d_act_tension_dlam, d_act_tension_d_dlamdt);
233 rT += (active_tension*detF/I4_fibre)*outer_prod(mCurrentElementFibreDirection,mCurrentElementFibreDirection);
236 double dTdE_coeff1 = -2*active_tension*detF/(I4_fibre*I4_fibre);
237 double dTdE_coeff2 = active_tension*detF/I4_fibre;
238 double dTdE_coeff_s1 = 0.0;
239 double dTdE_coeff_s2 = 0.0;
240 double dTdE_coeff_s3 = 0.0;
241 double dTdE_coeff_n1 = 0.0;
242 double dTdE_coeff_n2 = 0.0;
243 double dTdE_coeff_n3 = 0.0;
245 if (IsImplicitSolver())
247 double dt = mNextTime-mCurrentTime;
249 dTdE_coeff1 += (d_act_tension_dlam + d_act_tension_d_dlamdt/dt)*detF/(lambda_fibre*I4_fibre);
252 bool apply_cross_fibre_tension = (this->mrElectroMechanicsProblemDefinition.GetApplyCrossFibreTension()) && (DIM > 1);
253 if (apply_cross_fibre_tension)
255 double sheet_cross_fraction = mrElectroMechanicsProblemDefinition.GetSheetTensionFraction();
257 for (
unsigned i=0; i<DIM; i++)
259 mCurrentElementSheetDirection(i) = this->mChangeOfBasisMatrix(i,1);
262 double I4_sheet = inner_prod(mCurrentElementSheetDirection, prod(rC, mCurrentElementSheetDirection));
265 dTdE_coeff_s1 = -2*sheet_cross_fraction*detF*active_tension/(I4_sheet*I4_sheet);
267 if (IsImplicitSolver())
269 double dt = mNextTime-mCurrentTime;
270 dTdE_coeff_s3 = sheet_cross_fraction*(d_act_tension_dlam + d_act_tension_d_dlamdt/dt)*detF/(lambda_fibre*I4_sheet);
273 rT += sheet_cross_fraction*(active_tension*detF/I4_sheet)*outer_prod(mCurrentElementSheetDirection,mCurrentElementSheetDirection);
275 dTdE_coeff_s2 = active_tension*sheet_cross_fraction*detF/I4_sheet;
279 double sheet_normal_cross_fraction = mrElectroMechanicsProblemDefinition.GetSheetNormalTensionFraction();
280 for (
unsigned i=0; i<DIM; i++)
282 mCurrentElementSheetNormalDirection(i) = this->mChangeOfBasisMatrix(i,2);
285 double I4_sheet_normal = inner_prod(mCurrentElementSheetNormalDirection, prod(rC, mCurrentElementSheetNormalDirection));
287 dTdE_coeff_n1 =-2*sheet_normal_cross_fraction*detF*active_tension/(I4_sheet_normal*I4_sheet_normal);
289 rT += sheet_normal_cross_fraction*(active_tension*detF/I4_sheet_normal)*outer_prod(mCurrentElementSheetNormalDirection,mCurrentElementSheetNormalDirection);
291 dTdE_coeff_n2 = active_tension*sheet_normal_cross_fraction*detF/I4_sheet_normal;
292 if (IsImplicitSolver())
294 double dt = mNextTime-mCurrentTime;
295 dTdE_coeff_n3 = sheet_normal_cross_fraction*(d_act_tension_dlam + d_act_tension_d_dlamdt/dt)*detF/(lambda_fibre*I4_sheet_normal);
303 c_matrix<double,DIM,DIM> invC =
Inverse(rC);
305 for (
unsigned M=0; M<DIM; M++)
307 for (
unsigned N=0; N<DIM; N++)
309 for (
unsigned P=0; P<DIM; P++)
311 for (
unsigned Q=0; Q<DIM; Q++)
313 rDTdE(M,N,P,Q) += dTdE_coeff1 * mCurrentElementFibreDirection(M)
314 * mCurrentElementFibreDirection(N)
315 * mCurrentElementFibreDirection(P)
316 * mCurrentElementFibreDirection(Q)
318 + dTdE_coeff2 * mCurrentElementFibreDirection(M)
319 * mCurrentElementFibreDirection(N)
321 if (apply_cross_fibre_tension)
323 rDTdE(M,N,P,Q) += dTdE_coeff_s1 * mCurrentElementSheetDirection(M)
324 * mCurrentElementSheetDirection(N)
325 * mCurrentElementSheetDirection(P)
326 * mCurrentElementSheetDirection(Q)
328 + dTdE_coeff_s2 * mCurrentElementSheetDirection(M)
329 * mCurrentElementSheetDirection(N)
332 + dTdE_coeff_s3 * mCurrentElementSheetDirection(M)
333 * mCurrentElementSheetDirection(N)
334 * mCurrentElementFibreDirection(P)
335 * mCurrentElementFibreDirection(Q);
338 rDTdE(M,N,P,Q) += dTdE_coeff_n1 * mCurrentElementSheetNormalDirection(M)
339 * mCurrentElementSheetNormalDirection(N)
340 * mCurrentElementSheetNormalDirection(P)
341 * mCurrentElementSheetNormalDirection(Q)
343 + dTdE_coeff_n2 * mCurrentElementSheetNormalDirection(M)
344 * mCurrentElementSheetNormalDirection(N)
347 + dTdE_coeff_n3 * mCurrentElementSheetNormalDirection(M)
348 * mCurrentElementSheetNormalDirection(N)
349 * mCurrentElementFibreDirection(P)
350 * mCurrentElementFibreDirection(Q);
417 template<
class ELASTICITY_SOLVER,
unsigned DIM>
419 std::vector<c_matrix<double,DIM,DIM> >& rDeformationGradients,
420 std::vector<double>& rStretches)
422 assert(rStretches.size()==this->mrQuadMesh.GetNumElements());
425 assert(!mpVariableFibreSheetDirections || !mFibreSheetDirectionsDefinedByQuadraturePoint);
427 static c_matrix<double,DIM,NUM_VERTICES_PER_ELEMENT> element_current_displacements;
428 static c_matrix<double,DIM,NUM_VERTICES_PER_ELEMENT> grad_lin_phi;
429 static c_matrix<double,DIM,DIM> F;
431 static c_matrix<double,DIM,DIM> jacobian;
432 static c_matrix<double,DIM,DIM> inverse_jacobian;
433 double jacobian_determinant;
437 for (
unsigned elem_index=0; elem_index<this->mrQuadMesh.GetNumElements(); elem_index++)
442 SetupChangeOfBasisMatrix(elem_index, 0);
443 for (
unsigned i=0; i<DIM; i++)
445 mCurrentElementFibreDirection(i) = this->mChangeOfBasisMatrix(i,0);
449 for (
unsigned II=0; II<NUM_VERTICES_PER_ELEMENT; II++)
451 for (
unsigned JJ=0; JJ<DIM; JJ++)
454 element_current_displacements(JJ,II) = this->mCurrentSolution[this->mProblemDimension*p_elem->
GetNodeGlobalIndex(II) + JJ];
459 this->mrQuadMesh.GetInverseJacobianForElement(elem_index, jacobian, jacobian_determinant, inverse_jacobian);
462 F = identity_matrix<double>(DIM,DIM);
466 for (
unsigned node_index=0; node_index<NUM_VERTICES_PER_ELEMENT; node_index++)
468 for (
unsigned i=0; i<DIM; i++)
470 for (
unsigned M=0; M<DIM; M++)
472 F(i,M) += grad_lin_phi(M,node_index)*element_current_displacements(i,node_index);
477 rDeformationGradients[elem_index] = F;
480 c_vector<double,DIM> deformed_fibre = prod(F, mCurrentElementFibreDirection);
481 rStretches[elem_index] = norm_2(deformed_fibre);
486 template<
class ELASTICITY_SOLVER,
unsigned DIM>
489 mFibreSheetDirectionsDefinedByQuadraturePoint = definedPerQuadraturePoint;
495 if (!mFibreSheetDirectionsDefinedByQuadraturePoint && (num_entries!=this->mrQuadMesh.GetNumElements()) )
498 " does not match number of elements in the mesh, " <<
"found " << num_entries <<
499 ", expected " << this->mrQuadMesh.GetNumElements());
502 if (mFibreSheetDirectionsDefinedByQuadraturePoint && (num_entries!=mTotalQuadPoints) )
505 " does not match number of quadrature points defined, " <<
"found " << num_entries <<
506 ", expected " << mTotalQuadPoints);
509 mpVariableFibreSheetDirections =
new std::vector<c_matrix<double,DIM,DIM> >(num_entries, zero_matrix<double>(DIM,DIM));
510 for (
unsigned index=0; index<num_entries; index++)
516 template<
class ELASTICITY_SOLVER,
unsigned DIM>
519 mConstantFibreSheetDirections = rFibreSheetMatrix;
521 c_matrix<double,DIM,DIM> temp = prod(trans(rFibreSheetMatrix),rFibreSheetMatrix);
522 for (
unsigned i=0; i<DIM; i++)
524 for (
unsigned j=0; j<DIM; j++)
526 double val = (i==j ? 1.0 : 0.0);
527 if (fabs(temp(i,j)-val)>1e-4)
529 EXCEPTION(
"The given fibre-sheet matrix, " << rFibreSheetMatrix <<
", is not orthogonal");
ElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
void ComputeDeformationGradientAndStretchInEachElement(std::vector< c_matrix< double, DIM, DIM > > &rDeformationGradients, std::vector< double > &rStretches)
boost::numeric::ublas::c_matrix< T, 1, 1 > Inverse(const boost::numeric::ublas::c_matrix< T, 1, 1 > &rM)
unsigned GetNodeGlobalIndex(unsigned localIndex) const
unsigned GetNumLinesOfData()
void SetConstantFibreSheetDirections(const c_matrix< double, DIM, DIM > &rFibreSheetMatrix)
std::string GetAbsolutePath() const
AbstractCardiacMechanicsSolver(QuadraticMesh< DIM > &rQuadMesh, ElectroMechanicsProblemDefinition< DIM > &rProblemDefinition, std::string outputDirectory)
virtual unsigned GetNumElements() const
#define EXCEPTION(message)
static HeartRegionType GetValidBathId()
const AbstractTetrahedralMesh< DIM, DIM > & GetCoarseMesh() const
T Determinant(const boost::numeric::ublas::c_matrix< T, 1, 1 > &rM)
double StretchLastTimeStep
static void ComputeTransformedBasisFunctionDerivatives(const ChastePoint< ELEMENT_DIM > &rPoint, const c_matrix< double, ELEMENT_DIM, ELEMENT_DIM > &rInverseJacobian, c_matrix< double, ELEMENT_DIM, ELEMENT_DIM+1 > &rReturnValue)
bool GetOwnership() const
void AddActiveStressAndStressDerivative(c_matrix< double, DIM, DIM > &rC, unsigned elementIndex, unsigned currentQuadPointGlobalIndex, c_matrix< double, DIM, DIM > &rT, FourthOrderTensor< DIM, DIM, DIM, DIM > &rDTdE, bool addToDTdE)
void SetFineCoarseMeshPair(FineCoarseMeshPair< DIM > *pMeshPair)
AbstractContractionModel * ContractionModel
void SetCalciumAndVoltage(std::vector< double > &rCalciumConcentrations, std::vector< double > &rVoltages)
unsigned GetIndex() const
void SetVariableFibreSheetDirections(const FileFinder &rOrthoFile, bool definedPerQuadraturePoint)
virtual ~AbstractCardiacMechanicsSolver()
virtual AbstractContractionModel * CreateContractionCellForElement(Element< DIM, DIM > *pElement)=0
void GetFibreSheetAndNormalMatrix(unsigned fibreIndex, c_matrix< double, DIM, DIM > &rFibreMatrix, bool checkOrthogonality=true)
void SetupChangeOfBasisMatrix(unsigned elementIndex, unsigned currentQuadPointGlobalIndex)