MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
lor_dg_impl.hpp
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
12#pragma once
13
14#include "lor_dg.hpp"
18
19namespace mfem
20{
21
23{
24 Mesh &mesh = *fes_ho.GetMesh();
25 const int nf = mesh.GetNumFaces();
26 Array<int> face_info(nf * 6); // (e0, f0, o0, e1, f1, o1)
27 auto h_face_info = Reshape(face_info.HostWrite(), 6, nf);
28 for (int f = 0; f < nf; ++f)
29 {
30 auto finfo = mesh.GetFaceInformation(f);
31 h_face_info(0, f) = finfo.element[0].index;
32 h_face_info(1, f) = finfo.element[0].local_face_id;
33 h_face_info(2, f) = finfo.element[0].orientation;
34 if (finfo.IsLocal()) // Interior, non-shared face
35 {
36 h_face_info(3, f) = finfo.element[1].index;
37 h_face_info(4, f) = finfo.element[1].local_face_id;
38 h_face_info(5, f) = finfo.element[1].orientation;
39 }
40 else
41 {
42 h_face_info(3, f) = -1;
43 h_face_info(4, f) = -1;
44 h_face_info(5, f) = -1;
45 }
46 }
47 return face_info;
48}
49
51{
52 Mesh &mesh = *fes_ho.GetMesh();
53
54 const int nf = mesh.GetNumFaces();
57 {
58 int i_int = 0;
59 int i_bdr = 0;
60 for (int i = 0; i < nf; ++i)
61 {
62 const auto f = mesh.GetFaceInformation(i);
63 if (f.IsBoundary())
64 {
65 f_bdr[i_bdr] = i;
66 ++i_bdr;
67 }
68 else if (f.IsInterior())
69 {
70 f_int[i_int] = i;
71 ++i_int;
72 }
73 }
74 }
75
76 const auto geom = fes_ho.GetMesh()->GetGeometricFactors(
78
79 const int nq = ir_face.Size();
80 Vector face_Jh(nq * nf);
82 {
83 const int nft = mesh.GetNFbyType(ft);
84 auto *geom_face = mesh.GetFaceGeometricFactors(
86
87 const L2FaceValues fv = (ft == FaceType::Interior)
90 const int m = (fv == L2FaceValues::DoubleValued) ? 2 : 1;
91
93 Vector detJ_r(nq * m * nft);
94 r->Mult(geom->detJ, detJ_r);
95
96 const auto *d_i = (ft == FaceType::Interior) ? f_int.Read() : f_bdr.Read();
97 const auto d_detJ_face = Reshape(geom_face->detJ.Read(), nq, nft);
98 const auto d_detJ_r = Reshape(detJ_r.Read(), nq, m, nft);
99 auto d_face_Jh = Reshape(face_Jh.Write(), nq, nf);
100
101 mfem::forall(nft * nq, [=] MFEM_HOST_DEVICE (int ii)
102 {
103 const int i = ii % nq;
104 const int f = ii / nq;
105 const real_t J_el = 0.5*(d_detJ_r(i, 0, f) + d_detJ_r(i, m==2?1:0, f));
106 const real_t J_f = d_detJ_face(i, f);
107 d_face_Jh(i, d_i[f]) = J_f * J_f / J_el;
108 });
109 }
110 return face_Jh;
111}
112
114{
115 Mesh &mesh = *fes_ho.GetMesh();
116
117 const int nnz_per_row = 1 + mesh.Dimension()*2;
118 const int pp1 = fes_ho.GetMaxElementOrder() + 1;
119 const int nel_ho = mesh.GetNE();
120 const int nf = mesh.GetNumFaces();
121 const int nd_face = ir_face.Size();
122 const int nd = ir.Size();
123 const int dim = mesh.Dimension();
124
125 Array<int> face_info = GetFaceInfo();
126 const auto d_face_info = Reshape(face_info.Read(), 6, nf);
127
128 Vector face_Jh = GetBdrPenaltyFactor();
129 const auto d_face_Jh = Reshape(face_Jh.Read(), nd_face, nf);
130
131 const auto *w_face = ir_face.GetWeights().Read();
132
133 // Penalty parameter (avoid capturing *this in lambda)
134 const real_t d_kappa = kappa;
135
136 // Get diffusion coefficient
137 const bool const_dq = c2.Size() == 1;
138 const auto DQ = const_dq?Reshape(c2.Read(),1,1):Reshape(c2.Read(),nd,nel_ho);
139
140 // Sparse matrix entries
141 auto V = Reshape(sparse_ij.ReadWrite(), nnz_per_row, nd, nel_ho);
142
143 mfem::forall(nf, [=] MFEM_HOST_DEVICE (int f)
144 {
145 const int f_0 = d_face_info(1, f);
146 const int f_1 = d_face_info(4, f);
147 const int nsides = (f_1 >= 0) ? 2 : 1;
148 for (int el_i = 0; el_i < nsides; ++el_i)
149 {
150 const int e = d_face_info(3*el_i, f);
151 const int o = d_face_info(3*el_i + 2, f);
152 const int v_idx = 1 + ((el_i == 0) ? f_0 : f_1);
153 for (int i = 0; i < nd_face; ++i)
154 {
155 const int ii = internal::FaceIdxToVolIdx(dim, i, pp1, f_0, f_1, el_i, o);
156 const real_t Jh = d_face_Jh(i, f);
157 const real_t dq = const_dq ? DQ(0,0) : DQ(ii, e);
158 V(v_idx, ii, e) = -dq*d_kappa*Jh*w_face[i];
159 }
160 }
161 });
162}
163
164template <int ORDER, int SDIM>
166{
167 MFEM_VERIFY(SDIM == 2, "Surface meshes not currently supported for LOR-DG.")
168
169 static constexpr int pp1 = ORDER + 1;
170 static constexpr int ndof_per_el = pp1*pp1;
171 static constexpr int nnz_per_row = 5;
172 const int nel_ho = fes_ho.GetNE();
173
174 // Get element geometric factors; calling before AssembleFaceTerms, since
175 // in AssembleFaceTerms, element Jacobian determinants are used, potentially
176 // saving recomputation.
177 const auto factors = GeometricFactors::DETERMINANTS |
179 const auto *geom = fes_ho.GetMesh()->GetGeometricFactors(ir, factors);
180
181 // Sparse matrix entries
182 sparse_ij.SetSize(nnz_per_row*ndof_per_el*nel_ho);
183 sparse_ij.UseDevice(true);
184 sparse_ij = 0.0;
185 auto V = Reshape(sparse_ij.ReadWrite(), nnz_per_row, pp1, pp1, nel_ho);
186
188
189 // Populate Gauss-Lobatto quadrature rule of size (p+1)
190 IntegrationRule ir_pp1;
192 Vector glx_pp1(pp1), glw_pp1(pp1);
193 for (int i = 0; i < pp1; ++i)
194 {
195 glx_pp1[i] = ir_pp1[i].x;
196 glw_pp1[i] = ir_pp1[i].weight;
197 }
198 const auto *x_pp1 = glx_pp1.Read();
199 const auto *w_1d = glw_pp1.Read();
200
201 // Get coefficients for mass and diffusion
202 const bool const_mq = c1.Size() == 1;
203 const auto MQ = const_mq
204 ? Reshape(c1.Read(), 1, 1, 1)
205 : Reshape(c1.Read(), pp1, pp1, nel_ho);
206 const bool const_dq = c2.Size() == 1;
207 const auto DQ = const_dq
208 ? Reshape(c2.Read(), 1, 1, 1)
209 : Reshape(c2.Read(), pp1, pp1, nel_ho);
210
211 const auto detJ = Reshape(geom->detJ.Read(), pp1, pp1, nel_ho);
212 const auto J = Reshape(geom->J.Read(), pp1, pp1, 2, 2, nel_ho);
213 const auto W = Reshape(ir.GetWeights().Read(), pp1, pp1);
214
215 mfem::forall(nel_ho, [=] MFEM_HOST_DEVICE (int iel_ho)
216 {
217 for (int iy = 0; iy < pp1; ++iy)
218 {
219 for (int ix = 0; ix < pp1; ++ix)
220 {
221 const real_t mq = const_mq ? MQ(0,0,0) : MQ(ix, iy, iel_ho);
222 const real_t dq = const_dq ? DQ(0,0,0) : DQ(ix, iy, iel_ho);
223
224 for (int n_idx = 0; n_idx < 2; ++n_idx)
225 {
226 for (int e_i = 0; e_i < 2; ++e_i)
227 {
228 const int i_0 = (n_idx == 0) ? ix + e_i : ix;
229 const int j_0 = (n_idx == 1) ? iy + e_i : iy;
230
231 const bool bdr = (n_idx == 0 && (i_0 == 0 || i_0 == pp1)) ||
232 (n_idx == 1 && (j_0 == 0 || j_0 == pp1));
233
234 if (bdr) { continue; }
235
236 static constexpr int lex_map[] = {4, 2, 1, 3};
237 const int v_idx_lex = e_i + n_idx*2;
238 const int v_idx = lex_map[v_idx_lex];
239
240 const int w_idx = (n_idx == 0) ? iy : ix;
241 const int x_idx = (n_idx == 0) ? i_0 : j_0;
242
243 const real_t J1 = J(ix, iy, n_idx, !n_idx, iel_ho);
244 const real_t J2 = J(ix, iy, !n_idx, !n_idx, iel_ho);
245 const real_t Jh = (J1*J1 + J2*J2) / detJ(ix, iy, iel_ho);
246
247 V(v_idx, ix, iy, iel_ho) =
248 -dq * Jh * w_1d[w_idx] / (x_pp1[x_idx] - x_pp1[x_idx -1]);
249 }
250 }
251 V(0, ix, iy, iel_ho) = mq * detJ(ix, iy, iel_ho) * W(ix, iy);
252 for (int i = 1; i < nnz_per_row; ++i)
253 {
254 V(0, ix, iy, iel_ho) -= V(i, ix, iy, iel_ho);
255 }
256 }
257 }
258 });
259}
260
261template <int ORDER>
263{
264 static constexpr int pp1 = ORDER + 1;
265 static constexpr int ndof_per_el = pp1*pp1*pp1;
266 static constexpr int nnz_per_row = 7;
267 const int nel_ho = fes_ho.GetNE();
268
269 // Get element geometric factors; calling before AssembleFaceTerms, since
270 // in AssembleFaceTerms, element Jacobian determinants are used, potentially
271 // saving recomputation.
272 const auto factors = GeometricFactors::DETERMINANTS |
274 const auto geom = fes_ho.GetMesh()->GetGeometricFactors(ir, factors);
275
276 sparse_ij.SetSize(nnz_per_row*ndof_per_el*nel_ho);
277 sparse_ij.UseDevice(true);
278 sparse_ij = 0.0;
279 auto V = Reshape(sparse_ij.Write(), nnz_per_row, pp1, pp1, pp1, nel_ho);
280
282
283 // Populate Gauss-Lobatto quadrature rule of size (p+1)
284 IntegrationRule ir_pp1;
286 Vector glx_pp1(pp1), glw_pp1(pp1);
287 for (int i = 0; i < pp1; ++i)
288 {
289 glx_pp1[i] = ir_pp1[i].x;
290 glw_pp1[i] = ir_pp1[i].weight;
291 }
292 const auto *x_pp1 = glx_pp1.Read();
293 const auto *w_1d = glw_pp1.Read();
294
295 const bool const_mq = c1.Size() == 1;
296 const auto MQ = const_mq
297 ? Reshape(c1.Read(), 1, 1, 1, 1)
298 : Reshape(c1.Read(), pp1, pp1, pp1, nel_ho);
299 const bool const_dq = c2.Size() == 1;
300 const auto DQ = const_dq
301 ? Reshape(c2.Read(), 1, 1, 1, 1)
302 : Reshape(c2.Read(), pp1, pp1, pp1, nel_ho);
303 const auto W = Reshape(ir.GetWeights().Read(), pp1, pp1, pp1);
304
305 const auto detJ = Reshape(geom->detJ.Read(), pp1, pp1, pp1, nel_ho);
306 const auto J = Reshape(geom->J.Read(), pp1, pp1, pp1, 3, 3, nel_ho);
307
308 mfem::forall(nel_ho, [=] MFEM_HOST_DEVICE (int iel_ho)
309 {
310 for (int iz = 0; iz < pp1; ++iz)
311 {
312 for (int iy = 0; iy < pp1; ++iy)
313 {
314 for (int ix = 0; ix < pp1; ++ix)
315 {
316 const real_t mq = const_mq ? MQ(0,0,0,0) : MQ(ix, iy, iz, iel_ho);
317 const real_t dq = const_dq ? DQ(0,0,0,0) : DQ(ix, iy, iz, iel_ho);
318
319 const real_t DETJ = detJ(ix, iy, iz, iel_ho);
320
321 for (int n_idx = 0; n_idx < 3; ++n_idx)
322 {
323 for (int e_i = 0; e_i < 2; ++e_i)
324 {
325 static constexpr int lex_map[] = {5,3,2,4,1,6};
326 const int v_idx_lex = e_i + n_idx*2;
327 const int v_idx = lex_map[v_idx_lex];
328
329 const int i_0 = (n_idx == 0) ? ix + e_i : ix;
330 const int j_0 = (n_idx == 1) ? iy + e_i : iy;
331 const int k_0 = (n_idx == 2) ? iz + e_i : iz;
332
333 const bool bdr =
334 (n_idx == 0 && (i_0 == 0 || i_0 == pp1)) ||
335 (n_idx == 1 && (j_0 == 0 || j_0 == pp1)) ||
336 (n_idx == 2 && (k_0 == 0 || k_0 == pp1));
337
338 if (bdr) { continue; }
339
340 int x_idx = (n_idx == 0) ? i_0 : (n_idx == 1) ? j_0 : k_0;
341 int w_idx_1 = (n_idx == 0) ? iy : (n_idx == 1) ? iz : ix;
342 int w_idx_2 = (n_idx == 0) ? iz : (n_idx == 1) ? ix : iy;
343
344 const real_t J00 = J(ix, iy, iz, 0, 0, iel_ho);
345 const real_t J01 = J(ix, iy, iz, 0, 1, iel_ho);
346 const real_t J02 = J(ix, iy, iz, 0, 2, iel_ho);
347 const real_t J10 = J(ix, iy, iz, 1, 0, iel_ho);
348 const real_t J11 = J(ix, iy, iz, 1, 1, iel_ho);
349 const real_t J12 = J(ix, iy, iz, 1, 2, iel_ho);
350 const real_t J20 = J(ix, iy, iz, 2, 0, iel_ho);
351 const real_t J21 = J(ix, iy, iz, 2, 1, iel_ho);
352 const real_t J22 = J(ix, iy, iz, 2, 2, iel_ho);
353
354 real_t JinvJinvT_diag = 0.0;
355 if (n_idx == 0)
356 {
357 JinvJinvT_diag = J02*J02*(J11*J11 + J21*J21) + (J12*J21 - J11*J22)*
358 (J12*J21 - J11*J22) - 2*J01*J02*(J11*J12 + J21*J22) + J01*J01*
359 (J12*J12 + J22*J22);
360 }
361 else if (n_idx == 1)
362 {
363 JinvJinvT_diag = J02*J02*(J10*J10 + J20*J20) + (J12*J20 - J10*J22)*
364 (J12*J20 - J10*J22) - 2*J00*J02*(J10*J12 + J20*J22) + J00*J00*
365 (J12*J12 + J22*J22);
366 }
367 else if (n_idx == 2)
368 {
369 JinvJinvT_diag = J01*J01*(J10*J10 + J20*J20) + (J11*J20 - J10*J21)*
370 (J11*J20 - J10*J21) - 2*J00*J01*(J10*J11 + J20*J21) + J00*J00*
371 (J11*J11 + J21*J21);
372 }
373
374 const real_t Jh = JinvJinvT_diag / DETJ;
375
376 V(v_idx, ix, iy, iz, iel_ho) = -dq * Jh * w_1d[w_idx_1] * w_1d[w_idx_2] /
377 (x_pp1[x_idx] - x_pp1[x_idx -1]);
378 }
379 }
380 V(0, ix, iy, iz, iel_ho) = mq * DETJ * W(ix, iy, iz);
381 for (int i = 1; i < 7; ++i)
382 {
383 V(0, ix, iy, iz, iel_ho) -= V(i, ix, iy, iz, iel_ho);
384 }
385 }
386 }
387 }
388
389 });
390}
391
392} // namespace mfem
int Size() const
Return the logical size of the array.
Definition array.hpp:166
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
Definition array.hpp:381
T * HostWrite()
Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
Definition array.hpp:393
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:869
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:644
virtual int GetMaxElementOrder() const
Return the maximum polynomial order over all elements.
Definition fespace.hpp:674
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:1513
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
const Array< real_t > & GetWeights() const
Return the quadrature weights in a contiguous array.
Definition intrules.cpp:86
Mesh data type.
Definition mesh.hpp:65
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition mesh.cpp:6846
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:6862
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:903
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1377
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1306
FaceInformation GetFaceInformation(int f) const
Definition mesh.cpp:1293
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:883
static void GaussLobatto(const int np, IntegrationRule *ir)
Definition intrules.cpp:512
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:584
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:839
FaceType
Definition mesh.hpp:49
struct mfem::Mesh::FaceInformation::@15 element[2]