MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
linearform.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
12// Implementation of class LinearForm
13
14#include "fem.hpp"
15
16namespace mfem
17{
18
20 : Vector(f->GetVSize())
21{
22 ext = nullptr;
23 extern_lfs = 1;
24 fast_assembly = false;
25 fes = f;
26
27 // Linear forms are stored on the device
28 UseDevice(true);
29
30 // Copy the pointers to the integrators and the corresponding marker arrays
33
35
38
41
43}
44
46{
47 DeltaLFIntegrator *maybe_delta =
48 dynamic_cast<DeltaLFIntegrator *>(lfi);
49 if (!maybe_delta || !maybe_delta->IsDelta())
50 {
51 domain_integs.Append(lfi);
52 }
53 else
54 {
55 domain_delta_integs.Append(maybe_delta);
56 }
57 domain_integs_marker.Append(NULL);
58}
59
61 Array<int> &elem_marker)
62{
63 DeltaLFIntegrator *maybe_delta =
64 dynamic_cast<DeltaLFIntegrator *>(lfi);
65 if (!maybe_delta || !maybe_delta->IsDelta())
66 {
67 domain_integs.Append(lfi);
68 }
69 else
70 {
71 domain_delta_integs.Append(maybe_delta);
72 }
73 domain_integs_marker.Append(&elem_marker);
74}
75
77{
78 boundary_integs.Append (lfi);
79 boundary_integs_marker.Append(NULL); // NULL -> all attributes are active
80}
81
83 Array<int> &bdr_attr_marker)
84{
85 boundary_integs.Append (lfi);
86 boundary_integs_marker.Append(&bdr_attr_marker);
87}
88
90{
91 boundary_face_integs.Append(lfi);
92 // NULL -> all attributes are active
93 boundary_face_integs_marker.Append(NULL);
94}
95
97 Array<int> &bdr_attr_marker)
98{
99 boundary_face_integs.Append(lfi);
100 boundary_face_integs_marker.Append(&bdr_attr_marker);
101}
102
107
109{
110 // return false for NURBS meshes, so we don’t convert it to non-NURBS
111 // through Assemble, AssembleDevice, GetGeometricFactors and EnsureNodes
112 const Mesh &mesh = *fes->GetMesh();
113 if (mesh.NURBSext != nullptr) { return false; }
114
115 // scan integrators to verify that all can use device assembly
116 auto IntegratorsSupportDevice = [](const Array<LinearFormIntegrator*> &integ)
117 {
118 for (int k = 0; k < integ.Size(); k++)
119 {
120 if (!integ[k]->SupportsDevice()) { return false; }
121 }
122 return true;
123 };
124
125 if (!IntegratorsSupportDevice(domain_integs)) { return false; }
126 if (!IntegratorsSupportDevice(boundary_integs)) { return false; }
127 if (boundary_face_integs.Size() > 0 || interior_face_integs.Size() > 0 ||
128 domain_delta_integs.Size() > 0) { return false; }
129
130 if (boundary_integs.Size() > 0)
131 {
132 // Make sure there are no boundary faces that are not boundary elements
134 {
135 return false;
136 }
137 // Make sure every boundary element corresponds to a boundary face
138 for (int be = 0; be < fes->GetNBE(); ++be)
139 {
140 const int f = mesh.GetBdrElementFaceIndex(be);
141 const auto face_info = mesh.GetFaceInformation(f);
142 if (!face_info.IsBoundary())
143 {
144 return false;
145 }
146 }
147 }
148
149 // no support for elements with varying polynomial orders
150 if (fes->IsVariableOrder()) { return false; }
151
152 // no support for 1D and embedded meshes
153 const int mesh_dim = mesh.Dimension();
154 if (mesh_dim == 1 || mesh_dim != mesh.SpaceDimension()) { return false; }
155
156 // tensor-product finite element space only
157 if (!UsesTensorBasis(*fes)) { return false; }
158
159 return true;
160}
161
163{
164 fast_assembly = use_fa;
165
166 if (fast_assembly && SupportsDevice() && !ext)
167 {
168 ext = new LinearFormExtension(this);
169 }
170}
171
173{
174 Array<int> vdofs;
175 ElementTransformation *eltrans;
176 Vector elemvect;
177
179
180 // The above operation is executed on device because of UseDevice().
181 // The first use of AddElementVector() below will move it back to host
182 // because both 'vdofs' and 'elemvect' are on host.
183
184 if (fast_assembly && ext) { return ext->Assemble(); }
185
186 if (domain_integs.Size())
187 {
188 for (int k = 0; k < domain_integs.Size(); k++)
189 {
190 if (domain_integs_marker[k] != NULL)
191 {
192 MFEM_VERIFY(domain_integs_marker[k]->Size() ==
193 (fes->GetMesh()->attributes.Size() ?
194 fes->GetMesh()->attributes.Max() : 0),
195 "invalid element marker for domain linear form "
196 "integrator #" << k << ", counting from zero");
197 }
198 }
199
200 DofTransformation doftrans;
201 for (int i = 0; i < fes -> GetNE(); i++)
202 {
203 int elem_attr = fes->GetMesh()->GetAttribute(i);
204 for (int k = 0; k < domain_integs.Size(); k++)
205 {
206 const Array<int> * const markers = domain_integs_marker[k];
207 if (markers) { markers->HostRead(); }
208 if ( markers == NULL || (*markers)[elem_attr-1] == 1 )
209 {
210 fes -> GetElementVDofs (i, vdofs, doftrans);
211 eltrans = fes -> GetElementTransformation (i);
212 domain_integs[k]->AssembleRHSElementVect(*fes->GetFE(i),
213 *eltrans, elemvect);
214 doftrans.TransformDual(elemvect);
215 AddElementVector (vdofs, elemvect);
216 }
217 }
218 }
219 }
221
222 if (boundary_integs.Size())
223 {
224 Mesh *mesh = fes->GetMesh();
225
226 // Which boundary attributes need to be processed?
227 Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
228 mesh->bdr_attributes.Max() : 0);
229 bdr_attr_marker = 0;
230 for (int k = 0; k < boundary_integs.Size(); k++)
231 {
232 if (boundary_integs_marker[k] == NULL)
233 {
234 bdr_attr_marker = 1;
235 break;
236 }
237 Array<int> &bdr_marker = *boundary_integs_marker[k];
238 MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
239 "invalid boundary marker for boundary integrator #"
240 << k << ", counting from zero");
241 for (int i = 0; i < bdr_attr_marker.Size(); i++)
242 {
243 bdr_attr_marker[i] |= bdr_marker[i];
244 }
245 }
246
247 DofTransformation doftrans;
248 for (int i = 0; i < fes -> GetNBE(); i++)
249 {
250 const int bdr_attr = mesh->GetBdrAttribute(i);
251 if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
252 fes -> GetBdrElementVDofs (i, vdofs, doftrans);
253 eltrans = fes -> GetBdrElementTransformation (i);
254 for (int k=0; k < boundary_integs.Size(); k++)
255 {
256 if (boundary_integs_marker[k] &&
257 (*boundary_integs_marker[k])[bdr_attr-1] == 0) { continue; }
258
259 boundary_integs[k]->AssembleRHSElementVect(*fes->GetBE(i),
260 *eltrans, elemvect);
261 doftrans.TransformDual(elemvect);
262 AddElementVector (vdofs, elemvect);
263 }
264 }
265 }
266 if (boundary_face_integs.Size())
267 {
269 Mesh *mesh = fes->GetMesh();
270
271 // Which boundary attributes need to be processed?
272 Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
273 mesh->bdr_attributes.Max() : 0);
274 bdr_attr_marker = 0;
275 for (int k = 0; k < boundary_face_integs.Size(); k++)
276 {
277 if (boundary_face_integs_marker[k] == NULL)
278 {
279 bdr_attr_marker = 1;
280 break;
281 }
282 Array<int> &bdr_marker = *boundary_face_integs_marker[k];
283 MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
284 "invalid boundary marker for boundary face integrator #"
285 << k << ", counting from zero");
286 for (int i = 0; i < bdr_attr_marker.Size(); i++)
287 {
288 bdr_attr_marker[i] |= bdr_marker[i];
289 }
290 }
291
292 for (int i = 0; i < mesh->GetNBE(); i++)
293 {
294 const int bdr_attr = mesh->GetBdrAttribute(i);
295 if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
296
297 tr = mesh->GetBdrFaceTransformations(i);
298 if (tr != NULL)
299 {
300 fes -> GetElementVDofs (tr -> Elem1No, vdofs);
301 for (int k = 0; k < boundary_face_integs.Size(); k++)
302 {
304 (*boundary_face_integs_marker[k])[bdr_attr-1] == 0)
305 { continue; }
306
308 AssembleRHSElementVect(*fes->GetFE(tr->Elem1No),
309 *tr, elemvect);
310 AddElementVector (vdofs, elemvect);
311 }
312 }
313 }
314 }
315
316 if (interior_face_integs.Size())
317 {
318 Mesh *mesh = fes->GetMesh();
319
320 for (int k = 0; k < interior_face_integs.Size(); k++)
321 {
322 for (int i = 0; i < mesh->GetNumFaces(); i++)
323 {
325 tr = mesh->GetInteriorFaceTransformations (i);
326 if (tr != NULL)
327 {
328 fes -> GetElementVDofs (tr -> Elem1No, vdofs);
329 Array<int> vdofs2;
330 fes -> GetElementVDofs (tr -> Elem2No, vdofs2);
331 vdofs.Append(vdofs2);
333 AssembleRHSElementVect(*fes->GetFE(tr->Elem1No),
334 *fes->GetFE(tr->Elem2No),
335 *tr, elemvect);
336 AddElementVector (vdofs, elemvect);
337 }
338 }
339 }
340 }
341}
342
344{
346 if (ext) { ext->Update(); }
347}
348
350{
351 MFEM_ASSERT(v.Size() >= v_offset + f->GetVSize(), "");
352 fes = f;
353 v.UseDevice(true);
354 this->Vector::MakeRef(v, v_offset, fes->GetVSize());
356 if (ext) { ext->Update(); }
357}
358
360{
361 Update(f, v, v_offset);
362}
363
365{
366 if (domain_delta_integs.Size() == 0) { return; }
367
368 if (!HaveDeltaLocations())
369 {
370 int sdim = fes->GetMesh()->SpaceDimension();
371 Vector center;
372 DenseMatrix centers(sdim, domain_delta_integs.Size());
373 for (int i = 0; i < centers.Width(); i++)
374 {
375 centers.GetColumnReference(i, center);
376 domain_delta_integs[i]->GetDeltaCenter(center);
377 MFEM_VERIFY(center.Size() == sdim,
378 "Point dim " << center.Size() <<
379 " does not match space dim " << sdim);
380 }
383 }
384
385 Array<int> vdofs;
386 Vector elemvect;
387 for (int i = 0; i < domain_delta_integs.Size(); i++)
388 {
389 int elem_id = domain_delta_integs_elem_id[i];
390 // The delta center may be outside of this sub-domain, or
391 // (Par)Mesh::FindPoints() failed to find this point:
392 if (elem_id < 0) { continue; }
393
396 Trans.SetIntPoint(&ip);
397
398 fes->GetElementVDofs(elem_id, vdofs);
399 domain_delta_integs[i]->AssembleDeltaElementVect(*fes->GetFE(elem_id),
400 Trans, elemvect);
401 AddElementVector(vdofs, elemvect);
402 }
403}
404
406{
407 Vector::operator=(value);
408 return *this;
409}
410
412{
413 MFEM_ASSERT(fes && v.Size() == fes->GetVSize(), "");
415 return *this;
416}
417
419{
420 if (!extern_lfs)
421 {
422 int k;
423 for (k=0; k < domain_delta_integs.Size(); k++)
424 { delete domain_delta_integs[k]; }
425 for (k=0; k < domain_integs.Size(); k++) { delete domain_integs[k]; }
426 for (k=0; k < boundary_integs.Size(); k++) { delete boundary_integs[k]; }
427 for (k=0; k < boundary_face_integs.Size(); k++)
428 { delete boundary_face_integs[k]; }
429 for (k=0; k < interior_face_integs.Size(); k++)
430 { delete interior_face_integs[k]; }
431 }
432
433 delete ext;
434}
435
436}
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:69
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition array.hpp:385
int Size() const
Return the logical size of the array.
Definition array.hpp:166
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:912
Abstract class for integrators that support delta coefficients.
Definition lininteg.hpp:62
bool IsDelta() const
Returns true if the derived class instance uses a delta coefficient.
Definition lininteg.hpp:84
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
void GetColumnReference(int c, Vector &col)
Definition densemat.hpp:331
void TransformDual(real_t *v) const
Definition doftrans.cpp:77
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition eltrans.hpp:106
A specialized ElementTransformation class representing a face and its two neighboring elements.
Definition eltrans.hpp:750
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:208
bool IsVariableOrder() const
Returns true if the space contains elements of varying polynomial orders.
Definition fespace.hpp:678
const FiniteElement * GetBE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th boundary fac...
Definition fespace.cpp:3870
ElementTransformation * GetElementTransformation(int i) const
Definition fespace.hpp:905
int GetNBE() const
Returns number of boundary elements in the mesh.
Definition fespace.hpp:878
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for the i'th element. The returned indices are offsets into an ...
Definition fespace.cpp:304
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Definition fespace.cpp:3824
int GetNFbyType(FaceType type) const
Returns the number of faces according to the requested type.
Definition fespace.hpp:886
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:644
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:826
Class for integration point with weight.
Definition intrules.hpp:35
Class extending the LinearForm class to support assembly on devices.
void Update()
Update the linear form extension.
Abstract base class LinearFormIntegrator.
Definition lininteg.hpp:28
Vector with associated FE space and LinearFormIntegrators.
void AddInteriorFaceIntegrator(LinearFormIntegrator *lfi)
Adds new Interior Face Integrator. Assumes ownership of lfi.
void AddDomainIntegrator(LinearFormIntegrator *lfi)
Adds new Domain Integrator. Assumes ownership of lfi.
Array< Array< int > * > boundary_face_integs_marker
Entries not owned.
void AssembleDelta()
Assembles delta functions of the linear form.
virtual void MakeRef(FiniteElementSpace *f, Vector &v, int v_offset)
Make the LinearForm reference external data on a new FiniteElementSpace.
void AddBoundaryIntegrator(LinearFormIntegrator *lfi)
Adds new Boundary Integrator. Assumes ownership of lfi.
LinearForm()
Create an empty LinearForm without an associated FiniteElementSpace.
Array< LinearFormIntegrator * > boundary_face_integs
Set of Boundary Face Integrators to be applied.
void UseFastAssembly(bool use_fa)
Which assembly algorithm to use: the new device-compatible fast assembly (true), or the legacy CPU-on...
Array< int > domain_delta_integs_elem_id
The element ids where the centers of the delta functions lie.
virtual bool SupportsDevice() const
Return true if assembly on device is supported, false otherwise.
LinearForm & operator=(const LinearForm &rhs)
Copy assignment. Only the data of the base class Vector is copied.
Array< Array< int > * > boundary_integs_marker
Entries are not owned.
bool HaveDeltaLocations()
If true, the delta locations are not (re)computed during assembly.
FiniteElementSpace * fes
FE space on which the LinearForm lives. Not owned.
Array< Array< int > * > domain_integs_marker
Array< LinearFormIntegrator * > interior_face_integs
Set of Internal Face Integrators to be applied.
LinearFormExtension * ext
Extension for supporting different assembly levels.
void ResetDeltaLocations()
Force (re)computation of delta locations.
void Update()
Update the object according to the associated FE space fes.
Array< DeltaLFIntegrator * > domain_delta_integs
Separate array for integrators with delta function coefficients.
Array< LinearFormIntegrator * > domain_integs
Set of Domain Integrators to be applied.
~LinearForm()
Destroys linear form.
Array< IntegrationPoint > domain_delta_integs_ip
The reference coordinates where the centers of the delta functions lie.
Array< LinearFormIntegrator * > boundary_integs
Set of Boundary Integrators to be applied.
int extern_lfs
Indicates the LinearFormIntegrators stored in domain_integs, domain_delta_integs, boundary_integs,...
void AddBdrFaceIntegrator(LinearFormIntegrator *lfi)
Adds new Boundary Face Integrator. Assumes ownership of lfi.
void Assemble()
Assembles the linear form i.e. sums over all domain/bdr integrators.
bool fast_assembly
Should we use the device-compatible fast assembly algorithm (false by default)
Mesh data type.
Definition mesh.hpp:65
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:304
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition mesh.hpp:312
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition mesh.cpp:6846
int GetAttribute(int i) const
Return the attribute of element i.
Definition mesh.hpp:1484
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition mesh.hpp:1490
int GetBdrElementFaceIndex(int be_idx) const
Return the local face (codimension-1) index for the given boundary element index.
Definition mesh.hpp:1689
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
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1309
FaceElementTransformations * GetBdrFaceTransformations(int BdrElemNo)
Builds the transformation defining the given boundary face.
Definition mesh.cpp:1223
int GetNBE() const
Returns number of boundary elements.
Definition mesh.hpp:1380
virtual int FindPoints(DenseMatrix &point_mat, Array< int > &elem_ids, Array< IntegrationPoint > &ips, bool warn=true, InverseElementTransformation *inv_trans=NULL)
Find the ids of the elements that contain the given points, and their corresponding reference coordin...
Definition mesh.cpp:13800
FaceElementTransformations * GetInteriorFaceTransformations(int FaceNo)
See GetFaceElementTransformations().
Definition mesh.cpp:1203
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition mesh.hpp:302
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:72
Vector data type.
Definition vector.hpp:82
void AddElementVector(const Array< int > &dofs, const Vector &elemvect)
Add elements of the elemvect Vector to the entries listed in dofs. Negative dof values cause the -dof...
Definition vector.cpp:785
virtual bool UseDevice() const
Return the device flag of the Memory object used by the Vector.
Definition vector.hpp:148
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
Vector & operator=(const real_t *v)
Copy Size() entries from v.
Definition vector.cpp:197
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
Definition vector.hpp:660
bool UsesTensorBasis(const FiniteElementSpace &fes)
Return true if the mesh contains only one topology and the elements are tensor elements.
Definition fespace.hpp:1548
float real_t
Definition config.hpp:46
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30