ImplicitCardiacMechanicsAssembler.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2009
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 #include "ImplicitCardiacMechanicsAssembler.hpp"
00030 
00031 template<unsigned DIM>
00032 ImplicitCardiacMechanicsAssembler<DIM>::ImplicitCardiacMechanicsAssembler(
00033                                   QuadraticMesh<DIM>* pQuadMesh,
00034                                   std::string outputDirectory,
00035                                   std::vector<unsigned>& rFixedNodes,
00036                                   AbstractIncompressibleMaterialLaw<DIM>* pMaterialLaw)
00037     : NonlinearElasticityAssembler<DIM>(pQuadMesh,
00038                                         pMaterialLaw!=NULL ? pMaterialLaw : new NashHunterPoleZeroLaw<DIM>,
00039                                         zero_vector<double>(DIM),
00040                                         DOUBLE_UNSET,
00041                                         outputDirectory,
00042                                         rFixedNodes),
00043       mCurrentTime(DBL_MAX),
00044       mNextTime(DBL_MAX),
00045       mOdeTimestep(DBL_MAX)
00046 {
00047     // compute total num quad points
00048     mTotalQuadPoints = pQuadMesh->GetNumElements()*this->mpQuadratureRule->GetNumQuadPoints();
00049 
00050     // initialise stores
00051     mLambda.resize(mTotalQuadPoints, 1.0);
00052     mLambdaLastTimeStep.resize(mTotalQuadPoints, 1.0);
00053     mCellMechSystems.resize(mTotalQuadPoints);
00054 
00055     // note that if pMaterialLaw is NULL a new NashHunter law was sent to the
00056     // NonlinElas constuctor (see above)
00057     mAllocatedMaterialLawMemory = (pMaterialLaw==NULL);
00058 }
00059 
00060 template<unsigned DIM>
00061 ImplicitCardiacMechanicsAssembler<DIM>::~ImplicitCardiacMechanicsAssembler()
00062 {
00063     if(mAllocatedMaterialLawMemory)
00064     {
00065         assert(this->mMaterialLaws.size()==1); // haven't implemented heterogeniety yet
00066         delete this->mMaterialLaws[0];
00067     }
00068 }
00069 
00070 template<unsigned DIM>
00071 unsigned ImplicitCardiacMechanicsAssembler<DIM>::GetTotalNumQuadPoints()
00072 {
00073     return mTotalQuadPoints;
00074 }
00075 
00076 template<unsigned DIM>
00077 GaussianQuadratureRule<DIM>* ImplicitCardiacMechanicsAssembler<DIM>::GetQuadratureRule()
00078 {
00079     return this->mpQuadratureRule;
00080 }
00081 
00082 template<unsigned DIM>
00083 void ImplicitCardiacMechanicsAssembler<DIM>::SetIntracellularCalciumConcentrations(std::vector<double>& caI)
00084 {
00085     assert(caI.size() == mTotalQuadPoints);
00086     for(unsigned i=0; i<caI.size(); i++)
00087     {
00088         mCellMechSystems[i].SetIntracellularCalciumConcentration(caI[i]);
00089     }
00090 }
00091 
00092 template<unsigned DIM>
00093 std::vector<double>& ImplicitCardiacMechanicsAssembler<DIM>::rGetLambda()
00094 {
00095     return mLambda;
00096 }
00097 
00098 
00099 template<unsigned DIM>
00100 void ImplicitCardiacMechanicsAssembler<DIM>::Solve(double time, double nextTime, double odeTimestep)
00101 {
00102     // set the times, which are used in AssembleOnElement
00103     assert(time < nextTime);
00104     mCurrentTime = time;
00105     mNextTime = nextTime;
00106     mOdeTimestep = odeTimestep;
00107 
00108     // solve
00109     NonlinearElasticityAssembler<DIM>::Solve();
00110 
00111     // assemble residual again (to solve the cell models implicitly again
00112     // using the correct value of the deformation x (in case this wasn't the
00113     // last thing that was done
00114     this->AssembleSystem(true,false);
00115 
00116     // now update state variables, and set lambda at last timestep. Note
00117     // lambda was set in AssembleOnElement
00118     for(unsigned i=0; i<mCellMechSystems.size(); i++)
00119     {
00120          mCellMechSystems[i].UpdateStateVariables();
00121          mLambdaLastTimeStep[i] = mCellMechSystems[i].GetLambda();
00122     }
00123 }
00124 
00125 
00126 
00127 template<unsigned DIM>
00128 void ImplicitCardiacMechanicsAssembler<DIM>::AssembleOnElement(Element<DIM, DIM>& rElement,
00129                        c_matrix<double,STENCIL_SIZE,STENCIL_SIZE>& rAElem,
00130                        c_matrix<double,STENCIL_SIZE,STENCIL_SIZE>& rAElemPrecond,
00131                        c_vector<double,STENCIL_SIZE>& rBElem,
00132                        bool assembleResidual,
00133                        bool assembleJacobian)
00134 {
00135     // check these have been set
00136     assert(mCurrentTime != DBL_MAX);
00137     assert(mNextTime != DBL_MAX);
00138     assert(mOdeTimestep != DBL_MAX);
00139 
00140     c_matrix<double, DIM, DIM> jacobian, inverse_jacobian;
00141     double jacobian_determinant;
00142     this->mpQuadMesh->GetInverseJacobianForElement(rElement.GetIndex(), jacobian, jacobian_determinant, inverse_jacobian);
00143 
00144     if (assembleJacobian)
00145     {
00146         rAElem.clear();
00147         rAElemPrecond.clear();
00148     }
00149 
00150     if (assembleResidual)
00151     {
00152         rBElem.clear();
00153     }
00154 
00156     // Get the current displacement at the nodes
00158     static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> element_current_displacements;
00159     static c_vector<double,NUM_VERTICES_PER_ELEMENT> element_current_pressures;
00160     for(unsigned II=0; II<NUM_NODES_PER_ELEMENT; II++)
00161     {
00162         for(unsigned JJ=0; JJ<DIM; JJ++)
00163         {
00164             element_current_displacements(JJ,II) = this->mCurrentSolution[DIM*rElement.GetNodeGlobalIndex(II) + JJ];
00165         }
00166     }
00167 
00169     // Get the current pressure at the vertices
00171     for(unsigned II=0; II<NUM_VERTICES_PER_ELEMENT; II++)
00172     {
00173         element_current_pressures(II) = this->mCurrentSolution[DIM*this->mpQuadMesh->GetNumNodes() + rElement.GetNodeGlobalIndex(II)];
00174     }
00175 
00176     // allocate memory for the basis functions values and derivative values
00177     c_vector<double, NUM_VERTICES_PER_ELEMENT> linear_phi;
00178     c_vector<double, NUM_NODES_PER_ELEMENT> quad_phi;
00179     c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi;
00180 
00181     // get the material law
00182     AbstractIncompressibleMaterialLaw<DIM>* p_material_law;
00183     if(this->mMaterialLaws.size()==1)
00184     {
00185         // homogeneous
00186         p_material_law = this->mMaterialLaws[0];
00187     }
00188     else
00189     {
00190         // heterogeneous
00191         #define COVERAGE_IGNORE // not going to have tests in cts for everything
00192         p_material_law = this->mMaterialLaws[rElement.GetIndex()];
00193         #undef COVERAGE_IGNORE
00194     }
00195 
00197 //    assert(DIM==2);
00198 //    double   theta = 0.785398163/5 * elementIter->vertex(0)[0]; //0->pi/20
00199 //    this->mFibreSheetMat[0][0] =  cos(theta);
00200 //    this->mFibreSheetMat[0][1] =  sin(theta);
00201 //    this->mFibreSheetMat[1][0] = -sin(theta);
00202 //    this->mFibreSheetMat[1][1] =  cos(theta);
00203 //    this->mTransFibreSheetMat = transpose(this->mFibreSheetMat);
00204 
00205 
00211     for (unsigned quadrature_index=0; quadrature_index < this->mpQuadratureRule->GetNumQuadPoints(); quadrature_index++)
00212     {
00213         unsigned current_quad_point_global_index =   rElement.GetIndex()*this->mpQuadratureRule->GetNumQuadPoints()
00214                                                    + quadrature_index;
00215 
00216         double wJ = jacobian_determinant * this->mpQuadratureRule->GetWeight(quadrature_index);
00217 
00218         const ChastePoint<DIM>& quadrature_point = this->mpQuadratureRule->rGetQuadPoint(quadrature_index);
00219 
00221         // set up basis function info
00223         LinearBasisFunction<DIM>::ComputeBasisFunctions(quadrature_point, linear_phi);
00224         QuadraticBasisFunction<DIM>::ComputeBasisFunctions(quadrature_point, quad_phi);
00225         QuadraticBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(quadrature_point, inverse_jacobian, grad_quad_phi);
00226 
00228         // (dont get the body force)
00230 
00232         // interpolate grad_u and p
00234         static c_matrix<double,DIM,DIM> grad_u; // grad_u = (du_i/dX_M)
00235         grad_u = zero_matrix<double>(DIM,DIM);  // must be on new line!!
00236 
00237         for(unsigned node_index=0;
00238             node_index<NUM_NODES_PER_ELEMENT;
00239             node_index++)
00240         {
00241             for (unsigned i=0; i<DIM; i++)
00242             {
00243                 for(unsigned M=0; M<DIM; M++)
00244                 {
00245                     grad_u(i,M) += grad_quad_phi(M,node_index)*element_current_displacements(i,node_index);
00246                 }
00247             }
00248         }
00249 
00250         double pressure = 0;
00251         for(unsigned vertex_index=0;
00252             vertex_index<NUM_VERTICES_PER_ELEMENT;
00253             vertex_index++)
00254         {
00255             pressure += linear_phi(vertex_index)*element_current_pressures(vertex_index);
00256         }
00257 
00259         // calculate C, inv(C) and T
00261         static c_matrix<double,DIM,DIM> F;
00262         static c_matrix<double,DIM,DIM> C;
00263         static c_matrix<double,DIM,DIM> inv_C;
00264         static c_matrix<double,DIM,DIM> inv_F;
00265         static c_matrix<double,DIM,DIM> T;
00266 
00267         for (unsigned i=0; i<DIM; i++)
00268         {
00269             for (unsigned M=0; M<DIM; M++)
00270             {
00271                 F(i,M) = (i==M?1:0) + grad_u(i,M);
00272             }
00273         }
00274 
00275         C = prod(trans(F),F);
00276         inv_C = Inverse(C);
00277         inv_F = Inverse(F);
00278 
00279         double detF = Determinant(F);
00280 
00281         /************************************
00282          *  The cardiac-specific code PART 1
00283          ************************************/
00284         //static c_matrix<double,DIM,DIM> C_fibre;          // C when transformed to fibre-sheet axes
00285         //static c_matrix<double,DIM,DIM> inv_C_fibre;      // C^{-1} transformed to fibre-sheet axes
00286         //static c_matrix<double,DIM,DIM> T_fibre; // T when transformed to fibre-sheet axes
00287         //
00289         //C_fibre = this->mTransFibreSheetMat * C * this->mFibreSheetMat;
00290         //inv_C_fibre = this->mTransFibreSheetMat * inv_C * this->mFibreSheetMat;
00291 
00292         // store the stretch in the fibre direction
00293         this->mLambda[current_quad_point_global_index] = sqrt(C(0,0));
00294 
00295         double lam = sqrt(C(0,0));
00296         double dlam_dt = (lam-mLambdaLastTimeStep[current_quad_point_global_index])/(mNextTime-mCurrentTime);
00297 
00298         NhsSystemWithImplicitSolver& system = mCellMechSystems[current_quad_point_global_index];
00299 
00300         // get proper active tension
00301         // see NOTE below
00302         system.SetLambdaAndDerivative(lam, dlam_dt);
00303 
00304         double active_tension=0.0;
00305         try
00306         {
00307             system.SolveDoNotUpdate(mCurrentTime,mNextTime,mOdeTimestep);
00308             active_tension = system.GetActiveTensionAtNextTime();
00309         }
00310         catch (Exception& e)
00311         {
00312             #define COVERAGE_IGNORE
00313             if(assembleJacobian)
00314             {
00315                 EXCEPTION("Failed in solving NHS systems when assembling Jacobian");
00316             }
00317             #undef COVERAGE_IGNORE
00318         }
00319 
00320         // compute the derivative of the active tension wrt lam and dlam_dt
00321         double d_act_tension_dlam = 0.0; //Set and used if assembleJacobian==true
00322         double d_act_tension_d_dlamdt = 0.0; //Set and used if assembleJacobian==true
00323 
00324         if(assembleJacobian)
00325         {
00326             // get active tension for (lam+h,dlamdt)
00327             double h1 = std::max(1e-6, lam/100);
00328             system.SetLambdaAndDerivative(lam+h1, dlam_dt);
00329             system.SolveDoNotUpdate(mCurrentTime,mNextTime,mOdeTimestep);
00330             double active_tension_at_lam_plus_h = system.GetActiveTensionAtNextTime();
00331 
00332             // get active tension for (lam,dlamdt+h)
00333             double h2 = std::max(1e-6, dlam_dt/100);
00334             system.SetLambdaAndDerivative(lam, dlam_dt+h2);
00335             system.SolveDoNotUpdate(mCurrentTime,mNextTime,mOdeTimestep);
00336             double active_tension_at_dlamdt_plus_h = system.GetActiveTensionAtNextTime();
00337 
00338             d_act_tension_dlam = (active_tension_at_lam_plus_h - active_tension)/h1;
00339             d_act_tension_d_dlamdt = (active_tension_at_dlamdt_plus_h - active_tension)/h2;
00340         }
00341 
00342         // NOTE - have to get the active tension again, this must be done last!!
00343         // As if this turns out to be the correct solution, the state vars will be updated!
00344         // TODO: sort out this inefficiency
00345         system.SetLambdaAndDerivative(lam, dlam_dt);
00346         system.SetActiveTensionInitialGuess(active_tension);
00347 
00348         try
00349         {
00350             system.SolveDoNotUpdate(mCurrentTime,mNextTime,mOdeTimestep);
00351             assert( fabs(system.GetActiveTensionAtNextTime()-active_tension)<1e-8);
00352         }
00353         catch (Exception& e)
00354         {
00355             #define COVERAGE_IGNORE
00356             LOG(2, "WARNING in ImplicitCardiacMechanicsAssembler!\n");
00357             active_tension = 1e10;
00358             // should have done something above..
00359             #undef COVERAGE_IGNORE
00360         }
00361 
00362         //this->mDTdE_fibre.Zero();
00363 
00364         // compute the transformed tension. The material law should law be a cardiac-
00365         // specific law which assumes the x-axes in the fibre, the z-axes the sheet normal
00366         p_material_law->ComputeStressAndStressDerivative(C,inv_C,pressure,T,this->dTdE,assembleJacobian);
00367 
00368         // amend the stress and dTdE using the active tension
00369         T(0,0) += active_tension/C(0,0);
00370         this->dTdE(0,0,0,0) -= 2*active_tension/(C(0,0)*C(0,0));
00371 
00372 //            //// could do this without the loop now
00373 //            // transform T back to real coordinates
00374 //            for(unsigned M=0; M<DIM; M++)
00375 //            {
00376 //                for(unsigned N=0; N<DIM; N++)
00377 //                {
00378 //                    T[M][N] = 0;
00379 //                    for(unsigned al=0; al<DIM; al++)
00380 //                    {
00381 //                        for(unsigned be=0; be<DIM; be++)
00382 //                        {
00383 //                            T[M][N] +=                      T_fibre [al][be]
00384 //                                        *      this->mFibreSheetMat [M] [al]
00385 //                                        * this->mTransFibreSheetMat [be][N];
00386 //                        }
00387 //                    }
00388 //                }
00389 //            }
00390 //            static FourthOrderTensor<DIM> temp1;
00391 //            static FourthOrderTensor<DIM> temp2;
00392 //            static FourthOrderTensor<DIM> temp3;
00393 //
00394 //            temp1.SetAsProduct(this->mDTdE_fibre, this->mFibreSheetMat, 0);
00395 //            temp2.SetAsProduct(temp1,             this->mFibreSheetMat, 1);
00396 //            temp3.SetAsProduct(temp2,             this->mFibreSheetMat, 2);
00397 //
00398 //            this->dTdE.SetAsProduct(temp3, this->mFibreSheetMat, 3);
00399 
00400 
00401 
00402         static FourthOrderTensor<DIM> dTdE_F;
00403         static FourthOrderTensor<DIM> dTdE_FF1;
00404         static FourthOrderTensor<DIM> dTdE_FF2;
00405   
00406         dTdE_F.SetAsProduct(this->dTdE, F, 0);  // B^{aNPQ}  = F^a_M * dTdE^{MNPQ}
00407         dTdE_FF1.SetAsProduct(dTdE_F, F, 3);    // B1^{aNPb} = F^a_M * F^b_Q * dTdE^{MNPQ} 
00408         dTdE_FF2.SetAsProduct(dTdE_F, F, 2);    // B2^{aNbQ} = F^a_M * F^b_P * dTdE^{MNPQ}
00409 
00410 
00411         /*************************************
00412          * end of cardiac specific code PART 1
00413          *************************************/
00414 
00416         // residual vector
00418         if (assembleResidual)
00419         {
00420             for(unsigned index=0; index<NUM_NODES_PER_ELEMENT*DIM; index++)
00421             {
00422                 unsigned spatial_dim = index%DIM;
00423                 unsigned node_index = (index-spatial_dim)/DIM;
00424 
00425                 assert(node_index < NUM_NODES_PER_ELEMENT);
00426 
00427                 // no body force bit as body force = 0
00428 
00429                 for (unsigned M=0; M<DIM; M++)
00430                 {
00431                     for (unsigned N=0; N<DIM; N++)
00432                     {
00433                         rBElem(index) +=   T(M,N)
00434                                          * F(spatial_dim,M)
00435                                          * grad_quad_phi(N,node_index)
00436                                          * wJ;
00437                     }
00438                 }
00439             }
00440 
00441             for(unsigned vertex_index=0; vertex_index<NUM_VERTICES_PER_ELEMENT; vertex_index++)
00442             {
00443                 rBElem( NUM_NODES_PER_ELEMENT*DIM + vertex_index ) +=   linear_phi(vertex_index)
00444                                                                       * (detF - 1)
00445                                                                       * wJ;
00446             }
00447         }
00448 
00450         // Jacobian matrix
00452         if(assembleJacobian)
00453         {
00454             for(unsigned index1=0; index1<NUM_NODES_PER_ELEMENT*DIM; index1++)
00455             {
00456                 unsigned spatial_dim1 = index1%DIM;
00457                 unsigned node_index1 = (index1-spatial_dim1)/DIM;
00458 
00459 
00460                 for(unsigned index2=0; index2<NUM_NODES_PER_ELEMENT*DIM; index2++)
00461                 {
00462                     unsigned spatial_dim2 = index2%DIM;
00463                     unsigned node_index2 = (index2-spatial_dim2)/DIM;
00464 
00465                     for (unsigned M=0; M<DIM; M++)
00466                     {
00467                         for (unsigned N=0; N<DIM; N++)
00468                         {
00469                             rAElem(index1,index2) +=   T(M,N)
00470                                                      * grad_quad_phi(N,node_index1)
00471                                                      * grad_quad_phi(M,node_index2)
00472                                                      * (spatial_dim1==spatial_dim2?1:0)
00473                                                      * wJ;
00474 
00475 //                            for (unsigned P=0; P<DIM; P++)
00476 //                            {
00477 //                                for (unsigned Q=0; Q<DIM; Q++)
00478 //                                {
00479 //                                    rAElem(index1,index2)  +=   0.5
00480 //                                                              * this->dTdE(M,N,P,Q)
00481 //                                                              * (
00482 //                                                                  grad_quad_phi(P,node_index2)
00483 //                                                                * F(spatial_dim2,Q)
00484 //                                                                   +
00485 //                                                                  grad_quad_phi(Q,node_index2)
00486 //                                                                * F(spatial_dim2,P)
00487 //                                                                 )
00488 //                                                              * F(spatial_dim1,M)
00489 //                                                              * grad_quad_phi(N,node_index1)
00490 //                                                              * wJ;
00491 //                                }
00492 //                            }
00493                         }
00494                     }
00495                     
00496                     for (unsigned N=0; N<DIM; N++)
00497                     {
00498                         for (unsigned P=0; P<DIM; P++)
00499                         {
00500                             rAElem(index1,index2)  +=   0.5
00501                                                       * dTdE_FF1(spatial_dim1,N,P,spatial_dim2)
00502                                                       * grad_quad_phi(P,node_index2)
00503                                                       * grad_quad_phi(N,node_index1)
00504                                                       * wJ;
00505                         }
00506                         
00507                         for (unsigned Q=0; Q<DIM; Q++)
00508                         {
00509                            rAElem(index1,index2)  +=   0.5
00510                                                      * dTdE_FF2(spatial_dim1,N,spatial_dim2,Q)
00511                                                      * grad_quad_phi(Q,node_index2)
00512                                                      * grad_quad_phi(N,node_index1)
00513                                                      * wJ;
00514                         }
00515                     }
00516 
00517 
00518 
00519 
00520 
00521                     /************************************
00522                      *  The cardiac-specific code PART 2
00523                      ************************************/
00524                     rAElem(index1,index2) +=  (
00525                                                    d_act_tension_dlam
00526                                                  +
00527                                                    d_act_tension_d_dlamdt/(mNextTime-mCurrentTime)
00528                                                 )
00529                                                 * (F(spatial_dim2,0)/lam)
00530                                                 * grad_quad_phi(0,node_index2)
00531                                                 * F(spatial_dim1,0)
00532                                                 * grad_quad_phi(0,node_index1)
00533                                                 * wJ;
00534                    /************************************
00535                     *  End cardiac-specific code PART 2
00536                     ************************************/
00537                 }
00538 
00539 
00540                 for(unsigned vertex_index=0; vertex_index<NUM_VERTICES_PER_ELEMENT; vertex_index++)
00541                 {
00542                     unsigned index2 = NUM_NODES_PER_ELEMENT*DIM + vertex_index;
00543 
00544                     for (unsigned M=0; M<DIM; M++)
00545                     {
00546                         for (unsigned N=0; N<DIM; N++)
00547                         {
00548                             rAElem(index1,index2)  +=  - F(spatial_dim1,M)
00549                                                        * inv_C(M,N)
00550                                                        * grad_quad_phi(N,node_index1)
00551                                                        * linear_phi(vertex_index)
00552                                                        * wJ;
00553                         }
00554                     }
00555                 }
00556             }
00557 
00558             for(unsigned vertex_index=0; vertex_index<NUM_VERTICES_PER_ELEMENT; vertex_index++)
00559             {
00560                 unsigned index1 = NUM_NODES_PER_ELEMENT*DIM + vertex_index;
00561 
00562                 for(unsigned index2=0; index2<NUM_NODES_PER_ELEMENT*DIM; index2++)
00563                 {
00564                     unsigned spatial_dim2 = index2%DIM;
00565                     unsigned node_index2 = (index2-spatial_dim2)/DIM;
00566 
00567                     for (unsigned M=0; M<DIM; M++)
00568                     {
00569                         rAElem(index1,index2) +=   linear_phi(vertex_index)
00570                                                  * detF
00571                                                  * inv_F(M,spatial_dim2)
00572                                                  * grad_quad_phi(M,node_index2)
00573                                                  * wJ;
00574                     }
00575                 }
00576 
00578                 // Preconditioner matrix
00579                 // Fill the mass matrix (ie \intgl phi_i phi_j) in the
00580                 // pressure-pressure block. Note, the rest of the
00581                 // entries are filled in at the end
00583                 for(unsigned vertex_index2=0; vertex_index2< NUM_VERTICES_PER_ELEMENT; vertex_index2++)
00584                 {
00585                     unsigned index2 =  NUM_NODES_PER_ELEMENT*DIM + vertex_index2;
00586                     rAElemPrecond(index1,index2) +=   linear_phi(vertex_index)
00587                                                     * linear_phi(vertex_index2)
00588                                                     * wJ;
00589                 }
00590             }
00591         }
00592     }
00593 
00594 
00595     if (assembleJacobian)
00596     {
00597         // Fill in the other blocks of the preconditioner matrix. (This doesn't
00598         // effect the pressure-pressure block of the rAElemPrecond but the
00599         // pressure-pressure block of rAElem is zero
00600         rAElemPrecond = rAElemPrecond + rAElem;
00601     }
00602 }
00603 
00604 template class ImplicitCardiacMechanicsAssembler<2>;
00605 template class ImplicitCardiacMechanicsAssembler<3>;
00606 
00607 

Generated on Tue Aug 4 16:10:22 2009 for Chaste by  doxygen 1.5.5