Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/clang-tidy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ jobs:
echo "$file has clang-tidy issues"
EXIT_CODE=1
fi
done < <(find src -name "*.cpp" -o -name "*.hpp" -o -name "*.c" -o -name "*.h" -o -name "*.cc" -o -name "*.cxx" | grep -v 'src/pcms/capi/' | grep -v 'src/pcms/fortranapi/')
done < <(find src -name "*.cpp" -o -name "*.hpp" -o -name "*.c" -o -name "*.h" -o -name "*.cc" -o -name "*.cxx" | grep -v 'src/pcms/capi/' | grep -v 'src/pcms/fortranapi/' | grep -v 'src/pcms/pythonapi/')
if [ $EXIT_CODE -eq 1 ]; then
echo "Some C/C++ files have clang-tidy issues. Please fix them with clang-tidy-18."
exit 1
Expand Down
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ option(PCMS_ENABLE_CLIENT "enable the coupling client implementation" ON)
option(PCMS_ENABLE_XGC "enable xgc field adapter" ON)
option(PCMS_ENABLE_OMEGA_H "enable Omega_h field adapter" OFF)
option(PCMS_ENABLE_C "Enable pcms C api" ON)
option(PCMS_ENABLE_Python "Enable pcms Python api" OFF)

option(PCMS_ENABLE_PRINT "PCMS print statements enabled" ON)
option(PCMS_ENABLE_SPDLOG "use spdlog for logging" ON)
Expand All @@ -37,6 +38,9 @@ endif()
# broken
find_package(redev 4.3.0 REQUIRED)

if (PCMS_ENABLE_Python)
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
endif ()
if(PCMS_ENABLE_C)
enable_language(C)
option(PCMS_ENABLE_Fortran "Enable pcms fortran api" ON)
Expand Down
14 changes: 13 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ if(PCMS_ENABLE_XGC)
list(APPEND PCMS_HEADERS pcms/adapter/xgc/xgc_reverse_classification.h)
endif()
if(PCMS_ENABLE_OMEGA_H)
list(APPEND PCMS_SOURCES pcms/point_search.cpp)
list(APPEND PCMS_SOURCES
pcms/point_search.cpp
pcms/adapter/uniform_grid/uniform_grid_field_layout.cpp
pcms/adapter/uniform_grid/uniform_grid_field.cpp
)
list(
APPEND
PCMS_HEADERS
Expand All @@ -54,6 +58,8 @@ if(PCMS_ENABLE_OMEGA_H)
pcms/transfer_field2.h
pcms/uniform_grid.h
pcms/point_search.h
pcms/adapter/uniform_grid/uniform_grid_field_layout.h
pcms/adapter/uniform_grid/uniform_grid_field.h
)
endif()

Expand Down Expand Up @@ -125,6 +131,12 @@ install(
add_library(pcms_pcms INTERFACE)
target_link_libraries(pcms_pcms INTERFACE pcms::core)
set_target_properties(pcms_pcms PROPERTIES EXPORT_NAME pcms)
if (PCMS_ENABLE_Python)
# Disable LTO/IPO before adding Python subdirectory to avoid fatbinData conflicts
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF)
add_subdirectory(pcms/pythonapi)
#target_link_libraries(pcms_pcms INTERFACE pcms::pythonapi)
endif()
if(PCMS_ENABLE_C)
add_subdirectory(pcms/capi)
target_link_libraries(pcms_pcms INTERFACE pcms::capi)
Expand Down
105 changes: 86 additions & 19 deletions src/pcms/adapter/omega_h/omega_h_field2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,49 +161,102 @@ struct OmegaHField2LocalizationHint
{
OmegaHField2LocalizationHint(
Omega_h::Mesh& mesh,
Kokkos::View<GridPointSearch::Result*, HostMemorySpace> search_results)
: offsets_("", mesh.nelems() + 1),
coordinates_("", search_results.size(), mesh.dim() + 1),
indices_("", search_results.size())
Kokkos::View<GridPointSearch::Result*, HostMemorySpace> search_results,
OutOfBoundsMode mode)
: mode_(mode), num_valid_(0), num_missing_(0)
{
Kokkos::View<LO*, HostMemorySpace> elem_counts("", mesh.nelems());
// First pass: count valid and invalid points
std::vector<size_t> valid_point_indices;
std::vector<size_t> missing_point_indices;

if (mode_ == OutOfBoundsMode::ERROR) {
// Error mode - throw error immediately if any point is out of bounds
for (size_t i = 0; i < search_results.size(); ++i) {
auto [dim, elem_idx, coord] = search_results(i);
bool is_missing =
(static_cast<int>(dim) != mesh.dim()) || (elem_idx < 0);
PCMS_ALWAYS_ASSERT(!is_missing && "Points found outside mesh domain");
valid_point_indices.push_back(i);
}
} else {
// Other modes - collect valid and missing points separately
for (size_t i = 0; i < search_results.size(); ++i) {
auto [dim, elem_idx, coord] = search_results(i);
bool is_missing =
(static_cast<int>(dim) != mesh.dim()) || (elem_idx < 0);
if (is_missing) {
missing_point_indices.push_back(i);
} else {
valid_point_indices.push_back(i);
}
}
}

num_valid_ = valid_point_indices.size();
num_missing_ = missing_point_indices.size();

for (size_t i = 0; i < search_results.size(); ++i) {
auto [dim, elem_idx, coord] = search_results(i);
// Handle missing points based on mode
if (num_missing_ > 0 && mode_ == OutOfBoundsMode::NEAREST_BOUNDARY) {
PCMS_ALWAYS_ASSERT(false && "NEAREST_BOUNDARY mode not implemented yet");
}

// Allocate arrays for valid points only
offsets_ = Kokkos::View<LO*, HostMemorySpace>("offsets", mesh.nelems() + 1);
coordinates_ = Kokkos::View<Real**, HostMemorySpace>(
"coordinates", num_valid_, mesh.dim() + 1);
indices_ = Kokkos::View<LO*, HostMemorySpace>("indices", num_valid_);

// Store missing point indices
if (num_missing_ > 0) {
missing_indices_ =
Kokkos::View<LO*, HostMemorySpace>("missing_indices", num_missing_);
for (size_t i = 0; i < num_missing_; ++i) {
missing_indices_(i) = static_cast<LO>(missing_point_indices[i]);
}
}

// Count points per element (valid points only)
Kokkos::View<LO*, HostMemorySpace> elem_counts("elem_counts",
mesh.nelems());
for (size_t i = 0; i < num_valid_; ++i) {
auto [dim, elem_idx, coord] = search_results(valid_point_indices[i]);
elem_counts[elem_idx] += 1;
}

// Compute offsets
LO total;

ComputeOffsetsFunctor functor(offsets_, elem_counts);
Kokkos::parallel_scan(
"ComputeOffsets",
Kokkos::RangePolicy<HostMemorySpace::execution_space>(0, mesh.nelems()),
functor, total);
offsets_(mesh.nelems()) = total;

for (size_t i = 0; i < search_results.size(); ++i) {
auto [dim, elem_idx, coord] = search_results(i);
// currently don't handle case where point is on a boundary
PCMS_ALWAYS_ASSERT(static_cast<int>(dim) == mesh.dim());
// element should be inside the domain (positive)
PCMS_ALWAYS_ASSERT(elem_idx >= 0 && elem_idx < mesh.nelems());
// Fill coordinates and indices for valid points
for (size_t i = 0; i < num_valid_; ++i) {
size_t orig_idx = valid_point_indices[i];
auto [dim, elem_idx, coord] = search_results(orig_idx);
elem_counts(elem_idx) -= 1;
LO index = offsets_(elem_idx) + elem_counts(elem_idx);
for (int j = 0; j < (mesh.dim() + 1); ++j) {
coordinates_(index, j) = coord[j];
}
// coordinates_(index, mesh.dim()) = coord[0];
indices_(index) = i;
indices_(index) = static_cast<LO>(orig_idx);
}
}

OutOfBoundsMode mode_;
size_t num_valid_;
size_t num_missing_;

// offsets is the number of points in each element
Kokkos::View<LO*, HostMemorySpace> offsets_;
// coordinates are the parametric coordinates of each point
Kokkos::View<Real**, HostMemorySpace> coordinates_;
// indices are the index of the original point
// indices are the index of the original point (for valid points)
Kokkos::View<LO*, HostMemorySpace> indices_;
// indices of points not found in mesh
Kokkos::View<LO*, HostMemorySpace> missing_indices_;
};

/*
Expand All @@ -213,7 +266,7 @@ OmegaHField2::OmegaHField2(const OmegaHFieldLayout& layout)
: layout_(layout),
mesh_(layout.GetMesh()),
search_(mesh_, 10, 10),
dof_holder_data_("", static_cast<size_t>(layout.OwnedSize()))
dof_holder_data_("dof_holder_data", static_cast<size_t>(layout.OwnedSize()))
{
auto nodes_per_dim = layout.GetNodesPerDim();
if (nodes_per_dim[2] == 0 && nodes_per_dim[3] == 0) {
Expand Down Expand Up @@ -305,7 +358,8 @@ LocalizationHint OmegaHField2::GetLocalizationHint(
Kokkos::View<GridPointSearch::Result*, HostMemorySpace> results_h(
"results_h", results.size());
Kokkos::deep_copy(results_h, results);
auto hint = std::make_shared<OmegaHField2LocalizationHint>(mesh_, results_h);
auto hint = std::make_shared<OmegaHField2LocalizationHint>(
mesh_, results_h, out_of_bounds_mode_);

return LocalizationHint{hint};
}
Expand Down Expand Up @@ -335,11 +389,23 @@ void OmegaHField2::Evaluate(LocalizationHint location,
"eval_results_h", eval_results.extent(0), eval_results.extent(1));
deep_copy_mismatch_layouts(eval_results_h, eval_results);
Rank1View<Real, HostMemorySpace> values = results.GetValues();

// Copy results for valid points
Kokkos::parallel_for(
"CopyEvalResultsToValues",
Kokkos::RangePolicy<HostMemorySpace::execution_space>(
0, eval_results_h.extent(0)),
KOKKOS_LAMBDA(LO i) { values[hint.indices_(i)] = eval_results_h(i, 0); });

// Handle missing points based on mode
if (hint.num_missing_ > 0 && hint.mode_ == OutOfBoundsMode::FILL) {
auto fill_val = fill_value_;
Kokkos::parallel_for(
"FillMissingValues",
Kokkos::RangePolicy<HostMemorySpace::execution_space>(0,
hint.num_missing_),
KOKKOS_LAMBDA(LO i) { values[hint.missing_indices_(i)] = fill_val; });
}
}

void OmegaHField2::EvaluateGradient(
Expand Down Expand Up @@ -391,4 +457,5 @@ void OmegaHField2::Deserialize(

SetDOFHolderData(pcms::make_const_array_view(sorted_buffer));
}

} // namespace pcms
1 change: 1 addition & 0 deletions src/pcms/adapter/omega_h/omega_h_field2.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace pcms
{

class MeshFieldBackend
{
public:
Expand Down
Loading