From 6a8cf6aa20add083abbbd1349121be0e56c8e4ad Mon Sep 17 00:00:00 2001 From: Jacob Merson Date: Sat, 11 Jul 2026 21:29:49 -0400 Subject: [PATCH 1/4] Update Field/Function type hierarchy The idea is as follows: a function space creates a function. A Function represents an object that can be evaluated. A Function is a Field. A Field itself does not have evaluation capabilities, but has everything needed to be sent over the network. --- src/pcms/field/field.h | 73 ++++++++++++++----- src/pcms/field/function_space.h | 71 ++++++++++++++++-- src/pcms/field/function_space/lagrange.cpp | 6 +- .../polynomial_reconstruction.cpp | 5 +- src/pcms/field/function_space/spline.cpp | 5 +- src/pcms/pythonapi/bind_field_base.cpp | 10 ++- 6 files changed, 131 insertions(+), 39 deletions(-) diff --git a/src/pcms/field/field.h b/src/pcms/field/field.h index 433717d0..27c13a2b 100644 --- a/src/pcms/field/field.h +++ b/src/pcms/field/field.h @@ -2,12 +2,12 @@ #define PCMS_COUPLING_FIELD_H #include "field_data.h" -#include "field_evaluator_factory.h" #include "field_layout.h" #include "pcms/utility/arrays.h" #include "pcms/utility/memory_spaces.h" #include "pcms/utility/types.h" #include +#include #include namespace pcms @@ -15,12 +15,13 @@ namespace pcms class FunctionSpace; -// Field is a composed per-field object: it owns coefficient data and holds -// a shared reference to the evaluator factory so the function space stays alive -// as long as the field does. +// Field is the (layout + data) bundle: it pairs coefficient data with the +// FieldLayout that gives the DOF-holder ordering its meaning. It is the +// currency of the communication path and of TransferOperator::Apply; it is NOT +// evaluatable on its own (evaluation semantics live on FunctionSpace). // -// Fields are typically created via LagrangeFunctionSpace::CreateField(). -// They are move-only (unique_ptr member). +// Fields are created via FunctionSpace::CreateField(). They are move-only +// (unique_ptr member). template class Field { @@ -29,6 +30,7 @@ class Field Field& operator=(Field&&) = default; Field(const Field&) = delete; Field& operator=(const Field&) = delete; + ~Field() = default; FieldData& GetData() noexcept { return *data_; } const FieldData& GetData() const noexcept { return *data_; } @@ -55,32 +57,65 @@ class Field data_->SetDOFHolderData(v); } -private: - class CtorKey - { - CtorKey() = default; - friend class FunctionSpace; - }; - - Field(CtorKey, std::shared_ptr layout, - std::shared_ptr> evaluator_factory, +protected: + Field(std::shared_ptr layout, std::unique_ptr> data) - : layout_(std::move(layout)), - evaluator_factory_(std::move(evaluator_factory)), - data_(std::move(data)) + : layout_(std::move(layout)), data_(std::move(data)) { } + // FunctionSpace constructs Fields (via WrapField) and moves a Field's layout + // and data out to build a Function (via CreateFunction). friend class FunctionSpace; +private: std::shared_ptr layout_; - std::shared_ptr> evaluator_factory_; std::unique_ptr> data_; }; +// Function is a Field that additionally knows its FunctionSpace, so it can +// be evaluated and used to build transfer operators. It is-a Field so the +// communication path (FieldCommunicator holds Field&) and +// TransferOperator::Apply(const Field&) bind a Function slice-free. It adds no +// virtuals: moving a Function into a Field slot (e.g. AddField(Field&&)) +// intentionally slices off the space reference, leaving a valid comm-only +// Field. +template +class Function : public Field +{ +public: + Function(Function&&) = default; + Function& operator=(Function&&) = default; + Function(const Function&) = delete; + Function& operator=(const Function&) = delete; + + const FunctionSpace& GetSpace() const noexcept { return *space_; } + std::shared_ptr GetSpacePtr() const noexcept + { + return space_; + } + +protected: + Function(std::shared_ptr layout, + std::unique_ptr> data, + std::shared_ptr space) + : Field(std::move(layout), std::move(data)), space_(std::move(space)) + { + } + + friend class FunctionSpace; + +private: + std::shared_ptr space_; +}; + using FieldVariant = std::variant, Field, Field, Field, Field>; +using FunctionVariant = + std::variant, Function, Function, + Function, Function>; + } // namespace pcms #endif // PCMS_COUPLING_FIELD_H diff --git a/src/pcms/field/function_space.h b/src/pcms/field/function_space.h index a5e6f867..45548042 100644 --- a/src/pcms/field/function_space.h +++ b/src/pcms/field/function_space.h @@ -46,7 +46,12 @@ inline constexpr bool is_supported_field_type_v = // // FunctionSpace is used as the parameter type for operation objects such as // Interpolator, so that operations are not coupled to a specific backend. -class FunctionSpace +// +// FunctionSpace inherits enable_shared_from_this because CreateFunction stamps +// a shared_ptr into each Function it produces. Concrete +// spaces must therefore be owned by a shared_ptr (the From* factories return +// one); calling CreateFunction on a stack-allocated space throws bad_weak_ptr. +class FunctionSpace : public std::enable_shared_from_this { public: virtual std::shared_ptr GetDiscretization() @@ -73,6 +78,16 @@ class FunctionSpace template [[nodiscard]] Field CreateField(std::unique_ptr> data) const; + // Like CreateField, but returns a Function that retains a shared reference to + // this space (so it can be evaluated / used to build transfer operators). + // Requires this space to be owned by a shared_ptr (see class note). + template + [[nodiscard]] Function CreateFunction(FieldMetadata metadata = {}) const; + + template + [[nodiscard]] Function CreateFunction( + std::unique_ptr> data) const; + // Create a point evaluator for the given evaluation request. // Compile-time error for unsupported T; runtime error for T or capability // unsupported by the concrete backend. @@ -89,12 +104,17 @@ class FunctionSpace protected: template static Field WrapField(std::shared_ptr layout, - std::unique_ptr> data, - std::shared_ptr> - evaluator_factory = nullptr) + std::unique_ptr> data) { - return Field(typename Field::CtorKey{}, std::move(layout), - std::move(evaluator_factory), std::move(data)); + return Field(std::move(layout), std::move(data)); + } + + template + static Function WrapFunction(std::shared_ptr layout, + std::unique_ptr> data, + std::shared_ptr space) + { + return Function(std::move(layout), std::move(data), std::move(space)); } virtual FieldVariant CreateFieldImpl(Type value_type, @@ -106,6 +126,24 @@ class FunctionSpace Type value_type, const EvaluationRequest& request) const = 0; }; +// Wrap a by-value FunctionSpace (typically the result of a From* factory) in a +// shared_ptr so it can produce Functions and participate in transfers via +// AddFunction/CreateTransfer. Ordinary by-value use — CreateField, point +// evaluation, constructing a transfer operator directly — does not need this; +// only Function (which retains a shared_ptr) does. +// +// auto space = pcms::Share(LagrangeFunctionSpace::FromMesh(...)); +// auto fn = space->CreateFunction(); +template +[[nodiscard]] std::shared_ptr Share(Space&& space) +{ + static_assert( + std::is_base_of_v>, + "Share expects a FunctionSpace-derived type"); + return std::make_shared>( + std::forward(space)); +} + template Field FunctionSpace::CreateField(FieldMetadata metadata) const { @@ -125,6 +163,27 @@ Field FunctionSpace::CreateField(std::unique_ptr> data) const return std::get>(CreateFieldImpl(FieldDataVariant{std::move(data)})); } +template +Function FunctionSpace::CreateFunction(FieldMetadata metadata) const +{ + static_assert(is_supported_field_type_v, + "T is not a supported field type"); + Field field = CreateField(metadata); + return WrapFunction(std::move(field.layout_), std::move(field.data_), + shared_from_this()); +} + +template +Function FunctionSpace::CreateFunction( + std::unique_ptr> data) const +{ + static_assert(is_supported_field_type_v, + "T is not a supported field type"); + Field field = CreateField(std::move(data)); + return WrapFunction(std::move(field.layout_), std::move(field.data_), + shared_from_this()); +} + template std::unique_ptr> FunctionSpace::CreatePointEvaluator( const EvaluationRequest& request) const diff --git a/src/pcms/field/function_space/lagrange.cpp b/src/pcms/field/function_space/lagrange.cpp index 8328e266..99c8f286 100644 --- a/src/pcms/field/function_space/lagrange.cpp +++ b/src/pcms/field/function_space/lagrange.cpp @@ -251,8 +251,7 @@ FieldVariant LagrangeFunctionSpace::CreateFieldImpl( [this](auto&& fd) -> FieldVariant { using FD = std::decay_t; using T = typename FD::element_type::value_type; - return WrapField(layout_, std::forward(fd), - evaluator_factory_); + return WrapField(layout_, std::forward(fd)); }, std::move(field_data)); } @@ -269,8 +268,7 @@ FieldVariant LagrangeFunctionSpace::CreateFieldImpl(FieldDataVariant data) const "LagrangeFunctionSpace: int8_t is not a supported field type"); } else { ValidateLagrangeWrappedFieldData(*layout_, *fd); - return WrapField(layout_, std::forward(fd), - evaluator_factory_); + return WrapField(layout_, std::forward(fd)); } }, std::move(data)); diff --git a/src/pcms/field/function_space/polynomial_reconstruction.cpp b/src/pcms/field/function_space/polynomial_reconstruction.cpp index 060b9c24..d26beec1 100644 --- a/src/pcms/field/function_space/polynomial_reconstruction.cpp +++ b/src/pcms/field/function_space/polynomial_reconstruction.cpp @@ -93,8 +93,7 @@ FieldVariant PolynomialReconstructionFunctionSpace::CreateFieldImpl( "supported"); } else { return WrapField( - layout_, std::make_unique>(layout_, metadata), - evaluator_factory_); + layout_, std::make_unique>(layout_, metadata)); } }); } @@ -120,7 +119,7 @@ FieldVariant PolynomialReconstructionFunctionSpace::CreateFieldImpl( "PolynomialReconstructionFunctionSpace::CreateField: field data size " "does not match layout"); } - return WrapField(layout_, std::move(fd), evaluator_factory_); + return WrapField(layout_, std::move(fd)); } PointEvaluatorVariant diff --git a/src/pcms/field/function_space/spline.cpp b/src/pcms/field/function_space/spline.cpp index f4530fc8..167048b8 100644 --- a/src/pcms/field/function_space/spline.cpp +++ b/src/pcms/field/function_space/spline.cpp @@ -47,8 +47,7 @@ FieldVariant SplineFunctionSpace::CreateFieldImpl(Type value_type, throw pcms_error("SplineFunctionSpace: only double (Real) is supported"); } else { return WrapField( - layout_, std::make_unique>(layout_, metadata), - evaluator_factory_); + layout_, std::make_unique>(layout_, metadata)); } }); } @@ -70,7 +69,7 @@ FieldVariant SplineFunctionSpace::CreateFieldImpl(FieldDataVariant data) const "SplineFunctionSpace::CreateField: field data size does not match " "layout"); } - return WrapField(layout_, std::move(fd), evaluator_factory_); + return WrapField(layout_, std::move(fd)); } PointEvaluatorVariant SplineFunctionSpace::CreatePointEvaluatorImpl( diff --git a/src/pcms/pythonapi/bind_field_base.cpp b/src/pcms/pythonapi/bind_field_base.cpp index 77be9871..63ca6ecb 100644 --- a/src/pcms/pythonapi/bind_field_base.cpp +++ b/src/pcms/pythonapi/bind_field_base.cpp @@ -286,7 +286,7 @@ void bind_create_field_module(py::module& m) }, "DOF holder coordinates as a 2D numpy array (num_dof_holders × dim)"); - py::class_(m, "FunctionSpace") + py::class_>(m, "FunctionSpace") .def( "create_field", [](const FunctionSpace& self) { return self.CreateField(); }, @@ -317,8 +317,9 @@ void bind_create_field_module(py::module& m) "only)."); // Bind LagrangeFunctionSpace as a concrete FunctionSpace subtype. - py::class_ lagrange_space( - m, "LagrangeFunctionSpace"); + py::class_> + lagrange_space(m, "LagrangeFunctionSpace"); // Backend selecting the underlying field layout. The conservative-projection // transfer operators require the native Omega_h backend. @@ -386,7 +387,8 @@ void bind_create_field_module(py::module& m) // Bind PolynomialReconstructionFunctionSpace as a concrete FunctionSpace // subtype. - py::class_( + py::class_>( m, "PolynomialReconstructionFunctionSpace") .def_static( "from_coords", From c0f2c1c0aa63acfa963a02400a231f9fdbf728da Mon Sep 17 00:00:00 2001 From: Jacob Merson Date: Sat, 11 Jul 2026 23:55:32 -0400 Subject: [PATCH 2/4] Rework field construction and coupler registration around a two-level naming model, removing AddLayout. Our goal was to remove the need for AddLayout and forcing the user to *know* what layouts they needed to add. This was the simplest strategy of the ones we tested. It also aligns to the idea that fields are likely to have names anyways. So, having a field and layout both have names allows convenient cacheing of the layout communicator and naming of fields that follows on its construction. --- src/pcms/capi/client.cpp | 31 +-- src/pcms/coupler/coupler.cpp | 45 ++--- src/pcms/coupler/coupler.hpp | 178 ++++++++++++++---- src/pcms/coupler/field_communicator.hpp | 3 +- src/pcms/field/field.h | 18 +- src/pcms/field/field_layout.h | 8 + src/pcms/field/function_space.h | 59 +++--- src/pcms/field/function_space/lagrange.cpp | 13 +- src/pcms/field/function_space/lagrange.h | 11 +- src/pcms/field/function_space/xgc.h | 14 +- src/pcms/field/uniform_grid_binary_field.h | 2 +- test/test_field_communication.cpp | 28 ++- test/test_field_copy.cpp | 4 +- test/test_field_evaluation.cpp | 4 +- test/test_field_interpolation.cpp | 12 +- test/test_omega_h_field2_outofbounds.cpp | 2 +- test/test_omega_h_lagrange_field.cpp | 26 +-- ...lynomial_reconstruction_function_space.cpp | 10 +- ...lynomial_reconstruction_mls_evaluation.cpp | 14 +- test/test_proxy_coupling.cpp | 43 ++--- test/test_proxy_coupling_xgc_server.cpp | 25 ++- ...test_proxy_coupling_xgc_server_overlap.cpp | 27 ++- test/test_uniform_grid_field.cpp | 24 ++- test/test_xgc_field_data.cpp | 6 +- test/xgc_n0_coupling_server.cpp | 10 +- 25 files changed, 374 insertions(+), 243 deletions(-) diff --git a/src/pcms/capi/client.cpp b/src/pcms/capi/client.cpp index 3d320094..24ae038c 100644 --- a/src/pcms/capi/client.cpp +++ b/src/pcms/capi/client.cpp @@ -40,7 +40,12 @@ struct DummyFieldRegistration class EmptyFunctionSpace : public FunctionSpace { public: - EmptyFunctionSpace() : layout_(std::make_shared()) {} + explicit EmptyFunctionSpace(std::string layout_name = "") + { + auto layout = std::make_shared(); + layout->SetName(std::move(layout_name)); + layout_ = layout; + } [[nodiscard]] std::shared_ptr GetLayout() const noexcept override @@ -130,29 +135,31 @@ ClientState::HandleVariant RegisterField( Application& app, std::string name, const detail::XGCFieldRegistration& registration, bool participates) { + // The layout's coupling identity is the field name + // not the arbitrary adapter name given at creation. + registration.function_space.SetLayoutName(name); auto field = registration.function_space.template CreateField( - std::make_unique>( - registration.function_space.GetXGCLayout(), FieldMetadata{}, - registration.data)); - app.AddLayout(name, registration.function_space.GetLayout(), participates); + std::move(name), std::make_unique>( + registration.function_space.GetXGCLayout(), + FieldMetadata{}, registration.data)); std::unique_ptr> serializer = std::make_unique>(registration.plane_comm, participates); - return ClientState::HandleVariant{app.AddField( - std::move(name), std::move(field), std::move(serializer), participates)}; + return ClientState::HandleVariant{ + app.AddField(std::move(field), std::move(serializer), participates)}; } inline ClientState::HandleVariant RegisterField( Application& app, std::string name, const detail::DummyFieldRegistration&, bool participates) { - auto function_space = detail::EmptyFunctionSpace{}; - app.AddLayout(name, function_space.GetLayout(), participates); - auto field = function_space.CreateField(FieldMetadata{}); + auto function_space = detail::EmptyFunctionSpace{name}; + auto field = + function_space.CreateField(std::move(name), FieldMetadata{}); std::unique_ptr> serializer = std::make_unique>(); - return ClientState::HandleVariant{app.AddField( - std::move(name), std::move(field), std::move(serializer), participates)}; + return ClientState::HandleVariant{ + app.AddField(std::move(field), std::move(serializer), participates)}; } } // namespace pcms diff --git a/src/pcms/coupler/coupler.cpp b/src/pcms/coupler/coupler.cpp index a0c83e7d..91a1bf80 100644 --- a/src/pcms/coupler/coupler.cpp +++ b/src/pcms/coupler/coupler.cpp @@ -3,32 +3,23 @@ namespace pcms { -FieldLayoutCommunicator& Application::GetLayoutCommunicator( - const FieldLayout& layout) +FieldLayoutCommunicator& Application::GetOrCreateLayoutCommunicator( + const FieldLayout& layout, bool participates) { PCMS_FUNCTION_TIMER; - auto it = field_layout_communicators_.find(&layout); + const std::string& name = layout.GetName(); + if (name.empty()) { + throw pcms_error( + "Application: the field's layout has no name; name it at construction " + "(From*(..., layout_name)) before registering it with a coupler"); + } + + // Fields whose layouts share a name share one GID-exchange communicator. + auto it = field_layout_communicators_.find(name); if (it != field_layout_communicators_.end()) { return *it->second; - } else { - throw pcms_error("Field added with unregistered layout. Call AddLayout() " - "before AddField()."); } -} -const FieldLayout& Application::AddLayout( - std::string name, std::shared_ptr layout, - bool participates) -{ - return AddLayout(std::move(name), std::move(layout), - std::make_unique(), - participates); -} - -const FieldLayout& Application::AddLayout( - std::string name, std::shared_ptr layout, - std::unique_ptr planner, bool participates) -{ MPI_Comm mpi_comm_subset = MPI_COMM_NULL; bool own_mpi_comm = false; PCMS_ALWAYS_ASSERT((mpi_comm_ == MPI_COMM_NULL) ? (!participates) : true); @@ -39,21 +30,19 @@ const FieldLayout& Application::AddLayout( &mpi_comm_subset); own_mpi_comm = true; } - layouts_.push_back(std::move(layout)); - const FieldLayout& layout_ref = *layouts_.back(); - // Check if there's an overlap mask for this layout const OverlapMask* overlap_mask = nullptr; auto mask_it = layout_overlap_masks_.find(name); if (mask_it != layout_overlap_masks_.end()) { overlap_mask = mask_it->second.get(); } - field_layout_communicators_.emplace( - &layout_ref, std::make_unique( - name, mpi_comm_subset, redev_, channel_, layout_ref, - std::move(planner), own_mpi_comm, overlap_mask)); - return layout_ref; + auto [it2, inserted] = field_layout_communicators_.emplace( + name, std::make_unique( + name, mpi_comm_subset, redev_, channel_, layout, + std::make_unique(), own_mpi_comm, + overlap_mask)); + return *it2->second; } void Application::SetLayoutOverlapMask( diff --git a/src/pcms/coupler/coupler.hpp b/src/pcms/coupler/coupler.hpp index d2d12cb1..eef0f564 100644 --- a/src/pcms/coupler/coupler.hpp +++ b/src/pcms/coupler/coupler.hpp @@ -31,11 +31,41 @@ class FieldHandle void Receive(redev::Mode mode = redev::Mode::Synchronous) const; [[nodiscard]] Field& GetField() const; + [[nodiscard]] const std::string& GetName() const noexcept { return name_; } + private: Application* app_; std::string name_; }; +// FunctionHandle is a FieldHandle that additionally carries the function space, +// so it can be evaluated / used to build transfer operators. Only AddFunction +// produces one; CreateTransfer accepts FunctionHandle (not FieldHandle), which +// makes passing a comm-only field to a transfer a compile error. +template +class FunctionHandle : public FieldHandle +{ +public: + FunctionHandle(Application* app, std::string name, + std::shared_ptr space) + : FieldHandle(app, std::move(name)), space_(std::move(space)) + { + } + + [[nodiscard]] const FunctionSpace& GetSpace() const noexcept + { + return *space_; + } + [[nodiscard]] std::shared_ptr GetSpacePtr() + const noexcept + { + return space_; + } + +private: + std::shared_ptr space_; +}; + class Application { public: @@ -50,27 +80,33 @@ class Application PCMS_FUNCTION_TIMER; } - const FieldLayout& AddLayout(std::string name, - std::shared_ptr layout, - bool participates = true); - const FieldLayout& AddLayout(std::string name, - std::shared_ptr layout, - std::unique_ptr planner, - bool participates = true); - - // Set the overlap mask for a specific layout by name + // Set the overlap mask for a field's layout by name. Must be set before the + // AddField/AddFunction that first creates that layout's communicator. void SetLayoutOverlapMask(const std::string& layout_name, std::unique_ptr overlap_mask); + // Register a comm-only field, identified by its own name. The layout's + // communicator is created on first use and shared by any later + // field/function whose layout has the same name. template - FieldHandle AddField(std::string name, Field&& field, - bool participates = true); + FieldHandle AddField(Field&& field, bool participates = true); template - FieldHandle AddField(std::string name, Field&& field, + FieldHandle AddField(Field&& field, std::unique_ptr> serializer, bool participates = true); + // Register a transferable field: like AddField but retains the function space + // (via the stored Function) and returns a FunctionHandle usable in transfers. + template + FunctionHandle AddFunction(Function&& function, + bool participates = true); + + template + FunctionHandle AddFunction(Function&& function, + std::unique_ptr> serializer, + bool participates = true); + void SendField(const std::string& name, redev::Mode mode = redev::Mode::Synchronous) { @@ -144,20 +180,29 @@ class Application [[nodiscard]] Field& GetField(const std::string& name); private: - FieldLayoutCommunicator& GetLayoutCommunicator(const FieldLayout& layout); + // Returns the communicator for `layout`, creating it (MPI split + overlap + // mask lookup + planner) on first use and reusing it for any later + // field/function whose layout has the same name. + FieldLayoutCommunicator& GetOrCreateLayoutCommunicator( + const FieldLayout& layout, bool participates); + + template + void RegisterFieldCommunicator(Field& field_obj, + std::unique_ptr> serializer, + bool participates); MPI_Comm mpi_comm_; redev::Redev& redev_; redev::Channel channel_; - std::vector> layouts_; std::map fields_; + std::map functions_; std::vector> owned_field_layout_communicators_; // map is used rather than unordered_map because we give pointers to the // internal data and rehash of unordered_map can cause pointer invalidation. // map is less cache friendly, but pointers are not invalidated. std::map field_communicators_; - std::map> + std::map> field_layout_communicators_; std::map> layout_overlap_masks_; }; @@ -238,47 +283,106 @@ pcms::Field& pcms::FieldHandle::GetField() const template pcms::Field& pcms::Application::GetField(const std::string& name) { - auto* field = std::get_if>(&detail::find_or_error(name, fields_)); - if (field == nullptr) { - throw pcms_error("Field stored with different type than requested"); + auto field_it = fields_.find(name); + if (field_it != fields_.end()) { + auto* field = std::get_if>(&field_it->second); + if (field == nullptr) { + throw pcms_error("Field stored with different type than requested"); + } + return *field; + } + auto fn_it = functions_.find(name); + if (fn_it != functions_.end()) { + auto* function = std::get_if>(&fn_it->second); + if (function == nullptr) { + throw pcms_error("Field stored with different type than requested"); + } + return *function; + } + throw pcms_error("Field '" + name + "' not found"); +} + +template +void pcms::Application::RegisterFieldCommunicator( + Field& field_obj, std::unique_ptr> serializer, + bool participates) +{ + const std::string& name = field_obj.GetName(); + FieldLayoutCommunicator& layout_communicator = + GetOrCreateLayoutCommunicator(field_obj.GetLayout(), participates); + FieldCommunicator2Ptr field_communicator = + std::make_unique>(name, layout_communicator, field_obj, + std::move(serializer)); + auto [it, inserted] = + field_communicators_.emplace(name, std::move(field_communicator)); + if (!inserted) { + throw pcms_error("Field with this name already exists"); } - return *field; } template -pcms::FieldHandle pcms::Application::AddField(std::string name, - Field&& field, +pcms::FieldHandle pcms::Application::AddField(Field&& field, bool participates) { - return AddField(std::move(name), std::move(field), - std::make_unique>(), participates); + return AddField(std::move(field), std::make_unique>(), + participates); } template pcms::FieldHandle pcms::Application::AddField( - std::string name, Field&& field, - std::unique_ptr> serializer, bool participates) + Field&& field, std::unique_ptr> serializer, + bool participates) { PCMS_FUNCTION_TIMER; - (void)participates; + std::string name = field.GetName(); + if (name.empty()) { + throw pcms_error("Application::AddField: field has no name"); + } auto [field_it, field_inserted] = fields_.emplace(name, std::move(field)); if (!field_inserted) { throw pcms_error("Field with this name already exists"); } - auto& field_obj = std::get>(field_it->second); - const FieldLayout& layout = field_obj.GetLayout(); - FieldLayoutCommunicator& layout_communicator = GetLayoutCommunicator(layout); - FieldCommunicator2Ptr field_communicator = - std::make_unique>(name, layout_communicator, field_obj, - std::move(serializer)); - - auto [it, inserted] = - field_communicators_.emplace(name, std::move(field_communicator)); - if (!inserted) { + try { + RegisterFieldCommunicator(std::get>(field_it->second), + std::move(serializer), participates); + } catch (...) { fields_.erase(field_it); - throw pcms_error("Field with this name already exists"); + throw; } return FieldHandle{this, std::move(name)}; } +template +pcms::FunctionHandle pcms::Application::AddFunction(Function&& function, + bool participates) +{ + return AddFunction(std::move(function), + std::make_unique>(), participates); +} + +template +pcms::FunctionHandle pcms::Application::AddFunction( + Function&& function, std::unique_ptr> serializer, + bool participates) +{ + PCMS_FUNCTION_TIMER; + std::string name = function.GetName(); + if (name.empty()) { + throw pcms_error("Application::AddFunction: function has no name"); + } + auto space = function.GetSpacePtr(); + auto [fn_it, fn_inserted] = functions_.emplace(name, std::move(function)); + if (!fn_inserted) { + throw pcms_error("Field with this name already exists"); + } + try { + RegisterFieldCommunicator(std::get>(fn_it->second), + std::move(serializer), participates); + } catch (...) { + functions_.erase(fn_it); + throw; + } + return FunctionHandle{this, std::move(name), std::move(space)}; +} + #endif // COUPLER2_H_ diff --git a/src/pcms/coupler/field_communicator.hpp b/src/pcms/coupler/field_communicator.hpp index b1874507..fa731487 100644 --- a/src/pcms/coupler/field_communicator.hpp +++ b/src/pcms/coupler/field_communicator.hpp @@ -34,7 +34,8 @@ class FieldCommunicator field_(field), serializer_(std::move(serializer)) { - PCMS_ALWAYS_ASSERT(&layout_comm.GetLayout() == &field.GetLayout()); + PCMS_ALWAYS_ASSERT(layout_comm.GetLayout().GetName() == + field.GetLayout().GetName()); // The exchange plan is per DOF holder; the field payload carries // num_components values per holder, so the buffer is scaled accordingly. comm_buffer_.resize( diff --git a/src/pcms/field/field.h b/src/pcms/field/field.h index 27c13a2b..4b4a91c0 100644 --- a/src/pcms/field/field.h +++ b/src/pcms/field/field.h @@ -7,6 +7,7 @@ #include "pcms/utility/memory_spaces.h" #include "pcms/utility/types.h" #include +#include #include #include @@ -37,6 +38,9 @@ class Field const FieldLayout& GetLayout() const { return *layout_; } + // Optional identifier for this field. Empty by default; set at creation. + [[nodiscard]] const std::string& GetName() const noexcept { return name_; } + Rank2View GetDOFHolderDataHost() const { return data_->GetDOFHolderDataHost(); @@ -58,17 +62,18 @@ class Field } protected: - Field(std::shared_ptr layout, + Field(std::string name, std::shared_ptr layout, std::unique_ptr> data) - : layout_(std::move(layout)), data_(std::move(data)) + : name_(std::move(name)), layout_(std::move(layout)), data_(std::move(data)) { } - // FunctionSpace constructs Fields (via WrapField) and moves a Field's layout - // and data out to build a Function (via CreateFunction). + // FunctionSpace constructs Fields (via WrapField) and moves a Field's name, + // layout and data out to build a Function (via CreateFunction). friend class FunctionSpace; private: + std::string name_; std::shared_ptr layout_; std::unique_ptr> data_; }; @@ -96,10 +101,11 @@ class Function : public Field } protected: - Function(std::shared_ptr layout, + Function(std::string name, std::shared_ptr layout, std::unique_ptr> data, std::shared_ptr space) - : Field(std::move(layout), std::move(data)), space_(std::move(space)) + : Field(std::move(name), std::move(layout), std::move(data)), + space_(std::move(space)) { } diff --git a/src/pcms/field/field_layout.h b/src/pcms/field/field_layout.h index d01a13a0..b4551e4c 100644 --- a/src/pcms/field/field_layout.h +++ b/src/pcms/field/field_layout.h @@ -2,6 +2,7 @@ #define PCMS_FIELD_LAYOUT_H #include #include +#include #include #include "pcms/discretization/discretization.h" #include "pcms/utility/types.h" @@ -19,6 +20,12 @@ using ReversePartitionMap = std::map>; class FieldLayout { public: + // Optional identifier for this layout. Set once at construction (via a From* + // factory) and empty by default. Consumers that need to identify a layout by + // a stable name use it; it carries no meaning within the field layer itself. + [[nodiscard]] const std::string& GetName() const noexcept { return name_; } + void SetName(std::string name) { name_ = std::move(name); } + virtual std::shared_ptr GetDiscretization() const noexcept = 0; @@ -77,6 +84,7 @@ class FieldLayout void BuildGlobalToLocalPermutation(); private: + std::string name_; Kokkos::View global_to_local_host_; Kokkos::View global_to_local_; }; diff --git a/src/pcms/field/function_space.h b/src/pcms/field/function_space.h index 45548042..00e21dc9 100644 --- a/src/pcms/field/function_space.h +++ b/src/pcms/field/function_space.h @@ -66,27 +66,31 @@ class FunctionSpace : public std::enable_shared_from_this virtual ~FunctionSpace() noexcept = default; - // Create a new field with freshly allocated data for this function space. - // Compile-time error for unsupported T; runtime error for T unsupported by - // the concrete backend. + // Create a new named field with freshly allocated data for this function + // space. The name is optional (empty by default) and identifies the field to + // consumers such as a coupler. Compile-time error for unsupported T; runtime + // error for T unsupported by the concrete backend. template - [[nodiscard]] Field CreateField(FieldMetadata metadata = {}) const; + [[nodiscard]] Field CreateField(std::string name = "", + FieldMetadata metadata = {}) const; // Expert API: wrap externally constructed field data into a Field for this // function space. The concrete function space validates backend-specific // field-data type and storage size compatibility. template - [[nodiscard]] Field CreateField(std::unique_ptr> data) const; + [[nodiscard]] Field CreateField(std::string name, + std::unique_ptr> data) const; // Like CreateField, but returns a Function that retains a shared reference to // this space (so it can be evaluated / used to build transfer operators). // Requires this space to be owned by a shared_ptr (see class note). template - [[nodiscard]] Function CreateFunction(FieldMetadata metadata = {}) const; + [[nodiscard]] Function CreateFunction(std::string name = "", + FieldMetadata metadata = {}) const; template [[nodiscard]] Function CreateFunction( - std::unique_ptr> data) const; + std::string name, std::unique_ptr> data) const; // Create a point evaluator for the given evaluation request. // Compile-time error for unsupported T; runtime error for T or capability @@ -106,15 +110,17 @@ class FunctionSpace : public std::enable_shared_from_this static Field WrapField(std::shared_ptr layout, std::unique_ptr> data) { - return Field(std::move(layout), std::move(data)); + return Field(std::string{}, std::move(layout), std::move(data)); } template - static Function WrapFunction(std::shared_ptr layout, + static Function WrapFunction(std::string name, + std::shared_ptr layout, std::unique_ptr> data, std::shared_ptr space) { - return Function(std::move(layout), std::move(data), std::move(space)); + return Function(std::move(name), std::move(layout), std::move(data), + std::move(space)); } virtual FieldVariant CreateFieldImpl(Type value_type, @@ -145,43 +151,52 @@ template } template -Field FunctionSpace::CreateField(FieldMetadata metadata) const +Field FunctionSpace::CreateField(std::string name, + FieldMetadata metadata) const { static_assert(is_supported_field_type_v, "T is not a supported field type"); - return std::get>(CreateFieldImpl(TypeEnumFromType(), metadata)); + Field field = + std::get>(CreateFieldImpl(TypeEnumFromType(), metadata)); + field.name_ = std::move(name); + return field; } template -Field FunctionSpace::CreateField(std::unique_ptr> data) const +Field FunctionSpace::CreateField(std::string name, + std::unique_ptr> data) const { static_assert(is_supported_field_type_v, "T is not a supported field type"); if (!data) { throw pcms_error("FunctionSpace::CreateField: data must not be null"); } - return std::get>(CreateFieldImpl(FieldDataVariant{std::move(data)})); + Field field = + std::get>(CreateFieldImpl(FieldDataVariant{std::move(data)})); + field.name_ = std::move(name); + return field; } template -Function FunctionSpace::CreateFunction(FieldMetadata metadata) const +Function FunctionSpace::CreateFunction(std::string name, + FieldMetadata metadata) const { static_assert(is_supported_field_type_v, "T is not a supported field type"); - Field field = CreateField(metadata); - return WrapFunction(std::move(field.layout_), std::move(field.data_), - shared_from_this()); + Field field = CreateField(std::move(name), metadata); + return WrapFunction(std::move(field.name_), std::move(field.layout_), + std::move(field.data_), shared_from_this()); } template Function FunctionSpace::CreateFunction( - std::unique_ptr> data) const + std::string name, std::unique_ptr> data) const { static_assert(is_supported_field_type_v, "T is not a supported field type"); - Field field = CreateField(std::move(data)); - return WrapFunction(std::move(field.layout_), std::move(field.data_), - shared_from_this()); + Field field = CreateField(std::move(name), std::move(data)); + return WrapFunction(std::move(field.name_), std::move(field.layout_), + std::move(field.data_), shared_from_this()); } template diff --git a/src/pcms/field/function_space/lagrange.cpp b/src/pcms/field/function_space/lagrange.cpp index 99c8f286..7a16f2af 100644 --- a/src/pcms/field/function_space/lagrange.cpp +++ b/src/pcms/field/function_space/lagrange.cpp @@ -66,7 +66,7 @@ LagrangeFunctionSpace::LagrangeFunctionSpace( LagrangeFunctionSpace LagrangeFunctionSpace::FromMesh( Omega_h::Mesh& mesh, int order, int num_components, CoordinateSystem coordinate_system, std::string global_id_name, - Backend backend) + Backend backend, std::string layout_name) { // https://github.com/SCOREC/meshFields/issues/88 if (backend == Backend::MeshFields && order == 0) { @@ -89,6 +89,7 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromMesh( auto mesh_layout = std::make_shared( mesh, nodes_per_dim, num_components, coordinate_system, std::move(global_id_name)); + mesh_layout->SetName(layout_name); auto eval_factory = std::make_shared>(mesh_layout); return LagrangeFunctionSpace( @@ -126,6 +127,7 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromMesh( } auto layout = std::make_shared( mesh, order, num_components, coordinate_system, std::move(global_id_name)); + layout->SetName(std::move(layout_name)); auto eval_factory = std::make_shared>(layout); return LagrangeFunctionSpace( @@ -146,7 +148,7 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromMesh( LagrangeFunctionSpace LagrangeFunctionSpace::FromMesh( Omega_h::Mesh& mesh, int order, int num_components, CoordinateSystem coordinate_system, Omega_h::Read owned_mask, - std::string global_id_name, Backend backend) + std::string global_id_name, Backend backend, std::string layout_name) { if (backend == Backend::MeshFields) { throw pcms_error( @@ -161,6 +163,7 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromMesh( auto layout = std::make_shared( mesh, order, num_components, coordinate_system, std::move(owned_mask), std::move(global_id_name)); + layout->SetName(std::move(layout_name)); auto eval_factory = std::make_shared>(layout); return LagrangeFunctionSpace( @@ -180,7 +183,7 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromMesh( LagrangeFunctionSpace LagrangeFunctionSpace::FromUniformGrid( const UniformGrid<2>& grid, int num_components, - CoordinateSystem coordinate_system, int order) + CoordinateSystem coordinate_system, int order, std::string layout_name) { if (order != 0 && order != 1) { throw std::invalid_argument("LagrangeFunctionSpace::FromUniformGrid: only " @@ -188,6 +191,7 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromUniformGrid( } auto ug_layout = std::make_shared>( grid, num_components, coordinate_system, order); + ug_layout->SetName(std::move(layout_name)); auto eval_factory = std::make_shared>(ug_layout); return LagrangeFunctionSpace( @@ -207,7 +211,7 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromUniformGrid( LagrangeFunctionSpace LagrangeFunctionSpace::FromUniformGrid( const UniformGrid<3>& grid, int num_components, - CoordinateSystem coordinate_system, int order) + CoordinateSystem coordinate_system, int order, std::string layout_name) { if (order != 0 && order != 1) { throw std::invalid_argument("LagrangeFunctionSpace::FromUniformGrid: only " @@ -215,6 +219,7 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromUniformGrid( } auto ug_layout = std::make_shared>( grid, num_components, coordinate_system, order); + ug_layout->SetName(std::move(layout_name)); auto eval_factory = std::make_shared>(ug_layout); return LagrangeFunctionSpace( diff --git a/src/pcms/field/function_space/lagrange.h b/src/pcms/field/function_space/lagrange.h index 54b2f695..8526d58e 100644 --- a/src/pcms/field/function_space/lagrange.h +++ b/src/pcms/field/function_space/lagrange.h @@ -44,22 +44,25 @@ class LagrangeFunctionSpace : public FunctionSpace [[nodiscard]] static LagrangeFunctionSpace FromMesh( Omega_h::Mesh& mesh, int order, int num_components, CoordinateSystem coordinate_system, std::string global_id_name = "global", - Backend backend = DefaultBackend); + Backend backend = DefaultBackend, std::string layout_name = ""); [[nodiscard]] static LagrangeFunctionSpace FromMesh( Omega_h::Mesh& mesh, int order, int num_components, CoordinateSystem coordinate_system, Omega_h::Read owned_mask, - std::string global_id_name = "global", Backend backend = DefaultBackend); + std::string global_id_name = "global", Backend backend = DefaultBackend, + std::string layout_name = ""); // Structured uniform grid — order-1 H1-conforming nodal field on a regular // grid [[nodiscard]] static LagrangeFunctionSpace FromUniformGrid( const UniformGrid<2>& grid, int num_components, - CoordinateSystem coordinate_system, int order = 1); + CoordinateSystem coordinate_system, int order = 1, + std::string layout_name = ""); [[nodiscard]] static LagrangeFunctionSpace FromUniformGrid( const UniformGrid<3>& grid, int num_components, - CoordinateSystem coordinate_system, int order = 1); + CoordinateSystem coordinate_system, int order = 1, + std::string layout_name = ""); [[nodiscard]] std::shared_ptr GetLayout() const noexcept override; diff --git a/src/pcms/field/function_space/xgc.h b/src/pcms/field/function_space/xgc.h index 164abc7a..45a769ac 100644 --- a/src/pcms/field/function_space/xgc.h +++ b/src/pcms/field/function_space/xgc.h @@ -17,10 +17,20 @@ class XGCFunctionSpace : public FunctionSpace public: XGCFunctionSpace(const ReverseClassificationVertex& reverse_classification, std::function in_overlap, - LO num_plane_nodes) + LO num_plane_nodes, std::string layout_name = "") : layout_(std::make_shared( reverse_classification, std::move(in_overlap), num_plane_nodes)) { + layout_->SetName(std::move(layout_name)); + } + + // Set the layout name after construction. Const because the name is metadata + // that does not affect the (const) discretization; the layout pointee is + // mutable through the shared_ptr. Used by the capi, which learns a field's + // name only when it is added, after the space is built. + void SetLayoutName(std::string name) const + { + layout_->SetName(std::move(name)); } [[nodiscard]] std::shared_ptr GetLayout() @@ -82,7 +92,7 @@ class XGCFunctionSpace : public FunctionSpace } private: - std::shared_ptr layout_; + std::shared_ptr layout_; }; } // namespace pcms diff --git a/src/pcms/field/uniform_grid_binary_field.h b/src/pcms/field/uniform_grid_binary_field.h index 6a71de7a..8302cbd5 100644 --- a/src/pcms/field/uniform_grid_binary_field.h +++ b/src/pcms/field/uniform_grid_binary_field.h @@ -41,7 +41,7 @@ CreateUniformGridBinaryField(Omega_h::Mesh& mesh, const UniformGrid& grid) auto layout = std::dynamic_pointer_cast>( function_space.GetLayout()); PCMS_ALWAYS_ASSERT(layout != nullptr); - auto field = function_space.template CreateField(FieldMetadata{}); + auto field = function_space.template CreateField("", FieldMetadata{}); auto coord_view = layout->GetDOFHolderCoordinates(); auto coords = coord_view.GetValues(); diff --git a/test/test_field_communication.cpp b/test/test_field_communication.cpp index 83b8bc5b..30cb96b8 100644 --- a/test/test_field_communication.cpp +++ b/test/test_field_communication.cpp @@ -78,15 +78,12 @@ static void test_shared_layout(Omega_h::Library& lib, redev::Partition{partition}); auto* app = cpl.AddApplication("shared_layout"); auto factory = pcms::LagrangeFunctionSpace::FromMesh( - mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto layout = factory.GetLayout(); - app->AddLayout("shared", layout); + mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", + pcms::LagrangeFunctionSpace::DefaultBackend, "shared"); + auto f1 = app->AddField(factory.CreateField("field_a")); PCMS_ALWAYS_ASSERT(app->GetLayoutCommunicatorCount() == 1); - auto f1 = app->AddField("field_a", factory.CreateField()); - PCMS_ALWAYS_ASSERT(app->GetLayoutCommunicatorCount() == - 1); // still 1 after adding field - auto f2 = app->AddField("field_b", factory.CreateField()); - PCMS_ALWAYS_ASSERT(app->GetLayoutCommunicatorCount() == 1); // still 1 + auto f2 = app->AddField(factory.CreateField("field_b")); + PCMS_ALWAYS_ASSERT(app->GetLayoutCommunicatorCount() == 1); // shared layout app->ReceivePhase([&]() { f1.Receive(); f2.Receive(); @@ -100,11 +97,10 @@ static void test_shared_layout(Omega_h::Library& lib, redev::Partition{}); auto* app = cpl.AddApplication("shared_layout"); auto factory = pcms::LagrangeFunctionSpace::FromMesh( - mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto layout = factory.GetLayout(); - app->AddLayout("shared", layout); - auto f1 = app->AddField("field_a", factory.CreateField()); - auto f2 = app->AddField("field_b", factory.CreateField()); + mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", + pcms::LagrangeFunctionSpace::DefaultBackend, "shared"); + auto f1 = app->AddField(factory.CreateField("field_a")); + auto f2 = app->AddField(factory.CreateField("field_b")); app->SendPhase([&]() { f1.Send(); f2.Send(); @@ -134,7 +130,7 @@ void client1(MPI_Comm comm, Omega_h::Mesh& mesh, std::string comm_name, "id gid", Kokkos::RangePolicy(0, n), [=](int i) { ids[i] = gids[i]; }); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); field.SetDOFHolderDataHost( pcms::Rank2View(ids.data(), n, 1)); @@ -161,7 +157,7 @@ void client2(MPI_Comm comm, Omega_h::Mesh& mesh, std::string comm_name, auto gids = layout->GetGidsHost(); const auto n = layout->GetNumOwnedDofHolder(); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); pcms::FieldLayoutCommunicator layout_comm(comm_name + "2", comm, rdv, channel, *layout); pcms::FieldCommunicator field_comm(layout_comm.GetName(), @@ -224,7 +220,7 @@ void server(MPI_Comm comm, Omega_h::Mesh& mesh, std::string comm_name, "id 0", Kokkos::RangePolicy(0, n), [=](int i) { ids[i] = 0; }); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); pcms::FieldLayoutCommunicator layout_comm1(comm_name + "1", comm, rdv, channel1, *layout); pcms::FieldLayoutCommunicator layout_comm2(comm_name + "2", comm, rdv, diff --git a/test/test_field_copy.cpp b/test/test_field_copy.cpp index 9906bbbc..d9039eb1 100644 --- a/test/test_field_copy.cpp +++ b/test/test_field_copy.cpp @@ -29,12 +29,12 @@ void test_copy(Omega_h::CommPtr world, int dim, int order, int num_components) Kokkos::RangePolicy(0, ndata), [=](int i) { ids[i] = i; }); - auto original = factory.CreateField(pcms::FieldMetadata{}); + auto original = factory.CreateField(); original.SetDOFHolderDataHost( pcms::Rank2View( ids.data(), layout->GetNumOwnedDofHolder(), num_components)); - auto copied = factory.CreateField(pcms::FieldMetadata{}); + auto copied = factory.CreateField(); pcms::Copy copy(factory, factory); copy.Apply(original, copied); auto copied_array = pcms::FlattenToRank1View(copied.GetDOFHolderDataHost()); diff --git a/test/test_field_evaluation.cpp b/test/test_field_evaluation.cpp index c4a29378..6f10480f 100644 --- a/test/test_field_evaluation.cpp +++ b/test/test_field_evaluation.cpp @@ -30,7 +30,7 @@ TEST_CASE("evaluate linear 2d omega_h_field") 100, 0, false); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); pcms::test::SetField( field.GetData(), *factory.GetLayout(), @@ -75,7 +75,7 @@ TEST_CASE("evaluate quadratic 2d meshfields_field") }); Omega_h::HostWrite test_f_host(test_f); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); field.GetData().SetDOFHolderDataHost( pcms::Rank2View(test_f_host.data(), test_f_host.size(), 1)); diff --git a/test/test_field_interpolation.cpp b/test/test_field_interpolation.cpp index fdada727..21549571 100644 --- a/test/test_field_interpolation.cpp +++ b/test/test_field_interpolation.cpp @@ -27,8 +27,8 @@ TEST_CASE("interpolate linear 2d omega_h_field") Omega_h::build_box(world, OMEGA_H_SIMPLEX, 1, 1, 0, 100, 100, 0, false); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(pcms::FieldMetadata{}); - auto interpolated = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); + auto interpolated = factory.CreateField(); pcms::test::SetField( field, OMEGA_H_LAMBDA(Real x, Real y) { return -0.3 * x + 0.5 * y; }); @@ -80,8 +80,8 @@ TEST_CASE("interpolate quadratic 2d meshfields_field") }); Omega_h::HostWrite test_f_host(test_f); - auto field = factory2.CreateField(pcms::FieldMetadata{}); - auto interpolated = factory2.CreateField(pcms::FieldMetadata{}); + auto field = factory2.CreateField(); + auto interpolated = factory2.CreateField(); field.SetDOFHolderDataHost(pcms::Rank2View( test_f_host.data(), test_f_host.size(), 1)); @@ -126,8 +126,8 @@ TEST_CASE("Interpolator: construct once, apply twice with different data") auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto source = factory.CreateField(pcms::FieldMetadata{}); - auto target = factory.CreateField(pcms::FieldMetadata{}); + auto source = factory.CreateField(); + auto target = factory.CreateField(); // Construct Interpolator once — localization happens here. // Because source and target share the same layout (same factory), diff --git a/test/test_omega_h_field2_outofbounds.cpp b/test/test_omega_h_field2_outofbounds.cpp index da0cd338..dd8d8c94 100644 --- a/test/test_omega_h_field2_outofbounds.cpp +++ b/test/test_omega_h_field2_outofbounds.cpp @@ -19,7 +19,7 @@ TEST_CASE("omega_h_field2 out of bounds FILL mode") Omega_h::build_box(world, OMEGA_H_SIMPLEX, 1, 1, 0, 10, 10, 0, false); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); pcms::test::SetField( field.GetData(), *factory.GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + y; }); diff --git a/test/test_omega_h_lagrange_field.cpp b/test/test_omega_h_lagrange_field.cpp index 259a0165..64a9a0b6 100644 --- a/test/test_omega_h_lagrange_field.cpp +++ b/test/test_omega_h_lagrange_field.cpp @@ -115,8 +115,8 @@ TEST_CASE("OmegaHLagrangeLayout layout sharing") auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto f1 = factory.CreateField(pcms::FieldMetadata{}); - auto f2 = factory.CreateField(pcms::FieldMetadata{}); + auto f1 = factory.CreateField(); + auto f2 = factory.CreateField(); REQUIRE(&f1.GetLayout() == &f2.GetLayout()); } @@ -129,7 +129,7 @@ TEST_CASE("OmegaHLagrangeField order-1: set/get DOF data round-trip") auto mesh = MakeBox2D(lib.world()); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); int n = factory.GetLayout()->GetNumOwnedDofHolder(); std::vector data(n); @@ -151,7 +151,7 @@ TEST_CASE("OmegaHLagrangeField order-1: linear function evaluation") auto mesh = MakeBox2D(lib.world(), 20, 20); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); pcms::test::SetField( field.GetData(), *factory.GetLayout(), @@ -169,7 +169,7 @@ TEST_CASE("MeshFieldsAdapter order-1: linear function evaluation (shared util)") auto mesh = MakeBox2D(lib.world(), 20, 20); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); pcms::test::SetField( field.GetData(), *factory.GetLayout(), @@ -185,7 +185,7 @@ TEST_CASE("OmegaHLagrangeField order-1: out-of-bounds FILL mode") auto mesh = MakeBox2D(lib.world()); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); pcms::test::SetField( field.GetData(), *factory.GetLayout(), @@ -202,7 +202,7 @@ TEST_CASE("OmegaHLagrangeField order-1: serialize / deserialize round-trip") auto mesh = MakeBox2D(lib.world()); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); pcms::test::SetField( field.GetData(), *factory.GetLayout(), @@ -221,7 +221,7 @@ TEST_CASE( auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, nc, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); const int n = factory.GetLayout()->GetNumOwnedDofHolder(); std::vector data(static_cast(n) * nc); @@ -242,7 +242,7 @@ TEST_CASE("OmegaHLagrangeField order-0: set/get DOF data round-trip") auto mesh = MakeBox2D(lib.world()); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 0, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); int n = factory.GetLayout()->GetNumOwnedDofHolder(); std::vector data(n, 3.14); @@ -261,7 +261,7 @@ TEST_CASE("OmegaHLagrangeField order-0: constant field evaluation") auto mesh = MakeBox2D(lib.world(), 10, 10); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 0, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); const Real kValue = 42.0; int nelems = mesh.nelems(); @@ -296,7 +296,7 @@ TEST_CASE("OmegaHLagrangeField order-0: out-of-bounds FILL mode") auto mesh = MakeBox2D(lib.world()); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 0, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); int nelems = mesh.nelems(); std::vector data(nelems, 1.0); @@ -315,7 +315,7 @@ TEST_CASE("OmegaHLagrangeField order-0: serialize / deserialize round-trip") auto mesh = MakeBox2D(lib.world()); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 0, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); int nelems = mesh.nelems(); std::vector data(nelems); @@ -353,7 +353,7 @@ TEST_CASE("OmegaHLagrangeField: field valid after layout destruction") { auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - field.emplace(factory.CreateField(pcms::FieldMetadata{})); + field.emplace(factory.CreateField()); } // factory goes out of scope; field keeps layout alive pcms::test::SetField( diff --git a/test/test_polynomial_reconstruction_function_space.cpp b/test/test_polynomial_reconstruction_function_space.cpp index 1f3b675a..1b725ab7 100644 --- a/test/test_polynomial_reconstruction_function_space.cpp +++ b/test/test_polynomial_reconstruction_function_space.cpp @@ -64,8 +64,8 @@ TEST_CASE("PolynomialReconstructionFunctionSpace fields share layout") auto factory = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian); - auto source = factory.CreateField(pcms::FieldMetadata{}); - auto target = factory.CreateField(pcms::FieldMetadata{}); + auto source = factory.CreateField(); + auto target = factory.CreateField(); REQUIRE(&source.GetLayout() == &target.GetLayout()); } @@ -78,7 +78,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace point-cloud field set/get DOF " auto field = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian) - .CreateField(pcms::FieldMetadata{}); + .CreateField(); std::vector data{1.0, 2.0, 3.0, 4.0}; Rank2View data_view( @@ -100,7 +100,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace point-cloud field serialize / " auto factory = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); std::vector data{5.0, 6.0, 7.0, 8.0}; Rank2View data_view( @@ -119,7 +119,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace field keeps layout alive " auto field = [&]() { auto factory = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian); - return factory.CreateField(pcms::FieldMetadata{}); + return factory.CreateField(); }(); auto point_cloud_layout = diff --git a/test/test_polynomial_reconstruction_mls_evaluation.cpp b/test/test_polynomial_reconstruction_mls_evaluation.cpp index 8b979e68..6527e9e0 100644 --- a/test/test_polynomial_reconstruction_mls_evaluation.cpp +++ b/test/test_polynomial_reconstruction_mls_evaluation.cpp @@ -119,7 +119,7 @@ void CheckPolynomialReproduction(unsigned degree, auto fs = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian, SweepTestOptions(degree, basis)); - auto field = fs.CreateField(pcms::FieldMetadata{}); + auto field = fs.CreateField(); pcms::test::SetField(field.GetData(), *fs.GetLayout(), func); auto pts = QueryPoints(); @@ -170,8 +170,8 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: same PointEvaluator " auto fs = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian, DefaultTestOptions()); - auto field_a = fs.CreateField(pcms::FieldMetadata{}); - auto field_b = fs.CreateField(pcms::FieldMetadata{}); + auto field_a = fs.CreateField(); + auto field_b = fs.CreateField(); pcms::test::SetField( field_a.GetData(), *fs.GetLayout(), @@ -226,7 +226,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: Evaluate throws for " auto fs = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian); - auto field = fs.CreateField(pcms::FieldMetadata{}); + auto field = fs.CreateField(); auto pts = QueryPoints(); int n = static_cast(pts.size()) / 2; @@ -258,7 +258,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: default MLSOptions — " // Use default options — no third argument auto fs = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian); - auto field = fs.CreateField(pcms::FieldMetadata{}); + auto field = fs.CreateField(); pcms::test::SetField( field.GetData(), *fs.GetLayout(), OMEGA_H_LAMBDA(Real, Real) { return Real(1.0); }); @@ -332,7 +332,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: radius option is " auto fs = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian, opts); - auto field = fs.CreateField(pcms::FieldMetadata{}); + auto field = fs.CreateField(); std::vector dof_values{1.0, 5.0}; field.GetData().SetDOFHolderDataHost(Rank2View( dof_values.data(), static_cast(dof_values.size()), 1)); @@ -374,7 +374,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: 3D point clouds preserve " REQUIRE(layout_coords(i, 2) == Catch::Approx(src[3 * i + 2])); } - auto field = fs.CreateField(pcms::FieldMetadata{}); + auto field = fs.CreateField(); std::vector dof_values(27); for (int i = 0; i < 27; ++i) { const Real x = src[3 * i + 0]; diff --git a/test/test_proxy_coupling.cpp b/test/test_proxy_coupling.cpp index 455fc183..c0fbce75 100644 --- a/test/test_proxy_coupling.cpp +++ b/test/test_proxy_coupling.cpp @@ -90,11 +90,11 @@ void xgc_delta_f(MPI_Comm comm, Omega_h::Mesh& mesh) pcms::Application* app = coupler.AddApplication("proxy_couple_xgc_delta_f"); auto factory = pcms::LagrangeFunctionSpace::FromMesh( - mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - app->AddLayout("gids", factory.GetLayout()); + mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", + pcms::LagrangeFunctionSpace::DefaultBackend, "gids"); - auto gids_field = factory.CreateField(pcms::FieldMetadata{}); - auto gids2_field = factory.CreateField(pcms::FieldMetadata{}); + auto gids_field = factory.CreateField("gids"); + auto gids2_field = factory.CreateField("gids2"); auto* gids_ptr = &gids_field.GetData(); auto* gids2_ptr = &gids2_field.GetData(); @@ -102,8 +102,8 @@ void xgc_delta_f(MPI_Comm comm, Omega_h::Mesh& mesh) initializeFieldWithGids(*factory.GetLayout(), gids_ptr, 1.0); initializeFieldWithGids(*factory.GetLayout(), gids2_ptr, 2.0); - app->AddField("gids", std::move(gids_field)); - app->AddField("gids2", std::move(gids2_field)); + app->AddField(std::move(gids_field)); + app->AddField(std::move(gids2_field)); do { for (int i = 0; i < COMM_ROUNDS; ++i) { @@ -131,16 +131,16 @@ void xgc_total_f(MPI_Comm comm, Omega_h::Mesh& mesh) pcms::Application* app = coupler.AddApplication("proxy_couple_xgc_total_f"); auto factory = pcms::LagrangeFunctionSpace::FromMesh( - mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - app->AddLayout("gids", factory.GetLayout()); + mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", + pcms::LagrangeFunctionSpace::DefaultBackend, "gids"); - auto gids_field = factory.CreateField(pcms::FieldMetadata{}); + auto gids_field = factory.CreateField("gids"); auto* gids_ptr = &gids_field.GetData(); initializeFieldWithGids(*factory.GetLayout(), gids_ptr, 10.0); - app->AddField("gids", std::move(gids_field)); + app->AddField(std::move(gids_field)); do { for (int i = 0; i < COMM_ROUNDS; ++i) { @@ -173,27 +173,24 @@ void xgc_coupler(MPI_Comm comm, Omega_h::Mesh& mesh, std::string_view cpn_file) auto* total_f = cpl.AddApplication("proxy_couple_xgc_total_f"); auto* delta_f = cpl.AddApplication("proxy_couple_xgc_delta_f"); auto factory_total = pcms::LagrangeFunctionSpace::FromMesh( - mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - total_f->AddLayout("gids", factory_total.GetLayout()); + mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", + pcms::LagrangeFunctionSpace::DefaultBackend, "gids"); auto factory_delta = pcms::LagrangeFunctionSpace::FromMesh( - mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - delta_f->AddLayout("gids", factory_delta.GetLayout()); + mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", + pcms::LagrangeFunctionSpace::DefaultBackend, "gids"); // TODO, fields should have a transfer policy rather than parameters - auto total_gids_field = - factory_total.CreateField(pcms::FieldMetadata{}); - auto delta_gids_field = - factory_delta.CreateField(pcms::FieldMetadata{}); - auto delta_gids2_field = - factory_delta.CreateField(pcms::FieldMetadata{}); + auto total_gids_field = factory_total.CreateField("gids"); + auto delta_gids_field = factory_delta.CreateField("gids"); + auto delta_gids2_field = factory_delta.CreateField("gids2"); auto* total_gids_ptr = &total_gids_field.GetData(); auto* delta_gids_ptr = &delta_gids_field.GetData(); auto* delta_gids2_ptr = &delta_gids2_field.GetData(); - total_f->AddField("gids", std::move(total_gids_field)); - delta_f->AddField("gids", std::move(delta_gids_field)); - delta_f->AddField("gids2", std::move(delta_gids2_field)); + total_f->AddField(std::move(total_gids_field)); + delta_f->AddField(std::move(delta_gids_field)); + delta_f->AddField(std::move(delta_gids2_field)); do { for (int i = 0; i < COMM_ROUNDS; ++i) { diff --git a/test/test_proxy_coupling_xgc_server.cpp b/test/test_proxy_coupling_xgc_server.cpp index 4a76b748..938290db 100644 --- a/test/test_proxy_coupling_xgc_server.cpp +++ b/test/test_proxy_coupling_xgc_server.cpp @@ -51,17 +51,17 @@ void xgc_coupler(MPI_Comm comm, Omega_h::Mesh& mesh, std::string_view cpn_file) // FIXME: The current C/Fortran proxy API couples layout registration to // field registration, so each XGC plane is registered as a separate layout // communicator even though the layouts are geometrically identical. - auto function_space = pcms::XGCFunctionSpace( - rc, ts::IsModelEntInOverlap{}, static_cast(mesh.nverts())); + auto function_space = + pcms::XGCFunctionSpace(rc, ts::IsModelEntInOverlap{}, + static_cast(mesh.nverts()), ss.str()); auto field = function_space.CreateField( - std::make_unique>( - function_space.GetXGCLayout(), pcms::FieldMetadata{}, - make_array_view(data[i]))); - application->AddLayout(ss.str(), function_space.GetLayout()); + ss.str(), std::make_unique>( + function_space.GetXGCLayout(), pcms::FieldMetadata{}, + make_array_view(data[i]))); std::unique_ptr> serializer = std::make_unique>(comm); fields.push_back( - application->AddField(ss.str(), std::move(field), std::move(serializer))); + application->AddField(std::move(field), std::move(serializer))); } do { @@ -172,15 +172,14 @@ void omegah_coupler(MPI_Comm comm, Omega_h::Mesh& mesh, // communicator even though the layouts are geometrically identical. auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian, numbering, - pcms::LagrangeFunctionSpace::Backend::OmegaH); - application->AddLayout(ss.str(), factory.GetLayout()); - auto field = - factory.CreateField(std::make_unique>( - factory.GetLayout(), pcms::FieldMetadata{})); + pcms::LagrangeFunctionSpace::Backend::OmegaH, ss.str()); + auto field = factory.CreateField( + ss.str(), std::make_unique>( + factory.GetLayout(), pcms::FieldMetadata{})); std::unique_ptr> serializer = std::make_unique>(); fields.push_back( - application->AddField(ss.str(), std::move(field), std::move(serializer))); + application->AddField(std::move(field), std::move(serializer))); } do { application->ReceivePhase([&]() { diff --git a/test/test_proxy_coupling_xgc_server_overlap.cpp b/test/test_proxy_coupling_xgc_server_overlap.cpp index 0161ee4e..b12d9f80 100644 --- a/test/test_proxy_coupling_xgc_server_overlap.cpp +++ b/test/test_proxy_coupling_xgc_server_overlap.cpp @@ -54,21 +54,20 @@ void xgc_coupler_with_overlap(MPI_Comm comm, Omega_h::Mesh& mesh, application->SetLayoutOverlapMask(ss.str(), std::move(overlap_mask)); - auto function_space = pcms::XGCFunctionSpace( - rc, ts::IsModelEntInOverlap{}, static_cast(mesh.nverts())); - - application->AddLayout(ss.str(), function_space.GetLayout()); + auto function_space = + pcms::XGCFunctionSpace(rc, ts::IsModelEntInOverlap{}, + static_cast(mesh.nverts()), ss.str()); auto field = function_space.CreateField( - std::make_unique>( - function_space.GetXGCLayout(), pcms::FieldMetadata{}, - make_array_view(data[i]))); + ss.str(), std::make_unique>( + function_space.GetXGCLayout(), pcms::FieldMetadata{}, + make_array_view(data[i]))); std::unique_ptr> serializer = std::make_unique>(comm); fields.push_back( - application->AddField(ss.str(), std::move(field), std::move(serializer))); + application->AddField(std::move(field), std::move(serializer))); } do { @@ -175,19 +174,17 @@ void omegah_coupler_with_overlap(MPI_Comm comm, Omega_h::Mesh& mesh, auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian, numbering, - pcms::LagrangeFunctionSpace::Backend::OmegaH); - - application->AddLayout(ss.str(), factory.GetLayout()); + pcms::LagrangeFunctionSpace::Backend::OmegaH, ss.str()); - auto field = - factory.CreateField(std::make_unique>( - factory.GetLayout(), pcms::FieldMetadata{})); + auto field = factory.CreateField( + ss.str(), std::make_unique>( + factory.GetLayout(), pcms::FieldMetadata{})); std::unique_ptr> serializer = std::make_unique>(); fields.push_back( - application->AddField(ss.str(), std::move(field), std::move(serializer))); + application->AddField(std::move(field), std::move(serializer))); } do { diff --git a/test/test_uniform_grid_field.cpp b/test/test_uniform_grid_field.cpp index b179167d..5afff3f2 100644 --- a/test/test_uniform_grid_field.cpp +++ b/test/test_uniform_grid_field.cpp @@ -109,7 +109,7 @@ TEST_CASE("UniformGrid field creation") auto field_space = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian); - auto field = field_space.CreateField(pcms::FieldMetadata{}); + auto field = field_space.CreateField(); REQUIRE(field.GetDOFHolderDataHost().size() == static_cast(layout->OwnedSize())); } @@ -125,7 +125,7 @@ TEST_CASE("UniformGrid order-0 field creation and evaluation") grid, 1, pcms::CoordinateSystem::Cartesian, 0); auto field_space = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian, 0); - auto field = field_space.CreateField(pcms::FieldMetadata{}); + auto field = field_space.CreateField(); pcms::UniformGridEvaluatorFactory<2> eval_factory(layout); REQUIRE(layout->GetOrder() == 0); @@ -179,7 +179,7 @@ TEST_CASE("UniformGrid field data operations", "[uniform_grid_field]") grid, 1, pcms::CoordinateSystem::Cartesian); auto field_space = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian); - auto field = field_space.CreateField(pcms::FieldMetadata{}); + auto field = field_space.CreateField(); std::vector data(25); for (size_t i = 0; i < 25; ++i) @@ -206,7 +206,7 @@ TEST_CASE("UniformGrid field evaluation - piecewise constant") grid, 1, pcms::CoordinateSystem::Cartesian); auto field_space = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian); - auto field = field_space.CreateField(pcms::FieldMetadata{}); + auto field = field_space.CreateField(); pcms::UniformGridEvaluatorFactory<2> eval_factory(layout); // Set vertex values for a 2x2 cell grid (3x3 = 9 vertices) @@ -269,7 +269,7 @@ TEST_CASE("UniformGrid field serialization") grid, 1, pcms::CoordinateSystem::Cartesian); auto field_space = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian); - auto field = field_space.CreateField(pcms::FieldMetadata{}); + auto field = field_space.CreateField(); std::vector data(16); for (size_t i = 0; i < 16; ++i) @@ -303,12 +303,12 @@ TEST_CASE("UniformGrid field copy") auto factory = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(pcms::FieldMetadata{}); + auto field = factory.CreateField(); field.SetDOFHolderDataHost( pcms::Rank2View( data.data(), static_cast(data.size()), 1)); - auto field2 = factory.CreateField(pcms::FieldMetadata{}); + auto field2 = factory.CreateField(); pcms::Copy copy(factory, factory); copy.Apply(field, field2); @@ -326,8 +326,7 @@ TEST_CASE("Transfer from OmegaH field to UniformGrid field") auto omega_h_factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto omega_h_field = - omega_h_factory.CreateField(pcms::FieldMetadata{}); + auto omega_h_field = omega_h_factory.CreateField(); pcms::test::SetField( omega_h_field, OMEGA_H_LAMBDA(pcms::Real x, pcms::Real y) { return x + 2.0 * y; }); @@ -338,7 +337,7 @@ TEST_CASE("Transfer from OmegaH field to UniformGrid field") grid.divisions = {2, 2}; auto ug_factory = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian); - auto ug_field = ug_factory.CreateField(pcms::FieldMetadata{}); + auto ug_field = ug_factory.CreateField(); pcms::Interpolator interp(omega_h_factory, ug_factory); interp.Apply(omega_h_field, ug_field); @@ -640,15 +639,14 @@ TEST_CASE("UniformGrid workflow") auto omega_h_factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto omega_h_field = - omega_h_factory.CreateField(pcms::FieldMetadata{}); + auto omega_h_field = omega_h_factory.CreateField(); pcms::test::SetField( omega_h_field, OMEGA_H_LAMBDA(pcms::Real x, pcms::Real y) { return x + 2.0 * y; }); auto ug_factory = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian); - auto ug_field = ug_factory.CreateField(pcms::FieldMetadata{}); + auto ug_field = ug_factory.CreateField(); auto [mask_layout, mask_field] = pcms::CreateUniformGridBinaryField<2>(mesh, grid); diff --git a/test/test_xgc_field_data.cpp b/test/test_xgc_field_data.cpp index 234bd2d1..16322cf9 100644 --- a/test/test_xgc_field_data.cpp +++ b/test/test_xgc_field_data.cpp @@ -113,9 +113,9 @@ TEST_CASE("XGCFunctionSpace creates fields and rejects evaluator access") std::vector data(data_size); std::iota(data.begin(), data.end(), 0.0); auto field = function_space.CreateField( - std::make_unique>( - function_space.GetXGCLayout(), pcms::FieldMetadata{}, - pcms::make_array_view(data))); + "", std::make_unique>( + function_space.GetXGCLayout(), pcms::FieldMetadata{}, + pcms::make_array_view(data))); REQUIRE(&field.GetLayout() == function_space.GetLayout().get()); REQUIRE(function_space.GetCoordinateSystem() == pcms::CoordinateSystem::XGC); diff --git a/test/xgc_n0_coupling_server.cpp b/test/xgc_n0_coupling_server.cpp index ddbac140..e420b41c 100644 --- a/test/xgc_n0_coupling_server.cpp +++ b/test/xgc_n0_coupling_server.cpp @@ -48,11 +48,10 @@ static RegisteredField AddField( { PCMS_ALWAYS_ASSERT(application != nullptr); auto field_name = MakeFieldName(name, plane); - auto field = function_space.CreateField(pcms::FieldMetadata{}); + auto field = function_space.CreateField(path + field_name); std::unique_ptr> serializer = std::make_unique>(); - auto handle = application->AddField(path + field_name, std::move(field), - std::move(serializer)); + auto handle = application->AddField(std::move(field), std::move(serializer)); return {std::move(handle)}; } @@ -220,10 +219,7 @@ void omegah_coupler(MPI_Comm comm, Omega_h::Mesh& mesh, }); auto function_space = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian, is_overlap, numbering, - pcms::LagrangeFunctionSpace::Backend::OmegaH); - auto layout = function_space.GetLayout(); - core->AddLayout("core_layout", layout); - edge->AddLayout("edge_layout", layout); + pcms::LagrangeFunctionSpace::Backend::OmegaH, "n0_layout"); auto time2 = std::chrono::steady_clock::now(); elapsed_seconds = time2 - time1; ts::timeMinMaxAvg(elapsed_seconds.count(), min, max, avg); From 313c4ed68cbe0a2567eb9713133fc8404b5cea17 Mon Sep 17 00:00:00 2001 From: Jacob Merson Date: Sun, 12 Jul 2026 01:39:51 -0400 Subject: [PATCH 3/4] Fix the CreateFunction / CreateField split With Function being the object that handles evaluatable fields and Field being the non-evaluatable object that can be used for sending over the network. This commit makes the function naming/usage consisent. --- src/pcms/capi/client.cpp | 28 ++--- src/pcms/field/eqdsk_field.h | 6 +- src/pcms/field/field.h | 6 +- src/pcms/field/field_factory.h | 101 +++++++++++++++ src/pcms/field/function_space.h | 115 +++--------------- src/pcms/field/function_space/lagrange.cpp | 30 ++--- src/pcms/field/function_space/lagrange.h | 25 ++-- .../polynomial_reconstruction.cpp | 14 +-- .../polynomial_reconstruction.hpp | 27 ++-- src/pcms/field/function_space/spline.cpp | 7 +- src/pcms/field/function_space/spline.h | 17 ++- src/pcms/field/function_space/xgc.h | 43 +++---- src/pcms/field/uniform_grid_binary_field.h | 4 +- src/pcms/pythonapi/bind_field_base.cpp | 4 +- .../omega_h_control_variate_projection.cpp | 2 +- test/field_test_utils.h | 12 +- test/test_eqdsk.cpp | 6 +- test/test_field_communication.cpp | 20 +-- test/test_field_copy.cpp | 8 +- test/test_field_evaluation.cpp | 6 +- test/test_field_interpolation.cpp | 20 +-- .../test_mesh_intersection_field_transfer.cpp | 44 +++---- test/test_omega_h_field2_outofbounds.cpp | 4 +- ...st_omega_h_intersection_rhs_integrator.cpp | 33 ++--- test/test_omega_h_lagrange_field.cpp | 50 ++++---- test/test_omega_h_mass_integrator.cpp | 12 +- test/test_omega_h_mc_rhs_integrator.cpp | 41 ++++--- test/test_point_evaluator.cpp | 76 ++++++------ ...lynomial_reconstruction_function_space.cpp | 30 ++--- ...lynomial_reconstruction_mls_evaluation.cpp | 40 +++--- test/test_proxy_coupling.cpp | 26 ++-- test/test_proxy_coupling_xgc_server.cpp | 8 +- ...test_proxy_coupling_xgc_server_overlap.cpp | 8 +- test/test_uniform_grid_field.cpp | 34 +++--- test/test_xgc_field_data.cpp | 15 +-- test/xgc_n0_coupling_server.cpp | 6 +- 36 files changed, 473 insertions(+), 455 deletions(-) create mode 100644 src/pcms/field/field_factory.h diff --git a/src/pcms/capi/client.cpp b/src/pcms/capi/client.cpp index 24ae038c..485e3c12 100644 --- a/src/pcms/capi/client.cpp +++ b/src/pcms/capi/client.cpp @@ -1,5 +1,6 @@ #include "client.h" #include "pcms.h" +#include "pcms/field/field_factory.h" #include "pcms/field/function_space/xgc.h" #include "pcms/field/data/xgc.h" #include "pcms/field/layout/xgc.h" @@ -23,11 +24,11 @@ namespace detail template struct XGCFieldRegistration { - XGCFunctionSpace function_space; + XGCFieldFactory function_space; MPI_Comm plane_comm; Rank1View data; - XGCFieldRegistration(XGCFunctionSpace fs, MPI_Comm comm, + XGCFieldRegistration(XGCFieldFactory fs, MPI_Comm comm, Rank1View d) : function_space(std::move(fs)), plane_comm(comm), data(d) { @@ -37,10 +38,10 @@ struct XGCFieldRegistration struct DummyFieldRegistration {}; -class EmptyFunctionSpace : public FunctionSpace +class EmptyFieldFactory : public FieldFactory { public: - explicit EmptyFunctionSpace(std::string layout_name = "") + explicit EmptyFieldFactory(std::string layout_name = "") { auto layout = std::make_shared(); layout->SetName(std::move(layout_name)); @@ -53,11 +54,6 @@ class EmptyFunctionSpace : public FunctionSpace return layout_; } - [[nodiscard]] CoordinateSystem GetCoordinateSystem() const noexcept override - { - return CoordinateSystem::Cartesian; - } - protected: [[nodiscard]] FieldVariant CreateFieldImpl( Type value_type, FieldMetadata metadata) const override @@ -80,12 +76,12 @@ class EmptyFunctionSpace : public FunctionSpace PCMS_ALWAYS_ASSERT(fd != nullptr); if (dynamic_cast*>(fd.get()) == nullptr) { throw pcms_error( - "EmptyFunctionSpace::CreateField: requires SimpleFieldData"); + "EmptyFieldFactory::CreateField: requires SimpleFieldData"); } if (fd->GetDOFHolderDataHost().size() != detail::ExpectedFlatFieldDataSize(*layout_)) { throw pcms_error( - "EmptyFunctionSpace::CreateField: field data size does not match " + "EmptyFieldFactory::CreateField: field data size does not match " "layout"); } return WrapField(layout_, std::forward(fd)); @@ -93,12 +89,6 @@ class EmptyFunctionSpace : public FunctionSpace std::move(data)); } - [[nodiscard]] PointEvaluatorVariant CreatePointEvaluatorImpl( - Type /*value_type*/, const EvaluationRequest& /*request*/) const override - { - throw pcms_error("EmptyFunctionSpace does not support point evaluation"); - } - private: std::shared_ptr layout_; }; @@ -153,7 +143,7 @@ inline ClientState::HandleVariant RegisterField( Application& app, std::string name, const detail::DummyFieldRegistration&, bool participates) { - auto function_space = detail::EmptyFunctionSpace{name}; + auto function_space = detail::EmptyFieldFactory{name}; auto field = function_space.CreateField(std::move(name), FieldMetadata{}); std::unique_ptr> serializer = @@ -258,7 +248,7 @@ void pcms_create_xgc_field_adapter_t( { PCMS_ALWAYS_ASSERT((size > 0) ? (data != nullptr) : true); auto function_space = - pcms::XGCFunctionSpace(reverse_classification, in_overlap, size); + pcms::XGCFieldFactory(reverse_classification, in_overlap, size); pcms::Rank1View data_view( reinterpret_cast(data), size); field_adapter.emplace>( diff --git a/src/pcms/field/eqdsk_field.h b/src/pcms/field/eqdsk_field.h index bb4188c8..05e8308d 100644 --- a/src/pcms/field/eqdsk_field.h +++ b/src/pcms/field/eqdsk_field.h @@ -12,7 +12,7 @@ namespace pcms struct EQDSKField { - SplineFunctionSpace space; + std::shared_ptr space; Field field; }; @@ -20,7 +20,7 @@ struct EQDSKField struct EQDSKFieldWithData { EQDSKData data; - SplineFunctionSpace space; + std::shared_ptr space; Field field; }; @@ -43,7 +43,7 @@ inline EQDSKField MakeEQDSKField(const EQDSKData& eqdsk_data) { auto space = SplineFunctionSpace::FromUniformGrid( eqdsk_data.grid, CoordinateSystem::Cartesian); - auto field = space.CreateField(); + Field field = space->CreateFunction(); field.GetData().SetDOFHolderData(Rank2View( eqdsk_data.PSIZR.data(), eqdsk_data.PSIZR.extent(0), 1)); return {std::move(space), std::move(field)}; diff --git a/src/pcms/field/field.h b/src/pcms/field/field.h index 4b4a91c0..6da4261d 100644 --- a/src/pcms/field/field.h +++ b/src/pcms/field/field.h @@ -68,8 +68,10 @@ class Field { } - // FunctionSpace constructs Fields (via WrapField) and moves a Field's name, - // layout and data out to build a Function (via CreateFunction). + // FieldFactory constructs Fields (via WrapField); FunctionSpace constructs + // Fields the same way and moves a Field's name, layout and data out to build + // a Function (via CreateFunction). Both stamp the field name. + friend class FieldFactory; friend class FunctionSpace; private: diff --git a/src/pcms/field/field_factory.h b/src/pcms/field/field_factory.h new file mode 100644 index 00000000..6aa63a34 --- /dev/null +++ b/src/pcms/field/field_factory.h @@ -0,0 +1,101 @@ +#ifndef PCMS_FIELD_FACTORY_H +#define PCMS_FIELD_FACTORY_H + +#include "field.h" +#include "field_data.h" +#include "field_layout.h" +#include "field_metadata.h" +#include "pcms/utility/types.h" +#include +#include + +namespace pcms +{ + +namespace detail +{ + +inline size_t ExpectedFlatFieldDataSize(const FieldLayout& layout) +{ + return static_cast(layout.GetNumOwnedDofHolder()) * + static_cast(layout.GetNumComponents()); +} + +} // namespace detail + +// Compile-time gate: true only for the five supported field value types. +template +inline constexpr bool is_supported_field_type_v = + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || + std::is_same_v; + +// FieldFactory constructs Field bundles ({layout, data}) with no evaluation +// capability and no shared-ownership requirement. Comm-only backends (e.g. +// XGCFieldFactory) derive it directly. FunctionSpace is a separate abstraction +// (not a FieldFactory) that additionally supports evaluation and produces +// Functions; a FieldFactory can never be passed where a FunctionSpace is +// required, which is the compile-time form of "comm-only cannot be evaluated". +class FieldFactory +{ +public: + virtual std::shared_ptr GetLayout() const noexcept = 0; + + virtual ~FieldFactory() noexcept = default; + + // Create a new named field with freshly allocated data. The name is optional + // (empty by default) and identifies the field to consumers such as a coupler. + template + [[nodiscard]] Field CreateField(std::string name = "", + FieldMetadata metadata = {}) const; + + // Expert API: wrap externally constructed field data into a Field. The + // concrete factory validates backend-specific field-data type and storage + // size compatibility. + template + [[nodiscard]] Field CreateField(std::string name, + std::unique_ptr> data) const; + +protected: + template + static Field WrapField(std::shared_ptr layout, + std::unique_ptr> data) + { + return Field(std::string{}, std::move(layout), std::move(data)); + } + + virtual FieldVariant CreateFieldImpl(Type value_type, + FieldMetadata metadata) const = 0; + + virtual FieldVariant CreateFieldImpl(FieldDataVariant data) const = 0; +}; + +template +Field FieldFactory::CreateField(std::string name, FieldMetadata metadata) const +{ + static_assert(is_supported_field_type_v, + "T is not a supported field type"); + Field field = + std::get>(CreateFieldImpl(TypeEnumFromType(), metadata)); + field.name_ = std::move(name); + return field; +} + +template +Field FieldFactory::CreateField(std::string name, + std::unique_ptr> data) const +{ + static_assert(is_supported_field_type_v, + "T is not a supported field type"); + if (!data) { + throw pcms_error("FieldFactory::CreateField: data must not be null"); + } + Field field = + std::get>(CreateFieldImpl(FieldDataVariant{std::move(data)})); + field.name_ = std::move(name); + return field; +} + +} // namespace pcms + +#endif // PCMS_FIELD_FACTORY_H diff --git a/src/pcms/field/function_space.h b/src/pcms/field/function_space.h index 00e21dc9..26ef4fad 100644 --- a/src/pcms/field/function_space.h +++ b/src/pcms/field/function_space.h @@ -5,7 +5,7 @@ #include "evaluation_request.h" #include "field.h" #include "field_data.h" -#include "field_evaluator_factory.h" +#include "field_factory.h" #include "field_layout.h" #include "field_metadata.h" #include "out_of_bounds_policy.h" @@ -20,37 +20,17 @@ namespace pcms { -namespace detail -{ - -inline size_t ExpectedFlatFieldDataSize(const FieldLayout& layout) -{ - return static_cast(layout.GetNumOwnedDofHolder()) * - static_cast(layout.GetNumComponents()); -} - -} // namespace detail - -// Compile-time gate: true only for the five supported field value types. -template -inline constexpr bool is_supported_field_type_v = - std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v || - std::is_same_v; - // FunctionSpace is an abstract interface representing an evaluatable field -// space: layout, evaluation rules, and coordinate interpretation. +// 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. -// -// FunctionSpace is used as the parameter type for operation objects such as -// Interpolator, so that operations are not coupled to a specific backend. -// -// FunctionSpace inherits enable_shared_from_this because CreateFunction stamps -// a shared_ptr into each Function it produces. Concrete -// spaces must therefore be owned by a shared_ptr (the From* factories return -// one); calling CreateFunction on a stack-allocated space throws bad_weak_ptr. +// 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 std::enable_shared_from_this { public: @@ -66,28 +46,13 @@ class FunctionSpace : public std::enable_shared_from_this virtual ~FunctionSpace() noexcept = default; - // Create a new named field with freshly allocated data for this function - // space. The name is optional (empty by default) and identifies the field to - // consumers such as a coupler. Compile-time error for unsupported T; runtime - // error for T unsupported by the concrete backend. - template - [[nodiscard]] Field CreateField(std::string name = "", - FieldMetadata metadata = {}) const; - - // Expert API: wrap externally constructed field data into a Field for this - // function space. The concrete function space validates backend-specific - // field-data type and storage size compatibility. - template - [[nodiscard]] Field CreateField(std::string name, - std::unique_ptr> data) const; - - // Like CreateField, but returns a Function that retains a shared reference to - // this space (so it can be evaluated / used to build transfer operators). - // Requires this space to be owned by a shared_ptr (see class note). template [[nodiscard]] Function CreateFunction(std::string name = "", FieldMetadata metadata = {}) 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 [[nodiscard]] Function CreateFunction( std::string name, std::unique_ptr> data) const; @@ -132,70 +97,30 @@ class FunctionSpace : public std::enable_shared_from_this Type value_type, const EvaluationRequest& request) const = 0; }; -// Wrap a by-value FunctionSpace (typically the result of a From* factory) in a -// shared_ptr so it can produce Functions and participate in transfers via -// AddFunction/CreateTransfer. Ordinary by-value use — CreateField, point -// evaluation, constructing a transfer operator directly — does not need this; -// only Function (which retains a shared_ptr) does. -// -// auto space = pcms::Share(LagrangeFunctionSpace::FromMesh(...)); -// auto fn = space->CreateFunction(); -template -[[nodiscard]] std::shared_ptr Share(Space&& space) -{ - static_assert( - std::is_base_of_v>, - "Share expects a FunctionSpace-derived type"); - return std::make_shared>( - std::forward(space)); -} - template -Field FunctionSpace::CreateField(std::string name, - FieldMetadata metadata) const +Function FunctionSpace::CreateFunction(std::string name, + FieldMetadata metadata) const { static_assert(is_supported_field_type_v, "T is not a supported field type"); Field field = std::get>(CreateFieldImpl(TypeEnumFromType(), metadata)); - field.name_ = std::move(name); - return field; + return WrapFunction(std::move(name), std::move(field.layout_), + std::move(field.data_), shared_from_this()); } template -Field FunctionSpace::CreateField(std::string name, - std::unique_ptr> data) const +Function FunctionSpace::CreateFunction( + std::string name, std::unique_ptr> data) const { static_assert(is_supported_field_type_v, "T is not a supported field type"); if (!data) { - throw pcms_error("FunctionSpace::CreateField: data must not be null"); + throw pcms_error("FunctionSpace::CreateFunction: data must not be null"); } Field field = std::get>(CreateFieldImpl(FieldDataVariant{std::move(data)})); - field.name_ = std::move(name); - return field; -} - -template -Function FunctionSpace::CreateFunction(std::string name, - FieldMetadata metadata) const -{ - static_assert(is_supported_field_type_v, - "T is not a supported field type"); - Field field = CreateField(std::move(name), metadata); - return WrapFunction(std::move(field.name_), std::move(field.layout_), - std::move(field.data_), shared_from_this()); -} - -template -Function FunctionSpace::CreateFunction( - std::string name, std::unique_ptr> data) const -{ - static_assert(is_supported_field_type_v, - "T is not a supported field type"); - Field field = CreateField(std::move(name), std::move(data)); - return WrapFunction(std::move(field.name_), std::move(field.layout_), + return WrapFunction(std::move(name), std::move(field.layout_), std::move(field.data_), shared_from_this()); } diff --git a/src/pcms/field/function_space/lagrange.cpp b/src/pcms/field/function_space/lagrange.cpp index 7a16f2af..8d15a6ec 100644 --- a/src/pcms/field/function_space/lagrange.cpp +++ b/src/pcms/field/function_space/lagrange.cpp @@ -54,7 +54,7 @@ void ValidateLagrangeWrappedFieldData(const FieldLayout& layout, } // namespace LagrangeFunctionSpace::LagrangeFunctionSpace( - std::shared_ptr layout, + Key, std::shared_ptr layout, std::function create_field_data_fn, std::shared_ptr> evaluator_factory) noexcept : layout_(std::move(layout)), @@ -63,7 +63,7 @@ LagrangeFunctionSpace::LagrangeFunctionSpace( { } -LagrangeFunctionSpace LagrangeFunctionSpace::FromMesh( +std::shared_ptr LagrangeFunctionSpace::FromMesh( Omega_h::Mesh& mesh, int order, int num_components, CoordinateSystem coordinate_system, std::string global_id_name, Backend backend, std::string layout_name) @@ -92,8 +92,8 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromMesh( mesh_layout->SetName(layout_name); auto eval_factory = std::make_shared>(mesh_layout); - return LagrangeFunctionSpace( - mesh_layout, + return std::make_shared( + Key{}, mesh_layout, [mesh_layout](Type t, FieldMetadata metadata) -> FieldDataVariant { if (t == Type::Float) { if constexpr (std::is_same_v || @@ -130,8 +130,8 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromMesh( layout->SetName(std::move(layout_name)); auto eval_factory = std::make_shared>(layout); - return LagrangeFunctionSpace( - layout, + return std::make_shared( + Key{}, layout, [layout](Type t, FieldMetadata metadata) -> FieldDataVariant { return apply_to_type(t, [&](auto tag) -> FieldDataVariant { using T = typename decltype(tag)::type; @@ -145,7 +145,7 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromMesh( std::move(eval_factory)); } -LagrangeFunctionSpace LagrangeFunctionSpace::FromMesh( +std::shared_ptr LagrangeFunctionSpace::FromMesh( Omega_h::Mesh& mesh, int order, int num_components, CoordinateSystem coordinate_system, Omega_h::Read owned_mask, std::string global_id_name, Backend backend, std::string layout_name) @@ -166,8 +166,8 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromMesh( layout->SetName(std::move(layout_name)); auto eval_factory = std::make_shared>(layout); - return LagrangeFunctionSpace( - layout, + return std::make_shared( + Key{}, layout, [layout](Type t, FieldMetadata metadata) -> FieldDataVariant { return apply_to_type(t, [&](auto tag) -> FieldDataVariant { using T = typename decltype(tag)::type; @@ -181,7 +181,7 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromMesh( std::move(eval_factory)); } -LagrangeFunctionSpace LagrangeFunctionSpace::FromUniformGrid( +std::shared_ptr LagrangeFunctionSpace::FromUniformGrid( const UniformGrid<2>& grid, int num_components, CoordinateSystem coordinate_system, int order, std::string layout_name) { @@ -194,8 +194,8 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromUniformGrid( ug_layout->SetName(std::move(layout_name)); auto eval_factory = std::make_shared>(ug_layout); - return LagrangeFunctionSpace( - ug_layout, + return std::make_shared( + Key{}, ug_layout, [ug_layout](Type t, FieldMetadata metadata) -> FieldDataVariant { return apply_to_type(t, [&](auto tag) -> FieldDataVariant { using T = typename decltype(tag)::type; @@ -209,7 +209,7 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromUniformGrid( std::move(eval_factory)); } -LagrangeFunctionSpace LagrangeFunctionSpace::FromUniformGrid( +std::shared_ptr LagrangeFunctionSpace::FromUniformGrid( const UniformGrid<3>& grid, int num_components, CoordinateSystem coordinate_system, int order, std::string layout_name) { @@ -222,8 +222,8 @@ LagrangeFunctionSpace LagrangeFunctionSpace::FromUniformGrid( ug_layout->SetName(std::move(layout_name)); auto eval_factory = std::make_shared>(ug_layout); - return LagrangeFunctionSpace( - ug_layout, + return std::make_shared( + Key{}, ug_layout, [ug_layout](Type t, FieldMetadata metadata) -> FieldDataVariant { return apply_to_type(t, [&](auto tag) -> FieldDataVariant { using T = typename decltype(tag)::type; diff --git a/src/pcms/field/function_space/lagrange.h b/src/pcms/field/function_space/lagrange.h index 8526d58e..d729d628 100644 --- a/src/pcms/field/function_space/lagrange.h +++ b/src/pcms/field/function_space/lagrange.h @@ -27,7 +27,19 @@ namespace pcms class LagrangeFunctionSpace : public FunctionSpace { + // Passkey: only members (the From* factories) can create a Key, so only they + // can construct a space, while std::make_shared can still call the ctor. + struct Key + { + explicit Key() = default; + }; + public: + LagrangeFunctionSpace( + Key, std::shared_ptr layout, + std::function create_field_data_fn, + std::shared_ptr> evaluator_factory) noexcept; + enum class Backend { MeshFields, @@ -41,12 +53,12 @@ class LagrangeFunctionSpace : public FunctionSpace #endif // Unstructured mesh — dispatches to MeshFields or native Omega_h backend - [[nodiscard]] static LagrangeFunctionSpace FromMesh( + [[nodiscard]] static std::shared_ptr FromMesh( Omega_h::Mesh& mesh, int order, int num_components, CoordinateSystem coordinate_system, std::string global_id_name = "global", Backend backend = DefaultBackend, std::string layout_name = ""); - [[nodiscard]] static LagrangeFunctionSpace FromMesh( + [[nodiscard]] static std::shared_ptr FromMesh( Omega_h::Mesh& mesh, int order, int num_components, CoordinateSystem coordinate_system, Omega_h::Read owned_mask, std::string global_id_name = "global", Backend backend = DefaultBackend, @@ -54,12 +66,12 @@ class LagrangeFunctionSpace : public FunctionSpace // Structured uniform grid — order-1 H1-conforming nodal field on a regular // grid - [[nodiscard]] static LagrangeFunctionSpace FromUniformGrid( + [[nodiscard]] static std::shared_ptr FromUniformGrid( const UniformGrid<2>& grid, int num_components, CoordinateSystem coordinate_system, int order = 1, std::string layout_name = ""); - [[nodiscard]] static LagrangeFunctionSpace FromUniformGrid( + [[nodiscard]] static std::shared_ptr FromUniformGrid( const UniformGrid<3>& grid, int num_components, CoordinateSystem coordinate_system, int order = 1, std::string layout_name = ""); @@ -80,11 +92,6 @@ class LagrangeFunctionSpace : public FunctionSpace Type value_type, const EvaluationRequest& request) const override; private: - explicit LagrangeFunctionSpace( - std::shared_ptr layout, - std::function create_field_data_fn, - std::shared_ptr> evaluator_factory) noexcept; - std::shared_ptr layout_; std::function create_field_data_fn_; std::shared_ptr> evaluator_factory_; diff --git a/src/pcms/field/function_space/polynomial_reconstruction.cpp b/src/pcms/field/function_space/polynomial_reconstruction.cpp index d26beec1..397e5f7c 100644 --- a/src/pcms/field/function_space/polynomial_reconstruction.cpp +++ b/src/pcms/field/function_space/polynomial_reconstruction.cpp @@ -17,13 +17,13 @@ namespace pcms { PolynomialReconstructionFunctionSpace::PolynomialReconstructionFunctionSpace( - std::shared_ptr layout, + Key, std::shared_ptr layout, std::shared_ptr> evaluator_factory) noexcept : layout_(std::move(layout)), evaluator_factory_(std::move(evaluator_factory)) { } -PolynomialReconstructionFunctionSpace +std::shared_ptr PolynomialReconstructionFunctionSpace::Create( Rank2View coords, CoordinateSystem coordinate_system, MLSOptions options) @@ -40,11 +40,11 @@ PolynomialReconstructionFunctionSpace::Create( std::make_shared(pc_layout, options); auto eval_factory = std::make_shared( pc_layout, localization, options); - return PolynomialReconstructionFunctionSpace(pc_layout, - std::move(eval_factory)); + return std::make_shared( + Key{}, pc_layout, std::move(eval_factory)); } -PolynomialReconstructionFunctionSpace +std::shared_ptr PolynomialReconstructionFunctionSpace::FromMesh( Omega_h::Mesh& mesh, int source_entity_dim, CoordinateSystem coordinate_system, MLSOptions options) @@ -66,8 +66,8 @@ PolynomialReconstructionFunctionSpace::FromMesh( mesh, source_entity_dim, options); auto eval_factory = std::make_shared( mesh_layout, localization, options); - return PolynomialReconstructionFunctionSpace(mesh_layout, - std::move(eval_factory)); + return std::make_shared( + Key{}, mesh_layout, std::move(eval_factory)); } std::shared_ptr diff --git a/src/pcms/field/function_space/polynomial_reconstruction.hpp b/src/pcms/field/function_space/polynomial_reconstruction.hpp index 0222c282..890f61a7 100644 --- a/src/pcms/field/function_space/polynomial_reconstruction.hpp +++ b/src/pcms/field/function_space/polynomial_reconstruction.hpp @@ -23,14 +23,25 @@ class FieldEvaluatorFactory; class PolynomialReconstructionFunctionSpace : public FunctionSpace { + // Passkey: only members (the Create/FromMesh factories) can create a Key, so + // only they can construct a space, while std::make_shared can call the ctor. + struct Key + { + explicit Key() = default; + }; + public: - [[nodiscard]] static PolynomialReconstructionFunctionSpace Create( - Rank2View coords, CoordinateSystem coordinate_system, - MLSOptions options = {}); + PolynomialReconstructionFunctionSpace( + Key, std::shared_ptr layout, + std::shared_ptr> evaluator_factory) noexcept; + + [[nodiscard]] static std::shared_ptr + Create(Rank2View coords, + CoordinateSystem coordinate_system, MLSOptions options = {}); - [[nodiscard]] static PolynomialReconstructionFunctionSpace FromMesh( - Omega_h::Mesh& mesh, int source_entity_dim, - CoordinateSystem coordinate_system, MLSOptions options = {}); + [[nodiscard]] static std::shared_ptr + FromMesh(Omega_h::Mesh& mesh, int source_entity_dim, + CoordinateSystem coordinate_system, MLSOptions options = {}); [[nodiscard]] std::shared_ptr GetLayout() const noexcept override; @@ -48,10 +59,6 @@ class PolynomialReconstructionFunctionSpace : public FunctionSpace Type value_type, const EvaluationRequest& request) const override; private: - explicit PolynomialReconstructionFunctionSpace( - std::shared_ptr layout, - std::shared_ptr> evaluator_factory) noexcept; - std::shared_ptr layout_; std::shared_ptr> evaluator_factory_; }; diff --git a/src/pcms/field/function_space/spline.cpp b/src/pcms/field/function_space/spline.cpp index 167048b8..c746a8d2 100644 --- a/src/pcms/field/function_space/spline.cpp +++ b/src/pcms/field/function_space/spline.cpp @@ -11,20 +11,21 @@ namespace pcms { SplineFunctionSpace::SplineFunctionSpace( - std::shared_ptr layout, + Key, std::shared_ptr layout, std::shared_ptr> evaluator_factory) noexcept : layout_(std::move(layout)), evaluator_factory_(std::move(evaluator_factory)) { } -SplineFunctionSpace SplineFunctionSpace::FromUniformGrid( +std::shared_ptr SplineFunctionSpace::FromUniformGrid( const UniformGrid<2>& grid, CoordinateSystem coordinate_system) { auto layout = std::make_shared>(grid, 1, coordinate_system, 1); auto evaluator_factory = std::make_shared(layout); - return SplineFunctionSpace(layout, std::move(evaluator_factory)); + return std::make_shared(Key{}, layout, + std::move(evaluator_factory)); } std::shared_ptr SplineFunctionSpace::GetLayout() diff --git a/src/pcms/field/function_space/spline.h b/src/pcms/field/function_space/spline.h index 15c7d712..f8e467d7 100644 --- a/src/pcms/field/function_space/spline.h +++ b/src/pcms/field/function_space/spline.h @@ -21,8 +21,19 @@ namespace pcms class SplineFunctionSpace : public FunctionSpace { + // Passkey: only members (the From* factories) can create a Key, so only they + // can construct a space, while std::make_shared can still call the ctor. + struct Key + { + explicit Key() = default; + }; + public: - [[nodiscard]] static SplineFunctionSpace FromUniformGrid( + SplineFunctionSpace( + Key, std::shared_ptr layout, + std::shared_ptr> evaluator_factory) noexcept; + + [[nodiscard]] static std::shared_ptr FromUniformGrid( const UniformGrid<2>& grid, CoordinateSystem coordinate_system); [[nodiscard]] std::shared_ptr GetLayout() @@ -41,10 +52,6 @@ class SplineFunctionSpace : public FunctionSpace Type value_type, const EvaluationRequest& request) const override; private: - explicit SplineFunctionSpace( - std::shared_ptr layout, - std::shared_ptr> evaluator_factory) noexcept; - std::shared_ptr layout_; std::shared_ptr> evaluator_factory_; }; diff --git a/src/pcms/field/function_space/xgc.h b/src/pcms/field/function_space/xgc.h index 45a769ac..cbea70b4 100644 --- a/src/pcms/field/function_space/xgc.h +++ b/src/pcms/field/function_space/xgc.h @@ -1,9 +1,9 @@ -#ifndef PCMS_XGC_FUNCTION_SPACE_H -#define PCMS_XGC_FUNCTION_SPACE_H +#ifndef PCMS_XGC_FIELD_FACTORY_H +#define PCMS_XGC_FIELD_FACTORY_H #include "pcms/field/data/xgc.h" #include "pcms/field/field.h" -#include "pcms/field/function_space.h" +#include "pcms/field/field_factory.h" #include "pcms/field/field_metadata.h" #include "pcms/utility/common.h" #include @@ -12,22 +12,19 @@ namespace pcms { -class XGCFunctionSpace : public FunctionSpace +// XGC is a comm-only backend +class XGCFieldFactory : public FieldFactory { public: - XGCFunctionSpace(const ReverseClassificationVertex& reverse_classification, - std::function in_overlap, - LO num_plane_nodes, std::string layout_name = "") + XGCFieldFactory(const ReverseClassificationVertex& reverse_classification, + std::function in_overlap, + LO num_plane_nodes, std::string layout_name = "") : layout_(std::make_shared( reverse_classification, std::move(in_overlap), num_plane_nodes)) { layout_->SetName(std::move(layout_name)); } - // Set the layout name after construction. Const because the name is metadata - // that does not affect the (const) discretization; the layout pointee is - // mutable through the shared_ptr. Used by the capi, which learns a field's - // name only when it is added, after the space is built. void SetLayoutName(std::string name) const { layout_->SetName(std::move(name)); @@ -39,9 +36,10 @@ class XGCFunctionSpace : public FunctionSpace return layout_; } - [[nodiscard]] CoordinateSystem GetCoordinateSystem() const noexcept override + [[nodiscard]] std::shared_ptr GetXGCLayout() + const noexcept { - return CoordinateSystem::XGC; + return layout_; } protected: @@ -65,12 +63,12 @@ class XGCFunctionSpace : public FunctionSpace PCMS_ALWAYS_ASSERT(fd != nullptr); if (dynamic_cast*>(fd.get()) == nullptr) { throw pcms_error( - "XGCFunctionSpace::CreateField: requires XGCFieldData"); + "XGCFieldFactory::CreateField: requires XGCFieldData"); } if (fd->GetDOFHolderDataHost().size() != static_cast(layout_->GetFullDataSize())) { throw pcms_error( - "XGCFunctionSpace::CreateField: field data size does not match " + "XGCFieldFactory::CreateField: field data size does not match " "layout"); } return WrapField(layout_, std::move(fd)); @@ -78,23 +76,10 @@ class XGCFunctionSpace : public FunctionSpace std::move(data)); } - [[nodiscard]] PointEvaluatorVariant CreatePointEvaluatorImpl( - Type /*value_type*/, const EvaluationRequest& /*request*/) const override - { - throw pcms_error("XGCFunctionSpace does not support point evaluation"); - } - -public: - [[nodiscard]] std::shared_ptr GetXGCLayout() - const noexcept - { - return layout_; - } - private: std::shared_ptr layout_; }; } // namespace pcms -#endif // PCMS_XGC_FUNCTION_SPACE_H +#endif // PCMS_XGC_FIELD_FACTORY_H diff --git a/src/pcms/field/uniform_grid_binary_field.h b/src/pcms/field/uniform_grid_binary_field.h index 8302cbd5..bce42439 100644 --- a/src/pcms/field/uniform_grid_binary_field.h +++ b/src/pcms/field/uniform_grid_binary_field.h @@ -39,9 +39,9 @@ CreateUniformGridBinaryField(Omega_h::Mesh& mesh, const UniformGrid& grid) auto function_space = LagrangeFunctionSpace::FromUniformGrid( grid, 1, CoordinateSystem::Cartesian); auto layout = std::dynamic_pointer_cast>( - function_space.GetLayout()); + function_space->GetLayout()); PCMS_ALWAYS_ASSERT(layout != nullptr); - auto field = function_space.template CreateField("", FieldMetadata{}); + Field field = function_space->template CreateFunction(""); auto coord_view = layout->GetDOFHolderCoordinates(); auto coords = coord_view.GetValues(); diff --git a/src/pcms/pythonapi/bind_field_base.cpp b/src/pcms/pythonapi/bind_field_base.cpp index 63ca6ecb..eca1c98a 100644 --- a/src/pcms/pythonapi/bind_field_base.cpp +++ b/src/pcms/pythonapi/bind_field_base.cpp @@ -289,7 +289,9 @@ void bind_create_field_module(py::module& m) py::class_>(m, "FunctionSpace") .def( "create_field", - [](const FunctionSpace& self) { return self.CreateField(); }, + [](const FunctionSpace& self) -> Field { + return self.CreateFunction(); + }, "Create a Field for this function space.") .def( "create_point_evaluator", diff --git a/src/pcms/transfer/omega_h_control_variate_projection.cpp b/src/pcms/transfer/omega_h_control_variate_projection.cpp index bce1a89a..aea49cb2 100644 --- a/src/pcms/transfer/omega_h_control_variate_projection.cpp +++ b/src/pcms/transfer/omega_h_control_variate_projection.cpp @@ -18,7 +18,7 @@ OmegaHControlVariateProjection::OmegaHControlVariateProjection( target_layout_, target_space.GetCoordinateSystem(), samples_per_element, sampling, seed)), interpolator_(source_space, target_space), - control_variate_(target_space.CreateField()) + control_variate_(target_space.CreateFunction()) { const auto sample_coords = rhs_integrator_->GetIntegrationPoints().GetCoordinates(); diff --git a/test/field_test_utils.h b/test/field_test_utils.h index 3fbb624f..5aaac78e 100644 --- a/test/field_test_utils.h +++ b/test/field_test_utils.h @@ -282,8 +282,8 @@ void CheckEvaluation(const Factory& factory, const Field& field, double abs_tol = 1e-10) { auto device_coords = - CreateDeviceCoordinateView(pts, factory.GetCoordinateSystem()); - auto evaluator = factory.template CreatePointEvaluator( + CreateDeviceCoordinateView(pts, factory->GetCoordinateSystem()); + auto evaluator = factory->template CreatePointEvaluator( EvaluationRequest::FromCoordinates(device_coords.coordinate_view)); CheckEvaluation(*evaluator, field, pts, func, abs_tol); } @@ -314,9 +314,9 @@ void CheckFillMode(const Factory& factory, const Field& field, Real fill_value, const std::vector& outside_pts) { auto device_coords = - CreateDeviceCoordinateView(outside_pts, factory.GetCoordinateSystem()); + CreateDeviceCoordinateView(outside_pts, factory->GetCoordinateSystem()); OutOfBoundsPolicy policy{OutOfBoundsMode::FILL, fill_value}; - auto evaluator = factory.template CreatePointEvaluator( + auto evaluator = factory->template CreatePointEvaluator( EvaluationRequest::FromCoordinates(device_coords.coordinate_view, policy)); CheckFillMode(*evaluator, field, fill_value, outside_pts); } @@ -334,9 +334,9 @@ void CheckEvaluationWithFill(const Factory& factory, const Field& field, REQUIRE(static_cast(is_inside.size()) == n); auto device_coords = - CreateDeviceCoordinateView(pts, factory.GetCoordinateSystem()); + CreateDeviceCoordinateView(pts, factory->GetCoordinateSystem()); OutOfBoundsPolicy policy{OutOfBoundsMode::FILL, fill_value}; - auto evaluator = factory.template CreatePointEvaluator( + auto evaluator = factory->template CreatePointEvaluator( EvaluationRequest::FromCoordinates(device_coords.coordinate_view, policy)); Kokkos::View out_device("out_device", n); diff --git a/test/test_eqdsk.cpp b/test/test_eqdsk.cpp index 40150574..d546fbbe 100644 --- a/test/test_eqdsk.cpp +++ b/test/test_eqdsk.cpp @@ -182,10 +182,10 @@ TEST_CASE("EQDSKData with SplineFunctionSpace") { // auto spline_space = pcms::SplineFunctionSpace::FromEQDSK(eqdsk_data); - // auto psi_field = spline_space.CreateField(); + // auto psi_field = spline_space->CreateFunction(); auto [spline_space, psi_field] = pcms::MakeEQDSKField(eqdsk_data); - auto layout = spline_space.GetLayout(); + auto layout = spline_space->GetLayout(); const int layout_size = layout->OwnedSize(); const int psizr_size = static_cast(eqdsk_data.PSIZR.extent(0)); @@ -230,7 +230,7 @@ TEST_CASE("EQDSKData with SplineFunctionSpace") auto eval_request = pcms::EvaluationRequest::FromCoordinates(coord_view); auto evaluator = - spline_space.CreatePointEvaluator(eval_request); + spline_space->CreatePointEvaluator(eval_request); auto eval_results_1d = Kokkos::View( "eval_results", num_eval_points); diff --git a/test/test_field_communication.cpp b/test/test_field_communication.cpp index 30cb96b8..dcee3252 100644 --- a/test/test_field_communication.cpp +++ b/test/test_field_communication.cpp @@ -80,9 +80,9 @@ static void test_shared_layout(Omega_h::Library& lib, auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::DefaultBackend, "shared"); - auto f1 = app->AddField(factory.CreateField("field_a")); + auto f1 = app->AddField(factory->CreateFunction("field_a")); PCMS_ALWAYS_ASSERT(app->GetLayoutCommunicatorCount() == 1); - auto f2 = app->AddField(factory.CreateField("field_b")); + auto f2 = app->AddField(factory->CreateFunction("field_b")); PCMS_ALWAYS_ASSERT(app->GetLayoutCommunicatorCount() == 1); // shared layout app->ReceivePhase([&]() { f1.Receive(); @@ -99,8 +99,8 @@ static void test_shared_layout(Omega_h::Library& lib, auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::DefaultBackend, "shared"); - auto f1 = app->AddField(factory.CreateField("field_a")); - auto f2 = app->AddField(factory.CreateField("field_b")); + auto f1 = app->AddField(factory->CreateFunction("field_a")); + auto f2 = app->AddField(factory->CreateFunction("field_b")); app->SendPhase([&]() { f1.Send(); f2.Send(); @@ -121,7 +121,7 @@ void client1(MPI_Comm comm, Omega_h::Mesh& mesh, std::string comm_name, auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, order, 1, pcms::CoordinateSystem::Cartesian); - auto layout = factory.GetLayout(); + auto layout = factory->GetLayout(); auto gids = layout->GetGidsHost(); const auto n = layout->GetNumOwnedDofHolder(); Omega_h::HostWrite ids(n); @@ -130,7 +130,7 @@ void client1(MPI_Comm comm, Omega_h::Mesh& mesh, std::string comm_name, "id gid", Kokkos::RangePolicy(0, n), [=](int i) { ids[i] = gids[i]; }); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); field.SetDOFHolderDataHost( pcms::Rank2View(ids.data(), n, 1)); @@ -153,11 +153,11 @@ void client2(MPI_Comm comm, Omega_h::Mesh& mesh, std::string comm_name, auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, order, 1, pcms::CoordinateSystem::Cartesian); - auto layout = factory.GetLayout(); + auto layout = factory->GetLayout(); auto gids = layout->GetGidsHost(); const auto n = layout->GetNumOwnedDofHolder(); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); pcms::FieldLayoutCommunicator layout_comm(comm_name + "2", comm, rdv, channel, *layout); pcms::FieldCommunicator field_comm(layout_comm.GetName(), @@ -213,14 +213,14 @@ void server(MPI_Comm comm, Omega_h::Mesh& mesh, std::string comm_name, auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, order, 1, pcms::CoordinateSystem::Cartesian); - auto layout = factory.GetLayout(); + auto layout = factory->GetLayout(); const auto n = layout->GetNumOwnedDofHolder(); Omega_h::HostWrite ids(n); Kokkos::parallel_for( "id 0", Kokkos::RangePolicy(0, n), [=](int i) { ids[i] = 0; }); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); pcms::FieldLayoutCommunicator layout_comm1(comm_name + "1", comm, rdv, channel1, *layout); pcms::FieldLayoutCommunicator layout_comm2(comm_name + "2", comm, rdv, diff --git a/test/test_field_copy.cpp b/test/test_field_copy.cpp index d9039eb1..46a1b94e 100644 --- a/test/test_field_copy.cpp +++ b/test/test_field_copy.cpp @@ -22,20 +22,20 @@ void test_copy(Omega_h::CommPtr world, int dim, int order, int num_components) auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, order, num_components, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); - auto layout = factory.GetLayout(); + auto layout = factory->GetLayout(); int ndata = layout->GetNumOwnedDofHolder() * num_components; Omega_h::HostWrite ids(ndata); Kokkos::parallel_for( Kokkos::RangePolicy(0, ndata), [=](int i) { ids[i] = i; }); - auto original = factory.CreateField(); + auto original = factory->CreateFunction(); original.SetDOFHolderDataHost( pcms::Rank2View( ids.data(), layout->GetNumOwnedDofHolder(), num_components)); - auto copied = factory.CreateField(); - pcms::Copy copy(factory, factory); + auto copied = factory->CreateFunction(); + pcms::Copy copy(*factory, *factory); copy.Apply(original, copied); auto copied_array = pcms::FlattenToRank1View(copied.GetDOFHolderDataHost()); diff --git a/test/test_field_evaluation.cpp b/test/test_field_evaluation.cpp index 6f10480f..ff238e11 100644 --- a/test/test_field_evaluation.cpp +++ b/test/test_field_evaluation.cpp @@ -30,10 +30,10 @@ TEST_CASE("evaluate linear 2d omega_h_field") 100, 0, false); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); pcms::test::SetField( - field.GetData(), *factory.GetLayout(), + field.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + 2.0 * y; }); pcms::test::CheckEvaluation( factory, field, pcms::test::StandardEvalCoords2D(), @@ -75,7 +75,7 @@ TEST_CASE("evaluate quadratic 2d meshfields_field") }); Omega_h::HostWrite test_f_host(test_f); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); field.GetData().SetDOFHolderDataHost( pcms::Rank2View(test_f_host.data(), test_f_host.size(), 1)); diff --git a/test/test_field_interpolation.cpp b/test/test_field_interpolation.cpp index 21549571..bc88ab97 100644 --- a/test/test_field_interpolation.cpp +++ b/test/test_field_interpolation.cpp @@ -27,12 +27,12 @@ TEST_CASE("interpolate linear 2d omega_h_field") Omega_h::build_box(world, OMEGA_H_SIMPLEX, 1, 1, 0, 100, 100, 0, false); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(); - auto interpolated = factory.CreateField(); + auto field = factory->CreateFunction(); + auto interpolated = factory->CreateFunction(); pcms::test::SetField( field, OMEGA_H_LAMBDA(Real x, Real y) { return -0.3 * x + 0.5 * y; }); - pcms::Interpolator interp(factory, factory); + pcms::Interpolator interp(*factory, *factory); interp.Apply(field, interpolated); auto interpolated_dof = pcms::FlattenToRank1View(interpolated.GetDOFHolderDataHost()); @@ -55,7 +55,7 @@ TEST_CASE("interpolate quadratic 2d meshfields_field") auto factory2 = pcms::LagrangeFunctionSpace::FromMesh( mesh, 2, 1, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::MeshFields); - auto layout = factory2.GetLayout(); + auto layout = factory2->GetLayout(); const auto nverts = mesh.nents(0); const auto nedges = mesh.nents(1); auto mesh_coords = mesh.coords(); @@ -80,12 +80,12 @@ TEST_CASE("interpolate quadratic 2d meshfields_field") }); Omega_h::HostWrite test_f_host(test_f); - auto field = factory2.CreateField(); - auto interpolated = factory2.CreateField(); + auto field = factory2->CreateFunction(); + auto interpolated = factory2->CreateFunction(); field.SetDOFHolderDataHost(pcms::Rank2View( test_f_host.data(), test_f_host.size(), 1)); - pcms::Interpolator interp(factory2, factory2); + pcms::Interpolator interp(*factory2, *factory2); interp.Apply(field, interpolated); auto interpolated_dof = @@ -126,13 +126,13 @@ TEST_CASE("Interpolator: construct once, apply twice with different data") auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto source = factory.CreateField(); - auto target = factory.CreateField(); + auto source = factory->CreateFunction(); + auto target = factory->CreateFunction(); // Construct Interpolator once — localization happens here. // Because source and target share the same layout (same factory), // the target DOF holder coordinates are the source mesh node coordinates. - pcms::Interpolator interp(factory, factory); + pcms::Interpolator interp(*factory, *factory); // First application: linear function f(x,y) = -0.3*x + 0.5*y pcms::test::SetField( diff --git a/test/test_mesh_intersection_field_transfer.cpp b/test/test_mesh_intersection_field_transfer.cpp index 54b16038..fbb34ddb 100644 --- a/test/test_mesh_intersection_field_transfer.cpp +++ b/test/test_mesh_intersection_field_transfer.cpp @@ -39,7 +39,7 @@ Omega_h::Mesh BuildUnitSquare(Omega_h::Library& lib, const Omega_h::LOs& ev2v) return mesh; } -pcms::LagrangeFunctionSpace MakeP1Space( +std::shared_ptr MakeP1Space( Omega_h::Mesh& mesh, const std::string& global_id_name = "global") { return pcms::LagrangeFunctionSpace::FromMesh( @@ -47,7 +47,7 @@ pcms::LagrangeFunctionSpace MakeP1Space( pcms::LagrangeFunctionSpace::Backend::OmegaH); } -pcms::LagrangeFunctionSpace MakeP0Space(Omega_h::Mesh& mesh) +std::shared_ptr MakeP0Space(Omega_h::Mesh& mesh) { return pcms::LagrangeFunctionSpace::FromMesh( mesh, 0, 1, pcms::CoordinateSystem::Cartesian, "global", @@ -146,10 +146,10 @@ TEST_CASE("OmegaHConservativeProjection reproduces constant and linear fields", auto source_space = MakeP1Space(source_mesh); auto target_space = MakeP1Space(target_mesh); - auto source = source_space.CreateField(); - auto target = target_space.CreateField(); + auto source = source_space->CreateFunction(); + auto target = target_space->CreateFunction(); - pcms::OmegaHConservativeProjection projection(source_space, target_space); + pcms::OmegaHConservativeProjection projection(*source_space, *target_space); SECTION("constant field is preserved and conserved") { @@ -208,10 +208,10 @@ TEST_CASE("OmegaHConservativeProjection conserves the integral", auto source_space = MakeP1Space(source_mesh); auto target_space = MakeP1Space(target_mesh); - auto source = source_space.CreateField(); - auto target = target_space.CreateField(); + auto source = source_space->CreateFunction(); + auto target = target_space->CreateFunction(); - pcms::OmegaHConservativeProjection projection(source_space, target_space); + pcms::OmegaHConservativeProjection projection(*source_space, *target_space); pcms::test::SetField( source, OMEGA_H_LAMBDA(pcms::Real x, pcms::Real y) { @@ -246,18 +246,18 @@ TEST_CASE("OmegaHConservativeProjection writes reordered target GIDs in local " auto source_space = MakeP1Space(source_mesh); auto target_space = MakeP1Space(target_mesh, "reordered_global"); - auto source = source_space.CreateField(); - auto target = target_space.CreateField(); + auto source = source_space->CreateFunction(); + auto target = target_space->CreateFunction(); pcms::test::SetField( source, OMEGA_H_LAMBDA(pcms::Real x, pcms::Real y) { return x + 2.0 * y; }); - pcms::OmegaHConservativeProjection projection(source_space, target_space); + pcms::OmegaHConservativeProjection projection(*source_space, *target_space); projection.Apply(source, target); const auto target_values = target.GetDOFHolderDataHost(); const auto target_coords = - target_space.GetLayout()->GetDOFHolderCoordinates().GetValues(); + target_space->GetLayout()->GetDOFHolderCoordinates().GetValues(); const auto target_coords_h = pcms::test::CopyCoordinatesToHost( target_coords, target_mesh.nverts(), target_mesh.dim()); REQUIRE(static_cast(target_values.extent(0)) == @@ -285,18 +285,18 @@ TEST_CASE("OmegaHConservativeProjection maps sparse target GIDs to active " auto source_space = MakeP1Space(source_mesh); auto target_space = MakeP1Space(target_mesh, "sparse_global"); - auto source = source_space.CreateField(); - auto target = target_space.CreateField(); + auto source = source_space->CreateFunction(); + auto target = target_space->CreateFunction(); pcms::test::SetField( source, OMEGA_H_LAMBDA(pcms::Real x, pcms::Real y) { return x + 2.0 * y; }); - pcms::OmegaHConservativeProjection projection(source_space, target_space); + pcms::OmegaHConservativeProjection projection(*source_space, *target_space); projection.Apply(source, target); const auto target_values = target.GetDOFHolderDataHost(); const auto target_coords = - target_space.GetLayout()->GetDOFHolderCoordinates().GetValues(); + target_space->GetLayout()->GetDOFHolderCoordinates().GetValues(); const auto target_coords_h = pcms::test::CopyCoordinatesToHost( target_coords, target_mesh.nverts(), target_mesh.dim()); REQUIRE(static_cast(target_values.extent(0)) == @@ -325,10 +325,10 @@ TEST_CASE("OmegaHConservativeProjection P0 source to P1 target", auto source_space = MakeP0Space(source_mesh); auto target_space = MakeP1Space(target_mesh); - auto source = source_space.CreateField(); - auto target = target_space.CreateField(); + auto source = source_space->CreateFunction(); + auto target = target_space->CreateFunction(); - pcms::OmegaHConservativeProjection projection(source_space, target_space); + pcms::OmegaHConservativeProjection projection(*source_space, *target_space); SECTION("constant field is preserved and conserved") { @@ -379,10 +379,10 @@ TEST_CASE("OmegaHConservativeProjection P1 source to P0 target", auto source_space = MakeP1Space(source_mesh); auto target_space = MakeP0Space(target_mesh); - auto source = source_space.CreateField(); - auto target = target_space.CreateField(); + auto source = source_space->CreateFunction(); + auto target = target_space->CreateFunction(); - pcms::OmegaHConservativeProjection projection(source_space, target_space); + pcms::OmegaHConservativeProjection projection(*source_space, *target_space); SECTION("constant field is preserved and conserved") { diff --git a/test/test_omega_h_field2_outofbounds.cpp b/test/test_omega_h_field2_outofbounds.cpp index dd8d8c94..8581dcb5 100644 --- a/test/test_omega_h_field2_outofbounds.cpp +++ b/test/test_omega_h_field2_outofbounds.cpp @@ -19,9 +19,9 @@ TEST_CASE("omega_h_field2 out of bounds FILL mode") Omega_h::build_box(world, OMEGA_H_SIMPLEX, 1, 1, 0, 10, 10, 0, false); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); pcms::test::SetField( - field.GetData(), *factory.GetLayout(), + field.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + y; }); Real fill_value = -999.0; diff --git a/test/test_omega_h_intersection_rhs_integrator.cpp b/test/test_omega_h_intersection_rhs_integrator.cpp index b778f2ae..fcbb3aed 100644 --- a/test/test_omega_h_intersection_rhs_integrator.cpp +++ b/test/test_omega_h_intersection_rhs_integrator.cpp @@ -95,14 +95,15 @@ std::unordered_map ExpectedLoadByGid( // Assembles the integrator's load vector for source_field and compares it, // per global DOF id, against the supplied expected values. void CheckAssembledLoadMatches( - pcms::FunctionSpace& source_space, pcms::LinearFormIntegrator& integrator, + const std::shared_ptr& source_space, + pcms::LinearFormIntegrator& integrator, const pcms::Field& source_field, const std::unordered_map& expected) { const auto& pts = integrator.GetIntegrationPoints(); const std::size_t npts = pts.GetCoordinates().GetValues().extent(0); - auto evaluator = source_space.CreatePointEvaluator( + auto evaluator = source_space->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(pts.GetCoordinates())); Kokkos::View sampled("sampled", npts, 1); @@ -144,7 +145,7 @@ TEST_CASE("OmegaHIntersectionRHSIntegrator: integration points lie inside " pcms::LagrangeFunctionSpace::Backend::OmegaH); auto integrator = - pcms::BuildOmegaHConservativeRHSIntegrator(source_space, target_space); + pcms::BuildOmegaHConservativeRHSIntegrator(*source_space, *target_space); const auto raw_coords = integrator->GetIntegrationPoints().GetCoordinates().GetValues(); @@ -181,15 +182,15 @@ TEST_CASE("OmegaHIntersectionRHSIntegrator: zero source field gives zero " target_mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); - auto source_field = source_space.CreateField(); + auto source_field = source_space->CreateFunction(); // Default-constructed field has zero data. auto integrator = - pcms::BuildOmegaHConservativeRHSIntegrator(source_space, target_space); + pcms::BuildOmegaHConservativeRHSIntegrator(*source_space, *target_space); const auto& pts = integrator->GetIntegrationPoints(); const std::size_t npts = pts.GetCoordinates().GetValues().extent(0); - auto evaluator = source_space.CreatePointEvaluator( + auto evaluator = source_space->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(pts.GetCoordinates())); Kokkos::View sampled("sampled", npts, @@ -224,18 +225,18 @@ TEST_CASE("OmegaHIntersectionRHSIntegrator: constant field matches " pcms::LagrangeFunctionSpace::Backend::OmegaH); const double c = 2.0; - auto source_field = source_space.CreateField(); + auto source_field = source_space->CreateFunction(); pcms::test::SetField( source_field, OMEGA_H_LAMBDA(pcms::Real, pcms::Real) { return c; }); const auto target_layout = std::dynamic_pointer_cast( - target_space.GetLayout()); + target_space->GetLayout()); const std::vector g(target_mesh.nverts(), c); const auto expected = ExpectedLoadByGid(target_mesh, *target_layout, g); auto integrator = - pcms::BuildOmegaHConservativeRHSIntegrator(source_space, target_space); + pcms::BuildOmegaHConservativeRHSIntegrator(*source_space, *target_space); CheckAssembledLoadMatches(source_space, *integrator, source_field, expected); } @@ -260,13 +261,13 @@ TEST_CASE( target_mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); - auto source_field = source_space.CreateField(); + auto source_field = source_space->CreateFunction(); pcms::test::SetField( source_field, OMEGA_H_LAMBDA(pcms::Real x, pcms::Real y) { return x + y; }); const auto target_layout = std::dynamic_pointer_cast( - target_space.GetLayout()); + target_space->GetLayout()); const auto tgt_coords_h = Omega_h::HostRead(target_mesh.coords()); std::vector g(target_mesh.nverts()); @@ -276,7 +277,7 @@ TEST_CASE( const auto expected = ExpectedLoadByGid(target_mesh, *target_layout, g); auto integrator = - pcms::BuildOmegaHConservativeRHSIntegrator(source_space, target_space); + pcms::BuildOmegaHConservativeRHSIntegrator(*source_space, *target_space); CheckAssembledLoadMatches(source_space, *integrator, source_field, expected); } @@ -296,7 +297,7 @@ TEST_CASE("OmegaHIntersectionRHSIntegrator: rejects invalid layouts", target_mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); REQUIRE_THROWS( - pcms::BuildOmegaHConservativeRHSIntegrator(source_space, target_space)); + pcms::BuildOmegaHConservativeRHSIntegrator(*source_space, *target_space)); } SECTION("multi-component target space throws") @@ -308,7 +309,7 @@ TEST_CASE("OmegaHIntersectionRHSIntegrator: rejects invalid layouts", target_mesh, 1, 2, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); REQUIRE_THROWS( - pcms::BuildOmegaHConservativeRHSIntegrator(source_space, target_space)); + pcms::BuildOmegaHConservativeRHSIntegrator(*source_space, *target_space)); } SECTION("non-Cartesian source coordinate system throws") @@ -320,7 +321,7 @@ TEST_CASE("OmegaHIntersectionRHSIntegrator: rejects invalid layouts", target_mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); REQUIRE_THROWS( - pcms::BuildOmegaHConservativeRHSIntegrator(source_space, target_space)); + pcms::BuildOmegaHConservativeRHSIntegrator(*source_space, *target_space)); } SECTION("non-Cartesian target coordinate system throws") @@ -332,6 +333,6 @@ TEST_CASE("OmegaHIntersectionRHSIntegrator: rejects invalid layouts", target_mesh, 1, 1, pcms::CoordinateSystem::Cylindrical, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); REQUIRE_THROWS( - pcms::BuildOmegaHConservativeRHSIntegrator(source_space, target_space)); + pcms::BuildOmegaHConservativeRHSIntegrator(*source_space, *target_space)); } } diff --git a/test/test_omega_h_lagrange_field.cpp b/test/test_omega_h_lagrange_field.cpp index 64a9a0b6..c17d45b1 100644 --- a/test/test_omega_h_lagrange_field.cpp +++ b/test/test_omega_h_lagrange_field.cpp @@ -115,8 +115,8 @@ TEST_CASE("OmegaHLagrangeLayout layout sharing") auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto f1 = factory.CreateField(); - auto f2 = factory.CreateField(); + auto f1 = factory->CreateFunction(); + auto f2 = factory->CreateFunction(); REQUIRE(&f1.GetLayout() == &f2.GetLayout()); } @@ -129,9 +129,9 @@ TEST_CASE("OmegaHLagrangeField order-1: set/get DOF data round-trip") auto mesh = MakeBox2D(lib.world()); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); - int n = factory.GetLayout()->GetNumOwnedDofHolder(); + int n = factory->GetLayout()->GetNumOwnedDofHolder(); std::vector data(n); for (int i = 0; i < n; ++i) data[i] = static_cast(i); @@ -151,10 +151,10 @@ TEST_CASE("OmegaHLagrangeField order-1: linear function evaluation") auto mesh = MakeBox2D(lib.world(), 20, 20); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); pcms::test::SetField( - field.GetData(), *factory.GetLayout(), + field.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + 2.0 * y; }); pcms::test::CheckEvaluation( factory, field, pcms::test::StandardEvalCoords2D(), @@ -169,10 +169,10 @@ TEST_CASE("MeshFieldsAdapter order-1: linear function evaluation (shared util)") auto mesh = MakeBox2D(lib.world(), 20, 20); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); pcms::test::SetField( - field.GetData(), *factory.GetLayout(), + field.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + 2.0 * y; }); pcms::test::CheckEvaluation( factory, field, pcms::test::StandardEvalCoords2D(), @@ -185,10 +185,10 @@ TEST_CASE("OmegaHLagrangeField order-1: out-of-bounds FILL mode") auto mesh = MakeBox2D(lib.world()); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); pcms::test::SetField( - field.GetData(), *factory.GetLayout(), + field.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + 2.0 * y; }); Real fill_value = -999.0; @@ -202,12 +202,12 @@ TEST_CASE("OmegaHLagrangeField order-1: serialize / deserialize round-trip") auto mesh = MakeBox2D(lib.world()); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); pcms::test::SetField( - field.GetData(), *factory.GetLayout(), + field.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + 2.0 * y; }); - pcms::test::CheckSerializeDeserialize(*factory.GetLayout(), field.GetData()); + pcms::test::CheckSerializeDeserialize(*factory->GetLayout(), field.GetData()); } TEST_CASE( @@ -221,9 +221,9 @@ TEST_CASE( auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, nc, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); - const int n = factory.GetLayout()->GetNumOwnedDofHolder(); + const int n = factory->GetLayout()->GetNumOwnedDofHolder(); std::vector data(static_cast(n) * nc); for (int i = 0; i < n; ++i) for (int c = 0; c < nc; ++c) @@ -231,7 +231,7 @@ TEST_CASE( field.GetData().SetDOFHolderDataHost( pcms::Rank2View(data.data(), n, nc)); - pcms::test::CheckSerializeDeserialize(*factory.GetLayout(), field.GetData()); + pcms::test::CheckSerializeDeserialize(*factory->GetLayout(), field.GetData()); } // ---- Order-0 field tests ---------------------------------------------------- @@ -242,9 +242,9 @@ TEST_CASE("OmegaHLagrangeField order-0: set/get DOF data round-trip") auto mesh = MakeBox2D(lib.world()); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 0, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); - int n = factory.GetLayout()->GetNumOwnedDofHolder(); + int n = factory->GetLayout()->GetNumOwnedDofHolder(); std::vector data(n, 3.14); pcms::Rank2View view(data.data(), n, 1); field.GetData().SetDOFHolderDataHost(view); @@ -261,7 +261,7 @@ TEST_CASE("OmegaHLagrangeField order-0: constant field evaluation") auto mesh = MakeBox2D(lib.world(), 10, 10); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 0, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); const Real kValue = 42.0; int nelems = mesh.nelems(); @@ -273,8 +273,8 @@ TEST_CASE("OmegaHLagrangeField order-0: constant field evaluation") auto pts = pcms::test::StandardEvalCoords2D(); int n = static_cast(pts.size()) / 2; auto device_coords = - pcms::test::CreateDeviceCoordinateView(pts, factory.GetCoordinateSystem()); - auto evaluator = factory.CreatePointEvaluator( + pcms::test::CreateDeviceCoordinateView(pts, factory->GetCoordinateSystem()); + auto evaluator = factory->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view)); Kokkos::View eval_device("eval", n); @@ -296,7 +296,7 @@ TEST_CASE("OmegaHLagrangeField order-0: out-of-bounds FILL mode") auto mesh = MakeBox2D(lib.world()); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 0, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); int nelems = mesh.nelems(); std::vector data(nelems, 1.0); @@ -315,7 +315,7 @@ TEST_CASE("OmegaHLagrangeField order-0: serialize / deserialize round-trip") auto mesh = MakeBox2D(lib.world()); auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 0, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); int nelems = mesh.nelems(); std::vector data(nelems); @@ -325,7 +325,7 @@ TEST_CASE("OmegaHLagrangeField order-0: serialize / deserialize round-trip") 1); field.GetData().SetDOFHolderDataHost(view); - pcms::test::CheckSerializeDeserialize(*factory.GetLayout(), field.GetData()); + pcms::test::CheckSerializeDeserialize(*factory->GetLayout(), field.GetData()); } // ---- Layout sharing communicator contract ----------------------------------- @@ -353,7 +353,7 @@ TEST_CASE("OmegaHLagrangeField: field valid after layout destruction") { auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - field.emplace(factory.CreateField()); + field.emplace(factory->CreateFunction()); } // factory goes out of scope; field keeps layout alive pcms::test::SetField( diff --git a/test/test_omega_h_mass_integrator.cpp b/test/test_omega_h_mass_integrator.cpp index b916651c..f77fd85f 100644 --- a/test/test_omega_h_mass_integrator.cpp +++ b/test/test_omega_h_mass_integrator.cpp @@ -102,9 +102,9 @@ TEST_CASE( mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); - const auto ref = BuildReferenceMassMap(mesh, space); + const auto ref = BuildReferenceMassMap(mesh, *space); - auto integrator = pcms::BuildOmegaHMassIntegrator(space); + auto integrator = pcms::BuildOmegaHMassIntegrator(*space); Mat mat = integrator->GetMatrix(); for (const auto& [key, ref_val] : ref) { @@ -134,11 +134,11 @@ TEST_CASE("OmegaHMassIntegrator: row sums match lumped mass", const auto layout = std::dynamic_pointer_cast( - space.GetLayout()); + space->GetLayout()); const auto& gids = layout->GetGidsHost(); const int nverts = mesh.nverts(); - auto integrator = pcms::BuildOmegaHMassIntegrator(space); + auto integrator = pcms::BuildOmegaHMassIntegrator(*space); Mat mat = integrator->GetMatrix(); // Sum all row sums. @@ -174,7 +174,7 @@ TEST_CASE("OmegaHMassIntegrator: rejects invalid layouts", "[mass_integrator]") auto space = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 2, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); - REQUIRE_THROWS(pcms::BuildOmegaHMassIntegrator(space)); + REQUIRE_THROWS(pcms::BuildOmegaHMassIntegrator(*space)); } SECTION("non-Cartesian coordinate system throws") @@ -182,6 +182,6 @@ TEST_CASE("OmegaHMassIntegrator: rejects invalid layouts", "[mass_integrator]") auto space = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cylindrical, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); - REQUIRE_THROWS(pcms::BuildOmegaHMassIntegrator(space)); + REQUIRE_THROWS(pcms::BuildOmegaHMassIntegrator(*space)); } } diff --git a/test/test_omega_h_mc_rhs_integrator.cpp b/test/test_omega_h_mc_rhs_integrator.cpp index a26095ce..eabe5404 100644 --- a/test/test_omega_h_mc_rhs_integrator.cpp +++ b/test/test_omega_h_mc_rhs_integrator.cpp @@ -53,7 +53,7 @@ Omega_h::Mesh BuildUnitSquare(Omega_h::Library& lib, int diagonal) return mesh; } -pcms::LagrangeFunctionSpace MakeP1Space(Omega_h::Mesh& mesh) +std::shared_ptr MakeP1Space(Omega_h::Mesh& mesh) { return pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", @@ -61,13 +61,14 @@ pcms::LagrangeFunctionSpace MakeP1Space(Omega_h::Mesh& mesh) } // Evaluates source_field at the integrator's sample points and assembles. -void EvaluateAndAssemble(pcms::LinearFormIntegrator& integrator, - const pcms::FunctionSpace& source_space, - const pcms::Field& source_field) +void EvaluateAndAssemble( + pcms::LinearFormIntegrator& integrator, + const std::shared_ptr& source_space, + const pcms::Field& source_field) { const auto& pts = integrator.GetIntegrationPoints(); const std::size_t npts = pts.GetCoordinates().GetValues().extent(0); - auto evaluator = source_space.CreatePointEvaluator( + auto evaluator = source_space->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(pts.GetCoordinates())); Kokkos::View sampled("sampled", npts, 1); @@ -91,7 +92,7 @@ TEST_CASE("OmegaHMonteCarloRHSIntegrator: sample points lie inside the domain", const int samples_per_element = 16; for (const auto sampling : {pcms::MonteCarloSampling::UniformRandom}) { pcms::OmegaHMonteCarloRHSIntegrator integrator( - target_space, samples_per_element, sampling); + *target_space, samples_per_element, sampling); const auto raw_coords = integrator.GetIntegrationPoints().GetCoordinates().GetValues(); auto coords_view = Kokkos::View(); + auto source_field = source_space->CreateFunction(); pcms::test::SetField( source_field, OMEGA_H_LAMBDA(pcms::Real, pcms::Real) { return 2.0; }); for (const auto sampling : {pcms::MonteCarloSampling::UniformRandom}) { - pcms::OmegaHMonteCarloRHSIntegrator integrator(target_space, 8, sampling); + pcms::OmegaHMonteCarloRHSIntegrator integrator(*target_space, 8, sampling); EvaluateAndAssemble(integrator, source_space, source_field); PetscScalar sum = 0.0; @@ -157,14 +158,14 @@ TEST_CASE("OmegaHControlVariateProjection: exact for fields in the target " auto source_space = MakeP1Space(source_mesh); auto target_space = MakeP1Space(target_mesh); - auto source_field = source_space.CreateField(); - auto target_field = target_space.CreateField(); + auto source_field = source_space->CreateFunction(); + auto target_field = target_space->CreateFunction(); pcms::test::SetField( source_field, OMEGA_H_LAMBDA(pcms::Real x, pcms::Real y) { return 3.0 * x - y + 0.25; }); pcms::OmegaHControlVariateProjection projection( - source_space, target_space, /*samples_per_element=*/4, + *source_space, *target_space, /*samples_per_element=*/4, pcms::MonteCarloSampling::UniformRandom); projection.Apply(source_field, target_field); @@ -193,16 +194,16 @@ TEST_CASE("OmegaHControlVariateProjection: reduces error vs plain Monte Carlo", auto source_space = MakeP1Space(source_mesh); auto target_space = MakeP1Space(target_mesh); - auto source_field = source_space.CreateField(); + auto source_field = source_space->CreateFunction(); pcms::test::SetField( source_field, OMEGA_H_LAMBDA(pcms::Real x, pcms::Real y) { return x * x + x * y + 0.5 * y * y; }); // Reference: exact mesh-intersection quadrature projection. - auto reference_field = target_space.CreateField(); - pcms::OmegaHConservativeProjection reference_projection(source_space, - target_space); + auto reference_field = target_space->CreateFunction(); + pcms::OmegaHConservativeProjection reference_projection(*source_space, + *target_space); reference_projection.Apply(source_field, reference_field); const auto reference = pcms::FlattenToRank1View(reference_field.GetDOFHolderDataHost()); @@ -212,20 +213,20 @@ TEST_CASE("OmegaHControlVariateProjection: reduces error vs plain Monte Carlo", // Plain Monte Carlo projection. pcms::OmegaHMonteCarloRHSIntegrator mc_integrator( - target_space, samples_per_element, pcms::MonteCarloSampling::UniformRandom, + *target_space, samples_per_element, pcms::MonteCarloSampling::UniformRandom, seed); - auto evaluator = source_space.CreatePointEvaluator( + auto evaluator = source_space->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates( mc_integrator.GetIntegrationPoints().GetCoordinates())); - pcms::OmegaHMassIntegrator mass_integrator(target_space); + pcms::OmegaHMassIntegrator mass_integrator(*target_space); pcms::GalerkinProjectionSolver solver(mass_integrator, mc_integrator); const auto mc_projected = solver.Solve(*evaluator, source_field); const auto mc_projected_h = Omega_h::HostRead(mc_projected); // Control-variate projection with the same sampling configuration. - auto cv_field = target_space.CreateField(); + auto cv_field = target_space->CreateFunction(); pcms::OmegaHControlVariateProjection cv_projection( - source_space, target_space, samples_per_element, + *source_space, *target_space, samples_per_element, pcms::MonteCarloSampling::UniformRandom, seed); cv_projection.Apply(source_field, cv_field); const auto cv_values = diff --git a/test/test_point_evaluator.cpp b/test/test_point_evaluator.cpp index fa0fc2f5..dcc57087 100644 --- a/test/test_point_evaluator.cpp +++ b/test/test_point_evaluator.cpp @@ -31,16 +31,16 @@ TEST_CASE("PointEvaluator: OmegaH order-1 linear evaluation") mesh, 1, 1, CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); - auto field_data = factory.CreateField(); + auto field_data = factory->CreateFunction(); pcms::test::SetField( - field_data.GetData(), *factory.GetLayout(), + field_data.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + 2.0 * y; }); auto pts = pcms::test::StandardEvalCoords2D(); int n = static_cast(pts.size()) / 2; auto device_coords = pcms::test::CreateDeviceCoordinateView(pts, CoordinateSystem::Cartesian); - auto evaluator = factory.CreatePointEvaluator( + auto evaluator = factory->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view)); pcms::test::CheckEvaluation( *evaluator, field_data, pts, @@ -61,15 +61,15 @@ TEST_CASE("PointEvaluator: same evaluator reused for two FieldData objects") mesh, 1, 1, CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); - auto field_a = factory.CreateField(); - auto field_b = factory.CreateField(); + auto field_a = factory->CreateFunction(); + auto field_b = factory->CreateFunction(); // field_a: linear_f; field_b: constant 42 pcms::test::SetField( - field_a.GetData(), *factory.GetLayout(), + field_a.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + 2.0 * y; }); pcms::test::SetField( - field_b.GetData(), *factory.GetLayout(), + field_b.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real, Real) { return Real(42); }); auto pts = pcms::test::StandardEvalCoords2D(); @@ -78,7 +78,7 @@ TEST_CASE("PointEvaluator: same evaluator reused for two FieldData objects") pcms::test::CreateDeviceCoordinateView(pts, CoordinateSystem::Cartesian); // Create the PointEvaluator once - auto evaluator = factory.CreatePointEvaluator( + auto evaluator = factory->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view)); Kokkos::View out_a_device("out_a", n); @@ -122,9 +122,9 @@ TEST_CASE("PointEvaluator: OmegaH order-1 out-of-bounds fill") mesh, 1, 1, CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); - auto field_data = factory.CreateField(); + auto field_data = factory->CreateFunction(); pcms::test::SetField( - field_data.GetData(), *factory.GetLayout(), + field_data.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + 2.0 * y; }); // Points clearly outside [0,1]^2 @@ -133,9 +133,9 @@ TEST_CASE("PointEvaluator: OmegaH order-1 out-of-bounds fill") auto device_coords = pcms::test::CreateDeviceCoordinateView( outside_pts, CoordinateSystem::Cartesian); pcms::OutOfBoundsPolicy policy{pcms::OutOfBoundsMode::FILL, -999.0}; - auto evaluator = - factory.CreatePointEvaluator(pcms::EvaluationRequest::FromCoordinates( - device_coords.coordinate_view, policy)); + auto evaluator = factory->CreatePointEvaluator( + pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view, + policy)); pcms::test::CheckFillMode(*evaluator, field_data, -999.0, outside_pts); } @@ -155,15 +155,15 @@ TEST_CASE("PointEvaluator: UniformGrid order-1 linear evaluation") auto factory = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, CoordinateSystem::Cartesian, 1); - auto field_data = factory.CreateField(); + auto field_data = factory->CreateFunction(); pcms::test::SetField( - field_data.GetData(), *factory.GetLayout(), + field_data.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + 2.0 * y; }); auto pts = pcms::test::StandardEvalCoords2D(); int n = static_cast(pts.size()) / 2; auto device_coords = pcms::test::CreateDeviceCoordinateView(pts, CoordinateSystem::Cartesian); - auto evaluator = factory.CreatePointEvaluator( + auto evaluator = factory->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view)); pcms::test::CheckEvaluation( *evaluator, field_data, pts, @@ -181,15 +181,15 @@ TEST_CASE("PointEvaluator: SplineFunctionSpace uniform-grid evaluation") auto factory = pcms::SplineFunctionSpace::FromUniformGrid( grid, CoordinateSystem::Cartesian); - auto field_data = factory.CreateField(); + auto field_data = factory->CreateFunction(); pcms::test::SetField( - field_data.GetData(), *factory.GetLayout(), + field_data.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + 2.0 * y; }); auto pts = pcms::test::StandardEvalCoords2D(); int n = static_cast(pts.size()) / 2; auto device_coords = pcms::test::CreateDeviceCoordinateView(pts, CoordinateSystem::Cartesian); - auto evaluator = factory.CreatePointEvaluator( + auto evaluator = factory->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view)); pcms::test::CheckEvaluation( *evaluator, field_data, pts, @@ -209,7 +209,7 @@ TEST_CASE("FieldLayout: metadata queries") auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); - auto layout = factory.GetLayout(); + auto layout = factory->GetLayout(); auto coords = layout->GetDOFHolderCoordinates(); REQUIRE(coords.GetCoordinateSystem() == CoordinateSystem::Cartesian); @@ -230,9 +230,9 @@ TEST_CASE("FieldData: layout metadata queries") auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); - auto field_data = factory.CreateField(); + auto field_data = factory->CreateFunction(); - auto coords = factory.GetLayout()->GetDOFHolderCoordinates(); + auto coords = factory->GetLayout()->GetDOFHolderCoordinates(); REQUIRE(coords.GetCoordinateSystem() == CoordinateSystem::Cartesian); REQUIRE(coords.GetValues().extent(0) > 0); REQUIRE(coords.GetValues().extent(1) == 2); @@ -251,9 +251,9 @@ TEST_CASE("SimpleFieldData: set and get DOF holder data round-trip") auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::OmegaH); - auto field_data = factory.CreateField(); + auto field_data = factory->CreateFunction(); - auto& layout = *factory.GetLayout(); + auto& layout = *factory->GetLayout(); int n = layout.GetNumOwnedDofHolder(); REQUIRE(n > 0); @@ -288,7 +288,7 @@ TEST_CASE("FieldLayout: MeshFields metadata queries") mesh, 1, 1, CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::MeshFields); - auto layout = factory.GetLayout(); + auto layout = factory->GetLayout(); auto coords = layout->GetDOFHolderCoordinates(); REQUIRE(coords.GetCoordinateSystem() == CoordinateSystem::Cartesian); REQUIRE(coords.GetValues().extent(0) > 0); @@ -305,16 +305,16 @@ TEST_CASE("PointEvaluator: MeshFields order-1 linear evaluation") mesh, 1, 1, CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::MeshFields); - auto field_data = factory.CreateField(); + auto field_data = factory->CreateFunction(); pcms::test::SetField( - field_data.GetData(), *factory.GetLayout(), + field_data.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + 2.0 * y; }); auto pts = pcms::test::StandardEvalCoords2D(); int n = static_cast(pts.size()) / 2; auto device_coords = pcms::test::CreateDeviceCoordinateView(pts, CoordinateSystem::Cartesian); - auto evaluator = factory.CreatePointEvaluator( + auto evaluator = factory->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view)); pcms::test::CheckEvaluation( *evaluator, field_data, pts, @@ -331,9 +331,9 @@ TEST_CASE("PointEvaluator: MeshFields out-of-bounds fill") mesh, 1, 1, CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::MeshFields); - auto field_data = factory.CreateField(); + auto field_data = factory->CreateFunction(); pcms::test::SetField( - field_data.GetData(), *factory.GetLayout(), + field_data.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + 2.0 * y; }); const std::vector outside_pts = {-0.5, 0.5, 1.5, 0.5, @@ -341,9 +341,9 @@ TEST_CASE("PointEvaluator: MeshFields out-of-bounds fill") auto device_coords = pcms::test::CreateDeviceCoordinateView( outside_pts, CoordinateSystem::Cartesian); pcms::OutOfBoundsPolicy policy{pcms::OutOfBoundsMode::FILL, -999.0}; - auto evaluator = - factory.CreatePointEvaluator(pcms::EvaluationRequest::FromCoordinates( - device_coords.coordinate_view, policy)); + auto evaluator = factory->CreatePointEvaluator( + pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view, + policy)); pcms::test::CheckFillMode(*evaluator, field_data, -999.0, outside_pts); } @@ -358,13 +358,13 @@ TEST_CASE( mesh, 1, 1, CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::Backend::MeshFields); - auto field_a = factory.CreateField(); - auto field_b = factory.CreateField(); + auto field_a = factory->CreateFunction(); + auto field_b = factory->CreateFunction(); pcms::test::SetField( - field_a.GetData(), *factory.GetLayout(), + field_a.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + 2.0 * y; }); pcms::test::SetField( - field_b.GetData(), *factory.GetLayout(), + field_b.GetData(), *factory->GetLayout(), OMEGA_H_LAMBDA(Real, Real) { return Real(42); }); auto pts = pcms::test::StandardEvalCoords2D(); @@ -372,7 +372,7 @@ TEST_CASE( auto device_coords = pcms::test::CreateDeviceCoordinateView(pts, CoordinateSystem::Cartesian); - auto evaluator = factory.CreatePointEvaluator( + auto evaluator = factory->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view)); Kokkos::View out_a_device("out_a", n); diff --git a/test/test_polynomial_reconstruction_function_space.cpp b/test/test_polynomial_reconstruction_function_space.cpp index 1b725ab7..0281c13f 100644 --- a/test/test_polynomial_reconstruction_function_space.cpp +++ b/test/test_polynomial_reconstruction_function_space.cpp @@ -37,7 +37,7 @@ TEST_CASE( auto factory = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian); - auto layout = factory.GetLayout(); + auto layout = factory->GetLayout(); REQUIRE(layout->GetNumComponents() == 1); REQUIRE(layout->GetNumOwnedDofHolder() == 4); @@ -64,8 +64,8 @@ TEST_CASE("PolynomialReconstructionFunctionSpace fields share layout") auto factory = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian); - auto source = factory.CreateField(); - auto target = factory.CreateField(); + auto source = factory->CreateFunction(); + auto target = factory->CreateFunction(); REQUIRE(&source.GetLayout() == &target.GetLayout()); } @@ -78,7 +78,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace point-cloud field set/get DOF " auto field = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian) - .CreateField(); + ->CreateFunction(); std::vector data{1.0, 2.0, 3.0, 4.0}; Rank2View data_view( @@ -100,14 +100,14 @@ TEST_CASE("PolynomialReconstructionFunctionSpace point-cloud field serialize / " auto factory = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); std::vector data{5.0, 6.0, 7.0, 8.0}; Rank2View data_view( data.data(), static_cast(data.size()), 1); field.GetData().SetDOFHolderDataHost(data_view); - pcms::test::CheckSerializeDeserialize(*factory.GetLayout(), field.GetData()); + pcms::test::CheckSerializeDeserialize(*factory->GetLayout(), field.GetData()); } TEST_CASE("PolynomialReconstructionFunctionSpace field keeps layout alive " @@ -119,7 +119,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace field keeps layout alive " auto field = [&]() { auto factory = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian); - return factory.CreateField(); + return factory->CreateFunction(); }(); auto point_cloud_layout = @@ -148,15 +148,15 @@ TEST_CASE("Different layouts on the same mesh report SameEntities") auto lagrange = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, CoordinateSystem::Cartesian); - auto nodal_disc = nodal.GetLayout()->GetDiscretization(); - auto lagrange_disc = lagrange.GetLayout()->GetDiscretization(); + auto nodal_disc = nodal->GetLayout()->GetDiscretization(); + auto lagrange_disc = lagrange->GetLayout()->GetDiscretization(); REQUIRE(nodal_disc != nullptr); REQUIRE(lagrange_disc != nullptr); REQUIRE(nodal_disc->SameEntities(*lagrange_disc)); - REQUIRE(nodal.GetLayout()->GetNumOwnedDofHolder() == mesh.nfaces()); - REQUIRE(lagrange.GetLayout()->GetNumOwnedDofHolder() == mesh.nverts()); + REQUIRE(nodal->GetLayout()->GetNumOwnedDofHolder() == mesh.nfaces()); + REQUIRE(lagrange->GetLayout()->GetNumOwnedDofHolder() == mesh.nverts()); REQUIRE(nodal_disc->GetNumEntities(pcms::Face) == mesh.nfaces()); REQUIRE(lagrange_disc->GetNumEntities(pcms::Vertex) == mesh.nverts()); @@ -175,8 +175,8 @@ TEST_CASE("Layouts on different meshes do not report SameEntities") auto nodal_b = pcms::PolynomialReconstructionFunctionSpace::FromMesh( mesh_b, pcms::Vertex, CoordinateSystem::Cartesian); - auto disc_a = nodal_a.GetLayout()->GetDiscretization(); - auto disc_b = nodal_b.GetLayout()->GetDiscretization(); + auto disc_a = nodal_a->GetLayout()->GetDiscretization(); + auto disc_b = nodal_b->GetLayout()->GetDiscretization(); REQUIRE_FALSE(disc_a->SameEntities(*disc_b)); } @@ -196,8 +196,8 @@ TEST_CASE( auto standalone = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian); - auto mesh_disc = lagrange.GetLayout()->GetDiscretization(); - auto point_cloud_disc = standalone.GetLayout()->GetDiscretization(); + auto mesh_disc = lagrange->GetLayout()->GetDiscretization(); + auto point_cloud_disc = standalone->GetLayout()->GetDiscretization(); REQUIRE_FALSE(mesh_disc->SameEntities(*point_cloud_disc)); REQUIRE_FALSE(point_cloud_disc->SameEntities(*mesh_disc)); diff --git a/test/test_polynomial_reconstruction_mls_evaluation.cpp b/test/test_polynomial_reconstruction_mls_evaluation.cpp index 6527e9e0..888a83b1 100644 --- a/test/test_polynomial_reconstruction_mls_evaluation.cpp +++ b/test/test_polynomial_reconstruction_mls_evaluation.cpp @@ -119,13 +119,13 @@ void CheckPolynomialReproduction(unsigned degree, auto fs = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian, SweepTestOptions(degree, basis)); - auto field = fs.CreateField(); - pcms::test::SetField(field.GetData(), *fs.GetLayout(), func); + auto field = fs->CreateFunction(); + pcms::test::SetField(field.GetData(), *fs->GetLayout(), func); auto pts = QueryPoints(); auto device_coords = pcms::test::CreateDeviceCoordinateView(pts, CoordinateSystem::Cartesian); - auto evaluator = fs.CreatePointEvaluator( + auto evaluator = fs->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view)); pcms::test::CheckEvaluation(*evaluator, field, pts, func, abs_tol); } @@ -170,22 +170,22 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: same PointEvaluator " auto fs = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian, DefaultTestOptions()); - auto field_a = fs.CreateField(); - auto field_b = fs.CreateField(); + auto field_a = fs->CreateFunction(); + auto field_b = fs->CreateFunction(); pcms::test::SetField( - field_a.GetData(), *fs.GetLayout(), + field_a.GetData(), *fs->GetLayout(), OMEGA_H_LAMBDA(Real x, Real y) { return x + 2.0 * y; }); const Real cval = 7.0; pcms::test::SetField( - field_b.GetData(), *fs.GetLayout(), + field_b.GetData(), *fs->GetLayout(), OMEGA_H_LAMBDA(Real, Real) { return cval; }); auto pts = QueryPoints(); int n = static_cast(pts.size()) / 2; auto device_coords = pcms::test::CreateDeviceCoordinateView(pts, CoordinateSystem::Cartesian); - auto evaluator = fs.CreatePointEvaluator( + auto evaluator = fs->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view)); Kokkos::View out_a_device("out_a", n); @@ -226,13 +226,13 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: Evaluate throws for " auto fs = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian); - auto field = fs.CreateField(); + auto field = fs->CreateFunction(); auto pts = QueryPoints(); int n = static_cast(pts.size()) / 2; auto device_coords = pcms::test::CreateDeviceCoordinateView(pts, CoordinateSystem::Cartesian); - auto evaluator = fs.CreatePointEvaluator( + auto evaluator = fs->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view)); // Two-component output — must throw @@ -258,16 +258,16 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: default MLSOptions — " // Use default options — no third argument auto fs = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian); - auto field = fs.CreateField(); + auto field = fs->CreateFunction(); pcms::test::SetField( - field.GetData(), *fs.GetLayout(), + field.GetData(), *fs->GetLayout(), OMEGA_H_LAMBDA(Real, Real) { return Real(1.0); }); auto pts = QueryPoints(); int n = static_cast(pts.size()) / 2; auto device_coords = pcms::test::CreateDeviceCoordinateView(pts, CoordinateSystem::Cartesian); - auto evaluator = fs.CreatePointEvaluator( + auto evaluator = fs->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view)); Kokkos::View out_device("out", n); @@ -296,7 +296,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: CreatePointEvaluator " auto pts = QueryPoints(); auto device_coords = pcms::test::CreateDeviceCoordinateView(pts, CoordinateSystem::Cartesian); - REQUIRE_THROWS(fs.CreatePointEvaluator( + REQUIRE_THROWS(fs->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view))); } @@ -313,7 +313,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: CreatePointEvaluator " auto pts = QueryPoints(); auto device_coords = pcms::test::CreateDeviceCoordinateView(pts, CoordinateSystem::Cylindrical); - REQUIRE_THROWS(fs.CreatePointEvaluator( + REQUIRE_THROWS(fs->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view))); } @@ -332,7 +332,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: radius option is " auto fs = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian, opts); - auto field = fs.CreateField(); + auto field = fs->CreateFunction(); std::vector dof_values{1.0, 5.0}; field.GetData().SetDOFHolderDataHost(Rank2View( dof_values.data(), static_cast(dof_values.size()), 1)); @@ -340,7 +340,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: radius option is " std::vector pts{0.0, 0.0}; auto device_coords = pcms::test::CreateDeviceCoordinateView(pts, CoordinateSystem::Cartesian); - auto evaluator = fs.CreatePointEvaluator( + auto evaluator = fs->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view)); Kokkos::View out_device("out", 1); using LayoutPolicy = @@ -364,7 +364,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: 3D point clouds preserve " auto fs = pcms::PolynomialReconstructionFunctionSpace::Create( coords_view, CoordinateSystem::Cartesian, DefaultTestOptions3D()); auto layout_coords_device = - fs.GetLayout()->GetDOFHolderCoordinates().GetValues(); + fs->GetLayout()->GetDOFHolderCoordinates().GetValues(); auto layout_coords = pcms::test::CopyCoordinatesToHost(layout_coords_device, 27, 3); REQUIRE(static_cast(layout_coords.extent(1)) == 3); @@ -374,7 +374,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: 3D point clouds preserve " REQUIRE(layout_coords(i, 2) == Catch::Approx(src[3 * i + 2])); } - auto field = fs.CreateField(); + auto field = fs->CreateFunction(); std::vector dof_values(27); for (int i = 0; i < 27; ++i) { const Real x = src[3 * i + 0]; @@ -388,7 +388,7 @@ TEST_CASE("PolynomialReconstructionFunctionSpace MLS: 3D point clouds preserve " std::vector pts{0.5, 0.5, 0.25, 0.5, 0.5, 0.75}; auto device_coords = pcms::test::CreateDeviceCoordinateView(pts, CoordinateSystem::Cartesian, 3); - auto evaluator = fs.CreatePointEvaluator( + auto evaluator = fs->CreatePointEvaluator( pcms::EvaluationRequest::FromCoordinates(device_coords.coordinate_view)); Kokkos::View out_device("out", 2); using LayoutPolicy = diff --git a/test/test_proxy_coupling.cpp b/test/test_proxy_coupling.cpp index c0fbce75..6e166ad6 100644 --- a/test/test_proxy_coupling.cpp +++ b/test/test_proxy_coupling.cpp @@ -93,14 +93,14 @@ void xgc_delta_f(MPI_Comm comm, Omega_h::Mesh& mesh) mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::DefaultBackend, "gids"); - auto gids_field = factory.CreateField("gids"); - auto gids2_field = factory.CreateField("gids2"); + auto gids_field = factory->CreateFunction("gids"); + auto gids2_field = factory->CreateFunction("gids2"); auto* gids_ptr = &gids_field.GetData(); auto* gids2_ptr = &gids2_field.GetData(); - initializeFieldWithGids(*factory.GetLayout(), gids_ptr, 1.0); - initializeFieldWithGids(*factory.GetLayout(), gids2_ptr, 2.0); + initializeFieldWithGids(*factory->GetLayout(), gids_ptr, 1.0); + initializeFieldWithGids(*factory->GetLayout(), gids2_ptr, 2.0); app->AddField(std::move(gids_field)); app->AddField(std::move(gids2_field)); @@ -114,7 +114,7 @@ void xgc_delta_f(MPI_Comm comm, Omega_h::Mesh& mesh) app->ReceiveField("gids"); //(Alt) df_gid_field->Receive(); app->EndReceivePhase(); - if (!validateField(*factory.GetLayout(), gids_ptr, "gids", rank, 1.0)) { + if (!validateField(*factory->GetLayout(), gids_ptr, "gids", rank, 1.0)) { std::cerr << "xgc_delta_f: Field validation failed at round " << i << std::endl; exit(EXIT_FAILURE); @@ -134,11 +134,11 @@ void xgc_total_f(MPI_Comm comm, Omega_h::Mesh& mesh) mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::DefaultBackend, "gids"); - auto gids_field = factory.CreateField("gids"); + auto gids_field = factory->CreateFunction("gids"); auto* gids_ptr = &gids_field.GetData(); - initializeFieldWithGids(*factory.GetLayout(), gids_ptr, 10.0); + initializeFieldWithGids(*factory->GetLayout(), gids_ptr, 10.0); app->AddField(std::move(gids_field)); @@ -151,7 +151,7 @@ void xgc_total_f(MPI_Comm comm, Omega_h::Mesh& mesh) app->ReceiveField("gids"); //(Alt) tf_gid_field->Receive(); app->EndReceivePhase(); - if (!validateField(*factory.GetLayout(), gids_ptr, "gids", rank, 10.0)) { + if (!validateField(*factory->GetLayout(), gids_ptr, "gids", rank, 10.0)) { std::cerr << "xgc_total_f: Field validation failed at round " << i << std::endl; exit(EXIT_FAILURE); @@ -180,9 +180,9 @@ void xgc_coupler(MPI_Comm comm, Omega_h::Mesh& mesh, std::string_view cpn_file) mesh, 1, 1, pcms::CoordinateSystem::Cartesian, "global", pcms::LagrangeFunctionSpace::DefaultBackend, "gids"); // TODO, fields should have a transfer policy rather than parameters - auto total_gids_field = factory_total.CreateField("gids"); - auto delta_gids_field = factory_delta.CreateField("gids"); - auto delta_gids2_field = factory_delta.CreateField("gids2"); + auto total_gids_field = factory_total->CreateFunction("gids"); + auto delta_gids_field = factory_delta->CreateFunction("gids"); + auto delta_gids2_field = factory_delta->CreateFunction("gids2"); auto* total_gids_ptr = &total_gids_field.GetData(); auto* delta_gids_ptr = &delta_gids_field.GetData(); @@ -198,7 +198,7 @@ void xgc_coupler(MPI_Comm comm, Omega_h::Mesh& mesh, std::string_view cpn_file) total_f->ReceiveField("gids"); total_f->EndReceivePhase(); - if (!validateField(*factory_total.GetLayout(), total_gids_ptr, "gids", + if (!validateField(*factory_total->GetLayout(), total_gids_ptr, "gids", rank, 10.0)) { std::cerr << "xgc_coupler: total_f field validation failed at round " << i << std::endl; @@ -209,7 +209,7 @@ void xgc_coupler(MPI_Comm comm, Omega_h::Mesh& mesh, std::string_view cpn_file) delta_f->ReceiveField("gids"); delta_f->EndReceivePhase(); - if (!validateField(*factory_delta.GetLayout(), delta_gids_ptr, "gids", + if (!validateField(*factory_delta->GetLayout(), delta_gids_ptr, "gids", rank, 1.0)) { std::cerr << "xgc_coupler: delta_f field validation failed at round " << i << std::endl; diff --git a/test/test_proxy_coupling_xgc_server.cpp b/test/test_proxy_coupling_xgc_server.cpp index 938290db..ada0b759 100644 --- a/test/test_proxy_coupling_xgc_server.cpp +++ b/test/test_proxy_coupling_xgc_server.cpp @@ -52,8 +52,8 @@ void xgc_coupler(MPI_Comm comm, Omega_h::Mesh& mesh, std::string_view cpn_file) // field registration, so each XGC plane is registered as a separate layout // communicator even though the layouts are geometrically identical. auto function_space = - pcms::XGCFunctionSpace(rc, ts::IsModelEntInOverlap{}, - static_cast(mesh.nverts()), ss.str()); + pcms::XGCFieldFactory(rc, ts::IsModelEntInOverlap{}, + static_cast(mesh.nverts()), ss.str()); auto field = function_space.CreateField( ss.str(), std::make_unique>( function_space.GetXGCLayout(), pcms::FieldMetadata{}, @@ -173,9 +173,9 @@ void omegah_coupler(MPI_Comm comm, Omega_h::Mesh& mesh, auto factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian, numbering, pcms::LagrangeFunctionSpace::Backend::OmegaH, ss.str()); - auto field = factory.CreateField( + auto field = factory->CreateFunction( ss.str(), std::make_unique>( - factory.GetLayout(), pcms::FieldMetadata{})); + factory->GetLayout(), pcms::FieldMetadata{})); std::unique_ptr> serializer = std::make_unique>(); fields.push_back( diff --git a/test/test_proxy_coupling_xgc_server_overlap.cpp b/test/test_proxy_coupling_xgc_server_overlap.cpp index b12d9f80..4bfafc20 100644 --- a/test/test_proxy_coupling_xgc_server_overlap.cpp +++ b/test/test_proxy_coupling_xgc_server_overlap.cpp @@ -55,8 +55,8 @@ void xgc_coupler_with_overlap(MPI_Comm comm, Omega_h::Mesh& mesh, application->SetLayoutOverlapMask(ss.str(), std::move(overlap_mask)); auto function_space = - pcms::XGCFunctionSpace(rc, ts::IsModelEntInOverlap{}, - static_cast(mesh.nverts()), ss.str()); + pcms::XGCFieldFactory(rc, ts::IsModelEntInOverlap{}, + static_cast(mesh.nverts()), ss.str()); auto field = function_space.CreateField( ss.str(), std::make_unique>( @@ -176,9 +176,9 @@ void omegah_coupler_with_overlap(MPI_Comm comm, Omega_h::Mesh& mesh, mesh, 1, 1, pcms::CoordinateSystem::Cartesian, numbering, pcms::LagrangeFunctionSpace::Backend::OmegaH, ss.str()); - auto field = factory.CreateField( + auto field = factory->CreateFunction( ss.str(), std::make_unique>( - factory.GetLayout(), pcms::FieldMetadata{})); + factory->GetLayout(), pcms::FieldMetadata{})); std::unique_ptr> serializer = std::make_unique>(); diff --git a/test/test_uniform_grid_field.cpp b/test/test_uniform_grid_field.cpp index 5afff3f2..632bd4db 100644 --- a/test/test_uniform_grid_field.cpp +++ b/test/test_uniform_grid_field.cpp @@ -109,7 +109,7 @@ TEST_CASE("UniformGrid field creation") auto field_space = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian); - auto field = field_space.CreateField(); + auto field = field_space->CreateFunction(); REQUIRE(field.GetDOFHolderDataHost().size() == static_cast(layout->OwnedSize())); } @@ -125,7 +125,7 @@ TEST_CASE("UniformGrid order-0 field creation and evaluation") grid, 1, pcms::CoordinateSystem::Cartesian, 0); auto field_space = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian, 0); - auto field = field_space.CreateField(); + auto field = field_space->CreateFunction(); pcms::UniformGridEvaluatorFactory<2> eval_factory(layout); REQUIRE(layout->GetOrder() == 0); @@ -179,7 +179,7 @@ TEST_CASE("UniformGrid field data operations", "[uniform_grid_field]") grid, 1, pcms::CoordinateSystem::Cartesian); auto field_space = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian); - auto field = field_space.CreateField(); + auto field = field_space->CreateFunction(); std::vector data(25); for (size_t i = 0; i < 25; ++i) @@ -206,7 +206,7 @@ TEST_CASE("UniformGrid field evaluation - piecewise constant") grid, 1, pcms::CoordinateSystem::Cartesian); auto field_space = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian); - auto field = field_space.CreateField(); + auto field = field_space->CreateFunction(); pcms::UniformGridEvaluatorFactory<2> eval_factory(layout); // Set vertex values for a 2x2 cell grid (3x3 = 9 vertices) @@ -269,7 +269,7 @@ TEST_CASE("UniformGrid field serialization") grid, 1, pcms::CoordinateSystem::Cartesian); auto field_space = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian); - auto field = field_space.CreateField(); + auto field = field_space->CreateFunction(); std::vector data(16); for (size_t i = 0; i < 16; ++i) @@ -303,13 +303,13 @@ TEST_CASE("UniformGrid field copy") auto factory = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian); - auto field = factory.CreateField(); + auto field = factory->CreateFunction(); field.SetDOFHolderDataHost( pcms::Rank2View( data.data(), static_cast(data.size()), 1)); - auto field2 = factory.CreateField(); - pcms::Copy copy(factory, factory); + auto field2 = factory->CreateFunction(); + pcms::Copy copy(*factory, *factory); copy.Apply(field, field2); auto copied_data = pcms::FlattenToRank1View(field2.GetDOFHolderDataHost()); @@ -326,7 +326,7 @@ TEST_CASE("Transfer from OmegaH field to UniformGrid field") auto omega_h_factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto omega_h_field = omega_h_factory.CreateField(); + auto omega_h_field = omega_h_factory->CreateFunction(); pcms::test::SetField( omega_h_field, OMEGA_H_LAMBDA(pcms::Real x, pcms::Real y) { return x + 2.0 * y; }); @@ -337,15 +337,15 @@ TEST_CASE("Transfer from OmegaH field to UniformGrid field") grid.divisions = {2, 2}; auto ug_factory = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian); - auto ug_field = ug_factory.CreateField(); + auto ug_field = ug_factory->CreateFunction(); - pcms::Interpolator interp(omega_h_factory, ug_factory); + pcms::Interpolator interp(*omega_h_factory, *ug_factory); interp.Apply(omega_h_field, ug_field); auto transferred_data = pcms::FlattenToRank1View(ug_field.GetDOFHolderDataHost()); - auto ug_coords = ug_factory.GetLayout()->GetDOFHolderCoordinates(); - int num_ug_nodes = ug_factory.GetLayout()->GetNumOwnedDofHolder(); + auto ug_coords = ug_factory->GetLayout()->GetDOFHolderCoordinates(); + int num_ug_nodes = ug_factory->GetLayout()->GetNumOwnedDofHolder(); // set up_coords to host auto ug_coords_host = @@ -639,22 +639,22 @@ TEST_CASE("UniformGrid workflow") auto omega_h_factory = pcms::LagrangeFunctionSpace::FromMesh( mesh, 1, 1, pcms::CoordinateSystem::Cartesian); - auto omega_h_field = omega_h_factory.CreateField(); + auto omega_h_field = omega_h_factory->CreateFunction(); pcms::test::SetField( omega_h_field, OMEGA_H_LAMBDA(pcms::Real x, pcms::Real y) { return x + 2.0 * y; }); auto ug_factory = pcms::LagrangeFunctionSpace::FromUniformGrid( grid, 1, pcms::CoordinateSystem::Cartesian); - auto ug_field = ug_factory.CreateField(); + auto ug_field = ug_factory->CreateFunction(); auto [mask_layout, mask_field] = pcms::CreateUniformGridBinaryField<2>(mesh, grid); - pcms::Interpolator interp(omega_h_factory, ug_factory); + pcms::Interpolator interp(*omega_h_factory, *ug_factory); interp.Apply(omega_h_field, ug_field); auto ug_coords_device_view = - ug_factory.GetLayout()->GetDOFHolderCoordinates().GetValues(); + ug_factory->GetLayout()->GetDOFHolderCoordinates().GetValues(); auto ug_coords_host_view = pcms::test::CopyCoordinatesToHost(ug_coords_device_view, 25, 2); diff --git a/test/test_xgc_field_data.cpp b/test/test_xgc_field_data.cpp index 16322cf9..30a95163 100644 --- a/test/test_xgc_field_data.cpp +++ b/test/test_xgc_field_data.cpp @@ -104,11 +104,11 @@ TEST_CASE("XGC FieldData serializer preserves inactive entries") } } -TEST_CASE("XGCFunctionSpace creates fields and rejects evaluator access") +TEST_CASE("XGCFieldFactory creates fields and rejects evaluator access") { static constexpr int data_size = 16; auto rc = create_dummy_rc(data_size); - pcms::XGCFunctionSpace function_space(rc, in_overlap, data_size); + pcms::XGCFieldFactory function_space(rc, in_overlap, data_size); std::vector data(data_size); std::iota(data.begin(), data.end(), 0.0); @@ -118,15 +118,4 @@ TEST_CASE("XGCFunctionSpace creates fields and rejects evaluator access") pcms::make_array_view(data))); REQUIRE(&field.GetLayout() == function_space.GetLayout().get()); - REQUIRE(function_space.GetCoordinateSystem() == pcms::CoordinateSystem::XGC); - // XGC does not support point evaluation; CreatePointEvaluator throws. - using LayoutPolicy = - pcms::detail::default_layout_for_memory_space_t; - pcms::Rank2View - empty_coords{nullptr, 0, 2}; - REQUIRE_THROWS_AS(function_space.CreatePointEvaluator( - pcms::EvaluationRequest::FromCoordinates( - pcms::CoordinateView{ - pcms::CoordinateSystem::XGC, empty_coords})), - pcms::pcms_error); } diff --git a/test/xgc_n0_coupling_server.cpp b/test/xgc_n0_coupling_server.cpp index e420b41c..0484c810 100644 --- a/test/xgc_n0_coupling_server.cpp +++ b/test/xgc_n0_coupling_server.cpp @@ -43,12 +43,12 @@ struct RegisteredField [[nodiscard]] static RegisteredField AddField( pcms::Application* application, - const pcms::LagrangeFunctionSpace& function_space, const std::string& name, - const std::string& path, int plane) + const std::shared_ptr& function_space, + const std::string& name, const std::string& path, int plane) { PCMS_ALWAYS_ASSERT(application != nullptr); auto field_name = MakeFieldName(name, plane); - auto field = function_space.CreateField(path + field_name); + auto field = function_space->CreateFunction(path + field_name); std::unique_ptr> serializer = std::make_unique>(); auto handle = application->AddField(std::move(field), std::move(serializer)); From fed617ad1eca14f4b8a669c133fdbae1385ff8ac Mon Sep 17 00:00:00 2001 From: Jacob Merson Date: Sun, 12 Jul 2026 16:04:22 -0400 Subject: [PATCH 4/4] clang-format field_factory.h --- src/pcms/field/field_factory.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pcms/field/field_factory.h b/src/pcms/field/field_factory.h index 6aa63a34..7903c72e 100644 --- a/src/pcms/field/field_factory.h +++ b/src/pcms/field/field_factory.h @@ -71,7 +71,8 @@ class FieldFactory }; template -Field FieldFactory::CreateField(std::string name, FieldMetadata metadata) const +Field FieldFactory::CreateField(std::string name, + FieldMetadata metadata) const { static_assert(is_supported_field_type_v, "T is not a supported field type");