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 : #ifndef LIBMESH_SIMPLEX_REFINER_H 20 : #define LIBMESH_SIMPLEX_REFINER_H 21 : 22 : #include "libmesh/libmesh_config.h" 23 : 24 : // Local Includes 25 : #include "libmesh/elem.h" 26 : #include "libmesh/function_base.h" 27 : 28 : #include <map> 29 : #include <memory> 30 : #include <tuple> 31 : #include <unordered_map> 32 : #include <utility> 33 : #include <vector> 34 : 35 : namespace libMesh 36 : { 37 : 38 : // Forward Declarations 39 : class UnstructuredMesh; 40 : class Node; 41 : 42 : /** 43 : * A C++ class to refine a simplicial mesh via splitting edges that 44 : * exceed a given metric. 45 : * 46 : * \author Roy H. Stogner 47 : * \date 2024 48 : */ 49 : class SimplexRefiner 50 : { 51 : public: 52 : /** 53 : * The constructor. A reference to the mesh containing the elements 54 : * which are to be split by edge subdivision must be provided. 55 : * 56 : * At the time of refining this mesh should be conforming. 57 : */ 58 : explicit 59 : SimplexRefiner(UnstructuredMesh & mesh); 60 : 61 : /** 62 : * Finds elements which exceed the requested metric and refines them 63 : * via subdivision into new simplices as necessary. 64 : * 65 : * \returns \p true iff the mesh actually changed. 66 : */ 67 : bool refine_elements (); 68 : 69 : /** 70 : * Set a function giving desired element volume as a function of 71 : * position. Set this to nullptr to disable position-dependent volume 72 : * constraint (falling back on desired_volume()). 73 : */ 74 : virtual void set_desired_volume_function (FunctionBase<Real> * desired); 75 : 76 : /** 77 : * Get the function giving desired element volume as a function of 78 : * position, or \p nullptr if no such function has been set. 79 : */ 80 : virtual FunctionBase<Real> * get_desired_volume_function (); 81 : 82 : /** 83 : * Sets and/or gets the desired element volume. Set to zero to disable 84 : * volume constraint. 85 : * 86 : * If a \p desired_volume_function is set, then \p desired_volume() 87 : * should be used to set a *minimum* desired volume; this will reduce 88 : * "false negatives" by suggesting how finely to sample \p 89 : * desired_volume_function inside large elements, where ideally the 90 : * \p desired_volume_function will be satisfied in the element 91 : * interior and not just at the element vertices. 92 : */ 93 0 : Real & desired_volume() {return _desired_volume;} 94 : 95 : protected: 96 : 97 : /** 98 : * Finds elements which exceed the requested metric and refines them 99 : * via inserting new midedge nodes and bisecting as necessary. 100 : * 101 : * \returns the number of refined elements 102 : */ 103 : std::size_t refine_via_edges(); 104 : 105 : /** 106 : * Checks if an element exceeds the requested metric 107 : */ 108 : bool should_refine_elem(Elem & elem); 109 : 110 : /** 111 : * Checks if an element exceeds the requested metric or if it 112 : * has an edge which was split by a neighboring metric and refines 113 : * it (bisecting it, removing it from the mesh to be replaced by the 114 : * two subelements, and recursing into those) if necessary. 115 : * 116 : * The \p coarse_id specifies which coarse element this one is (or 117 : * which this one was originally refined from), to make global 118 : * communication easier after local refinement is done. 119 : * 120 : * \returns the number of refinements done; this may be greater than 121 : * 1 if subelements were themselves refined. 122 : */ 123 : 124 : std::size_t refine_via_edges(Elem & elem, 125 : dof_id_type coarse_id); 126 : 127 : private: 128 : 129 : /** 130 : * Reference to the mesh which is to be refined. 131 : */ 132 : UnstructuredMesh & _mesh; 133 : 134 : /** 135 : * The desired volume for the elements in the resulting mesh. 136 : */ 137 : Real _desired_volume; 138 : 139 : /** 140 : * Location-dependent volume requirements 141 : */ 142 : std::unique_ptr<FunctionBase<Real>> _desired_volume_func; 143 : 144 : /** 145 : * Keep track of new nodes on edges. A new node x in between node y 146 : * and node z (with y<z) will be reflected by new_nodes[(y,z)]=x 147 : */ 148 : std::map<std::pair<Node *, Node *>, Node *> new_nodes; 149 : 150 : /** 151 : * Keep track of elements to add so we don't invalidate iterators 152 : * during an iteration over elements. 153 : */ 154 : std::vector<std::unique_ptr<Elem>> new_elements; 155 : 156 : /** 157 : * Keep track of coarse remote edges for which we should query about 158 : * additional point splits 159 : */ 160 : std::unordered_map 161 : <processor_id_type, 162 : std::vector<std::pair<dof_id_type, dof_id_type>>> 163 : edge_queries; 164 : 165 : // All the "refine first and second to get third" that was 166 : // done to this edge, including the processor to assign the new node 167 : // to. 168 : typedef 169 : std::vector<std::tuple<dof_id_type, dof_id_type, 170 : dof_id_type, processor_id_type>> 171 : refinement_datum; 172 : 173 : /** 174 : * Helper for responding to edge queries 175 : */ 176 : void fill_refinement_datum(std::pair<Node *, Node *> vertices, 177 : refinement_datum & vec); 178 : 179 : /** 180 : * Keep track of elements added within each original element, so we 181 : * can answer queries about them from other processors. If the 182 : * element originally with id i is split, its replacements e1 and e2 183 : * will be in added_elements[i][ei.vertex_average()] 184 : */ 185 : std::unordered_map<dof_id_type, std::unordered_map<Point, Elem *>> added_elements; 186 : 187 : /** 188 : * Keep track of added elements' original coarse ids, so we get 189 : * subsequent splits assigned to the correct coarse id. 190 : */ 191 : std::unordered_map<Elem *, dof_id_type> coarse_parent; 192 : 193 : /** 194 : * Keep track of what processor an element's neighbors came from 195 : */ 196 : std::unordered_map<processor_id_type, std::unique_ptr<Elem>> proxy_elements; 197 : }; 198 : 199 : 200 : } // namespace libMesh 201 : 202 : #endif // ifndef LIBMESH_SIMPLEX_REFINER_H