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

Generated on Wed Mar 18 12:51:52 2009 for Chaste by  doxygen 1.5.5