libMesh
optimization_ex1.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 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/boundary_info.h"
51 #include "libmesh/string_to_enum.h"
52 #include "libmesh/getpot.h"
53 #include "libmesh/zero_function.h"
54 #include "libmesh/dirichlet_boundaries.h"
55 #include "libmesh/optimization_system.h"
56 #include "libmesh/optimization_solver.h"
57 
58 // Bring in everything from the libMesh namespace
59 using namespace libMesh;
60 
61 
70 {
71 private:
72 
77 
78 public:
79 
84 
90  void assemble_A_and_F();
91 
95  virtual Number objective (const NumericVector<Number> & soln,
96  OptimizationSystem & /*sys*/);
97 
101  virtual void gradient (const NumericVector<Number> & soln,
102  NumericVector<Number> & grad_f,
103  OptimizationSystem & /*sys*/);
104 
108  virtual void hessian (const NumericVector<Number> & soln,
109  SparseMatrix<Number> & H_f,
110  OptimizationSystem & /*sys*/);
111 
118 
124 };
125 
127  _sys(sys_in)
128 {}
129 
131 {
132  A_matrix->zero();
133  F_vector->zero();
134 
135  const MeshBase & mesh = _sys.get_mesh();
136 
137  const unsigned int dim = mesh.mesh_dimension();
138  const unsigned int u_var = _sys.variable_number ("u");
139 
140  const DofMap & dof_map = _sys.get_dof_map();
141  FEType fe_type = dof_map.variable_type(u_var);
142  std::unique_ptr<FEBase> fe (FEBase::build(dim, fe_type));
143  QGauss qrule (dim, fe_type.default_quadrature_order());
144  fe->attach_quadrature_rule (&qrule);
145 
146  const std::vector<Real> & JxW = fe->get_JxW();
147  const std::vector<std::vector<Real>> & phi = fe->get_phi();
148  const std::vector<std::vector<RealGradient>> & dphi = fe->get_dphi();
149 
150  std::vector<dof_id_type> dof_indices;
151 
154 
155  for (const auto & elem : mesh.active_local_element_ptr_range())
156  {
157  dof_map.dof_indices (elem, dof_indices);
158 
159  const unsigned int n_dofs = dof_indices.size();
160 
161  fe->reinit (elem);
162 
163  Ke.resize (n_dofs, n_dofs);
164  Fe.resize (n_dofs);
165 
166  for (unsigned int qp=0; qp<qrule.n_points(); qp++)
167  {
168  for (unsigned int dof_i=0; dof_i<n_dofs; dof_i++)
169  {
170  for (unsigned int dof_j=0; dof_j<n_dofs; dof_j++)
171  {
172  Ke(dof_i, dof_j) += JxW[qp] * (dphi[dof_j][qp]* dphi[dof_i][qp]);
173  }
174  Fe(dof_i) += JxW[qp] * phi[dof_i][qp];
175  }
176  }
177 
178 #ifdef LIBMESH_ENABLE_CONSTRAINTS
179  // This will zero off-diagonal entries of Ke corresponding to
180  // Dirichlet dofs.
181  dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices);
182 
183  // We want the diagonal of constrained dofs to be zero too
184  for (unsigned int local_dof_index=0; local_dof_index<n_dofs; local_dof_index++)
185  {
186  dof_id_type global_dof_index = dof_indices[local_dof_index];
187  if (dof_map.is_constrained_dof(global_dof_index))
188  {
189  Ke(local_dof_index, local_dof_index) = 0.;
190  }
191  }
192 #endif // LIBMESH_ENABLE_CONSTRAINTS
193 
194  A_matrix->add_matrix (Ke, dof_indices);
195  F_vector->add_vector (Fe, dof_indices);
196  }
197 
198  A_matrix->close();
199  F_vector->close();
200 }
201 
203  OptimizationSystem & /*sys*/)
204 {
205  std::unique_ptr<NumericVector<Number>> AxU = soln.zero_clone();
206 
207  A_matrix->vector_mult(*AxU, soln);
208 
209  Number
210  UTxAxU = AxU->dot(soln),
211  UTxF = F_vector->dot(soln);
212 
213  return 0.5 * UTxAxU - UTxF;
214 }
215 
217  NumericVector<Number> & grad_f,
218  OptimizationSystem & /*sys*/)
219 {
220  grad_f.zero();
221 
222  // Since we've enforced constraints on soln, A and F,
223  // this automatically sets grad_f to zero for constrained
224  // dofs.
225  A_matrix->vector_mult(grad_f, soln);
226  grad_f.add(-1, *F_vector);
227 }
228 
229 
231  SparseMatrix<Number> & H_f,
232  OptimizationSystem & /*sys*/)
233 {
234  H_f.zero();
235  H_f.add(1., *A_matrix);
236 }
237 
238 
239 int main (int argc, char ** argv)
240 {
241  LibMeshInit init (argc, argv);
242 
243 #ifndef LIBMESH_HAVE_PETSC_TAO
244 
245  libmesh_example_requires(false, "PETSc >= 3.5.0 with built-in TAO support");
246 
247 #elif !defined(LIBMESH_ENABLE_GHOSTED)
248 
249  libmesh_example_requires(false, "--enable-ghosted");
250 
251 #elif LIBMESH_USE_COMPLEX_NUMBERS
252 
253  // According to
254  // http://www.mcs.anl.gov/research/projects/tao/documentation/installation.html
255  // TAO & PETSc-complex are currently mutually exclusive
256  libmesh_example_requires(false, "PETSc >= 3.5.0 with built-in TAO support & real-numbers only");
257 
258 #endif
259 
260  // We use a 2D domain.
261  libmesh_example_requires(LIBMESH_DIM > 1, "--disable-1D-only");
262 
263  // We use Dirichlet boundary conditions here
264 #ifndef LIBMESH_ENABLE_DIRICHLET
265  libmesh_example_requires(false, "--enable-dirichlet");
266 #endif
267 
268  if (libMesh::on_command_line ("--use-eigen"))
269  {
270  libMesh::err << "This example requires an OptimizationSolver, and therefore does not "
271  << "support --use-eigen on the command line."
272  << std::endl;
273  return 0;
274  }
275 
276  GetPot infile("optimization_ex1.in");
277  const std::string approx_order = infile("approx_order", "FIRST");
278  const std::string fe_family = infile("fe_family", "LAGRANGE");
279  const unsigned int n_elem = infile("n_elem", 10);
280 
281  Mesh mesh(init.comm());
283  n_elem,
284  n_elem,
285  -1., 1.,
286  -1., 1.,
287  QUAD9);
288 
289  mesh.print_info();
290 
291  EquationSystems equation_systems (mesh);
292 
293  OptimizationSystem & system =
294  equation_systems.add_system<OptimizationSystem> ("Optimization");
295 
296  // The default is to use PETSc/Tao solvers, but let the user change
297  // the optimization solver package on the fly.
298  {
299  const std::string optimization_solver_type = infile("optimization_solver_type",
300  "PETSC_SOLVERS");
301  SolverPackage sp = Utility::string_to_enum<SolverPackage>(optimization_solver_type);
302  std::unique_ptr<OptimizationSolver<Number>> new_solver =
304  system.optimization_solver.reset(new_solver.release());
305  }
306 
307  // Set tolerances and maximum iteration counts directly on the optimization solver.
308  system.optimization_solver->max_objective_function_evaluations = 128;
309  system.optimization_solver->objective_function_relative_tolerance = 1.e-4;
310  system.optimization_solver->verbose = true;
311 
312  AssembleOptimization assemble_opt(system);
313 
314  system.optimization_solver->objective_object = &assemble_opt;
315  system.optimization_solver->gradient_object = &assemble_opt;
316  system.optimization_solver->hessian_object = &assemble_opt;
317 
318  // system.matrix and system.rhs are used for the gradient and Hessian,
319  // so in this case we add an extra matrix and vector to store A and F.
320  // This makes it easy to write the code for evaluating the objective,
321  // gradient, and hessian.
322  system.add_matrix("A_matrix");
323  system.add_vector("F_vector");
324  assemble_opt.A_matrix = &system.get_matrix("A_matrix");
325  assemble_opt.F_vector = &system.get_vector("F_vector");
326 
327 #ifdef LIBMESH_ENABLE_DIRICHLET
328  unsigned int u_var = system.add_variable("u",
329  Utility::string_to_enum<Order> (approx_order),
330  Utility::string_to_enum<FEFamily>(fe_family));
331 
332  // Apply Dirichlet constraints. This will be used to apply constraints
333  // to the objective function, gradient and Hessian.
334  std::set<boundary_id_type> boundary_ids;
335  boundary_ids.insert(0);
336  boundary_ids.insert(1);
337  boundary_ids.insert(2);
338  boundary_ids.insert(3);
339  std::vector<unsigned int> variables;
340  variables.push_back(u_var);
341  ZeroFunction<> zf;
342 
343  // Most DirichletBoundary users will want to supply a "locally
344  // indexed" functor
345  DirichletBoundary dirichlet_bc(boundary_ids, variables, zf,
347  system.get_dof_map().add_dirichlet_boundary(dirichlet_bc);
348 #endif // LIBMESH_ENABLE_DIRICHLET
349 
350  equation_systems.init();
351  equation_systems.print_info();
352 
353  assemble_opt.assemble_A_and_F();
354 
355  // We need to close the matrix so that we can use it to store the
356  // Hessian during the solve.
357  system.matrix->close();
358  system.solve();
359 
360  // Print convergence information
361  system.optimization_solver->print_converged_reason();
362 
363 #ifdef LIBMESH_HAVE_EXODUS_API
364  std::stringstream filename;
365  ExodusII_IO (mesh).write_equation_systems("optimization_soln.exo",
366  equation_systems);
367 #endif
368 
369  return 0;
370 }
libMesh::OptimizationSystem
This System subclass enables us to assemble an objective function, gradient, Hessian and bounds for o...
Definition: optimization_system.h:43
libMesh::SparseMatrix::close
virtual void close()=0
Calls the SparseMatrix's internal assembly routines, ensuring that the values are consistent across p...
libMesh::NumericVector::zero
virtual void zero()=0
Set all entries to zero.
libMesh::SolverPackage
SolverPackage
Defines an enum for various linear solver packages.
Definition: enum_solver_package.h:34
libMesh::dof_id_type
uint8_t dof_id_type
Definition: id_types.h:67
libMesh::Number
Real Number
Definition: libmesh_common.h:195
libMesh::NumericVector::add
virtual void add(const numeric_index_type i, const T value)=0
Adds value to each entry of the vector.
libMesh::Mesh
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
AssembleOptimization::gradient
virtual void gradient(const NumericVector< Number > &soln, NumericVector< Number > &grad_f, OptimizationSystem &)
Evaluate the gradient.
Definition: optimization_ex1.C:216
main
int main(int argc, char **argv)
Definition: optimization_ex1.C:239
libMesh::EquationSystems::add_system
virtual System & add_system(const std::string &system_type, const std::string &name)
Add the system of type system_type named name to the systems array.
Definition: equation_systems.C:345
libMesh::MeshTools::n_elem
dof_id_type n_elem(const MeshBase::const_element_iterator &begin, const MeshBase::const_element_iterator &end)
Count up the number of elements of a specific type (as defined by an iterator range).
Definition: mesh_tools.C:705
libMesh::QGauss
This class implements specific orders of Gauss quadrature.
Definition: quadrature_gauss.h:39
libMesh::DofMap::dof_indices
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Fills the vector di with the global degree of freedom indices for the element.
Definition: dof_map.C:1967
AssembleOptimization::AssembleOptimization
AssembleOptimization(OptimizationSystem &sys_in)
Constructor.
Definition: optimization_ex1.C:126
libMesh::DofMap::add_dirichlet_boundary
void add_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary)
Adds a copy of the specified Dirichlet boundary to the system.
Definition: dof_map_constraints.C:4390
AssembleOptimization::_sys
OptimizationSystem & _sys
Keep a reference to the OptimizationSystem.
Definition: optimization_ex1.C:76
libMesh::MeshBase::active_local_element_ptr_range
virtual SimpleRange< element_iterator > active_local_element_ptr_range()=0
libMesh::OptimizationSystem::solve
virtual void solve() override
Solves the optimization problem.
Definition: optimization_system.C:162
libMesh::SparseMatrix::vector_mult
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.
Definition: sparse_matrix.C:170
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::NumericVector::close
virtual void close()=0
Calls the NumericVector's internal assembly routines, ensuring that the values are consistent across ...
libMesh::ImplicitSystem::add_matrix
SparseMatrix< Number > & add_matrix(const std::string &mat_name)
Adds the additional matrix mat_name to this system.
Definition: implicit_system.C:202
AssembleOptimization
This class encapsulate all functionality required for assembling the objective function,...
Definition: optimization_ex1.C:66
libMesh::DenseMatrix< Number >
libMesh::OptimizationSystem::ComputeHessian
Abstract base class to be used to calculate the Hessian of an objective function.
Definition: optimization_system.h:116
mesh
MeshBase & mesh
Definition: mesh_communication.C:1257
libMesh::MeshBase::mesh_dimension
unsigned int mesh_dimension() const
Definition: mesh_base.C:135
libMesh::ExodusII_IO
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition: exodusII_io.h:51
libMesh::DofMap::is_constrained_dof
bool is_constrained_dof(const dof_id_type dof) const
Definition: dof_map.h:1962
libMesh::SparseMatrix< Number >
dim
unsigned int dim
Definition: adaptivity_ex3.C:113
libMesh::DenseMatrix::resize
void resize(const unsigned int new_m, const unsigned int new_n)
Resize the matrix.
Definition: dense_matrix.h:822
libMesh::NumericVector< Number >
libMesh::TriangleWrapper::init
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
libMesh::LOCAL_VARIABLE_ORDER
Definition: dirichlet_boundaries.h:62
AssembleOptimization::F_vector
NumericVector< Number > * F_vector
Vector for storing F.
Definition: optimization_ex1.C:123
libMesh::MeshTools::Generation::build_square
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.
Definition: mesh_generation.C:1501
libMesh::NumericVector::add_vector
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].
Definition: numeric_vector.C:363
libMesh::MeshBase
This is the MeshBase class.
Definition: mesh_base.h:78
AssembleOptimization::hessian
virtual void hessian(const NumericVector< Number > &soln, SparseMatrix< Number > &H_f, OptimizationSystem &)
Evaluate the Hessian.
Definition: optimization_ex1.C:230
libMesh::OptimizationSolver
This base class can be inherited from to provide interfaces to optimization solvers from different pa...
Definition: optimization_solver.h:60
AssembleOptimization::assemble_A_and_F
void assemble_A_and_F()
The optimization problem we consider here is: min_U 0.5*U^T A U - U^T F.
Definition: optimization_ex1.C:130
libMesh::System::get_mesh
const MeshBase & get_mesh() const
Definition: system.h:2083
libMesh::OptimizationSystem::optimization_solver
std::unique_ptr< OptimizationSolver< Number > > optimization_solver
The OptimizationSolver that is used for performing the optimization.
Definition: optimization_system.h:268
libMesh::System::add_variable
unsigned int add_variable(const std::string &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:1069
libMesh::EquationSystems::init
virtual void init()
Initialize all the systems.
Definition: equation_systems.C:96
libMesh::ImplicitSystem::matrix
SparseMatrix< Number > * matrix
The system matrix.
Definition: implicit_system.h:393
libMesh::DofMap::variable_type
const FEType & variable_type(const unsigned int c) const
Definition: dof_map.h:1924
libMesh::LibMeshInit
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition: libmesh.h:83
libMesh::OptimizationSystem::ComputeObjective
Abstract base class to be used to calculate the objective function for optimization.
Definition: optimization_system.h:74
libMesh::OptimizationSystem::ComputeGradient
Abstract base class to be used to calculate the gradient of an objective function.
Definition: optimization_system.h:95
libMesh::ZeroFunction
ConstFunction that simply returns 0.
Definition: zero_function.h:36
libMesh::SparseMatrix::add
virtual void add(const numeric_index_type i, const numeric_index_type j, const T value)=0
Add value to the element (i,j).
libMesh::EquationSystems::print_info
void print_info(std::ostream &os=libMesh::out) const
Prints information about the equation systems, by default to libMesh::out.
Definition: equation_systems.C:1314
libMesh::EquationSystems
This is the EquationSystems class.
Definition: equation_systems.h:74
libMesh::DofMap::constrain_element_matrix_and_vector
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:2034
libMesh::MeshOutput::write_equation_systems
virtual void write_equation_systems(const std::string &, const EquationSystems &, const std::set< std::string > *system_names=nullptr)
This method implements writing a mesh with data to a specified file where the data is taken from the ...
Definition: mesh_output.C:31
libMesh::DenseVector::resize
void resize(const unsigned int n)
Resize the vector.
Definition: dense_vector.h:355
libMesh::SparseMatrix::add_matrix
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.
libMesh::FEType
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:178
libMesh::DofMap
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:176
libMesh::MeshBase::print_info
void print_info(std::ostream &os=libMesh::out) const
Prints relevant information about the mesh.
Definition: mesh_base.C:585
AssembleOptimization::objective
virtual Number objective(const NumericVector< Number > &soln, OptimizationSystem &)
Evaluate the objective function.
Definition: optimization_ex1.C:202
libMesh::DirichletBoundary
This class allows one to associate Dirichlet boundary values with a given set of mesh boundary ids an...
Definition: dirichlet_boundaries.h:88
libMesh::System::variable_number
unsigned short int variable_number(const std::string &var) const
Definition: system.C:1232
libMesh::on_command_line
bool on_command_line(std::string arg)
Definition: libmesh.C:898
AssembleOptimization::A_matrix
SparseMatrix< Number > * A_matrix
Sparse matrix for storing the matrix A.
Definition: optimization_ex1.C:117
libMesh::System::add_vector
NumericVector< Number > & add_vector(const std::string &vec_name, const bool projections=true, const ParallelType type=PARALLEL)
Adds the additional vector vec_name to this system.
Definition: system.C:661
libMesh::QUAD9
Definition: enum_elem_type.h:43
libMesh::System::get_dof_map
const DofMap & get_dof_map() const
Definition: system.h:2099
libMesh::err
OStreamProxy err
libMesh::FEType::default_quadrature_order
Order default_quadrature_order() const
Definition: fe_type.h:353
libMesh::ImplicitSystem::get_matrix
const SparseMatrix< Number > & get_matrix(const std::string &mat_name) const
Definition: implicit_system.C:262
libMesh::System::get_vector
const NumericVector< Number > & get_vector(const std::string &vec_name) const
Definition: system.C:774
libMesh::SparseMatrix::zero
virtual void zero()=0
Set all entries to 0.
libMesh::NumericVector::zero_clone
virtual std::unique_ptr< NumericVector< T > > zero_clone() const =0
libMesh::NumericVector::dot
virtual T dot(const NumericVector< T > &v) const =0
libMesh::DenseVector< Number >