Chaste Release::3.1
AbstractCardiacTissue.cpp
00001 /*
00002 
00003 Copyright (c) 2005-2012, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 
00036 #include "AbstractCardiacTissue.hpp"
00037 
00038 #include "DistributedVector.hpp"
00039 #include "AxisymmetricConductivityTensors.hpp"
00040 #include "OrthotropicConductivityTensors.hpp"
00041 #include "Exception.hpp"
00042 #include "ChastePoint.hpp"
00043 #include "AbstractChasteRegion.hpp"
00044 #include "HeartEventHandler.hpp"
00045 #include "PetscTools.hpp"
00046 #include "PetscVecTools.hpp"
00047 
00048 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00049 AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::AbstractCardiacTissue(
00050             AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory,
00051             bool exchangeHalos)
00052     : mpMesh(pCellFactory->GetMesh()),
00053       mpDistributedVectorFactory(mpMesh->GetDistributedVectorFactory()),
00054       mpConductivityModifier(NULL),
00055       mHasPurkinje(false),
00056       mDoCacheReplication(true),
00057       mMeshUnarchived(false),
00058       mExchangeHalos(exchangeHalos)
00059 {
00060     //This constructor is called from the Initialise() method of the CardiacProblem class
00061     assert(pCellFactory != NULL);
00062     assert(pCellFactory->GetMesh() != NULL);
00063 
00064     if (PetscTools::IsSequential())
00065     {
00066         //Remove the request for a halo exchange
00067         mExchangeHalos = false;
00068     }
00069 
00070     unsigned num_local_nodes = mpDistributedVectorFactory->GetLocalOwnership();
00071     unsigned ownership_range_low = mpDistributedVectorFactory->GetLow();
00072     mCellsDistributed.resize(num_local_nodes);
00073 
00074     // Figure out if we're dealing with Purkinje
00075     AbstractPurkinjeCellFactory<ELEMENT_DIM,SPACE_DIM>* p_purkinje_cell_factory
00076        = dynamic_cast<AbstractPurkinjeCellFactory<ELEMENT_DIM,SPACE_DIM>*>(pCellFactory);
00077     if (p_purkinje_cell_factory)
00078     {
00079         mHasPurkinje = true;
00080         mPurkinjeCellsDistributed.resize(num_local_nodes);
00081     }
00082 
00084     // Set up cells
00086     try
00087     {
00088         for (unsigned local_index = 0; local_index < num_local_nodes; local_index++)
00089         {
00090             unsigned global_index = ownership_range_low + local_index;
00091             mCellsDistributed[local_index] = pCellFactory->CreateCardiacCellForNode(global_index);
00092             mCellsDistributed[local_index]->SetUsedInTissueSimulation();
00093 
00094             if (mHasPurkinje)
00095             {
00096                 mPurkinjeCellsDistributed[local_index]
00097                     = p_purkinje_cell_factory->CreatePurkinjeCellForNode(global_index, mCellsDistributed[local_index]);
00098                 mPurkinjeCellsDistributed[local_index]->SetUsedInTissueSimulation();
00099             }
00100         }
00101 
00102         pCellFactory->FinaliseCellCreation(&mCellsDistributed,
00103                                            mpDistributedVectorFactory->GetLow(),
00104                                            mpDistributedVectorFactory->GetHigh());
00105         if (mHasPurkinje)
00106         {
00107             p_purkinje_cell_factory->FinalisePurkinjeCellCreation(&mPurkinjeCellsDistributed,
00108                                                                   mpDistributedVectorFactory->GetLow(),
00109                                                                   mpDistributedVectorFactory->GetHigh());
00110         }
00111     }
00112     catch (const Exception& e)
00113     {
00114         // This catch statement is quite tricky to cover, but it is actually done in TestCardiacSimulation::TestMono1dSodiumBlockBySettingNamedParameter
00115 
00116         // Errors thrown creating cells will often be process-specific
00117         PetscTools::ReplicateException(true);
00118 
00119         // Delete cells
00120         // Should really do this for other processes too, but this is all we need
00121         // to get memory testing to pass, and leaking when we're about to die isn't
00122         // that bad!
00123         for (std::vector<AbstractCardiacCellInterface*>::iterator cell_iterator = mCellsDistributed.begin();
00124              cell_iterator != mCellsDistributed.end();
00125              ++cell_iterator)
00126         {
00127             delete (*cell_iterator);
00128         }
00129 
00130         throw e;
00131     }
00132     PetscTools::ReplicateException(false);
00133 
00134     // Halo nodes (if required)
00135     SetUpHaloCells(pCellFactory);
00136 
00137     HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00138     mIionicCacheReplicated.Resize( pCellFactory->GetNumberOfCells() );
00139     mIntracellularStimulusCacheReplicated.Resize( pCellFactory->GetNumberOfCells() );
00140 
00141     if (mHasPurkinje)
00142     {
00143         mPurkinjeIionicCacheReplicated.Resize( pCellFactory->GetNumberOfCells() );
00144         mPurkinjeIntracellularStimulusCacheReplicated.Resize( pCellFactory->GetNumberOfCells() );
00145     }
00146     HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00147 
00148     if(HeartConfig::Instance()->IsMeshProvided() && HeartConfig::Instance()->GetLoadMesh())
00149     {
00150         mFibreFilePathNoExtension = "./" + HeartConfig::Instance()->GetMeshName();
00151     }
00152     else
00153     {
00154         // As of 10671 fibre orientation can only be defined when loading a mesh from disc.
00155         mFibreFilePathNoExtension = "";
00156     }
00157     CreateIntracellularConductivityTensor();
00158 }
00159 
00160 // Constructor used for archiving
00161 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00162 AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::AbstractCardiacTissue(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00163     : mpMesh(pMesh),
00164       mpDistributedVectorFactory(mpMesh->GetDistributedVectorFactory()),
00165       mHasPurkinje(false),
00166       mDoCacheReplication(true),
00167       mMeshUnarchived(true),
00168       mExchangeHalos(false)
00169 {
00170     mIionicCacheReplicated.Resize(mpDistributedVectorFactory->GetProblemSize());
00171     mIntracellularStimulusCacheReplicated.Resize(mpDistributedVectorFactory->GetProblemSize());
00172 
00173     mFibreFilePathNoExtension = ArchiveLocationInfo::GetArchiveDirectory() + ArchiveLocationInfo::GetMeshFilename();
00174     CreateIntracellularConductivityTensor();
00175 }
00176 
00177 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00178 AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::~AbstractCardiacTissue()
00179 {
00180     // Delete cells
00181     for (std::vector<AbstractCardiacCellInterface*>::iterator iter = mCellsDistributed.begin();
00182          iter != mCellsDistributed.end();
00183          ++iter)
00184     {
00185         delete (*iter);
00186     }
00187 
00188     // Delete cells for halo nodes
00189     for (std::vector<AbstractCardiacCellInterface*>::iterator iter = mHaloCellsDistributed.begin();
00190          iter != mHaloCellsDistributed.end();
00191          ++iter)
00192     {
00193         delete (*iter);
00194     }
00195 
00196     delete mpIntracellularConductivityTensors;
00197 
00198     // Delete Purkinje cells
00199     for (std::vector<AbstractCardiacCellInterface*>::iterator iter = mPurkinjeCellsDistributed.begin();
00200          iter != mPurkinjeCellsDistributed.end();
00201          ++iter)
00202     {
00203         delete (*iter);
00204     }
00205 
00206     // If the mesh was unarchived we need to free it explicitly.
00207     if (mMeshUnarchived)
00208     {
00209         delete mpMesh;
00210     }
00211 }
00212 
00213 
00214 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00215 bool AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::HasPurkinje()
00216 {
00217     return mHasPurkinje;
00218 }
00219 
00220 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00221 void AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::CreateIntracellularConductivityTensor()
00222 {
00223     HeartEventHandler::BeginEvent(HeartEventHandler::READ_MESH);
00224     mpConfig = HeartConfig::Instance();
00225 
00226     if (mpConfig->IsMeshProvided() && mpConfig->GetLoadMesh())
00227     {
00228         assert(mFibreFilePathNoExtension != "");
00229 
00230         switch (mpConfig->GetConductivityMedia())
00231         {
00232             case cp::media_type::Orthotropic:
00233             {
00234                 mpIntracellularConductivityTensors = new OrthotropicConductivityTensors<ELEMENT_DIM,SPACE_DIM>;
00235                 FileFinder ortho_file(mFibreFilePathNoExtension + ".ortho", RelativeTo::AbsoluteOrCwd);
00236                 assert(ortho_file.Exists());
00237                 mpIntracellularConductivityTensors->SetFibreOrientationFile(ortho_file);
00238                 break;
00239             }
00240 
00241             case cp::media_type::Axisymmetric:
00242             {
00243                 mpIntracellularConductivityTensors = new AxisymmetricConductivityTensors<ELEMENT_DIM,SPACE_DIM>;
00244                 FileFinder axi_file(mFibreFilePathNoExtension + ".axi", RelativeTo::AbsoluteOrCwd);
00245                 assert(axi_file.Exists());
00246                 mpIntracellularConductivityTensors->SetFibreOrientationFile(axi_file);
00247                 break;
00248             }
00249 
00250             case cp::media_type::NoFibreOrientation:
00252                 mpIntracellularConductivityTensors = new OrthotropicConductivityTensors<ELEMENT_DIM,SPACE_DIM>;
00253                 break;
00254 
00255             default :
00256                 NEVER_REACHED;
00257         }
00258     }
00259     else // Slab defined in config file or SetMesh() called; no fibre orientation assumed
00260     {
00262         mpIntracellularConductivityTensors = new OrthotropicConductivityTensors<ELEMENT_DIM,SPACE_DIM>;
00263     }
00264 
00265     c_vector<double, SPACE_DIM> intra_conductivities;
00266     mpConfig->GetIntracellularConductivities(intra_conductivities);
00267 
00268     // this definition must be here (and not inside the if statement) because SetNonConstantConductivities() will keep
00269     // a pointer to it and we don't want it to go out of scope before Init() is called
00270     unsigned num_local_elements = mpMesh->GetNumLocalElements();
00271     std::vector<c_vector<double, SPACE_DIM> > hetero_intra_conductivities;
00272 
00273     if (mpConfig->GetConductivityHeterogeneitiesProvided())
00274     {
00275         try
00276         {
00277             assert(hetero_intra_conductivities.size()==0);
00278             hetero_intra_conductivities.resize(num_local_elements, intra_conductivities);
00279         }
00280         catch(std::bad_alloc &r_bad_alloc)
00281         {
00282 #define COVERAGE_IGNORE
00283             std::cout << "Failed to allocate std::vector of size " << num_local_elements << std::endl;
00284             PetscTools::ReplicateException(true);
00285             throw r_bad_alloc;
00286 #undef COVERAGE_IGNORE
00287         }
00288         PetscTools::ReplicateException(false);
00289 
00290         std::vector<boost::shared_ptr<AbstractChasteRegion<SPACE_DIM> > > conductivities_heterogeneity_areas;
00291         std::vector< c_vector<double,3> > intra_h_conductivities;
00292         std::vector< c_vector<double,3> > extra_h_conductivities;
00293         HeartConfig::Instance()->GetConductivityHeterogeneities(conductivities_heterogeneity_areas,
00294                                                                 intra_h_conductivities,
00295                                                                 extra_h_conductivities);
00296 
00297         unsigned local_element_index = 0;
00298 
00299         for (typename AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>::ElementIterator it = mpMesh->GetElementIteratorBegin();
00300              it != mpMesh->GetElementIteratorEnd();
00301              ++it)
00302         {
00303 //            unsigned element_index = it->GetIndex();
00304             // if element centroid is contained in the region
00305             ChastePoint<SPACE_DIM> element_centroid(it->CalculateCentroid());
00306             for (unsigned region_index=0; region_index< conductivities_heterogeneity_areas.size(); region_index++)
00307             {
00308                 if ( conductivities_heterogeneity_areas[region_index]->DoesContain(element_centroid) )
00309                 {
00310                     //We don't use ublas vector assignment here, because we might be getting a subvector of a 3-vector
00311                     for (unsigned i=0; i<SPACE_DIM; i++)
00312                     {
00313                         hetero_intra_conductivities[local_element_index][i] = intra_h_conductivities[region_index][i];
00314                     }
00315                 }
00316             }
00317             local_element_index++;
00318         }
00319 
00320         mpIntracellularConductivityTensors->SetNonConstantConductivities(&hetero_intra_conductivities);
00321     }
00322     else
00323     {
00324         mpIntracellularConductivityTensors->SetConstantConductivities(intra_conductivities);
00325     }
00326 
00327     mpIntracellularConductivityTensors->Init(this->mpMesh);
00328     HeartEventHandler::EndEvent(HeartEventHandler::READ_MESH);
00329 }
00330 
00331 
00332 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00333 void AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::SetCacheReplication(bool doCacheReplication)
00334 {
00335     mDoCacheReplication = doCacheReplication;
00336 }
00337 
00338 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00339 bool AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::GetDoCacheReplication()
00340 {
00341     return mDoCacheReplication;
00342 }
00343 
00344 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00345 const c_matrix<double, SPACE_DIM, SPACE_DIM>& AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::rGetIntracellularConductivityTensor(unsigned elementIndex)
00346 {
00347     assert( mpIntracellularConductivityTensors);
00348     if(mpConductivityModifier==NULL)
00349     {
00350         return (*mpIntracellularConductivityTensors)[elementIndex];
00351     }
00352     else
00353     {
00354         return mpConductivityModifier->rGetModifiedConductivityTensor(elementIndex, (*mpIntracellularConductivityTensors)[elementIndex]);
00355     }
00356 }
00357 
00358 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00359 const c_matrix<double, SPACE_DIM, SPACE_DIM>& AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::rGetExtracellularConductivityTensor(unsigned elementIndex)
00360 {
00361      EXCEPTION("Monodomain tissues do not have extracellular conductivity tensors.");
00362 }
00363 
00364 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00365 AbstractCardiacCellInterface* AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::GetCardiacCell( unsigned globalIndex )
00366 {
00367     assert(mpDistributedVectorFactory->GetLow() <= globalIndex &&
00368            globalIndex < mpDistributedVectorFactory->GetHigh());
00369     return mCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
00370 }
00371 
00372 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00373 AbstractCardiacCellInterface* AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::GetPurkinjeCell( unsigned globalIndex )
00374 {
00375     assert(mpDistributedVectorFactory->GetLow() <= globalIndex &&
00376            globalIndex < mpDistributedVectorFactory->GetHigh());
00377     EXCEPT_IF_NOT(mHasPurkinje);
00378     return mPurkinjeCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
00379 }
00380 
00381 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00382 AbstractCardiacCellInterface* AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::GetCardiacCellOrHaloCell( unsigned globalIndex )
00383 {
00384     std::map<unsigned, unsigned>::const_iterator node_position;
00385     // First search the halo
00386     if ((node_position=mHaloGlobalToLocalIndexMap.find(globalIndex)) != mHaloGlobalToLocalIndexMap.end())
00387     {
00388         //Found a halo node
00389         return mHaloCellsDistributed[node_position->second];
00390     }
00391     // Then search the owned node
00392     if ( mpDistributedVectorFactory->IsGlobalIndexLocal(globalIndex)  )
00393     {
00394         //Found an owned node
00395         return mCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
00396     }
00397     // Not here
00398     EXCEPTION("Requested node/halo " << globalIndex << " does not belong to processor " << PetscTools::GetMyRank());
00399 }
00400 
00401 
00402 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00403 void AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::CalculateHaloNodesFromNodeExchange()
00404 {
00405     std::set<unsigned> halos_as_set;
00406     for (unsigned proc=0; proc<PetscTools::GetNumProcs(); proc++)
00407     {
00408         halos_as_set.insert(mNodesToReceivePerProcess[proc].begin(), mNodesToReceivePerProcess[proc].end());
00409     }
00410     mHaloNodes = std::vector<unsigned>(halos_as_set.begin(), halos_as_set.end());
00411     //PRINT_VECTOR(mHaloNodes);
00412 }
00413 
00414 
00415 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00416 void AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::SetUpHaloCells(AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory)
00417 {
00418     if (mExchangeHalos)
00419     {
00420         mpMesh->CalculateNodeExchange(mNodesToSendPerProcess, mNodesToReceivePerProcess);
00421         //Note that the following call will not work for a TetrahedralMesh which has no concept of halo nodes.
00422         //mpMesh->GetHaloNodeIndices( mHaloNodes );
00423         CalculateHaloNodesFromNodeExchange();
00424         unsigned num_halo_nodes = mHaloNodes.size();
00425         mHaloCellsDistributed.resize( num_halo_nodes );
00426 
00427         try
00428         {
00429             for (unsigned local_index = 0; local_index < num_halo_nodes; local_index++)
00430             {
00431                 unsigned global_index = mHaloNodes[local_index];
00432                 mHaloCellsDistributed[local_index] = pCellFactory->CreateCardiacCellForNode(global_index);
00433                 mHaloCellsDistributed[local_index]->SetUsedInTissueSimulation();
00434                 mHaloGlobalToLocalIndexMap[global_index] = local_index;
00435             }
00436 
00437             // No need to call FinaliseCellCreation() as halo node cardiac cells will
00438             // never be stimulated (their values are communicated from the process that
00439             // owns them.
00440         }
00441         catch (const Exception& e)
00442         {
00443             // Errors thrown creating cells will often be process-specific
00444             PetscTools::ReplicateException(true);
00445 
00446             // Delete cells
00447             // Should really do this for other processes too, but this is all we need
00448             // to get memory testing to pass, and leaking when we're about to die isn't
00449             // that bad!
00450             for (std::vector<AbstractCardiacCellInterface*>::iterator cell_iterator = mHaloCellsDistributed.begin();
00451                  cell_iterator != mHaloCellsDistributed.end();
00452                  ++cell_iterator)
00453             {
00454                 delete (*cell_iterator);
00455             }
00456 
00457             throw e;
00458         }
00459         PetscTools::ReplicateException(false);
00460     }
00461 }
00462 
00463 
00464 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00465 void AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::SolveCellSystems(Vec existingSolution, double time, double nextTime, bool updateVoltage)
00466 {
00467     if(mHasPurkinje)
00468     {
00469         // can't do Purkinje and operator splitting
00470         assert(!updateVoltage);
00471         // The code below assumes Purkinje is are monodomain, so the vector has two stripes.
00472         // The assert will fail the first time bidomain purkinje is coded - need to decide what
00473         // ordering the three stripes (V, V_purk, phi_e) are in
00474         assert(PetscVecTools::GetSize(existingSolution)==2*mpMesh->GetNumNodes());
00475     }
00476 
00477     HeartEventHandler::BeginEvent(HeartEventHandler::SOLVE_ODES);
00478 
00479     DistributedVector dist_solution = mpDistributedVectorFactory->CreateDistributedVector(existingSolution);
00480 
00482     // Solve cell models (except purkinje cell models)
00484     DistributedVector::Stripe voltage(dist_solution, 0);
00485     try
00486     {
00487         for (DistributedVector::Iterator index = dist_solution.Begin();
00488              index != dist_solution.End();
00489              ++index)
00490         {
00491             mCellsDistributed[index.Local]->SetVoltage( voltage[index] );
00492 
00493             if (!updateVoltage)
00494             {
00495                 // solve
00496                 // Note: Voltage is not being updated. The voltage is updated in the PDE solve.
00497                 mCellsDistributed[index.Local]->ComputeExceptVoltage(time, nextTime);
00498             }
00499             else
00500             {
00501                 // solve, including updating the voltage (for the operator-splitting implementation of the monodomain solver)
00502                 mCellsDistributed[index.Local]->SolveAndUpdateState(time, nextTime);
00503                 voltage[index] = mCellsDistributed[index.Local]->GetVoltage();
00504             }
00505 
00506             // update the Iionic and stimulus caches
00507             UpdateCaches(index.Global, index.Local, nextTime);
00508         }
00509 
00510         if (updateVoltage)
00511         {
00512             dist_solution.Restore();
00513         }
00514     }
00515     catch (Exception &e)
00516     {
00517         PetscTools::ReplicateException(true);
00518         throw e;
00519     }
00520 
00522     // Solve purkinje cell models
00524     if (mHasPurkinje)
00525     {
00526         DistributedVector::Stripe purkinje_voltage(dist_solution, 1);
00527         try
00528         {
00529             for (DistributedVector::Iterator index = dist_solution.Begin();
00530                  index != dist_solution.End();
00531                  ++index)
00532             {
00533                 // overwrite the voltage with the input value
00534                 mPurkinjeCellsDistributed[index.Local]->SetVoltage( purkinje_voltage[index] );
00535 
00536                 // solve
00537                 // Note: Voltage is not being updated. The voltage is updated in the PDE solve.
00538                 mPurkinjeCellsDistributed[index.Local]->ComputeExceptVoltage(time, nextTime);
00539 
00540                 // update the Iionic and stimulus caches
00541                 UpdatePurkinjeCaches(index.Global, index.Local, nextTime);
00542             }
00543         }
00544         catch (Exception &e)
00545         {
00549 
00550             NEVER_REACHED;
00551             //PetscTools::ReplicateException(true);
00552             //throw e;
00553         }
00554     }
00555 
00556 
00557 
00558     PetscTools::ReplicateException(false);
00559     HeartEventHandler::EndEvent(HeartEventHandler::SOLVE_ODES);
00560 
00561     // Communicate new state variable values to halo nodes
00562     if (mExchangeHalos)
00563     {
00564         assert(!mHasPurkinje);
00565 
00566         for ( unsigned rank_offset = 1; rank_offset < PetscTools::GetNumProcs(); rank_offset++ )
00567         {
00568             unsigned send_to      = (PetscTools::GetMyRank() + rank_offset) % (PetscTools::GetNumProcs());
00569             unsigned receive_from = (PetscTools::GetMyRank() + PetscTools::GetNumProcs()- rank_offset ) % (PetscTools::GetNumProcs());
00570 
00571             unsigned number_of_cells_to_send    = mNodesToSendPerProcess[send_to].size();
00572             unsigned number_of_cells_to_receive = mNodesToReceivePerProcess[receive_from].size();
00573 
00574             // Pack
00575             if ( number_of_cells_to_send > 0 )
00576             {
00577                 unsigned send_size = 0;
00578                 for (unsigned i=0; i<number_of_cells_to_send; i++)
00579                 {
00580                     unsigned global_cell_index = mNodesToSendPerProcess[send_to][i];
00581                     send_size += mCellsDistributed[global_cell_index - mpDistributedVectorFactory->GetLow()]->GetNumberOfStateVariables();
00582                 }
00583 
00584                 double send_data[send_size];
00585 
00586                 unsigned send_index = 0;
00587                 for (unsigned cell = 0; cell < number_of_cells_to_send; cell++)
00588                 {
00589                     unsigned global_cell_index = mNodesToSendPerProcess[send_to][cell];
00590                     AbstractCardiacCellInterface* p_cell = mCellsDistributed[global_cell_index - mpDistributedVectorFactory->GetLow()];
00591                     std::vector<double> cell_data = p_cell->GetStdVecStateVariables();
00592                     const unsigned num_state_vars = p_cell->GetNumberOfStateVariables();
00593                     for (unsigned state_variable = 0; state_variable < num_state_vars; state_variable++)
00594                     {
00595                         send_data[send_index++] = cell_data[state_variable];
00596                     }
00597                 }
00598 
00599                 // Send
00600                 int ret;
00601                 ret = MPI_Send( send_data,
00602                                 send_size,
00603                                 MPI_DOUBLE,
00604                                 send_to,
00605                                 0,
00606                                 PETSC_COMM_WORLD );
00607                 assert ( ret == MPI_SUCCESS );
00608             }
00609 
00610             if ( number_of_cells_to_receive > 0 )
00611             {
00612                 // Receive
00613                 unsigned receive_size = 0;
00614                 for (unsigned i=0; i<number_of_cells_to_receive; i++)
00615                 {
00616                     unsigned halo_cell_index = mHaloGlobalToLocalIndexMap[mNodesToReceivePerProcess[receive_from][i]];
00617                     receive_size += mHaloCellsDistributed[halo_cell_index]->GetNumberOfStateVariables();
00618                 }
00619 
00620                 double receive_data[receive_size];
00621                 MPI_Status status;
00622 
00623                 int ret;
00624                 ret = MPI_Recv( receive_data,
00625                                 receive_size,
00626                                 MPI_DOUBLE,
00627                                 receive_from,
00628                                 0,
00629                                 PETSC_COMM_WORLD,
00630                                 &status );
00631                 assert ( ret == MPI_SUCCESS);
00632 
00633                 // Unpack
00634                 unsigned receive_index = 0;
00635                 for ( unsigned cell = 0; cell < number_of_cells_to_receive; cell++ )
00636                 {
00637                     AbstractCardiacCellInterface* p_cell = mHaloCellsDistributed[mHaloGlobalToLocalIndexMap[mNodesToReceivePerProcess[receive_from][cell]]];
00638                     const unsigned number_of_state_variables = p_cell->GetNumberOfStateVariables();
00639 
00640                     std::vector<double> cell_data(number_of_state_variables);
00641                     for (unsigned state_variable = 0; state_variable < number_of_state_variables; state_variable++)
00642                     {
00643                         cell_data[state_variable] = receive_data[receive_index++];
00644                     }
00645                     p_cell->SetStateVariables(cell_data);
00646                 }
00647             }
00648         }
00649     }
00650 
00651     HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00652     if ( mDoCacheReplication )
00653     {
00654         ReplicateCaches();
00655     }
00656     HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00657 }
00658 
00659 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00660 ReplicatableVector& AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::rGetIionicCacheReplicated()
00661 {
00662     return mIionicCacheReplicated;
00663 }
00664 
00665 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00666 ReplicatableVector& AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::rGetIntracellularStimulusCacheReplicated()
00667 {
00668     return mIntracellularStimulusCacheReplicated;
00669 }
00670 
00671 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00672 ReplicatableVector& AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::rGetPurkinjeIionicCacheReplicated()
00673 {
00674     EXCEPT_IF_NOT(mHasPurkinje);
00675     return mPurkinjeIionicCacheReplicated;
00676 }
00677 
00678 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00679 ReplicatableVector& AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::rGetPurkinjeIntracellularStimulusCacheReplicated()
00680 {
00681     EXCEPT_IF_NOT(mHasPurkinje);
00682     return mPurkinjeIntracellularStimulusCacheReplicated;
00683 }
00684 
00685 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00686 void AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::UpdateCaches(unsigned globalIndex, unsigned localIndex, double nextTime)
00687 {
00688     mIionicCacheReplicated[globalIndex] = mCellsDistributed[localIndex]->GetIIonic();
00689     mIntracellularStimulusCacheReplicated[globalIndex] = mCellsDistributed[localIndex]->GetIntracellularStimulus(nextTime);
00690 }
00691 
00692 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00693 void AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::UpdatePurkinjeCaches(unsigned globalIndex, unsigned localIndex, double nextTime)
00694 {
00695     assert(mHasPurkinje);
00696     mPurkinjeIionicCacheReplicated[globalIndex] = mPurkinjeCellsDistributed[localIndex]->GetIIonic();
00697     mPurkinjeIntracellularStimulusCacheReplicated[globalIndex] = mPurkinjeCellsDistributed[localIndex]->GetIntracellularStimulus(nextTime);
00698 }
00699 
00700 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00701 void AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::ReplicateCaches()
00702 {
00703     // ReplicateCaches only needed for SVI (and non-matrix based assembly which is no longer in code)
00704     // which is not implemented with purkinje. See commented code below if introducing this.
00705     assert(!mHasPurkinje);
00706 
00707     mIionicCacheReplicated.Replicate(mpDistributedVectorFactory->GetLow(), mpDistributedVectorFactory->GetHigh());
00708     mIntracellularStimulusCacheReplicated.Replicate(mpDistributedVectorFactory->GetLow(), mpDistributedVectorFactory->GetHigh());
00709 
00710     //if (mHasPurkinje)
00711     //{
00712     //    mPurkinjeIionicCacheReplicated.Replicate(mpDistributedVectorFactory->GetLow(), mpDistributedVectorFactory->GetHigh());
00713     //    mPurkinjeIntracellularStimulusCacheReplicated.Replicate(mpDistributedVectorFactory->GetLow(), mpDistributedVectorFactory->GetHigh());
00714     //}
00715 }
00716 
00717 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00718 const std::vector<AbstractCardiacCellInterface*>& AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::rGetCellsDistributed() const
00719 {
00720     return mCellsDistributed;
00721 }
00722 
00723 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00724 const std::vector<AbstractCardiacCellInterface*>& AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::rGetPurkinjeCellsDistributed() const
00725 {
00726     EXCEPT_IF_NOT(mHasPurkinje);
00727     return mPurkinjeCellsDistributed;
00728 }
00729 
00730 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00731 const AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::pGetMesh() const
00732 {
00733     return mpMesh;
00734 }
00735 
00736 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00737 void AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::SetConductivityModifier(AbstractConductivityModifier<ELEMENT_DIM,SPACE_DIM>* pModifier)
00738 {
00739     assert(pModifier!=NULL);
00740     assert(mpConductivityModifier==NULL); // shouldn't be called twice for example, or with two different modifiers (remove this assert
00741                                           // if for whatever reason want to be able to overwrite modifiers
00742     mpConductivityModifier = pModifier;
00743 }
00744 
00745 
00747 // Explicit instantiation
00749 
00750 template class AbstractCardiacTissue<1,1>;
00751 template class AbstractCardiacTissue<1,2>;
00752 template class AbstractCardiacTissue<1,3>;
00753 template class AbstractCardiacTissue<2,2>;
00754 template class AbstractCardiacTissue<3,3>;