78template <
typename dscalar_t,
int dim = 2>
79class MinimalSurface :
public Operator
82 static constexpr int SOLUTION_U = 1;
83 static constexpr int MESH_NODES = 2;
86 MFEM_HOST_DEVICE
inline
115 MFEM_HOST_DEVICE
inline
121 const auto invJ =
inv(J);
122 const auto dudx = dudxi * invJ;
131 struct ManualDerivativeApply
133 MFEM_HOST_DEVICE
inline
140 const auto invJ =
inv(J);
141 const auto dudx = dudxi * invJ;
142 const auto ddelta_udx = ddelta_udxi * invJ;
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;
155 class MinimalSurfaceJacobian :
public Operator
158 MinimalSurfaceJacobian(
const MinimalSurface *minsurface,
161 minsurface(minsurface),
171 dres_du = minsurface->res->GetDerivative(
172 SOLUTION_U, {&minsurface->u}, {mesh_nodes});
183 const auto d_x = x.
Read();
184 const auto d_dofs = minsurface->ess_tdofs.
Read();
187 d_y[d_dofs[i]] = d_x[d_dofs[i]];
192 const MinimalSurface *minsurface =
nullptr;
195 std::shared_ptr<DerivativeOperator> dres_du;
203 class MinimalSurfaceHandcodedJacobian :
public Operator
207 static constexpr int DIRECTION_U = 3;
210 MinimalSurfaceHandcodedJacobian(
const MinimalSurface *minsurface,
213 minsurface(minsurface),
221 auto &mesh_nodes_fes = *mesh_nodes.
ParFESpace();
223 std::vector<FieldDescriptor> solutions =
225 {DIRECTION_U, &minsurface->H1}
227 std::vector<FieldDescriptor> parameters =
229 {SOLUTION_U, &minsurface->H1},
230 {MESH_NODES, &mesh_nodes_fes}
233 dres_du = std::make_shared<DifferentiableOperator>(
234 solutions, parameters, *minsurface->H1.
GetParMesh());
236 auto input_operators =
tuple
244 auto output_operators =
tuple
249 ManualDerivativeApply manual_derivative_apply;
250 dres_du->AddDomainIntegrator(manual_derivative_apply, input_operators,
251 output_operators, minsurface->ir,
255 dres_du->SetParameters({&minsurface->u, &mesh_nodes});
267 for (
int i = 0; i < minsurface->ess_tdofs.
Size(); i++)
269 d_y[minsurface->ess_tdofs[i]] = d_x[minsurface->ess_tdofs[i]];
273 const MinimalSurface *minsurface =
nullptr;
274 std::shared_ptr<DifferentiableOperator> dres_du;
287 derivative_type(deriv_type)
294 auto &mesh_nodes_fes = *mesh_nodes.
ParFESpace();
302 std::vector<FieldDescriptor> solutions;
304 std::vector<FieldDescriptor> parameters;
308 res = std::make_shared<DifferentiableOperator>(
323 auto input_operators =
tuple
342 auto output_operators =
tuple
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);
365 res->SetParameters({&mesh_nodes});
380 switch (derivative_type)
383 fd_jac = std::make_shared<FDJacobian>(*
this, x);
388 man_dres_du = std::make_shared<MinimalSurfaceHandcodedJacobian>(
395 dres_du = std::make_shared<MinimalSurfaceJacobian>(
this, x);
400 std::shared_ptr<MinimalSurfaceJacobian> GetJacobian()
405 const Array<int>& GetEssentialTrueDofs()
const
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;
425template <
typename dscalar_t,
int dim = 2>
426class AMGPC :
public Solver
434 void SetOperator(
const Operator &)
override
436 auto minsurface =
static_cast<MinimalSurface<dscalar_t, dim>&
>(op);
441 minsurface.GetJacobian()->dres_du->Assemble(A);
442 auto Ae = A->EliminateRowsCols(minsurface.GetEssentialTrueDofs());
469 const real_t x = coords(0);
470 const real_t y = coords(1);
471 if (coords.
Size() == 3)
473 MFEM_ABORT(
"internal error");
479int main(
int argc,
char *argv[])
487 const char *device_config =
"cpu";
488 bool visualization =
true;
491 bool enable_pcamg =
false;
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.");
511 Device device(device_config);
518 auto transform_mesh = [](
const Vector &cold,
Vector &cnew)
528 for (
int i = 0; i < refinements; i++)
536 ParMesh pmesh(MPI_COMM_WORLD, mesh);
551 std::unique_ptr<Operator> minsurface;
552#ifdef MFEM_USE_ENZYME
554 minsurface = std::make_unique<MinimalSurface<real_t>>(H1, *ir,
561 minsurface = std::make_unique<MinimalSurface<dual_t>>(H1, *ir,
571 u.ProjectCoefficient(boundary_coeff);
573 u.ProjectBdrCoefficient(boundary_coeff, ess_bdr);
582 std::shared_ptr<AMGPC<real_t>> amgpc;
587 amgpc.reset(
new AMGPC<real_t>(*minsurface));
592 MFEM_ABORT(
"AMG only available for the AUTODIFF derivative type");
617 sol_sock <<
"parallel "
619 sol_sock.precision(8);
620 sol_sock <<
"solution\n" << pmesh <<
u << std::flush;
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
int Size() const
Return the logical size of the array.
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
Conjugate gradient method.
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 ...
void Print(std::ostream &os=mfem::out)
Print the configuration of the MFEM virtual device object.
Mesh * GetMesh() const
Returns the mesh.
A general function coefficient.
Arbitrary order H1-conforming (continuous) finite elements.
The BoomerAMG solver in hypre.
void SetPrintLevel(int print_level)
virtual void Mult(const HypreParVector &b, HypreParVector &x) const
Solve the linear system Ax=b.
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
Wrapper for hypre's ParCSR matrix class.
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
Class for an integration rule - an Array of IntegrationPoint.
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
void SetRelTol(real_t rtol)
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
void SetMaxIter(int max_it)
void SetAbsTol(real_t atol)
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Geometry::Type GetTypicalElementGeometry() const
If the local mesh is not empty, return GetElementGeometry(0); otherwise, return a typical Geometry pr...
void Clear()
Clear the contents of the Mesh.
int Dimension() const
Dimension of the reference space used within the elements.
void Transform(std::function< void(const Vector &, Vector &)> f)
void GetNodes(Vector &node_coord) const
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...
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.
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Array< int > attributes
A list of all unique element attributes used by the Mesh.
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.
void Mult(const Vector &b, Vector &x) const override
Solve the nonlinear system with right-hand side b.
void SetOperator(const Operator &op) override
Also calls SetOperator for the preconditioner if there is one.
virtual void SetSolver(Solver &solver)
Set the linear solver for inverting the Jacobian.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
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...
Abstract parallel finite element space.
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.
const Operator * GetProlongationMatrix() const override
const SparseMatrix * GetRestrictionMatrix() const override
Get the R matrix which restricts a local dof vector to true dof vector.
ParMesh * GetParMesh() const
Class for parallel grid function.
void SetFromTrueDofs(const Vector &tv) override
Set the GridFunction from the given true-dof vector.
ParFiniteElementSpace * ParFESpace() const
Class for parallel meshes.
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)
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
virtual const real_t * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
virtual real_t * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
int Size() const
Returns the size of the vector.
virtual real_t * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
real_t boundary_func(const Vector &coords)
MFEM_HOST_DEVICE T sqnorm(const tensor< T, m > &A)
Returns the squared Frobenius norm of the tensor.
MFEM_HOST_DEVICE dual< value_type, gradient_type > cos(dual< value_type, gradient_type > a)
implementation of cosine for dual numbers
MFEM_HOST_DEVICE T det(const tensor< T, 1, 1 > &A)
Returns the determinant of a matrix.
MFEM_HOST_DEVICE dual< value_type, gradient_type > log(dual< value_type, gradient_type > a)
implementation of the natural logarithm function for dual numbers
MFEM_HOST_DEVICE tensor< T, 1, 1 > inv(const tensor< T, 1, 1 > &A)
Inverts a matrix.
MFEM_HOST_DEVICE tensor< T, n, m > transpose(const tensor< T, m, n > &A)
Returns the transpose of the matrix.
MFEM_HOST_DEVICE dual< value_type, gradient_type > sqrt(dual< value_type, gradient_type > x)
implementation of square root for dual numbers
MFEM_HOST_DEVICE zero dot(const T &, zero)
the dot product of anything with zero is zero
int GetTrueVSize(const FieldDescriptor &f)
Get the true dof size of a field descriptor.
real_t u(const Vector &xvec)
void forall(int N, lambda &&body)
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Dual number struct (value plus gradient)
This is a class that mimics most of std::tuple's interface, except that it is usable in CUDA kernels ...
A sentinel struct for eliding no-op tensor operations.