ExtendedBidomainProblem.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
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 "ExtendedBidomainProblem.hpp"
00031 #include "ExtendedBidomainSolver.hpp"
00032 #include "AbstractDynamicLinearPdeSolver.hpp"
00033 #include "HeartConfig.hpp"
00034 #include "Exception.hpp"
00035 #include "DistributedVector.hpp"
00036 #include "ReplicatableVector.hpp"
00037 
00038 
00039 
00040 template<unsigned DIM>
00041 ExtendedBidomainProblem<DIM>::ExtendedBidomainProblem(
00042             AbstractCardiacCellFactory<DIM>* pCellFactory, AbstractCardiacCellFactory<DIM>* pSecondCellFactory, bool hasBath)
00043     : AbstractCardiacProblem<DIM,DIM, 3>(pCellFactory),
00044       mpSecondCellFactory(pSecondCellFactory),
00045       mpExtendedBidomainTissue(NULL),
00046       mUserSpecifiedSecondCellConductivities(false),
00047       mUserHasSetBidomainValuesExplicitly(false),
00048       mpExtracellularStimulusFactory(NULL),
00049       mRowForAverageOfPhiZeroed(INT_MAX),
00050       mApplyAveragePhieZeroConstraintAfterSolving(false),
00051       mUserSuppliedExtracellularStimulus(false),
00052       mHasBath(hasBath)
00053 {
00054     mFixedExtracellularPotentialNodes.resize(0);
00055 }
00056 
00057 template<unsigned DIM>
00058 ExtendedBidomainProblem<DIM>::ExtendedBidomainProblem()
00059     : AbstractCardiacProblem<DIM,DIM, 3>(),
00060       mpSecondCellFactory(NULL),
00061       mpExtendedBidomainTissue(NULL),
00062       mUserSpecifiedSecondCellConductivities(false),
00063       mUserHasSetBidomainValuesExplicitly(false),
00064       mpExtracellularStimulusFactory(NULL),
00065       mRowForAverageOfPhiZeroed(INT_MAX),
00066       mApplyAveragePhieZeroConstraintAfterSolving(false),
00067       mUserSuppliedExtracellularStimulus(false)
00068 {
00069     mFixedExtracellularPotentialNodes.resize(0);
00070 }
00071 
00072 
00073 template<unsigned DIM>
00074 Vec ExtendedBidomainProblem<DIM>::CreateInitialCondition()
00075 {
00076 
00077     DistributedVectorFactory* p_factory = this->mpMesh->GetDistributedVectorFactory();
00078     Vec initial_condition = p_factory->CreateVec(3);
00079     DistributedVector ic = p_factory->CreateDistributedVector(initial_condition);
00080     std::vector<DistributedVector::Stripe> stripe;
00081     stripe.reserve(3);
00082 
00083     stripe.push_back(DistributedVector::Stripe(ic, 0));
00084     stripe.push_back(DistributedVector::Stripe(ic, 1));
00085     stripe.push_back(DistributedVector::Stripe(ic, 2));
00086 
00087     for (DistributedVector::Iterator index = ic.Begin();
00088          index != ic.End();
00089          ++index)
00090     {
00091         stripe[0][index] = mpExtendedBidomainTissue->GetCardiacCell(index.Global)->GetVoltage();//phi_i of frrst cell = Vm first cell at the start
00092         stripe[1][index] = mpExtendedBidomainTissue->GetCardiacSecondCell(index.Global)->GetVoltage();//phi_i of second cell = Vm second cell at the start
00093         stripe[2][index] = 0.0;//
00094     }
00095     ic.Restore();
00096 
00097     return initial_condition;
00098 }
00099 
00100 template<unsigned DIM>
00101 void ExtendedBidomainProblem<DIM>::ProcessExtracellularStimulus()
00102 {
00103     if ((mpExtracellularStimulusFactory == NULL))//user has not passed in any extracelular stimulus in any form
00104     {
00105         mpExtracellularStimulusFactory = new AbstractStimulusFactory<DIM>();
00106         //create one (with default implementation to zero stimulus everywhere)
00107     }
00108 
00109     assert(mpExtracellularStimulusFactory);//should be created by now, either above or by the user...
00110     mpExtracellularStimulusFactory->SetMesh(this->mpMesh);//so, set the mesh into it.
00111     mpExtracellularStimulusFactory->SetCompatibleExtracellularStimulus();//make sure compatibility condition will be valid
00112 
00113     std::vector<AbstractChasteRegion<DIM>* > grounded_regions = mpExtracellularStimulusFactory->GetRegionsToBeGrounded();
00114 
00115     if ( (mUserSuppliedExtracellularStimulus) && grounded_regions.size() > 0 ) //we check for grunded nodes here
00116     {
00117         std::vector<unsigned> grounded_indices;
00118         for (unsigned global_node_index = 0; global_node_index < this->mpMesh->GetNumNodes(); global_node_index++)
00119         {
00120             if (this->mpMesh->GetDistributedVectorFactory()->IsGlobalIndexLocal(global_node_index))
00121             {
00122                 for (unsigned region_index = 0; region_index <grounded_regions.size(); region_index++)
00123                 {
00124                     if ( grounded_regions[region_index]->DoesContain( this->mpMesh->GetNode(global_node_index)->GetPoint() ) )
00125                     {
00126                         grounded_indices.push_back( this->mpMesh->GetNode(global_node_index)->GetIndex() );
00127                     }
00128                 }
00129             }
00130         }
00131         PetscTools::Barrier();
00132         SetFixedExtracellularPotentialNodes(grounded_indices);
00133     }
00134 }
00135 
00136 template<unsigned DIM>
00137 AbstractCardiacTissue<DIM> * ExtendedBidomainProblem<DIM>::CreateCardiacTissue()
00138 {
00139     //set the mesh into the second cell factory as well.
00140     mpSecondCellFactory->SetMesh(this->mpMesh);
00141 
00142     //deal with extracellular stimulus, if any
00143     ProcessExtracellularStimulus();
00144 
00145     //Now create the tissue object
00146     mpExtendedBidomainTissue = new ExtendedBidomainTissue<DIM>(this->mpCellFactory, mpSecondCellFactory,mpExtracellularStimulusFactory);
00147 
00148     //Let the Tissue know if the user wants an extracellular stimulus (or if we had to create a default zero one).
00149     mpExtendedBidomainTissue->SetUserSuppliedExtracellularStimulus(mUserSuppliedExtracellularStimulus);
00150 
00151     //if the user remembered to set a different value for the sigma of the second cell...
00152     if (mUserSpecifiedSecondCellConductivities)
00153     {
00154         mpExtendedBidomainTissue->SetIntracellularConductivitiesSecondCell(mIntracellularConductivitiesSecondCell);
00155     }
00156     else //..otherwise it gets the same as the first cell (according to heartconfig...)
00157     {
00158         c_vector<double, DIM> intra_conductivities;
00159         HeartConfig::Instance()->GetIntracellularConductivities(intra_conductivities);
00160         mpExtendedBidomainTissue->SetIntracellularConductivitiesSecondCell(intra_conductivities);
00161     }
00162 
00163     //the conductivities for the first cell are created within the tissue constructor in the abstract class
00164     //here we create the ones for the second cell
00165     mpExtendedBidomainTissue->CreateIntracellularConductivityTensorSecondCell();
00166 
00167     if (mUserHasSetBidomainValuesExplicitly)
00168     {
00169         mpExtendedBidomainTissue->SetAmFirstCell(mAmFirstCell);
00170         mpExtendedBidomainTissue->SetAmSecondCell(mAmSecondCell);
00171         mpExtendedBidomainTissue->SetAmGap(mAmGap);
00172         mpExtendedBidomainTissue->SetGGap(mGGap);
00173         mpExtendedBidomainTissue->SetCmFirstCell(mCmFirstCell);
00174         mpExtendedBidomainTissue->SetCmSecondCell(mCmSecondCell);
00175     }
00176     else//we set all the Am and Cm to the values set by the heartconfig (only one value for all Am and one value for all Cms)
00177     {
00178         mpExtendedBidomainTissue->SetAmFirstCell(HeartConfig::Instance()->GetSurfaceAreaToVolumeRatio());
00179         mpExtendedBidomainTissue->SetAmSecondCell(HeartConfig::Instance()->GetSurfaceAreaToVolumeRatio());
00180         mpExtendedBidomainTissue->SetAmGap(HeartConfig::Instance()->GetSurfaceAreaToVolumeRatio());
00181         mpExtendedBidomainTissue->SetGGap(0.0);
00182         mpExtendedBidomainTissue->SetCmFirstCell(HeartConfig::Instance()->GetCapacitance());
00183         mpExtendedBidomainTissue->SetCmSecondCell(HeartConfig::Instance()->GetCapacitance());
00184     }
00185 
00186     mpExtendedBidomainTissue->SetGgapHeterogeneities(mGgapHeterogeneityRegions, mGgapHeterogenousValues);//set user input into the tissue class
00187     mpExtendedBidomainTissue->CreateGGapConductivities();//if vectors are empty, mGgap will be put everywhere by this method.
00188 
00189     return mpExtendedBidomainTissue;
00190 }
00191 
00192 template<unsigned DIM>
00193 void ExtendedBidomainProblem<DIM>::SetExtendedBidomainParameters(double Am1, double Am2, double AmGap, double Cm1, double Cm2, double Ggap)
00194 {
00195      mAmFirstCell = Am1;
00196      mAmSecondCell = Am2;
00197      mAmGap = AmGap;
00198      mCmFirstCell = Cm1;
00199      mCmSecondCell = Cm2;
00200      mGGap = Ggap;
00201 
00202      mUserHasSetBidomainValuesExplicitly = true;
00203 }
00204 
00205 template <unsigned DIM>
00206 void ExtendedBidomainProblem<DIM>::SetGgapHeterogeneities ( std::vector<boost::shared_ptr<AbstractChasteRegion<DIM> > >& rGgapHeterogeneityRegions, std::vector<double>& rGgapValues)
00207 {
00208     if (rGgapHeterogeneityRegions.size() != rGgapValues.size() )
00209     {
00210         EXCEPTION  ("Gap junction heterogeneity areas must be of the same number as the heterogeneity values");
00211     }
00212     mGgapHeterogeneityRegions = rGgapHeterogeneityRegions;
00213     mGgapHeterogenousValues =rGgapValues;
00214 }
00215 
00216 template <unsigned DIM>
00217 void ExtendedBidomainProblem<DIM>::SetExtracellularStimulusFactory( AbstractStimulusFactory<DIM>* pFactory)
00218 {
00219     mpExtracellularStimulusFactory = pFactory;
00220     mUserSuppliedExtracellularStimulus = true;
00221 }
00222 
00223 template<unsigned DIM>
00224 AbstractDynamicLinearPdeSolver<DIM, DIM, 3>* ExtendedBidomainProblem<DIM>::CreateSolver()
00225 {
00226     /*
00227      * NOTE: The this->mpBoundaryConditionsContainer.get() lines below convert a
00228      * boost::shared_ptr to a normal pointer, as this is what the assemblers are
00229      * expecting. We have to be a bit careful though as boost could decide to delete
00230      * them whenever it feels like as it won't count the assembers as using them.
00231      *
00232      * As long as they are kept as member variables here for as long as they are
00233      * required in the assemblers it should all work OK.
00234      */
00235 
00236 
00237     mpSolver = new ExtendedBidomainSolver<DIM,DIM>( mHasBath,
00238                                                     this->mpMesh,
00239                                                     mpExtendedBidomainTissue,
00240                                                     this->mpBoundaryConditionsContainer.get(),
00241                                                     2);//2 is number of quad points
00242 
00243 
00244     try
00245     {
00246         mpSolver->SetFixedExtracellularPotentialNodes(mFixedExtracellularPotentialNodes);
00247         mpSolver->SetRowForAverageOfPhiZeroed(mRowForAverageOfPhiZeroed);
00248     }
00249     catch (const Exception& e)
00250     {
00251         delete mpSolver;
00252         throw e;
00253     }
00254 
00255     return mpSolver;
00256 }
00257 
00258 template<unsigned DIM>
00259 ExtendedBidomainProblem<DIM>::~ExtendedBidomainProblem()
00260 {
00261     if (!mUserSuppliedExtracellularStimulus)
00262     {
00263         delete mpExtracellularStimulusFactory;
00264     }
00265 }
00266 
00267 template<unsigned DIM>
00268 void ExtendedBidomainProblem<DIM>::SetIntracellularConductivitiesForSecondCell(c_vector<double, DIM> conductivities)
00269 {
00270     for (unsigned i = 0; i < DIM; i++)
00271     {
00272         mIntracellularConductivitiesSecondCell[i] = conductivities[i];
00273     }
00274     mUserSpecifiedSecondCellConductivities = true;
00275 }
00276 
00277 template<unsigned DIM>
00278 void ExtendedBidomainProblem<DIM>::SetFixedExtracellularPotentialNodes(std::vector<unsigned> nodes)
00279 {
00280     assert(mFixedExtracellularPotentialNodes.size() == 0); //TODO turn this into an exception if the user calls this twice...
00281     mFixedExtracellularPotentialNodes.resize(nodes.size());
00282     for (unsigned i=0; i<nodes.size(); i++)
00283     {
00284         // the assembler checks that the nodes[i] is less than
00285         // the number of nodes in the mesh so this is not done here
00286         mFixedExtracellularPotentialNodes[i] = nodes[i];
00287     }
00288 }
00289 
00290 template<unsigned DIM>
00291 void ExtendedBidomainProblem<DIM>::SetNodeForAverageOfPhiZeroed(unsigned node)
00292 {
00293     if (node==0)
00294     {
00295         mRowForAverageOfPhiZeroed = 2;
00296     }
00297     else
00298     {
00299         //Phie is every three lines, starting from zero...
00300         mRowForAverageOfPhiZeroed = 3*node  - 1;
00301     }
00302 }
00303 
00304 template<unsigned DIM>
00305 ExtendedBidomainTissue<DIM>* ExtendedBidomainProblem<DIM>::GetExtendedBidomainTissue()
00306 {
00307     assert(mpExtendedBidomainTissue!=NULL);
00308     return mpExtendedBidomainTissue;
00309 }
00310 
00311 template<unsigned DIM>
00312 void ExtendedBidomainProblem<DIM>::WriteInfo(double time)
00313 {
00314     if (PetscTools::AmMaster())
00315     {
00316         std::cout << "Solved to time " << time << "\n" << std::flush;
00317     }
00318 
00319     double phi_i_max_first_cell, phi_i_min_first_cell, phi_i_max_second_cell, phi_i_min_second_cell, phi_e_min, phi_e_max;
00320 
00321     VecSetBlockSize( this->mSolution, 3 );
00322 
00323     VecStrideMax( this->mSolution, 0, PETSC_NULL, &phi_i_max_first_cell );
00324     VecStrideMin( this->mSolution, 0, PETSC_NULL, &phi_i_min_first_cell );
00325 
00326     VecStrideMax( this->mSolution, 1, PETSC_NULL, &phi_i_max_second_cell );
00327     VecStrideMin( this->mSolution, 1, PETSC_NULL, &phi_i_min_second_cell );
00328 
00329     VecStrideMax( this->mSolution, 2, PETSC_NULL, &phi_e_max );
00330     VecStrideMin( this->mSolution, 2, PETSC_NULL, &phi_e_min );
00331 
00332     if (PetscTools::AmMaster())
00333     {
00334         std::cout << " Phi_i first cell = " << "[" <<phi_i_max_first_cell << ", " << phi_i_min_first_cell << "]" << ";\n"
00335                   << " Phi_i second cell = " << "[" <<phi_i_max_second_cell << ", " << phi_i_min_second_cell << "]" << ";\n"
00336                   << " Phi_e = " << "[" <<phi_e_max << ", " << phi_e_min << "]" << ";\n"
00337                   << std::flush;
00338     }
00339 }
00340 
00341 template<unsigned DIM>
00342 void ExtendedBidomainProblem<DIM>::DefineWriterColumns(bool extending)
00343 {
00344     if (!extending)
00345     {
00346         if ( this->mNodesToOutput.empty() )
00347         {
00348             //Set writer to output all nodes
00349             this->mpWriter->DefineFixedDimension( this->mpMesh->GetNumNodes() );
00350         }
00351 //        else
00352 //        {
00353 //            //Output only the nodes indicted
00354 //            this->mpWriter->DefineFixedDimension( this->mNodesToOutput, this->mpMesh->GetNumNodes() );
00355 //        }
00356         //mNodeColumnId = mpWriter->DefineVariable("Node", "dimensionless");
00357         mVoltageColumnId_Vm1 = this->mpWriter->DefineVariable("V","mV");
00358         mVoltageColumnId_Vm2 = this->mpWriter->DefineVariable("V_2","mV");
00359         mVoltageColumnId_Phie = this->mpWriter->DefineVariable("Phi_e","mV");
00360         mVariablesIDs.push_back(mVoltageColumnId_Vm1);
00361         mVariablesIDs.push_back(mVoltageColumnId_Vm2);
00362         mVariablesIDs.push_back(mVoltageColumnId_Phie);
00363         this->mpWriter->DefineUnlimitedDimension("Time","msecs");
00364     }
00365     else
00366     {
00367         mVoltageColumnId_Vm1 = this->mpWriter->GetVariableByName("V");
00368         mVoltageColumnId_Vm2 = this->mpWriter->GetVariableByName("V_2");
00369         mVoltageColumnId_Phie = this->mpWriter->GetVariableByName("Phi_e");
00370     }
00371     //define any extra variable. NOTE: it must be in the first cell (not the second)
00372     AbstractCardiacProblem<DIM,DIM,3>::DefineExtraVariablesWriterColumns(extending);
00373 
00374 }
00375 
00376 template<unsigned DIM>
00377 void ExtendedBidomainProblem<DIM>::WriteOneStep(double time, Vec voltageVec)
00378 {
00379     this->mpWriter->PutUnlimitedVariable(time);
00380 
00381    // Create a striped vector
00382     Vec ordered_voltages =  this->mpMesh->GetDistributedVectorFactory()->CreateVec(3);
00383     DistributedVector wrapped_ordered_solution = this->mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(ordered_voltages);
00384     DistributedVector wrapped_solution = this->mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(voltageVec);
00385 
00386     DistributedVector::Stripe phi_i_first_cell_stripe(wrapped_solution,0);
00387     DistributedVector::Stripe phi_i_second_cell_stripe(wrapped_solution,1);
00388     DistributedVector::Stripe phi_e_stripe(wrapped_solution,2);
00389 
00390     DistributedVector::Stripe wrapped_ordered_solution_first_stripe(wrapped_ordered_solution,0);
00391     DistributedVector::Stripe wrapped_ordered_solution_second_stripe(wrapped_ordered_solution,1);
00392     DistributedVector::Stripe wrapped_ordered_solution_third_stripe(wrapped_ordered_solution,2);
00393 
00394     for (DistributedVector::Iterator index = wrapped_solution.Begin();
00395          index != wrapped_solution.End();
00396          ++index)
00397     {
00398         wrapped_ordered_solution_first_stripe[index] = phi_i_first_cell_stripe[index] - phi_e_stripe[index];
00399         wrapped_ordered_solution_second_stripe[index] = phi_i_second_cell_stripe[index] - phi_e_stripe[index];
00400         wrapped_ordered_solution_third_stripe[index] = phi_e_stripe[index];
00401     }
00402     wrapped_solution.Restore();
00403     wrapped_ordered_solution.Restore();
00404 
00405     this->mpWriter->PutStripedVector(mVariablesIDs, ordered_voltages);
00406     VecDestroy(ordered_voltages);
00407     //write any extra variable. Note that this method in the parent class will
00408     //take the extra variable only from the first cell. ///\todo write a specific method for this class
00409     AbstractCardiacProblem<DIM,DIM,3>::WriteExtraVariablesOneStep();
00410 }
00411 
00412 template<unsigned DIM>
00413 void ExtendedBidomainProblem<DIM>::PreSolveChecks()
00414 {
00415     AbstractCardiacProblem<DIM,DIM, 3>::PreSolveChecks();
00416     if (mFixedExtracellularPotentialNodes.empty())
00417     {
00418         // We're not pinning any nodes.
00419         if (mRowForAverageOfPhiZeroed==INT_MAX)
00420         {
00421             // We're not using the constrain Average phi_e to 0 method, hence use a null space
00422             // Check that the KSP solver isn't going to do anything stupid:
00423             // phi_e is not bounded, so it'd be wrong to use a relative tolerance
00424             if (HeartConfig::Instance()->GetUseRelativeTolerance())
00425             {
00426                 EXCEPTION("Bidomain external voltage is not bounded in this simulation - use KSP *absolute* tolerance");
00427             }
00428         }
00429     }
00430 }
00431 
00432 template<unsigned DIM>
00433 bool ExtendedBidomainProblem<DIM>::GetHasBath()
00434 {
00435     return mHasBath;
00436 }
00437 
00438 
00439 template<unsigned DIM>
00440 void ExtendedBidomainProblem<DIM>::SetHasBath(bool hasBath)
00441 {
00442     mHasBath = hasBath;
00443 }
00444 
00446 // Explicit instantiation
00448 
00449 template class ExtendedBidomainProblem<1>;
00450 template class ExtendedBidomainProblem<2>;
00451 template class ExtendedBidomainProblem<3>;
00452 
00453 // Serialization for Boost >= 1.36
00454 #include "SerializationExportWrapperForCpp.hpp"
00455 EXPORT_TEMPLATE_CLASS_SAME_DIMS(ExtendedBidomainProblem)
Generated on Thu Dec 22 13:00:06 2011 for Chaste by  doxygen 1.6.3