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 #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
00054
00055
00056
00057
00058
00059 #ifdef MECH_VERBOSE
00060 #include "Timer.hpp"
00061 #endif
00062
00063
00064
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;
00084
00086 static const size_t NUM_NODES_PER_BOUNDARY_ELEMENT = DIM*(DIM+1)/2;
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
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
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
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
00575
00576
00577
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
00588
00589
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
00601 if (i<mrQuadMesh.GetNumVertices())
00602 {
00603 num_non_zeros_each_row[DIM*mrQuadMesh.GetNumNodes() + i] = num_non_zeros_upper_bound;
00604 }
00605 }
00606 }
00607
00608
00609
00610
00611
00612
00615
00616
00618
00619
00620
00621
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
00663
00664
00665
00666
00667
00668
00669 delete [] num_non_zeros_each_row;
00670 }
00671 }
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702 template<unsigned DIM>
00703 void AbstractNonlinearElasticitySolver<DIM>::ApplyDirichletBoundaryConditions(bool applyToLinearSystem)
00704 {
00705 assert(mResidualVector);
00706 if (applyToLinearSystem)
00707 {
00708 assert(mJacobianMatrix);
00709 assert(mLinearSystemRhsVector);
00710 }
00711
00712
00713
00714
00715
00716
00717
00718 std::vector<unsigned> rows;
00719 std::vector<double> values;
00720
00721
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);
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
00751 for (unsigned i=0; i<rows.size(); i++)
00752 {
00753 unsigned col = rows[i];
00754 double minus_value = -values[i];
00755
00756
00757
00758
00759
00760
00761 Vec matrix_col = PetscMatTools::GetMatrixRowDistributed(mJacobianMatrix,col);
00762
00763
00764 PetscVecTools::SetElement(matrix_col, col, 0.0);
00765
00766
00767
00768
00769
00770 PetscVecTools::AddScaledVector(mDirichletBoundaryConditionsVector, matrix_col, minus_value);
00771 VecDestroy(matrix_col);
00772 }
00773 }
00774
00775 if (applyToLinearSystem)
00776 {
00777
00778
00779
00780 if (applySymmetrically)
00781 {
00782 PetscMatTools::ZeroRowsAndColumnsWithValueOnDiagonal(mJacobianMatrix, rows, 1.0);
00783 PetscMatTools::ZeroRowsAndColumnsWithValueOnDiagonal(mPreconditionMatrix, rows, 1.0);
00784
00785
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
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
00845 AssembleSystem(true, false);
00846 }
00847 else
00848 {
00849 try
00850 {
00851
00852 AssembleSystem(true, false);
00853 }
00854 catch(Exception& e)
00855 {
00856
00857 return DBL_MAX;
00858 }
00859 }
00860
00861
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
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
00908
00909
00910
00911
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 );
00924
00925 if (mCompressibilityType==COMPRESSIBLE)
00926 {
00927 KSPSetType(solver,KSPCG);
00928
00929 PCSetType(pc, PCICC);
00930 PetscOptionsSetValue("-pc_factor_shift_positive_definite", "");
00931
00932
00933
00934
00936
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);
00946 #else
00947
00948
00949
00951 PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00952
00953
00954
00955 PCSetType(pc, PCHYPRE);
00956 KSPSetPreconditionerSide(solver, PC_RIGHT);
00957
00958
00959
00960
00961
00962
00963 #endif
00964 }
00965
00966
00967
00968
00969 #ifdef MECH_KSP_MONITOR
00970 PetscOptionsSetValue("-ksp_monitor","");
00971
00972 #endif
00973
00974 KSPSetFromOptions(solver);
00975 KSPSetUp(solver);
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
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 );
01023 }
01024 else
01025 {
01026 KSPSetTolerances(solver, 1e-16, mKspAbsoluteTol, PETSC_DEFAULT, PETSC_DEFAULT );
01027 }
01028
01029 #ifdef MECH_VERBOSE
01030 Timer::PrintAndReset("KSP Setup");
01031 #endif
01032
01033 KSPSolve(solver,mLinearSystemRhsVector,solution);
01034
01036
01038
01039
01040 KSPConvergedReason reason;
01041 KSPGetConvergedReason(solver,&reason);
01042
01043 if(reason != KSP_DIVERGED_ITS)
01044 {
01045
01046
01047
01048 #define COVERAGE_IGNORE
01049 KSPEXCEPT(reason);
01050 #undef COVERAGE_IGNORE
01051 }
01052 else
01053 {
01054
01055
01056
01057
01058
01059
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
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
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
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;
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
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
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
01150
01151 while ( (next_resid_norm==DBL_MAX)
01152 || ( (next_resid_norm < current_resid_norm) && (index<damping_values.size()) ) )
01153 {
01154 current_resid_norm = next_resid_norm;
01155
01156
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
01169
01170
01171
01172
01173 #define COVERAGE_IGNORE
01174
01175
01176 current_resid_norm = next_resid_norm;
01177 best_index = index-1;
01178 #undef COVERAGE_IGNORE
01179 }
01180 else
01181 {
01182
01183
01184 best_index = index-2;
01185 }
01186
01187
01188 if (initial_norm_resid < current_resid_norm)
01189 {
01190 #define COVERAGE_IGNORE
01191
01192
01193 std::cout << "CHASTE ERROR: (AbstractNonlinearElasticitySolver.hpp): Residual does not appear to decrease in newton direction, quitting.\n" << std::flush;
01194 exit(0);
01195
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
01283 mrProblemDefinition.Validate();
01284
01285
01286
01287
01288
01289
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
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)
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
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
01374 WriteCurrentDeformation("solution");
01375 }
01376
01377 template<unsigned DIM>
01378 void AbstractNonlinearElasticitySolver<DIM>::WriteCurrentDeformation(std::string fileName, int counterToAppend)
01379 {
01380
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();
01490 writer.WriteDeformationPositions(r_deformed_positions, 1);
01491 writer.WriteCmguiScript();
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
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
01515 static c_matrix<double, DIM, NUM_NODES_PER_ELEMENT> grad_quad_phi;
01516
01517
01518
01519
01520
01521 static c_matrix<double,DIM,DIM> grad_u;
01522
01523
01524
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
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
01563
01564
01565
01566
01567
01568 }
01569
01570
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