DiscontinuityMeasure Class Reference

#include <discontinuity_measure.h>

Inheritance diagram for DiscontinuityMeasure:

List of all members.

Public Types

typedef std::map< std::pair
< const System *, unsigned int >
, ErrorVector * > 
ErrorMap

Public Member Functions

 DiscontinuityMeasure ()
 ~DiscontinuityMeasure ()
void attach_essential_bc_function (std::pair< bool, Real > fptr(const System &system, const Point &p, const std::string &var_name))
virtual 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

bool scale_by_n_flux_faces
SystemNorm error_norm

Protected Member Functions

virtual void initialize (const System &system, ErrorVector &error_per_cell, bool estimate_parent_error)
virtual void internal_side_integration ()
virtual bool boundary_side_integration ()
void reinit_sides ()
float coarse_n_flux_faces_increment ()
void reduce_error (std::vector< float > &error_per_cell) const

Protected Attributes

const Systemmy_system
std::pair< bool, Real >(* _bc_function )(const System &system, const Point &p, const std::string &var_name)
bool integrate_boundary_sides
const Elemfine_elem
const Elemcoarse_elem
Real fine_error
Real coarse_error
unsigned int fine_side
unsigned int var
DenseVector< NumberUfine
DenseVector< NumberUcoarse
AutoPtr< FEBasefe_fine
AutoPtr< FEBasefe_coarse


Detailed Description

This class measures discontinuities between elements for debugging purposes. It derives from ErrorEstimator just in case someone finds it useful in a DG framework.

Author:
Roy H. Stogner, 2006.

Definition at line 46 of file discontinuity_measure.h.


Member Typedef Documentation

typedef std::map<std::pair<const System*, unsigned int>, ErrorVector*> ErrorEstimator::ErrorMap [inherited]

When calculating many error vectors at once, we need a data structure to hold them all

Definition at line 105 of file error_estimator.h.


Constructor & Destructor Documentation

DiscontinuityMeasure::DiscontinuityMeasure (  )  [inline]

Constructor. Responsible for initializing the _bc_function function pointer to NULL. Defaults to L2 norm; changes to system norm are ignored.

Definition at line 55 of file discontinuity_measure.h.

References ErrorEstimator::error_norm, and libMeshEnums::L2.

00055 : _bc_function(NULL) { error_norm = L2; }

DiscontinuityMeasure::~DiscontinuityMeasure (  )  [inline]

Destructor.

Definition at line 60 of file discontinuity_measure.h.

00060 {}


Member Function Documentation

void DiscontinuityMeasure::attach_essential_bc_function ( std::pair< bool, Real >   fptrconst System &system,const Point &p,const std::string &var_name  ) 

Register a user function to use in computing the essential BCs. The return value is std::pair<bool, Real>

Definition at line 163 of file discontinuity_measure.C.

00166 {
00167   _bc_function = fptr;
00168 
00169 // We may be turning boundary side integration on or off
00170   if (fptr)
00171     integrate_boundary_sides = true;
00172   else
00173     integrate_boundary_sides = false;
00174 }

bool DiscontinuityMeasure::boundary_side_integration (  )  [protected, virtual]

The function which calculates a normal derivative jump based error term on a boundary side. Returns true if the flux bc function is in fact defined on the current side.

Reimplemented from JumpErrorEstimator.

Definition at line 95 of file discontinuity_measure.C.

References _bc_function, ErrorEstimator::error_norm, JumpErrorEstimator::fe_fine, JumpErrorEstimator::fine_elem, JumpErrorEstimator::fine_error, Elem::hmax(), libmesh_norm(), my_system, JumpErrorEstimator::Ufine, JumpErrorEstimator::var, System::variable_name(), and SystemNorm::weight().

00096 {
00097   const std::string &var_name = my_system->variable_name(var);
00098 
00099   std::vector<std::vector<Real> > phi_fine = fe_fine->get_phi();
00100   std::vector<Real> JxW_face = fe_fine->get_JxW();
00101   std::vector<Point> qface_point = fe_fine->get_xyz();
00102 
00103   // The reinitialization also recomputes the locations of
00104   // the quadrature points on the side.  By checking if the
00105   // first quadrature point on the side is on an essential boundary
00106   // for a particular variable, we will determine if the whole
00107   // element is on an essential boundary (assuming quadrature points
00108   // are strictly contained in the side).
00109   if (this->_bc_function(*my_system, qface_point[0], var_name).first)
00110     {
00111       const Real h = fine_elem->hmax();
00112                     
00113       // The number of quadrature points
00114       const unsigned int n_qp = fe_fine->n_quadrature_points();
00115 
00116       // The error contribution from this face
00117       Real error = 1.e-30;
00118                     
00119       // loop over the integration points on the face.
00120       for (unsigned int qp=0; qp<n_qp; qp++)
00121         {
00122           // Value of the imposed essential BC at this quadrature point.
00123           const std::pair<bool,Real> essential_bc =
00124             this->_bc_function(*my_system, qface_point[qp], var_name);
00125 
00126           // Be sure the BC function still thinks we're on the 
00127           // essential boundary.
00128           libmesh_assert (essential_bc.first == true);
00129 
00130           // The solution gradient from each element
00131           Number u_fine = 0.;
00132 
00133           // Compute the solution gradient on element e
00134           for (unsigned int i=0; i != Ufine.size(); i++)
00135             u_fine += phi_fine[i][qp] * Ufine(i);
00136 
00137           // The difference between the desired BC and the approximate solution. 
00138           const Number jump = essential_bc.second - u_fine;
00139 
00140           // The flux jump squared.  If using complex numbers,
00141           // libmesh_norm(z) returns |z|^2, where |z| is the modulus of z.
00142           const Real jump2 = libmesh_norm(jump);
00143 
00144           // Integrate the error on the face.  The error is
00145           // scaled by an additional power of h, where h is
00146           // the maximum side length for the element.  This
00147           // arises in the definition of the indicator.
00148           error += JxW_face[qp]*jump2;                  
00149                         
00150         } // End quadrature point loop
00151 
00152       fine_error = error*h*error_norm.weight(var);
00153 
00154       return true;
00155     } // end if side on flux boundary
00156   return false;
00157 }

float JumpErrorEstimator::coarse_n_flux_faces_increment (  )  [protected, inherited]

A utility function to correctly increase n_flux_faces for the coarse element

Definition at line 433 of file jump_error_estimator.C.

References JumpErrorEstimator::coarse_elem, Elem::dim(), dim, JumpErrorEstimator::fine_elem, and Elem::level().

Referenced by JumpErrorEstimator::estimate_error().

00434 {
00435   // Keep track of the number of internal flux sides found on each
00436   // element
00437   unsigned int dim = coarse_elem->dim();
00438 
00439   const unsigned int divisor =
00440     1 << (dim-1)*(fine_elem->level() - coarse_elem->level());
00441 
00442   // With a difference of n levels between fine and coarse elements,
00443   // we compute a fractional flux face for the coarse element by adding:
00444   // 1/2^n in 2D
00445   // 1/4^n in 3D
00446   // each time.  This code will get hit 2^n times in 2D and 4^n
00447   // times in 3D so that the final flux face count for the coarse
00448   // element will be an integer value.
00449 
00450   return 1.0 / static_cast<Real>(divisor);
00451 }

void JumpErrorEstimator::estimate_error ( const System system,
ErrorVector error_per_cell,
const NumericVector< Number > *  solution_vector = NULL,
bool  estimate_parent_error = false 
) [virtual, inherited]

This function uses the derived class's jump error estimate formula to estimate the error on each cell. The estimated error is output in the vector error_per_cell

Implements ErrorEstimator.

Definition at line 52 of file jump_error_estimator.C.

References Elem::active(), MeshBase::active_local_elements_begin(), MeshBase::active_local_elements_end(), JumpErrorEstimator::boundary_side_integration(), FEBase::build(), Elem::child(), JumpErrorEstimator::coarse_elem, JumpErrorEstimator::coarse_error, JumpErrorEstimator::coarse_n_flux_faces_increment(), FEBase::coarsened_dof_values(), System::current_solution(), FEType::default_quadrature_order(), dim, DofMap::dof_indices(), ErrorEstimator::error_norm, JumpErrorEstimator::fe_coarse, JumpErrorEstimator::fe_fine, FEBase::fe_type, JumpErrorEstimator::fine_elem, JumpErrorEstimator::fine_error, JumpErrorEstimator::fine_side, System::get_dof_map(), System::get_mesh(), DofObject::id(), JumpErrorEstimator::initialize(), JumpErrorEstimator::integrate_boundary_sides, JumpErrorEstimator::internal_side_integration(), Elem::level(), MeshBase::max_elem_id(), mesh, MeshBase::mesh_dimension(), Elem::n_children(), Elem::n_neighbors(), System::n_vars(), n_vars, Elem::neighbor(), Elem::parent(), FEBase::qrule, ErrorEstimator::reduce_error(), JumpErrorEstimator::reinit_sides(), JumpErrorEstimator::scale_by_n_flux_faces, System::solution, NumericVector< T >::swap(), JumpErrorEstimator::Ucoarse, JumpErrorEstimator::Ufine, JumpErrorEstimator::var, DofMap::variable_type(), and SystemNorm::weight().

Referenced by Adaptive< T >::solve().

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

void 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.

Definition at line 92 of file error_estimator.C.

References ErrorEstimator::error_norm, ErrorEstimator::estimate_error(), EquationSystems::get_system(), EquationSystems::n_systems(), System::n_vars(), n_vars, and SystemNorm::type().

00096 {
00097   SystemNorm old_error_norm = this->error_norm;
00098 
00099   // Find the requested error values from each system
00100   for (unsigned int s = 0; s != equation_systems.n_systems(); ++s)
00101     {
00102       const System &sys = equation_systems.get_system(s);
00103 
00104       unsigned int n_vars = sys.n_vars();
00105 
00106       for (unsigned int v = 0; v != n_vars; ++v)
00107         {
00108           // Only fill in ErrorVectors the user asks for
00109           if (errors_per_cell.find(std::make_pair(&sys, v)) ==
00110               errors_per_cell.end())
00111             continue;
00112 
00113           // Calculate error in only one variable
00114           std::vector<Real> weights(n_vars, 0.0);
00115           weights[v] = 1.0;
00116           this->error_norm =
00117             SystemNorm(std::vector<FEMNormType>(n_vars, old_error_norm.type(0)),
00118                        weights);
00119 
00120           const NumericVector<Number>* solution_vector = NULL;
00121           if (solution_vectors &&
00122               solution_vectors->find(&sys) != solution_vectors->end())
00123             solution_vector = solution_vectors->find(&sys)->second;
00124 
00125           this->estimate_error
00126             (sys, *errors_per_cell[std::make_pair(&sys, v)],
00127              solution_vector, estimate_parent_error);
00128         }
00129     }
00130 
00131   // Restore our old state before returning
00132   this->error_norm = old_error_norm;
00133 }

void 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 UniformRefinementEstimator.

Definition at line 46 of file error_estimator.C.

References ErrorEstimator::error_norm, ErrorEstimator::estimate_error(), EquationSystems::get_system(), and EquationSystems::n_systems().

00051 {
00052   SystemNorm old_error_norm = this->error_norm;
00053 
00054   // Sum the error values from each system
00055   for (unsigned int s = 0; s != equation_systems.n_systems(); ++s)
00056     {
00057       ErrorVector system_error_per_cell;
00058       const System &sys = equation_systems.get_system(s);
00059       if (error_norms.find(&sys) == error_norms.end())
00060         this->error_norm = old_error_norm;
00061       else
00062         this->error_norm = error_norms.find(&sys)->second;
00063 
00064       const NumericVector<Number>* solution_vector = NULL;
00065       if (solution_vectors &&
00066           solution_vectors->find(&sys) != solution_vectors->end())
00067         solution_vector = solution_vectors->find(&sys)->second;
00068 
00069       this->estimate_error(sys, system_error_per_cell,
00070                            solution_vector, estimate_parent_error);
00071 
00072       if (s)
00073         {
00074           libmesh_assert(error_per_cell.size() == system_error_per_cell.size());
00075           for (unsigned int i=0; i != error_per_cell.size(); ++i)
00076             error_per_cell[i] += system_error_per_cell[i];
00077         }
00078       else
00079         error_per_cell = system_error_per_cell;
00080     }
00081 
00082   // Restore our old state before returning
00083   this->error_norm = old_error_norm;
00084 }

void DiscontinuityMeasure::initialize ( const System system,
ErrorVector error_per_cell,
bool  estimate_parent_error 
) [protected, virtual]

An initialization function, for requesting specific data from the FE objects

Reimplemented from JumpErrorEstimator.

Definition at line 41 of file discontinuity_measure.C.

References JumpErrorEstimator::fe_coarse, JumpErrorEstimator::fe_fine, and my_system.

00044 {
00045   // Hang onto the system - we may need it for variable names later.
00046   my_system = &system;
00047 
00048   // We'll need values for jump computation
00049   fe_fine->get_phi();
00050   fe_coarse->get_phi();
00051 }

void DiscontinuityMeasure::internal_side_integration (  )  [protected, virtual]

The function which calculates a normal derivative jump based error term on an internal side

Implements JumpErrorEstimator.

Definition at line 56 of file discontinuity_measure.C.

References JumpErrorEstimator::coarse_elem, JumpErrorEstimator::coarse_error, ErrorEstimator::error_norm, JumpErrorEstimator::fe_coarse, JumpErrorEstimator::fe_fine, JumpErrorEstimator::fine_elem, JumpErrorEstimator::fine_error, Elem::hmax(), libmesh_norm(), JumpErrorEstimator::Ucoarse, JumpErrorEstimator::Ufine, JumpErrorEstimator::var, and SystemNorm::weight().

00057 {
00058   Real error = 1.e-30;
00059   unsigned int n_qp = fe_fine->n_quadrature_points();
00060   unsigned int n_fine_dofs = Ufine.size();
00061   unsigned int n_coarse_dofs = Ucoarse.size();
00062 
00063   std::vector<std::vector<Real> > phi_coarse = fe_coarse->get_phi();
00064   std::vector<std::vector<Real> > phi_fine = fe_fine->get_phi();
00065   std::vector<Real> JxW_face = fe_fine->get_JxW();
00066 
00067   for (unsigned int qp=0; qp != n_qp; ++qp)
00068     {
00069       // Calculate solution values on fine and coarse elements
00070       // at this quadrature point
00071       Number u_fine = 0., u_coarse = 0.;
00072       for (unsigned int i=0; i != n_coarse_dofs; ++i)
00073         u_coarse += phi_coarse[i][qp] * Ucoarse(i);
00074 
00075       for (unsigned int i=0; i != n_fine_dofs; ++i)
00076         u_fine += phi_fine[i][qp] * Ufine(i);
00077                                 
00078       // Find the jump in the value
00079       // at this quadrature point
00080       const Number jump = u_fine - u_coarse;
00081       const Real jump2 = libmesh_norm(jump);
00082       // Accumulate the jump integral
00083       error += JxW_face[qp] * jump2;
00084     }
00085 
00086   // Add the h-weighted jump integral to each error term
00087   fine_error =
00088     error * fine_elem->hmax() * error_norm.weight(var);
00089   coarse_error =
00090     error * coarse_elem->hmax() * error_norm.weight(var);
00091 }

void ErrorEstimator::reduce_error ( std::vector< float > &  error_per_cell  )  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.

Referenced by PatchRecoveryErrorEstimator::estimate_error(), and JumpErrorEstimator::estimate_error().

void JumpErrorEstimator::reinit_sides (  )  [protected, inherited]

A utility function to reinit the finite element data on elements sharing a side

Definition at line 412 of file jump_error_estimator.C.

References JumpErrorEstimator::coarse_elem, Elem::dim(), JumpErrorEstimator::fe_coarse, JumpErrorEstimator::fe_fine, JumpErrorEstimator::fine_elem, JumpErrorEstimator::fine_side, and InfFE< Dim, T_radial, T_map >::inverse_map().

Referenced by JumpErrorEstimator::estimate_error().

00413 {
00414   // The master quadrature point locations on the coarse element
00415   std::vector<Point> qp_coarse;
00416 
00417   // Reinitialize shape functions on the fine element side
00418   fe_fine->reinit (fine_elem, fine_side);
00419 
00420   // Get the physical locations of the fine element quadrature points
00421   std::vector<Point> qface_point = fe_fine->get_xyz();
00422 
00423   // Find their locations on the coarse element
00424   FEInterface::inverse_map (coarse_elem->dim(), fe_coarse->get_fe_type(),
00425                             coarse_elem, qface_point, qp_coarse);
00426 
00427   // Calculate the coarse element shape functions at those locations
00428   fe_coarse->reinit (coarse_elem, &qp_coarse);
00429 }


Member Data Documentation

std::pair<bool,Real>(* DiscontinuityMeasure::_bc_function)(const System &system, const Point &p, const std::string &var_name) [protected]

Pointer to function that returns BC information.

Referenced by boundary_side_integration().

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 137 of file error_estimator.h.

Referenced by KellyErrorEstimator::boundary_side_integration(), boundary_side_integration(), DiscontinuityMeasure(), JumpErrorEstimator::estimate_error(), ErrorEstimator::estimate_errors(), ExactErrorEstimator::ExactErrorEstimator(), ExactErrorEstimator::find_squared_element_error(), KellyErrorEstimator::internal_side_integration(), LaplacianErrorEstimator::internal_side_integration(), internal_side_integration(), KellyErrorEstimator::KellyErrorEstimator(), LaplacianErrorEstimator::LaplacianErrorEstimator(), PatchRecoveryErrorEstimator::EstimateError::operator()(), PatchRecoveryErrorEstimator::PatchRecoveryErrorEstimator(), and UniformRefinementEstimator::UniformRefinementEstimator().

unsigned int JumpErrorEstimator::fine_side [protected, inherited]

Which side of the fine element is this?

Definition at line 140 of file jump_error_estimator.h.

Referenced by JumpErrorEstimator::estimate_error(), and JumpErrorEstimator::reinit_sides().

bool JumpErrorEstimator::integrate_boundary_sides [protected, inherited]

A boolean flag, by default false, to be set to true if integrations with boundary_side_integration() should be performed

Definition at line 125 of file jump_error_estimator.h.

Referenced by KellyErrorEstimator::attach_flux_bc_function(), and JumpErrorEstimator::estimate_error().

A pointer to the current System

Definition at line 96 of file discontinuity_measure.h.

Referenced by boundary_side_integration(), and initialize().

This boolean flag allows you to scale the error indicator result for each element by the number of "flux faces" the element actually has. This tends to weight more evenly cells which are on the boundaries and thus have fewer contributions to their flux. The value is initialized to false, simply set it to true if you want to use the feature.

Definition at line 86 of file jump_error_estimator.h.

Referenced by JumpErrorEstimator::estimate_error().


The documentation for this class was generated from the following files:

Site Created By: libMesh Developers
Last modified: November 25 2009 03:44:04.

Hosted By:
SourceForge.net Logo