AbstractCardiacPde.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #include "AbstractCardiacPde.hpp"
00030 
00031 #include "DistributedVector.hpp"
00032 #include "AxisymmetricConductivityTensors.hpp"
00033 #include "OrthotropicConductivityTensors.hpp"
00034 #include "ChastePoint.hpp"
00035 #include "ChasteCuboid.hpp"
00036 #include "HeartEventHandler.hpp"
00037 #include "PetscTools.hpp"
00038 #include "FakeBathCell.hpp"
00039 
00040 
00041 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00042 AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::AbstractCardiacPde(
00043             AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory,
00044             const unsigned stride)
00045     : mpMesh(pCellFactory->GetMesh()),
00046       mStride(stride),
00047       mDoCacheReplication(true),
00048       mDoOneCacheReplication(true),
00049       mpDistributedVectorFactory(mpMesh->GetDistributedVectorFactory()),
00050       mMeshUnarchived(false)
00051 {
00052     //This constructor is called from the Initialise() method of the CardiacProblem class
00053     assert(pCellFactory != NULL);
00054     assert(pCellFactory->GetMesh() != NULL);
00055 
00056     unsigned num_local_nodes = mpDistributedVectorFactory->GetLocalOwnership();
00057     unsigned ownership_range_low = mpDistributedVectorFactory->GetLow();
00058     mCellsDistributed.resize(num_local_nodes);
00059 
00060     for (unsigned local_index = 0; local_index < num_local_nodes; local_index++)
00061     {
00062         unsigned global_index = ownership_range_low + local_index;
00063         mCellsDistributed[local_index] = pCellFactory->CreateCardiacCellForNode(global_index);
00064     }
00065 
00066     pCellFactory->FinaliseCellCreation(&mCellsDistributed,
00067                                        mpDistributedVectorFactory->GetLow(),
00068                                        mpDistributedVectorFactory->GetHigh());
00069 
00070     HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00071     mIionicCacheReplicated.Resize( pCellFactory->GetNumberOfCells() );
00072     mIntracellularStimulusCacheReplicated.Resize( pCellFactory->GetNumberOfCells() );
00073     HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00074 
00075     CreateIntracellularConductivityTensor();
00076 }
00077 
00078 // Constructor used for archiving
00079 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00080 AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::AbstractCardiacPde(std::vector<AbstractCardiacCell*> & rCellsDistributed,
00081                                                               AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh,
00082                                                               const unsigned stride)
00083     : mpMesh(pMesh),
00084       mCellsDistributed(rCellsDistributed),
00085       mStride(stride),
00086       mDoCacheReplication(true),
00087       mDoOneCacheReplication(true),
00088       mpDistributedVectorFactory(mpMesh->GetDistributedVectorFactory()),
00089       mMeshUnarchived(true)
00090 {
00091     mIionicCacheReplicated.Resize(mpDistributedVectorFactory->GetProblemSize());
00092     mIntracellularStimulusCacheReplicated.Resize(mpDistributedVectorFactory->GetProblemSize());
00093 
00094     CreateIntracellularConductivityTensor();
00095 }
00096 
00097 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00098 void AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::DeleteCells(bool deleteFakeCells)
00099 {
00100     std::set<FakeBathCell*> fake_cells;
00101     for (std::vector<AbstractCardiacCell*>::iterator cell_iterator = mCellsDistributed.begin();
00102          cell_iterator != mCellsDistributed.end();
00103          ++cell_iterator)
00104     {
00105         // Only delete real cells, unless we were loaded from an archive
00106         FakeBathCell* p_fake = dynamic_cast<FakeBathCell*>(*cell_iterator);
00107         if (p_fake == NULL)
00108         {
00109             delete (*cell_iterator);
00110         }
00111         else
00112         {
00113             fake_cells.insert(p_fake);
00114         }
00115     }
00116 
00117     if (deleteFakeCells)
00118     {
00119         // Likewise for fake cells
00120         for (std::set<FakeBathCell*>::iterator it = fake_cells.begin();
00121              it != fake_cells.end();
00122              ++it)
00123         {
00124             delete (*it);
00125         }
00126     }
00127 }
00128 
00129 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00130 AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::~AbstractCardiacPde()
00131 {
00132     DeleteCells(mMeshUnarchived);
00133 
00134     delete mpIntracellularConductivityTensors;
00135 
00136     // If the mesh was unarchived we need to free it explicitly.
00137     if (mMeshUnarchived)
00138     {
00139         delete mpMesh;
00140     }
00141 }
00142 
00143 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00144 void AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::MergeCells(const std::vector<AbstractCardiacCell*>& rOtherCells)
00145 {
00146     assert(rOtherCells.size() == mCellsDistributed.size());
00147     for (unsigned i=0; i<rOtherCells.size(); i++)
00148     {
00149         if (rOtherCells[i] != NULL)
00150         {
00151             assert(mCellsDistributed[i] == NULL);
00152             mCellsDistributed[i] = rOtherCells[i];
00153         }
00154     }
00155 }
00156 
00157 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00158 void AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::CreateIntracellularConductivityTensor()
00159 {
00160     HeartEventHandler::BeginEvent(HeartEventHandler::READ_MESH);
00161     mpConfig = HeartConfig::Instance();
00162 
00163     if (mpConfig->IsMeshProvided() && mpConfig->GetLoadMesh())
00164     {
00165         switch (mpConfig->GetConductivityMedia())
00166         {
00167             case cp::media_type::Orthotropic:
00168                 mpIntracellularConductivityTensors = new OrthotropicConductivityTensors<SPACE_DIM>;
00169                 mpIntracellularConductivityTensors->SetFibreOrientationFile(mpConfig->GetMeshName() + ".ortho");
00170                 break;
00171 
00172             case cp::media_type::Axisymmetric:
00173                 mpIntracellularConductivityTensors = new AxisymmetricConductivityTensors<SPACE_DIM>;
00174                 mpIntracellularConductivityTensors->SetFibreOrientationFile(mpConfig->GetMeshName() + ".axi");
00175                 break;
00176 
00177             case cp::media_type::NoFibreOrientation:
00179                 mpIntracellularConductivityTensors = new OrthotropicConductivityTensors<SPACE_DIM>;
00180                 break;
00181 
00182             default :
00183                 NEVER_REACHED;
00184         }
00185     }
00186     else // Slab defined in config file or SetMesh() called; no fibre orientation assumed
00187     {
00189         mpIntracellularConductivityTensors = new OrthotropicConductivityTensors<SPACE_DIM>;
00190     }
00191 
00192     c_vector<double, SPACE_DIM> intra_conductivities;
00193     mpConfig->GetIntracellularConductivities(intra_conductivities);
00194 
00195     // this definition must be here (and not inside the if statement) because SetNonConstantConductivities() will keep
00196     // a pointer to it and we don't want it to go out of scope before Init() is called
00197     unsigned num_elements = mpMesh->GetNumElements();
00198     std::vector<c_vector<double, SPACE_DIM> > hetero_intra_conductivities;
00199 
00200     if (mpConfig->GetConductivityHeterogeneitiesProvided())
00201     {
00202         try
00203         {
00204             hetero_intra_conductivities.resize(num_elements);
00205         }
00206         catch(std::bad_alloc &badAlloc)
00207         {
00208 #define COVERAGE_IGNORE
00209             std::cout << "Failed to allocate std::vector of size " << num_elements << std::endl;
00210             PetscTools::ReplicateException(true);
00211             throw badAlloc;
00212 #undef COVERAGE_IGNORE
00213         }
00214         PetscTools::ReplicateException(false);
00215 
00216         std::vector<ChasteCuboid<SPACE_DIM> > conductivities_heterogeneity_areas;
00217         std::vector< c_vector<double,3> > intra_h_conductivities;
00218         std::vector< c_vector<double,3> > extra_h_conductivities;
00219         HeartConfig::Instance()->GetConductivityHeterogeneities(conductivities_heterogeneity_areas,
00220                                                                 intra_h_conductivities,
00221                                                                 extra_h_conductivities);
00222 
00223         for (unsigned element_index=0; element_index<num_elements; element_index++)
00224         {
00225             for (unsigned region_index=0; region_index< conductivities_heterogeneity_areas.size(); region_index++)
00226             {
00227                 // if element centroid is contained in the region
00228                 ChastePoint<SPACE_DIM> element_centroid(mpMesh->GetElement(element_index)->CalculateCentroid());
00229                 if ( conductivities_heterogeneity_areas[region_index].DoesContain(element_centroid) )
00230                 {
00231                     hetero_intra_conductivities[element_index] = intra_h_conductivities[region_index];
00232                 }
00233                 else
00234                 {
00235                     hetero_intra_conductivities[element_index] = intra_conductivities;
00236                 }
00237             }
00238         }
00239 
00240         mpIntracellularConductivityTensors->SetNonConstantConductivities(&hetero_intra_conductivities);
00241     }
00242     else
00243     {
00244         mpIntracellularConductivityTensors->SetConstantConductivities(intra_conductivities);
00245     }
00246 
00247     mpIntracellularConductivityTensors->Init();
00248     HeartEventHandler::EndEvent(HeartEventHandler::READ_MESH);
00249 }
00250 
00251 
00252 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00253 void AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::SetCacheReplication(bool doCacheReplication)
00254 {
00255     mDoCacheReplication = doCacheReplication;
00256     mDoOneCacheReplication = true; //If we have reset to false (even from false) then we may have created a new matrix-based assembler and need to run it once
00257 }
00258 
00259 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00260 bool AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::GetDoCacheReplication()
00261 {
00262     return mDoCacheReplication;
00263 }
00264 
00265 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00266 const c_matrix<double, SPACE_DIM, SPACE_DIM>& AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::rGetIntracellularConductivityTensor(unsigned elementIndex)
00267 {
00268     assert( mpIntracellularConductivityTensors);
00269     return (*mpIntracellularConductivityTensors)[elementIndex];
00270 }
00271 
00272 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00273 AbstractCardiacCell* AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::GetCardiacCell( unsigned globalIndex )
00274 {
00275     assert(mpDistributedVectorFactory->GetLow() <= globalIndex &&
00276            globalIndex < mpDistributedVectorFactory->GetHigh());
00277     return mCellsDistributed[globalIndex - mpDistributedVectorFactory->GetLow()];
00278 }
00279 
00280 
00281 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00282 void AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::SolveCellSystems(Vec existingSolution, double time, double nextTime)
00283 {
00284     HeartEventHandler::BeginEvent(HeartEventHandler::SOLVE_ODES);
00285 
00286     DistributedVector dist_solution = mpDistributedVectorFactory->CreateDistributedVector(existingSolution);
00287     DistributedVector::Stripe voltage(dist_solution, 0);
00288     for (DistributedVector::Iterator index = dist_solution.Begin();
00289          index != dist_solution.End();
00290          ++index)
00291     {
00292         // overwrite the voltage with the input value
00293         mCellsDistributed[index.Local]->SetVoltage( voltage[index] );
00294         try
00295         {
00296             // solve
00297             // Note: Voltage should not be updated. GetIIonic will be called later
00298             // and needs the old voltage. The voltage will be updated from the pde.
00299             mCellsDistributed[index.Local]->ComputeExceptVoltage(time, nextTime);
00300         }
00301         catch (Exception &e)
00302         {
00303             PetscTools::ReplicateException(true);
00304             throw e;
00305         }
00306 
00307         // update the Iionic and stimulus caches
00308         UpdateCaches(index.Global, index.Local, nextTime);
00309     }
00310     PetscTools::ReplicateException(false);
00311     HeartEventHandler::EndEvent(HeartEventHandler::SOLVE_ODES);
00312 
00313     HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00314     if ( mDoCacheReplication || mDoOneCacheReplication )
00315     {
00316         ReplicateCaches();
00317         mDoOneCacheReplication=false;
00318     }
00319     HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00320 }
00321 
00322 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00323 ReplicatableVector& AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::rGetIionicCacheReplicated()
00324 {
00325     return mIionicCacheReplicated;
00326 }
00327 
00328 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00329 ReplicatableVector& AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::rGetIntracellularStimulusCacheReplicated()
00330 {
00331     return mIntracellularStimulusCacheReplicated;
00332 }
00333 
00334 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00335 void AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::UpdateCaches(unsigned globalIndex, unsigned localIndex, double nextTime)
00336 {
00337     mIionicCacheReplicated[globalIndex] = mCellsDistributed[localIndex]->GetIIonic();
00338     mIntracellularStimulusCacheReplicated[globalIndex] = mCellsDistributed[localIndex]->GetIntracellularStimulus(nextTime);
00339 }
00340 
00341 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00342 void AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::ReplicateCaches()
00343 {
00344     mIionicCacheReplicated.Replicate(mpDistributedVectorFactory->GetLow(), mpDistributedVectorFactory->GetHigh());
00345     mIntracellularStimulusCacheReplicated.Replicate(mpDistributedVectorFactory->GetLow(), mpDistributedVectorFactory->GetHigh());
00346 }
00347 
00348 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00349 const std::vector<AbstractCardiacCell*>& AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::rGetCellsDistributed() const
00350 {
00351     return mCellsDistributed;
00352 }
00353 
00354 template <unsigned ELEMENT_DIM,unsigned SPACE_DIM>
00355 const AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::pGetMesh() const
00356 {
00357     return mpMesh;
00358 }
00359 
00360 
00362 // Explicit instantiation
00364 
00365 template class AbstractCardiacPde<1,1>;
00366 template class AbstractCardiacPde<1,2>;
00367 template class AbstractCardiacPde<1,3>;
00368 template class AbstractCardiacPde<2,2>;
00369 template class AbstractCardiacPde<3,3>;

Generated by  doxygen 1.6.2