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