$extrastylesheet
jump_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/jump_error_estimator.h"
00028 #include "libmesh/dof_map.h"
00029 #include "libmesh/error_vector.h"
00030 #include "libmesh/fe_base.h"
00031 #include "libmesh/fe_interface.h"
00032 #include "libmesh/quadrature_gauss.h"
00033 #include "libmesh/libmesh_logging.h"
00034 #include "libmesh/elem.h"
00035 #include "libmesh/mesh_base.h"
00036 #include "libmesh/system.h"
00037 
00038 #include "libmesh/dense_vector.h"
00039 #include "libmesh/numeric_vector.h"
00040 
00041 namespace libMesh
00042 {
00043 
00044 //-----------------------------------------------------------------
00045 // JumpErrorEstimator implementations
00046 void JumpErrorEstimator::initialize (const System&,
00047                                      ErrorVector&,
00048                                      bool)
00049 {
00050 }
00051 
00052 
00053 
00054 void JumpErrorEstimator::estimate_error (const System& system,
00055                                          ErrorVector& error_per_cell,
00056                                          const NumericVector<Number>* solution_vector,
00057                                          bool estimate_parent_error)
00058 {
00059   START_LOG("estimate_error()", "JumpErrorEstimator");
00060   /*
00061 
00062     Conventions for assigning the direction of the normal:
00063 
00064     - e & f are global element ids
00065 
00066     Case (1.) Elements are at the same level, e<f
00067     Compute the flux jump on the face and
00068     add it as a contribution to error_per_cell[e]
00069     and error_per_cell[f]
00070 
00071     ----------------------
00072     |           |          |
00073     |           |    f     |
00074     |           |          |
00075     |    e      |---> n    |
00076     |           |          |
00077     |           |          |
00078     ----------------------
00079 
00080 
00081     Case (2.) The neighbor is at a higher level.
00082     Compute the flux jump on e's face and
00083     add it as a contribution to error_per_cell[e]
00084     and error_per_cell[f]
00085 
00086     ----------------------
00087     |     |     |          |
00088     |     |  e  |---> n    |
00089     |     |     |          |
00090     |-----------|    f     |
00091     |     |     |          |
00092     |     |     |          |
00093     |     |     |          |
00094     ----------------------
00095   */
00096 
00097   // The current mesh
00098   const MeshBase& mesh = system.get_mesh();
00099 
00100   // The dimensionality of the mesh
00101   const unsigned int dim = mesh.mesh_dimension();
00102 
00103   // The number of variables in the system
00104   const unsigned int n_vars = system.n_vars();
00105 
00106   // The DofMap for this system
00107   const DofMap& dof_map = system.get_dof_map();
00108 
00109   // Resize the error_per_cell vector to be
00110   // the number of elements, initialize it to 0.
00111   error_per_cell.resize (mesh.max_elem_id());
00112   std::fill (error_per_cell.begin(), error_per_cell.end(), 0.);
00113 
00114   // Declare a vector of floats which is as long as
00115   // error_per_cell above, and fill with zeros.  This vector will be
00116   // used to keep track of the number of edges (faces) on each active
00117   // element which are either:
00118   // 1) an internal edge
00119   // 2) an edge on a Neumann boundary for which a boundary condition
00120   //    function has been specified.
00121   // The error estimator can be scaled by the number of flux edges (faces)
00122   // which the element actually has to obtain a more uniform measure
00123   // of the error.  Use floats instead of ints since in case 2 (above)
00124   // f gets 1/2 of a flux face contribution from each of his
00125   // neighbors
00126   std::vector<float> n_flux_faces (error_per_cell.size());
00127 
00128   // Prepare current_local_solution to localize a non-standard
00129   // solution vector if necessary
00130   if (solution_vector && solution_vector != system.solution.get())
00131     {
00132       NumericVector<Number>* newsol =
00133         const_cast<NumericVector<Number>*>(solution_vector);
00134       System &sys = const_cast<System&>(system);
00135       newsol->swap(*sys.solution);
00136       sys.update();
00137     }
00138 
00139   // Loop over all the variables in the system
00140   for (var=0; var<n_vars; var++)
00141     {
00142       // Possibly skip this variable
00143       if (error_norm.weight(var) == 0.0) continue;
00144 
00145       // The type of finite element to use for this variable
00146       const FEType& fe_type = dof_map.variable_type (var);
00147 
00148       // Finite element objects for the same face from
00149       // different sides
00150       fe_fine = FEBase::build (dim, fe_type);
00151       fe_coarse = FEBase::build (dim, fe_type);
00152 
00153       // Build an appropriate Gaussian quadrature rule
00154       QGauss qrule (dim-1, fe_type.default_quadrature_order());
00155 
00156       // Tell the finite element for the fine element about the quadrature
00157       // rule.  The finite element for the coarse element need not know about it
00158       fe_fine->attach_quadrature_rule (&qrule);
00159 
00160       // By convention we will always do the integration
00161       // on the face of element e.  We'll need its Jacobian values and
00162       // physical point locations, at least
00163       fe_fine->get_JxW();
00164       fe_fine->get_xyz();
00165 
00166       // Our derived classes may want to do some initialization here
00167       this->initialize(system, error_per_cell, estimate_parent_error);
00168 
00169       // The global DOF indices for elements e & f
00170       std::vector<dof_id_type> dof_indices_fine;
00171       std::vector<dof_id_type> dof_indices_coarse;
00172 
00173 
00174 
00175       // Iterate over all the active elements in the mesh
00176       // that live on this processor.
00177       MeshBase::const_element_iterator       elem_it  = mesh.active_local_elements_begin();
00178       const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end();
00179 
00180       for (; elem_it != elem_end; ++elem_it)
00181         {
00182           // e is necessarily an active element on the local processor
00183           const Elem* e = *elem_it;
00184           const dof_id_type e_id = e->id();
00185 
00186 #ifdef LIBMESH_ENABLE_AMR
00187           // See if the parent of element e has been examined yet;
00188           // if not, we may want to compute the estimator on it
00189           const Elem* parent = e->parent();
00190 
00191           // We only can compute and only need to compute on
00192           // parents with all active children
00193           bool compute_on_parent = true;
00194           if (!parent || !estimate_parent_error)
00195             compute_on_parent = false;
00196           else
00197             for (unsigned int c=0; c != parent->n_children(); ++c)
00198               if (!parent->child(c)->active())
00199                 compute_on_parent = false;
00200 
00201           if (compute_on_parent &&
00202               !error_per_cell[parent->id()])
00203             {
00204               // Compute a projection onto the parent
00205               DenseVector<Number> Uparent;
00206               FEBase::coarsened_dof_values(*(system.solution),
00207                                            dof_map, parent, Uparent,
00208                                            var, false);
00209 
00210               // Loop over the neighbors of the parent
00211               for (unsigned int n_p=0; n_p<parent->n_neighbors(); n_p++)
00212                 {
00213                   if (parent->neighbor(n_p) != NULL) // parent has a neighbor here
00214                     {
00215                       // Find the active neighbors in this direction
00216                       std::vector<const Elem*> active_neighbors;
00217                       parent->neighbor(n_p)->
00218                         active_family_tree_by_neighbor(active_neighbors,
00219                                                        parent);
00220                       // Compute the flux to each active neighbor
00221                       for (unsigned int a=0;
00222                            a != active_neighbors.size(); ++a)
00223                         {
00224                           const Elem *f = active_neighbors[a];
00225                           // FIXME - what about when f->level <
00226                           // parent->level()??
00227                           if (f->level() >= parent->level())
00228                             {
00229                               fine_elem = f;
00230                               coarse_elem = parent;
00231                               Ucoarse = Uparent;
00232 
00233                               dof_map.dof_indices (fine_elem, dof_indices_fine, var);
00234                               const unsigned int n_dofs_fine =
00235                                 cast_int<unsigned int>(dof_indices_fine.size());
00236                               Ufine.resize(n_dofs_fine);
00237 
00238                               for (unsigned int i=0; i<n_dofs_fine; i++)
00239                                 Ufine(i) = system.current_solution(dof_indices_fine[i]);
00240                               this->reinit_sides();
00241                               this->internal_side_integration();
00242 
00243                               error_per_cell[fine_elem->id()] +=
00244                                 static_cast<ErrorVectorReal>(fine_error);
00245                               error_per_cell[coarse_elem->id()] +=
00246                                 static_cast<ErrorVectorReal>(coarse_error);
00247 
00248                               // Keep track of the number of internal flux
00249                               // sides found on each element
00250                               n_flux_faces[fine_elem->id()]++;
00251                               n_flux_faces[coarse_elem->id()] += this->coarse_n_flux_faces_increment();
00252                             }
00253                         }
00254                     }
00255                   else if (integrate_boundary_sides)
00256                     {
00257                       fine_elem = parent;
00258                       Ufine = Uparent;
00259 
00260                       // Reinitialize shape functions on the fine element side
00261                       fe_fine->reinit (fine_elem, fine_side);
00262 
00263                       if (this->boundary_side_integration())
00264                         {
00265                           error_per_cell[fine_elem->id()] +=
00266                             static_cast<ErrorVectorReal>(fine_error);
00267                           n_flux_faces[fine_elem->id()]++;
00268                         }
00269                     }
00270                 }
00271             }
00272 #endif // #ifdef LIBMESH_ENABLE_AMR
00273 
00274           // If we do any more flux integration, e will be the fine element
00275           fine_elem = e;
00276 
00277           // Loop over the neighbors of element e
00278           for (unsigned int n_e=0; n_e<e->n_neighbors(); n_e++)
00279             {
00280               fine_side = n_e;
00281 
00282               if (e->neighbor(n_e) != NULL) // e is not on the boundary
00283                 {
00284                   const Elem* f           = e->neighbor(n_e);
00285                   const dof_id_type f_id = f->id();
00286 
00287                   // Compute flux jumps if we are in case 1 or case 2.
00288                   if ((f->active() && (f->level() == e->level()) && (e_id < f_id))
00289                       || (f->level() < e->level()))
00290                     {
00291                       // f is now the coarse element
00292                       coarse_elem = f;
00293 
00294                       // Get the DOF indices for the two elements
00295                       dof_map.dof_indices (fine_elem, dof_indices_fine, var);
00296                       dof_map.dof_indices (coarse_elem, dof_indices_coarse, var);
00297 
00298                       // The number of DOFS on each element
00299                       const unsigned int n_dofs_fine =
00300                         cast_int<unsigned int>(dof_indices_fine.size());
00301                       const unsigned int n_dofs_coarse =
00302                         cast_int<unsigned int>(dof_indices_coarse.size());
00303                       Ufine.resize(n_dofs_fine);
00304                       Ucoarse.resize(n_dofs_coarse);
00305 
00306                       // The local solutions on each element
00307                       for (unsigned int i=0; i<n_dofs_fine; i++)
00308                         Ufine(i) = system.current_solution(dof_indices_fine[i]);
00309                       for (unsigned int i=0; i<n_dofs_coarse; i++)
00310                         Ucoarse(i) = system.current_solution(dof_indices_coarse[i]);
00311 
00312                       this->reinit_sides();
00313                       this->internal_side_integration();
00314 
00315                       error_per_cell[fine_elem->id()] +=
00316                         static_cast<ErrorVectorReal>(fine_error);
00317                       error_per_cell[coarse_elem->id()] +=
00318                         static_cast<ErrorVectorReal>(coarse_error);
00319 
00320                       // Keep track of the number of internal flux
00321                       // sides found on each element
00322                       n_flux_faces[fine_elem->id()]++;
00323                       n_flux_faces[coarse_elem->id()] += this->coarse_n_flux_faces_increment();
00324                     } // end if (case1 || case2)
00325                 } // if (e->neigbor(n_e) != NULL)
00326 
00327               // Otherwise, e is on the boundary.  If it happens to
00328               // be on a Dirichlet boundary, we need not do anything.
00329               // On the other hand, if e is on a Neumann (flux) boundary
00330               // with grad(u).n = g, we need to compute the additional residual
00331               // (h * \int |g - grad(u_h).n|^2 dS)^(1/2).
00332               // We can only do this with some knowledge of the boundary
00333               // conditions, i.e. the user must have attached an appropriate
00334               // BC function.
00335               else
00336                 {
00337                   if (integrate_boundary_sides)
00338                     {
00339                       // Reinitialize shape functions on the fine element side
00340                       fe_fine->reinit (fine_elem, fine_side);
00341 
00342                       // Get the DOF indices
00343                       dof_map.dof_indices (fine_elem, dof_indices_fine, var);
00344 
00345                       // The number of DOFS on each element
00346                       const unsigned int n_dofs_fine =
00347                         cast_int<unsigned int>(dof_indices_fine.size());
00348                       Ufine.resize(n_dofs_fine);
00349 
00350                       for (unsigned int i=0; i<n_dofs_fine; i++)
00351                         Ufine(i) = system.current_solution(dof_indices_fine[i]);
00352 
00353                       if (this->boundary_side_integration())
00354                         {
00355                           error_per_cell[fine_elem->id()] +=
00356                             static_cast<ErrorVectorReal>(fine_error);
00357                           n_flux_faces[fine_elem->id()]++;
00358                         }
00359                     } // end if _bc_function != NULL
00360                 } // end if (e->neighbor(n_e) == NULL)
00361             } // end loop over neighbors
00362         } // End loop over active local elements
00363     } // End loop over variables
00364 
00365 
00366 
00367   // Each processor has now computed the error contribuions
00368   // for its local elements.  We need to sum the vector
00369   // and then take the square-root of each component.  Note
00370   // that we only need to sum if we are running on multiple
00371   // processors, and we only need to take the square-root
00372   // if the value is nonzero.  There will in general be many
00373   // zeros for the inactive elements.
00374 
00375   // First sum the vector of estimated error values
00376   this->reduce_error(error_per_cell, system.comm());
00377 
00378   // Compute the square-root of each component.
00379   for (std::size_t i=0; i<error_per_cell.size(); i++)
00380     if (error_per_cell[i] != 0.)
00381       error_per_cell[i] = std::sqrt(error_per_cell[i]);
00382 
00383 
00384   if (this->scale_by_n_flux_faces)
00385     {
00386       // Sum the vector of flux face counts
00387       this->reduce_error(n_flux_faces, system.comm());
00388 
00389       // Sanity check: Make sure the number of flux faces is
00390       // always an integer value
00391 #ifdef DEBUG
00392       for (unsigned int i=0; i<n_flux_faces.size(); ++i)
00393         libmesh_assert_equal_to (n_flux_faces[i], static_cast<float>(static_cast<unsigned int>(n_flux_faces[i])) );
00394 #endif
00395 
00396       // Scale the error by the number of flux faces for each element
00397       for (unsigned int i=0; i<n_flux_faces.size(); ++i)
00398         {
00399           if (n_flux_faces[i] == 0.0) // inactive or non-local element
00400             continue;
00401 
00402           //libMesh::out << "Element " << i << " has " << n_flux_faces[i] << " flux faces." << std::endl;
00403           error_per_cell[i] /= static_cast<ErrorVectorReal>(n_flux_faces[i]);
00404         }
00405     }
00406 
00407   // If we used a non-standard solution before, now is the time to fix
00408   // the current_local_solution
00409   if (solution_vector && solution_vector != system.solution.get())
00410     {
00411       NumericVector<Number>* newsol =
00412         const_cast<NumericVector<Number>*>(solution_vector);
00413       System &sys = const_cast<System&>(system);
00414       newsol->swap(*sys.solution);
00415       sys.update();
00416     }
00417 
00418   STOP_LOG("estimate_error()", "JumpErrorEstimator");
00419 }
00420 
00421 
00422 
00423 void
00424 JumpErrorEstimator::reinit_sides ()
00425 {
00426   // The master quadrature point locations on the coarse element
00427   std::vector<Point> qp_coarse;
00428 
00429   // Reinitialize shape functions on the fine element side
00430   fe_fine->reinit (fine_elem, fine_side);
00431 
00432   // Get the physical locations of the fine element quadrature points
00433   std::vector<Point> qface_point = fe_fine->get_xyz();
00434 
00435   // Find their locations on the coarse element
00436   FEInterface::inverse_map (coarse_elem->dim(), fe_coarse->get_fe_type(),
00437                             coarse_elem, qface_point, qp_coarse);
00438 
00439   // Calculate the coarse element shape functions at those locations
00440   fe_coarse->reinit (coarse_elem, &qp_coarse);
00441 }
00442 
00443 
00444 
00445 float JumpErrorEstimator::coarse_n_flux_faces_increment ()
00446 {
00447   // Keep track of the number of internal flux sides found on each
00448   // element
00449   unsigned int dim = coarse_elem->dim();
00450 
00451   const unsigned int divisor =
00452     1 << (dim-1)*(fine_elem->level() - coarse_elem->level());
00453 
00454   // With a difference of n levels between fine and coarse elements,
00455   // we compute a fractional flux face for the coarse element by adding:
00456   // 1/2^n in 2D
00457   // 1/4^n in 3D
00458   // each time.  This code will get hit 2^n times in 2D and 4^n
00459   // times in 3D so that the final flux face count for the coarse
00460   // element will be an integer value.
00461 
00462   return 1.0f / static_cast<float>(divisor);
00463 }
00464 
00465 } // namespace libMesh