adjoint_residual_error_estimator.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2018 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
21 #include "libmesh/error_vector.h"
24 #include "libmesh/numeric_vector.h"
25 #include "libmesh/system.h"
26 #include "libmesh/system_norm.h"
27 #include "libmesh/qoi_set.h"
29 #include "libmesh/int_range.h"
30 
31 // C++ includes
32 #include <iostream>
33 #include <iomanip>
34 #include <sstream>
35 
36 namespace libMesh
37 {
38 
39 //-----------------------------------------------------------------
40 // AdjointResidualErrorEstimator implementations
43  error_plot_suffix(),
44  _primal_error_estimator(new PatchRecoveryErrorEstimator()),
45  _dual_error_estimator(new PatchRecoveryErrorEstimator()),
46  _qoi_set(QoISet())
47 {
48 }
49 
50 
51 
54 {
55  return ADJOINT_RESIDUAL;
56 }
57 
58 
59 
61  ErrorVector & error_per_cell,
62  const NumericVector<Number> * solution_vector,
63  bool estimate_parent_error)
64 {
65  LOG_SCOPE("estimate_error()", "AdjointResidualErrorEstimator");
66 
67  // The current mesh
68  const MeshBase & mesh = _system.get_mesh();
69 
70  // Resize the error_per_cell vector to be
71  // the number of elements, initialize it to 0.
72  error_per_cell.resize (mesh.max_elem_id());
73  std::fill (error_per_cell.begin(), error_per_cell.end(), 0.);
74 
75  // Get the number of variables in the system
76  unsigned int n_vars = _system.n_vars();
77 
78  // We need to make a map of the pointer to the solution vector
79  std::map<const System *, const NumericVector<Number> *>solutionvecs;
80  solutionvecs[&_system] = _system.solution.get();
81 
82  // Solve the dual problem if we have to
83  if (!_system.is_adjoint_already_solved())
84  {
85  // FIXME - we'll need to change a lot of APIs to make this trick
86  // work with a const System...
87  System & system = const_cast<System &>(_system);
88  system.adjoint_solve(_qoi_set);
89  }
90 
91  // Flag to check whether we have not been asked to weight the variable error contributions in any specific manner
92  bool error_norm_is_identity = error_norm.is_identity();
93 
94  // Create an ErrorMap/ErrorVector to store the primal, dual and total_dual variable errors
95  ErrorMap primal_errors_per_cell;
96  ErrorMap dual_errors_per_cell;
97  ErrorMap total_dual_errors_per_cell;
98  // Allocate ErrorVectors to this map if we're going to use it
99  if (!error_norm_is_identity)
100  for (unsigned int v = 0; v < n_vars; v++)
101  {
102  primal_errors_per_cell[std::make_pair(&_system, v)] = new ErrorVector;
103  dual_errors_per_cell[std::make_pair(&_system, v)] = new ErrorVector;
104  total_dual_errors_per_cell[std::make_pair(&_system, v)] = new ErrorVector;
105  }
106  ErrorVector primal_error_per_cell;
107  ErrorVector dual_error_per_cell;
108  ErrorVector total_dual_error_per_cell;
109 
110  // Have we been asked to weight the variable error contributions in any specific manner
111  if (!error_norm_is_identity) // If we do
112  {
113  // Estimate the primal problem error for each variable
114  _primal_error_estimator->estimate_errors
115  (_system.get_equation_systems(), primal_errors_per_cell, &solutionvecs, estimate_parent_error);
116  }
117  else // If not
118  {
119  // Just get the combined error estimate
120  _primal_error_estimator->estimate_error
121  (_system, primal_error_per_cell, solution_vector, estimate_parent_error);
122  }
123 
124  // Sum and weight the dual error estimate based on our QoISet
125  for (unsigned int i = 0, n_qois = _system.n_qois(); i != n_qois; ++i)
126  {
127  if (_qoi_set.has_index(i))
128  {
129  // Get the weight for the current QoI
130  Real error_weight = _qoi_set.weight(i);
131 
132  // We need to make a map of the pointer to the adjoint solution vector
133  std::map<const System *, const NumericVector<Number> *>adjointsolutionvecs;
134  adjointsolutionvecs[&_system] = &_system.get_adjoint_solution(i);
135 
136  // Have we been asked to weight the variable error contributions in any specific manner
137  if (!error_norm_is_identity) // If we have
138  {
139  _dual_error_estimator->estimate_errors
140  (_system.get_equation_systems(), dual_errors_per_cell, &adjointsolutionvecs,
141  estimate_parent_error);
142  }
143  else // If not
144  {
145  // Just get the combined error estimate
146  _dual_error_estimator->estimate_error
147  (_system, dual_error_per_cell, &(_system.get_adjoint_solution(i)), estimate_parent_error);
148  }
149 
150  std::size_t error_size;
151 
152  // Get the size of the first ErrorMap vector; this will give us the number of elements
153  if (!error_norm_is_identity) // If in non default weights case
154  {
155  error_size = dual_errors_per_cell[std::make_pair(&_system, 0)]->size();
156  }
157  else // If in the standard default weights case
158  {
159  error_size = dual_error_per_cell.size();
160  }
161 
162  // Resize the ErrorVector(s)
163  if (!error_norm_is_identity)
164  {
165  // Loop over variables
166  for (unsigned int v = 0; v < n_vars; v++)
167  {
168  libmesh_assert(!total_dual_errors_per_cell[std::make_pair(&_system, v)]->size() ||
169  total_dual_errors_per_cell[std::make_pair(&_system, v)]->size() == error_size) ;
170  total_dual_errors_per_cell[std::make_pair(&_system, v)]->resize(error_size);
171  }
172  }
173  else
174  {
175  libmesh_assert(!total_dual_error_per_cell.size() ||
176  total_dual_error_per_cell.size() == error_size);
177  total_dual_error_per_cell.resize(error_size);
178  }
179 
180  for (std::size_t e = 0; e != error_size; ++e)
181  {
182  // Have we been asked to weight the variable error contributions in any specific manner
183  if (!error_norm_is_identity) // If we have
184  {
185  // Loop over variables
186  for (unsigned int v = 0; v < n_vars; v++)
187  {
188  // Now fill in total_dual_error ErrorMap with the weight
189  (*total_dual_errors_per_cell[std::make_pair(&_system, v)])[e] +=
190  static_cast<ErrorVectorReal>
191  (error_weight *
192  (*dual_errors_per_cell[std::make_pair(&_system, v)])[e]);
193  }
194  }
195  else // If not
196  {
197  total_dual_error_per_cell[e] +=
198  static_cast<ErrorVectorReal>(error_weight * dual_error_per_cell[e]);
199  }
200  }
201  }
202  }
203 
204  // Do some debugging plots if requested
205  if (!error_plot_suffix.empty())
206  {
207  if (!error_norm_is_identity) // If we have
208  {
209  // Loop over variables
210  for (unsigned int v = 0; v < n_vars; v++)
211  {
212  std::ostringstream primal_out;
213  std::ostringstream dual_out;
214  primal_out << "primal_" << error_plot_suffix << ".";
215  dual_out << "dual_" << error_plot_suffix << ".";
216 
217  primal_out << std::setw(1)
218  << std::setprecision(0)
219  << std::setfill('0')
220  << std::right
221  << v;
222 
223  dual_out << std::setw(1)
224  << std::setprecision(0)
225  << std::setfill('0')
226  << std::right
227  << v;
228 
229  (*primal_errors_per_cell[std::make_pair(&_system, v)]).plot_error(primal_out.str(), _system.get_mesh());
230  (*total_dual_errors_per_cell[std::make_pair(&_system, v)]).plot_error(dual_out.str(), _system.get_mesh());
231 
232  primal_out.clear();
233  dual_out.clear();
234  }
235  }
236  else // If not
237  {
238  std::ostringstream primal_out;
239  std::ostringstream dual_out;
240  primal_out << "primal_" << error_plot_suffix ;
241  dual_out << "dual_" << error_plot_suffix ;
242 
243  primal_error_per_cell.plot_error(primal_out.str(), _system.get_mesh());
244  total_dual_error_per_cell.plot_error(dual_out.str(), _system.get_mesh());
245 
246  primal_out.clear();
247  dual_out.clear();
248  }
249  }
250 
251  // Weight the primal error by the dual error using the system norm object
252  // FIXME: we ought to thread this
253  for (auto i : index_range(error_per_cell))
254  {
255  // Have we been asked to weight the variable error contributions in any specific manner
256  if (!error_norm_is_identity) // If we do
257  {
258  // Create Error Vectors to pass to calculate_norm
259  std::vector<Real> cell_primal_error;
260  std::vector<Real> cell_dual_error;
261 
262  for (unsigned int v = 0; v < n_vars; v++)
263  {
264  cell_primal_error.push_back((*primal_errors_per_cell[std::make_pair(&_system, v)])[i]);
265  cell_dual_error.push_back((*total_dual_errors_per_cell[std::make_pair(&_system, v)])[i]);
266  }
267 
268  error_per_cell[i] =
269  static_cast<ErrorVectorReal>
270  (error_norm.calculate_norm(cell_primal_error, cell_dual_error));
271  }
272  else // If not
273  {
274  error_per_cell[i] = primal_error_per_cell[i]*total_dual_error_per_cell[i];
275  }
276  }
277 
278  // Deallocate the ErrorMap contents if we allocated them earlier
279  if (!error_norm_is_identity)
280  for (unsigned int v = 0; v < n_vars; v++)
281  {
282  delete primal_errors_per_cell[std::make_pair(&_system, v)];
283  delete dual_errors_per_cell[std::make_pair(&_system, v)];
284  delete total_dual_errors_per_cell[std::make_pair(&_system, v)];
285  }
286 }
287 
288 } // namespace libMesh
Used to specify quantities of interest in a simulation.
Definition: qoi_set.h:45
unsigned int n_qois() const
Definition: system.h:2278
const EquationSystems & get_equation_systems() const
Definition: system.h:712
MeshBase & mesh
IntRange< std::size_t > index_range(const std::vector< T > &vec)
Definition: int_range.h:104
const unsigned int n_vars
Definition: tecplot_io.C:69
const MeshBase & get_mesh() const
Definition: system.h:2033
DIE A HORRIBLE DEATH HERE typedef float ErrorVectorReal
Base class for Mesh.
Definition: mesh_base.h:77
bool has_index(std::size_t) const
Definition: qoi_set.h:221
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:92
std::unique_ptr< NumericVector< Number > > solution
Definition: system.h:1523
virtual std::pair< unsigned int, Real > adjoint_solve(const QoISet &qoi_indices=QoISet())
Definition: system.h:2300
std::map< std::pair< const System *, unsigned int >, ErrorVector * > ErrorMap
void plot_error(const std::string &filename, const MeshBase &mesh) const
Definition: error_vector.C:210
std::unique_ptr< ErrorEstimator > _dual_error_estimator
bool is_adjoint_already_solved() const
Definition: system.h:388
Real weight(std::size_t) const
Definition: qoi_set.h:240
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Real calculate_norm(const std::vector< Real > &v)
Definition: system_norm.C:230
std::unique_ptr< ErrorEstimator > _primal_error_estimator
NumericVector< Number > & get_adjoint_solution(unsigned int i=0)
Definition: system.C:969
unsigned int n_vars() const
Definition: system.h:2105
virtual void estimate_error(const System &system, ErrorVector &error_per_cell, const NumericVector< Number > *solution_vector=nullptr, bool estimate_parent_error=false) override
virtual ErrorEstimatorType type() const override