1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560 | // *****************************************************************************
/*!
\file src/Inciter/DG.hpp
\copyright 2012-2015 J. Bakosi,
2016-2018 Los Alamos National Security, LLC.,
2019-2021 Triad National Security, LLC.
All rights reserved. See the LICENSE file for details.
\brief DG advances a system of PDEs with the discontinuous Galerkin scheme
\details DG advances a system of partial differential equations (PDEs) using
discontinuous Galerkin (DG) finite element (FE) spatial discretization (on
tetrahedron elements) combined with Runge-Kutta (RK) time stepping.
There are a potentially large number of DG Charm++ chares created by
Transporter. Each DG gets a chunk of the full load (part of the mesh)
and does the same: initializes and advances a number of PDE systems in time.
The implementation uses the Charm++ runtime system and is fully
asynchronous, overlapping computation and communication. The algorithm
utilizes the structured dagger (SDAG) Charm++ functionality. The high-level
overview of the algorithm structure and how it interfaces with Charm++ is
discussed in the Charm++ interface file src/Inciter/dg.ci.
*/
// *****************************************************************************
#ifndef DG_h
#define DG_h
#include <array>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include "DerivedData.hpp"
#include "FaceData.hpp"
#include "ElemDiagnostics.hpp"
#include "NoWarning/dg.decl.h"
namespace inciter {
//! DG Charm++ chare array used to advance PDEs in time with DG+RK
class DG : public CBase_DG {
public:
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#elif defined(STRICT_GNUC)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(__INTEL_COMPILER)
#pragma warning( push )
#pragma warning( disable: 1478 )
#endif
// Include Charm++ SDAG code. See http://charm.cs.illinois.edu/manuals/html/
// charm++/manual.html, Sec. "Structured Control Flow: Structured Dagger".
DG_SDAG_CODE
#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(STRICT_GNUC)
#pragma GCC diagnostic pop
#elif defined(__INTEL_COMPILER)
#pragma warning( pop )
#endif
//! Constructor
explicit DG( const CProxy_Discretization& disc,
const std::map< int, std::vector< std::size_t > >& bface,
const std::map< int, std::vector< std::size_t > >& /* bnode */,
const std::vector< std::size_t >& triinpoel );
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundefined-func-template"
#endif
//! Migrate constructor
// cppcheck-suppress uninitMemberVar
explicit DG( CkMigrateMessage* msg ) : CBase_DG( msg ) {}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
//! Return from migration
void ResumeFromSync() override;
//! Start sizing communication buffers and setting up ghost data
void resizeComm();
//! Receive unique set of faces we potentially share with/from another chare
void comfac( int fromch, const tk::UnsMesh::FaceSet& infaces );
//! Receive ghost data on chare boundaries from fellow chare
void comGhost( int fromch, const GhostData& ghost );
//! Receive requests for ghost data
void reqGhost();
//! Send all of our ghost data to fellow chares
void sendGhost();
//! Setup node-neighborhood (esup)
void nodeNeighSetup();
//! Receive element-surr-points data on chare boundaries from fellow chare
void comEsup( int fromch,
const std::unordered_map< std::size_t, std::vector< std::size_t > >&
bndEsup,
const std::unordered_map< std::size_t, std::vector< tk::real > >&
nodeBndCells );
//! Configure Charm++ reduction types for concatenating BC nodelists
static void registerReducers();
//! Setup: query boundary conditions, output mesh, etc.
void setup();
//! Receive total box IC volume and set conditions in box
void box( tk::real v );
// Evaluate whether to do load balancing
void evalLB( int nrestart );
//! Start time stepping
void start();
//! Continue to next time step
void next();
//! Receive chare-boundary limiter function data from neighboring chares
void comlim( int fromch,
const std::vector< std::size_t >& tetid,
const std::vector< std::vector< tk::real > >& u,
const std::vector< std::vector< tk::real > >& prim,
const std::vector< std::size_t >& ndof );
//! Receive chare-boundary reconstructed data from neighboring chares
void comreco( int fromch,
const std::vector< std::size_t >& tetid,
const std::vector< std::vector< tk::real > >& u,
const std::vector< std::vector< tk::real > >& prim,
const std::vector< std::size_t >& ndof );
//! Receive chare-boundary ghost data from neighboring chares
void comsol( int fromch,
std::size_t fromstage,
const std::vector< std::size_t >& tetid,
const std::vector< std::vector< tk::real > >& u,
const std::vector< std::vector< tk::real > >& prim,
const std::vector< std::size_t >& ndof );
//! Receive contributions to nodal gradients on chare-boundaries
void
comnodalExtrema( const std::vector< std::size_t >& gid,
const std::vector< std::vector< tk::real > >& G1,
const std::vector< std::vector< tk::real > >& G2 );
//! Initialize the vector of nodal extrema
void resizeNodalExtremac();
//! Compute the nodal extrema for chare-boundary nodes
void evalNodalExtrm( const std::size_t ncomp,
const std::size_t nprim,
const std::size_t ndof_NodalExtrm,
const std::vector< std::size_t >& bndel,
const std::vector< std::size_t >& inpoel,
const tk::UnsMesh::Coords& coord,
const std::vector< std::size_t >& gid,
const std::unordered_map< std::size_t, std::size_t >&
bid,
const tk::Fields& U,
const tk::Fields& P,
std::vector< std::vector<tk::real> >& uNodalExtrm,
std::vector< std::vector<tk::real> >& pNodalExtrm );
//! \brief Receive nodal solution (ofor field output) contributions from
//! neighboring chares
void comnodeout( const std::vector< std::size_t >& gid,
const std::vector< std::size_t >& nesup,
const std::vector< std::vector< tk::real > >& L );
//! Optionally refine/derefine mesh
void refine( const std::vector< tk::real >& l2res );
//! Receive new mesh from Refiner
void resizePostAMR(
const std::vector< std::size_t >& /* ginpoel */,
const tk::UnsMesh::Chunk& chunk,
const tk::UnsMesh::Coords& coord,
const std::unordered_map< std::size_t, tk::UnsMesh::Edge >& /* addedNodes */,
const std::unordered_map< std::size_t, std::size_t >& addedTets,
const std::set< std::size_t >& /*removedNodes*/,
const tk::NodeCommMap& nodeCommMap,
const std::map< int, std::vector< std::size_t > >& bface,
const std::map< int, std::vector< std::size_t > >& /* bnode */,
const std::vector< std::size_t >& triinpoel );
//! Extract field output going to file
void extractFieldOutput(
const std::vector< std::size_t >& /* ginpoel */,
const tk::UnsMesh::Chunk& chunk,
const tk::UnsMesh::Coords& coord,
const std::unordered_map< std::size_t, tk::UnsMesh::Edge >& /* addedNodes */,
const std::unordered_map< std::size_t, std::size_t >& addedTets,
const tk::NodeCommMap& nodeCommMap,
const std::map< int, std::vector< std::size_t > >& bface,
const std::map< int, std::vector< std::size_t > >& /* bnode */,
const std::vector< std::size_t >& triinpoel,
CkCallback c );
//! Const-ref access to current solution
//! \return Const-ref to current solution
const tk::Fields& solution() const { return m_u; }
//! Compute left hand side
void lhs();
//! Unused in DG
void resized() {}
//! Compute right hand side and solve system
void solve( tk::real newdt );
//! Evaluate whether to continue with next time step
void step();
/** @name Charm++ pack/unpack serializer member functions */
///@{
//! \brief Pack/Unpack serialize member function
//! \param[in,out] p Charm++'s PUP::er serializer object reference
void pup( PUP::er &p ) override {
p | m_disc;
p | m_ndof_NodalExtrm;
p | m_ncomfac;
p | m_nadj;
p | m_ncomEsup;
p | m_nsol;
p | m_ninitsol;
p | m_nlim;
p | m_nnod;
p | m_nreco;
p | m_nnodalExtrema;
p | m_inpoel;
p | m_coord;
p | m_fd;
p | m_u;
p | m_un;
p | m_p;
p | m_geoFace;
p | m_geoElem;
p | m_lhs;
p | m_uNodalExtrm;
p | m_pNodalExtrm;
p | m_uNodalExtrmc;
p | m_pNodalExtrmc;
p | m_rhs;
p | m_nfac;
p | m_nunk;
p | m_npoin;
p | m_ipface;
p | m_bndFace;
p | m_ghostData;
p | m_sendGhost;
p | m_ghostReq;
p | m_ghost;
p | m_exptGhost;
p | m_recvGhost;
p | m_diag;
p | m_stage;
p | m_ndof;
p | m_numEqDof;
p | m_bid;
p | m_uc;
p | m_pc;
p | m_ndofc;
p | m_initial;
p | m_expChBndFace;
p | m_infaces;
p | m_esup;
p | m_esupc;
p | m_elemfields;
p | m_nodefields;
p | m_nodefieldsc;
p | m_outmesh;
p | m_boxelems;
p | m_shockmarker;
}
//! \brief Pack/Unpack serialize operator|
//! \param[in,out] p Charm++'s PUP::er serializer object reference
//! \param[in,out] i DG object reference
friend void operator|( PUP::er& p, DG& i ) { i.pup(p); }
//@}
private:
//! Local face & tet IDs associated to 3 global node IDs
//! \details This map stores tetrahedron cell faces (map key) and their
//! associated local face ID and inner local tet id adjacent to the face
//! (map value). A face is given by 3 global node IDs.
using FaceMap =
std::unordered_map< tk::UnsMesh::Face, // 3 global node IDs
std::array< std::size_t, 2 >, // local face & tet ID
tk::UnsMesh::Hash<3>,
tk::UnsMesh::Eq<3> >;
//! Storage type for refined mesh used for field output
struct OutMesh {
//! Element connectivity, local->global node ids, global->local nodes ids
tk::UnsMesh::Chunk chunk;
//! Node coordinates
tk::UnsMesh::Coords coord;
//! Triangle element connectivity
std::vector< std::size_t > triinpoel;
//! Boundary-face connectivity
std::map< int, std::vector< std::size_t > > bface;
//! Node communinaction map
tk::NodeCommMap nodeCommMap;
//! \brief Pack/Unpack serialize member function
//! \param[in,out] p Charm++'s PUP::er serializer object reference
void pup( PUP::er& p ) {<--- Parameter 'p' can be declared with const
p|chunk; p|coord; p|triinpoel; p|bface; p|nodeCommMap;
}
//! Destroyer
void destroy() {
tk::destroy( std::get<0>(chunk) );
tk::destroy( std::get<1>(chunk) );
tk::destroy( std::get<2>(chunk) );
tk::destroy( coord[0] );
tk::destroy( coord[1] );
tk::destroy( coord[2] );
tk::destroy( triinpoel );
tk::destroy( bface );
tk::destroy( nodeCommMap );
}
};
//! Discretization proxy
CProxy_Discretization m_disc;
//! \brief Degree of freedom for nodal extrema vector. When DGP1 is applied,
//! there is one degree of freedom for cell average variable. When DGP2 is
//! applied, the degree of freedom is 4 which refers to cell average and
//! gradients in three directions
std::size_t m_ndof_NodalExtrm;
//! Counter for face adjacency communication map
std::size_t m_ncomfac;
//! Counter signaling that all ghost data have been received
std::size_t m_nadj;
//! Counter for element-surr-node adjacency communication map
std::size_t m_ncomEsup;
//! Counter signaling that we have received all our solution ghost data
std::size_t m_nsol;
//! \brief Counter signaling that we have received all our solution ghost
//! data during setup
std::size_t m_ninitsol;
//! \brief Counter signaling that we have received all our limiter function
//! ghost data
std::size_t m_nlim;
//! \brief Counter signaling that we have received all our node solution
//! contributions
std::size_t m_nnod;
//! Counter signaling that we have received all our reconstructed ghost data
std::size_t m_nreco;
//! \brief Counter signaling that we have received all our nodal extrema from
//! ghost chare partitions
std::size_t m_nnodalExtrema;
//! Mesh connectivity extended
std::vector< std::size_t > m_inpoel;
//! Node coordinates extended
tk::UnsMesh::Coords m_coord;
//! Face data
FaceData m_fd;
//! Vector of unknown/solution average over each mesh element
tk::Fields m_u;
//! Vector of unknown at previous time-step
tk::Fields m_un;
//! Vector of primitive quantities over each mesh element
tk::Fields m_p;
//! Face geometry
tk::Fields m_geoFace;
//! Element geometry
tk::Fields m_geoElem;
//! Left-hand side mass-matrix which is a diagonal matrix
tk::Fields m_lhs;
//! Vector of right-hand side
tk::Fields m_rhs;
//! Vector of nodal extrema for conservative variables
std::vector< std::vector<tk::real> > m_uNodalExtrm;
//! Vector of nodal extrema for primitive variables
std::vector< std::vector<tk::real> > m_pNodalExtrm;
//! Buffer for vector of nodal extrema for conservative variables
std::unordered_map< std::size_t, std::vector< tk::real > > m_uNodalExtrmc;
//! Buffer for vector of nodal extrema for primitive variables
std::unordered_map< std::size_t, std::vector< tk::real > > m_pNodalExtrmc;
//! Counter for number of faces on this chare (including chare boundaries)
std::size_t m_nfac;
//! Counter for number of unknowns on this chare (including ghosts)
std::size_t m_nunk;
//! Counter for number of nodes on this chare excluding ghosts
std::size_t m_npoin;
//! Internal + physical boundary faces (inverse of inpofa)
tk::UnsMesh::FaceSet m_ipface;
//! Face & tet IDs associated to global node IDs of the face for each chare
//! \details This map stores not only the unique faces associated to
//! fellow chares, but also a newly assigned local face ID and adjacent
//! local tet ID.
std::unordered_map< int, FaceMap > m_bndFace;
//! Ghost data associated to chare IDs we communicate with
std::unordered_map< int, GhostData > m_ghostData;
//! Elements which are ghosts for other chares associated to those chare IDs
std::unordered_map< int, std::unordered_set< std::size_t > > m_sendGhost;
//! Number of chares requesting ghost data
std::size_t m_ghostReq;
//! Local element id associated to ghost remote id charewise
//! \details This map associates the local element id (inner map value) to
//! the (remote) element id of the ghost (inner map key) based on the
//! chare id (outer map key) this remote element lies in.
std::unordered_map< int,
std::unordered_map< std::size_t, std::size_t > > m_ghost;
//! Expected ghost tet ids (used only in DEBUG)
std::set< std::size_t > m_exptGhost;
//! Received ghost tet ids (used only in DEBUG)
std::set< std::size_t > m_recvGhost;
//! Diagnostics object
ElemDiagnostics m_diag;
//! Runge-Kutta stage counter
std::size_t m_stage;
//! Vector of local number of degrees of freedom for each element
std::vector< std::size_t > m_ndof;
//! Vector of number of degrees of freedom for each PDE equation/component
std::vector< std::size_t > m_numEqDof;
//! Map local ghost tet ids (value) and zero-based boundary ids (key)
std::unordered_map< std::size_t, std::size_t > m_bid;
//! Solution receive buffers for ghosts only
std::array< std::vector< std::vector< tk::real > >, 3 > m_uc;
//! Primitive-variable receive buffers for ghosts only
std::array< std::vector< std::vector< tk::real > >, 3 > m_pc;
//! \brief Number of degrees of freedom (for p-adaptive) receive buffers
//! for ghosts only
std::array< std::vector< std::size_t >, 3 > m_ndofc;
//! 1 if starting time stepping, 0 if during time stepping
std::size_t m_initial;
//! Unique set of chare-boundary faces this chare is expected to receive
tk::UnsMesh::FaceSet m_expChBndFace;
//! Incoming communication buffer during chare-boundary face communication
std::unordered_map< int, tk::UnsMesh::FaceSet > m_infaces;
//! Elements (value) surrounding point (key) data-structure
std::map< std::size_t, std::vector< std::size_t > > m_esup;
//! Communication buffer for esup data-structure
std::map< std::size_t, std::vector< std::size_t > > m_esupc;
//! Elem output fields
std::vector< std::vector< tk::real > > m_elemfields;
//! Node output fields
std::vector< std::vector< tk::real > > m_nodefields;
//! Receive buffer for communication of node output fields
//! \details Key: global node id, value: output fields and number of
//! elements surrounding the node
std::unordered_map< std::size_t, std::pair< std::vector< tk::real >,
std::size_t > > m_nodefieldsc;
//! Storage for refined mesh used for field output
OutMesh m_outmesh;
//! Element ids at which box ICs are defined by user (multiple boxes)
std::vector< std::unordered_set< std::size_t > > m_boxelems;
//! Shock detection marker for field output
std::vector< std::size_t > m_shockmarker;
//! Access bound Discretization class pointer
Discretization* Disc() const {
Assert( m_disc[ thisIndex ].ckLocal() != nullptr, "ckLocal() null" );
return m_disc[ thisIndex ].ckLocal();
}
//! Compute partial boundary surface integral and sum across all chares
void bndIntegral();
//! Compute chare-boundary faces
void bndFaces();
//! Perform leak test on chare-boundary faces
bool leakyAdjacency();
//! Check if esuf of chare-boundary faces matches
bool faceMatch();
//! Verify that all chare-boundary faces have been received
bool receivedChBndFaces();
//! Check if entries in inpoel, inpofa and node-triplet are consistent
std::size_t
nodetripletMatch( const std::array< std::size_t, 2 >& id,
const tk::UnsMesh::Face& t );
//! Find any chare for face (given by 3 global node IDs)
int findchare( const tk::UnsMesh::Face& t );
//! Setup own ghost data on this chare
void setupGhost();
//! Continue after face adjacency communication map completed on this chare
void faceAdj();
//! Continue after node adjacency communication map completed on this chare
void adj();
//! Fill elements surrounding a face along chare boundary
void addEsuf( const std::array< std::size_t, 2 >& id, std::size_t ghostid );
//! Fill elements surrounding a element along chare boundary
void addEsuel( const std::array< std::size_t, 2 >& id,
std::size_t ghostid,
const tk::UnsMesh::Face& t );
void addEsup();
//! Fill face geometry data along chare boundary
void addGeoFace( const tk::UnsMesh::Face& t,
const std::array< std::size_t, 2 >& id );
//! Output mesh field data
void writeFields( CkCallback c );
//! Compute solution reconstructions
void reco();
//! Compute nodal extrema at chare-boundary nodes
void nodalExtrema();
//! Compute limiter function
void lim();
//! Compute time step size
void dt();
//! Evaluate whether to continue with next time step stage
void stage();
//! Evaluate whether to save checkpoint/restart
void evalRestart();
//! p-refine all elements that are adjacent to p-refined elements
void propagate_ndof();
//! Evaluate solution on incomping (a potentially refined) mesh
std::tuple< tk::Fields, tk::Fields, tk::Fields, tk::Fields >
evalSolution(
const std::vector< std::size_t >& inpoel,
const tk::UnsMesh::Coords& coord,
const std::unordered_map< std::size_t, std::size_t >& addedTets );
//! Decide wether to output field data
bool fieldOutput() const;
//! Decide if we write field output using a refined mesh
bool refinedOutput() const;
//! Start preparing fields for output to file
void startFieldOutput( CkCallback c );
};
} // inciter::
#endif // DG_h
|