LCOV - code coverage report
Current view: top level - src/SBMBndElement - SBMBndElementBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose shifted_boundary_method: #33416 (b10b36) with base 9fbd27 Lines: 36 36 100.0 %
Date: 2026-07-23 16:20:15 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "SBMBndElementBase.h"
      11             : #include "Ball.h"
      12             : #include "GeometryBase.h"
      13             : #include "LineSegment.h"
      14             : #include "libmesh/string_to_enum.h"
      15             : 
      16         255 : SBMBndElementBase::SBMBndElementBase(const Elem * elem, const Point & normal)
      17         255 :   : _elem(elem), _normal(normal)
      18             : {
      19             :   mooseAssert(elem, "Element must not be null");
      20             :   mooseAssert(MooseUtils::absoluteFuzzyEqual(_normal.norm(), 1),
      21             :               "normal vector must be unit length, length = " << _normal.norm());
      22             : 
      23             :   // Validate side type once, here, so distanceFrom() can trust the invariant
      24             :   // without paying a per-call check. libMesh standard elements have uniform
      25             :   // side types, so probing side(0) is sufficient.
      26         255 :   if (elem && elem->n_sides() > 0)
      27             :   {
      28         255 :     const auto t = elem->build_side_ptr(0)->type();
      29         255 :     if (t != EDGE2 && t != NODEELEM)
      30           1 :       mooseError("SBMBndElementBase: unsupported side type ",
      31           2 :                  libMesh::Utility::enum_to_string(t),
      32             :                  " (from element type ",
      33           1 :                  libMesh::Utility::enum_to_string(elem->type()),
      34             :                  "). distanceFrom() only handles EDGE2 and NODEELEM sides.");
      35             :   }
      36         254 : }
      37             : 
      38             : Point
      39     3685190 : SBMBndElementBase::distanceFrom(const Point & pt) const
      40             : {
      41             :   // Side-type precondition is validated once in the base ctor; no per-call
      42             :   // check needed here.
      43             : 
      44             :   // (a) Project pt onto the normal direction
      45     3685190 :   const auto vec_to_first = _elem->point(0) - pt;
      46             :   const auto scale = vec_to_first * _normal;
      47             :   const auto projection = _normal * scale;
      48             : 
      49             :   // Check if projection point lands inside the geometry
      50     3685190 :   if (_elem->contains_point(pt + projection))
      51             :     return projection;
      52             : 
      53             :   // (d) Point to closest edge or node
      54             :   Real min_dist = std::numeric_limits<Real>::max();
      55             :   Point closest_vec;
      56             : 
      57     1680066 :   const unsigned int n_edges = _elem->n_sides();
      58     5679239 :   for (unsigned int j = 0; j < n_edges; ++j)
      59             :   {
      60     3999173 :     std::unique_ptr<const Elem> curr_edge = _elem->build_side_ptr(j);
      61             : 
      62     3999173 :     switch (curr_edge->type())
      63             :     {
      64             :       case EDGE2:
      65             :       {
      66             :         const Point & p1 = *curr_edge->node_ptr(0);
      67             :         const Point & p2 = *curr_edge->node_ptr(1);
      68             : 
      69             :         const Point edge = p2 - p1;
      70     1917123 :         Real t = ((pt - p1) * edge) / (edge * edge);
      71     3834246 :         t = std::clamp(t, 0.0, 1.0);
      72             :         const Point proj = p1 + t * edge;
      73     1917123 :         const Real dist = (pt - proj).norm();
      74             : 
      75     1917123 :         if (dist < min_dist)
      76             :         {
      77             :           min_dist = dist;
      78             :           closest_vec = proj - pt;
      79             :         }
      80             :         break;
      81             :       }
      82             : 
      83             :       case NODEELEM:
      84             :       {
      85             :         const Point & p = *curr_edge->node_ptr(0);
      86     2082050 :         const Real dist = (pt - p).norm();
      87     2082050 :         if (dist < min_dist)
      88             :         {
      89             :           min_dist = dist;
      90             :           closest_vec = p - pt;
      91             :         }
      92             :         break;
      93             :       }
      94             : 
      95     3999173 :       default:
      96             :         mooseAssert(false, "unreachable: side type validated in SBMBndElementBase ctor");
      97             :     }
      98     3999173 :   }
      99             : 
     100     1680066 :   return closest_vec;
     101             : }
     102             : 
     103             : Real
     104           2 : SBMBndElementBase::getProjectedBoundingBoxDiagonal(const Point & normal_dir) const
     105             : {
     106           2 :   BoundingBox bbox = _elem->loose_bounding_box();
     107             : 
     108             :   const Point & min_pt = bbox.first;
     109             :   const Point & max_pt = bbox.second;
     110             : 
     111             :   // Step (a): Calculate box_vec
     112             :   Point box_vec = max_pt - min_pt;
     113             : 
     114             :   // Step (b): Project box_vec onto normal_dir
     115             :   Real normal_scale = box_vec * normal_dir;
     116             :   Point normal_box_vec = normal_dir * normal_scale;
     117             : 
     118             :   // Step (c): Calculate tangent_vec and its norm
     119             :   Point tangent_vec = box_vec - normal_box_vec;
     120             : 
     121           2 :   return tangent_vec.norm();
     122             : }
     123             : 
     124             : bool
     125           5 : SBMBndElementBase::intersect(const LineSegment & line_segment) const
     126             : {
     127           5 :   if (const auto * geom = dynamic_cast<const GeometryBase *>(this))
     128           4 :     return geom->intersect(line_segment);
     129             : 
     130           1 :   mooseError("SBMBndElementBase::intersect: unsupported geometry type");
     131             : }
     132             : 
     133             : Ball
     134           3 : SBMBndElementBase::computeBoundingBall() const
     135             : {
     136           3 :   if (const auto * geom = dynamic_cast<const GeometryBase *>(this))
     137           2 :     return geom->computeBoundingBall();
     138             : 
     139           1 :   mooseError("SBMBndElementBase::computeBoundingBall: unsupported geometry type");
     140             : }

Generated by: LCOV version 1.14