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