AbstractFeCableIntegralAssembler.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 ABSTRACTFECABLEINTEGRALASSEMBLER_HPP_
00037 #define ABSTRACTFECABLEINTEGRALASSEMBLER_HPP_
00038 
00039 #include "AbstractFeAssemblerCommon.hpp"
00040 #include "GaussianQuadratureRule.hpp"
00041 #include "PetscVecTools.hpp"
00042 #include "PetscMatTools.hpp"
00043 
00050 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM, bool CAN_ASSEMBLE_VECTOR, bool CAN_ASSEMBLE_MATRIX, InterpolationLevel INTERPOLATION_LEVEL>
00051 class AbstractFeCableIntegralAssembler : public AbstractFeAssemblerCommon<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM,CAN_ASSEMBLE_VECTOR,CAN_ASSEMBLE_MATRIX,INTERPOLATION_LEVEL>
00052 {
00053 protected:
00055     static const unsigned CABLE_ELEMENT_DIM = 1;
00056 
00058     static const unsigned NUM_CABLE_ELEMENT_NODES = 2;
00059 
00061     MixedDimensionMesh<ELEMENT_DIM, SPACE_DIM>* mpMesh;
00062 
00064     GaussianQuadratureRule<1>* mpCableQuadRule;
00065 
00067     typedef LinearBasisFunction<1> CableBasisFunction;
00068 
00083     void ComputeTransformedBasisFunctionDerivatives(const ChastePoint<CABLE_ELEMENT_DIM>& rPoint,
00084                                                     const c_matrix<double, CABLE_ELEMENT_DIM, SPACE_DIM>& rInverseJacobian,
00085                                                     c_matrix<double, SPACE_DIM, NUM_CABLE_ELEMENT_NODES>& rReturnValue);
00086 
00092     void DoAssemble();
00093 
00116     virtual c_matrix<double,PROBLEM_DIM*NUM_CABLE_ELEMENT_NODES,PROBLEM_DIM*NUM_CABLE_ELEMENT_NODES> ComputeCableMatrixTerm(
00117         c_vector<double, NUM_CABLE_ELEMENT_NODES>& rPhi,
00118         c_matrix<double, SPACE_DIM, NUM_CABLE_ELEMENT_NODES>& rGradPhi,
00119         ChastePoint<SPACE_DIM>& rX,
00120         c_vector<double,PROBLEM_DIM>& rU,
00121         c_matrix<double, PROBLEM_DIM, SPACE_DIM>& rGradU,
00122         Element<CABLE_ELEMENT_DIM,SPACE_DIM>* pElement)
00123     {
00124         // If this line is reached this means this method probably hasn't been over-ridden correctly in
00125         // the concrete class
00126         NEVER_REACHED;
00127         return zero_matrix<double>(PROBLEM_DIM*NUM_CABLE_ELEMENT_NODES,PROBLEM_DIM*NUM_CABLE_ELEMENT_NODES);
00128     }
00129 
00150     virtual c_vector<double,PROBLEM_DIM*NUM_CABLE_ELEMENT_NODES> ComputeCableVectorTerm(
00151         c_vector<double, NUM_CABLE_ELEMENT_NODES>& rPhi,
00152         c_matrix<double, SPACE_DIM, NUM_CABLE_ELEMENT_NODES>& rGradPhi,
00153         ChastePoint<SPACE_DIM>& rX,
00154         c_vector<double,PROBLEM_DIM>& rU,
00155         c_matrix<double, PROBLEM_DIM, SPACE_DIM>& rGradU,
00156         Element<CABLE_ELEMENT_DIM,SPACE_DIM>* pElement)
00157     {
00158         // If this line is reached this means this method probably hasn't been over-ridden correctly in
00159         // the concrete class
00160         NEVER_REACHED;
00161         return zero_vector<double>(PROBLEM_DIM*NUM_CABLE_ELEMENT_NODES);
00162     }
00163 
00178     virtual void AssembleOnCableElement(Element<CABLE_ELEMENT_DIM,SPACE_DIM>& rElement,
00179                                         c_matrix<double, PROBLEM_DIM*NUM_CABLE_ELEMENT_NODES, PROBLEM_DIM*NUM_CABLE_ELEMENT_NODES >& rAElem,
00180                                         c_vector<double, PROBLEM_DIM*NUM_CABLE_ELEMENT_NODES>& rBElem);
00181 
00182 
00190     virtual bool ElementAssemblyCriterion(Element<CABLE_ELEMENT_DIM,SPACE_DIM>& rElement)
00191     {
00192         return true;
00193     }
00194 
00195 public:
00196 
00202     AbstractFeCableIntegralAssembler(MixedDimensionMesh<ELEMENT_DIM,SPACE_DIM>* pMesh);
00203 
00207     virtual ~AbstractFeCableIntegralAssembler()
00208     {
00209         delete mpCableQuadRule;
00210     }
00211 };
00212 
00213 
00214 
00215 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM, bool CAN_ASSEMBLE_VECTOR, bool CAN_ASSEMBLE_MATRIX, InterpolationLevel INTERPOLATION_LEVEL>
00216 AbstractFeCableIntegralAssembler<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM, CAN_ASSEMBLE_VECTOR, CAN_ASSEMBLE_MATRIX, INTERPOLATION_LEVEL>::AbstractFeCableIntegralAssembler(
00217             MixedDimensionMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00218     : AbstractFeAssemblerCommon<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM, CAN_ASSEMBLE_VECTOR, CAN_ASSEMBLE_MATRIX, INTERPOLATION_LEVEL>(),
00219       mpMesh(pMesh)
00220 {
00221     assert(pMesh);
00222     assert(CAN_ASSEMBLE_VECTOR || CAN_ASSEMBLE_MATRIX);
00223     // Default to 2nd order quadrature.  Our default basis functions are piecewise linear
00224     // which means that we are integrating functions which in the worst case (mass matrix)
00225     // are quadratic.
00226     mpCableQuadRule = new GaussianQuadratureRule<CABLE_ELEMENT_DIM>(2);
00227 
00228     // Not supporting this yet - if a nonlinear assembler on cable elements is required, uncomment code
00229     // in AssembleOnCableElement below (search for NONLINEAR)
00230     assert(INTERPOLATION_LEVEL!=NONLINEAR);
00231 }
00232 
00233 
00234 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM, bool CAN_ASSEMBLE_VECTOR, bool CAN_ASSEMBLE_MATRIX, InterpolationLevel INTERPOLATION_LEVEL>
00235 void AbstractFeCableIntegralAssembler<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM, CAN_ASSEMBLE_VECTOR, CAN_ASSEMBLE_MATRIX, INTERPOLATION_LEVEL>::DoAssemble()
00236 {
00237     HeartEventHandler::EventType assemble_event;
00238     if (this->mAssembleMatrix)
00239     {
00240         assemble_event = HeartEventHandler::ASSEMBLE_SYSTEM;
00241     }
00242     else
00243     {
00244         assemble_event = HeartEventHandler::ASSEMBLE_RHS;
00245     }
00246 
00247     if (this->mAssembleMatrix && this->mMatrixToAssemble==NULL)
00248     {
00249         EXCEPTION("Matrix to be assembled has not been set");
00250     }
00251     if (this->mAssembleVector && this->mVectorToAssemble==NULL)
00252     {
00253         EXCEPTION("Vector to be assembled has not been set");
00254     }
00255 
00256     // This has to be below PrepareForAssembleSystem as in that method the ODEs are solved in cardiac problems
00257     HeartEventHandler::BeginEvent(assemble_event);
00258 
00259     // Zero the matrix/vector if it is to be assembled
00260     if (this->mAssembleVector && this->mZeroVectorBeforeAssembly)
00261     {
00262         PetscVecTools::Zero(this->mVectorToAssemble);
00263     }
00264     if (this->mAssembleMatrix && this->mZeroMatrixBeforeAssembly)
00265     {
00266         PetscMatTools::Zero(this->mMatrixToAssemble);
00267     }
00268 
00269     const size_t STENCIL_SIZE=PROBLEM_DIM*NUM_CABLE_ELEMENT_NODES;
00270     c_matrix<double, STENCIL_SIZE, STENCIL_SIZE> a_elem;
00271     c_vector<double, STENCIL_SIZE> b_elem;
00272 
00273     // Loop over elements
00274     if (this->mAssembleMatrix || this->mAssembleVector)
00275     {
00276         for (typename MixedDimensionMesh<CABLE_ELEMENT_DIM, SPACE_DIM>::CableElementIterator iter = mpMesh->GetCableElementIteratorBegin();
00277              iter != mpMesh->GetCableElementIteratorEnd();
00278              ++iter)
00279         {
00280             Element<CABLE_ELEMENT_DIM, SPACE_DIM>& r_element = *(*iter);
00281 
00282             // Test for ownership first, since it's pointless to test the criterion on something which we might know nothing about.
00283             if ( r_element.GetOwnership() == true && ElementAssemblyCriterion(r_element)==true )
00284             {
00285                 AssembleOnCableElement(r_element, a_elem, b_elem);
00286 
00287                 unsigned p_indices[STENCIL_SIZE];
00288                 r_element.GetStiffnessMatrixGlobalIndices(PROBLEM_DIM, p_indices);
00289 
00290                 if (this->mAssembleMatrix)
00291                 {
00292                     PetscMatTools::AddMultipleValues<STENCIL_SIZE>(this->mMatrixToAssemble, p_indices, a_elem);
00293                 }
00294 
00295                 if (this->mAssembleVector)
00296                 {
00297                     PetscVecTools::AddMultipleValues<STENCIL_SIZE>(this->mVectorToAssemble, p_indices, b_elem);
00298                 }
00299             }
00300         }
00301     }
00302 
00303     HeartEventHandler::EndEvent(assemble_event);
00304 }
00305 
00307 // Implementation - AssembleOnCableElement and smaller
00309 
00310 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM, bool CAN_ASSEMBLE_VECTOR, bool CAN_ASSEMBLE_MATRIX, InterpolationLevel INTERPOLATION_LEVEL>
00311 void AbstractFeCableIntegralAssembler<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM, CAN_ASSEMBLE_VECTOR, CAN_ASSEMBLE_MATRIX, INTERPOLATION_LEVEL>::ComputeTransformedBasisFunctionDerivatives(
00312         const ChastePoint<CABLE_ELEMENT_DIM>& rPoint,
00313         const c_matrix<double, CABLE_ELEMENT_DIM, SPACE_DIM>& rInverseJacobian,
00314         c_matrix<double, SPACE_DIM, NUM_CABLE_ELEMENT_NODES>& rReturnValue)
00315 {
00316     static c_matrix<double, CABLE_ELEMENT_DIM, NUM_CABLE_ELEMENT_NODES> grad_phi;
00317 
00318     LinearBasisFunction<CABLE_ELEMENT_DIM>::ComputeBasisFunctionDerivatives(rPoint, grad_phi);
00319     rReturnValue = prod(trans(rInverseJacobian), grad_phi);
00320 }
00321 
00322 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM, bool CAN_ASSEMBLE_VECTOR, bool CAN_ASSEMBLE_MATRIX, InterpolationLevel INTERPOLATION_LEVEL>
00323 void AbstractFeCableIntegralAssembler<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM, CAN_ASSEMBLE_VECTOR, CAN_ASSEMBLE_MATRIX, INTERPOLATION_LEVEL>::AssembleOnCableElement(
00324     Element<CABLE_ELEMENT_DIM,SPACE_DIM>& rElement,
00325     c_matrix<double, PROBLEM_DIM*NUM_CABLE_ELEMENT_NODES, PROBLEM_DIM*NUM_CABLE_ELEMENT_NODES >& rAElem,
00326     c_vector<double, PROBLEM_DIM*NUM_CABLE_ELEMENT_NODES>& rBElem)
00327 {
00333     c_matrix<double, SPACE_DIM, CABLE_ELEMENT_DIM> jacobian;
00334     c_matrix<double, CABLE_ELEMENT_DIM, SPACE_DIM> inverse_jacobian;
00335     double jacobian_determinant;
00336 
00339     // mpMesh->GetInverseJacobianForElement(rElement.GetIndex(), jacobian, jacobian_determinant, inverse_jacobian);
00341     rElement.CalculateInverseJacobian(jacobian, jacobian_determinant, inverse_jacobian);
00342 
00343     if (this->mAssembleMatrix)
00344     {
00345         rAElem.clear();
00346     }
00347 
00348     if (this->mAssembleVector)
00349     {
00350         rBElem.clear();
00351     }
00352 
00353     const unsigned num_nodes = rElement.GetNumNodes();
00354 
00355     // Allocate memory for the basis functions values and derivative values
00356     c_vector<double, NUM_CABLE_ELEMENT_NODES> phi;
00357     c_matrix<double, SPACE_DIM, NUM_CABLE_ELEMENT_NODES> grad_phi;
00358 
00359     // Loop over Gauss points
00360     for (unsigned quad_index=0; quad_index < mpCableQuadRule->GetNumQuadPoints(); quad_index++)
00361     {
00362         const ChastePoint<CABLE_ELEMENT_DIM>& quad_point = mpCableQuadRule->rGetQuadPoint(quad_index);
00363 
00364         CableBasisFunction::ComputeBasisFunctions(quad_point, phi);
00365 
00366         if ( this->mAssembleMatrix || INTERPOLATION_LEVEL==NONLINEAR )
00367         {
00368             ComputeTransformedBasisFunctionDerivatives(quad_point, inverse_jacobian, grad_phi);
00369         }
00370 
00371         // Location of the Gauss point in the original element will be stored in x
00372         // Where applicable, u will be set to the value of the current solution at x
00373         ChastePoint<SPACE_DIM> x(0,0,0);
00374 
00375         c_vector<double,PROBLEM_DIM> u = zero_vector<double>(PROBLEM_DIM);
00376         c_matrix<double,PROBLEM_DIM,SPACE_DIM> grad_u = zero_matrix<double>(PROBLEM_DIM,SPACE_DIM);
00377 
00378         // Allow the concrete version of the assembler to interpolate any desired quantities
00379         this->ResetInterpolatedQuantities();
00380 
00381         // Interpolation
00382         for (unsigned i=0; i<num_nodes; i++)
00383         {
00384             const Node<SPACE_DIM>* p_node = rElement.GetNode(i);
00385 
00386             if (INTERPOLATION_LEVEL != CARDIAC) // don't interpolate X if cardiac problem
00387             {
00388                 const c_vector<double, SPACE_DIM>& r_node_loc = p_node->rGetLocation();
00389                 // interpolate x
00390                 x.rGetLocation() += phi(i)*r_node_loc;
00391             }
00392 
00393             // Interpolate u and grad u if a current solution or guess exists
00394             unsigned node_global_index = rElement.GetNodeGlobalIndex(i);
00395             if (this->mCurrentSolutionOrGuessReplicated.GetSize() > 0)
00396             {
00397                 for (unsigned index_of_unknown=0; index_of_unknown<(INTERPOLATION_LEVEL!=CARDIAC ? PROBLEM_DIM : 1); index_of_unknown++)
00398                 {
00399                     /*
00400                      * If we have a solution (e.g. this is a dynamic problem) then
00401                      * interpolate the value at this quadrature point.
00402                      *
00403                      * NOTE: the following assumes that if, say, there are two unknowns
00404                      * u and v, they are stored in the current solution vector as
00405                      * [U1 V1 U2 V2 ... U_n V_n].
00406                      */
00407                     double u_at_node = this->GetCurrentSolutionOrGuessValue(node_global_index, index_of_unknown);
00408                     u(index_of_unknown) += phi(i)*u_at_node;
00409 
00411 //                    if (INTERPOLATION_LEVEL==NONLINEAR) // don't need to construct grad_phi or grad_u in other cases
00412 //                    {
00413 //                        for (unsigned j=0; j<SPACE_DIM; j++)
00414 //                        {
00415 //                            grad_u(index_of_unknown,j) += grad_phi(j,i)*u_at_node;
00416 //                        }
00417 //                    }
00418                 }
00419             }
00420 
00421             // Allow the concrete version of the assembler to interpolate any desired quantities
00422             this->IncrementInterpolatedQuantities(phi(i), p_node);
00423         }
00424 
00425         double wJ = jacobian_determinant * mpCableQuadRule->GetWeight(quad_index);
00426 
00427         // Create rAElem and rBElem
00428         if (this->mAssembleMatrix)
00429         {
00430             noalias(rAElem) += ComputeCableMatrixTerm(phi, grad_phi, x, u, grad_u, &rElement) * wJ;
00431         }
00432 
00433         if (this->mAssembleVector)
00434         {
00435             noalias(rBElem) += ComputeCableVectorTerm(phi, grad_phi, x, u, grad_u, &rElement) * wJ;
00436         }
00437     }
00438 }
00439 
00440 #endif /*ABSTRACTFECABLEINTEGRALASSEMBLER_HPP_*/

Generated by  doxygen 1.6.2