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