StokesFlowSolver.hpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 
00036 #ifndef STOKESFLOWSOLVER_HPP_
00037 #define STOKESFLOWSOLVER_HPP_
00038 
00039 #include "AbstractContinuumMechanicsSolver.hpp"
00040 #include "LinearSystem.hpp"
00041 #include "LinearBasisFunction.hpp"
00042 #include "QuadraticBasisFunction.hpp"
00043 #include "Timer.hpp"
00044 #include "PetscMatTools.hpp"
00045 #include "PetscVecTools.hpp"
00046 #include "StokesFlowProblemDefinition.hpp"
00047 #include "StokesFlowAssembler.hpp"
00048 #include "StokesFlowPreconditionerAssembler.hpp"
00049 #include "ContinuumMechanicsNeumannBcsAssembler.hpp"
00050 
00054 template<unsigned DIM>
00055 class StokesFlowSolver : public AbstractContinuumMechanicsSolver<DIM>
00056 {
00057     friend class TestStokesFlowSolver;
00058 
00059 private:
00061     StokesFlowProblemDefinition<DIM>& mrProblemDefinition;
00062 
00064     StokesFlowAssembler<DIM>* mpStokesFlowAssembler;
00065 
00070     StokesFlowPreconditionerAssembler<DIM>* mpStokesFlowPreconditionerAssembler;
00071 
00076     ContinuumMechanicsNeumannBcsAssembler<DIM>* mpNeumannBcsAssembler;
00077 
00083     double mKspAbsoluteTol;
00084 
00088     void AssembleSystem();
00089 
00090 public:
00091 
00099     StokesFlowSolver(AbstractTetrahedralMesh<DIM,DIM>& rQuadMesh,
00100                      StokesFlowProblemDefinition<DIM>& rProblemDefinition,
00101                      std::string outputDirectory);
00102 
00106     virtual ~StokesFlowSolver();
00107 
00111     void Solve();
00112 
00119     void SetKspAbsoluteTolerance(double kspAbsoluteTolerance);
00120 
00121 
00126     std::vector<c_vector<double,DIM> >& rGetSpatialSolution();
00127 
00132     std::vector<c_vector<double,DIM> >& rGetVelocities();
00133 };
00134 
00136 // Implementation
00138 
00139 
00140 template<unsigned DIM>
00141 StokesFlowSolver<DIM>::StokesFlowSolver(AbstractTetrahedralMesh<DIM,DIM>& rQuadMesh,
00142                                         StokesFlowProblemDefinition<DIM>& rProblemDefinition,
00143                                         std::string outputDirectory)
00144     : AbstractContinuumMechanicsSolver<DIM>(rQuadMesh, rProblemDefinition, outputDirectory, INCOMPRESSIBLE),
00145       mrProblemDefinition(rProblemDefinition),
00146       mKspAbsoluteTol(-1)
00147 {
00148     assert(DIM==2 || DIM==3);
00149     assert(!mrProblemDefinition.rGetDirichletNodes().empty());
00150 
00151     mpStokesFlowAssembler = new StokesFlowAssembler<DIM>(&this->mrQuadMesh, &mrProblemDefinition);
00152     mpStokesFlowPreconditionerAssembler = new StokesFlowPreconditionerAssembler<DIM>(&this->mrQuadMesh, &mrProblemDefinition);
00153     mpNeumannBcsAssembler = new ContinuumMechanicsNeumannBcsAssembler<DIM>(&this->mrQuadMesh, &mrProblemDefinition);
00154 }
00155 
00156 template<unsigned DIM>
00157 StokesFlowSolver<DIM>::~StokesFlowSolver()
00158 {
00159     delete mpStokesFlowAssembler;
00160     delete mpStokesFlowPreconditionerAssembler;
00161     delete mpNeumannBcsAssembler;
00162 }
00163 
00164 template<unsigned DIM>
00165 void StokesFlowSolver<DIM>::Solve()
00166 {
00167     mrProblemDefinition.Validate();
00168 
00169     if(this->mVerbose)
00170     {
00171         Timer::Reset();
00172     }
00173 
00174     // Assemble Jacobian (and preconditioner)
00175     MechanicsEventHandler::BeginEvent(MechanicsEventHandler::ASSEMBLE);
00176     AssembleSystem();
00177     MechanicsEventHandler::EndEvent(MechanicsEventHandler::ASSEMBLE);
00178 
00179     if(this->mVerbose)
00180     {
00181         Timer::PrintAndReset("AssembleSystem");
00182     }
00183 
00184     /*
00185      * Solve the linear system using PETSc GMRES and an LU factorisation
00186      * of the preconditioner. Note we don't call Solve on the linear_system
00187      * as we want to set PETSc options.
00188      */
00189     MechanicsEventHandler::BeginEvent(MechanicsEventHandler::SOLVE);
00190 
00191     Vec solution;
00192     VecDuplicate(this->mLinearSystemRhsVector,&solution);
00193     PetscVecTools::Zero(solution);
00194 
00195     KSP solver;
00196     KSPCreate(PETSC_COMM_WORLD,&solver);
00197 #if ( PETSC_VERSION_MAJOR==3 && PETSC_VERSION_MINOR>=5 )
00198     KSPSetOperators(solver, this->mSystemLhsMatrix, this->mPreconditionMatrix);
00199 #else
00200     KSPSetOperators(solver, this->mSystemLhsMatrix, this->mPreconditionMatrix, DIFFERENT_NONZERO_PATTERN /*in precond between successive solves*/);
00201 #endif
00202     KSPSetType(solver, KSPGMRES);
00203 
00204     if (mKspAbsoluteTol < 0)
00205     {
00206         double ksp_rel_tol = 1e-6;
00207         KSPSetTolerances(solver, ksp_rel_tol, PETSC_DEFAULT, PETSC_DEFAULT, 10000 /*max iter*/); //hopefully with the preconditioner this max is way too high
00208     }
00209     else
00210     {
00211         KSPSetTolerances(solver, 1e-16, mKspAbsoluteTol, PETSC_DEFAULT, 10000 /*max iter*/); //hopefully with the preconditioner this max is way too high
00212     }
00213     unsigned num_restarts = 100;
00214     KSPGMRESSetRestart(solver,num_restarts); // gmres num restarts
00215 
00216     PC pc;
00217     KSPGetPC(solver, &pc);
00218     PCSetType(pc, PCJACOBI);
00219 
00220     KSPSetUp(solver);
00221 
00222     KSPSetFromOptions(solver);
00223 
00224 //    ///// For printing matrix when debugging
00225 //    OutputFileHandler handler("TEMP");
00226 //    out_stream p_file = handler.OpenOutputFile("matrix.txt");
00227 //    for(unsigned i=0; i<this->mNumDofs; i++)
00228 //    {
00229 //        for(unsigned j=0; j<this->mNumDofs; j++)
00230 //        {
00231 //            *p_file << PetscMatTools::GetElement(this->mSystemLhsMatrix, i, j) << " ";
00232 //        }
00233 //        *p_file << "\n";
00234 //    }
00235 //    p_file->close();
00236 //
00237 //    out_stream p_file2 = handler.OpenOutputFile("rhs.txt");
00238 //    for(unsigned i=0; i<this->mNumDofs; i++)
00239 //    {
00240 //        *p_file2 << PetscVecTools::GetElement(this->mLinearSystemRhsVector, i) << "\n";
00241 //    }
00242 //    p_file2->close();
00243 
00244     if(this->mVerbose)
00245     {
00246         Timer::PrintAndReset("KSP Setup");
00247     }
00248 
00249     KSPSolve(solver,this->mLinearSystemRhsVector,solution);
00250 
00251     KSPConvergedReason reason;
00252     KSPGetConvergedReason(solver,&reason);
00253     KSPEXCEPT(reason);
00254 
00255     if(this->mVerbose)
00256     {
00257         Timer::PrintAndReset("KSP Solve");
00258         int num_iters;
00259         KSPGetIterationNumber(solver, &num_iters);
00260         std::cout << "[" << PetscTools::GetMyRank() << "]: Num iterations = " << num_iters << "\n" << std::flush;
00261     }
00262 
00263     MechanicsEventHandler::EndEvent(MechanicsEventHandler::SOLVE);
00264 
00265     // Copy solution into the std::vector
00266     ReplicatableVector solution_repl(solution);
00267     for (unsigned i=0; i<this->mNumDofs; i++)
00268     {
00269         this->mCurrentSolution[i] = solution_repl[i];
00270     }
00271 
00272     // Remove pressure dummy values (P=0 at internal nodes, which should have been
00273     // been the result of the solve above), by linear interpolating from vertices of
00274     // edges to the internal node
00275     this->RemovePressureDummyValuesThroughLinearInterpolation();
00276 
00277     PetscTools::Destroy(solution);
00278     KSPDestroy(PETSC_DESTROY_PARAM(solver));
00279 
00280     this->WriteCurrentSpatialSolution("flow_solution", "nodes");
00281     this->WriteCurrentPressureSolution();
00282 }
00283 
00284 
00285 
00286 template<unsigned DIM>
00287 void StokesFlowSolver<DIM>::AssembleSystem()
00288 {
00289     // Use assembler to assemble volume integral part....
00290     mpStokesFlowAssembler->SetMatrixToAssemble(this->mSystemLhsMatrix, true);
00291     mpStokesFlowAssembler->SetVectorToAssemble(this->mLinearSystemRhsVector, true);
00292     mpStokesFlowAssembler->Assemble();
00293 
00294     mpStokesFlowPreconditionerAssembler->SetMatrixToAssemble(this->mPreconditionMatrix, true);
00295     mpStokesFlowPreconditionerAssembler->AssembleMatrix();
00296 
00297     mpNeumannBcsAssembler->SetVectorToAssemble(this->mLinearSystemRhsVector, false /*don't zero!*/);
00298     mpNeumannBcsAssembler->AssembleVector();
00299 
00300     PetscVecTools::Finalise(this->mLinearSystemRhsVector);
00301     PetscMatTools::SwitchWriteMode(this->mSystemLhsMatrix);
00302     PetscMatTools::SwitchWriteMode(this->mPreconditionMatrix);
00303 
00304     // Note: maintaining symmetry for Dirichlet BCs is possible at the moment (the second parameter)
00305     // but doing so for the identity block is not yet implemented (the second parameter must be false)
00306     // Not sure if maintaining symmetry is worth it - may allow CG to work, but matrix is indefinite
00307     // so GC not guaranteed to work..
00308     //
00309     // Note: the identity block needs to be added before the BCs - see comments in
00310     // PetscMatTools::ZeroRowsWithValueOnDiagonal()
00311     this->AddIdentityBlockForDummyPressureVariables(LINEAR_PROBLEM);
00312     this->ApplyDirichletBoundaryConditions(LINEAR_PROBLEM, true);
00313 
00314     PetscVecTools::Finalise(this->mLinearSystemRhsVector);
00315     PetscMatTools::Finalise(this->mSystemLhsMatrix);
00316     PetscMatTools::Finalise(this->mPreconditionMatrix);
00317 }
00318 
00319 template<unsigned DIM>
00320 void StokesFlowSolver<DIM>::SetKspAbsoluteTolerance(double kspAbsoluteTolerance)
00321 {
00322     assert(kspAbsoluteTolerance > 0);
00323     mKspAbsoluteTol = kspAbsoluteTolerance;
00324 }
00325 
00326 template<unsigned DIM>
00327 std::vector<c_vector<double,DIM> >& StokesFlowSolver<DIM>::rGetSpatialSolution()
00328 {
00329     this->mSpatialSolution.resize(this->mrQuadMesh.GetNumNodes(), zero_vector<double>(DIM));
00330     for (unsigned i=0; i<this->mrQuadMesh.GetNumNodes(); i++)
00331     {
00332         for (unsigned j=0; j<DIM; j++)
00333         {
00334             // DIM+1 is the problem dimension
00335             this->mSpatialSolution[i](j) = this->mCurrentSolution[(DIM+1)*i+j];
00336         }
00337     }
00338     return this->mSpatialSolution;
00339 }
00340 
00341 template<unsigned DIM>
00342 std::vector<c_vector<double,DIM> >& StokesFlowSolver<DIM>::rGetVelocities()
00343 {
00344     return rGetSpatialSolution();
00345 }
00346 
00347 
00348 
00349 #endif /* STOKESFLOWSOLVER_HPP_ */

Generated by  doxygen 1.6.2