MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
qfunction.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#include "qfunction.hpp"
13#include "quadinterpolator.hpp"
15#include "../general/forall.hpp"
16#include "../mesh/pmesh.hpp"
17
18namespace mfem
19{
20
21QuadratureFunction &QuadratureFunction::operator=(real_t value)
22{
23 Vector::operator=(value);
24 return *this;
25}
26
27QuadratureFunction &QuadratureFunction::operator=(const Vector &v)
28{
29 MFEM_ASSERT(qspace && v.Size() == this->Size(), "");
31 return *this;
32}
33
34
35QuadratureFunction::QuadratureFunction(Mesh *mesh, std::istream &in)
36 : QuadratureFunction()
37{
38 const char *msg = "invalid input stream";
39 std::string ident;
40
41 qspace = new QuadratureSpace(mesh, in);
42 own_qspace = true;
43
44 in >> ident; MFEM_VERIFY(ident == "VDim:", msg);
45 in >> vdim;
46
47 Load(in, vdim*qspace->GetSize());
48}
49
50void QuadratureFunction::Save(std::ostream &os) const
51{
52 GetSpace()->Save(os);
53 os << "VDim: " << vdim << '\n'
54 << '\n';
55 Vector::Print(os, vdim);
56 os.flush();
57}
58
59void QuadratureFunction::ProjectGridFunctionFallback(const GridFunction &gf)
60{
61 if (gf.VectorDim() == 1)
62 {
63 GridFunctionCoefficient coeff(&gf);
64 coeff.Coefficient::Project(*this);
65 }
66 else
67 {
68 VectorGridFunctionCoefficient coeff(&gf);
69 coeff.VectorCoefficient::Project(*this);
70 }
71}
72
73void QuadratureFunction::ProjectGridFunction(const GridFunction &gf)
74{
75 SetVDim(gf.VectorDim());
76
77 if (auto *qs_elem = dynamic_cast<QuadratureSpace*>(qspace))
78 {
79 const FiniteElementSpace &gf_fes = *gf.FESpace();
80 const bool use_tensor_products = UsesTensorBasis(gf_fes);
81 const ElementDofOrdering ordering = use_tensor_products ?
82 ElementDofOrdering::LEXICOGRAPHIC :
83 ElementDofOrdering::NATIVE;
84
85 // Use quadrature interpolator to go from E-vector to Q-vector
86 const QuadratureInterpolator *qi =
87 gf_fes.GetQuadratureInterpolator(*qs_elem);
88
89 // If quadrature interpolator doesn't support this space, then fallback
90 // on slower (non-device) version, and return early.
91 if (!qi)
92 {
93 ProjectGridFunctionFallback(gf);
94 return;
95 }
96
97 // Use element restriction to go from L-vector to E-vector
98 const Operator *R = gf_fes.GetElementRestriction(ordering);
99 Vector e_vec(R->Height());
100 R->Mult(gf, e_vec);
101
102 qi->SetOutputLayout(QVectorLayout::byVDIM);
103 qi->DisableTensorProducts(!use_tensor_products);
104 qi->PhysValues(e_vec, *this);
105 }
106 else if (auto *qs_face = dynamic_cast<FaceQuadratureSpace*>(qspace))
107 {
108 const FiniteElementSpace &gf_fes = *gf.FESpace();
109 const FaceType face_type = qs_face->GetFaceType();
110 const bool use_tensor_products = UsesTensorBasis(gf_fes);
111 const ElementDofOrdering ordering = use_tensor_products ?
112 ElementDofOrdering::LEXICOGRAPHIC :
113 ElementDofOrdering::NATIVE;
114
115 // Use quadrature interpolator to go from E-vector to Q-vector
116 const FaceQuadratureInterpolator *qi =
117 gf_fes.GetFaceQuadratureInterpolator(qspace->GetIntRule(0), face_type);
118
119 // If quadrature interpolator doesn't support this space, then fallback
120 // on slower (non-device) version, and return early. Also, currently,
121 // ElementDofOrdering::NATIVE in FaceRestriction, so fall back in that
122 // case too.
123 if (qi == nullptr || ordering == ElementDofOrdering::NATIVE)
124 {
125 ProjectGridFunctionFallback(gf);
126 return;
127 }
128
129 // Use element restriction to go from L-vector to E-vector
130 const Operator *R = gf_fes.GetFaceRestriction(
131 ordering, face_type, L2FaceValues::SingleValued);
132 Vector e_vec(R->Height());
133 R->Mult(gf, e_vec);
134
135 qi->SetOutputLayout(QVectorLayout::byVDIM);
136 qi->DisableTensorProducts(!use_tensor_products);
137 qi->Values(e_vec, *this);
138 }
139 else
140 {
141 // This branch should be unreachable
142 MFEM_ABORT("Unsupported case.");
143 }
144}
145
146std::ostream &operator<<(std::ostream &os, const QuadratureFunction &qf)
147{
148 qf.Save(os);
149 return os;
150}
151
152void QuadratureFunction::SaveVTU(std::ostream &os, VTKFormat format,
153 int compression_level,
154 const std::string &field_name) const
155{
156 os << R"(<VTKFile type="UnstructuredGrid" version="2.2")";
157 if (compression_level != 0)
158 {
159 os << R"( compressor="vtkZLibDataCompressor")";
160 }
161 os << " byte_order=\"" << VTKByteOrder() << "\">\n";
162 os << "<UnstructuredGrid>\n";
163
164 const char *fmt_str = (format == VTKFormat::ASCII) ? "ascii" : "binary";
165 const char *type_str = (format != VTKFormat::BINARY32) ? "Float64" : "Float32";
166 std::vector<char> buf;
167
168 const int np = qspace->GetSize();
169 const int ne = qspace->GetNE();
170 const int sdim = qspace->GetMesh()->SpaceDimension();
171
172 // For quadrature functions, each point is a vertex cell, so number of cells
173 // is equal to number of points
174 os << "<Piece NumberOfPoints=\"" << np
175 << "\" NumberOfCells=\"" << np << "\">\n";
176
177 // print out the points
178 os << "<Points>\n";
179 os << "<DataArray type=\"" << type_str
180 << "\" NumberOfComponents=\"3\" format=\"" << fmt_str << "\">\n";
181
182 Vector pt(sdim);
183 for (int i = 0; i < ne; i++)
184 {
185 ElementTransformation &T = *qspace->GetTransformation(i);
186 const IntegrationRule &ir = GetIntRule(i);
187 for (int j = 0; j < ir.Size(); j++)
188 {
189 T.Transform(ir[j], pt);
190 WriteBinaryOrASCII(os, buf, pt[0], " ", format);
191 if (sdim > 1) { WriteBinaryOrASCII(os, buf, pt[1], " ", format); }
192 else { WriteBinaryOrASCII(os, buf, 0.0, " ", format); }
193 if (sdim > 2) { WriteBinaryOrASCII(os, buf, pt[2], "", format); }
194 else { WriteBinaryOrASCII(os, buf, 0.0, "", format); }
195 if (format == VTKFormat::ASCII) { os << '\n'; }
196 }
197 }
198 if (format != VTKFormat::ASCII)
199 {
200 WriteBase64WithSizeAndClear(os, buf, compression_level);
201 }
202 os << "</DataArray>\n";
203 os << "</Points>\n";
204
205 // Write cells (each cell is just a vertex)
206 os << "<Cells>\n";
207 // Connectivity
208 os << R"(<DataArray type="Int32" Name="connectivity" format=")"
209 << fmt_str << "\">\n";
210
211 for (int i=0; i<np; ++i) { WriteBinaryOrASCII(os, buf, i, "\n", format); }
212 if (format != VTKFormat::ASCII)
213 {
214 WriteBase64WithSizeAndClear(os, buf, compression_level);
215 }
216 os << "</DataArray>\n";
217 // Offsets
218 os << R"(<DataArray type="Int32" Name="offsets" format=")"
219 << fmt_str << "\">\n";
220 for (int i=0; i<np; ++i) { WriteBinaryOrASCII(os, buf, i, "\n", format); }
221 if (format != VTKFormat::ASCII)
222 {
223 WriteBase64WithSizeAndClear(os, buf, compression_level);
224 }
225 os << "</DataArray>\n";
226 // Types
227 os << R"(<DataArray type="UInt8" Name="types" format=")"
228 << fmt_str << "\">\n";
229 for (int i = 0; i < np; i++)
230 {
231 uint8_t vtk_cell_type = VTKGeometry::POINT;
232 WriteBinaryOrASCII(os, buf, vtk_cell_type, "\n", format);
233 }
234 if (format != VTKFormat::ASCII)
235 {
236 WriteBase64WithSizeAndClear(os, buf, compression_level);
237 }
238 os << "</DataArray>\n";
239 os << "</Cells>\n";
240
241 os << "<PointData>\n";
242 os << "<DataArray type=\"" << type_str << "\" Name=\"" << field_name
243 << "\" format=\"" << fmt_str << "\" NumberOfComponents=\"" << vdim << "\" "
244 << VTKComponentLabels(vdim) << " "
245 << ">\n";
246 for (int i = 0; i < ne; i++)
247 {
248 DenseMatrix vals;
249 GetValues(i, vals);
250 for (int j = 0; j < vals.Size(); ++j)
251 {
252 for (int vd = 0; vd < vdim; ++vd)
253 {
254 WriteBinaryOrASCII(os, buf, vals(vd, j), " ", format);
255 }
256 if (format == VTKFormat::ASCII) { os << '\n'; }
257 }
258 }
259 if (format != VTKFormat::ASCII)
260 {
261 WriteBase64WithSizeAndClear(os, buf, compression_level);
262 }
263 os << "</DataArray>\n";
264 os << "</PointData>\n";
265
266 os << "</Piece>\n";
267 os << "</UnstructuredGrid>\n";
268 os << "</VTKFile>" << std::endl;
269}
270
271void QuadratureFunction::SaveVTU(const std::string &filename, VTKFormat format,
272 int compression_level,
273 const std::string &field_name) const
274{
275 std::ofstream f(filename + ".vtu");
276 SaveVTU(f, format, compression_level, field_name);
277}
278
279static real_t ReduceReal(const Mesh *mesh, real_t value)
280{
281#ifdef MFEM_USE_MPI
282 if (auto *pmesh = dynamic_cast<const ParMesh*>(mesh))
283 {
284 MPI_Comm comm = pmesh->GetComm();
285 MPI_Allreduce(MPI_IN_PLACE, &value, 1, MPITypeMap<real_t>::mpi_type,
286 MPI_SUM, comm);
287 }
288#endif
289 return value;
290}
291
292real_t QuadratureFunction::Integrate() const
293{
294 MFEM_VERIFY(vdim == 1, "Only scalar functions are supported.")
295 const real_t local_integral = InnerProduct(*this, qspace->GetWeights());
296 return ReduceReal(qspace->GetMesh(), local_integral);
297}
298
299void QuadratureFunction::Integrate(Vector &integrals) const
300{
301 integrals.SetSize(vdim);
302
303 const Vector &weights = qspace->GetWeights();
304 QuadratureFunction component(qspace);
305 const int N = component.Size();
306 const int VDIM = vdim; // avoid capturing 'this' in lambda body
307 const real_t *d_v = Read();
308
309 for (int vd = 0; vd < vdim; ++vd)
310 {
311 // Extract the component 'vd' into component.
312 real_t *d_c = component.Write();
313 mfem::forall(N, [=] MFEM_HOST_DEVICE (int i)
314 {
315 d_c[i] = d_v[vd + i*VDIM];
316 });
317 integrals[vd] = ReduceReal(qspace->GetMesh(),
318 InnerProduct(component, weights));
319 }
320}
321
322}
QuadratureFunction()
Default constructor, results in an empty vector.
Definition qfunction.hpp:34
QuadratureFunction & operator=(real_t value)
Set this equal to a constant value.
QuadratureSpaceBase * qspace
Associated QuadratureSpaceBase object.
Definition qfunction.hpp:26
Vector & operator=(const real_t *v)
Copy Size() entries from v.
Definition vector.cpp:197
ostream & operator<<(ostream &v, void(*f)(VisMan &))
Definition ex17.cpp:406
Mesh * GetMesh(int type)
Definition ex29.cpp:218
real_t f(const Vector &p)
mfem::real_t real_t
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:348
real_t InnerProduct(HypreParVector *x, HypreParVector *y)
Definition hypre.cpp:468
void WriteBase64WithSizeAndClear(std::ostream &os, std::vector< char > &buf, int compression_level)
Encode in base 64 (and potentially compress) the given data, write it to the output stream (with a he...
Definition vtk.cpp:654
bool UsesTensorBasis(const FiniteElementSpace &fes)
Return true if the mesh contains only one topology and the elements are tensor elements.
Definition fespace.hpp:1548
void WriteBinaryOrASCII(std::ostream &os, std::vector< char > &buf, const T &val, const char *suffix, VTKFormat format)
Write either ASCII data to the stream or binary data to the buffer depending on the given format.
Definition vtk.hpp:148
const char * VTKByteOrder()
Determine the byte order and return either "BigEndian" or "LittleEndian".
Definition vtk.cpp:602
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition fespace.hpp:47
void forall(int N, lambda &&body)
Definition forall.hpp:839
FaceType
Definition mesh.hpp:49
std::string VTKComponentLabels(int vdim)
Returns a string defining the component labels for vector-valued data arrays for use in XML VTU files...
Definition vtk.cpp:662