libMesh
Loading...
Searching...
No Matches
optimization_ex1.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19
20// <h1>Optimization Example 1 - Optimization of a quadratic objective function</h1>
21// \author David Knezevic
22// \date 2015
23//
24// In this example we demonstrate how to use OptimizationSystem to
25// solve the optimization problem:
26// min_U 0.5*U^T A U - U^T F
27// We enforce Dirichlet constraints on U so that the minimization is
28// well-posed. But note that we do not use OptimizationSystem's
29// interface for imposing constraints in this case, so we can use an
30// unconstrained solver (e.g. TAO's "Newton's method with line search"
31// for unconstrained optimization is the default choice).
32
33// C++ include files that we need
34#include <iostream>
35
36// libMesh includes
37#include "libmesh/libmesh.h"
38#include "libmesh/mesh.h"
39#include "libmesh/mesh_generation.h"
40#include "libmesh/exodusII_io.h"
41#include "libmesh/equation_systems.h"
42#include "libmesh/fe.h"
43#include "libmesh/quadrature_gauss.h"
44#include "libmesh/dof_map.h"
45#include "libmesh/sparse_matrix.h"
46#include "libmesh/numeric_vector.h"
47#include "libmesh/dense_matrix.h"
48#include "libmesh/dense_vector.h"
49#include "libmesh/elem.h"
50#include "libmesh/fpe_disabler.h"
51#include "libmesh/boundary_info.h"
52#include "libmesh/string_to_enum.h"
53#include "libmesh/getpot.h"
54#include "libmesh/zero_function.h"
55#include "libmesh/dirichlet_boundaries.h"
56#include "libmesh/optimization_system.h"
57#include "libmesh/optimization_solver.h"
58
59// Bring in everything from the libMesh namespace
60using namespace libMesh;
61
62
71{
72private:
73
78
79public:
80
85
91 void assemble_A_and_F();
92
96 virtual Number objective (const NumericVector<Number> & soln,
97 OptimizationSystem & /*sys*/);
98
102 virtual void gradient (const NumericVector<Number> & soln,
103 NumericVector<Number> & grad_f,
104 OptimizationSystem & /*sys*/);
105
109 virtual void hessian (const NumericVector<Number> & soln,
111 OptimizationSystem & /*sys*/);
112
119
125};
126
130
132{
133 A_matrix->zero();
134 F_vector->zero();
135
136 const MeshBase & mesh = _sys.get_mesh();
137
138 const unsigned int dim = mesh.mesh_dimension();
139 const unsigned int u_var = _sys.variable_number ("u");
140
141 const DofMap & dof_map = _sys.get_dof_map();
142 FEType fe_type = dof_map.variable_type(u_var);
143 std::unique_ptr<FEBase> fe (FEBase::build(dim, fe_type));
144 QGauss qrule (dim, fe_type.default_quadrature_order());
145 fe->attach_quadrature_rule (&qrule);
146
147 const std::vector<Real> & JxW = fe->get_JxW();
148 const std::vector<std::vector<Real>> & phi = fe->get_phi();
149 const std::vector<std::vector<RealGradient>> & dphi = fe->get_dphi();
150
151 std::vector<dof_id_type> dof_indices;
152
155
156 for (const auto & elem : mesh.active_local_element_ptr_range())
157 {
158 dof_map.dof_indices (elem, dof_indices);
159
160 const unsigned int n_dofs = dof_indices.size();
161
162 fe->reinit (elem);
163
164 Ke.resize (n_dofs, n_dofs);
165 Fe.resize (n_dofs);
166
167 for (unsigned int qp=0; qp<qrule.n_points(); qp++)
168 {
169 for (unsigned int dof_i=0; dof_i<n_dofs; dof_i++)
170 {
171 for (unsigned int dof_j=0; dof_j<n_dofs; dof_j++)
172 {
173 Ke(dof_i, dof_j) += JxW[qp] * (dphi[dof_j][qp]* dphi[dof_i][qp]);
174 }
175 Fe(dof_i) += JxW[qp] * phi[dof_i][qp];
176 }
177 }
178
179#ifdef LIBMESH_ENABLE_CONSTRAINTS
180 // This will zero off-diagonal entries of Ke corresponding to
181 // Dirichlet dofs.
182 dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices);
183
184 // We want the diagonal of constrained dofs to be zero too
185 for (unsigned int local_dof_index=0; local_dof_index<n_dofs; local_dof_index++)
186 {
187 dof_id_type global_dof_index = dof_indices[local_dof_index];
188 if (dof_map.is_constrained_dof(global_dof_index))
189 {
190 Ke(local_dof_index, local_dof_index) = 0.;
191 }
192 }
193#endif // LIBMESH_ENABLE_CONSTRAINTS
194
195 A_matrix->add_matrix (Ke, dof_indices);
196 F_vector->add_vector (Fe, dof_indices);
197 }
198
199 A_matrix->close();
200 F_vector->close();
201}
202
204 OptimizationSystem & /*sys*/)
205{
206 std::unique_ptr<NumericVector<Number>> AxU = soln.zero_clone();
207
208 A_matrix->vector_mult(*AxU, soln);
209
210 Number
211 UTxAxU = AxU->dot(soln),
212 UTxF = F_vector->dot(soln);
213
214 return 0.5 * UTxAxU - UTxF;
215}
216
218 NumericVector<Number> & grad_f,
219 OptimizationSystem & /*sys*/)
220{
221 grad_f.zero();
222
223 // Since we've enforced constraints on soln, A and F,
224 // this automatically sets grad_f to zero for constrained
225 // dofs.
226 A_matrix->vector_mult(grad_f, soln);
227 grad_f.add(-1, *F_vector);
228}
229
230
233 OptimizationSystem & /*sys*/)
234{
235 LOG_SCOPE("hessian()", "AssembleOptimization");
236 H_f.zero();
237 H_f.add(1., *A_matrix);
238}
239
240
241int main (int argc, char ** argv)
242{
243 LibMeshInit init (argc, argv);
244
245#ifndef LIBMESH_HAVE_PETSC_TAO
246
247 libmesh_example_requires(false, "PETSc >= 3.5.0 with built-in TAO support");
248
249#elif !defined(LIBMESH_ENABLE_GHOSTED)
250
251 libmesh_example_requires(false, "--enable-ghosted");
252
253#elif LIBMESH_USE_COMPLEX_NUMBERS
254
255 // According to
256 // http://www.mcs.anl.gov/research/projects/tao/documentation/installation.html
257 // TAO & PETSc-complex are currently mutually exclusive
258 libmesh_example_requires(false, "PETSc >= 3.5.0 with built-in TAO support & real-numbers only");
259
260#endif
261
262 // We use a 2D domain.
263 libmesh_example_requires(LIBMESH_DIM > 1, "--disable-1D-only");
264
265 // We use Dirichlet boundary conditions here
266#ifndef LIBMESH_ENABLE_DIRICHLET
267 libmesh_example_requires(false, "--enable-dirichlet");
268#endif
269
270 if (libMesh::on_command_line ("--use-eigen"))
271 {
272 libMesh::err << "This example requires an OptimizationSolver, and therefore does not "
273 << "support --use-eigen on the command line."
274 << std::endl;
275 return 0;
276 }
277
278 GetPot infile("optimization_ex1.in");
279 infile.parse_command_line(argc, argv);
280
281 const std::string approx_order = infile("approx_order", "FIRST");
282 const std::string fe_family = infile("fe_family", "LAGRANGE");
283 const unsigned int n_elem = infile("n_elem", 10);
284
285 Mesh mesh(init.comm());
287 n_elem,
288 n_elem,
289 -1., 1.,
290 -1., 1.,
291 QUAD9);
292
294
295 EquationSystems equation_systems (mesh);
296
297 OptimizationSystem & system =
298 equation_systems.add_system<OptimizationSystem> ("Optimization");
299
300 // The default is to use PETSc/Tao solvers, but let the user change
301 // the optimization solver package on the fly.
302 {
303 const std::string optimization_solver_type = infile("optimization_solver_type",
304 "PETSC_SOLVERS");
305 SolverPackage sp = Utility::string_to_enum<SolverPackage>(optimization_solver_type);
306 std::unique_ptr<OptimizationSolver<Number>> new_solver =
308 system.optimization_solver.reset(new_solver.release());
309 }
310
311 // Set tolerances and maximum iteration counts directly on the optimization solver.
312 system.optimization_solver->max_objective_function_evaluations = 128;
313 system.optimization_solver->objective_function_relative_tolerance = 1.e-4;
314 system.optimization_solver->verbose = true;
315
316 AssembleOptimization assemble_opt(system);
317
318 system.optimization_solver->objective_object = &assemble_opt;
319 system.optimization_solver->gradient_object = &assemble_opt;
320 system.optimization_solver->hessian_object = &assemble_opt;
321
322 // system.matrix and system.rhs are used for the gradient and Hessian,
323 // so in this case we add an extra matrix and vector to store A and F.
324 // This makes it easy to write the code for evaluating the objective,
325 // gradient, and hessian.
326 system.add_matrix("A_matrix");
327 system.add_vector("F_vector");
328 assemble_opt.A_matrix = &system.get_matrix("A_matrix");
329 assemble_opt.F_vector = &system.get_vector("F_vector");
330
331#ifdef LIBMESH_ENABLE_DIRICHLET
332 unsigned int u_var = system.add_variable("u",
333 Utility::string_to_enum<Order> (approx_order),
334 Utility::string_to_enum<FEFamily>(fe_family));
335
336 // Apply Dirichlet constraints. This will be used to apply constraints
337 // to the objective function, gradient and Hessian.
339
340 // Most DirichletBoundary users will want to supply a "locally
341 // indexed" functor
342 DirichletBoundary dirichlet_bc({0,1,2,3}, {u_var}, zf,
344 system.get_dof_map().add_dirichlet_boundary(dirichlet_bc);
345#endif // LIBMESH_ENABLE_DIRICHLET
346
347 equation_systems.init();
348 equation_systems.print_info();
349
350 assemble_opt.assemble_A_and_F();
351
352 // We need to close the matrix so that we can use it to store the
353 // Hessian during the solve.
354 system.get_system_matrix().close();
355
356 // We can get division-by-zero from ILU within the TAO solver, but
357 // they can recover from it, so if we have FPEs turned on we should
358 // turn them off.
359 FPEDisabler disable_fpes;
360
361 system.solve();
362
363 // Print convergence information
364 system.optimization_solver->print_converged_reason();
365
366#ifdef LIBMESH_HAVE_EXODUS_API
367 std::stringstream filename;
368 ExodusII_IO (mesh).write_equation_systems("optimization_soln.exo",
369 equation_systems);
370#endif
371
372 return 0;
373}
unsigned int dim
This class encapsulate all functionality required for assembling the objective function,...
virtual void hessian(const NumericVector< Number > &soln, SparseMatrix< Number > &H_f, OptimizationSystem &)
Evaluate the Hessian.
virtual Number objective(const NumericVector< Number > &soln, OptimizationSystem &)
Evaluate the objective function.
NumericVector< Number > * F_vector
Vector for storing F.
OptimizationSystem & _sys
Keep a reference to the OptimizationSystem.
virtual void gradient(const NumericVector< Number > &soln, NumericVector< Number > &grad_f, OptimizationSystem &)
Evaluate the gradient.
AssembleOptimization(OptimizationSystem &sys_in)
Constructor.
void assemble_A_and_F()
The optimization problem we consider here is: min_U 0.5*U^T A U - U^T F.
SparseMatrix< Number > * A_matrix
Sparse matrix for storing the matrix A.
Defines a dense matrix for use in Finite Element-type computations.
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
Defines a dense vector for use in Finite Element-type computations.
void resize(const unsigned int n)
Resize the vector.
This class allows one to associate Dirichlet boundary values with a given set of mesh boundary ids an...
This class handles the numbering of degrees of freedom on a mesh.
Definition dof_map.h:181
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition dof_map.C:2201
void add_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary)
Adds a copy of the specified Dirichlet boundary to the system.
const FEType & variable_type(const unsigned int i) const
Definition dof_map.h:2388
bool is_constrained_dof(const dof_id_type dof) const
Definition dof_map.h:2426
void constrain_element_matrix_and_vector(DenseMatrix< Number > &matrix, DenseVector< Number > &rhs, std::vector< dof_id_type > &elem_dofs, bool asymmetric_constraint_rows=true) const
Constrains the element matrix and vector.
Definition dof_map.h:2498
This is the EquationSystems class.
void print_info(std::ostream &os=libMesh::out) const
Prints information about the equation systems, by default to libMesh::out.
virtual void init()
Initialize all the systems.
virtual System & add_system(std::string_view system_type, std::string_view name)
Add the system of type system_type named name to the systems array.
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition exodusII_io.h:53
virtual void write_equation_systems(const std::string &fname, const EquationSystems &es, const std::set< std::string > *system_names=nullptr) override
Writes out the solution for no specific time or timestep.
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
Order default_quadrature_order() const
Definition fe_type.h:415
const SparseMatrix< Number > & get_system_matrix() const
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition libmesh.h:92
This is the MeshBase class.
Definition mesh_base.h:81
unsigned int mesh_dimension() const
Definition mesh_base.C:430
void print_info(std::ostream &os=libMesh::out, const unsigned int verbosity=0, const bool global=true) const
Prints relevant information about the mesh.
Definition mesh_base.C:1755
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition mesh.h:51
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
virtual void close()=0
Calls the NumericVector's internal assembly routines, ensuring that the values are consistent across ...
virtual T dot(const NumericVector< T > &v) const =0
virtual void add_vector(const T *v, const std::vector< numeric_index_type > &dof_indices)
Computes , where v is a pointer and each dof_indices[i] specifies where to add value v[i].
virtual void zero()=0
Set all entries to zero.
virtual std::unique_ptr< NumericVector< T > > zero_clone() const =0
virtual void add(const numeric_index_type i, const T value)=0
Adds value to the vector entry specified by i.
static std::unique_ptr< OptimizationSolver< T > > build(sys_type &s, const SolverPackage solver_package=libMesh::default_solver_package())
Builds an OptimizationSolver using the package specified by solver_package.
Abstract base class to be used to calculate the gradient of an objective function.
Abstract base class to be used to calculate the Hessian of an objective function.
Abstract base class to be used to calculate the objective function for optimization.
This System subclass enables us to assemble an objective function, gradient, Hessian and bounds for o...
virtual void solve() override
Solves the optimization problem.
std::unique_ptr< OptimizationSolver< Number > > optimization_solver
The OptimizationSolver that is used for performing the optimization.
unsigned int n_points() const
Definition quadrature.h:131
This class implements specific orders of Gauss quadrature.
Generic sparse matrix.
virtual void close()=0
Calls the SparseMatrix's internal assembly routines, ensuring that the values are consistent across p...
void vector_mult(NumericVector< T > &dest, const NumericVector< T > &arg) const
Multiplies the matrix by the NumericVector arg and stores the result in NumericVector dest.
virtual void add_matrix(const DenseMatrix< T > &dm, const std::vector< numeric_index_type > &rows, const std::vector< numeric_index_type > &cols)=0
Add the full matrix dm to the SparseMatrix.
virtual void zero()=0
Set all entries to 0.
virtual void add(const numeric_index_type i, const numeric_index_type j, const T value)=0
Add value to the element (i,j).
SparseMatrix< Number > & add_matrix(std::string_view mat_name, ParallelType type=PARALLEL, MatrixBuildType mat_build_type=MatrixBuildType::AUTOMATIC)
Adds the additional matrix mat_name to this system.
Definition system.C:998
const SparseMatrix< Number > & get_matrix(std::string_view mat_name) const
Definition system.C:1111
unsigned int add_variable(std::string_view var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
Definition system.C:1344
NumericVector< Number > & add_vector(std::string_view vec_name, const bool projections=true, const ParallelType type=PARALLEL)
Adds the additional vector vec_name to this system.
Definition system.C:756
unsigned int variable_number(std::string_view var) const
Definition system.C:1398
const DofMap & get_dof_map() const
Definition system.h:2417
const NumericVector< Number > & get_vector(std::string_view vec_name) const
Definition system.C:931
const MeshBase & get_mesh() const
Definition system.h:2401
ConstFunction that simply returns 0.
MeshBase & mesh
void build_square(UnstructuredMesh &mesh, const unsigned int nx, const unsigned int ny, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 2D meshes.
The libMesh namespace provides an interface to certain functionality in the library.
OStreamProxy err
SolverPackage
Defines an enum for various linear solver packages.
uint8_t dof_id_type
Definition id_types.h:67
bool on_command_line(std::string arg)
Definition libmesh.C:934
The FPEDisabler class puts Floating-Point Exception (FPE) trapping on hold during its lifetime,...
int main()