MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
bilininteg_mixedcurl_pa.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
12#include "../bilininteg.hpp"
13#include "../gridfunc.hpp"
14#include "../qfunction.hpp"
18
19namespace mfem
20{
21
22namespace
23{
24
25class Rotated2DVectorCoefficient : public VectorCoefficient
26{
27public:
28 explicit Rotated2DVectorCoefficient(VectorCoefficient &coeff)
29 : VectorCoefficient(2), coeff_(&coeff), value_(2) { }
30
31 void SetTime(real_t t) override { coeff_->SetTime(t); }
32
34 void Eval(Vector &V, ElementTransformation &T,
35 const IntegrationPoint &ip) override
36 {
37 coeff_->Eval(value_, T, ip);
38 V.SetSize(2);
39 V(0) = -value_(1);
40 V(1) = value_(0);
41 }
42
43private:
44 VectorCoefficient *coeff_;
45 mutable Vector value_;
46};
47
48void PAHcurlDotSetup2D(const int q1d,
49 const int ne,
50 const bool test_map_integral,
51 const Array<real_t> &w,
52 const Vector &jacobians,
53 const Vector &coeff,
54 Vector &op)
55{
56 auto W = Reshape(w.Read(), q1d, q1d);
57 auto J = Reshape(jacobians.Read(), q1d, q1d, 2, 2, ne);
58 auto C = Reshape(coeff.Read(), 2, q1d, q1d, ne);
59 auto O = Reshape(op.Write(), 2, q1d, q1d, ne);
60
61 mfem::forall_2D(ne, q1d, q1d, [=] MFEM_HOST_DEVICE (int e)
62 {
63 MFEM_FOREACH_THREAD(qy, y, q1d)
64 {
65 MFEM_FOREACH_THREAD(qx, x, q1d)
66 {
67 const real_t J11 = J(qx, qy, 0, 0, e);
68 const real_t J12 = J(qx, qy, 0, 1, e);
69 const real_t J21 = J(qx, qy, 1, 0, e);
70 const real_t J22 = J(qx, qy, 1, 1, e);
71 const real_t detJ = (J11 * J22) - (J21 * J12);
72 const real_t scale = W(qx, qy) * (test_map_integral ? 1.0 / detJ : 1.0);
73 const real_t Vx = C(0, qx, qy, e);
74 const real_t Vy = C(1, qx, qy, e);
75
76 O(0, qx, qy, e) = scale * ( J22 * Vx - J12 * Vy);
77 O(1, qx, qy, e) = scale * (-J21 * Vx + J11 * Vy);
78 }
79 }
80 });
81}
82
83void PAHcurlDotSetup3D(const int q1d,
84 const int ne,
85 const bool test_map_integral,
86 const Array<real_t> &w,
87 const Vector &jacobians,
88 const Vector &coeff,
89 Vector &op)
90{
91 auto W = Reshape(w.Read(), q1d, q1d, q1d);
92 auto J = Reshape(jacobians.Read(), q1d, q1d, q1d, 3, 3, ne);
93 auto C = Reshape(coeff.Read(), 3, q1d, q1d, q1d, ne);
94 auto O = Reshape(op.Write(), 3, q1d, q1d, q1d, ne);
95
96 mfem::forall_3D(ne, q1d, q1d, q1d, [=] MFEM_HOST_DEVICE (int e)
97 {
98 MFEM_FOREACH_THREAD(qz, z, q1d)
99 {
100 MFEM_FOREACH_THREAD(qy, y, q1d)
101 {
102 MFEM_FOREACH_THREAD(qx, x, q1d)
103 {
104 const real_t J11 = J(qx, qy, qz, 0, 0, e);
105 const real_t J12 = J(qx, qy, qz, 0, 1, e);
106 const real_t J13 = J(qx, qy, qz, 0, 2, e);
107 const real_t J21 = J(qx, qy, qz, 1, 0, e);
108 const real_t J22 = J(qx, qy, qz, 1, 1, e);
109 const real_t J23 = J(qx, qy, qz, 1, 2, e);
110 const real_t J31 = J(qx, qy, qz, 2, 0, e);
111 const real_t J32 = J(qx, qy, qz, 2, 1, e);
112 const real_t J33 = J(qx, qy, qz, 2, 2, e);
113 const real_t detJ = J11 * (J22 * J33 - J32 * J23)
114 - J21 * (J12 * J33 - J32 * J13)
115 + J31 * (J12 * J23 - J22 * J13);
116 const real_t scale = W(qx, qy, qz) *
117 (test_map_integral ? 1.0 / detJ : 1.0);
118 const real_t Vx = C(0, qx, qy, qz, e);
119 const real_t Vy = C(1, qx, qy, qz, e);
120 const real_t Vz = C(2, qx, qy, qz, e);
121
122 O(0, qx, qy, qz, e) = scale *
123 ((J22 * J33 - J23 * J32) * Vx +
124 (J13 * J32 - J12 * J33) * Vy +
125 (J12 * J23 - J13 * J22) * Vz);
126 O(1, qx, qy, qz, e) = scale *
127 ((J23 * J31 - J21 * J33) * Vx +
128 (J11 * J33 - J13 * J31) * Vy +
129 (J13 * J21 - J11 * J23) * Vz);
130 O(2, qx, qy, qz, e) = scale *
131 ((J21 * J32 - J22 * J31) * Vx +
132 (J12 * J31 - J11 * J32) * Vy +
133 (J11 * J22 - J12 * J21) * Vz);
134 }
135 }
136 }
137 });
138}
139
140void PAHcurlDotApply2D(const int d1d,
141 const int d1d_test,
142 const int q1d,
143 const int ne,
144 const Array<real_t> &bo,
145 const Array<real_t> &bc,
146 const Array<real_t> &bt,
147 const Vector &pa_data,
148 const Vector &x,
149 Vector &y)
150{
151 MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D, "");
152 MFEM_VERIFY(d1d_test <= DeviceDofQuadLimits::Get().MAX_D1D, "");
153 MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D, "");
154
155 auto Bo = Reshape(bo.Read(), q1d, d1d - 1);
156 auto Bc = Reshape(bc.Read(), q1d, d1d);
157 auto Bt = Reshape(bt.Read(), d1d_test, q1d);
158 auto O = Reshape(pa_data.Read(), 2, q1d, q1d, ne);
159 auto X = Reshape(x.Read(), 2 * (d1d - 1) * d1d, ne);
160 auto Y = Reshape(y.ReadWrite(), d1d_test, d1d_test, ne);
161
162 mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
163 {
164 constexpr int MAX_D1D = DofQuadLimits::MAX_D1D;
165 constexpr int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
166
167 real_t u0[MAX_Q1D][MAX_Q1D];
168 real_t u1[MAX_Q1D][MAX_Q1D];
169
170 for (int qy = 0; qy < q1d; ++qy)
171 {
172 for (int qx = 0; qx < q1d; ++qx)
173 {
174 u0[qy][qx] = 0.0;
175 u1[qy][qx] = 0.0;
176 }
177 }
178
179 int osc = 0;
180 for (int dy = 0; dy < d1d; ++dy)
181 {
182 real_t mass_x[MAX_Q1D];
183 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] = 0.0; }
184 for (int dx = 0; dx < d1d - 1; ++dx)
185 {
186 const real_t t = X(dx + (dy * (d1d - 1)) + osc, e);
187 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] += t * Bo(qx, dx); }
188 }
189 for (int qy = 0; qy < q1d; ++qy)
190 {
191 const real_t wy = Bc(qy, dy);
192 for (int qx = 0; qx < q1d; ++qx) { u0[qy][qx] += mass_x[qx] * wy; }
193 }
194 }
195
196 osc += (d1d - 1) * d1d;
197 for (int dy = 0; dy < d1d - 1; ++dy)
198 {
199 real_t mass_x[MAX_Q1D];
200 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] = 0.0; }
201 for (int dx = 0; dx < d1d; ++dx)
202 {
203 const real_t t = X(dx + (dy * d1d) + osc, e);
204 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] += t * Bc(qx, dx); }
205 }
206 for (int qy = 0; qy < q1d; ++qy)
207 {
208 const real_t wy = Bo(qy, dy);
209 for (int qx = 0; qx < q1d; ++qx) { u1[qy][qx] += mass_x[qx] * wy; }
210 }
211 }
212
213 for (int qy = 0; qy < q1d; ++qy)
214 {
215 real_t sol_x[MAX_D1D];
216 for (int dx = 0; dx < d1d_test; ++dx) { sol_x[dx] = 0.0; }
217 for (int qx = 0; qx < q1d; ++qx)
218 {
219 const real_t s = O(0, qx, qy, e) * u0[qy][qx]
220 + O(1, qx, qy, e) * u1[qy][qx];
221 for (int dx = 0; dx < d1d_test; ++dx)
222 {
223 sol_x[dx] += s * Bt(dx, qx);
224 }
225 }
226 for (int dy = 0; dy < d1d_test; ++dy)
227 {
228 const real_t wy = Bt(dy, qy);
229 for (int dx = 0; dx < d1d_test; ++dx)
230 {
231 Y(dx, dy, e) += sol_x[dx] * wy;
232 }
233 }
234 }
235 });
236}
237
238void PAHcurlDotApplyTranspose2D(const int d1d,
239 const int d1d_test,
240 const int q1d,
241 const int ne,
242 const Array<real_t> &bo,
243 const Array<real_t> &bc,
244 const Array<real_t> &b,
245 const Vector &pa_data,
246 const Vector &x,
247 Vector &y)
248{
249 MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D, "");
250 MFEM_VERIFY(d1d_test <= DeviceDofQuadLimits::Get().MAX_D1D, "");
251 MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D, "");
252
253 auto Bo = Reshape(bo.Read(), q1d, d1d - 1);
254 auto Bc = Reshape(bc.Read(), q1d, d1d);
255 auto B = Reshape(b.Read(), q1d, d1d_test);
256 auto O = Reshape(pa_data.Read(), 2, q1d, q1d, ne);
257 auto X = Reshape(x.Read(), d1d_test, d1d_test, ne);
258 auto Y = Reshape(y.ReadWrite(), 2 * (d1d - 1) * d1d, ne);
259
260 mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
261 {
262 constexpr int MAX_D1D = DofQuadLimits::MAX_D1D;
263 constexpr int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
264
265 real_t mass[MAX_Q1D][MAX_Q1D];
266 for (int qy = 0; qy < q1d; ++qy)
267 {
268 for (int qx = 0; qx < q1d; ++qx)
269 {
270 mass[qy][qx] = 0.0;
271 }
272 }
273
274 for (int dy = 0; dy < d1d_test; ++dy)
275 {
276 real_t sol_x[MAX_Q1D];
277 for (int qx = 0; qx < q1d; ++qx) { sol_x[qx] = 0.0; }
278 for (int dx = 0; dx < d1d_test; ++dx)
279 {
280 const real_t t = X(dx, dy, e);
281 for (int qx = 0; qx < q1d; ++qx) { sol_x[qx] += t * B(qx, dx); }
282 }
283 for (int qy = 0; qy < q1d; ++qy)
284 {
285 const real_t wy = B(qy, dy);
286 for (int qx = 0; qx < q1d; ++qx) { mass[qy][qx] += sol_x[qx] * wy; }
287 }
288 }
289
290 int osc = 0;
291 for (int qy = 0; qy < q1d; ++qy)
292 {
293 real_t mass_x[MAX_D1D];
294 for (int dx = 0; dx < d1d - 1; ++dx) { mass_x[dx] = 0.0; }
295 for (int qx = 0; qx < q1d; ++qx)
296 {
297 const real_t s = O(0, qx, qy, e) * mass[qy][qx];
298 for (int dx = 0; dx < d1d - 1; ++dx) { mass_x[dx] += s * Bo(qx, dx); }
299 }
300 for (int dy = 0; dy < d1d; ++dy)
301 {
302 const real_t wy = Bc(qy, dy);
303 for (int dx = 0; dx < d1d - 1; ++dx)
304 {
305 Y(dx + (dy * (d1d - 1)) + osc, e) += mass_x[dx] * wy;
306 }
307 }
308 }
309
310 osc += (d1d - 1) * d1d;
311 for (int qy = 0; qy < q1d; ++qy)
312 {
313 real_t mass_x[MAX_D1D];
314 for (int dx = 0; dx < d1d; ++dx) { mass_x[dx] = 0.0; }
315 for (int qx = 0; qx < q1d; ++qx)
316 {
317 const real_t s = O(1, qx, qy, e) * mass[qy][qx];
318 for (int dx = 0; dx < d1d; ++dx) { mass_x[dx] += s * Bc(qx, dx); }
319 }
320 for (int dy = 0; dy < d1d - 1; ++dy)
321 {
322 const real_t wy = Bo(qy, dy);
323 for (int dx = 0; dx < d1d; ++dx)
324 {
325 Y(dx + (dy * d1d) + osc, e) += mass_x[dx] * wy;
326 }
327 }
328 }
329 });
330}
331
332void PAHdivDotSetup2D(const int q1d,
333 const int ne,
334 const bool test_map_integral,
335 const Array<real_t> &w,
336 const Vector &jacobians,
337 const Vector &coeff,
338 Vector &op)
339{
340 auto W = Reshape(w.Read(), q1d, q1d);
341 auto J = Reshape(jacobians.Read(), q1d, q1d, 2, 2, ne);
342 auto C = Reshape(coeff.Read(), 2, q1d, q1d, ne);
343 auto O = Reshape(op.Write(), 2, q1d, q1d, ne);
344
345 mfem::forall_2D(ne, q1d, q1d, [=] MFEM_HOST_DEVICE (int e)
346 {
347 MFEM_FOREACH_THREAD(qy, y, q1d)
348 {
349 MFEM_FOREACH_THREAD(qx, x, q1d)
350 {
351 const real_t J11 = J(qx, qy, 0, 0, e);
352 const real_t J12 = J(qx, qy, 0, 1, e);
353 const real_t J21 = J(qx, qy, 1, 0, e);
354 const real_t J22 = J(qx, qy, 1, 1, e);
355 const real_t detJ = (J11 * J22) - (J21 * J12);
356 const real_t scale = W(qx, qy) * (test_map_integral ? 1.0 / detJ : 1.0);
357 const real_t Vx = C(0, qx, qy, e);
358 const real_t Vy = C(1, qx, qy, e);
359
360 O(0, qx, qy, e) = scale * (J11 * Vx + J21 * Vy);
361 O(1, qx, qy, e) = scale * (J12 * Vx + J22 * Vy);
362 }
363 }
364 });
365}
366
367void PAHdivDotApply2D(const int d1d,
368 const int d1d_test,
369 const int q1d,
370 const int ne,
371 const Array<real_t> &bo,
372 const Array<real_t> &bc,
373 const Array<real_t> &bt,
374 const Vector &pa_data,
375 const Vector &x,
376 Vector &y)
377{
378 MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D, "");
379 MFEM_VERIFY(d1d_test <= DeviceDofQuadLimits::Get().MAX_D1D, "");
380 MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D, "");
381
382 auto Bo = Reshape(bo.Read(), q1d, d1d - 1);
383 auto Bc = Reshape(bc.Read(), q1d, d1d);
384 auto Bt = Reshape(bt.Read(), d1d_test, q1d);
385 auto O = Reshape(pa_data.Read(), 2, q1d, q1d, ne);
386 auto X = Reshape(x.Read(), 2 * (d1d - 1) * d1d, ne);
387 auto Y = Reshape(y.ReadWrite(), d1d_test, d1d_test, ne);
388
389 mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
390 {
391 constexpr int MAX_D1D = DofQuadLimits::MAX_D1D;
392 constexpr int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
393
394 real_t mass[MAX_Q1D][MAX_Q1D][2];
395 for (int qy = 0; qy < q1d; ++qy)
396 {
397 for (int qx = 0; qx < q1d; ++qx)
398 {
399 mass[qy][qx][0] = 0.0;
400 mass[qy][qx][1] = 0.0;
401 }
402 }
403
404 int osc = 0;
405 for (int dy = 0; dy < d1d - 1; ++dy)
406 {
407 real_t mass_x[MAX_Q1D];
408 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] = 0.0; }
409 for (int dx = 0; dx < d1d; ++dx)
410 {
411 const real_t t = X(dx + (dy * d1d) + osc, e);
412 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] += t * Bc(qx, dx); }
413 }
414 for (int qy = 0; qy < q1d; ++qy)
415 {
416 const real_t wy = Bo(qy, dy);
417 for (int qx = 0; qx < q1d; ++qx) { mass[qy][qx][0] += mass_x[qx] * wy; }
418 }
419 }
420
421 osc += d1d * (d1d - 1);
422 for (int dy = 0; dy < d1d; ++dy)
423 {
424 real_t mass_x[MAX_Q1D];
425 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] = 0.0; }
426 for (int dx = 0; dx < d1d - 1; ++dx)
427 {
428 const real_t t = X(dx + (dy * (d1d - 1)) + osc, e);
429 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] += t * Bo(qx, dx); }
430 }
431 for (int qy = 0; qy < q1d; ++qy)
432 {
433 const real_t wy = Bc(qy, dy);
434 for (int qx = 0; qx < q1d; ++qx) { mass[qy][qx][1] += mass_x[qx] * wy; }
435 }
436 }
437
438 for (int qy = 0; qy < q1d; ++qy)
439 {
440 real_t sol_x[MAX_D1D];
441 for (int dx = 0; dx < d1d_test; ++dx) { sol_x[dx] = 0.0; }
442 for (int qx = 0; qx < q1d; ++qx)
443 {
444 const real_t s = O(0, qx, qy, e) * mass[qy][qx][0]
445 + O(1, qx, qy, e) * mass[qy][qx][1];
446 for (int dx = 0; dx < d1d_test; ++dx)
447 {
448 sol_x[dx] += s * Bt(dx, qx);
449 }
450 }
451 for (int dy = 0; dy < d1d_test; ++dy)
452 {
453 const real_t wy = Bt(dy, qy);
454 for (int dx = 0; dx < d1d_test; ++dx)
455 {
456 Y(dx, dy, e) += sol_x[dx] * wy;
457 }
458 }
459 }
460 });
461}
462
463void PAHdivDotApplyTranspose2D(const int d1d,
464 const int d1d_test,
465 const int q1d,
466 const int ne,
467 const Array<real_t> &bo,
468 const Array<real_t> &bc,
469 const Array<real_t> &b,
470 const Vector &pa_data,
471 const Vector &x,
472 Vector &y)
473{
474 MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D, "");
475 MFEM_VERIFY(d1d_test <= DeviceDofQuadLimits::Get().MAX_D1D, "");
476 MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D, "");
477
478 auto Bo = Reshape(bo.Read(), q1d, d1d - 1);
479 auto Bc = Reshape(bc.Read(), q1d, d1d);
480 auto B = Reshape(b.Read(), q1d, d1d_test);
481 auto O = Reshape(pa_data.Read(), 2, q1d, q1d, ne);
482 auto X = Reshape(x.Read(), d1d_test, d1d_test, ne);
483 auto Y = Reshape(y.ReadWrite(), 2 * (d1d - 1) * d1d, ne);
484
485 mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
486 {
487 constexpr int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
488
489 real_t mass[MAX_Q1D][MAX_Q1D];
490 for (int qy = 0; qy < q1d; ++qy)
491 {
492 for (int qx = 0; qx < q1d; ++qx)
493 {
494 mass[qy][qx] = 0.0;
495 }
496 }
497
498 for (int dy = 0; dy < d1d_test; ++dy)
499 {
500 real_t sol_x[MAX_Q1D];
501 for (int qx = 0; qx < q1d; ++qx) { sol_x[qx] = 0.0; }
502 for (int dx = 0; dx < d1d_test; ++dx)
503 {
504 const real_t t = X(dx, dy, e);
505 for (int qx = 0; qx < q1d; ++qx) { sol_x[qx] += t * B(qx, dx); }
506 }
507 for (int qy = 0; qy < q1d; ++qy)
508 {
509 const real_t wy = B(qy, dy);
510 for (int qx = 0; qx < q1d; ++qx) { mass[qy][qx] += sol_x[qx] * wy; }
511 }
512 }
513
514 int osc = 0;
515 for (int dy = 0; dy < d1d - 1; ++dy)
516 {
517 real_t mass_x[MAX_Q1D];
518 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] = 0.0; }
519 for (int qy = 0; qy < q1d; ++qy)
520 {
521 const real_t wy = Bo(qy, dy);
522 for (int qx = 0; qx < q1d; ++qx)
523 {
524 mass_x[qx] += (O(0, qx, qy, e) * mass[qy][qx]) * wy;
525 }
526 }
527 for (int dx = 0; dx < d1d; ++dx)
528 {
529 real_t sum = 0.0;
530 for (int qx = 0; qx < q1d; ++qx) { sum += mass_x[qx] * Bc(qx, dx); }
531 Y(dx + (dy * d1d) + osc, e) += sum;
532 }
533 }
534
535 osc += d1d * (d1d - 1);
536 for (int dy = 0; dy < d1d; ++dy)
537 {
538 real_t mass_x[MAX_Q1D];
539 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] = 0.0; }
540 for (int qy = 0; qy < q1d; ++qy)
541 {
542 const real_t wy = Bc(qy, dy);
543 for (int qx = 0; qx < q1d; ++qx)
544 {
545 mass_x[qx] += (O(1, qx, qy, e) * mass[qy][qx]) * wy;
546 }
547 }
548 for (int dx = 0; dx < d1d - 1; ++dx)
549 {
550 real_t sum = 0.0;
551 for (int qx = 0; qx < q1d; ++qx) { sum += mass_x[qx] * Bo(qx, dx); }
552 Y(dx + (dy * (d1d - 1)) + osc, e) += sum;
553 }
554 }
555 });
556}
557
558void PAHcurlDotApply3D(const int d1d,
559 const int d1d_test,
560 const int q1d,
561 const int ne,
562 const Array<real_t> &bo,
563 const Array<real_t> &bc,
564 const Array<real_t> &bt,
565 const Vector &pa_data,
566 const Vector &x,
567 Vector &y)
568{
569 MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D, "");
570 MFEM_VERIFY(d1d_test <= DeviceDofQuadLimits::Get().MAX_D1D, "");
571 MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D, "");
572
573 auto Bo = Reshape(bo.Read(), q1d, d1d - 1);
574 auto Bc = Reshape(bc.Read(), q1d, d1d);
575 auto Bt = Reshape(bt.Read(), d1d_test, q1d);
576 auto O = Reshape(pa_data.Read(), 3, q1d, q1d, q1d, ne);
577 auto X = Reshape(x.Read(), 3 * (d1d - 1) * d1d * d1d, ne);
578 auto Y = Reshape(y.ReadWrite(), d1d_test, d1d_test, d1d_test, ne);
579
580 mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
581 {
582 constexpr int MAX_D1D = DofQuadLimits::MAX_D1D;
583 constexpr int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
584
585 real_t u[MAX_Q1D][MAX_Q1D][MAX_Q1D][3];
586 for (int qz = 0; qz < q1d; ++qz)
587 {
588 for (int qy = 0; qy < q1d; ++qy)
589 {
590 for (int qx = 0; qx < q1d; ++qx)
591 {
592 for (int c = 0; c < 3; ++c) { u[qz][qy][qx][c] = 0.0; }
593 }
594 }
595 }
596
597 int osc = 0;
598 for (int dz = 0; dz < d1d; ++dz)
599 {
600 real_t mass_xy[MAX_Q1D][MAX_Q1D];
601 for (int qy = 0; qy < q1d; ++qy)
602 {
603 for (int qx = 0; qx < q1d; ++qx) { mass_xy[qy][qx] = 0.0; }
604 }
605
606 for (int dy = 0; dy < d1d; ++dy)
607 {
608 real_t mass_x[MAX_Q1D];
609 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] = 0.0; }
610 for (int dx = 0; dx < d1d - 1; ++dx)
611 {
612 const real_t t = X(dx + ((dy + (dz * d1d)) * (d1d - 1)) + osc, e);
613 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] += t * Bo(qx, dx); }
614 }
615 for (int qy = 0; qy < q1d; ++qy)
616 {
617 const real_t wy = Bc(qy, dy);
618 for (int qx = 0; qx < q1d; ++qx) { mass_xy[qy][qx] += mass_x[qx] * wy; }
619 }
620 }
621
622 for (int qz = 0; qz < q1d; ++qz)
623 {
624 const real_t wz = Bc(qz, dz);
625 for (int qy = 0; qy < q1d; ++qy)
626 {
627 for (int qx = 0; qx < q1d; ++qx) { u[qz][qy][qx][0] += mass_xy[qy][qx] * wz; }
628 }
629 }
630 }
631
632 osc += (d1d - 1) * d1d * d1d;
633 for (int dz = 0; dz < d1d; ++dz)
634 {
635 real_t mass_xy[MAX_Q1D][MAX_Q1D];
636 for (int qy = 0; qy < q1d; ++qy)
637 {
638 for (int qx = 0; qx < q1d; ++qx) { mass_xy[qy][qx] = 0.0; }
639 }
640
641 for (int dy = 0; dy < d1d - 1; ++dy)
642 {
643 real_t mass_x[MAX_Q1D];
644 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] = 0.0; }
645 for (int dx = 0; dx < d1d; ++dx)
646 {
647 const real_t t = X(dx + ((dy + (dz * (d1d - 1))) * d1d) + osc, e);
648 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] += t * Bc(qx, dx); }
649 }
650 for (int qy = 0; qy < q1d; ++qy)
651 {
652 const real_t wy = Bo(qy, dy);
653 for (int qx = 0; qx < q1d; ++qx) { mass_xy[qy][qx] += mass_x[qx] * wy; }
654 }
655 }
656
657 for (int qz = 0; qz < q1d; ++qz)
658 {
659 const real_t wz = Bc(qz, dz);
660 for (int qy = 0; qy < q1d; ++qy)
661 {
662 for (int qx = 0; qx < q1d; ++qx) { u[qz][qy][qx][1] += mass_xy[qy][qx] * wz; }
663 }
664 }
665 }
666
667 osc += (d1d - 1) * d1d * d1d;
668 for (int dz = 0; dz < d1d - 1; ++dz)
669 {
670 real_t mass_xy[MAX_Q1D][MAX_Q1D];
671 for (int qy = 0; qy < q1d; ++qy)
672 {
673 for (int qx = 0; qx < q1d; ++qx) { mass_xy[qy][qx] = 0.0; }
674 }
675
676 for (int dy = 0; dy < d1d; ++dy)
677 {
678 real_t mass_x[MAX_Q1D];
679 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] = 0.0; }
680 for (int dx = 0; dx < d1d; ++dx)
681 {
682 const real_t t = X(dx + ((dy + (dz * d1d)) * d1d) + osc, e);
683 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] += t * Bc(qx, dx); }
684 }
685 for (int qy = 0; qy < q1d; ++qy)
686 {
687 const real_t wy = Bc(qy, dy);
688 for (int qx = 0; qx < q1d; ++qx) { mass_xy[qy][qx] += mass_x[qx] * wy; }
689 }
690 }
691
692 for (int qz = 0; qz < q1d; ++qz)
693 {
694 const real_t wz = Bo(qz, dz);
695 for (int qy = 0; qy < q1d; ++qy)
696 {
697 for (int qx = 0; qx < q1d; ++qx) { u[qz][qy][qx][2] += mass_xy[qy][qx] * wz; }
698 }
699 }
700 }
701
702 for (int qz = 0; qz < q1d; ++qz)
703 {
704 real_t mass_xy[MAX_D1D][MAX_D1D];
705 for (int dy = 0; dy < d1d_test; ++dy)
706 {
707 for (int dx = 0; dx < d1d_test; ++dx) { mass_xy[dy][dx] = 0.0; }
708 }
709
710 for (int qy = 0; qy < q1d; ++qy)
711 {
712 real_t mass_x[MAX_D1D];
713 for (int dx = 0; dx < d1d_test; ++dx) { mass_x[dx] = 0.0; }
714 for (int qx = 0; qx < q1d; ++qx)
715 {
716 const real_t s = O(0, qx, qy, qz, e) * u[qz][qy][qx][0]
717 + O(1, qx, qy, qz, e) * u[qz][qy][qx][1]
718 + O(2, qx, qy, qz, e) * u[qz][qy][qx][2];
719 for (int dx = 0; dx < d1d_test; ++dx) { mass_x[dx] += s * Bt(dx, qx); }
720 }
721 for (int dy = 0; dy < d1d_test; ++dy)
722 {
723 const real_t wy = Bt(dy, qy);
724 for (int dx = 0; dx < d1d_test; ++dx) { mass_xy[dy][dx] += mass_x[dx] * wy; }
725 }
726 }
727
728 for (int dz = 0; dz < d1d_test; ++dz)
729 {
730 const real_t wz = Bt(dz, qz);
731 for (int dy = 0; dy < d1d_test; ++dy)
732 {
733 for (int dx = 0; dx < d1d_test; ++dx)
734 {
735 Y(dx, dy, dz, e) += mass_xy[dy][dx] * wz;
736 }
737 }
738 }
739 }
740 });
741}
742
743void PAHcurlDotApplyTranspose3D(const int d1d,
744 const int d1d_test,
745 const int q1d,
746 const int ne,
747 const Array<real_t> &bo,
748 const Array<real_t> &bc,
749 const Array<real_t> &b,
750 const Vector &pa_data,
751 const Vector &x,
752 Vector &y)
753{
754 MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D, "");
755 MFEM_VERIFY(d1d_test <= DeviceDofQuadLimits::Get().MAX_D1D, "");
756 MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D, "");
757
758 auto Bo = Reshape(bo.Read(), q1d, d1d - 1);
759 auto Bc = Reshape(bc.Read(), q1d, d1d);
760 auto B = Reshape(b.Read(), q1d, d1d_test);
761 auto O = Reshape(pa_data.Read(), 3, q1d, q1d, q1d, ne);
762 auto X = Reshape(x.Read(), d1d_test, d1d_test, d1d_test, ne);
763 auto Y = Reshape(y.ReadWrite(), 3 * (d1d - 1) * d1d * d1d, ne);
764
765 mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
766 {
767 constexpr int MAX_D1D = DofQuadLimits::MAX_D1D;
768 constexpr int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
769
770 real_t mass[MAX_Q1D][MAX_Q1D][MAX_Q1D];
771 for (int qz = 0; qz < q1d; ++qz)
772 {
773 for (int qy = 0; qy < q1d; ++qy)
774 {
775 for (int qx = 0; qx < q1d; ++qx) { mass[qz][qy][qx] = 0.0; }
776 }
777 }
778
779 for (int dz = 0; dz < d1d_test; ++dz)
780 {
781 real_t mass_xy[MAX_Q1D][MAX_Q1D];
782 for (int qy = 0; qy < q1d; ++qy)
783 {
784 for (int qx = 0; qx < q1d; ++qx) { mass_xy[qy][qx] = 0.0; }
785 }
786
787 for (int dy = 0; dy < d1d_test; ++dy)
788 {
789 real_t mass_x[MAX_Q1D];
790 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] = 0.0; }
791 for (int dx = 0; dx < d1d_test; ++dx)
792 {
793 const real_t t = X(dx, dy, dz, e);
794 for (int qx = 0; qx < q1d; ++qx) { mass_x[qx] += t * B(qx, dx); }
795 }
796 for (int qy = 0; qy < q1d; ++qy)
797 {
798 const real_t wy = B(qy, dy);
799 for (int qx = 0; qx < q1d; ++qx) { mass_xy[qy][qx] += mass_x[qx] * wy; }
800 }
801 }
802
803 for (int qz = 0; qz < q1d; ++qz)
804 {
805 const real_t wz = B(qz, dz);
806 for (int qy = 0; qy < q1d; ++qy)
807 {
808 for (int qx = 0; qx < q1d; ++qx) { mass[qz][qy][qx] += mass_xy[qy][qx] * wz; }
809 }
810 }
811 }
812
813 int osc = 0;
814 for (int qz = 0; qz < q1d; ++qz)
815 {
816 real_t mass_xy[MAX_D1D][MAX_D1D];
817 for (int dy = 0; dy < d1d; ++dy)
818 {
819 for (int dx = 0; dx < d1d - 1; ++dx) { mass_xy[dy][dx] = 0.0; }
820 }
821
822 for (int qy = 0; qy < q1d; ++qy)
823 {
824 real_t mass_x[MAX_D1D];
825 for (int dx = 0; dx < d1d - 1; ++dx) { mass_x[dx] = 0.0; }
826 for (int qx = 0; qx < q1d; ++qx)
827 {
828 const real_t s = O(0, qx, qy, qz, e) * mass[qz][qy][qx];
829 for (int dx = 0; dx < d1d - 1; ++dx) { mass_x[dx] += s * Bo(qx, dx); }
830 }
831 for (int dy = 0; dy < d1d; ++dy)
832 {
833 const real_t wy = Bc(qy, dy);
834 for (int dx = 0; dx < d1d - 1; ++dx) { mass_xy[dy][dx] += mass_x[dx] * wy; }
835 }
836 }
837
838 for (int dz = 0; dz < d1d; ++dz)
839 {
840 const real_t wz = Bc(qz, dz);
841 for (int dy = 0; dy < d1d; ++dy)
842 {
843 for (int dx = 0; dx < d1d - 1; ++dx)
844 {
845 Y(dx + ((dy + (dz * d1d)) * (d1d - 1)) + osc, e) += mass_xy[dy][dx] * wz;
846 }
847 }
848 }
849 }
850
851 osc += (d1d - 1) * d1d * d1d;
852 for (int qz = 0; qz < q1d; ++qz)
853 {
854 real_t mass_xy[MAX_D1D][MAX_D1D];
855 for (int dy = 0; dy < d1d - 1; ++dy)
856 {
857 for (int dx = 0; dx < d1d; ++dx) { mass_xy[dy][dx] = 0.0; }
858 }
859
860 for (int qy = 0; qy < q1d; ++qy)
861 {
862 real_t mass_x[MAX_D1D];
863 for (int dx = 0; dx < d1d; ++dx) { mass_x[dx] = 0.0; }
864 for (int qx = 0; qx < q1d; ++qx)
865 {
866 const real_t s = O(1, qx, qy, qz, e) * mass[qz][qy][qx];
867 for (int dx = 0; dx < d1d; ++dx) { mass_x[dx] += s * Bc(qx, dx); }
868 }
869 for (int dy = 0; dy < d1d - 1; ++dy)
870 {
871 const real_t wy = Bo(qy, dy);
872 for (int dx = 0; dx < d1d; ++dx) { mass_xy[dy][dx] += mass_x[dx] * wy; }
873 }
874 }
875
876 for (int dz = 0; dz < d1d; ++dz)
877 {
878 const real_t wz = Bc(qz, dz);
879 for (int dy = 0; dy < d1d - 1; ++dy)
880 {
881 for (int dx = 0; dx < d1d; ++dx)
882 {
883 Y(dx + ((dy + (dz * (d1d - 1))) * d1d) + osc, e) += mass_xy[dy][dx] * wz;
884 }
885 }
886 }
887 }
888
889 osc += (d1d - 1) * d1d * d1d;
890 for (int qz = 0; qz < q1d; ++qz)
891 {
892 real_t mass_xy[MAX_D1D][MAX_D1D];
893 for (int dy = 0; dy < d1d; ++dy)
894 {
895 for (int dx = 0; dx < d1d; ++dx) { mass_xy[dy][dx] = 0.0; }
896 }
897
898 for (int qy = 0; qy < q1d; ++qy)
899 {
900 real_t mass_x[MAX_D1D];
901 for (int dx = 0; dx < d1d; ++dx) { mass_x[dx] = 0.0; }
902 for (int qx = 0; qx < q1d; ++qx)
903 {
904 const real_t s = O(2, qx, qy, qz, e) * mass[qz][qy][qx];
905 for (int dx = 0; dx < d1d; ++dx) { mass_x[dx] += s * Bc(qx, dx); }
906 }
907 for (int dy = 0; dy < d1d; ++dy)
908 {
909 const real_t wy = Bc(qy, dy);
910 for (int dx = 0; dx < d1d; ++dx) { mass_xy[dy][dx] += mass_x[dx] * wy; }
911 }
912 }
913
914 for (int dz = 0; dz < d1d - 1; ++dz)
915 {
916 const real_t wz = Bo(qz, dz);
917 for (int dy = 0; dy < d1d; ++dy)
918 {
919 for (int dx = 0; dx < d1d; ++dx)
920 {
921 Y(dx + ((dy + (dz * d1d)) * d1d) + osc, e) += mass_xy[dy][dx] * wz;
922 }
923 }
924 }
925 }
926 });
927}
928
929} // namespace
930
932 const FiniteElementSpace &test_fes)
933{
934 Mesh *mesh = trial_fes.GetMesh();
935 const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
936 const FiniteElement *test_fel = test_fes.GetTypicalFE();
937
938 const VectorTensorFiniteElement *trial_el =
939 dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
940 MFEM_VERIFY(trial_el != NULL, "Only VectorTensorFiniteElement is supported!");
941
942 const TensorBasisElement *test_tensor_el =
943 dynamic_cast<const TensorBasisElement*>(test_fel);
944 MFEM_VERIFY(test_tensor_el != NULL,
945 "Only tensor-product scalar test elements are supported!");
946
947 MFEM_VERIFY(trial_el->GetDerivType() == mfem::FiniteElement::CURL,
948 "Only H(curl) trial spaces are supported!");
949
950 const IntegrationRule *ir = IntRule;
951 if (ir == nullptr)
952 {
953 const int order = trial_fel->GetOrder() + test_fel->GetOrder()
955 ir = &IntRules.Get(trial_fel->GetGeomType(), order);
956 }
957
958 dim = mesh->Dimension();
959 MFEM_VERIFY(dim == 2 || dim == 3, "Unsupported dimension!");
960 MFEM_VERIFY(trial_el->GetDim() == dim && test_fel->GetDim() == dim,
961 "Trial/test dimension mismatch.");
962
963 ne = trial_fes.GetNE();
964 MFEM_VERIFY(ne == test_fes.GetNE(),
965 "Different meshes for test and trial spaces");
966
968 mapsC = &trial_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
969 mapsO = &trial_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
970 mapsTest = &test_fel->GetDofToQuad(*ir, DofToQuad::TENSOR);
971
972 dofs1D = mapsC->ndof;
973 dofs1Dtest = mapsTest->ndof;
974 quad1D = mapsC->nqpt;
975 test_map_integral = (test_fel->GetMapType() == FiniteElement::INTEGRAL);
976
977 MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
978 MFEM_VERIFY(quad1D == mapsTest->nqpt, "Trial/test quadrature mismatch");
979 MFEM_VERIFY(dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D, "");
980 MFEM_VERIFY(dofs1Dtest <= DeviceDofQuadLimits::Get().MAX_D1D, "");
981 MFEM_VERIFY(quad1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D, "");
982
983 const int nq = ir->GetNPoints();
984 if (dim == 2) { MFEM_VERIFY(nq == quad1D * quad1D, ""); }
985 else { MFEM_VERIFY(nq == quad1D * quad1D * quad1D, ""); }
986
987 QuadratureSpace qs(*mesh, *ir);
989 MFEM_VERIFY(coeff.GetVDim() == dim, "Vector coefficient dimension mismatch.");
990
991 pa_data.SetSize(dim * nq * ne, Device::GetMemoryType());
992
993 if (dim == 2)
994 {
995 PAHcurlDotSetup2D(quad1D, ne, test_map_integral, ir->GetWeights(),
996 geom->J, coeff, pa_data);
997 }
998 else
999 {
1000 PAHcurlDotSetup3D(quad1D, ne, test_map_integral, ir->GetWeights(),
1001 geom->J, coeff, pa_data);
1002 }
1003}
1004
1006{
1007 if (dim == 2)
1008 {
1009 PAHcurlDotApply2D(dofs1D, dofs1Dtest, quad1D, ne,
1010 mapsO->B, mapsC->B, mapsTest->Bt, pa_data, x, y);
1011 }
1012 else if (dim == 3)
1013 {
1014 PAHcurlDotApply3D(dofs1D, dofs1Dtest, quad1D, ne,
1015 mapsO->B, mapsC->B, mapsTest->Bt, pa_data, x, y);
1016 }
1017 else
1018 {
1019 MFEM_ABORT("Unsupported dimension!");
1020 }
1021}
1022
1024 Vector &y) const
1025{
1026 if (dim == 2)
1027 {
1028 PAHcurlDotApplyTranspose2D(dofs1D, dofs1Dtest, quad1D, ne,
1029 mapsO->B, mapsC->B, mapsTest->B,
1030 pa_data, x, y);
1031 }
1032 else if (dim == 3)
1033 {
1034 PAHcurlDotApplyTranspose3D(dofs1D, dofs1Dtest, quad1D, ne,
1035 mapsO->B, mapsC->B, mapsTest->B,
1036 pa_data, x, y);
1037 }
1038 else
1039 {
1040 MFEM_ABORT("Unsupported dimension!");
1041 }
1042}
1043
1045 const FiniteElementSpace &test_fes)
1046{
1047 // Assumes tensor-product elements
1048 Mesh *mesh = trial_fes.GetMesh();
1049 const FiniteElement *fel = trial_fes.GetTypicalFE(); // In H(curl)
1050 const FiniteElement *eltest = test_fes.GetTypicalFE(); // In scalar space
1051
1052 const VectorTensorFiniteElement *el =
1053 dynamic_cast<const VectorTensorFiniteElement*>(fel);
1054 MFEM_VERIFY(el != NULL, "Only VectorTensorFiniteElement is supported!");
1055
1057 {
1058 MFEM_ABORT("Unknown kernel.");
1059 }
1060
1061 // Use the same logic as the standard FA:
1062 const IntegrationRule *ir;
1063 {
1064 auto &T = *mesh->GetTypicalElementTransformation();
1065 ir = GetIntegrationRule(*fel, *eltest, T);
1066 if (!ir)
1067 {
1068 const int ir_order = GetIntegrationOrder(*fel, *eltest, T);
1069 ir = &IntRules.Get(fel->GetGeomType(), ir_order);
1070 }
1071 }
1072
1073 auto map_type = eltest->GetMapType();
1074
1075 const int dims = el->GetDim();
1076 MFEM_VERIFY(dims == 2, "");
1077
1078 const int nq = ir->GetNPoints();
1079 dim = mesh->Dimension();
1080 MFEM_VERIFY(dim == 2, "");
1081
1082 ne = test_fes.GetNE();
1085 dofs1D = mapsC->ndof;
1086 quad1D = mapsC->nqpt;
1087
1088 MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
1089
1090 if (el->GetOrder() == eltest->GetOrder())
1091 {
1093 }
1094 else
1095 {
1096 dofs1Dtest = dofs1D - 1;
1097 }
1098
1100
1101 QuadratureSpace qs(*mesh, *ir);
1103
1104 if (dim == 2)
1105 {
1106 switch (map_type)
1107 {
1109 internal::PAHcurlL2Setup2D(quad1D, ne, ir->GetWeights(), coeff,
1110 pa_data);
1111 break;
1113 {
1114 const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
1116 auto geom = mesh->GetGeometricFactors(*ir, GeometricFactors::DETERMINANTS, mt);
1117 internal::PAHcurlL2IntSetup2D(quad1D, ne, ir->GetWeights(), coeff,
1118 geom->detJ, pa_data);
1119 } break;
1120 default:
1121 MFEM_ABORT("Unsupported map type");
1122 }
1123 }
1124 else
1125 {
1126 MFEM_ABORT("Unsupported dimension!");
1127 }
1128}
1129
1131{
1132 if (dim == 2)
1133 {
1134 internal::PAHcurlL2Apply2D(dofs1D, dofs1Dtest, quad1D, ne, mapsO->B,
1135 mapsO->Bt, mapsC->Bt, mapsC->G, pa_data,
1136 x, y);
1137 }
1138 else
1139 {
1140 MFEM_ABORT("Unsupported dimension!");
1141 }
1142}
1143
1145 Vector &y) const
1146{
1147 if (dim == 2)
1148 {
1149 internal::PAHcurlL2ApplyTranspose2D(dofs1D, dofs1Dtest, quad1D, ne, mapsO->B,
1150 mapsO->Bt, mapsC->B, mapsC->Gt, pa_data,
1151 x, y);
1152 }
1153 else
1154 {
1155 MFEM_ABORT("Unsupported dimension!");
1156 }
1157}
1158
1160 const FiniteElementSpace &test_fes)
1161{
1162 // Assumes tensor-product elements, with vector test and trial spaces.
1163 Mesh *mesh = trial_fes.GetMesh();
1164 const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
1165 const FiniteElement *test_fel = test_fes.GetTypicalFE();
1166
1167 const VectorTensorFiniteElement *trial_el =
1168 dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
1169 MFEM_VERIFY(trial_el != NULL, "Only VectorTensorFiniteElement is supported!");
1170
1171 const VectorTensorFiniteElement *test_el =
1172 dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
1173 MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
1174
1175 const IntegrationRule *ir
1176 = IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *test_el,
1178 const int dims = trial_el->GetDim();
1179 MFEM_VERIFY(dims == 3, "");
1180
1181 const int nq = ir->GetNPoints();
1182 dim = mesh->Dimension();
1183 MFEM_VERIFY(dim == 3, "");
1184
1185 MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
1186
1187 ne = trial_fes.GetNE();
1189 mapsC = &trial_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
1190 mapsO = &trial_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
1191 mapsCtest = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
1192 mapsOtest = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
1193 dofs1D = mapsC->ndof;
1194 quad1D = mapsC->nqpt;
1195 dofs1Dtest = mapsCtest->ndof;
1196
1197 MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
1198
1199 testType = test_el->GetDerivType();
1200 trialType = trial_el->GetDerivType();
1201
1202 const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
1203 coeffDim = (DQ ? 3 : 1);
1204
1205 const bool curlSpaces = (testType == mfem::FiniteElement::CURL &&
1206 trialType == mfem::FiniteElement::CURL);
1207
1208 const int ndata = curlSpaces ? (coeffDim == 1 ? 1 : 9) : symmDims;
1209 pa_data.SetSize(ndata * nq * ne, Device::GetMemoryType());
1210
1211 QuadratureSpace qs(*mesh, *ir);
1213 if (Q) { coeff.Project(*Q); }
1214 else if (DQ) { coeff.Project(*DQ); }
1215 else { coeff.SetConstant(1.0); }
1216
1217 if (testType == mfem::FiniteElement::CURL &&
1218 trialType == mfem::FiniteElement::CURL && dim == 3)
1219 {
1220 if (coeffDim == 1)
1221 {
1222 internal::PAHcurlL2Setup3D(nq, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
1223 }
1224 else
1225 {
1226 internal::PAHcurlHdivMassSetup3D(quad1D, coeffDim, ne, false, ir->GetWeights(),
1227 geom->J, coeff, pa_data);
1228 }
1229 }
1230 else if (testType == mfem::FiniteElement::DIV &&
1231 trialType == mfem::FiniteElement::CURL && dim == 3 &&
1232 test_fel->GetOrder() == trial_fel->GetOrder())
1233 {
1234 internal::PACurlCurlSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
1235 coeff, pa_data);
1236 }
1237 else
1238 {
1239 MFEM_ABORT("Unknown kernel.");
1240 }
1241}
1242
1244{
1245 if (testType == mfem::FiniteElement::CURL &&
1246 trialType == mfem::FiniteElement::CURL && dim == 3)
1247 {
1248 const int ndata = coeffDim == 1 ? 1 : 9;
1249
1251 {
1252 const int ID = (dofs1D << 4) | quad1D;
1253 switch (ID)
1254 {
1255 case 0x23:
1256 return internal::SmemPAHcurlL2Apply3D<2,3>(
1257 dofs1D, quad1D, ndata, ne,
1258 mapsO->B, mapsC->B, mapsC->G,
1259 pa_data, x, y);
1260 case 0x34:
1261 return internal::SmemPAHcurlL2Apply3D<3,4>(
1262 dofs1D, quad1D, ndata, ne,
1263 mapsO->B, mapsC->B, mapsC->G,
1264 pa_data, x, y);
1265 case 0x45:
1266 return internal::SmemPAHcurlL2Apply3D<4,5>(
1267 dofs1D, quad1D, ndata, ne,
1268 mapsO->B, mapsC->B, mapsC->G,
1269 pa_data, x, y);
1270 case 0x56:
1271 return internal::SmemPAHcurlL2Apply3D<5,6>(
1272 dofs1D, quad1D, ndata, ne,
1273 mapsO->B, mapsC->B, mapsC->G,
1274 pa_data, x, y);
1275 default:
1276 return internal::SmemPAHcurlL2Apply3D(
1277 dofs1D, quad1D, ndata, ne,
1278 mapsO->B, mapsC->B, mapsC->G,
1279 pa_data, x, y);
1280 }
1281 }
1282 else
1283 {
1284 internal::PAHcurlL2Apply3D(dofs1D, quad1D, ndata, ne, mapsO->B, mapsC->B,
1285 mapsO->Bt, mapsC->Bt, mapsC->G, pa_data, x, y);
1286 }
1287 }
1288 else if (testType == mfem::FiniteElement::DIV &&
1289 trialType == mfem::FiniteElement::CURL && dim == 3)
1290 {
1291 internal::PAHcurlHdivApply3D(dofs1D, dofs1Dtest, quad1D, ne, mapsO->B,
1292 mapsC->B, mapsOtest->Bt, mapsCtest->Bt, mapsC->G,
1293 pa_data, x, y);
1294 }
1295 else
1296 {
1297 MFEM_ABORT("Unsupported dimension or space!");
1298 }
1299}
1300
1302 Vector &y) const
1303{
1304 if (testType == mfem::FiniteElement::DIV &&
1305 trialType == mfem::FiniteElement::CURL && dim == 3)
1306 {
1307 internal::PAHcurlHdivApplyTranspose3D(dofs1D, dofs1Dtest, quad1D, ne, mapsO->B,
1308 mapsC->B, mapsOtest->Bt, mapsCtest->Bt,
1309 mapsC->Gt, pa_data, x, y);
1310 }
1311 else
1312 {
1313 MFEM_ABORT("Unsupported dimension or space!");
1314 }
1315}
1316
1318 &trial_fes,
1319 const FiniteElementSpace &test_fes)
1320{
1321 // Assumes tensor-product elements, with vector test and trial spaces.
1322 Mesh *mesh = trial_fes.GetMesh();
1323 const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
1324 const FiniteElement *test_fel = test_fes.GetTypicalFE();
1325
1326 const VectorTensorFiniteElement *trial_el =
1327 dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
1328 MFEM_VERIFY(trial_el != NULL, "Only VectorTensorFiniteElement is supported!");
1329
1330 const VectorTensorFiniteElement *test_el =
1331 dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
1332 MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
1333
1334 const IntegrationRule *ir
1335 = IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *test_el,
1337 const int dims = trial_el->GetDim();
1338 MFEM_VERIFY(dims == 3, "");
1339
1340 const int nq = ir->GetNPoints();
1341 dim = mesh->Dimension();
1342 MFEM_VERIFY(dim == 3, "");
1343
1344 MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
1345
1346 ne = trial_fes.GetNE();
1348 mapsC = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
1349 mapsO = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
1350 dofs1D = mapsC->ndof;
1351 quad1D = mapsC->nqpt;
1352
1353 MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
1354
1355 testType = test_el->GetDerivType();
1356 trialType = trial_el->GetDerivType();
1357
1358 const bool curlSpaces = (testType == mfem::FiniteElement::CURL &&
1359 trialType == mfem::FiniteElement::CURL);
1360
1361 const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
1362
1363 coeffDim = DQ ? 3 : 1;
1364 const int ndata = curlSpaces ? (DQ ? 9 : 1) : symmDims;
1365
1366 pa_data.SetSize(ndata * nq * ne, Device::GetMemoryType());
1367
1368 QuadratureSpace qs(*mesh, *ir);
1370 if (Q) { coeff.Project(*Q); }
1371 else if (DQ) { coeff.Project(*DQ); }
1372 else if (MQ) { MFEM_ABORT("Not implemented."); }
1373 else { coeff.SetConstant(1.0); }
1374
1375 if (trialType == mfem::FiniteElement::CURL && dim == 3)
1376 {
1377 if (coeffDim == 1)
1378 {
1379 internal::PAHcurlL2Setup3D(nq, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
1380 }
1381 else
1382 {
1383 internal::PAHcurlHdivMassSetup3D(quad1D, coeffDim, ne, false, ir->GetWeights(),
1384 geom->J, coeff, pa_data);
1385 }
1386 }
1387 else if (trialType == mfem::FiniteElement::DIV && dim == 3 &&
1388 test_el->GetOrder() == trial_el->GetOrder())
1389 {
1390 internal::PACurlCurlSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
1391 coeff, pa_data);
1392 }
1393 else
1394 {
1395 MFEM_ABORT("Unknown kernel.");
1396 }
1397}
1398
1400{
1401 if (testType == mfem::FiniteElement::CURL &&
1402 trialType == mfem::FiniteElement::CURL && dim == 3)
1403 {
1404 const int ndata = coeffDim == 1 ? 1 : 9;
1406 {
1407 const int ID = (dofs1D << 4) | quad1D;
1408 switch (ID)
1409 {
1410 case 0x23:
1411 return internal::SmemPAHcurlL2ApplyTranspose3D<2,3>(
1412 dofs1D, quad1D, ndata,
1413 ne, mapsO->B, mapsC->B,
1414 mapsC->G, pa_data, x, y);
1415 case 0x34:
1416 return internal::SmemPAHcurlL2ApplyTranspose3D<3,4>(
1417 dofs1D, quad1D, ndata,
1418 ne, mapsO->B, mapsC->B,
1419 mapsC->G, pa_data, x, y);
1420 case 0x45:
1421 return internal::SmemPAHcurlL2ApplyTranspose3D<4,5>(
1422 dofs1D, quad1D, ndata,
1423 ne, mapsO->B, mapsC->B,
1424 mapsC->G, pa_data, x, y);
1425 case 0x56:
1426 return internal::SmemPAHcurlL2ApplyTranspose3D<5,6>(
1427 dofs1D, quad1D, ndata,
1428 ne, mapsO->B, mapsC->B,
1429 mapsC->G, pa_data, x, y);
1430 default:
1431 return internal::SmemPAHcurlL2ApplyTranspose3D(
1432 dofs1D, quad1D, ndata, ne,
1433 mapsO->B, mapsC->B,
1434 mapsC->G, pa_data, x, y);
1435 }
1436 }
1437 else
1438 {
1439 internal::PAHcurlL2ApplyTranspose3D(dofs1D, quad1D, ndata, ne, mapsO->B,
1440 mapsC->B, mapsO->Bt, mapsC->Bt, mapsC->Gt,
1441 pa_data, x, y);
1442 }
1443 }
1444 else if (testType == mfem::FiniteElement::CURL &&
1445 trialType == mfem::FiniteElement::DIV && dim == 3)
1446 {
1447 internal::PAHcurlHdivApplyTranspose3D(dofs1D, dofs1D, quad1D, ne, mapsO->B,
1448 mapsC->B, mapsO->Bt, mapsC->Bt,
1449 mapsC->Gt, pa_data, x, y);
1450 }
1451 else
1452 {
1453 MFEM_ABORT("Unsupported dimension or space!");
1454 }
1455}
1456
1458 Vector &y) const
1459{
1460 if (testType == mfem::FiniteElement::CURL &&
1461 trialType == mfem::FiniteElement::DIV && dim == 3)
1462 {
1463 internal::PAHcurlHdivApply3D(dofs1D, dofs1D, quad1D, ne, mapsO->B,
1464 mapsC->B, mapsO->Bt, mapsC->Bt, mapsC->G,
1465 pa_data, x, y);
1466 }
1467 else
1468 {
1469 MFEM_ABORT("Unsupported dimension or space!");
1470 }
1471}
1472
1474 &trial_fes,
1475 const FiniteElementSpace &test_fes)
1476{
1477 Mesh *mesh = trial_fes.GetMesh();
1478 const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
1479 const FiniteElement *test_fel = test_fes.GetTypicalFE();
1480
1481 const TensorBasisElement *trial_tensor_el =
1482 dynamic_cast<const TensorBasisElement*>(trial_fel);
1483 MFEM_VERIFY(trial_tensor_el != NULL,
1484 "Only tensor-product scalar trial elements are supported!");
1485
1486 const VectorTensorFiniteElement *test_el =
1487 dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
1488 MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
1489 MFEM_VERIFY(test_el->GetDerivType() == mfem::FiniteElement::DIV,
1490 "Only H(div) test spaces are supported!");
1491
1493 *trial_fel, *test_fel,
1495
1496 const int dims = test_el->GetDim();
1497 MFEM_VERIFY(dims == 2 || dims == 3, "");
1498
1499 const int nq = ir->GetNPoints();
1500 dim = mesh->Dimension();
1501 MFEM_VERIFY(dim == 2 || dim == 3, "");
1502
1503 ne = trial_fes.GetNE();
1504 MFEM_VERIFY(ne == test_fes.GetNE(),
1505 "Different meshes for test and trial spaces");
1506
1507 mapsC = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
1508 mapsO = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
1509 dofs1D = mapsC->ndof;
1510 quad1D = mapsC->nqpt;
1511
1512 L2mapsO = &trial_fel->GetDofToQuad(*ir, DofToQuad::TENSOR);
1514
1515 MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
1516 if (dim == 2) { MFEM_VERIFY(nq == quad1D * quad1D, ""); }
1517 else { MFEM_VERIFY(nq == quad1D * quad1D * quad1D, ""); }
1518
1520
1521 QuadratureSpace qs(*mesh, *ir);
1523
1524 const GeometricFactors *geom = nullptr;
1525 if (trial_fel->GetMapType() == FiniteElement::INTEGRAL)
1526 {
1528 }
1529
1530 if (dim == 2)
1531 {
1532 internal::PAHdivL2Setup2D(quad1D, ne, ir->GetWeights(), coeff, pa_data,
1533 geom);
1534 }
1535 else
1536 {
1537 internal::PAHdivL2Setup3D(quad1D, ne, ir->GetWeights(), coeff, pa_data,
1538 geom);
1539 }
1540 pa_data *= -1_r;
1541}
1542
1544 Vector &y) const
1545{
1546 if (dim == 2)
1547 {
1548 internal::PAHdivL2ApplyTranspose2D(dofs1D, quad1D, L2dofs1D, ne, L2mapsO->B,
1549 mapsC->Gt, mapsO->Bt, pa_data, x, y);
1550 }
1551 else if (dim == 3)
1552 {
1553 internal::PAHdivL2ApplyTranspose3D(dofs1D, quad1D, L2dofs1D, ne, L2mapsO->B,
1554 mapsC->Gt, mapsO->Bt, pa_data, x, y);
1555 }
1556 else
1557 {
1558 MFEM_ABORT("Unsupported dimension!");
1559 }
1560}
1561
1563 Vector &y) const
1564{
1565 if (dim == 2)
1566 {
1567 internal::PAHdivL2Apply2D(dofs1D, quad1D, L2dofs1D, ne, mapsO->B, mapsC->G,
1568 L2mapsO->Bt, pa_data, x, y);
1569 }
1570 else if (dim == 3)
1571 {
1572 internal::PAHdivL2Apply3D(dofs1D, quad1D, L2dofs1D, ne, mapsO->B, mapsC->G,
1573 L2mapsO->Bt, pa_data, x, y);
1574 }
1575 else
1576 {
1577 MFEM_ABORT("Unsupported dimension!");
1578 }
1579}
1580
1582 &trial_fes,
1583 const FiniteElementSpace &test_fes)
1584{
1585 Mesh *mesh = trial_fes.GetMesh();
1586 const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
1587 const FiniteElement *test_fel = test_fes.GetTypicalFE();
1588
1589 const VectorTensorFiniteElement *trial_el =
1590 dynamic_cast<const VectorTensorFiniteElement *>(trial_fel);
1591 MFEM_VERIFY(trial_el != NULL, "Only VectorTensorFiniteElement is supported!");
1592 MFEM_VERIFY(trial_el->GetDerivType() == mfem::FiniteElement::DIV,
1593 "Only H(div) trial spaces are supported!");
1594
1595 const TensorBasisElement *test_tensor_el =
1596 dynamic_cast<const TensorBasisElement*>(test_fel);
1597 MFEM_VERIFY(test_tensor_el != NULL,
1598 "Only tensor-product scalar test elements are supported!");
1599
1600 const IntegrationRule *ir = IntRule;
1601 if (ir == nullptr)
1602 {
1603 const int order = trial_fel->GetOrder() + test_fel->GetOrder()
1605 ir = &IntRules.Get(trial_fel->GetGeomType(), order);
1606 }
1607
1608 dim = mesh->Dimension();
1609 MFEM_VERIFY(dim == 2, "Only 2D is supported.");
1610 MFEM_VERIFY(trial_el->GetDim() == dim && test_fel->GetDim() == dim,
1611 "Trial/test dimension mismatch.");
1612
1613 ne = trial_fes.GetNE();
1614 MFEM_VERIFY(ne == test_fes.GetNE(),
1615 "Different meshes for test and trial spaces");
1616
1618 mapsC = &trial_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
1619 mapsO = &trial_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
1620 mapsTest = &test_fel->GetDofToQuad(*ir, DofToQuad::TENSOR);
1621
1622 dofs1D = mapsC->ndof;
1623 dofs1Dtest = mapsTest->ndof;
1624 quad1D = mapsC->nqpt;
1625 test_map_integral = (test_fel->GetMapType() == FiniteElement::INTEGRAL);
1626
1627 MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
1628 MFEM_VERIFY(quad1D == mapsTest->nqpt, "Trial/test quadrature mismatch");
1629 MFEM_VERIFY(dofs1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D, "");
1630 MFEM_VERIFY(dofs1Dtest <= DeviceDofQuadLimits::Get().MAX_D1D, "");
1631 MFEM_VERIFY(quad1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D, "");
1632
1633 const int nq = ir->GetNPoints();
1634 MFEM_VERIFY(nq == quad1D * quad1D, "");
1635
1636 Rotated2DVectorCoefficient rotated(*VQ);
1637 QuadratureSpace qs(*mesh, *ir);
1638 CoefficientVector coeff(rotated, qs, CoefficientStorage::FULL);
1639
1640 pa_data.SetSize(dim * nq * ne, Device::GetMemoryType());
1641 PAHdivDotSetup2D(quad1D, ne, test_map_integral, ir->GetWeights(),
1642 geom->J, coeff, pa_data);
1643}
1644
1646 Vector &y) const
1647{
1648 PAHdivDotApply2D(dofs1D, dofs1Dtest, quad1D, ne,
1649 mapsO->B, mapsC->B, mapsTest->Bt,
1650 pa_data, x, y);
1651}
1652
1654 Vector &y) const
1655{
1656 PAHdivDotApplyTranspose2D(dofs1D, dofs1Dtest, quad1D, ne,
1657 mapsO->B, mapsC->B, mapsTest->B,
1658 pa_data, x, y);
1659}
1660
1662 const FiniteElementSpace &trial_fes,
1663 const FiniteElementSpace &test_fes)
1664{
1665 Mesh *mesh = trial_fes.GetMesh();
1666 const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
1667 const FiniteElement *test_fel = test_fes.GetTypicalFE();
1668
1669 const TensorBasisElement *trial_tensor_el =
1670 dynamic_cast<const TensorBasisElement*>(trial_fel);
1671 MFEM_VERIFY(trial_tensor_el != NULL,
1672 "Only tensor-product scalar trial elements are supported!");
1673
1674 const VectorTensorFiniteElement *test_el =
1675 dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
1676 MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
1677 MFEM_VERIFY(test_el->GetDerivType() == mfem::FiniteElement::CURL,
1678 "Only H(curl) test spaces are supported!");
1679
1680 const IntegrationRule *ir = IntRule;
1681 if (ir == nullptr)
1682 {
1683 const int order = trial_fel->GetOrder() + test_fel->GetOrder()
1685 ir = &IntRules.Get(trial_fel->GetGeomType(), order);
1686 }
1687
1688 dim = mesh->Dimension();
1689 MFEM_VERIFY(dim == 2, "Only 2D is supported.");
1690 MFEM_VERIFY(test_el->GetDim() == dim && trial_fel->GetDim() == dim,
1691 "Trial/test dimension mismatch.");
1692
1693 ne = trial_fes.GetNE();
1694 MFEM_VERIFY(ne == test_fes.GetNE(),
1695 "Different meshes for test and trial spaces");
1696
1698 mapsC = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
1699 mapsO = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
1700 mapsTrial = &trial_fel->GetDofToQuad(*ir, DofToQuad::TENSOR);
1701
1702 dofs1D = mapsC->ndof;
1703 dofs1Dtrial = mapsTrial->ndof;
1704 quad1D = mapsC->nqpt;
1705 trial_map_integral = (trial_fel->GetMapType() == FiniteElement::INTEGRAL);
1706
1707 MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
1708 MFEM_VERIFY(quad1D == mapsTrial->nqpt, "Trial/test quadrature mismatch");
1709 MFEM_VERIFY(dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D, "");
1710 MFEM_VERIFY(dofs1Dtrial <= DeviceDofQuadLimits::Get().MAX_D1D, "");
1711 MFEM_VERIFY(quad1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D, "");
1712
1713 const int nq = ir->GetNPoints();
1714 MFEM_VERIFY(nq == quad1D * quad1D, "");
1715
1716 Rotated2DVectorCoefficient rotated(*VQ);
1717 QuadratureSpace qs(*mesh, *ir);
1718 CoefficientVector coeff(rotated, qs, CoefficientStorage::FULL);
1719
1720 pa_data.SetSize(dim * nq * ne, Device::GetMemoryType());
1721 PAHcurlDotSetup2D(quad1D, ne, trial_map_integral, ir->GetWeights(),
1722 geom->J, coeff, pa_data);
1723 // Match the extra sign introduced by the legacy assembled path's
1724 // MixedScalarWeakCrossProductIntegrator::CalcShape().
1725 pa_data *= -1_r;
1726}
1727
1729 Vector &y) const
1730{
1731 PAHcurlDotApplyTranspose2D(dofs1D, dofs1Dtrial, quad1D, ne,
1732 mapsO->B, mapsC->B, mapsTrial->B,
1733 pa_data, x, y);
1734}
1735
1737 Vector &y) const
1738{
1739 PAHcurlDotApply2D(dofs1D, dofs1Dtrial, quad1D, ne,
1740 mapsO->B, mapsC->B, mapsTrial->Bt,
1741 pa_data, x, y);
1742}
1743
1744} // namespace mfem
Class to represent a coefficient evaluated at quadrature points.
void SetConstant(real_t constant)
Set this vector to the given constant.
void Project(Coefficient &coeff)
Evaluate the given Coefficient at the quadrature points defined by qs.
int GetVDim() const
Return the number of values per quadrature point.
static MemoryType GetMemoryType()
(DEPRECATED) Equivalent to GetDeviceMemoryType().
Definition device.hpp:302
static bool Allows(unsigned long b_mask)
Return true if any of the backends in the backend mask, b_mask, are allowed.
Definition device.hpp:271
static MemoryType GetDeviceMemoryType()
Get the current Device MemoryType. This is the MemoryType used by most MFEM classes when allocating m...
Definition device.hpp:298
Array< real_t > G
Gradients/divergences/curls of basis functions evaluated at quadrature points.
Definition fe_base.hpp:222
@ TENSOR
Tensor product representation using 1D matrices/tensors with dimensions using 1D number of quadrature...
Definition fe_base.hpp:165
Array< real_t > B
Basis functions evaluated at quadrature points.
Definition fe_base.hpp:201
int ndof
Number of degrees of freedom = number of basis functions. When mode is TENSOR, this is the 1D number.
Definition fe_base.hpp:186
Array< real_t > Gt
Transpose of G.
Definition fe_base.hpp:229
int nqpt
Number of quadrature points. When mode is TENSOR, this is the 1D number.
Definition fe_base.hpp:190
Array< real_t > Bt
Transpose of B.
Definition fe_base.hpp:207
virtual int OrderW() const =0
Return the order of the determinant of the Jacobian (weight) of the transformation.
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:210
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:867
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:639
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Definition fespace.cpp:3896
Abstract class for all finite elements.
Definition fe_base.hpp:294
virtual const DofToQuad & GetDofToQuad(const IntegrationRule &ir, DofToQuad::Mode mode) const
Return a DofToQuad structure corresponding to the given IntegrationRule using the given DofToQuad::Mo...
Definition fe_base.cpp:373
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition fe_base.hpp:414
int GetDerivType() const
Returns the FiniteElement::DerivType of the element describing the spatial derivative method implemen...
Definition fe_base.hpp:441
int GetDim() const
Returns the reference space dimension for the finite element.
Definition fe_base.hpp:381
int GetMapType() const
Returns the FiniteElement::MapType of the element describing how reference functions are mapped to ph...
Definition fe_base.hpp:436
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition fe_base.hpp:407
@ DIV
Implements CalcDivShape methods.
Definition fe_base.hpp:366
@ CURL
Implements CalcCurlShape methods.
Definition fe_base.hpp:367
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
Definition mesh.hpp:3119
Vector J
Jacobians of the element transformations at all quadrature points.
Definition mesh.hpp:3158
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:96
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:255
const Array< real_t > & GetWeights() const
Return the quadrature weights in a contiguous array.
Definition intrules.cpp:98
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
const IntegrationRule * GetIntegrationRule() const
Equivalent to GetIntRule, but retained for backward compatibility with applications.
const IntegrationRule * IntRule
static const IntegrationRule & GetRule(const FiniteElement &trial_fe, const FiniteElement &test_fe, const ElementTransformation &Trans, const bool stroud=false)
Mesh data type.
Definition mesh.hpp:67
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1314
ElementTransformation * GetTypicalElementTransformation()
If the local mesh is not empty return GetElementTransformation(0); otherwise, return the identity tra...
Definition mesh.cpp:394
const GeometricFactors * GetGeometricFactors(const IntegrationRule &ir, const int flags, MemoryType d_mt=MemoryType::DEFAULT)
Return the mesh geometric factors corresponding to the given integration rule.
Definition mesh.cpp:958
void AddMultTransposePA(const Vector &, Vector &) const override
Method for partially assembled transposed action.
void AssemblePA(const FiniteElementSpace &trial_fes, const FiniteElementSpace &test_fes) override
void AddMultPA(const Vector &, Vector &) const override
Method for partially assembled action.
void AssemblePA(const FiniteElementSpace &trial_fes, const FiniteElementSpace &test_fes) override
void AddMultPA(const Vector &x, Vector &y) const override
Method for partially assembled action.
void AddMultTransposePA(const Vector &x, Vector &y) const override
Method for partially assembled transposed action.
const DofToQuad * mapsO
Not owned. DOF-to-quad map, open.
const DofToQuad * mapsC
Not owned. DOF-to-quad map, closed.
int GetIntegrationOrder(const FiniteElement &trial_fe, const FiniteElement &test_fe, ElementTransformation &Trans) override
void AddMultTransposePA(const Vector &x, Vector &y) const override
Method for partially assembled transposed action.
void AssemblePA(const FiniteElementSpace &trial_fes, const FiniteElementSpace &test_fes) override
void AddMultPA(const Vector &, Vector &) const override
Method for partially assembled action.
void AddMultTransposePA(const Vector &x, Vector &y) const override
Method for partially assembled transposed action.
void AssemblePA(const FiniteElementSpace &trial_fes, const FiniteElementSpace &test_fes) override
void AddMultPA(const Vector &x, Vector &y) const override
Method for partially assembled action.
const DofToQuad * L2mapsO
Not owned. Scalar open/closed map.
void AssemblePA(const FiniteElementSpace &trial_fes, const FiniteElementSpace &test_fes) override
const DofToQuad * mapsO
Not owned. HDiv open map.
void AddMultPA(const Vector &x, Vector &y) const override
Method for partially assembled action.
const DofToQuad * mapsC
Not owned. HDiv closed map.
void AddMultTransposePA(const Vector &x, Vector &y) const override
Method for partially assembled transposed action.
void AddMultTransposePA(const Vector &, Vector &) const override
Method for partially assembled transposed action.
void AddMultPA(const Vector &, Vector &) const override
Method for partially assembled action.
void AssemblePA(const FiniteElementSpace &trial_fes, const FiniteElementSpace &test_fes) override
MatrixCoefficient * MQ
DiagonalMatrixCoefficient * DQ
void AddMultPA(const Vector &, Vector &) const override
Method for partially assembled action.
void AddMultTransposePA(const Vector &, Vector &) const override
Method for partially assembled transposed action.
void AssemblePA(const FiniteElementSpace &trial_fes, const FiniteElementSpace &test_fes) override
Class representing the storage layout of a QuadratureFunction.
Definition qspace.hpp:164
virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip)=0
Evaluate the vector coefficient in the element described by T at the point ip, storing the result in ...
const DofToQuad & GetDofToQuadOpen(const IntegrationRule &ir, DofToQuad::Mode mode) const
Definition fe_base.hpp:1442
const DofToQuad & GetDofToQuad(const IntegrationRule &ir, DofToQuad::Mode mode) const override
Return a DofToQuad structure corresponding to the given IntegrationRule using the given DofToQuad::Mo...
Definition fe_base.hpp:1434
Vector data type.
Definition vector.hpp:82
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:633
real_t b
Definition lissajous.cpp:42
mfem::real_t real_t
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
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
@ FULL
Store the coefficient as a full QuadratureFunction.
void forall_2D(int N, int X, int Y, lambda &&body)
Definition forall.hpp:1220
void forall_3D(int N, int X, int Y, int Z, lambda &&body)
Definition forall.hpp:1244
MemoryType
Memory types supported by MFEM.
void forall(int N, lambda &&body)
Definition forall.hpp:1134
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:549
@ DEVICE_MASK
Biwise-OR of all device backends.
Definition device.hpp:104
static const DeviceDofQuadLimits & Get()
Return a const reference to the DeviceDofQuadLimits singleton.
Definition forall.hpp:138