00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #ifndef ABSTRACTNONLINEARELASTICITYSOLVER_HPP_
00037 #define ABSTRACTNONLINEARELASTICITYSOLVER_HPP_
00038
00039 #include <vector>
00040 #include <cmath>
00041 #include "AbstractContinuumMechanicsSolver.hpp"
00042 #include "LinearSystem.hpp"
00043 #include "LogFile.hpp"
00044 #include "MechanicsEventHandler.hpp"
00045 #include "ReplicatableVector.hpp"
00046 #include "FourthOrderTensor.hpp"
00047 #include "CmguiDeformedSolutionsWriter.hpp"
00048 #include "AbstractMaterialLaw.hpp"
00049 #include "QuadraticBasisFunction.hpp"
00050 #include "SolidMechanicsProblemDefinition.hpp"
00051 #include "Timer.hpp"
00052 #include "AbstractPerElementWriter.hpp"
00053 #include "petscsnes.h"
00054
00055
00056
00057
00058
00059
00064 typedef enum StrainType_
00065 {
00066 DEFORMATION_GRADIENT_F = 0,
00067 DEFORMATION_TENSOR_C,
00068 LAGRANGE_STRAIN_E
00069 } StrainType;
00070
00071
00072
00073
00074 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00075 extern PetscErrorCode KSPInitialResidual(KSP,Vec,Vec,Vec,Vec,Vec);
00076 #endif
00077
00078
00080
00082
00092 template<unsigned DIM>
00093 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeResidual(SNES snes,
00094 Vec currentGuess,
00095 Vec residualVector,
00096 void* pContext);
00097
00108 template<unsigned DIM>
00109 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeJacobian(SNES snes,
00110 Vec currentGuess,
00111 Mat* pGlobalJacobian,
00112 Mat* pPreconditioner,
00113 MatStructure* pMatStructure,
00114 void* pContext);
00115 template <unsigned DIM>
00116 class AbstractNonlinearElasticitySolver;
00117
00124 template<unsigned DIM>
00125 class StressPerElementWriter : public AbstractPerElementWriter<DIM, DIM, DIM*DIM>
00126 {
00127 private:
00128 AbstractNonlinearElasticitySolver<DIM>* mpSolver;
00129 public:
00130
00135 StressPerElementWriter(AbstractTetrahedralMesh<DIM, DIM>* pMesh,
00136 AbstractNonlinearElasticitySolver<DIM>* pSolver)
00137 : AbstractPerElementWriter<DIM, DIM, DIM*DIM>(pMesh),
00138 mpSolver(pSolver)
00139 {
00140 }
00141
00149 void Visit(Element<DIM, DIM>* pElement, unsigned localIndex, c_vector<double, DIM*DIM>& rData)
00150 {
00154 assert(localIndex == pElement->GetIndex());
00155
00156 c_matrix<double, DIM, DIM> data = mpSolver->GetAverageStressPerElement(localIndex);
00157 for (unsigned i=0; i<DIM; i++)
00158 {
00159 for (unsigned j=0; j<DIM; j++)
00160 {
00161 rData[i*DIM+j] = data(i,j);
00162 }
00163 }
00164 }
00165 };
00166
00178 template<unsigned DIM>
00179 class AbstractNonlinearElasticitySolver : public AbstractContinuumMechanicsSolver<DIM>
00180 {
00181 friend class StressRecoveror<DIM>;
00182 friend class VtkNonlinearElasticitySolutionWriter<DIM>;
00183
00184
00185 protected:
00186
00188 static const size_t NUM_VERTICES_PER_ELEMENT = DIM+1;
00189
00191 static const size_t NUM_NODES_PER_ELEMENT = (DIM+1)*(DIM+2)/2;
00192
00194 static const size_t NUM_NODES_PER_BOUNDARY_ELEMENT = DIM*(DIM+1)/2;
00195
00200 static const size_t BOUNDARY_STENCIL_SIZE = DIM*NUM_NODES_PER_BOUNDARY_ELEMENT;
00201
00209 static double MAX_NEWTON_ABS_TOL;
00210
00212 static double MIN_NEWTON_ABS_TOL;
00213
00215 static double NEWTON_REL_TOL;
00216
00221 SolidMechanicsProblemDefinition<DIM>& mrProblemDefinition;
00222
00227 Mat& mrJacobianMatrix;
00228
00235 c_matrix<double,DIM,DIM> mChangeOfBasisMatrix;
00236
00242 double mKspAbsoluteTol;
00243
00249 bool mWriteOutputEachNewtonIteration;
00250
00254 FourthOrderTensor<DIM,DIM,DIM,DIM> dTdE;
00255
00257 unsigned mNumNewtonIterations;
00258
00264 double mCurrentTime;
00265
00266
00270 bool mCheckedOutwardNormals;
00271
00276 bool mUseSnesSolver;
00277
00283 double mLastDampingValue;
00284
00288 bool mFirstStep;
00289
00294 bool mTakeFullFirstNewtonStep;
00295
00299 bool mPetscDirectSolve;
00300
00308 bool mIncludeActiveTension;
00309
00314 bool mSetComputeAverageStressPerElement;
00315
00323 std::vector<c_vector<double,DIM*(DIM+1)/2> > mAverageStressesPerElement;
00324
00332 void AddStressToAverageStressPerElement(c_matrix<double,DIM,DIM>& rT, unsigned elementIndex);
00333
00342 virtual void SetKspSolverAndPcType(KSP solver);
00343
00344
00357 virtual void AssembleSystem(bool assembleResidual, bool assembleLinearSystem)=0;
00358
00359
00360
00368 virtual void FinishAssembleSystem(bool assembleResidual, bool assembleLinearSystem);
00369
00370
00372
00373
00374
00376
00384 void GetElementCentroidStrain(StrainType strainType,
00385 Element<DIM,DIM>& rElement,
00386 c_matrix<double,DIM,DIM>& rDeformationGradient);
00387
00406 virtual void AddActiveStressAndStressDerivative(c_matrix<double,DIM,DIM>& rC,
00407 unsigned elementIndex,
00408 unsigned currentQuadPointGlobalIndex,
00409 c_matrix<double,DIM,DIM>& rT,
00410 FourthOrderTensor<DIM,DIM,DIM,DIM>& rDTdE,
00411 bool addToDTdE)
00412 {
00413
00414 }
00415
00423 virtual void SetupChangeOfBasisMatrix(unsigned elementIndex, unsigned currentQuadPointGlobalIndex)
00424 {
00425 }
00426
00427
00428
00447 void AssembleOnBoundaryElement(BoundaryElement<DIM-1, DIM>& rBoundaryElement,
00448 c_matrix<double, BOUNDARY_STENCIL_SIZE, BOUNDARY_STENCIL_SIZE>& rAelem,
00449 c_vector<double, BOUNDARY_STENCIL_SIZE>& rBelem,
00450 bool assembleResidual,
00451 bool assembleJacobian,
00452 unsigned boundaryConditionIndex);
00453
00454
00469 bool ShouldAssembleMatrixTermForPressureOnDeformedBc();
00470
00490 void AssembleOnBoundaryElementForPressureOnDeformedBc(BoundaryElement<DIM-1,DIM>& rBoundaryElement,
00491 c_matrix<double,BOUNDARY_STENCIL_SIZE,BOUNDARY_STENCIL_SIZE>& rAelem,
00492 c_vector<double,BOUNDARY_STENCIL_SIZE>& rBelem,
00493 bool assembleResidual,
00494 bool assembleJacobian,
00495 unsigned boundaryConditionIndex);
00496
00498
00499
00500
00502
00514 double ComputeResidualAndGetNorm(bool allowException);
00515
00517 double CalculateResidualNorm();
00518
00528 void VectorSum(std::vector<double>& rX, ReplicatableVector& rY, double a, std::vector<double>& rZ);
00529
00537 void PrintLineSearchResult(double s, double residNorm);
00538
00546 double TakeNewtonStep();
00547
00557 double UpdateSolutionUsingLineSearch(Vec solution);
00558
00566 virtual void PostNewtonStep(unsigned counter, double normResidual);
00567
00573 void SolveNonSnes(double tol=-1.0);
00574
00575
00577
00578
00579
00581 public:
00588 void ComputeResidual(Vec currentGuess, Vec residualVector);
00589
00597 void ComputeJacobian(Vec currentGuess, Mat* pJacobian, Mat* pPreconditioner);
00598
00599 private:
00604 void SolveSnes();
00605
00606 public:
00607
00618 AbstractNonlinearElasticitySolver(AbstractTetrahedralMesh<DIM,DIM>& rQuadMesh,
00619 SolidMechanicsProblemDefinition<DIM>& rProblemDefinition,
00620 std::string outputDirectory,
00621 CompressibilityType compressibilityType);
00622
00626 virtual ~AbstractNonlinearElasticitySolver();
00627
00633 void Solve(double tol=-1.0);
00634
00644 void SetIncludeActiveTension(bool includeActiveTension = true)
00645 {
00646 mIncludeActiveTension = includeActiveTension;
00647 }
00648
00652 unsigned GetNumNewtonIterations();
00653
00654
00662 void SetWriteOutputEachNewtonIteration(bool writeOutputEachNewtonIteration=true)
00663 {
00664 mWriteOutputEachNewtonIteration = writeOutputEachNewtonIteration;
00665 }
00666
00673 void SetKspAbsoluteTolerance(double kspAbsoluteTolerance)
00674 {
00675 assert(kspAbsoluteTolerance > 0);
00676 mKspAbsoluteTol = kspAbsoluteTolerance;
00677 }
00678
00692 void SetTakeFullFirstNewtonStep(bool takeFullFirstStep = true)
00693 {
00694 mTakeFullFirstNewtonStep = takeFullFirstStep;
00695 }
00696
00710 void SetUsePetscDirectSolve(bool usePetscDirectSolve = true)
00711 {
00712 mPetscDirectSolve = usePetscDirectSolve;
00713 }
00714
00715
00722 void SetCurrentTime(double time)
00723 {
00724 mCurrentTime = time;
00725 }
00726
00731 void CreateCmguiOutput();
00732
00733
00747 void WriteCurrentStrains(StrainType strainType, std::string fileName, int counterToAppend = -1);
00748
00755 void SetComputeAverageStressPerElementDuringSolve(bool setComputeAverageStressPerElement = true);
00756
00770 void WriteCurrentAverageElementStresses(std::string fileName, int counterToAppend = -1);
00771
00776 std::vector<c_vector<double,DIM> >& rGetSpatialSolution();
00777
00782 std::vector<c_vector<double,DIM> >& rGetDeformedPosition();
00783
00792 c_matrix<double,DIM,DIM> GetAverageStressPerElement(unsigned elementIndex);
00793 };
00794
00796
00798
00799 template<unsigned DIM>
00800 AbstractNonlinearElasticitySolver<DIM>::AbstractNonlinearElasticitySolver(AbstractTetrahedralMesh<DIM,DIM>& rQuadMesh,
00801 SolidMechanicsProblemDefinition<DIM>& rProblemDefinition,
00802 std::string outputDirectory,
00803 CompressibilityType compressibilityType)
00804 : AbstractContinuumMechanicsSolver<DIM>(rQuadMesh, rProblemDefinition, outputDirectory, compressibilityType),
00805 mrProblemDefinition(rProblemDefinition),
00806 mrJacobianMatrix(this->mSystemLhsMatrix),
00807 mKspAbsoluteTol(-1),
00808 mWriteOutputEachNewtonIteration(false),
00809 mNumNewtonIterations(0),
00810 mCurrentTime(0.0),
00811 mCheckedOutwardNormals(false),
00812 mLastDampingValue(0.0),
00813 mIncludeActiveTension(true),
00814 mSetComputeAverageStressPerElement(false)
00815 {
00816 mUseSnesSolver = (mrProblemDefinition.GetSolveUsingSnes() ||
00817 CommandLineArguments::Instance()->OptionExists("-mech_use_snes") );
00818
00819 mChangeOfBasisMatrix = identity_matrix<double>(DIM,DIM);
00820
00821 mTakeFullFirstNewtonStep = CommandLineArguments::Instance()->OptionExists("-mech_full_first_newton_step");
00822 mPetscDirectSolve = CommandLineArguments::Instance()->OptionExists("-mech_petsc_direct_solve");
00823 }
00824
00825 template<unsigned DIM>
00826 AbstractNonlinearElasticitySolver<DIM>::~AbstractNonlinearElasticitySolver()
00827 {
00828 }
00829
00830
00831 template<unsigned DIM>
00832 void AbstractNonlinearElasticitySolver<DIM>::FinishAssembleSystem(bool assembleResidual, bool assembleJacobian)
00833 {
00834 PetscVecTools::Finalise(this->mResidualVector);
00835
00836 if (assembleJacobian)
00837 {
00838 PetscMatTools::SwitchWriteMode(mrJacobianMatrix);
00839 PetscMatTools::SwitchWriteMode(this->mPreconditionMatrix);
00840
00841 VecCopy(this->mResidualVector, this->mLinearSystemRhsVector);
00842 }
00843
00844
00845 if(assembleJacobian)
00846 {
00847 this->ApplyDirichletBoundaryConditions(NONLINEAR_PROBLEM_APPLY_TO_EVERYTHING, this->mCompressibilityType==COMPRESSIBLE);
00848 }
00849 else if (assembleResidual)
00850 {
00851 this->ApplyDirichletBoundaryConditions(NONLINEAR_PROBLEM_APPLY_TO_RESIDUAL_ONLY, this->mCompressibilityType==COMPRESSIBLE);
00852 }
00853
00854 if (assembleResidual)
00855 {
00856 PetscVecTools::Finalise(this->mResidualVector);
00857 }
00858 if (assembleJacobian)
00859 {
00860 PetscMatTools::Finalise(mrJacobianMatrix);
00861 PetscMatTools::Finalise(this->mPreconditionMatrix);
00862 PetscVecTools::Finalise(this->mLinearSystemRhsVector);
00863 }
00864 }
00865
00866
00867 template<unsigned DIM>
00868 std::vector<c_vector<double,DIM> >& AbstractNonlinearElasticitySolver<DIM>::rGetSpatialSolution()
00869 {
00870 this->mSpatialSolution.clear();
00871 this->mSpatialSolution.resize(this->mrQuadMesh.GetNumNodes(), zero_vector<double>(DIM));
00872 for (unsigned i=0; i<this->mrQuadMesh.GetNumNodes(); i++)
00873 {
00874 for (unsigned j=0; j<DIM; j++)
00875 {
00876 this->mSpatialSolution[i](j) = this->mrQuadMesh.GetNode(i)->rGetLocation()[j] + this->mCurrentSolution[this->mProblemDimension*i+j];
00877 }
00878 }
00879 return this->mSpatialSolution;
00880 }
00881
00882 template<unsigned DIM>
00883 std::vector<c_vector<double,DIM> >& AbstractNonlinearElasticitySolver<DIM>::rGetDeformedPosition()
00884 {
00885 return rGetSpatialSolution();
00886 }
00887
00888
00889 template<unsigned DIM>
00890 void AbstractNonlinearElasticitySolver<DIM>::WriteCurrentStrains(StrainType strainType, std::string fileName, int counterToAppend)
00891 {
00892 if (!this->mWriteOutput)
00893 {
00894 return;
00895 }
00896
00897 std::stringstream file_name;
00898 file_name << fileName;
00899 if (counterToAppend >= 0)
00900 {
00901 file_name << "_" << counterToAppend;
00902 }
00903 file_name << ".strain";
00904
00905 out_stream p_file = this->mpOutputFileHandler->OpenOutputFile(file_name.str());
00906
00907 c_matrix<double,DIM,DIM> strain;
00908
00909 for (typename AbstractTetrahedralMesh<DIM,DIM>::ElementIterator iter = this->mrQuadMesh.GetElementIteratorBegin();
00910 iter != this->mrQuadMesh.GetElementIteratorEnd();
00911 ++iter)
00912 {
00913 GetElementCentroidStrain(strainType, *iter, strain);
00914 for(unsigned i=0; i<DIM; i++)
00915 {
00916 for(unsigned j=0; j<DIM; j++)
00917 {
00918 *p_file << strain(i,j) << " ";
00919 }
00920 }
00921 *p_file << "\n";
00922 }
00923 p_file->close();
00924 }
00925
00926
00927
00928 template<unsigned DIM>
00929 void AbstractNonlinearElasticitySolver<DIM>::WriteCurrentAverageElementStresses(std::string fileName, int counterToAppend)
00930 {
00931 if (!this->mWriteOutput)
00932 {
00933 return;
00934 }
00935
00936 if(!mSetComputeAverageStressPerElement)
00937 {
00938 EXCEPTION("Call SetComputeAverageStressPerElementDuringSolve() before solve if calling WriteCurrentAverageElementStresses()");
00939 }
00940
00941 std::stringstream file_name;
00942 file_name << fileName;
00943 if (counterToAppend >= 0)
00944 {
00945 file_name << "_" << counterToAppend;
00946 }
00947 file_name << ".stress";
00948 assert(mAverageStressesPerElement.size()==this->mrQuadMesh.GetNumElements());
00949
00950 StressPerElementWriter<DIM> stress_writer(&(this->mrQuadMesh),this);
00951 stress_writer.WriteData(*(this->mpOutputFileHandler), file_name.str());
00952 }
00953
00954
00955 template<unsigned DIM>
00956 void AbstractNonlinearElasticitySolver<DIM>::CreateCmguiOutput()
00957 {
00958 if (this->mOutputDirectory=="")
00959 {
00960 EXCEPTION("No output directory was given so no output was written, cannot convert to cmgui format");
00961 }
00962
00963 CmguiDeformedSolutionsWriter<DIM> writer(this->mOutputDirectory + "/cmgui",
00964 "solution",
00965 this->mrQuadMesh,
00966 WRITE_QUADRATIC_MESH);
00967
00968 std::vector<c_vector<double,DIM> >& r_deformed_positions = this->rGetDeformedPosition();
00969 writer.WriteInitialMesh();
00970 writer.WriteDeformationPositions(r_deformed_positions, 1);
00971 writer.WriteCmguiScript();
00972 }
00973
00974 template<unsigned DIM>
00975 void AbstractNonlinearElasticitySolver<DIM>::SetComputeAverageStressPerElementDuringSolve(bool setComputeAverageStressPerElement)
00976 {
00977 mSetComputeAverageStressPerElement = setComputeAverageStressPerElement;
00978 if(setComputeAverageStressPerElement && mAverageStressesPerElement.size()==0)
00979 {
00980 mAverageStressesPerElement.resize(this->mrQuadMesh.GetNumElements(), zero_vector<double>(DIM*(DIM+1)/2));
00981 }
00982 }
00983
00984 template<unsigned DIM>
00985 void AbstractNonlinearElasticitySolver<DIM>::AddStressToAverageStressPerElement(c_matrix<double,DIM,DIM>& rT, unsigned elemIndex)
00986 {
00987 assert(mSetComputeAverageStressPerElement);
00988 assert(elemIndex<this->mrQuadMesh.GetNumElements());
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998 for(unsigned i=0; i<DIM*(DIM+1)/2; i++)
00999 {
01000 unsigned row;
01001 unsigned col;
01002 if(DIM==2)
01003 {
01004 row = i<=1 ? 0 : 1;
01005 col = i==0 ? 0 : 1;
01006 }
01007 else
01008 {
01009 row = i<=2 ? 0 : (i<=4? 1 : 2);
01010 col = i==0 ? 0 : (i==1 || i==3? 1 : 2);
01011 }
01012
01013 this->mAverageStressesPerElement[elemIndex](i) += rT(row,col);
01014 }
01015 }
01016
01017
01018 template<unsigned DIM>
01019 c_matrix<double,DIM,DIM> AbstractNonlinearElasticitySolver<DIM>::GetAverageStressPerElement(unsigned elementIndex)
01020 {
01021 if(!mSetComputeAverageStressPerElement)
01022 {
01023 EXCEPTION("Call SetComputeAverageStressPerElementDuringSolve() before solve if calling GetAverageStressesPerElement()");
01024 }
01025 assert(elementIndex<this->mrQuadMesh.GetNumElements());
01026
01027 c_matrix<double,DIM,DIM> stress;
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037 if(DIM==2)
01038 {
01039 stress(0,0) = mAverageStressesPerElement[elementIndex](0);
01040 stress(1,0) = stress(0,1) = mAverageStressesPerElement[elementIndex](1);
01041 stress(1,1) = mAverageStressesPerElement[elementIndex](2);
01042 }
01043 else
01044 {
01045 stress(0,0) = mAverageStressesPerElement[elementIndex](0);
01046 stress(1,0) = stress(0,1) = mAverageStressesPerElement[elementIndex](1);
01047 stress(2,0) = stress(0,2) = mAverageStressesPerElement[elementIndex](2);
01048 stress(1,1) = mAverageStressesPerElement[elementIndex](3);
01049 stress(2,1) = stress(1,2) = mAverageStressesPerElement[elementIndex](4);
01050 stress(2,2) = mAverageStressesPerElement[elementIndex](5);
01051 }
01052
01053 return stress;
01054 }
01055
01056
01058
01060
01061 template<unsigned DIM>
01062 void AbstractNonlinearElasticitySolver<DIM>::GetElementCentroidStrain(StrainType strainType,
01063 Element<DIM,DIM>& rElement,
01064 c_matrix<double,DIM,DIM>& rStrain)
01065 {
01066 static c_matrix<double,DIM,DIM> jacobian;
01067 static c_matrix<double,DIM,DIM> inverse_jacobian;
01068 double jacobian_determinant;
01069
01070 this->mrQuadMesh.GetInverseJacobianForElement(rElement.GetIndex(), jacobian, jacobian_determinant, inverse_jacobian);
01071
01072
01073 static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> element_current_displacements;
01074 for (unsigned II=0; II<NUM_NODES_PER_ELEMENT; II++)
01075 {
01076 for (unsigned JJ=0; JJ<DIM; JJ++)
01077 {
01078 element_current_displacements(JJ,II) = this->mCurrentSolution[this->mProblemDimension*rElement.GetNodeGlobalIndex(II) + JJ];
01079 }
01080 }
01081
01082
01083 static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi;
01084 static c_matrix<double,DIM,DIM> grad_u;
01085
01086
01087
01088 ChastePoint<DIM> quadrature_point;
01089 if(DIM==2)
01090 {
01091 quadrature_point.rGetLocation()(0) = 1.0/3.0;
01092 quadrature_point.rGetLocation()(1) = 1.0/3.0;
01093 }
01094 else
01095 {
01096 assert(DIM==3);
01097 quadrature_point.rGetLocation()(0) = 1.0/4.0;
01098 quadrature_point.rGetLocation()(1) = 1.0/4.0;
01099 quadrature_point.rGetLocation()(2) = 1.0/4.0;
01100 }
01101
01102 QuadraticBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(quadrature_point, inverse_jacobian, grad_quad_phi);
01103
01104
01105 grad_u = zero_matrix<double>(DIM,DIM);
01106 for (unsigned node_index=0; node_index<NUM_NODES_PER_ELEMENT; node_index++)
01107 {
01108 for (unsigned i=0; i<DIM; i++)
01109 {
01110 for (unsigned M=0; M<DIM; M++)
01111 {
01112 grad_u(i,M) += grad_quad_phi(M,node_index)*element_current_displacements(i,node_index);
01113 }
01114 }
01115 }
01116
01117 c_matrix<double,DIM,DIM> deformation_gradient;
01118
01119 for (unsigned i=0; i<DIM; i++)
01120 {
01121 for (unsigned M=0; M<DIM; M++)
01122 {
01123 deformation_gradient(i,M) = (i==M?1:0) + grad_u(i,M);
01124 }
01125 }
01126
01127 switch(strainType)
01128 {
01129 case DEFORMATION_GRADIENT_F:
01130 {
01131 rStrain = deformation_gradient;
01132 break;
01133 }
01134 case DEFORMATION_TENSOR_C:
01135 {
01136 rStrain = prod(trans(deformation_gradient),deformation_gradient);
01137 break;
01138 }
01139 case LAGRANGE_STRAIN_E:
01140 {
01141 c_matrix<double,DIM,DIM> C = prod(trans(deformation_gradient),deformation_gradient);
01142 for (unsigned M=0; M<DIM; M++)
01143 {
01144 for (unsigned N=0; N<DIM; N++)
01145 {
01146 rStrain(M,N) = 0.5* ( C(M,N)-(M==N?1:0) );
01147 }
01148 }
01149 break;
01150 }
01151 default:
01152 {
01153 NEVER_REACHED;
01154 break;
01155 }
01156 }
01157 }
01158
01159
01160
01161 template<unsigned DIM>
01162 void AbstractNonlinearElasticitySolver<DIM>::AssembleOnBoundaryElement(
01163 BoundaryElement<DIM-1,DIM>& rBoundaryElement,
01164 c_matrix<double,BOUNDARY_STENCIL_SIZE,BOUNDARY_STENCIL_SIZE>& rAelem,
01165 c_vector<double,BOUNDARY_STENCIL_SIZE>& rBelem,
01166 bool assembleResidual,
01167 bool assembleJacobian,
01168 unsigned boundaryConditionIndex)
01169 {
01170 if( this->mrProblemDefinition.GetTractionBoundaryConditionType() == PRESSURE_ON_DEFORMED
01171 || this->mrProblemDefinition.GetTractionBoundaryConditionType() == FUNCTIONAL_PRESSURE_ON_DEFORMED)
01172 {
01173 AssembleOnBoundaryElementForPressureOnDeformedBc(rBoundaryElement, rAelem, rBelem,
01174 assembleResidual, assembleJacobian, boundaryConditionIndex);
01175 return;
01176 }
01177
01178 rAelem.clear();
01179 rBelem.clear();
01180
01181 if (assembleJacobian && !assembleResidual)
01182 {
01183
01184 return;
01185 }
01186
01187 c_vector<double, DIM> weighted_direction;
01188 double jacobian_determinant;
01189 this->mrQuadMesh.GetWeightedDirectionForBoundaryElement(rBoundaryElement.GetIndex(), weighted_direction, jacobian_determinant);
01190
01191 c_vector<double,NUM_NODES_PER_BOUNDARY_ELEMENT> phi;
01192
01193 for (unsigned quad_index=0; quad_index<this->mpBoundaryQuadratureRule->GetNumQuadPoints(); quad_index++)
01194 {
01195 double wJ = jacobian_determinant * this->mpBoundaryQuadratureRule->GetWeight(quad_index);
01196
01197 const ChastePoint<DIM-1>& quad_point = this->mpBoundaryQuadratureRule->rGetQuadPoint(quad_index);
01198
01199 QuadraticBasisFunction<DIM-1>::ComputeBasisFunctions(quad_point, phi);
01200
01201
01202
01203 c_vector<double,DIM> traction = zero_vector<double>(DIM);
01204 switch (this->mrProblemDefinition.GetTractionBoundaryConditionType())
01205 {
01206 case FUNCTIONAL_TRACTION:
01207 {
01208 c_vector<double,DIM> X = zero_vector<double>(DIM);
01209 for (unsigned node_index=0; node_index<NUM_NODES_PER_BOUNDARY_ELEMENT; node_index++)
01210 {
01211 X += phi(node_index)*this->mrQuadMesh.GetNode( rBoundaryElement.GetNodeGlobalIndex(node_index) )->rGetLocation();
01212 }
01213 traction = this->mrProblemDefinition.EvaluateTractionFunction(X, this->mCurrentTime);
01214 break;
01215 }
01216 case ELEMENTWISE_TRACTION:
01217 {
01218 traction = this->mrProblemDefinition.rGetElementwiseTractions()[boundaryConditionIndex];
01219 break;
01220 }
01221 default:
01222 NEVER_REACHED;
01223 }
01224
01225
01226 for (unsigned index=0; index<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index++)
01227 {
01228 unsigned spatial_dim = index%DIM;
01229 unsigned node_index = (index-spatial_dim)/DIM;
01230
01231 assert(node_index < NUM_NODES_PER_BOUNDARY_ELEMENT);
01232
01233 rBelem(index) -= traction(spatial_dim)
01234 * phi(node_index)
01235 * wJ;
01236 }
01237 }
01238 }
01239
01240 template<unsigned DIM>
01241 bool AbstractNonlinearElasticitySolver<DIM>::ShouldAssembleMatrixTermForPressureOnDeformedBc()
01242 {
01243 if(mUseSnesSolver)
01244 {
01245
01246
01247
01248
01249 return true;
01250
01251
01252
01253
01254
01255 }
01256 else
01257 {
01258 return (mLastDampingValue >= 0.5);
01259 }
01260
01261 }
01262
01263 template<unsigned DIM>
01264 void AbstractNonlinearElasticitySolver<DIM>::AssembleOnBoundaryElementForPressureOnDeformedBc(
01265 BoundaryElement<DIM-1,DIM>& rBoundaryElement,
01266 c_matrix<double,BOUNDARY_STENCIL_SIZE,BOUNDARY_STENCIL_SIZE>& rAelem,
01267 c_vector<double,BOUNDARY_STENCIL_SIZE>& rBelem,
01268 bool assembleResidual,
01269 bool assembleJacobian,
01270 unsigned boundaryConditionIndex)
01271 {
01272 assert( this->mrProblemDefinition.GetTractionBoundaryConditionType()==PRESSURE_ON_DEFORMED
01273 || this->mrProblemDefinition.GetTractionBoundaryConditionType()==FUNCTIONAL_PRESSURE_ON_DEFORMED);
01274
01275 rAelem.clear();
01276 rBelem.clear();
01277
01278 c_vector<double, DIM> weighted_direction;
01279 double jacobian_determinant;
01280
01281 this->mrQuadMesh.GetWeightedDirectionForBoundaryElement(rBoundaryElement.GetIndex(), weighted_direction, jacobian_determinant);
01282
01283
01285
01286
01288
01289 Element<DIM,DIM>* p_containing_vol_element = NULL;
01290
01291 std::set<unsigned> potential_elements = rBoundaryElement.GetNode(0)->rGetContainingElementIndices();
01292 for(std::set<unsigned>::iterator iter = potential_elements.begin();
01293 iter != potential_elements.end();
01294 iter++)
01295 {
01296 p_containing_vol_element = this->mrQuadMesh.GetElement(*iter);
01297
01298 bool this_vol_ele_contains_surf_ele = true;
01299
01300 for(unsigned i=1; i<NUM_NODES_PER_BOUNDARY_ELEMENT; i++)
01301 {
01302 unsigned surf_element_node_index = rBoundaryElement.GetNodeGlobalIndex(i);
01303 bool found_this_node = false;
01304 for(unsigned j=0; j<p_containing_vol_element->GetNumNodes(); j++)
01305 {
01306 unsigned vol_element_node_index = p_containing_vol_element->GetNodeGlobalIndex(j);
01307 if(surf_element_node_index == vol_element_node_index)
01308 {
01309 found_this_node = true;
01310 break;
01311 }
01312 }
01313 if(!found_this_node)
01314 {
01315 this_vol_ele_contains_surf_ele = false;
01316 break;
01317 }
01318 }
01319 if(this_vol_ele_contains_surf_ele)
01320 {
01321 break;
01322 }
01323 }
01324
01325
01326 std::vector<unsigned> surf_to_vol_map(NUM_NODES_PER_BOUNDARY_ELEMENT);
01327 for(unsigned i=0; i<NUM_NODES_PER_BOUNDARY_ELEMENT; i++)
01328 {
01329 unsigned index = rBoundaryElement.GetNodeGlobalIndex(i);
01330 for(unsigned j=0; j<NUM_NODES_PER_ELEMENT; j++)
01331 {
01332 if(p_containing_vol_element->GetNodeGlobalIndex(j)==index)
01333 {
01334 surf_to_vol_map[i] = j;
01335 break;
01336 }
01337 }
01338 }
01339
01340
01341
01342
01343 static c_matrix<double,DIM,DIM> jacobian_vol_element;
01344 static c_matrix<double,DIM,DIM> inverse_jacobian_vol_element;
01345 double jacobian_determinant_vol_element;
01346 this->mrQuadMesh.GetInverseJacobianForElement(p_containing_vol_element->GetIndex(), jacobian_vol_element, jacobian_determinant_vol_element, inverse_jacobian_vol_element);
01347
01348
01349 static c_matrix<double,DIM,NUM_NODES_PER_ELEMENT> element_current_displacements;
01350 for (unsigned II=0; II<NUM_NODES_PER_ELEMENT; II++)
01351 {
01352 for (unsigned JJ=0; JJ<DIM; JJ++)
01353 {
01354 element_current_displacements(JJ,II) = this->mCurrentSolution[this->mProblemDimension*p_containing_vol_element->GetNodeGlobalIndex(II) + JJ];
01355 }
01356 }
01357
01358
01359
01360 static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi_vol_element;
01361
01362 c_vector<double,NUM_NODES_PER_BOUNDARY_ELEMENT> quad_phi_surf_element;
01363
01364 static c_matrix<double, DIM, NUM_NODES_PER_BOUNDARY_ELEMENT> grad_quad_phi_surf_element;
01365
01366 c_matrix<double,DIM,DIM> F;
01367 c_matrix<double,DIM,DIM> invF;
01368
01369 c_vector<double,DIM> normal = rBoundaryElement.CalculateNormal();
01370 c_matrix<double,1,DIM> normal_as_mat;
01371 for(unsigned i=0; i<DIM; i++)
01372 {
01373 normal_as_mat(0,i) = normal(i);
01374 }
01375
01376 double normal_pressure;
01377 switch (this->mrProblemDefinition.GetTractionBoundaryConditionType())
01378 {
01379 case PRESSURE_ON_DEFORMED:
01380 normal_pressure = this->mrProblemDefinition.GetNormalPressure();
01381 break;
01382 case FUNCTIONAL_PRESSURE_ON_DEFORMED:
01383 normal_pressure = this->mrProblemDefinition.EvaluateNormalPressureFunction(this->mCurrentTime);
01384 break;
01385 default:
01386 NEVER_REACHED;
01387 }
01388
01389
01390
01391 for (unsigned quad_index=0; quad_index<this->mpBoundaryQuadratureRule->GetNumQuadPoints(); quad_index++)
01392 {
01393 double wJ = jacobian_determinant * this->mpBoundaryQuadratureRule->GetWeight(quad_index);
01394
01395
01396
01397 const ChastePoint<DIM-1>& quadrature_point = this->mpBoundaryQuadratureRule->rGetQuadPoint(quad_index);
01398 QuadraticBasisFunction<DIM-1>::ComputeBasisFunctions(quadrature_point, quad_phi_surf_element);
01399
01400
01401
01402
01403
01404 c_vector<double,DIM> X = zero_vector<double>(DIM);
01405 for (unsigned node_index=0; node_index<NUM_NODES_PER_BOUNDARY_ELEMENT; node_index++)
01406 {
01407 X += quad_phi_surf_element(node_index)*rBoundaryElement.GetNode(node_index)->rGetLocation();
01408 }
01409
01410
01411
01412 c_vector<double,DIM+1> weight = p_containing_vol_element->CalculateInterpolationWeights(X);
01413 c_vector<double,DIM> xi;
01414 for(unsigned i=0; i<DIM; i++)
01415 {
01416 xi(i) = weight(i+1);
01417 }
01418
01419
01420 if(DIM==2)
01421 {
01422 assert( DIM!=2 || (fabs(weight(0))<1e-6) || (fabs(weight(1))<1e-6) || (fabs(weight(2))<1e-6) );
01423 }
01424 else
01425 {
01426 #define COVERAGE_IGNORE
01427 assert( DIM!=3 || (fabs(weight(0))<1e-6) || (fabs(weight(1))<1e-6) || (fabs(weight(2))<1e-6) || (fabs(weight(3))<1e-6) );
01428 #undef COVERAGE_IGNORE
01429 }
01430
01431
01432 QuadraticBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(xi, inverse_jacobian_vol_element, grad_quad_phi_vol_element);
01433
01434 F = identity_matrix<double>(DIM,DIM);
01435 for (unsigned node_index=0; node_index<NUM_NODES_PER_ELEMENT; node_index++)
01436 {
01437 for (unsigned i=0; i<DIM; i++)
01438 {
01439 for (unsigned M=0; M<DIM; M++)
01440 {
01441 F(i,M) += grad_quad_phi_vol_element(M,node_index)*element_current_displacements(i,node_index);
01442 }
01443 }
01444 }
01445
01446 double detF = Determinant(F);
01447 invF = Inverse(F);
01448
01449 if(assembleResidual)
01450 {
01451 c_vector<double,DIM> traction = detF*normal_pressure*prod(trans(invF),normal);
01452
01453
01454 for (unsigned index=0; index<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index++)
01455 {
01456 unsigned spatial_dim = index%DIM;
01457 unsigned node_index = (index-spatial_dim)/DIM;
01458
01459 assert(node_index < NUM_NODES_PER_BOUNDARY_ELEMENT);
01460
01461 rBelem(index) -= traction(spatial_dim)
01462 * quad_phi_surf_element(node_index)
01463 * wJ;
01464 }
01465 }
01466
01467
01468
01469
01470
01471 if(assembleJacobian && ShouldAssembleMatrixTermForPressureOnDeformedBc())
01472 {
01473 for(unsigned II=0; II<NUM_NODES_PER_BOUNDARY_ELEMENT; II++)
01474 {
01475 for(unsigned N=0; N<DIM; N++)
01476 {
01477 grad_quad_phi_surf_element(N,II) = grad_quad_phi_vol_element(N,surf_to_vol_map[II]);
01478 }
01479 }
01480
01481 static FourthOrderTensor<DIM,DIM,DIM,DIM> tensor1;
01482 for(unsigned N=0; N<DIM; N++)
01483 {
01484 for(unsigned e=0; e<DIM; e++)
01485 {
01486 for(unsigned M=0; M<DIM; M++)
01487 {
01488 for(unsigned d=0; d<DIM; d++)
01489 {
01490 tensor1(N,e,M,d) = invF(N,e)*invF(M,d) - invF(M,e)*invF(N,d);
01491 }
01492 }
01493 }
01494 }
01495
01496
01497 static FourthOrderTensor<NUM_NODES_PER_BOUNDARY_ELEMENT,DIM,DIM,DIM> tensor2;
01498 tensor2.template SetAsContractionOnFirstDimension<DIM>( trans(grad_quad_phi_surf_element), tensor1);
01499
01500
01501
01502 static FourthOrderTensor<NUM_NODES_PER_BOUNDARY_ELEMENT,DIM,1,DIM> tensor3;
01503 tensor3.template SetAsContractionOnThirdDimension<DIM>( normal_as_mat, tensor2);
01504
01505 for (unsigned index1=0; index1<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index1++)
01506 {
01507 unsigned spatial_dim1 = index1%DIM;
01508 unsigned node_index1 = (index1-spatial_dim1)/DIM;
01509
01510 for (unsigned index2=0; index2<NUM_NODES_PER_BOUNDARY_ELEMENT*DIM; index2++)
01511 {
01512 unsigned spatial_dim2 = index2%DIM;
01513 unsigned node_index2 = (index2-spatial_dim2)/DIM;
01514
01515 rAelem(index1,index2) -= normal_pressure
01516 * detF
01517 * tensor3(node_index2,spatial_dim2,0,spatial_dim1)
01518 * quad_phi_surf_element(node_index1)
01519 * wJ;
01520 }
01521 }
01522 }
01523 }
01524 }
01525
01526
01527
01528
01529 template<unsigned DIM>
01530 void AbstractNonlinearElasticitySolver<DIM>::Solve(double tol)
01531 {
01532
01533
01534 mrProblemDefinition.Validate();
01535
01536
01537
01538
01539
01540
01541 if(mrProblemDefinition.GetTractionBoundaryConditionType()==PRESSURE_ON_DEFORMED && mCheckedOutwardNormals==false)
01542 {
01543 this->mrQuadMesh.CheckOutwardNormals();
01544 mCheckedOutwardNormals = true;
01545 }
01546
01547
01548 this->WriteCurrentSpatialSolution("initial", "nodes");
01549
01550 if(mUseSnesSolver)
01551 {
01552 SolveSnes();
01553 }
01554 else
01555 {
01556 SolveNonSnes(tol);
01557 }
01558
01559
01560
01561
01562 if(this->mCompressibilityType==INCOMPRESSIBLE)
01563 {
01564 this->RemovePressureDummyValuesThroughLinearInterpolation();
01565 }
01566
01567
01568 this->WriteCurrentSpatialSolution("solution", "nodes");
01569
01570 }
01571
01572
01576 template<unsigned DIM>
01577 void AbstractNonlinearElasticitySolver<DIM>::SetKspSolverAndPcType(KSP solver)
01578 {
01579
01580
01581
01582
01583
01584
01585
01586 PC pc;
01587 KSPGetPC(solver, &pc);
01588
01589
01590 if (mPetscDirectSolve)
01591 {
01592 if(this->mCompressibilityType==COMPRESSIBLE)
01593 {
01594 KSPSetType(solver,KSPPREONLY);
01595
01596 }
01597 PCSetType(pc, PCLU);
01598
01599
01600
01601 }
01602 else
01603 {
01604 if (this->mCompressibilityType==COMPRESSIBLE)
01605 {
01606 KSPSetType(solver,KSPCG);
01607 if(PetscTools::IsSequential())
01608 {
01609 PCSetType(pc, PCICC);
01610
01611
01612
01613 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 1) //PETSc 3.1 or later
01614 PetscOptionsSetValue("-pc_factor_shift_type", "positive_definite");
01615 #else
01616 PetscOptionsSetValue("-pc_factor_shift_positive_definite", "");
01617 #endif
01618 }
01619 else
01620 {
01621 PCSetType(pc, PCBJACOBI);
01622 }
01623 }
01624 else
01625 {
01626 unsigned num_restarts = 100;
01627 KSPSetType(solver,KSPGMRES);
01628 KSPGMRESSetRestart(solver,num_restarts);
01629
01630 #ifndef MECH_USE_HYPRE
01631 PCSetType(pc, PCBJACOBI);
01632 #else
01634 // Speed up linear solve time massively for larger simulations (in fact GMRES may stagnate without
01635
01637 PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
01638
01639
01640
01641 PCSetType(pc, PCHYPRE);
01642 KSPSetPreconditionerSide(solver, PC_RIGHT);
01643
01644
01645
01646
01647
01648
01649 #endif
01650 }
01651 }
01652 }
01653
01654
01655
01657
01658
01660
01661 template<unsigned DIM>
01662 double AbstractNonlinearElasticitySolver<DIM>::ComputeResidualAndGetNorm(bool allowException)
01663 {
01664 if (!allowException)
01665 {
01666
01667 AssembleSystem(true, false);
01668 }
01669 else
01670 {
01671 try
01672 {
01673
01674 AssembleSystem(true, false);
01675 }
01676 catch(Exception&)
01677 {
01678
01679 return DBL_MAX;
01680 }
01681 }
01682
01683
01684 return CalculateResidualNorm();
01685 }
01686
01687 template<unsigned DIM>
01688 double AbstractNonlinearElasticitySolver<DIM>::CalculateResidualNorm()
01689 {
01690 double norm;
01691
01692
01693 VecNorm(this->mResidualVector, NORM_2, &norm);
01694 return norm/this->mNumDofs;
01695 }
01696
01697 template<unsigned DIM>
01698 void AbstractNonlinearElasticitySolver<DIM>::VectorSum(std::vector<double>& rX,
01699 ReplicatableVector& rY,
01700 double a,
01701 std::vector<double>& rZ)
01702 {
01703 assert(rX.size()==rY.GetSize());
01704 assert(rY.GetSize()==rZ.size());
01705 for (unsigned i=0; i<rX.size(); i++)
01706 {
01707 rZ[i] = rX[i] + a*rY[i];
01708 }
01709 }
01710
01711
01712 template<unsigned DIM>
01713 double AbstractNonlinearElasticitySolver<DIM>::TakeNewtonStep()
01714 {
01715 if(this->mVerbose)
01716 {
01717 Timer::Reset();
01718 }
01719
01721
01723 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::ASSEMBLE);
01724 AssembleSystem(true, true);
01725 MechanicsEventHandler::EndEvent(MechanicsEventHandler::ASSEMBLE);
01726 if(this->mVerbose)
01727 {
01728 Timer::PrintAndReset("AssembleSystem");
01729 }
01730
01732
01734 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::SOLVE);
01735
01736 Vec solution;
01737 VecDuplicate(this->mResidualVector,&solution);
01738
01739 KSP solver;
01740 KSPCreate(PETSC_COMM_WORLD,&solver);
01741
01742 KSPSetOperators(solver, mrJacobianMatrix, this->mPreconditionMatrix, DIFFERENT_NONZERO_PATTERN );
01743
01744
01745 SetKspSolverAndPcType(solver);
01746
01747
01748
01749
01750 KSPSetFromOptions(solver);
01751 KSPSetUp(solver);
01752
01753
01754
01755
01756
01757 if (mKspAbsoluteTol < 0)
01758 {
01759 Vec temp;
01760 VecDuplicate(this->mResidualVector, &temp);
01761 Vec temp2;
01762 VecDuplicate(this->mResidualVector, &temp2);
01763 Vec linsys_residual;
01764 VecDuplicate(this->mResidualVector, &linsys_residual);
01765
01766 KSPInitialResidual(solver, solution, temp, temp2, linsys_residual, this->mLinearSystemRhsVector);
01767 double initial_resid_norm;
01768 VecNorm(linsys_residual, NORM_2, &initial_resid_norm);
01769
01770 PetscTools::Destroy(temp);
01771 PetscTools::Destroy(temp2);
01772 PetscTools::Destroy(linsys_residual);
01773
01774 double ksp_rel_tol = 1e-6;
01775 double absolute_tol = ksp_rel_tol * initial_resid_norm;
01776 if(absolute_tol < 1e-12)
01777 {
01778 absolute_tol = 1e-12;
01779 }
01780 KSPSetTolerances(solver, 1e-16, absolute_tol, PETSC_DEFAULT, 1000 );
01781 }
01782 else
01783 {
01784 KSPSetTolerances(solver, 1e-16, mKspAbsoluteTol, PETSC_DEFAULT, 1000 );
01785 }
01786
01787 if(this->mVerbose)
01788 {
01789 Timer::PrintAndReset("KSP Setup");
01790 }
01791
01792 KSPSolve(solver,this->mLinearSystemRhsVector,solution);
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01814
01816
01817
01818 KSPConvergedReason reason;
01819 KSPGetConvergedReason(solver,&reason);
01820
01821 if(reason != KSP_DIVERGED_ITS)
01822 {
01823
01824
01825
01826 #define COVERAGE_IGNORE
01827 KSPEXCEPT(reason);
01828 #undef COVERAGE_IGNORE
01829 }
01830 else
01831 {
01832
01833
01834
01835
01836
01837
01838 #define COVERAGE_IGNORE
01839 WARN_ONCE_ONLY("Linear solve (within a mechanics solve) didn't converge, but this may not stop nonlinear solve converging")
01840 #undef COVERAGE_IGNORE
01841 }
01842
01843
01844 int num_iters;
01845 KSPGetIterationNumber(solver, &num_iters);
01846 if (num_iters==0)
01847 {
01848 PetscTools::Destroy(solution);
01849 KSPDestroy(PETSC_DESTROY_PARAM(solver));
01850 EXCEPTION("KSP Absolute tolerance was too high, linear system wasn't solved - there will be no decrease in Newton residual. Decrease KspAbsoluteTolerance");
01851 }
01852
01853
01854 if(this->mVerbose)
01855 {
01856 Timer::PrintAndReset("KSP Solve");
01857 std::cout << "[" << PetscTools::GetMyRank() << "]: Num iterations = " << num_iters << "\n" << std::flush;
01858 }
01859
01860 MechanicsEventHandler::EndEvent(MechanicsEventHandler::SOLVE);
01861
01863
01864
01865
01866
01867
01868
01869
01870
01871
01872
01873
01875 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::UPDATE);
01876 double new_norm_resid = UpdateSolutionUsingLineSearch(solution);
01877 MechanicsEventHandler::EndEvent(MechanicsEventHandler::UPDATE);
01878
01879 PetscTools::Destroy(solution);
01880 KSPDestroy(PETSC_DESTROY_PARAM(solver));
01881
01882 return new_norm_resid;
01883 }
01884
01885
01886 template<unsigned DIM>
01887 void AbstractNonlinearElasticitySolver<DIM>::PrintLineSearchResult(double s, double residNorm)
01888 {
01889 if(this->mVerbose)
01890 {
01891 std::cout << "\tTesting s = " << s << ", |f| = " << residNorm << "\n" << std::flush;
01892 }
01893 }
01894
01895 template<unsigned DIM>
01896 double AbstractNonlinearElasticitySolver<DIM>::UpdateSolutionUsingLineSearch(Vec solution)
01897 {
01898 double initial_norm_resid = CalculateResidualNorm();
01899 if(this->mVerbose)
01900 {
01901 std::cout << "\tInitial |f| [corresponding to s=0] is " << initial_norm_resid << "\n" << std::flush;
01902 }
01903
01904 ReplicatableVector update(solution);
01905
01906 std::vector<double> old_solution = this->mCurrentSolution;
01907
01908 std::vector<double> damping_values;
01909 for (unsigned i=10; i>=1; i--)
01910 {
01911 damping_values.push_back((double)i/10.0);
01912 }
01913 damping_values.push_back(0.05);
01914 assert(damping_values.size()==11);
01915
01917
01918 unsigned index = 0;
01919 VectorSum(old_solution, update, -damping_values[index], this->mCurrentSolution);
01920 double current_resid_norm = ComputeResidualAndGetNorm(true);
01921 PrintLineSearchResult(damping_values[index], current_resid_norm);
01922
01924
01925 index = 1;
01926 VectorSum(old_solution, update, -damping_values[index], this->mCurrentSolution);
01927 double next_resid_norm = ComputeResidualAndGetNorm(true);
01928 PrintLineSearchResult(damping_values[index], next_resid_norm);
01929
01930 index = 2;
01931
01932
01933 while ( (next_resid_norm==DBL_MAX)
01934 || ( (next_resid_norm < current_resid_norm) && (index<damping_values.size()) ) )
01935 {
01936 current_resid_norm = next_resid_norm;
01937
01938
01939 VectorSum(old_solution, update, -damping_values[index], this->mCurrentSolution);
01940 next_resid_norm = ComputeResidualAndGetNorm(true);
01941 PrintLineSearchResult(damping_values[index], next_resid_norm);
01942
01943 index++;
01944 }
01945
01946 unsigned best_index;
01947
01948 if (index==damping_values.size() && (next_resid_norm < current_resid_norm))
01949 {
01950
01951
01952
01953
01954
01955 #define COVERAGE_IGNORE
01956
01957
01958 current_resid_norm = next_resid_norm;
01959 best_index = index-1;
01960 #undef COVERAGE_IGNORE
01961 }
01962 else
01963 {
01964
01965
01966 best_index = index-2;
01967 }
01968
01969
01970 bool full_first_step = mTakeFullFirstNewtonStep && mFirstStep;
01971
01972
01973
01974 if (initial_norm_resid < current_resid_norm && !full_first_step)
01975 {
01976 #define COVERAGE_IGNORE
01977 EXCEPTION("Residual does not appear to decrease in newton direction, quitting");
01978 #undef COVERAGE_IGNORE
01979 }
01980
01981
01982 if(full_first_step)
01983 {
01984 if(this->mVerbose)
01985 {
01986 std::cout << "\tTaking full first Newton step...\n";
01987 }
01988 best_index = 0;
01989 }
01990
01991 if(this->mVerbose)
01992 {
01993 std::cout << "\tChoosing s = " << damping_values[best_index] << "\n" << std::flush;
01994 }
01995
01996
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030 VectorSum(old_solution, update, -damping_values[best_index], this->mCurrentSolution);
02031
02032 mLastDampingValue = damping_values[best_index];
02033 return current_resid_norm;
02034 }
02035
02036 template<unsigned DIM>
02037 void AbstractNonlinearElasticitySolver<DIM>::PostNewtonStep(unsigned counter, double normResidual)
02038 {
02039 }
02040
02041
02042 template<unsigned DIM>
02043 void AbstractNonlinearElasticitySolver<DIM>::SolveNonSnes(double tol)
02044 {
02045 mLastDampingValue = 0;
02046
02047 if (mWriteOutputEachNewtonIteration)
02048 {
02049 this->WriteCurrentSpatialSolution("newton_iteration", "nodes", 0);
02050 }
02051
02052
02053 double norm_resid = ComputeResidualAndGetNorm(false);
02054 if(this->mVerbose)
02055 {
02056 std::cout << "\nNorm of residual is " << norm_resid << "\n";
02057 }
02058
02059 mNumNewtonIterations = 0;
02060 unsigned iteration_number = 1;
02061
02062 if (tol < 0)
02063 {
02064 tol = NEWTON_REL_TOL*norm_resid;
02065
02066 #define COVERAGE_IGNORE // not going to have tests in cts for everything
02067 if (tol > MAX_NEWTON_ABS_TOL)
02068 {
02069 tol = MAX_NEWTON_ABS_TOL;
02070 }
02071 if (tol < MIN_NEWTON_ABS_TOL)
02072 {
02073 tol = MIN_NEWTON_ABS_TOL;
02074 }
02075 #undef COVERAGE_IGNORE
02076 }
02077
02078 if(this->mVerbose)
02079 {
02080 std::cout << "Solving with tolerance " << tol << "\n";
02081 }
02082
02083 while (norm_resid > tol)
02084 {
02085 if(this->mVerbose)
02086 {
02087 std::cout << "\n-------------------\n"
02088 << "Newton iteration " << iteration_number
02089 << ":\n-------------------\n";
02090 }
02091
02092
02093 mFirstStep = (iteration_number==1);
02094 norm_resid = TakeNewtonStep();
02095
02096 if(this->mVerbose)
02097 {
02098 std::cout << "Norm of residual is " << norm_resid << "\n";
02099 }
02100
02101 if (mWriteOutputEachNewtonIteration)
02102 {
02103 this->WriteCurrentSpatialSolution("newton_iteration", "nodes", iteration_number);
02104 }
02105
02106 mNumNewtonIterations = iteration_number;
02107
02108 PostNewtonStep(iteration_number,norm_resid);
02109
02110 iteration_number++;
02111 if (iteration_number==20)
02112 {
02113 #define COVERAGE_IGNORE
02114 EXCEPTION("Not converged after 20 newton iterations, quitting");
02115 #undef COVERAGE_IGNORE
02116 }
02117 }
02118
02119 if (norm_resid > tol)
02120 {
02121 #define COVERAGE_IGNORE
02122 EXCEPTION("Failed to converge");
02123 #undef COVERAGE_IGNORE
02124 }
02125 }
02126
02127
02128
02129 template<unsigned DIM>
02130 unsigned AbstractNonlinearElasticitySolver<DIM>::GetNumNewtonIterations()
02131 {
02132 return mNumNewtonIterations;
02133 }
02134
02135
02136
02138
02140
02141
02142 template<unsigned DIM>
02143 void AbstractNonlinearElasticitySolver<DIM>::SolveSnes()
02144 {
02145
02146 Vec initial_guess;
02147 VecDuplicate(this->mResidualVector, &initial_guess);
02148 double* p_initial_guess;
02149 VecGetArray(initial_guess, &p_initial_guess);
02150 int lo, hi;
02151 VecGetOwnershipRange(initial_guess, &lo, &hi);
02152 for (int global_index=lo; global_index<hi; global_index++)
02153 {
02154 int local_index = global_index - lo;
02155 p_initial_guess[local_index] = this->mCurrentSolution[global_index];
02156 }
02157 VecRestoreArray(initial_guess, &p_initial_guess);
02158 PetscVecTools::Finalise(initial_guess);
02159
02160 Vec snes_residual_vec;
02161 VecDuplicate(this->mResidualVector, &snes_residual_vec);
02162
02163 SNES snes;
02164
02165 SNESCreate(PETSC_COMM_WORLD, &snes);
02166 SNESSetFunction(snes, snes_residual_vec, &AbstractNonlinearElasticitySolver_ComputeResidual<DIM>, this);
02167 SNESSetJacobian(snes, mrJacobianMatrix, this->mPreconditionMatrix, &AbstractNonlinearElasticitySolver_ComputeJacobian<DIM>, this);
02168 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 4) //PETSc 3.4 or later
02169 SNESSetType(snes, SNESNEWTONLS);
02170 #else
02171 SNESSetType(snes, SNESLS);
02172 #endif
02173 SNESSetTolerances(snes,1e-5,1e-5,1e-5,PETSC_DEFAULT,PETSC_DEFAULT);
02174 SNESSetMaxLinearSolveFailures(snes,100);
02175
02176 KSP ksp;
02177 SNESGetKSP(snes, &ksp);
02178
02179 KSPSetTolerances(ksp, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 1000 );
02180
02181
02182 SetKspSolverAndPcType(ksp);
02183
02184 if(this->mVerbose)
02185 {
02186 PetscOptionsSetValue("-snes_monitor","");
02187 }
02188 SNESSetFromOptions(snes);
02189
02190 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
02191 PetscErrorCode err = SNESSolve(snes, initial_guess);
02192 #else
02193 PetscErrorCode err = SNESSolve(snes, PETSC_NULL, initial_guess);
02194 #endif
02195
02196 SNESConvergedReason reason;
02197 SNESGetConvergedReason(snes,&reason);
02198
02199 #define COVERAGE_IGNORE
02200 if (err != 0)
02201 {
02202 std::stringstream err_stream;
02203 err_stream << err;
02204 PetscTools::Destroy(initial_guess);
02205 PetscTools::Destroy(snes_residual_vec);
02206 SNESDestroy(PETSC_DESTROY_PARAM(snes));
02207 EXCEPTION("Nonlinear Solver failed. PETSc error code: "+err_stream.str()+" .");
02208 }
02209
02210 if (reason < 0)
02211 {
02212 std::stringstream reason_stream;
02213 reason_stream << reason;
02214 PetscTools::Destroy(initial_guess);
02215 PetscTools::Destroy(snes_residual_vec);
02216 SNESDestroy(PETSC_DESTROY_PARAM(snes));
02217 EXCEPTION("Nonlinear Solver did not converge. PETSc reason code: "+reason_stream.str()+" .");
02218 }
02219 #undef COVERAGE_IGNORE
02220
02221 PetscInt num_iters;
02222 SNESGetIterationNumber(snes,&num_iters);
02223 mNumNewtonIterations = num_iters;
02224
02225 PetscTools::Destroy(initial_guess);
02226 PetscTools::Destroy(snes_residual_vec);
02227 SNESDestroy(PETSC_DESTROY_PARAM(snes));
02228 }
02229
02230
02231 template<unsigned DIM>
02232 void AbstractNonlinearElasticitySolver<DIM>::ComputeResidual(Vec currentGuess, Vec residualVector)
02233 {
02234
02235
02236
02237
02238 ReplicatableVector guess_repl(currentGuess);
02239 for(unsigned i=0; i<guess_repl.GetSize(); i++)
02240 {
02241 this->mCurrentSolution[i] = guess_repl[i];
02242 }
02243 AssembleSystem(true,false);
02244 VecCopy(this->mResidualVector, residualVector);
02245 }
02246
02247 template<unsigned DIM>
02248 void AbstractNonlinearElasticitySolver<DIM>::ComputeJacobian(Vec currentGuess, Mat* pJacobian, Mat* pPreconditioner)
02249 {
02250
02251
02252
02253
02254
02255
02256
02257 assert(mrJacobianMatrix==*pJacobian);
02258 assert(this->mPreconditionMatrix==*pPreconditioner);
02259
02260 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::ASSEMBLE);
02261 ReplicatableVector guess_repl(currentGuess);
02262 for(unsigned i=0; i<guess_repl.GetSize(); i++)
02263 {
02264 this->mCurrentSolution[i] = guess_repl[i];
02265 }
02266
02267 AssembleSystem(false,true);
02268 MechanicsEventHandler::EndEvent(MechanicsEventHandler::ASSEMBLE);
02269 }
02270
02271
02272
02273 template<unsigned DIM>
02274 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeResidual(SNES snes,
02275 Vec currentGuess,
02276 Vec residualVector,
02277 void* pContext)
02278 {
02279
02280 AbstractNonlinearElasticitySolver<DIM>* p_solver = (AbstractNonlinearElasticitySolver<DIM>*)pContext;
02281 p_solver->ComputeResidual(currentGuess, residualVector);
02282 return 0;
02283 }
02284
02285 template<unsigned DIM>
02286 PetscErrorCode AbstractNonlinearElasticitySolver_ComputeJacobian(SNES snes,
02287 Vec currentGuess,
02288 Mat* pGlobalJacobian,
02289 Mat* pPreconditioner,
02290 MatStructure* pMatStructure,
02291 void* pContext)
02292 {
02293
02294 AbstractNonlinearElasticitySolver<DIM>* p_solver = (AbstractNonlinearElasticitySolver<DIM>*) pContext;
02295 p_solver->ComputeJacobian(currentGuess, pGlobalJacobian, pPreconditioner);
02296 return 0;
02297 }
02298
02299
02300
02301
02302 template<unsigned DIM>
02303 double AbstractNonlinearElasticitySolver<DIM>::MAX_NEWTON_ABS_TOL = 1e-7;
02304
02305 template<unsigned DIM>
02306 double AbstractNonlinearElasticitySolver<DIM>::MIN_NEWTON_ABS_TOL = 1e-10;
02307
02308 template<unsigned DIM>
02309 double AbstractNonlinearElasticitySolver<DIM>::NEWTON_REL_TOL = 1e-4;
02310
02311 #endif