AbstractStaticAssembler.hpp

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 #ifndef _ABSTRACTSTATICASSEMBLER_HPP_
00029 #define _ABSTRACTSTATICASSEMBLER_HPP_
00030 
00031 #include "AbstractAssembler.hpp"
00032 #include "LinearBasisFunction.hpp"
00033 #include "GaussianQuadratureRule.hpp"
00034 #include "AbstractMesh.hpp"
00035 #include "BoundaryConditionsContainer.hpp"
00036 #include "LinearSystem.hpp"
00037 #include "GaussianQuadratureRule.hpp"
00038 #include "ReplicatableVector.hpp"
00039 #include "DistributedVector.hpp"
00040 #include "PetscTools.hpp"
00041 #include "HeartEventHandler.hpp"
00042 #include <iostream>
00043 
00044 #include <boost/mpl/void.hpp>
00045 
00062 template<class T>
00063 struct AssemblerTraits
00064 {
00066     typedef T CVT_CLS;
00068     typedef T CMT_CLS;
00070     typedef AbstractAssembler<T::E_DIM, T::S_DIM, T::P_DIM> INTERPOLATE_CLS;
00071 };
00072 
00074 template<>
00075 struct AssemblerTraits<boost::mpl::void_>
00076 {
00077     typedef boost::mpl::void_ CVT_CLS;
00078     typedef boost::mpl::void_ CMT_CLS;
00079     typedef boost::mpl::void_ INTERPOLATE_CLS;
00080 };
00081 
00100 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM, bool NON_HEART, class CONCRETE>
00101 class AbstractStaticAssembler : virtual public AbstractAssembler<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>
00102 {
00103 protected:
00105     AbstractMesh<ELEMENT_DIM, SPACE_DIM>* mpMesh;
00106 
00108     GaussianQuadratureRule<ELEMENT_DIM> *mpQuadRule;
00110     GaussianQuadratureRule<ELEMENT_DIM-1> *mpSurfaceQuadRule;
00111 
00112 
00114     typedef LinearBasisFunction<ELEMENT_DIM> BasisFunction;
00116     typedef LinearBasisFunction<ELEMENT_DIM-1> SurfaceBasisFunction;
00117 
00122     ReplicatableVector mCurrentSolutionOrGuessReplicated;
00123 
00128     LinearSystem *mpLinearSystem;
00129 
00130 
00152     virtual void AssembleOnElement( Element<ELEMENT_DIM,SPACE_DIM> &rElement,
00153                                     c_matrix<double, PROBLEM_DIM*(ELEMENT_DIM+1), PROBLEM_DIM*(ELEMENT_DIM+1) > &rAElem,
00154                                     c_vector<double, PROBLEM_DIM*(ELEMENT_DIM+1)> &rBElem,
00155                                     bool assembleVector,
00156                                     bool assembleMatrix)
00157     {
00158         GaussianQuadratureRule<ELEMENT_DIM> &quad_rule =
00159             *(AbstractStaticAssembler<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM, NON_HEART, CONCRETE>::mpQuadRule);
00160 
00166         c_matrix<double, SPACE_DIM, SPACE_DIM> jacobian;
00167         c_matrix<double, SPACE_DIM, SPACE_DIM> inverse_jacobian;
00168         double jacobian_determinant;
00169         
00170         mpMesh->GetInverseJacobianForElement(rElement.GetIndex(), jacobian, jacobian_determinant, inverse_jacobian);
00171 
00172 // With the new signature of GetInverseJacobianForElement, inverse and jacobian are returned at the same time
00173 //        // Initialise element contributions to zero
00174 //        if ( assembleMatrix || this->ProblemIsNonlinear() ) // don't need to construct grad_phi or grad_u in that case
00175 //        {
00176 //            this->mpMesh->GetInverseJacobianForElement(rElement.GetIndex(), inverse_jacobian);
00177 //        }
00178 
00179         if (assembleMatrix)
00180         {
00181             rAElem.clear();
00182         }
00183 
00184         if (assembleVector)
00185         {
00186             rBElem.clear();
00187         }
00188 
00189         const unsigned num_nodes = rElement.GetNumNodes();
00190 
00191         // allocate memory for the basis functions values and derivative values
00192         c_vector<double, ELEMENT_DIM+1> phi;
00193         c_matrix<double, ELEMENT_DIM, ELEMENT_DIM+1> grad_phi;
00194 
00195         // loop over Gauss points
00196         for (unsigned quad_index=0; quad_index < quad_rule.GetNumQuadPoints(); quad_index++)
00197         {
00198             const ChastePoint<ELEMENT_DIM>& quad_point = quad_rule.rGetQuadPoint(quad_index);
00199 
00200             BasisFunction::ComputeBasisFunctions(quad_point, phi);
00201 
00202             if ( assembleMatrix || this->ProblemIsNonlinear() )
00203             {
00204                 BasisFunction::ComputeTransformedBasisFunctionDerivatives(quad_point, inverse_jacobian, grad_phi);
00205             }
00206 
00207             // Location of the gauss point in the original element will be stored in x
00208             // Where applicable, u will be set to the value of the current solution at x
00209             ChastePoint<SPACE_DIM> x(0,0,0);
00210 
00211             c_vector<double,PROBLEM_DIM> u = zero_vector<double>(PROBLEM_DIM);
00212             c_matrix<double,PROBLEM_DIM,SPACE_DIM> grad_u = zero_matrix<double>(PROBLEM_DIM,SPACE_DIM);
00213 
00214             // allow the concrete version of the assembler to interpolate any
00215             // desired quantities
00216             static_cast<typename AssemblerTraits<CONCRETE>::INTERPOLATE_CLS *>(this)->ResetInterpolatedQuantities();
00217 
00218 
00220             // interpolation
00222             for (unsigned i=0; i<num_nodes; i++)
00223             {
00224                 const Node<SPACE_DIM> *p_node = rElement.GetNode(i);
00225 
00226                 if (NON_HEART)
00227                 {
00228                     const c_vector<double, SPACE_DIM>& r_node_loc = p_node->rGetLocation();
00229                     // interpolate x
00230                     x.rGetLocation() += phi(i)*r_node_loc;
00231                 }
00232 
00233                 // interpolate u and grad u if a current solution or guess exists
00234                 unsigned node_global_index = rElement.GetNodeGlobalIndex(i);
00235                 if (mCurrentSolutionOrGuessReplicated.size()>0)
00236                 {
00237                     for (unsigned index_of_unknown=0; index_of_unknown<(NON_HEART ? PROBLEM_DIM : 1); index_of_unknown++)
00238                     {
00239                         // If we have a current solution (e.g. this is a dynamic problem)
00240                         // get the value in a usable form.rElement
00241 
00242                         // NOTE - currentSolutionOrGuess input is actually now redundant at this point -
00243 
00244                         // NOTE - following assumes that, if say there are two unknowns u and v, they
00245                         // are stored in the current solution vector as
00246                         // [U1 V1 U2 V2 ... U_n V_n]
00247                         double u_at_node=GetCurrentSolutionOrGuessValue(node_global_index, index_of_unknown);
00248                         u(index_of_unknown) += phi(i)*u_at_node;
00249 
00250                         if (this->ProblemIsNonlinear() ) // don't need to construct grad_phi or grad_u in that case
00251                         {
00252                             for (unsigned j=0; j<SPACE_DIM; j++)
00253                             {
00254                                 grad_u(index_of_unknown,j) += grad_phi(j,i)*u_at_node;
00255                             }
00256                         }
00257                     }
00258                 }
00259 
00260                 // allow the concrete version of the assembler to interpolate any
00261                 // desired quantities
00262                 static_cast<typename AssemblerTraits<CONCRETE>::INTERPOLATE_CLS *>(this)->IncrementInterpolatedQuantities(phi(i), p_node);
00263             }
00264             
00265             //HeartEventHandler::BeginEvent(HeartEventHandler::USER1); //Temporarily using USER1 to instrument the Compute.. terms
00266             double wJ = jacobian_determinant * quad_rule.GetWeight(quad_index);
00267 
00269             // create rAElem and rBElem
00271             if (assembleMatrix)
00272             {
00273                 noalias(rAElem) += static_cast<typename AssemblerTraits<CONCRETE>::CMT_CLS *>(this)->ComputeMatrixTerm(phi, grad_phi, x, u, grad_u, &rElement) * wJ;
00274             }
00275 
00276             if (assembleVector)
00277             {
00278                 noalias(rBElem) += static_cast<typename AssemblerTraits<CONCRETE>::CVT_CLS *>(this)->ComputeVectorTerm(phi, grad_phi, x, u, grad_u, &rElement) * wJ;
00279             }
00280             //HeartEventHandler::EndEvent(HeartEventHandler::USER1); //Temporarily using USER1 to instrument the Compute.. terms
00281         }
00282     }
00283 
00284 
00285 
00295     virtual void AssembleOnSurfaceElement(const BoundaryElement<ELEMENT_DIM-1,SPACE_DIM> &rSurfaceElement,
00296                                           c_vector<double, PROBLEM_DIM*ELEMENT_DIM> &rBSurfElem)
00297     {
00298         GaussianQuadratureRule<ELEMENT_DIM-1> &quad_rule =
00299             *(AbstractStaticAssembler<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM, NON_HEART, CONCRETE>::mpSurfaceQuadRule);
00300 
00301         c_vector<double, SPACE_DIM> weighted_direction;
00302         double jacobian_determinant;
00303         mpMesh->GetWeightedDirectionForBoundaryElement(rSurfaceElement.GetIndex(), weighted_direction, jacobian_determinant);
00304 
00305         rBSurfElem.clear();
00306 
00307         // allocate memory for the basis function values
00308         c_vector<double, ELEMENT_DIM>  phi;
00309 
00310         // loop over Gauss points
00311         for (unsigned quad_index=0; quad_index<quad_rule.GetNumQuadPoints(); quad_index++)
00312         {
00313             const ChastePoint<ELEMENT_DIM-1>& quad_point = quad_rule.rGetQuadPoint(quad_index);
00314 
00315             SurfaceBasisFunction::ComputeBasisFunctions(quad_point, phi);
00316 
00317 
00319             // interpolation
00321 
00322             // Location of the gauss point in the original element will be
00323             // stored in x
00324             ChastePoint<SPACE_DIM> x(0,0,0);
00325 
00326             this->ResetInterpolatedQuantities();
00327             for (unsigned i=0; i<rSurfaceElement.GetNumNodes(); i++)
00328             {
00329                 const c_vector<double, SPACE_DIM> node_loc = rSurfaceElement.GetNode(i)->rGetLocation();
00330                 x.rGetLocation() += phi(i)*node_loc;
00331 
00332                 // allow the concrete version of the assembler to interpolate any
00333                 // desired quantities
00334                 IncrementInterpolatedQuantities(phi(i), rSurfaceElement.GetNode(i));
00335 
00337             }
00338 
00339             double wJ = jacobian_determinant * quad_rule.GetWeight(quad_index);
00340 
00342             // create rAElem and rBElem
00345             noalias(rBSurfElem) += ComputeVectorSurfaceTerm(rSurfaceElement, phi, x) * wJ;
00346         }
00347     }
00348 
00349 
00350 
00378     virtual void AssembleSystem(bool assembleVector, bool assembleMatrix,
00379                                 Vec currentSolutionOrGuess=NULL, double currentTime=0.0)
00380     {
00381         HeartEventHandler::EventType assemble_event;
00382         if(assembleMatrix)
00383         {
00384             assemble_event = HeartEventHandler::ASSEMBLE_SYSTEM;
00385         }
00386         else
00387         {
00388             assemble_event = HeartEventHandler::ASSEMBLE_RHS;
00389         }
00390 
00391         // Check we've actually been asked to do something!
00392         assert(assembleVector || assembleMatrix);
00393 
00394         // Check the linear system object has been set up correctly
00395         assert(mpLinearSystem != NULL);
00396         assert(mpLinearSystem->GetSize() == PROBLEM_DIM * this->mpMesh->GetNumNodes());
00397         assert(!assembleVector || mpLinearSystem->rGetRhsVector() != NULL);
00398         assert(!assembleMatrix || mpLinearSystem->rGetLhsMatrix() != NULL);
00399 
00400 //        // Is the matrix symmetric?
00401 //        if (assembleMatrix && !this->mpBoundaryConditions->HasDirichletBoundaryConditions())
00402 //        {
00403 //            mpLinearSystem->SetMatrixIsSymmetric();
00404 //        }
00405 
00406         // Replicate the current solution and store so can be used in
00407         // AssembleOnElement
00408         if (currentSolutionOrGuess != NULL)
00409         {
00410             HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00411             this->mCurrentSolutionOrGuessReplicated.ReplicatePetscVector(currentSolutionOrGuess);
00412             HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00413         }
00414 
00415 
00416         // the AssembleOnElement type methods will determine if a current solution or
00417         // current guess exists by looking at the size of the replicated vector, so
00418         // check the size is zero if there isn't a current solution
00419         assert(    ( currentSolutionOrGuess && mCurrentSolutionOrGuessReplicated.size()>0)
00420                 || ( !currentSolutionOrGuess && mCurrentSolutionOrGuessReplicated.size()==0));
00421 
00422 
00423         // the concrete class can override this following method if there is
00424         // work to be done before assembly
00425         this->PrepareForAssembleSystem(currentSolutionOrGuess, currentTime);
00426 
00427         // this has to be below PrepareForAssembleSystem as in that
00428         // method the odes are solved in cardiac problems
00429         HeartEventHandler::BeginEvent(assemble_event);
00430 
00431         // Zero the matrix/vector if it is to be assembled
00432         if (assembleVector)
00433         {
00434             mpLinearSystem->ZeroRhsVector();
00435         }
00436         if (assembleMatrix)
00437         {
00438             mpLinearSystem->ZeroLhsMatrix();
00439         }
00440 
00441         // Get an iterator over the elements of the mesh
00442         typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator
00443             iter = this->mpMesh->GetElementIteratorBegin();
00444 
00445         const size_t STENCIL_SIZE=PROBLEM_DIM*(ELEMENT_DIM+1);
00446         c_matrix<double, STENCIL_SIZE, STENCIL_SIZE> a_elem;
00447         c_vector<double, STENCIL_SIZE> b_elem;
00448 
00449 
00451         // loop over elements
00453         while (iter != this->mpMesh->GetElementIteratorEnd())
00454         {
00455             Element<ELEMENT_DIM, SPACE_DIM>& element = **iter;
00456 
00457             if (element.GetOwnership() == true)
00458             {
00459                 AssembleOnElement(element, a_elem, b_elem, assembleVector, assembleMatrix);
00460 
00461                 unsigned p_indices[STENCIL_SIZE];
00462                 element.GetStiffnessMatrixGlobalIndices(PROBLEM_DIM, p_indices);
00463 
00464                 if (assembleMatrix)
00465                 {
00466                     mpLinearSystem->AddLhsMultipleValues(p_indices, a_elem);
00467                 }
00468 
00469                 if (assembleVector)
00470                 {
00471                     mpLinearSystem->AddRhsMultipleValues(p_indices, b_elem);
00472                 }
00473             }
00474 
00475             iter++;
00476         }
00477 
00478         // add the integrals associated with Neumann boundary conditions to the linear system
00479         typename AbstractMesh<ELEMENT_DIM, SPACE_DIM>::BoundaryElementIterator
00480             surf_iter = this->mpMesh->GetBoundaryElementIteratorBegin();
00481 
00482 
00484         // Apply any Neumann boundary conditions
00485         //
00486         // NB. We assume that if an element has a boundary condition on any unknown there is a boundary condition
00487         // on unknown 0. This can be so for any problem by adding zero constant conditions where required
00488         // although this is a bit inefficient. Proper solution involves changing BCC to have a map of arrays
00489         // boundary conditions rather than an array of maps.
00491         if (assembleVector)
00492         {
00493             this->ApplyNeummanBoundaryConditions();
00494         }
00495 
00496         if (assembleVector)
00497         {
00498             mpLinearSystem->AssembleRhsVector();
00499         }
00500         
00501         if (assembleMatrix)
00502         {
00503             mpLinearSystem->AssembleIntermediateLhsMatrix();
00504         }
00505 
00506         // Apply dirichlet boundary conditions
00507         this->ApplyDirichletConditions(currentSolutionOrGuess, assembleMatrix);
00508 
00509         this->FinaliseLinearSystem(currentSolutionOrGuess, currentTime, assembleVector, assembleMatrix);
00510 
00511         if (assembleVector)
00512         {
00513             mpLinearSystem->AssembleRhsVector();
00514         }
00515         if (assembleMatrix)
00516         {
00517             mpLinearSystem->AssembleFinalLhsMatrix();
00518         }
00519 
00520         // overload this method if the assembler has to do anything else
00521         // required (like setting up a null basis (see BidomainDg0Assembler))
00522         this->FinaliseAssembleSystem(currentSolutionOrGuess, currentTime);
00523 
00524         HeartEventHandler::EndEvent(assemble_event);
00525     }
00526 
00527 
00528 
00533     virtual void PrepareForSolve()
00534     {
00535         assert(mpMesh != NULL);
00536 
00537         // NOTE: this line used to be commented out because FlaggedMeshAssembler
00538         // has it's own FlaggedMeshBcc. (design issue). FlaggedMeshAssembler (and
00539         // related classes has now been deleted so can bring this back)
00540         assert(this->mpBoundaryConditions != NULL);
00541 
00542         std::vector<unsigned>& r_nodes_per_processor = mpMesh->rGetNodesPerProcessor();
00543 
00544         // check number of processor agrees with definition in mesh
00545         if((r_nodes_per_processor.size() != 0) && (r_nodes_per_processor.size() != PetscTools::NumProcs()) )
00546         {
00547             EXCEPTION("Number of processors defined in mesh class not equal to number of processors used");
00548         }
00549 
00550         if(r_nodes_per_processor.size() != 0)
00551         {
00552             unsigned num_local_nodes = r_nodes_per_processor[ PetscTools::GetMyRank() ];
00553             DistributedVector::SetProblemSizePerProcessor(this->mpMesh->GetNumNodes(), num_local_nodes);
00554         }
00555         else
00556         {
00557             DistributedVector::SetProblemSize(this->mpMesh->GetNumNodes());
00558         }
00559 
00560         this->mpMesh->SetElementOwnerships(DistributedVector::Begin().Global,
00561                                            DistributedVector::End().Global);
00562     }
00563 
00564 
00565 
00570     LinearSystem** GetLinearSystem()
00571     {
00572         return &mpLinearSystem;
00573     }
00574 
00579     ReplicatableVector& rGetCurrentSolutionOrGuess()
00580     {
00581         return mCurrentSolutionOrGuessReplicated;
00582     }
00583 
00587     virtual double GetCurrentSolutionOrGuessValue(unsigned nodeIndex, unsigned indexOfUnknown)
00588     {
00589         return mCurrentSolutionOrGuessReplicated[ PROBLEM_DIM*nodeIndex + indexOfUnknown];
00590     }
00591 
00592 public:
00598     AbstractStaticAssembler(unsigned numQuadPoints = 2)
00599         : AbstractAssembler<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>()
00600     {
00601         // Initialise mesh and bcs to null, so we can check they
00602         // have been set before attempting to solve
00603         mpMesh = NULL;
00604 
00605         mpQuadRule = NULL;
00606         mpSurfaceQuadRule = NULL;
00607         SetNumberOfQuadraturePointsPerDimension(numQuadPoints);
00608 
00609         mpLinearSystem = NULL;
00610     }
00611 
00621     void SetNumberOfQuadraturePointsPerDimension(unsigned numQuadPoints)
00622     {
00623         delete mpQuadRule;
00624         mpQuadRule = new GaussianQuadratureRule<ELEMENT_DIM>(numQuadPoints);
00625         delete mpSurfaceQuadRule;
00626         mpSurfaceQuadRule = new GaussianQuadratureRule<ELEMENT_DIM-1>(numQuadPoints);
00627     }
00628 
00629 
00633     void SetMesh(AbstractMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00634     {
00635         mpMesh = pMesh;
00636     }
00637 
00638 
00642     virtual ~AbstractStaticAssembler()
00643     {
00644         delete mpQuadRule;
00645         delete mpSurfaceQuadRule;
00646         delete mpLinearSystem;
00647     }
00648 };
00649 
00650 #endif //_ABSTRACTSTATICASSEMBLER_HPP_

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