/* * == Test 2: Solving a linear parabolic PDE == * * Now we solve a parabolic PDE. We choose a simple problem so that the code changes * needed from the elliptic case are clearer. We will solve * du/dt = div(grad u) + u, in 3d, with boundary conditions u=1 on the boundary, and initial * conditions u=1. * */ void TestSolvingParabolicPde() throw(Exception) { /* Create a 10 by 10 by 10 mesh in 3D, this time using the {{{ConstructRegularSlabMesh}}} method * on the mesh. The first parameter is the cartesian space-step and the other three parameters are the width, height and depth of the mesh.*/ TetrahedralMesh<3,3> mesh; mesh.ConstructRegularSlabMesh(0.1, 1.0, 1.0, 1.0); /* Our PDE object should be a class that is derived from the {{{AbstractLinearParabolicPde}}}. * We could write it ourselves as in the previous test, but since the PDE we want to solve is * so simple, it has already been defined (look it up! - it is located in pde/test/pdes). */ HeatEquationWithSourceTerm<3> pde; /* Create a new boundary conditions container and specify u=1.0 on the boundary. */ BoundaryConditionsContainer<3,3,1> bcc; bcc.DefineConstantDirichletOnMeshBoundary(&mesh, 1.0); /* Create an instance of the solver, passing in the mesh, pde and boundary conditions. */ SimpleLinearParabolicSolver<3,3> solver(&mesh,&pde,&bcc); /* For parabolic problems, initial conditions are also needed. The solver will expect * a PETSc vector, where the i-th entry is the initial solution at node i, to be passed * in. To create this PETSc {{{Vec}}}, we will use a helper function in the {{{PetscTools}}} * class to create a {{{Vec}}} of size num_nodes, with each entry set to 1.0. Then we * set the initial condition on the solver. */ Vec initial_condition = PetscTools::CreateAndSetVec(mesh.GetNumNodes(), 1.0); solver.SetInitialCondition(initial_condition); /* Next define the start time, end time, and timestep, and set them. */ double t_start = 0; double t_end = 1; double dt = 0.01; solver.SetTimes(t_start, t_end); solver.SetTimeStep(dt); /* HOW_TO_TAG PDE * Output results to file for time-dependent PDE solvers */ /* When we call Solve() below we will just get the solution at the final time. If we want * to have intermediate solutions written to file, we do the following. We start by * specifying an output directory and filename prefix for our results file: */ solver.SetOutputDirectoryAndPrefix("ParabolicSolverTutorial","results"); /* When an output directory has been specified, the solver writes output in HDF5 format. To * convert this to another output format, we call the relevant method. Here, we convert * the output to plain text files (VTK or cmgui formats are also possible). We also say how * often to write the data, telling the solver to output results to file every tenth timestep. * The solver will create one file for each variable (in this case there is only one variable) * and for each time, so for example, the file * `results_Variable_0_10` is the results for u, over all nodes, at the 11th printed time. * Have a look in the output directory after running the test. (For comments on visualising the data in * matlab or octave, see the end of the tutorial UserTutorials/WritingPdeSolvers.) */ solver.SetOutputToTxt(true); solver.SetPrintingTimestepMultiple(10); /* Now we can solve the problem. The {{{Vec}}} that is returned can be passed into a * {{{ReplicatableVector}}} as before. */ Vec solution = solver.Solve(); ReplicatableVector solution_repl(solution); /* Let's also solve the equivalent static PDE, i.e. set du/dt=0, so 0=div(gradu) + u. This * is easy, as the PDE class has already been defined. */ SimplePoissonEquation<3,3> static_pde; SimpleLinearEllipticSolver<3,3> static_solver(&mesh, &static_pde, &bcc); Vec static_solution = static_solver.Solve(); ReplicatableVector static_solution_repl(static_solution); /* We can now compare the solution of the parabolic PDE at t=1 with the static solution, * to see if the static equilibrium solution was reached in the former. (Ideally we should * compute some relative error, but we just compute an absolute error for simplicity.) */ for (unsigned i=0; i<static_solution_repl.GetSize(); i++) { TS_ASSERT_DELTA( solution_repl[i], static_solution_repl[i], 1e-3); } /* All PETSc vectors should be destroyed when they are no longer needed. */ PetscTools::Destroy(initial_condition); PetscTools::Destroy(solution); PetscTools::Destroy(static_solution); }