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 123799 : PointIndexedMap(const Point & mesh_max_coords) 22 123799 : { 23 495196 : for (auto i : make_range(LIBMESH_DIM)) 24 371397 : normalization(i) = 25 742794 : MooseUtils::absoluteFuzzyEqual(mesh_max_coords(i), 0) ? 1 : mesh_max_coords(i); 26 123799 : } 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 8739856 : 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 8739856 : std::vector<Real> rounded_p{round(p(0) / normalization(0) * pow(10, 12)), 43 8739856 : round(p(1) / normalization(1) * pow(10, 12)), 44 17479712 : round(p(2) / normalization(2) * pow(10, 12))}; 45 17479712 : return Point(rounded_p[0], rounded_p[1], rounded_p[2]); 46 8739856 : } 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 9330534 : std::size_t operator()(const Point & p) const 55 : { 56 9330534 : std::size_t seed = 0; 57 9330534 : Moose::hash_combine(seed, p(0), p(1), p(2)); 58 9330534 : 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 519026 : Number & operator[](Point p) 69 : { 70 519026 : auto it = find(p); 71 519026 : if (it != end()) 72 151957 : return const_cast<Number &>(it->second); 73 : else 74 : { 75 367069 : const auto rp = getRoundedPoint(p); 76 367069 : return base_map[rp]; 77 : } 78 : } 79 : 80 393826 : unsigned int hasKey(Point p) 81 : { 82 393826 : auto it = find(p); 83 393826 : if (it != end()) 84 95476 : return true; 85 : else 86 298350 : return false; 87 : } 88 : 89 1211823 : std::unordered_map<Point, Number, hash_point>::const_iterator find(const Point & pt) const 90 : { 91 1211823 : const auto rp = getRoundedPoint(pt); 92 : 93 1211823 : auto it = base_map.find(rp); 94 1211823 : if (it != base_map.end()) 95 316695 : return it; 96 : else 97 : { 98 : // Search the point with coordinates rounded down to origin 99 895128 : auto rounded = base_map.find(rp); 100 895128 : if (rounded != base_map.end()) 101 0 : return rounded; 102 : 103 : // To store the output of tentative searches 104 895128 : std::unordered_map<Point, Number, hash_point>::const_iterator out; 105 : 106 : // Search in all directions around 107 2685324 : for (int i : make_range(2)) 108 5370708 : for (int j : make_range(2)) 109 10741416 : for (int k : make_range(2)) 110 7160964 : if (attempt_find(pt, 2 * i - 1, 2 * j - 1, 2 * k - 1, out)) 111 60 : return out; 112 : 113 895068 : return base_map.end(); 114 : } 115 : } 116 : 117 7160964 : 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 7160964 : const auto eps = 1e-13; 126 14321928 : const auto shifted_rp = getRoundedPoint(p + Point(dx * eps * normalization(0), 127 7160964 : dy * eps * normalization(1), 128 14321928 : dz * eps * normalization(2))); 129 7160964 : out = base_map.find(shifted_rp); 130 7160964 : if (out != base_map.end()) 131 60 : return true; 132 7160904 : return false; 133 : } 134 : 135 1211823 : std::unordered_map<Point, Number, hash_point>::const_iterator end() const 136 : { 137 1211823 : return base_map.end(); 138 : } 139 : };