LCOV - code coverage report
Current view: top level - src/error_estimation - discontinuity_measure.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 37 67 55.2 %
Date: 2025-08-19 19:27:09 Functions: 3 6 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : // C++ includes
      20             : #include <algorithm> // for std::fill
      21             : #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
      22             : #include <cmath>    // for sqrt
      23             : 
      24             : 
      25             : // Local Includes
      26             : #include "libmesh/libmesh_common.h"
      27             : #include "libmesh/discontinuity_measure.h"
      28             : #include "libmesh/error_vector.h"
      29             : #include "libmesh/fe_base.h"
      30             : #include "libmesh/libmesh_logging.h"
      31             : #include "libmesh/elem.h"
      32             : #include "libmesh/system.h"
      33             : #include "libmesh/dense_vector.h"
      34             : #include "libmesh/tensor_tools.h"
      35             : #include "libmesh/enum_error_estimator_type.h"
      36             : #include "libmesh/enum_norm_type.h"
      37             : 
      38             : namespace libMesh
      39             : {
      40             : 
      41        7881 : DiscontinuityMeasure::DiscontinuityMeasure() :
      42             :   JumpErrorEstimator(),
      43        7881 :   _bc_function(nullptr)
      44             : {
      45        7881 :   error_norm = L2;
      46        7881 : }
      47             : 
      48             : 
      49             : 
      50             : ErrorEstimatorType
      51           0 : DiscontinuityMeasure::type() const
      52             : {
      53           0 :   return DISCONTINUITY_MEASURE;
      54             : }
      55             : 
      56             : 
      57             : 
      58             : void
      59       15762 : DiscontinuityMeasure::init_context(FEMContext & c)
      60             : {
      61         444 :   const unsigned int n_vars = c.n_vars();
      62       31524 :   for (unsigned int v=0; v<n_vars; v++)
      63             :     {
      64             :       // Possibly skip this variable
      65       15762 :       if (error_norm.weight(v) == 0.0) continue;
      66             : 
      67             :       // FIXME: Need to generalize this to vector-valued elements. [PB]
      68         444 :       FEBase * side_fe = nullptr;
      69             : 
      70             :       const std::set<unsigned char> & elem_dims =
      71         444 :         c.elem_dimensions();
      72             : 
      73       31524 :       for (const auto & dim : elem_dims)
      74             :         {
      75       15762 :           c.get_side_fe( v, side_fe, dim );
      76             : 
      77             :           // We'll need values and mapping Jacobians on both sides for
      78             :           // discontinuity computation
      79         444 :           side_fe->get_phi();
      80             : 
      81             :           // But we only need mapping Jacobians from one side
      82       15762 :           if (&c != coarse_context.get())
      83         555 :             side_fe->get_JxW();
      84             :         }
      85             :     }
      86       15762 : }
      87             : 
      88             : 
      89             : 
      90             : void
      91      113985 : DiscontinuityMeasure::internal_side_integration ()
      92             : {
      93       19017 :   const Elem & coarse_elem = coarse_context->get_elem();
      94       19017 :   const Elem & fine_elem = fine_context->get_elem();
      95             : 
      96        9508 :   FEBase * fe_fine = nullptr;
      97      113985 :   fine_context->get_side_fe( var, fe_fine, fine_elem.dim() );
      98             : 
      99        9508 :   FEBase * fe_coarse = nullptr;
     100      113985 :   coarse_context->get_side_fe( var, fe_coarse, fine_elem.dim() );
     101             : 
     102        9508 :   Real error = 1.e-30;
     103      113985 :   unsigned int n_qp = fe_fine->n_quadrature_points();
     104             : 
     105       28527 :   const std::vector<Real> & JxW_face = fe_fine->get_JxW();
     106             : 
     107      476940 :   for (unsigned int qp=0; qp != n_qp; ++qp)
     108             :     {
     109             :       // Calculate solution values on fine and coarse elements
     110             :       // at this quadrature point
     111             :       Number
     112      362955 :         u_fine   = fine_context->side_value(var, qp),
     113      362955 :         u_coarse = coarse_context->side_value(var, qp);
     114             : 
     115             :       // Find the jump in the value
     116             :       // at this quadrature point
     117      332689 :       const Number jump = u_fine - u_coarse;
     118       30264 :       const Real jump2 = TensorTools::norm_sq(jump);
     119             :       // Accumulate the jump integral
     120      393220 :       error += JxW_face[qp] * jump2;
     121             :     }
     122             : 
     123             :   // Add the h-weighted jump integral to each error term
     124      113985 :   fine_error =
     125      113985 :     error * fine_elem.hmax() * error_norm.weight(var);
     126      113985 :   coarse_error =
     127      113985 :     error * coarse_elem.hmax() * error_norm.weight(var);
     128      113985 : }
     129             : 
     130             : 
     131             : bool
     132           0 : DiscontinuityMeasure::boundary_side_integration ()
     133             : {
     134           0 :   const Elem & fine_elem = fine_context->get_elem();
     135             : 
     136           0 :   FEBase * fe_fine = nullptr;
     137           0 :   fine_context->get_side_fe( var, fe_fine, fine_elem.dim() );
     138             : 
     139             :   const std::string & var_name =
     140           0 :     fine_context->get_system().variable_name(var);
     141             : 
     142           0 :   const std::vector<Real> & JxW_face = fe_fine->get_JxW();
     143           0 :   const std::vector<Point> & qface_point = fe_fine->get_xyz();
     144             : 
     145             :   // The reinitialization also recomputes the locations of
     146             :   // the quadrature points on the side.  By checking if the
     147             :   // first quadrature point on the side is on an essential boundary
     148             :   // for a particular variable, we will determine if the whole
     149             :   // element is on an essential boundary (assuming quadrature points
     150             :   // are strictly contained in the side).
     151           0 :   if (this->_bc_function(fine_context->get_system(),
     152           0 :                          qface_point[0], var_name).first)
     153             :     {
     154           0 :       const Real h = fine_elem.hmax();
     155             : 
     156             :       // The number of quadrature points
     157           0 :       const unsigned int n_qp = fe_fine->n_quadrature_points();
     158             : 
     159             :       // The error contribution from this face
     160           0 :       Real error = 1.e-30;
     161             : 
     162             :       // loop over the integration points on the face.
     163           0 :       for (unsigned int qp=0; qp<n_qp; qp++)
     164             :         {
     165             :           // Value of the imposed essential BC at this quadrature point.
     166             :           const std::pair<bool,Real> essential_bc =
     167           0 :             this->_bc_function(fine_context->get_system(), qface_point[qp],
     168             :                                var_name);
     169             : 
     170             :           // Be sure the BC function still thinks we're on the
     171             :           // essential boundary.
     172           0 :           libmesh_assert_equal_to (essential_bc.first, true);
     173             : 
     174             :           // The solution value on each point
     175           0 :           Number u_fine = fine_context->side_value(var, qp);
     176             : 
     177             :           // The difference between the desired BC and the approximate solution.
     178           0 :           const Number jump = essential_bc.second - u_fine;
     179             : 
     180             :           // The flux jump squared.  If using complex numbers,
     181             :           // norm_sq(z) returns |z|^2, where |z| is the modulus of z.
     182           0 :           const Real jump2 = TensorTools::norm_sq(jump);
     183             : 
     184             :           // Integrate the error on the face.  The error is
     185             :           // scaled by an additional power of h, where h is
     186             :           // the maximum side length for the element.  This
     187             :           // arises in the definition of the indicator.
     188           0 :           error += JxW_face[qp]*jump2;
     189             : 
     190             :         } // End quadrature point loop
     191             : 
     192           0 :       fine_error = error*h*error_norm.weight(var);
     193             : 
     194           0 :       return true;
     195             :     } // end if side on flux boundary
     196           0 :   return false;
     197             : }
     198             : 
     199             : 
     200             : 
     201             : void
     202           0 : DiscontinuityMeasure::attach_essential_bc_function (std::pair<bool,Real> fptr(const System & system,
     203             :                                                                               const Point & p,
     204             :                                                                               const std::string & var_name))
     205             : {
     206           0 :   _bc_function = fptr;
     207             : 
     208             :   // We may be turning boundary side integration on or off
     209           0 :   if (fptr)
     210           0 :     integrate_boundary_sides = true;
     211             :   else
     212           0 :     integrate_boundary_sides = false;
     213           0 : }
     214             : 
     215             : } // namespace libMesh

Generated by: LCOV version 1.14