00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
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
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
00070 this->mpLinearSystem->SetMatrixIsSymmetric(true);
00071 }
00072 else
00073 {
00074
00075 PetscMatTools::TurnOffVariableAllocationError(this->mpLinearSystem->rGetLhsMatrix());
00076
00077 this->mpLinearSystem->SetMatrixIsSymmetric(false);
00078 }
00079 }
00080
00081
00082 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00083 void AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::PrepareForSetupLinearSystem(Vec existingSolution)
00084 {
00085 mpExtendedBidomainTissue->SolveCellSystems(existingSolution, PdeSimulationTime::GetTime(), PdeSimulationTime::GetNextTime());
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
00120 if (mRowForAverageOfPhiZeroed==INT_MAX)
00121 {
00122
00123 if (!mNullSpaceCreated)
00124 {
00125
00126 Vec nullbasis[] = {GenerateNullBasis()};
00127
00128 this->mpLinearSystem->SetNullBasis(nullbasis, 1);
00129
00130 PetscTools::Destroy(nullbasis[0]);
00131 mNullSpaceCreated = true;
00132 }
00133 }
00134 else
00135 {
00136
00137 this->mpLinearSystem->SetKspType("gmres");
00138 mpConfig->SetKSPSolver("gmres", true);
00139
00140
00141
00142 unsigned matrix_size = this->mpLinearSystem->GetSize();
00143 if (!this->mMatrixIsAssembled)
00144 {
00145
00146
00147 std::vector<unsigned> row_for_average;
00148 row_for_average.push_back(mRowForAverageOfPhiZeroed);
00149 this->mpLinearSystem->ZeroMatrixRowsWithValueOnDiagonal(row_for_average, 0.0);
00150 for (unsigned col_index=0; col_index<matrix_size; col_index++)
00151 {
00152 if (((col_index-2)%3 == 0) && (col_index>1))
00153 {
00154 this->mpLinearSystem->SetMatrixElement(mRowForAverageOfPhiZeroed, col_index, 1);
00155 }
00156
00157 }
00158 this->mpLinearSystem->FinaliseLhsMatrix();
00159 }
00160
00161 this->mpLinearSystem->SetRhsVectorElement(mRowForAverageOfPhiZeroed, 0);
00162
00163 this->mpLinearSystem->FinaliseRhsVector();
00164 }
00165 }
00166 CheckCompatibilityCondition();
00167 }
00168
00169 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00170 void AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::CheckCompatibilityCondition()
00171 {
00172 if (this->mpBoundaryConditions->HasDirichletBoundaryConditions() || mRowForAverageOfPhiZeroed!=INT_MAX )
00173 {
00174
00175 return;
00176 }
00177
00178 #ifndef NDEBUG
00179 DistributedVector distributed_rhs=this->mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(this->mpLinearSystem->rGetRhsVector());
00180 DistributedVector::Stripe distributed_rhs_phi_entries(distributed_rhs,2);
00181
00182 double local_sum=0;
00183 for (DistributedVector::Iterator index = distributed_rhs.Begin();
00184 index!= distributed_rhs.End();
00185 ++index)
00186 {
00187 local_sum += distributed_rhs_phi_entries[index];
00188 }
00189
00190 double global_sum;
00191 int mpi_ret = MPI_Allreduce(&local_sum, &global_sum, 1, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD);
00192 assert(mpi_ret == MPI_SUCCESS);
00193
00194 if(fabs(global_sum)>1e-6)
00195 {
00196 #define COVERAGE_IGNORE
00197
00198 std::cout << "Sum of b_{every 3 items} = " << global_sum << " (should be zero for compatibility)\n";
00199 EXCEPTION("Linear system does not satisfy compatibility constraint!");
00200 #undef COVERAGE_IGNORE
00201 }
00202 #endif
00203 }
00204
00205 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00206 AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::AbstractExtendedBidomainSolver(
00207 bool bathSimulation,
00208 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh,
00209 ExtendedBidomainTissue<SPACE_DIM>* pTissue,
00210 BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, 3>* pBcc)
00211 : AbstractDynamicLinearPdeSolver<ELEMENT_DIM,SPACE_DIM,3>(pMesh),
00212 mBathSimulation(bathSimulation),
00213 mpExtendedBidomainTissue(pTissue),
00214 mpBoundaryConditions(pBcc)
00215 {
00216 assert(pTissue != NULL);
00217 assert(pBcc != NULL);
00218
00219 mNullSpaceCreated = false;
00220
00221
00222 this->mMatrixIsConstant = true;
00223
00224 mRowForAverageOfPhiZeroed = INT_MAX;
00225 mpConfig = HeartConfig::Instance();
00226
00227 mpExtendedBidomainAssembler = NULL;
00228 }
00229
00230 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00231 AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::~AbstractExtendedBidomainSolver()
00232 {
00233 }
00234
00235 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00236 void AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::SetFixedExtracellularPotentialNodes(
00237 std::vector<unsigned> fixedExtracellularPotentialNodes)
00238 {
00239 for (unsigned i=0; i<fixedExtracellularPotentialNodes.size(); i++)
00240 {
00241 if (fixedExtracellularPotentialNodes[i] >= this->mpMesh->GetNumNodes() )
00242 {
00243 EXCEPTION("Fixed node number must be less than total number nodes");
00244 }
00245 }
00246
00247 mFixedExtracellularPotentialNodes = fixedExtracellularPotentialNodes;
00248
00249
00250 this->mpBoundaryConditions->ResetDirichletCommunication();
00251
00252 for (unsigned i=0; i<mFixedExtracellularPotentialNodes.size(); i++)
00253 {
00254 if (this->mpMesh->GetDistributedVectorFactory()->IsGlobalIndexLocal(mFixedExtracellularPotentialNodes[i]))
00255 {
00256 ConstBoundaryCondition<SPACE_DIM>* p_boundary_condition = new ConstBoundaryCondition<SPACE_DIM>(0.0);
00257
00258
00259 Node<SPACE_DIM>* p_node = this->mpMesh->GetNode(mFixedExtracellularPotentialNodes[i]);
00260
00261
00262 GetBoundaryConditions()->AddDirichletBoundaryCondition(p_node, p_boundary_condition, 2, false);
00263 }
00264 }
00265 }
00266
00267 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00268 void AbstractExtendedBidomainSolver<ELEMENT_DIM,SPACE_DIM>::SetRowForAverageOfPhiZeroed(unsigned row)
00269 {
00270
00271 if ( ((row-2)%3 != 0) && row!=INT_MAX)
00272 {
00273 EXCEPTION("Row for applying the constraint 'Average of phi_e = zero' should be every 3 rows");
00274 }
00275
00276 mRowForAverageOfPhiZeroed = row;
00277 }
00278
00280
00282
00283 template class AbstractExtendedBidomainSolver<1,1>;
00284 template class AbstractExtendedBidomainSolver<2,2>;
00285 template class AbstractExtendedBidomainSolver<3,3>;