Chaste Release::3.1
|
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 #include "AbstractExtendedBidomainSolver.hpp" 00037 00038 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00039 void AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::InitialiseForSolve(Vec initialSolution) 00040 { 00041 if (this->mpLinearSystem != NULL) 00042 { 00043 return; 00044 } 00045 00046 // linear system created here 00047 AbstractDynamicLinearPdeSolver<ELEMENT_DIM,SPACE_DIM,3>::InitialiseForSolve(initialSolution); 00048 00049 if (HeartConfig::Instance()->GetUseAbsoluteTolerance()) 00050 { 00051 #ifdef TRACE_KSP 00052 std::cout << "Using absolute tolerance: " << mpConfig->GetAbsoluteTolerance() <<"\n"; 00053 #endif 00054 this->mpLinearSystem->SetAbsoluteTolerance(mpConfig->GetAbsoluteTolerance()); 00055 } 00056 else 00057 { 00058 #ifdef TRACE_KSP 00059 std::cout << "Using relative tolerance: " << mpConfig->GetRelativeTolerance() <<"\n"; 00060 #endif 00061 this->mpLinearSystem->SetRelativeTolerance(mpConfig->GetRelativeTolerance()); 00062 } 00063 00064 this->mpLinearSystem->SetKspType(HeartConfig::Instance()->GetKSPSolver()); 00065 this->mpLinearSystem->SetPcType(HeartConfig::Instance()->GetKSPPreconditioner()); 00066 00067 if (mRowForAverageOfPhiZeroed==INT_MAX) 00068 { 00069 // not applying average(phi)=0 constraint, so matrix is symmetric 00070 this->mpLinearSystem->SetMatrixIsSymmetric(true); 00071 } 00072 else 00073 { 00074 // applying average(phi)=0 constraint, so matrix is not symmetric 00075 this->mpLinearSystem->SetMatrixIsSymmetric(false); 00076 } 00077 } 00078 00079 00080 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00081 void AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::PrepareForSetupLinearSystem(Vec existingSolution) 00082 { 00083 double time = PdeSimulationTime::GetTime(); 00084 double delta_t = PdeSimulationTime::GetPdeTimeStep(); 00085 mpExtendedBidomainTissue->SolveCellSystems(existingSolution, time, time + delta_t); 00086 } 00087 00088 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00089 Vec AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::GenerateNullBasis() const 00090 { 00091 double sqrrt_num_nodes = sqrt( this->mpMesh->GetNumNodes()); 00092 double normalised_basis_value = 1.0 / sqrrt_num_nodes; 00093 00094 Vec nullbasis; 00095 DistributedVectorFactory* p_factory = this->mpMesh->GetDistributedVectorFactory(); 00096 nullbasis=p_factory->CreateVec(3); 00097 DistributedVector dist_null_basis = p_factory->CreateDistributedVector(nullbasis); 00098 DistributedVector::Stripe null_basis_stripe_0(dist_null_basis,0); 00099 DistributedVector::Stripe null_basis_stripe_1(dist_null_basis,1); 00100 DistributedVector::Stripe null_basis_stripe_2(dist_null_basis,2); 00101 for (DistributedVector::Iterator index = dist_null_basis.Begin(); 00102 index != dist_null_basis.End(); 00103 ++index) 00104 { 00105 null_basis_stripe_0[index] = 0.0; 00106 null_basis_stripe_1[index] = 0.0; 00107 null_basis_stripe_2[index] = normalised_basis_value; 00108 } 00109 dist_null_basis.Restore(); 00110 return nullbasis; 00111 } 00112 00113 00114 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00115 void AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::FinaliseLinearSystem(Vec existingSolution) 00116 { 00117 if (!(this->mpBoundaryConditions->HasDirichletBoundaryConditions())) 00118 { 00119 // We're not pinning any nodes. 00120 if (mRowForAverageOfPhiZeroed==INT_MAX) 00121 { 00122 // We're not using the 'Average phi_e = 0' method, hence use a null space 00123 if (!mNullSpaceCreated) 00124 { 00125 // No null space set up, so create one and pass it to the linear system 00126 Vec nullbasis[] = {GenerateNullBasis()}; 00127 00128 this->mpLinearSystem->SetNullBasis(nullbasis, 1); 00129 00130 PetscTools::Destroy(nullbasis[0]); 00131 mNullSpaceCreated = true; 00132 } 00133 } 00134 else // mRowForAverageOfPhiZeroed!=INT_MAX, i.e. we're using the 'Average phi_e = 0' method 00135 { 00136 // CG (default solver) won't work since the system isn't symmetric anymore. Switch to GMRES 00137 this->mpLinearSystem->SetKspType("gmres"); // Switches the solver 00138 mpConfig->SetKSPSolver("gmres"); // Makes sure this change will be reflected in the XML file written to disk at the end of the simulation. 00139 00140 // Set average phi_e to zero 00141 unsigned matrix_size = this->mpLinearSystem->GetSize(); 00142 if (!this->mMatrixIsAssembled) 00143 { 00144 00145 // Set the mRowForAverageOfPhiZeroed-th matrix row to 0 0 1 0 0 1 ... 00146 std::vector<unsigned> row_for_average; 00147 row_for_average.push_back(mRowForAverageOfPhiZeroed); 00148 this->mpLinearSystem->ZeroMatrixRowsWithValueOnDiagonal(row_for_average, 0.0); 00149 for (unsigned col_index=0; col_index<matrix_size; col_index++) 00150 { 00151 if (((col_index-2)%3 == 0) && (col_index>1))//phi_e column indices are 2,5,8,11 etc.... 00152 { 00153 this->mpLinearSystem->SetMatrixElement(mRowForAverageOfPhiZeroed, col_index, 1); 00154 } 00155 00156 } 00157 this->mpLinearSystem->FinaliseLhsMatrix(); 00158 } 00159 // Set the mRowForAverageOfPhiZeroed-th rhs vector row to 0 00160 this->mpLinearSystem->SetRhsVectorElement(mRowForAverageOfPhiZeroed, 0); 00161 00162 this->mpLinearSystem->FinaliseRhsVector(); 00163 } 00164 } 00165 CheckCompatibilityCondition(); 00166 } 00167 00168 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00169 void AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::CheckCompatibilityCondition() 00170 { 00171 if (this->mpBoundaryConditions->HasDirichletBoundaryConditions() || mRowForAverageOfPhiZeroed!=INT_MAX ) 00172 { 00173 // not a singular system, no compability condition 00174 return; 00175 } 00176 00177 #ifndef NDEBUG 00178 DistributedVector distributed_rhs=this->mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(this->mpLinearSystem->rGetRhsVector()); 00179 DistributedVector::Stripe distributed_rhs_phi_entries(distributed_rhs,2); // stripe number 2 -> phi_e 00180 00181 double local_sum=0; 00182 for (DistributedVector::Iterator index = distributed_rhs.Begin(); 00183 index!= distributed_rhs.End(); 00184 ++index) 00185 { 00186 local_sum += distributed_rhs_phi_entries[index]; 00187 } 00188 00189 double global_sum; 00190 int mpi_ret = MPI_Allreduce(&local_sum, &global_sum, 1, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD); 00191 assert(mpi_ret == MPI_SUCCESS); 00192 00193 if(fabs(global_sum)>1e-6) // magic number! sum should really be a sum of zeros and exactly zero though anyway (or a-a+b-b+c-c.. etc in the case of electrodes) 00194 { 00195 #define COVERAGE_IGNORE 00196 // shouldn't ever reach this line but useful to have the error printed out if you do 00197 std::cout << "Sum of b_{every 3 items} = " << global_sum << " (should be zero for compatibility)\n"; 00198 EXCEPTION("Linear system does not satisfy compatibility constraint!"); 00199 #undef COVERAGE_IGNORE 00200 } 00201 #endif 00202 } 00203 00204 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00205 AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::AbstractExtendedBidomainSolver( 00206 bool bathSimulation, 00207 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh, 00208 ExtendedBidomainTissue<SPACE_DIM>* pTissue, 00209 BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, 3>* pBcc, 00210 unsigned numQuadPoints) 00211 : AbstractDynamicLinearPdeSolver<ELEMENT_DIM,SPACE_DIM,3>(pMesh), 00212 mBathSimulation(bathSimulation), 00213 mpExtendedBidomainTissue(pTissue), 00214 mpBoundaryConditions(pBcc), 00215 mNumQuadPoints(numQuadPoints) 00216 { 00217 assert(pTissue != NULL); 00218 assert(pBcc != NULL); 00219 00220 mNullSpaceCreated = false; 00221 00222 // important! 00223 this->mMatrixIsConstant = true; 00224 00225 mRowForAverageOfPhiZeroed = INT_MAX; //this->mpLinearSystem->GetSize() - 1; 00226 mpConfig = HeartConfig::Instance(); 00227 00228 mpExtendedBidomainAssembler = NULL; // can't initialise until know what dt is 00229 } 00230 00231 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00232 AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::~AbstractExtendedBidomainSolver() 00233 { 00234 } 00235 00236 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00237 void AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::SetFixedExtracellularPotentialNodes( 00238 std::vector<unsigned> fixedExtracellularPotentialNodes) 00239 { 00240 for (unsigned i=0; i<fixedExtracellularPotentialNodes.size(); i++) 00241 { 00242 if (fixedExtracellularPotentialNodes[i] >= this->mpMesh->GetNumNodes() ) 00243 { 00244 EXCEPTION("Fixed node number must be less than total number nodes"); 00245 } 00246 } 00247 00248 mFixedExtracellularPotentialNodes = fixedExtracellularPotentialNodes; 00249 00250 // We will need to recalculate this when HasDirichletBoundaryConditions() is called. 00251 this->mpBoundaryConditions->ResetDirichletCommunication(); 00252 00253 for (unsigned i=0; i<mFixedExtracellularPotentialNodes.size(); i++) 00254 { 00255 if (this->mpMesh->GetDistributedVectorFactory()->IsGlobalIndexLocal(mFixedExtracellularPotentialNodes[i])) 00256 { 00257 ConstBoundaryCondition<SPACE_DIM>* p_boundary_condition = new ConstBoundaryCondition<SPACE_DIM>(0.0); 00258 00259 //Throws if node is not owned locally 00260 Node<SPACE_DIM>* p_node = this->mpMesh->GetNode(mFixedExtracellularPotentialNodes[i]); 00261 00262 //the "false" passed in tells not to check that it is a boundary node (since we might have grounded electrodes within the tissue) 00263 GetBoundaryConditions()->AddDirichletBoundaryCondition(p_node, p_boundary_condition, 2, false); 00264 } 00265 } 00266 } 00267 00268 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00269 void AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::SetRowForAverageOfPhiZeroed(unsigned row) 00270 { 00271 // Row should be every 3 entries, starting from zero... 00272 if ( ((row-2)%3 != 0) && row!=INT_MAX) 00273 { 00274 EXCEPTION("Row for applying the constraint 'Average of phi_e = zero' should be every 3 rows"); 00275 } 00276 00277 mRowForAverageOfPhiZeroed = row; 00278 } 00279 00281 // Explicit instantiation 00283 00284 template class AbstractExtendedBidomainSolver<1,1>; 00285 template class AbstractExtendedBidomainSolver<2,2>; 00286 template class AbstractExtendedBidomainSolver<3,3>;