Program Listing for File function_space.h
↰ Return to documentation for file (src/pcms/field/function_space.h)
#ifndef PCMS_FUNCTION_SPACE_H
#define PCMS_FUNCTION_SPACE_H
#include "pcms/field/coordinate_system.hpp"
#include "pcms/field/coordinate_view.hpp"
#include "evaluation_request.h"
#include "field.h"
#include "field_data.h"
#include "field_factory.h"
#include "field_layout.h"
#include "pcms/field/value_view.hpp"
#include "out_of_bounds_policy.h"
#include "point_evaluator.h"
#include "pcms/field/point_evaluator_factory.hpp"
#include "pcms/discretization/discretization.h"
#include "pcms/utility/arrays.h"
#include "pcms/utility/memory_spaces.h"
#include "pcms/utility/types.h"
#include <memory>
#include <optional>
#include <variant>
namespace pcms
{
// FunctionSpace is an abstract interface representing an evaluatable field
// space: layout, evaluation rules, and coordinate interpretation. It produces
// Functions (a Field bound to this space).
//
// Concrete implementations (e.g. LagrangeFunctionSpace) provide backends for
// specific discretizations or mesh types, and their From* factories return a
// shared_ptr. A Function co-owns its space via shared_ptr (obtained through
// enable_shared_from_this), which is why concrete spaces are always
// shared-owned; a stack-allocated FunctionSpace is not constructible (the
// backend constructors are private and reachable only via the shared_ptr
// From* factories).
class FunctionSpace
: public PointEvaluatorFactory
, public std::enable_shared_from_this<FunctionSpace>
{
public:
virtual std::shared_ptr<const Discretization> GetDiscretization()
const noexcept
{
return GetLayout()->GetDiscretization();
}
virtual std::shared_ptr<const FieldLayout> GetLayout() const noexcept = 0;
[[nodiscard]] const std::shared_ptr<const CoordinateSystem>&
GetCoordinateSystem() const override
{
return GetLayout()->GetCoordinateSystem();
}
virtual ~FunctionSpace() noexcept = default;
template <typename T>
[[nodiscard]] Function<T> CreateFunction(
std::string name = "", VarianceSignature variance = values::Scalar,
std::optional<ComponentScaling> scaling = std::nullopt) const;
template <typename T>
[[nodiscard]] Function<T> CreateFunction(
std::string name, VarianceSignature variance,
std::shared_ptr<const CoordinateSystem> system,
std::optional<ComponentScaling> scaling = std::nullopt) const;
// Expert API: wrap externally constructed field data into a Function for this
// space. The concrete space validates backend-specific field-data type and
// storage size compatibility.
template <typename T>
[[nodiscard]] Function<T> CreateFunction(
std::string name, std::unique_ptr<FieldData<T>> data) const;
protected:
template <typename T>
static Field<T> WrapField(std::shared_ptr<const FieldLayout> layout,
std::unique_ptr<FieldData<T>> data)
{
return Field<T>(std::string{}, std::move(layout), std::move(data));
}
template <typename T>
static Function<T> WrapFunction(std::string name,
std::shared_ptr<const FieldLayout> layout,
std::unique_ptr<FieldData<T>> data,
std::shared_ptr<const FunctionSpace> space)
{
return Function<T>(std::move(name), std::move(layout), std::move(data),
std::move(space));
}
virtual FieldVariant CreateFieldImpl(Type storage_type,
ValueBasis basis) const = 0;
virtual FieldVariant CreateFieldImpl(FieldDataVariant data) const = 0;
};
template <typename T>
Function<T> FunctionSpace::CreateFunction(
std::string name, VarianceSignature variance,
std::optional<ComponentScaling> scaling) const
{
return CreateFunction<T>(std::move(name), variance, nullptr, scaling);
}
template <typename T>
Function<T> FunctionSpace::CreateFunction(
std::string name, VarianceSignature variance,
std::shared_ptr<const CoordinateSystem> system,
std::optional<ComponentScaling> scaling) const
{
static_assert(is_supported_field_type_v<T>,
"T is not a supported field type");
ValueBasis basis = detail::MakeValueBasis(GetCoordinateSystem(), variance,
std::move(system), scaling);
detail::ValidateValueSemantics(basis, GetLayout()->GetNumComponents());
Field<T> field = std::get<Field<T>>(
CreateFieldImpl(TypeEnumFromType<T>(), std::move(basis)));
return WrapFunction<T>(std::move(name), std::move(field.layout_),
std::move(field.data_), shared_from_this());
}
template <typename T>
Function<T> FunctionSpace::CreateFunction(
std::string name, std::unique_ptr<FieldData<T>> data) const
{
static_assert(is_supported_field_type_v<T>,
"T is not a supported field type");
if (!data) {
throw pcms_error("FunctionSpace::CreateFunction: data must not be null");
}
detail::ValidateValueSemantics(data->GetValueBasis(),
GetLayout()->GetNumComponents());
Field<T> field =
std::get<Field<T>>(CreateFieldImpl(FieldDataVariant{std::move(data)}));
return WrapFunction<T>(std::move(name), std::move(field.layout_),
std::move(field.data_), shared_from_this());
}
inline EvaluationRequest EvaluationRequest::FromCoordinates(
CoordinateView<DeviceMemorySpace> coords, OutOfBoundsPolicy policy)
{
return EvaluationRequest(coords, nullptr, policy);
}
inline EvaluationRequest EvaluationRequest::FromLayout(
std::shared_ptr<const FieldLayout> layout, OutOfBoundsPolicy policy)
{
if (layout == nullptr) {
throw pcms_error("EvaluationRequest::FromLayout: layout must not be null");
}
// Must evaluate GetDOFHolderCoordinates() before std::move(layout)
auto coords = layout->GetDOFHolderCoordinates();
return EvaluationRequest(coords, std::move(layout), policy);
}
inline EvaluationRequest EvaluationRequest::FromFunctionSpace(
const FunctionSpace& function_space, OutOfBoundsPolicy policy)
{
return FromLayout(function_space.GetLayout(), policy);
}
} // namespace pcms
#endif // PCMS_FUNCTION_SPACE_H