CompressibleNonlinearElasticitySolver.cpp

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 
00030 
00031 /*
00032  * NOTE ON COMPILATION ERRORS:
00033  *
00034  * (The following applies to NonlinearElasticityAssembler; possibly/probably holds for this class too).
00035  *
00036  * This file won't compile with Intel icpc version 9.1.039, with error message:
00037  * "Terminate with:
00038   (0): internal error: backend signals"
00039  *
00040  * Try recompiling with icpc version 10.0.025.
00041  */
00042 
00043 #include "CompressibleNonlinearElasticitySolver.hpp"
00044 #include "LinearBasisFunction.hpp"
00045 #include "QuadraticBasisFunction.hpp"
00046 #include <algorithm>
00047 
00048 template<size_t DIM>
00049 void CompressibleNonlinearElasticitySolver<DIM>::AssembleSystem(bool assembleResidual,
00050                                                                 bool assembleJacobian)
00051 {
00052     // Check we've actually been asked to do something!
00053     assert(assembleResidual || assembleJacobian);
00054     assert(this->mCurrentSolution.size()==this->mNumDofs);
00055 
00056     // Zero the matrix/vector if it is to be assembled
00057     if (assembleResidual)
00058     {
00059         PetscVecTools::Zero(this->mResidualVector);
00060     }
00061     if (assembleJacobian)
00062     {
00063         PetscMatTools::Zero(this->mJacobianMatrix);
00064         PetscMatTools::Zero(this->mPreconditionMatrix);
00065     }
00066 
00067     c_matrix<double, STENCIL_SIZE, STENCIL_SIZE> a_elem;
00068     // the (element) preconditioner matrix: this is the same as the jacobian, but
00069     // with the mass matrix (ie \intgl phi_i phi_j) in the pressure-pressure block.
00070     c_matrix<double, STENCIL_SIZE, STENCIL_SIZE> a_elem_precond;
00071     c_vector<double, STENCIL_SIZE> b_elem;
00072 
00074     // loop over elements
00076     for (typename AbstractTetrahedralMesh<DIM, DIM>::ElementIterator iter = this->mpQuadMesh->GetElementIteratorBegin();
00077          iter != this->mpQuadMesh->GetElementIteratorEnd();
00078          ++iter)
00079     {
00080         #ifdef MECH_VERY_VERBOSE
00081         if (assembleJacobian) // && ((*iter).GetIndex()%500==0))
00082         {
00083             std::cout << "\r[" << PetscTools::GetMyRank() << "]: Element " << (*iter).GetIndex() << " of " << this->mpQuadMesh->GetNumElements() << std::flush;
00084         }
00085         #endif
00086 
00087         Element<DIM, DIM>& element = *iter;
00088 
00089         if (element.GetOwnership() == true)
00090         {
00091             AssembleOnElement(element, a_elem, a_elem_precond, b_elem, assembleResidual, assembleJacobian);
00092             
00096             //for(unsigned i=0; i<STENCIL_SIZE; i++)
00097             //{
00098             //    for(unsigned j=0; j<STENCIL_SIZE; j++)
00099             //    {
00100             //        a_elem(i,j)=1.0;
00101             //    }
00102             //}
00103             
00104 
00105             unsigned p_indices[STENCIL_SIZE];
00106             for (unsigned i=0; i<NUM_NODES_PER_ELEMENT; i++)
00107             {
00108                 for (unsigned j=0; j<DIM; j++)
00109                 {
00110                     p_indices[DIM*i+j] = DIM*element.GetNodeGlobalIndex(i) + j;
00111                 }
00112             }
00113 
00114             if (assembleJacobian)
00115             {
00116                 PetscMatTools::AddMultipleValues<STENCIL_SIZE>(this->mJacobianMatrix, p_indices, a_elem);
00117                 PetscMatTools::AddMultipleValues<STENCIL_SIZE>(this->mPreconditionMatrix, p_indices, a_elem_precond);
00118             }
00119 
00120             if (assembleResidual)
00121             {
00122                 PetscVecTools::AddMultipleValues<STENCIL_SIZE>(this->mResidualVector, p_indices, b_elem);
00123             }
00124         }
00125     }
00126 
00128     // loop over specified boundary elements and compute
00129     // surface traction terms
00131     c_vector<double, BOUNDARY_STENCIL_SIZE> b_boundary_elem;
00132     c_matrix<double, BOUNDARY_STENCIL_SIZE, BOUNDARY_STENCIL_SIZE> a_boundary_elem;
00133     if (this->mBoundaryElements.size()>0)
00134     {
00135         for (unsigned i=0; i<this->mBoundaryElements.size(); i++)
00136         {
00137             BoundaryElement<DIM-1,DIM>& r_boundary_element = *(this->mBoundaryElements[i]);
00138             AssembleOnBoundaryElement(r_boundary_element, a_boundary_elem, b_boundary_elem, this->mSurfaceTractions[i], assembleResidual, assembleJacobian);
00139 
00140             unsigned p_indices[BOUNDARY_STENCIL_SIZE];
00141             for (unsigned i=0; i<NUM_NODES_PER_BOUNDARY_ELEMENT; i++)
00142             {
00143                 for (unsigned j=0; j<DIM; j++)
00144                 {
00145                     p_indices[DIM*i+j] = DIM*r_boundary_element.GetNodeGlobalIndex(i) + j;
00146                 }
00147             }
00148 
00149             if (assembleJacobian)
00150             {
00151                 PetscMatTools::AddMultipleValues<BOUNDARY_STENCIL_SIZE>(this->mJacobianMatrix, p_indices, a_boundary_elem);
00152                 PetscMatTools::AddMultipleValues<BOUNDARY_STENCIL_SIZE>(this->mPreconditionMatrix, p_indices, a_boundary_elem);
00153             }
00154 
00155             if (assembleResidual)
00156             {
00157                 PetscVecTools::AddMultipleValues<BOUNDARY_STENCIL_SIZE>(this->mResidualVector, p_indices, b_boundary_elem);
00158             }
00159         }
00160     }
00161 
00162     this->FinishAssembleSystem(assembleResidual, assembleJacobian);
00163 }
00164 
00165 template<size_t DIM>
00166 void CompressibleNonlinearElasticitySolver<DIM>::AssembleOnElement(
00167             Element<DIM, DIM>& rElement,
00168             c_matrix<double, STENCIL_SIZE, STENCIL_SIZE >& rAElem,
00169             c_matrix<double, STENCIL_SIZE, STENCIL_SIZE >& rAElemPrecond,
00170             c_vector<double, STENCIL_SIZE>& rBElem,
00171             bool assembleResidual,
00172             bool assembleJacobian)
00173 {
00174     static c_matrix<double,DIM,DIM> jacobian;
00175     static c_matrix<double,DIM,DIM> inverse_jacobian;
00176     double jacobian_determinant;
00177     
00178     this->mpQuadMesh->GetInverseJacobianForElement(rElement.GetIndex(), jacobian, jacobian_determinant, inverse_jacobian);
00179 
00180     if (assembleJacobian)
00181     {
00182         rAElem.clear();
00183         rAElemPrecond.clear();
00184     }
00185 
00186     if (assembleResidual)
00187     {
00188         rBElem.clear();
00189     }
00190 
00192     // Get the current displacement at the nodes
00194     static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> element_current_displacements;
00195     for (unsigned II=0; II<NUM_NODES_PER_ELEMENT; II++)
00196     {
00197         for (unsigned JJ=0; JJ<DIM; JJ++)
00198         {
00199             element_current_displacements(JJ,II) = this->mCurrentSolution[DIM*rElement.GetNodeGlobalIndex(II) + JJ];
00200         }
00201     }
00202 
00203     // allocate memory for the basis functions values and derivative values
00204     static c_vector<double, NUM_VERTICES_PER_ELEMENT> linear_phi;
00205     static c_vector<double, NUM_NODES_PER_ELEMENT> quad_phi;
00206     static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi;
00207     static c_matrix<double, NUM_NODES_PER_ELEMENT, DIM> trans_grad_quad_phi;
00208 
00209 
00210     // get the material law
00211     AbstractCompressibleMaterialLaw<DIM>* p_material_law;
00212     if (this->mMaterialLaws.size()==1)
00213     {
00214         // homogeneous
00215         p_material_law = this->mMaterialLaws[0];
00216     }
00217     else
00218     {
00219         // heterogeneous
00220         #define COVERAGE_IGNORE // not going to have tests in cts for everything
00221         p_material_law = this->mMaterialLaws[rElement.GetIndex()];
00222         #undef COVERAGE_IGNORE
00223     }
00224     
00225     
00226     static c_matrix<double,DIM,DIM> grad_u; // grad_u = (du_i/dX_M)
00227             
00228     static c_matrix<double,DIM,DIM> F;      // the deformation gradient, F = dx/dX, F_{iM} = dx_i/dX_M
00229     static c_matrix<double,DIM,DIM> C;      // Green deformation tensor, C = F^T F
00230     static c_matrix<double,DIM,DIM> inv_C;  // inverse(C)
00231     static c_matrix<double,DIM,DIM> inv_F;  // inverse(F)
00232     static c_matrix<double,DIM,DIM> T;      // Second Piola-Kirchoff stress tensor (= dW/dE = 2dW/dC) 
00233 
00234     static c_matrix<double,DIM,DIM> F_T;    // F*T
00235     static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> F_T_grad_quad_phi; // F*T*grad_quad_phi
00236 
00237     c_vector<double,DIM> body_force;
00238 
00239     static FourthOrderTensor<DIM,DIM,DIM,DIM> dTdE;    // dTdE(M,N,P,Q) = dT_{MN}/dE_{PQ} 
00240     static FourthOrderTensor<DIM,DIM,DIM,DIM> dSdF;    // dSdF(M,i,N,j) = dS_{Mi}/dF_{jN} 
00241 
00242     static FourthOrderTensor<NUM_NODES_PER_ELEMENT,DIM,DIM,DIM> temp_tensor;
00243     static FourthOrderTensor<NUM_NODES_PER_ELEMENT,DIM,NUM_NODES_PER_ELEMENT,DIM> dSdF_quad_quad;
00244 
00245     static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> temp_matrix;
00246     static c_matrix<double,NUM_NODES_PER_ELEMENT,DIM> grad_quad_phi_times_invF;
00247 
00248 
00249 
00255     for (unsigned quadrature_index=0; quadrature_index < this->mpQuadratureRule->GetNumQuadPoints(); quadrature_index++)
00256     {
00257         // this is needed by the cardiac mechanics solver
00258         unsigned current_quad_point_global_index =   rElement.GetIndex()*this->mpQuadratureRule->GetNumQuadPoints()
00259                                                    + quadrature_index;
00260 
00261         double wJ = jacobian_determinant * this->mpQuadratureRule->GetWeight(quadrature_index);
00262 
00263         const ChastePoint<DIM>& quadrature_point = this->mpQuadratureRule->rGetQuadPoint(quadrature_index);
00264 
00266         // set up basis function info
00268         LinearBasisFunction<DIM>::ComputeBasisFunctions(quadrature_point, linear_phi);
00269         QuadraticBasisFunction<DIM>::ComputeBasisFunctions(quadrature_point, quad_phi);
00270         QuadraticBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(quadrature_point, inverse_jacobian, grad_quad_phi);
00271         trans_grad_quad_phi = trans(grad_quad_phi);
00272         
00273         
00275         // get the body force, interpolating X if necessary
00277 
00278         if(assembleResidual)
00279         {
00280             if (this->mUsingBodyForceFunction)
00281             {
00282                 c_vector<double,DIM> X = zero_vector<double>(DIM);
00283                 // interpolate X (using the vertices and the /linear/ bases, as no curvilinear elements
00284                 for (unsigned node_index=0; node_index<NUM_VERTICES_PER_ELEMENT; node_index++)
00285                 {
00286                     X += linear_phi(node_index)*this->mpQuadMesh->GetNode( rElement.GetNodeGlobalIndex(node_index) )->rGetLocation();
00287                 }
00288                 body_force = (*(this->mpBodyForceFunction))(X, this->mCurrentTime);
00289             }
00290             else
00291             {
00292                 body_force = this->mBodyForce;
00293             }
00294         }
00295 
00297         // interpolate grad_u
00299         grad_u = zero_matrix<double>(DIM,DIM); 
00300 
00301         for (unsigned node_index=0; node_index<NUM_NODES_PER_ELEMENT; node_index++)
00302         {
00303             for (unsigned i=0; i<DIM; i++)
00304             {
00305                 for (unsigned M=0; M<DIM; M++)
00306                 {
00307                     grad_u(i,M) += grad_quad_phi(M,node_index)*element_current_displacements(i,node_index);
00308                 }
00309             }
00310         }
00311 
00312 
00314         // calculate C, inv(C) and T
00316         for (unsigned i=0; i<DIM; i++)
00317         {
00318             for (unsigned M=0; M<DIM; M++)
00319             {
00320                 F(i,M) = (i==M?1:0) + grad_u(i,M);
00321             }
00322         }
00323 
00324         C = prod(trans(F),F);
00325         inv_C = Inverse(C);
00326         inv_F = Inverse(F);
00327 
00328         this->ComputeStressAndStressDerivative(p_material_law, C, inv_C, 0.0, rElement.GetIndex(), current_quad_point_global_index,
00329                                                T, dTdE, assembleJacobian);
00330 
00331 
00333         // residual vector
00335         if (assembleResidual)
00336         {
00337             F_T = prod(F,T);
00338             F_T_grad_quad_phi = prod(F_T, grad_quad_phi);
00339             
00340             for (unsigned index=0; index<NUM_NODES_PER_ELEMENT*DIM; index++)
00341             {
00342                 unsigned spatial_dim = index%DIM;
00343                 unsigned node_index = (index-spatial_dim)/DIM;
00344 
00345                 rBElem(index) +=  - this->mDensity
00346                                   * body_force(spatial_dim)
00347                                   * quad_phi(node_index)
00348                                   * wJ;
00349                                   
00350                 // the  T(M,N)*F(spatial_dim,M)*grad_quad_phi(N,node_index)  term                  
00351                 rBElem(index) +=   F_T_grad_quad_phi(spatial_dim,node_index)
00352                                  * wJ;
00353             }
00354         }
00355         
00356         
00358         // Jacobian matrix
00360         if (assembleJacobian) 
00361         {
00362             // save trans(grad_quad_phi) * invF
00363             grad_quad_phi_times_invF = prod(trans_grad_quad_phi, inv_F);
00364             
00366             // Set up the tensor dSdF
00367             //
00368             // dSdF as a function of T and dTdE (which is what the material law returns) is given by:
00369             //
00370             // dS_{Mi}/dF_{jN} = (dT_{MN}/dC_{PQ}+dT_{MN}/dC_{PQ}) F{iP} F_{jQ}  + T_{MN} delta_{ij}
00371             //
00372             // todo1: this should probably move into the material law (but need to make sure 
00373             // memory is handled efficiently
00374             // todo2: get material law to return this immediately, not dTdE
00376 
00377             // set up the tensor 0.5(dTdE(M,N,P,Q) + dTdE(M,N,Q,P))
00378             for (unsigned M=0; M<DIM; M++)
00379             {
00380                 for (unsigned N=0; N<DIM; N++)
00381                 {
00382                     for (unsigned P=0; P<DIM; P++)
00383                     {
00384                         for (unsigned Q=0; Q<DIM; Q++)
00385                         {
00386                             // this is NOT dSdF, just using this as storage space
00387                             dSdF(M,N,P,Q) = 0.5*(dTdE(M,N,P,Q) + dTdE(M,N,Q,P));
00388                         }
00389                     }
00390                 }
00391             }
00392             // This is NOT dTdE, just reusing memory. A^{MdPQ}  = F^d_N * dTdE_sym^{MNPQ}
00393             dTdE.template SetAsContractionOnSecondDimension<DIM>(F, dSdF);  
00394             // dSdF{MdPe} := F^d_N * F^e_Q * dTdE_sym^{MNPQ}
00395             dSdF.template SetAsContractionOnFourthDimension<DIM>(F, dTdE);  
00396             
00397             // now add the T_{MN} delta_{ij} term
00398             for(unsigned M=0; M<DIM; M++)
00399             {
00400                 for(unsigned N=0; N<DIM; N++)
00401                 {
00402                     for(unsigned i=0; i<DIM; i++)
00403                     {
00404                         dSdF(M,i,N,i) += T(M,N);
00405                     }
00406                 }
00407             }
00408             
00409 
00411             // Set up the tensor  
00412             //   dSdF_quad_quad(node_index1, spatial_dim1, node_index2, spatial_dim2)
00413             //            =    dS_{M,spatial_dim1}/d_F{spatial_dim2,N}      
00414             //               * grad_quad_phi(M,node_index1) 
00415             //               * grad_quad_phi(P,node_index2)
00416             //
00417             //            =    dSdF(M,spatial_index1,N,spatial_index2)
00418             //               * grad_quad_phi(M,node_index1) 
00419             //               * grad_quad_phi(P,node_index2)
00420             //            
00422             temp_tensor.template SetAsContractionOnFirstDimension<DIM>( trans_grad_quad_phi, dSdF );
00423             dSdF_quad_quad.template SetAsContractionOnThirdDimension<DIM>( trans_grad_quad_phi, temp_tensor );
00424 
00425 
00426 
00427 
00428             for (unsigned index1=0; index1<NUM_NODES_PER_ELEMENT*DIM; index1++)
00429             {
00430                 unsigned spatial_dim1 = index1%DIM;
00431                 unsigned node_index1 = (index1-spatial_dim1)/DIM;
00432 
00433 
00434                 for (unsigned index2=0; index2<NUM_NODES_PER_ELEMENT*DIM; index2++)
00435                 {
00436                     unsigned spatial_dim2 = index2%DIM;
00437                     unsigned node_index2 = (index2-spatial_dim2)/DIM;
00438 
00439                     // the dSdF*grad_quad_phi*grad_quad_phi term
00440                     rAElem(index1,index2)  +=   dSdF_quad_quad(node_index1,spatial_dim1,node_index2,spatial_dim2)
00441                                               * wJ;
00442                 }
00443             }
00444         }
00445     }
00446 
00447     rAElemPrecond.clear();
00448     if (assembleJacobian)
00449     {
00450 //        for(unsigned index1=0; index1<NUM_NODES_PER_ELEMENT; index1++)
00451 //        {
00452 //            for(unsigned index2=0; index2<NUM_NODES_PER_ELEMENT; index2++)
00453 //            {
00454 //                for(unsigned dim=0; dim<DIM; dim++)
00455 //                {
00456 //                    rAElemPrecond(NUM_NODES_PER_ELEMENT*dim + index1, NUM_NODES_PER_ELEMENT*dim + index2)
00457 //                        = rAElem(NUM_NODES_PER_ELEMENT*dim + index1, NUM_NODES_PER_ELEMENT*dim + index2);
00458 //                }
00459 //            }
00460 //        }
00461         rAElemPrecond = rAElem;
00462     }
00463 }
00464 
00465 
00466 
00467 template<size_t DIM>
00468 void CompressibleNonlinearElasticitySolver<DIM>::AssembleOnBoundaryElement(
00469             BoundaryElement<DIM-1,DIM>& rBoundaryElement,
00470             c_matrix<double,BOUNDARY_STENCIL_SIZE,BOUNDARY_STENCIL_SIZE>& rAelem,
00471             c_vector<double,BOUNDARY_STENCIL_SIZE>& rBelem,
00472             c_vector<double,DIM>& rTraction,
00473             bool assembleResidual,
00474             bool assembleJacobian)
00475 {
00476     rAelem.clear();
00477     rBelem.clear();
00478 
00479     if (assembleJacobian && !assembleResidual)
00480     {
00481         // nothing to do
00482         return;
00483     }
00484 
00485     c_vector<double, DIM> weighted_direction;
00486     double jacobian_determinant;
00487     this->mpQuadMesh->GetWeightedDirectionForBoundaryElement(rBoundaryElement.GetIndex(), weighted_direction, jacobian_determinant);
00488 
00489     c_vector<double,NUM_NODES_PER_BOUNDARY_ELEMENT> phi;
00490 
00491     for (unsigned quad_index=0; quad_index<this->mpBoundaryQuadratureRule->GetNumQuadPoints(); quad_index++)
00492     {
00493         double wJ = jacobian_determinant * this->mpBoundaryQuadratureRule->GetWeight(quad_index);
00494 
00495         const ChastePoint<DIM-1>& quad_point = this->mpBoundaryQuadratureRule->rGetQuadPoint(quad_index);
00496 
00497         QuadraticBasisFunction<DIM-1>::ComputeBasisFunctions(quad_point, phi);
00498 
00499         // get the required traction, interpolating X (slightly inefficiently, as interpolating
00500         // using quad bases) if necessary.
00501         c_vector<double,DIM> traction = zero_vector<double>(DIM);
00502         if (this->mUsingTractionBoundaryConditionFunction)
00503         {
00504             c_vector<double,DIM> X = zero_vector<double>(DIM);
00505             for (unsigned node_index=0; node_index<NUM_NODES_PER_BOUNDARY_ELEMENT; node_index++)
00506             {
00507                 X += phi(node_index)*this->mpQuadMesh->GetNode( rBoundaryElement.GetNodeGlobalIndex(node_index) )->rGetLocation();
00508             }
00509             traction = (*(this->mpTractionBoundaryConditionFunction))(X, this->mCurrentTime);
00510         }
00511         else
00512         {
00513             traction = rTraction;
00514         }
00515 
00516 
00517         for (unsigned index=0; index<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index++)
00518         {
00519             unsigned spatial_dim = index%DIM;
00520             unsigned node_index = (index-spatial_dim)/DIM;
00521 
00522             assert(node_index < NUM_NODES_PER_BOUNDARY_ELEMENT);
00523 
00524             rBelem(index) -=    traction(spatial_dim)
00525                               * phi(node_index)
00526                               * wJ;
00527         }
00528     }
00529 }
00530 
00531 
00532 
00533 template<size_t DIM>
00534 CompressibleNonlinearElasticitySolver<DIM>::CompressibleNonlinearElasticitySolver(
00535             QuadraticMesh<DIM>* pQuadMesh,
00536             AbstractMaterialLaw<DIM>* pMaterialLaw,
00537             c_vector<double,DIM> bodyForce,
00538             double density,
00539             std::string outputDirectory,
00540             std::vector<unsigned>& fixedNodes,
00541             std::vector<c_vector<double,DIM> >* pFixedNodeLocations)
00542     : AbstractNonlinearElasticitySolver<DIM>(pQuadMesh,
00543                                              bodyForce, density,
00544                                              outputDirectory, fixedNodes,
00545                                              COMPRESSIBLE)
00546 {
00547     assert(pMaterialLaw != NULL);
00548 
00549     AbstractCompressibleMaterialLaw<DIM>* p_law = dynamic_cast<AbstractCompressibleMaterialLaw<DIM>*>(pMaterialLaw);
00550     if(!p_law)
00551     {
00552         EXCEPTION("CompressibleNonlinearElasticitySolver must take in a compressible material law (ie of type AbstractCompressibleMaterialLaw)");
00553     }
00554     mMaterialLaws.push_back(p_law);
00555 
00556     Initialise(pFixedNodeLocations);
00557 }
00558 
00559 
00560 template<size_t DIM>
00561 CompressibleNonlinearElasticitySolver<DIM>::CompressibleNonlinearElasticitySolver(
00562             QuadraticMesh<DIM>* pQuadMesh,
00563             std::vector<AbstractMaterialLaw<DIM>*>& rMaterialLaws,
00564             c_vector<double,DIM> bodyForce,
00565             double density,
00566             std::string outputDirectory,
00567             std::vector<unsigned>& fixedNodes,
00568             std::vector<c_vector<double,DIM> >* pFixedNodeLocations)
00569     : AbstractNonlinearElasticitySolver<DIM>(pQuadMesh,
00570                                              bodyForce, density,
00571                                              outputDirectory, fixedNodes,
00572                                              COMPRESSIBLE)
00573 {
00574     mMaterialLaws.resize(rMaterialLaws.size(), NULL);
00575     for (unsigned i=0; i<mMaterialLaws.size(); i++)
00576     {
00577         AbstractCompressibleMaterialLaw<DIM>* p_law = dynamic_cast<AbstractCompressibleMaterialLaw<DIM>*>(rMaterialLaws[i]);
00578         if(!p_law)
00579         {
00580             EXCEPTION("CompressibleNonlinearElasticitySolver must take in a compressible material law (ie of type AbstractCompressibleMaterialLaw)");
00581         }
00582         assert(rMaterialLaws[i] != NULL);
00583         mMaterialLaws[i] = p_law;
00584     }
00585 
00586     assert(rMaterialLaws.size()==pQuadMesh->GetNumElements());
00587     Initialise(pFixedNodeLocations);
00588 }
00589 
00590 
00591 template<size_t DIM>
00592 CompressibleNonlinearElasticitySolver<DIM>::~CompressibleNonlinearElasticitySolver()
00593 {
00594 }
00596 // Explicit instantiation
00598 
00599 //template class CompressibleNonlinearElasticitySolver<1>;
00600 template class CompressibleNonlinearElasticitySolver<2>;
00601 template class CompressibleNonlinearElasticitySolver<3>;

Generated on Tue May 31 14:31:49 2011 for Chaste by  doxygen 1.5.5