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"
52 template <
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);
180 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
183 mpDistributedVectorFactory(mpMesh->GetDistributedVectorFactory()),
185 mDoCacheReplication(true),
186 mMeshUnarchived(true),
187 mExchangeHalos(false)
196 template <
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();
233 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
239 template <
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);
352 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
355 mDoCacheReplication = doCacheReplication;
358 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
361 return mDoCacheReplication;
364 template <
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);
378 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
381 EXCEPTION(
"Monodomain tissues do not have extracellular conductivity tensors.");
384 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
387 assert(mpDistributedVectorFactory->GetLow() <= globalIndex &&
388 globalIndex < mpDistributedVectorFactory->GetHigh());
389 return mCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
392 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
395 assert(mpDistributedVectorFactory->GetLow() <= globalIndex &&
396 globalIndex < mpDistributedVectorFactory->GetHigh());
398 return mPurkinjeCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
401 template <
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()];
422 template <
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());
435 template <
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;
463 template <
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);
515 if (dynamic_cast<AbstractCvodeCell*>(mCellsDistributed[index.Local]))
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.");
529 #endif // CHASTE_CVODE
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)
703 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
706 return mIionicCacheReplicated;
709 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
712 return mIntracellularStimulusCacheReplicated;
715 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
719 return mPurkinjeIionicCacheReplicated;
722 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
726 return mPurkinjeIntracellularStimulusCacheReplicated;
729 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
732 mIionicCacheReplicated[globalIndex] = mCellsDistributed[localIndex]->GetIIonic();
733 mIntracellularStimulusCacheReplicated[globalIndex] = mCellsDistributed[localIndex]->GetIntracellularStimulus(nextTime);
736 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
739 assert(mHasPurkinje);
740 mPurkinjeIionicCacheReplicated[globalIndex] = mPurkinjeCellsDistributed[localIndex]->GetIIonic();
741 mPurkinjeIntracellularStimulusCacheReplicated[globalIndex] = mPurkinjeCellsDistributed[localIndex]->GetIntracellularStimulus(nextTime);
744 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
749 assert(!mHasPurkinje);
751 mIionicCacheReplicated.Replicate(mpDistributedVectorFactory->GetLow(), mpDistributedVectorFactory->GetHigh());
752 mIntracellularStimulusCacheReplicated.Replicate(mpDistributedVectorFactory->GetLow(), mpDistributedVectorFactory->GetHigh());
761 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
764 return mCellsDistributed;
767 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
771 return mPurkinjeCellsDistributed;
774 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
780 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
783 assert(pModifier!=NULL);
784 assert(mpConductivityModifier==NULL);
786 mpConductivityModifier = pModifier;
virtual void FinaliseCellCreation(std::vector< AbstractCardiacCellInterface * > *pCellsDistributed, unsigned lo, unsigned hi)
ReplicatableVector mIntracellularStimulusCacheReplicated
virtual AbstractCardiacCellInterface * CreateCardiacCellForNode(Node< SPACE_DIM > *pNode)
void SetConductivityModifier(AbstractConductivityModifier< ELEMENT_DIM, SPACE_DIM > *pModifier)
void CreateIntracellularConductivityTensor()
DistributedVectorFactory * mpDistributedVectorFactory
AbstractCardiacCellInterface * CreatePurkinjeCellForNode(Node< SPACE_DIM > *pNode, AbstractCardiacCellInterface *pCardiacCell)
virtual unsigned GetNumberOfCells()
ReplicatableVector & rGetPurkinjeIionicCacheReplicated()
AbstractCardiacTissue(AbstractCardiacCellFactory< ELEMENT_DIM, SPACE_DIM > *pCellFactory, bool exchangeHalos=false)
AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > * GetMesh()
virtual void SolveCellSystems(Vec existingSolution, double time, double nextTime, bool updateVoltage=false)
static std::string GetMeshFilename()
#define EXCEPTION(message)
static void BeginEvent(unsigned event)
virtual ~AbstractCardiacTissue()
void UpdateCaches(unsigned globalIndex, unsigned localIndex, double nextTime)
ReplicatableVector mPurkinjeIionicCacheReplicated
void SetUsedInTissueSimulation(bool tissue=true)
std::vector< AbstractCardiacCellInterface * > mPurkinjeCellsDistributed
virtual std::vector< double > GetStdVecStateVariables()=0
const std::vector< std::string > & rGetStateVariableNames() const
ReplicatableVector mPurkinjeIntracellularStimulusCacheReplicated
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
virtual void SetStateVariables(const std::vector< double > &rVariables)=0
virtual unsigned GetNumberOfStateVariables() const =0
std::vector< AbstractCardiacCellInterface * > mCellsDistributed
bool GetDoCacheReplication()
AbstractCardiacCellInterface * GetCardiacCellOrHaloCell(unsigned globalIndex)
std::string mFibreFilePathNoExtension
ReplicatableVector & rGetIntracellularStimulusCacheReplicated()
AbstractCardiacCellInterface * GetPurkinjeCell(unsigned globalIndex)
void SetUpHaloCells(AbstractCardiacCellFactory< ELEMENT_DIM, SPACE_DIM > *pCellFactory)
unsigned GetProblemSize() const
virtual void FinalisePurkinjeCellCreation(std::vector< AbstractCardiacCellInterface * > *pPurkinjeCellsDistributed, unsigned lo, unsigned hi)
ReplicatableVector mIionicCacheReplicated
AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > * mpMesh
void ComputeExceptVoltage(double tStart, double tEnd)
#define EXCEPT_IF_NOT(test)
const std::vector< AbstractCardiacCellInterface * > & rGetCellsDistributed() const
virtual const c_matrix< double, SPACE_DIM, SPACE_DIM > & rGetExtracellularConductivityTensor(unsigned elementIndex)
unsigned GetLocalOwnership() const
void Resize(unsigned size)
const std::vector< AbstractCardiacCellInterface * > & rGetPurkinjeCellsDistributed() const
void CalculateHaloNodesFromNodeExchange()
void SetCacheReplication(bool doCacheReplication)
ReplicatableVector & rGetPurkinjeIntracellularStimulusCacheReplicated()
static void EndEvent(unsigned event)
const c_matrix< double, SPACE_DIM, SPACE_DIM > & rGetIntracellularConductivityTensor(unsigned elementIndex)
static std::string GetArchiveDirectory()
AbstractCardiacCellInterface * GetCardiacCell(unsigned globalIndex)
void UpdatePurkinjeCaches(unsigned globalIndex, unsigned localIndex, double nextTime)
static HeartConfig * Instance()
const AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > * pGetMesh() const
ReplicatableVector & rGetIionicCacheReplicated()