AbstractDynamicLinearPdeSolver.hpp

00001 
00002 /*
00003 
00004 Copyright (C) University of Oxford, 2005-2011
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 Chaste is free software: you can redistribute it and/or modify it
00013 under the terms of the GNU Lesser General Public License as published
00014 by the Free Software Foundation, either version 2.1 of the License, or
00015 (at your option) any later version.
00016 
00017 Chaste is distributed in the hope that it will be useful, but WITHOUT
00018 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00019 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00020 License for more details. The offer of Chaste under the terms of the
00021 License is subject to the License being interpreted in accordance with
00022 English Law and subject to any action against the University of Oxford
00023 being under the jurisdiction of the English Courts.
00024 
00025 You should have received a copy of the GNU Lesser General Public License
00026 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00027 
00028 */
00029 
00030 #ifndef ABSTRACTDYNAMICLINEARPDESOLVER_HPP_
00031 #define ABSTRACTDYNAMICLINEARPDESOLVER_HPP_
00032 
00033 #include "Exception.hpp"
00034 #include "TimeStepper.hpp"
00035 #include "AbstractLinearPdeSolver.hpp"
00036 #include "PdeSimulationTime.hpp"
00037 #include "AbstractTimeAdaptivityController.hpp"
00038 #include "Hdf5DataWriter.hpp"
00039 #include "Hdf5ToVtkConverter.hpp"
00040 #include "Hdf5ToTxtConverter.hpp"
00041 
00048 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00049 class AbstractDynamicLinearPdeSolver : public AbstractLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>
00050 {
00051     friend class TestSimpleLinearParabolicSolver;
00052 protected:
00053 
00055     double mTstart;
00056 
00058     double mTend;
00059 
00061     bool mTimesSet;
00062 
00064     Vec mInitialCondition;
00065 
00067     bool mMatrixIsAssembled;
00068 
00073     bool mMatrixIsConstant;
00074 
00079     double mIdealTimeStep;
00080 
00082     double mLastWorkingTimeStep;
00083 
00085     AbstractTimeAdaptivityController* mpTimeAdaptivityController;
00086 
00091     bool mOutputToVtk;
00092 
00097     bool mOutputToParallelVtk;
00098 
00103     bool mOutputToTxt;
00104 
00106     std::string mOutputDirectory;
00107 
00109     std::string mFilenamePrefix;
00110 
00116     unsigned mPrintingTimestepMultiple;
00117 
00119     Hdf5DataWriter* mpHdf5Writer;
00120 
00122     std::vector<int> mVariableColumnIds;
00123 
00128     void InitialiseHdf5Writer();
00129 
00136     void WriteOneStep(double time, Vec solution);
00137 
00138 public:
00139 
00145     AbstractDynamicLinearPdeSolver(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh);
00146 
00153     void SetTimes(double tStart, double tEnd);
00154 
00160     void SetTimeStep(double dt);
00161 
00170     void SetInitialCondition(Vec initialCondition);
00171 
00173     Vec Solve();
00174 
00176     void SetMatrixIsNotAssembled();
00177 
00183     void SetTimeAdaptivityController(AbstractTimeAdaptivityController* pTimeAdaptivityController);
00184 
00188     void SetOutputToVtk(bool output);
00189 
00193     void SetOutputToParallelVtk(bool output);
00194 
00198     void SetOutputToTxt(bool output);
00199 
00204     void SetOutputDirectoryAndPrefix(std::string outputDirectory, std::string prefix);
00205 
00210     void SetPrintingTimestepMultiple(unsigned multiple);
00211 };
00212 
00213 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00214 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::InitialiseHdf5Writer()
00215 {
00216     // Check that everything is set up correctly
00217     if ((mOutputDirectory=="") || (mFilenamePrefix==""))
00218     {
00219         EXCEPTION("Output directory or filename prefix has not been set");
00220     }
00221 
00222     // Create writer
00223     mpHdf5Writer = new Hdf5DataWriter(*(this->mpMesh)->GetDistributedVectorFactory(),
00224                                       mOutputDirectory,
00225                                       mFilenamePrefix);
00226 
00227     // Set writer to output all nodes
00228     mpHdf5Writer->DefineFixedDimension((this->mpMesh)->GetNumNodes());
00229 
00230     // Only used to get an estimate of the number of timesteps below
00231     unsigned estimated_num_printing_timesteps = 1u + (unsigned)((mTend - mTstart)/(mIdealTimeStep*mPrintingTimestepMultiple));
00232 
00239     assert(mVariableColumnIds.empty());
00240     for (unsigned i=0; i<PROBLEM_DIM; i++)
00241     {
00242         std::stringstream variable_name;
00243         variable_name << "Variable_" << i;
00244         mVariableColumnIds.push_back(mpHdf5Writer->DefineVariable(variable_name.str(),"undefined"));
00245     }
00246     mpHdf5Writer->DefineUnlimitedDimension("Time", "undefined", estimated_num_printing_timesteps);
00247 
00248     // End the define mode of the writer
00249     mpHdf5Writer->EndDefineMode();
00250 }
00251 
00252 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00253 AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::AbstractDynamicLinearPdeSolver(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00254     : AbstractLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>(pMesh),
00255       mTimesSet(false),
00256       mInitialCondition(NULL),
00257       mMatrixIsAssembled(false),
00258       mMatrixIsConstant(false),
00259       mIdealTimeStep(-1.0),
00260       mLastWorkingTimeStep(-1),
00261       mpTimeAdaptivityController(NULL),
00262       mOutputToVtk(false),
00263       mOutputToParallelVtk(false),
00264       mOutputToTxt(false),
00265       mOutputDirectory(""),
00266       mFilenamePrefix(""),
00267       mPrintingTimestepMultiple(1),
00268       mpHdf5Writer(NULL)
00269 {
00270 }
00271 
00272 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00273 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetTimes(double tStart, double tEnd)
00274 {
00275     mTstart = tStart;
00276     mTend = tEnd;
00277 
00278     if (mTstart >= mTend)
00279     {
00280         EXCEPTION("Start time has to be less than end time");
00281     }
00282 
00283     mTimesSet = true;
00284 }
00285 
00286 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00287 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetTimeStep(double dt)
00288 {
00289     if (dt <= 0)
00290     {
00291         EXCEPTION("Time step has to be greater than zero");
00292     }
00293 
00294     mIdealTimeStep = dt;
00295 }
00296 
00297 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00298 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetInitialCondition(Vec initialCondition)
00299 {
00300     assert(initialCondition != NULL);
00301     mInitialCondition = initialCondition;
00302 }
00303 
00304 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00305 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::WriteOneStep(double time, Vec solution)
00306 {
00307     mpHdf5Writer->PutUnlimitedVariable(time);
00308     if (PROBLEM_DIM == 1)
00309     {
00310         mpHdf5Writer->PutVector(mVariableColumnIds[0], solution);
00311     }
00312     else
00313     {
00314         mpHdf5Writer->PutStripedVector(mVariableColumnIds, solution);
00315     }
00316 }
00317 
00318 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00319 Vec AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::Solve()
00320 {
00321     // Begin by checking that everything has been set up correctly
00322     if (!mTimesSet)
00323     {
00324         EXCEPTION("SetTimes() has not been called");
00325     }
00326     if ((mIdealTimeStep <= 0.0) && (mpTimeAdaptivityController==NULL))
00327     {
00328         EXCEPTION("SetTimeStep() has not been called");
00329     }
00330     if (mInitialCondition == NULL)
00331     {
00332         EXCEPTION("SetInitialCondition() has not been called");
00333     }
00334 
00335     // If required, initialise HDF5 writer and output initial condition to HDF5 file
00336     bool print_output = (mOutputToVtk || mOutputToParallelVtk || mOutputToTxt);
00337     if (print_output)
00338     {
00339         InitialiseHdf5Writer();
00340         WriteOneStep(mTstart, mInitialCondition);
00341         mpHdf5Writer->AdvanceAlongUnlimitedDimension();
00342     }
00343 
00344     this->InitialiseForSolve(mInitialCondition);
00345 
00346     if (mIdealTimeStep < 0) // hasn't been set, so a controller must have been given
00347     {
00348         mIdealTimeStep = mpTimeAdaptivityController->GetNextTimeStep(mTstart, mInitialCondition);
00349     }
00350 
00351     /*
00352      * Note: we use the mIdealTimeStep here (the original timestep that was passed in, or
00353      * the last timestep suggested by the controller), rather than the last timestep used
00354      * (mLastWorkingTimeStep), because the timestep will be very slightly altered by the
00355      * stepper in the final timestep of the last printing-timestep-loop, and these floating
00356      * point errors can add up and eventually cause exceptions being thrown.
00357      */
00358     TimeStepper stepper(mTstart, mTend, mIdealTimeStep, mMatrixIsConstant);
00359 
00360     Vec solution = mInitialCondition;
00361     Vec next_solution;
00362 
00363     while (!stepper.IsTimeAtEnd())
00364     {
00365         bool timestep_changed = false;
00366 
00367         PdeSimulationTime::SetTime(stepper.GetTime());
00368 
00369         // Determine timestep to use
00370         double new_dt;
00371         if (mpTimeAdaptivityController)
00372         {
00373             // Get the timestep the controller wants to use and store it as the ideal timestep
00374             mIdealTimeStep = mpTimeAdaptivityController->GetNextTimeStep(stepper.GetTime(), solution);
00375 
00376             // Tell the stepper to use this timestep from now on...
00377             stepper.ResetTimeStep(mIdealTimeStep);
00378 
00379             // ..but now get the timestep from the stepper, as the stepper might need
00380             // to trim the timestep if it would take us over the end time
00381             new_dt = stepper.GetNextTimeStep();
00382             // Changes in timestep bigger than 0.001% will trigger matrix re-computation
00383             timestep_changed = (fabs(new_dt/mLastWorkingTimeStep - 1.0) > 1e-5);
00384         }
00385         else
00386         {
00387             new_dt = stepper.GetNextTimeStep();
00388 
00389             //new_dt should be roughly the same size as mIdealTimeStep - we should never need to take a tiny step
00390 
00391             if (mMatrixIsConstant && fabs(new_dt/mIdealTimeStep - 1.0) > 1e-5)
00392             {
00393                 // Here we allow for changes of up to 0.001%
00394                 // Note that the TimeStepper guarantees that changes in dt are no bigger than DBL_EPSILON*current_time
00395                 NEVER_REACHED;
00396             }
00397         }
00398 
00399         // Save the timestep as the last one use, and also put it in PdeSimulationTime
00400         // so everyone can see it
00401         mLastWorkingTimeStep = new_dt;
00402         PdeSimulationTime::SetPdeTimeStep(new_dt);
00403 
00404         // Solve
00405 
00406         this->PrepareForSetupLinearSystem(solution);
00407 
00408         bool compute_matrix = (!mMatrixIsConstant || !mMatrixIsAssembled || timestep_changed);
00409 
00410         this->SetupLinearSystem(solution, compute_matrix);
00411 
00412         this->FinaliseLinearSystem(solution);
00413 
00414         if (compute_matrix)
00415         {
00416             this->mpLinearSystem->ResetKspSolver();
00417         }
00418 
00419         next_solution = this->mpLinearSystem->Solve(solution);
00420 
00421         if (mMatrixIsConstant)
00422         {
00423             mMatrixIsAssembled = true;
00424         }
00425 
00426         this->FollowingSolveLinearSystem(next_solution);
00427 
00428         stepper.AdvanceOneTimeStep();
00429 
00430         // Avoid memory leaks
00431         if (solution != mInitialCondition)
00432         {
00433             HeartEventHandler::BeginEvent(HeartEventHandler::COMMUNICATION);
00434             VecDestroy(solution);
00435             HeartEventHandler::EndEvent(HeartEventHandler::COMMUNICATION);
00436         }
00437         solution = next_solution;
00438 
00439         // If required, output next solution to HDF5 file
00440         if (print_output && (stepper.GetTotalTimeStepsTaken()%mPrintingTimestepMultiple == 0) )
00441         {
00442             WriteOneStep(stepper.GetTime(), solution);
00443             mpHdf5Writer->AdvanceAlongUnlimitedDimension();
00444         }
00445     }
00446 
00447     // Avoid memory leaks
00448     if (mpHdf5Writer != NULL)
00449     {
00450         delete mpHdf5Writer;
00451         mpHdf5Writer = NULL;
00452     }
00453 
00454     // Convert HDF5 output to other formats as required
00455 
00456     if (mOutputToVtk)
00457     {
00458         Hdf5ToVtkConverter<ELEMENT_DIM,SPACE_DIM> converter(mOutputDirectory, mFilenamePrefix, this->mpMesh, false, false);
00459     }
00460     if (mOutputToParallelVtk)
00461     {
00462         Hdf5ToVtkConverter<ELEMENT_DIM,SPACE_DIM> converter(mOutputDirectory, mFilenamePrefix, this->mpMesh, true, false);
00463     }
00464     if (mOutputToTxt)
00465     {
00466         Hdf5ToTxtConverter<ELEMENT_DIM,SPACE_DIM> converter(mOutputDirectory, mFilenamePrefix, this->mpMesh);
00467     }
00468 
00469     return solution;
00470 }
00471 
00472 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00473 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetMatrixIsNotAssembled()
00474 {
00475     mMatrixIsAssembled = false;
00476 }
00477 
00478 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00479 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetTimeAdaptivityController(AbstractTimeAdaptivityController* pTimeAdaptivityController)
00480 {
00481     assert(pTimeAdaptivityController != NULL);
00482     assert(mpTimeAdaptivityController == NULL);
00483     mpTimeAdaptivityController = pTimeAdaptivityController;
00484 }
00485 
00486 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00487 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetOutputToVtk(bool output)
00488 {
00489     mOutputToVtk = output;
00490 }
00491 
00492 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00493 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetOutputToParallelVtk(bool output)
00494 {
00495     mOutputToParallelVtk = output;
00496 }
00497 
00498 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00499 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetOutputToTxt(bool output)
00500 {
00501     mOutputToTxt = output;
00502 }
00503 
00504 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00505 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetOutputDirectoryAndPrefix(std::string outputDirectory, std::string prefix)
00506 {
00507     mOutputDirectory = outputDirectory;
00508     mFilenamePrefix = prefix;
00509 }
00510 
00511 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00512 void AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetPrintingTimestepMultiple(unsigned multiple)
00513 {
00514     mPrintingTimestepMultiple = multiple;
00515 }
00516 
00517 #endif /*ABSTRACTDYNAMICLINEARPDESOLVER_HPP_*/
Generated on Thu Dec 22 13:00:17 2011 for Chaste by  doxygen 1.6.3