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);
83 #define COVERAGE_IGNORE
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");
86 #undef COVERAGE_IGNORE
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);
299 catch(std::bad_alloc &r_bad_alloc)
301 #define COVERAGE_IGNORE
302 std::cout <<
"Failed to allocate std::vector of size " << num_local_elements << std::endl;
305 #undef COVERAGE_IGNORE
309 std::vector<boost::shared_ptr<AbstractChasteRegion<SPACE_DIM> > > conductivities_heterogeneity_areas;
310 std::vector< c_vector<double,3> > intra_h_conductivities;
311 std::vector< c_vector<double,3> > extra_h_conductivities;
313 intra_h_conductivities,
314 extra_h_conductivities);
316 unsigned local_element_index = 0;
319 it != mpMesh->GetElementIteratorEnd();
325 for (
unsigned region_index=0; region_index< conductivities_heterogeneity_areas.size(); region_index++)
327 if ( conductivities_heterogeneity_areas[region_index]->DoesContain(element_centroid) )
330 for (
unsigned i=0; i<SPACE_DIM; i++)
332 hetero_intra_conductivities[local_element_index][i] = intra_h_conductivities[region_index][i];
336 local_element_index++;
339 mpIntracellularConductivityTensors->SetNonConstantConductivities(&hetero_intra_conductivities);
343 mpIntracellularConductivityTensors->SetConstantConductivities(intra_conductivities);
346 mpIntracellularConductivityTensors->Init(this->mpMesh);
351 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
354 mDoCacheReplication = doCacheReplication;
357 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
360 return mDoCacheReplication;
363 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
366 assert( mpIntracellularConductivityTensors);
367 if (mpConductivityModifier==NULL)
369 return (*mpIntracellularConductivityTensors)[elementIndex];
373 return mpConductivityModifier->rGetModifiedConductivityTensor(elementIndex, (*mpIntracellularConductivityTensors)[elementIndex], 0u);
377 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
380 EXCEPTION(
"Monodomain tissues do not have extracellular conductivity tensors.");
383 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
386 assert(mpDistributedVectorFactory->GetLow() <= globalIndex &&
387 globalIndex < mpDistributedVectorFactory->GetHigh());
388 return mCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
391 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
394 assert(mpDistributedVectorFactory->GetLow() <= globalIndex &&
395 globalIndex < mpDistributedVectorFactory->GetHigh());
397 return mPurkinjeCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
400 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
403 std::map<unsigned, unsigned>::const_iterator node_position;
405 if ((node_position=mHaloGlobalToLocalIndexMap.find(globalIndex)) != mHaloGlobalToLocalIndexMap.end())
408 return mHaloCellsDistributed[node_position->second];
411 if ( mpDistributedVectorFactory->IsGlobalIndexLocal(globalIndex) )
414 return mCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
421 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
424 std::set<unsigned> halos_as_set;
427 halos_as_set.insert(mNodesToReceivePerProcess[proc].begin(), mNodesToReceivePerProcess[proc].end());
429 mHaloNodes = std::vector<unsigned>(halos_as_set.begin(), halos_as_set.end());
434 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
439 mpMesh->CalculateNodeExchange(mNodesToSendPerProcess, mNodesToReceivePerProcess);
443 CalculateHaloNodesFromNodeExchange();
444 unsigned num_halo_nodes = mHaloNodes.size();
445 mHaloCellsDistributed.resize( num_halo_nodes );
446 for (
unsigned local_index = 0; local_index < num_halo_nodes; local_index++)
448 unsigned global_index = mHaloNodes[local_index];
453 mHaloGlobalToLocalIndexMap[global_index] = local_index;
462 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
468 assert(!updateVoltage);
477 DistributedVector dist_solution = mpDistributedVectorFactory->CreateDistributedVector(existingSolution);
485 double voltage_before_update;
487 index != dist_solution.
End();
490 voltage_before_update = voltage[index];
491 mCellsDistributed[index.Local]->SetVoltage( voltage_before_update );
502 mCellsDistributed[index.Local]->ComputeExceptVoltage(time, nextTime);
508 mCellsDistributed[index.Local]->ComputeExceptVoltage(time, nextTime);
514 if(dynamic_cast<AbstractCvodeCell*>(mCellsDistributed[index.Local]))
519 WARNING(
"Global node " << index.Global <<
" had an ODE solving problem in t = [" << time <<
520 ", " << nextTime <<
"] ms. This was fixed by a reset of CVODE, but may suggest PDE time"
521 " step should be reduced, or CVODE tolerances relaxed.");
528 #endif // CHASTE_CVODE
533 mCellsDistributed[index.Local]->SolveAndUpdateState(time, nextTime);
534 voltage[index] = mCellsDistributed[index.Local]->GetVoltage();
539 std::cout << std::setprecision(16);
540 std::cout <<
"Global node " << index.Global <<
" had problems with ODE solve between "
541 "t = " << time <<
" and " << nextTime <<
"ms.\n";
543 std::cout <<
"Voltage at this node before solve was " << voltage_before_update <<
"mV\n"
544 "(this SHOULD NOT necessarily be the same as the one in the state variables,\n"
545 "which can be ignored and stay at the initial condition - the voltage is dictated by PDE instead of state variable.)\n";
547 std::cout <<
"Stimulus current (NB converted to micro-Amps per cm^3) applied here is equal to:\n\t"
548 << mCellsDistributed[index.Local]->GetIntracellularStimulus(time) <<
" at t = " << time <<
"ms,\n\t"
549 << mCellsDistributed[index.Local]->GetIntracellularStimulus(nextTime) <<
" at t = " << nextTime <<
"ms.\n";
553 std::cout <<
"All state variables are now:\n";
554 std::vector<double> state_vars = mCellsDistributed[index.Local]->GetStdVecStateVariables();
556 for (
unsigned i=0; i<state_vars.size(); i++)
558 std::cout <<
"\t" << state_var_names[i] <<
"\t:\t" << state_vars[i] <<
"\n";
560 std::cout << std::flush;
565 UpdateCaches(index.Global, index.Local, nextTime);
588 index != dist_solution.
End();
592 mPurkinjeCellsDistributed[index.Local]->SetVoltage( purkinje_voltage[index] );
596 mPurkinjeCellsDistributed[index.Local]->ComputeExceptVoltage(time, nextTime);
599 UpdatePurkinjeCaches(index.Global, index.Local, nextTime);
622 assert(!mHasPurkinje);
629 unsigned number_of_cells_to_send = mNodesToSendPerProcess[send_to].size();
630 unsigned number_of_cells_to_receive = mNodesToReceivePerProcess[receive_from].size();
633 unsigned send_size = 0;
634 for (
unsigned i=0; i<number_of_cells_to_send; i++)
636 unsigned global_cell_index = mNodesToSendPerProcess[send_to][i];
637 send_size += mCellsDistributed[global_cell_index - mpDistributedVectorFactory->GetLow()]->GetNumberOfStateVariables();
640 boost::scoped_array<double> send_data(
new double[send_size]);
642 unsigned send_index = 0;
643 for (
unsigned cell = 0; cell < number_of_cells_to_send; cell++)
645 unsigned global_cell_index = mNodesToSendPerProcess[send_to][cell];
649 for (
unsigned state_variable = 0; state_variable < num_state_vars; state_variable++)
651 send_data[send_index++] = cell_data[state_variable];
655 unsigned receive_size = 0;
656 for (
unsigned i=0; i<number_of_cells_to_receive; i++)
658 unsigned halo_cell_index = mHaloGlobalToLocalIndexMap[mNodesToReceivePerProcess[receive_from][i]];
659 receive_size += mHaloCellsDistributed[halo_cell_index]->GetNumberOfStateVariables();
662 boost::scoped_array<double> receive_data(
new double[receive_size]);
667 ret = MPI_Sendrecv(send_data.get(), send_size,
670 receive_data.get(), receive_size,
673 PETSC_COMM_WORLD, &status);
675 assert ( ret == MPI_SUCCESS);
678 unsigned receive_index = 0;
679 for (
unsigned cell = 0; cell < number_of_cells_to_receive; cell++ )
681 AbstractCardiacCellInterface* p_cell = mHaloCellsDistributed[mHaloGlobalToLocalIndexMap[mNodesToReceivePerProcess[receive_from][cell]]];
684 std::vector<double> cell_data(number_of_state_variables);
685 for (
unsigned state_variable = 0; state_variable < number_of_state_variables; state_variable++)
687 cell_data[state_variable] = receive_data[receive_index++];
695 if ( mDoCacheReplication )
702 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
705 return mIionicCacheReplicated;
708 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
711 return mIntracellularStimulusCacheReplicated;
714 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
718 return mPurkinjeIionicCacheReplicated;
721 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
725 return mPurkinjeIntracellularStimulusCacheReplicated;
728 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
731 mIionicCacheReplicated[globalIndex] = mCellsDistributed[localIndex]->GetIIonic();
732 mIntracellularStimulusCacheReplicated[globalIndex] = mCellsDistributed[localIndex]->GetIntracellularStimulus(nextTime);
735 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
738 assert(mHasPurkinje);
739 mPurkinjeIionicCacheReplicated[globalIndex] = mPurkinjeCellsDistributed[localIndex]->GetIIonic();
740 mPurkinjeIntracellularStimulusCacheReplicated[globalIndex] = mPurkinjeCellsDistributed[localIndex]->GetIntracellularStimulus(nextTime);
743 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
748 assert(!mHasPurkinje);
750 mIionicCacheReplicated.Replicate(mpDistributedVectorFactory->GetLow(), mpDistributedVectorFactory->GetHigh());
751 mIntracellularStimulusCacheReplicated.Replicate(mpDistributedVectorFactory->GetLow(), mpDistributedVectorFactory->GetHigh());
760 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
763 return mCellsDistributed;
766 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
770 return mPurkinjeCellsDistributed;
773 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
779 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
782 assert(pModifier!=NULL);
783 assert(mpConductivityModifier==NULL);
785 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()