LCOV - code coverage report
Current view: top level - include/utils - PointIndexedMap.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 52 53 98.1 %
Date: 2025-07-17 01:28:37 Functions: 8 8 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             : #pragma once
      11             : 
      12             : #include "MooseUtils.h"
      13             : #include "MooseHashing.h"
      14             : #include "libmesh/point.h"
      15             : 
      16             : /// An unordered map indexed by Point, eg 3 floating point numbers
      17             : /// Because floating point rounding errors can affect the hashing, eg the binning of values,
      18             : /// we may need to look near a Point/key for where the initial value was stored
      19             : struct PointIndexedMap
      20             : {
      21      116681 :   PointIndexedMap(const Point & mesh_max_coords)
      22      116681 :   {
      23      466724 :     for (auto i : make_range(LIBMESH_DIM))
      24      350043 :       normalization(i) =
      25      700086 :           MooseUtils::absoluteFuzzyEqual(mesh_max_coords(i), 0) ? 1 : mesh_max_coords(i);
      26      116681 :   }
      27             : 
      28             :   /**
      29             :    * Normalize, expand then round a point to create local bins
      30             :    * - normalize the point by dividing by the meshes max (non-zero) absolute coordinates
      31             :    * - multiply the result by 1e12 and round, which keeps a fixed number of digits
      32             :    */
      33     7781120 :   inline Point getRoundedPoint(const Point & p) const
      34             :   {
      35             :     // We cant support coordinates too far from the normalization point
      36             :     mooseAssert(p(0) / normalization(0) < 1 && p(1) / normalization(1) < 1 &&
      37             :                     p(2) / normalization(2) < 1,
      38             :                 "Point coordinates for indexing must be normalized below 1. "
      39             :                 "Point: "
      40             :                     << p << " normalization: " << normalization);
      41             : 
      42     7781120 :     std::vector<Real> rounded_p{round(p(0) / normalization(0) * pow(10, 12)),
      43     7781120 :                                 round(p(1) / normalization(1) * pow(10, 12)),
      44    15562240 :                                 round(p(2) / normalization(2) * pow(10, 12))};
      45    15562240 :     return Point(rounded_p[0], rounded_p[1], rounded_p[2]);
      46     7781120 :   }
      47             : 
      48             :   // This needs to be moved into libMesh according to Fande
      49             :   // The hash helps sort the points in buckets
      50             :   // Hashing the floats also leads to floating point comparison errors in their own way
      51             :   // We hash a rounding of the float instead
      52             :   struct hash_point
      53             :   {
      54     8274018 :     std::size_t operator()(const Point & p) const
      55             :     {
      56     8274018 :       std::size_t seed = 0;
      57     8274018 :       Moose::hash_combine(seed, p(0), p(1), p(2));
      58     8274018 :       return seed;
      59             :     }
      60             :   };
      61             : 
      62             :   /// The container indexed by points
      63             :   std::unordered_map<Point, Number, hash_point> base_map;
      64             : 
      65             :   /// Normalization factors used to scale points before insertions/comparisons
      66             :   Point normalization;
      67             : 
      68      462974 :   Number & operator[](Point p)
      69             :   {
      70      462974 :     auto it = find(p);
      71      462974 :     if (it != end())
      72      136689 :       return const_cast<Number &>(it->second);
      73             :     else
      74             :     {
      75      326285 :       const auto rp = getRoundedPoint(p);
      76      326285 :       return base_map[rp];
      77             :     }
      78             :   }
      79             : 
      80      360676 :   unsigned int hasKey(Point p)
      81             :   {
      82      360676 :     auto it = find(p);
      83      360676 :     if (it != end())
      84       95476 :       return true;
      85             :     else
      86      265200 :       return false;
      87             :   }
      88             : 
      89     1089471 :   std::unordered_map<Point, Number, hash_point>::const_iterator find(const Point & pt) const
      90             :   {
      91     1089471 :     const auto rp = getRoundedPoint(pt);
      92             : 
      93     1089471 :     auto it = base_map.find(rp);
      94     1089471 :     if (it != base_map.end())
      95      293793 :       return it;
      96             :     else
      97             :     {
      98             :       // Search the point with coordinates rounded down to origin
      99      795678 :       auto rounded = base_map.find(rp);
     100      795678 :       if (rounded != base_map.end())
     101           0 :         return rounded;
     102             : 
     103             :       // To store the output of tentative searches
     104      795678 :       std::unordered_map<Point, Number, hash_point>::const_iterator out;
     105             : 
     106             :       // Search in all directions around
     107     2386974 :       for (int i : make_range(2))
     108     4774008 :         for (int j : make_range(2))
     109     9548016 :           for (int k : make_range(2))
     110     6365364 :             if (attempt_find(pt, 2 * i - 1, 2 * j - 1, 2 * k - 1, out))
     111          60 :               return out;
     112             : 
     113      795618 :       return base_map.end();
     114             :     }
     115             :   }
     116             : 
     117     6365364 :   bool attempt_find(const Point & p,
     118             :                     Real dx,
     119             :                     Real dy,
     120             :                     Real dz,
     121             :                     std::unordered_map<Point, Number, hash_point>::const_iterator & out) const
     122             :   {
     123             :     // Some epsilon to move the point by.
     124             :     // There is no multiplicative epsilon that will reliably change the last decimal
     125     6365364 :     const auto eps = 1e-13;
     126    12730728 :     const auto shifted_rp = getRoundedPoint(p + Point(dx * eps * normalization(0),
     127     6365364 :                                                       dy * eps * normalization(1),
     128    12730728 :                                                       dz * eps * normalization(2)));
     129     6365364 :     out = base_map.find(shifted_rp);
     130     6365364 :     if (out != base_map.end())
     131          60 :       return true;
     132     6365304 :     return false;
     133             :   }
     134             : 
     135     1089471 :   std::unordered_map<Point, Number, hash_point>::const_iterator end() const
     136             :   {
     137     1089471 :     return base_map.end();
     138             :   }
     139             : };

Generated by: LCOV version 1.14