$extrastylesheet
adjoint_residual_error_estimator.C
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00003 
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 
00019 // C++ includes
00020 #include <iostream>
00021 #include <iomanip>
00022 #include <sstream>
00023 
00024 // Local Includes
00025 #include "libmesh/adjoint_residual_error_estimator.h"
00026 #include "libmesh/error_vector.h"
00027 #include "libmesh/patch_recovery_error_estimator.h"
00028 #include "libmesh/libmesh_logging.h"
00029 #include "libmesh/numeric_vector.h"
00030 #include "libmesh/system.h"
00031 #include "libmesh/system_norm.h"
00032 #include "libmesh/qoi_set.h"
00033 
00034 
00035 namespace libMesh
00036 {
00037 
00038 //-----------------------------------------------------------------
00039 // AdjointResidualErrorEstimator implementations
00040 AdjointResidualErrorEstimator::AdjointResidualErrorEstimator () :
00041   ErrorEstimator(),
00042   error_plot_suffix(),
00043   _primal_error_estimator(new PatchRecoveryErrorEstimator()),
00044   _dual_error_estimator(new PatchRecoveryErrorEstimator()),
00045   _qoi_set(QoISet())
00046 {
00047 }
00048 
00049 
00050 
00051 void AdjointResidualErrorEstimator::estimate_error (const System& _system,
00052                                                     ErrorVector& error_per_cell,
00053                                                     const NumericVector<Number>* solution_vector,
00054                                                     bool estimate_parent_error)
00055 {
00056   START_LOG("estimate_error()", "AdjointResidualErrorEstimator");
00057 
00058   // The current mesh
00059   const MeshBase& mesh = _system.get_mesh();
00060 
00061   // Resize the error_per_cell vector to be
00062   // the number of elements, initialize it to 0.
00063   error_per_cell.resize (mesh.max_elem_id());
00064   std::fill (error_per_cell.begin(), error_per_cell.end(), 0.);
00065 
00066   // Get the number of variables in the system
00067   unsigned int n_vars = _system.n_vars();
00068 
00069   // We need to make a map of the pointer to the solution vector
00070   std::map<const System*, const NumericVector<Number>*>solutionvecs;
00071   solutionvecs[&_system] = _system.solution.get();
00072 
00073   // Solve the dual problem if we have to
00074   if (!_system.is_adjoint_already_solved())
00075     {
00076       // FIXME - we'll need to change a lot of APIs to make this trick
00077       // work with a const System...
00078       System&  system = const_cast<System&>(_system);
00079       system.adjoint_solve(_qoi_set);
00080     }
00081 
00082   // Flag to check whether we have not been asked to weight the variable error contributions in any specific manner
00083   bool error_norm_is_identity = error_norm.is_identity();
00084 
00085   // Create an ErrorMap/ErrorVector to store the primal, dual and total_dual variable errors
00086   ErrorMap primal_errors_per_cell;
00087   ErrorMap dual_errors_per_cell;
00088   ErrorMap total_dual_errors_per_cell;
00089   // Allocate ErrorVectors to this map if we're going to use it
00090   if (!error_norm_is_identity)
00091     for(unsigned int v = 0; v < n_vars; v++)
00092       {
00093         primal_errors_per_cell[std::make_pair(&_system, v)] = new ErrorVector;
00094         dual_errors_per_cell[std::make_pair(&_system, v)] = new ErrorVector;
00095         total_dual_errors_per_cell[std::make_pair(&_system, v)] = new ErrorVector;
00096       }
00097   ErrorVector primal_error_per_cell;
00098   ErrorVector dual_error_per_cell;
00099   ErrorVector total_dual_error_per_cell;
00100 
00101   // Have we been asked to weight the variable error contributions in any specific manner
00102   if(!error_norm_is_identity) // If we do
00103     {
00104       // Estimate the primal problem error for each variable
00105       _primal_error_estimator->estimate_errors
00106         (_system.get_equation_systems(), primal_errors_per_cell, &solutionvecs, estimate_parent_error);
00107     }
00108   else // If not
00109     {
00110       // Just get the combined error estimate
00111       _primal_error_estimator->estimate_error
00112         (_system, primal_error_per_cell, solution_vector, estimate_parent_error);
00113     }
00114 
00115   // Sum and weight the dual error estimate based on our QoISet
00116   for (unsigned int i = 0; i != _system.qoi.size(); ++i)
00117     {
00118       if (_qoi_set.has_index(i))
00119         {
00120           // Get the weight for the current QoI
00121           Real error_weight = _qoi_set.weight(i);
00122 
00123           // We need to make a map of the pointer to the adjoint solution vector
00124           std::map<const System*, const NumericVector<Number>*>adjointsolutionvecs;
00125           adjointsolutionvecs[&_system] = &_system.get_adjoint_solution(i);
00126 
00127           // Have we been asked to weight the variable error contributions in any specific manner
00128           if(!error_norm_is_identity) // If we have
00129             {
00130               _dual_error_estimator->estimate_errors
00131                 (_system.get_equation_systems(), dual_errors_per_cell, &adjointsolutionvecs,
00132                  estimate_parent_error);
00133             }
00134           else // If not
00135             {
00136               // Just get the combined error estimate
00137               _dual_error_estimator->estimate_error
00138                 (_system, dual_error_per_cell, &(_system.get_adjoint_solution(i)), estimate_parent_error);
00139             }
00140 
00141           std::size_t error_size;
00142 
00143           // Get the size of the first ErrorMap vector; this will give us the number of elements
00144           if(!error_norm_is_identity) // If in non default weights case
00145             {
00146               error_size = dual_errors_per_cell[std::make_pair(&_system, 0)]->size();
00147             }
00148           else // If in the standard default weights case
00149             {
00150               error_size = dual_error_per_cell.size();
00151             }
00152 
00153           // Resize the ErrorVector(s)
00154           if(!error_norm_is_identity)
00155             {
00156               // Loop over variables
00157               for(unsigned int v = 0; v < n_vars; v++)
00158                 {
00159                   libmesh_assert(!total_dual_errors_per_cell[std::make_pair(&_system, v)]->size() ||
00160                                  total_dual_errors_per_cell[std::make_pair(&_system, v)]->size() == error_size) ;
00161                   total_dual_errors_per_cell[std::make_pair(&_system, v)]->resize(error_size);
00162                 }
00163             }
00164           else
00165             {
00166               libmesh_assert(!total_dual_error_per_cell.size() ||
00167                              total_dual_error_per_cell.size() == error_size);
00168               total_dual_error_per_cell.resize(error_size);
00169             }
00170 
00171           for (std::size_t e = 0; e != error_size; ++e)
00172             {
00173               // Have we been asked to weight the variable error contributions in any specific manner
00174               if(!error_norm_is_identity) // If we have
00175                 {
00176                   // Loop over variables
00177                   for(unsigned int v = 0; v < n_vars; v++)
00178                     {
00179                       // Now fill in total_dual_error ErrorMap with the weight
00180                       (*total_dual_errors_per_cell[std::make_pair(&_system, v)])[e] +=
00181                         static_cast<ErrorVectorReal>
00182                         (error_weight *
00183                          (*dual_errors_per_cell[std::make_pair(&_system, v)])[e]);
00184                     }
00185                 }
00186               else // If not
00187                 {
00188                   total_dual_error_per_cell[e] +=
00189                     static_cast<ErrorVectorReal>(error_weight * dual_error_per_cell[e]);
00190                 }
00191             }
00192         }
00193     }
00194 
00195   // Do some debugging plots if requested
00196   if (!error_plot_suffix.empty())
00197     {
00198       if(!error_norm_is_identity) // If we have
00199         {
00200           // Loop over variables
00201           for(unsigned int v = 0; v < n_vars; v++)
00202             {
00203               std::ostringstream primal_out;
00204               std::ostringstream dual_out;
00205               primal_out << "primal_" << error_plot_suffix << ".";
00206               dual_out << "dual_" << error_plot_suffix << ".";
00207 
00208               primal_out << std::setw(1)
00209                          << std::setprecision(0)
00210                          << std::setfill('0')
00211                          << std::right
00212                          << v;
00213 
00214               dual_out << std::setw(1)
00215                        << std::setprecision(0)
00216                        << std::setfill('0')
00217                        << std::right
00218                        << v;
00219 
00220               (*primal_errors_per_cell[std::make_pair(&_system, v)]).plot_error(primal_out.str(), _system.get_mesh());
00221               (*total_dual_errors_per_cell[std::make_pair(&_system, v)]).plot_error(dual_out.str(), _system.get_mesh());
00222 
00223               primal_out.clear();
00224               dual_out.clear();
00225             }
00226         }
00227       else // If not
00228         {
00229           std::ostringstream primal_out;
00230           std::ostringstream dual_out;
00231           primal_out << "primal_" << error_plot_suffix ;
00232           dual_out << "dual_" << error_plot_suffix ;
00233 
00234           primal_error_per_cell.plot_error(primal_out.str(), _system.get_mesh());
00235           total_dual_error_per_cell.plot_error(dual_out.str(), _system.get_mesh());
00236 
00237           primal_out.clear();
00238           dual_out.clear();
00239         }
00240     }
00241 
00242   // Weight the primal error by the dual error using the system norm object
00243   // FIXME: we ought to thread this
00244   for (unsigned int i=0; i != error_per_cell.size(); ++i)
00245     {
00246       // Have we been asked to weight the variable error contributions in any specific manner
00247       if(!error_norm_is_identity) // If we do
00248         {
00249           // Create Error Vectors to pass to calculate_norm
00250           std::vector<Real> cell_primal_error;
00251           std::vector<Real> cell_dual_error;
00252 
00253           for(unsigned int v = 0; v < n_vars; v++)
00254             {
00255               cell_primal_error.push_back((*primal_errors_per_cell[std::make_pair(&_system, v)])[i]);
00256               cell_dual_error.push_back((*total_dual_errors_per_cell[std::make_pair(&_system, v)])[i]);
00257             }
00258 
00259           error_per_cell[i] =
00260             static_cast<ErrorVectorReal>
00261             (error_norm.calculate_norm(cell_primal_error, cell_dual_error));
00262         }
00263       else // If not
00264         {
00265           error_per_cell[i] = primal_error_per_cell[i]*total_dual_error_per_cell[i];
00266         }
00267     }
00268 
00269   // Deallocate the ErrorMap contents if we allocated them earlier
00270   if (!error_norm_is_identity)
00271     for(unsigned int v = 0; v < n_vars; v++)
00272       {
00273         delete primal_errors_per_cell[std::make_pair(&_system, v)];
00274         delete dual_errors_per_cell[std::make_pair(&_system, v)];
00275         delete total_dual_errors_per_cell[std::make_pair(&_system, v)];
00276       }
00277 
00278   STOP_LOG("estimate_error()", "AdjointResidualErrorEstimator");
00279 }
00280 
00281 } // namespace libMesh