MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
bilininteg_diffusion_kernels.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
13
14namespace mfem
15{
16
17// PA Diffusion Integrator
18
42
43namespace internal
44{
45
46template<>
47void PADiffusionSetup2D<2>(const int Q1D,
48 const int coeffDim,
49 const int NE,
50 const Array<real_t> &w,
51 const Vector &j,
52 const Vector &c,
53 Vector &d);
54
55template<>
56void PADiffusionSetup2D<3>(const int Q1D,
57 const int coeffDim,
58 const int NE,
59 const Array<real_t> &w,
60 const Vector &j,
61 const Vector &c,
62 Vector &d);
63
64void PADiffusionSetup(const int dim,
65 const int sdim,
66 const int D1D,
67 const int Q1D,
68 const int coeffDim,
69 const int NE,
70 const Array<real_t> &W,
71 const Vector &J,
72 const Vector &C,
73 Vector &D)
74{
75 if (dim == 1) { MFEM_ABORT("dim==1 not supported in PADiffusionSetup"); }
76 if (dim == 2)
77 {
78#ifdef MFEM_USE_OCCA
79 if (DeviceCanUseOcca())
80 {
81 OccaPADiffusionSetup2D(D1D, Q1D, NE, W, J, C, D);
82 return;
83 }
84#else
85 MFEM_CONTRACT_VAR(D1D);
86#endif // MFEM_USE_OCCA
87 if (sdim == 2) { PADiffusionSetup2D<2>(Q1D, coeffDim, NE, W, J, C, D); }
88 if (sdim == 3) { PADiffusionSetup2D<3>(Q1D, coeffDim, NE, W, J, C, D); }
89 }
90 if (dim == 3)
91 {
92#ifdef MFEM_USE_OCCA
93 if (DeviceCanUseOcca())
94 {
95 OccaPADiffusionSetup3D(D1D, Q1D, NE, W, J, C, D);
96 return;
97 }
98#endif // MFEM_USE_OCCA
99 PADiffusionSetup3D(Q1D, coeffDim, NE, W, J, C, D);
100 }
101}
102
103template<>
104void PADiffusionSetup2D<2>(const int Q1D,
105 const int coeffDim,
106 const int NE,
107 const Array<real_t> &w,
108 const Vector &j,
109 const Vector &c,
110 Vector &d)
111{
112 const bool symmetric = (coeffDim != 4);
113 const bool const_c = c.Size() == 1;
114 MFEM_VERIFY(coeffDim < 3 ||
115 !const_c, "Constant matrix coefficient not supported");
116 const auto W = Reshape(w.Read(), Q1D,Q1D);
117 const auto J = Reshape(j.Read(), Q1D,Q1D,2,2,NE);
118 const auto C = const_c ? Reshape(c.Read(), 1,1,1,1) :
119 Reshape(c.Read(), coeffDim,Q1D,Q1D,NE);
120 auto D = Reshape(d.Write(), Q1D,Q1D, symmetric ? 3 : 4, NE);
121 mfem::forall_2D(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
122 {
123 MFEM_FOREACH_THREAD(qx,x,Q1D)
124 {
125 MFEM_FOREACH_THREAD(qy,y,Q1D)
126 {
127 const real_t J11 = J(qx,qy,0,0,e);
128 const real_t J21 = J(qx,qy,1,0,e);
129 const real_t J12 = J(qx,qy,0,1,e);
130 const real_t J22 = J(qx,qy,1,1,e);
131 const real_t w_detJ = W(qx,qy) / ((J11*J22)-(J21*J12));
132 if (coeffDim == 3 || coeffDim == 4) // Matrix coefficient
133 {
134 // First compute entries of R = MJ^{-T}, without det J factor.
135 const real_t M11 = C(0,qx,qy,e);
136 const real_t M12 = C(1,qx,qy,e);
137 const real_t M21 = symmetric ? M12 : C(2,qx,qy,e);
138 const real_t M22 = symmetric ? C(2,qx,qy,e) : C(3,qx,qy,e);
139 const real_t R11 = M11*J22 - M12*J12;
140 const real_t R21 = M21*J22 - M22*J12;
141 const real_t R12 = -M11*J21 + M12*J11;
142 const real_t R22 = -M21*J21 + M22*J11;
143
144 // Now set y to J^{-1}R.
145 D(qx,qy,0,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
146 D(qx,qy,1,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
147 D(qx,qy,2,e) = w_detJ * (symmetric ? (-J21*R12 + J11*R22) :
148 (J22*R12 - J12*R22)); // 2,2 or 1,2
149 if (!symmetric)
150 {
151 D(qx,qy,3,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
152 }
153 }
154 else // Vector or scalar coefficient
155 {
156 const real_t C1 = const_c ? C(0,0,0,0) : C(0,qx,qy,e);
157 const real_t C2 = const_c ? C(0,0,0,0) :
158 (coeffDim == 2 ? C(1,qx,qy,e) : C(0,qx,qy,e));
159
160 D(qx,qy,0,e) = w_detJ * (C2*J12*J12 + C1*J22*J22); // 1,1
161 D(qx,qy,1,e) = -w_detJ * (C2*J12*J11 + C1*J22*J21); // 1,2
162 D(qx,qy,2,e) = w_detJ * (C2*J11*J11 + C1*J21*J21); // 2,2
163 }
164 }
165 }
166 });
167}
168
169template<>
170void PADiffusionSetup2D<3>(const int Q1D,
171 const int coeffDim,
172 const int NE,
173 const Array<real_t> &w,
174 const Vector &j,
175 const Vector &c,
176 Vector &d)
177{
178 MFEM_VERIFY(coeffDim == 1, "Matrix and vector coefficients not supported");
179 constexpr int DIM = 2;
180 constexpr int SDIM = 3;
181 const bool const_c = c.Size() == 1;
182 const auto W = Reshape(w.Read(), Q1D,Q1D);
183 const auto J = Reshape(j.Read(), Q1D,Q1D,SDIM,DIM,NE);
184 const auto C = const_c ? Reshape(c.Read(), 1,1,1) :
185 Reshape(c.Read(), Q1D,Q1D,NE);
186 auto D = Reshape(d.Write(), Q1D,Q1D, 3, NE);
187 mfem::forall_2D(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
188 {
189 MFEM_FOREACH_THREAD(qx,x,Q1D)
190 {
191 MFEM_FOREACH_THREAD(qy,y,Q1D)
192 {
193 const real_t wq = W(qx,qy);
194 const real_t J11 = J(qx,qy,0,0,e);
195 const real_t J21 = J(qx,qy,1,0,e);
196 const real_t J31 = J(qx,qy,2,0,e);
197 const real_t J12 = J(qx,qy,0,1,e);
198 const real_t J22 = J(qx,qy,1,1,e);
199 const real_t J32 = J(qx,qy,2,1,e);
200 const real_t E = J11*J11 + J21*J21 + J31*J31;
201 const real_t G = J12*J12 + J22*J22 + J32*J32;
202 const real_t F = J11*J12 + J21*J22 + J31*J32;
203 const real_t iw = 1.0 / sqrt(E*G - F*F);
204 const real_t coeff = const_c ? C(0,0,0) : C(qx,qy,e);
205 const real_t alpha = wq * coeff * iw;
206 D(qx,qy,0,e) = alpha * G; // 1,1
207 D(qx,qy,1,e) = -alpha * F; // 1,2
208 D(qx,qy,2,e) = alpha * E; // 2,2
209 }
210 }
211 });
212}
213
214void PADiffusionSetup3D(const int Q1D,
215 const int coeffDim,
216 const int NE,
217 const Array<real_t> &w,
218 const Vector &j,
219 const Vector &c,
220 Vector &d)
221{
222 const bool symmetric = (coeffDim != 9);
223 const bool const_c = c.Size() == 1;
224 MFEM_VERIFY(coeffDim < 6 ||
225 !const_c, "Constant matrix coefficient not supported");
226 const auto W = Reshape(w.Read(), Q1D,Q1D,Q1D);
227 const auto J = Reshape(j.Read(), Q1D,Q1D,Q1D,3,3,NE);
228 const auto C = const_c ? Reshape(c.Read(), 1,1,1,1,1) :
229 Reshape(c.Read(), coeffDim,Q1D,Q1D,Q1D,NE);
230 auto D = Reshape(d.Write(), Q1D,Q1D,Q1D, symmetric ? 6 : 9, NE);
231 mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
232 {
233 MFEM_FOREACH_THREAD(qx,x,Q1D)
234 {
235 MFEM_FOREACH_THREAD(qy,y,Q1D)
236 {
237 MFEM_FOREACH_THREAD(qz,z,Q1D)
238 {
239 const real_t J11 = J(qx,qy,qz,0,0,e);
240 const real_t J21 = J(qx,qy,qz,1,0,e);
241 const real_t J31 = J(qx,qy,qz,2,0,e);
242 const real_t J12 = J(qx,qy,qz,0,1,e);
243 const real_t J22 = J(qx,qy,qz,1,1,e);
244 const real_t J32 = J(qx,qy,qz,2,1,e);
245 const real_t J13 = J(qx,qy,qz,0,2,e);
246 const real_t J23 = J(qx,qy,qz,1,2,e);
247 const real_t J33 = J(qx,qy,qz,2,2,e);
248 const real_t detJ = J11 * (J22 * J33 - J32 * J23) -
249 J21 * (J12 * J33 - J32 * J13) +
250 J31 * (J12 * J23 - J22 * J13);
251 const real_t w_detJ = W(qx,qy,qz) / detJ;
252 // adj(J)
253 const real_t A11 = (J22 * J33) - (J23 * J32);
254 const real_t A12 = (J32 * J13) - (J12 * J33);
255 const real_t A13 = (J12 * J23) - (J22 * J13);
256 const real_t A21 = (J31 * J23) - (J21 * J33);
257 const real_t A22 = (J11 * J33) - (J13 * J31);
258 const real_t A23 = (J21 * J13) - (J11 * J23);
259 const real_t A31 = (J21 * J32) - (J31 * J22);
260 const real_t A32 = (J31 * J12) - (J11 * J32);
261 const real_t A33 = (J11 * J22) - (J12 * J21);
262
263 if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
264 {
265 // Compute entries of R = MJ^{-T} = M adj(J)^T, without det J.
266 const real_t M11 = C(0, qx,qy,qz, e);
267 const real_t M12 = C(1, qx,qy,qz, e);
268 const real_t M13 = C(2, qx,qy,qz, e);
269 const real_t M21 = (!symmetric) ? C(3, qx,qy,qz, e) : M12;
270 const real_t M22 = (!symmetric) ? C(4, qx,qy,qz, e) : C(3, qx,qy,qz, e);
271 const real_t M23 = (!symmetric) ? C(5, qx,qy,qz, e) : C(4, qx,qy,qz, e);
272 const real_t M31 = (!symmetric) ? C(6, qx,qy,qz, e) : M13;
273 const real_t M32 = (!symmetric) ? C(7, qx,qy,qz, e) : M23;
274 const real_t M33 = (!symmetric) ? C(8, qx,qy,qz, e) : C(5, qx,qy,qz, e);
275
276 const real_t R11 = M11*A11 + M12*A12 + M13*A13;
277 const real_t R12 = M11*A21 + M12*A22 + M13*A23;
278 const real_t R13 = M11*A31 + M12*A32 + M13*A33;
279 const real_t R21 = M21*A11 + M22*A12 + M23*A13;
280 const real_t R22 = M21*A21 + M22*A22 + M23*A23;
281 const real_t R23 = M21*A31 + M22*A32 + M23*A33;
282 const real_t R31 = M31*A11 + M32*A12 + M33*A13;
283 const real_t R32 = M31*A21 + M32*A22 + M33*A23;
284 const real_t R33 = M31*A31 + M32*A32 + M33*A33;
285
286 // Now set D to J^{-1} R = adj(J) R
287 D(qx,qy,qz,0,e) = w_detJ * (A11*R11 + A12*R21 + A13*R31); // 1,1
288 const real_t D12 = w_detJ * (A11*R12 + A12*R22 + A13*R32);
289 D(qx,qy,qz,1,e) = D12; // 1,2
290 D(qx,qy,qz,2,e) = w_detJ * (A11*R13 + A12*R23 + A13*R33); // 1,3
291
292 const real_t D22 = w_detJ * (A21*R12 + A22*R22 + A23*R32);
293 const real_t D23 = w_detJ * (A21*R13 + A22*R23 + A23*R33);
294
295 const real_t D33 = w_detJ * (A31*R13 + A32*R23 + A33*R33);
296
297 D(qx,qy,qz,4,e) = symmetric ? D23 : D22; // 2,3 or 2,2
298 D(qx,qy,qz,5,e) = symmetric ? D33 : D23; // 3,3 or 2,3
299
300 if (symmetric)
301 {
302 D(qx,qy,qz,3,e) = D22; // 2,2
303 }
304 else
305 {
306 D(qx,qy,qz,3,e) = w_detJ * (A21*R11 + A22*R21 + A23*R31); // 2,1
307 D(qx,qy,qz,6,e) = w_detJ * (A31*R11 + A32*R21 + A33*R31); // 3,1
308 D(qx,qy,qz,7,e) = w_detJ * (A31*R12 + A32*R22 + A33*R32); // 3,2
309 D(qx,qy,qz,8,e) = D33; // 3,3
310 }
311 }
312 else // Vector or scalar coefficient version
313 {
314 const real_t C1 = const_c ? C(0,0,0,0,0) : C(0,qx,qy,qz,e);
315 const real_t C2 = const_c ? C(0,0,0,0,0) :
316 (coeffDim == 3 ? C(1,qx,qy,qz,e) : C(0,qx,qy,qz,e));
317 const real_t C3 = const_c ? C(0,0,0,0,0) :
318 (coeffDim == 3 ? C(2,qx,qy,qz,e) : C(0,qx,qy,qz,e));
319
320 // detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
321 D(qx,qy,qz,0,e) = w_detJ * (C1*A11*A11 + C2*A12*A12 + C3*A13*A13); // 1,1
322 D(qx,qy,qz,1,e) = w_detJ * (C1*A11*A21 + C2*A12*A22 + C3*A13*A23); // 2,1
323 D(qx,qy,qz,2,e) = w_detJ * (C1*A11*A31 + C2*A12*A32 + C3*A13*A33); // 3,1
324 D(qx,qy,qz,3,e) = w_detJ * (C1*A21*A21 + C2*A22*A22 + C3*A23*A23); // 2,2
325 D(qx,qy,qz,4,e) = w_detJ * (C1*A21*A31 + C2*A22*A32 + C3*A23*A33); // 3,2
326 D(qx,qy,qz,5,e) = w_detJ * (C1*A31*A31 + C2*A32*A32 + C3*A33*A33); // 3,3
327 }
328 }
329 }
330 }
331 });
332}
333
334#ifdef MFEM_USE_OCCA
335void OccaPADiffusionSetup2D(const int D1D,
336 const int Q1D,
337 const int NE,
338 const Array<real_t> &W,
339 const Vector &J,
340 const Vector &C,
341 Vector &op)
342{
343 occa::properties props;
344 props["defines/D1D"] = D1D;
345 props["defines/Q1D"] = Q1D;
346 const occa::memory o_W = OccaMemoryRead(W.GetMemory(), W.Size());
347 const occa::memory o_J = OccaMemoryRead(J.GetMemory(), J.Size());
348 const occa::memory o_C = OccaMemoryRead(C.GetMemory(), C.Size());
349 occa::memory o_op = OccaMemoryWrite(op.GetMemory(), op.Size());
350 const bool const_c = C.Size() == 1;
351 const occa_id_t id = std::make_pair(D1D,Q1D);
352 static occa_kernel_t OccaDiffSetup2D_ker;
353 if (OccaDiffSetup2D_ker.find(id) == OccaDiffSetup2D_ker.end())
354 {
355 const occa::kernel DiffusionSetup2D =
356 mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
357 "DiffusionSetup2D", props);
358 OccaDiffSetup2D_ker.emplace(id, DiffusionSetup2D);
359 }
360 OccaDiffSetup2D_ker.at(id)(NE, o_W, o_J, o_C, o_op, const_c);
361}
362
363void OccaPADiffusionSetup3D(const int D1D,
364 const int Q1D,
365 const int NE,
366 const Array<real_t> &W,
367 const Vector &J,
368 const Vector &C,
369 Vector &op)
370{
371 occa::properties props;
372 props["defines/D1D"] = D1D;
373 props["defines/Q1D"] = Q1D;
374 const occa::memory o_W = OccaMemoryRead(W.GetMemory(), W.Size());
375 const occa::memory o_J = OccaMemoryRead(J.GetMemory(), J.Size());
376 const occa::memory o_C = OccaMemoryRead(C.GetMemory(), C.Size());
377 occa::memory o_op = OccaMemoryWrite(op.GetMemory(), op.Size());
378 const bool const_c = C.Size() == 1;
379 const occa_id_t id = std::make_pair(D1D,Q1D);
380 static occa_kernel_t OccaDiffSetup3D_ker;
381 if (OccaDiffSetup3D_ker.find(id) == OccaDiffSetup3D_ker.end())
382 {
383 const occa::kernel DiffusionSetup3D =
384 mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
385 "DiffusionSetup3D", props);
386 OccaDiffSetup3D_ker.emplace(id, DiffusionSetup3D);
387 }
388 OccaDiffSetup3D_ker.at(id)(NE, o_W, o_J, o_C, o_op, const_c);
389}
390
391void OccaPADiffusionApply2D(const int D1D,
392 const int Q1D,
393 const int NE,
394 const Array<real_t> &B,
395 const Array<real_t> &G,
396 const Array<real_t> &Bt,
397 const Array<real_t> &Gt,
398 const Vector &D,
399 const Vector &X,
400 Vector &Y)
401{
402 occa::properties props;
403 props["defines/D1D"] = D1D;
404 props["defines/Q1D"] = Q1D;
405 const occa::memory o_B = OccaMemoryRead(B.GetMemory(), B.Size());
406 const occa::memory o_G = OccaMemoryRead(G.GetMemory(), G.Size());
407 const occa::memory o_Bt = OccaMemoryRead(Bt.GetMemory(), Bt.Size());
408 const occa::memory o_Gt = OccaMemoryRead(Gt.GetMemory(), Gt.Size());
409 const occa::memory o_D = OccaMemoryRead(D.GetMemory(), D.Size());
410 const occa::memory o_X = OccaMemoryRead(X.GetMemory(), X.Size());
411 occa::memory o_Y = OccaMemoryReadWrite(Y.GetMemory(), Y.Size());
412 const occa_id_t id = std::make_pair(D1D,Q1D);
413 if (!Device::Allows(Backend::OCCA_CUDA))
414 {
415 static occa_kernel_t OccaDiffApply2D_cpu;
416 if (OccaDiffApply2D_cpu.find(id) == OccaDiffApply2D_cpu.end())
417 {
418 const occa::kernel DiffusionApply2D_CPU =
419 mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
420 "DiffusionApply2D_CPU", props);
421 OccaDiffApply2D_cpu.emplace(id, DiffusionApply2D_CPU);
422 }
423 OccaDiffApply2D_cpu.at(id)(NE, o_B, o_G, o_Bt, o_Gt, o_D, o_X, o_Y);
424 }
425 else
426 {
427 static occa_kernel_t OccaDiffApply2D_gpu;
428 if (OccaDiffApply2D_gpu.find(id) == OccaDiffApply2D_gpu.end())
429 {
430 const occa::kernel DiffusionApply2D_GPU =
431 mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
432 "DiffusionApply2D_GPU", props);
433 OccaDiffApply2D_gpu.emplace(id, DiffusionApply2D_GPU);
434 }
435 OccaDiffApply2D_gpu.at(id)(NE, o_B, o_G, o_Bt, o_Gt, o_D, o_X, o_Y);
436 }
437}
438
439void OccaPADiffusionApply3D(const int D1D,
440 const int Q1D,
441 const int NE,
442 const Array<real_t> &B,
443 const Array<real_t> &G,
444 const Array<real_t> &Bt,
445 const Array<real_t> &Gt,
446 const Vector &D,
447 const Vector &X,
448 Vector &Y)
449{
450 occa::properties props;
451 props["defines/D1D"] = D1D;
452 props["defines/Q1D"] = Q1D;
453 const occa::memory o_B = OccaMemoryRead(B.GetMemory(), B.Size());
454 const occa::memory o_G = OccaMemoryRead(G.GetMemory(), G.Size());
455 const occa::memory o_Bt = OccaMemoryRead(Bt.GetMemory(), Bt.Size());
456 const occa::memory o_Gt = OccaMemoryRead(Gt.GetMemory(), Gt.Size());
457 const occa::memory o_D = OccaMemoryRead(D.GetMemory(), D.Size());
458 const occa::memory o_X = OccaMemoryRead(X.GetMemory(), X.Size());
459 occa::memory o_Y = OccaMemoryReadWrite(Y.GetMemory(), Y.Size());
460 const occa_id_t id = std::make_pair(D1D,Q1D);
461 if (!Device::Allows(Backend::OCCA_CUDA))
462 {
463 static occa_kernel_t OccaDiffApply3D_cpu;
464 if (OccaDiffApply3D_cpu.find(id) == OccaDiffApply3D_cpu.end())
465 {
466 const occa::kernel DiffusionApply3D_CPU =
467 mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
468 "DiffusionApply3D_CPU", props);
469 OccaDiffApply3D_cpu.emplace(id, DiffusionApply3D_CPU);
470 }
471 OccaDiffApply3D_cpu.at(id)(NE, o_B, o_G, o_Bt, o_Gt, o_D, o_X, o_Y);
472 }
473 else
474 {
475 static occa_kernel_t OccaDiffApply3D_gpu;
476 if (OccaDiffApply3D_gpu.find(id) == OccaDiffApply3D_gpu.end())
477 {
478 const occa::kernel DiffusionApply3D_GPU =
479 mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
480 "DiffusionApply3D_GPU", props);
481 OccaDiffApply3D_gpu.emplace(id, DiffusionApply3D_GPU);
482 }
483 OccaDiffApply3D_gpu.at(id)(NE, o_B, o_G, o_Bt, o_Gt, o_D, o_X, o_Y);
484 }
485}
486#endif // MFEM_USE_OCCA
487
488} // namespace internal
489
490} // namespace mfem
static void AddSpecialization()
Vector data type.
Definition vector.hpp:82
const real_t alpha
Definition ex15.cpp:369
int dim
Definition ex24.cpp:53
constexpr int SDIM
constexpr int DIM
occa::memory OccaMemoryReadWrite(Memory< T > &mem, size_t size)
Wrap a Memory object as occa::memory for read-write access with the mfem::Device MemoryClass....
Definition occa.hpp:59
const T * Read(const Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for read access to mem with the mfem::Device's DeviceMemoryClass, if on_dev = true,...
Definition device.hpp:341
occa::memory OccaMemoryWrite(Memory< T > &mem, size_t size)
Wrap a Memory object as occa::memory for write only access with the mfem::Device MemoryClass....
Definition occa.hpp:48
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
Definition dtensor.hpp:131
void forall_2D(int N, int X, int Y, lambda &&body)
Definition forall.hpp:762
std::map< occa_id_t, occa::kernel > occa_kernel_t
Definition occa.hpp:79
void forall_3D(int N, int X, int Y, int Z, lambda &&body)
Definition forall.hpp:774
bool DeviceCanUseOcca()
Function that determines if an OCCA kernel should be used, based on the current mfem::Device configur...
Definition occa.hpp:69
float real_t
Definition config.hpp:43
const occa::memory OccaMemoryRead(const Memory< T > &mem, size_t size)
Wrap a Memory object as occa::memory for read only access with the mfem::Device MemoryClass....
Definition occa.hpp:37
occa::device & OccaDev()
Return the default occa::device used by MFEM.
Definition occa.cpp:27
std::pair< int, int > occa_id_t
Definition occa.hpp:78