BidomainProblem.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2009
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 
00030 #include "BidomainProblem.hpp"
00031 #include "BidomainDg0Assembler.hpp"
00032 #include "BidomainMatrixBasedAssembler.hpp"
00033 #include "BidomainWithBathAssembler.hpp"
00034 #include "BidomainWithBathMatrixBasedAssembler.hpp"
00035 #include "HeartConfig.hpp"
00036 #include "Exception.hpp"
00037 #include "DistributedVector.hpp"
00038 #include "ReplicatableVector.hpp"
00039 
00040 template <unsigned DIM>
00041 void BidomainProblem<DIM>::AnalyseMeshForBath()
00042 {
00043     // Annotate bath notes with correct region code
00044     if (mHasBath)
00045     {
00046         // Initialize all nodes to be bath nodes
00047         for (typename AbstractTetrahedralMesh<DIM,DIM>::NodeIterator iter=this->mpMesh->GetNodeIteratorBegin();
00048              iter != this->mpMesh->GetNodeIteratorEnd();
00049             ++iter)
00050         {
00051             (*iter).SetRegion(HeartRegionCode::BATH);
00052         }
00053 
00054         bool any_bath_element_found = false;
00055 
00056         // Set nodes that are part of a heart element to be heart nodes
00057         //for (unsigned i=0; i<this->mpMesh->GetNumElements(); i++)
00058         for (typename AbstractTetrahedralMesh<DIM,DIM>::ElementIterator it = this->mpMesh->GetElementIteratorBegin();
00059              it != this->mpMesh->GetElementIteratorEnd();
00060              ++it)
00061         {
00062             Element<DIM, DIM>& r_element = *it;
00063 
00064             if (r_element.GetRegion() == HeartRegionCode::TISSUE)
00065             {
00066                 for (unsigned j=0; j<r_element.GetNumNodes(); j++)
00067                 {
00068                     r_element.GetNode(j)->SetRegion(HeartRegionCode::TISSUE);
00069                 }
00070             }
00071             else
00072             {
00073                 assert(r_element.GetRegion() == HeartRegionCode::BATH);
00074                 any_bath_element_found = true;
00075             }
00076         }
00077 
00078         if (!any_bath_element_found)
00079         {
00080             EXCEPTION("No bath element found");
00081         }
00082     }
00083 }
00084 
00085 
00086 template<unsigned DIM>
00087 Vec BidomainProblem<DIM>::CreateInitialCondition()
00088 {
00089     Vec init_cond = AbstractCardiacProblem<DIM,DIM,2>::CreateInitialCondition();
00090     if (mHasBath)
00091     {
00092         // get the voltage stripe
00093         DistributedVector ic = this->mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(init_cond);
00094         DistributedVector::Stripe voltage_stripe = DistributedVector::Stripe(ic,0);
00095 
00096         for (DistributedVector::Iterator index = ic.Begin();
00097              index!= ic.End();
00098              ++index)
00099         {
00100             if (this->mpMesh->GetNode( index.Global )->GetRegion() == HeartRegionCode::BATH)
00101             {
00102                 voltage_stripe[index] = 0.0;
00103             }
00104         }
00105         ic.Restore();
00106     }
00107 
00108     return init_cond;
00109 }
00110 
00111 template<unsigned DIM>
00112 AbstractCardiacPde<DIM> * BidomainProblem<DIM>::CreateCardiacPde()
00113 {
00114     AnalyseMeshForBath();
00115     mpBidomainPde = new BidomainPde<DIM>(this->mpCellFactory);
00116     return mpBidomainPde;
00117 }
00118 
00119 template<unsigned DIM>
00120 AbstractDynamicAssemblerMixin<DIM, DIM, 2>* BidomainProblem<DIM>::CreateAssembler()
00121 {
00122     if (mHasBath)
00123     {
00124         if (!this->mUseMatrixBasedRhsAssembly)
00125         {
00126             mpAssembler
00127                 = new BidomainWithBathAssembler<DIM,DIM>(this->mpMesh,
00128                                                          mpBidomainPde,
00129                                                          this->mpBoundaryConditionsContainer,
00130                                                          2);
00131         }
00132         else
00133         {
00134             mpAssembler
00135                 = new BidomainWithBathMatrixBasedAssembler<DIM,DIM>(this->mpMesh,
00136                                                             mpBidomainPde,
00137                                                             this->mpBoundaryConditionsContainer,
00138                                                             2);
00139         }
00140 
00141     }
00142     else
00143     {
00144         if (!this->mUseMatrixBasedRhsAssembly)
00145         {
00146             mpAssembler
00147                 = new BidomainDg0Assembler<DIM,DIM>(this->mpMesh,
00148                                                     mpBidomainPde,
00149                                                     this->mpBoundaryConditionsContainer,
00150                                                     2);
00151         }
00152         else
00153         {
00154             mpAssembler
00155                 = new BidomainMatrixBasedAssembler<DIM,DIM>(this->mpMesh,
00156                                                             mpBidomainPde,
00157                                                             this->mpBoundaryConditionsContainer,
00158                                                             2);
00159         }
00160     }
00161 
00162     try
00163     {
00164         mpAssembler->SetFixedExtracellularPotentialNodes(mFixedExtracellularPotentialNodes);
00165         mpAssembler->SetRowForAverageOfPhiZeroed(mRowForAverageOfPhiZeroed);
00166     }
00167     catch (const Exception& e)
00168     {
00169         delete mpAssembler;
00170         throw e;
00171     }
00172 
00173     return mpAssembler;
00174 }
00175 
00176 template<unsigned DIM>
00177 BidomainProblem<DIM>::BidomainProblem(
00178             AbstractCardiacCellFactory<DIM>* pCellFactory, bool hasBath)
00179     : AbstractCardiacProblem<DIM,DIM, 2>(pCellFactory),
00180       mpBidomainPde(NULL),
00181       mRowForAverageOfPhiZeroed(INT_MAX),
00182       mHasBath(hasBath),
00183       mpElectrodes(NULL)
00184 {
00185     mFixedExtracellularPotentialNodes.resize(0);
00186 }
00187 
00188 template<unsigned DIM>
00189 void BidomainProblem<DIM>::SetFixedExtracellularPotentialNodes(std::vector<unsigned> nodes)
00190 {
00191     mFixedExtracellularPotentialNodes.resize(nodes.size());
00192     for (unsigned i=0; i<nodes.size(); i++)
00193     {
00194         // the assembler checks that the nodes[i] is less than
00195         // the number of nodes in the mesh so this is not done here
00196         mFixedExtracellularPotentialNodes[i] = nodes[i];
00197     }
00198 }
00199 
00200 template<unsigned DIM>
00201 void BidomainProblem<DIM>::SetNodeForAverageOfPhiZeroed(unsigned node)
00202 {
00203     mRowForAverageOfPhiZeroed = 2*node+1;
00204 }
00205 
00206 template<unsigned DIM>
00207 BidomainPde<DIM>* BidomainProblem<DIM>::GetBidomainPde()
00208 {
00209     assert(mpBidomainPde!=NULL);
00210     return mpBidomainPde;
00211 }
00212 
00213 template<unsigned DIM>
00214 void BidomainProblem<DIM>::WriteInfo(double time)
00215 {
00216     std::cout << "Solved to time " << time << "\n" << std::flush;
00217     ReplicatableVector voltage_replicated;
00218     voltage_replicated.ReplicatePetscVector(this->mSolution);
00219     double v_max = -1e5, v_min = 1e5, phi_max = -1e5, phi_min = 1e5;
00220 
00221     for (unsigned i=0; i<this->mpMesh->GetNumNodes(); i++)
00222     {
00223         double v=voltage_replicated[2*i];
00224         double phi=voltage_replicated[2*i+1];
00225 
00226         #define COVERAGE_IGNORE
00227         if (std::isnan(v) || std::isnan(phi))
00228         {
00229             EXCEPTION("Not-a-number encountered");
00230         }
00231         #undef COVERAGE_IGNORE
00232         if ( v > v_max)
00233         {
00234             v_max = v;
00235         }
00236         if ( v < v_min)
00237         {
00238             v_min = v;
00239         }
00240         if ( phi > phi_max)
00241         {
00242             phi_max = phi;
00243         }
00244         if ( phi < phi_min)
00245         {
00246             phi_min = phi;
00247         }
00248     }
00249     std::cout << " V; phi_e = " << "[" <<v_min << ", " << v_max << "]" << ";\t"
00250               << "[" <<phi_min << ", " << phi_max << "]" << "\n"
00251               << std::flush;
00252 }
00253 
00254 template<unsigned DIM>
00255 void BidomainProblem<DIM>::DefineWriterColumns()
00256 {
00257     AbstractCardiacProblem<DIM,DIM,2>::DefineWriterColumns();
00258     mExtracelluarColumnId = this->mpWriter->DefineVariable("Phi_e","mV");
00259 }
00260 
00261 template<unsigned DIM>
00262 void BidomainProblem<DIM>::WriteOneStep(double time, Vec voltageVec)
00263 {
00264     this->mpWriter->PutUnlimitedVariable(time);
00265     this->mpWriter->PutStripedVector(this->mVoltageColumnId, mExtracelluarColumnId, voltageVec);
00266 }
00267 
00268 template<unsigned DIM>
00269 void BidomainProblem<DIM>::PreSolveChecks()
00270 {
00271     AbstractCardiacProblem<DIM,DIM, 2>::PreSolveChecks();
00272     if (mFixedExtracellularPotentialNodes.empty())
00273     {
00274         // We're not pinning any nodes.
00275         if (mRowForAverageOfPhiZeroed==INT_MAX)
00276         {
00277             // We're not using the constrain Average phi_e to 0 method, hence use a null space
00278             // Check that the KSP solver isn't going to do anything stupid:
00279             // phi_e is not bounded, so it'd be wrong to use a relative tolerance
00280             if (HeartConfig::Instance()->GetUseRelativeTolerance())
00281             {
00282                 EXCEPTION("Bidomain external voltage is not bounded in this simulation - use KSP *absolute* tolerance");
00283             }
00284         }
00285     }
00286 }
00287 
00288 template<unsigned DIM>
00289 void BidomainProblem<DIM>::SetElectrodes(Electrodes<DIM>& rElectrodes)
00290 {
00291     if(!mHasBath)
00292     {
00293         EXCEPTION("Cannot set electrodes when problem has been defined to not have a bath");
00294     }
00295 
00296     mpElectrodes = &rElectrodes;
00297 
00298     SetBoundaryConditionsContainer(mpElectrodes->GetBoundaryConditionsContainer());
00299 }
00300 
00301 
00302 template<unsigned DIM>
00303 void BidomainProblem<DIM>::OnEndOfTimestep(double time)
00304 {
00305     if( (mpElectrodes!=NULL) && (mpElectrodes->SwitchOff(time)) )
00306     {
00307         // at the moment mpBcc should exist and therefore
00308         // mpDefaultBcc should be null
00309         assert(this->mpBoundaryConditionsContainer!=NULL);
00310         assert(this->mpDefaultBoundaryConditionsContainer==NULL);
00311 
00315 
00316         // set up default boundary conditions container - no Neumann fluxes
00317         // or Dirichlet fixed nodes
00318         if(this->mpDefaultBoundaryConditionsContainer==NULL)
00319         {
00320             this->mpDefaultBoundaryConditionsContainer = new BoundaryConditionsContainer<DIM,DIM,2>;
00321             for (unsigned problem_index=0; problem_index<2; problem_index++)
00322             {
00323                 this->mpDefaultBoundaryConditionsContainer->DefineZeroNeumannOnMeshBoundary(this->mpMesh, problem_index);
00324             }
00325         }
00326         // Note, no point calling SetBoundaryConditionsContainer() as the
00327         // assembler has already been created..
00328         mpAssembler->SetBoundaryConditionsContainer(this->mpDefaultBoundaryConditionsContainer);
00329         // ..but we set mpBcc to be mpDefaultBcc anyway, so the local mpBcc is
00330         // the same as the one being used in the assembler (and so the deletion
00331         // works later)
00332         this->mpBoundaryConditionsContainer = this->mpDefaultBoundaryConditionsContainer;
00333     }
00334 }
00335 
00337 // Explicit instantiation
00339 
00340 template class BidomainProblem<1>;
00341 template class BidomainProblem<2>;
00342 template class BidomainProblem<3>;

Generated on Tue Aug 4 16:10:22 2009 for Chaste by  doxygen 1.5.5