AbstractNonlinearElasticitySolver.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 ABSTRACTNONLINEARELASTICITYSOLVER_HPP_
00030 #define ABSTRACTNONLINEARELASTICITYSOLVER_HPP_
00031 
00032 #include <vector>
00033 #include <cmath>
00034 #include "LinearSystem.hpp"
00035 #include "OutputFileHandler.hpp"
00036 #include "LogFile.hpp"
00037 #include "PetscTools.hpp"
00038 #include "MechanicsEventHandler.hpp"
00039 #include "ReplicatableVector.hpp"
00040 #include "FourthOrderTensor.hpp"
00041 #include "QuadraticMesh.hpp"
00042 #include "GaussianQuadratureRule.hpp"
00043 #include "CmguiDeformedSolutionsWriter.hpp"
00044 #include "AbstractMaterialLaw.hpp"
00045 #include "Warnings.hpp"
00046 #include "PetscException.hpp"
00047 #include "CompressibilityType.hpp"
00048 #include "QuadraticBasisFunction.hpp"
00049 
00050 #include "SolidMechanicsProblemDefinition.hpp"
00051 #include "DeformedBoundaryElement.hpp"
00052 
00053 //#define MECH_VERBOSE      // Print output on how nonlinear solve is progressing
00054 //#define MECH_VERY_VERBOSE // See number of elements done whilst assembling vectors or matrices
00055 //#define MECH_USE_HYPRE    // uses HYPRE to solve linear systems, requires PETSc to be installed with HYPRE
00056 //#define MECH_KSP_MONITOR  // Print residual norm each iteration in linear solve (ie -ksp_monitor).
00057 
00058 
00059 #ifdef MECH_VERBOSE
00060 #include "Timer.hpp"
00061 #endif
00062 
00063 
00064 // Bizarrely PETSc 2.2 has this, but doesn't put it in the petscksp.h header...
00065 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00066 extern PetscErrorCode KSPInitialResidual(KSP,Vec,Vec,Vec,Vec,Vec);
00067 #endif
00068 
00069 
00070 
00074 template<unsigned DIM>
00075 class AbstractNonlinearElasticitySolver
00076 {
00077 protected:
00078 
00080     static const size_t NUM_VERTICES_PER_ELEMENT = DIM+1;
00081 
00083     static const size_t NUM_NODES_PER_ELEMENT = (DIM+1)*(DIM+2)/2;      // assuming quadratic
00084 
00086     static const size_t NUM_NODES_PER_BOUNDARY_ELEMENT = DIM*(DIM+1)/2; // assuming quadratic
00087 
00095     static double MAX_NEWTON_ABS_TOL;
00096 
00098     static double MIN_NEWTON_ABS_TOL;
00099 
00101     static double NEWTON_REL_TOL;
00102 
00107     QuadraticMesh<DIM>& mrQuadMesh;
00108 
00113     SolidMechanicsProblemDefinition<DIM>& mrProblemDefinition;
00114 
00116     GaussianQuadratureRule<DIM>* mpQuadratureRule;
00117 
00119     GaussianQuadratureRule<DIM-1>* mpBoundaryQuadratureRule;
00120 
00126     double mKspAbsoluteTol;
00127 
00133     unsigned mNumDofs;
00134 
00139     Vec mResidualVector;
00140 
00157     Vec mLinearSystemRhsVector;
00158 
00162     Mat mJacobianMatrix;
00163 
00167     Vec mDirichletBoundaryConditionsVector;
00168 
00187     Mat mPreconditionMatrix;
00188 
00190     bool mWriteOutput;
00191 
00193     std::string mOutputDirectory;
00194 
00196     OutputFileHandler* mpOutputFileHandler;
00197 
00203     bool mWriteOutputEachNewtonIteration;
00204 
00211     std::vector<double> mCurrentSolution;
00212 
00216     FourthOrderTensor<DIM,DIM,DIM,DIM> dTdE;
00217 
00219     unsigned mNumNewtonIterations;
00220 
00222     std::vector<c_vector<double,DIM> > mDeformedPosition;
00223 
00231     DeformedBoundaryElement<DIM-1,DIM> mDeformedBoundaryElement;
00232 
00238     double mCurrentTime;
00239 
00244     CompressibilityType mCompressibilityType;
00245 
00249     bool mCheckedOutwardNormals;
00250 
00263     virtual void AssembleSystem(bool assembleResidual, bool assembleLinearSystem)=0;
00264 
00268     void Initialise();
00269 
00274     void AllocateMatrixMemory();
00275 
00292     void ApplyDirichletBoundaryConditions(bool applyToMatrix);
00293 
00301     virtual void FinishAssembleSystem(bool assembleResidual, bool assembleLinearSystem);
00302 
00313     double ComputeResidualAndGetNorm(bool allowException);
00314 
00316     double CalculateResidualNorm();
00317 
00327     void VectorSum(std::vector<double>& rX, ReplicatableVector& rY, double a, std::vector<double>& rZ);
00328 
00336     void PrintLineSearchResult(double s, double residNorm);
00337 
00345     double TakeNewtonStep();
00346 
00355     double UpdateSolutionUsingLineSearch(Vec solution);
00356 
00364     virtual void PostNewtonStep(unsigned counter, double normResidual);
00365 
00372     void GetElementCentroidDeformationGradient(Element<DIM,DIM>& rElement,
00373                                                c_matrix<double,DIM,DIM>& rDeformationGradient);
00374 
00394     virtual void ComputeStressAndStressDerivative(AbstractMaterialLaw<DIM>* pMaterialLaw,
00395                                                   c_matrix<double,DIM,DIM>& rC,
00396                                                   c_matrix<double,DIM,DIM>& rInvC,
00397                                                   double pressure,
00398                                                   unsigned elementIndex,
00399                                                   unsigned currentQuadPointGlobalIndex,
00400                                                   c_matrix<double,DIM,DIM>& rT,
00401                                                   FourthOrderTensor<DIM,DIM,DIM,DIM>& rDTdE,
00402                                                   bool computeDTdE)
00403     {
00404         // Just call the method on the material law
00405         pMaterialLaw->ComputeStressAndStressDerivative(rC,rInvC,pressure,rT,rDTdE,computeDTdE);
00406     }
00407 
00408 public:
00409 
00420     AbstractNonlinearElasticitySolver(QuadraticMesh<DIM>& rQuadMesh,
00421                                       SolidMechanicsProblemDefinition<DIM>& rProblemDefinition,
00422                                       std::string outputDirectory,
00423                                       CompressibilityType compressibilityType);
00424 
00428     virtual ~AbstractNonlinearElasticitySolver();
00429 
00437     void Solve(double tol=-1.0,
00438                unsigned maxNumNewtonIterations=INT_MAX,
00439                bool quitIfNoConvergence=true);
00440 
00451     void WriteCurrentDeformation(std::string fileName, int counterToAppend=-1);
00452 
00456     unsigned GetNumNewtonIterations();
00457 
00458 
00464     void SetWriteOutput(bool writeOutput=true);
00465 
00473     void SetWriteOutputEachNewtonIteration(bool writeOutputEachNewtonIteration=true)
00474     {
00475         mWriteOutputEachNewtonIteration = writeOutputEachNewtonIteration;
00476     }
00477 
00484     void SetKspAbsoluteTolerance(double kspAbsoluteTolerance)
00485     {
00486         assert(kspAbsoluteTolerance > 0);
00487         mKspAbsoluteTol = kspAbsoluteTolerance;
00488     }
00489 
00494     std::vector<double>& rGetCurrentSolution()
00495     {
00496         return mCurrentSolution;
00497     }
00498 
00499 
00503     std::vector<c_vector<double,DIM> >& rGetDeformedPosition();
00504 
00511     void SetCurrentTime(double time)
00512     {
00513         mCurrentTime = time;
00514     }
00515 
00520     void CreateCmguiOutput();
00521 
00522 
00534     void WriteCurrentDeformationGradients(std::string fileName, int counterToAppend);
00535 };
00536 
00538 // Implementation
00540 
00541 template<unsigned DIM>
00542 void AbstractNonlinearElasticitySolver<DIM>::Initialise()
00543 {
00544     AllocateMatrixMemory();
00545 
00546     mpQuadratureRule = new GaussianQuadratureRule<DIM>(3);
00547     mpBoundaryQuadratureRule = new GaussianQuadratureRule<DIM-1>(3);
00548 
00549     mCurrentSolution.resize(mNumDofs, 0.0);
00550 }
00551 
00552 template<unsigned DIM>
00553 void AbstractNonlinearElasticitySolver<DIM>::AllocateMatrixMemory()
00554 {
00555     mResidualVector = PetscTools::CreateVec(mNumDofs);
00556     VecDuplicate(mResidualVector, &mLinearSystemRhsVector);
00557     if (mCompressibilityType == COMPRESSIBLE)
00558     {
00559         VecDuplicate(mResidualVector, &mDirichletBoundaryConditionsVector);
00560     }
00561 
00562     if (DIM==2)
00563     {
00564         // 2D: N elements around a point => 7N+3 non-zeros in that row? Assume N<=10 (structured mesh would have N_max=6) => 73.
00565         unsigned num_non_zeros = std::min(75u, mNumDofs);
00566 
00567         PetscTools::SetupMat(mJacobianMatrix, mNumDofs, mNumDofs, num_non_zeros, PETSC_DECIDE, PETSC_DECIDE);
00568         PetscTools::SetupMat(mPreconditionMatrix, mNumDofs, mNumDofs, num_non_zeros, PETSC_DECIDE, PETSC_DECIDE);
00569     }
00570     else
00571     {
00572         assert(DIM==3);
00573 
00574         // 3D: N elements around a point. nz < (3*10+6)N (lazy estimate). Better estimate is 23N+4?. Assume N<20 => 500ish
00575 
00576         // in 3d we get the number of containing elements for each node and use that to obtain an upper bound
00577         // for the number of non-zeros for each DOF associated with that node.
00578 
00579         int* num_non_zeros_each_row = new int[mNumDofs];
00580         for (unsigned i=0; i<mNumDofs; i++)
00581         {
00582             num_non_zeros_each_row[i] = 0;
00583         }
00584 
00585         for (unsigned i=0; i<mrQuadMesh.GetNumNodes(); i++)
00586         {
00587             // this upper bound neglects the fact that two containing elements will share the same nodes..
00588             // 4 = max num dofs associated with this node
00589             // 30 = 3*9+3 = 3 dimensions x 9 other nodes on this element   +  3 vertices with a pressure unknown
00590             unsigned num_non_zeros_upper_bound = 4 + 30*mrQuadMesh.GetNode(i)->GetNumContainingElements();
00591 
00592             num_non_zeros_upper_bound = std::min(num_non_zeros_upper_bound, mNumDofs);
00593 
00594             num_non_zeros_each_row[DIM*i + 0] = num_non_zeros_upper_bound;
00595             num_non_zeros_each_row[DIM*i + 1] = num_non_zeros_upper_bound;
00596             num_non_zeros_each_row[DIM*i + 2] = num_non_zeros_upper_bound;
00597 
00598             if (mCompressibilityType==INCOMPRESSIBLE)
00599             {
00600                 //Could do !mrQuadMesh.GetNode(i)->IsInternal()
00601                 if (i<mrQuadMesh.GetNumVertices()) // then this is a vertex
00602                 {
00603                     num_non_zeros_each_row[DIM*mrQuadMesh.GetNumNodes() + i] = num_non_zeros_upper_bound;
00604                 }
00605             }
00606         }
00607 
00608         // NOTE: PetscTools::SetupMat() or the below creates a MATAIJ matrix, which means the matrix will
00609         // be of type MATSEQAIJ if num_procs=1 and MATMPIAIJ otherwise. In the former case
00610         // MatSeqAIJSetPreallocation MUST be called [MatMPIAIJSetPreallocation will have
00611         // no effect (silently)], and vice versa in the latter case
00612 
00615         //PetscTools::SetupMat(mJacobianMatrix, mNumDofs, mNumDofs, 0, PETSC_DECIDE, PETSC_DECIDE);
00616         //PetscTools::SetupMat(mPreconditionMatrix, mNumDofs, mNumDofs, 0, PETSC_DECIDE, PETSC_DECIDE);
00618 
00619         // possible todo: create a PetscTools::SetupMatNoAllocation()
00620 
00621         // In the future, when parallelising, remember to think about MAT_IGNORE_OFF_PROC_ENTRIES (see #1682)
00622 
00623 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00624         MatCreate(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,mNumDofs,mNumDofs,&mJacobianMatrix);
00625         MatCreate(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,mNumDofs,mNumDofs,&mPreconditionMatrix);
00626 #else //New API
00627         MatCreate(PETSC_COMM_WORLD,&mJacobianMatrix);
00628         MatCreate(PETSC_COMM_WORLD,&mPreconditionMatrix);
00629         MatSetSizes(mJacobianMatrix,PETSC_DECIDE,PETSC_DECIDE,mNumDofs,mNumDofs);
00630         MatSetSizes(mPreconditionMatrix,PETSC_DECIDE,PETSC_DECIDE,mNumDofs,mNumDofs);
00631 #endif
00632 
00633         if (PetscTools::IsSequential())
00634         {
00635             MatSetType(mJacobianMatrix, MATSEQAIJ);
00636             MatSetType(mPreconditionMatrix, MATSEQAIJ);
00637             MatSeqAIJSetPreallocation(mJacobianMatrix,     PETSC_NULL, num_non_zeros_each_row);
00638             MatSeqAIJSetPreallocation(mPreconditionMatrix, PETSC_NULL, num_non_zeros_each_row);
00639         }
00640         else
00641         {
00642             PetscInt lo, hi;
00643             VecGetOwnershipRange(mResidualVector, &lo, &hi);
00644 
00645             int* num_non_zeros_each_row_this_proc = new int[hi-lo];
00646             int* zero = new int[hi-lo];
00647             for (unsigned i=0; i<unsigned(hi-lo); i++)
00648             {
00649                 num_non_zeros_each_row_this_proc[i] = num_non_zeros_each_row[lo+i];
00650                 zero[i] = 0;
00651             }
00652 
00653             MatSetType(mJacobianMatrix, MATMPIAIJ);
00654             MatSetType(mPreconditionMatrix, MATMPIAIJ);
00655             MatMPIAIJSetPreallocation(mJacobianMatrix,     PETSC_NULL, num_non_zeros_each_row_this_proc, PETSC_NULL, num_non_zeros_each_row_this_proc);
00656             MatMPIAIJSetPreallocation(mPreconditionMatrix, PETSC_NULL, num_non_zeros_each_row_this_proc, PETSC_NULL, num_non_zeros_each_row_this_proc);
00657         }
00658 
00659         MatSetFromOptions(mJacobianMatrix);
00660         MatSetFromOptions(mPreconditionMatrix);
00661 
00662         //unsigned total_non_zeros = 0;
00663         //for (unsigned i=0; i<mNumDofs; i++)
00664         //{
00665         //   total_non_zeros += num_non_zeros_each_row[i];
00666         //}
00667         //std::cout << total_non_zeros << " versus " << 500*mNumDofs << "\n" << std::flush;
00668 
00669         delete [] num_non_zeros_each_row;
00670     }
00671 }
00672 
00673 /*
00674  * This method applies the appropriate BCs to the residual vector, and possible also the linear system.
00675  *
00676  * For the latter, in the compressible case, the BCs are imposed in such a way as to ensure that a
00677  * symmetric linear system remains symmetric. For each row with boundary condition applied, both the
00678  * row and column are zero'd and the RHS vector modified to take into account the zero'd column.
00679  *
00680  * Suppose we have a matrix
00681  * [a b c] [x] = [ b1 ]
00682  * [d e f] [y]   [ b2 ]
00683  * [g h i] [z]   [ b3 ]
00684  * and we want to apply the boundary condition x=v without losing symmetry if the matrix is
00685  * symmetric. We apply the boundary condition
00686  * [1 0 0] [x] = [ v  ]
00687  * [d e f] [y]   [ b2 ]
00688  * [g h i] [z]   [ b3 ]
00689  * and then zero the column as well, adding a term to the RHS to take account for the
00690  * zero-matrix components
00691  * [1 0 0] [x] = [ v  ] - v[ 0 ]
00692  * [0 e f] [y]   [ b2 ]    [ d ]
00693  * [0 h i] [z]   [ b3 ]    [ g ]
00694  * Note the last term is the first column of the matrix, with one component zeroed, and
00695  * multiplied by the boundary condition value. This last term is then stored in
00696  * rLinearSystem.rGetDirichletBoundaryConditionsVector(), and in general form is the
00697  * SUM_{d=1..D} v_d a'_d
00698  * where v_d is the boundary value of boundary condition d (d an index into the matrix),
00699  * and a'_d is the dth-column of the matrix but with the d-th component zeroed, and where
00700  * there are D boundary conditions
00701  */
00702 template<unsigned DIM>
00703 void AbstractNonlinearElasticitySolver<DIM>::ApplyDirichletBoundaryConditions(bool applyToLinearSystem)
00704 {
00705     assert(mResidualVector); // BCs will be added to all the time
00706     if (applyToLinearSystem)
00707     {
00708         assert(mJacobianMatrix);
00709         assert(mLinearSystemRhsVector);
00710     }
00711 
00712     // The boundary conditions on the NONLINEAR SYSTEM are x=boundary_values
00713     // on the boundary nodes. However:
00714     // The boundary conditions on the LINEAR SYSTEM  Ju=f, where J is the
00715     // u the negative update vector and f is the residual is
00716     // u=current_soln-boundary_values on the boundary nodes
00717 
00718     std::vector<unsigned> rows;
00719     std::vector<double> values;
00720 
00721     // Whether to apply symmetrically, ie alter columns as well as rows (see comment above)
00722     bool applySymmetrically = (applyToLinearSystem) && (mCompressibilityType==COMPRESSIBLE);
00723 
00724     if (applySymmetrically)
00725     {
00726         assert(applyToLinearSystem);
00727         PetscVecTools::Zero(mDirichletBoundaryConditionsVector);
00728         PetscMatTools::Finalise(mJacobianMatrix);
00729     }
00730 
00731     for (unsigned i=0; i<mrProblemDefinition.rGetDirichletNodes().size(); i++)
00732     {
00733         unsigned node_index = mrProblemDefinition.rGetDirichletNodes()[i];
00734 
00735         for (unsigned j=0; j<DIM; j++)
00736         {
00737             double disp = mrProblemDefinition.rGetDirichletNodeValues()[i](j); // problem defn returns DISPLACEMENTS here
00738 
00739             if(disp != SolidMechanicsProblemDefinition<DIM>::FREE)
00740             {
00741                 unsigned dof_index = DIM*node_index+j;
00742                 rows.push_back(dof_index);
00743                 values.push_back(mCurrentSolution[dof_index] - disp);
00744             }
00745         }
00746     }
00747 
00748     if (applySymmetrically)
00749     {
00750         // Modify the matrix columns
00751         for (unsigned i=0; i<rows.size(); i++)
00752         {
00753             unsigned col = rows[i];
00754             double minus_value = -values[i];
00755 
00756             // Get a vector which will store the column of the matrix (column d, where d is
00757             // the index of the row (and column) to be altered for the boundary condition.
00758             // Since the matrix is symmetric when get row number "col" and treat it as a column.
00759             // PETSc uses compressed row format and therefore getting rows is far more efficient
00760             // than getting columns.
00761             Vec matrix_col = PetscMatTools::GetMatrixRowDistributed(mJacobianMatrix,col);
00762 
00763             // Zero the correct entry of the column
00764             PetscVecTools::SetElement(matrix_col, col, 0.0);
00765 
00766             // Set up the RHS Dirichlet boundary conditions vector
00767             // Assuming one boundary at the zeroth node (x_0 = value), this is equal to
00768             //   -value*[0 a_21 a_31 .. a_N1]
00769             // and will be added to the RHS.
00770             PetscVecTools::AddScaledVector(mDirichletBoundaryConditionsVector, matrix_col, minus_value);
00771             VecDestroy(matrix_col);
00772         }
00773     }
00774 
00775     if (applyToLinearSystem)
00776     {
00777         // Now zero the appropriate rows and columns of the matrix. If the matrix is symmetric we apply the
00778         // boundary conditions in a way the symmetry isn't lost (rows and columns). If not only the row is
00779         // zeroed.
00780         if (applySymmetrically)
00781         {
00782             PetscMatTools::ZeroRowsAndColumnsWithValueOnDiagonal(mJacobianMatrix, rows, 1.0);
00783             PetscMatTools::ZeroRowsAndColumnsWithValueOnDiagonal(mPreconditionMatrix, rows, 1.0);
00784 
00785             // Apply the RHS boundary conditions modification if required.
00786             PetscVecTools::AddScaledVector(mLinearSystemRhsVector, mDirichletBoundaryConditionsVector, 1.0);
00787         }
00788         else
00789         {
00790             PetscMatTools::ZeroRowsWithValueOnDiagonal(mJacobianMatrix, rows, 1.0);
00791             PetscMatTools::ZeroRowsWithValueOnDiagonal(mPreconditionMatrix, rows, 1.0);
00792         }
00793     }
00794 
00795     for (unsigned i=0; i<rows.size(); i++)
00796     {
00797         PetscVecTools::SetElement(mResidualVector, rows[i], values[i]);
00798     }
00799 
00800     if (applyToLinearSystem)
00801     {
00802         for (unsigned i=0; i<rows.size(); i++)
00803         {
00804             PetscVecTools::SetElement(mLinearSystemRhsVector, rows[i], values[i]);
00805         }
00806     }
00807 }
00808 
00809 template<unsigned DIM>
00810 void AbstractNonlinearElasticitySolver<DIM>::FinishAssembleSystem(bool assembleResidual, bool assembleJacobian)
00811 {
00812     if (assembleResidual)
00813     {
00814         PetscVecTools::Finalise(mResidualVector);
00815     }
00816     if (assembleJacobian)
00817     {
00818         PetscMatTools::SwitchWriteMode(mJacobianMatrix);
00819         PetscMatTools::SwitchWriteMode(mPreconditionMatrix);
00820 
00821         VecCopy(mResidualVector, mLinearSystemRhsVector);
00822     }
00823 
00824     // Apply Dirichlet boundary conditions
00825     ApplyDirichletBoundaryConditions(assembleJacobian);
00826 
00827     if (assembleResidual)
00828     {
00829         PetscVecTools::Finalise(mResidualVector);
00830     }
00831     if (assembleJacobian)
00832     {
00833         PetscMatTools::Finalise(mJacobianMatrix);
00834         PetscMatTools::Finalise(mPreconditionMatrix);
00835         PetscVecTools::Finalise(mLinearSystemRhsVector);
00836     }
00837 }
00838 
00839 template<unsigned DIM>
00840 double AbstractNonlinearElasticitySolver<DIM>::ComputeResidualAndGetNorm(bool allowException)
00841 {
00842     if (!allowException)
00843     {
00844         // Assemble the residual
00845         AssembleSystem(true, false);
00846     }
00847     else
00848     {
00849         try
00850         {
00851             // Try to assemble the residual using this current solution
00852             AssembleSystem(true, false);
00853         }
00854         catch(Exception& e)
00855         {
00856             // If fail (because e.g. ODEs fail to solve, or strains are too large for material law), return infinity
00857             return DBL_MAX;
00858         }
00859     }
00860 
00861     // Return the scaled norm of the residual
00862     return CalculateResidualNorm();
00863 }
00864 
00865 template<unsigned DIM>
00866 double AbstractNonlinearElasticitySolver<DIM>::CalculateResidualNorm()
00867 {
00868     double norm;
00869     VecNorm(mResidualVector, NORM_2, &norm);
00870     return norm/mNumDofs;
00871 }
00872 
00873 template<unsigned DIM>
00874 void AbstractNonlinearElasticitySolver<DIM>::VectorSum(std::vector<double>& rX,
00875                                                        ReplicatableVector& rY,
00876                                                        double a,
00877                                                        std::vector<double>& rZ)
00878 {
00879     assert(rX.size()==rY.GetSize());
00880     assert(rY.GetSize()==rZ.size());
00881     for (unsigned i=0; i<rX.size(); i++)
00882     {
00883         rZ[i] = rX[i] + a*rY[i];
00884     }
00885 }
00886 
00887 
00888 template<unsigned DIM>
00889 double AbstractNonlinearElasticitySolver<DIM>::TakeNewtonStep()
00890 {
00891     #ifdef MECH_VERBOSE
00892     Timer::Reset();
00893     #endif
00894 
00896     // Assemble Jacobian (and preconditioner)
00898     MechanicsEventHandler::BeginEvent(MechanicsEventHandler::ASSEMBLE);
00899     AssembleSystem(true, true);
00900     MechanicsEventHandler::EndEvent(MechanicsEventHandler::ASSEMBLE);
00901     #ifdef MECH_VERBOSE
00902     Timer::PrintAndReset("AssembleSystem");
00903     #endif
00904 
00906     //
00907     // Solve the linear system.
00908     // Three alternatives
00909     //   (a) Incompressible: GMRES with ILU preconditioner (or bjacobi=ILU on each process) [default]. Very poor on large problems.
00910     //   (b) Incompressible: GMRES with AMG preconditioner. Uncomment #define MECH_USE_HYPRE above. Requires Petsc3 with HYPRE installed.
00911     //   (c) Compressible: CG with ???
00913     MechanicsEventHandler::BeginEvent(MechanicsEventHandler::SOLVE);
00914 
00915     Vec solution;
00916     VecDuplicate(mResidualVector,&solution);
00917 
00918     KSP solver;
00919     KSPCreate(PETSC_COMM_WORLD,&solver);
00920     PC pc;
00921     KSPGetPC(solver, &pc);
00922 
00923     KSPSetOperators(solver, mJacobianMatrix, mPreconditionMatrix, DIFFERENT_NONZERO_PATTERN /*in precond between successive solves*/);
00924 
00925     if (mCompressibilityType==COMPRESSIBLE)
00926     {
00927         KSPSetType(solver,KSPCG);
00928         //PCSetType(pc, PCSOR);
00929         PCSetType(pc, PCICC); 
00930         PetscOptionsSetValue("-pc_factor_shift_positive_definite", "");
00931 
00932         //needed for ICC preconditioner
00933         //PetscOptionsSetValue("-pc_factor_shift_positive_definite", "");
00934 
00936         //assert( PetscMatTools::CheckSymmetry(mJacobianMatrix) );
00937     }
00938     else
00939     {
00940         unsigned num_restarts = 100;
00941         KSPSetType(solver,KSPGMRES);
00942         KSPGMRESSetRestart(solver,num_restarts);
00943 
00944         #ifndef MECH_USE_HYPRE
00945             PCSetType(pc, PCBJACOBI); // BJACOBI = ILU on each block (block = part of matrix on each process)
00946         #else
00947 
00948             // Speed up linear solve time massively for larger simulations (in fact GMRES may stagnate without
00949             // this for larger problems), by using a AMG preconditioner -- needs HYPRE installed
00951             PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00952             // PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1");
00953             // PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0");
00954 
00955             PCSetType(pc, PCHYPRE);
00956             KSPSetPreconditionerSide(solver, PC_RIGHT);
00957 
00958             // other possible preconditioners..
00959             //PCBlockDiagonalMechanics* p_custom_pc = new PCBlockDiagonalMechanics(solver, mPreconditionMatrix, mBlock1Size, mBlock2Size);
00960             //PCLDUFactorisationMechanics* p_custom_pc = new PCLDUFactorisationMechanics(solver, mPreconditionMatrix, mBlock1Size, mBlock2Size);
00961             //remember to delete memory..
00962             //KSPSetPreconditionerSide(solver, PC_RIGHT);
00963         #endif
00964     }
00965 
00966 
00967 
00968 
00969     #ifdef MECH_KSP_MONITOR
00970     PetscOptionsSetValue("-ksp_monitor","");
00971     //PetscOptionsSetValue("-ksp_norm_type","natural");
00972     #endif
00973 
00974     KSPSetFromOptions(solver);
00975     KSPSetUp(solver);
00976 
00977 
00978 //    ///// For printing matrix when debugging
00979 //    OutputFileHandler handler("TEMP");
00980 //    out_stream p_file = handler.OpenOutputFile("matrix.txt");
00981 //    for(unsigned i=0; i<mNumDofs; i++)
00982 //    {
00983 //        for(unsigned j=0; j<mNumDofs; j++)
00984 //        {
00985 //            *p_file << PetscMatTools::GetElement(mJacobianMatrix, i, j) << " ";
00986 //        }
00987 //        *p_file << "\n";
00988 //    }
00989 //    p_file->close();
00990 //
00991 //    out_stream p_file2 = handler.OpenOutputFile("rhs.txt");
00992 //    for(unsigned i=0; i<mNumDofs; i++)
00993 //    {
00994 //        *p_file2 << PetscVecTools::GetElement(mLinearSystemRhsVector, i) << "\n";
00995 //    }
00996 //    p_file2->close();
00997 
00998 
00999     // Set the linear system absolute tolerance.
01000     // This is either the user provided value, or set to
01001     // max {1e-6 * initial_residual, 1e-12}
01002     if (mKspAbsoluteTol < 0)
01003     {
01004         Vec temp = PetscTools::CreateVec(mNumDofs);
01005         Vec temp2 = PetscTools::CreateVec(mNumDofs);
01006         Vec linsys_residual = PetscTools::CreateVec(mNumDofs);
01007 
01008         KSPInitialResidual(solver, solution, temp, temp2, linsys_residual, mLinearSystemRhsVector);
01009         double initial_resid_norm;
01010         VecNorm(linsys_residual, NORM_2, &initial_resid_norm);
01011 
01012         VecDestroy(temp);
01013         VecDestroy(temp2);
01014         VecDestroy(linsys_residual);
01015 
01016         double ksp_rel_tol = 1e-6;
01017         double absolute_tol = ksp_rel_tol * initial_resid_norm;
01018         if(absolute_tol < 1e-12)
01019         {
01020             absolute_tol = 1e-12;
01021         }
01022         KSPSetTolerances(solver, 1e-16, absolute_tol, PETSC_DEFAULT, PETSC_DEFAULT /* max iters */); // Note, max iters seems to be 1000 whatever we give here
01023     }
01024     else
01025     {
01026         KSPSetTolerances(solver, 1e-16, mKspAbsoluteTol, PETSC_DEFAULT, PETSC_DEFAULT /* max iters */); // Note, max iters seems to be 1000 whatever we give here
01027     }
01028 
01029     #ifdef MECH_VERBOSE
01030     Timer::PrintAndReset("KSP Setup");
01031     #endif
01032 
01033     KSPSolve(solver,mLinearSystemRhsVector,solution);
01034 
01036     // Error checking for linear solve
01038 
01039     // warn if ksp reports failure
01040     KSPConvergedReason reason;
01041     KSPGetConvergedReason(solver,&reason);
01042 
01043     if(reason != KSP_DIVERGED_ITS)
01044     {
01045         // Throw an exception if the solver failed for any reason other than DIVERGED_ITS.
01046         // This is not covered as would be difficult to cover - requires a bad matrix to
01047         // assembled, for example.
01048         #define COVERAGE_IGNORE
01049         KSPEXCEPT(reason);
01050         #undef COVERAGE_IGNORE
01051     }
01052     else
01053     {
01054         // DIVERGED_ITS just means it didn't converge in the given maximum number of iterations,
01055         // which is potentially not a problem, as the nonlinear solver may (and often will) still converge.
01056         // Just warn once.
01057         // (Very difficult to cover in normal tests, requires relative and absolute ksp tols to be very small, there
01058         // is no interface for setting both of these. Could be covered by setting up a problem the solver
01059         // finds difficult to solve, but this would be overkill.)
01060         #define COVERAGE_IGNORE
01061         WARN_ONCE_ONLY("Linear solve (within a mechanics solve) didn't converge, but this may not stop nonlinear solve converging")
01062         #undef COVERAGE_IGNORE
01063     }
01064 
01065     // quit if no ksp iterations were done
01066     int num_iters;
01067     KSPGetIterationNumber(solver, &num_iters);
01068     if (num_iters==0)
01069     {
01070         VecDestroy(solution);
01071         KSPDestroy(solver);
01072         EXCEPTION("KSP Absolute tolerance was too high, linear system wasn't solved - there will be no decrease in Newton residual. Decrease KspAbsoluteTolerance");
01073     }
01074 
01075 
01076     #ifdef MECH_VERBOSE
01077     Timer::PrintAndReset("KSP Solve");
01078     std::cout << "[" << PetscTools::GetMyRank() << "]: Num iterations = " << num_iters << "\n" << std::flush;
01079     #endif
01080 
01081     MechanicsEventHandler::EndEvent(MechanicsEventHandler::SOLVE);
01082 
01084     // Update the solution
01085     //  Newton method:       sol = sol - update, where update=Jac^{-1}*residual
01086     //  Newton with damping: sol = sol - s*update, where s is chosen
01087     //   such that |residual(sol)| is minimised. Damping is important to
01088     //   avoid initial divergence.
01089     //
01090     // Normally, finding the best s from say 0.05,0.1,0.2,..,1.0 is cheap,
01091     // but this is not the case in cardiac electromechanics calculations.
01092     // Therefore, we initially check s=1 (expected to be the best most of the
01093     // time, then s=0.9. If the norm of the residual increases, we assume
01094     // s=1 is the best. Otherwise, check s=0.8 to see if s=0.9 is a local min.
01096     MechanicsEventHandler::BeginEvent(MechanicsEventHandler::UPDATE);
01097     double new_norm_resid = UpdateSolutionUsingLineSearch(solution);
01098     MechanicsEventHandler::EndEvent(MechanicsEventHandler::UPDATE);
01099 
01100     VecDestroy(solution);
01101     KSPDestroy(solver);
01102 
01103     return new_norm_resid;
01104 }
01105 
01106 template<unsigned DIM>
01107 void AbstractNonlinearElasticitySolver<DIM>::PrintLineSearchResult(double s, double residNorm)
01108 {
01109     #ifdef MECH_VERBOSE
01110     std::cout << "\tTesting s = " << s << ", |f| = " << residNorm << "\n" << std::flush;
01111     #endif
01112 }
01113 
01114 template<unsigned DIM>
01115 double AbstractNonlinearElasticitySolver<DIM>::UpdateSolutionUsingLineSearch(Vec solution)
01116 {
01117     double initial_norm_resid = CalculateResidualNorm();
01118     #ifdef MECH_VERBOSE
01119     std::cout << "\tInitial |f| [corresponding to s=0] is " << initial_norm_resid << "\n"  << std::flush;
01120     #endif
01121 
01122     ReplicatableVector update(solution);
01123 
01124     std::vector<double> old_solution = mCurrentSolution;
01125 
01126     std::vector<double> damping_values; // = {1.0, 0.9, .., 0.2, 0.1, 0.05} ie size 11
01127     for (unsigned i=10; i>=1; i--)
01128     {
01129         damping_values.push_back((double)i/10.0);
01130     }
01131     damping_values.push_back(0.05);
01132     assert(damping_values.size()==11);
01133 
01135     // let mCurrentSolution = old_solution - damping_val[0]*update; and compute residual
01136     unsigned index = 0;
01137     VectorSum(old_solution, update, -damping_values[index], mCurrentSolution);
01138     double current_resid_norm = ComputeResidualAndGetNorm(true);
01139     PrintLineSearchResult(damping_values[index], current_resid_norm);
01140 
01142     // let mCurrentSolution = old_solution - damping_val[1]*update; and compute residual
01143     index = 1;
01144     VectorSum(old_solution, update, -damping_values[index], mCurrentSolution);
01145     double next_resid_norm = ComputeResidualAndGetNorm(true);
01146     PrintLineSearchResult(damping_values[index], next_resid_norm);
01147 
01148     index = 2;
01149     // While f(s_next) < f(s_current), [f = residnorm], keep trying new damping values,
01150     // ie exit thus loop when next norm of the residual first increases
01151     while (    (next_resid_norm==DBL_MAX) // the residual is returned as infinity if the deformation is so large to cause exceptions in the material law/EM contraction model
01152             || ( (next_resid_norm < current_resid_norm) && (index<damping_values.size()) ) )
01153     {
01154         current_resid_norm = next_resid_norm;
01155 
01156         // let mCurrentSolution = old_solution - damping_val*update; and compute residual
01157         VectorSum(old_solution, update, -damping_values[index], mCurrentSolution);
01158         next_resid_norm = ComputeResidualAndGetNorm(true);
01159         PrintLineSearchResult(damping_values[index], next_resid_norm);
01160 
01161         index++;
01162     }
01163 
01164     unsigned best_index;
01165 
01166     if (index==damping_values.size() && (next_resid_norm < current_resid_norm))
01167     {
01168         // Difficult to come up with large forces/tractions such that it had to
01169         // test right down to s=0.05, but overall doesn't fail.
01170         // The possible damping values have been manually temporarily altered to
01171         // get this code to be called, it appears to work correctly. Even if it
01172         // didn't tests wouldn't fail, they would just be v. slightly less efficient.
01173         #define COVERAGE_IGNORE
01174         // if we exited because we got to the end of the possible damping values, the
01175         // best one was the last one (excl the final index++ at the end)
01176         current_resid_norm = next_resid_norm;
01177         best_index = index-1;
01178         #undef COVERAGE_IGNORE
01179     }
01180     else
01181     {
01182         // else the best one must have been the second last one (excl the final index++ at the end)
01183         // (as we would have exited when the resid norm first increased)
01184         best_index = index-2;
01185     }
01186 
01187     // Check out best was better than the original residual-norm
01188     if (initial_norm_resid < current_resid_norm)
01189     {
01190         #define COVERAGE_IGNORE
01191         // Have to use an assert/exit here as the following exception causes a seg fault (in cardiac mech problems?)
01192         // Don't know why
01193         std::cout << "CHASTE ERROR: (AbstractNonlinearElasticitySolver.hpp): Residual does not appear to decrease in newton direction, quitting.\n" << std::flush;
01194         exit(0);
01195         //EXCEPTION("Residual does not appear to decrease in newton direction, quitting");
01196         #undef COVERAGE_IGNORE
01197     }
01198 
01199     #ifdef MECH_VERBOSE
01200     std::cout << "\tBest s = " << damping_values[best_index] << "\n"  << std::flush;
01201     #endif
01202     VectorSum(old_solution, update, -damping_values[best_index], mCurrentSolution);
01203 
01204     return current_resid_norm;
01205 }
01206 
01207 template<unsigned DIM>
01208 void AbstractNonlinearElasticitySolver<DIM>::PostNewtonStep(unsigned counter, double normResidual)
01209 {
01210 }
01211 
01212 template<unsigned DIM>
01213 AbstractNonlinearElasticitySolver<DIM>::AbstractNonlinearElasticitySolver(QuadraticMesh<DIM>& rQuadMesh,
01214                                                                           SolidMechanicsProblemDefinition<DIM>& rProblemDefinition,
01215                                                                           std::string outputDirectory,
01216                                                                           CompressibilityType compressibilityType)
01217     : mrQuadMesh(rQuadMesh),
01218       mrProblemDefinition(rProblemDefinition),
01219       mpQuadratureRule(NULL),
01220       mpBoundaryQuadratureRule(NULL),
01221       mKspAbsoluteTol(-1),
01222       mResidualVector(NULL),
01223       mJacobianMatrix(NULL),
01224       mPreconditionMatrix(NULL),
01225       mOutputDirectory(outputDirectory),
01226       mpOutputFileHandler(NULL),
01227       mWriteOutputEachNewtonIteration(false),
01228       mNumNewtonIterations(0),
01229       mCurrentTime(0.0),
01230       mCompressibilityType(compressibilityType),
01231       mCheckedOutwardNormals(false)
01232 {
01233     assert(DIM==2 || DIM==3);
01234 
01235     if (mCompressibilityType==COMPRESSIBLE)
01236     {
01237         mNumDofs = DIM*mrQuadMesh.GetNumNodes();
01238     }
01239     else
01240     {
01241         mNumDofs = DIM*mrQuadMesh.GetNumNodes() + mrQuadMesh.GetNumVertices();
01242     }
01243 
01244     mWriteOutput = (mOutputDirectory != "");
01245     if (mWriteOutput)
01246     {
01247         mpOutputFileHandler = new OutputFileHandler(mOutputDirectory);
01248     }
01249 }
01250 
01251 template<unsigned DIM>
01252 AbstractNonlinearElasticitySolver<DIM>::~AbstractNonlinearElasticitySolver()
01253 {
01254     if (mResidualVector)
01255     {
01256         VecDestroy(mResidualVector);
01257         VecDestroy(mLinearSystemRhsVector);
01258         MatDestroy(mJacobianMatrix);
01259         MatDestroy(mPreconditionMatrix);
01260         if (mCompressibilityType==COMPRESSIBLE)
01261         {
01262             VecDestroy(mDirichletBoundaryConditionsVector);
01263         }
01264     }
01265 
01266     if (mpQuadratureRule)
01267     {
01268         delete mpQuadratureRule;
01269         delete mpBoundaryQuadratureRule;
01270     }
01271     if (mpOutputFileHandler)
01272     {
01273         delete mpOutputFileHandler;
01274     }
01275 }
01276 
01277 template<unsigned DIM>
01278 void AbstractNonlinearElasticitySolver<DIM>::Solve(double tol,
01279                                                    unsigned maxNumNewtonIterations,
01280                                                    bool quitIfNoConvergence)
01281 {
01282     // check the problem definition is set up correctly (and fully).
01283     mrProblemDefinition.Validate();
01284 
01285     // If the problem includes specified pressures on deformed surfaces (as opposed
01286     // to specified tractions), the code needs to compute normals, and they need
01287     // to be consistently all facing outward (or all facing inward). Check the undeformed
01288     // mesh boundary elements has nodes that are ordered so that all normals are
01289     // outward-facing
01290     if(mrProblemDefinition.GetTractionBoundaryConditionType()==PRESSURE_ON_DEFORMED && mCheckedOutwardNormals==false)
01291     {
01292         std::cout << "checking...\n";
01293         mrQuadMesh.CheckOutwardNormals();
01294         mCheckedOutwardNormals = true;
01295     }
01296 
01297 
01298     WriteCurrentDeformation("initial");
01299 
01300     if (mWriteOutputEachNewtonIteration)
01301     {
01302         WriteCurrentDeformation("newton_iteration", 0);
01303     }
01304 
01305     // Compute residual
01306     double norm_resid = ComputeResidualAndGetNorm(false);
01307     #ifdef MECH_VERBOSE
01308     std::cout << "\nNorm of residual is " << norm_resid << "\n";
01309     #endif
01310 
01311     mNumNewtonIterations = 0;
01312     unsigned iteration_number = 1;
01313 
01314     if (tol < 0) // i.e. if wasn't passed in as a parameter
01315     {
01316         tol = NEWTON_REL_TOL*norm_resid;
01317 
01318         #define COVERAGE_IGNORE // not going to have tests in cts for everything
01319         if (tol > MAX_NEWTON_ABS_TOL)
01320         {
01321             tol = MAX_NEWTON_ABS_TOL;
01322         }
01323         if (tol < MIN_NEWTON_ABS_TOL)
01324         {
01325             tol = MIN_NEWTON_ABS_TOL;
01326         }
01327         #undef COVERAGE_IGNORE
01328     }
01329 
01330     #ifdef MECH_VERBOSE
01331     std::cout << "Solving with tolerance " << tol << "\n";
01332     #endif
01333 
01334     while (norm_resid > tol && iteration_number<=maxNumNewtonIterations)
01335     {
01336         #ifdef MECH_VERBOSE
01337         std::cout <<  "\n-------------------\n"
01338                   <<   "Newton iteration " << iteration_number
01339                   << ":\n-------------------\n";
01340         #endif
01341 
01342         // take newton step (and get returned residual)
01343         norm_resid = TakeNewtonStep();
01344 
01345         #ifdef MECH_VERBOSE
01346         std::cout << "Norm of residual is " << norm_resid << "\n";
01347         #endif
01348         if (mWriteOutputEachNewtonIteration)
01349         {
01350             WriteCurrentDeformation("newton_iteration", iteration_number);
01351         }
01352 
01353         mNumNewtonIterations = iteration_number;
01354 
01355         PostNewtonStep(iteration_number,norm_resid);
01356 
01357         iteration_number++;
01358         if (iteration_number==20)
01359         {
01360             #define COVERAGE_IGNORE
01361             EXCEPTION("Not converged after 20 newton iterations, quitting");
01362             #undef COVERAGE_IGNORE
01363         }
01364     }
01365 
01366     if ((norm_resid > tol) && quitIfNoConvergence)
01367     {
01368         #define COVERAGE_IGNORE
01369         EXCEPTION("Failed to converge");
01370         #undef COVERAGE_IGNORE
01371     }
01372 
01373     // Write the final solution
01374     WriteCurrentDeformation("solution");
01375 }
01376 
01377 template<unsigned DIM>
01378 void AbstractNonlinearElasticitySolver<DIM>::WriteCurrentDeformation(std::string fileName, int counterToAppend)
01379 {
01380     // Only write output if the flag mWriteOutput has been set
01381     if (!mWriteOutput)
01382     {
01383         return;
01384     }
01385 
01386     std::stringstream file_name;
01387     file_name << fileName;
01388     if (counterToAppend >= 0)
01389     {
01390         file_name << "_" << counterToAppend;
01391     }
01392     file_name << ".nodes";
01393 
01394     out_stream p_file = mpOutputFileHandler->OpenOutputFile(file_name.str());
01395 
01396     std::vector<c_vector<double,DIM> >& r_deformed_position = rGetDeformedPosition();
01397     for (unsigned i=0; i<r_deformed_position.size(); i++)
01398     {
01399         for (unsigned j=0; j<DIM; j++)
01400         {
01401             *p_file << r_deformed_position[i](j) << " ";
01402         }
01403         *p_file << "\n";
01404     }
01405     p_file->close();
01406 }
01407 
01408 template<unsigned DIM>
01409 void AbstractNonlinearElasticitySolver<DIM>::WriteCurrentDeformationGradients(std::string fileName, int counterToAppend)
01410 {
01411     if (!mWriteOutput)
01412     {
01413         return;
01414     }
01415 
01416     std::stringstream file_name;
01417     file_name << fileName;
01418     if (counterToAppend >= 0)
01419     {
01420         file_name << "_" << counterToAppend;
01421     }
01422     file_name << ".strain";
01423 
01424     out_stream p_file = mpOutputFileHandler->OpenOutputFile(file_name.str());
01425 
01426     c_matrix<double,DIM,DIM> deformation_gradient;
01427 
01428     for (typename AbstractTetrahedralMesh<DIM,DIM>::ElementIterator iter = mrQuadMesh.GetElementIteratorBegin();
01429          iter != mrQuadMesh.GetElementIteratorEnd();
01430          ++iter)
01431     {
01432         GetElementCentroidDeformationGradient(*iter, deformation_gradient);
01433         for(unsigned i=0; i<DIM; i++)
01434         {
01435             for(unsigned j=0; j<DIM; j++)
01436             {
01437                 *p_file << deformation_gradient(i,j) << " ";
01438             }
01439         }
01440         *p_file << "\n";
01441     }
01442     p_file->close();
01443 }
01444 
01445 template<unsigned DIM>
01446 unsigned AbstractNonlinearElasticitySolver<DIM>::GetNumNewtonIterations()
01447 {
01448     return mNumNewtonIterations;
01449 }
01450 
01451 template<unsigned DIM>
01452 void AbstractNonlinearElasticitySolver<DIM>::SetWriteOutput(bool writeOutput)
01453 {
01454     if (writeOutput && (mOutputDirectory==""))
01455     {
01456         EXCEPTION("Can't write output if no output directory was given in constructor");
01457     }
01458     mWriteOutput = writeOutput;
01459 }
01460 
01461 template<unsigned DIM>
01462 std::vector<c_vector<double,DIM> >& AbstractNonlinearElasticitySolver<DIM>::rGetDeformedPosition()
01463 {
01464     mDeformedPosition.resize(mrQuadMesh.GetNumNodes(), zero_vector<double>(DIM));
01465     for (unsigned i=0; i<mrQuadMesh.GetNumNodes(); i++)
01466     {
01467         for (unsigned j=0; j<DIM; j++)
01468         {
01469             mDeformedPosition[i](j) = mrQuadMesh.GetNode(i)->rGetLocation()[j] + mCurrentSolution[DIM*i+j];
01470         }
01471     }
01472     return mDeformedPosition;
01473 }
01474 
01475 template<unsigned DIM>
01476 void AbstractNonlinearElasticitySolver<DIM>::CreateCmguiOutput()
01477 {
01478     if (mOutputDirectory=="")
01479     {
01480         EXCEPTION("No output directory was given so no output was written, cannot convert to cmgui format");
01481     }
01482 
01483     CmguiDeformedSolutionsWriter<DIM> writer(mOutputDirectory + "/cmgui",
01484                                              "solution",
01485                                              mrQuadMesh,
01486                                              WRITE_QUADRATIC_MESH);
01487 
01488     std::vector<c_vector<double,DIM> >& r_deformed_positions = rGetDeformedPosition();
01489     writer.WriteInitialMesh(); // this writes solution_0.exnode and .exelem
01490     writer.WriteDeformationPositions(r_deformed_positions, 1); // this writes the final solution as solution_1.exnode
01491     writer.WriteCmguiScript(); // writes LoadSolutions.com
01492 }
01493 
01494 template<unsigned DIM>
01495 void AbstractNonlinearElasticitySolver<DIM>::GetElementCentroidDeformationGradient(Element<DIM,DIM>& rElement,
01496                                                                                    c_matrix<double,DIM,DIM>& rDeformationGradient)
01497 {
01498     static c_matrix<double,DIM,DIM> jacobian;
01499     static c_matrix<double,DIM,DIM> inverse_jacobian;
01500     double jacobian_determinant;
01501 
01502     this->mrQuadMesh.GetInverseJacobianForElement(rElement.GetIndex(), jacobian, jacobian_determinant, inverse_jacobian);
01503 
01504     // Get the current displacement at the nodes
01505     static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> element_current_displacements;
01506     for (unsigned II=0; II<NUM_NODES_PER_ELEMENT; II++)
01507     {
01508         for (unsigned JJ=0; JJ<DIM; JJ++)
01509         {
01510             element_current_displacements(JJ,II) = this->mCurrentSolution[DIM*rElement.GetNodeGlobalIndex(II) + JJ];
01511         }
01512     }
01513 
01514     // Allocate memory for the basis functions values and derivative values
01515     static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi;
01516 
01517 //    // Get the material law
01518 //    AbstractCompressibleMaterialLaw<DIM>* p_material_law
01519 //       = this->mrProblemDefinition.GetCompressibleMaterialLaw(rElement.GetIndex());
01520 
01521     static c_matrix<double,DIM,DIM> grad_u; // grad_u = (du_i/dX_M)
01522 
01523     // we need the point in the canonical element which corresponds to the centroid of the
01524     // version of the element in physical space. This point can be shown to be (1/3,1/3).
01525     ChastePoint<DIM> quadrature_point;
01526     if(DIM==2)
01527     {
01528         quadrature_point.rGetLocation()(0) = 1.0/3.0;
01529         quadrature_point.rGetLocation()(1) = 1.0/3.0;
01530     }
01531     else
01532     {
01533         assert(DIM==3);
01534         quadrature_point.rGetLocation()(0) = 1.0/4.0;
01535         quadrature_point.rGetLocation()(1) = 1.0/4.0;
01536         quadrature_point.rGetLocation()(2) = 1.0/4.0;
01537     }
01538 
01539     QuadraticBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(quadrature_point, inverse_jacobian, grad_quad_phi);
01540 
01541     // Interpolate grad_u
01542     grad_u = zero_matrix<double>(DIM,DIM);
01543     for (unsigned node_index=0; node_index<NUM_NODES_PER_ELEMENT; node_index++)
01544     {
01545         for (unsigned i=0; i<DIM; i++)
01546         {
01547             for (unsigned M=0; M<DIM; M++)
01548             {
01549                 grad_u(i,M) += grad_quad_phi(M,node_index)*element_current_displacements(i,node_index);
01550             }
01551         }
01552     }
01553 
01554     for (unsigned i=0; i<DIM; i++)
01555     {
01556         for (unsigned M=0; M<DIM; M++)
01557         {
01558             rDeformationGradient(i,M) = (i==M?1:0) + grad_u(i,M);
01559         }
01560     }
01561 //
01562 //        C = prod(trans(F),F);
01563 //        inv_C = Inverse(C);
01564 //        inv_F = Inverse(F);
01565 //
01566 //        this->ComputeStressAndStressDerivative(p_material_law, C, inv_C, 0.0, rElement.GetIndex(), current_quad_point_global_index,
01567 //                                               T, dTdE, assembleJacobian);
01568 }
01569 
01570 // Constant setting definitions
01571 
01572 template<unsigned DIM>
01573 double AbstractNonlinearElasticitySolver<DIM>::MAX_NEWTON_ABS_TOL = 1e-7;
01574 
01575 template<unsigned DIM>
01576 double AbstractNonlinearElasticitySolver<DIM>::MIN_NEWTON_ABS_TOL = 1e-10;
01577 
01578 template<unsigned DIM>
01579 double AbstractNonlinearElasticitySolver<DIM>::NEWTON_REL_TOL = 1e-4;
01580 
01581 #endif /*ABSTRACTNONLINEARELASTICITYSOLVER_HPP_*/
Generated on Thu Dec 22 13:00:05 2011 for Chaste by  doxygen 1.6.3