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;
166 template<
class ELASTICITY_SOLVER,
unsigned DIM>
168 std::vector<double>& rVoltages)
171 assert(rCalciumConcentrations.size() == mTotalQuadPoints);
172 assert(rVoltages.size() == mTotalQuadPoints);
176 for(
unsigned i=0; i<rCalciumConcentrations.size(); i++)
179 input_parameters.voltage = rVoltages[i];
182 std::map<unsigned,DataAtQuadraturePoint>::iterator iter = mQuadPointToDataAtQuadPointMap.find(i);
183 if(iter != mQuadPointToDataAtQuadPointMap.end())
185 iter->second.ContractionModel->SetInputParameters(input_parameters);
191 template<
class ELASTICITY_SOLVER,
unsigned DIM>
193 unsigned currentQuadPointGlobalIndex)
195 if(!mpVariableFibreSheetDirections)
197 this->mChangeOfBasisMatrix = mConstantFibreSheetDirections;
199 else if(!mFibreSheetDirectionsDefinedByQuadraturePoint)
201 this->mChangeOfBasisMatrix = (*mpVariableFibreSheetDirections)[elementIndex];
205 this->mChangeOfBasisMatrix = (*mpVariableFibreSheetDirections)[currentQuadPointGlobalIndex];
211 template<
class ELASTICITY_SOLVER,
unsigned DIM>
213 unsigned elementIndex,
214 unsigned currentQuadPointGlobalIndex,
215 c_matrix<double,DIM,DIM>& rT,
219 for(
unsigned i=0; i<DIM; i++)
221 mCurrentElementFibreDirection(i) = this->mChangeOfBasisMatrix(i,0);
225 double I4_fibre = inner_prod(mCurrentElementFibreDirection, prod(rC, mCurrentElementFibreDirection));
226 double lambda_fibre = sqrt(I4_fibre);
228 double active_tension = 0;
229 double d_act_tension_dlam = 0.0;
230 double d_act_tension_d_dlamdt = 0.0;
232 GetActiveTensionAndTensionDerivs(lambda_fibre, currentQuadPointGlobalIndex, addToDTdE,
233 active_tension, d_act_tension_dlam, d_act_tension_d_dlamdt);
237 rT += (active_tension*detF/I4_fibre)*outer_prod(mCurrentElementFibreDirection,mCurrentElementFibreDirection);
240 double dTdE_coeff1 = -2*active_tension*detF/(I4_fibre*I4_fibre);
241 double dTdE_coeff2 = active_tension*detF/I4_fibre;
242 double dTdE_coeff_s1 = 0.0;
243 double dTdE_coeff_s2 = 0.0;
244 double dTdE_coeff_s3 = 0.0;
245 double dTdE_coeff_n1 = 0.0;
246 double dTdE_coeff_n2 = 0.0;
247 double dTdE_coeff_n3 = 0.0;
249 if(IsImplicitSolver())
251 double dt = mNextTime-mCurrentTime;
253 dTdE_coeff1 += (d_act_tension_dlam + d_act_tension_d_dlamdt/dt)*detF/(lambda_fibre*I4_fibre);
256 bool apply_cross_fibre_tension = (this->mrElectroMechanicsProblemDefinition.GetApplyCrossFibreTension()) && (DIM > 1);
257 if(apply_cross_fibre_tension)
259 double sheet_cross_fraction = mrElectroMechanicsProblemDefinition.GetSheetTensionFraction();
261 for(
unsigned i=0; i<DIM; i++)
263 mCurrentElementSheetDirection(i) = this->mChangeOfBasisMatrix(i,1);
266 double I4_sheet = inner_prod(mCurrentElementSheetDirection, prod(rC, mCurrentElementSheetDirection));
269 dTdE_coeff_s1 = -2*sheet_cross_fraction*detF*active_tension/(I4_sheet*I4_sheet);
271 if(IsImplicitSolver())
273 double dt = mNextTime-mCurrentTime;
274 dTdE_coeff_s3 = sheet_cross_fraction*(d_act_tension_dlam + d_act_tension_d_dlamdt/dt)*detF/(lambda_fibre*I4_sheet);
277 rT += sheet_cross_fraction*(active_tension*detF/I4_sheet)*outer_prod(mCurrentElementSheetDirection,mCurrentElementSheetDirection);
279 dTdE_coeff_s2 = active_tension*sheet_cross_fraction*detF/I4_sheet;
283 double sheet_normal_cross_fraction = mrElectroMechanicsProblemDefinition.GetSheetNormalTensionFraction();
284 for(
unsigned i=0; i<DIM; i++)
286 mCurrentElementSheetNormalDirection(i) = this->mChangeOfBasisMatrix(i,2);
289 double I4_sheet_normal = inner_prod(mCurrentElementSheetNormalDirection, prod(rC, mCurrentElementSheetNormalDirection));
291 dTdE_coeff_n1 =-2*sheet_normal_cross_fraction*detF*active_tension/(I4_sheet_normal*I4_sheet_normal);
293 rT += sheet_normal_cross_fraction*(active_tension*detF/I4_sheet_normal)*outer_prod(mCurrentElementSheetNormalDirection,mCurrentElementSheetNormalDirection);
295 dTdE_coeff_n2 = active_tension*sheet_normal_cross_fraction*detF/I4_sheet_normal;
296 if(IsImplicitSolver())
298 double dt = mNextTime-mCurrentTime;
299 dTdE_coeff_n3 = sheet_normal_cross_fraction*(d_act_tension_dlam + d_act_tension_d_dlamdt/dt)*detF/(lambda_fibre*I4_sheet_normal);
307 c_matrix<double,DIM,DIM> invC =
Inverse(rC);
309 for (
unsigned M=0; M<DIM; M++)
311 for (
unsigned N=0; N<DIM; N++)
313 for (
unsigned P=0; P<DIM; P++)
315 for (
unsigned Q=0; Q<DIM; Q++)
317 rDTdE(M,N,P,Q) += dTdE_coeff1 * mCurrentElementFibreDirection(M)
318 * mCurrentElementFibreDirection(N)
319 * mCurrentElementFibreDirection(P)
320 * mCurrentElementFibreDirection(Q)
322 + dTdE_coeff2 * mCurrentElementFibreDirection(M)
323 * mCurrentElementFibreDirection(N)
325 if(apply_cross_fibre_tension)
327 rDTdE(M,N,P,Q) += dTdE_coeff_s1 * mCurrentElementSheetDirection(M)
328 * mCurrentElementSheetDirection(N)
329 * mCurrentElementSheetDirection(P)
330 * mCurrentElementSheetDirection(Q)
332 + dTdE_coeff_s2 * mCurrentElementSheetDirection(M)
333 * mCurrentElementSheetDirection(N)
336 + dTdE_coeff_s3 * mCurrentElementSheetDirection(M)
337 * mCurrentElementSheetDirection(N)
338 * mCurrentElementFibreDirection(P)
339 * mCurrentElementFibreDirection(Q);
342 rDTdE(M,N,P,Q) += dTdE_coeff_n1 * mCurrentElementSheetNormalDirection(M)
343 * mCurrentElementSheetNormalDirection(N)
344 * mCurrentElementSheetNormalDirection(P)
345 * mCurrentElementSheetNormalDirection(Q)
347 + dTdE_coeff_n2 * mCurrentElementSheetNormalDirection(M)
348 * mCurrentElementSheetNormalDirection(N)
351 + dTdE_coeff_n3 * mCurrentElementSheetNormalDirection(M)
352 * mCurrentElementSheetNormalDirection(N)
353 * mCurrentElementFibreDirection(P)
354 * mCurrentElementFibreDirection(Q);
421 template<
class ELASTICITY_SOLVER,
unsigned DIM>
423 std::vector<c_matrix<double,DIM,DIM> >& rDeformationGradients,
424 std::vector<double>& rStretches)
426 assert(rStretches.size()==this->mrQuadMesh.GetNumElements());
429 assert(!mpVariableFibreSheetDirections || !mFibreSheetDirectionsDefinedByQuadraturePoint);
431 static c_matrix<double,DIM,NUM_VERTICES_PER_ELEMENT> element_current_displacements;
432 static c_matrix<double,DIM,NUM_VERTICES_PER_ELEMENT> grad_lin_phi;
433 static c_matrix<double,DIM,DIM> F;
435 static c_matrix<double,DIM,DIM> jacobian;
436 static c_matrix<double,DIM,DIM> inverse_jacobian;
437 double jacobian_determinant;
441 for(
unsigned elem_index=0; elem_index<this->mrQuadMesh.GetNumElements(); elem_index++)
446 SetupChangeOfBasisMatrix(elem_index, 0);
447 for(
unsigned i=0; i<DIM; i++)
449 mCurrentElementFibreDirection(i) = this->mChangeOfBasisMatrix(i,0);
453 for (
unsigned II=0; II<NUM_VERTICES_PER_ELEMENT; II++)
455 for (
unsigned JJ=0; JJ<DIM; JJ++)
458 element_current_displacements(JJ,II) = this->mCurrentSolution[this->mProblemDimension*p_elem->
GetNodeGlobalIndex(II) + JJ];
463 this->mrQuadMesh.GetInverseJacobianForElement(elem_index, jacobian, jacobian_determinant, inverse_jacobian);
466 F = identity_matrix<double>(DIM,DIM);
470 for (
unsigned node_index=0; node_index<NUM_VERTICES_PER_ELEMENT; node_index++)
472 for (
unsigned i=0; i<DIM; i++)
474 for (
unsigned M=0; M<DIM; M++)
476 F(i,M) += grad_lin_phi(M,node_index)*element_current_displacements(i,node_index);
481 rDeformationGradients[elem_index] = F;
484 c_vector<double,DIM> deformed_fibre = prod(F, mCurrentElementFibreDirection);
485 rStretches[elem_index] = norm_2(deformed_fibre);
490 template<
class ELASTICITY_SOLVER,
unsigned DIM>
493 mFibreSheetDirectionsDefinedByQuadraturePoint = definedPerQuadraturePoint;
499 if (!mFibreSheetDirectionsDefinedByQuadraturePoint && (num_entries!=this->mrQuadMesh.GetNumElements()) )
502 " does not match number of elements in the mesh, " <<
"found " << num_entries <<
503 ", expected " << this->mrQuadMesh.GetNumElements());
506 if (mFibreSheetDirectionsDefinedByQuadraturePoint && (num_entries!=mTotalQuadPoints) )
509 " does not match number of quadrature points defined, " <<
"found " << num_entries <<
510 ", expected " << mTotalQuadPoints);
513 mpVariableFibreSheetDirections =
new std::vector<c_matrix<double,DIM,DIM> >(num_entries, zero_matrix<double>(DIM,DIM));
514 for(
unsigned index=0; index<num_entries; index++)
520 template<
class ELASTICITY_SOLVER,
unsigned DIM>
523 mConstantFibreSheetDirections = rFibreSheetMatrix;
525 c_matrix<double,DIM,DIM> temp = prod(trans(rFibreSheetMatrix),rFibreSheetMatrix);
526 for(
unsigned i=0; i<DIM; i++)
528 for(
unsigned j=0; j<DIM; j++)
530 double val = (i==j ? 1.0 : 0.0);
531 if(fabs(temp(i,j)-val)>1e-4)
533 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)