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