36#include "AbstractCardiacTissue.hpp"
38#include <boost/scoped_array.hpp>
40#include "DistributedVector.hpp"
41#include "AxisymmetricConductivityTensors.hpp"
42#include "OrthotropicConductivityTensors.hpp"
44#include "ChastePoint.hpp"
45#include "AbstractChasteRegion.hpp"
46#include "HeartEventHandler.hpp"
48#include "PetscVecTools.hpp"
49#include "AbstractCvodeCell.hpp"
50#include "Warnings.hpp"
52template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
56 : mpMesh(pCellFactory->GetMesh()),
57 mpDistributedVectorFactory(mpMesh->GetDistributedVectorFactory()),
58 mpConductivityModifier(NULL),
60 mDoCacheReplication(true),
61 mMeshUnarchived(false),
62 mExchangeHalos(exchangeHalos)
65 assert(pCellFactory != NULL);
66 assert(pCellFactory->
GetMesh() != NULL);
75 bool process_has_no_nodes = (num_local_nodes == 0u);
85 EXCEPTION(
"No cells were assigned some process in AbstractCardiacTissue constructor. Advice: Make total number of processors no greater than number of nodes in the mesh");
94 if (p_purkinje_cell_factory)
105 for (
unsigned local_index = 0; local_index < num_local_nodes; local_index++)
107 unsigned global_index = ownership_range_low + local_index;
142 for (std::vector<AbstractCardiacCellInterface*>::iterator cell_iterator =
mCellsDistributed.begin();
146 delete (*cell_iterator);
180template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
183 mpDistributedVectorFactory(mpMesh->GetDistributedVectorFactory()),
185 mDoCacheReplication(true),
186 mMeshUnarchived(true),
187 mExchangeHalos(false)
196template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
200 for (std::vector<AbstractCardiacCellInterface*>::iterator iter = mCellsDistributed.begin();
201 iter != mCellsDistributed.end();
208 for (std::vector<AbstractCardiacCellInterface*>::iterator iter = mHaloCellsDistributed.begin();
209 iter != mHaloCellsDistributed.end();
215 delete mpIntracellularConductivityTensors;
218 for (std::vector<AbstractCardiacCellInterface*>::iterator iter = mPurkinjeCellsDistributed.begin();
219 iter != mPurkinjeCellsDistributed.end();
233template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
239template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
245 if (mpConfig->IsMeshProvided() && mpConfig->GetLoadMesh())
247 assert(mFibreFilePathNoExtension !=
"");
249 switch (mpConfig->GetConductivityMedia())
251 case cp::media_type::Orthotropic:
255 assert(ortho_file.
Exists());
256 mpIntracellularConductivityTensors->SetFibreOrientationFile(ortho_file);
260 case cp::media_type::Axisymmetric:
264 assert(axi_file.
Exists());
265 mpIntracellularConductivityTensors->SetFibreOrientationFile(axi_file);
269 case cp::media_type::NoFibreOrientation:
284 c_vector<double, SPACE_DIM> intra_conductivities;
285 mpConfig->GetIntracellularConductivities(intra_conductivities);
289 unsigned num_local_elements = mpMesh->GetNumLocalElements();
290 std::vector<c_vector<double, SPACE_DIM> > hetero_intra_conductivities;
292 if (mpConfig->GetConductivityHeterogeneitiesProvided())
296 assert(hetero_intra_conductivities.size()==0);
297 hetero_intra_conductivities.resize(num_local_elements, intra_conductivities);
300 catch(std::bad_alloc &r_bad_alloc)
302 std::cout <<
"Failed to allocate std::vector of size " << num_local_elements << std::endl;
310 std::vector<boost::shared_ptr<AbstractChasteRegion<SPACE_DIM> > > conductivities_heterogeneity_areas;
311 std::vector< c_vector<double,3> > intra_h_conductivities;
312 std::vector< c_vector<double,3> > extra_h_conductivities;
314 intra_h_conductivities,
315 extra_h_conductivities);
317 unsigned local_element_index = 0;
320 it != mpMesh->GetElementIteratorEnd();
326 for (
unsigned region_index=0; region_index< conductivities_heterogeneity_areas.size(); region_index++)
328 if (conductivities_heterogeneity_areas[region_index]->DoesContain(element_centroid))
331 for (
unsigned i=0; i<SPACE_DIM; i++)
333 hetero_intra_conductivities[local_element_index][i] = intra_h_conductivities[region_index][i];
337 local_element_index++;
340 mpIntracellularConductivityTensors->SetNonConstantConductivities(&hetero_intra_conductivities);
344 mpIntracellularConductivityTensors->SetConstantConductivities(intra_conductivities);
347 mpIntracellularConductivityTensors->Init(this->mpMesh);
352template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
355 mDoCacheReplication = doCacheReplication;
358template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
361 return mDoCacheReplication;
364template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
367 assert( mpIntracellularConductivityTensors);
368 if (mpConductivityModifier==NULL)
370 return (*mpIntracellularConductivityTensors)[elementIndex];
374 return mpConductivityModifier->rGetModifiedConductivityTensor(elementIndex, (*mpIntracellularConductivityTensors)[elementIndex], 0u);
378template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
381 EXCEPTION(
"Monodomain tissues do not have extracellular conductivity tensors.");
384template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
387 assert(mpDistributedVectorFactory->GetLow() <= globalIndex &&
388 globalIndex < mpDistributedVectorFactory->GetHigh());
389 return mCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
392template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
395 assert(mpDistributedVectorFactory->GetLow() <= globalIndex &&
396 globalIndex < mpDistributedVectorFactory->GetHigh());
398 return mPurkinjeCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
401template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
404 std::map<unsigned, unsigned>::const_iterator node_position;
406 if ((node_position=mHaloGlobalToLocalIndexMap.find(globalIndex)) != mHaloGlobalToLocalIndexMap.end())
409 return mHaloCellsDistributed[node_position->second];
412 if (mpDistributedVectorFactory->IsGlobalIndexLocal(globalIndex))
415 return mCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
422template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
425 std::set<unsigned> halos_as_set;
428 halos_as_set.insert(mNodesToReceivePerProcess[proc].begin(), mNodesToReceivePerProcess[proc].end());
430 mHaloNodes = std::vector<unsigned>(halos_as_set.begin(), halos_as_set.end());
435template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
440 mpMesh->CalculateNodeExchange(mNodesToSendPerProcess, mNodesToReceivePerProcess);
444 CalculateHaloNodesFromNodeExchange();
445 unsigned num_halo_nodes = mHaloNodes.size();
446 mHaloCellsDistributed.resize( num_halo_nodes );
447 for (
unsigned local_index = 0; local_index < num_halo_nodes; local_index++)
449 unsigned global_index = mHaloNodes[local_index];
454 mHaloGlobalToLocalIndexMap[global_index] = local_index;
463template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
469 assert(!updateVoltage);
478 DistributedVector dist_solution = mpDistributedVectorFactory->CreateDistributedVector(existingSolution);
486 double voltage_before_update;
488 index != dist_solution.
End();
491 voltage_before_update = voltage[index];
492 mCellsDistributed[index.Local]->SetVoltage( voltage_before_update );
503 mCellsDistributed[index.Local]->ComputeExceptVoltage(time, nextTime);
509 mCellsDistributed[index.Local]->ComputeExceptVoltage(time, nextTime);
520 WARNING(
"Global node " << index.Global <<
" had an ODE solving problem in t = [" << time <<
521 ", " << nextTime <<
"] ms. This was fixed by a reset of CVODE, but may suggest PDE time"
522 " step should be reduced, or CVODE tolerances relaxed.");
534 mCellsDistributed[index.Local]->SolveAndUpdateState(time, nextTime);
535 voltage[index] = mCellsDistributed[index.Local]->GetVoltage();
540 std::cout << std::setprecision(16);
541 std::cout <<
"Global node " << index.Global <<
" had problems with ODE solve between "
542 "t = " << time <<
" and " << nextTime <<
"ms.\n";
544 std::cout <<
"Voltage at this node before solve was " << voltage_before_update <<
"mV\n"
545 "(this SHOULD NOT necessarily be the same as the one in the state variables,\n"
546 "which can be ignored and stay at the initial condition - the voltage is dictated by PDE instead of state variable.)\n";
548 std::cout <<
"Stimulus current (NB converted to micro-Amps per cm^3) applied here is equal to:\n\t"
549 << mCellsDistributed[index.Local]->GetIntracellularStimulus(time) <<
" at t = " << time <<
"ms,\n\t"
550 << mCellsDistributed[index.Local]->GetIntracellularStimulus(nextTime) <<
" at t = " << nextTime <<
"ms.\n";
554 std::cout <<
"All state variables are now:\n";
555 std::vector<double> state_vars = mCellsDistributed[index.Local]->GetStdVecStateVariables();
557 for (
unsigned i=0; i<state_vars.size(); i++)
559 std::cout <<
"\t" << state_var_names[i] <<
"\t:\t" << state_vars[i] <<
"\n";
561 std::cout << std::flush;
566 UpdateCaches(index.Global, index.Local, nextTime);
589 index != dist_solution.
End();
593 mPurkinjeCellsDistributed[index.Local]->SetVoltage( purkinje_voltage[index] );
597 mPurkinjeCellsDistributed[index.Local]->ComputeExceptVoltage(time, nextTime);
600 UpdatePurkinjeCaches(index.Global, index.Local, nextTime);
623 assert(!mHasPurkinje);
630 unsigned number_of_cells_to_send = mNodesToSendPerProcess[send_to].size();
631 unsigned number_of_cells_to_receive = mNodesToReceivePerProcess[receive_from].size();
634 unsigned send_size = 0;
635 for (
unsigned i=0; i<number_of_cells_to_send; i++)
637 unsigned global_cell_index = mNodesToSendPerProcess[send_to][i];
638 send_size += mCellsDistributed[global_cell_index - mpDistributedVectorFactory->GetLow()]->GetNumberOfStateVariables();
641 boost::scoped_array<double> send_data(
new double[send_size]);
643 unsigned send_index = 0;
644 for (
unsigned cell = 0; cell < number_of_cells_to_send; cell++)
646 unsigned global_cell_index = mNodesToSendPerProcess[send_to][cell];
650 for (
unsigned state_variable = 0; state_variable < num_state_vars; state_variable++)
652 send_data[send_index++] = cell_data[state_variable];
656 unsigned receive_size = 0;
657 for (
unsigned i=0; i<number_of_cells_to_receive; i++)
659 unsigned halo_cell_index = mHaloGlobalToLocalIndexMap[mNodesToReceivePerProcess[receive_from][i]];
660 receive_size += mHaloCellsDistributed[halo_cell_index]->GetNumberOfStateVariables();
663 boost::scoped_array<double> receive_data(
new double[receive_size]);
668 ret = MPI_Sendrecv(send_data.get(), send_size,
671 receive_data.get(), receive_size,
674 PETSC_COMM_WORLD, &status);
676 assert ( ret == MPI_SUCCESS);
679 unsigned receive_index = 0;
680 for (
unsigned cell = 0; cell < number_of_cells_to_receive; cell++ )
682 AbstractCardiacCellInterface* p_cell = mHaloCellsDistributed[mHaloGlobalToLocalIndexMap[mNodesToReceivePerProcess[receive_from][cell]]];
685 std::vector<double> cell_data(number_of_state_variables);
686 for (
unsigned state_variable = 0; state_variable < number_of_state_variables; state_variable++)
688 cell_data[state_variable] = receive_data[receive_index++];
696 if (mDoCacheReplication)
703template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
706 return mIionicCacheReplicated;
709template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
712 return mIntracellularStimulusCacheReplicated;
715template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
719 return mPurkinjeIionicCacheReplicated;
722template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
726 return mPurkinjeIntracellularStimulusCacheReplicated;
729template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
732 mIionicCacheReplicated[globalIndex] = mCellsDistributed[localIndex]->GetIIonic();
733 mIntracellularStimulusCacheReplicated[globalIndex] = mCellsDistributed[localIndex]->GetIntracellularStimulus(nextTime);
736template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
739 assert(mHasPurkinje);
740 mPurkinjeIionicCacheReplicated[globalIndex] = mPurkinjeCellsDistributed[localIndex]->GetIIonic();
741 mPurkinjeIntracellularStimulusCacheReplicated[globalIndex] = mPurkinjeCellsDistributed[localIndex]->GetIntracellularStimulus(nextTime);
744template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
749 assert(!mHasPurkinje);
751 mIionicCacheReplicated.Replicate(mpDistributedVectorFactory->GetLow(), mpDistributedVectorFactory->GetHigh());
752 mIntracellularStimulusCacheReplicated.Replicate(mpDistributedVectorFactory->GetLow(), mpDistributedVectorFactory->GetHigh());
761template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
764 return mCellsDistributed;
767template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
771 return mPurkinjeCellsDistributed;
774template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
780template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
783 assert(pModifier!=NULL);
784 assert(mpConductivityModifier==NULL);
786 mpConductivityModifier = pModifier;
#define EXCEPTION(message)
#define EXCEPT_IF_NOT(test)
virtual AbstractCardiacCellInterface * CreateCardiacCellForNode(Node< SPACE_DIM > *pNode)
AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > * GetMesh()
virtual void FinaliseCellCreation(std::vector< AbstractCardiacCellInterface * > *pCellsDistributed, unsigned lo, unsigned hi)
virtual unsigned GetNumberOfCells()
virtual void SetStateVariables(const std::vector< double > &rVariables)=0
void SetUsedInTissueSimulation(bool tissue=true)
virtual unsigned GetNumberOfStateVariables() const =0
virtual std::vector< double > GetStdVecStateVariables()=0
const std::vector< AbstractCardiacCellInterface * > & rGetPurkinjeCellsDistributed() const
ReplicatableVector mPurkinjeIntracellularStimulusCacheReplicated
ReplicatableVector & rGetIionicCacheReplicated()
ReplicatableVector mIntracellularStimulusCacheReplicated
const AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > * pGetMesh() const
std::string mFibreFilePathNoExtension
AbstractCardiacCellInterface * GetCardiacCellOrHaloCell(unsigned globalIndex)
void UpdateCaches(unsigned globalIndex, unsigned localIndex, double nextTime)
void UpdatePurkinjeCaches(unsigned globalIndex, unsigned localIndex, double nextTime)
const std::vector< AbstractCardiacCellInterface * > & rGetCellsDistributed() const
ReplicatableVector & rGetPurkinjeIntracellularStimulusCacheReplicated()
virtual void SolveCellSystems(Vec existingSolution, double time, double nextTime, bool updateVoltage=false)
ReplicatableVector & rGetIntracellularStimulusCacheReplicated()
void CalculateHaloNodesFromNodeExchange()
DistributedVectorFactory * mpDistributedVectorFactory
void SetCacheReplication(bool doCacheReplication)
bool GetDoCacheReplication()
ReplicatableVector & rGetPurkinjeIionicCacheReplicated()
std::vector< AbstractCardiacCellInterface * > mPurkinjeCellsDistributed
AbstractCardiacCellInterface * GetPurkinjeCell(unsigned globalIndex)
void CreateIntracellularConductivityTensor()
void SetConductivityModifier(AbstractConductivityModifier< ELEMENT_DIM, SPACE_DIM > *pModifier)
std::vector< AbstractCardiacCellInterface * > mCellsDistributed
virtual ~AbstractCardiacTissue()
ReplicatableVector mPurkinjeIionicCacheReplicated
void SetUpHaloCells(AbstractCardiacCellFactory< ELEMENT_DIM, SPACE_DIM > *pCellFactory)
AbstractCardiacCellInterface * GetCardiacCell(unsigned globalIndex)
virtual const c_matrix< double, SPACE_DIM, SPACE_DIM > & rGetExtracellularConductivityTensor(unsigned elementIndex)
const c_matrix< double, SPACE_DIM, SPACE_DIM > & rGetIntracellularConductivityTensor(unsigned elementIndex)
AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > * mpMesh
AbstractCardiacTissue(AbstractCardiacCellFactory< ELEMENT_DIM, SPACE_DIM > *pCellFactory, bool exchangeHalos=false)
ReplicatableVector mIionicCacheReplicated
void ComputeExceptVoltage(double tStart, double tEnd)
virtual void FinalisePurkinjeCellCreation(std::vector< AbstractCardiacCellInterface * > *pPurkinjeCellsDistributed, unsigned lo, unsigned hi)
AbstractCardiacCellInterface * CreatePurkinjeCellForNode(Node< SPACE_DIM > *pNode, AbstractCardiacCellInterface *pCardiacCell)
const std::vector< std::string > & rGetStateVariableNames() const
static std::string GetMeshFilename()
static std::string GetArchiveDirectory()
unsigned GetProblemSize() const
unsigned GetLocalOwnership() const
static void BeginEvent(unsigned event)
static void EndEvent(unsigned event)
std::string GetMeshName() const
void GetConductivityHeterogeneities(std::vector< boost::shared_ptr< AbstractChasteRegion< DIM > > > &conductivitiesHeterogeneityAreas, std::vector< c_vector< double, 3 > > &intraConductivities, std::vector< c_vector< double, 3 > > &extraConductivities) const
static HeartConfig * Instance()
void Resize(unsigned size)