Chaste Release::3.1
|
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>;