AbstractContinuumMechanicsAssembler.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
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 #ifndef ABSTRACTCONTINUUMMECHANICSASSEMBLER_HPP_
00030 #define ABSTRACTCONTINUUMMECHANICSASSEMBLER_HPP_
00031 
00032 #include "AbstractFeAssemblerInterface.hpp"
00033 #include "QuadraticMesh.hpp"
00034 #include "LinearBasisFunction.hpp"
00035 #include "QuadraticBasisFunction.hpp"
00036 #include "ReplicatableVector.hpp"
00037 #include "DistributedVector.hpp"
00038 #include "PetscTools.hpp"
00039 #include "PetscVecTools.hpp"
00040 #include "PetscMatTools.hpp"
00041 #include "GaussianQuadratureRule.hpp"
00042 
00043 
00062 template<unsigned DIM, bool CAN_ASSEMBLE_VECTOR, bool CAN_ASSEMBLE_MATRIX>
00063 class AbstractContinuumMechanicsAssembler : public AbstractFeAssemblerInterface<CAN_ASSEMBLE_VECTOR,CAN_ASSEMBLE_MATRIX>
00064 {
00068     static const bool BLOCK_SYMMETRIC_MATRIX = true; //generalise to non-block symmetric matrices later (when needed maybe)
00069 
00071     static const unsigned NUM_VERTICES_PER_ELEMENT = DIM+1;
00072 
00074     static const unsigned NUM_NODES_PER_ELEMENT = (DIM+1)*(DIM+2)/2; // assuming quadratic
00075 
00077     static const unsigned SPATIAL_BLOCK_SIZE_ELEMENTAL = DIM*NUM_NODES_PER_ELEMENT;
00079     static const unsigned PRESSURE_BLOCK_SIZE_ELEMENTAL = NUM_VERTICES_PER_ELEMENT;
00080 
00082     static const unsigned STENCIL_SIZE = DIM*NUM_NODES_PER_ELEMENT + NUM_VERTICES_PER_ELEMENT;
00083 
00084 protected:
00086     QuadraticMesh<DIM>* mpMesh;
00087 
00089     GaussianQuadratureRule<DIM>* mpQuadRule;
00090 
00097     void DoAssemble();
00098 
00099 
00118     virtual c_matrix<double,SPATIAL_BLOCK_SIZE_ELEMENTAL,SPATIAL_BLOCK_SIZE_ELEMENTAL> ComputeSpatialSpatialMatrixTerm(
00119         c_vector<double, NUM_NODES_PER_ELEMENT>& rQuadPhi,
00120         c_matrix<double, DIM, NUM_NODES_PER_ELEMENT>& rGradQuadPhi,
00121         c_vector<double,DIM>& rX,
00122         Element<DIM,DIM>* pElement)
00123     {
00124         return zero_matrix<double>(SPATIAL_BLOCK_SIZE_ELEMENTAL,SPATIAL_BLOCK_SIZE_ELEMENTAL);
00125     }
00126 
00148     virtual c_matrix<double,SPATIAL_BLOCK_SIZE_ELEMENTAL,PRESSURE_BLOCK_SIZE_ELEMENTAL> ComputeSpatialPressureMatrixTerm(
00149         c_vector<double, NUM_NODES_PER_ELEMENT>& rQuadPhi,
00150         c_matrix<double, DIM, NUM_NODES_PER_ELEMENT>& rGradQuadPhi,
00151         c_vector<double, NUM_VERTICES_PER_ELEMENT>& rLinearPhi,
00152         c_matrix<double, DIM, NUM_VERTICES_PER_ELEMENT>& rGradLinearPhi,
00153         c_vector<double,DIM>& rX,
00154         Element<DIM,DIM>* pElement)
00155     {
00156         return zero_matrix<double>(SPATIAL_BLOCK_SIZE_ELEMENTAL,PRESSURE_BLOCK_SIZE_ELEMENTAL);
00157     }
00158 
00159 
00178     virtual c_matrix<double,PRESSURE_BLOCK_SIZE_ELEMENTAL,PRESSURE_BLOCK_SIZE_ELEMENTAL> ComputePressurePressureMatrixTerm(
00179         c_vector<double, NUM_VERTICES_PER_ELEMENT>& rLinearPhi,
00180         c_matrix<double, DIM, NUM_VERTICES_PER_ELEMENT>& rGradLinearPhi,
00181         c_vector<double,DIM>& rX,
00182         Element<DIM,DIM>* pElement)
00183     {
00184         return zero_matrix<double>(PRESSURE_BLOCK_SIZE_ELEMENTAL,PRESSURE_BLOCK_SIZE_ELEMENTAL);
00185     }
00186 
00187 
00209     virtual c_vector<double,SPATIAL_BLOCK_SIZE_ELEMENTAL> ComputeSpatialVectorTerm(
00210         c_vector<double, NUM_NODES_PER_ELEMENT>& rQuadPhi,
00211         c_matrix<double, DIM, NUM_NODES_PER_ELEMENT>& rGradQuadPhi,
00212         c_vector<double,DIM>& rX,
00213         Element<DIM,DIM>* pElement)
00214     {
00215         return zero_vector<double>(SPATIAL_BLOCK_SIZE_ELEMENTAL);
00216     }
00217 
00218 
00240     virtual c_vector<double,PRESSURE_BLOCK_SIZE_ELEMENTAL> ComputePressureVectorTerm(
00241             c_vector<double, NUM_VERTICES_PER_ELEMENT>& rLinearPhi,
00242             c_matrix<double, DIM, NUM_VERTICES_PER_ELEMENT>& rGradLinearPhi,
00243             c_vector<double,DIM>& rX,
00244             Element<DIM,DIM>* pElement)
00245     {
00246         return zero_vector<double>(PRESSURE_BLOCK_SIZE_ELEMENTAL);
00247     }
00248 
00249 
00250 
00262     void AssembleOnElement(Element<DIM, DIM>& rElement,
00263                            c_matrix<double, STENCIL_SIZE, STENCIL_SIZE >& rAElem,
00264                            c_vector<double, STENCIL_SIZE>& rBElem);
00265 
00266 public:
00270     AbstractContinuumMechanicsAssembler(QuadraticMesh<DIM>* pMesh, unsigned numQuadPoints = 3)
00271         : AbstractFeAssemblerInterface<CAN_ASSEMBLE_VECTOR,CAN_ASSEMBLE_MATRIX>(),
00272           mpMesh(pMesh)
00273     {
00274         assert(pMesh);
00275         mpQuadRule = new GaussianQuadratureRule<DIM>(numQuadPoints);
00276     }
00277 
00278 
00279 //    void SetCurrentSolution(Vec currentSolution);
00280 
00281 
00285     virtual ~AbstractContinuumMechanicsAssembler()
00286     {
00287         delete mpQuadRule;
00288     }
00289 };
00290 
00291 
00293 //template<unsigned DIM, bool CAN_ASSEMBLE_VECTOR, bool CAN_ASSEMBLE_MATRIX>
00294 //void AbstractContinuumMechanicsAssembler<DIM,CAN_ASSEMBLE_VECTOR,CAN_ASSEMBLE_MATRIX>::SetCurrentSolution(Vec currentSolution)
00295 //{
00296 //    assert(currentSolution != NULL);
00297 //
00298 //    // Replicate the current solution and store so can be used in AssembleOnElement
00299 //    HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00300 //    mCurrentSolutionOrGuessReplicated.ReplicatePetscVector(currentSolution);
00301 //    HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00302 //
00303 //    // The AssembleOnElement type methods will determine if a current solution or
00304 //    // current guess exists by looking at the size of the replicated vector, so
00305 //    // check the size is zero if there isn't a current solution.
00306 //    assert(mCurrentSolutionOrGuessReplicated.GetSize() > 0);
00307 //}
00308 
00309 template<unsigned DIM, bool CAN_ASSEMBLE_VECTOR, bool CAN_ASSEMBLE_MATRIX>
00310 void AbstractContinuumMechanicsAssembler<DIM,CAN_ASSEMBLE_VECTOR,CAN_ASSEMBLE_MATRIX>::DoAssemble()
00311 {
00312     assert(this->mAssembleMatrix || this->mAssembleVector);
00313     if (this->mAssembleMatrix)
00314     {
00315         if(this->mMatrixToAssemble==NULL)
00316         {
00317             EXCEPTION("Matrix to be assembled has not been set");
00318         }
00319         if( PetscMatTools::GetSize(this->mMatrixToAssemble) != DIM*mpMesh->GetNumNodes()+mpMesh->GetNumVertices() )
00320         {
00321             EXCEPTION("Matrix provided to be assembled has size " << PetscMatTools::GetSize(this->mMatrixToAssemble) << ", not expected size of " << DIM*mpMesh->GetNumNodes()+mpMesh->GetNumVertices() << " (dim*num_nodes+num_vertices)");
00322         }
00323     }
00324 
00325     if (this->mAssembleVector)
00326     {
00327         if(this->mVectorToAssemble==NULL)
00328         {
00329             EXCEPTION("Vector to be assembled has not been set");
00330         }
00331         if( PetscVecTools::GetSize(this->mVectorToAssemble) != DIM*mpMesh->GetNumNodes()+mpMesh->GetNumVertices() )
00332         {
00333             EXCEPTION("Vector provided to be assembled has size " << PetscVecTools::GetSize(this->mVectorToAssemble) << ", not expected size of " << DIM*mpMesh->GetNumNodes()+mpMesh->GetNumVertices() << " (dim*num_nodes+num_vertices)");
00334         }
00335     }
00336 
00337     // Zero the matrix/vector if it is to be assembled
00338     if (this->mAssembleVector && this->mZeroVectorBeforeAssembly)
00339     {
00340         PetscVecTools::Zero(this->mVectorToAssemble);
00341     }
00342     if (this->mAssembleMatrix && this->mZeroMatrixBeforeAssembly)
00343     {
00344         PetscMatTools::Zero(this->mMatrixToAssemble);
00345     }
00346 
00347 //todo!
00348 //mpPreconditionMatrixLinearSystem->ZeroLhsMatrix();
00349 
00350     c_matrix<double, STENCIL_SIZE, STENCIL_SIZE> a_elem = zero_matrix<double>(STENCIL_SIZE,STENCIL_SIZE);
00351     c_vector<double, STENCIL_SIZE> b_elem = zero_vector<double>(STENCIL_SIZE);
00352 
00353 
00354     // Loop over elements
00355     for (typename AbstractTetrahedralMesh<DIM, DIM>::ElementIterator iter = mpMesh->GetElementIteratorBegin();
00356          iter != mpMesh->GetElementIteratorEnd();
00357          ++iter)
00358     {
00359         Element<DIM, DIM>& r_element = *iter;
00360 
00361         // Test for ownership first, since it's pointless to test the criterion on something which we might know nothing about.
00362         if ( r_element.GetOwnership() == true  /*&& ElementAssemblyCriterion(r_element)==true*/ )
00363         {
00364             AssembleOnElement(r_element, a_elem, b_elem);
00365 
00366             unsigned p_indices[STENCIL_SIZE];
00367             for (unsigned i=0; i<NUM_NODES_PER_ELEMENT; i++)
00368             {
00369                 for (unsigned j=0; j<DIM; j++)
00370                 {
00371                     p_indices[DIM*i+j] = DIM*r_element.GetNodeGlobalIndex(i) + j;
00372                 }
00373             }
00374 
00375             for (unsigned i=0; i<NUM_VERTICES_PER_ELEMENT; i++)
00376             {
00377                 p_indices[DIM*NUM_NODES_PER_ELEMENT + i] = DIM*mpMesh->GetNumNodes() + r_element.GetNodeGlobalIndex(i);
00378             }
00379 
00380             if (this->mMatrixToAssemble)
00381             {
00382                 PetscMatTools::AddMultipleValues<STENCIL_SIZE>(this->mMatrixToAssemble, p_indices, a_elem);
00383             }
00384 
00385 //mpPreconditionMatrixLinearSystem->AddLhsMultipleValues(p_indices, a_elem_precond);
00386 
00387             if (this->mAssembleVector)
00388             {
00389                 PetscVecTools::AddMultipleValues<STENCIL_SIZE>(this->mVectorToAssemble, p_indices, b_elem);
00390             }
00391         }
00392     }
00393 }
00394 
00395 template<unsigned DIM, bool CAN_ASSEMBLE_VECTOR, bool CAN_ASSEMBLE_MATRIX>
00396 void AbstractContinuumMechanicsAssembler<DIM,CAN_ASSEMBLE_VECTOR,CAN_ASSEMBLE_MATRIX>::AssembleOnElement(Element<DIM, DIM>& rElement,
00397                                                                                                          c_matrix<double, STENCIL_SIZE, STENCIL_SIZE >& rAElem,
00398                                                                                                          c_vector<double, STENCIL_SIZE>& rBElem)
00399 {
00400     static c_matrix<double,DIM,DIM> jacobian;
00401     static c_matrix<double,DIM,DIM> inverse_jacobian;
00402     double jacobian_determinant;
00403 
00404     mpMesh->GetInverseJacobianForElement(rElement.GetIndex(), jacobian, jacobian_determinant, inverse_jacobian);
00405 
00406     if (this->mAssembleMatrix)
00407     {
00408         rAElem.clear();
00409     }
00410 
00411     if (this->mAssembleVector)
00412     {
00413         rBElem.clear();
00414     }
00415 
00416 
00417     // Allocate memory for the basis functions values and derivative values
00418     static c_vector<double, NUM_VERTICES_PER_ELEMENT> linear_phi;
00419     static c_vector<double, NUM_NODES_PER_ELEMENT> quad_phi;
00420     static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi;
00421     static c_matrix<double, DIM, NUM_VERTICES_PER_ELEMENT> grad_linear_phi;
00422 
00423     c_vector<double,DIM> body_force;
00424 
00425     // Loop over Gauss points
00426     for (unsigned quadrature_index=0; quadrature_index < mpQuadRule->GetNumQuadPoints(); quadrature_index++)
00427     {
00428         double wJ = jacobian_determinant * mpQuadRule->GetWeight(quadrature_index);
00429         const ChastePoint<DIM>& quadrature_point = mpQuadRule->rGetQuadPoint(quadrature_index);
00430 
00431         // Set up basis function info
00432         LinearBasisFunction<DIM>::ComputeBasisFunctions(quadrature_point, linear_phi);
00433         QuadraticBasisFunction<DIM>::ComputeBasisFunctions(quadrature_point, quad_phi);
00434         QuadraticBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(quadrature_point, inverse_jacobian, grad_quad_phi);
00435         LinearBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(quadrature_point, inverse_jacobian, grad_linear_phi);
00436 
00437         // interpolate X (ie physical location of this quad point).
00438         c_vector<double,DIM> X = zero_vector<double>(DIM);
00439         for (unsigned vertex_index=0; vertex_index<NUM_VERTICES_PER_ELEMENT; vertex_index++)
00440         {
00441             for(unsigned j=0; j<DIM; j++)
00442             {
00443                 X(j) += linear_phi(vertex_index)*rElement.GetNode(vertex_index)->rGetLocation()(j);
00444             }
00445         }
00446 
00447         if(this->mAssembleVector)
00448         {
00449             c_vector<double,SPATIAL_BLOCK_SIZE_ELEMENTAL> b_spatial
00450                 = ComputeSpatialVectorTerm(quad_phi, grad_quad_phi, X, &rElement);
00451             c_vector<double,PRESSURE_BLOCK_SIZE_ELEMENTAL> b_pressure = ComputePressureVectorTerm(linear_phi, grad_linear_phi, X, &rElement);
00452 
00453             for (unsigned i=0; i<SPATIAL_BLOCK_SIZE_ELEMENTAL; i++)
00454             {
00455                 rBElem(i) += b_spatial(i)*wJ;
00456             }
00457 
00458 
00459             for (unsigned i=0; i<PRESSURE_BLOCK_SIZE_ELEMENTAL; i++)
00460             {
00461                 rBElem(SPATIAL_BLOCK_SIZE_ELEMENTAL + i) += b_pressure(i)*wJ;
00462             }
00463         }
00464 
00465 
00466         if(this->mAssembleMatrix)
00467         {
00468             c_matrix<double,SPATIAL_BLOCK_SIZE_ELEMENTAL,SPATIAL_BLOCK_SIZE_ELEMENTAL> a_spatial_spatial
00469                 = ComputeSpatialSpatialMatrixTerm(quad_phi, grad_quad_phi, X, &rElement);
00470 
00471             c_matrix<double,SPATIAL_BLOCK_SIZE_ELEMENTAL,PRESSURE_BLOCK_SIZE_ELEMENTAL> a_spatial_pressure
00472                 = ComputeSpatialPressureMatrixTerm(quad_phi, grad_quad_phi, linear_phi, grad_linear_phi, X, &rElement);
00473 
00474             c_matrix<double,PRESSURE_BLOCK_SIZE_ELEMENTAL,SPATIAL_BLOCK_SIZE_ELEMENTAL> a_pressure_spatial;
00475             if(!BLOCK_SYMMETRIC_MATRIX)
00476             {
00477                 NEVER_REACHED; // to-come: non-mixed problems
00478                 //a_pressure_spatial = ComputeSpatialPressureMatrixTerm(quad_phi, grad_quad_phi, lin_phi, grad_lin_phi, x, &rElement);
00479             }
00480 
00481             c_matrix<double,PRESSURE_BLOCK_SIZE_ELEMENTAL,PRESSURE_BLOCK_SIZE_ELEMENTAL> a_pressure_pressure
00482                 = ComputePressurePressureMatrixTerm(linear_phi, grad_linear_phi, X, &rElement);
00483 
00484             for (unsigned i=0; i<SPATIAL_BLOCK_SIZE_ELEMENTAL; i++)
00485             {
00486                 for(unsigned j=0; j<SPATIAL_BLOCK_SIZE_ELEMENTAL; j++)
00487                 {
00488                     rAElem(i,j) += a_spatial_spatial(i,j)*wJ;
00489                 }
00490 
00491                 for(unsigned j=0; j<PRESSURE_BLOCK_SIZE_ELEMENTAL; j++)
00492                 {
00493                     rAElem(i, SPATIAL_BLOCK_SIZE_ELEMENTAL + j) += a_spatial_pressure(i,j)*wJ;
00494                 }
00495             }
00496 
00497             for(unsigned i=0; i<PRESSURE_BLOCK_SIZE_ELEMENTAL; i++)
00498             {
00499                 if(BLOCK_SYMMETRIC_MATRIX)
00500                 {
00501                     for(unsigned j=0; j<SPATIAL_BLOCK_SIZE_ELEMENTAL; j++)
00502                     {
00503                         rAElem(SPATIAL_BLOCK_SIZE_ELEMENTAL + i, j) += a_spatial_pressure(j,i)*wJ;
00504                     }
00505                 }
00506                 else
00507                 {
00508                     NEVER_REACHED; // to-come: non-mixed problems
00509                 }
00510 
00511                 for(unsigned j=0; j<PRESSURE_BLOCK_SIZE_ELEMENTAL; j++)
00512                 {
00513                     rAElem(SPATIAL_BLOCK_SIZE_ELEMENTAL + i, SPATIAL_BLOCK_SIZE_ELEMENTAL + j) += a_pressure_pressure(i,j)*wJ;
00514                 }
00515             }
00516         }
00517     }
00518 }
00519 
00520 
00521 #endif // ABSTRACTCONTINUUMMECHANICSASSEMBLER_HPP_
Generated on Thu Dec 22 13:00:05 2011 for Chaste by  doxygen 1.6.3