Chaste  Release::3.4
AbstractCardiacMechanicsSolver.cpp
1 /*
2 
3 Copyright (c) 2005-2016, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 
36 #include "AbstractCardiacMechanicsSolver.hpp"
37 #include "AbstractContractionCellFactory.hpp"
38 #include "FakeBathContractionModel.hpp"
39 
40 template<class ELASTICITY_SOLVER,unsigned DIM>
42  ElectroMechanicsProblemDefinition<DIM>& rProblemDefinition,
43  std::string outputDirectory)
44  : ELASTICITY_SOLVER(rQuadMesh,
45  rProblemDefinition,
46  outputDirectory),
47  mpMeshPair(NULL),
48  mCurrentTime(DBL_MAX),
49  mNextTime(DBL_MAX),
50  mOdeTimestep(DBL_MAX),
51  mrElectroMechanicsProblemDefinition(rProblemDefinition)
52 {
53 }
54 
55 template<class ELASTICITY_SOLVER,unsigned DIM>
57 {
58  // compute total num quad points
59  unsigned num_quad_pts_per_element = this->mpQuadratureRule->GetNumQuadPoints();
60  mTotalQuadPoints = this->mrQuadMesh.GetNumElements()*num_quad_pts_per_element;
61 
62  std::vector<ElementAndWeights<DIM> > fine_elements = mpMeshPair->rGetElementsAndWeights();
63  assert(fine_elements.size()==mTotalQuadPoints);
64  assert(mpMeshPair!=NULL);
65 
66  AbstractContractionCellFactory<DIM>* p_factory = mrElectroMechanicsProblemDefinition.GetContractionCellFactory();
67 
69  iter != this->mrQuadMesh.GetElementIteratorEnd();
70  ++iter)
71  {
72  Element<DIM, DIM>& element = *iter;
73 
74  if (element.GetOwnership() == true)
75  {
76  for(unsigned j=0; j<num_quad_pts_per_element; j++)
77  {
78  unsigned quad_pt_global_index = element.GetIndex()*num_quad_pts_per_element + j;
79 
80  // We construct a set of data to be assigned to each quadrature point
81  // this includes a contraction cell model set as bath or by the contraction
82  // cell factory.
83  DataAtQuadraturePoint data_at_quad_point;
84  data_at_quad_point.Stretch = 1.0;
85  data_at_quad_point.StretchLastTimeStep = 1.0;
86 
87  if ( mpMeshPair->GetFineMesh().GetElement(fine_elements[quad_pt_global_index].ElementNum)
88  ->GetUnsignedAttribute() == HeartRegionCode::GetValidBathId() )
89  {
90  // Bath
91  data_at_quad_point.ContractionModel = new FakeBathContractionModel;
92  }
93  else
94  {
95  // Tissue
96  data_at_quad_point.ContractionModel = p_factory->CreateContractionCellForElement( &element );
97  }
98  mQuadPointToDataAtQuadPointMap[quad_pt_global_index] = data_at_quad_point;
99  }
100  }
101  }
102 
103  // initialise the iterator to point at the beginning
104  mMapIterator = mQuadPointToDataAtQuadPointMap.begin();
105 
106  // initialise fibre/sheet direction matrix to be the identity, fibres in X-direction, and sheet in XY-plane
107  mConstantFibreSheetDirections = zero_matrix<double>(DIM,DIM);
108  for(unsigned i=0; i<DIM; i++)
109  {
110  mConstantFibreSheetDirections(i,i) = 1.0;
111  }
112 
113  mpVariableFibreSheetDirections = NULL;
114 
115  // Check that we are using the right kind of solver.
116  for(std::map<unsigned,DataAtQuadraturePoint>::iterator iter = this->mQuadPointToDataAtQuadPointMap.begin();
117  iter != this->mQuadPointToDataAtQuadPointMap.end();
118  iter++)
119  {
120  if (!IsImplicitSolver() && (*iter).second.ContractionModel->IsStretchRateDependent())
121  {
122  EXCEPTION("stretch-rate-dependent contraction model requires an IMPLICIT cardiac mechanics solver.");
123  }
124 
125  if (!IsImplicitSolver() && (*iter).second.ContractionModel->IsStretchDependent())
126  {
127  WARN_ONCE_ONLY("stretch-dependent contraction model may require an IMPLICIT cardiac mechanics solver.");
128  }
129  }
130 }
131 
132 
133 template<class ELASTICITY_SOLVER,unsigned DIM>
135 {
136  assert(pMeshPair!=NULL);
137  if (pMeshPair->GetCoarseMesh().GetNumElements() != this->mrQuadMesh.GetNumElements())
138  {
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");
140  }
141  mpMeshPair = pMeshPair;
142 }
143 
144 template<class ELASTICITY_SOLVER,unsigned DIM>
146 {
147  for(mMapIterator = mQuadPointToDataAtQuadPointMap.begin();
148  mMapIterator != mQuadPointToDataAtQuadPointMap.end();
149  ++mMapIterator)
150  {
151  AbstractContractionModel* p_model = mMapIterator->second.ContractionModel;
152  if (p_model)
153  {
154  delete p_model;
155  }
156  }
157 
158  if(mpVariableFibreSheetDirections)
159  {
160  delete mpVariableFibreSheetDirections;
161  }
162 }
163 
164 
165 
166 template<class ELASTICITY_SOLVER,unsigned DIM>
168  std::vector<double>& rVoltages)
169 
170 {
171  assert(rCalciumConcentrations.size() == mTotalQuadPoints);
172  assert(rVoltages.size() == mTotalQuadPoints);
173 
174  ContractionModelInputParameters input_parameters;
175 
176  for(unsigned i=0; i<rCalciumConcentrations.size(); i++)
177  {
178  input_parameters.intracellularCalciumConcentration = rCalciumConcentrations[i];
179  input_parameters.voltage = rVoltages[i];
180 
182  std::map<unsigned,DataAtQuadraturePoint>::iterator iter = mQuadPointToDataAtQuadPointMap.find(i);
183  if(iter != mQuadPointToDataAtQuadPointMap.end())
184  {
185  iter->second.ContractionModel->SetInputParameters(input_parameters);
186  }
187  }
188 }
189 
190 
191 template<class ELASTICITY_SOLVER,unsigned DIM>
193  unsigned currentQuadPointGlobalIndex)
194 {
195  if(!mpVariableFibreSheetDirections) // constant fibre directions
196  {
197  this->mChangeOfBasisMatrix = mConstantFibreSheetDirections;
198  }
199  else if(!mFibreSheetDirectionsDefinedByQuadraturePoint) // fibre directions defined for each mechanics mesh element
200  {
201  this->mChangeOfBasisMatrix = (*mpVariableFibreSheetDirections)[elementIndex];
202  }
203  else // fibre directions defined for each mechanics mesh quadrature point
204  {
205  this->mChangeOfBasisMatrix = (*mpVariableFibreSheetDirections)[currentQuadPointGlobalIndex];
206  }
207 }
208 
209 
210 
211 template<class ELASTICITY_SOLVER,unsigned DIM>
213  unsigned elementIndex,
214  unsigned currentQuadPointGlobalIndex,
215  c_matrix<double,DIM,DIM>& rT,
217  bool addToDTdE)
218 {
219  for(unsigned i=0; i<DIM; i++)
220  {
221  mCurrentElementFibreDirection(i) = this->mChangeOfBasisMatrix(i,0);
222  }
223 
224  //Compute the active tension and add to the stress and stress-derivative
225  double I4_fibre = inner_prod(mCurrentElementFibreDirection, prod(rC, mCurrentElementFibreDirection));
226  double lambda_fibre = sqrt(I4_fibre);
227 
228  double active_tension = 0;
229  double d_act_tension_dlam = 0.0; // Set and used if assembleJacobian==true
230  double d_act_tension_d_dlamdt = 0.0; // Set and used if assembleJacobian==true
231 
232  GetActiveTensionAndTensionDerivs(lambda_fibre, currentQuadPointGlobalIndex, addToDTdE,
233  active_tension, d_act_tension_dlam, d_act_tension_d_dlamdt);
234 
235 
236  double detF = sqrt(Determinant(rC));
237  rT += (active_tension*detF/I4_fibre)*outer_prod(mCurrentElementFibreDirection,mCurrentElementFibreDirection);
238 
239  // amend the stress and dTdE using the active tension
240  double dTdE_coeff1 = -2*active_tension*detF/(I4_fibre*I4_fibre); // note: I4_fibre*I4_fibre = lam^4
241  double dTdE_coeff2 = active_tension*detF/I4_fibre;
242  double dTdE_coeff_s1 = 0.0; // only set non-zero if we apply cross fibre tension (in 2/3D)
243  double dTdE_coeff_s2 = 0.0; // only set non-zero if we apply cross fibre tension (in 2/3D)
244  double dTdE_coeff_s3 = 0.0; // only set non-zero if we apply cross fibre tension and implicit (in 2/3D)
245  double dTdE_coeff_n1 = 0.0; // only set non-zero if we apply cross fibre tension in 3D
246  double dTdE_coeff_n2 = 0.0; // only set non-zero if we apply cross fibre tension in 3D
247  double dTdE_coeff_n3 = 0.0; // only set non-zero if we apply cross fibre tension in 3D and implicit
248 
249  if(IsImplicitSolver())
250  {
251  double dt = mNextTime-mCurrentTime;
252  //std::cout << "d sigma / d lamda = " << d_act_tension_dlam << ", d sigma / d lamdat = " << d_act_tension_d_dlamdt << "\n" << std::flush;
253  dTdE_coeff1 += (d_act_tension_dlam + d_act_tension_d_dlamdt/dt)*detF/(lambda_fibre*I4_fibre); // note: I4_fibre*lam = lam^3
254  }
255 
256  bool apply_cross_fibre_tension = (this->mrElectroMechanicsProblemDefinition.GetApplyCrossFibreTension()) && (DIM > 1);
257  if(apply_cross_fibre_tension)
258  {
259  double sheet_cross_fraction = mrElectroMechanicsProblemDefinition.GetSheetTensionFraction();
260 
261  for(unsigned i=0; i<DIM; i++)
262  {
263  mCurrentElementSheetDirection(i) = this->mChangeOfBasisMatrix(i,1);
264  }
265 
266  double I4_sheet = inner_prod(mCurrentElementSheetDirection, prod(rC, mCurrentElementSheetDirection));
267 
268  // amend the stress and dTdE using the active tension
269  dTdE_coeff_s1 = -2*sheet_cross_fraction*detF*active_tension/(I4_sheet*I4_sheet); // note: I4*I4 = lam^4
270 
271  if(IsImplicitSolver())
272  {
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); // note: I4*lam = lam^3
275  }
276 
277  rT += sheet_cross_fraction*(active_tension*detF/I4_sheet)*outer_prod(mCurrentElementSheetDirection,mCurrentElementSheetDirection);
278 
279  dTdE_coeff_s2 = active_tension*sheet_cross_fraction*detF/I4_sheet;
280 
281  if (DIM>2)
282  {
283  double sheet_normal_cross_fraction = mrElectroMechanicsProblemDefinition.GetSheetNormalTensionFraction();
284  for(unsigned i=0; i<DIM; i++)
285  {
286  mCurrentElementSheetNormalDirection(i) = this->mChangeOfBasisMatrix(i,2);
287  }
288 
289  double I4_sheet_normal = inner_prod(mCurrentElementSheetNormalDirection, prod(rC, mCurrentElementSheetNormalDirection));
290 
291  dTdE_coeff_n1 =-2*sheet_normal_cross_fraction*detF*active_tension/(I4_sheet_normal*I4_sheet_normal); // note: I4*I4 = lam^4
292 
293  rT += sheet_normal_cross_fraction*(active_tension*detF/I4_sheet_normal)*outer_prod(mCurrentElementSheetNormalDirection,mCurrentElementSheetNormalDirection);
294 
295  dTdE_coeff_n2 = active_tension*sheet_normal_cross_fraction*detF/I4_sheet_normal;
296  if(IsImplicitSolver())
297  {
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); // note: I4*lam = lam^3
300  }
301  }
302  }
303 
304 
305  if(addToDTdE)
306  {
307  c_matrix<double,DIM,DIM> invC = Inverse(rC);
308 
309  for (unsigned M=0; M<DIM; M++)
310  {
311  for (unsigned N=0; N<DIM; N++)
312  {
313  for (unsigned P=0; P<DIM; P++)
314  {
315  for (unsigned Q=0; Q<DIM; Q++)
316  {
317  rDTdE(M,N,P,Q) += dTdE_coeff1 * mCurrentElementFibreDirection(M)
318  * mCurrentElementFibreDirection(N)
319  * mCurrentElementFibreDirection(P)
320  * mCurrentElementFibreDirection(Q)
321 
322  + dTdE_coeff2 * mCurrentElementFibreDirection(M)
323  * mCurrentElementFibreDirection(N)
324  * invC(P,Q);
325  if(apply_cross_fibre_tension)
326  {
327  rDTdE(M,N,P,Q) += dTdE_coeff_s1 * mCurrentElementSheetDirection(M)
328  * mCurrentElementSheetDirection(N)
329  * mCurrentElementSheetDirection(P)
330  * mCurrentElementSheetDirection(Q)
331 
332  + dTdE_coeff_s2 * mCurrentElementSheetDirection(M)
333  * mCurrentElementSheetDirection(N)
334  * invC(P,Q)
335 
336  + dTdE_coeff_s3 * mCurrentElementSheetDirection(M)
337  * mCurrentElementSheetDirection(N)
338  * mCurrentElementFibreDirection(P)
339  * mCurrentElementFibreDirection(Q);
340  if (DIM>2)
341  {
342  rDTdE(M,N,P,Q) += dTdE_coeff_n1 * mCurrentElementSheetNormalDirection(M)
343  * mCurrentElementSheetNormalDirection(N)
344  * mCurrentElementSheetNormalDirection(P)
345  * mCurrentElementSheetNormalDirection(Q)
346 
347  + dTdE_coeff_n2 * mCurrentElementSheetNormalDirection(M)
348  * mCurrentElementSheetNormalDirection(N)
349  * invC(P,Q)
350 
351  + dTdE_coeff_n3 * mCurrentElementSheetNormalDirection(M)
352  * mCurrentElementSheetNormalDirection(N)
353  * mCurrentElementFibreDirection(P)
354  * mCurrentElementFibreDirection(Q);
355  }
356  }
357  }
358  }
359  }
360  }
361  }
362 
363 // ///\todo #2180 The code below applies a cross fibre tension in the 2D case. Things that need doing:
364 // // * Refactor the common code between the block below and the block above to avoid duplication.
365 // // * Handle the 3D case.
366 // if(this->mrElectroMechanicsProblemDefinition.GetApplyCrossFibreTension() && DIM > 1)
367 // {
368 // double sheet_cross_fraction = mrElectroMechanicsProblemDefinition.GetSheetTensionFraction();
369 //
370 // for(unsigned i=0; i<DIM; i++)
371 // {
372 // mCurrentElementSheetDirection(i) = this->mChangeOfBasisMatrix(i,1);
373 // }
374 //
375 // double I4_sheet = inner_prod(mCurrentElementSheetDirection, prod(rC, mCurrentElementSheetDirection));
376 //
377 // // amend the stress and dTdE using the active tension
378 // double dTdE_coeff_s1 = -2*sheet_cross_fraction*detF*active_tension/(I4_sheet*I4_sheet); // note: I4*I4 = lam^4
379 //
380 // ///\todo #2180 The code below is specific to the implicit cardiac mechanics solver. Currently
381 // // the cross-fibre code is only tested using the explicit solver so the code below fails coverage.
382 // // This will need to be added back in once an implicit test is in place.
383 // double lambda_sheet = sqrt(I4_sheet);
384 // if(IsImplicitSolver())
385 // {
386 // double dt = mNextTime-mCurrentTime;
387 // dTdE_coeff_s1 += (d_act_tension_dlam + d_act_tension_d_dlamdt/dt)/(lambda_sheet*I4_sheet); // note: I4*lam = lam^3
388 // }
389 //
390 // rT += sheet_cross_fraction*(active_tension*detF/I4_sheet)*outer_prod(mCurrentElementSheetDirection,mCurrentElementSheetDirection);
391 //
392 // double dTdE_coeff_s2 = active_tension*detF/I4_sheet;
393 // if(addToDTdE)
394 // {
395 // for (unsigned M=0; M<DIM; M++)
396 // {
397 // for (unsigned N=0; N<DIM; N++)
398 // {
399 // for (unsigned P=0; P<DIM; P++)
400 // {
401 // for (unsigned Q=0; Q<DIM; Q++)
402 // {
403 // rDTdE(M,N,P,Q) += dTdE_coeff_s1 * mCurrentElementSheetDirection(M)
404 // * mCurrentElementSheetDirection(N)
405 // * mCurrentElementSheetDirection(P)
406 // * mCurrentElementSheetDirection(Q)
407 //
408 // + dTdE_coeff_s2 * mCurrentElementFibreDirection(M)
409 // * mCurrentElementFibreDirection(N)
410 // * invC(P,Q);
411 //
412 // }
413 // }
414 // }
415 // }
416 // }
417 // }
418 }
419 
420 
421 template<class ELASTICITY_SOLVER,unsigned DIM>
423  std::vector<c_matrix<double,DIM,DIM> >& rDeformationGradients,
424  std::vector<double>& rStretches)
425 {
426  assert(rStretches.size()==this->mrQuadMesh.GetNumElements());
427 
428  // this will only work currently if the coarse mesh fibre info is defined per element, not per quad point
429  assert(!mpVariableFibreSheetDirections || !mFibreSheetDirectionsDefinedByQuadraturePoint);
430 
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; // the deformation gradient, F = dx/dX, F_{iM} = dx_i/dX_M
434 
435  static c_matrix<double,DIM,DIM> jacobian;
436  static c_matrix<double,DIM,DIM> inverse_jacobian;
437  double jacobian_determinant;
438  ChastePoint<DIM> quadrature_point; // not needed, but has to be passed in
439 
440  // loop over all the elements
441  for(unsigned elem_index=0; elem_index<this->mrQuadMesh.GetNumElements(); elem_index++)
442  {
443  Element<DIM,DIM>* p_elem = this->mrQuadMesh.GetElement(elem_index);
444 
445  // get the fibre direction for this element
446  SetupChangeOfBasisMatrix(elem_index, 0); // 0 is quad index, and doesn't matter as checked that fibres not defined by quad pt above.
447  for(unsigned i=0; i<DIM; i++)
448  {
449  mCurrentElementFibreDirection(i) = this->mChangeOfBasisMatrix(i,0);
450  }
451 
452  // get the displacement at this element
453  for (unsigned II=0; II<NUM_VERTICES_PER_ELEMENT; II++)
454  {
455  for (unsigned JJ=0; JJ<DIM; JJ++)
456  {
457  // mProblemDimension = DIM for compressible elasticity and DIM+1 for incompressible elasticity
458  element_current_displacements(JJ,II) = this->mCurrentSolution[this->mProblemDimension*p_elem->GetNodeGlobalIndex(II) + JJ];
459  }
460  }
461 
462  // set up the linear basis functions
463  this->mrQuadMesh.GetInverseJacobianForElement(elem_index, jacobian, jacobian_determinant, inverse_jacobian);
464  LinearBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(quadrature_point, inverse_jacobian, grad_lin_phi);
465 
466  F = identity_matrix<double>(DIM,DIM);
467 
468  // loop over the vertices and interpolate F, the deformation gradient
469  // (note: could use matrix-mult if this becomes inefficient
470  for (unsigned node_index=0; node_index<NUM_VERTICES_PER_ELEMENT; node_index++)
471  {
472  for (unsigned i=0; i<DIM; i++)
473  {
474  for (unsigned M=0; M<DIM; M++)
475  {
476  F(i,M) += grad_lin_phi(M,node_index)*element_current_displacements(i,node_index);
477  }
478  }
479  }
480 
481  rDeformationGradients[elem_index] = F;
482 
483  // compute and save the stretch: m^T C m = ||Fm||
484  c_vector<double,DIM> deformed_fibre = prod(F, mCurrentElementFibreDirection);
485  rStretches[elem_index] = norm_2(deformed_fibre);
486  }
487 }
488 
489 
490 template<class ELASTICITY_SOLVER,unsigned DIM>
492 {
493  mFibreSheetDirectionsDefinedByQuadraturePoint = definedPerQuadraturePoint;
494 
495  FibreReader<DIM> reader(rOrthoFile, ORTHO);
496 
497  unsigned num_entries = reader.GetNumLinesOfData();
498 
499  if (!mFibreSheetDirectionsDefinedByQuadraturePoint && (num_entries!=this->mrQuadMesh.GetNumElements()) )
500  {
501  EXCEPTION("Number of entries defined at top of file " << rOrthoFile.GetAbsolutePath() <<
502  " does not match number of elements in the mesh, " << "found " << num_entries <<
503  ", expected " << this->mrQuadMesh.GetNumElements());
504  }
505 
506  if (mFibreSheetDirectionsDefinedByQuadraturePoint && (num_entries!=mTotalQuadPoints) )
507  {
508  EXCEPTION("Number of entries defined at top of file " << rOrthoFile.GetAbsolutePath() <<
509  " does not match number of quadrature points defined, " << "found " << num_entries <<
510  ", expected " << mTotalQuadPoints);
511  }
512 
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++)
515  {
516  reader.GetFibreSheetAndNormalMatrix(index, (*mpVariableFibreSheetDirections)[index] );
517  }
518 }
519 
520 template<class ELASTICITY_SOLVER,unsigned DIM>
522 {
523  mConstantFibreSheetDirections = rFibreSheetMatrix;
524  // check orthogonality
525  c_matrix<double,DIM,DIM> temp = prod(trans(rFibreSheetMatrix),rFibreSheetMatrix);
526  for(unsigned i=0; i<DIM; i++)
527  {
528  for(unsigned j=0; j<DIM; j++)
529  {
530  double val = (i==j ? 1.0 : 0.0);
531  if(fabs(temp(i,j)-val)>1e-4)
532  {
533  EXCEPTION("The given fibre-sheet matrix, " << rFibreSheetMatrix << ", is not orthogonal");
534  }
535  }
536  }
537 }
538 
543 
544 
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
Definition: FileFinder.cpp:221
AbstractCardiacMechanicsSolver(QuadraticMesh< DIM > &rQuadMesh, ElectroMechanicsProblemDefinition< DIM > &rProblemDefinition, std::string outputDirectory)
virtual unsigned GetNumElements() const
#define EXCEPTION(message)
Definition: Exception.hpp:143
static HeartRegionType GetValidBathId()
const AbstractTetrahedralMesh< DIM, DIM > & GetCoarseMesh() const
T Determinant(const boost::numeric::ublas::c_matrix< T, 1, 1 > &rM)
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 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)