MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
seqheat.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2024, 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// SeqHeat Miniapp: Gradients of PDE constrained objective function
14// ----------------------------------------------------------------
15// (Sequential Version)
16//
17// The following example computes the gradients of a specified objective
18// function with respect to parametric fields. The objective function is having
19// the following form f(u(\rho)) where u(\rho) is a solution of a specific state
20// problem (in the example that is the diffusion equation), and \rho is a
21// parametric field discretized by finite elements. The parametric field (also
22// called density in topology optimization) controls the coefficients of the
23// state equation. For the considered case, the density controls the diffusion
24// coefficient within the computational domain.
25//
26// For more information, the users are referred to:
27//
28// Hinze, M.; Pinnau, R.; Ulbrich, M. & Ulbrich, S.
29// Optimization with PDE Constraints
30// Springer Netherlands, 2009
31//
32// Bendsøe, M. P. & Sigmund, O.
33// Topology Optimization - Theory, Methods and Applications
34// Springer Verlag, Berlin Heidelberg, 2003
35//
36// Compile with: make seqheat
37//
38// Sample runs:
39//
40// seqheat -m ../../data/star-mixed.mesh
41// seqheat --visualization
42
43#include "mfem.hpp"
44#include <fstream>
45#include <iostream>
46
47#include "mtop_integrators.hpp"
48
49using namespace mfem;
50
51int main(int argc, char *argv[])
52{
53 const char *mesh_file = "../../data/star.vtk";
54 int ser_ref_levels = 1;
55 int order = 2;
56 bool visualization = false;
57 real_t newton_rel_tol = 1e-4;
58 real_t newton_abs_tol = 1e-6;
59 int newton_iter = 10;
60 int print_level = 0;
61
62 mfem::OptionsParser args(argc, argv);
63 args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
64 args.AddOption(&ser_ref_levels,
65 "-rs",
66 "--refine-serial",
67 "Number of times to refine the mesh uniformly in serial.");
68 args.AddOption(&order,
69 "-o",
70 "--order",
71 "Order (degree) of the finite elements.");
72 args.AddOption(&visualization,
73 "-vis",
74 "--visualization",
75 "-no-vis",
76 "--no-visualization",
77 "Enable or disable GLVis visualization.");
78 args.AddOption(&newton_rel_tol,
79 "-rel",
80 "--relative-tolerance",
81 "Relative tolerance for the Newton solve.");
82 args.AddOption(&newton_abs_tol,
83 "-abs",
84 "--absolute-tolerance",
85 "Absolute tolerance for the Newton solve.");
86 args.AddOption(&newton_iter,
87 "-it",
88 "--newton-iterations",
89 "Maximum iterations for the Newton solve.");
90 args.Parse();
91 if (!args.Good())
92 {
93 args.PrintUsage(std::cout);
94 return 1;
95 }
96 args.PrintOptions(std::cout);
97
98 // Read the (serial) mesh from the given mesh file on all processors. We
99 // can handle triangular, quadrilateral, tetrahedral and hexahedral meshes
100 // with the same code.
101 mfem::Mesh *mesh = new mfem::Mesh(mesh_file, 1, 1);
102 int dim = mesh->Dimension();
103
104 // Refine the mesh in serial to increase the resolution. In this example
105 // we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
106 // a command-line parameter.
107 for (int lev = 0; lev < ser_ref_levels; lev++)
108 {
109 mesh->UniformRefinement();
110 }
111
112 // Diffusion coefficient
114 // Heat source
116 // Define the q-function
117 mfem::QLinearDiffusion* qfun=new mfem::QLinearDiffusion(*diffco,*loadco,1.0,
118 1e-7,4.0,0.5);
119
120 // Define FE collection and space for the state solution
121 mfem::H1_FECollection sfec(order, dim);
123 // Define FE collection and space for the density field
124 mfem::L2_FECollection pfec(order, dim);
126
127 // Define the arrays for the nonlinear form
130
131 asfes.Append(sfes);
132 apfes.Append(pfes);
133 // Define parametric block nonlinear form using single scalar H1 field
134 // and L2 scalar density field
136 // Add the parametric integrator
138
139 // Define true block vectors for state, adjoint, residual
140 mfem::BlockVector solbv; solbv.Update(nf->GetBlockTrueOffsets()); solbv=0.0;
141 mfem::BlockVector adjbv; adjbv.Update(nf->GetBlockTrueOffsets()); adjbv=0.0;
142 mfem::BlockVector resbv; resbv.Update(nf->GetBlockTrueOffsets()); resbv=0.0;
143 // Define true block vectors for parametric field and gradients
145 prmbv=0.0;
147 grdbv=0.0;
148
149 // Set the BC for the physics
152 ess_bdr.Append(new mfem::Array<int>(mesh->bdr_attributes.Max()));
153 ess_rhs.Append(nullptr);
154 (*ess_bdr[0]) = 1;
155 nf->SetEssentialBC(ess_bdr,ess_rhs);
156 delete ess_bdr[0];
157
158 // Define the linear solvers
159 mfem::GMRESSolver *gmres;
160 gmres = new mfem::GMRESSolver();
161 gmres->SetAbsTol(newton_abs_tol/10);
162 gmres->SetRelTol(newton_rel_tol/10);
163 gmres->SetMaxIter(300);
164 gmres->SetPrintLevel(print_level);
165
166 // Define the Newton solver
168 ns = new mfem::NewtonSolver();
169 ns->iterative_mode = true;
170 ns->SetSolver(*gmres);
171 ns->SetOperator(*nf);
172 ns->SetPrintLevel(print_level);
173 ns->SetRelTol(newton_rel_tol);
174 ns->SetAbsTol(newton_abs_tol);
175 ns->SetMaxIter(newton_iter);
176
177 // Solve the problem
178 // Set the density to 0.5
179 prmbv=0.5;
180 nf->SetParamFields(prmbv); // Set the density
181 // Define the RHS
183 solbv=0.0;
184 // Newton solve
185 ns->Mult(b, solbv);
186
187 // Compute the residual
188 nf->Mult(solbv,resbv);
189 std::cout<<"Norm residual="<<resbv.Norml2()<<std::endl;
190
191 // Compute the energy of the state system
192 real_t energy = nf->GetEnergy(solbv);
193 std::cout<<"energy ="<< energy<<std::endl;
194
195 // Define the block nonlinear form utilized for representing the
196 // objective. The input is the state array asfes defined earlier.
198
199 // Add the integrator for the objective
201
202 // Compute the objective
203 real_t obj=ob->GetEnergy(solbv);
204 std::cout<<"Objective ="<<obj<<std::endl;
205
206 // Solve the adjoint
207 {
208 mfem::BlockVector adjrhs; adjrhs.Update(nf->GetBlockTrueOffsets()); adjrhs=0.0;
209 // Compute the RHS for the adjoint
210 ob->Mult(solbv, adjrhs);
211 // Get the tangent matrix from the state problem
212 mfem::BlockOperator& A=nf->GetGradient(solbv);
213 // We do not need to transpose the operator for diffusion
214 gmres->SetOperator(A.GetBlock(0,0));
215 // Compute the adjoint solution
216 gmres->Mult(adjrhs.GetBlock(0), adjbv.GetBlock(0));
217 }
218
219 // Compute gradients
220 nf->SetAdjointFields(adjbv);
221 nf->SetStateFields(solbv);
222 nf->ParamMult(prmbv, grdbv);
223
224 // Dump out the data
225 if (visualization)
226 {
228 mesh);
229 mfem::GridFunction gfgrd(pfes); gfgrd.SetFromTrueDofs(grdbv.GetBlock(0));
230 mfem::GridFunction gfdns(pfes); gfdns.SetFromTrueDofs(prmbv.GetBlock(0));
231 // Define state grid function
232 mfem::GridFunction gfsol(sfes); gfsol.SetFromTrueDofs(solbv.GetBlock(0));
233 mfem::GridFunction gfadj(sfes); gfadj.SetFromTrueDofs(adjbv.GetBlock(0));
234
235 dacol->SetLevelsOfDetail(order);
236 dacol->RegisterField("sol", &gfsol);
237 dacol->RegisterField("adj", &gfadj);
238 dacol->RegisterField("dns", &gfdns);
239 dacol->RegisterField("grd", &gfgrd);
240
241 dacol->SetTime(1.0);
242 dacol->SetCycle(1);
243 dacol->Save();
244
245 delete dacol;
246 }
247
248 // FD check
249 {
250 // Perturbation vector
251 mfem::BlockVector prtbv;
252 mfem::BlockVector tmpbv;
253 prtbv.Update(nf->ParamGetBlockTrueOffsets());
254 tmpbv.Update(nf->ParamGetBlockTrueOffsets());
255 // Generate the perturbation
256 prtbv.GetBlock(0).Randomize();
257 prtbv*=1.0;
258 // Scaling parameter
259 real_t lsc=1.0;
260
261 // Compute initial objective
262 real_t gQoI=ob->GetEnergy(solbv);
263 real_t lQoI;
264
265 // Norm of the perturbation
266 real_t nd=mfem::InnerProduct(prtbv,prtbv);
267 // Projection of the adjoint gradient on the perturbation
268 real_t td=mfem::InnerProduct(prtbv,grdbv);
269 // Normalize the directional derivative
270 td=td/nd;
271
272 for (int l = 0; l < 10; l++)
273 {
274 lsc/=10.0;
275 // Scale the perturbation
276 prtbv/=10.0;
277 // Add the perturbation to the original density
278 add(prmbv,prtbv,tmpbv);
279 nf->SetParamFields(tmpbv);
280 // Solve the physics
281 ns->Mult(b,solbv);
282 // Compute the objective
283 lQoI=ob->GetEnergy(solbv);
284 // FD approximation
285 real_t ld=(lQoI-gQoI)/lsc;
286 std::cout << "dx=" << lsc << " FD gradient=" << ld/nd
287 << " adjoint gradient=" << td
288 << " err=" << std::fabs(ld/nd-td) << std::endl;
289 }
290 }
291
292 delete ob;
293
294 delete ns;
295 delete gmres;
296
297 delete nf;
298 delete pfes;
299 delete sfes;
300
301 delete qfun;
302 delete loadco;
303 delete diffco;
304
305 delete mesh;
306
307 return 0;
308}
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:68
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:769
A class representing a general block nonlinear operator defined on the Cartesian product of multiple ...
void AddDomainIntegrator(BlockNonlinearFormIntegrator *nlfi)
Adds new Domain Integrator.
virtual real_t GetEnergy(const Vector &x) const
virtual void Mult(const Vector &x, Vector &y) const
A class to handle Block systems in a matrix-free implementation.
Operator & GetBlock(int i, int j)
Return a reference to block i,j.
A class to handle Vectors in a block fashion.
void Update(real_t *data, const Array< int > &bOffsets)
Update method.
Vector & GetBlock(int i)
Get the i-th vector in the block.
A coefficient that is constant across space and time.
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)
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:220
GMRES method.
Definition solvers.hpp:547
virtual void Mult(const Vector &b, Vector &x) const
Iterative solution of the linear system using the GMRES method.
Definition solvers.cpp:980
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:31
virtual void SetFromTrueDofs(const Vector &tv)
Set the GridFunction from the given true-dof vector.
Definition gridfunc.cpp:381
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:260
virtual void SetOperator(const Operator &op) override
Also calls SetOperator for the preconditioner if there is one.
Definition solvers.cpp:179
void SetRelTol(real_t rtol)
Definition solvers.hpp:209
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
Definition solvers.cpp:71
void SetMaxIter(int max_it)
Definition solvers.hpp:211
void SetAbsTol(real_t atol)
Definition solvers.hpp:210
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:330
Mesh data type.
Definition mesh.hpp:56
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:282
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1160
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:10970
Newton's method for solving F(x)=b for a given operator F.
Definition solvers.hpp:667
virtual void SetOperator(const Operator &op)
Also calls SetOperator for the preconditioner if there is one.
Definition solvers.cpp:1810
virtual void SetSolver(Solver &solver)
Set the linear solver for inverting the Jacobian.
Definition solvers.hpp:714
virtual void Mult(const Vector &b, Vector &x) const
Solve the nonlinear system with right-hand side b.
Definition solvers.cpp:1821
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.
Helper class for ParaView visualization data.
void SetLevelsOfDetail(int levels_of_detail_)
virtual void Save() override
A class representing a general parametric block nonlinear operator defined on the Cartesian product o...
virtual void ParamMult(const Vector &x, Vector &y) const
virtual void SetStateFields(const Vector &xv) const
Set the state fields.
const Array< int > & GetBlockTrueOffsets() const
Return the true-dof offsets.
virtual real_t GetEnergy(const Vector &x) const
Computes the energy for a state vector x.
virtual BlockOperator & GetGradient(const Vector &x) const
virtual void SetAdjointFields(const Vector &av) const
Set the adjoint fields.
virtual void Mult(const Vector &x, Vector &y) const
const Array< int > & ParamGetBlockTrueOffsets() const
Return the true-dof offsets for the parameters.
virtual void SetEssentialBC(const Array< Array< int > * > &bdr_attr_is_ess, Array< Vector * > &rhs)
Set the essential boundary conditions.
virtual void SetParamFields(const Vector &dv) const
Set the parameters/design fields.
void AddDomainIntegrator(ParametricBNLFormIntegrator *nlfi)
Adds new Domain Integrator.
bool iterative_mode
If true, use the second argument of Mult() as an initial guess.
Definition operator.hpp:686
Vector data type.
Definition vector.hpp:80
void Randomize(int seed=0)
Set random values in the vector.
Definition vector.cpp:816
real_t Norml2() const
Returns the l2 norm of the vector.
Definition vector.cpp:832
int dim
Definition ex24.cpp:53
int main()
real_t b
Definition lissajous.cpp:42
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition vector.cpp:316
real_t InnerProduct(HypreParVector *x, HypreParVector *y)
Definition hypre.cpp:439
float real_t
Definition config.hpp:43