Chaste Release::3.1
AbstractDynamicLinearPdeSolver.hpp
00001 
00002 /*
00003 
00004 Copyright (c) 2005-2012, University of Oxford.
00005 All rights reserved.
00006 
00007 University of Oxford means the Chancellor, Masters and Scholars of the
00008 University of Oxford, having an administrative office at Wellington
00009 Square, Oxford OX1 2JD, UK.
00010 
00011 This file is part of Chaste.
00012 
00013 Redistribution and use in source and binary forms, with or without
00014 modification, are permitted provided that the following conditions are met:
00015  * Redistributions of source code must retain the above copyright notice,
00016    this list of conditions and the following disclaimer.
00017  * Redistributions in binary form must reproduce the above copyright notice,
00018    this list of conditions and the following disclaimer in the documentation
00019    and/or other materials provided with the distribution.
00020  * Neither the name of the University of Oxford nor the names of its
00021    contributors may be used to endorse or promote products derived from this
00022    software without specific prior written permission.
00023 
00024 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00025 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00027 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00028 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00029 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00030 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00031 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00033 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 
00035 */
00036 
00037 #ifndef ABSTRACTDYNAMICLINEARPDESOLVER_HPP_
00038 #define ABSTRACTDYNAMICLINEARPDESOLVER_HPP_
00039 
00040 #include "Exception.hpp"
00041 #include "TimeStepper.hpp"
00042 #include "AbstractLinearPdeSolver.hpp"
00043 #include "PdeSimulationTime.hpp"
00044 #include "AbstractTimeAdaptivityController.hpp"
00045 #include "Hdf5DataWriter.hpp"
00046 #include "Hdf5ToVtkConverter.hpp"
00047 #include "Hdf5ToTxtConverter.hpp"
00048 
00055 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00056 class AbstractDynamicLinearPdeSolver : public AbstractLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>
00057 {
00058     friend class TestSimpleLinearParabolicSolver;
00059 protected:
00060 
00062     double mTstart;
00063 
00065     double mTend;
00066 
00068     bool mTimesSet;
00069 
00071     Vec mInitialCondition;
00072 
00074     bool mMatrixIsAssembled;
00075 
00080     bool mMatrixIsConstant;
00081 
00086     double mIdealTimeStep;
00087 
00089     double mLastWorkingTimeStep;
00090 
00092     AbstractTimeAdaptivityController* mpTimeAdaptivityController;
00093 
00098     bool mOutputToVtk;
00099 
00104     bool mOutputToParallelVtk;
00105 
00110     bool mOutputToTxt;
00111 
00113     std::string mOutputDirectory;
00114 
00116     std::string mFilenamePrefix;
00117 
00123     unsigned mPrintingTimestepMultiple;
00124 
00126     Hdf5DataWriter* mpHdf5Writer;
00127 
00129     std::vector<int> mVariableColumnIds;
00130 
00135     void InitialiseHdf5Writer();
00136 
00143     void WriteOneStep(double time, Vec solution);
00144 
00145 public:
00146 
00152     AbstractDynamicLinearPdeSolver(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh);
00153 
00160     void SetTimes(double tStart, double tEnd);
00161 
00167     void SetTimeStep(double dt);
00168 
00177     void SetInitialCondition(Vec initialCondition);
00178 
00180     Vec Solve();
00181 
00183     void SetMatrixIsNotAssembled();
00184 
00190     void SetTimeAdaptivityController(AbstractTimeAdaptivityController* pTimeAdaptivityController);
00191 
00195     void SetOutputToVtk(bool output);
00196 
00200     void SetOutputToParallelVtk(bool output);
00201 
00205     void SetOutputToTxt(bool output);
00206 
00211     void SetOutputDirectoryAndPrefix(std::string outputDirectory, std::string prefix);
00212 
00217     void SetPrintingTimestepMultiple(unsigned multiple);
00218 };
00219 
00220 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00221 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::InitialiseHdf5Writer()
00222 {
00223     // Check that everything is set up correctly
00224     if ((mOutputDirectory=="") || (mFilenamePrefix==""))
00225     {
00226         EXCEPTION("Output directory or filename prefix has not been set");
00227     }
00228 
00229     // Create writer
00230     mpHdf5Writer = new Hdf5DataWriter(*(this->mpMesh)->GetDistributedVectorFactory(),
00231                                       mOutputDirectory,
00232                                       mFilenamePrefix);
00233 
00234     // Set writer to output all nodes
00235     mpHdf5Writer->DefineFixedDimension((this->mpMesh)->GetNumNodes());
00236 
00237     // Only used to get an estimate of the number of timesteps below
00238     unsigned estimated_num_printing_timesteps = 1u + (unsigned)((mTend - mTstart)/(mIdealTimeStep*mPrintingTimestepMultiple));
00239 
00246     assert(mVariableColumnIds.empty());
00247     for (unsigned i=0; i<PROBLEM_DIM; i++)
00248     {
00249         std::stringstream variable_name;
00250         variable_name << "Variable_" << i;
00251         mVariableColumnIds.push_back(mpHdf5Writer->DefineVariable(variable_name.str(),"undefined"));
00252     }
00253     mpHdf5Writer->DefineUnlimitedDimension("Time", "undefined", estimated_num_printing_timesteps);
00254 
00255     // End the define mode of the writer
00256     mpHdf5Writer->EndDefineMode();
00257 }
00258 
00259 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00260 AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::AbstractDynamicLinearPdeSolver(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00261     : AbstractLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>(pMesh),
00262       mTimesSet(false),
00263       mInitialCondition(NULL),
00264       mMatrixIsAssembled(false),
00265       mMatrixIsConstant(false),
00266       mIdealTimeStep(-1.0),
00267       mLastWorkingTimeStep(-1),
00268       mpTimeAdaptivityController(NULL),
00269       mOutputToVtk(false),
00270       mOutputToParallelVtk(false),
00271       mOutputToTxt(false),
00272       mOutputDirectory(""),
00273       mFilenamePrefix(""),
00274       mPrintingTimestepMultiple(1),
00275       mpHdf5Writer(NULL)
00276 {
00277 }
00278 
00279 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00280 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetTimes(double tStart, double tEnd)
00281 {
00282     mTstart = tStart;
00283     mTend = tEnd;
00284 
00285     if (mTstart >= mTend)
00286     {
00287         EXCEPTION("Start time has to be less than end time");
00288     }
00289 
00290     mTimesSet = true;
00291 }
00292 
00293 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00294 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetTimeStep(double dt)
00295 {
00296     if (dt <= 0)
00297     {
00298         EXCEPTION("Time step has to be greater than zero");
00299     }
00300 
00301     mIdealTimeStep = dt;
00302 }
00303 
00304 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00305 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetInitialCondition(Vec initialCondition)
00306 {
00307     assert(initialCondition != NULL);
00308     mInitialCondition = initialCondition;
00309 }
00310 
00311 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00312 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::WriteOneStep(double time, Vec solution)
00313 {
00314     mpHdf5Writer->PutUnlimitedVariable(time);
00315     if (PROBLEM_DIM == 1)
00316     {
00317         mpHdf5Writer->PutVector(mVariableColumnIds[0], solution);
00318     }
00319     else
00320     {
00321         mpHdf5Writer->PutStripedVector(mVariableColumnIds, solution);
00322     }
00323 }
00324 
00325 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00326 Vec AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::Solve()
00327 {
00328     // Begin by checking that everything has been set up correctly
00329     if (!mTimesSet)
00330     {
00331         EXCEPTION("SetTimes() has not been called");
00332     }
00333     if ((mIdealTimeStep <= 0.0) && (mpTimeAdaptivityController==NULL))
00334     {
00335         EXCEPTION("SetTimeStep() has not been called");
00336     }
00337     if (mInitialCondition == NULL)
00338     {
00339         EXCEPTION("SetInitialCondition() has not been called");
00340     }
00341 
00342     // If required, initialise HDF5 writer and output initial condition to HDF5 file
00343     bool print_output = (mOutputToVtk || mOutputToParallelVtk || mOutputToTxt);
00344     if (print_output)
00345     {
00346         InitialiseHdf5Writer();
00347         WriteOneStep(mTstart, mInitialCondition);
00348         mpHdf5Writer->AdvanceAlongUnlimitedDimension();
00349     }
00350 
00351     this->InitialiseForSolve(mInitialCondition);
00352 
00353     if (mIdealTimeStep < 0) // hasn't been set, so a controller must have been given
00354     {
00355         mIdealTimeStep = mpTimeAdaptivityController->GetNextTimeStep(mTstart, mInitialCondition);
00356     }
00357 
00358     /*
00359      * Note: we use the mIdealTimeStep here (the original timestep that was passed in, or
00360      * the last timestep suggested by the controller), rather than the last timestep used
00361      * (mLastWorkingTimeStep), because the timestep will be very slightly altered by the
00362      * stepper in the final timestep of the last printing-timestep-loop, and these floating
00363      * point errors can add up and eventually cause exceptions being thrown.
00364      */
00365     TimeStepper stepper(mTstart, mTend, mIdealTimeStep, mMatrixIsConstant);
00366 
00367     Vec solution = mInitialCondition;
00368     Vec next_solution;
00369 
00370     while (!stepper.IsTimeAtEnd())
00371     {
00372         bool timestep_changed = false;
00373 
00374         PdeSimulationTime::SetTime(stepper.GetTime());
00375 
00376         // Determine timestep to use
00377         double new_dt;
00378         if (mpTimeAdaptivityController)
00379         {
00380             // Get the timestep the controller wants to use and store it as the ideal timestep
00381             mIdealTimeStep = mpTimeAdaptivityController->GetNextTimeStep(stepper.GetTime(), solution);
00382 
00383             // Tell the stepper to use this timestep from now on...
00384             stepper.ResetTimeStep(mIdealTimeStep);
00385 
00386             // ..but now get the timestep from the stepper, as the stepper might need
00387             // to trim the timestep if it would take us over the end time
00388             new_dt = stepper.GetNextTimeStep();
00389             // Changes in timestep bigger than 0.001% will trigger matrix re-computation
00390             timestep_changed = (fabs(new_dt/mLastWorkingTimeStep - 1.0) > 1e-5);
00391         }
00392         else
00393         {
00394             new_dt = stepper.GetNextTimeStep();
00395 
00396             //new_dt should be roughly the same size as mIdealTimeStep - we should never need to take a tiny step
00397 
00398             if (mMatrixIsConstant && fabs(new_dt/mIdealTimeStep - 1.0) > 1e-5)
00399             {
00400                 // Here we allow for changes of up to 0.001%
00401                 // Note that the TimeStepper guarantees that changes in dt are no bigger than DBL_EPSILON*current_time
00402                 NEVER_REACHED;
00403             }
00404         }
00405 
00406         // Save the timestep as the last one use, and also put it in PdeSimulationTime
00407         // so everyone can see it
00408         mLastWorkingTimeStep = new_dt;
00409         PdeSimulationTime::SetPdeTimeStep(new_dt);
00410 
00411         // Solve
00412 
00413         this->PrepareForSetupLinearSystem(solution);
00414 
00415         bool compute_matrix = (!mMatrixIsConstant || !mMatrixIsAssembled || timestep_changed);
00416 
00417         this->SetupLinearSystem(solution, compute_matrix);
00418 
00419         this->FinaliseLinearSystem(solution);
00420 
00421         if (compute_matrix)
00422         {
00423             this->mpLinearSystem->ResetKspSolver();
00424         }
00425 
00426         next_solution = this->mpLinearSystem->Solve(solution);
00427 
00428         if (mMatrixIsConstant)
00429         {
00430             mMatrixIsAssembled = true;
00431         }
00432 
00433         this->FollowingSolveLinearSystem(next_solution);
00434 
00435         stepper.AdvanceOneTimeStep();
00436 
00437         // Avoid memory leaks
00438         if (solution != mInitialCondition)
00439         {
00440             HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00441             PetscTools::Destroy(solution);
00442             HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00443         }
00444         solution = next_solution;
00445 
00446         // If required, output next solution to HDF5 file
00447         if (print_output && (stepper.GetTotalTimeStepsTaken()%mPrintingTimestepMultiple == 0) )
00448         {
00449             WriteOneStep(stepper.GetTime(), solution);
00450             mpHdf5Writer->AdvanceAlongUnlimitedDimension();
00451         }
00452     }
00453 
00454     // Avoid memory leaks
00455     if (mpHdf5Writer != NULL)
00456     {
00457         delete mpHdf5Writer;
00458         mpHdf5Writer = NULL;
00459     }
00460 
00461     // Convert HDF5 output to other formats as required
00462 
00463     if (mOutputToVtk)
00464     {
00465         Hdf5ToVtkConverter<ELEMENT_DIM,SPACE_DIM> converter(mOutputDirectory, mFilenamePrefix, this->mpMesh, false, false);
00466     }
00467     if (mOutputToParallelVtk)
00468     {
00469         Hdf5ToVtkConverter<ELEMENT_DIM,SPACE_DIM> converter(mOutputDirectory, mFilenamePrefix, this->mpMesh, true, false);
00470     }
00471     if (mOutputToTxt)
00472     {
00473         Hdf5ToTxtConverter<ELEMENT_DIM,SPACE_DIM> converter(mOutputDirectory, mFilenamePrefix, this->mpMesh);
00474     }
00475 
00476     return solution;
00477 }
00478 
00479 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00480 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetMatrixIsNotAssembled()
00481 {
00482     mMatrixIsAssembled = false;
00483 }
00484 
00485 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00486 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetTimeAdaptivityController(AbstractTimeAdaptivityController* pTimeAdaptivityController)
00487 {
00488     assert(pTimeAdaptivityController != NULL);
00489     assert(mpTimeAdaptivityController == NULL);
00490     mpTimeAdaptivityController = pTimeAdaptivityController;
00491 }
00492 
00493 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00494 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetOutputToVtk(bool output)
00495 {
00496     mOutputToVtk = output;
00497 }
00498 
00499 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00500 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetOutputToParallelVtk(bool output)
00501 {
00502     mOutputToParallelVtk = output;
00503 }
00504 
00505 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00506 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetOutputToTxt(bool output)
00507 {
00508     mOutputToTxt = output;
00509 }
00510 
00511 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00512 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetOutputDirectoryAndPrefix(std::string outputDirectory, std::string prefix)
00513 {
00514     mOutputDirectory = outputDirectory;
00515     mFilenamePrefix = prefix;
00516 }
00517 
00518 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00519 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetPrintingTimestepMultiple(unsigned multiple)
00520 {
00521     mPrintingTimestepMultiple = multiple;
00522 }
00523 
00524 #endif /*ABSTRACTDYNAMICLINEARPDESOLVER_HPP_*/