MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
bilininteg_hcurl_kernels.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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 PAHcurlMassAssembleDiagonal2D(const int D1D,
21 const int Q1D,
22 const int NE,
23 const bool symmetric,
24 const Array<real_t> &bo,
25 const Array<real_t> &bc,
26 const Vector &pa_data,
27 Vector &diag)
28{
29 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
30 auto Bc = Reshape(bc.Read(), Q1D, D1D);
31 auto op = Reshape(pa_data.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
32 auto D = Reshape(diag.ReadWrite(), 2*(D1D-1)*D1D, NE);
33
34 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
35 {
36 constexpr static int VDIM = 2;
37 constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
38
39 int osc = 0;
40
41 for (int c = 0; c < VDIM; ++c) // loop over x, y components
42 {
43 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
44 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
45
46 real_t mass[MAX_Q1D];
47
48 for (int dy = 0; dy < D1Dy; ++dy)
49 {
50 for (int qx = 0; qx < Q1D; ++qx)
51 {
52 mass[qx] = 0.0;
53 for (int qy = 0; qy < Q1D; ++qy)
54 {
55 const real_t wy = (c == 1) ? Bo(qy,dy) : Bc(qy,dy);
56
57 mass[qx] += wy * wy * ((c == 0) ? op(qx,qy,0,e) :
58 op(qx,qy,symmetric ? 2 : 3, e));
59 }
60 }
61
62 for (int dx = 0; dx < D1Dx; ++dx)
63 {
64 for (int qx = 0; qx < Q1D; ++qx)
65 {
66 const real_t wx = ((c == 0) ? Bo(qx,dx) : Bc(qx,dx));
67 D(dx + (dy * D1Dx) + osc, e) += mass[qx] * wx * wx;
68 }
69 }
70 }
71
72 osc += D1Dx * D1Dy;
73 } // loop c
74 }); // end of element loop
75}
76
77void PAHcurlMassAssembleDiagonal3D(const int D1D,
78 const int Q1D,
79 const int NE,
80 const bool symmetric,
81 const Array<real_t> &bo,
82 const Array<real_t> &bc,
83 const Vector &pa_data,
84 Vector &diag)
85{
86 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
87 "Error: D1D > MAX_D1D");
88 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
89 "Error: Q1D > MAX_Q1D");
90 constexpr static int VDIM = 3;
91
92 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
93 auto Bc = Reshape(bc.Read(), Q1D, D1D);
94 auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
95 auto D = Reshape(diag.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
96
97 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
98 {
99 constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
100
101 int osc = 0;
102
103 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
104 {
105 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
106 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
107 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
108
109 const int opc = (c == 0) ? 0 : ((c == 1) ? (symmetric ? 3 : 4) :
110 (symmetric ? 5 : 8));
111
112 real_t mass[MAX_Q1D];
113
114 for (int dz = 0; dz < D1Dz; ++dz)
115 {
116 for (int dy = 0; dy < D1Dy; ++dy)
117 {
118 for (int qx = 0; qx < Q1D; ++qx)
119 {
120 mass[qx] = 0.0;
121 for (int qy = 0; qy < Q1D; ++qy)
122 {
123 const real_t wy = (c == 1) ? Bo(qy,dy) : Bc(qy,dy);
124
125 for (int qz = 0; qz < Q1D; ++qz)
126 {
127 const real_t wz = (c == 2) ? Bo(qz,dz) : Bc(qz,dz);
128
129 mass[qx] += wy * wy * wz * wz * op(qx,qy,qz,opc,e);
130 }
131 }
132 }
133
134 for (int dx = 0; dx < D1Dx; ++dx)
135 {
136 for (int qx = 0; qx < Q1D; ++qx)
137 {
138 const real_t wx = ((c == 0) ? Bo(qx,dx) : Bc(qx,dx));
139 D(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += mass[qx] * wx * wx;
140 }
141 }
142 }
143 }
144
145 osc += D1Dx * D1Dy * D1Dz;
146 } // loop c
147 }); // end of element loop
148}
149
150void PAHcurlMassApply2D(const int D1D,
151 const int Q1D,
152 const int NE,
153 const bool symmetric,
154 const Array<real_t> &bo,
155 const Array<real_t> &bc,
156 const Array<real_t> &bot,
157 const Array<real_t> &bct,
158 const Vector &pa_data,
159 const Vector &x,
160 Vector &y)
161{
162 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
163 auto Bc = Reshape(bc.Read(), Q1D, D1D);
164 auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
165 auto Bct = Reshape(bct.Read(), D1D, Q1D);
166 auto op = Reshape(pa_data.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
167 auto X = Reshape(x.Read(), 2*(D1D-1)*D1D, NE);
168 auto Y = Reshape(y.ReadWrite(), 2*(D1D-1)*D1D, NE);
169
170 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
171 {
172 constexpr static int VDIM = 2;
173 constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
174 constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
175
176 real_t mass[MAX_Q1D][MAX_Q1D][VDIM];
177
178 for (int qy = 0; qy < Q1D; ++qy)
179 {
180 for (int qx = 0; qx < Q1D; ++qx)
181 {
182 for (int c = 0; c < VDIM; ++c)
183 {
184 mass[qy][qx][c] = 0.0;
185 }
186 }
187 }
188
189 int osc = 0;
190
191 for (int c = 0; c < VDIM; ++c) // loop over x, y components
192 {
193 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
194 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
195
196 for (int dy = 0; dy < D1Dy; ++dy)
197 {
198 real_t massX[MAX_Q1D];
199 for (int qx = 0; qx < Q1D; ++qx)
200 {
201 massX[qx] = 0.0;
202 }
203
204 for (int dx = 0; dx < D1Dx; ++dx)
205 {
206 const real_t t = X(dx + (dy * D1Dx) + osc, e);
207 for (int qx = 0; qx < Q1D; ++qx)
208 {
209 massX[qx] += t * ((c == 0) ? Bo(qx,dx) : Bc(qx,dx));
210 }
211 }
212
213 for (int qy = 0; qy < Q1D; ++qy)
214 {
215 const real_t wy = (c == 1) ? Bo(qy,dy) : Bc(qy,dy);
216 for (int qx = 0; qx < Q1D; ++qx)
217 {
218 mass[qy][qx][c] += massX[qx] * wy;
219 }
220 }
221 }
222
223 osc += D1Dx * D1Dy;
224 } // loop (c) over components
225
226 // Apply D operator.
227 for (int qy = 0; qy < Q1D; ++qy)
228 {
229 for (int qx = 0; qx < Q1D; ++qx)
230 {
231 const real_t O11 = op(qx,qy,0,e);
232 const real_t O21 = op(qx,qy,1,e);
233 const real_t O12 = symmetric ? O21 : op(qx,qy,2,e);
234 const real_t O22 = symmetric ? op(qx,qy,2,e) : op(qx,qy,3,e);
235 const real_t massX = mass[qy][qx][0];
236 const real_t massY = mass[qy][qx][1];
237 mass[qy][qx][0] = (O11*massX)+(O12*massY);
238 mass[qy][qx][1] = (O21*massX)+(O22*massY);
239 }
240 }
241
242 for (int qy = 0; qy < Q1D; ++qy)
243 {
244 osc = 0;
245
246 for (int c = 0; c < VDIM; ++c) // loop over x, y components
247 {
248 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
249 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
250
251 real_t massX[MAX_D1D];
252 for (int dx = 0; dx < D1Dx; ++dx)
253 {
254 massX[dx] = 0.0;
255 }
256 for (int qx = 0; qx < Q1D; ++qx)
257 {
258 for (int dx = 0; dx < D1Dx; ++dx)
259 {
260 massX[dx] += mass[qy][qx][c] * ((c == 0) ? Bot(dx,qx) : Bct(dx,qx));
261 }
262 }
263
264 for (int dy = 0; dy < D1Dy; ++dy)
265 {
266 const real_t wy = (c == 1) ? Bot(dy,qy) : Bct(dy,qy);
267
268 for (int dx = 0; dx < D1Dx; ++dx)
269 {
270 Y(dx + (dy * D1Dx) + osc, e) += massX[dx] * wy;
271 }
272 }
273
274 osc += D1Dx * D1Dy;
275 } // loop c
276 } // loop qy
277 }); // end of element loop
278}
279
280void PAHcurlMassApply3D(const int D1D,
281 const int Q1D,
282 const int NE,
283 const bool symmetric,
284 const Array<real_t> &bo,
285 const Array<real_t> &bc,
286 const Array<real_t> &bot,
287 const Array<real_t> &bct,
288 const Vector &pa_data,
289 const Vector &x,
290 Vector &y)
291{
292 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
293 "Error: D1D > MAX_D1D");
294 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
295 "Error: Q1D > MAX_Q1D");
296 constexpr static int VDIM = 3;
297
298 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
299 auto Bc = Reshape(bc.Read(), Q1D, D1D);
300 auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
301 auto Bct = Reshape(bct.Read(), D1D, Q1D);
302 auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
303 auto X = Reshape(x.Read(), 3*(D1D-1)*D1D*D1D, NE);
304 auto Y = Reshape(y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
305
306 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
307 {
308 constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
309 constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
310
311 real_t mass[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
312
313 for (int qz = 0; qz < Q1D; ++qz)
314 {
315 for (int qy = 0; qy < Q1D; ++qy)
316 {
317 for (int qx = 0; qx < Q1D; ++qx)
318 {
319 for (int c = 0; c < VDIM; ++c)
320 {
321 mass[qz][qy][qx][c] = 0.0;
322 }
323 }
324 }
325 }
326
327 int osc = 0;
328
329 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
330 {
331 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
332 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
333 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
334
335 for (int dz = 0; dz < D1Dz; ++dz)
336 {
337 real_t massXY[MAX_Q1D][MAX_Q1D];
338 for (int qy = 0; qy < Q1D; ++qy)
339 {
340 for (int qx = 0; qx < Q1D; ++qx)
341 {
342 massXY[qy][qx] = 0.0;
343 }
344 }
345
346 for (int dy = 0; dy < D1Dy; ++dy)
347 {
348 real_t massX[MAX_Q1D];
349 for (int qx = 0; qx < Q1D; ++qx)
350 {
351 massX[qx] = 0.0;
352 }
353
354 for (int dx = 0; dx < D1Dx; ++dx)
355 {
356 const real_t t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
357 for (int qx = 0; qx < Q1D; ++qx)
358 {
359 massX[qx] += t * ((c == 0) ? Bo(qx,dx) : Bc(qx,dx));
360 }
361 }
362
363 for (int qy = 0; qy < Q1D; ++qy)
364 {
365 const real_t wy = (c == 1) ? Bo(qy,dy) : Bc(qy,dy);
366 for (int qx = 0; qx < Q1D; ++qx)
367 {
368 const real_t wx = massX[qx];
369 massXY[qy][qx] += wx * wy;
370 }
371 }
372 }
373
374 for (int qz = 0; qz < Q1D; ++qz)
375 {
376 const real_t wz = (c == 2) ? Bo(qz,dz) : Bc(qz,dz);
377 for (int qy = 0; qy < Q1D; ++qy)
378 {
379 for (int qx = 0; qx < Q1D; ++qx)
380 {
381 mass[qz][qy][qx][c] += massXY[qy][qx] * wz;
382 }
383 }
384 }
385 }
386
387 osc += D1Dx * D1Dy * D1Dz;
388 } // loop (c) over components
389
390 // Apply D operator.
391 for (int qz = 0; qz < Q1D; ++qz)
392 {
393 for (int qy = 0; qy < Q1D; ++qy)
394 {
395 for (int qx = 0; qx < Q1D; ++qx)
396 {
397 const real_t O11 = op(qx,qy,qz,0,e);
398 const real_t O12 = op(qx,qy,qz,1,e);
399 const real_t O13 = op(qx,qy,qz,2,e);
400 const real_t O21 = symmetric ? O12 : op(qx,qy,qz,3,e);
401 const real_t O22 = symmetric ? op(qx,qy,qz,3,e) : op(qx,qy,qz,4,e);
402 const real_t O23 = symmetric ? op(qx,qy,qz,4,e) : op(qx,qy,qz,5,e);
403 const real_t O31 = symmetric ? O13 : op(qx,qy,qz,6,e);
404 const real_t O32 = symmetric ? O23 : op(qx,qy,qz,7,e);
405 const real_t O33 = symmetric ? op(qx,qy,qz,5,e) : op(qx,qy,qz,8,e);
406 const real_t massX = mass[qz][qy][qx][0];
407 const real_t massY = mass[qz][qy][qx][1];
408 const real_t massZ = mass[qz][qy][qx][2];
409 mass[qz][qy][qx][0] = (O11*massX)+(O12*massY)+(O13*massZ);
410 mass[qz][qy][qx][1] = (O21*massX)+(O22*massY)+(O23*massZ);
411 mass[qz][qy][qx][2] = (O31*massX)+(O32*massY)+(O33*massZ);
412 }
413 }
414 }
415
416 for (int qz = 0; qz < Q1D; ++qz)
417 {
418 real_t massXY[MAX_D1D][MAX_D1D];
419
420 osc = 0;
421
422 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
423 {
424 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
425 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
426 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
427
428 for (int dy = 0; dy < D1Dy; ++dy)
429 {
430 for (int dx = 0; dx < D1Dx; ++dx)
431 {
432 massXY[dy][dx] = 0.0;
433 }
434 }
435 for (int qy = 0; qy < Q1D; ++qy)
436 {
437 real_t massX[MAX_D1D];
438 for (int dx = 0; dx < D1Dx; ++dx)
439 {
440 massX[dx] = 0;
441 }
442 for (int qx = 0; qx < Q1D; ++qx)
443 {
444 for (int dx = 0; dx < D1Dx; ++dx)
445 {
446 massX[dx] += mass[qz][qy][qx][c] * ((c == 0) ? Bot(dx,qx) : Bct(dx,qx));
447 }
448 }
449 for (int dy = 0; dy < D1Dy; ++dy)
450 {
451 const real_t wy = (c == 1) ? Bot(dy,qy) : Bct(dy,qy);
452 for (int dx = 0; dx < D1Dx; ++dx)
453 {
454 massXY[dy][dx] += massX[dx] * wy;
455 }
456 }
457 }
458
459 for (int dz = 0; dz < D1Dz; ++dz)
460 {
461 const real_t wz = (c == 2) ? Bot(dz,qz) : Bct(dz,qz);
462 for (int dy = 0; dy < D1Dy; ++dy)
463 {
464 for (int dx = 0; dx < D1Dx; ++dx)
465 {
466 Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += massXY[dy][dx] * wz;
467 }
468 }
469 }
470
471 osc += D1Dx * D1Dy * D1Dz;
472 } // loop c
473 } // loop qz
474 }); // end of element loop
475}
476
477void PACurlCurlSetup2D(const int Q1D,
478 const int NE,
479 const Array<real_t> &w,
480 const Vector &j,
481 Vector &coeff,
482 Vector &op)
483{
484 const int NQ = Q1D*Q1D;
485 auto W = w.Read();
486 auto J = Reshape(j.Read(), NQ, 2, 2, NE);
487 auto C = Reshape(coeff.Read(), NQ, NE);
488 auto y = Reshape(op.Write(), NQ, NE);
489 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
490 {
491 for (int q = 0; q < NQ; ++q)
492 {
493 const real_t J11 = J(q,0,0,e);
494 const real_t J21 = J(q,1,0,e);
495 const real_t J12 = J(q,0,1,e);
496 const real_t J22 = J(q,1,1,e);
497 const real_t detJ = (J11*J22)-(J21*J12);
498 y(q,e) = W[q] * C(q,e) / detJ;
499 }
500 });
501}
502
503void PACurlCurlSetup3D(const int Q1D,
504 const int coeffDim,
505 const int NE,
506 const Array<real_t> &w,
507 const Vector &j,
508 Vector &coeff,
509 Vector &op)
510{
511 const int NQ = Q1D*Q1D*Q1D;
512 const bool symmetric = (coeffDim != 9);
513 auto W = w.Read();
514 auto J = Reshape(j.Read(), NQ, 3, 3, NE);
515 auto C = Reshape(coeff.Read(), coeffDim, NQ, NE);
516 auto y = Reshape(op.Write(), NQ, symmetric ? 6 : 9, NE);
517
518 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
519 {
520 for (int q = 0; q < NQ; ++q)
521 {
522 const real_t J11 = J(q,0,0,e);
523 const real_t J21 = J(q,1,0,e);
524 const real_t J31 = J(q,2,0,e);
525 const real_t J12 = J(q,0,1,e);
526 const real_t J22 = J(q,1,1,e);
527 const real_t J32 = J(q,2,1,e);
528 const real_t J13 = J(q,0,2,e);
529 const real_t J23 = J(q,1,2,e);
530 const real_t J33 = J(q,2,2,e);
531 const real_t detJ = J11 * (J22 * J33 - J32 * J23) -
532 J21 * (J12 * J33 - J32 * J13) +
533 J31 * (J12 * J23 - J22 * J13);
534
535 const real_t c_detJ = W[q] / detJ;
536
537 if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
538 {
539 // Set y to the 6 or 9 entries of J^T M J / det
540 const real_t M11 = C(0, q, e);
541 const real_t M12 = C(1, q, e);
542 const real_t M13 = C(2, q, e);
543 const real_t M21 = (!symmetric) ? C(3, q, e) : M12;
544 const real_t M22 = (!symmetric) ? C(4, q, e) : C(3, q, e);
545 const real_t M23 = (!symmetric) ? C(5, q, e) : C(4, q, e);
546 const real_t M31 = (!symmetric) ? C(6, q, e) : M13;
547 const real_t M32 = (!symmetric) ? C(7, q, e) : M23;
548 const real_t M33 = (!symmetric) ? C(8, q, e) : C(5, q, e);
549
550 // First compute R = MJ
551 const real_t R11 = M11*J11 + M12*J21 + M13*J31;
552 const real_t R12 = M11*J12 + M12*J22 + M13*J32;
553 const real_t R13 = M11*J13 + M12*J23 + M13*J33;
554 const real_t R21 = M21*J11 + M22*J21 + M23*J31;
555 const real_t R22 = M21*J12 + M22*J22 + M23*J32;
556 const real_t R23 = M21*J13 + M22*J23 + M23*J33;
557 const real_t R31 = M31*J11 + M32*J21 + M33*J31;
558 const real_t R32 = M31*J12 + M32*J22 + M33*J32;
559 const real_t R33 = M31*J13 + M32*J23 + M33*J33;
560
561 // Now set y to J^T R / det
562 y(q,0,e) = c_detJ * (J11*R11 + J21*R21 + J31*R31); // 1,1
563 const real_t Y12 = c_detJ * (J11*R12 + J21*R22 + J31*R32);
564 y(q,1,e) = Y12; // 1,2
565 y(q,2,e) = c_detJ * (J11*R13 + J21*R23 + J31*R33); // 1,3
566
567 const real_t Y21 = c_detJ * (J12*R11 + J22*R21 + J32*R31);
568 const real_t Y22 = c_detJ * (J12*R12 + J22*R22 + J32*R32);
569 const real_t Y23 = c_detJ * (J12*R13 + J22*R23 + J32*R33);
570
571 const real_t Y33 = c_detJ * (J13*R13 + J23*R23 + J33*R33);
572
573 y(q,3,e) = symmetric ? Y22 : Y21; // 2,2 or 2,1
574 y(q,4,e) = symmetric ? Y23 : Y22; // 2,3 or 2,2
575 y(q,5,e) = symmetric ? Y33 : Y23; // 3,3 or 2,3
576
577 if (!symmetric)
578 {
579 y(q,6,e) = c_detJ * (J13*R11 + J23*R21 + J33*R31); // 3,1
580 y(q,7,e) = c_detJ * (J13*R12 + J23*R22 + J33*R32); // 3,2
581 y(q,8,e) = Y33; // 3,3
582 }
583 }
584 else // Vector or scalar coefficient version
585 {
586 // Set y to the 6 entries of J^T D J / det^2
587 const real_t D1 = C(0, q, e);
588 const real_t D2 = coeffDim == 3 ? C(1, q, e) : D1;
589 const real_t D3 = coeffDim == 3 ? C(2, q, e) : D1;
590
591 y(q,0,e) = c_detJ * (D1*J11*J11 + D2*J21*J21 + D3*J31*J31); // 1,1
592 y(q,1,e) = c_detJ * (D1*J11*J12 + D2*J21*J22 + D3*J31*J32); // 1,2
593 y(q,2,e) = c_detJ * (D1*J11*J13 + D2*J21*J23 + D3*J31*J33); // 1,3
594 y(q,3,e) = c_detJ * (D1*J12*J12 + D2*J22*J22 + D3*J32*J32); // 2,2
595 y(q,4,e) = c_detJ * (D1*J12*J13 + D2*J22*J23 + D3*J32*J33); // 2,3
596 y(q,5,e) = c_detJ * (D1*J13*J13 + D2*J23*J23 + D3*J33*J33); // 3,3
597 }
598 }
599 });
600}
601
602void PACurlCurlAssembleDiagonal2D(const int D1D,
603 const int Q1D,
604 const int NE,
605 const Array<real_t> &bo,
606 const Array<real_t> &gc,
607 const Vector &pa_data,
608 Vector &diag)
609{
610 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
611 auto Gc = Reshape(gc.Read(), Q1D, D1D);
612 auto op = Reshape(pa_data.Read(), Q1D, Q1D, NE);
613 auto D = Reshape(diag.ReadWrite(), 2*(D1D-1)*D1D, NE);
614
615 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
616 {
617 constexpr static int VDIM = 2;
618 constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
619
620 int osc = 0;
621
622 for (int c = 0; c < VDIM; ++c) // loop over x, y components
623 {
624 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
625 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
626
627 real_t t[MAX_Q1D];
628
629 for (int dy = 0; dy < D1Dy; ++dy)
630 {
631 for (int qx = 0; qx < Q1D; ++qx)
632 {
633 t[qx] = 0.0;
634 for (int qy = 0; qy < Q1D; ++qy)
635 {
636 const real_t wy = (c == 1) ? Bo(qy,dy) : -Gc(qy,dy);
637 t[qx] += wy * wy * op(qx,qy,e);
638 }
639 }
640
641 for (int dx = 0; dx < D1Dx; ++dx)
642 {
643 for (int qx = 0; qx < Q1D; ++qx)
644 {
645 const real_t wx = ((c == 0) ? Bo(qx,dx) : Gc(qx,dx));
646 D(dx + (dy * D1Dx) + osc, e) += t[qx] * wx * wx;
647 }
648 }
649 }
650
651 osc += D1Dx * D1Dy;
652 } // loop c
653 }); // end of element loop
654}
655
656void PACurlCurlApply2D(const int D1D,
657 const int Q1D,
658 const int NE,
659 const Array<real_t> &bo,
660 const Array<real_t> &bot,
661 const Array<real_t> &gc,
662 const Array<real_t> &gct,
663 const Vector &pa_data,
664 const Vector &x,
665 Vector &y)
666{
667
668 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
669 auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
670 auto Gc = Reshape(gc.Read(), Q1D, D1D);
671 auto Gct = Reshape(gct.Read(), D1D, Q1D);
672 auto op = Reshape(pa_data.Read(), Q1D, Q1D, NE);
673 auto X = Reshape(x.Read(), 2*(D1D-1)*D1D, NE);
674 auto Y = Reshape(y.ReadWrite(), 2*(D1D-1)*D1D, NE);
675
676 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
677 {
678 constexpr static int VDIM = 2;
679 constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
680 constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
681
682 real_t curl[MAX_Q1D][MAX_Q1D];
683
684 // curl[qy][qx] will be computed as du_y/dx - du_x/dy
685
686 for (int qy = 0; qy < Q1D; ++qy)
687 {
688 for (int qx = 0; qx < Q1D; ++qx)
689 {
690 curl[qy][qx] = 0.0;
691 }
692 }
693
694 int osc = 0;
695
696 for (int c = 0; c < VDIM; ++c) // loop over x, y components
697 {
698 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
699 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
700
701 for (int dy = 0; dy < D1Dy; ++dy)
702 {
703 real_t gradX[MAX_Q1D];
704 for (int qx = 0; qx < Q1D; ++qx)
705 {
706 gradX[qx] = 0;
707 }
708
709 for (int dx = 0; dx < D1Dx; ++dx)
710 {
711 const real_t t = X(dx + (dy * D1Dx) + osc, e);
712 for (int qx = 0; qx < Q1D; ++qx)
713 {
714 gradX[qx] += t * ((c == 0) ? Bo(qx,dx) : Gc(qx,dx));
715 }
716 }
717
718 for (int qy = 0; qy < Q1D; ++qy)
719 {
720 const real_t wy = (c == 0) ? -Gc(qy,dy) : Bo(qy,dy);
721 for (int qx = 0; qx < Q1D; ++qx)
722 {
723 curl[qy][qx] += gradX[qx] * wy;
724 }
725 }
726 }
727
728 osc += D1Dx * D1Dy;
729 } // loop (c) over components
730
731 // Apply D operator.
732 for (int qy = 0; qy < Q1D; ++qy)
733 {
734 for (int qx = 0; qx < Q1D; ++qx)
735 {
736 curl[qy][qx] *= op(qx,qy,e);
737 }
738 }
739
740 for (int qy = 0; qy < Q1D; ++qy)
741 {
742 osc = 0;
743
744 for (int c = 0; c < VDIM; ++c) // loop over x, y components
745 {
746 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
747 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
748
749 real_t gradX[MAX_D1D];
750 for (int dx = 0; dx < D1Dx; ++dx)
751 {
752 gradX[dx] = 0.0;
753 }
754 for (int qx = 0; qx < Q1D; ++qx)
755 {
756 for (int dx = 0; dx < D1Dx; ++dx)
757 {
758 gradX[dx] += curl[qy][qx] * ((c == 0) ? Bot(dx,qx) : Gct(dx,qx));
759 }
760 }
761 for (int dy = 0; dy < D1Dy; ++dy)
762 {
763 const real_t wy = (c == 0) ? -Gct(dy,qy) : Bot(dy,qy);
764
765 for (int dx = 0; dx < D1Dx; ++dx)
766 {
767 Y(dx + (dy * D1Dx) + osc, e) += gradX[dx] * wy;
768 }
769 }
770
771 osc += D1Dx * D1Dy;
772 } // loop c
773 } // loop qy
774 }); // end of element loop
775}
776
777void PAHcurlL2Setup2D(const int Q1D,
778 const int NE,
779 const Array<real_t> &w,
780 Vector &coeff,
781 Vector &op)
782{
783 const int NQ = Q1D*Q1D;
784 auto W = w.Read();
785 auto C = Reshape(coeff.Read(), NQ, NE);
786 auto y = Reshape(op.Write(), NQ, NE);
787 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
788 {
789 for (int q = 0; q < NQ; ++q)
790 {
791 y(q,e) = W[q] * C(q,e);
792 }
793 });
794}
795
796void PAHcurlL2Setup3D(const int NQ,
797 const int coeffDim,
798 const int NE,
799 const Array<real_t> &w,
800 Vector &coeff,
801 Vector &op)
802{
803 auto W = w.Read();
804 auto C = Reshape(coeff.Read(), coeffDim, NQ, NE);
805 auto y = Reshape(op.Write(), coeffDim, NQ, NE);
806
807 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
808 {
809 for (int q = 0; q < NQ; ++q)
810 {
811 for (int c=0; c<coeffDim; ++c)
812 {
813 y(c,q,e) = W[q] * C(c,q,e);
814 }
815 }
816 });
817}
818
819void PAHcurlL2Apply2D(const int D1D,
820 const int D1Dtest,
821 const int Q1D,
822 const int NE,
823 const Array<real_t> &bo,
824 const Array<real_t> &bot,
825 const Array<real_t> &bt,
826 const Array<real_t> &gc,
827 const Vector &pa_data,
828 const Vector &x, // trial = H(curl)
829 Vector &y) // test = L2 or H1
830{
831 const int H1 = (D1Dtest == D1D);
832
833 MFEM_VERIFY(y.Size() == NE*D1Dtest*D1Dtest, "Test vector of wrong dimension");
834
835 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
836 auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
837 auto Bt = Reshape(bt.Read(), D1D, Q1D);
838 auto Gc = Reshape(gc.Read(), Q1D, D1D);
839 auto op = Reshape(pa_data.Read(), Q1D, Q1D, NE);
840 auto X = Reshape(x.Read(), 2*(D1D-1)*D1D, NE);
841 auto Y = Reshape(y.ReadWrite(), D1Dtest, D1Dtest, NE);
842
843 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
844 {
845 constexpr static int VDIM = 2;
846 constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
847 constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
848
849 real_t curl[MAX_Q1D][MAX_Q1D];
850
851 // curl[qy][qx] will be computed as du_y/dx - du_x/dy
852
853 for (int qy = 0; qy < Q1D; ++qy)
854 {
855 for (int qx = 0; qx < Q1D; ++qx)
856 {
857 curl[qy][qx] = 0.0;
858 }
859 }
860
861 int osc = 0;
862
863 for (int c = 0; c < VDIM; ++c) // loop over x, y components
864 {
865 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
866 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
867
868 for (int dy = 0; dy < D1Dy; ++dy)
869 {
870 real_t gradX[MAX_Q1D];
871 for (int qx = 0; qx < Q1D; ++qx)
872 {
873 gradX[qx] = 0;
874 }
875
876 for (int dx = 0; dx < D1Dx; ++dx)
877 {
878 const real_t t = X(dx + (dy * D1Dx) + osc, e);
879 for (int qx = 0; qx < Q1D; ++qx)
880 {
881 gradX[qx] += t * ((c == 0) ? Bo(qx,dx) : Gc(qx,dx));
882 }
883 }
884
885 for (int qy = 0; qy < Q1D; ++qy)
886 {
887 const real_t wy = (c == 0) ? -Gc(qy,dy) : Bo(qy,dy);
888 for (int qx = 0; qx < Q1D; ++qx)
889 {
890 curl[qy][qx] += gradX[qx] * wy;
891 }
892 }
893 }
894
895 osc += D1Dx * D1Dy;
896 } // loop (c) over components
897
898 // Apply D operator.
899 for (int qy = 0; qy < Q1D; ++qy)
900 {
901 for (int qx = 0; qx < Q1D; ++qx)
902 {
903 curl[qy][qx] *= op(qx,qy,e);
904 }
905 }
906
907 for (int qy = 0; qy < Q1D; ++qy)
908 {
909 real_t sol_x[MAX_D1D];
910 for (int dx = 0; dx < D1Dtest; ++dx)
911 {
912 sol_x[dx] = 0.0;
913 }
914 for (int qx = 0; qx < Q1D; ++qx)
915 {
916 const real_t s = curl[qy][qx];
917 for (int dx = 0; dx < D1Dtest; ++dx)
918 {
919 sol_x[dx] += s * ((H1 == 1) ? Bt(dx,qx) : Bot(dx,qx));
920 }
921 }
922 for (int dy = 0; dy < D1Dtest; ++dy)
923 {
924 const real_t wy = (H1 == 1) ? Bt(dy,qy) : Bot(dy,qy);
925
926 for (int dx = 0; dx < D1Dtest; ++dx)
927 {
928 Y(dx,dy,e) += sol_x[dx] * wy;
929 }
930 }
931 } // loop qy
932 }); // end of element loop
933}
934
935void PAHcurlL2ApplyTranspose2D(const int D1D,
936 const int D1Dtest,
937 const int Q1D,
938 const int NE,
939 const Array<real_t> &bo,
940 const Array<real_t> &bot,
941 const Array<real_t> &b,
942 const Array<real_t> &gct,
943 const Vector &pa_data,
944 const Vector &x, // trial = H(curl)
945 Vector &y) // test = L2 or H1
946{
947 const int H1 = (D1Dtest == D1D);
948
949 MFEM_VERIFY(x.Size() == NE*D1Dtest*D1Dtest, "Test vector of wrong dimension");
950
951 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
952 auto B = Reshape(b.Read(), Q1D, D1D);
953 auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
954 auto Gct = Reshape(gct.Read(), D1D, Q1D);
955 auto op = Reshape(pa_data.Read(), Q1D, Q1D, NE);
956 auto X = Reshape(x.Read(), D1Dtest, D1Dtest, NE);
957 auto Y = Reshape(y.ReadWrite(), 2*(D1D-1)*D1D, NE);
958
959 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
960 {
961 constexpr static int VDIM = 2;
962 constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
963 constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
964
965 real_t mass[MAX_Q1D][MAX_Q1D];
966
967 // Zero-order term in L2 or H1 test space
968
969 for (int qy = 0; qy < Q1D; ++qy)
970 {
971 for (int qx = 0; qx < Q1D; ++qx)
972 {
973 mass[qy][qx] = 0.0;
974 }
975 }
976
977 for (int dy = 0; dy < D1Dtest; ++dy)
978 {
979 real_t sol_x[MAX_Q1D];
980 for (int qy = 0; qy < Q1D; ++qy)
981 {
982 sol_x[qy] = 0.0;
983 }
984 for (int dx = 0; dx < D1Dtest; ++dx)
985 {
986 const real_t s = X(dx,dy,e);
987 for (int qx = 0; qx < Q1D; ++qx)
988 {
989 sol_x[qx] += s * ((H1 == 1) ? B(qx,dx) : Bo(qx,dx));
990 }
991 }
992 for (int qy = 0; qy < Q1D; ++qy)
993 {
994 const real_t d2q = (H1 == 1) ? B(qy,dy) : Bo(qy,dy);
995 for (int qx = 0; qx < Q1D; ++qx)
996 {
997 mass[qy][qx] += d2q * sol_x[qx];
998 }
999 }
1000 }
1001
1002 // Apply D operator.
1003 for (int qy = 0; qy < Q1D; ++qy)
1004 {
1005 for (int qx = 0; qx < Q1D; ++qx)
1006 {
1007 mass[qy][qx] *= op(qx,qy,e);
1008 }
1009 }
1010
1011 for (int qy = 0; qy < Q1D; ++qy)
1012 {
1013 int osc = 0;
1014
1015 for (int c = 0; c < VDIM; ++c) // loop over x, y components
1016 {
1017 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
1018 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
1019
1020 real_t gradX[MAX_D1D];
1021 for (int dx = 0; dx < D1Dx; ++dx)
1022 {
1023 gradX[dx] = 0.0;
1024 }
1025 for (int qx = 0; qx < Q1D; ++qx)
1026 {
1027 for (int dx = 0; dx < D1Dx; ++dx)
1028 {
1029 gradX[dx] += mass[qy][qx] * ((c == 0) ? Bot(dx,qx) : Gct(dx,qx));
1030 }
1031 }
1032 for (int dy = 0; dy < D1Dy; ++dy)
1033 {
1034 const real_t wy = (c == 0) ? -Gct(dy,qy) : Bot(dy,qy);
1035
1036 for (int dx = 0; dx < D1Dx; ++dx)
1037 {
1038 Y(dx + (dy * D1Dx) + osc, e) += gradX[dx] * wy;
1039 }
1040 }
1041
1042 osc += D1Dx * D1Dy;
1043 } // loop c
1044 } // loop qy
1045 }); // end of element loop
1046}
1047
1048} // namespace internal
1049
1050} // namespace mfem
real_t b
Definition lissajous.cpp:42
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:131
float real_t
Definition config.hpp:43
void forall(int N, lambda &&body)
Definition forall.hpp:753
static const DeviceDofQuadLimits & Get()
Return a const reference to the DeviceDofQuadLimits singleton.
Definition forall.hpp:128