Chaste Release::3.1
|
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_*/