BidomainWithBathAssembler.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 #include "BidomainWithBathAssembler.hpp"
00030 
00031 #include <boost/numeric/ublas/vector_proxy.hpp>
00032 
00033 #include "ConstBoundaryCondition.hpp"
00034 #include "HeartRegionCodes.hpp"
00035 
00036 
00037 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00038 c_matrix<double,2*(ELEMENT_DIM+1),2*(ELEMENT_DIM+1)>
00039     BidomainWithBathAssembler<ELEMENT_DIM,SPACE_DIM>::ComputeMatrixTerm(
00040             c_vector<double, ELEMENT_DIM+1> &rPhi,
00041             c_matrix<double, ELEMENT_DIM, ELEMENT_DIM+1> &rGradPhi,
00042             ChastePoint<SPACE_DIM> &rX,
00043             c_vector<double,2> &rU,
00044             c_matrix<double, 2, SPACE_DIM> &rGradU /* not used */,
00045             Element<ELEMENT_DIM,SPACE_DIM>* pElement)
00046 {
00047     if (pElement->GetRegion() != HeartRegionCode::BATH) // ie if a tissue element
00048     {
00049         return BidomainDg0Assembler<ELEMENT_DIM,SPACE_DIM>::ComputeMatrixTerm(rPhi,rGradPhi,rX,rU,rGradU,pElement);
00050     }
00051     else // bath element
00052     {
00053         double bath_cond=HeartConfig::Instance()->GetBathConductivity();
00054         const c_matrix<double, SPACE_DIM, SPACE_DIM>& sigma_b = bath_cond*identity_matrix<double>(SPACE_DIM);
00055 
00056         c_matrix<double, ELEMENT_DIM, ELEMENT_DIM+1> temp = prod(sigma_b, rGradPhi);
00057         c_matrix<double, ELEMENT_DIM+1, ELEMENT_DIM+1> grad_phi_sigma_b_grad_phi =
00058             prod(trans(rGradPhi), temp);
00059 
00060         c_matrix<double,2*(ELEMENT_DIM+1),2*(ELEMENT_DIM+1)> ret = zero_matrix<double>(2*(ELEMENT_DIM+1));
00061 
00062         // even rows, even columns
00063         //matrix_slice<c_matrix<double, 2*ELEMENT_DIM+2, 2*ELEMENT_DIM+2> >
00064         //slice00(ret, slice (0, 2, ELEMENT_DIM+1), slice (0, 2, ELEMENT_DIM+1));
00065         //slice00 = 0;
00066 
00067         // odd rows, even columns
00068         //matrix_slice<c_matrix<double, 2*ELEMENT_DIM+2, 2*ELEMENT_DIM+2> >
00069         //slice10(ret, slice (1, 2, ELEMENT_DIM+1), slice (0, 2, ELEMENT_DIM+1));
00070         //slice10 = 0
00071 
00072         // even rows, odd columns
00073         //matrix_slice<c_matrix<double, 2*ELEMENT_DIM+2, 2*ELEMENT_DIM+2> >
00074         //slice01(ret, slice (0, 2, ELEMENT_DIM+1), slice (1, 2, ELEMENT_DIM+1));
00075         //slice01 = 0;
00076 
00077         // odd rows, odd columns
00078         matrix_slice<c_matrix<double, 2*ELEMENT_DIM+2, 2*ELEMENT_DIM+2> >
00079         slice11(ret, slice (1, 2, ELEMENT_DIM+1), slice (1, 2, ELEMENT_DIM+1));
00080         slice11 = grad_phi_sigma_b_grad_phi;
00081 
00082         return ret;
00083     }
00084 }
00085 
00086 
00087 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00088 c_vector<double,2*(ELEMENT_DIM+1)>
00089     BidomainWithBathAssembler<ELEMENT_DIM,SPACE_DIM>::ComputeVectorTerm(
00090             c_vector<double, ELEMENT_DIM+1> &rPhi,
00091             c_matrix<double, ELEMENT_DIM, ELEMENT_DIM+1> &rGradPhi,
00092             ChastePoint<SPACE_DIM> &rX,
00093             c_vector<double,2> &rU,
00094             c_matrix<double, 2, SPACE_DIM> &rGradU /* not used */,
00095             Element<ELEMENT_DIM,SPACE_DIM>* pElement)
00096 {
00097     if (pElement->GetRegion() != HeartRegionCode::BATH) // ie if a tissue element
00098     {
00099         return BidomainDg0Assembler<ELEMENT_DIM,SPACE_DIM>::ComputeVectorTerm(rPhi,rGradPhi,rX,rU,rGradU,pElement);
00100     }
00101     else // bath element
00102     {
00103         c_vector<double,2*(ELEMENT_DIM+1)> ret = zero_vector<double>(2*(ELEMENT_DIM+1));
00104 
00105         //vector_slice<c_vector<double, 2*(ELEMENT_DIM+1)> > slice_V  (ret, slice (0, 2, ELEMENT_DIM+1));
00106         //vector_slice<c_vector<double, 2*(ELEMENT_DIM+1)> > slice_Phi(ret, slice (1, 2, ELEMENT_DIM+1));
00107 
00108         // u(0) = voltage
00109         //noalias(slice_V) = zero_vector<double>(ELEMENT_DIM+1);
00110         //noalias(slice_Phi) = zero_vector<double>(ELEMENT_DIM+1);
00111 
00112         return ret;
00113     }
00114 }
00115 
00116 
00117 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00118 void BidomainWithBathAssembler<ELEMENT_DIM,SPACE_DIM>::FinaliseLinearSystem(
00119             Vec existingSolutionOrGuess,
00120             double time,
00121             bool assembleVector, bool assembleMatrix)
00122 {
00123     // CG (default solver) won't work since the system is indefinite. Switch to SYMMLQ
00124     this->mpLinearSystem->SetKspType("symmlq"); // Switches the solver
00125     this->mpConfig->SetKSPSolver("symmlq"); // Makes sure this change will be reflected in the XML file written to disk at the end of the simulation.            
00126 
00127     unsigned* is_node_bath = new unsigned[this->mpMesh->GetNumNodes()];
00128     for(unsigned i = 0; i < this->mpMesh->GetNumNodes(); ++i)
00129     {
00130         is_node_bath[i] = 0;
00131     }
00132     
00133     for (typename AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>::NodeIterator iter=this->mpMesh->GetNodeIteratorBegin();
00134          iter != this->mpMesh->GetNodeIteratorEnd();
00135          ++iter)
00136     {        
00137         // ZeroMatrixColumn and ZeroMatrixRow are collective operations so we need all the processors
00138         // calling them. When using ParallelTetrahedralMesh the knowledge about which nodes are bath
00139         // is distributed. Processors need to agree before zeroing.
00140 
00141         if ((*iter).GetRegion() == HeartRegionCode::BATH)
00142         {
00143             is_node_bath[(*iter).GetIndex()] = 1;
00144         }
00145     }
00146     
00147     unsigned* is_node_bath_reduced = new unsigned[this->mpMesh->GetNumNodes()];
00148     MPI_Allreduce(is_node_bath, is_node_bath_reduced, this->mpMesh->GetNumNodes(), MPI_UNSIGNED, MPI_SUM, PETSC_COMM_WORLD);    
00149     
00150     for(unsigned i=0; i<this->mpMesh->GetNumNodes(); i++)
00151     {
00152         if(is_node_bath_reduced[i] > 0) // ie is a bath node
00153         {
00154             PetscInt index[1];
00155             index[0] = 2*i; 
00156 
00157             if(assembleMatrix)
00158             {
00159                 /*
00160                  *  Before revision 6516, we used to zero out i-th row and column here. It seems to be redundant because they are already zero after assembly.
00161                  *  When assembling a bath element you get a matrix subblock that looks like (2D example):
00162                  * 
00163                  *     Vm   0 0 0 0 0 0 
00164                  *     Vm   0 0 0 0 0 0 
00165                  *     Vm   0 0 0 0 0 0 
00166                  *     Phie 0 0 0 x x x
00167                  *     Phie 0 0 0 x x x  -> the x subblock is assembled from div(grad_phi) = 0
00168                  *     Phie 0 0 0 x x x
00169                  *
00170                  *  Therefore, all the Vm entries of this node are already 0.
00171                  * 
00172                  *  Explicitely checking it in non-production builds.  
00173                  */
00174 #ifndef NDEBUG
00175                 int num_equation = 2*i; 
00176 
00177                 // Matrix need to be assembled in order to use GetMatrixElement()
00178                 MatAssemblyBegin((*this->GetLinearSystem())->rGetLhsMatrix(), MAT_FINAL_ASSEMBLY);
00179                 MatAssemblyEnd((*this->GetLinearSystem())->rGetLhsMatrix(), MAT_FINAL_ASSEMBLY);
00180     
00181                 PetscInt local_lo, local_hi;
00182                 (*this->GetLinearSystem())->GetOwnershipRange(local_lo, local_hi);
00183                 
00184                 // If this processor owns i-th row, check it.
00185                 if ((local_lo <= (int)num_equation) && ((int)num_equation < local_hi))
00186                 {
00187                     for (unsigned column=0; column < (*this->GetLinearSystem())->GetSize(); column++)
00188                     {
00189                         assert((*this->GetLinearSystem())->GetMatrixElement(num_equation, column)==0.0);                                        
00190                     }
00191                 }
00192                 
00193                 // Check the local entries of the i-th column
00194                 for (int row=local_lo; row<local_hi; row++)
00195                 {
00196                     assert((*this->GetLinearSystem())->GetMatrixElement(row, num_equation)==0);                                                        
00197                 }
00198 #endif
00199                 // put 1.0 on the diagonal
00200                 Mat& r_matrix = (*(this->GetLinearSystem()))->rGetLhsMatrix();
00201                 MatSetValue(r_matrix,index[0],index[0],1.0,INSERT_VALUES);
00202             }
00203 
00204             if(assembleVector)
00205             {
00206                 // zero rhs vector entry
00207                 VecSetValue((*(this->GetLinearSystem()))->rGetRhsVector(), index[0], 0.0, INSERT_VALUES);
00208             }
00209         }
00210     }
00211     
00212     delete is_node_bath;
00213     delete is_node_bath_reduced;
00214 }
00215 
00216 
00217 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00218 BidomainWithBathAssembler<ELEMENT_DIM,SPACE_DIM>::BidomainWithBathAssembler(
00219             AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh,
00220             BidomainPde<SPACE_DIM>* pPde,
00221             BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, 2>* pBcc,
00222             unsigned numQuadPoints)
00223     : BidomainDg0Assembler<ELEMENT_DIM,SPACE_DIM>(pMesh, pPde, pBcc, numQuadPoints)
00224 {
00225 }
00226 
00228 // Explicit instantiation
00230 
00231 template class BidomainWithBathAssembler<1,1>;
00232 template class BidomainWithBathAssembler<2,2>;
00233 template class BidomainWithBathAssembler<3,3>;

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