MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
lor_dg_impl.hpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#pragma once
13
14#include "lor_dg.hpp"
18
19namespace mfem
20{
21
23{
24 Mesh &mesh = *fes_ho.GetMesh();
25 const Array<int> &bdr_face_attrs = mesh.GetBdrFaceAttributes();
26 const int nf = mesh.GetNumFaces();
27 Array<int> face_info(nf * 6); // (e0, f0, o0, e1, f1, o1)
28 auto h_face_info = Reshape(face_info.HostWrite(), 6, nf);
29
30 int bdr_face_counter = 0;
31
32 for (int f = 0; f < nf; ++f)
33 {
34 auto finfo = mesh.GetFaceInformation(f);
35 h_face_info(0, f) = finfo.element[0].index;
36 h_face_info(1, f) = finfo.element[0].local_face_id;
37 h_face_info(2, f) = finfo.element[0].orientation;
38 if (finfo.IsLocal()) // Interior, non-shared face
39 {
40 h_face_info(3, f) = finfo.element[1].index;
41 h_face_info(4, f) = finfo.element[1].local_face_id;
42 h_face_info(5, f) = finfo.element[1].orientation;
43 }
44 else
45 {
46 h_face_info(3, f) = -1;
47 h_face_info(4, f) = -1;
48 h_face_info(5, f) = -1;
49 }
50
51 if (finfo.IsBoundary())
52 {
53 // Check if Neumann boundary; skip these when adding boundary penalties
54 const int bdr_attr = bdr_face_attrs[bdr_face_counter];
55 if (!has_bdr_integ || (bdr_markers && !(*bdr_markers)[bdr_attr - 1]))
56 {
57 h_face_info(0, f) = -1;
58 h_face_info(1, f) = -1;
59 h_face_info(2, f) = -1;
60 }
61 bdr_face_counter += 1;
62 }
63 }
64 return face_info;
65}
66
68{
69 Mesh &mesh = *fes_ho.GetMesh();
70
71 const int nf = mesh.GetNumFaces();
74 {
75 int i_int = 0;
76 int i_bdr = 0;
77 for (int i = 0; i < nf; ++i)
78 {
79 const auto f = mesh.GetFaceInformation(i);
80 if (f.IsBoundary())
81 {
82 f_bdr[i_bdr] = i;
83 ++i_bdr;
84 }
85 else if (f.IsInterior())
86 {
87 f_int[i_int] = i;
88 ++i_int;
89 }
90 }
91 }
92
93 const auto geom = fes_ho.GetMesh()->GetGeometricFactors(
95
96 const int nq = ir_face.Size();
97 Vector face_Jh(nq * nf);
99 {
100 const int nft = mesh.GetNFbyType(ft);
101 auto *geom_face = mesh.GetFaceGeometricFactors(
103
104 const L2FaceValues fv = (ft == FaceType::Interior)
107 const int m = (fv == L2FaceValues::DoubleValued) ? 2 : 1;
108
110 Vector detJ_r(nq * m * nft);
111 r->Mult(geom->detJ, detJ_r);
112
113 const auto *d_i = (ft == FaceType::Interior) ? f_int.Read() : f_bdr.Read();
114 const auto d_detJ_face = Reshape(geom_face->detJ.Read(), nq, nft);
115 const auto d_detJ_r = Reshape(detJ_r.Read(), nq, m, nft);
116 auto d_face_Jh = Reshape(face_Jh.Write(), nq, nf);
117
118 mfem::forall(nft * nq, [=] MFEM_HOST_DEVICE (int ii)
119 {
120 const int i = ii % nq;
121 const int f = ii / nq;
122 const real_t J_el = 0.5*(d_detJ_r(i, 0, f) + d_detJ_r(i, m==2?1:0, f));
123 const real_t J_f = d_detJ_face(i, f);
124 d_face_Jh(i, d_i[f]) = J_f * J_f / J_el;
125 });
126 }
127 return face_Jh;
128}
129
131{
132 Mesh &mesh = *fes_ho.GetMesh();
133
134 const int nnz_per_row = 1 + mesh.Dimension()*2;
135 const int pp1 = fes_ho.GetMaxElementOrder() + 1;
136 const int nel_ho = mesh.GetNE();
137 const int nf = mesh.GetNumFaces();
138 const int nd_face = ir_face.Size();
139 const int nd = ir.Size();
140 const int dim = mesh.Dimension();
141
142 Array<int> face_info = GetFaceInfo();
143 const auto d_face_info = Reshape(face_info.Read(), 6, nf);
144
145 Vector face_Jh = GetBdrPenaltyFactor();
146 const auto d_face_Jh = Reshape(face_Jh.Read(), nd_face, nf);
147
148 const auto *w_face = ir_face.GetWeights().Read();
149
150 // Penalty parameter (avoid capturing *this in lambda)
151 const real_t d_kappa = kappa;
152
153 // Get diffusion coefficient
154 const bool const_dq = c2.Size() == 1;
155 const auto DQ = const_dq?Reshape(c2.Read(),1,1):Reshape(c2.Read(),nd,nel_ho);
156
157 // Sparse matrix entries
158 auto V = Reshape(sparse_ij.ReadWrite(), nnz_per_row, nd, nel_ho);
159
160 mfem::forall(nf, [=] MFEM_HOST_DEVICE (int f)
161 {
162 const int f_0 = d_face_info(1, f);
163 const int f_1 = d_face_info(4, f);
164 if (f_0 < 0) { return; } // Skip Neumann boundary faces
165 const int nsides = (f_1 >= 0) ? 2 : 1;
166 for (int el_i = 0; el_i < nsides; ++el_i)
167 {
168 const int e = d_face_info(3*el_i, f);
169 const int o = d_face_info(3*el_i + 2, f);
170 const int v_idx = 1 + ((el_i == 0) ? f_0 : f_1);
171 for (int i = 0; i < nd_face; ++i)
172 {
173 const int ii = internal::FaceIdxToVolIdx(dim, i, pp1, f_0, f_1, el_i, o);
174 const real_t Jh = d_face_Jh(i, f);
175 const real_t dq = const_dq ? DQ(0,0) : DQ(ii, e);
176 V(v_idx, ii, e) = -dq*d_kappa*Jh*w_face[i];
177 }
178 }
179 });
180}
181
182template <int ORDER, int SDIM>
184{
185 MFEM_VERIFY(SDIM == 2, "Surface meshes not currently supported for LOR-DG.")
186
187 static constexpr int pp1 = ORDER + 1;
188 static constexpr int ndof_per_el = pp1*pp1;
189 static constexpr int nnz_per_row = 5;
190 const int nel_ho = fes_ho.GetNE();
191
192 // Get element geometric factors; calling before AssembleFaceTerms, since
193 // in AssembleFaceTerms, element Jacobian determinants are used, potentially
194 // saving recomputation.
195 const auto factors = GeometricFactors::DETERMINANTS |
197 const auto *geom = fes_ho.GetMesh()->GetGeometricFactors(ir, factors);
198
199 // Sparse matrix entries
200 sparse_ij.SetSize(nnz_per_row*ndof_per_el*nel_ho);
201 sparse_ij.UseDevice(true);
202 sparse_ij = 0.0;
203 auto V = Reshape(sparse_ij.ReadWrite(), nnz_per_row, pp1, pp1, nel_ho);
204
206
207 // Populate Gauss-Lobatto quadrature rule of size (p+1)
208 IntegrationRule ir_pp1;
210 Vector glx_pp1(pp1), glw_pp1(pp1);
211 for (int i = 0; i < pp1; ++i)
212 {
213 glx_pp1[i] = ir_pp1[i].x;
214 glw_pp1[i] = ir_pp1[i].weight;
215 }
216 const auto *x_pp1 = glx_pp1.Read();
217 const auto *w_1d = glw_pp1.Read();
218
219 // Get coefficients for mass and diffusion
220 const bool const_mq = c1.Size() == 1;
221 const auto MQ = const_mq
222 ? Reshape(c1.Read(), 1, 1, 1)
223 : Reshape(c1.Read(), pp1, pp1, nel_ho);
224 const bool const_dq = c2.Size() == 1;
225 const auto DQ = const_dq
226 ? Reshape(c2.Read(), 1, 1, 1)
227 : Reshape(c2.Read(), pp1, pp1, nel_ho);
228
229 const auto detJ = Reshape(geom->detJ.Read(), pp1, pp1, nel_ho);
230 const auto J = Reshape(geom->J.Read(), pp1, pp1, 2, 2, nel_ho);
231 const auto W = Reshape(ir.GetWeights().Read(), pp1, pp1);
232
233 mfem::forall(nel_ho, [=] MFEM_HOST_DEVICE (int iel_ho)
234 {
235 for (int iy = 0; iy < pp1; ++iy)
236 {
237 for (int ix = 0; ix < pp1; ++ix)
238 {
239 const real_t mq = const_mq ? MQ(0,0,0) : MQ(ix, iy, iel_ho);
240 const real_t dq = const_dq ? DQ(0,0,0) : DQ(ix, iy, iel_ho);
241
242 for (int n_idx = 0; n_idx < 2; ++n_idx)
243 {
244 for (int e_i = 0; e_i < 2; ++e_i)
245 {
246 const int i_0 = (n_idx == 0) ? ix + e_i : ix;
247 const int j_0 = (n_idx == 1) ? iy + e_i : iy;
248
249 const bool bdr = (n_idx == 0 && (i_0 == 0 || i_0 == pp1)) ||
250 (n_idx == 1 && (j_0 == 0 || j_0 == pp1));
251
252 if (bdr) { continue; }
253
254 static constexpr int lex_map[] = {4, 2, 1, 3};
255 const int v_idx_lex = e_i + n_idx*2;
256 const int v_idx = lex_map[v_idx_lex];
257
258 const int w_idx = (n_idx == 0) ? iy : ix;
259 const int x_idx = (n_idx == 0) ? i_0 : j_0;
260
261 const real_t J1 = J(ix, iy, n_idx, !n_idx, iel_ho);
262 const real_t J2 = J(ix, iy, !n_idx, !n_idx, iel_ho);
263 const real_t Jh = (J1*J1 + J2*J2) / detJ(ix, iy, iel_ho);
264
265 V(v_idx, ix, iy, iel_ho) =
266 -dq * Jh * w_1d[w_idx] / (x_pp1[x_idx] - x_pp1[x_idx -1]);
267 }
268 }
269 V(0, ix, iy, iel_ho) = mq * detJ(ix, iy, iel_ho) * W(ix, iy);
270 for (int i = 1; i < nnz_per_row; ++i)
271 {
272 V(0, ix, iy, iel_ho) -= V(i, ix, iy, iel_ho);
273 }
274 }
275 }
276 });
277}
278
279template <int ORDER>
281{
282 static constexpr int pp1 = ORDER + 1;
283 static constexpr int ndof_per_el = pp1*pp1*pp1;
284 static constexpr int nnz_per_row = 7;
285 const int nel_ho = fes_ho.GetNE();
286
287 // Get element geometric factors; calling before AssembleFaceTerms, since
288 // in AssembleFaceTerms, element Jacobian determinants are used, potentially
289 // saving recomputation.
290 const auto factors = GeometricFactors::DETERMINANTS |
292 const auto geom = fes_ho.GetMesh()->GetGeometricFactors(ir, factors);
293
294 sparse_ij.SetSize(nnz_per_row*ndof_per_el*nel_ho);
295 sparse_ij.UseDevice(true);
296 sparse_ij = 0.0;
297 auto V = Reshape(sparse_ij.Write(), nnz_per_row, pp1, pp1, pp1, nel_ho);
298
300
301 // Populate Gauss-Lobatto quadrature rule of size (p+1)
302 IntegrationRule ir_pp1;
304 Vector glx_pp1(pp1), glw_pp1(pp1);
305 for (int i = 0; i < pp1; ++i)
306 {
307 glx_pp1[i] = ir_pp1[i].x;
308 glw_pp1[i] = ir_pp1[i].weight;
309 }
310 const auto *x_pp1 = glx_pp1.Read();
311 const auto *w_1d = glw_pp1.Read();
312
313 const bool const_mq = c1.Size() == 1;
314 const auto MQ = const_mq
315 ? Reshape(c1.Read(), 1, 1, 1, 1)
316 : Reshape(c1.Read(), pp1, pp1, pp1, nel_ho);
317 const bool const_dq = c2.Size() == 1;
318 const auto DQ = const_dq
319 ? Reshape(c2.Read(), 1, 1, 1, 1)
320 : Reshape(c2.Read(), pp1, pp1, pp1, nel_ho);
321 const auto W = Reshape(ir.GetWeights().Read(), pp1, pp1, pp1);
322
323 const auto detJ = Reshape(geom->detJ.Read(), pp1, pp1, pp1, nel_ho);
324 const auto J = Reshape(geom->J.Read(), pp1, pp1, pp1, 3, 3, nel_ho);
325
326 mfem::forall(nel_ho, [=] MFEM_HOST_DEVICE (int iel_ho)
327 {
328 for (int iz = 0; iz < pp1; ++iz)
329 {
330 for (int iy = 0; iy < pp1; ++iy)
331 {
332 for (int ix = 0; ix < pp1; ++ix)
333 {
334 const real_t mq = const_mq ? MQ(0,0,0,0) : MQ(ix, iy, iz, iel_ho);
335 const real_t dq = const_dq ? DQ(0,0,0,0) : DQ(ix, iy, iz, iel_ho);
336
337 const real_t DETJ = detJ(ix, iy, iz, iel_ho);
338
339 for (int n_idx = 0; n_idx < 3; ++n_idx)
340 {
341 for (int e_i = 0; e_i < 2; ++e_i)
342 {
343 static constexpr int lex_map[] = {5,3,2,4,1,6};
344 const int v_idx_lex = e_i + n_idx*2;
345 const int v_idx = lex_map[v_idx_lex];
346
347 const int i_0 = (n_idx == 0) ? ix + e_i : ix;
348 const int j_0 = (n_idx == 1) ? iy + e_i : iy;
349 const int k_0 = (n_idx == 2) ? iz + e_i : iz;
350
351 const bool bdr =
352 (n_idx == 0 && (i_0 == 0 || i_0 == pp1)) ||
353 (n_idx == 1 && (j_0 == 0 || j_0 == pp1)) ||
354 (n_idx == 2 && (k_0 == 0 || k_0 == pp1));
355
356 if (bdr) { continue; }
357
358 int x_idx = (n_idx == 0) ? i_0 : (n_idx == 1) ? j_0 : k_0;
359 int w_idx_1 = (n_idx == 0) ? iy : (n_idx == 1) ? iz : ix;
360 int w_idx_2 = (n_idx == 0) ? iz : (n_idx == 1) ? ix : iy;
361
362 const real_t J00 = J(ix, iy, iz, 0, 0, iel_ho);
363 const real_t J01 = J(ix, iy, iz, 0, 1, iel_ho);
364 const real_t J02 = J(ix, iy, iz, 0, 2, iel_ho);
365 const real_t J10 = J(ix, iy, iz, 1, 0, iel_ho);
366 const real_t J11 = J(ix, iy, iz, 1, 1, iel_ho);
367 const real_t J12 = J(ix, iy, iz, 1, 2, iel_ho);
368 const real_t J20 = J(ix, iy, iz, 2, 0, iel_ho);
369 const real_t J21 = J(ix, iy, iz, 2, 1, iel_ho);
370 const real_t J22 = J(ix, iy, iz, 2, 2, iel_ho);
371
372 real_t JinvJinvT_diag = 0.0;
373 if (n_idx == 0)
374 {
375 JinvJinvT_diag = J02*J02*(J11*J11 + J21*J21) + (J12*J21 - J11*J22)*
376 (J12*J21 - J11*J22) - 2*J01*J02*(J11*J12 + J21*J22) + J01*J01*
377 (J12*J12 + J22*J22);
378 }
379 else if (n_idx == 1)
380 {
381 JinvJinvT_diag = J02*J02*(J10*J10 + J20*J20) + (J12*J20 - J10*J22)*
382 (J12*J20 - J10*J22) - 2*J00*J02*(J10*J12 + J20*J22) + J00*J00*
383 (J12*J12 + J22*J22);
384 }
385 else if (n_idx == 2)
386 {
387 JinvJinvT_diag = J01*J01*(J10*J10 + J20*J20) + (J11*J20 - J10*J21)*
388 (J11*J20 - J10*J21) - 2*J00*J01*(J10*J11 + J20*J21) + J00*J00*
389 (J11*J11 + J21*J21);
390 }
391
392 const real_t Jh = JinvJinvT_diag / DETJ;
393
394 V(v_idx, ix, iy, iz, iel_ho) = -dq * Jh * w_1d[w_idx_1] * w_1d[w_idx_2] /
395 (x_pp1[x_idx] - x_pp1[x_idx -1]);
396 }
397 }
398 V(0, ix, iy, iz, iel_ho) = mq * DETJ * W(ix, iy, iz);
399 for (int i = 1; i < 7; ++i)
400 {
401 V(0, ix, iy, iz, iel_ho) -= V(i, ix, iy, iz, iel_ho);
402 }
403 }
404 }
405 }
406
407 });
408}
409
410} // namespace mfem
int Size() const
Return the logical size of the array.
Definition array.hpp:192
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
Definition array.hpp:410
T * HostWrite()
Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
Definition array.hpp:422
FiniteElementSpace & fes_ho
The associated high-order space.
CoefficientVector c2
Coefficient of second integrator.
Vector & sparse_ij
Local element sparsity matrix data.
CoefficientVector c1
Coefficient of first integrator.
IntegrationRule ir
Collocated integration rule.
Array< int > GetFaceInfo() const
Compute and return the face info array.
void AssembleFaceTerms()
Assemble the face penalty terms in the matrix sparse_ij.
Vector GetBdrPenaltyFactor() const
Compute and return the boundary penalty factor.
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:867
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:639
virtual int GetMaxElementOrder() const
Return the maximum polynomial order over all elements.
Definition fespace.hpp:669
virtual const FaceRestriction * GetFaceRestriction(ElementDofOrdering f_ordering, FaceType, L2FaceValues mul=L2FaceValues::DoubleValued) const
Return an Operator that converts L-vectors to E-vectors on each face.
Definition fespace.cpp:1509
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:96
const Array< real_t > & GetWeights() const
Return the quadrature weights in a contiguous array.
Definition intrules.cpp:98
Mesh data type.
Definition mesh.hpp:67
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition mesh.cpp:7302
virtual int GetNFbyType(FaceType type) const
Returns the number of faces according to the requested type, does not count master nonconforming face...
Definition mesh.cpp:7318
const FaceGeometricFactors * GetFaceGeometricFactors(const IntegrationRule &ir, const int flags, FaceType type, MemoryType d_mt=MemoryType::DEFAULT)
Return the mesh geometric factors for the faces corresponding to the given integration rule.
Definition mesh.cpp:978
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1390
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1314
FaceInformation GetFaceInformation(int f) const
Definition mesh.cpp:1368
const GeometricFactors * GetGeometricFactors(const IntegrationRule &ir, const int flags, MemoryType d_mt=MemoryType::DEFAULT)
Return the mesh geometric factors corresponding to the given integration rule.
Definition mesh.cpp:958
const Array< int > & GetBdrFaceAttributes() const
Returns the attributes for all boundary elements in this mesh.
Definition mesh.cpp:1000
static void GaussLobatto(const int np, IntegrationRule *ir)
Definition intrules.cpp:708
Vector data type.
Definition vector.hpp:82
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:520
virtual real_t * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:536
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Definition vector.hpp:145
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:633
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:528
int dim
Definition ex24.cpp:53
constexpr int SDIM
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
Definition dtensor.hpp:138
float real_t
Definition config.hpp:46
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
void forall(int N, lambda &&body)
Definition forall.hpp:1134
FaceType
Definition mesh.hpp:49
struct mfem::Mesh::FaceInformation::@15 element[2]
Information about the adjacent elements.