MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
dfem-minimal-surface.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11//
12// -------------------------------------
13// Minimal Surface 2D Problem with dFEM
14// -------------------------------------
15//
16// Compile with: make dfem-minimal-surface
17//
18// Sample runs: mpirun -np 4 dfem-minimal-surface -der 0
19// mpirun -np 4 dfem-minimal-surface -der 0 -o 2
20// mpirun -np 4 dfem-minimal-surface -der 0 -r 1
21// mpirun -np 4 dfem-minimal-surface -der 0 -o 2 -r 4 -pcamg
22// mpirun -np 4 dfem-minimal-surface -der 1
23// mpirun -np 4 dfem-minimal-surface -der 2
24//
25// Device sample runs:
26// mpirun -np 4 dfem-minimal-surface -der 0 -r 1 -o 2 -d cuda
27// mpirun -np 4 dfem-minimal-surface -der 1 -r 1 -o 2 -d cuda
28// * mpirun -np 4 dfem-minimal-surface -der 0 -r 1 -o 2 -d hip
29// * mpirun -np 4 dfem-minimal-surface -der 1 -r 1 -o 2 -d hip
30//
31// Description: This example code demonstrates the use of MFEM to solve the
32// minimal surface problem in 2D:
33//
34// $ \min \left( -\nabla \cdot (1 / \sqrt(1 + |\nabla u|^2) \nabla u) \right) $
35//
36// with Dirichlet boundary conditions. The nonlinear problem is
37// solved using Newton's method, where the necessary derivatives
38// are computed in one of three ways (controlled by -der command
39// line parameter):
40//
41// -der 0 = Automatic differentiation using Enzyme or dual type
42// (default)
43// -der 1 = Hand-coded derivatives
44// -der 2 = Finite differences
45//
46// The example demonstrates the use of MFEM's nonlinear solvers,
47// automatic differentiation capabilities, and GLVis/ParaView
48// visualization.
49
50#include "mfem.hpp"
51
52using namespace mfem;
53
54// This example code demonstrates the use of new features in MFEM that are in
55// development but exposed through the mfem::future namespace. All features
56// under this namespace might change their interface or behavior in upcoming
57// releases until they have stabilized.
58using namespace mfem::future;
60
61// Derivative type enum
62// This enum is used to specify the type of derivative computation.
63// Possibilities are:
64// - AUTODIFF, which uses automatic differentiation (Enzyme or dual type),
65// - HANDCODED, which uses a manually implemented derivative, and
66// - FD, finite difference.
73
74// Minimal surface operator.
75//
76// This class implements the minimal surface equation, which is a nonlinear
77// operator that provides the residual.
78template <typename dscalar_t, int dim = 2>
79class MinimalSurface : public Operator
80{
81private:
82 static constexpr int SOLUTION_U = 1;
83 static constexpr int MESH_NODES = 2;
84
85 template <typename T>
86 MFEM_HOST_DEVICE inline
87 static auto coeff(const tensor<T, dim> &a)
88 {
89 return 1_r / sqrt(1_r + sqnorm(a));
90 }
91
92 // The 'nvcc' compiler needs MFApply and ManualDerivativeApply to be public.
93public:
94 // Matrix-Free version of the pointwise residual form for the minimal
95 // surface equation.
96 struct MFApply
97 {
98 // Using DifferentiableOperator, we can define the residual form as a
99 // matrix-free operation. This allows us to compute the residual without
100 // explicitly forming any matrices or other large, temporary data
101 // structures.
102 //
103 // The inputs are the gradient of the solution in *reference coordinates*,
104 // the Jacobian of the coordinates, and the integration rule weights.
105 //
106 // The output is the residual in *physical coordinates* which also
107 // includes the necessary transformation from reference to physical
108 // coordinates for the gradient of the test function.
109 //
110 // Due to the description of how this pointwise operation is used in
111 // DifferentiableOperator, we know it is applied to the gradient of the
112 // test function in reference coordinates e.g.
113 // $ \int coeff(\nabla_x u) (\nabla_x u) J^{-T} \det(J) w
114 // (\nabla_{\xi} v) d\xi $
115 MFEM_HOST_DEVICE inline
116 auto operator()(
117 const tensor<dscalar_t, dim> &dudxi,
119 const real_t &w) const
120 {
121 const auto invJ = inv(J);
122 const auto dudx = dudxi * invJ;
123 return tuple{coeff(dudx) * dudx * transpose(invJ) * det(J) * w};
124 }
125 };
126
127 // This is the derivative of the residual form with respect to the
128 // solution $u$.
129 //
130 // The inputs and outputs follow the same rules as the MFApply operator.
131 struct ManualDerivativeApply
132 {
133 MFEM_HOST_DEVICE inline
134 auto operator()(
135 const tensor<real_t, dim> &ddelta_udxi,
136 const tensor<real_t, dim> &dudxi,
138 const real_t &w) const
139 {
140 const auto invJ = inv(J);
141 const auto dudx = dudxi * invJ;
142 const auto ddelta_udx = ddelta_udxi * invJ;
143
144 const auto c = coeff(dudx);
145 const auto term1 = c * ddelta_udx;
146 const auto term2 = c * c * c * dot(dudx, ddelta_udx) * dudx;
147
148 return tuple{(term1 - term2) * transpose(invJ) * det(J) * w};
149 }
150 };
151
152 // This class implements the Jacobian of the minimal surface operator. It
153 // mostly acts as a wrapper to retrieve the Jacobian and apply essential
154 // boundary conditions appropriately.
155 class MinimalSurfaceJacobian : public Operator
156 {
157 public:
158 MinimalSurfaceJacobian(const MinimalSurface *minsurface,
159 const Vector &x) :
160 Operator(minsurface->Height()),
161 minsurface(minsurface),
162 z(minsurface->Height())
163 {
164 minsurface->u.SetFromTrueDofs(x);
165 auto mesh_nodes = static_cast<ParGridFunction*>
166 (minsurface->H1.GetParMesh()->GetNodes());
167
168 // One can retrieve the derivative of a DifferentiableOperator wrt a
169 // field variable if the derivative has been requested during the
170 // DifferentiableOperator::AddDomainIntegrator call.
171 dres_du = minsurface->res->GetDerivative(
172 SOLUTION_U, {&minsurface->u}, {mesh_nodes});
173 }
174
175 void Mult(const Vector &x, Vector &y) const override
176 {
177 z = x;
178 z.SetSubVector(minsurface->ess_tdofs, 0.0);
179
180 dres_du->Mult(z, y);
181
182 auto d_y = y.ReadWrite();
183 const auto d_x = x.Read();
184 const auto d_dofs = minsurface->ess_tdofs.Read();
185 mfem::forall(minsurface->ess_tdofs.Size(), [=] MFEM_HOST_DEVICE (int i)
186 {
187 d_y[d_dofs[i]] = d_x[d_dofs[i]];
188 });
189 }
190
191 // Pointer to the wrapped MinimalSurface operator
192 const MinimalSurface *minsurface = nullptr;
193
194 // Pointer to the DifferentiableOperator that computes the Jacobian
195 std::shared_ptr<DerivativeOperator> dres_du;
196
197 // Temporary vector
198 mutable Vector z;
199 };
200
201 // This class implements the Jacobian of the minimal surface operator using
202 // manually computed derivatives.
203 class MinimalSurfaceHandcodedJacobian : public Operator
204 {
205 // For the Jacobian action we need another field ID for the direction
206 // of u, called du, in dR/du = J * du.
207 static constexpr int DIRECTION_U = 3;
208
209 public:
210 MinimalSurfaceHandcodedJacobian(const MinimalSurface *minsurface,
211 const Vector &x) :
212 Operator(minsurface->Height()),
213 minsurface(minsurface),
214 z(minsurface->Height())
215 {
216 Array<int> all_domain_attr(minsurface->H1.GetMesh()->attributes.Max());
217 all_domain_attr = 1;
218
219 auto &mesh_nodes = *static_cast<ParGridFunction *>
220 (minsurface->H1.GetParMesh()->GetNodes());
221 auto &mesh_nodes_fes = *mesh_nodes.ParFESpace();
222
223 std::vector<FieldDescriptor> solutions =
224 {
225 {DIRECTION_U, &minsurface->H1}
226 };
227 std::vector<FieldDescriptor> parameters =
228 {
229 {SOLUTION_U, &minsurface->H1},
230 {MESH_NODES, &mesh_nodes_fes}
231 };
232
233 dres_du = std::make_shared<DifferentiableOperator>(
234 solutions, parameters, *minsurface->H1.GetParMesh());
235
236 auto input_operators = tuple
237 {
241 Weight{}
242 };
243
244 auto output_operators = tuple
245 {
247 };
248
249 ManualDerivativeApply manual_derivative_apply;
250 dres_du->AddDomainIntegrator(manual_derivative_apply, input_operators,
251 output_operators, minsurface->ir,
252 all_domain_attr);
253
254 minsurface->u.SetFromTrueDofs(x);
255 dres_du->SetParameters({&minsurface->u, &mesh_nodes});
256 }
257
258 void Mult(const Vector &x, Vector &y) const override
259 {
260 z = x;
261 z.SetSubVector(minsurface->ess_tdofs, 0.0);
262
263 dres_du->Mult(z, y);
264
265 auto d_y = y.HostReadWrite();
266 const auto d_x = x.HostRead();
267 for (int i = 0; i < minsurface->ess_tdofs.Size(); i++)
268 {
269 d_y[minsurface->ess_tdofs[i]] = d_x[minsurface->ess_tdofs[i]];
270 }
271 }
272
273 const MinimalSurface *minsurface = nullptr;
274 std::shared_ptr<DifferentiableOperator> dres_du;
275 mutable Vector z;
276 };
277
278
279public:
280 MinimalSurface(ParFiniteElementSpace &H1,
281 const IntegrationRule &ir,
282 int deriv_type = AUTODIFF) :
284 H1(H1),
285 ir(ir),
286 u(&H1),
287 derivative_type(deriv_type)
288 {
289 Array<int> all_domain_attr(H1.GetMesh()->attributes.Max());
290 all_domain_attr = 1;
291
292 auto &mesh_nodes =
293 *static_cast<ParGridFunction *>(H1.GetParMesh()->GetNodes());
294 auto &mesh_nodes_fes = *mesh_nodes.ParFESpace();
295
296 // The following section is the heart of this example. It shows how to
297 // create and interact with the DifferentialOperator class.
298
299 // The constructor of DifferentiableOperator takes two vectors of
300 // FieldDescriptors. A FieldDescriptor can be viewed as a a pair of an
301 // identifier (the field ID) and it's accompanying space.
302 std::vector<FieldDescriptor> solutions;
303 solutions.push_back(FieldDescriptor(SOLUTION_U, &H1));
304 std::vector<FieldDescriptor> parameters;
305 parameters.push_back(FieldDescriptor(MESH_NODES, &mesh_nodes_fes));
306
307 // Create the DifferentiableOperator on the desired mesh.
308 res = std::make_shared<DifferentiableOperator>(
309 solutions, parameters, *H1.GetParMesh());
310
311 // DifferentiableOperator::AddIntegrator consists mainly of multiple
312 // components. The input and output operators and the pointwise
313 // "quadrature function" form a description of how the inputs and outputs
314 // to the pointwise function have to be treated.
315
316 // The input operators tuple consists of derived FieldOperator types.
317 // Here, we use Gradient<FIELD_ID> to signal that we request the gradient
318 // on the reference coordinates of the FIELD_ID field to be interpolated
319 // and translated to the pointwise function as the first and second input.
320 // Other choices are possible, e.g. Value<FIELD_ID> to interpolate the
321 // pointwise funciton. `Weight` is a special field that translates the
322 // integration rule weights to the input of the pointwise function.
323 auto input_operators = tuple
324 {
327 Weight{}
328 };
329
330 // The output operators tuple also consists of derived FieldOperator
331 // types. Currently, only _one_ output operator is allowed. One should
332 // think of this as an operator on the output of a pointwise function. For
333 // example with the above input operators and the output operator below we
334 // create the following operator sequence:
335 //
336 // $ B^T D(B u, B x, w) $
337 //
338 // where B is the gradient interpolation operator, D is the pointwise
339 // function and u and x are solution and coordinate functions,
340 // respectively. The output operator is the gradient of the basis of the
341 // solution, which completes the "diffusion" like weak form.
342 auto output_operators = tuple
343 {
345 };
346
347 // The pointwise function is defined as a lambda function. Here we just
348 // instantiate an object for it which is passed to
349 // DifferentiableOperator::AddDomainIntegrator.
350 MFApply mf_apply_qf;
351
352 // The integeger sequence is used to specify which derivatives of the
353 // formed integrator should be formed. This is necessary to specify at
354 // compile time in order to instantiate the correct functions.
355 auto derivatives = std::integer_sequence<size_t, SOLUTION_U> {};
356 res->AddDomainIntegrator(mf_apply_qf, input_operators, output_operators,
357 ir, all_domain_attr, derivatives);
358
359 // Before we are able to use DifferentiableOperator::Mult, we need to call
360 // DifferentiableOperator::SetParameters to set the parameters of the
361 // operator. Here, only the mesh node function is required. We do this
362 // here once, because we know that the nodes won't change. If they do,
363 // we'd have to call SetParameters before each call to Mult. This is done
364 // to be mathematically consistent with fixing paramaters.
365 res->SetParameters({&mesh_nodes});
366
367 Array<int> ess_bdr(H1.GetParMesh()->bdr_attributes.Max());
368 ess_bdr = 1;
369 H1.GetEssentialTrueDofs(ess_bdr, ess_tdofs);
370 }
371
372 void Mult(const Vector &x, Vector &y) const override
373 {
374 res->Mult(x, y);
375 y.SetSubVector(ess_tdofs, 0.0);
376 }
377
378 Operator& GetGradient(const Vector &x) const override
379 {
380 switch (derivative_type)
381 {
382 case FD:
383 fd_jac = std::make_shared<FDJacobian>(*this, x);
384 return *fd_jac;
385
386 case HANDCODED:
387 {
388 man_dres_du = std::make_shared<MinimalSurfaceHandcodedJacobian>(
389 this, x);
390 return *man_dres_du;
391 }
392
393 case AUTODIFF:
394 default:
395 dres_du = std::make_shared<MinimalSurfaceJacobian>(this, x);
396 return *dres_du;
397 }
398 }
399
400 std::shared_ptr<MinimalSurfaceJacobian> GetJacobian()
401 {
402 return dres_du;
403 }
404
405 const Array<int>& GetEssentialTrueDofs() const
406 {
407 return ess_tdofs;
408 }
409
410private:
412 const IntegrationRule &ir;
413
414 mutable ParGridFunction u;
415
416 Array<int> ess_tdofs;
417
418 std::shared_ptr<DifferentiableOperator> res;
419 mutable std::shared_ptr<MinimalSurfaceJacobian> dres_du;
420 mutable std::shared_ptr<MinimalSurfaceHandcodedJacobian> man_dres_du;
421 mutable std::shared_ptr<FDJacobian> fd_jac;
422 int derivative_type;
423};
424
425template <typename dscalar_t, int dim = 2>
426class AMGPC : public Solver
427{
428public:
429 AMGPC(Operator &op) :
430 Solver(op.Height()),
431 op(op)
432 {}
433
434 void SetOperator(const Operator &) override
435 {
436 auto minsurface = static_cast<MinimalSurface<dscalar_t, dim>&>(op);
437 // We leverage dFEM to assemble the Jacobian of the minimal surface
438 // operator into a HypreParMatrix.
439 delete A;
440 A = nullptr;
441 minsurface.GetJacobian()->dres_du->Assemble(A);
442 auto Ae = A->EliminateRowsCols(minsurface.GetEssentialTrueDofs());
443 delete Ae;
444 amg.SetPrintLevel(0);
445 amg.SetOperator(*A);
446 }
447
448 void Mult(const Vector &x, Vector &y) const override
449 {
450 amg.Mult(x, y);
451 }
452
453 ~AMGPC()
454 {
455 delete A;
456 }
457
458private:
459 Operator &op;
460 HypreParMatrix *A = nullptr;
461 HypreBoomerAMG amg;
462};
463
464// Boundary function for the minimal surface problem described by the Scherk
465// surface.
466// See https://en.wikipedia.org/wiki/Scherk_surface for more details.
468{
469 const real_t x = coords(0);
470 const real_t y = coords(1);
471 if (coords.Size() == 3)
472 {
473 MFEM_ABORT("internal error");
474 }
475 const real_t a = 1.0e-2;
476 return log(cos(a * x) / cos(a * y)) / a;
477}
478
479int main(int argc, char *argv[])
480{
481 // 1. Initialize MPI and HYPRE
482 Mpi::Init();
483 Hypre::Init();
484
485 // 2. Parse command-line options
486 int order = 1;
487 const char *device_config = "cpu";
488 bool visualization = true;
489 int refinements = 0;
490 int derivative_type = AUTODIFF;
491 bool enable_pcamg = false;
492
493 OptionsParser args(argc, argv);
494 args.AddOption(&order, "-o", "--order",
495 "Finite element order (polynomial degree).");
496 args.AddOption(&device_config, "-d", "--device",
497 "Device configuration string, see Device::Configure().");
498 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
499 "--no-visualization",
500 "Enable or disable GLVis visualization.");
501 args.AddOption(&refinements, "-r", "--refinements", "");
502 args.AddOption(&derivative_type, "-der", "--derivative-type",
503 "Derivative computation type: 0=AutomaticDifferentiation,"
504 " 1=HandCoded, 2=FiniteDifference");
505 args.AddOption(&enable_pcamg, "-pcamg", "--pcamg", "-no-pcamg", "--no-pcamg",
506 "Enable AMG as a preconditioner when using automatic differentiation.");
507 args.ParseCheck();
508
509 // 3. Enable hardware devices such as GPUs, and programming models such as
510 // CUDA
511 Device device(device_config);
512 if (Mpi::Root()) { device.Print(); }
513
514 // 4. Create a 2D mesh on the square domain [-Ï€/2,Ï€/2]^2
516 mesh.SetCurvature(order);
517
518 auto transform_mesh = [](const Vector &cold, Vector &cnew)
519 {
520 cnew = cold;
521 cnew -= 0.5;
522 cnew *= M_PI;
523 };
524
525 mesh.Transform(transform_mesh);
526
527 // 5. Refine the mesh to increase the resolution
528 for (int i = 0; i < refinements; i++)
529 {
530 mesh.UniformRefinement();
531 }
532
533 int dim = mesh.Dimension();
534
535 // 6. Define a parallel mesh
536 ParMesh pmesh(MPI_COMM_WORLD, mesh);
537 mesh.Clear();
538
539 // 7. Define a parallel finite element space on the parallel mesh
540 H1_FECollection fec(order, dim);
541 ParFiniteElementSpace H1(&pmesh, &fec);
542
543 // 8. Set up the integration rule
544 const auto *ir = &IntRules.Get(pmesh.GetTypicalElementGeometry(),
545 2 * order + 1);
546
547 ParGridFunction u(&H1);
548 Vector X(H1.GetTrueVSize());
549
550 // 9. Create the nonlinear operator for the minimal surface equation
551 std::unique_ptr<Operator> minsurface;
552#ifdef MFEM_USE_ENZYME
553 // When Enzyme is available, use it for automatic differentiation
554 minsurface = std::make_unique<MinimalSurface<real_t>>(H1, *ir,
555 derivative_type);
556#else
557 // When Enzyme is not available, use the dual type for automatic
558 // differentiation
559 using mfem::future::dual;
560 using dual_t = dual<real_t, real_t>;
561 minsurface = std::make_unique<MinimalSurface<dual_t>>(H1, *ir,
562 derivative_type);
563#endif
564
565 // 10. Set up and apply the boundary conditions
566 Array<int> ess_bdr(H1.GetParMesh()->bdr_attributes.Max());
567 ess_bdr = 1;
568
569 // 11. Set up the essential boundary conditions and initial condition
570 FunctionCoefficient boundary_coeff(boundary_func);
571 u.ProjectCoefficient(boundary_coeff);
572 u *= 1e-2;
573 u.ProjectBdrCoefficient(boundary_coeff, ess_bdr);
574
575 // 12. Set up the linear solver to be used within Newton's method
576 CGSolver krylov(MPI_COMM_WORLD);
577 krylov.SetAbsTol(0.0);
578 krylov.SetRelTol(1e-4);
579 krylov.SetMaxIter(500);
580 krylov.SetPrintLevel(2);
581
582 std::shared_ptr<AMGPC<real_t>> amgpc;
583 if (enable_pcamg)
584 {
585 if (derivative_type == AUTODIFF)
586 {
587 amgpc.reset(new AMGPC<real_t>(*minsurface));
588 krylov.SetPreconditioner(*amgpc);
589 }
590 else
591 {
592 MFEM_ABORT("AMG only available for the AUTODIFF derivative type");
593 }
594 }
595
596 // 13. Set up the nonlinear solver (Newton) for the minimal surface equation
597 NewtonSolver newton(MPI_COMM_WORLD);
598 newton.SetOperator(*minsurface);
599 newton.SetAbsTol(0.0);
600 newton.SetRelTol(1e-6);
601 newton.SetMaxIter(10);
602 newton.SetSolver(krylov);
603 newton.SetPrintLevel(1);
604
605 // 14. Solve the nonlinear system using Newton's method
606 H1.GetRestrictionMatrix()->Mult(u, X);
607 Vector zero;
608 newton.Mult(zero, X);
609 H1.GetProlongationMatrix()->Mult(X, u);
610
611 // 15. Send the solution by socket to a GLVis server.
612 if (visualization)
613 {
614 char vishost[] = "localhost";
615 int visport = 19916;
616 socketstream sol_sock(vishost, visport);
617 sol_sock << "parallel "
618 << Mpi::WorldSize() << " " << Mpi::WorldRank() << "\n";
619 sol_sock.precision(8);
620 sol_sock << "solution\n" << pmesh << u << std::flush;
621 }
622
623 // 16. Save the solution in parallel using ParaView format
624 ParaViewDataCollection dc("dfem-minimal-surface-output", &pmesh);
625 dc.SetHighOrderOutput(true);
626 dc.SetLevelsOfDetail(order);
627 dc.RegisterField("solution", &u);
628 dc.SetCycle(0);
629 dc.Save();
630
631 return 0;
632}
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:69
int Size() const
Return the logical size of the array.
Definition array.hpp:166
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
Definition array.hpp:381
Conjugate gradient method.
Definition solvers.hpp:627
virtual void RegisterField(const std::string &field_name, GridFunction *gf)
Add a grid function to the collection.
void SetCycle(int c)
Set time cycle (for time-dependent simulations)
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
Definition device.hpp:124
void Print(std::ostream &os=mfem::out)
Print the configuration of the MFEM virtual device object.
Definition device.cpp:317
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:644
A general function coefficient.
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:279
The BoomerAMG solver in hypre.
Definition hypre.hpp:1737
void SetPrintLevel(int print_level)
Definition hypre.hpp:1817
virtual void Mult(const HypreParVector &b, HypreParVector &x) const
Solve the linear system Ax=b.
Definition hypre.cpp:4121
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
Definition hypre.cpp:5166
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:419
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
Definition hypre.cpp:33
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
void SetRelTol(real_t rtol)
Definition solvers.hpp:238
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Definition solvers.cpp:178
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
Definition solvers.cpp:76
void SetMaxIter(int max_it)
Definition solvers.hpp:240
void SetAbsTol(real_t atol)
Definition solvers.hpp:239
Mesh data type.
Definition mesh.hpp:65
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:304
Geometry::Type GetTypicalElementGeometry() const
If the local mesh is not empty, return GetElementGeometry(0); otherwise, return a typical Geometry pr...
Definition mesh.cpp:1628
void Clear()
Clear the contents of the Mesh.
Definition mesh.hpp:827
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1306
void Transform(std::function< void(const Vector &, Vector &)> f)
Definition mesh.cpp:13540
void GetNodes(Vector &node_coord) const
Definition mesh.cpp:9627
static Mesh MakeCartesian2D(int nx, int ny, Element::Type type, bool generate_edges=false, real_t sx=1.0, real_t sy=1.0, bool sfc_ordering=true)
Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny quadrilaterals if type = QUADRILATER...
Definition mesh.cpp:4617
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
Set the curvature of the mesh nodes using the given polynomial degree.
Definition mesh.cpp:6799
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:11637
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition mesh.hpp:302
static bool Root()
Return true if the rank in MPI_COMM_WORLD is zero.
static int WorldRank()
Return the MPI rank in MPI_COMM_WORLD.
static int WorldSize()
Return the size of MPI_COMM_WORLD.
static void Init(int &argc, char **&argv, int required=default_thread_required, int *provided=nullptr)
Singleton creation with Mpi::Init(argc, argv).
Newton's method for solving F(x)=b for a given operator F.
Definition solvers.hpp:781
void Mult(const Vector &b, Vector &x) const override
Solve the nonlinear system with right-hand side b.
Definition solvers.cpp:2062
void SetOperator(const Operator &op) override
Also calls SetOperator for the preconditioner if there is one.
Definition solvers.cpp:2048
virtual void SetSolver(Solver &solver)
Set the linear solver for inverting the Jacobian.
Definition solvers.hpp:828
Abstract operator.
Definition operator.hpp:25
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:66
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
void ParseCheck(std::ostream &out=mfem::out)
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
Abstract parallel finite element space.
Definition pfespace.hpp:31
void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1) const override
int GetTrueVSize() const override
Return the number of local vector true dofs.
Definition pfespace.hpp:353
const Operator * GetProlongationMatrix() const override
const SparseMatrix * GetRestrictionMatrix() const override
Get the R matrix which restricts a local dof vector to true dof vector.
Definition pfespace.hpp:470
ParMesh * GetParMesh() const
Definition pfespace.hpp:341
Class for parallel grid function.
Definition pgridfunc.hpp:50
void SetFromTrueDofs(const Vector &tv) override
Set the GridFunction from the given true-dof vector.
ParFiniteElementSpace * ParFESpace() const
Class for parallel meshes.
Definition pmesh.hpp:34
void SetLevelsOfDetail(int levels_of_detail_)
Set the refinement level.
void SetHighOrderOutput(bool high_order_output_)
Sets whether or not to output the data as high-order elements (false by default).
Writer for ParaView visualization (PVD and VTU format)
Base class for solvers.
Definition operator.hpp:792
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
Vector data type.
Definition vector.hpp:82
virtual const real_t * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:524
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:520
virtual real_t * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:536
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
Definition vector.cpp:702
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
virtual real_t * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:540
Gradient FieldOperator.
Weight FieldOperator.
real_t boundary_func(const Vector &coords)
int dim
Definition ex24.cpp:53
int main()
real_t a
Definition lissajous.cpp:41
MFEM_HOST_DEVICE T sqnorm(const tensor< T, m > &A)
Returns the squared Frobenius norm of the tensor.
Definition tensor.hpp:1236
MFEM_HOST_DEVICE dual< value_type, gradient_type > cos(dual< value_type, gradient_type > a)
implementation of cosine for dual numbers
Definition dual.hpp:296
MFEM_HOST_DEVICE T det(const tensor< T, 1, 1 > &A)
Returns the determinant of a matrix.
Definition tensor.hpp:1406
MFEM_HOST_DEVICE dual< value_type, gradient_type > log(dual< value_type, gradient_type > a)
implementation of the natural logarithm function for dual numbers
Definition dual.hpp:366
MFEM_HOST_DEVICE tensor< T, 1, 1 > inv(const tensor< T, 1, 1 > &A)
Inverts a matrix.
Definition tensor.hpp:1707
MFEM_HOST_DEVICE tensor< T, n, m > transpose(const tensor< T, m, n > &A)
Returns the transpose of the matrix.
Definition tensor.hpp:1388
MFEM_HOST_DEVICE dual< value_type, gradient_type > sqrt(dual< value_type, gradient_type > x)
implementation of square root for dual numbers
Definition dual.hpp:288
MFEM_HOST_DEVICE zero dot(const T &, zero)
the dot product of anything with zero is zero
Definition tensor.hpp:288
int GetTrueVSize(const FieldDescriptor &f)
Get the true dof size of a field descriptor.
Definition util.hpp:829
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
float real_t
Definition config.hpp:46
void forall(int N, lambda &&body)
Definition forall.hpp:839
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:492
const char vishost[]
FieldDescriptor struct.
Definition util.hpp:551
Dual number struct (value plus gradient)
Definition dual.hpp:36
This is a class that mimics most of std::tuple's interface, except that it is usable in CUDA kernels ...
Definition tuple.hpp:49
A sentinel struct for eliding no-op tensor operations.
Definition tensor.hpp:170