MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
bilininteg_hdiv_kernels.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
13
14namespace mfem
15{
16
17namespace internal
18{
19
20void PAHdivMassSetup2D(const int Q1D,
21 const int coeffDim,
22 const int NE,
23 const Array<real_t> &w,
24 const Vector &j,
25 Vector &coeff_,
26 Vector &op)
27{
28 const bool symmetric = (coeffDim != 4);
29 const int NQ = Q1D*Q1D;
30 auto W = w.Read();
31
32 auto J = Reshape(j.Read(), NQ, 2, 2, NE);
33 auto C = Reshape(coeff_.Read(), coeffDim, NQ, NE);
34 auto y = Reshape(op.Write(), NQ, symmetric ? 3 : 4, NE);
35
36 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
37 {
38 for (int q = 0; q < NQ; ++q)
39 {
40 const real_t J11 = J(q,0,0,e);
41 const real_t J21 = J(q,1,0,e);
42 const real_t J12 = J(q,0,1,e);
43 const real_t J22 = J(q,1,1,e);
44 const real_t c_detJ = W[q] / ((J11*J22)-(J21*J12));
45
46 // (1/detJ) J^T C J
47 if (coeffDim == 3 || coeffDim == 4) // Matrix coefficient
48 {
49 const real_t C11 = C(0,q,e);
50 const real_t C12 = C(1,q,e);
51 const real_t C21 = symmetric ? C12 : C(2,q,e);
52 const real_t C22 = symmetric ? C(2,q,e) : C(3,q,e);
53 const real_t R11 = C11*J11 + C12*J21;
54 const real_t R21 = C21*J11 + C22*J21;
55 const real_t R12 = C11*J12 + C12*J22;
56 const real_t R22 = C21*J12 + C22*J22;
57
58 y(q,0,e) = c_detJ * (J11*R11 + J21*R21); // 1,1
59 y(q,1,e) = c_detJ * (J11*R12 + J21*R22); // 1,2
60
61 if (symmetric)
62 {
63 y(q,2,e) = c_detJ * (J12*R12 + J22*R22); // 2,2
64 }
65 else
66 {
67 y(q,2,e) = c_detJ * (J12*R11 + J22*R21); // 2,1
68 y(q,3,e) = c_detJ * (J12*R12 + J22*R22); // 2,2
69 }
70 }
71 else // Vector or scalar coefficient
72 {
73 const real_t C1 = C(0,q,e);
74 const real_t C2 = (coeffDim == 2 ? C(1,q,e) : C1);
75 y(q,0,e) = c_detJ * (J11*C1*J11 + J21*C2*J21); // 1,1
76 y(q,1,e) = c_detJ * (J11*C1*J12 + J21*C2*J22); // 1,2
77 y(q,2,e) = c_detJ * (J12*C1*J12 + J22*C2*J22); // 2,2
78 }
79 }
80 });
81}
82
83void PAHdivMassSetup3D(const int Q1D,
84 const int coeffDim,
85 const int NE,
86 const Array<real_t> &w,
87 const Vector &j,
88 Vector &coeff_,
89 Vector &op)
90{
91 const bool symmetric = (coeffDim != 9);
92 const int NQ = Q1D*Q1D*Q1D;
93 auto W = w.Read();
94 auto J = Reshape(j.Read(), NQ, 3, 3, NE);
95 auto C = Reshape(coeff_.Read(), coeffDim, NQ, NE);
96 auto y = Reshape(op.Write(), NQ, symmetric ? 6 : 9, NE);
97
98 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
99 {
100 for (int q = 0; q < NQ; ++q)
101 {
102 const real_t J11 = J(q,0,0,e);
103 const real_t J21 = J(q,1,0,e);
104 const real_t J31 = J(q,2,0,e);
105 const real_t J12 = J(q,0,1,e);
106 const real_t J22 = J(q,1,1,e);
107 const real_t J32 = J(q,2,1,e);
108 const real_t J13 = J(q,0,2,e);
109 const real_t J23 = J(q,1,2,e);
110 const real_t J33 = J(q,2,2,e);
111 const real_t detJ = J11 * (J22 * J33 - J32 * J23) -
112 J21 * (J12 * J33 - J32 * J13) +
113 J31 * (J12 * J23 - J22 * J13);
114 const real_t c_detJ = W[q] / detJ;
115
116 // (1/detJ) J^T C J
117 if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
118 {
119 real_t M[3][3];
120 M[0][0] = C(0, q, e);
121 M[0][1] = C(1, q, e);
122 M[0][2] = C(2, q, e);
123 M[1][0] = (!symmetric) ? C(3, q, e) : M[0][1];
124 M[1][1] = (!symmetric) ? C(4, q, e) : C(3, q, e);
125 M[1][2] = (!symmetric) ? C(5, q, e) : C(4, q, e);
126 M[2][0] = (!symmetric) ? C(6, q, e) : M[0][2];
127 M[2][1] = (!symmetric) ? C(7, q, e) : M[1][2];
128 M[2][2] = (!symmetric) ? C(8, q, e) : C(5, q, e);
129
130 int idx = 0;
131 for (int i=0; i<3; ++i)
132 for (int j = (symmetric ? i : 0); j<3; ++j)
133 {
134 y(q,idx,e) = 0.0;
135 for (int k=0; k<3; ++k)
136 {
137 real_t MJ_kj = 0.0;
138 for (int l=0; l<3; ++l)
139 {
140 MJ_kj += M[k][l] * J(q,l,j,e);
141 }
142
143 y(q,idx,e) += J(q,k,i,e) * MJ_kj;
144 }
145
146 y(q,idx,e) *= c_detJ;
147 idx++;
148 }
149 }
150 else // Vector or scalar coefficient version
151 {
152 int idx = 0;
153 for (int i=0; i<3; ++i)
154 for (int j=i; j<3; ++j)
155 {
156 y(q,idx,e) = 0.0;
157 for (int k=0; k<3; ++k)
158 {
159 y(q,idx,e) += J(q,k,i,e) * C(coeffDim == 3 ? k : 0, q, e) * J(q,k,j,e);
160 }
161
162 y(q,idx,e) *= c_detJ;
163 idx++;
164 }
165 }
166 }
167 });
168}
169
170void PAHdivMassAssembleDiagonal2D(const int D1D,
171 const int Q1D,
172 const int NE,
173 const bool symmetric,
174 const Array<real_t> &Bo_,
175 const Array<real_t> &Bc_,
176 const Vector &op_,
177 Vector &diag_)
178{
179 auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
180 auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
181 auto op = Reshape(op_.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
182 auto diag = Reshape(diag_.ReadWrite(), 2*(D1D-1)*D1D, NE);
183
184 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
185 {
186 constexpr static int VDIM = 2;
187 constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
188
189 int osc = 0;
190
191 for (int c = 0; c < VDIM; ++c) // loop over x, y components
192 {
193 const int D1Dx = (c == 1) ? D1D - 1 : D1D;
194 const int D1Dy = (c == 0) ? D1D - 1 : D1D;
195
196 for (int dy = 0; dy < D1Dy; ++dy)
197 {
198 real_t mass[MAX_Q1D];
199 for (int qx = 0; qx < Q1D; ++qx)
200 {
201 mass[qx] = 0.0;
202 for (int qy = 0; qy < Q1D; ++qy)
203 {
204 const real_t wy = (c == 1) ? Bc(qy,dy) : Bo(qy,dy);
205 mass[qx] += wy*wy*((c == 0) ? op(qx,qy,0,e) : op(qx,qy,symmetric ? 2 : 3,e));
206 }
207 }
208
209 for (int dx = 0; dx < D1Dx; ++dx)
210 {
211 real_t val = 0.0;
212 for (int qx = 0; qx < Q1D; ++qx)
213 {
214 const real_t wx = (c == 0) ? Bc(qx,dx) : Bo(qx,dx);
215 val += mass[qx] * wx * wx;
216 }
217 diag(dx + (dy * D1Dx) + osc, e) += val;
218 }
219 }
220
221 osc += D1Dx * D1Dy;
222 } // loop (c) over components
223 }); // end of element loop
224}
225
226void PAHdivMassAssembleDiagonal3D(const int D1D,
227 const int Q1D,
228 const int NE,
229 const bool symmetric,
230 const Array<real_t> &Bo_,
231 const Array<real_t> &Bc_,
232 const Vector &op_,
233 Vector &diag_)
234{
235 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
236 "Error: D1D > HDIV_MAX_D1D");
237 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
238 "Error: Q1D > HDIV_MAX_Q1D");
239 constexpr static int VDIM = 3;
240
241 auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
242 auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
243 auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
244 auto diag = Reshape(diag_.ReadWrite(), 3*(D1D-1)*(D1D-1)*D1D, NE);
245
246 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
247 {
248 int osc = 0;
249
250 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
251 {
252 const int D1Dz = (c == 2) ? D1D : D1D - 1;
253 const int D1Dy = (c == 1) ? D1D : D1D - 1;
254 const int D1Dx = (c == 0) ? D1D : D1D - 1;
255
256 const int opc = (c == 0) ? 0 : ((c == 1) ? (symmetric ? 3 : 4) :
257 (symmetric ? 5 : 8));
258
259 real_t mass[DofQuadLimits::HDIV_MAX_Q1D];
260
261 for (int dz = 0; dz < D1Dz; ++dz)
262 {
263 for (int dy = 0; dy < D1Dy; ++dy)
264 {
265 for (int qx = 0; qx < Q1D; ++qx)
266 {
267 mass[qx] = 0.0;
268 for (int qy = 0; qy < Q1D; ++qy)
269 {
270 const real_t wy = (c == 1) ? Bc(qy,dy) : Bo(qy,dy);
271 for (int qz = 0; qz < Q1D; ++qz)
272 {
273 const real_t wz = (c == 2) ? Bc(qz,dz) : Bo(qz,dz);
274 mass[qx] += wy * wy * wz * wz * op(qx,qy,qz,opc,e);
275 }
276 }
277 }
278
279 for (int dx = 0; dx < D1Dx; ++dx)
280 {
281 real_t val = 0.0;
282 for (int qx = 0; qx < Q1D; ++qx)
283 {
284 const real_t wx = (c == 0) ? Bc(qx,dx) : Bo(qx,dx);
285 val += mass[qx] * wx * wx;
286 }
287 diag(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += val;
288 }
289 }
290 }
291
292 osc += D1Dx * D1Dy * D1Dz;
293 } // loop c
294 }); // end of element loop
295}
296
297void PAHdivMassApply2D(const int NE, const bool symmetric, const bool,
298 const Array<real_t> &Bo_, const Array<real_t> &Bc_,
299 const Array<real_t> &Bot_, const Array<real_t> &Bct_,
300 const Vector &op_, const Vector &x_, Vector &y_,
301 const int D1D, const int TestD1D, const int Q1D)
302{
303 MFEM_VERIFY(D1D == TestD1D,
304 "Trial and test spaces must have same number of dofs");
305 auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
306 auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
307 auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
308 auto Bct = Reshape(Bct_.Read(), D1D, Q1D);
309 auto op = Reshape(op_.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
310 auto x = Reshape(x_.Read(), 2*(D1D-1)*D1D, NE);
311 auto y = Reshape(y_.ReadWrite(), 2*(D1D-1)*D1D, NE);
312
313 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
314 {
315 constexpr static int VDIM = 2;
316 constexpr static int MAX_D1D = DofQuadLimits::HDIV_MAX_D1D;
317 constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
318
319 real_t mass[MAX_Q1D][MAX_Q1D][VDIM];
320
321 for (int qy = 0; qy < Q1D; ++qy)
322 {
323 for (int qx = 0; qx < Q1D; ++qx)
324 {
325 for (int c = 0; c < VDIM; ++c)
326 {
327 mass[qy][qx][c] = 0.0;
328 }
329 }
330 }
331
332 int osc = 0;
333
334 for (int c = 0; c < VDIM; ++c) // loop over x, y components
335 {
336 const int D1Dx = (c == 1) ? D1D - 1 : D1D;
337 const int D1Dy = (c == 0) ? D1D - 1 : D1D;
338
339 for (int dy = 0; dy < D1Dy; ++dy)
340 {
341 real_t massX[MAX_Q1D];
342 for (int qx = 0; qx < Q1D; ++qx)
343 {
344 massX[qx] = 0.0;
345 }
346
347 for (int dx = 0; dx < D1Dx; ++dx)
348 {
349 const real_t t = x(dx + (dy * D1Dx) + osc, e);
350 for (int qx = 0; qx < Q1D; ++qx)
351 {
352 massX[qx] += t * ((c == 0) ? Bc(qx,dx) : Bo(qx,dx));
353 }
354 }
355
356 for (int qy = 0; qy < Q1D; ++qy)
357 {
358 const real_t wy = (c == 1) ? Bc(qy,dy) : Bo(qy,dy);
359 for (int qx = 0; qx < Q1D; ++qx)
360 {
361 mass[qy][qx][c] += massX[qx] * wy;
362 }
363 }
364 }
365
366 osc += D1Dx * D1Dy;
367 } // loop (c) over components
368
369 // Apply D operator.
370 for (int qy = 0; qy < Q1D; ++qy)
371 {
372 for (int qx = 0; qx < Q1D; ++qx)
373 {
374 const real_t O11 = op(qx,qy,0,e);
375 const real_t O12 = op(qx,qy,1,e);
376 const real_t O21 = symmetric ? O12 : op(qx,qy,2,e);
377 const real_t O22 = symmetric ? op(qx,qy,2,e) : op(qx,qy,3,e);
378 const real_t massX = mass[qy][qx][0];
379 const real_t massY = mass[qy][qx][1];
380 mass[qy][qx][0] = (O11*massX)+(O12*massY);
381 mass[qy][qx][1] = (O21*massX)+(O22*massY);
382 }
383 }
384
385 for (int qy = 0; qy < Q1D; ++qy)
386 {
387 osc = 0;
388
389 for (int c = 0; c < VDIM; ++c) // loop over x, y components
390 {
391 const int D1Dx = (c == 1) ? D1D - 1 : D1D;
392 const int D1Dy = (c == 0) ? D1D - 1 : D1D;
393
394 real_t massX[MAX_D1D];
395 for (int dx = 0; dx < D1Dx; ++dx)
396 {
397 massX[dx] = 0;
398 }
399 for (int qx = 0; qx < Q1D; ++qx)
400 {
401 for (int dx = 0; dx < D1Dx; ++dx)
402 {
403 massX[dx] += mass[qy][qx][c] * ((c == 0) ? Bct(dx,qx) :
404 Bot(dx,qx));
405 }
406 }
407
408 for (int dy = 0; dy < D1Dy; ++dy)
409 {
410 const real_t wy = (c == 1) ? Bct(dy,qy) : Bot(dy,qy);
411
412 for (int dx = 0; dx < D1Dx; ++dx)
413 {
414 y(dx + (dy * D1Dx) + osc, e) += massX[dx] * wy;
415 }
416 }
417
418 osc += D1Dx * D1Dy;
419 } // loop c
420 } // loop qy
421 }); // end of element loop
422}
423
424void PAHdivMassApply3D(const int NE, const bool symmetric, const bool,
425 const Array<real_t> &Bo_, const Array<real_t> &Bc_,
426 const Array<real_t> &Bot_, const Array<real_t> &Bct_,
427 const Vector &op_, const Vector &x_, Vector &y_,
428 const int D1D, const int TestD1D, const int Q1D)
429{
430 MFEM_VERIFY(D1D == TestD1D,
431 "Trial and test spaces must have same number of dofs");
432 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
433 "Error: D1D > HDIV_MAX_D1D");
434 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
435 "Error: Q1D > HDIV_MAX_Q1D");
436 constexpr static int VDIM = 3;
437
438 auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
439 auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
440 auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
441 auto Bct = Reshape(Bct_.Read(), D1D, Q1D);
442 auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
443 auto x = Reshape(x_.Read(), 3*(D1D-1)*(D1D-1)*D1D, NE);
444 auto y = Reshape(y_.ReadWrite(), 3*(D1D-1)*(D1D-1)*D1D, NE);
445
446 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
447 {
448 real_t mass[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][VDIM];
449
450 for (int qz = 0; qz < Q1D; ++qz)
451 {
452 for (int qy = 0; qy < Q1D; ++qy)
453 {
454 for (int qx = 0; qx < Q1D; ++qx)
455 {
456 for (int c = 0; c < VDIM; ++c)
457 {
458 mass[qz][qy][qx][c] = 0.0;
459 }
460 }
461 }
462 }
463
464 int osc = 0;
465
466 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
467 {
468 const int D1Dz = (c == 2) ? D1D : D1D - 1;
469 const int D1Dy = (c == 1) ? D1D : D1D - 1;
470 const int D1Dx = (c == 0) ? D1D : D1D - 1;
471
472 for (int dz = 0; dz < D1Dz; ++dz)
473 {
474 real_t massXY[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
475 for (int qy = 0; qy < Q1D; ++qy)
476 {
477 for (int qx = 0; qx < Q1D; ++qx)
478 {
479 massXY[qy][qx] = 0.0;
480 }
481 }
482
483 for (int dy = 0; dy < D1Dy; ++dy)
484 {
485 real_t massX[DofQuadLimits::HDIV_MAX_Q1D];
486 for (int qx = 0; qx < Q1D; ++qx)
487 {
488 massX[qx] = 0.0;
489 }
490
491 for (int dx = 0; dx < D1Dx; ++dx)
492 {
493 const real_t t = x(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
494 for (int qx = 0; qx < Q1D; ++qx)
495 {
496 massX[qx] += t * ((c == 0) ? Bc(qx,dx) : Bo(qx,dx));
497 }
498 }
499
500 for (int qy = 0; qy < Q1D; ++qy)
501 {
502 const real_t wy = (c == 1) ? Bc(qy,dy) : Bo(qy,dy);
503 for (int qx = 0; qx < Q1D; ++qx)
504 {
505 const real_t wx = massX[qx];
506 massXY[qy][qx] += wx * wy;
507 }
508 }
509 }
510
511 for (int qz = 0; qz < Q1D; ++qz)
512 {
513 const real_t wz = (c == 2) ? Bc(qz,dz) : Bo(qz,dz);
514 for (int qy = 0; qy < Q1D; ++qy)
515 {
516 for (int qx = 0; qx < Q1D; ++qx)
517 {
518 mass[qz][qy][qx][c] += massXY[qy][qx] * wz;
519 }
520 }
521 }
522 }
523
524 osc += D1Dx * D1Dy * D1Dz;
525 } // loop (c) over components
526
527 // Apply D operator.
528 for (int qz = 0; qz < Q1D; ++qz)
529 {
530 for (int qy = 0; qy < Q1D; ++qy)
531 {
532 for (int qx = 0; qx < Q1D; ++qx)
533 {
534 const real_t O11 = op(qx,qy,qz,0,e);
535 const real_t O12 = op(qx,qy,qz,1,e);
536 const real_t O13 = op(qx,qy,qz,2,e);
537 const real_t O21 = symmetric ? O12 : op(qx,qy,qz,3,e);
538 const real_t O22 = symmetric ? op(qx,qy,qz,3,e) : op(qx,qy,qz,4,e);
539 const real_t O23 = symmetric ? op(qx,qy,qz,4,e) : op(qx,qy,qz,5,e);
540 const real_t O31 = symmetric ? O13 : op(qx,qy,qz,6,e);
541 const real_t O32 = symmetric ? O23 : op(qx,qy,qz,7,e);
542 const real_t O33 = symmetric ? op(qx,qy,qz,5,e) : op(qx,qy,qz,8,e);
543
544 const real_t massX = mass[qz][qy][qx][0];
545 const real_t massY = mass[qz][qy][qx][1];
546 const real_t massZ = mass[qz][qy][qx][2];
547 mass[qz][qy][qx][0] = (O11*massX)+(O12*massY)+(O13*massZ);
548 mass[qz][qy][qx][1] = (O21*massX)+(O22*massY)+(O23*massZ);
549 mass[qz][qy][qx][2] = (O31*massX)+(O32*massY)+(O33*massZ);
550 }
551 }
552 }
553
554 for (int qz = 0; qz < Q1D; ++qz)
555 {
556 real_t massXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
557
558 osc = 0;
559
560 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
561 {
562 const int D1Dz = (c == 2) ? D1D : D1D - 1;
563 const int D1Dy = (c == 1) ? D1D : D1D - 1;
564 const int D1Dx = (c == 0) ? D1D : D1D - 1;
565
566 for (int dy = 0; dy < D1Dy; ++dy)
567 {
568 for (int dx = 0; dx < D1Dx; ++dx)
569 {
570 massXY[dy][dx] = 0;
571 }
572 }
573 for (int qy = 0; qy < Q1D; ++qy)
574 {
575 real_t massX[DofQuadLimits::HDIV_MAX_D1D];
576 for (int dx = 0; dx < D1Dx; ++dx)
577 {
578 massX[dx] = 0;
579 }
580 for (int qx = 0; qx < Q1D; ++qx)
581 {
582 for (int dx = 0; dx < D1Dx; ++dx)
583 {
584 massX[dx] += mass[qz][qy][qx][c] *
585 ((c == 0) ? Bct(dx,qx) : Bot(dx,qx));
586 }
587 }
588 for (int dy = 0; dy < D1Dy; ++dy)
589 {
590 const real_t wy = (c == 1) ? Bct(dy,qy) : Bot(dy,qy);
591 for (int dx = 0; dx < D1Dx; ++dx)
592 {
593 massXY[dy][dx] += massX[dx] * wy;
594 }
595 }
596 }
597
598 for (int dz = 0; dz < D1Dz; ++dz)
599 {
600 const real_t wz = (c == 2) ? Bct(dz,qz) : Bot(dz,qz);
601 for (int dy = 0; dy < D1Dy; ++dy)
602 {
603 for (int dx = 0; dx < D1Dx; ++dx)
604 {
605 y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) +=
606 massXY[dy][dx] * wz;
607 }
608 }
609 }
610
611 osc += D1Dx * D1Dy * D1Dz;
612 } // loop c
613 } // loop qz
614 }); // end of element loop
615}
616
617// NOTE: this is identical to PACurlCurlSetup2D
618void PADivDivSetup2D(const int Q1D,
619 const int NE,
620 const Array<real_t> &w,
621 const Vector &j,
622 Vector &coeff_,
623 Vector &op)
624{
625 const int NQ = Q1D*Q1D;
626 auto W = w.Read();
627 auto J = Reshape(j.Read(), NQ, 2, 2, NE);
628 auto coeff = Reshape(coeff_.Read(), NQ, NE);
629 auto y = Reshape(op.Write(), NQ, NE);
630 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
631 {
632 for (int q = 0; q < NQ; ++q)
633 {
634 const real_t J11 = J(q,0,0,e);
635 const real_t J21 = J(q,1,0,e);
636 const real_t J12 = J(q,0,1,e);
637 const real_t J22 = J(q,1,1,e);
638 const real_t detJ = (J11*J22)-(J21*J12);
639 y(q,e) = W[q] * coeff(q,e) / detJ;
640 }
641 });
642}
643
644void PADivDivSetup3D(const int Q1D,
645 const int NE,
646 const Array<real_t> &w,
647 const Vector &j,
648 Vector &coeff_,
649 Vector &op)
650{
651 const int NQ = Q1D*Q1D*Q1D;
652 auto W = w.Read();
653 auto J = Reshape(j.Read(), NQ, 3, 3, NE);
654 auto coeff = Reshape(coeff_.Read(), NQ, NE);
655 auto y = Reshape(op.Write(), NQ, NE);
656
657 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
658 {
659 for (int q = 0; q < NQ; ++q)
660 {
661 const real_t J11 = J(q,0,0,e);
662 const real_t J21 = J(q,1,0,e);
663 const real_t J31 = J(q,2,0,e);
664 const real_t J12 = J(q,0,1,e);
665 const real_t J22 = J(q,1,1,e);
666 const real_t J32 = J(q,2,1,e);
667 const real_t J13 = J(q,0,2,e);
668 const real_t J23 = J(q,1,2,e);
669 const real_t J33 = J(q,2,2,e);
670 const real_t detJ = J11 * (J22 * J33 - J32 * J23) -
671 J21 * (J12 * J33 - J32 * J13) +
672 J31 * (J12 * J23 - J22 * J13);
673 y(q,e) = W[q] * coeff(q, e) / detJ;
674 }
675 });
676}
677
678void PADivDivAssembleDiagonal2D(const int D1D,
679 const int Q1D,
680 const int NE,
681 const Array<real_t> &Bo_,
682 const Array<real_t> &Gc_,
683 const Vector &op_,
684 Vector &diag_)
685{
686 auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
687 auto Gc = Reshape(Gc_.Read(), Q1D, D1D);
688 auto op = Reshape(op_.Read(), Q1D, Q1D, NE);
689 auto diag = Reshape(diag_.ReadWrite(), 2*(D1D-1)*D1D, NE);
690
691 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
692 {
693 constexpr static int VDIM = 2;
694 constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
695
696 int osc = 0;
697
698 for (int c = 0; c < VDIM; ++c) // loop over x, y components
699 {
700 const int D1Dx = (c == 1) ? D1D - 1 : D1D;
701 const int D1Dy = (c == 0) ? D1D - 1 : D1D;
702
703 real_t div[MAX_Q1D];
704
705 for (int dy = 0; dy < D1Dy; ++dy)
706 {
707 for (int qx = 0; qx < Q1D; ++qx)
708 {
709 div[qx] = 0.0;
710 for (int qy = 0; qy < Q1D; ++qy)
711 {
712 const real_t wy = (c == 0) ? Bo(qy,dy) : Gc(qy,dy);
713 div[qx] += wy * wy * op(qx,qy,e);
714 }
715 }
716
717 for (int dx = 0; dx < D1Dx; ++dx)
718 {
719 real_t val = 0.0;
720 for (int qx = 0; qx < Q1D; ++qx)
721 {
722 const real_t wx = (c == 0) ? Gc(qx,dx) : Bo(qx,dx);
723 val += div[qx] * wx * wx;
724 }
725 diag(dx + (dy * D1Dx) + osc, e) += val;
726 }
727 }
728
729 osc += D1Dx * D1Dy;
730 } // loop c
731 });
732}
733
734void PADivDivAssembleDiagonal3D(const int D1D,
735 const int Q1D,
736 const int NE,
737 const Array<real_t> &Bo_,
738 const Array<real_t> &Gc_,
739 const Vector &op_,
740 Vector &diag_)
741{
742 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
743 "Error: D1D > HDIV_MAX_D1D");
744 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
745 "Error: Q1D > HDIV_MAX_Q1D");
746 constexpr static int VDIM = 3;
747
748 auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
749 auto Gc = Reshape(Gc_.Read(), Q1D, D1D);
750 auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, NE);
751 auto diag = Reshape(diag_.ReadWrite(), 3*(D1D-1)*(D1D-1)*D1D, NE);
752
753 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
754 {
755 int osc = 0;
756
757 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
758 {
759 const int D1Dz = (c == 2) ? D1D : D1D - 1;
760 const int D1Dy = (c == 1) ? D1D : D1D - 1;
761 const int D1Dx = (c == 0) ? D1D : D1D - 1;
762
763 for (int dz = 0; dz < D1Dz; ++dz)
764 {
765 for (int dy = 0; dy < D1Dy; ++dy)
766 {
767 real_t a[DofQuadLimits::HDIV_MAX_Q1D];
768
769 for (int qx = 0; qx < Q1D; ++qx)
770 {
771 a[qx] = 0.0;
772 for (int qy = 0; qy < Q1D; ++qy)
773 {
774 const real_t wy = (c == 1) ? Gc(qy,dy) : Bo(qy,dy);
775
776 for (int qz = 0; qz < Q1D; ++qz)
777 {
778 const real_t wz = (c == 2) ? Gc(qz,dz) : Bo(qz,dz);
779 a[qx] += wy * wy * wz * wz * op(qx,qy,qz,e);
780 }
781 }
782 }
783
784 for (int dx = 0; dx < D1Dx; ++dx)
785 {
786 real_t val = 0.0;
787 for (int qx = 0; qx < Q1D; ++qx)
788 {
789 const real_t wx = (c == 0) ? Gc(qx,dx) : Bo(qx,dx);
790 val += a[qx] * wx * wx;
791 }
792 diag(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += val;
793 }
794 }
795 }
796
797 osc += D1Dx * D1Dy * D1Dz;
798 } // loop c
799 }); // end of element loop
800}
801
802void PADivDivApply2D(const int D1D,
803 const int Q1D,
804 const int NE,
805 const Array<real_t> &Bo_,
806 const Array<real_t> &Gc_,
807 const Array<real_t> &Bot_,
808 const Array<real_t> &Gct_,
809 const Vector &op_,
810 const Vector &x_,
811 Vector &y_)
812{
813 auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
814 auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
815 auto Gc = Reshape(Gc_.Read(), Q1D, D1D);
816 auto Gct = Reshape(Gct_.Read(), D1D, Q1D);
817 auto op = Reshape(op_.Read(), Q1D, Q1D, NE);
818 auto x = Reshape(x_.Read(), 2*(D1D-1)*D1D, NE);
819 auto y = Reshape(y_.ReadWrite(), 2*(D1D-1)*D1D, NE);
820
821 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
822 {
823 constexpr static int VDIM = 2;
824 constexpr static int MAX_D1D = DofQuadLimits::HDIV_MAX_D1D;
825 constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
826
827 real_t div[MAX_Q1D][MAX_Q1D];
828
829 // div[qy][qx] will be computed as du_x/dx + du_y/dy
830
831 for (int qy = 0; qy < Q1D; ++qy)
832 {
833 for (int qx = 0; qx < Q1D; ++qx)
834 {
835 div[qy][qx] = 0;
836 }
837 }
838
839 int osc = 0;
840
841 for (int c = 0; c < VDIM; ++c) // loop over x, y components
842 {
843 const int D1Dx = (c == 1) ? D1D - 1 : D1D;
844 const int D1Dy = (c == 0) ? D1D - 1 : D1D;
845
846 for (int dy = 0; dy < D1Dy; ++dy)
847 {
848 real_t gradX[MAX_Q1D];
849 for (int qx = 0; qx < Q1D; ++qx)
850 {
851 gradX[qx] = 0;
852 }
853
854 for (int dx = 0; dx < D1Dx; ++dx)
855 {
856 const real_t t = x(dx + (dy * D1Dx) + osc, e);
857 for (int qx = 0; qx < Q1D; ++qx)
858 {
859 gradX[qx] += t * ((c == 0) ? Gc(qx,dx) : Bo(qx,dx));
860 }
861 }
862
863 for (int qy = 0; qy < Q1D; ++qy)
864 {
865 const real_t wy = (c == 0) ? Bo(qy,dy) : Gc(qy,dy);
866 for (int qx = 0; qx < Q1D; ++qx)
867 {
868 div[qy][qx] += gradX[qx] * wy;
869 }
870 }
871 }
872
873 osc += D1Dx * D1Dy;
874 } // loop (c) over components
875
876 // Apply D operator.
877 for (int qy = 0; qy < Q1D; ++qy)
878 {
879 for (int qx = 0; qx < Q1D; ++qx)
880 {
881 div[qy][qx] *= op(qx,qy,e);
882 }
883 }
884
885 for (int qy = 0; qy < Q1D; ++qy)
886 {
887 osc = 0;
888
889 for (int c = 0; c < VDIM; ++c) // loop over x, y components
890 {
891 const int D1Dx = (c == 1) ? D1D - 1 : D1D;
892 const int D1Dy = (c == 0) ? D1D - 1 : D1D;
893
894 real_t gradX[MAX_D1D];
895 for (int dx = 0; dx < D1Dx; ++dx)
896 {
897 gradX[dx] = 0;
898 }
899 for (int qx = 0; qx < Q1D; ++qx)
900 {
901 for (int dx = 0; dx < D1Dx; ++dx)
902 {
903 gradX[dx] += div[qy][qx] * (c == 0 ? Gct(dx,qx) : Bot(dx,qx));
904 }
905 }
906 for (int dy = 0; dy < D1Dy; ++dy)
907 {
908 const real_t wy = (c == 0) ? Bot(dy,qy) : Gct(dy,qy);
909 for (int dx = 0; dx < D1Dx; ++dx)
910 {
911 y(dx + (dy * D1Dx) + osc, e) += gradX[dx] * wy;
912 }
913 }
914
915 osc += D1Dx * D1Dy;
916 } // loop c
917 } // loop qy
918 }); // end of element loop
919}
920
921void PADivDivApply3D(const int D1D,
922 const int Q1D,
923 const int NE,
924 const Array<real_t> &Bo_,
925 const Array<real_t> &Gc_,
926 const Array<real_t> &Bot_,
927 const Array<real_t> &Gct_,
928 const Vector &op_,
929 const Vector &x_,
930 Vector &y_)
931{
932 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
933 "Error: D1D > HDIV_MAX_D1D");
934 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
935 "Error: Q1D > HDIV_MAX_Q1D");
936 constexpr static int VDIM = 3;
937
938 auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
939 auto Gc = Reshape(Gc_.Read(), Q1D, D1D);
940 auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
941 auto Gct = Reshape(Gct_.Read(), D1D, Q1D);
942 auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, NE);
943 auto x = Reshape(x_.Read(), 3*(D1D-1)*(D1D-1)*D1D, NE);
944 auto y = Reshape(y_.ReadWrite(), 3*(D1D-1)*(D1D-1)*D1D, NE);
945
946 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
947 {
948 real_t div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
949
950 for (int qz = 0; qz < Q1D; ++qz)
951 {
952 for (int qy = 0; qy < Q1D; ++qy)
953 {
954 for (int qx = 0; qx < Q1D; ++qx)
955 {
956 div[qz][qy][qx] = 0.0;
957 }
958 }
959 }
960
961 int osc = 0;
962
963 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
964 {
965 const int D1Dz = (c == 2) ? D1D : D1D - 1;
966 const int D1Dy = (c == 1) ? D1D : D1D - 1;
967 const int D1Dx = (c == 0) ? D1D : D1D - 1;
968
969 for (int dz = 0; dz < D1Dz; ++dz)
970 {
971 real_t aXY[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
972 for (int qy = 0; qy < Q1D; ++qy)
973 {
974 for (int qx = 0; qx < Q1D; ++qx)
975 {
976 aXY[qy][qx] = 0.0;
977 }
978 }
979
980 for (int dy = 0; dy < D1Dy; ++dy)
981 {
982 real_t aX[DofQuadLimits::HDIV_MAX_Q1D];
983 for (int qx = 0; qx < Q1D; ++qx)
984 {
985 aX[qx] = 0.0;
986 }
987
988 for (int dx = 0; dx < D1Dx; ++dx)
989 {
990 const real_t t = x(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
991 for (int qx = 0; qx < Q1D; ++qx)
992 {
993 aX[qx] += t * ((c == 0) ? Gc(qx,dx) : Bo(qx,dx));
994 }
995 }
996
997 for (int qy = 0; qy < Q1D; ++qy)
998 {
999 const real_t wy = (c == 1) ? Gc(qy,dy) : Bo(qy,dy);
1000 for (int qx = 0; qx < Q1D; ++qx)
1001 {
1002 const real_t wx = aX[qx];
1003 aXY[qy][qx] += wx * wy;
1004 }
1005 }
1006 }
1007
1008 for (int qz = 0; qz < Q1D; ++qz)
1009 {
1010 const real_t wz = (c == 2) ? Gc(qz,dz) : Bo(qz,dz);
1011 for (int qy = 0; qy < Q1D; ++qy)
1012 {
1013 for (int qx = 0; qx < Q1D; ++qx)
1014 {
1015 div[qz][qy][qx] += aXY[qy][qx] * wz;
1016 }
1017 }
1018 }
1019 }
1020
1021 osc += D1Dx * D1Dy * D1Dz;
1022 } // loop (c) over components
1023
1024 // Apply D operator.
1025 for (int qz = 0; qz < Q1D; ++qz)
1026 {
1027 for (int qy = 0; qy < Q1D; ++qy)
1028 {
1029 for (int qx = 0; qx < Q1D; ++qx)
1030 {
1031 div[qz][qy][qx] *= op(qx,qy,qz,e);
1032 }
1033 }
1034 }
1035
1036 for (int qz = 0; qz < Q1D; ++qz)
1037 {
1038 real_t aXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
1039
1040 osc = 0;
1041
1042 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
1043 {
1044 const int D1Dz = (c == 2) ? D1D : D1D - 1;
1045 const int D1Dy = (c == 1) ? D1D : D1D - 1;
1046 const int D1Dx = (c == 0) ? D1D : D1D - 1;
1047
1048 for (int dy = 0; dy < D1Dy; ++dy)
1049 {
1050 for (int dx = 0; dx < D1Dx; ++dx)
1051 {
1052 aXY[dy][dx] = 0;
1053 }
1054 }
1055 for (int qy = 0; qy < Q1D; ++qy)
1056 {
1057 real_t aX[DofQuadLimits::HDIV_MAX_D1D];
1058 for (int dx = 0; dx < D1Dx; ++dx)
1059 {
1060 aX[dx] = 0;
1061 }
1062 for (int qx = 0; qx < Q1D; ++qx)
1063 {
1064 for (int dx = 0; dx < D1Dx; ++dx)
1065 {
1066 aX[dx] += div[qz][qy][qx] *
1067 (c == 0 ? Gct(dx,qx) : Bot(dx,qx));
1068 }
1069 }
1070 for (int dy = 0; dy < D1Dy; ++dy)
1071 {
1072 const real_t wy = (c == 1) ? Gct(dy,qy) : Bot(dy,qy);
1073 for (int dx = 0; dx < D1Dx; ++dx)
1074 {
1075 aXY[dy][dx] += aX[dx] * wy;
1076 }
1077 }
1078 }
1079
1080 for (int dz = 0; dz < D1Dz; ++dz)
1081 {
1082 const real_t wz = (c == 2) ? Gct(dz,qz) : Bot(dz,qz);
1083 for (int dy = 0; dy < D1Dy; ++dy)
1084 {
1085 for (int dx = 0; dx < D1Dx; ++dx)
1086 {
1087 y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) +=
1088 aXY[dy][dx] * wz;
1089 }
1090 }
1091 }
1092
1093 osc += D1Dx * D1Dy * D1Dz;
1094 } // loop c
1095 } // loop qz
1096 }); // end of element loop
1097}
1098
1099void PAHdivL2Setup2D(const int Q1D, const int NE, const Array<real_t> &w,
1100 Vector &coeff_, Vector &op, const GeometricFactors *geom)
1101{
1102 const int NQ = Q1D*Q1D;
1103 auto W = w.Read();
1104 auto coeff = Reshape(coeff_.Read(), NQ, NE);
1105 auto y = Reshape(op.Write(), NQ, NE);
1106 bool have_detJ = (geom != nullptr);
1107 auto detJ = Reshape(have_detJ ? geom->detJ.Read() : nullptr, NQ, NE);
1108 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
1109 {
1110 for (int q = 0; q < NQ; ++q)
1111 {
1112 if (have_detJ)
1113 {
1114 y(q, e) = W[q] * coeff(q, e) / detJ(q, e);
1115 }
1116 else
1117 {
1118 y(q, e) = W[q] * coeff(q, e);
1119 }
1120 }
1121 });
1122}
1123
1124void PAHdivL2Setup3D(const int Q1D, const int NE, const Array<real_t> &w,
1125 Vector &coeff_, Vector &op, const GeometricFactors *geom)
1126{
1127 const int NQ = Q1D*Q1D*Q1D;
1128 auto W = w.Read();
1129 auto coeff = Reshape(coeff_.Read(), NQ, NE);
1130 auto y = Reshape(op.Write(), NQ, NE);
1131
1132 bool have_detJ = (geom != nullptr);
1133 auto detJ = Reshape(have_detJ ? geom->detJ.Read() : nullptr, NQ, NE);
1134
1135 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
1136 {
1137 for (int q = 0; q < NQ; ++q)
1138 {
1139 if (have_detJ)
1140 {
1141 y(q, e) = W[q] * coeff(q, e) / detJ(q, e);
1142 }
1143 else
1144 {
1145 y(q, e) = W[q] * coeff(q, e);
1146 }
1147 }
1148 });
1149}
1150
1151void PAHdivL2AssembleDiagonal_ADAt_2D(const int D1D,
1152 const int Q1D,
1153 const int L2D1D,
1154 const int NE,
1155 const Array<real_t> &L2Bo_,
1156 const Array<real_t> &Gct_,
1157 const Array<real_t> &Bot_,
1158 const Vector &op_,
1159 const Vector &D_,
1160 Vector &diag_)
1161{
1162 constexpr static int VDIM = 2;
1163
1164 auto L2Bo = Reshape(L2Bo_.Read(), Q1D, L2D1D);
1165 auto Gct = Reshape(Gct_.Read(), D1D, Q1D);
1166 auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
1167 auto op = Reshape(op_.Read(), Q1D, Q1D, NE);
1168 auto D = Reshape(D_.Read(), 2*(D1D-1)*D1D, NE);
1169 auto diag = Reshape(diag_.ReadWrite(), L2D1D, L2D1D, NE);
1170
1171 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
1172 {
1173 for (int ry = 0; ry < L2D1D; ++ry)
1174 {
1175 for (int rx = 0; rx < L2D1D; ++rx)
1176 {
1177 // Compute row (rx,ry), assuming all contributions are from
1178 // a single element.
1179
1180 real_t row[2*DofQuadLimits::HDIV_MAX_D1D*(DofQuadLimits::HDIV_MAX_D1D-1)];
1181 real_t div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
1182
1183 for (int i=0; i<2*D1D*(D1D - 1); ++i)
1184 {
1185 row[i] = 0;
1186 }
1187
1188 for (int qy = 0; qy < Q1D; ++qy)
1189 {
1190 for (int qx = 0; qx < Q1D; ++qx)
1191 {
1192 div[qy][qx] = op(qx,qy,e) * L2Bo(qx,rx) * L2Bo(qy,ry);
1193 }
1194 }
1195
1196 for (int qy = 0; qy < Q1D; ++qy)
1197 {
1198 int osc = 0;
1199 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
1200 {
1201 const int D1Dy = (c == 1) ? D1D : D1D - 1;
1202 const int D1Dx = (c == 0) ? D1D : D1D - 1;
1203
1204 real_t aX[DofQuadLimits::HDIV_MAX_D1D];
1205 for (int dx = 0; dx < D1Dx; ++dx)
1206 {
1207 aX[dx] = 0;
1208 }
1209 for (int qx = 0; qx < Q1D; ++qx)
1210 {
1211 for (int dx = 0; dx < D1Dx; ++dx)
1212 {
1213 aX[dx] += div[qy][qx] * ((c == 0) ? Gct(dx,qx) :
1214 Bot(dx,qx));
1215 }
1216 }
1217
1218 for (int dy = 0; dy < D1Dy; ++dy)
1219 {
1220 const real_t wy = (c == 1) ? Gct(dy,qy) : Bot(dy,qy);
1221
1222 for (int dx = 0; dx < D1Dx; ++dx)
1223 {
1224 row[dx + (dy * D1Dx) + osc] += aX[dx] * wy;
1225 }
1226 }
1227
1228 osc += D1Dx * D1Dy;
1229 } // loop c
1230 } // loop qy
1231
1232 real_t val = 0.0;
1233 for (int i=0; i<2*D1D*(D1D - 1); ++i)
1234 {
1235 val += row[i] * row[i] * D(i,e);
1236 }
1237 diag(rx,ry,e) += val;
1238 } // loop rx
1239 } // loop ry
1240 }); // end of element loop
1241}
1242
1243void PAHdivL2AssembleDiagonal_ADAt_3D(const int D1D,
1244 const int Q1D,
1245 const int L2D1D,
1246 const int NE,
1247 const Array<real_t> &L2Bo_,
1248 const Array<real_t> &Gct_,
1249 const Array<real_t> &Bot_,
1250 const Vector &op_,
1251 const Vector &D_,
1252 Vector &diag_)
1253{
1254 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
1255 "Error: D1D > HDIV_MAX_D1D");
1256 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
1257 "Error: Q1D > HDIV_MAX_Q1D");
1258 constexpr static int VDIM = 3;
1259
1260 auto L2Bo = Reshape(L2Bo_.Read(), Q1D, L2D1D);
1261 auto Gct = Reshape(Gct_.Read(), D1D, Q1D);
1262 auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
1263 auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, NE);
1264 auto D = Reshape(D_.Read(), 3*(D1D-1)*(D1D-1)*D1D, NE);
1265 auto diag = Reshape(diag_.ReadWrite(), L2D1D, L2D1D, L2D1D, NE);
1266
1267 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
1268 {
1269 for (int rz = 0; rz < L2D1D; ++rz)
1270 {
1271 for (int ry = 0; ry < L2D1D; ++ry)
1272 {
1273 for (int rx = 0; rx < L2D1D; ++rx)
1274 {
1275 // Compute row (rx,ry,rz), assuming all contributions are from
1276 // a single element.
1277
1278 real_t row[3*DofQuadLimits::HDIV_MAX_D1D*(DofQuadLimits::HDIV_MAX_D1D-1)*
1279 (DofQuadLimits::HDIV_MAX_D1D-1)];
1280 real_t div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
1281
1282 for (int i=0; i<3*D1D*(D1D - 1)*(D1D - 1); ++i)
1283 {
1284 row[i] = 0;
1285 }
1286
1287 for (int qz = 0; qz < Q1D; ++qz)
1288 {
1289 for (int qy = 0; qy < Q1D; ++qy)
1290 {
1291 for (int qx = 0; qx < Q1D; ++qx)
1292 {
1293 div[qz][qy][qx] = op(qx,qy,qz,e) * L2Bo(qx,rx) *
1294 L2Bo(qy,ry) * L2Bo(qz,rz);
1295 }
1296 }
1297 }
1298
1299 for (int qz = 0; qz < Q1D; ++qz)
1300 {
1301 real_t aXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
1302
1303 int osc = 0;
1304 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
1305 {
1306 const int D1Dz = (c == 2) ? D1D : D1D - 1;
1307 const int D1Dy = (c == 1) ? D1D : D1D - 1;
1308 const int D1Dx = (c == 0) ? D1D : D1D - 1;
1309
1310 for (int dy = 0; dy < D1Dy; ++dy)
1311 {
1312 for (int dx = 0; dx < D1Dx; ++dx)
1313 {
1314 aXY[dy][dx] = 0;
1315 }
1316 }
1317 for (int qy = 0; qy < Q1D; ++qy)
1318 {
1319 real_t aX[DofQuadLimits::HDIV_MAX_D1D];
1320 for (int dx = 0; dx < D1Dx; ++dx)
1321 {
1322 aX[dx] = 0;
1323 }
1324 for (int qx = 0; qx < Q1D; ++qx)
1325 {
1326 for (int dx = 0; dx < D1Dx; ++dx)
1327 {
1328 aX[dx] += div[qz][qy][qx] * ((c == 0) ? Gct(dx,qx)
1329 : Bot(dx,qx));
1330 }
1331 }
1332 for (int dy = 0; dy < D1Dy; ++dy)
1333 {
1334 const real_t wy = (c == 1) ? Gct(dy,qy) : Bot(dy,qy);
1335 for (int dx = 0; dx < D1Dx; ++dx)
1336 {
1337 aXY[dy][dx] += aX[dx] * wy;
1338 }
1339 }
1340 }
1341
1342 for (int dz = 0; dz < D1Dz; ++dz)
1343 {
1344 const real_t wz = (c == 2) ? Gct(dz,qz) : Bot(dz,qz);
1345 for (int dy = 0; dy < D1Dy; ++dy)
1346 {
1347 for (int dx = 0; dx < D1Dx; ++dx)
1348 {
1349 row[dx + ((dy + (dz * D1Dy)) * D1Dx) + osc] +=
1350 aXY[dy][dx] * wz;
1351 }
1352 }
1353 }
1354
1355 osc += D1Dx * D1Dy * D1Dz;
1356 } // loop c
1357 } // loop qz
1358
1359 real_t val = 0.0;
1360 for (int i=0; i<3*D1D*(D1D - 1)*(D1D - 1); ++i)
1361 {
1362 val += row[i] * row[i] * D(i,e);
1363 }
1364 diag(rx,ry,rz,e) += val;
1365 } // loop rx
1366 } // loop ry
1367 } // loop rz
1368 }); // end of element loop
1369}
1370
1371// Apply to x corresponding to DOFs in H(div) (trial), whose divergence is
1372// integrated against L_2 test functions corresponding to y.
1373void PAHdivL2Apply2D(const int D1D,
1374 const int Q1D,
1375 const int L2D1D,
1376 const int NE,
1377 const Array<real_t> &Bo_,
1378 const Array<real_t> &Gc_,
1379 const Array<real_t> &L2Bot_,
1380 const Vector &op_,
1381 const Vector &x_,
1382 Vector &y_)
1383{
1384 auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
1385 auto Gc = Reshape(Gc_.Read(), Q1D, D1D);
1386 auto L2Bot = Reshape(L2Bot_.Read(), L2D1D, Q1D);
1387 auto op = Reshape(op_.Read(), Q1D, Q1D, NE);
1388 auto x = Reshape(x_.Read(), 2*(D1D-1)*D1D, NE);
1389 auto y = Reshape(y_.ReadWrite(), L2D1D, L2D1D, NE);
1390
1391 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
1392 {
1393 constexpr static int VDIM = 2;
1394 constexpr static int MAX_D1D = DofQuadLimits::HDIV_MAX_D1D;
1395 constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
1396
1397 real_t div[MAX_Q1D][MAX_Q1D];
1398
1399 for (int qy = 0; qy < Q1D; ++qy)
1400 {
1401 for (int qx = 0; qx < Q1D; ++qx)
1402 {
1403 div[qy][qx] = 0.0;
1404 }
1405 }
1406
1407 int osc = 0;
1408
1409 for (int c = 0; c < VDIM; ++c) // loop over x, y components
1410 {
1411 const int D1Dy = (c == 1) ? D1D : D1D - 1;
1412 const int D1Dx = (c == 0) ? D1D : D1D - 1;
1413
1414 for (int dy = 0; dy < D1Dy; ++dy)
1415 {
1416 real_t aX[MAX_Q1D];
1417 for (int qx = 0; qx < Q1D; ++qx)
1418 {
1419 aX[qx] = 0.0;
1420 }
1421
1422 for (int dx = 0; dx < D1Dx; ++dx)
1423 {
1424 const real_t t = x(dx + (dy * D1Dx) + osc, e);
1425 for (int qx = 0; qx < Q1D; ++qx)
1426 {
1427 aX[qx] += t * ((c == 0) ? Gc(qx,dx) : Bo(qx,dx));
1428 }
1429 }
1430
1431 for (int qy = 0; qy < Q1D; ++qy)
1432 {
1433 const real_t wy = (c == 1) ? Gc(qy,dy) : Bo(qy,dy);
1434 for (int qx = 0; qx < Q1D; ++qx)
1435 {
1436 div[qy][qx] += aX[qx] * wy;
1437 }
1438 }
1439 }
1440
1441 osc += D1Dx * D1Dy;
1442 } // loop (c) over components
1443
1444 // Apply D operator.
1445 for (int qy = 0; qy < Q1D; ++qy)
1446 {
1447 for (int qx = 0; qx < Q1D; ++qx)
1448 {
1449 div[qy][qx] *= op(qx,qy,e);
1450 }
1451 }
1452
1453 for (int qy = 0; qy < Q1D; ++qy)
1454 {
1455 real_t aX[MAX_D1D];
1456 for (int dx = 0; dx < L2D1D; ++dx)
1457 {
1458 aX[dx] = 0;
1459 }
1460 for (int qx = 0; qx < Q1D; ++qx)
1461 {
1462 for (int dx = 0; dx < L2D1D; ++dx)
1463 {
1464 aX[dx] += div[qy][qx] * L2Bot(dx,qx);
1465 }
1466 }
1467 for (int dy = 0; dy < L2D1D; ++dy)
1468 {
1469 const real_t wy = L2Bot(dy,qy);
1470 for (int dx = 0; dx < L2D1D; ++dx)
1471 {
1472 y(dx,dy,e) += aX[dx] * wy;
1473 }
1474 }
1475 }
1476 }); // end of element loop
1477}
1478
1479void PAHdivL2ApplyTranspose2D(const int D1D,
1480 const int Q1D,
1481 const int L2D1D,
1482 const int NE,
1483 const Array<real_t> &L2Bo_,
1484 const Array<real_t> &Gct_,
1485 const Array<real_t> &Bot_,
1486 const Vector &op_,
1487 const Vector &x_,
1488 Vector &y_)
1489{
1490 auto L2Bo = Reshape(L2Bo_.Read(), Q1D, L2D1D);
1491 auto Gct = Reshape(Gct_.Read(), D1D, Q1D);
1492 auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
1493 auto op = Reshape(op_.Read(), Q1D, Q1D, NE);
1494 auto x = Reshape(x_.Read(), L2D1D, L2D1D, NE);
1495 auto y = Reshape(y_.ReadWrite(), 2*(D1D-1)*D1D, NE);
1496
1497 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
1498 {
1499 constexpr static int VDIM = 2;
1500 constexpr static int MAX_D1D = DofQuadLimits::HDIV_MAX_D1D;
1501 constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
1502
1503 real_t div[MAX_Q1D][MAX_Q1D];
1504
1505 for (int qy = 0; qy < Q1D; ++qy)
1506 {
1507 for (int qx = 0; qx < Q1D; ++qx)
1508 {
1509 div[qy][qx] = 0.0;
1510 }
1511 }
1512
1513 for (int dy = 0; dy < L2D1D; ++dy)
1514 {
1515 real_t aX[MAX_Q1D];
1516 for (int qx = 0; qx < Q1D; ++qx)
1517 {
1518 aX[qx] = 0.0;
1519 }
1520
1521 for (int dx = 0; dx < L2D1D; ++dx)
1522 {
1523 const real_t t = x(dx,dy,e);
1524 for (int qx = 0; qx < Q1D; ++qx)
1525 {
1526 aX[qx] += t * L2Bo(qx,dx);
1527 }
1528 }
1529
1530 for (int qy = 0; qy < Q1D; ++qy)
1531 {
1532 const real_t wy = L2Bo(qy,dy);
1533 for (int qx = 0; qx < Q1D; ++qx)
1534 {
1535 div[qy][qx] += aX[qx] * wy;
1536 }
1537 }
1538 }
1539
1540 // Apply D operator.
1541 for (int qy = 0; qy < Q1D; ++qy)
1542 {
1543 for (int qx = 0; qx < Q1D; ++qx)
1544 {
1545 div[qy][qx] *= op(qx,qy,e);
1546 }
1547 }
1548
1549 for (int qy = 0; qy < Q1D; ++qy)
1550 {
1551 real_t aX[MAX_D1D];
1552
1553 int osc = 0;
1554 for (int c = 0; c < VDIM; ++c) // loop over x, y components
1555 {
1556 const int D1Dy = (c == 1) ? D1D : D1D - 1;
1557 const int D1Dx = (c == 0) ? D1D : D1D - 1;
1558
1559 for (int dx = 0; dx < D1Dx; ++dx)
1560 {
1561 aX[dx] = 0;
1562 }
1563 for (int qx = 0; qx < Q1D; ++qx)
1564 {
1565 for (int dx = 0; dx < D1Dx; ++dx)
1566 {
1567 aX[dx] += div[qy][qx] * ((c == 0) ? Gct(dx,qx) : Bot(dx,qx));
1568 }
1569 }
1570 for (int dy = 0; dy < D1Dy; ++dy)
1571 {
1572 const real_t wy = (c == 0) ? Bot(dy,qy) : Gct(dy,qy);
1573 for (int dx = 0; dx < D1Dx; ++dx)
1574 {
1575 y(dx + (dy * D1Dx) + osc, e) += aX[dx] * wy;
1576 }
1577 }
1578
1579 osc += D1Dx * D1Dy;
1580 } // loop c
1581 } // loop qy
1582 }); // end of element loop
1583}
1584
1585// Apply to x corresponding to DOFs in H(div) (trial), whose divergence is
1586// integrated against L_2 test functions corresponding to y.
1587void PAHdivL2Apply3D(const int D1D,
1588 const int Q1D,
1589 const int L2D1D,
1590 const int NE,
1591 const Array<real_t> &Bo_,
1592 const Array<real_t> &Gc_,
1593 const Array<real_t> &L2Bot_,
1594 const Vector &op_,
1595 const Vector &x_,
1596 Vector &y_)
1597{
1598 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
1599 "Error: D1D > HDIV_MAX_D1D");
1600 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
1601 "Error: Q1D > HDIV_MAX_Q1D");
1602 constexpr static int VDIM = 3;
1603
1604 auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
1605 auto Gc = Reshape(Gc_.Read(), Q1D, D1D);
1606 auto L2Bot = Reshape(L2Bot_.Read(), L2D1D, Q1D);
1607 auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, NE);
1608 auto x = Reshape(x_.Read(), 3*(D1D-1)*(D1D-1)*D1D, NE);
1609 auto y = Reshape(y_.ReadWrite(), L2D1D, L2D1D, L2D1D, NE);
1610
1611 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
1612 {
1613 real_t div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
1614
1615 for (int qz = 0; qz < Q1D; ++qz)
1616 {
1617 for (int qy = 0; qy < Q1D; ++qy)
1618 {
1619 for (int qx = 0; qx < Q1D; ++qx)
1620 {
1621 div[qz][qy][qx] = 0.0;
1622 }
1623 }
1624 }
1625
1626 int osc = 0;
1627
1628 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
1629 {
1630 const int D1Dz = (c == 2) ? D1D : D1D - 1;
1631 const int D1Dy = (c == 1) ? D1D : D1D - 1;
1632 const int D1Dx = (c == 0) ? D1D : D1D - 1;
1633
1634 for (int dz = 0; dz < D1Dz; ++dz)
1635 {
1636 real_t aXY[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
1637 for (int qy = 0; qy < Q1D; ++qy)
1638 {
1639 for (int qx = 0; qx < Q1D; ++qx)
1640 {
1641 aXY[qy][qx] = 0.0;
1642 }
1643 }
1644
1645 for (int dy = 0; dy < D1Dy; ++dy)
1646 {
1647 real_t aX[DofQuadLimits::HDIV_MAX_Q1D];
1648 for (int qx = 0; qx < Q1D; ++qx)
1649 {
1650 aX[qx] = 0.0;
1651 }
1652
1653 for (int dx = 0; dx < D1Dx; ++dx)
1654 {
1655 const real_t t = x(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
1656 for (int qx = 0; qx < Q1D; ++qx)
1657 {
1658 aX[qx] += t * ((c == 0) ? Gc(qx,dx) : Bo(qx,dx));
1659 }
1660 }
1661
1662 for (int qy = 0; qy < Q1D; ++qy)
1663 {
1664 const real_t wy = (c == 1) ? Gc(qy,dy) : Bo(qy,dy);
1665 for (int qx = 0; qx < Q1D; ++qx)
1666 {
1667 aXY[qy][qx] += aX[qx] * wy;
1668 }
1669 }
1670 }
1671
1672 for (int qz = 0; qz < Q1D; ++qz)
1673 {
1674 const real_t wz = (c == 2) ? Gc(qz,dz) : Bo(qz,dz);
1675 for (int qy = 0; qy < Q1D; ++qy)
1676 {
1677 for (int qx = 0; qx < Q1D; ++qx)
1678 {
1679 div[qz][qy][qx] += aXY[qy][qx] * wz;
1680 }
1681 }
1682 }
1683 }
1684
1685 osc += D1Dx * D1Dy * D1Dz;
1686 } // loop (c) over components
1687
1688 // Apply D operator.
1689 for (int qz = 0; qz < Q1D; ++qz)
1690 {
1691 for (int qy = 0; qy < Q1D; ++qy)
1692 {
1693 for (int qx = 0; qx < Q1D; ++qx)
1694 {
1695 div[qz][qy][qx] *= op(qx,qy,qz,e);
1696 }
1697 }
1698 }
1699
1700 for (int qz = 0; qz < Q1D; ++qz)
1701 {
1702 real_t aXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
1703
1704 for (int dy = 0; dy < L2D1D; ++dy)
1705 {
1706 for (int dx = 0; dx < L2D1D; ++dx)
1707 {
1708 aXY[dy][dx] = 0;
1709 }
1710 }
1711 for (int qy = 0; qy < Q1D; ++qy)
1712 {
1713 real_t aX[DofQuadLimits::HDIV_MAX_D1D];
1714 for (int dx = 0; dx < L2D1D; ++dx)
1715 {
1716 aX[dx] = 0;
1717 }
1718 for (int qx = 0; qx < Q1D; ++qx)
1719 {
1720 for (int dx = 0; dx < L2D1D; ++dx)
1721 {
1722 aX[dx] += div[qz][qy][qx] * L2Bot(dx,qx);
1723 }
1724 }
1725 for (int dy = 0; dy < L2D1D; ++dy)
1726 {
1727 const real_t wy = L2Bot(dy,qy);
1728 for (int dx = 0; dx < L2D1D; ++dx)
1729 {
1730 aXY[dy][dx] += aX[dx] * wy;
1731 }
1732 }
1733 }
1734
1735 for (int dz = 0; dz < L2D1D; ++dz)
1736 {
1737 const real_t wz = L2Bot(dz,qz);
1738 for (int dy = 0; dy < L2D1D; ++dy)
1739 {
1740 for (int dx = 0; dx < L2D1D; ++dx)
1741 {
1742 y(dx,dy,dz,e) += aXY[dy][dx] * wz;
1743 }
1744 }
1745 }
1746 } // loop qz
1747 }); // end of element loop
1748}
1749
1750void PAHdivL2ApplyTranspose3D(const int D1D,
1751 const int Q1D,
1752 const int L2D1D,
1753 const int NE,
1754 const Array<real_t> &L2Bo_,
1755 const Array<real_t> &Gct_,
1756 const Array<real_t> &Bot_,
1757 const Vector &op_,
1758 const Vector &x_,
1759 Vector &y_)
1760{
1761 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
1762 "Error: D1D > HDIV_MAX_D1D");
1763 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
1764 "Error: Q1D > HDIV_MAX_Q1D");
1765 constexpr static int VDIM = 3;
1766
1767 auto L2Bo = Reshape(L2Bo_.Read(), Q1D, L2D1D);
1768 auto Gct = Reshape(Gct_.Read(), D1D, Q1D);
1769 auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
1770 auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, NE);
1771 auto x = Reshape(x_.Read(), L2D1D, L2D1D, L2D1D, NE);
1772 auto y = Reshape(y_.ReadWrite(), 3*(D1D-1)*(D1D-1)*D1D, NE);
1773
1774 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
1775 {
1776 real_t div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
1777
1778 for (int qz = 0; qz < Q1D; ++qz)
1779 {
1780 for (int qy = 0; qy < Q1D; ++qy)
1781 {
1782 for (int qx = 0; qx < Q1D; ++qx)
1783 {
1784 div[qz][qy][qx] = 0.0;
1785 }
1786 }
1787 }
1788
1789 for (int dz = 0; dz < L2D1D; ++dz)
1790 {
1791 real_t aXY[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
1792 for (int qy = 0; qy < Q1D; ++qy)
1793 {
1794 for (int qx = 0; qx < Q1D; ++qx)
1795 {
1796 aXY[qy][qx] = 0.0;
1797 }
1798 }
1799
1800 for (int dy = 0; dy < L2D1D; ++dy)
1801 {
1802 real_t aX[DofQuadLimits::HDIV_MAX_Q1D];
1803 for (int qx = 0; qx < Q1D; ++qx)
1804 {
1805 aX[qx] = 0.0;
1806 }
1807
1808 for (int dx = 0; dx < L2D1D; ++dx)
1809 {
1810 const real_t t = x(dx,dy,dz,e);
1811 for (int qx = 0; qx < Q1D; ++qx)
1812 {
1813 aX[qx] += t * L2Bo(qx,dx);
1814 }
1815 }
1816
1817 for (int qy = 0; qy < Q1D; ++qy)
1818 {
1819 const real_t wy = L2Bo(qy,dy);
1820 for (int qx = 0; qx < Q1D; ++qx)
1821 {
1822 aXY[qy][qx] += aX[qx] * wy;
1823 }
1824 }
1825 }
1826
1827 for (int qz = 0; qz < Q1D; ++qz)
1828 {
1829 const real_t wz = L2Bo(qz,dz);
1830 for (int qy = 0; qy < Q1D; ++qy)
1831 {
1832 for (int qx = 0; qx < Q1D; ++qx)
1833 {
1834 div[qz][qy][qx] += aXY[qy][qx] * wz;
1835 }
1836 }
1837 }
1838 }
1839
1840 // Apply D operator.
1841 for (int qz = 0; qz < Q1D; ++qz)
1842 {
1843 for (int qy = 0; qy < Q1D; ++qy)
1844 {
1845 for (int qx = 0; qx < Q1D; ++qx)
1846 {
1847 div[qz][qy][qx] *= op(qx,qy,qz,e);
1848 }
1849 }
1850 }
1851
1852 for (int qz = 0; qz < Q1D; ++qz)
1853 {
1854 real_t aXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
1855
1856 int osc = 0;
1857 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
1858 {
1859 const int D1Dz = (c == 2) ? D1D : D1D - 1;
1860 const int D1Dy = (c == 1) ? D1D : D1D - 1;
1861 const int D1Dx = (c == 0) ? D1D : D1D - 1;
1862
1863 for (int dy = 0; dy < D1Dy; ++dy)
1864 {
1865 for (int dx = 0; dx < D1Dx; ++dx)
1866 {
1867 aXY[dy][dx] = 0;
1868 }
1869 }
1870 for (int qy = 0; qy < Q1D; ++qy)
1871 {
1872 real_t aX[DofQuadLimits::HDIV_MAX_D1D];
1873 for (int dx = 0; dx < D1Dx; ++dx)
1874 {
1875 aX[dx] = 0;
1876 }
1877 for (int qx = 0; qx < Q1D; ++qx)
1878 {
1879 for (int dx = 0; dx < D1Dx; ++dx)
1880 {
1881 aX[dx] += div[qz][qy][qx] * ((c == 0) ? Gct(dx,qx) :
1882 Bot(dx,qx));
1883 }
1884 }
1885 for (int dy = 0; dy < D1Dy; ++dy)
1886 {
1887 const real_t wy = (c == 1) ? Gct(dy,qy) : Bot(dy,qy);
1888 for (int dx = 0; dx < D1Dx; ++dx)
1889 {
1890 aXY[dy][dx] += aX[dx] * wy;
1891 }
1892 }
1893 }
1894
1895 for (int dz = 0; dz < D1Dz; ++dz)
1896 {
1897 const real_t wz = (c == 2) ? Gct(dz,qz) : Bot(dz,qz);
1898 for (int dy = 0; dy < D1Dy; ++dy)
1899 {
1900 for (int dx = 0; dx < D1Dx; ++dx)
1901 {
1902 y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) +=
1903 aXY[dy][dx] * wz;
1904 }
1905 }
1906 }
1907
1908 osc += D1Dx * D1Dy * D1Dz;
1909 } // loop c
1910 } // loop qz
1911 }); // end of element loop
1912}
1913
1914} // namespace internal
1915
1916} // namespace mfem
real_t a
Definition lissajous.cpp:41
mfem::real_t real_t
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
Definition dtensor.hpp:138
void forall(int N, lambda &&body)
Definition forall.hpp:1134
static const DeviceDofQuadLimits & Get()
Return a const reference to the DeviceDofQuadLimits singleton.
Definition forall.hpp:138