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 "AbstractIncompressibleMaterialLaw.hpp"
00036 #include "OutputFileHandler.hpp"
00037 #include "LogFile.hpp"
00038 #include "PetscTools.hpp"
00039 #include "MechanicsEventHandler.hpp"
00040 #include "ReplicatableVector.hpp"
00041
00042
00043
00044
00045
00046
00047
00048
00050
00051
00052
00053
00054
00055 #ifdef MECH_VERBOSE
00056 #include "Timer.hpp"
00057 #endif
00058
00062 template<unsigned DIM>
00063 class AbstractNonlinearElasticitySolver
00064 {
00065 protected:
00066
00072 static const double MAX_NEWTON_ABS_TOL;
00073
00075 static const double MIN_NEWTON_ABS_TOL;
00076
00078 static const double NEWTON_REL_TOL;
00079
00083 double mKspAbsoluteTol;
00084
00089 unsigned mNumDofs;
00090
00096 std::vector<AbstractIncompressibleMaterialLaw<DIM>*> mMaterialLaws;
00097
00103 LinearSystem* mpLinearSystem;
00104
00123 LinearSystem* mpPreconditionMatrixLinearSystem;
00124
00126 c_vector<double,DIM> mBodyForce;
00127
00129 double mDensity;
00130
00132 std::string mOutputDirectory;
00133
00135 std::vector<unsigned> mFixedNodes;
00136
00138 std::vector<c_vector<double,DIM> > mFixedNodeDisplacements;
00139
00141 bool mWriteOutput;
00142
00148 std::vector<double> mCurrentSolution;
00149
00154 FourthOrderTensor<DIM,DIM,DIM,DIM> dTdE;
00155
00157 unsigned mNumNewtonIterations;
00158
00160 std::vector<c_vector<double,DIM> > mDeformedPosition;
00161
00166 std::vector<double> mPressures;
00167
00172 std::vector<c_vector<double,DIM> > mSurfaceTractions;
00173
00175 c_vector<double,DIM> (*mpBodyForceFunction)(c_vector<double,DIM>&);
00176
00181 c_vector<double,DIM> (*mpTractionBoundaryConditionFunction)(c_vector<double,DIM>&);
00182
00184 bool mUsingBodyForceFunction;
00185
00187 bool mUsingTractionBoundaryConditionFunction;
00188
00193 virtual void FormInitialGuess()=0;
00194
00205 virtual void AssembleSystem(bool assembleResidual, bool assembleJacobian)=0;
00206
00211 virtual std::vector<c_vector<double,DIM> >& rGetDeformedPosition()=0;
00212
00218 void ApplyBoundaryConditions(bool applyToMatrix);
00219
00230 double ComputeResidualAndGetNorm(bool allowException);
00231
00233 double CalculateResidualNorm();
00234
00242 void VectorSum(std::vector<double>& rX, ReplicatableVector& rY, double a, std::vector<double>& rZ);
00243
00250 void PrintLineSearchResult(double s, double residNorm);
00251
00252
00260 double TakeNewtonStep();
00261
00269 double UpdateSolutionUsingLineSearch(Vec solution);
00270
00271
00279 virtual void PostNewtonStep(unsigned counter, double normResidual);
00280
00281 public:
00282
00293 AbstractNonlinearElasticitySolver(unsigned numDofs,
00294 AbstractIncompressibleMaterialLaw<DIM>* pMaterialLaw,
00295 c_vector<double,DIM> bodyForce,
00296 double density,
00297 std::string outputDirectory,
00298 std::vector<unsigned>& fixedNodes);
00299
00310 AbstractNonlinearElasticitySolver(unsigned numDofs,
00311 std::vector<AbstractIncompressibleMaterialLaw<DIM>*>& rMaterialLaws,
00312 c_vector<double,DIM> bodyForce,
00313 double density,
00314 std::string outputDirectory,
00315 std::vector<unsigned>& fixedNodes);
00316
00320 virtual ~AbstractNonlinearElasticitySolver();
00321
00330 void Solve(double tol=-1.0,
00331 unsigned offset=0,
00332 unsigned maxNumNewtonIterations=INT_MAX,
00333 bool quitIfNoConvergence=true);
00334
00340 void WriteOutput(unsigned counter);
00341
00345 unsigned GetNumNewtonIterations();
00346
00353 void SetFunctionalBodyForce(c_vector<double,DIM> (*pFunction)(c_vector<double,DIM>&));
00354
00360 void SetWriteOutput(bool writeOutput=true);
00361
00362
00368 void SetKspAbsoluteTolerance(double kspAbsoluteTolerance)
00369 {
00370 assert(kspAbsoluteTolerance>0);
00371 mKspAbsoluteTol = kspAbsoluteTolerance;
00372 }
00373
00378 std::vector<double>& rGetCurrentSolution()
00379 {
00380 return mCurrentSolution;
00381 }
00382 };
00383
00384
00386
00388
00389
00390 template<unsigned DIM>
00391 void AbstractNonlinearElasticitySolver<DIM>::ApplyBoundaryConditions(bool applyToMatrix)
00392 {
00393 assert(mFixedNodeDisplacements.size()==mFixedNodes.size());
00394
00395
00396
00397
00398
00399
00400
00401 std::vector<unsigned> rows;
00402 if(applyToMatrix)
00403 {
00404 rows.resize(DIM*mFixedNodes.size());
00405 }
00406
00407 for (unsigned i=0; i<mFixedNodes.size(); i++)
00408 {
00409 unsigned node_index = mFixedNodes[i];
00410 for (unsigned j=0; j<DIM; j++)
00411 {
00412 unsigned dof_index = DIM*node_index+j;
00413
00414 if(applyToMatrix)
00415 {
00416 rows[DIM*i+j] = dof_index;
00417 }
00418
00419 double value = mCurrentSolution[dof_index] - mFixedNodeDisplacements[i](j);
00420 mpLinearSystem->SetRhsVectorElement(dof_index, value);
00421 }
00422 }
00423
00424 if(applyToMatrix)
00425 {
00426 mpLinearSystem->ZeroMatrixRowsWithValueOnDiagonal(rows, 1.0);
00427 mpPreconditionMatrixLinearSystem->ZeroMatrixRowsWithValueOnDiagonal(rows, 1.0);
00428 }
00429 }
00430
00431 template<unsigned DIM>
00432 double AbstractNonlinearElasticitySolver<DIM>::ComputeResidualAndGetNorm(bool allowException)
00433 {
00434 if(!allowException)
00435 {
00436
00437 AssembleSystem(true, false);
00438 }
00439 else
00440 {
00441 try
00442 {
00443
00444 AssembleSystem(true, false);
00445 }
00446 catch(Exception& e)
00447 {
00448
00449
00450 return DBL_MAX;
00451 }
00452 }
00453
00454
00455 return CalculateResidualNorm();
00456 }
00457
00458 template<unsigned DIM>
00459 double AbstractNonlinearElasticitySolver<DIM>::CalculateResidualNorm()
00460 {
00461 double norm;
00462 VecNorm(mpLinearSystem->rGetRhsVector(), NORM_2, &norm);
00463 return norm/mNumDofs;
00464 }
00465
00466 template<unsigned DIM>
00467 void AbstractNonlinearElasticitySolver<DIM>::VectorSum(std::vector<double>& rX,
00468 ReplicatableVector& rY,
00469 double a,
00470 std::vector<double>& rZ)
00471 {
00472 assert(rX.size()==rY.GetSize());
00473 assert(rY.GetSize()==rZ.size());
00474 for(unsigned i=0; i<rX.size(); i++)
00475 {
00476 rZ[i] = rX[i] + a*rY[i];
00477 }
00478 }
00479
00480
00481 template<unsigned DIM>
00482 double AbstractNonlinearElasticitySolver<DIM>::TakeNewtonStep()
00483 {
00484 #ifdef MECH_VERBOSE
00485 Timer::Reset();
00486 #endif
00487
00489
00491 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::ASSEMBLE);
00492 AssembleSystem(true, true);
00493 MechanicsEventHandler::EndEvent(MechanicsEventHandler::ASSEMBLE);
00494 #ifdef MECH_VERBOSE
00495 Timer::PrintAndReset("AssembleSystem");
00496 #endif
00497
00498
00500
00501
00502
00503
00504
00505
00506
00508 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::SOLVE);
00509
00510 Vec solution;
00511 VecDuplicate(mpLinearSystem->rGetRhsVector(),&solution);
00512
00513 Mat& r_jac = mpLinearSystem->rGetLhsMatrix();
00514
00515 KSP solver;
00516 KSPCreate(PETSC_COMM_WORLD,&solver);
00517 PC pc;
00518 KSPGetPC(solver, &pc);
00519
00520 #ifdef MECH_USE_MUMPS
00521
00522 KSPSetOperators(solver, r_jac, r_jac, DIFFERENT_NONZERO_PATTERN );
00523
00524 KSPSetType(solver, KSPPREONLY);
00525 PCSetType(pc, PCLU);
00526 PCFactorSetMatSolverPackage(pc, MAT_SOLVER_MUMPS);
00527
00528
00529 PCFactorSetShiftNonzero(pc, PETSC_DECIDE);
00530
00531 PCASMSetUseInPlace(pc);
00532 #else
00533 Mat& r_precond_jac = mpPreconditionMatrixLinearSystem->rGetLhsMatrix();
00534 KSPSetOperators(solver, r_jac, r_precond_jac, DIFFERENT_NONZERO_PATTERN );
00535
00536 unsigned num_restarts = 100;
00537 KSPSetType(solver,KSPGMRES);
00538 KSPGMRESSetRestart(solver,num_restarts);
00539
00540 if(mKspAbsoluteTol < 0)
00541 {
00542 double ksp_rel_tol = 1e-6;
00543 KSPSetTolerances(solver, ksp_rel_tol, PETSC_DEFAULT, PETSC_DEFAULT, 10000 );
00544 }
00545 else
00546 {
00547 KSPSetTolerances(solver, 1e-16, mKspAbsoluteTol, PETSC_DEFAULT, 10000 );
00548 }
00549
00550 #ifndef MECH_USE_HYPRE
00551 PCSetType(pc, PCBJACOBI);
00552 #else
00554 // Speed up linear solve time massively for larger simulations (in fact GMRES may stagnate without
00555
00557 PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00558
00559
00560
00561 PCSetType(pc, PCHYPRE);
00562 KSPSetPreconditionerSide(solver, PC_RIGHT);
00563
00564
00565
00566
00567
00568
00569 #endif
00570
00571
00572
00573
00574
00575
00576 KSPSetFromOptions(solver);
00577 KSPSetUp(solver);
00578 #endif
00579
00580 #ifdef MECH_VERBOSE
00581 Timer::PrintAndReset("KSP Setup");
00582 #endif
00583
00584 KSPSolve(solver,mpLinearSystem->rGetRhsVector(),solution);
00585
00586 int num_iters;
00587 KSPGetIterationNumber(solver, &num_iters);
00588 if(num_iters==0)
00589 {
00590 VecDestroy(solution);
00591 KSPDestroy(solver);
00592 EXCEPTION("KSP Absolute tolerance was too high, linear system wasn't solved - there will be no decrease in Newton residual. Decrease KspAbsoluteTolerance");
00593 }
00594
00595 #ifdef MECH_VERBOSE
00596 Timer::PrintAndReset("KSP Solve");
00597
00598 std::cout << "[" << PetscTools::GetMyRank() << "]: Num iterations = " << num_iters << "\n" << std::flush;
00599 #endif
00600
00601 MechanicsEventHandler::EndEvent(MechanicsEventHandler::SOLVE);
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00615 MechanicsEventHandler::BeginEvent(MechanicsEventHandler::UPDATE);
00616 double new_norm_resid = UpdateSolutionUsingLineSearch(solution);
00617 MechanicsEventHandler::EndEvent(MechanicsEventHandler::UPDATE);
00618
00619 VecDestroy(solution);
00620 KSPDestroy(solver);
00621
00622 return new_norm_resid;
00623 }
00624
00625 template<unsigned DIM>
00626 void AbstractNonlinearElasticitySolver<DIM>::PrintLineSearchResult(double s, double residNorm)
00627 {
00628 #ifdef MECH_VERBOSE
00629 std::cout << "\tTesting s = " << s << ", |f| = " << residNorm << "\n" << std::flush;
00630 #endif
00631 }
00632
00633 template<unsigned DIM>
00634 double AbstractNonlinearElasticitySolver<DIM>::UpdateSolutionUsingLineSearch(Vec solution)
00635 {
00636 double initial_norm_resid = CalculateResidualNorm();
00637 #ifdef MECH_VERBOSE
00638 std::cout << "\tInitial |f| [corresponding to s=0] is " << initial_norm_resid << "\n" << std::flush;
00639 #endif
00640
00641 ReplicatableVector update(solution);
00642
00643 std::vector<double> old_solution = mCurrentSolution;
00644
00645 std::vector<double> damping_values;
00646 for (unsigned i=10; i>=1; i--)
00647 {
00648 damping_values.push_back((double)i/10.0);
00649 }
00650 damping_values.push_back(0.05);
00651 assert(damping_values.size()==11);
00652
00653
00655
00656 unsigned index = 0;
00657 VectorSum(old_solution, update, -damping_values[index], mCurrentSolution);
00658 double current_resid_norm = ComputeResidualAndGetNorm(true);
00659 PrintLineSearchResult(damping_values[index], current_resid_norm);
00660
00662
00663 index = 1;
00664 VectorSum(old_solution, update, -damping_values[index], mCurrentSolution);
00665 double next_resid_norm = ComputeResidualAndGetNorm(true);
00666 PrintLineSearchResult(damping_values[index], next_resid_norm);
00667
00668 index = 2;
00669
00670
00671 while ( (next_resid_norm==DBL_MAX)
00672 || ( (next_resid_norm < current_resid_norm) && (index<damping_values.size()) ) )
00673 {
00674 current_resid_norm = next_resid_norm;
00675
00676
00677 VectorSum(old_solution, update, -damping_values[index], mCurrentSolution);
00678 next_resid_norm = ComputeResidualAndGetNorm(true);
00679 PrintLineSearchResult(damping_values[index], next_resid_norm);
00680
00681 index++;
00682 }
00683
00684 unsigned best_index;
00685
00686 if(index==damping_values.size() && (next_resid_norm < current_resid_norm))
00687 {
00688
00689
00690
00691
00692
00693 #define COVERAGE_IGNORE
00694
00695
00696 current_resid_norm = next_resid_norm;
00697 best_index = index-1;
00698 #undef COVERAGE_IGNORE
00699 }
00700 else
00701 {
00702
00703
00704 best_index = index-2;
00705 }
00706
00707
00708 if (initial_norm_resid < current_resid_norm)
00709 {
00710 #define COVERAGE_IGNORE
00711
00712
00713 std::cout << "CHASTE ERROR: (AbstractNonlinearElasticitySolver.hpp): Residual does not appear to decrease in newton direction, quitting.\n" << std::flush;
00714 exit(0);
00715
00716 #undef COVERAGE_IGNORE
00717 }
00718
00719 #ifdef MECH_VERBOSE
00720 std::cout << "\tBest s = " << damping_values[best_index] << "\n" << std::flush;
00721 #endif
00722 VectorSum(old_solution, update, -damping_values[best_index], mCurrentSolution);
00723
00724 return current_resid_norm;
00725
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775 }
00776
00777
00778
00779 template<unsigned DIM>
00780 void AbstractNonlinearElasticitySolver<DIM>::PostNewtonStep(unsigned counter, double normResidual)
00781 {
00782 }
00783
00784
00785 template<unsigned DIM>
00786 AbstractNonlinearElasticitySolver<DIM>::AbstractNonlinearElasticitySolver(unsigned numDofs,
00787 AbstractIncompressibleMaterialLaw<DIM>* pMaterialLaw,
00788 c_vector<double,DIM> bodyForce,
00789 double density,
00790 std::string outputDirectory,
00791 std::vector<unsigned>& fixedNodes)
00792 : mKspAbsoluteTol(-1),
00793 mNumDofs(numDofs),
00794 mBodyForce(bodyForce),
00795 mDensity(density),
00796 mOutputDirectory(outputDirectory),
00797 mFixedNodes(fixedNodes),
00798 mNumNewtonIterations(0),
00799 mUsingBodyForceFunction(false),
00800 mUsingTractionBoundaryConditionFunction(false)
00801 {
00802 assert(pMaterialLaw != NULL);
00803 mMaterialLaws.push_back(pMaterialLaw);
00804
00805 assert(DIM==2 || DIM==3);
00806 assert(density > 0);
00807 assert(fixedNodes.size() > 0);
00808 mWriteOutput = (mOutputDirectory != "");
00809 }
00810
00811
00812 template<unsigned DIM>
00813 AbstractNonlinearElasticitySolver<DIM>::AbstractNonlinearElasticitySolver(unsigned numDofs,
00814 std::vector<AbstractIncompressibleMaterialLaw<DIM>*>& rMaterialLaws,
00815 c_vector<double,DIM> bodyForce,
00816 double density,
00817 std::string outputDirectory,
00818 std::vector<unsigned>& fixedNodes)
00819 : mKspAbsoluteTol(-1),
00820 mNumDofs(numDofs),
00821 mBodyForce(bodyForce),
00822 mDensity(density),
00823 mOutputDirectory(outputDirectory),
00824 mFixedNodes(fixedNodes),
00825 mNumNewtonIterations(0),
00826 mUsingBodyForceFunction(false),
00827 mUsingTractionBoundaryConditionFunction(false)
00828 {
00829 mMaterialLaws.resize(rMaterialLaws.size(), NULL);
00830 for (unsigned i=0; i<mMaterialLaws.size(); i++)
00831 {
00832 assert(rMaterialLaws[i] != NULL);
00833 mMaterialLaws[i] = rMaterialLaws[i];
00834 }
00835
00836 assert(DIM==2 || DIM==3);
00837 assert(density > 0);
00838 assert(fixedNodes.size() > 0);
00839 mWriteOutput = (mOutputDirectory != "");
00840 }
00841
00842
00843 template<unsigned DIM>
00844 AbstractNonlinearElasticitySolver<DIM>::~AbstractNonlinearElasticitySolver()
00845 {
00846 delete mpLinearSystem;
00847 delete mpPreconditionMatrixLinearSystem;
00848 }
00849
00850
00851 template<unsigned DIM>
00852 void AbstractNonlinearElasticitySolver<DIM>::Solve(double tol,
00853 unsigned offset,
00854 unsigned maxNumNewtonIterations,
00855 bool quitIfNoConvergence)
00856 {
00857 if (mWriteOutput)
00858 {
00859 WriteOutput(0+offset);
00860 }
00861
00862
00863 double norm_resid = this->ComputeResidualAndGetNorm(false);
00864 #ifdef MECH_VERBOSE
00865 std::cout << "\nNorm of residual is " << norm_resid << "\n";
00866 #endif
00867
00868 mNumNewtonIterations = 0;
00869 unsigned counter = 1;
00870
00871 if (tol < 0)
00872 {
00873 tol = NEWTON_REL_TOL*norm_resid;
00874
00875 #define COVERAGE_IGNORE // not going to have tests in cts for everything
00876 if (tol > MAX_NEWTON_ABS_TOL)
00877 {
00878 tol = MAX_NEWTON_ABS_TOL;
00879 }
00880 if (tol < MIN_NEWTON_ABS_TOL)
00881 {
00882 tol = MIN_NEWTON_ABS_TOL;
00883 }
00884 #undef COVERAGE_IGNORE
00885 }
00886
00887 #ifdef MECH_VERBOSE
00888 std::cout << "Solving with tolerance " << tol << "\n";
00889 #endif
00890
00891 while (norm_resid > tol && counter<=maxNumNewtonIterations)
00892 {
00893 #ifdef MECH_VERBOSE
00894 std::cout << "\n-------------------\n"
00895 << "Newton iteration " << counter
00896 << ":\n-------------------\n";
00897 #endif
00898
00899
00900 norm_resid = TakeNewtonStep();
00901
00902 #ifdef MECH_VERBOSE
00903 std::cout << "Norm of residual is " << norm_resid << "\n";
00904 #endif
00905 if (mWriteOutput)
00906 {
00907 WriteOutput(counter+offset);
00908 }
00909
00910 mNumNewtonIterations = counter;
00911
00912 PostNewtonStep(counter,norm_resid);
00913
00914 counter++;
00915 if (counter==20)
00916 {
00917 #define COVERAGE_IGNORE
00918 EXCEPTION("Not converged after 20 newton iterations, quitting");
00919 #undef COVERAGE_IGNORE
00920 }
00921 }
00922
00923 if ((norm_resid > tol) && quitIfNoConvergence)
00924 {
00925 #define COVERAGE_IGNORE
00926 EXCEPTION("Failed to converge");
00927 #undef COVERAGE_IGNORE
00928 }
00929 }
00930
00931
00932 template<unsigned DIM>
00933 void AbstractNonlinearElasticitySolver<DIM>::WriteOutput(unsigned counter)
00934 {
00935
00936 if (!mWriteOutput)
00937 {
00938 return;
00939 }
00940
00941 OutputFileHandler output_file_handler(mOutputDirectory, (counter==0));
00942 std::stringstream file_name;
00943 file_name << "/solution_" << counter << ".nodes";
00944
00945 out_stream p_file = output_file_handler.OpenOutputFile(file_name.str());
00946
00947 std::vector<c_vector<double,DIM> >& r_deformed_position = rGetDeformedPosition();
00948 for (unsigned i=0; i<r_deformed_position.size(); i++)
00949 {
00950 for (unsigned j=0; j<DIM; j++)
00951 {
00952 * p_file << r_deformed_position[i](j) << " ";
00953 }
00954 * p_file << "\n";
00955 }
00956 p_file->close();
00957 }
00958
00959
00960 template<unsigned DIM>
00961 unsigned AbstractNonlinearElasticitySolver<DIM>::GetNumNewtonIterations()
00962 {
00963 return mNumNewtonIterations;
00964 }
00965
00966
00967 template<unsigned DIM>
00968 void AbstractNonlinearElasticitySolver<DIM>::SetFunctionalBodyForce(c_vector<double,DIM> (*pFunction)(c_vector<double,DIM>&))
00969 {
00970 mUsingBodyForceFunction = true;
00971 mpBodyForceFunction = pFunction;
00972 }
00973
00974
00975 template<unsigned DIM>
00976 void AbstractNonlinearElasticitySolver<DIM>::SetWriteOutput(bool writeOutput)
00977 {
00978 if (writeOutput && (mOutputDirectory==""))
00979 {
00980 EXCEPTION("Can't write output if no output directory was given in constructor");
00981 }
00982 mWriteOutput = writeOutput;
00983 }
00984
00985
00986
00987
00988 template<unsigned DIM>
00989 const double AbstractNonlinearElasticitySolver<DIM>::MAX_NEWTON_ABS_TOL = 1e-7;
00990
00991 template<unsigned DIM>
00992 const double AbstractNonlinearElasticitySolver<DIM>::MIN_NEWTON_ABS_TOL = 1e-10;
00993
00994 template<unsigned DIM>
00995 const double AbstractNonlinearElasticitySolver<DIM>::NEWTON_REL_TOL = 1e-4;
00996
00997
00998 #endif