Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/Inciter/Refiner.hpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.,
7 : : 2022-2024 J. Bakosi
8 : : All rights reserved. See the LICENSE file for details.
9 : : \brief Mesh refiner for interfacing the mesh refinement library
10 : : \details Mesh refiner is a Charm++ chare array and is used to interface the
11 : : mesh refinement object which does not know about parallelization and thus the
12 : : distributed nature of the mesh it operates on, i.e., it operates on mesh
13 : : chunks. Thus it does not do parallel communication and also does not know
14 : : about global vs local IDs. Instead this Charm++ chare array is the one that
15 : : does all parallel computing aspects, i.e., communcation, and using the mesh
16 : : refiner object as a library.
17 : : */
18 : : // *****************************************************************************
19 : : #pragma once
20 : :
21 : : #include <vector>
22 : : #include <unordered_map>
23 : :
24 : : #include "PUPAMR.hpp"
25 : : #include "AMR/mesh_adapter.hpp"
26 : : #include "TaggedTuple.hpp"
27 : : #include "Callback.hpp"
28 : : #include "UnsMesh.hpp"
29 : : #include "Base/Fields.hpp"
30 : : #include "RieCG.hpp"
31 : : #include "LaxCG.hpp"
32 : : #include "ZalCG.hpp"
33 : : #include "KozCG.hpp"
34 : : #include "ChoCG.hpp"
35 : : #include "LohCG.hpp"
36 : :
37 : : #include "NoWarning/transporter.decl.h"
38 : : #include "NoWarning/refiner.decl.h"
39 : :
40 : : namespace inciter {
41 : :
42 : : //! Mesh refiner for interfacing the mesh refinement library
43 : : class Refiner : public CBase_Refiner {
44 : :
45 : : private:
46 : : using Edge = tk::UnsMesh::Edge;
47 : : using Face = tk::UnsMesh::Face;
48 : : using Tet = tk::UnsMesh::Tet;
49 : : using EdgeSet = tk::UnsMesh::EdgeSet;
50 : : using FaceSet = tk::UnsMesh::FaceSet;
51 : : using TetSet = tk::UnsMesh::TetSet;
52 : : template< std::size_t N > using Hash = tk::UnsMesh::Hash< N >;
53 : : template< std::size_t N > using Eq = tk::UnsMesh::Eq< N >;
54 : :
55 : : //! Boundary face data, see boundary()
56 : : using BndFaceData = std::unordered_map< Face, std::size_t, Hash<3>, Eq<3> >;
57 : :
58 : : //! Used to associate error to edges
59 : : using EdgeError = std::unordered_map< Edge, tk::real, Hash<2>, Eq<2> >;
60 : :
61 : : public:
62 : : //! Mode of operation: the way Refiner is used
63 : : enum class RefMode : std::size_t {
64 : : T0REF = 1 //!< Initial (t<0) refinement
65 : : , DTREF //!< During time stepping (t>0)
66 : : };
67 : :
68 : : //! Constructor
69 : : explicit Refiner( std::size_t meshid,
70 : : const CProxy_Transporter& transporter,
71 : : const CProxy_Sorter& sorter,
72 : : const tk::CProxy_MeshWriter& meshwriter,
73 : : const CProxy_Discretization& discretization,
74 : : const CProxy_RieCG& riecg,
75 : : const CProxy_LaxCG& laxcg,
76 : : const CProxy_ZalCG& zalcg,
77 : : const CProxy_KozCG& kozcg,
78 : : const CProxy_ChoCG& chocg,
79 : : const CProxy_LohCG& lohcg,
80 : : const tk::CProxy_ConjugateGradients& cgpre,
81 : : const tk::CProxy_ConjugateGradients& cgmom,
82 : : const tk::RefinerCallback& cbr,
83 : : const tk::SorterCallback& cbs,
84 : : const std::vector< std::size_t >& ginpoel,
85 : : const tk::UnsMesh::CoordMap& coordmap,
86 : : const std::map< int, std::vector< std::size_t > >& bface,
87 : : const std::vector< std::size_t >& triinpoel,
88 : : const std::map< int, std::vector< std::size_t > >& bnode,
89 : : int nchare );
90 : :
91 : : #if defined(__clang__)
92 : : #pragma clang diagnostic push
93 : : #pragma clang diagnostic ignored "-Wundefined-func-template"
94 : : #endif
95 : : //! Migrate constructor
96 : : // cppcheck-suppress uninitMemberVar
97 [ + - ][ + - ]: 4675 : explicit Refiner( CkMigrateMessage* m ) : CBase_Refiner( m ) {}
98 : : #if defined(__clang__)
99 : : #pragma clang diagnostic pop
100 : : #endif
101 : :
102 : : //! \brief Incoming query for a list boundary edges for which this chare
103 : : //! compiles shared edges
104 : : void query( int fromch, const EdgeSet& edges );
105 : : //! Receive receipt of boundary edge lists to quer
106 : : void recvquery();
107 : : //! Respond to boundary edge list queries
108 : : void response();
109 : : //! Receive shared boundary edges for our mesh chunk
110 : : void bnd( int fromch, const std::vector< int >& chares );
111 : : //! Receive receipt of shared boundary edges
112 : : void recvbnd();
113 : :
114 : : //! Query Sorter and update local mesh with the reordered one
115 : : void reorder();
116 : :
117 : : //! Start new step of initial mesh refinement/derefinement
118 : : void start();
119 : :
120 : : //! Continue after finishing a refinemen/derefinementt step
121 : : void next();
122 : :
123 : : //! Start mesh refinement (during time stepping, t>0)
124 : : void dtref( const std::map< int, std::vector< std::size_t > >& bface,
125 : : const std::map< int, std::vector< std::size_t > >& bnode,
126 : : const std::vector< std::size_t >& triinpoel );
127 : :
128 : : //! Do a single step of mesh refinemen/derefinementt (only tag edges)
129 : : void refine();
130 : :
131 : : //! Receive newly added mesh edges and locks on our chare boundary
132 : : void addRefBndEdges( int fromch,
133 : : const AMR::EdgeData& ed,
134 : : const std::unordered_set<size_t>& intermediates );
135 : :
136 : : //! Correct refinement to arrive at conforming mesh across chare boundaries
137 : : void correctref();
138 : :
139 : : //! Communicate refined edges after a refinement/derefinement step
140 : : void comExtra();
141 : :
142 : : //! Perform mesh refinement and decide how to continue
143 : : void perform();
144 : :
145 : : //! Send Refiner proxy to Discretization objects
146 : : void sendProxy();
147 : :
148 : : //! Get refinement field data in mesh cells
149 : : std::tuple< std::vector< std::string >,
150 : : std::vector< std::vector< tk::real > >,
151 : : std::vector< std::string >,
152 : : std::vector< std::vector< tk::real > > >
153 : : refinementFields() const;
154 : :
155 : : /** @name Charm++ pack/unpack serializer member functions */
156 : : ///@{
157 : : //! \brief Pack/Unpack serialize member function
158 : : //! \param[in,out] p Charm++'s PUP::er serializer object reference
159 : 14707 : void pup( PUP::er &p ) override {
160 : 14707 : p | m_meshid;
161 : 14707 : p | m_ncit;
162 : 14707 : p | m_host;
163 : 14707 : p | m_sorter;
164 : 14707 : p | m_meshwriter;
165 : 14707 : p | m_disc;
166 : 14707 : p | m_riecg;
167 : 14707 : p | m_laxcg;
168 : 14707 : p | m_zalcg;
169 : 14707 : p | m_kozcg;
170 : 14707 : p | m_chocg;
171 : 14707 : p | m_lohcg;
172 : 14707 : p | m_cgpre;
173 : 14707 : p | m_cgmom;
174 : 14707 : p | m_cbr;
175 : 14707 : p | m_cbs;
176 : 14707 : p | m_ginpoel;
177 : 14707 : p | m_el;
178 [ + + ]: 14707 : if (p.isUnpacking()) {
179 : 4675 : m_inpoel = std::get< 0 >( m_el );
180 : 4675 : m_gid = std::get< 1 >( m_el );
181 : 4675 : m_lid = std::get< 2 >( m_el );
182 : : }
183 : 14707 : p | m_coordmap;
184 : 14707 : p | m_coord;
185 : 14707 : p | m_bface;
186 : 14707 : p | m_bnode;
187 : 14707 : p | m_triinpoel;
188 : 14707 : p | m_nchare;
189 : 14707 : p | m_mode;
190 : 14707 : p | m_initref;
191 : 14707 : p | m_refiner;
192 : 14707 : p | m_nref;
193 : 14707 : p | m_nbnd;
194 : 14707 : p | m_extra;
195 : 14707 : p | m_ch;
196 : 14707 : p | m_edgech;
197 : 14707 : p | m_chedge;
198 : 14707 : p | m_localEdgeData;
199 : 14707 : p | m_remoteEdgeData;
200 : 14707 : p | m_remoteEdges;
201 : 14707 : p | m_intermediates;
202 : 14707 : p | m_nodeCommMap;
203 : 14707 : p | m_oldTets;
204 : 14707 : p | m_addedNodes;
205 : 14707 : p | m_addedTets;
206 : 14707 : p | m_removedNodes;
207 : 14707 : p | m_amrNodeMap;
208 : 14707 : p | m_oldntets;
209 : 14707 : p | m_coarseBndFaces;
210 : 14707 : p | m_coarseBndNodes;
211 : 14707 : p | m_rid;
212 : : //p | m_oldrid;
213 : 14707 : p | m_lref;
214 : : //p | m_oldlref;
215 : : //p | m_oldparent;
216 : 14707 : p | m_writeCallback;
217 : 14707 : }
218 : : //! \brief Pack/Unpack serialize operator|
219 : : //! \param[in,out] p Charm++'s PUP::er serializer object reference
220 : : //! \param[in,out] r Refiner object reference
221 : : friend void operator|( PUP::er& p, Refiner& r ) { r.pup(p); }
222 : : //@}
223 : :
224 : : private:
225 : : //! Mesh ID
226 : : std::size_t m_meshid;
227 : : //! Number of parallel-compatibility (mesh ref correction) iterations
228 : : std::size_t m_ncit;
229 : : //! Host proxy
230 : : CProxy_Transporter m_host;
231 : : //! Mesh sorter proxy
232 : : CProxy_Sorter m_sorter;
233 : : //! Mesh writer proxy
234 : : tk::CProxy_MeshWriter m_meshwriter;
235 : : //! Discretization base proxy
236 : : CProxy_Discretization m_disc;
237 : : //! Discretization scheme proxy
238 : : CProxy_RieCG m_riecg;
239 : : //! Discretization scheme proxy
240 : : CProxy_LaxCG m_laxcg;
241 : : //! Discretization scheme proxy
242 : : CProxy_ZalCG m_zalcg;
243 : : //! Discretization scheme proxy
244 : : CProxy_KozCG m_kozcg;
245 : : //! Discretization scheme proxy
246 : : CProxy_ChoCG m_chocg;
247 : : //! Discretization scheme proxy
248 : : CProxy_LohCG m_lohcg;
249 : : //! Conjugate Gradients Charm++ proxy for pressure solve
250 : : tk::CProxy_ConjugateGradients m_cgpre;
251 : : //! Conjugate Gradients Charm++ proxy for momentum solve
252 : : tk::CProxy_ConjugateGradients m_cgmom;
253 : : //! Charm++ callbacks associated to compile-time tags for refiner
254 : : tk::RefinerCallback m_cbr;
255 : : //! Charm++ callbacks associated to compile-time tags for sorter
256 : : tk::SorterCallback m_cbs;
257 : : //! Tetrtahedron element connectivity of our chunk of the mesh (global ids)
258 : : std::vector< std::size_t > m_ginpoel;
259 : : //! Elements of the mesh chunk we operate on
260 : : //! \details The first vector is the element connectivity (local IDs), the
261 : : //! second vector is the global node IDs of owned elements, while the
262 : : //! third one is a map of global->local node IDs.
263 : : tk::UnsMesh::Chunk m_el;
264 : : //! Alias to element connectivity with local node IDs in m_el
265 : : std::vector< std::size_t >& m_inpoel = std::get<0>( m_el );
266 : : //! Alias to global node IDs of owned elements in m_el
267 : : std::vector< std::size_t >& m_gid = std::get<1>( m_el );
268 : : //! \brief Alias to local node IDs associated to the global ones of owned
269 : : //! elements in m_el
270 : : std::unordered_map< std::size_t, std::size_t >& m_lid = std::get<2>( m_el );
271 : : //! Coordinates associated to global node IDs of our mesh chunk
272 : : tk::UnsMesh::CoordMap m_coordmap;
273 : : //! Coordinates of mesh nodes of our chunk of the mesh
274 : : tk::UnsMesh::Coords m_coord;
275 : : //! List of boundary faces associated to side-set IDs
276 : : std::map< int, std::vector< std::size_t > > m_bface;
277 : : //! List of boundary nodes associated to side-set IDs
278 : : std::map< int, std::vector< std::size_t > > m_bnode;
279 : : //! Boundary face-node connectivity
280 : : std::vector< std::size_t > m_triinpoel;
281 : : //! Total number of refiner chares
282 : : int m_nchare;
283 : : //! True if initial AMR, false if during time stepping
284 : : RefMode m_mode;
285 : : //! Initial mesh refinement type list (in reverse order)
286 : : std::vector< std::string > m_initref;
287 : : //! Number of initial mesh refinement/derefinement steps
288 : : std::size_t m_ninitref;
289 : : //! Mesh refiner (library) object
290 : : AMR::mesh_adapter_t m_refiner;
291 : : //! Counter during distribution of newly added nodes to chare-boundary edges
292 : : std::size_t m_nref;
293 : : //! Counter for number of chares contributing to chare boundary edges
294 : : std::size_t m_nbnd;
295 : : //! Number of chare-boundary newly added nodes that need correction
296 : : std::size_t m_extra;
297 : : //! Chares we share at least a single edge with
298 : : std::unordered_set< int > m_ch;
299 : : //! Edge->chare map used to build shared boundary edges
300 : : std::unordered_map< Edge, std::vector< int >, Hash<2>, Eq<2> > m_edgech;
301 : : //! Chare->edge map used to build shared boundary edges
302 : : std::unordered_map< int, EdgeSet > m_chedge;
303 : : //! Refinement data associated to edges (edges stored with node-gids)
304 : : AMR::EdgeData m_localEdgeData;
305 : : //! \brief Refinement data associated to edges shared with other chares
306 : : //! (edges stored with node-gids)
307 : : std::unordered_map< int, std::vector< std::tuple<
308 : : Edge, int, int, AMR::Edge_Lock_Case > > > m_remoteEdgeData;
309 : : //! Edges received from other chares
310 : : std::unordered_map< int, std::vector< Edge > > m_remoteEdges;
311 : : //! Intermediate nodes
312 : : std::unordered_set< size_t> m_intermediates;
313 : : //! \brief Global mesh node IDs bordering the mesh chunk held by fellow
314 : : //! worker chares associated to their chare IDs for the coarse mesh
315 : : std::unordered_map< int, std::unordered_set< std::size_t > > m_nodeCommMap;
316 : : //! Tetrahedra before refinement/derefinement step
317 : : TetSet m_oldTets;
318 : : //! Newly added mesh nodes (local id) and their parents (local ids)
319 : : std::unordered_map< std::size_t, Edge > m_addedNodes;
320 : : //! Newly added mesh cells (local id) and their parent (local id)
321 : : std::unordered_map< std::size_t, std::size_t > m_addedTets;
322 : : //! Newly removed mesh node local ids
323 : : std::set< std::size_t > m_removedNodes;
324 : : //! Node id maps from old mesh to new refined mesh
325 : : std::unordered_map< std::size_t, std::size_t > m_amrNodeMap;
326 : : //! Number of tetrahedra in the mesh before refinement/derefinement step
327 : : std::size_t m_oldntets;
328 : : //! A unique set of faces associated to side sets of the coarsest mesh
329 : : std::unordered_map< int, FaceSet > m_coarseBndFaces;
330 : : //! A unique set of nodes associated to side sets of the coarsest mesh
331 : : std::unordered_map< int, std::unordered_set<std::size_t> > m_coarseBndNodes;
332 : : //! Local -> refiner lib node id map
333 : : std::vector< std::size_t > m_rid;
334 : : //! Local -> refiner lib node id map for previous mesh
335 : : //std::vector< std::size_t > m_oldrid;
336 : : //! Refiner lib -> local node id map
337 : : std::unordered_map< std::size_t, std::size_t > m_lref;
338 : : //! Refiner lib -> local node id map for previous mesh
339 : : //std::unordered_map< std::size_t, std::size_t > m_oldlref;
340 : : //! Child -> parent tet map for previous mesh
341 : : //std::unordered_map< Tet, Tet, Hash<4>, Eq<4> > m_oldparent;
342 : : //! Function to continue with after writing field output
343 : : CkCallback m_writeCallback;
344 : :
345 : : //! (Re-)generate local -> refiner lib node id map and its inverse
346 : : void libmap();
347 : :
348 : : //! (Re-)generate side set and block data structures for coarse mesh
349 : : void coarseMesh();
350 : :
351 : : //! Generate flat coordinate data from coordinate map
352 : : tk::UnsMesh::Coords flatcoord( const tk::UnsMesh::CoordMap& coordmap );
353 : :
354 : : //! Output mesh to file before a new step of mesh refinement/derefinement
355 : : void t0ref();
356 : :
357 : : //! Generate boundary edges and send them to all chares
358 : : void bndEdges();
359 : :
360 : : //! Finish initiel mesh refinement
361 : : void endt0ref();
362 : :
363 : : //! Do uniform mesh refinement
364 : : void uniformRefine();
365 : :
366 : : //! Do uniform mesh derefinement
367 : : void uniformDeRefine();
368 : :
369 : : //! Do error-based mesh refinement
370 : : void errorRefine();
371 : :
372 : : //! Compute errors in edges
373 : : EdgeError
374 : : errorsInEdges( std::size_t npoin,
375 : : const std::pair< std::vector< std::size_t >,
376 : : std::vector< std::size_t > >& esup,
377 : : const tk::Fields& u ) const;
378 : :
379 : : //! Update (or evaluate) solution on current mesh
380 : : tk::Fields
381 : : solution( std::size_t npoin,
382 : : const std::pair< std::vector< std::size_t >,
383 : : std::vector< std::size_t > >& esup ) const;
384 : :
385 : : //! Do mesh refinement based on user explicitly tagging edges
386 : : void edgelistRefine();
387 : :
388 : : //! Do mesh refinement based on tagging edges based on end-point coordinates
389 : : void coordRefine();
390 : :
391 : : //! Query AMR lib and update our local store of edge data
392 : : void updateEdgeData();
393 : :
394 : : //! Query AMR lib and update our local store of boundary edge data
395 : : void updateBndEdgeData();
396 : :
397 : : //! Aggregate number of extra edges across all chares
398 : : void matched();
399 : :
400 : : //! Update old mesh after refinement
401 : : void updateMesh();
402 : :
403 : : //! Update volume mesh after mesh refinement
404 : : void newVolMesh( const std::unordered_set< std::size_t >& old,
405 : : const std::unordered_set< std::size_t >& ref );
406 : :
407 : : //! Update boundary data structures after mesh refinement
408 : : void newBndMesh( const std::unordered_set< std::size_t >& ref );
409 : :
410 : : //! \brief Generate boundary data structures used to update
411 : : //! refined/derefined boundary faces and nodes of side sets
412 : : BndFaceData boundary();
413 : :
414 : : //! Regenerate boundary faces and nodes after AMR step
415 : : void updateBndData( const std::unordered_set< std::size_t >& ref,
416 : : const BndFaceData& pcFaceTets );
417 : :
418 : : //! Evaluate initial conditions (IC) at mesh nodes
419 : : tk::Fields
420 : : nodeinit( std::size_t /*npoin*/,
421 : : const std::pair< std::vector< std::size_t >,
422 : : std::vector< std::size_t > >& /*esup*/ ) const;
423 : :
424 : : //! Output mesh to file(s)
425 : : void writeMesh( const std::string& basefilename,
426 : : uint64_t it,
427 : : tk::real t,
428 : : CkCallback c ) const;
429 : :
430 : : //! Compute partial boundary surface integral and sum across all chares
431 : : bool bndIntegral();
432 : :
433 : : //! Find the oldest parents of a mesh node in the AMR hierarchy
434 : : std::unordered_set< std::size_t >
435 : : ancestors( std::size_t n );
436 : :
437 : : //! Return a set of keys among whose values a primitive is found
438 : : //! \tparam Sets Type of map of sets we search for the primitive
439 : : //! \tparam Primitive The primitive we search for in the sets
440 : : //! \note Sets::mapped_type == Primitive
441 : : //! \param[in] sets Map of sets we search in
442 : : //! \param[in] p Primitive we search for
443 : : //! \return A unique set of set ids in which the primitive is found or
444 : : //! an empty set if the primitive was not found.
445 : : //! \details This function searches a map of sets for an item (a primitive,
446 : : //! e.g., a single id or a face given by 3 node ids) and returns a
447 : : //! unique set of keys behind whose associated sets the item was found.
448 : : template< class Sets, class Primitive >
449 : : std::unordered_set< int >
450 : 1161854 : keys( const Sets& sets, const Primitive& p ) {
451 : : static_assert( std::is_same< typename Sets::mapped_type::value_type,
452 : : Primitive >::value, "Type of primitive (face/node) in map of sets must "
453 : : "be the same as the type of primitive (face/node) that is searched" );
454 : 1161854 : std::unordered_set< int > ss;
455 [ + + ]: 7275024 : for (const auto& s : sets)
456 [ + - ][ + + ]: 6113170 : if (s.second.find(p) != end(s.second))
457 [ + - ]: 1725540 : ss.insert( s.first );
458 : 1161854 : return ss;
459 : 0 : }
460 : : };
461 : :
462 : : } // inciter::
|