$extrastylesheet
exact_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 <algorithm> // for std::fill
00021 #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
00022 #include <cmath>    // for sqrt
00023 
00024 
00025 // Local Includes
00026 #include "libmesh/libmesh_common.h"
00027 #include "libmesh/exact_error_estimator.h"
00028 #include "libmesh/dof_map.h"
00029 #include "libmesh/equation_systems.h"
00030 #include "libmesh/error_vector.h"
00031 #include "libmesh/fe_base.h"
00032 #include "libmesh/libmesh_logging.h"
00033 #include "libmesh/elem.h"
00034 #include "libmesh/mesh_base.h"
00035 #include "libmesh/mesh_function.h"
00036 #include "libmesh/numeric_vector.h"
00037 #include "libmesh/quadrature.h"
00038 #include "libmesh/system.h"
00039 #include "libmesh/tensor_tools.h"
00040 
00041 namespace libMesh
00042 {
00043 
00044 //-----------------------------------------------------------------
00045 // ErrorEstimator implementations
00046 void ExactErrorEstimator::attach_exact_value (Number fptr(const Point& p,
00047                                                           const Parameters& parameters,
00048                                                           const std::string& sys_name,
00049                                                           const std::string& unknown_name))
00050 {
00051   libmesh_assert(fptr);
00052   _exact_value = fptr;
00053 
00054   // We're not using a fine grid solution
00055   _equation_systems_fine = NULL;
00056 
00057   // We're not using user-provided functors
00058   this->clear_functors();
00059 }
00060 
00061 
00062 void ExactErrorEstimator::attach_exact_values (std::vector<FunctionBase<Number> *> f)
00063 {
00064   // Clear out any previous _exact_values entries, then add a new
00065   // entry for each system.
00066   for (unsigned int i=0; i != _exact_values.size(); ++i)
00067     delete (_exact_values[i]);
00068 
00069   _exact_values.clear();
00070   _exact_values.resize(f.size(), NULL);
00071 
00072   // We use clone() to get non-sliced copies of FunctionBase
00073   // subclasses, but we don't currently put the resulting UniquePtrs
00074   // into an STL container.
00075   for (unsigned int i=0; i != f.size(); ++i)
00076     if (f[i])
00077       _exact_values[i] = f[i]->clone().release();
00078 }
00079 
00080 
00081 void ExactErrorEstimator::attach_exact_value (unsigned int sys_num,
00082                                               FunctionBase<Number> * f)
00083 {
00084   if (_exact_values.size() <= sys_num)
00085     _exact_values.resize(sys_num+1, NULL);
00086 
00087   if (f)
00088     _exact_values[sys_num] = f->clone().release();
00089 }
00090 
00091 
00092 void ExactErrorEstimator::attach_exact_deriv (Gradient gptr(const Point& p,
00093                                                             const Parameters& parameters,
00094                                                             const std::string& sys_name,
00095                                                             const std::string& unknown_name))
00096 {
00097   libmesh_assert(gptr);
00098   _exact_deriv = gptr;
00099 
00100   // We're not using a fine grid solution
00101   _equation_systems_fine = NULL;
00102 
00103   // We're not using user-provided functors
00104   this->clear_functors();
00105 }
00106 
00107 
00108 void ExactErrorEstimator::attach_exact_derivs (std::vector<FunctionBase<Gradient> *> g)
00109 {
00110   // Clear out any previous _exact_derivs entries, then add a new
00111   // entry for each system.
00112   for (unsigned int i=0; i != _exact_derivs.size(); ++i)
00113     delete (_exact_derivs[i]);
00114 
00115   _exact_derivs.clear();
00116   _exact_derivs.resize(g.size(), NULL);
00117 
00118   // We use clone() to get non-sliced copies of FunctionBase
00119   // subclasses, but we don't currently put the resulting UniquePtrs
00120   // into an STL container.
00121   for (unsigned int i=0; i != g.size(); ++i)
00122     if (g[i])
00123       _exact_derivs[i] = g[i]->clone().release();
00124 }
00125 
00126 
00127 void ExactErrorEstimator::attach_exact_deriv (unsigned int sys_num,
00128                                               FunctionBase<Gradient>* g)
00129 {
00130   if (_exact_derivs.size() <= sys_num)
00131     _exact_derivs.resize(sys_num+1, NULL);
00132 
00133   if (g)
00134     _exact_derivs[sys_num] = g->clone().release();
00135 }
00136 
00137 
00138 
00139 
00140 void ExactErrorEstimator::attach_exact_hessian (Tensor hptr(const Point& p,
00141                                                             const Parameters& parameters,
00142                                                             const std::string& sys_name,
00143                                                             const std::string& unknown_name))
00144 {
00145   libmesh_assert(hptr);
00146   _exact_hessian = hptr;
00147 
00148   // We're not using a fine grid solution
00149   _equation_systems_fine = NULL;
00150 
00151   // We're not using user-provided functors
00152   this->clear_functors();
00153 }
00154 
00155 
00156 void ExactErrorEstimator::attach_exact_hessians (std::vector<FunctionBase<Tensor> *> h)
00157 {
00158   // Clear out any previous _exact_hessians entries, then add a new
00159   // entry for each system.
00160   for (unsigned int i=0; i != _exact_hessians.size(); ++i)
00161     delete (_exact_hessians[i]);
00162 
00163   _exact_hessians.clear();
00164   _exact_hessians.resize(h.size(), NULL);
00165 
00166   // We use clone() to get non-sliced copies of FunctionBase
00167   // subclasses, but we don't currently put the resulting UniquePtrs
00168   // into an STL container.
00169   for (unsigned int i=0; i != h.size(); ++i)
00170     if (h[i])
00171       _exact_hessians[i] = h[i]->clone().release();
00172 }
00173 
00174 
00175 void ExactErrorEstimator::attach_exact_hessian (unsigned int sys_num,
00176                                                 FunctionBase<Tensor>* h)
00177 {
00178   if (_exact_hessians.size() <= sys_num)
00179     _exact_hessians.resize(sys_num+1, NULL);
00180 
00181   if (h)
00182     _exact_hessians[sys_num] = h->clone().release();
00183 }
00184 
00185 
00186 void ExactErrorEstimator::attach_reference_solution (EquationSystems* es_fine)
00187 {
00188   libmesh_assert(es_fine);
00189   _equation_systems_fine = es_fine;
00190 
00191   // If we're using a fine grid solution, we're not using exact value
00192   // function pointers or functors.
00193   _exact_value = NULL;
00194   _exact_deriv = NULL;
00195   _exact_hessian = NULL;
00196 
00197   this->clear_functors();
00198 }
00199 
00200 #ifdef LIBMESH_ENABLE_AMR
00201 void ExactErrorEstimator::estimate_error (const System& system,
00202                                           ErrorVector& error_per_cell,
00203                                           const NumericVector<Number>* solution_vector,
00204                                           bool estimate_parent_error)
00205 #else
00206   void ExactErrorEstimator::estimate_error (const System& system,
00207                                             ErrorVector& error_per_cell,
00208                                             const NumericVector<Number>* solution_vector,
00209                                             bool /* estimate_parent_error */ )
00210 #endif
00211 {
00212   // The current mesh
00213   const MeshBase& mesh = system.get_mesh();
00214 
00215   // The dimensionality of the mesh
00216   const unsigned int dim = mesh.mesh_dimension();
00217 
00218   // The number of variables in the system
00219   const unsigned int n_vars = system.n_vars();
00220 
00221   // The DofMap for this system
00222   const DofMap& dof_map = system.get_dof_map();
00223 
00224   // Resize the error_per_cell vector to be
00225   // the number of elements, initialize it to 0.
00226   error_per_cell.resize (mesh.max_elem_id());
00227   std::fill (error_per_cell.begin(), error_per_cell.end(), 0.);
00228 
00229   // Prepare current_local_solution to localize a non-standard
00230   // solution vector if necessary
00231   if (solution_vector && solution_vector != system.solution.get())
00232     {
00233       NumericVector<Number>* newsol =
00234         const_cast<NumericVector<Number>*>(solution_vector);
00235       System &sys = const_cast<System&>(system);
00236       newsol->swap(*sys.solution);
00237       sys.update();
00238     }
00239 
00240   // Loop over all the variables in the system
00241   for (unsigned int var=0; var<n_vars; var++)
00242     {
00243       // Possibly skip this variable
00244       if (error_norm.weight(var) == 0.0) continue;
00245 
00246       // The (string) name of this variable
00247       const std::string& var_name = system.variable_name(var);
00248 
00249       // The type of finite element to use for this variable
00250       const FEType& fe_type = dof_map.variable_type (var);
00251 
00252       UniquePtr<FEBase> fe (FEBase::build (dim, fe_type));
00253 
00254       // Build an appropriate Gaussian quadrature rule
00255       UniquePtr<QBase> qrule =
00256         fe_type.default_quadrature_rule (dim,
00257                                          _extra_order);
00258 
00259       fe->attach_quadrature_rule (qrule.get());
00260 
00261       // Prepare a global solution and a MeshFunction of the fine system if we need one
00262       UniquePtr<MeshFunction> fine_values;
00263       UniquePtr<NumericVector<Number> > fine_soln = NumericVector<Number>::build(system.comm());
00264       if (_equation_systems_fine)
00265         {
00266           const System& fine_system = _equation_systems_fine->get_system(system.name());
00267 
00268           std::vector<Number> global_soln;
00269           // FIXME - we're assuming that the fine system solution gets
00270           // used even when a different vector is used for the coarse
00271           // system
00272           fine_system.update_global_solution(global_soln);
00273           fine_soln->init
00274             (cast_int<numeric_index_type>(global_soln.size()), true,
00275              SERIAL);
00276           (*fine_soln) = global_soln;
00277 
00278           fine_values = UniquePtr<MeshFunction>
00279             (new MeshFunction(*_equation_systems_fine,
00280                               *fine_soln,
00281                               fine_system.get_dof_map(),
00282                               fine_system.variable_number(var_name)));
00283           fine_values->init();
00284         } else {
00285         // Initialize functors if we're using them
00286         for (unsigned int i=0; i != _exact_values.size(); ++i)
00287           if (_exact_values[i])
00288             _exact_values[i]->init();
00289 
00290         for (unsigned int i=0; i != _exact_derivs.size(); ++i)
00291           if (_exact_derivs[i])
00292             _exact_derivs[i]->init();
00293 
00294         for (unsigned int i=0; i != _exact_hessians.size(); ++i)
00295           if (_exact_hessians[i])
00296             _exact_hessians[i]->init();
00297       }
00298 
00299       // Request the data we'll need to compute with
00300       fe->get_JxW();
00301       fe->get_phi();
00302       fe->get_dphi();
00303 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00304       fe->get_d2phi();
00305 #endif
00306       fe->get_xyz();
00307 
00308 #ifdef LIBMESH_ENABLE_AMR
00309       // If we compute on parent elements, we'll want to do so only
00310       // once on each, so we need to keep track of which we've done.
00311       std::vector<bool> computed_var_on_parent;
00312 
00313       if (estimate_parent_error)
00314         computed_var_on_parent.resize(error_per_cell.size(), false);
00315 #endif
00316 
00317       // TODO: this ought to be threaded (and using subordinate
00318       // MeshFunction objects in each thread rather than a single
00319       // master)
00320 
00321       // Iterate over all the active elements in the mesh
00322       // that live on this processor.
00323       MeshBase::const_element_iterator
00324         elem_it  = mesh.active_local_elements_begin();
00325       const MeshBase::const_element_iterator
00326         elem_end = mesh.active_local_elements_end();
00327 
00328       for (;elem_it != elem_end; ++elem_it)
00329         {
00330           // e is necessarily an active element on the local processor
00331           const Elem* elem = *elem_it;
00332           const dof_id_type e_id = elem->id();
00333 
00334 #ifdef LIBMESH_ENABLE_AMR
00335           // See if the parent of element e has been examined yet;
00336           // if not, we may want to compute the estimator on it
00337           const Elem* parent = elem->parent();
00338 
00339           // We only can compute and only need to compute on
00340           // parents with all active children
00341           bool compute_on_parent = true;
00342           if (!parent || !estimate_parent_error)
00343             compute_on_parent = false;
00344           else
00345             for (unsigned int c=0; c != parent->n_children(); ++c)
00346               if (!parent->child(c)->active())
00347                 compute_on_parent = false;
00348 
00349           if (compute_on_parent &&
00350               !computed_var_on_parent[parent->id()])
00351             {
00352               computed_var_on_parent[parent->id()] = true;
00353 
00354               // Compute a projection onto the parent
00355               DenseVector<Number> Uparent;
00356               FEBase::coarsened_dof_values(*(system.current_local_solution),
00357                                            dof_map, parent, Uparent,
00358                                            var, false);
00359 
00360               error_per_cell[parent->id()] +=
00361                 static_cast<ErrorVectorReal>
00362                 (find_squared_element_error(system, var_name,
00363                                             parent, Uparent,
00364                                             fe.get(),
00365                                             fine_values.get()));
00366             }
00367 #endif
00368 
00369           // Get the local to global degree of freedom maps
00370           std::vector<dof_id_type> dof_indices;
00371           dof_map.dof_indices (elem, dof_indices, var);
00372           const unsigned int n_dofs =
00373             cast_int<unsigned int>(dof_indices.size());
00374           DenseVector<Number> Uelem(n_dofs);
00375           for (unsigned int i=0; i != n_dofs; ++i)
00376             Uelem(i) = system.current_solution(dof_indices[i]);
00377 
00378           error_per_cell[e_id] +=
00379             static_cast<ErrorVectorReal>
00380             (find_squared_element_error(system, var_name, elem,
00381                                         Uelem, fe.get(),
00382                                         fine_values.get()));
00383 
00384         } // End loop over active local elements
00385     } // End loop over variables
00386 
00387 
00388 
00389   // Each processor has now computed the error contribuions
00390   // for its local elements.  We need to sum the vector
00391   // and then take the square-root of each component.  Note
00392   // that we only need to sum if we are running on multiple
00393   // processors, and we only need to take the square-root
00394   // if the value is nonzero.  There will in general be many
00395   // zeros for the inactive elements.
00396 
00397   // First sum the vector of estimated error values
00398   this->reduce_error(error_per_cell, system.comm());
00399 
00400   // Compute the square-root of each component.
00401   START_LOG("std::sqrt()", "ExactErrorEstimator");
00402   for (dof_id_type i=0; i<error_per_cell.size(); i++)
00403     {
00404 
00405       if (error_per_cell[i] != 0.)
00406         {
00407           libmesh_assert_greater (error_per_cell[i], 0.);
00408           error_per_cell[i] = std::sqrt(error_per_cell[i]);
00409         }
00410 
00411 
00412     }
00413   STOP_LOG("std::sqrt()", "ExactErrorEstimator");
00414 
00415   // If we used a non-standard solution before, now is the time to fix
00416   // the current_local_solution
00417   if (solution_vector && solution_vector != system.solution.get())
00418     {
00419       NumericVector<Number>* newsol =
00420         const_cast<NumericVector<Number>*>(solution_vector);
00421       System &sys = const_cast<System&>(system);
00422       newsol->swap(*sys.solution);
00423       sys.update();
00424     }
00425 }
00426 
00427 
00428 
00429 Real ExactErrorEstimator::find_squared_element_error(const System& system,
00430                                                      const std::string& var_name,
00431                                                      const Elem *elem,
00432                                                      const DenseVector<Number> &Uelem,
00433                                                      FEBase *fe,
00434                                                      MeshFunction *fine_values) const
00435 {
00436   // The (string) name of this system
00437   const std::string& sys_name = system.name();
00438   const unsigned int sys_num = system.number();
00439 
00440   const unsigned int var = system.variable_number(var_name);
00441   const unsigned int var_component =
00442     system.variable_scalar_number(var, 0);
00443 
00444   const Parameters& parameters = system.get_equation_systems().parameters;
00445 
00446   // reinitialize the element-specific data
00447   // for the current element
00448   fe->reinit (elem);
00449 
00450   // Get the data we need to compute with
00451   const std::vector<Real> &                      JxW          = fe->get_JxW();
00452   const std::vector<std::vector<Real> >&         phi_values   = fe->get_phi();
00453   const std::vector<std::vector<RealGradient> >& dphi_values  = fe->get_dphi();
00454   const std::vector<Point>&                      q_point      = fe->get_xyz();
00455 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00456   const std::vector<std::vector<RealTensor> >&   d2phi_values = fe->get_d2phi();
00457 #endif
00458 
00459   // The number of shape functions
00460   const unsigned int n_sf =
00461     cast_int<unsigned int>(Uelem.size());
00462 
00463   // The number of quadrature points
00464   const unsigned int n_qp =
00465     cast_int<unsigned int>(JxW.size());
00466 
00467   Real error_val = 0;
00468 
00469   // Begin the loop over the Quadrature points.
00470   //
00471   for (unsigned int qp=0; qp<n_qp; qp++)
00472     {
00473       // Real u_h = 0.;
00474       // RealGradient grad_u_h;
00475 
00476       Number u_h = 0.;
00477 
00478       Gradient grad_u_h;
00479 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00480       Tensor grad2_u_h;
00481 #endif
00482 
00483       // Compute solution values at the current
00484       // quadrature point.  This reqiures a sum
00485       // over all the shape functions evaluated
00486       // at the quadrature point.
00487       for (unsigned int i=0; i<n_sf; i++)
00488         {
00489           // Values from current solution.
00490           u_h      += phi_values[i][qp]*Uelem(i);
00491           grad_u_h += dphi_values[i][qp]*Uelem(i);
00492 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00493           grad2_u_h += d2phi_values[i][qp]*Uelem(i);
00494 #endif
00495         }
00496 
00497       // Compute the value of the error at this quadrature point
00498       if (error_norm.type(var) == L2 ||
00499           error_norm.type(var) == H1 ||
00500           error_norm.type(var) == H2)
00501         {
00502           Number val_error = u_h;
00503           if (_exact_value)
00504             val_error -= _exact_value(q_point[qp],parameters,sys_name,var_name);
00505           else if (_exact_values.size() > sys_num && _exact_values[sys_num])
00506             val_error -= _exact_values[sys_num]->
00507               component(var_component, q_point[qp], system.time);
00508           else if (_equation_systems_fine)
00509             val_error -= (*fine_values)(q_point[qp]);
00510 
00511           // Add the squares of the error to each contribution
00512           error_val += JxW[qp]*TensorTools::norm_sq(val_error);
00513         }
00514 
00515       // Compute the value of the error in the gradient at this
00516       // quadrature point
00517       if (error_norm.type(var) == H1 ||
00518           error_norm.type(var) == H1_SEMINORM ||
00519           error_norm.type(var) == H2)
00520         {
00521           Gradient grad_error = grad_u_h;
00522           if(_exact_deriv)
00523             grad_error -= _exact_deriv(q_point[qp],parameters,sys_name,var_name);
00524           else if (_exact_derivs.size() > sys_num && _exact_derivs[sys_num])
00525             grad_error -= _exact_derivs[sys_num]->
00526               component(var_component, q_point[qp], system.time);
00527           else if(_equation_systems_fine)
00528             grad_error -= fine_values->gradient(q_point[qp]);
00529 
00530           error_val += JxW[qp]*grad_error.size_sq();
00531         }
00532 
00533 
00534 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
00535       // Compute the value of the error in the hessian at this
00536       // quadrature point
00537       if ((error_norm.type(var) == H2_SEMINORM ||
00538            error_norm.type(var) == H2))
00539         {
00540           Tensor grad2_error = grad2_u_h;
00541           if(_exact_hessian)
00542             grad2_error -= _exact_hessian(q_point[qp],parameters,sys_name,var_name);
00543           else if (_exact_hessians.size() > sys_num && _exact_hessians[sys_num])
00544             grad2_error -= _exact_hessians[sys_num]->
00545               component(var_component, q_point[qp], system.time);
00546           else if (_equation_systems_fine)
00547             grad2_error -= fine_values->hessian(q_point[qp]);
00548 
00549           error_val += JxW[qp]*grad2_error.size_sq();
00550         }
00551 #endif
00552 
00553     } // end qp loop
00554 
00555   libmesh_assert_greater_equal (error_val, 0.);
00556 
00557   return error_val;
00558 }
00559 
00560 
00561 
00562 void ExactErrorEstimator::clear_functors()
00563 {
00564   // delete will clean up any cloned functors and no-op on any NULL
00565   // pointers
00566 
00567   for (unsigned int i=0; i != _exact_values.size(); ++i)
00568     delete (_exact_values[i]);
00569 
00570   for (unsigned int i=0; i != _exact_derivs.size(); ++i)
00571     delete (_exact_derivs[i]);
00572 
00573   for (unsigned int i=0; i != _exact_hessians.size(); ++i)
00574     delete (_exact_hessians[i]);
00575 }
00576 
00577 
00578 
00579 } // namespace libMesh