Theseus
Compressible flow solver
Loading...
Searching...
No Matches
NSOperator_impl.hpp
Go to the documentation of this file.
1// Copyright (c) 2025-2026 Board of Trustees of the University of Illinois
2//
3// This file is part of Theseus.
4//
5// SPDX-License-Identifier: BSD-3-Clause
6
7namespace Theseus
8{
9
10 // Device version of ComputeGlobalEntropyVector
11 template<typename PhysicsT>
12 void NSOperator<PhysicsT>::ComputeEntropyState(const mfem::Vector &u, mfem::Vector &e) const
13 {
14 Theseus::ScopedTimer timer("ComputeEntropyState");
15
16 // This block is executed by the host
17 const int nval_restr = operator_cache.restr_v->Height();
18
19 // Copy the device cache so that it is not member data
20 auto dc = device_cache;
21
22 // Device cache parameters
23 const int ne = dc.num_elements;
24 const int ndof = dc.ndof_scalar_el;
25 const int neq = dc.num_equations;
26 const int npts = ndof * ne;
27
28 MFEM_ASSERT(nval_restr == npts*neq, "Unexpected size in ComputeEntropyState");
29
30 auto gas = dc.gas;
31
32 if (operator_cache.uVol.Size() != nval_restr){
33 operator_cache.uVol.SetSize(nval_restr);
34 operator_cache.uVol.UseDevice();
35 }
36 mfem::Vector &restrU(operator_cache.uVol);
37 if (operator_cache.uVol.Size() != nval_restr){
38 operator_cache.uVol.SetSize(nval_restr);
39 operator_cache.uVol.UseDevice();
40 }
41 mfem::Vector &restrE(operator_cache.sVol);
42 if(restrE.Size() != nval_restr){
43 restrE.SetSize(nval_restr);
44 restrE.UseDevice();
45 }
46 mfem::real_t *eState_d = restrE.Write();
47 operator_cache.restr_v->Mult(u, restrU);
48
49 if(e.Size() != u.Size()){
50 e.SetSize(u.Size());
51 e.UseDevice();
52 }
53
54 const mfem::real_t *restrU_d = restrU.Read();
55 const int estride = ndof*neq;
56
57 // Inside the FORALL below, executed on device
58 mfem::forall(npts, [=] MFEM_HOST_DEVICE (int pt)
59 {
60 const int elno = pt / ndof;
61 const int ept = pt % ndof;
62 const int eoff = elno * estride;
63 const mfem::real_t *u_el = restrU_d + eoff;
64
65 mfem::real_t elUstate[Theseus::MAXEQ];
66 Theseus::Kernels::el_gather_state(u_el, ndof, neq, ept, elUstate);
67 Theseus::PointStateView S{elUstate};
68
69 mfem::real_t elEState[Theseus::MAXEQ];
70 Theseus::PointStateViewRW E{elEState};
71 gas.entropy_state(S, E);
72 mfem::real_t *e_el = eState_d + eoff;
73 Theseus::Kernels::el_scatter_assign(elEState, ndof, neq, ept, 1.0, e_el);
74 });
75
76 operator_cache.restr_v->MultTranspose(restrE, e);
77
78 }
79
80 // This routine replaces the gradient of the entropy stored in gradState with the gradient
81 // of the primitive variables so that all the data in gradState is replaced.
82 template<typename PhysicsT>
83 void NSOperator<PhysicsT>::ComputeGradPrimFromGradEntropy(const mfem::Vector &u, std::vector<mfem::Vector *> &gradEntropy) const
84 {
85 Theseus::ScopedTimer timer("GradEntropyToGradPrim");
86 // This block is executed by the host
87 const int nval_restr = operator_cache.restr_v->Height();
88
89 // Copy the device cache so that it is not member data
90 auto dc = device_cache;
91
92 // Device cache parameters
93 const int ne = dc.num_elements;
94 const int ndof = dc.ndof_scalar_el;
95 const int neq = dc.num_equations;
96 const int npts = ndof * ne;
97 const int dim = dc.dim;
98
99 MFEM_ASSERT(nval_restr == npts*neq, "Unexpected size in ComputeEntropyState");
100
101 auto gas = dc.gas;
102
103 if (operator_cache.uVol.Size() != nval_restr){
104 operator_cache.uVol.SetSize(nval_restr);
105 operator_cache.uVol.UseDevice();
106 }
107 mfem::Vector &restr_state(operator_cache.uVol);
108 if(!operator_cache.u_vol_restr_ready){
109 operator_cache.restr_v->Mult(u, restr_state);
110 operator_cache.u_vol_restr_ready = true;
111 }
112 const mfem::real_t *restr_state_d = restr_state.Read();
113 const int estride = ndof*neq;
114
115 // Leave this temporary for now
116 if(operator_cache.volAux.Size() != nval_restr){
117 operator_cache.volAux.SetSize(nval_restr);
118 operator_cache.volAux.UseDevice();
119 }
120 mfem::Vector &restr_grad_prim_dir(operator_cache.volAux);
121
122 for(int idim = 0;idim < dim;idim++){
123
124 mfem::Vector &grad_state_dir(*gradEntropy[idim]);
125 operator_cache.restr_v->Mult(grad_state_dir, restr_grad_prim_dir);
126 mfem::real_t *grad_prim_dir_d = restr_grad_prim_dir.Write();
127
128 // Inside the FORALL below, executed on device
129 mfem::forall(npts, [=] MFEM_HOST_DEVICE (int pt)
130 {
131 const int e = pt / ndof;
132 const int ept = pt % ndof;
133 const int eoff = e * estride;
134 const mfem::real_t *u_el = restr_state_d + eoff;
135 mfem::real_t *grad_prim_el = grad_prim_dir_d + eoff;
136
137 mfem::real_t el_U[Theseus::MAXEQ];
138 Theseus::Kernels::el_gather_state(u_el, ndof, neq, ept, el_U);
140
141 mfem::real_t el_gradS[Theseus::MAXEQ];
142 Theseus::Kernels::el_gather_state(grad_prim_el, ndof, neq, ept, el_gradS);
143 Theseus::PointStateView dS{el_gradS};
144
145 mfem::real_t el_gradP[Theseus::MAXEQ];
146 Theseus::PointStateViewRW dP{el_gradP};
147 gas.grad_entropy_to_grad_prim(CV, dS, dP);
148 if (dc.axisymmetric)
149 {
150 ProjectAxisPrimitiveGradientDirection(gas, dc.elRadius_d[pt], idim, el_gradP);
151 }
152 Kernels::el_scatter_assign(el_gradP, ndof, neq, ept, 1.0, grad_prim_el);
153
154 });
155
156 operator_cache.restr_v->MultTranspose(restr_grad_prim_dir, grad_state_dir);
157
158 }
159 }
160
161 template<typename PhysicsT>
162 void NSOperator<PhysicsT>::FlowMult(const mfem::Vector &u, mfem::Vector &pdudt) const
163 {
164 Theseus::ScopedTimer timer("NSRHS");
165
166 const int dim = operator_cache.dim;
167 {
168 mfem::Vector &entropyState(operator_cache.entropyState);
169 {
170 if (entropyState.Size() != u.Size()){
171 entropyState.SetSize(u.Size());
172 entropyState.UseDevice();
173 }
174 ComputeEntropyState(u, entropyState);
175 }
176 std::vector<mfem::Vector *> gradPrim(dim);
177 {
178 // grad_u is a vector of parallel grid functions
179 // this bit grabs an mfem::Vector ref.
180 // Note that incoming grad_u is really grad of entropy,
181 // which we pack into gradPrim, and then call a
182 // function which overwrites the entropy gradient
183 // with the primitive gradient.
184 for(int idim = 0;idim < dim;idim++){
185 gradPrim[idim] = &(*grad_u[idim]);
186 }
187 GradOperator(entropyState, gradPrim);
188 ComputeGradPrimFromGradEntropy(u, gradPrim);
189 }
190 MultCNS(u, gradPrim, pdudt);
191 }
192 }
193
194 template<typename PhysicsT>
195 void NSOperator<PhysicsT>::GradOperator_Volume(const mfem::Vector &pu,
196 std::vector<mfem::Vector *> &p_grad_u) const
197 {
198 Theseus::ScopedTimer timer("GradOperator_Volume");
199
200 const int dim = operator_cache.dim;
201 const int restr_size = operator_cache.restr_v->Height();
202
203 if(operator_cache.sVol.Size() != restr_size){
204 operator_cache.sVol.SetSize(restr_size);
205 operator_cache.sVol.UseDevice();
206 }
207 mfem::Vector &Ue(operator_cache.sVol);
208 mfem::real_t *dU_d[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
209 mfem::real_t *pgrad_d[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
210 if (operator_cache.gradVol.size() != dim){
211 operator_cache.gradVol.resize(dim);
212 for(int idim = 0;idim < dim;idim++){
213 operator_cache.gradVol[idim].SetSize(restr_size);
214 operator_cache.gradVol[idim].UseDevice();
215 }
216 }
217 std::vector<mfem::Vector> &dUe(operator_cache.gradVol);
218 for(int idim = 0;idim < dim;idim++){
219 dU_d[idim] = dUe[idim].Write();
220 pgrad_d[idim] = p_grad_u[idim]->Write();
221 }
222
223 mfem::forall(restr_size, [=] MFEM_HOST_DEVICE (int i)
224 {
225 for(int idim = 0;idim < dim;idim++){
226 dU_d[idim][i] = mfem::real_t(0);
227 pgrad_d[idim][i] = mfem::real_t(0);
228 }
229 });
230
231 operator_cache.restr_v->Mult(pu, Ue);
232 const mfem::real_t *Ue_d = Ue.Read();
233
234 auto dc = device_cache;
235
236 const int ne = dc.num_elements;
237 const int ndof = dc.ndof_scalar_el;
238 const int neq = dc.num_equations;
239 const int npoints = ne * ndof;
240 const int estride = ndof * neq;
241 const int jac_stride = ndof;
242 const int metric_stride = ndof * dc.dim * dc.dim;
243
244 const mfem::real_t *elJac_d = dc.elJac_d;
245 const mfem::real_t *elMetric_d = dc.elMetric_d;
246
247#ifdef POINT_PARALLEL_VOLUME
248 mfem::forall(npoints, [=] MFEM_HOST_DEVICE (int p)
249 {
250 const int e = p / ndof;
251 const int point = p % ndof;
252 const int element_offset = e * estride;
253 mfem::real_t *du_el_d[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
254 for(int idim = 0; idim < dim; ++idim){
255 du_el_d[idim] = dU_d[idim] + element_offset;
256 }
257
258 Theseus::DGSEMIntegrator::AssembleGradVolumePointKernel(
259 dc, Ue_d + element_offset, elJac_d + e*jac_stride,
260 elMetric_d + e*metric_stride, point, du_el_d);
261 });
262#else
263 mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
264 {
265 const mfem::real_t *u_el = Ue_d + e * estride;
266 mfem::real_t *du_el_d[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
267 for(int idim = 0;idim < dim;idim++){
268 du_el_d[idim] = dU_d[idim] + e*estride;
269 }
270
271 const mfem::real_t *jac_el = elJac_d + e * jac_stride;
272 const mfem::real_t *metric_el = elMetric_d + e * metric_stride;
273
274 Theseus::DGSEMIntegrator::AssembleGradElementVolumeKernel(dc, u_el, jac_el, metric_el,
275 du_el_d);
276 });
277#endif
278
279 for(int idim = 0;idim < dim;idim++){
280 operator_cache.restr_v->AddMultTranspose(dUe[idim], *p_grad_u[idim]);
281 }
282
283 }
284
285 template<typename PhysicsT>
287 std::vector<mfem::Vector *> &p_grad_u) const
288 {
289 Theseus::ScopedTimer timer("GradOperator_BoundaryFaces");
290
291 auto dc = device_cache;
292 const int dim = dc.dim;
293 const int neq = dc.num_equations;
294 const int nfp = dc.num_face_points;
295 const int face_size = nfp * neq;
296 const int restr_size = operator_cache.restr_b->Height();
297 const int nfaces_restr = restr_size / face_size;
298 const int norm_size = nfp * dim;
299 const int npoints_bnd = nfaces_restr * nfp;
300 const int psize = pu.Size();
301
302 if(restr_size == 0){
303 return;
304 }
305
306 mfem::Vector &u_faces(operator_cache.sBnd);
307 if(u_faces.Size() != restr_size){
308 u_faces.SetSize(restr_size);
309 u_faces.UseDevice();
310 }
311
312 std::vector<mfem::Vector> &rhs_faces(operator_cache.gradBnd);
313 if(rhs_faces.size() != dim){
314 rhs_faces.resize(dim);
315 for(int idim = 0;idim < dim;idim++){
316 rhs_faces[idim].SetSize(restr_size);
317 rhs_faces[idim].UseDevice();
318 }
319 }
320
321 mfem::Vector &duBnd(operator_cache.duBnd);
322 if(duBnd.Size() != psize){
323 duBnd.SetSize(psize);
324 duBnd.UseDevice();
325 }
326
327 operator_cache.restr_b->Mult(pu, u_faces);
328
329 const mfem::real_t *u_d = u_faces.Read();
330 const mfem::real_t *nor_d = dc.bnd_nor_d;
331 const mfem::real_t *wt_d = dc.bnd_wt_d;
332 const int *bnd_marker_index_d = dc.bnd_marker_index_d;
333
334 mfem::real_t *rhs_d[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
335 mfem::real_t *du_d[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
336 for(int idim = 0;idim < dim;idim++){
337 rhs_d[idim] = rhs_faces[idim].Write();
338 du_d[idim] = duBnd.Write();
339 }
340
341 for (int idim = 0; idim < dim; ++idim) {
342 mfem::real_t *rd = rhs_d[idim];
343 mfem::forall(restr_size, [=] MFEM_HOST_DEVICE (int i) { rd[i] = mfem::real_t(0); });
344 }
345 for (int idim = 0; idim < 1; ++idim) {
346 mfem::real_t *dud = du_d[idim];
347 mfem::forall(psize, [=] MFEM_HOST_DEVICE (int i) { dud[i] = mfem::real_t(0); });
348 }
349
350 mfem::forall(npoints_bnd, [=] MFEM_HOST_DEVICE (int p)
351 {
352 const int f = p / nfp;
353 const int fp = p % nfp;
354
355 const int bnd_face_marker_index = bnd_marker_index_d[f];
356 if (bnd_face_marker_index < 0)
357 {
358 return;
359 }
360
361 const int bc_index = bnd_face_marker_index; // same convention as inviscid device path for now
362 if (bc_index < 0)
363 {
364 return;
365 }
366
367 const Theseus::BCDescriptor &bc = dc.bc_descr_d[bc_index];
368 if (bc.type == int(Theseus::BCType::Invalid))
369 {
370 return;
371 }
372
373 const int face_offset = f * face_size;
374 const int norm_offset = f * norm_size;
375 const int w_offset = f * nfp;
376
377 const mfem::real_t *u_face_d = u_d + face_offset;
378
379 const mfem::real_t *nor_face_d = nor_d + norm_offset;
380 const mfem::real_t *nor_point = nor_face_d + fp * dim;
381
382 // Legacy one-sided boundary lifting uses +1/(w0*J1)
383 const mfem::real_t scale = wt_d[w_offset + fp];
384
385 mfem::real_t *rhs_face[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
386 for(int idim = 0;idim < dim;idim++){
387 rhs_face[idim] = rhs_d[idim] + face_offset;
388 }
389
390 Theseus::DGSEMIntegrator::AssembleGradBoundaryPointKernel(dc, bc,
391 u_face_d,
392 nor_point,
393 scale,
394 fp,
395 rhs_face);
396 });
397
398 for(int idim = 0;idim < dim;idim++){
399 operator_cache.restr_b->MultTranspose(rhs_faces[idim], duBnd);
400 *p_grad_u[idim] += duBnd;
401 }
402
403 }
404
405 template<typename PhysicsT>
407 std::vector<mfem::Vector *> &p_grad_u) const
408 {
409 Theseus::ScopedTimer timer("GradOperator_InteriorFaces");
410
411 auto dc = device_cache;
412 const int dim = dc.dim;
413 const int psize = pu.Size();
414 const int restr_size = operator_cache.restr_f->Height();
415 const int neq = dc.num_equations;
416 const int nfp = dc.num_face_points;
417 const int nfaces = restr_size / (2 * nfp * neq);
418 const int npoints = nfaces * nfp;
419 const int face_size = 2 * nfp * neq;
420
421 mfem::Vector &u_faces(operator_cache.sInt);
422 if(u_faces.Size() != restr_size){
423 u_faces.SetSize(restr_size);
424 u_faces.UseDevice();
425 }
426
427 std::vector<mfem::Vector> &rhs_faces(operator_cache.gradInt);
428 if(rhs_faces.size() != dim){
429 rhs_faces.resize(dim);
430 for(int idim = 0;idim < dim;idim++){
431 rhs_faces[idim].SetSize(restr_size);
432 rhs_faces[idim].UseDevice();
433 }
434 }
435
436 mfem::Vector &duInt(operator_cache.duInt);
437 if(duInt.Size() != psize){
438 duInt.SetSize(psize);
439 duInt.UseDevice();
440 }
441
442 operator_cache.restr_f->Mult(pu, u_faces);
443 const mfem::real_t *u_d = u_faces.Read();
444
445 mfem::real_t *rhs_d[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
446 mfem::real_t *du_d[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
447 for(int idim = 0;idim < dim;idim++){
448 rhs_d[idim] = rhs_faces[idim].Write();
449 // We only need 1dim at a time, lets only use 1 temp
450 du_d[idim] = duInt.Write();
451 }
452
453 for (int idim = 0; idim < dim; ++idim) {
454 mfem::real_t *rd = rhs_d[idim];
455 mfem::forall(restr_size, [=] MFEM_HOST_DEVICE (int i) { rd[i] = mfem::real_t(0); });
456 }
457 // HardCode to dim=1 for now - temporary is only 1d
458 for (int idim = 0; idim < 1; ++idim) {
459 mfem::real_t *dud = du_d[idim];
460 mfem::forall(psize, [=] MFEM_HOST_DEVICE (int i) { dud[i] = mfem::real_t(0); });
461 }
462
463 const mfem::real_t *nor_d = dc.nor_d;
464 const mfem::real_t *wm_d = dc.fw_minus_d;
465 const mfem::real_t *wp_d = dc.fw_plus_d;
466
467#ifdef POINT_PARALLEL_INTERIOR_FACES
468 mfem::forall(npoints, [=] MFEM_HOST_DEVICE (int p)
469 {
470 const int f = p / nfp;
471 const int fp = p % nfp;
472 const int face_offset = f * face_size;
473 const int point_offset = f * nfp + fp;
474
475 mfem::real_t *rhs_face[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
476 for(int idim = 0; idim < dim; ++idim){
477 rhs_face[idim] = rhs_d[idim] + face_offset;
478 }
479
480 Theseus::DGSEMIntegrator::AssembleGradInteriorFacePointKernel(
481 dc, u_d + face_offset, nor_d + point_offset*dim,
482 wm_d[point_offset], wp_d[point_offset], fp, rhs_face);
483 });
484#else
485 const int norm_size = nfp * dim;
486 mfem::forall(nfaces, [=] MFEM_HOST_DEVICE (int f)
487 {
488 const int face_offset = f * face_size;
489 const int norm_offset = f * norm_size;
490 const int w_offset = f * nfp;
491
492 const mfem::real_t *u_face_d = u_d + face_offset;
493 const mfem::real_t *nor_face_d = nor_d + norm_offset;
494 const mfem::real_t *w_minus_d = wm_d + w_offset;
495 const mfem::real_t *w_plus_d = wp_d + w_offset;
496
497 mfem::real_t *rhs_face[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
498 for(int idim = 0;idim < dim;idim++){
499 rhs_face[idim] = rhs_d[idim] + face_offset;
500 }
501
502 Theseus::DGSEMIntegrator::AssembleGradInteriorFaceKernel(dc,
503 u_face_d,
504 nor_face_d,
505 w_minus_d,
506 w_plus_d,
507 rhs_face);
508 });
509#endif
510
511 for(int idim = 0;idim < dim;idim++){
512 operator_cache.restr_f->MultTranspose(rhs_faces[idim], duInt);
513 *p_grad_u[idim] += duInt;
514 }
515
516 }
517
518 template<typename PhysicsT>
519 void NSOperator<PhysicsT>::GradOperator(const mfem::Vector &u,
520 std::vector<mfem::Vector *> &grad_u) const
521 {
522 Theseus::ScopedTimer timer("GradOperator");
523 const int dim = operator_cache.dim;
524 const mfem::Vector &pu = this->Prolongate(u);
525 std::vector<mfem::Vector *> p_grad_(dim);
526 if (this->P)
527 {
528 const int psize = this->P->Height();
529 if(operator_cache.pGrad.size() != dim){
530 operator_cache.pGrad.resize(dim);
531 for(int idim = 0;idim < dim;idim++){
532 operator_cache.pGrad[idim].SetSize(psize);
533 operator_cache.pGrad[idim].UseDevice();
534 }
535 }
536 for(int idim = 0;idim < dim;idim++){
537 p_grad_[idim] = &(operator_cache.pGrad[idim]);
538 }
539 }
540 std::vector<mfem::Vector *> &p_grad_u = this->P ? p_grad_ : grad_u;
541
542 MFEM_ASSERT(p_grad_u.size() == dim, "Size mismatch for gradient storage");
543 MFEM_ASSERT(grad_u.size() == dim, "Size mismatch for gradient storage");
544
545 GradOperator_Volume(pu, p_grad_u);
546
547 GradOperator_InteriorFaces(pu, p_grad_u);
548
549 GradOperator_BoundaryFaces(pu, p_grad_u);
550
551 if (this->Serial())
552 {
553 if (this->cP)
554 {
555 for(int idim = 0;idim < dim;idim++){
556 this->cP->MultTranspose(*p_grad_u[idim], *grad_u[idim]);
557 }
558 }
559 }
560 else
561 {
562 if(this->P){
563 for(int idim = 0;idim < dim;idim++){
564 this->P->MultTranspose(*p_grad_u[idim], *grad_u[idim]);
565 }
566 }
567 }
568
569 const int N = this->ess_tdof_list.Size();
570 const auto idx = this->ess_tdof_list.Read();
571 // std::cout << "N ZERO = " << N << std::endl;
572 for(int idim = 0;idim < dim;idim++){
573 auto gradu_dim_d = grad_u[idim]->ReadWrite();
574 mfem::forall(N, [=] MFEM_HOST_DEVICE (int i) { gradu_dim_d[idx[i]] = 0.0; });
575 }
576 }
577
578 template<typename PhysicsT>
580 const std::vector<mfem::Vector *> &p_grad_prim,
581 mfem::Vector &pdudt) const
582 {
583 Theseus::ScopedTimer timer("MultCNS_InteriorFaces");
584
585 auto dc = device_cache;
586 const int dim = dc.dim;
587 const int neq = dc.num_equations;
588 const int nfp = dc.num_face_points;
589 const int nfaces = operator_cache.restr_f->Height() / (nfp * neq * 2); // (+/-)
590 const int npoints = nfaces * nfp;
591 const int face_size = 2*nfp*neq;
592
593 const int restr_size = operator_cache.restr_f->Height();
594 mfem::Vector &int_u(operator_cache.uInt);
595 if(int_u.Size() != restr_size){
596 int_u.SetSize(restr_size);
597 int_u.UseDevice();
598 }
599
600 mfem::Vector &rhs_faces(operator_cache.rhsInt);
601 if(rhs_faces.Size() != restr_size){
602 rhs_faces.SetSize(restr_size);
603 rhs_faces.UseDevice();
604 }
605
606 mfem::Vector &faces_dudt(operator_cache.dudtInt);
607 if(faces_dudt.Size() != pdudt.Size()){
608 faces_dudt.SetSize(pdudt.Size());
609 faces_dudt.UseDevice();
610 }
611 // faces_dudt = pdudt;
612
613 const mfem::real_t *grad_prim_d[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
614 std::vector<mfem::Vector> &int_grad_prim(operator_cache.gradInt);
615
616 if(int_grad_prim.size() != dim){
617 int_grad_prim.resize(dim);
618 for(int idim = 0;idim < dim;idim++){
619 int_grad_prim[idim].SetSize(restr_size);
620 int_grad_prim[idim].UseDevice();
621 }
622 }
623
624 {
625 Theseus::ScopedTimer gradrestr("GradInteriorFaceRestrict");
626 for(int idim = 0;idim < dim;idim++){
627 operator_cache.restr_f->Mult(*p_grad_prim[idim], int_grad_prim[idim]);
628 grad_prim_d[idim] = int_grad_prim[idim].Read();
629 }
630 }
631
632 // If zeroed before accumulation, do it explicitly on device:
633 // Potentially, this is not needed at all since I think we overwrite everything
634 {
635 Theseus::ScopedTimer intfacezero("InteriorFaceRHSZero");
636 mfem::real_t *d = rhs_faces.Write();
637 mfem::forall(rhs_faces.Size(), [=] MFEM_HOST_DEVICE (int i) { d[i] = mfem::real_t(0); });
638 }
639
640 if(!operator_cache.u_int_restr_ready){
641 operator_cache.restr_f->Mult(pu, int_u);
642 operator_cache.u_int_restr_ready = true;
643 }
644
645 const mfem::real_t *u_d = int_u.Read();
646 mfem::real_t *rhs_d = rhs_faces.Write();
647 const mfem::real_t *nor_d = dc.nor_d; // size nfaces*nfp*dim
648 const mfem::real_t *inv1_d = dc.fw_minus_d; // size nfaces*nfp
649 const mfem::real_t *inv2_d = dc.fw_plus_d; // size nfaces*nfp
650 const mfem::real_t *face_radius_d = dc.face_radius_d;
651
652 {
653 Theseus::ScopedTimer ifkern("CNSInteriorFaceKernel");
654#ifdef POINT_PARALLEL_INTERIOR_FACES
655 mfem::forall(npoints, [=] MFEM_HOST_DEVICE (int p)
656 {
657 const int f = p / nfp;
658 const int fp = p % nfp;
659 const int face_offset = f*face_size;
660 const int point_offset = f*nfp + fp;
661
662 const mfem::real_t *u_face_d = u_d + face_offset;
663 mfem::real_t *rhs_face_d = rhs_d + face_offset;
664 const mfem::real_t *dprim_face_x =
665 (dim > 0) ? grad_prim_d[0] + face_offset : nullptr;
666 const mfem::real_t *dprim_face_y =
667 (dim > 1) ? grad_prim_d[1] + face_offset : nullptr;
668 const mfem::real_t *dprim_face_z =
669 (dim > 2) ? grad_prim_d[2] + face_offset : nullptr;
670 const mfem::real_t radius =
671 dc.axisymmetric ? face_radius_d[point_offset] : 0.0;
672
673 Theseus::DGSEMIntegrator::AssembleViscousFacePointKernel(
674 dc, u_face_d, nor_d + point_offset*dim,
675 inv1_d[point_offset], inv2_d[point_offset],
676 dprim_face_x, dprim_face_y, dprim_face_z, radius, fp, rhs_face_d);
677 });
678#else
679 const int norm_size = nfp*dim;
680 mfem::forall(nfaces, [=] MFEM_HOST_DEVICE (int f)
681 {
682 const int face_offset = f*face_size;
683 const int n_offset = f*norm_size;
684 const int w_offset = f*nfp;
685
686 const mfem::real_t *u_face_d = u_d + face_offset;
687 mfem::real_t *rhs_face_d = rhs_d + face_offset;
688 const mfem::real_t *nor_face_d = nor_d + n_offset;
689 const mfem::real_t *w_minus_d = inv1_d + w_offset;
690 const mfem::real_t *w_plus_d = inv2_d + w_offset;
691 const mfem::real_t *radius_face_d = dc.axisymmetric ?
692 face_radius_d + w_offset : nullptr;
693 const mfem::real_t *dprim_face_x = (dim > 0) ? grad_prim_d[0] + face_offset : nullptr;
694 const mfem::real_t *dprim_face_y = (dim > 1) ? grad_prim_d[1] + face_offset : nullptr;
695 const mfem::real_t *dprim_face_z = (dim > 2) ? grad_prim_d[2] + face_offset : nullptr;
696
697 // Call one fused kernel for inviscid and viscous facial terms
698 Theseus::DGSEMIntegrator::AssembleViscousElementFaceKernel(
699 dc, u_face_d, nor_face_d, w_minus_d, w_plus_d,
700 dprim_face_x, dprim_face_y, dprim_face_z, radius_face_d,
701 rhs_face_d);
702 });
703#endif
704 }
705
706 {
707 Theseus::ScopedTimer ifscatter("CNSInteriorFaceScatter");
708 operator_cache.restr_f->MultTranspose(rhs_faces, faces_dudt);
709 pdudt += faces_dudt; // on device?
710 }
711
712 }
713
714
715 template<typename PhysicsT>
717 const std::vector<mfem::Vector *> &p_grad_prim,
718 mfem::Vector &pdudt) const
719 {
720 Theseus::ScopedTimer timer("MultCNS_BoundaryFaces");
721
722 auto dc = device_cache;
723 const int dim = dc.dim;
724 const int neq = dc.num_equations;
725 const int nfp = dc.num_face_points;
726 const int face_size = nfp * neq;
727 const int restr_size = operator_cache.restr_b->Height();
728 const int nfaces_restr = restr_size / face_size;
729 const int norm_size = nfp * dc.dim;
730 const int npoints_bnd = nfaces_restr * nfp;
731 const int psize = pdudt.Size();
732
733 if(restr_size == 0){
734 return;
735 }
736
737 mfem::Vector &rhs_faces(operator_cache.rhsBnd);
738 mfem::Vector &faces_dudt(operator_cache.dudtBnd);
739 if(rhs_faces.Size() != restr_size){
740 rhs_faces.SetSize(restr_size);
741 rhs_faces.UseDevice();
742 }
743 if(faces_dudt.Size() != psize){
744 faces_dudt.SetSize(psize);
745 faces_dudt.UseDevice();
746 }
747 mfem::Vector &bnd_u(operator_cache.uBnd);
748 if(bnd_u.Size() != restr_size){
749 bnd_u.SetSize(restr_size);
750 bnd_u.UseDevice();
751 }
752 const mfem::real_t *grad_prim_d[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
753 std::vector<mfem::Vector> &bnd_grad_prim(operator_cache.gradBnd);
754 if(bnd_grad_prim.size() != dim){
755 bnd_grad_prim.resize(dim);
756 for(int idim = 0;idim < dim;idim++){
757 bnd_grad_prim[idim].SetSize(restr_size);
758 bnd_grad_prim[idim].UseDevice();
759 }
760 }
761 for(int idim = 0;idim < dim;idim++){
762 operator_cache.restr_b->Mult(*p_grad_prim[idim], bnd_grad_prim[idim]);
763 grad_prim_d[idim] = bnd_grad_prim[idim].Read();
764 }
765
766 // If zeroed before accumulation, do it explicitly on device:
767 // Potentially, this is not needed at all since I think we overwrite everything
768 {
769 mfem::real_t *rd = rhs_faces.Write();
770 mfem::forall(rhs_faces.Size(), [=] MFEM_HOST_DEVICE (int i)
771 { rd[i] = mfem::real_t(0);});
772 mfem::real_t *fd = faces_dudt.Write();
773 mfem::forall(faces_dudt.Size(), [=] MFEM_HOST_DEVICE (int i)
774 { fd[i] = mfem::real_t(0);});
775 }
776
777 if(!operator_cache.u_bnd_restr_ready){
778 operator_cache.restr_b->Mult(pu, bnd_u);
779 operator_cache.u_bnd_restr_ready = true;
780 }
781
782 const mfem::real_t *u_d = bnd_u.Read();
783 mfem::real_t *rhs_d = rhs_faces.Write();
784
785 const mfem::real_t *nor_d = dc.bnd_nor_d; // size nfaces*nfp*dim
786 const mfem::real_t *radius_d = dc.bnd_radius_d;
787 const mfem::real_t *inv1_d = dc.bnd_wt_d; // size nfaces*nfp
788 const int *bnd_marker_index_d = dc.bnd_marker_index_d;
789 mfem::forall(npoints_bnd, [=] MFEM_HOST_DEVICE (int p)
790 {
791 const int f = p / nfp;
792 const int fp = p % nfp;
793
794 int bnd_face_marker_index = bnd_marker_index_d[f];
795 if(bnd_face_marker_index < 0){
796 return;
797 }
798 int bc_index = bnd_face_marker_index; // no mapping atm
799 if(bc_index < 0){
800 return;
801 }
802 const Theseus::BCDescriptor &bc = dc.bc_descr_d[bc_index];
803 if (bc.type == int(Theseus::BCType::Invalid))
804 {
805 return;
806 }
807
808 const int face_offset = f * face_size;
809 const int n_offset = f * norm_size;
810 const int w_offset = f * nfp;
811
812 const mfem::real_t *u_face_d = u_d + face_offset;
813 mfem::real_t *rhs_face_d = rhs_d + face_offset;
814 const mfem::real_t *nor_face_d = nor_d + n_offset;
815 const mfem::real_t *w_minus_d = inv1_d + w_offset;
816 const mfem::real_t *nor_point = nor_face_d + fp*dim;
817 const mfem::real_t radius = dc.axisymmetric ? radius_d[w_offset + fp] : 0.0;
818 mfem::real_t scale = -w_minus_d[fp];
819 mfem::real_t state1[Theseus::MAXEQ];
820 mfem::real_t fluxN[Theseus::MAXEQ];
821 mfem::real_t gradPrim_x[Theseus::MAXEQ];
822 mfem::real_t gradPrim_y[Theseus::MAXEQ];
823 mfem::real_t gradPrim_z[Theseus::MAXEQ];
824 const mfem::real_t *dprim_face_x = (dim > 0) ? grad_prim_d[0] + face_offset : nullptr;
825 const mfem::real_t *dprim_face_y = (dim > 1) ? grad_prim_d[1] + face_offset : nullptr;
826 const mfem::real_t *dprim_face_z = (dim > 2) ? grad_prim_d[2] + face_offset : nullptr;
827 Theseus::Kernels::el_gather_grad_state(dprim_face_x, dprim_face_y, dprim_face_z,
828 dim, nfp, neq, fp, gradPrim_x, gradPrim_y,
829 gradPrim_z);
830 Theseus::Kernels::el_gather_state(u_face_d, nfp, neq, fp, state1);
831
833 dc, bc, state1, gradPrim_x, gradPrim_y,
834 gradPrim_z, nor_point, radius, fluxN);
835 Theseus::Kernels::el_scatter_add(fluxN, nfp, neq, fp, scale, rhs_face_d);
836 });
837
838 operator_cache.restr_b->MultTranspose(rhs_faces, faces_dudt);
839 pdudt += faces_dudt; // on device? (likely yes)
840
841 }
842
843 template<typename PhysicsT>
844 void NSOperator<PhysicsT>::MultCNS_Volume(const mfem::Vector &pu, const std::vector<mfem::Vector *> &p_grad_prim,
845 mfem::Vector &pdudt) const
846 {
847 Theseus::ScopedTimer timer("MultCNS_Volume");
848 // Copy the device cache so that it is not member data
849 auto dc = device_cache;
850 const int dim = dc.dim;
851 const int restr_size = operator_cache.restr_v->Height();
852
853 mfem::Vector &vol_u(operator_cache.uVol);
854 if(vol_u.Size() != restr_size){
855 vol_u.SetSize(restr_size);
856 vol_u.UseDevice();
857 }
858
859 mfem::Vector &dUe(operator_cache.rhsVol);
860 if(dUe.Size() != restr_size){
861 dUe.SetSize(restr_size);
862 dUe.UseDevice();
863 }
864
865 std::vector<mfem::Vector> &vol_grad_prim(operator_cache.gradVol);
866 if(vol_grad_prim.size() != dim){
867 vol_grad_prim.resize(dim);
868 for(int idim = 0;idim < dim;idim++){
869 vol_grad_prim[idim].SetSize(restr_size);
870 vol_grad_prim[idim].UseDevice();
871 }
872 }
873
874 if(!operator_cache.u_vol_restr_ready){
875 operator_cache.restr_v->Mult(pu, vol_u);
876 operator_cache.u_vol_restr_ready = true;
877 }
878 for(int idim = 0;idim < dim;idim++){
879 operator_cache.restr_v->Mult(*p_grad_prim[idim], vol_grad_prim[idim]);
880 }
881
882 // Zero the RHS array on-device
883 {
884 mfem::real_t *d = dUe.Write();
885 mfem::forall(dUe.Size(), [=] MFEM_HOST_DEVICE (int i) { d[i] = mfem::real_t(0); });
886 }
887
888 // Set up the read-only pointers for restr inputs
889 const mfem::real_t *Ue_d = vol_u.Read();
890 const mfem::real_t *gradPrim_d[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
891 for(int idim = 0;idim < dim;idim++){
892 gradPrim_d[idim] = vol_grad_prim[idim].Read();
893 }
894
895 // Write-only for RHS
896 mfem::real_t *dUe_d = dUe.Write();
897
898 // Device cache parameters
899 const int ne = dc.num_elements;
900 const int ndof = dc.ndof_scalar_el;
901 const int neq = dc.num_equations;
902
903#ifdef SUBCELL_FV_BLENDING
904 const int Np_x = dc.Np_x;
905 const int Np_y = dc.Np_y;
906 const int Np_z = dc.Np_z;
907 const int npe_metric_xi = (Np_x + 1)*Np_y*Np_z;
908 const int npe_metric_eta = Np_x*(Np_y + 1)*Np_z;
909 const int npe_metric_zeta = Np_x * Np_y * (Np_z + 1);
910 const mfem::real_t *metric_xi_d = dc.subcell_metric_xi_d;
911 const mfem::real_t *metric_eta_d = (dim > 1 ? dc.subcell_metric_eta_d : nullptr);
912 const mfem::real_t *metric_zeta_d = (dim > 2 ? dc.subcell_metric_zeta_d : nullptr);
913
914 mfem::Vector dUfv(operator_cache.restr_v->Height());
915 dUfv.UseDevice();
916 mfem::real_t *dUfv_d = dUfv.Write();
917 // zero the array on-device
918 {
919 mfem::real_t *d = dUfv_d;
920 mfem::forall(dUfv.Size(), [=] MFEM_HOST_DEVICE (int i) { d[i] = mfem::real_t(0); });
921 }
922
923 const mfem::real_t *alpha_d = operator_cache.alpha->Read();
924#endif
925
926 // Derived parameters
927 const int metric_stride = ndof * dim * dim;
928 const int jac_stride = ndof;
929 const int estride = ndof*neq;
930
931 // Device cache data/arrays
932 const int *elem_attr_d = dc.elem_attr_d;
933 const int *attr_marker_d = dc.attr_marker_d;
934 const mfem::real_t *elJac_d = dc.elJac_d;
935 const mfem::real_t *elMetric_d = dc.elMetric_d;
936 const mfem::real_t *elRadius_d = dc.elRadius_d;
937
938#ifdef POINT_PARALLEL_VOLUME
939 const int npoints = ne * ndof;
940 mfem::forall(npoints, [=] MFEM_HOST_DEVICE (int p)
941 {
942 const int e = p / ndof;
943 const int point = p % ndof;
944 const int attr = elem_attr_d[e];
945 if (attr_marker_d[attr-1] == 0) {
946 return;
947 }
948
949 const int element_offset = e * estride;
950 DGSEMIntegrator::AssembleVolumePointKernel(
951 dc, Ue_d + element_offset, elJac_d + e*jac_stride,
952 elMetric_d + e*metric_stride, point, dUe_d + element_offset);
953 });
954#endif
955
956 // Inside the FORALL below, executed on device
957 mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
958 {
959
960 const mfem::real_t *jac_el = elJac_d + e * jac_stride;
961 const mfem::real_t *metric_el = elMetric_d + e * metric_stride;
962 const mfem::real_t *radius_el = dc.axisymmetric ?
963 elRadius_d + e * jac_stride : nullptr;
964
965 const int attr = elem_attr_d[e];
966 if (attr_marker_d[attr-1] == 0) {
967 return;
968 }
969
970 // Element-specific inputs and outputs
971 const int eoff = e * estride;
972 const mfem::real_t *u_el = Ue_d + eoff;
973 mfem::real_t *du_el = dUe_d + eoff;
974
975#ifndef POINT_PARALLEL_VOLUME
976 Theseus::DGSEMIntegrator::AssembleElementVolumeKernel(
977 dc, u_el, jac_el, metric_el, du_el);
978#endif
979#ifdef SUBCELL_FV_BLENDING
980 mfem::real_t alpha_fv = alpha_d[e];
981 if(alpha_fv > 1e-16){
982 mfem::real_t alpha_dg = (1.0 - alpha_fv);
983 mfem::real_t *du_fv = dUfv_d + eoff;
984 const mfem::real_t *el_metric_xi = metric_xi_d + e * npe_metric_xi * dim;
985 const mfem::real_t *el_metric_eta = (dim > 1 ? metric_eta_d + e * npe_metric_eta * dim :
986 nullptr);
987 const mfem::real_t *el_metric_zeta = (dim > 2 ? metric_zeta_d + e * npe_metric_zeta * dim :
988 nullptr);
989 Theseus::DGSEMIntegrator::ComputeFVFluxesKernel(
990 dc, u_el, jac_el, el_metric_xi, el_metric_eta,
991 el_metric_zeta, du_fv);
992
993 for(int ipt = 0;ipt < estride;ipt++){
994 du_el[ipt] = alpha_dg * du_el[ipt] + alpha_fv * du_fv[ipt];
995 }
996
997 }
998#endif
1000 dc, u_el, radius_el, jac_el, metric_el, du_el);
1001#ifndef POINT_PARALLEL_VOLUME
1002 const mfem::real_t *grad_prim_el[Theseus::MAXDIM] = {nullptr, nullptr, nullptr};
1003 for(int idim = 0;idim < dim;idim++){
1004 grad_prim_el[idim] = gradPrim_d[idim] + eoff;
1005 }
1006
1007 Theseus::DGSEMIntegrator::AssembleViscousElementVolumeKernel(dc, u_el, jac_el, metric_el,
1008 radius_el,
1009 grad_prim_el[0], grad_prim_el[1],
1010 grad_prim_el[2], du_el);
1011#endif
1012
1013 });
1014
1015#ifdef POINT_PARALLEL_VOLUME
1016 mfem::forall(npoints, [=] MFEM_HOST_DEVICE (int p)
1017 {
1018 const int e = p / ndof;
1019 const int point = p % ndof;
1020 const int attr = elem_attr_d[e];
1021 if (attr_marker_d[attr-1] == 0) {
1022 return;
1023 }
1024
1025 const int element_offset = e * estride;
1026 const mfem::real_t *grad_prim_el[Theseus::MAXDIM] = {
1027 nullptr, nullptr, nullptr};
1028 for(int idim = 0; idim < dim; ++idim){
1029 grad_prim_el[idim] = gradPrim_d[idim] + element_offset;
1030 }
1031
1032 Theseus::DGSEMIntegrator::AssembleViscousVolumePointKernel(
1033 dc, Ue_d + element_offset, elJac_d + e*jac_stride,
1034 elMetric_d + e*metric_stride,
1035 dc.axisymmetric ? elRadius_d + e*jac_stride : nullptr,
1036 grad_prim_el[0], grad_prim_el[1], grad_prim_el[2], point,
1037 dUe_d + element_offset);
1038 });
1039#endif
1040
1041 // The rest is identical to Euler operator
1042 // Scatter RHS back to storage
1043 operator_cache.restr_v->AddMultTranspose(dUe, pdudt);
1044
1045 }
1046
1047 template<typename PhysicsT>
1048 void NSOperator<PhysicsT>::MultCNS(const mfem::Vector &u, const std::vector<mfem::Vector *> &grad_prim,
1049 mfem::Vector &pdudt) const
1050 {
1051 const int dim = operator_cache.dim;
1052 std::vector<mfem::Vector *> p_grad_(dim);
1053 if (this->P)
1054 {
1055 const int psize = this->P->Height();
1056 if(operator_cache.pGrad.size() != dim){
1057 operator_cache.pGrad.resize(dim);
1058 for(int idim = 0;idim < dim;idim++){
1059 operator_cache.pGrad[idim].SetSize(psize);
1060 operator_cache.pGrad[idim].UseDevice();
1061 }
1062 }
1063 for(int idim = 0;idim < dim;idim++){
1064 p_grad_[idim] = &(operator_cache.pGrad[idim]);
1065 this->P->Mult(*grad_prim[idim], *p_grad_[idim]);
1066 }
1067 if(operator_cache.pdudt.Size() != psize){
1068 operator_cache.pdudt.SetSize(psize);
1069 operator_cache.pdudt.UseDevice();
1070 }
1071 }
1072 const std::vector<mfem::Vector *> &pGradPrim = this->P ? p_grad_ : grad_prim;
1073
1074 MultCNS_Volume(u, pGradPrim, pdudt);
1075 MultCNS_InteriorFaces(u, pGradPrim, pdudt);
1076 MultCNS_BoundaryFaces(u, pGradPrim, pdudt);
1077 }
1078
1079}
void MultCNS_InteriorFaces(const mfem::Vector &pu, const std::vector< mfem::Vector * > &p_grad_prim, mfem::Vector &pdudt) const
Definition NSOperator_impl.hpp:579
void ComputeEntropyState(const mfem::Vector &u, mfem::Vector &e) const
Definition NSOperator_impl.hpp:12
void GradOperator(const mfem::Vector &u, std::vector< mfem::Vector * > &grad_u) const
Definition NSOperator_impl.hpp:519
void MultCNS(const mfem::Vector &u, const std::vector< mfem::Vector * > &grad_prim, mfem::Vector &pdudt) const
Definition NSOperator_impl.hpp:1048
void GradOperator_Volume(const mfem::Vector &pu, std::vector< mfem::Vector * > &p_grad_u) const
Definition NSOperator_impl.hpp:195
void GradOperator_InteriorFaces(const mfem::Vector &pu, std::vector< mfem::Vector * > &p_grad_u) const
Definition NSOperator_impl.hpp:406
void FlowMult(const mfem::Vector &u, mfem::Vector &dudt) const override
Definition NSOperator_impl.hpp:162
void ComputeGradPrimFromGradEntropy(const mfem::Vector &u, std::vector< mfem::Vector * > &gradEntropy) const
Definition NSOperator_impl.hpp:83
void MultCNS_Volume(const mfem::Vector &pu, const std::vector< mfem::Vector * > &p_grad_prim, mfem::Vector &pdudt) const
Definition NSOperator_impl.hpp:844
void MultCNS_BoundaryFaces(const mfem::Vector &pu, const std::vector< mfem::Vector * > &p_grad_prim, mfem::Vector &pdudt) const
Definition NSOperator_impl.hpp:716
void GradOperator_BoundaryFaces(const mfem::Vector &pu, std::vector< mfem::Vector * > &p_grad_u) const
Definition NSOperator_impl.hpp:286
Definition timer.hpp:22
MFEM_HOST_DEVICE void ApplyViscousBoundaryCondition(const DeviceCacheT &dc, const Theseus::BCDescriptor &bc, const mfem::real_t *state1, const mfem::real_t *gradPrim_x, const mfem::real_t *gradPrim_y, const mfem::real_t *gradPrim_z, const mfem::real_t *nor, mfem::real_t radius, mfem::real_t *fluxN)
Definition bc_kernels.hpp:383
MFEM_HOST_DEVICE void el_scatter_add(const mfem::real_t *f, const int dof, const int num_eq, const int id, const mfem::real_t scale, mfem::real_t *du)
Definition theseus_kernels.hpp:153
MFEM_HOST_DEVICE void el_gather_state(const mfem::real_t *u, const int dof, const int num_eq, const int id, mfem::real_t *dst)
Definition theseus_kernels.hpp:135
MFEM_HOST_DEVICE void el_scatter_assign(const mfem::real_t *f, const int dof, const int num_eq, const int id, const mfem::real_t scale, mfem::real_t *du)
Definition theseus_kernels.hpp:170
MFEM_HOST_DEVICE void el_gather_grad_state(const mfem::real_t *grad_state_x, const mfem::real_t *grad_state_y, const mfem::real_t *grad_state_z, const int dim, const int dof, const int neq, const int id, mfem::real_t *dqx, mfem::real_t *dqy, mfem::real_t *dqz)
Definition theseus_kernels.hpp:143
Definition AxisymmetricGeometry.hpp:15
MFEM_HOST_DEVICE void AddAxisymmetricEulerElementSource(const ContextT &ctx, const mfem::real_t *element_state, const mfem::real_t *element_radius, const mfem::real_t *element_jacobian, const mfem::real_t *element_metric, mfem::real_t *element_rate)
Definition AxisymmetricSource.hpp:221
constexpr const int MAXDIM
Definition theseus_kernels.hpp:14
constexpr const int MAXEQ
Definition theseus_kernels.hpp:13
MFEM_HOST_DEVICE bool ProjectAxisPrimitiveGradientDirection(const GasT &gas, mfem::real_t radius, int derivative_direction, mfem::real_t *dprim)
Definition AxisymmetricSource.hpp:261
Definition bc_cache_utilities.hpp:35
int type
Definition bc_cache_utilities.hpp:36
Definition GasState.hpp:218
Definition GasState.hpp:127