Files
mfem/fem/qfunction.hpp
T
Veselin Dobrev 2d021685de Fix a bug in QuadratureFunction::GetValues when getting a reference to
the data for one mesh element as a DenseMatrix.

Added new methods:
- Array<T>::MakeRef(Memory<T> &base, int offset, int size_)
- DenseMatrix::MakeRef(Memory<real_t> &base, int offset, int h, int w)
2026-02-02 08:42:58 -08:00

325 lines
12 KiB
C++

// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_QFUNCTION
#define MFEM_QFUNCTION
#include "../config/config.hpp"
#include "qspace.hpp"
#include "gridfunc.hpp"
namespace mfem
{
/// Represents values or vectors of values at quadrature points on a mesh.
class QuadratureFunction : public Vector
{
protected:
QuadratureSpaceBase *qspace; ///< Associated QuadratureSpaceBase object.
bool own_qspace; ///< Does this own the associated QuadratureSpaceBase?
int vdim; ///< Vector dimension.
void ProjectGridFunctionFallback(const GridFunction &gf);
public:
/// Default constructor, results in an empty vector.
QuadratureFunction() : qspace(nullptr), own_qspace(false), vdim(0)
{ UseDevice(true); }
/// Create a QuadratureFunction based on the given QuadratureSpaceBase.
/** The QuadratureFunction does not assume ownership of the
QuadratureSpaceBase.
@note The Vector data is not initialized. */
QuadratureFunction(QuadratureSpaceBase &qspace_, int vdim_ = 1)
: Vector(vdim_*qspace_.GetSize()),
qspace(&qspace_), own_qspace(false), vdim(vdim_)
{ UseDevice(true); }
/// Same as above but specify the device memory type
QuadratureFunction(QuadratureSpaceBase &qspace_, MemoryType mt, int vdim_ = 1)
: Vector(vdim_*qspace_.GetSize(), mt),
qspace(&qspace_), own_qspace(false), vdim(vdim_)
{ UseDevice(true); }
/// Create a QuadratureFunction based on the given QuadratureSpaceBase.
/** The QuadratureFunction does not assume ownership of the
QuadratureSpaceBase.
@warning @a qspace_ may not be NULL. */
QuadratureFunction(QuadratureSpaceBase *qspace_, int vdim_ = 1)
: QuadratureFunction(*qspace_, vdim_) { }
/// Same as above but specify the device memory type
QuadratureFunction(QuadratureSpaceBase *qspace_, MemoryType mt, int vdim_ = 1)
: QuadratureFunction(*qspace_, mt, vdim_) { }
/** @brief Create a QuadratureFunction based on the given QuadratureSpaceBase,
using the external (host) data, @a qf_data. */
/** The QuadratureFunction does not assume ownership of the
QuadratureSpaceBase or the external data.
@warning @a qspace_ may not be NULL.
@note @a qf_data must be a valid **host** pointer (see the constructor
Vector::Vector(double *, int)). */
QuadratureFunction(QuadratureSpaceBase *qspace_, real_t *qf_data, int vdim_ = 1)
: Vector(qf_data, vdim_*qspace_->GetSize()),
qspace(qspace_), own_qspace(false), vdim(vdim_) { UseDevice(true); }
/** @brief Copy constructor. The QuadratureSpace ownership flag, #own_qspace,
in the new object is set to false. */
QuadratureFunction(const QuadratureFunction &orig)
: QuadratureFunction(*orig.qspace, orig.vdim)
{
Vector::operator=(orig);
}
/// Read a QuadratureFunction from the stream @a in.
/** The QuadratureFunction assumes ownership of the read QuadratureSpace. */
QuadratureFunction(Mesh *mesh, std::istream &in);
/// Get the vector dimension.
int GetVDim() const { return vdim; }
/// Set the vector dimension, updating the size by calling Vector::SetSize().
void SetVDim(int vdim_)
{ vdim = vdim_; SetSize(vdim*qspace->GetSize()); }
/// Get the associated QuadratureSpaceBase object.
QuadratureSpaceBase *GetSpace() { return qspace; }
/// Get the associated QuadratureSpaceBase object (const version).
const QuadratureSpaceBase *GetSpace() const { return qspace; }
/// Change the QuadratureSpaceBase and optionally the vector dimension.
/** If the new QuadratureSpaceBase is different from the current one, the
QuadratureFunction will not assume ownership of the new space; otherwise,
the ownership flag remains the same.
If the new vector dimension @a vdim_ < 0, the vector dimension remains
the same.
The data size is updated by calling Vector::SetSize(). */
inline void SetSpace(QuadratureSpaceBase *qspace_, int vdim_ = -1);
/** @brief Change the QuadratureSpaceBase, the data array, and optionally the
vector dimension. */
/** If the new QuadratureSpaceBase is different from the current one, the
QuadratureFunction will not assume ownership of the new space; otherwise,
the ownership flag remains the same.
If the new vector dimension @a vdim_ < 0, the vector dimension remains
the same.
The data array is replaced by calling Vector::NewDataAndSize(). */
inline void SetSpace(QuadratureSpaceBase *qspace_, real_t *qf_data,
int vdim_ = -1);
/// Get the QuadratureSpaceBase ownership flag.
bool OwnsSpace() { return own_qspace; }
/// Set the QuadratureSpaceBase ownership flag.
void SetOwnsSpace(bool own) { own_qspace = own; }
/// Set this equal to a constant value.
QuadratureFunction &operator=(real_t value);
/// Copy the data from @a v.
/** The size of @a v must be equal to the size of the associated
QuadratureSpaceBase #qspace times the QuadratureFunction vector
dimension i.e. QuadratureFunction::Size(). */
QuadratureFunction &operator=(const Vector &v);
/// Evaluate a grid function at each quadrature point.
void ProjectGridFunction(const GridFunction &gf);
/// Return all values associated with mesh element @a idx in a Vector.
/** The result is stored in the Vector @a values as a reference to the
global values.
Inside the Vector @a values, the index `i+vdim*j` corresponds to the
`i`-th vector component at the `j`-th quadrature point.
*/
inline void GetValues(int idx, Vector &values);
/// Return all values associated with mesh element @a idx in a Vector.
/** The result is stored in the Vector @a values as a copy of the
global values.
Inside the Vector @a values, the index `i+vdim*j` corresponds to the
`i`-th vector component at the `j`-th quadrature point.
*/
inline void GetValues(int idx, Vector &values) const;
/// Return the quadrature function values at an integration point.
/** The result is stored in the Vector @a values as a reference to the
global values. */
inline void GetValues(int idx, const int ip_num, Vector &values);
/// Return the quadrature function values at an integration point.
/** The result is stored in the Vector @a values as a copy to the
global values. */
inline void GetValues(int idx, const int ip_num, Vector &values) const;
/// Return all values associated with mesh element @a idx in a DenseMatrix.
/** The result is stored in the DenseMatrix @a values as a reference to the
global values.
Inside the DenseMatrix @a values, the `(i,j)` entry corresponds to the
`i`-th vector component at the `j`-th quadrature point.
*/
inline void GetValues(int idx, DenseMatrix &values);
/// Return all values associated with mesh element @a idx in a const DenseMatrix.
/** The result is stored in the DenseMatrix @a values as a copy of the
global values.
Inside the DenseMatrix @a values, the `(i,j)` entry corresponds to the
`i`-th vector component at the `j`-th quadrature point.
*/
inline void GetValues(int idx, DenseMatrix &values) const;
/// Get the IntegrationRule associated with entity (element or face) @a idx.
const IntegrationRule &GetIntRule(int idx) const
{ return GetSpace()->GetIntRule(idx); }
/// Write the QuadratureFunction to the stream @a out.
void Save(std::ostream &out) const;
/// @brief Write the QuadratureFunction to @a out in VTU (ParaView) format.
///
/// The data will be uncompressed if @a compression_level is zero, or if the
/// format is VTKFormat::ASCII. Otherwise, zlib compression will be used for
/// binary data.
void SaveVTU(std::ostream &out, VTKFormat format=VTKFormat::ASCII,
int compression_level=0, const std::string &field_name="u") const;
/// @brief Save the QuadratureFunction to a VTU (ParaView) file.
///
/// The extension ".vtu" will be appended to @a filename.
/// @sa SaveVTU(std::ostream &out, VTKFormat format=VTKFormat::ASCII,
/// int compression_level=0)
void SaveVTU(const std::string &filename, VTKFormat format=VTKFormat::ASCII,
int compression_level=0, const std::string &field_name="u") const;
/// Return the integral of the quadrature function (vdim = 1 only).
real_t Integrate() const;
/// @brief Integrate the (potentially vector-valued) quadrature function,
/// storing the results in @a integrals (length @a vdim).
void Integrate(Vector &integrals) const;
virtual ~QuadratureFunction()
{
if (own_qspace) { delete qspace; }
}
};
// Inline methods
inline void QuadratureFunction::GetValues(
int idx, Vector &values)
{
const int s_offset = qspace->Offset(idx);
const int sl_size = qspace->Offset(idx + 1) - s_offset;
values.MakeRef(*this, vdim*s_offset, vdim*sl_size);
}
inline void QuadratureFunction::GetValues(
int idx, Vector &values) const
{
const int s_offset = qspace->Offset(idx);
const int sl_size = qspace->Offset(idx + 1) - s_offset;
values.SetSize(vdim*sl_size);
values.HostWrite();
const real_t *q = HostRead() + vdim*s_offset;
for (int i = 0; i<values.Size(); i++)
{
values(i) = *(q++);
}
}
inline void QuadratureFunction::GetValues(
int idx, const int ip_num, Vector &values)
{
const int s_offset = qspace->Offset(idx) * vdim + ip_num * vdim;
values.MakeRef(*this, s_offset, vdim);
}
inline void QuadratureFunction::GetValues(
int idx, const int ip_num, Vector &values) const
{
const int s_offset = qspace->Offset(idx) * vdim + ip_num * vdim;
values.SetSize(vdim);
values.HostWrite();
const real_t *q = HostRead() + s_offset;
for (int i = 0; i < values.Size(); i++)
{
values(i) = *(q++);
}
}
inline void QuadratureFunction::GetValues(
int idx, DenseMatrix &values)
{
const int s_offset = qspace->Offset(idx);
const int sl_size = qspace->Offset(idx + 1) - s_offset;
// Make the values matrix memory an alias of the quadrature function memory
values.MakeRef(GetMemory(), vdim*s_offset, vdim, sl_size);
}
inline void QuadratureFunction::GetValues(
int idx, DenseMatrix &values) const
{
const int s_offset = qspace->Offset(idx);
const int sl_size = qspace->Offset(idx + 1) - s_offset;
values.SetSize(vdim, sl_size);
values.HostWrite();
const real_t *q = HostRead() + vdim*s_offset;
for (int j = 0; j<sl_size; j++)
{
for (int i = 0; i<vdim; i++)
{
values(i,j) = *(q++);
}
}
}
inline void QuadratureFunction::SetSpace(QuadratureSpaceBase *qspace_,
int vdim_)
{
if (qspace_ != qspace)
{
if (own_qspace) { delete qspace; }
qspace = qspace_;
own_qspace = false;
}
vdim = (vdim_ < 0) ? vdim : vdim_;
SetSize(vdim*qspace->GetSize());
}
inline void QuadratureFunction::SetSpace(
QuadratureSpaceBase *qspace_, real_t *qf_data, int vdim_)
{
if (qspace_ != qspace)
{
if (own_qspace) { delete qspace; }
qspace = qspace_;
own_qspace = false;
}
vdim = (vdim_ < 0) ? vdim : vdim_;
NewDataAndSize(qf_data, vdim*qspace->GetSize());
}
} // namespace mfem
#endif