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