libMesh
Loading...
Searching...
No Matches
adjoint_residual_error_estimator.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// Local Includes
20#include "libmesh/adjoint_residual_error_estimator.h"
21#include "libmesh/error_vector.h"
22#include "libmesh/patch_recovery_error_estimator.h"
23#include "libmesh/libmesh_logging.h"
24#include "libmesh/numeric_vector.h"
25#include "libmesh/system.h"
26#include "libmesh/system_norm.h"
27#include "libmesh/qoi_set.h"
28#include "libmesh/enum_error_estimator_type.h"
29#include "libmesh/int_range.h"
30
31// C++ includes
32#include <iostream>
33#include <iomanip>
34#include <memory>
35#include <sstream>
36
37namespace libMesh
38{
39
40//-----------------------------------------------------------------
41// AdjointResidualErrorEstimator implementations
44 error_plot_suffix(),
45 _primal_error_estimator(std::make_unique<PatchRecoveryErrorEstimator>()),
46 _dual_error_estimator(std::make_unique<PatchRecoveryErrorEstimator>()),
47 _qoi_set(QoISet())
48{
49}
50
51
52
58
59
60
62 ErrorVector & error_per_cell,
63 const NumericVector<Number> * solution_vector,
64 bool estimate_parent_error)
65{
66 LOG_SCOPE("estimate_error()", "AdjointResidualErrorEstimator");
67
68 // The current mesh
69 const MeshBase & mesh = _system.get_mesh();
70
71 // Resize the error_per_cell vector to be
72 // the number of elements, initialize it to 0.
73 error_per_cell.resize (mesh.max_elem_id());
74 std::fill (error_per_cell.begin(), error_per_cell.end(), 0.);
75
76 // Get the number of variables in the system
77 unsigned int n_vars = _system.n_vars();
78
79 // We need to make a map of the pointer to the solution vector
80 std::map<const System *, const NumericVector<Number> *>solutionvecs;
81 solutionvecs[&_system] = _system.solution.get();
82
83 // Solve the dual problem if we have to
84 if (!_system.is_adjoint_already_solved())
85 {
86 // FIXME - we'll need to change a lot of APIs to make this trick
87 // work with a const System...
88 System & system = const_cast<System &>(_system);
89 system.adjoint_solve(_qoi_set);
90 }
91
92 // Flag to check whether we have not been asked to weight the variable error contributions in any specific manner
93 bool error_norm_is_identity = error_norm.is_identity();
94
95 // Create an ErrorMap/ErrorVector to store the primal, dual and total_dual variable errors
96 ErrorMap primal_errors_per_cell;
97 ErrorMap dual_errors_per_cell;
98 ErrorMap total_dual_errors_per_cell;
99 // Allocate ErrorVectors to this map if we're going to use it
100 if (!error_norm_is_identity)
101 for (unsigned int v = 0; v < n_vars; v++)
102 {
103 primal_errors_per_cell[std::make_pair(&_system, v)] = std::make_unique<ErrorVector>();
104 dual_errors_per_cell[std::make_pair(&_system, v)] = std::make_unique<ErrorVector>();
105 total_dual_errors_per_cell[std::make_pair(&_system, v)] = std::make_unique<ErrorVector>();
106 }
107 ErrorVector primal_error_per_cell;
108 ErrorVector dual_error_per_cell;
109 ErrorVector total_dual_error_per_cell;
110
111 // Have we been asked to weight the variable error contributions in any specific manner
112 if (!error_norm_is_identity) // If we do
113 {
114 // Estimate the primal problem error for each variable
115 _primal_error_estimator->estimate_errors
116 (_system.get_equation_systems(), primal_errors_per_cell, &solutionvecs, estimate_parent_error);
117 }
118 else // If not
119 {
120 // Just get the combined error estimate
121 _primal_error_estimator->estimate_error
122 (_system, primal_error_per_cell, solution_vector, estimate_parent_error);
123 }
124
125 // Sum and weight the dual error estimate based on our QoISet
126 for (unsigned int i = 0, n_qois = _system.n_qois(); i != n_qois; ++i)
127 {
128 if (_qoi_set.has_index(i))
129 {
130 // Get the weight for the current QoI
131 Real error_weight = _qoi_set.weight(i);
132
133 // We need to make a map of the pointer to the adjoint solution vector
134 std::map<const System *, const NumericVector<Number> *>adjointsolutionvecs;
135 adjointsolutionvecs[&_system] = &_system.get_adjoint_solution(i);
136
137 // Have we been asked to weight the variable error contributions in any specific manner
138 if (!error_norm_is_identity) // If we have
139 {
140 _dual_error_estimator->estimate_errors
141 (_system.get_equation_systems(), dual_errors_per_cell, &adjointsolutionvecs,
142 estimate_parent_error);
143 }
144 else // If not
145 {
146 // Just get the combined error estimate
147 _dual_error_estimator->estimate_error
148 (_system, dual_error_per_cell, &(_system.get_adjoint_solution(i)), estimate_parent_error);
149 }
150
151 std::size_t error_size;
152
153 // Get the size of the first ErrorMap vector; this will give us the number of elements
154 if (!error_norm_is_identity) // If in non default weights case
155 {
156 error_size = dual_errors_per_cell[std::make_pair(&_system, 0)]->size();
157 }
158 else // If in the standard default weights case
159 {
160 error_size = dual_error_per_cell.size();
161 }
162
163 // Resize the ErrorVector(s)
164 if (!error_norm_is_identity)
165 {
166 // Loop over variables
167 for (unsigned int v = 0; v < n_vars; v++)
168 {
169 libmesh_assert(!total_dual_errors_per_cell[std::make_pair(&_system, v)]->size() ||
170 total_dual_errors_per_cell[std::make_pair(&_system, v)]->size() == error_size) ;
171 total_dual_errors_per_cell[std::make_pair(&_system, v)]->resize(error_size);
172 }
173 }
174 else
175 {
176 libmesh_assert(!total_dual_error_per_cell.size() ||
177 total_dual_error_per_cell.size() == error_size);
178 total_dual_error_per_cell.resize(error_size);
179 }
180
181 for (std::size_t e = 0; e != error_size; ++e)
182 {
183 // Have we been asked to weight the variable error contributions in any specific manner
184 if (!error_norm_is_identity) // If we have
185 {
186 // Loop over variables
187 for (unsigned int v = 0; v < n_vars; v++)
188 {
189 // Now fill in total_dual_error ErrorMap with the weight
190 (*total_dual_errors_per_cell[std::make_pair(&_system, v)])[e] +=
191 static_cast<ErrorVectorReal>
192 (error_weight *
193 (*dual_errors_per_cell[std::make_pair(&_system, v)])[e]);
194 }
195 }
196 else // If not
197 {
198 total_dual_error_per_cell[e] +=
199 static_cast<ErrorVectorReal>(error_weight * dual_error_per_cell[e]);
200 }
201 }
202 }
203 }
204
205 // Do some debugging plots if requested
206 if (!error_plot_suffix.empty())
207 {
208 if (!error_norm_is_identity) // If we have
209 {
210 // Loop over variables
211 for (unsigned int v = 0; v < n_vars; v++)
212 {
213 std::ostringstream primal_out;
214 std::ostringstream dual_out;
215 primal_out << "primal_" << error_plot_suffix << ".";
216 dual_out << "dual_" << error_plot_suffix << ".";
217
218 primal_out << std::setw(1)
219 << std::setprecision(0)
220 << std::setfill('0')
221 << std::right
222 << v;
223
224 dual_out << std::setw(1)
225 << std::setprecision(0)
226 << std::setfill('0')
227 << std::right
228 << v;
229
230 primal_errors_per_cell[std::make_pair(&_system, v)]->plot_error(primal_out.str(), _system.get_mesh());
231 total_dual_errors_per_cell[std::make_pair(&_system, v)]->plot_error(dual_out.str(), _system.get_mesh());
232
233 primal_out.clear();
234 dual_out.clear();
235 }
236 }
237 else // If not
238 {
239 std::ostringstream primal_out;
240 std::ostringstream dual_out;
241 primal_out << "primal_" << error_plot_suffix ;
242 dual_out << "dual_" << error_plot_suffix ;
243
244 primal_error_per_cell.plot_error(primal_out.str(), _system.get_mesh());
245 total_dual_error_per_cell.plot_error(dual_out.str(), _system.get_mesh());
246
247 primal_out.clear();
248 dual_out.clear();
249 }
250 }
251
252 // Weight the primal error by the dual error using the system norm object
253 // FIXME: we ought to thread this
254 for (auto i : index_range(error_per_cell))
255 {
256 // Have we been asked to weight the variable error contributions in any specific manner
257 if (!error_norm_is_identity) // If we do
258 {
259 // Create Error Vectors to pass to calculate_norm
260 std::vector<Real> cell_primal_error;
261 std::vector<Real> cell_dual_error;
262
263 for (unsigned int v = 0; v < n_vars; v++)
264 {
265 cell_primal_error.push_back((*primal_errors_per_cell[std::make_pair(&_system, v)])[i]);
266 cell_dual_error.push_back((*total_dual_errors_per_cell[std::make_pair(&_system, v)])[i]);
267 }
268
269 error_per_cell[i] =
270 static_cast<ErrorVectorReal>
271 (error_norm.calculate_norm(cell_primal_error, cell_dual_error));
272 }
273 else // If not
274 {
275 error_per_cell[i] = primal_error_per_cell[i]*total_dual_error_per_cell[i];
276 }
277 }
278}
279
280} // namespace libMesh
unsigned int n_vars
virtual ErrorEstimatorType type() const override
std::unique_ptr< ErrorEstimator > _dual_error_estimator
An error estimator for the adjoint problem.
std::unique_ptr< ErrorEstimator > _primal_error_estimator
An error estimator for the forward problem.
std::string error_plot_suffix
To aid in investigating error estimator behavior, set this string to a suffix with which to plot (pre...
QoISet _qoi_set
A QoISet to handle cases with multiple QoIs available.
virtual void estimate_error(const System &system, ErrorVector &error_per_cell, const NumericVector< Number > *solution_vector=nullptr, bool estimate_parent_error=false) override
Compute the adjoint-weighted error on each element and place it in the error_per_cell vector.
This class holds functions that will estimate the error in a finite element solution on a given mesh.
SystemNorm error_norm
When estimating the error in a single system, the error_norm is used to control the scaling and norm ...
std::map< std::pair< const System *, unsigned int >, std::unique_ptr< ErrorVector > > ErrorMap
When calculating many error vectors at once, we need a data structure to hold them all.
The ErrorVector is a specialization of the StatisticsVector for error data computed on a finite eleme...
void plot_error(const std::string &filename, const MeshBase &mesh, const std::string &data_type="error") const
Plots a data file, of a type determined by looking at the file extension in filename,...
This is the MeshBase class.
Definition mesh_base.h:81
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
virtual numeric_index_type size() const =0
This class implements the Patch Recovery error indicator.
Data structure for specifying which Quantities of Interest should be calculated in an adjoint or a pa...
Definition qoi_set.h:46
Real weight(std::size_t) const
Get the weight for this index (default 1.0)
Definition qoi_set.h:243
bool has_index(std::size_t) const
Return whether or not this index is in the set to be calculated.
Definition qoi_set.h:224
Real calculate_norm(const std::vector< Real > &v)
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition system.h:100
virtual std::pair< unsigned int, Real > adjoint_solve(const QoISet &qoi_indices=QoISet())
Solves the adjoint system, for the specified qoi indices, or for every qoi if qoi_indices is nullptr.
Definition system.h:2586
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition system.h:1655
unsigned int n_qois() const
Number of currently active quantities of interest.
Definition system.h:2562
bool is_adjoint_already_solved() const
Accessor for the adjoint_already_solved boolean.
Definition system.h:411
unsigned int n_vars() const
Definition system.C:2674
NumericVector< Number > & get_adjoint_solution(unsigned int i=0)
Definition system.C:1232
const EquationSystems & get_equation_systems() const
Definition system.h:767
const MeshBase & get_mesh() const
Definition system.h:2401
MeshBase & mesh
The libMesh namespace provides an interface to certain functionality in the library.
DIE A HORRIBLE DEATH HERE typedef float ErrorVectorReal
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
ErrorEstimatorType
Defines an enum for the different types of error estimators which are available.
libmesh_assert(ctx)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real