$extrastylesheet
#include <adjoint_residual_error_estimator.h>

Public Types | |
| typedef std::map< std::pair < const System *, unsigned int > , ErrorVector * > | ErrorMap |
Public Member Functions | |
| AdjointResidualErrorEstimator () | |
| ~AdjointResidualErrorEstimator () | |
| UniquePtr< ErrorEstimator > & | primal_error_estimator () |
| UniquePtr< ErrorEstimator > & | dual_error_estimator () |
| QoISet & | qoi_set () |
| const QoISet & | qoi_set () const |
| void | estimate_error (const System &system, ErrorVector &error_per_cell, const NumericVector< Number > *solution_vector=NULL, bool estimate_parent_error=false) |
| virtual void | estimate_errors (const EquationSystems &equation_systems, ErrorVector &error_per_cell, const std::map< const System *, SystemNorm > &error_norms, const std::map< const System *, const NumericVector< Number > * > *solution_vectors=NULL, bool estimate_parent_error=false) |
| virtual void | estimate_errors (const EquationSystems &equation_systems, ErrorMap &errors_per_cell, const std::map< const System *, const NumericVector< Number > * > *solution_vectors=NULL, bool estimate_parent_error=false) |
Public Attributes | |
| std::string | error_plot_suffix |
| SystemNorm | error_norm |
Protected Member Functions | |
| void | reduce_error (std::vector< float > &error_per_cell, const Parallel::Communicator &comm LIBMESH_CAN_DEFAULT_TO_COMMWORLD) const |
Protected Attributes | |
| UniquePtr< ErrorEstimator > | _primal_error_estimator |
| UniquePtr< ErrorEstimator > | _dual_error_estimator |
| QoISet | _qoi_set |
This class implements a goal oriented error indicator, by weighting residual-based estimates from the primal problem against estimates from the adjoint problem.
This is based on a trick suggested by Brian Carnes, (first proposed by Babuska and Miller in 1984) but if it doesn't actually work then the misunderstanding or misimplementation will be the fault of Roy Stogner. It's also Roy's fault there's no literature reference here yet.
Definition at line 55 of file adjoint_residual_error_estimator.h.
typedef std::map<std::pair<const System*, unsigned int>, ErrorVector*> libMesh::ErrorEstimator::ErrorMap [inherited] |
When calculating many error vectors at once, we need a data structure to hold them all
Definition at line 110 of file error_estimator.h.
Constructor. Responsible for picking default subestimators.
Definition at line 40 of file adjoint_residual_error_estimator.C.
: ErrorEstimator(), error_plot_suffix(), _primal_error_estimator(new PatchRecoveryErrorEstimator()), _dual_error_estimator(new PatchRecoveryErrorEstimator()), _qoi_set(QoISet()) { }
| UniquePtr<ErrorEstimator>& libMesh::AdjointResidualErrorEstimator::dual_error_estimator | ( | ) | [inline] |
Access to the "subestimator" (default: PatchRecovery) to use on the dual/adjoint solution
Definition at line 79 of file adjoint_residual_error_estimator.h.
References _dual_error_estimator.
{ return _dual_error_estimator; }
| void libMesh::AdjointResidualErrorEstimator::estimate_error | ( | const System & | system, |
| ErrorVector & | error_per_cell, | ||
| const NumericVector< Number > * | solution_vector = NULL, |
||
| bool | estimate_parent_error = false |
||
| ) | [virtual] |
Compute the adjoint-weighted error on each element and place it in the error_per_cell vector. Note that this->error_norm is ignored; the error estimate is in the seminorm given by the absolute value of the error in the quantity of interest functional. The primal and dual subestimator error_norm values are used, and should be chosen appropriately for your model.
Implements libMesh::ErrorEstimator.
Definition at line 51 of file adjoint_residual_error_estimator.C.
References _dual_error_estimator, _primal_error_estimator, _qoi_set, libMesh::System::adjoint_solve(), libMesh::SystemNorm::calculate_norm(), libMesh::ErrorEstimator::error_norm, error_plot_suffix, libMesh::ErrorVectorReal, libMesh::System::get_adjoint_solution(), libMesh::System::get_equation_systems(), libMesh::System::get_mesh(), libMesh::QoISet::has_index(), libMesh::System::is_adjoint_already_solved(), libMesh::SystemNorm::is_identity(), libMesh::libmesh_assert(), libMesh::MeshBase::max_elem_id(), mesh, n_vars, libMesh::System::n_vars(), libMesh::ErrorVector::plot_error(), libMesh::System::qoi, libMesh::Real, libMesh::System::solution, libMesh::START_LOG(), and libMesh::QoISet::weight().
{
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 (!_system.is_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);
}
std::size_t 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 (std::size_t 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] +=
static_cast<ErrorVectorReal>
(error_weight *
(*dual_errors_per_cell[std::make_pair(&_system, v)])[e]);
}
}
else // If not
{
total_dual_error_per_cell[e] +=
static_cast<ErrorVectorReal>(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] =
static_cast<ErrorVectorReal>
(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");
}
| void libMesh::ErrorEstimator::estimate_errors | ( | const EquationSystems & | equation_systems, |
| ErrorVector & | error_per_cell, | ||
| const std::map< const System *, SystemNorm > & | error_norms, | ||
| const std::map< const System *, const NumericVector< Number > * > * | solution_vectors = NULL, |
||
| bool | estimate_parent_error = false |
||
| ) | [virtual, inherited] |
This virtual function can be redefined in derived classes, but by default computes the sum of the error_per_cell for each system in the equation_systems.
Currently this function ignores the error_norm member variable, and uses the function argument error_norms instead.
This function is named estimate_errors instead of estimate_error because otherwise C++ can get confused.
Reimplemented in libMesh::UniformRefinementEstimator.
Definition at line 48 of file error_estimator.C.
References libMesh::ErrorEstimator::error_norm, libMesh::ErrorEstimator::estimate_error(), libMesh::EquationSystems::get_system(), libMesh::EquationSystems::n_systems(), and libMesh::sys.
{
SystemNorm old_error_norm = this->error_norm;
// Sum the error values from each system
for (unsigned int s = 0; s != equation_systems.n_systems(); ++s)
{
ErrorVector system_error_per_cell;
const System &sys = equation_systems.get_system(s);
if (error_norms.find(&sys) == error_norms.end())
this->error_norm = old_error_norm;
else
this->error_norm = error_norms.find(&sys)->second;
const NumericVector<Number>* solution_vector = NULL;
if (solution_vectors &&
solution_vectors->find(&sys) != solution_vectors->end())
solution_vector = solution_vectors->find(&sys)->second;
this->estimate_error(sys, system_error_per_cell,
solution_vector, estimate_parent_error);
if (s)
{
libmesh_assert_equal_to (error_per_cell.size(), system_error_per_cell.size());
for (unsigned int i=0; i != error_per_cell.size(); ++i)
error_per_cell[i] += system_error_per_cell[i];
}
else
error_per_cell = system_error_per_cell;
}
// Restore our old state before returning
this->error_norm = old_error_norm;
}
| void libMesh::ErrorEstimator::estimate_errors | ( | const EquationSystems & | equation_systems, |
| ErrorMap & | errors_per_cell, | ||
| const std::map< const System *, const NumericVector< Number > * > * | solution_vectors = NULL, |
||
| bool | estimate_parent_error = false |
||
| ) | [virtual, inherited] |
This virtual function can be redefined in derived classes, but by default it calls estimate_error repeatedly to calculate the requested error vectors.
Currently this function ignores the error_norm.weight() values because it calculates each variable's error individually, unscaled.
The user selects which errors get computed by filling a map with error vectors: If errors_per_cell[&system][v] exists, it will be filled with the error values in variable v of system
FIXME: This is a default implementation - derived classes should reimplement it for efficiency.
Reimplemented in libMesh::UniformRefinementEstimator.
Definition at line 94 of file error_estimator.C.
References libMesh::ErrorEstimator::error_norm, libMesh::ErrorEstimator::estimate_error(), libMesh::EquationSystems::get_system(), libMesh::EquationSystems::n_systems(), n_vars, libMesh::System::n_vars(), libMesh::sys, and libMesh::SystemNorm::type().
{
SystemNorm old_error_norm = this->error_norm;
// Find the requested error values from each system
for (unsigned int s = 0; s != equation_systems.n_systems(); ++s)
{
const System &sys = equation_systems.get_system(s);
unsigned int n_vars = sys.n_vars();
for (unsigned int v = 0; v != n_vars; ++v)
{
// Only fill in ErrorVectors the user asks for
if (errors_per_cell.find(std::make_pair(&sys, v)) ==
errors_per_cell.end())
continue;
// Calculate error in only one variable
std::vector<Real> weights(n_vars, 0.0);
weights[v] = 1.0;
this->error_norm =
SystemNorm(std::vector<FEMNormType>(n_vars, old_error_norm.type(v)),
weights);
const NumericVector<Number>* solution_vector = NULL;
if (solution_vectors &&
solution_vectors->find(&sys) != solution_vectors->end())
solution_vector = solution_vectors->find(&sys)->second;
this->estimate_error
(sys, *errors_per_cell[std::make_pair(&sys, v)],
solution_vector, estimate_parent_error);
}
}
// Restore our old state before returning
this->error_norm = old_error_norm;
}
| UniquePtr<ErrorEstimator>& libMesh::AdjointResidualErrorEstimator::primal_error_estimator | ( | ) | [inline] |
Access to the "subestimator" (default: PatchRecovery) to use on the primal/forward solution
Definition at line 73 of file adjoint_residual_error_estimator.h.
References _primal_error_estimator.
{ return _primal_error_estimator; }
| QoISet& libMesh::AdjointResidualErrorEstimator::qoi_set | ( | ) | [inline] |
Access to the QoISet (default: weight all QoIs equally) to use when computing errors
Definition at line 85 of file adjoint_residual_error_estimator.h.
References _qoi_set.
{ return _qoi_set; }
| const QoISet& libMesh::AdjointResidualErrorEstimator::qoi_set | ( | ) | const [inline] |
Access to the QoISet (default: weight all QoIs equally) to use when computing errors
Definition at line 91 of file adjoint_residual_error_estimator.h.
References _qoi_set.
{ return _qoi_set; }
| void libMesh::ErrorEstimator::reduce_error | ( | std::vector< float > & | error_per_cell, |
| const Parallel::Communicator &comm | LIBMESH_CAN_DEFAULT_TO_COMMWORLD | ||
| ) | const [protected, inherited] |
This method takes the local error contributions in error_per_cell from each processor and combines them to get the global error vector.
Definition at line 33 of file error_estimator.C.
References libMesh::Parallel::Communicator::sum().
Referenced by libMesh::UniformRefinementEstimator::_estimate_error(), libMesh::WeightedPatchRecoveryErrorEstimator::estimate_error(), libMesh::PatchRecoveryErrorEstimator::estimate_error(), libMesh::JumpErrorEstimator::estimate_error(), and libMesh::AdjointRefinementEstimator::estimate_error().
{
// This function must be run on all processors at once
// parallel_object_only();
// Each processor has now computed the error contribuions
// for its local elements. We may need to sum the vector to
// recover the error for each element.
comm.sum(error_per_cell);
}
UniquePtr<ErrorEstimator> libMesh::AdjointResidualErrorEstimator::_dual_error_estimator [protected] |
An error estimator for the adjoint problem
Definition at line 125 of file adjoint_residual_error_estimator.h.
Referenced by dual_error_estimator(), and estimate_error().
UniquePtr<ErrorEstimator> libMesh::AdjointResidualErrorEstimator::_primal_error_estimator [protected] |
An error estimator for the forward problem
Definition at line 120 of file adjoint_residual_error_estimator.h.
Referenced by estimate_error(), and primal_error_estimator().
A QoISet to handle cases with multiple QoIs available
Definition at line 130 of file adjoint_residual_error_estimator.h.
Referenced by estimate_error(), and qoi_set().
SystemNorm libMesh::ErrorEstimator::error_norm [inherited] |
When estimating the error in a single system, the error_norm is used to control the scaling and norm choice for each variable. Not all estimators will support all norm choices. The default scaling is for all variables to be weighted equally. The default norm choice depends on the error estimator.
Part of this functionality was supported via component_scale and sobolev_order in older libMesh versions, and a small part was supported via component_mask in even older versions. Hopefully the encapsulation here will allow us to avoid changing this API again.
Definition at line 142 of file error_estimator.h.
Referenced by libMesh::UniformRefinementEstimator::_estimate_error(), libMesh::AdjointRefinementEstimator::AdjointRefinementEstimator(), libMesh::DiscontinuityMeasure::boundary_side_integration(), libMesh::KellyErrorEstimator::boundary_side_integration(), libMesh::DiscontinuityMeasure::DiscontinuityMeasure(), libMesh::JumpErrorEstimator::estimate_error(), estimate_error(), libMesh::ErrorEstimator::estimate_errors(), libMesh::ExactErrorEstimator::ExactErrorEstimator(), libMesh::ExactErrorEstimator::find_squared_element_error(), libMesh::LaplacianErrorEstimator::internal_side_integration(), libMesh::DiscontinuityMeasure::internal_side_integration(), libMesh::KellyErrorEstimator::internal_side_integration(), libMesh::KellyErrorEstimator::KellyErrorEstimator(), libMesh::LaplacianErrorEstimator::LaplacianErrorEstimator(), libMesh::WeightedPatchRecoveryErrorEstimator::EstimateError::operator()(), libMesh::PatchRecoveryErrorEstimator::EstimateError::operator()(), libMesh::PatchRecoveryErrorEstimator::PatchRecoveryErrorEstimator(), and libMesh::UniformRefinementEstimator::UniformRefinementEstimator().
To aid in investigating error estimator behavior, set this string to a suffix with which to plot (prefixed by "primal_" or "dual_") the subestimator results. The suffix should end with a file extension (e.g. ".gmv") that the ErrorVector::plot_error recognizes.
Definition at line 100 of file adjoint_residual_error_estimator.h.
Referenced by estimate_error().