NonlinearElasticityAssembler.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
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 
00030 
00031 /*
00032  * NOTE ON COMPILATION ERRORS:
00033  *
00034  * This file won't compile with Intel icpc version 9.1.039, with error message:
00035  * "Terminate with:
00036   (0): internal error: backend signals"
00037  *
00038  * Try recompiling with icpc version 10.0.025.
00039  */
00040 
00041 #include "NonlinearElasticityAssembler.hpp"
00042 #include "LinearBasisFunction.hpp"
00043 #include "QuadraticBasisFunction.hpp"
00044 
00045 
00046 template<size_t DIM>
00047 void NonlinearElasticityAssembler<DIM>::AssembleSystem(bool assembleResidual,
00048                                                        bool assembleJacobian)
00049 {
00050     // Check we've actually been asked to do something!
00051     assert(assembleResidual || assembleJacobian);
00052     assert(this->mCurrentSolution.size()==this->mNumDofs);
00053 
00054     // Zero the matrix/vector if it is to be assembled
00055     if (assembleResidual)
00056     {
00057         this->mpLinearSystem->ZeroRhsVector();
00058     }
00059     if (assembleJacobian)
00060     {
00061         this->mpLinearSystem->ZeroLhsMatrix();
00062         this->mpPreconditionMatrixLinearSystem->ZeroLhsMatrix();
00063     }
00064 
00065     c_matrix<double, STENCIL_SIZE, STENCIL_SIZE> a_elem;
00066     // the (element) preconditioner matrix: this is the same as the jacobian, but
00067     // with the mass matrix (ie \intgl phi_i phi_j) in the pressure-pressure block.
00068     c_matrix<double, STENCIL_SIZE, STENCIL_SIZE> a_elem_precond;
00069     c_vector<double, STENCIL_SIZE> b_elem;
00070 
00072     // loop over elements
00074     for (typename AbstractTetrahedralMesh<DIM, DIM>::ElementIterator iter = mpQuadMesh->GetElementIteratorBegin();
00075          iter != mpQuadMesh->GetElementIteratorEnd();
00076          ++iter)
00077     {
00078         #ifdef MECH_VERY_VERBOSE
00079         if (assembleJacobian) // && ((*iter).GetIndex()%500==0))
00080         {
00081             std::cout << "\r[" << PetscTools::GetMyRank() << "]: Element " << (*iter).GetIndex() << " of " << this->mpQuadMesh->GetNumElements() << std::flush;
00082         }
00083         #endif
00084 
00085         Element<DIM, DIM>& element = *iter;
00086 
00087         if (element.GetOwnership() == true)
00088         {
00089             AssembleOnElement(element, a_elem, a_elem_precond, b_elem, assembleResidual, assembleJacobian);
00090 
00091             unsigned p_indices[STENCIL_SIZE];
00092             for (unsigned i=0; i<NUM_NODES_PER_ELEMENT; i++)
00093             {
00094                 for (unsigned j=0; j<DIM; j++)
00095                 {
00096                     p_indices[DIM*i+j] = DIM*element.GetNodeGlobalIndex(i) + j;
00097                 }
00098             }
00099 
00100             for (unsigned i=0; i<NUM_VERTICES_PER_ELEMENT; i++)
00101             {
00102                 p_indices[DIM*NUM_NODES_PER_ELEMENT + i] = DIM*mpQuadMesh->GetNumNodes() + element.GetNodeGlobalIndex(i);
00103             }
00104 
00105             if (assembleJacobian)
00106             {
00107                 this->mpLinearSystem->AddLhsMultipleValues(p_indices, a_elem);
00108                 this->mpPreconditionMatrixLinearSystem->AddLhsMultipleValues(p_indices, a_elem_precond);
00109             }
00110 
00111             if (assembleResidual)
00112             {
00113                 this->mpLinearSystem->AddRhsMultipleValues(p_indices, b_elem);
00114             }
00115         }
00116     }
00117 
00119     // loop over specified boundary elements and compute
00120     // surface traction terms
00122     c_vector<double, BOUNDARY_STENCIL_SIZE> b_boundary_elem;
00123     c_matrix<double, BOUNDARY_STENCIL_SIZE, BOUNDARY_STENCIL_SIZE> a_boundary_elem;
00124     if (mBoundaryElements.size()>0)
00125     {
00126         for (unsigned i=0; i<mBoundaryElements.size(); i++)
00127         {
00128             BoundaryElement<DIM-1,DIM>& r_boundary_element = *(mBoundaryElements[i]);
00129             AssembleOnBoundaryElement(r_boundary_element, a_boundary_elem, b_boundary_elem, this->mSurfaceTractions[i], assembleResidual, assembleJacobian);
00130 
00131             unsigned p_indices[BOUNDARY_STENCIL_SIZE];
00132             for (unsigned i=0; i<NUM_NODES_PER_BOUNDARY_ELEMENT; i++)
00133             {
00134                 for (unsigned j=0; j<DIM; j++)
00135                 {
00136                     p_indices[DIM*i+j] = DIM*r_boundary_element.GetNodeGlobalIndex(i) + j;
00137                 }
00138             }
00139 
00140             for (unsigned i=0; i<DIM /*vertices per boundary elem */; i++)
00141             {
00142                 p_indices[DIM*NUM_NODES_PER_BOUNDARY_ELEMENT + i] = DIM*mpQuadMesh->GetNumNodes() + r_boundary_element.GetNodeGlobalIndex(i);
00143             }
00144 
00145             if (assembleJacobian)
00146             {
00147                 this->mpLinearSystem->AddLhsMultipleValues(p_indices, a_boundary_elem);
00148                 this->mpPreconditionMatrixLinearSystem->AddLhsMultipleValues(p_indices, a_boundary_elem);
00149             }
00150 
00151             if (assembleResidual)
00152             {
00153                 this->mpLinearSystem->AddRhsMultipleValues(p_indices, b_boundary_elem);
00154             }
00155 
00156             // some extra checking
00157             if (DIM==2)
00158             {
00159                 assert(8==BOUNDARY_STENCIL_SIZE);
00160                 assert(b_boundary_elem(6)==0);
00161                 assert(b_boundary_elem(7)==0);
00162             }
00163         }
00164     }
00165 
00166     if (assembleResidual)
00167     {
00168         this->mpLinearSystem->AssembleRhsVector();
00169     }
00170     if (assembleJacobian)
00171     {
00172         this->mpLinearSystem->AssembleIntermediateLhsMatrix();
00173         this->mpPreconditionMatrixLinearSystem->AssembleIntermediateLhsMatrix();
00174     }
00175 
00176     // Apply Dirichlet boundary conditions
00177     this->ApplyBoundaryConditions(assembleJacobian);
00178 
00179     if (assembleResidual)
00180     {
00181         this->mpLinearSystem->AssembleRhsVector();
00182     }
00183     if (assembleJacobian)
00184     {
00185         this->mpLinearSystem->AssembleFinalLhsMatrix();
00186         this->mpPreconditionMatrixLinearSystem->AssembleFinalLhsMatrix();
00187     }
00188 }
00189 
00190 template<size_t DIM>
00191 void NonlinearElasticityAssembler<DIM>::AssembleOnElement(
00192             Element<DIM, DIM>& rElement,
00193             c_matrix<double, STENCIL_SIZE, STENCIL_SIZE >& rAElem,
00194             c_matrix<double, STENCIL_SIZE, STENCIL_SIZE >& rAElemPrecond,
00195             c_vector<double, STENCIL_SIZE>& rBElem,
00196             bool assembleResidual,
00197             bool assembleJacobian)
00198 {
00199     c_matrix<double, DIM, DIM> jacobian, inverse_jacobian;
00200     double jacobian_determinant;
00201 
00202     mpQuadMesh->GetInverseJacobianForElement(rElement.GetIndex(), jacobian, jacobian_determinant, inverse_jacobian);
00203 
00204     if (assembleJacobian)
00205     {
00206         rAElem.clear();
00207         rAElemPrecond.clear();
00208     }
00209 
00210     if (assembleResidual)
00211     {
00212         rBElem.clear();
00213     }
00214 
00216     // Get the current displacement at the nodes
00218     static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> element_current_displacements;
00219     static c_vector<double,NUM_VERTICES_PER_ELEMENT> element_current_pressures;
00220     for (unsigned II=0; II<NUM_NODES_PER_ELEMENT; II++)
00221     {
00222         for (unsigned JJ=0; JJ<DIM; JJ++)
00223         {
00224             element_current_displacements(JJ,II) = this->mCurrentSolution[DIM*rElement.GetNodeGlobalIndex(II) + JJ];
00225         }
00226     }
00227 
00229     // Get the current pressure at the vertices
00231     for (unsigned II=0; II<NUM_VERTICES_PER_ELEMENT; II++)
00232     {
00233         element_current_pressures(II) = this->mCurrentSolution[DIM*mpQuadMesh->GetNumNodes() + rElement.GetNodeGlobalIndex(II)];
00234     }
00235 
00236     // allocate memory for the basis functions values and derivative values
00237     c_vector<double, NUM_VERTICES_PER_ELEMENT> linear_phi;
00238     c_vector<double, NUM_NODES_PER_ELEMENT> quad_phi;
00239     c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi;
00240 
00241     // get the material law
00242     AbstractIncompressibleMaterialLaw<DIM>* p_material_law;
00243     if (this->mMaterialLaws.size()==1)
00244     {
00245         // homogeneous
00246         p_material_law = this->mMaterialLaws[0];
00247     }
00248     else
00249     {
00250         // heterogeneous
00251         #define COVERAGE_IGNORE // not going to have tests in cts for everything
00252         p_material_law = this->mMaterialLaws[rElement.GetIndex()];
00253         #undef COVERAGE_IGNORE
00254     }
00255 
00256 
00262     for (unsigned quadrature_index=0; quadrature_index < this->mpQuadratureRule->GetNumQuadPoints(); quadrature_index++)
00263     {
00264         double wJ = jacobian_determinant * this->mpQuadratureRule->GetWeight(quadrature_index);
00265 
00266         const ChastePoint<DIM>& quadrature_point = this->mpQuadratureRule->rGetQuadPoint(quadrature_index);
00267 
00269         // set up basis function info
00271         LinearBasisFunction<DIM>::ComputeBasisFunctions(quadrature_point, linear_phi);
00272         QuadraticBasisFunction<DIM>::ComputeBasisFunctions(quadrature_point, quad_phi);
00273         QuadraticBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(quadrature_point, inverse_jacobian, grad_quad_phi);
00274 
00275 
00277         // get the body force, interpolating X if necessary
00279         c_vector<double,DIM> body_force;
00280 
00281         if (this->mUsingBodyForceFunction)
00282         {
00283             c_vector<double,DIM> X = zero_vector<double>(DIM);
00284             // interpolate X (using the vertices and the /linear/ bases, as no curvilinear elements
00285             for (unsigned node_index=0; node_index<NUM_VERTICES_PER_ELEMENT; node_index++)
00286             {
00287                 X += linear_phi(node_index)*mpQuadMesh->GetNode( rElement.GetNodeGlobalIndex(node_index) )->rGetLocation();
00288             }
00289             body_force = (*(this->mpBodyForceFunction))(X);
00290         }
00291         else
00292         {
00293             body_force = this->mBodyForce;
00294         }
00295 
00297         // interpolate grad_u and p
00299         static c_matrix<double,DIM,DIM> grad_u; // grad_u = (du_i/dX_M)
00300         grad_u = zero_matrix<double>(DIM,DIM);  // must be on new line!!
00301 
00302         for (unsigned node_index=0; node_index<NUM_NODES_PER_ELEMENT; node_index++)
00303         {
00304             for (unsigned i=0; i<DIM; i++)
00305             {
00306                 for (unsigned M=0; M<DIM; M++)
00307                 {
00308                     grad_u(i,M) += grad_quad_phi(M,node_index)*element_current_displacements(i,node_index);
00309                 }
00310             }
00311         }
00312 
00313         double pressure = 0;
00314         for (unsigned vertex_index=0; vertex_index<NUM_VERTICES_PER_ELEMENT; vertex_index++)
00315         {
00316             pressure += linear_phi(vertex_index)*element_current_pressures(vertex_index);
00317         }
00318 
00319 
00321         // calculate C, inv(C) and T
00323         static c_matrix<double,DIM,DIM> F;
00324         static c_matrix<double,DIM,DIM> C;
00325         static c_matrix<double,DIM,DIM> inv_C;
00326         static c_matrix<double,DIM,DIM> inv_F;
00327         static c_matrix<double,DIM,DIM> T;
00328 
00329         for (unsigned i=0; i<DIM; i++)
00330         {
00331             for (unsigned M=0; M<DIM; M++)
00332             {
00333                 F(i,M) = (i==M?1:0) + grad_u(i,M);
00334             }
00335         }
00336 
00337         C = prod(trans(F),F);
00338         inv_C = Inverse(C);
00339         inv_F = Inverse(F);
00340 
00341         double detF = Determinant(F);
00342 
00343         p_material_law->ComputeStressAndStressDerivative(C,inv_C,pressure,T,this->dTdE,assembleJacobian);
00344 
00345         static FourthOrderTensor<DIM> dTdE_F;
00346         static FourthOrderTensor<DIM> dTdE_FF1;
00347         static FourthOrderTensor<DIM> dTdE_FF2;
00348 
00349         dTdE_F.SetAsProduct(this->dTdE, F, 1);  // B^{MdPQ}  = F^d_N * dTdE^{MdPQ}
00350         dTdE_FF1.SetAsProduct(dTdE_F, F, 3);    // B1^{MdPe} = F^d_N * F^e_Q * dTdE^{MNPQ}
00351         dTdE_FF2.SetAsProduct(dTdE_F, F, 2);    // B2^{MdeQ} = F^d_N * F^e_P * dTdE^{MNPQ}
00352 
00353 
00355         // residual vector
00357         if (assembleResidual)
00358         {
00359             for (unsigned index=0; index<NUM_NODES_PER_ELEMENT*DIM; index++)
00360             {
00361                 unsigned spatial_dim = index%DIM;
00362                 unsigned node_index = (index-spatial_dim)/DIM;
00363 
00364                 assert(node_index < NUM_NODES_PER_ELEMENT);
00365 
00366                 rBElem(index) +=  - this->mDensity
00367                                   * body_force(spatial_dim)
00368                                   * quad_phi(node_index)
00369                                   * wJ;
00370 
00371                 for (unsigned M=0; M<DIM; M++)
00372                 {
00373                     for (unsigned N=0; N<DIM; N++)
00374                     {
00375                         rBElem(index) +=   T(M,N)
00376                                          * F(spatial_dim,M)
00377                                          * grad_quad_phi(N,node_index)
00378                                          * wJ;
00379                     }
00380                 }
00381             }
00382 
00383             for (unsigned vertex_index=0; vertex_index<NUM_VERTICES_PER_ELEMENT; vertex_index++)
00384             {
00385                 rBElem( NUM_NODES_PER_ELEMENT*DIM + vertex_index ) +=   linear_phi(vertex_index)
00386                                                                       * (detF - 1)
00387                                                                       * wJ;
00388             }
00389         }
00390 
00392         // Jacobian matrix
00394         if (assembleJacobian)
00395         {
00396             for (unsigned index1=0; index1<NUM_NODES_PER_ELEMENT*DIM; index1++)
00397             {
00398                 unsigned spatial_dim1 = index1%DIM;
00399                 unsigned node_index1 = (index1-spatial_dim1)/DIM;
00400 
00401 
00402                 for (unsigned index2=0; index2<NUM_NODES_PER_ELEMENT*DIM; index2++)
00403                 {
00404                     unsigned spatial_dim2 = index2%DIM;
00405                     unsigned node_index2 = (index2-spatial_dim2)/DIM;
00406 
00407                     for (unsigned M=0; M<DIM; M++)
00408                     {
00409                         for (unsigned N=0; N<DIM; N++)
00410                         {
00411                             rAElem(index1,index2) +=   T(M,N)
00412                                                      * grad_quad_phi(M,node_index1)
00413                                                      * grad_quad_phi(N,node_index2)
00414                                                      * (spatial_dim1==spatial_dim2?1:0)
00415                                                      * wJ;
00416                         }
00417                     }
00418 
00419                     for (unsigned M=0; M<DIM; M++)
00420                     {
00421                         for (unsigned P=0; P<DIM; P++)
00422                         {
00423                             rAElem(index1,index2)  +=   0.5
00424                                                       * dTdE_FF1(M,spatial_dim1,P,spatial_dim2)
00425                                                       * grad_quad_phi(P,node_index2)
00426                                                       * grad_quad_phi(M,node_index1)
00427                                                       * wJ;
00428                         }
00429 
00430                         for (unsigned Q=0; Q<DIM; Q++)
00431                         {
00432                            rAElem(index1,index2)  +=   0.5
00433                                                      * dTdE_FF2(M,spatial_dim1,spatial_dim2,Q)
00434                                                      * grad_quad_phi(Q,node_index2)
00435                                                      * grad_quad_phi(M,node_index1)
00436                                                      * wJ;
00437                         }
00438                     }
00439                 }
00440 
00441                 for (unsigned vertex_index=0; vertex_index<NUM_VERTICES_PER_ELEMENT; vertex_index++)
00442                 {
00443                     unsigned index2 = NUM_NODES_PER_ELEMENT*DIM + vertex_index;
00444 
00445                     for (unsigned M=0; M<DIM; M++)
00446                     {
00447                          rAElem(index1,index2)  +=  - inv_F(M,spatial_dim1)
00448                                                     * grad_quad_phi(M,node_index1)
00449                                                     * linear_phi(vertex_index)
00450                                                     * wJ;
00451                     }
00452                 }
00453             }
00454 
00455             for (unsigned vertex_index=0; vertex_index<NUM_VERTICES_PER_ELEMENT; vertex_index++)
00456             {
00457                 unsigned index1 = NUM_NODES_PER_ELEMENT*DIM + vertex_index;
00458 
00459                 for (unsigned index2=0; index2<NUM_NODES_PER_ELEMENT*DIM; index2++)
00460                 {
00461                     unsigned spatial_dim2 = index2%DIM;
00462                     unsigned node_index2 = (index2-spatial_dim2)/DIM;
00463 
00464                     for (unsigned M=0; M<DIM; M++)
00465                     {
00466                         // same as (negative of) the opposite block (ie a few lines up), except for detF
00467                         rAElem(index1,index2) +=   detF
00468                                                  * inv_F(M,spatial_dim2)
00469                                                  * grad_quad_phi(M,node_index2)
00470                                                  * linear_phi(vertex_index)
00471                                                  * wJ;
00472                     }
00473                 }
00474 
00476                 // Preconditioner matrix
00477                 // Fill the mass matrix (ie \intgl phi_i phi_j) in the
00478                 // pressure-pressure block. Note, the rest of the
00479                 // entries are filled in at the end
00481                 for (unsigned vertex_index2=0; vertex_index2<NUM_VERTICES_PER_ELEMENT; vertex_index2++)
00482                 {
00483                     unsigned index2 = NUM_NODES_PER_ELEMENT*DIM + vertex_index2;
00484                     rAElemPrecond(index1,index2) +=   linear_phi(vertex_index)
00485                                                     * linear_phi(vertex_index2)
00486                                                     * wJ;
00487                 }
00488             }
00489         }
00490     }
00491 
00492     if (assembleJacobian)
00493     {
00494         // Fill in the other blocks of the preconditioner matrix, by adding 
00495         // the jacobian matrix (this doesn't effect the pressure-pressure block 
00496         // of rAElemPrecond as the pressure-pressure block of rAElem is zero),
00497         // and the zero a block.
00498         //
00499         // The following altogether gives the preconditioner  [ A  B1^T ]
00500         //                                                    [ 0  M    ]
00501 
00502         rAElemPrecond = rAElemPrecond + rAElem;
00503         for(unsigned i=NUM_NODES_PER_ELEMENT*DIM; i<STENCIL_SIZE; i++)
00504         {
00505             for(unsigned j=0; j<NUM_NODES_PER_ELEMENT*DIM; j++)
00506             {
00507                 rAElemPrecond(i,j) = 0.0;
00508             }
00509         }
00510     }
00511 }
00512 
00513 template<size_t DIM>
00514 void NonlinearElasticityAssembler<DIM>::AssembleOnBoundaryElement(
00515             BoundaryElement<DIM-1,DIM>& rBoundaryElement,
00516             c_matrix<double,BOUNDARY_STENCIL_SIZE,BOUNDARY_STENCIL_SIZE>& rAelem,
00517             c_vector<double,BOUNDARY_STENCIL_SIZE>& rBelem,
00518             c_vector<double,DIM>& rTraction,
00519             bool assembleResidual,
00520             bool assembleJacobian)
00521 {
00522     rAelem.clear();
00523     rBelem.clear();
00524 
00525     if (assembleJacobian && !assembleResidual)
00526     {
00527         // nothing to do
00528         return;
00529     }
00530 
00531     c_vector<double, DIM> weighted_direction;
00532     double jacobian_determinant;
00533     mpQuadMesh->GetWeightedDirectionForBoundaryElement(rBoundaryElement.GetIndex(), weighted_direction, jacobian_determinant);
00534 
00535     c_vector<double,NUM_NODES_PER_BOUNDARY_ELEMENT> phi;
00536 
00537     for (unsigned quad_index=0; quad_index<this->mpBoundaryQuadratureRule->GetNumQuadPoints(); quad_index++)
00538     {
00539         double wJ = jacobian_determinant * this->mpBoundaryQuadratureRule->GetWeight(quad_index);
00540 
00541         const ChastePoint<DIM-1>& quad_point = this->mpBoundaryQuadratureRule->rGetQuadPoint(quad_index);
00542 
00543         QuadraticBasisFunction<DIM-1>::ComputeBasisFunctions(quad_point, phi);
00544 
00545         // get the required traction, interpolating X (slightly inefficiently, as interpolating
00546         // using quad bases) if necessary.
00547         c_vector<double,DIM> traction = zero_vector<double>(DIM);
00548         if (this->mUsingTractionBoundaryConditionFunction)
00549         {
00550             c_vector<double,DIM> X = zero_vector<double>(DIM);
00551             for (unsigned node_index=0; node_index<NUM_NODES_PER_BOUNDARY_ELEMENT; node_index++)
00552             {
00553                 X += phi(node_index)*mpQuadMesh->GetNode( rBoundaryElement.GetNodeGlobalIndex(node_index) )->rGetLocation();
00554             }
00555             traction = (*(this->mpTractionBoundaryConditionFunction))(X);
00556         }
00557         else
00558         {
00559             traction = rTraction;
00560         }
00561 
00562 
00563         for (unsigned index=0; index<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index++)
00564         {
00565             unsigned spatial_dim = index%DIM;
00566             unsigned node_index = (index-spatial_dim)/DIM;
00567 
00568             assert(node_index < NUM_NODES_PER_BOUNDARY_ELEMENT);
00569 
00570             rBelem(index) -=    traction(spatial_dim)
00571                               * phi(node_index)
00572                               * wJ;
00573         }
00574     }
00575 }
00576 
00577 template<size_t DIM>
00578 void NonlinearElasticityAssembler<DIM>::FormInitialGuess()
00579 {
00580     this->mCurrentSolution.resize(this->mNumDofs, 0.0);
00581 
00582     for (unsigned i=0; i<mpQuadMesh->GetNumElements(); i++)
00583     {
00584         double zero_strain_pressure;
00585         if (this->mMaterialLaws.size()==1)
00586         {
00587             // homogeneous
00588             zero_strain_pressure = this->mMaterialLaws[0]->GetZeroStrainPressure();
00589         }
00590         else
00591         {
00592             // heterogeneous
00593             zero_strain_pressure = this->mMaterialLaws[i]->GetZeroStrainPressure();
00594         }
00595 
00596         // loop over vertices and set pressure solution to be zero-strain-pressure
00597         for (unsigned j=0; j<NUM_VERTICES_PER_ELEMENT; j++)
00598         {
00599             unsigned index = mpQuadMesh->GetElement(i)->GetNodeGlobalIndex(j);
00600             this->mCurrentSolution[ DIM*mpQuadMesh->GetNumNodes() + index ] = zero_strain_pressure;
00601         }
00602     }
00603 }
00604 
00605 template<size_t DIM>
00606 void NonlinearElasticityAssembler<DIM>::Initialise(std::vector<c_vector<double,DIM> >* pFixedNodeLocations)
00607 {
00608     assert(mpQuadMesh);
00609 
00610     AllocateMatrixMemory();
00611 
00612     for (unsigned i=0; i<this->mFixedNodes.size(); i++)
00613     {
00614         assert(this->mFixedNodes[i] < mpQuadMesh->GetNumNodes());
00615     }
00616 
00617     this->mpQuadratureRule = new GaussianQuadratureRule<DIM>(3);
00618     this->mpBoundaryQuadratureRule = new GaussianQuadratureRule<DIM-1>(3);
00619 
00620     FormInitialGuess();
00621 
00622     // compute the displacements at each of the fixed nodes, given the
00623     // fixed nodes locations.
00624     if (pFixedNodeLocations == NULL)
00625     {
00626         this->mFixedNodeDisplacements.clear();
00627         for (unsigned i=0; i<this->mFixedNodes.size(); i++)
00628         {
00629             this->mFixedNodeDisplacements.push_back(zero_vector<double>(DIM));
00630         }
00631     }
00632     else
00633     {
00634         assert(pFixedNodeLocations->size()==this->mFixedNodes.size());
00635         for (unsigned i=0; i<this->mFixedNodes.size(); i++)
00636         {
00637             unsigned index = this->mFixedNodes[i];
00638             c_vector<double,DIM> displacement = (*pFixedNodeLocations)[i]-mpQuadMesh->GetNode(index)->rGetLocation();
00639             this->mFixedNodeDisplacements.push_back(displacement);
00640         }
00641     }
00642     assert(this->mFixedNodeDisplacements.size()==this->mFixedNodes.size());
00643 }
00644 
00645 template<size_t DIM>
00646 void NonlinearElasticityAssembler<DIM>::AllocateMatrixMemory()
00647 {
00648 
00650     // without leaking memory. This is the call to preallocate an MPI AIJ matrix:
00651     // MatSeqAIJSetPreallocation(mpLinearSystem->rGetLhsMatrix(), num_non_zeros, PETSC_NULL, (PetscInt) (num_non_zeros*0.5), PETSC_NULL);
00652 
00653     this->mpLinearSystem = new LinearSystem(this->mNumDofs, (MatType)MATAIJ); // default Mat type is MATMPIAIJ, see above
00654     this->mpPreconditionMatrixLinearSystem = new LinearSystem(this->mNumDofs, (MatType)MATAIJ); //MATAIJ is needed for precond to work
00655 
00656     // 3D: N elements around a point. nz < (3*10+6)N (lazy estimate). Better estimate is 23N+4?. Assume N<20 => 500ish
00657 
00658     if(DIM==2)
00659     {
00660         // 2D: N elements around a point => 7N+3 non-zeros in that row? Assume N<=10 (structured mesh would have N_max=6) => 73.
00661         unsigned num_non_zeros = 75;
00662 
00663         if(PetscTools::GetNumProcs()==1)
00664         {
00665             MatSeqAIJSetPreallocation(this->mpLinearSystem->rGetLhsMatrix(),                   num_non_zeros, PETSC_NULL);
00666             MatSeqAIJSetPreallocation(this->mpPreconditionMatrixLinearSystem->rGetLhsMatrix(), num_non_zeros, PETSC_NULL);
00667         }
00668         else
00669         {
00670             MatMPIAIJSetPreallocation(this->mpLinearSystem->rGetLhsMatrix(), num_non_zeros, PETSC_NULL, num_non_zeros, PETSC_NULL);
00671             MatMPIAIJSetPreallocation(this->mpPreconditionMatrixLinearSystem->rGetLhsMatrix(), num_non_zeros, PETSC_NULL, num_non_zeros, PETSC_NULL);
00672         }
00673     }
00674     else
00675     {
00676         assert(DIM==3);
00677 
00678         // in 3d we get the number of containing elements for each node and use that to obtain an upper bound
00679         // for the number of non-zeros for each DOF associated with that node.
00680 
00681         int* num_non_zeros_each_row = new int[this->mNumDofs];
00682         for(unsigned i=0; i<this->mNumDofs; i++)
00683         {
00684             num_non_zeros_each_row[i] = 0;
00685         }
00686 
00687         for(unsigned i=0; i<mpQuadMesh->GetNumNodes(); i++)
00688         {
00689             // this upper bound neglects the fact that two containing elements will share the same nodes..
00690             // 4 = max num dofs associated with this node
00691             // 30 = 3*9+3 = 3 dimensions x 9 other nodes on this element   +  3 vertices with a pressure unknown
00692             unsigned num_non_zeros_upper_bound = 4 + 30*mpQuadMesh->GetNode(i)->GetNumContainingElements();
00693 
00694             num_non_zeros_each_row[DIM*i + 0] = num_non_zeros_upper_bound;
00695             num_non_zeros_each_row[DIM*i + 1] = num_non_zeros_upper_bound;
00696             num_non_zeros_each_row[DIM*i + 2] = num_non_zeros_upper_bound;
00697 
00698             if(i<mpQuadMesh->GetNumVertices()) // then this is a vertex
00699             {
00700                 num_non_zeros_each_row[DIM*mpQuadMesh->GetNumNodes() + i] = num_non_zeros_upper_bound;
00701             }
00702         }
00703 
00704         if(PetscTools::GetNumProcs()==1)
00705         {
00706             MatSeqAIJSetPreallocation(this->mpLinearSystem->rGetLhsMatrix(),                   PETSC_NULL, num_non_zeros_each_row);
00707             MatSeqAIJSetPreallocation(this->mpPreconditionMatrixLinearSystem->rGetLhsMatrix(), PETSC_NULL, num_non_zeros_each_row);
00708         }
00709         else
00710         {
00711             PetscInt lo, hi;
00712             this->mpLinearSystem->GetOwnershipRange(lo, hi);
00713             int* num_non_zeros_each_row_this_proc = new int[hi-lo];
00714             for(unsigned i=0; i<unsigned(hi-lo); i++)
00715             {
00716                 num_non_zeros_each_row_this_proc[i] = num_non_zeros_each_row[lo+i];
00717             }
00718 
00719             MatMPIAIJSetPreallocation(this->mpLinearSystem->rGetLhsMatrix(), PETSC_NULL, num_non_zeros_each_row_this_proc, PETSC_NULL, num_non_zeros_each_row_this_proc);
00720             MatMPIAIJSetPreallocation(this->mpPreconditionMatrixLinearSystem->rGetLhsMatrix(), PETSC_NULL, num_non_zeros_each_row_this_proc, PETSC_NULL, num_non_zeros_each_row_this_proc);
00721         }
00722 
00723         //unsigned total_non_zeros = 0;
00724         //for(unsigned i=0; i<this->mNumDofs; i++)
00725         //{
00726         //   total_non_zeros += num_non_zeros_each_row[i];
00727         //}
00728         //std::cout << total_non_zeros << " versus " << 500*this->mNumDofs << "\n" << std::flush;
00729 
00730         delete [] num_non_zeros_each_row;
00731     }
00732 }
00733 
00734 
00735 
00736 template<size_t DIM>
00737 NonlinearElasticityAssembler<DIM>::NonlinearElasticityAssembler(
00738             QuadraticMesh<DIM>* pQuadMesh,
00739             AbstractIncompressibleMaterialLaw<DIM>* pMaterialLaw,
00740             c_vector<double,DIM> bodyForce,
00741             double density,
00742             std::string outputDirectory,
00743             std::vector<unsigned>& fixedNodes,
00744             std::vector<c_vector<double,DIM> >* pFixedNodeLocations)
00745     : AbstractNonlinearElasticityAssembler<DIM>(DIM*pQuadMesh->GetNumNodes()+pQuadMesh->GetNumVertices(),
00746                                                 pMaterialLaw, bodyForce, density,
00747                                                 outputDirectory, fixedNodes),
00748       mpQuadMesh(pQuadMesh)
00749 {
00750     Initialise(pFixedNodeLocations);
00751 }
00752 
00753 
00754 template<size_t DIM>
00755 NonlinearElasticityAssembler<DIM>::NonlinearElasticityAssembler(
00756             QuadraticMesh<DIM>* pQuadMesh,
00757             std::vector<AbstractIncompressibleMaterialLaw<DIM>*>& rMaterialLaws,
00758             c_vector<double,DIM> bodyForce,
00759             double density,
00760             std::string outputDirectory,
00761             std::vector<unsigned>& fixedNodes,
00762             std::vector<c_vector<double,DIM> >* pFixedNodeLocations)
00763     : AbstractNonlinearElasticityAssembler<DIM>(DIM*pQuadMesh->GetNumNodes()+pQuadMesh->GetNumVertices(),
00764                                                 rMaterialLaws, bodyForce, density,
00765                                                 outputDirectory, fixedNodes),
00766       mpQuadMesh(pQuadMesh)
00767 {
00768     assert(rMaterialLaws.size()==pQuadMesh->GetNumElements());
00769     Initialise(pFixedNodeLocations);
00770 }
00771 
00772 
00773 template<size_t DIM>
00774 NonlinearElasticityAssembler<DIM>::~NonlinearElasticityAssembler()
00775 {
00776     delete mpQuadratureRule;
00777     delete mpBoundaryQuadratureRule;
00778 }
00779 
00780 template<size_t DIM>
00781 void NonlinearElasticityAssembler<DIM>::SetSurfaceTractionBoundaryConditions(
00782             std::vector<BoundaryElement<DIM-1,DIM>*>& rBoundaryElements,
00783             std::vector<c_vector<double,DIM> >& rSurfaceTractions)
00784 {
00785     assert(rBoundaryElements.size()==rSurfaceTractions.size());
00786     mBoundaryElements = rBoundaryElements;
00787     this->mSurfaceTractions = rSurfaceTractions;
00788 }
00789 
00790 template<size_t DIM>
00791 void NonlinearElasticityAssembler<DIM>::SetFunctionalTractionBoundaryCondition(
00792             std::vector<BoundaryElement<DIM-1,DIM>*> rBoundaryElements,
00793             c_vector<double,DIM> (*pFunction)(c_vector<double,DIM>&))
00794 {
00795     mBoundaryElements = rBoundaryElements;
00796     this->mUsingTractionBoundaryConditionFunction = true;
00797     this->mpTractionBoundaryConditionFunction = pFunction;
00798 }
00799 
00800 template<size_t DIM>
00801 std::vector<double>& NonlinearElasticityAssembler<DIM>::rGetPressures()
00802 {
00803     this->mPressures.clear();
00804     this->mPressures.resize(mpQuadMesh->GetNumVertices());
00805 
00806     for (unsigned i=0; i<mpQuadMesh->GetNumVertices(); i++)
00807     {
00808         this->mPressures[i] = this->mCurrentSolution[DIM*mpQuadMesh->GetNumNodes() + i];
00809     }
00810     return this->mPressures;
00811 }
00812 
00813 template<size_t DIM>
00814 std::vector<c_vector<double,DIM> >& NonlinearElasticityAssembler<DIM>::rGetDeformedPosition()
00815 {
00816     this->mDeformedPosition.resize(mpQuadMesh->GetNumNodes(), zero_vector<double>(DIM));
00817     for (unsigned i=0; i<mpQuadMesh->GetNumNodes(); i++)
00818     {
00819         for (unsigned j=0; j<DIM; j++)
00820         {
00821             this->mDeformedPosition[i](j) = mpQuadMesh->GetNode(i)->rGetLocation()[j] + this->mCurrentSolution[DIM*i+j];
00822         }
00823     }
00824     return this->mDeformedPosition;
00825 }
00826 
00827 
00829 // Explicit instantiation
00831 
00832 //template class NonlinearElasticityAssembler<1>;
00833 template class NonlinearElasticityAssembler<2>;
00834 template class NonlinearElasticityAssembler<3>;

Generated by  doxygen 1.6.2