MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
ex16.cpp
Go to the documentation of this file.
1// MFEM Example 16
2//
3// Compile with: make ex16
4//
5// Sample runs: ex16
6// ex16 -m ../data/inline-tri.mesh
7// ex16 -m ../data/disc-nurbs.mesh -tf 2
8// ex16 -s 21 -a 0.0 -k 1.0
9// ex16 -s 22 -a 1.0 -k 0.0
10// ex16 -s 23 -a 0.5 -k 0.5 -o 4
11// ex16 -s 4 -dt 1.0e-4 -tf 4.0e-2 -vs 40
12// ex16 -m ../data/fichera-q2.mesh
13// ex16 -m ../data/fichera-mixed.mesh
14// ex16 -m ../data/escher.mesh
15// ex16 -m ../data/beam-tet.mesh -tf 10 -dt 0.1
16// ex16 -m ../data/amr-quad.mesh -o 4 -r 0
17// ex16 -m ../data/amr-hex.mesh -o 2 -r 0
18// ex16 -m ../data/amr-hex.mesh -o 2 -r 0 -s 21 -imp-state
19//
20// Description: This example solves a time dependent nonlinear heat equation
21// problem of the form du/dt = C(u), with a non-linear diffusion
22// operator C(u) = \nabla \cdot (\kappa + \alpha u) \nabla u.
23//
24// The example demonstrates the use of nonlinear operators (the
25// class ConductionOperator defining C(u)), as well as their
26// implicit time integration. Note that implementing the method
27// ConductionOperator::ImplicitSolve is the only requirement for
28// high-order implicit (SDIRK) time integration. In this example,
29// the diffusion operator is linearized by evaluating with the
30// lagged solution from the previous timestep, so there is only
31// a linear solve.
32//
33// We recommend viewing examples 2, 9 and 10 before viewing this
34// example.
35
36#include "mfem.hpp"
37#include <fstream>
38#include <iostream>
39
40using namespace std;
41using namespace mfem;
42
43/** After spatial discretization, the conduction model can be written as:
44 *
45 * du/dt = M^{-1}(-Ku)
46 *
47 * where u is the vector representing the temperature, M is the mass matrix,
48 * and K is the diffusion operator with diffusivity depending on u:
49 * (\kappa + \alpha u).
50 *
51 * Class ConductionOperator represents the right-hand side of the above ODE.
52 */
53class ConductionOperator : public TimeDependentOperator
54{
55protected:
56 FiniteElementSpace &fespace;
57 Array<int> ess_tdof_list; // this list remains empty for pure Neumann b.c.
58
59 BilinearForm *M;
60 BilinearForm *K;
61
62 SparseMatrix Mmat, Kmat;
63 SparseMatrix *T; // T = M + dt K
64 real_t current_dt;
65
66 CGSolver M_solver; // Krylov solver for inverting the mass matrix M
67 DSmoother M_prec; // Preconditioner for the mass matrix M
68
69 CGSolver T_solver; // Implicit solver for T = M + dt K
70 DSmoother T_prec; // Preconditioner for the implicit solver
71
72 real_t alpha, kappa;
73
74 mutable Vector z; // auxiliary vector
75
76public:
77 ConductionOperator(FiniteElementSpace &f, real_t alpha, real_t kappa,
78 const Vector &u);
79
80 void Mult(const Vector &u, Vector &du_dt) const override;
81 /** Solve the Backward-Euler equation: k = f(u + dt*k, t), for the unknown k.
82 This is the only requirement for high-order SDIRK implicit integration.*/
83 void ImplicitSolve(const real_t dt, const Vector &u, Vector &k) override;
84
85 /// Update the diffusion BilinearForm K using the given true-dof vector `u`.
86 void SetParameters(const Vector &u);
87
88 ~ConductionOperator() override;
89};
90
92
93int main(int argc, char *argv[])
94{
95 // 1. Parse command-line options.
96 const char *mesh_file = "../data/star.mesh";
97 int ref_levels = 2;
98 int order = 2;
99
100 int ode_solver_type = 23; // SDIRK33Solver
101 real_t t_final = 0.5;
102 real_t dt = 1.0e-2;
103 real_t alpha = 1.0e-2;
104 real_t kappa = 0.5;
105
106 bool visualization = true;
107 bool visit = false;
108 int vis_steps = 5;
109 bool solve_implicit_state = false;
110
111 int precision = 8;
112 cout.precision(precision);
113
114 OptionsParser args(argc, argv);
115 args.AddOption(&mesh_file, "-m", "--mesh",
116 "Mesh file to use.");
117 args.AddOption(&ref_levels, "-r", "--refine",
118 "Number of times to refine the mesh uniformly.");
119 args.AddOption(&order, "-o", "--order",
120 "Order (degree) of the finite elements.");
121 args.AddOption(&ode_solver_type, "-s", "--ode-solver",
122 ODESolver::Types.c_str());
123 args.AddOption(&t_final, "-tf", "--t-final",
124 "Final time; start time is 0.");
125 args.AddOption(&dt, "-dt", "--time-step",
126 "Time step.");
127 args.AddOption(&alpha, "-a", "--alpha",
128 "Alpha coefficient.");
129 args.AddOption(&kappa, "-k", "--kappa",
130 "Kappa coefficient offset.");
131 args.AddOption(&solve_implicit_state, "-imp-state", "--implicit-state",
132 "-imp-slope", "--implicit-slope",
133 "Implicitly solve for stage state or slope.");
134 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
135 "--no-visualization",
136 "Enable or disable GLVis visualization.");
137 args.AddOption(&visit, "-visit", "--visit-datafiles", "-no-visit",
138 "--no-visit-datafiles",
139 "Save data files for VisIt (visit.llnl.gov) visualization.");
140 args.AddOption(&vis_steps, "-vs", "--visualization-steps",
141 "Visualize every n-th timestep.");
142 args.Parse();
143 if (!args.Good())
144 {
145 args.PrintUsage(cout);
146 return 1;
147 }
148 args.PrintOptions(cout);
149
150 // 2. Read the mesh from the given mesh file. We can handle triangular,
151 // quadrilateral, tetrahedral and hexahedral meshes with the same code.
152 Mesh *mesh = new Mesh(mesh_file, 1, 1);
153 int dim = mesh->Dimension();
154
155 // 3. Define the ODE solver used for time integration. Several implicit
156 // singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
157 // explicit Runge-Kutta methods are available.
158 unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
159
160 // 4. Refine the mesh to increase the resolution. In this example we do
161 // 'ref_levels' of uniform refinement, where 'ref_levels' is a
162 // command-line parameter.
163 for (int lev = 0; lev < ref_levels; lev++)
164 {
165 mesh->UniformRefinement();
166 }
167
168 // 5. Define the vector finite element space representing the current and the
169 // initial temperature, u_ref.
170 H1_FECollection fe_coll(order, dim);
171 FiniteElementSpace fespace(mesh, &fe_coll);
172
173 int fe_size = fespace.GetTrueVSize();
174 cout << "Number of temperature unknowns: " << fe_size << endl;
175
176 GridFunction u_gf(&fespace);
177
178 // 6. Set the initial conditions for u. All boundaries are considered
179 // natural.
181 u_gf.ProjectCoefficient(u_0);
182 Vector u;
183 u_gf.GetTrueDofs(u);
184
185 // 7. Initialize the conduction operator and the visualization.
186 ConductionOperator oper(fespace, alpha, kappa, u);
187
188 u_gf.SetFromTrueDofs(u);
189 {
190 ofstream omesh("ex16.mesh");
191 omesh.precision(precision);
192 mesh->Print(omesh);
193 ofstream osol("ex16-init.gf");
194 osol.precision(precision);
195 u_gf.Save(osol);
196 }
197
198 VisItDataCollection visit_dc("Example16", mesh);
199 visit_dc.RegisterField("temperature", &u_gf);
200 if (visit)
201 {
202 visit_dc.SetCycle(0);
203 visit_dc.SetTime(0.0);
204 visit_dc.Save();
205 }
206
207 socketstream sout;
208 if (visualization)
209 {
210 char vishost[] = "localhost";
211 int visport = 19916;
212 sout.open(vishost, visport);
213 if (!sout)
214 {
215 cout << "Unable to connect to GLVis server at "
216 << vishost << ':' << visport << endl;
217 visualization = false;
218 cout << "GLVis visualization disabled.\n";
219 }
220 else
221 {
222 sout.precision(precision);
223 sout << "solution\n" << *mesh << u_gf;
224 sout << "pause\n";
225 sout << flush;
226 cout << "GLVis visualization paused."
227 << " Press space (in the GLVis window) to resume it.\n";
228 }
229 }
230
231 using ImplicitVariableType = ConductionOperator::ImplicitVariableType;
232 ImplicitVariableType imp_var = solve_implicit_state ?
233 ImplicitVariableType::STATE
234 : ImplicitVariableType::SLOPE;
235
236 // 8. Perform time-integration (looping over the time iterations, ti, with a
237 // time-step dt).
238 ode_solver->Init(oper);
239 ode_solver->SetImplicitVariableType(imp_var);
240 real_t t = 0.0;
241
242 bool last_step = false;
243 for (int ti = 1; !last_step; ti++)
244 {
245 if (t + dt >= t_final - dt/2)
246 {
247 last_step = true;
248 }
249
250 ode_solver->Step(u, t, dt);
251
252 if (last_step || (ti % vis_steps) == 0)
253 {
254 cout << "step " << ti << ", t = " << t << endl;
255
256 u_gf.SetFromTrueDofs(u);
257 if (visualization)
258 {
259 sout << "solution\n" << *mesh << u_gf << flush;
260 }
261
262 if (visit)
263 {
264 visit_dc.SetCycle(ti);
265 visit_dc.SetTime(t);
266 visit_dc.Save();
267 }
268 }
269 oper.SetParameters(u);
270 }
271
272 // 9. Save the final solution. This output can be viewed later using GLVis:
273 // "glvis -m ex16.mesh -g ex16-final.gf".
274 {
275 ofstream osol("ex16-final.gf");
276 osol.precision(precision);
277 u_gf.Save(osol);
278 }
279
280 // 10. Free the used memory.
281 delete mesh;
282
283 return 0;
284}
285
286ConductionOperator::ConductionOperator(FiniteElementSpace &f, real_t al,
287 real_t kap, const Vector &u)
288 : TimeDependentOperator(f.GetTrueVSize(), (real_t) 0.0), fespace(f),
289 M(NULL), K(NULL), T(NULL), current_dt(0.0), z(height)
290{
291 const real_t rel_tol = 1e-8;
292
293 M = new BilinearForm(&fespace);
294 M->AddDomainIntegrator(new MassIntegrator());
295 M->Assemble();
296 M->FormSystemMatrix(ess_tdof_list, Mmat);
297
298 M_solver.iterative_mode = false;
299 M_solver.SetRelTol(rel_tol);
300 M_solver.SetAbsTol(0.0);
301 M_solver.SetMaxIter(30);
302 M_solver.SetPrintLevel(0);
303 M_solver.SetPreconditioner(M_prec);
304 M_solver.SetOperator(Mmat);
305
306 alpha = al;
307 kappa = kap;
308
309 T_solver.iterative_mode = false;
310 T_solver.SetRelTol(rel_tol);
311 T_solver.SetAbsTol(0.0);
312 T_solver.SetMaxIter(100);
313 T_solver.SetPrintLevel(0);
314 T_solver.SetPreconditioner(T_prec);
315
316 SetParameters(u);
317}
318
319void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
320{
321 // Compute:
322 // du_dt = M^{-1}*-Ku
323 // for du_dt, where K is linearized by using u from the previous timestep
324 Kmat.Mult(u, z);
325 z.Neg(); // z = -z
326 M_solver.Mult(z, du_dt);
327}
328
329void ConductionOperator::ImplicitSolve(const real_t dt,
330 const Vector &u, Vector &k)
331{
332 // Solve the equation:
333 // M*k = -K(u + dt*k) for k = du/dt, if solving for stage-slope
334 // or
335 // M*k = -dt*K(k) + M*u for k = u_s, if solving for stage-state
336 // where K is linearized by using u from the previous timestep, and
337 // the stage-state and slope relation: du/dt = (u_s - u)/dt.
338 if (!T)
339 {
340 T = Add(1.0, Mmat, dt, Kmat);
341 current_dt = dt;
342 T_solver.SetOperator(*T);
343 }
344 MFEM_VERIFY(dt == current_dt, ""); // SDIRK methods use the same dt
345
346 // Construct current right-hand side for stage state vs. slope solve
348 {
349 // k, on return, is the stage value u_s
350 Mmat.Mult(u, z);
351 }
352 else
353 {
354 // k, on return, is the stage slope du/dt
355 Kmat.Mult(u, z);
356 z.Neg();
357 }
358 T_solver.Mult(z, k);
359}
360
361void ConductionOperator::SetParameters(const Vector &u)
362{
363 GridFunction u_alpha_gf(&fespace);
364 u_alpha_gf.SetFromTrueDofs(u);
365 for (int i = 0; i < u_alpha_gf.Size(); i++)
366 {
367 u_alpha_gf(i) = kappa + alpha*u_alpha_gf(i);
368 }
369
370 delete K;
371 K = new BilinearForm(&fespace);
372
373 GridFunctionCoefficient u_coeff(&u_alpha_gf);
374
376 K->Assemble();
377 K->FormSystemMatrix(ess_tdof_list, Kmat);
378 delete T;
379 T = NULL; // re-compute T on the next ImplicitSolve
380}
381
382ConductionOperator::~ConductionOperator()
383{
384 delete T;
385 delete M;
386 delete K;
387}
388
390{
391 if (x.Norml2() < 0.5)
392 {
393 return 2.0;
394 }
395 else
396 {
397 return 1.0;
398 }
399}
A "square matrix" operator for the associated FE space and BLFIntegrators The sum of all the BLFInteg...
void AddDomainIntegrator(BilinearFormIntegrator *bfi)
Adds new Domain Integrator. Assumes ownership of bfi.
void Assemble(int skip_zeros=1)
Assembles the form i.e. sums over all domain/bdr integrators.
virtual void FormSystemMatrix(const Array< int > &ess_tdof_list, OperatorHandle &A)
Form the linear system matrix A, see FormLinearSystem() for details.
Conjugate gradient method.
Definition solvers.hpp:627
void Mult(const Vector &b, Vector &x) const override
Iterative solution of the linear system using the Conjugate Gradient method.
Definition solvers.cpp:869
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
Definition solvers.hpp:640
Jacobi-type diagonal smoother of a sparse matrix.
void SetCycle(int c)
Set time cycle (for time-dependent simulations)
void SetTime(real_t t)
Set physical time (for time-dependent simulations)
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:210
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Definition fespace.hpp:827
A general function coefficient.
Coefficient defined by a GridFunction. This coefficient is mesh dependent.
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:53
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
virtual void SetFromTrueDofs(const Vector &tv)
Set the GridFunction from the given true-dof vector.
Definition gridfunc.cpp:363
virtual void ProjectCoefficient(Coefficient &coeff, ProjectType type=ProjectType::DEFAULT)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
void GetTrueDofs(Vector &tv) const
Extract the true-dofs from the GridFunction.
Definition gridfunc.cpp:348
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:291
Mesh data type.
Definition mesh.hpp:67
virtual void Print(std::ostream &os=mfem::out, const std::string &comments="") const
Print the mesh to the given stream using the default MFEM mesh format.
Definition mesh.hpp:2610
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1314
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:12125
static MFEM_EXPORT std::string Types
Definition ode.hpp:235
static MFEM_EXPORT std::unique_ptr< ODESolver > Select(const int ode_solver_type)
Definition ode.cpp:41
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
void PrintUsage(std::ostream &out) const
Print the usage message.
void PrintOptions(std::ostream &out) const
Print the options.
void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, bool required=false)
Add a boolean option and set 'var' to receive the value. Enable/disable tags are used to set the bool...
Definition optparser.hpp:82
bool Good() const
Return true if the command line options were parsed successfully.
Data type sparse matrix.
Definition sparsemat.hpp:51
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
Base abstract class for first order time dependent operators.
Definition operator.hpp:367
virtual bool ImplicitVarTypeIsState() const
Returns true if implicit variable is STATE and false otherwise. Used by ODESolver to identify the sta...
Definition operator.hpp:484
Vector data type.
Definition vector.hpp:82
void Neg()
(*this) = -(*this)
Definition vector.cpp:376
real_t Norml2() const
Returns the l2 norm of the vector.
Definition vector.cpp:968
Data collection with VisIt I/O routines.
void Save() override
Save the collection and a VisIt root file.
void RegisterField(const std::string &field_name, GridFunction *gf) override
Add a grid function to the collection and update the root file.
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
const int * ess_tdof_list
const real_t alpha
Definition ex15.cpp:369
real_t InitialTemperature(const Vector &x)
Definition ex16.cpp:389
real_t kappa
Definition ex24.cpp:54
int dim
Definition ex24.cpp:53
int main()
int GetTrueVSize(const FieldDescriptor &f)
Get the true dof size of a field descriptor.
Definition util.hpp:786
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
float real_t
Definition config.hpp:46
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
void Add(const DenseMatrix &A, const DenseMatrix &B, real_t alpha, DenseMatrix &C)
C = A + alpha*B.
const char vishost[]
STL namespace.