AbstractNonlinearElasticitySolver.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #ifndef ABSTRACTNONLINEARELASTICITYSOLVER_HPP_
00030 #define ABSTRACTNONLINEARELASTICITYSOLVER_HPP_
00031 
00032 #include <vector>
00033 #include <cmath>
00034 #include "LinearSystem.hpp"
00035 #include "AbstractIncompressibleMaterialLaw.hpp"
00036 #include "OutputFileHandler.hpp"
00037 #include "LogFile.hpp"
00038 #include "PetscTools.hpp"
00039 #include "MechanicsEventHandler.hpp"
00040 #include "ReplicatableVector.hpp"
00041 
00042 //#include "PCBlockDiagonalMechanics.hpp"
00043 //#include "PCLDUFactorisationMechanics.hpp"
00044 
00045 
00046 //#define MECH_VERBOSE
00047 //#define MECH_VERY_VERBOSE
00048 
00050 //#define MECH_USE_MUMPS  // requires Petsc to be installed with MUMPS
00051 //#define MECH_USE_HYPRE  // requires Petsc to be installed with HYPRE
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 // Implementation
00388 
00389 
00390 template<unsigned DIM>
00391 void AbstractNonlinearElasticitySolver<DIM>::ApplyBoundaryConditions(bool applyToMatrix)
00392 {
00393     assert(mFixedNodeDisplacements.size()==mFixedNodes.size());
00394 
00395     // The boundary conditions on the NONLINEAR SYSTEM are x=boundary_values
00396     // on the boundary nodes. However:
00397     // The boundary conditions on the LINEAR SYSTEM  Ju=f, where J is the
00398     // u the negative update vector and f is the residual is
00399     // u=current_soln-boundary_values on the boundary nodes
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         // assemble the residual
00437         AssembleSystem(true, false);
00438     }
00439     else
00440     {
00441         try
00442         {
00443             // try to assemble the residual using this current solution
00444             AssembleSystem(true, false);
00445         }
00446         catch(Exception& e)
00447         {
00448             // if fail (because eg ODEs fail to solve, or strains are too large for material law), 
00449             // return infinity
00450             return DBL_MAX;
00451         }
00452     }
00453 
00454     // return the scaled norm of the residual
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     // Assemble Jacobian (and preconditioner)
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     // Solve the linear system.
00502     // Three alternatives
00503     //   (a) GMRES with ILU preconditioner (or bjacobi=ILU on each process) [default]. Very poor on large problems.
00504     //   (b) GMRES with AMG preconditioner. Uncomment #define MECH_USE_HYPRE above. Requires Petsc3 with HYPRE installed.
00505     //   (c) Solve using MUMPS direct solver Uncomment #define MECH_USE_MUMPS above. Requires Petsc 3 with MUMPS installed.
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         // no need for the precondition matrix
00522         KSPSetOperators(solver, r_jac, r_jac, DIFFERENT_NONZERO_PATTERN /*in precond between successive solves*/);
00523 
00524         KSPSetType(solver, KSPPREONLY);
00525         PCSetType(pc, PCLU);
00526         PCFactorSetMatSolverPackage(pc, MAT_SOLVER_MUMPS);
00527 
00528         // Allow matrices with zero diagonals to be solved
00529         PCFactorSetShiftNonzero(pc, PETSC_DECIDE);
00530         // "Do LU factorization in-place (saves memory)"
00531         PCASMSetUseInPlace(pc);
00532     #else
00533         Mat& r_precond_jac = mpPreconditionMatrixLinearSystem->rGetLhsMatrix();
00534         KSPSetOperators(solver, r_jac, r_precond_jac, DIFFERENT_NONZERO_PATTERN /*in precond between successive solves*/);
00535 
00536         unsigned num_restarts = 100;
00537         KSPSetType(solver,KSPGMRES);
00538         KSPGMRESSetRestart(solver,num_restarts); // gmres 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 /*max iter*/); //hopefully with the preconditioner this max is way too high
00544         }
00545         else
00546         {
00547             KSPSetTolerances(solver, 1e-16, mKspAbsoluteTol, PETSC_DEFAULT, 10000 /*max iter*/); //hopefully with the preconditioner this max is way too high
00548         }
00549 
00550         #ifndef MECH_USE_HYPRE 
00551             PCSetType(pc, PCBJACOBI); // BJACOBI = ILU on each block (block = part of matrix on each process)
00552         #else
00554             // Speed up linear solve time massively for larger simulations (in fact GMRES may stagnate without
00555             // this for larger problems), by using a AMG preconditioner -- needs HYPRE installed 
00557             PetscOptionsSetValue("-pc_hypre_type", "boomeramg");
00558             // PetscOptionsSetValue("-pc_hypre_boomeramg_max_iter", "1");
00559             // PetscOptionsSetValue("-pc_hypre_boomeramg_strong_threshold", "0.0");
00560         
00561             PCSetType(pc, PCHYPRE);
00562             KSPSetPreconditionerSide(solver, PC_RIGHT);
00563             
00564             // other possible preconditioners..
00565             //PCBlockDiagonalMechanics* p_custom_pc = new PCBlockDiagonalMechanics(solver, r_precond_jac, mBlock1Size, mBlock2Size);
00566             //PCLDUFactorisationMechanics* p_custom_pc = new PCLDUFactorisationMechanics(solver, r_precond_jac, mBlock1Size, mBlock2Size);
00567             //remember to delete memory..
00568             //KSPSetPreconditionerSide(solver, PC_RIGHT);
00569         #endif
00570 
00571         // uncomment to get convergence information
00572         //#ifdef MECH_VERBOSE
00573         //PetscOptionsSetValue("-ksp_monitor","");
00574         //#endif
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     // Update the solution
00604     //  Newton method:       sol = sol - update, where update=Jac^{-1}*residual
00605     //  Newton with damping: sol = sol - s*update, where s is chosen
00606     //   such that |residual(sol)| is minimised. Damping is important to
00607     //   avoid initial divergence.
00608     //
00609     // Normally, finding the best s from say 0.05,0.1,0.2,..,1.0 is cheap,
00610     // but this is not the case in cardiac electromechanics calculations.
00611     // Therefore, we initially check s=1 (expected to be the best most of the
00612     // time, then s=0.9. If the norm of the residual increases, we assume
00613     // s=1 is the best. Otherwise, check s=0.8 to see if s=0.9 is a local min.
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; // = {1.0, 0.9, .., 0.2, 0.1, 0.05} ie size 11
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     // let mCurrentSolution = old_solution - damping_val[0]*update; and compute residual
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     // let mCurrentSolution = old_solution - damping_val[1]*update; and compute residual
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     // While f(s_next) < f(s_current), [f = residnorm], keep trying new damping values,
00670     // ie exit thus loop when next norm of the residual first increases
00671     while (    (next_resid_norm==DBL_MAX) // the residual is returned as infinity if the deformation is so large to cause exceptions in the material law/EM contraction model
00672             || ( (next_resid_norm < current_resid_norm) && (index<damping_values.size()) ) )
00673     {
00674         current_resid_norm = next_resid_norm;
00675 
00676         // let mCurrentSolution = old_solution - damping_val*update; and compute residual
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         // Difficult to come up with large forces/tractions such that it had to
00689         // test right down to s=0.05, but overall doesn't fail.
00690         // The possible damping values have been manually temporarily altered to
00691         // get this code to be called, it appears to work correctly. Even if it
00692         // didn't tests wouldn't fail, they would just be v. slightly less efficient.
00693         #define COVERAGE_IGNORE
00694         // if we exited because we got to the end of the possible damping values, the
00695         // best one was the last one (excl the final index++ at the end)
00696         current_resid_norm = next_resid_norm;
00697         best_index = index-1;
00698         #undef COVERAGE_IGNORE
00699     }
00700     else
00701     {
00702         // else the best one must have been the second last one (excl the final index++ at the end)
00703         // (as we would have exited when the resid norm first increased)
00704         best_index = index-2;
00705     }
00706 
00707     // check out best was better than the original residual-norm
00708     if (initial_norm_resid < current_resid_norm)
00709     {
00710         #define COVERAGE_IGNORE
00711         // Have to use an assert/exit here as the following exception causes a seg fault (in cardiac mech problems?)
00712         // Don't know why
00713         std::cout << "CHASTE ERROR: (AbstractNonlinearElasticitySolver.hpp): Residual does not appear to decrease in newton direction, quitting.\n" << std::flush;
00714         exit(0);
00715         //EXCEPTION("Residual does not appear to decrease in newton direction, quitting");
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 //        double best_norm_resid = DBL_MAX;
00728 //        double best_damping_value = 0.0;
00729 //
00730 //        std::vector<double> damping_values;
00731 //        damping_values.reserve(12);
00732 //        damping_values.push_back(0.0);
00733 //        damping_values.push_back(0.05);
00734 //        for (unsigned i=1; i<=10; i++)
00735 //        {
00736 //            damping_values.push_back((double)i/10.0);
00737 //        }
00738 //
00739 //        for (unsigned i=0; i<damping_values.size(); i++)
00740 //        {
00741 //            for (unsigned j=0; j<mNumDofs; j++)
00742 //            {
00743 //                mCurrentSolution[j] = old_solution[j] - damping_values[i]*update[j];
00744 //            }
00745 //
00746 //            // compute residual
00747 //            double norm_resid = ComputeResidualAndGetNorm();
00748 //
00749 //            std::cout << "\tTesting s = " << damping_values[i] << ", |f| = " << norm_resid << "\n" << std::flush;
00750 //            if (norm_resid < best_norm_resid)
00751 //            {
00752 //                best_norm_resid = norm_resid;
00753 //                best_damping_value = damping_values[i];
00754 //            }
00755 //        }
00756 //
00757 //        if (best_damping_value == 0.0)
00758 //        {
00759 //            #define COVERAGE_IGNORE
00760 //            assert(0);
00761 //            EXCEPTION("Residual does not decrease in newton direction, quitting");
00762 //            #undef COVERAGE_IGNORE
00763 //        }
00764 //        else
00765 //        {
00766 //            std::cout << "\tBest s = " << best_damping_value << "\n"  << std::flush;
00767 //        }
00768 //        //Timer::PrintAndReset("Find best damping");
00769 //
00770 //        // implement best update and recalculate residual
00771 //        for (unsigned j=0; j<mNumDofs; j++)
00772 //        {
00773 //            mCurrentSolution[j] = old_solution[j] - best_damping_value*update[j];
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     // compute residual
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) // ie if wasn't passed in as a parameter
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         // take newton step (and get returned residual)
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     // only write output if the flag mWriteOutput has been set
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 // Constant setting definitions
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 /*ABSTRACTNONLINEARELASTICITYSOLVER_HPP_*/

Generated on Mon Nov 1 12:35:24 2010 for Chaste by  doxygen 1.5.5