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");
93 if (p_purkinje_cell_factory)
104 for (
unsigned local_index = 0; local_index < num_local_nodes; local_index++)
106 unsigned global_index = ownership_range_low + local_index;
140 for (std::vector<AbstractCardiacCellInterface*>::iterator cell_iterator =
mCellsDistributed.begin();
144 delete (*cell_iterator);
178template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
181 mpDistributedVectorFactory(mpMesh->GetDistributedVectorFactory()),
183 mDoCacheReplication(true),
184 mMeshUnarchived(true),
185 mExchangeHalos(false)
194template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
198 for (std::vector<AbstractCardiacCellInterface*>::iterator iter = mCellsDistributed.begin();
199 iter != mCellsDistributed.end();
206 for (std::vector<AbstractCardiacCellInterface*>::iterator iter = mHaloCellsDistributed.begin();
207 iter != mHaloCellsDistributed.end();
213 delete mpIntracellularConductivityTensors;
216 for (std::vector<AbstractCardiacCellInterface*>::iterator iter = mPurkinjeCellsDistributed.begin();
217 iter != mPurkinjeCellsDistributed.end();
231template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
237template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
243 if (mpConfig->IsMeshProvided() && mpConfig->GetLoadMesh())
245 assert(mFibreFilePathNoExtension !=
"");
247 switch (mpConfig->GetConductivityMedia())
249 case cp::media_type::Orthotropic:
253 assert(ortho_file.
Exists());
254 mpIntracellularConductivityTensors->SetFibreOrientationFile(ortho_file);
258 case cp::media_type::Axisymmetric:
262 assert(axi_file.
Exists());
263 mpIntracellularConductivityTensors->SetFibreOrientationFile(axi_file);
267 case cp::media_type::NoFibreOrientation:
282 c_vector<double, SPACE_DIM> intra_conductivities;
283 mpConfig->GetIntracellularConductivities(intra_conductivities);
287 unsigned num_local_elements = mpMesh->GetNumLocalElements();
288 std::vector<c_vector<double, SPACE_DIM> > hetero_intra_conductivities;
290 if (mpConfig->GetConductivityHeterogeneitiesProvided())
294 assert(hetero_intra_conductivities.size()==0);
295 hetero_intra_conductivities.resize(num_local_elements, intra_conductivities);
298 catch(std::bad_alloc &r_bad_alloc)
300 std::cout <<
"Failed to allocate std::vector of size " << num_local_elements << std::endl;
308 std::vector<boost::shared_ptr<AbstractChasteRegion<SPACE_DIM> > > conductivities_heterogeneity_areas;
309 std::vector< c_vector<double,3> > intra_h_conductivities;
310 std::vector< c_vector<double,3> > extra_h_conductivities;
312 intra_h_conductivities,
313 extra_h_conductivities);
315 unsigned local_element_index = 0;
318 it != mpMesh->GetElementIteratorEnd();
324 for (
unsigned region_index=0; region_index< conductivities_heterogeneity_areas.size(); region_index++)
326 if (conductivities_heterogeneity_areas[region_index]->DoesContain(element_centroid))
329 for (
unsigned i=0; i<SPACE_DIM; i++)
331 hetero_intra_conductivities[local_element_index][i] = intra_h_conductivities[region_index][i];
335 local_element_index++;
338 mpIntracellularConductivityTensors->SetNonConstantConductivities(&hetero_intra_conductivities);
342 mpIntracellularConductivityTensors->SetConstantConductivities(intra_conductivities);
345 mpIntracellularConductivityTensors->Init(this->mpMesh);
350template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
353 mDoCacheReplication = doCacheReplication;
356template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
359 return mDoCacheReplication;
362template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
365 assert( mpIntracellularConductivityTensors);
366 if (mpConductivityModifier==NULL)
368 return (*mpIntracellularConductivityTensors)[elementIndex];
372 return mpConductivityModifier->rGetModifiedConductivityTensor(elementIndex, (*mpIntracellularConductivityTensors)[elementIndex], 0u);
376template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
379 EXCEPTION(
"Monodomain tissues do not have extracellular conductivity tensors.");
382template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
385 assert(mpDistributedVectorFactory->GetLow() <= globalIndex &&
386 globalIndex < mpDistributedVectorFactory->GetHigh());
387 return mCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
390template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
393 assert(mpDistributedVectorFactory->GetLow() <= globalIndex &&
394 globalIndex < mpDistributedVectorFactory->GetHigh());
396 return mPurkinjeCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
399template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
402 std::map<unsigned, unsigned>::const_iterator node_position;
404 if ((node_position=mHaloGlobalToLocalIndexMap.find(globalIndex)) != mHaloGlobalToLocalIndexMap.end())
407 return mHaloCellsDistributed[node_position->second];
410 if (mpDistributedVectorFactory->IsGlobalIndexLocal(globalIndex))
413 return mCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
420template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
423 std::set<unsigned> halos_as_set;
426 halos_as_set.insert(mNodesToReceivePerProcess[proc].begin(), mNodesToReceivePerProcess[proc].end());
428 mHaloNodes = std::vector<unsigned>(halos_as_set.begin(), halos_as_set.end());
433template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
438 mpMesh->CalculateNodeExchange(mNodesToSendPerProcess, mNodesToReceivePerProcess);
442 CalculateHaloNodesFromNodeExchange();
443 unsigned num_halo_nodes = mHaloNodes.size();
444 mHaloCellsDistributed.resize( num_halo_nodes );
445 for (
unsigned local_index = 0; local_index < num_halo_nodes; local_index++)
447 unsigned global_index = mHaloNodes[local_index];
452 mHaloGlobalToLocalIndexMap[global_index] = local_index;
461template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
467 assert(!updateVoltage);
476 DistributedVector dist_solution = mpDistributedVectorFactory->CreateDistributedVector(existingSolution);
484 double voltage_before_update;
486 index != dist_solution.
End();
489 voltage_before_update = voltage[index];
490 mCellsDistributed[index.Local]->SetVoltage( voltage_before_update );
501 mCellsDistributed[index.Local]->ComputeExceptVoltage(time, nextTime);
507 mCellsDistributed[index.Local]->ComputeExceptVoltage(time, nextTime);
518 WARNING(
"Global node " << index.Global <<
" had an ODE solving problem in t = [" << time <<
519 ", " << nextTime <<
"] ms. This was fixed by a reset of CVODE, but may suggest PDE time"
520 " step should be reduced, or CVODE tolerances relaxed.");
532 mCellsDistributed[index.Local]->SolveAndUpdateState(time, nextTime);
533 voltage[index] = mCellsDistributed[index.Local]->GetVoltage();
538 std::cout << std::setprecision(16);
539 std::cout <<
"Global node " << index.Global <<
" had problems with ODE solve between "
540 "t = " << time <<
" and " << nextTime <<
"ms.\n";
542 std::cout <<
"Voltage at this node before solve was " << voltage_before_update <<
"mV\n"
543 "(this SHOULD NOT necessarily be the same as the one in the state variables,\n"
544 "which can be ignored and stay at the initial condition - the voltage is dictated by PDE instead of state variable.)\n";
546 std::cout <<
"Stimulus current (NB converted to micro-Amps per cm^3) applied here is equal to:\n\t"
547 << mCellsDistributed[index.Local]->GetIntracellularStimulus(time) <<
" at t = " << time <<
"ms,\n\t"
548 << mCellsDistributed[index.Local]->GetIntracellularStimulus(nextTime) <<
" at t = " << nextTime <<
"ms.\n";
552 std::cout <<
"All state variables are now:\n";
553 std::vector<double> state_vars = mCellsDistributed[index.Local]->GetStdVecStateVariables();
555 for (
unsigned i=0; i<state_vars.size(); i++)
557 std::cout <<
"\t" << state_var_names[i] <<
"\t:\t" << state_vars[i] <<
"\n";
559 std::cout << std::flush;
564 UpdateCaches(index.Global, index.Local, nextTime);
587 index != dist_solution.
End();
591 mPurkinjeCellsDistributed[index.Local]->SetVoltage( purkinje_voltage[index] );
595 mPurkinjeCellsDistributed[index.Local]->ComputeExceptVoltage(time, nextTime);
598 UpdatePurkinjeCaches(index.Global, index.Local, nextTime);
621 assert(!mHasPurkinje);
628 unsigned number_of_cells_to_send = mNodesToSendPerProcess[send_to].size();
629 unsigned number_of_cells_to_receive = mNodesToReceivePerProcess[receive_from].size();
632 unsigned send_size = 0;
633 for (
unsigned i=0; i<number_of_cells_to_send; i++)
635 unsigned global_cell_index = mNodesToSendPerProcess[send_to][i];
636 send_size += mCellsDistributed[global_cell_index - mpDistributedVectorFactory->GetLow()]->GetNumberOfStateVariables();
639 boost::scoped_array<double> send_data(
new double[send_size]);
641 unsigned send_index = 0;
642 for (
unsigned cell = 0; cell < number_of_cells_to_send; cell++)
644 unsigned global_cell_index = mNodesToSendPerProcess[send_to][cell];
648 for (
unsigned state_variable = 0; state_variable < num_state_vars; state_variable++)
650 send_data[send_index++] = cell_data[state_variable];
654 unsigned receive_size = 0;
655 for (
unsigned i=0; i<number_of_cells_to_receive; i++)
657 unsigned halo_cell_index = mHaloGlobalToLocalIndexMap[mNodesToReceivePerProcess[receive_from][i]];
658 receive_size += mHaloCellsDistributed[halo_cell_index]->GetNumberOfStateVariables();
661 boost::scoped_array<double> receive_data(
new double[receive_size]);
666 ret = MPI_Sendrecv(send_data.get(), send_size,
669 receive_data.get(), receive_size,
672 PETSC_COMM_WORLD, &status);
674 assert ( ret == MPI_SUCCESS);
677 unsigned receive_index = 0;
678 for (
unsigned cell = 0; cell < number_of_cells_to_receive; cell++ )
680 AbstractCardiacCellInterface* p_cell = mHaloCellsDistributed[mHaloGlobalToLocalIndexMap[mNodesToReceivePerProcess[receive_from][cell]]];
683 std::vector<double> cell_data(number_of_state_variables);
684 for (
unsigned state_variable = 0; state_variable < number_of_state_variables; state_variable++)
686 cell_data[state_variable] = receive_data[receive_index++];
694 if (mDoCacheReplication)
701template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
704 return mIionicCacheReplicated;
707template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
710 return mIntracellularStimulusCacheReplicated;
713template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
717 return mPurkinjeIionicCacheReplicated;
720template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
724 return mPurkinjeIntracellularStimulusCacheReplicated;
727template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
730 mIionicCacheReplicated[globalIndex] = mCellsDistributed[localIndex]->GetIIonic();
731 mIntracellularStimulusCacheReplicated[globalIndex] = mCellsDistributed[localIndex]->GetIntracellularStimulus(nextTime);
734template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
737 assert(mHasPurkinje);
738 mPurkinjeIionicCacheReplicated[globalIndex] = mPurkinjeCellsDistributed[localIndex]->GetIIonic();
739 mPurkinjeIntracellularStimulusCacheReplicated[globalIndex] = mPurkinjeCellsDistributed[localIndex]->GetIntracellularStimulus(nextTime);
742template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
747 assert(!mHasPurkinje);
749 mIionicCacheReplicated.Replicate(mpDistributedVectorFactory->GetLow(), mpDistributedVectorFactory->GetHigh());
750 mIntracellularStimulusCacheReplicated.Replicate(mpDistributedVectorFactory->GetLow(), mpDistributedVectorFactory->GetHigh());
759template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
762 return mCellsDistributed;
765template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
769 return mPurkinjeCellsDistributed;
772template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
778template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
781 assert(pModifier!=NULL);
782 assert(mpConductivityModifier==NULL);
784 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)
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)