-
Notifications
You must be signed in to change notification settings - Fork 18
Conservative projection in C-Fortran API #349
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -133,3 +133,156 @@ void pcms_interpolate(PcmsInterpolatorHandle interpolator, void* input, | |
|
|
||
| mls_interpolator->eval(input_array, output_array); | ||
| } | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
| // Conservative Projection (mesh-intersection-based) | ||
| // --------------------------------------------------------------------------- | ||
|
|
||
| #if defined(PCMS_ENABLE_PETSC) && defined(PCMS_ENABLE_MESHFIELDS) | ||
| #include <Omega_h_file.hpp> | ||
| #include <Omega_h_library.hpp> | ||
| #include <pcms/field/field.h> | ||
| #include <pcms/field/function_space/lagrange.h> | ||
| #include <pcms/transfer/omega_h_conservative_projection.hpp> | ||
| #include <pcms/utility/arrays.h> | ||
| #include <cstring> | ||
| #include <memory> | ||
| #include <string> | ||
|
|
||
| namespace | ||
| { | ||
|
|
||
| // Trims trailing whitespace from a C string (Fortran strings may be padded). | ||
| std::string trim_filename(const char* filename) | ||
| { | ||
| auto fname = std::string(filename); | ||
| fname.erase(fname.find_last_not_of(" \n\r\t") + 1); | ||
| return fname; | ||
| } | ||
|
|
||
| struct ConservativeProjectionContext | ||
| { | ||
| // Library must be declared before meshes (Omega_h::Mesh holds a pointer to | ||
| // it). | ||
| Omega_h::Library library; | ||
| Omega_h::Mesh source_mesh; | ||
| Omega_h::Mesh target_mesh; | ||
| std::shared_ptr<pcms::LagrangeFunctionSpace> source_space; | ||
| std::shared_ptr<pcms::LagrangeFunctionSpace> target_space; | ||
| std::unique_ptr<pcms::OmegaHConservativeProjection> projection; | ||
| pcms::Function<pcms::Real> source_field; | ||
| pcms::Function<pcms::Real> target_field; | ||
|
|
||
| ConservativeProjectionContext(const char* source_mesh_name, | ||
| const char* target_mesh_name, int src_order, | ||
| int tgt_order) | ||
| : library(nullptr, nullptr, MPI_COMM_SELF), | ||
| source_mesh(Omega_h::binary::read(trim_filename(source_mesh_name), | ||
| library.world())), | ||
| target_mesh(Omega_h::binary::read(trim_filename(target_mesh_name), | ||
| library.world())), | ||
| source_space(pcms::LagrangeFunctionSpace::FromMesh( | ||
| source_mesh, src_order, 1, pcms::CoordinateSystem::Cartesian, "global", | ||
| pcms::LagrangeFunctionSpace::Backend::OmegaH)), | ||
| target_space(pcms::LagrangeFunctionSpace::FromMesh( | ||
| target_mesh, tgt_order, 1, pcms::CoordinateSystem::Cartesian, "global", | ||
| pcms::LagrangeFunctionSpace::Backend::OmegaH)), | ||
| projection(std::make_unique<pcms::OmegaHConservativeProjection>( | ||
| *source_space, *target_space)), | ||
| source_field(source_space->CreateFunction<pcms::Real>()), | ||
| target_field(target_space->CreateFunction<pcms::Real>()) | ||
| { | ||
| } | ||
| }; | ||
|
|
||
| } // namespace | ||
|
|
||
| PcmsConservativeProjectionHandle pcms_create_conservative_projection( | ||
| const char* source_mesh_name, int source_order, const char* target_mesh_name, | ||
| int target_order) | ||
| { | ||
| auto* ctx = new ConservativeProjectionContext( | ||
| source_mesh_name, target_mesh_name, source_order, target_order); | ||
| return {reinterpret_cast<void*>(ctx)}; | ||
| } | ||
|
Comment on lines
+200
to
+207
|
||
|
|
||
| int pcms_conservative_projection_get_source_size( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| PcmsConservativeProjectionHandle projection) | ||
| { | ||
| auto* ctx = | ||
| reinterpret_cast<ConservativeProjectionContext*>(projection.pointer); | ||
| return ctx->source_space->GetLayout()->GetNumOwnedDofHolder(); | ||
| } | ||
|
Comment on lines
+209
to
+215
|
||
|
|
||
| int pcms_conservative_projection_get_target_size( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| PcmsConservativeProjectionHandle projection) | ||
| { | ||
| auto* ctx = | ||
| reinterpret_cast<ConservativeProjectionContext*>(projection.pointer); | ||
| return ctx->target_space->GetLayout()->GetNumOwnedDofHolder(); | ||
| } | ||
|
|
||
| void pcms_conservative_projection_apply( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| PcmsConservativeProjectionHandle projection, void* source_data, | ||
| int source_size, void* target_data, int target_size) | ||
| { | ||
| auto* ctx = | ||
| reinterpret_cast<ConservativeProjectionContext*>(projection.pointer); | ||
|
|
||
| // Copy source data into internal field | ||
| auto source_view = pcms::Rank2View<const pcms::Real, pcms::HostMemorySpace>( | ||
| reinterpret_cast<pcms::Real*>(source_data), source_size, 1); | ||
| ctx->source_field.SetDOFHolderDataHost(source_view); | ||
|
|
||
| // Apply conservative projection | ||
| ctx->projection->Apply(ctx->source_field, ctx->target_field); | ||
|
|
||
| // Copy result back to user buffer | ||
| auto target_view = ctx->target_field.GetDOFHolderDataHost(); | ||
| auto flat = pcms::FlattenToRank1View(target_view); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suspect we can probably avoid this memcopy if the target field is constructed based on the target field pointer. I think the XGC field data is non-owning specifically for this reason, however I implemented that a while ago so it needs to be checked. |
||
| std::memcpy(target_data, flat.data_handle(), | ||
| static_cast<std::size_t>(target_size) * sizeof(double)); | ||
| } | ||
|
Comment on lines
+225
to
+245
|
||
|
|
||
| void pcms_destroy_conservative_projection( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| PcmsConservativeProjectionHandle projection) | ||
| { | ||
| if (projection.pointer != nullptr) { | ||
| delete reinterpret_cast<ConservativeProjectionContext*>(projection.pointer); | ||
| } | ||
| } | ||
|
|
||
| #else // !(PCMS_ENABLE_PETSC && PCMS_ENABLE_MESHFIELDS) | ||
|
|
||
| // Stub implementations when PETSc or MeshFields are unavailable | ||
|
|
||
| PcmsConservativeProjectionHandle pcms_create_conservative_projection( | ||
| const char*, int, const char*, int) | ||
| { | ||
| pcms::printError("Conservative projection requires PCMS_ENABLE_PETSC and " | ||
| "PCMS_ENABLE_MESHFIELDS\n"); | ||
| return {nullptr}; | ||
| } | ||
|
|
||
| int pcms_conservative_projection_get_source_size( | ||
| PcmsConservativeProjectionHandle) | ||
| { | ||
| return 0; | ||
| } | ||
|
|
||
| int pcms_conservative_projection_get_target_size( | ||
| PcmsConservativeProjectionHandle) | ||
| { | ||
| return 0; | ||
| } | ||
|
|
||
| void pcms_conservative_projection_apply(PcmsConservativeProjectionHandle, void*, | ||
| int, void*, int) | ||
| { | ||
| pcms::printError("Conservative projection requires PCMS_ENABLE_PETSC and " | ||
| "PCMS_ENABLE_MESHFIELDS\n"); | ||
| } | ||
|
|
||
| void pcms_destroy_conservative_projection(PcmsConservativeProjectionHandle) {} | ||
|
|
||
| #endif | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this return a TransferOperatorHandle? With the new API, all of the transfer operators should be able to be used the same way after construction.