AbstractFeVolumeIntegralAssembler.hpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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 #ifndef ABSTRACTFEVOLUMEINTEGRALASSEMBLER_HPP_
00037 #define ABSTRACTFEVOLUMEINTEGRALASSEMBLER_HPP_
00038 
00039 #include "AbstractFeAssemblerCommon.hpp"
00040 #include "GaussianQuadratureRule.hpp"
00041 #include "BoundaryConditionsContainer.hpp"
00042 #include "PetscVecTools.hpp"
00043 #include "PetscMatTools.hpp"
00044 
00077 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM, bool CAN_ASSEMBLE_VECTOR, bool CAN_ASSEMBLE_MATRIX, InterpolationLevel INTERPOLATION_LEVEL>
00078 class AbstractFeVolumeIntegralAssembler :
00079      public AbstractFeAssemblerCommon<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM,CAN_ASSEMBLE_VECTOR,CAN_ASSEMBLE_MATRIX,INTERPOLATION_LEVEL>
00080 {
00081 protected:
00083     AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>* mpMesh;
00084 
00086     GaussianQuadratureRule<ELEMENT_DIM>* mpQuadRule;
00087 
00089     typedef LinearBasisFunction<ELEMENT_DIM> BasisFunction;
00090 
00110     void ComputeTransformedBasisFunctionDerivatives(const ChastePoint<ELEMENT_DIM>& rPoint,
00111                                                     const c_matrix<double, ELEMENT_DIM, SPACE_DIM>& rInverseJacobian,
00112                                                     c_matrix<double, SPACE_DIM, ELEMENT_DIM+1>& rReturnValue);
00113 
00119     void DoAssemble();
00120 
00121 protected:
00122 
00142     virtual c_matrix<double,PROBLEM_DIM*(ELEMENT_DIM+1),PROBLEM_DIM*(ELEMENT_DIM+1)> ComputeMatrixTerm(
00143         c_vector<double, ELEMENT_DIM+1>& rPhi,
00144         c_matrix<double, SPACE_DIM, ELEMENT_DIM+1>& rGradPhi,
00145         ChastePoint<SPACE_DIM>& rX,
00146         c_vector<double,PROBLEM_DIM>& rU,
00147         c_matrix<double, PROBLEM_DIM, SPACE_DIM>& rGradU,
00148         Element<ELEMENT_DIM,SPACE_DIM>* pElement)
00149     {
00150         // If this line is reached this means this method probably hasn't been over-ridden correctly in
00151         // the concrete class
00152         NEVER_REACHED;
00153         return zero_matrix<double>(PROBLEM_DIM*(ELEMENT_DIM+1),PROBLEM_DIM*(ELEMENT_DIM+1));
00154     }
00155 
00175     virtual c_vector<double,PROBLEM_DIM*(ELEMENT_DIM+1)> ComputeVectorTerm(
00176         c_vector<double, ELEMENT_DIM+1>& rPhi,
00177         c_matrix<double, SPACE_DIM, ELEMENT_DIM+1>& rGradPhi,
00178         ChastePoint<SPACE_DIM>& rX,
00179         c_vector<double,PROBLEM_DIM>& rU,
00180         c_matrix<double, PROBLEM_DIM, SPACE_DIM>& rGradU,
00181         Element<ELEMENT_DIM,SPACE_DIM>* pElement)
00182     {
00183         // If this line is reached this means this method probably hasn't been over-ridden correctly in
00184         // the concrete class
00185         NEVER_REACHED;
00186         return zero_vector<double>(PROBLEM_DIM*(ELEMENT_DIM+1));
00187     }
00188 
00189 
00204     virtual void AssembleOnElement(Element<ELEMENT_DIM,SPACE_DIM>& rElement,
00205                                    c_matrix<double, PROBLEM_DIM*(ELEMENT_DIM+1), PROBLEM_DIM*(ELEMENT_DIM+1) >& rAElem,
00206                                    c_vector<double, PROBLEM_DIM*(ELEMENT_DIM+1)>& rBElem);
00207 
00215     virtual bool ElementAssemblyCriterion(Element<ELEMENT_DIM,SPACE_DIM>& rElement)
00216     {
00217         return true;
00218     }
00219 
00220 
00221 public:
00222 
00228     AbstractFeVolumeIntegralAssembler(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh);
00229 
00233     virtual ~AbstractFeVolumeIntegralAssembler()
00234     {
00235         delete mpQuadRule;
00236     }
00237 };
00238 
00239 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM, bool CAN_ASSEMBLE_VECTOR, bool CAN_ASSEMBLE_MATRIX, InterpolationLevel INTERPOLATION_LEVEL>
00240 AbstractFeVolumeIntegralAssembler<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM, CAN_ASSEMBLE_VECTOR, CAN_ASSEMBLE_MATRIX, INTERPOLATION_LEVEL>::AbstractFeVolumeIntegralAssembler(
00241             AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00242     : AbstractFeAssemblerCommon<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM, CAN_ASSEMBLE_VECTOR, CAN_ASSEMBLE_MATRIX, INTERPOLATION_LEVEL>(),
00243       mpMesh(pMesh)
00244 {
00245     assert(pMesh);
00246     // Default to 2nd order quadrature.  Our default basis functions are piecewise linear
00247     // which means that we are integrating functions which in the worst case (mass matrix)
00248     // are quadratic.
00249     mpQuadRule = new GaussianQuadratureRule<ELEMENT_DIM>(2);
00250 }
00251 
00252 
00253 
00254 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM, bool CAN_ASSEMBLE_VECTOR, bool CAN_ASSEMBLE_MATRIX, InterpolationLevel INTERPOLATION_LEVEL>
00255 void AbstractFeVolumeIntegralAssembler<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM, CAN_ASSEMBLE_VECTOR, CAN_ASSEMBLE_MATRIX, INTERPOLATION_LEVEL>::DoAssemble()
00256 {
00257     assert(this->mAssembleMatrix || this->mAssembleVector);
00258 
00259     HeartEventHandler::EventType assemble_event;
00260     if (this->mAssembleMatrix)
00261     {
00262         assemble_event = HeartEventHandler::ASSEMBLE_SYSTEM;
00263     }
00264     else
00265     {
00266         assemble_event = HeartEventHandler::ASSEMBLE_RHS;
00267     }
00268 
00269     if (this->mAssembleMatrix && this->mMatrixToAssemble==NULL)
00270     {
00271         EXCEPTION("Matrix to be assembled has not been set");
00272     }
00273     if (this->mAssembleVector && this->mVectorToAssemble==NULL)
00274     {
00275         EXCEPTION("Vector to be assembled has not been set");
00276     }
00277 
00278     HeartEventHandler::BeginEvent(assemble_event);
00279 
00280     // Zero the matrix/vector if it is to be assembled
00281     if (this->mAssembleVector && this->mZeroVectorBeforeAssembly)
00282     {
00283         PetscVecTools::Zero(this->mVectorToAssemble);
00284     }
00285     if (this->mAssembleMatrix && this->mZeroMatrixBeforeAssembly)
00286     {
00287         PetscMatTools::Zero(this->mMatrixToAssemble);
00288     }
00289 
00290     const size_t STENCIL_SIZE=PROBLEM_DIM*(ELEMENT_DIM+1);
00291     c_matrix<double, STENCIL_SIZE, STENCIL_SIZE> a_elem;
00292     c_vector<double, STENCIL_SIZE> b_elem;
00293 
00294     // Loop over elements
00295     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = mpMesh->GetElementIteratorBegin();
00296          iter != mpMesh->GetElementIteratorEnd();
00297          ++iter)
00298     {
00299         Element<ELEMENT_DIM, SPACE_DIM>& r_element = *iter;
00300 
00301         // Test for ownership first, since it's pointless to test the criterion on something which we might know nothing about.
00302         if ( r_element.GetOwnership() == true && ElementAssemblyCriterion(r_element)==true )
00303         {
00304             AssembleOnElement(r_element, a_elem, b_elem);
00305 
00306             unsigned p_indices[STENCIL_SIZE];
00307             r_element.GetStiffnessMatrixGlobalIndices(PROBLEM_DIM, p_indices);
00308 
00309             if (this->mAssembleMatrix)
00310             {
00311                 PetscMatTools::AddMultipleValues<STENCIL_SIZE>(this->mMatrixToAssemble, p_indices, a_elem);
00312             }
00313 
00314             if (this->mAssembleVector)
00315             {
00316                 PetscVecTools::AddMultipleValues<STENCIL_SIZE>(this->mVectorToAssemble, p_indices, b_elem);
00317             }
00318         }
00319     }
00320 
00321     HeartEventHandler::EndEvent(assemble_event);
00322 }
00323 
00324 
00326 // Implementation - AssembleOnElement and smaller
00328 
00329 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM, bool CAN_ASSEMBLE_VECTOR, bool CAN_ASSEMBLE_MATRIX, InterpolationLevel INTERPOLATION_LEVEL>
00330 void AbstractFeVolumeIntegralAssembler<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM, CAN_ASSEMBLE_VECTOR, CAN_ASSEMBLE_MATRIX, INTERPOLATION_LEVEL>::ComputeTransformedBasisFunctionDerivatives(
00331         const ChastePoint<ELEMENT_DIM>& rPoint,
00332         const c_matrix<double, ELEMENT_DIM, SPACE_DIM>& rInverseJacobian,
00333         c_matrix<double, SPACE_DIM, ELEMENT_DIM+1>& rReturnValue)
00334 {
00335     assert(ELEMENT_DIM < 4 && ELEMENT_DIM > 0);
00336     static c_matrix<double, ELEMENT_DIM, ELEMENT_DIM+1> grad_phi;
00337 
00338     LinearBasisFunction<ELEMENT_DIM>::ComputeBasisFunctionDerivatives(rPoint, grad_phi);
00339     rReturnValue = prod(trans(rInverseJacobian), grad_phi);
00340 }
00341 
00342 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM, bool CAN_ASSEMBLE_VECTOR, bool CAN_ASSEMBLE_MATRIX, InterpolationLevel INTERPOLATION_LEVEL>
00343 void AbstractFeVolumeIntegralAssembler<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM, CAN_ASSEMBLE_VECTOR, CAN_ASSEMBLE_MATRIX, INTERPOLATION_LEVEL>::AssembleOnElement(
00344     Element<ELEMENT_DIM,SPACE_DIM>& rElement,
00345     c_matrix<double, PROBLEM_DIM*(ELEMENT_DIM+1), PROBLEM_DIM*(ELEMENT_DIM+1) >& rAElem,
00346     c_vector<double, PROBLEM_DIM*(ELEMENT_DIM+1)>& rBElem)
00347 {
00353     c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian;
00354     c_matrix<double, ELEMENT_DIM, SPACE_DIM> inverse_jacobian;
00355     double jacobian_determinant;
00356 
00357     mpMesh->GetInverseJacobianForElement(rElement.GetIndex(), jacobian, jacobian_determinant, inverse_jacobian);
00358 
00359     if (this->mAssembleMatrix)
00360     {
00361         rAElem.clear();
00362     }
00363 
00364     if (this->mAssembleVector)
00365     {
00366         rBElem.clear();
00367     }
00368 
00369     const unsigned num_nodes = rElement.GetNumNodes();
00370 
00371     // Allocate memory for the basis functions values and derivative values
00372     c_vector<double, ELEMENT_DIM+1> phi;
00373     c_matrix<double, SPACE_DIM, ELEMENT_DIM+1> grad_phi;
00374 
00375     // Loop over Gauss points
00376     for (unsigned quad_index=0; quad_index < mpQuadRule->GetNumQuadPoints(); quad_index++)
00377     {
00378         const ChastePoint<ELEMENT_DIM>& quad_point = mpQuadRule->rGetQuadPoint(quad_index);
00379 
00380         BasisFunction::ComputeBasisFunctions(quad_point, phi);
00381 
00382         if ( this->mAssembleMatrix || INTERPOLATION_LEVEL==NONLINEAR )
00383         {
00384             ComputeTransformedBasisFunctionDerivatives(quad_point, inverse_jacobian, grad_phi);
00385         }
00386 
00387         // Location of the Gauss point in the original element will be stored in x
00388         // Where applicable, u will be set to the value of the current solution at x
00389         ChastePoint<SPACE_DIM> x(0,0,0);
00390 
00391         c_vector<double,PROBLEM_DIM> u = zero_vector<double>(PROBLEM_DIM);
00392         c_matrix<double,PROBLEM_DIM,SPACE_DIM> grad_u = zero_matrix<double>(PROBLEM_DIM,SPACE_DIM);
00393 
00394         // Allow the concrete version of the assembler to interpolate any desired quantities
00395         this->ResetInterpolatedQuantities();
00396 
00397         // Interpolation
00398         for (unsigned i=0; i<num_nodes; i++)
00399         {
00400             const Node<SPACE_DIM>* p_node = rElement.GetNode(i);
00401 
00402             if (INTERPOLATION_LEVEL != CARDIAC) // don't even interpolate X if cardiac problem
00403             {
00404                 const c_vector<double, SPACE_DIM>& r_node_loc = p_node->rGetLocation();
00405                 // interpolate x
00406                 x.rGetLocation() += phi(i)*r_node_loc;
00407             }
00408 
00409             // Interpolate u and grad u if a current solution or guess exists
00410             unsigned node_global_index = rElement.GetNodeGlobalIndex(i);
00411             if (this->mCurrentSolutionOrGuessReplicated.GetSize() > 0)
00412             {
00413                 for (unsigned index_of_unknown=0; index_of_unknown<(INTERPOLATION_LEVEL!=CARDIAC ? PROBLEM_DIM : 1); index_of_unknown++)
00414                 {
00415                     /*
00416                      * If we have a solution (e.g. this is a dynamic problem) then
00417                      * interpolate the value at this quadrature point.
00418                      *
00419                      * NOTE: the following assumes that if, say, there are two unknowns
00420                      * u and v, they are stored in the current solution vector as
00421                      * [U1 V1 U2 V2 ... U_n V_n].
00422                      */
00423                     double u_at_node = this->GetCurrentSolutionOrGuessValue(node_global_index, index_of_unknown);
00424                     u(index_of_unknown) += phi(i)*u_at_node;
00425 
00426                     if (INTERPOLATION_LEVEL==NONLINEAR) // don't need to construct grad_phi or grad_u in other cases
00427                     {
00428                         for (unsigned j=0; j<SPACE_DIM; j++)
00429                         {
00430                             grad_u(index_of_unknown,j) += grad_phi(j,i)*u_at_node;
00431                         }
00432                     }
00433                 }
00434             }
00435 
00436             // Allow the concrete version of the assembler to interpolate any desired quantities
00437             this->IncrementInterpolatedQuantities(phi(i), p_node);
00438             if ( this->mAssembleMatrix || INTERPOLATION_LEVEL==NONLINEAR )
00439             {
00440                 this->IncrementInterpolatedGradientQuantities(grad_phi, i, p_node);
00441             }
00442         }
00443 
00444         double wJ = jacobian_determinant * mpQuadRule->GetWeight(quad_index);
00445 
00446         // Create rAElem and rBElem
00447         if (this->mAssembleMatrix)
00448         {
00449             noalias(rAElem) += ComputeMatrixTerm(phi, grad_phi, x, u, grad_u, &rElement) * wJ;
00450         }
00451 
00452         if (this->mAssembleVector)
00453         {
00454             noalias(rBElem) += ComputeVectorTerm(phi, grad_phi, x, u, grad_u, &rElement) * wJ;
00455         }
00456     }
00457 }
00458 
00459 
00460 #endif /*ABSTRACTFEVOLUMEINTEGRALASSEMBLER_HPP_*/

Generated by  doxygen 1.6.2