-
Notifications
You must be signed in to change notification settings - Fork 285
/
adjoint_residual_error_estimator.C
276 lines (236 loc) · 9.57 KB
/
adjoint_residual_error_estimator.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// C++ includes
#include <iostream>
#include <iomanip>
// Local Includes
#include "libmesh/adjoint_residual_error_estimator.h"
#include "libmesh/error_vector.h"
#include "libmesh/patch_recovery_error_estimator.h"
#include "libmesh/libmesh_logging.h"
#include "libmesh/numeric_vector.h"
#include "libmesh/system.h"
#include "libmesh/system_norm.h"
#include "libmesh/qoi_set.h"
namespace libMesh
{
//-----------------------------------------------------------------
// AdjointResidualErrorEstimator implementations
AdjointResidualErrorEstimator::AdjointResidualErrorEstimator () :
adjoint_already_solved(false),
error_plot_suffix(),
_primal_error_estimator(new PatchRecoveryErrorEstimator()),
_dual_error_estimator(new PatchRecoveryErrorEstimator()),
_qoi_set(QoISet())
{
}
void AdjointResidualErrorEstimator::estimate_error (const System& _system,
ErrorVector& error_per_cell,
const NumericVector<Number>* solution_vector,
bool estimate_parent_error)
{
START_LOG("estimate_error()", "AdjointResidualErrorEstimator");
// The current mesh
const MeshBase& mesh = _system.get_mesh();
// Resize the error_per_cell vector to be
// the number of elements, initialize it to 0.
error_per_cell.resize (mesh.max_elem_id());
std::fill (error_per_cell.begin(), error_per_cell.end(), 0.);
// Get the number of variables in the system
unsigned int n_vars = _system.n_vars();
// We need to make a map of the pointer to the solution vector
std::map<const System*, const NumericVector<Number>*>solutionvecs;
solutionvecs[&_system] = _system.solution.get();
// Solve the dual problem if we have to
if (!adjoint_already_solved)
{
// FIXME - we'll need to change a lot of APIs to make this trick
// work with a const System...
System& system = const_cast<System&>(_system);
system.adjoint_solve(_qoi_set);
}
// Flag to check whether we have not been asked to weight the variable error contributions in any specific manner
bool error_norm_is_identity = error_norm.is_identity();
// Create an ErrorMap/ErrorVector to store the primal, dual and total_dual variable errors
ErrorMap primal_errors_per_cell;
ErrorMap dual_errors_per_cell;
ErrorMap total_dual_errors_per_cell;
// Allocate ErrorVectors to this map if we're going to use it
if (!error_norm_is_identity)
for(unsigned int v = 0; v < n_vars; v++)
{
primal_errors_per_cell[std::make_pair(&_system, v)] = new ErrorVector;
dual_errors_per_cell[std::make_pair(&_system, v)] = new ErrorVector;
total_dual_errors_per_cell[std::make_pair(&_system, v)] = new ErrorVector;
}
ErrorVector primal_error_per_cell;
ErrorVector dual_error_per_cell;
ErrorVector total_dual_error_per_cell;
// Have we been asked to weight the variable error contributions in any specific manner
if(!error_norm_is_identity) // If we do
{
// Estimate the primal problem error for each variable
_primal_error_estimator->estimate_errors
(_system.get_equation_systems(), primal_errors_per_cell, &solutionvecs, estimate_parent_error);
}
else // If not
{
// Just get the combined error estimate
_primal_error_estimator->estimate_error
(_system, primal_error_per_cell, solution_vector, estimate_parent_error);
}
// Sum and weight the dual error estimate based on our QoISet
for (unsigned int i = 0; i != _system.qoi.size(); ++i)
{
if (_qoi_set.has_index(i))
{
// Get the weight for the current QoI
Real error_weight = _qoi_set.weight(i);
// We need to make a map of the pointer to the adjoint solution vector
std::map<const System*, const NumericVector<Number>*>adjointsolutionvecs;
adjointsolutionvecs[&_system] = &_system.get_adjoint_solution(i);
// Have we been asked to weight the variable error contributions in any specific manner
if(!error_norm_is_identity) // If we have
{
_dual_error_estimator->estimate_errors
(_system.get_equation_systems(), dual_errors_per_cell, &adjointsolutionvecs,
estimate_parent_error);
}
else // If not
{
// Just get the combined error estimate
_dual_error_estimator->estimate_error
(_system, dual_error_per_cell, &(_system.get_adjoint_solution(i)), estimate_parent_error);
}
unsigned int error_size;
// Get the size of the first ErrorMap vector; this will give us the number of elements
if(!error_norm_is_identity) // If in non default weights case
{
error_size = dual_errors_per_cell[std::make_pair(&_system, 0)]->size();
}
else // If in the standard default weights case
{
error_size = dual_error_per_cell.size();
}
// Resize the ErrorVector(s)
if(!error_norm_is_identity)
{
// Loop over variables
for(unsigned int v = 0; v < n_vars; v++)
{
libmesh_assert(!total_dual_errors_per_cell[std::make_pair(&_system, v)]->size() ||
total_dual_errors_per_cell[std::make_pair(&_system, v)]->size() == error_size) ;
total_dual_errors_per_cell[std::make_pair(&_system, v)]->resize(error_size);
}
}
else
{
libmesh_assert(!total_dual_error_per_cell.size() ||
total_dual_error_per_cell.size() == error_size);
total_dual_error_per_cell.resize(error_size);
}
for (unsigned int e = 0; e != error_size; ++e)
{
// Have we been asked to weight the variable error contributions in any specific manner
if(!error_norm_is_identity) // If we have
{
// Loop over variables
for(unsigned int v = 0; v < n_vars; v++)
{
// Now fill in total_dual_error ErrorMap with the weight
(*total_dual_errors_per_cell[std::make_pair(&_system, v)])[e] +=
error_weight * (*dual_errors_per_cell[std::make_pair(&_system, v)])[e];
}
}
else // If not
{
total_dual_error_per_cell[e] +=
error_weight * dual_error_per_cell[e];
}
}
}
}
// Do some debugging plots if requested
if (!error_plot_suffix.empty())
{
if(!error_norm_is_identity) // If we have
{
// Loop over variables
for(unsigned int v = 0; v < n_vars; v++)
{
std::ostringstream primal_out;
std::ostringstream dual_out;
primal_out << "primal_" << error_plot_suffix << ".";
dual_out << "dual_" << error_plot_suffix << ".";
primal_out << std::setw(1)
<< std::setprecision(0)
<< std::setfill('0')
<< std::right
<< v;
dual_out << std::setw(1)
<< std::setprecision(0)
<< std::setfill('0')
<< std::right
<< v;
(*primal_errors_per_cell[std::make_pair(&_system, v)]).plot_error(primal_out.str(), _system.get_mesh());
(*total_dual_errors_per_cell[std::make_pair(&_system, v)]).plot_error(dual_out.str(), _system.get_mesh());
primal_out.clear();
dual_out.clear();
}
}
else // If not
{
std::ostringstream primal_out;
std::ostringstream dual_out;
primal_out << "primal_" << error_plot_suffix ;
dual_out << "dual_" << error_plot_suffix ;
primal_error_per_cell.plot_error(primal_out.str(), _system.get_mesh());
total_dual_error_per_cell.plot_error(dual_out.str(), _system.get_mesh());
primal_out.clear();
dual_out.clear();
}
}
// Weight the primal error by the dual error using the system norm object
// FIXME: we ought to thread this
for (unsigned int i=0; i != error_per_cell.size(); ++i)
{
// Have we been asked to weight the variable error contributions in any specific manner
if(!error_norm_is_identity) // If we do
{
// Create Error Vectors to pass to calculate_norm
std::vector<Real> cell_primal_error;
std::vector<Real> cell_dual_error;
for(unsigned int v = 0; v < n_vars; v++)
{
cell_primal_error.push_back((*primal_errors_per_cell[std::make_pair(&_system, v)])[i]);
cell_dual_error.push_back((*total_dual_errors_per_cell[std::make_pair(&_system, v)])[i]);
}
error_per_cell[i] = error_norm.calculate_norm(cell_primal_error, cell_dual_error);
}
else // If not
{
error_per_cell[i] = primal_error_per_cell[i]*total_dual_error_per_cell[i];
}
}
// Deallocate the ErrorMap contents if we allocated them earlier
if (!error_norm_is_identity)
for(unsigned int v = 0; v < n_vars; v++)
{
delete primal_errors_per_cell[std::make_pair(&_system, v)];
delete dual_errors_per_cell[std::make_pair(&_system, v)];
delete total_dual_errors_per_cell[std::make_pair(&_system, v)];
}
STOP_LOG("estimate_error()", "AdjointResidualErrorEstimator");
}
} // namespace libMesh