Chaste Release::3.1
ExtendedBidomainTissue.hpp
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 
00037 #ifndef EXTENDEDBIDOMAINTISSUE_HPP_
00038 #define EXTENDEDBIDOMAINTISSUE_HPP_
00039 
00040 #include "ChasteSerialization.hpp"
00041 #include <boost/serialization/base_object.hpp>
00042 
00043 #include <vector>
00044 #include <boost/numeric/ublas/matrix.hpp>
00045 
00046 #include "AbstractStimulusFunction.hpp"
00047 #include "AbstractStimulusFactory.hpp"
00048 #include "AbstractConductivityTensors.hpp"
00049 
00050 #include "AbstractCardiacTissue.hpp"
00051 
00076 template <unsigned SPACE_DIM>
00077 class ExtendedBidomainTissue : public virtual AbstractCardiacTissue<SPACE_DIM>
00078 {
00079 private:
00080     friend class TestExtendedBidomainTissue; // for testing.
00081 
00083     friend class boost::serialization::access;
00090     template<class Archive>
00091     void serialize(Archive & archive, const unsigned int version)
00092     {
00093         archive & boost::serialization::base_object<AbstractCardiacTissue<SPACE_DIM> >(*this);
00094         // Conductivity tensors are dealt with by HeartConfig, and the caches get regenerated.
00095 
00096         archive & mAmFirstCell;
00097         archive & mAmSecondCell;
00098         archive & mAmGap;
00099         archive & mCmFirstCell;
00100         archive & mCmSecondCell;
00101         archive & mGGap;
00102         archive & mUserSuppliedExtracellularStimulus;
00103     }
00104 
00106     AbstractConductivityTensors<SPACE_DIM, SPACE_DIM> *mpIntracellularConductivityTensorsSecondCell;
00107 
00112     c_vector<double, SPACE_DIM>  mIntracellularConductivitiesSecondCell;
00113 
00114 
00116     AbstractConductivityTensors<SPACE_DIM, SPACE_DIM> *mpExtracellularConductivityTensors;
00117 
00122     ReplicatableVector mExtracellularStimulusCacheReplicated;
00123 
00128     ReplicatableVector mGgapCacheReplicated;
00129 
00134     ReplicatableVector mIionicCacheReplicatedSecondCell;
00135 
00140     ReplicatableVector mIntracellularStimulusCacheReplicatedSecondCell;
00141 
00143     std::vector< AbstractCardiacCellInterface* > mCellsDistributedSecondCell;
00144 
00146     std::vector<boost::shared_ptr<AbstractStimulusFunction> > mExtracellularStimuliDistributed;
00147 
00149     std::vector<double> mGgapDistributed;
00150 
00152     double mAmFirstCell;
00154     double mAmSecondCell;
00156     double mAmGap;
00158     double mCmFirstCell;
00160     double mCmSecondCell;
00162     double mGGap;
00163 
00168     bool mUserSuppliedExtracellularStimulus;
00169 
00173     void CreateExtracellularConductivityTensors();
00174 
00189     void UpdateAdditionalCaches(unsigned globalIndex, unsigned localIndex, double nextTime);
00190 
00201     void ReplicateAdditionalCaches();
00202 
00204     std::vector<boost::shared_ptr<AbstractChasteRegion<SPACE_DIM> > > mGgapHeterogeneityRegions;
00206     std::vector<double> mGgapValues;
00207 
00208 public:
00209 
00216     ExtendedBidomainTissue(AbstractCardiacCellFactory<SPACE_DIM>* pCellFactory, AbstractCardiacCellFactory<SPACE_DIM>* pCellFactorySecondCell, AbstractStimulusFactory<SPACE_DIM>* pExtracellularStimulusFactory);
00217 
00227     ExtendedBidomainTissue(std::vector<AbstractCardiacCellInterface*> & rCellsDistributed, std::vector<AbstractCardiacCellInterface*> & rSecondCellsDistributed, std::vector<boost::shared_ptr<AbstractStimulusFunction> > & rExtraStimuliDistributed, std::vector<double>& rGgapsDistributed, AbstractTetrahedralMesh<SPACE_DIM,SPACE_DIM>* pMesh, c_vector<double, SPACE_DIM>  intracellularConductivitiesSecondCell);
00228 
00232     ~ExtendedBidomainTissue();
00233 
00239     void SetIntracellularConductivitiesSecondCell(c_vector<double, SPACE_DIM> conductivities);
00240 
00246     AbstractCardiacCellInterface* GetCardiacSecondCell( unsigned globalIndex );
00247 
00248 
00254     boost::shared_ptr<AbstractStimulusFunction> GetExtracellularStimulus( unsigned globalIndex );
00255 
00259     const std::vector<AbstractCardiacCellInterface*>& rGetSecondCellsDistributed() const;
00260 
00264     const std::vector<double>& rGetGapsDistributed() const;
00265 
00266 
00270     const std::vector<boost::shared_ptr<AbstractStimulusFunction> >& rGetExtracellularStimulusDistributed() const;
00271 
00272 
00276     c_vector<double, SPACE_DIM> GetIntracellularConductivitiesSecondCell() const;
00277 
00287     virtual void SolveCellSystems(Vec existingSolution, double time, double nextTime, bool updateVoltage = false);
00288 
00292     void CreateIntracellularConductivityTensorSecondCell();
00293 
00300     void SetGgapHeterogeneities ( std::vector<boost::shared_ptr<AbstractChasteRegion<SPACE_DIM> > > & rGgapHeterogeneityRegions, std::vector<double> rGgapValues);
00301 
00307     void CreateGGapConductivities();
00308 
00313      const c_matrix<double, SPACE_DIM, SPACE_DIM>& rGetExtracellularConductivityTensor(unsigned elementIndex);
00314 
00319       const c_matrix<double, SPACE_DIM, SPACE_DIM>& rGetIntracellularConductivityTensorSecondCell(unsigned elementIndex);
00320 
00321 
00323      ReplicatableVector& rGetIionicCacheReplicatedSecondCell();
00324 
00326      ReplicatableVector& rGetIntracellularStimulusCacheReplicatedSecondCell();
00327 
00329      ReplicatableVector& rGetExtracellularStimulusCacheReplicated();
00330 
00332      ReplicatableVector& rGetGgapCacheReplicated();
00333 
00337      double GetAmFirstCell();
00338 
00342      double GetAmSecondCell();
00343 
00347      double GetAmGap();
00348 
00352      double GetCmFirstCell();
00353 
00357      double GetCmSecondCell();
00358 
00362      double GetGGap();
00363 
00367      void SetAmFirstCell(double value);
00368 
00372      void SetAmSecondCell(double value);
00373 
00377      void SetAmGap(double value);
00378 
00382      void SetCmFirstCell(double value);
00383 
00387      void SetCmSecondCell(double value);
00388 
00392      void SetGGap(double value);
00393 
00401      bool HasTheUserSuppliedExtracellularStimulus();
00402 
00410      void SetUserSuppliedExtracellularStimulus(bool flag);
00411 
00412 
00419      template<class Archive>
00420      void SaveExtendedBidomainCells(Archive & archive, const unsigned int version) const
00421      {
00422          Archive& r_archive = *ProcessSpecificArchive<Archive>::Get();
00423          const std::vector<AbstractCardiacCellInterface*> & r_cells_distributed = this->rGetCellsDistributed();
00424          const std::vector<AbstractCardiacCellInterface*> & r_cells_distributed_second_cell = rGetSecondCellsDistributed();
00425          const std::vector<double> & r_ggaps_distributed = rGetGapsDistributed();
00426 
00427          r_archive & this->mpDistributedVectorFactory; // Needed when loading
00428          const unsigned num_cells = r_cells_distributed.size();
00429          r_archive & num_cells;
00430          for (unsigned i=0; i<num_cells; i++)
00431          {
00432              AbstractDynamicallyLoadableEntity* p_entity = dynamic_cast<AbstractDynamicallyLoadableEntity*>(r_cells_distributed[i]);
00433              bool is_dynamic = (p_entity != NULL);
00434              r_archive & is_dynamic;
00435              if (is_dynamic)
00436              {
00437  #ifdef CHASTE_CAN_CHECKPOINT_DLLS
00438                  r_archive & p_entity->GetLoader()->GetLoadableModulePath();
00439  #else
00440                  // We should have thrown an exception before this point
00441                  NEVER_REACHED;
00442  #endif // CHASTE_CAN_CHECKPOINT_DLLS
00443              }
00444              r_archive & r_cells_distributed[i];
00445              r_archive & r_cells_distributed_second_cell[i];
00446              r_archive & r_ggaps_distributed[i];
00447          }
00448      }
00449 
00464      template<class Archive>
00465      static void LoadExtendedBidomainCells(Archive & archive, const unsigned int version,
00466                                   std::vector<AbstractCardiacCellInterface*>& rCells,
00467                                   std::vector<AbstractCardiacCellInterface*>& rSecondCells,
00468                                   std::vector<double>& rGgaps,
00469                                   AbstractTetrahedralMesh<SPACE_DIM,SPACE_DIM>* pMesh)
00470      {
00471          assert(pMesh!=NULL);
00472          DistributedVectorFactory* p_factory;
00473          archive & p_factory;
00474          unsigned num_cells;
00475          archive & num_cells;
00476          rCells.resize(p_factory->GetLocalOwnership());
00477          rSecondCells.resize(p_factory->GetLocalOwnership());
00478          rGgaps.resize(p_factory->GetLocalOwnership());
00479  #ifndef NDEBUG
00480          // Paranoia
00481          assert(rCells.size() == rSecondCells.size());
00482          for (unsigned i=0; i<rCells.size(); i++)
00483          {
00484              assert(rCells[i] == NULL);
00485              assert(rSecondCells[i] == NULL);
00486          }
00487  #endif
00488 
00489          // We don't store a cell index in the archive, so need to work out what global
00490          // index this tissue starts up.  If we're migrating (so have an
00491          // original factory) we use the original low index; otherwise we use the current
00492          // low index.
00493          unsigned index_low = p_factory->GetOriginalFactory() ? p_factory->GetOriginalFactory()->GetLow() : p_factory->GetLow();
00494 
00495          for (unsigned local_index=0; local_index<num_cells; local_index++)
00496          {
00497              unsigned global_index = index_low + local_index;
00498              unsigned new_local_index = global_index - p_factory->GetLow();
00499              bool local = p_factory->IsGlobalIndexLocal(global_index);
00500 
00501              bool is_dynamic;
00502              archive & is_dynamic;
00503 
00504              if (is_dynamic)
00505              {
00506  #ifdef CHASTE_CAN_CHECKPOINT_DLLS
00507                  // Ensure the shared object file for this cell model is loaded.
00508                  // We need to do this here, rather than in the class' serialization code,
00509                  // because that code won't be available until this is done...
00510                  std::string shared_object_path;
00511                  archive & shared_object_path;
00512                  DynamicModelLoaderRegistry::Instance()->GetLoader(shared_object_path);
00513  #else
00514                  // Since checkpoints with dynamically loadable cells can only be
00515                  // created on Boost>=1.37, trying to load such a checkpoint on an
00516                  // earlier Boost would give an error when first opening the archive.
00517                  NEVER_REACHED;
00518  #endif // CHASTE_CAN_CHECKPOINT_DLLS
00519              }
00520 
00521              AbstractCardiacCellInterface* p_cell;
00522              AbstractCardiacCellInterface* p_second_cell;
00523              double g_gap;
00524              archive & p_cell;
00525              archive & p_second_cell;
00526              archive & g_gap;
00527              if (local)
00528              {
00529                  rCells[new_local_index] = p_cell; // Add to local cells
00530                  rSecondCells[new_local_index] = p_second_cell;
00531                  rGgaps[new_local_index] = g_gap;
00532              }
00533              else
00534              {
00535                  //not sure how to cover this, we are already looping over local cells...
00536                  NEVER_REACHED;
00537                 // Non-local real cell, so free the memory.
00538                 // delete p_cell;
00539                 // delete p_second_cell;
00540              }
00541          }
00542      }
00543 
00550      template<class Archive>
00551      void SaveExtracellularStimulus(Archive & archive, const unsigned int version) const
00552      {
00553          Archive& r_archive = *ProcessSpecificArchive<Archive>::Get();
00554          const std::vector<boost::shared_ptr<AbstractStimulusFunction> > & r_stimulus_distributed = rGetExtracellularStimulusDistributed();
00555          r_archive & this->mpDistributedVectorFactory; // Needed when loading
00556          const unsigned num_cells = r_stimulus_distributed.size();
00557          r_archive & num_cells;
00558          for (unsigned i=0; i<num_cells; i++)
00559          {
00560              r_archive & r_stimulus_distributed[i];
00561          }
00562      }
00563 
00572      template<class Archive>
00573      void LoadExtracellularStimulus(Archive & archive, const unsigned int version,
00574                                                std::vector<boost::shared_ptr<AbstractStimulusFunction> >& rStimuli,
00575                                                AbstractTetrahedralMesh<SPACE_DIM,SPACE_DIM>* pMesh)
00576      {
00577 
00578         DistributedVectorFactory* p_factory;
00579         archive & p_factory;
00580         unsigned num_cells;
00581         archive & num_cells;
00582         rStimuli.resize(p_factory->GetLocalOwnership());
00583 #ifndef NDEBUG
00584           // Paranoia
00585           for (unsigned i=0; i<rStimuli.size(); i++)
00586           {
00587               assert(rStimuli[i] == NULL);
00588           }
00589 #endif
00590 
00591         // We don't store a cell index in the archive, so need to work out what global
00592         // index this tissue starts up.  If we're migrating (so have an
00593         // original factory) we use the original low index; otherwise we use the current
00594         // low index.
00595         unsigned index_low = p_factory->GetOriginalFactory() ? p_factory->GetOriginalFactory()->GetLow() : p_factory->GetLow();
00596 
00597         assert(pMesh!=NULL);
00598         //unsigned num_cells = pMesh->GetNumNodes();
00599         for (unsigned local_index=0; local_index<num_cells; local_index++)
00600         {
00601           unsigned global_index = index_low + local_index;
00602 
00603           unsigned new_local_index = global_index - p_factory->GetLow();
00604           bool local = p_factory->IsGlobalIndexLocal(global_index);
00605 
00606           boost::shared_ptr<AbstractStimulusFunction> p_stim;
00607           archive & p_stim;//get from archive
00608 
00609           if (local)
00610           {
00611               rStimuli[new_local_index] = p_stim; // Add stimulus to local cells
00612           }
00613           //otherwise we should delete, but I think shared pointers delete themselves?
00614         }
00615     }
00616 };
00617 
00618  // Declare identifier for the serializer
00619  #include "SerializationExportWrapper.hpp"
00620  EXPORT_TEMPLATE_CLASS_SAME_DIMS(ExtendedBidomainTissue)
00621 
00622  namespace boost
00623  {
00624  namespace serialization
00625  {
00626 
00627  template<class Archive, unsigned SPACE_DIM>
00628  inline void save_construct_data(
00629      Archive & ar, const ExtendedBidomainTissue<SPACE_DIM> * t, const unsigned int file_version)
00630  {
00631      //archive the conductivity tensor of the second cell (which may not be dealt with by heartconfig)
00632      c_vector<double, SPACE_DIM>  intracellular_conductivities_second_cell = t->GetIntracellularConductivitiesSecondCell();
00633      //note that simple: ar & intracellular_conductivities_second_cell may not be liked by some boost versions
00634      for (unsigned i = 0; i < SPACE_DIM; i++)
00635      {
00636          ar & intracellular_conductivities_second_cell(i);
00637      }
00638 
00639      const AbstractTetrahedralMesh<SPACE_DIM,SPACE_DIM>* p_mesh = t->pGetMesh();
00640      ar & p_mesh;
00641 
00642      // Don't use the std::vector serialization for cardiac cells, so that we can load them
00643      // more cleverly when migrating checkpoints.
00644      t->SaveExtendedBidomainCells(ar, file_version);
00645      t->SaveExtracellularStimulus(ar, file_version);
00646 
00647      // Creation of conductivity tensors are called by constructor and uses HeartConfig. So make sure that it is
00648      // archived too (needs doing before construction so appears here instead of usual archive location).
00649      HeartConfig* p_config = HeartConfig::Instance();
00650      ar & *p_config;
00651      ar & p_config;
00652  }
00653 
00658  template<class Archive, unsigned SPACE_DIM>
00659  inline void load_construct_data(
00660      Archive & ar, ExtendedBidomainTissue<SPACE_DIM> * t, const unsigned int file_version)
00661  {
00662      //Load conductivities of the conductivity of the second cell.
00663      c_vector<double, SPACE_DIM>  intra_cond_second_cell;
00664      //note that simple: ar & intra_cond_second_cell may not be liked by some boost versions
00665      for (unsigned i = 0; i < SPACE_DIM; i++)
00666      {
00667          double cond;
00668          ar & cond;
00669          intra_cond_second_cell(i) = cond;
00670      }
00671 
00672 
00673      std::vector<AbstractCardiacCellInterface*> cells_distributed;
00674      std::vector<AbstractCardiacCellInterface*> cells_distributed_second_cell;
00675      std::vector<boost::shared_ptr<AbstractStimulusFunction> > extra_stim;
00676      std::vector<double> g_gaps;
00677      AbstractTetrahedralMesh<SPACE_DIM,SPACE_DIM>* p_mesh;
00678      ar & p_mesh;
00679 
00680      // Load only the cells we actually own
00681      t->LoadExtendedBidomainCells(
00682              *ProcessSpecificArchive<Archive>::Get(), file_version, cells_distributed, cells_distributed_second_cell, g_gaps, p_mesh);
00683 
00684      t->LoadExtracellularStimulus(
00685              *ProcessSpecificArchive<Archive>::Get(), file_version, extra_stim, p_mesh);
00686 
00687      // CreateIntracellularConductivityTensor() is called by AbstractCardiacTissue constructor and uses HeartConfig.
00688      // (as does CreateExtracellularConductivityTensor). So make sure that it is
00689      // archived too (needs doing before construction so appears here instead of usual archive location).
00690      HeartConfig* p_config = HeartConfig::Instance();
00691      ar & *p_config;
00692      ar & p_config;
00693 
00694      ::new(t)ExtendedBidomainTissue<SPACE_DIM>(cells_distributed, cells_distributed_second_cell, extra_stim, g_gaps, p_mesh, intra_cond_second_cell);
00695  }
00696  }
00697  } // namespace ...
00698 
00699 
00700 
00701 #endif /*EXTENDEDBIDOMAINTISSUE_HPP_*/