Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a291953
Initial implementation of the XDG mesh
pshriwise Feb 3, 2026
d85fd1f
Accounting for XDGMesh when creating MeshFilters
pshriwise Feb 4, 2026
612c891
Updating call to XDG for element connectivity
pshriwise Feb 6, 2026
e860ea9
Adding XDG unstructured mesh tallies mirroring those of the current u…
pshriwise Feb 9, 2026
f3603fc
Use explicit name for kwarg for clarity
pshriwise Feb 10, 2026
36dc4ac
Report XDG availability in build info
pshriwise Mar 13, 2026
2ec0d47
Only set libmesh comms in XDG if it has libMesh enabled
pshriwise Mar 13, 2026
645c97f
Adding XDG to CI builds. MOAB and libMesh should be built if XDG is e…
pshriwise Mar 13, 2026
1b3a9a2
Adding init files for proper test discovery with pytest
pshriwise Mar 13, 2026
028a9ad
Update submodules when cloning XDG in CI
pshriwise Mar 13, 2026
380b81b
Add XDG to the OpenMC CMake config file
pshriwise Mar 15, 2026
ca5bd5a
Adding more test scenarios for XDG meshes
pshriwise Mar 15, 2026
8c178fd
More descriptive test labels
pshriwise Mar 15, 2026
ab9b610
Use existing vendor targets if they exist
pshriwise Mar 18, 2026
6cfde21
Returning const string ref for mesh filename
pshriwise Mar 18, 2026
1584b93
C++ style
pshriwise Mar 18, 2026
fe27f04
Apply suggestions from @nuclearkevin
pshriwise Mar 21, 2026
443290a
Fix includes in xdg.h/cpp
paulromano May 21, 2026
9c959ea
Add some Doxygen comments in xdg.h
paulromano May 21, 2026
b0fbd79
Reorder methods
paulromano May 21, 2026
4ca53f2
Python imports
paulromano May 21, 2026
19ba002
Remove extra line
paulromano May 21, 2026
1bc11f5
Combined two #ifdefs
paulromano May 21, 2026
cbff2ad
Rename local variable to center to avoid same name as method
paulromano May 22, 2026
da34bf6
Test updates
paulromano May 22, 2026
d3a9268
Use pathlib in test
paulromano May 22, 2026
a892100
Fix circular import
paulromano May 22, 2026
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
16 changes: 15 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ jobs:
mpi: [n, y]
omp: [n, y]
dagmc: [n]
xdg: [n]
libmesh: [n]
Comment on lines 49 to 51
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if maybe we should just have a single configuration that covers DAGMC, libMesh, and XDG. Do you see any downside of that?

event: [n]

Expand All @@ -64,6 +65,11 @@ jobs:
python-version: "3.12"
mpi: y
omp: y
- xdg: y
python-version: "3.12"
libmesh: y
mpi: n
omp: y
- libmesh: y
python-version: "3.12"
mpi: y
Expand All @@ -78,13 +84,15 @@ jobs:
mpi: n
name: "Python ${{ matrix.python-version }} (omp=${{ matrix.omp }},
mpi=${{ matrix.mpi }}, dagmc=${{ matrix.dagmc }},
libmesh=${{ matrix.libmesh }}, event=${{ matrix.event }}"
xdg=${{ matrix.xdg }}, libmesh=${{ matrix.libmesh }},
event=${{ matrix.event }}"

env:
MPI: ${{ matrix.mpi }}
PHDF5: ${{ matrix.mpi }}
OMP: ${{ matrix.omp }}
DAGMC: ${{ matrix.dagmc }}
XDG: ${{ matrix.xdg }}
EVENT: ${{ matrix.event }}
LIBMESH: ${{ matrix.libmesh }}
NPY_DISABLE_CPU_FEATURES: "AVX512F AVX512_SKX"
Expand Down Expand Up @@ -146,6 +154,12 @@ jobs:
sudo update-alternatives --set mpirun /usr/bin/mpirun.mpich
sudo update-alternatives --set mpi-x86_64-linux-gnu /usr/include/x86_64-linux-gnu/mpich

- name: Optional apt dependencies for XDG
shell: bash
if: ${{ matrix.xdg == 'y' }}
run: |
sudo apt install -y libembree-dev

- name: install
shell: bash
run: |
Expand Down
16 changes: 16 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ option(OPENMC_BUILD_TESTS "Build tests"
option(OPENMC_ENABLE_PROFILE "Compile with profiling flags" OFF)
option(OPENMC_ENABLE_COVERAGE "Compile with coverage analysis flags" OFF)
option(OPENMC_USE_DAGMC "Enable support for DAGMC (CAD) geometry" OFF)
option(OPENMC_USE_XDG "Enable support for XDG discretized CAD geometry" OFF)
option(OPENMC_USE_LIBMESH "Enable support for libMesh unstructured mesh tallies" OFF)
option(OPENMC_USE_MPI "Enable MPI" OFF)
option(OPENMC_USE_UWUW "Enable UWUW" OFF)
Expand Down Expand Up @@ -156,6 +157,15 @@ if(OPENMC_USE_DAGMC)
endif()
endif()

#===============================================================================
# XDG Mesh and Geometry Support
#===============================================================================

if(OPENMC_USE_XDG)
find_package(XDG REQUIRED PATH_SUFFIXES lib/cmake)
message(STATUS "Found XDG: ${XDG_DIR} (version ${XDG_VERSION})")
endif()

#===============================================================================
# libMesh Unstructured Mesh Support
#===============================================================================
Expand Down Expand Up @@ -428,6 +438,7 @@ list(APPEND libopenmc_SOURCES
src/string_utils.cpp
src/summary.cpp
src/surface.cpp
src/xdg.cpp
src/tallies/derivative.cpp
src/tallies/filter.cpp
src/tallies/filter_azimuthal.cpp
Expand Down Expand Up @@ -544,6 +555,11 @@ elseif(OPENMC_USE_UWUW)
message(FATAL_ERROR "DAGMC must be enabled when UWUW is enabled.")
endif()

if(OPENMC_USE_XDG)
target_compile_definitions(libopenmc PRIVATE OPENMC_XDG_ENABLED)
target_link_libraries(libopenmc xdg::xdg)
endif()

if(OPENMC_USE_LIBMESH)
target_compile_definitions(libopenmc PRIVATE OPENMC_LIBMESH_ENABLED)
target_link_libraries(libopenmc PkgConfig::LIBMESH)
Expand Down
43 changes: 32 additions & 11 deletions cmake/OpenMCConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
get_filename_component(OpenMC_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)

# Compute the install prefix from this file's location
get_filename_component(_OPENMC_PREFIX "${OpenMC_CMAKE_DIR}/../../.." ABSOLUTE)
include(CMakeFindDependencyMacro)

find_package(fmt CONFIG REQUIRED HINTS ${_OPENMC_PREFIX})
find_package(pugixml CONFIG REQUIRED HINTS ${_OPENMC_PREFIX})
if(@OPENMC_USE_DAGMC@)
find_package(DAGMC REQUIRED HINTS @DAGMC_DIR@)
if(@OPENMC_USE_XDG@)
if(NOT TARGET xdg::xdg)
find_dependency(XDG CONFIG REQUIRED HINTS "@XDG_DIR@")
endif()
endif()

if(@OPENMC_USE_LIBMESH@)
Expand All @@ -16,18 +15,40 @@ if(@OPENMC_USE_LIBMESH@)
pkg_check_modules(LIBMESH REQUIRED @LIBMESH_PC_FILE@>=1.7.0 IMPORTED_TARGET)
endif()

find_package(PNG)
if(@OPENMC_USE_DAGMC@)
if(NOT TARGET dagmc-shared)
find_dependency(DAGMC REQUIRED HINTS "@DAGMC_DIR@")
endif()
endif()

if(NOT TARGET OpenMC::libopenmc)
include("${OpenMC_CMAKE_DIR}/OpenMCTargets.cmake")
if(NOT TARGET fmt::fmt)
find_dependency(fmt CONFIG REQUIRED)
endif()

if(NOT TARGET pugixml::pugixml AND NOT TARGET pugixml)
find_dependency(pugixml CONFIG REQUIRED)
endif()

if(@PNG_FOUND@)
if(NOT TARGET PNG::PNG)
find_dependency(PNG REQUIRED)
endif()
endif()

if(@OPENMC_USE_MPI@)
find_package(MPI REQUIRED)
if(NOT TARGET MPI::MPI_CXX)
find_dependency(MPI REQUIRED)
endif()
endif()

if(@OPENMC_USE_OPENMP@)
find_package(OpenMP REQUIRED)
if(NOT TARGET OpenMP::OpenMP_CXX)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that #3653 is merged, you'll need to update this file. One difference between #3653 and what you have here is that you also have the calls to if(NOT TARGET ...). Not sure if those are strictly necessary? @ahnaf-tahmid-chowdhury do you have an opinion on the matter?

find_dependency(OpenMP REQUIRED)
endif()
endif()

if(NOT TARGET OpenMC::libopenmc)
include("${OpenMC_CMAKE_DIR}/OpenMCTargets.cmake")
endif()

if(@OPENMC_USE_UWUW@ AND NOT ${DAGMC_BUILD_UWUW})
Expand Down
40 changes: 39 additions & 1 deletion include/openmc/mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ namespace openmc {

enum class ElementType { UNSUPPORTED = -1, LINEAR_TET, LINEAR_HEX };

struct NextMeshCell {
double distance {INFTY};
int face_idx {-1};
std::array<int, 3> next_ijk;
};
Comment on lines +50 to +54
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only used by distance_to_bin_boundary, which itself is never used


//==============================================================================
// Global variables
//==============================================================================
Expand Down Expand Up @@ -771,6 +777,9 @@ class UnstructuredMesh : public Mesh {
//! Get the library used for this unstructured mesh
virtual std::string library() const = 0;

//! Get the mesh filename
virtual const std::string& filename() const { return filename_; }

// Data members
bool output_ {
true}; //!< Write tallies onto the unstructured mesh at the end of a run
Expand All @@ -797,7 +806,36 @@ class UnstructuredMesh : public Mesh {
//! \param[in] coords Coordinates of the tetrahedron
//! \param[in] seed Random number generation seed
//! \return Sampled position within the tetrahedron
Position sample_tet(std::array<Position, 4> coords, uint64_t* seed) const;
template<typename V>
Position sample_tet(span<V> coords, uint64_t* seed) const
{
// Uniform distribution
double s = prn(seed);
double t = prn(seed);
double u = prn(seed);

// From PyNE implementation of moab tet sampling C. Rocchini & P. Cignoni
// (2000) Generating Random Points in a Tetrahedron, Journal of Graphics
// Tools, 5:4, 9-12, DOI: 10.1080/10867651.2000.10487528
if (s + t > 1) {
s = 1.0 - s;
t = 1.0 - t;
}
if (s + t + u > 1) {
if (t + u > 1) {
double old_t = t;
t = 1.0 - u;
u = 1.0 - s - old_t;
} else if (t + u <= 1) {
double old_s = s;
s = 1.0 - t - u;
u = old_s + t + u - 1;
}
}
V result = s * (coords[1] - coords[0]) + t * (coords[2] - coords[0]) +
u * (coords[3] - coords[0]) + coords[0];
return {result[0], result[1], result[2]};
}

// Data members
double length_multiplier_ {
Expand Down
137 changes: 137 additions & 0 deletions include/openmc/xdg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#ifndef OPENMC_XDG_H
#define OPENMC_XDG_H

namespace openmc {
extern "C" const bool XDG_ENABLED;
}

#ifdef OPENMC_XDG_ENABLED

#include "xdg/xdg.h"

#include "openmc/mesh.h"
#include "openmc/position.h"
#include "openmc/xml_interface.h"

namespace openmc {

class XDGMesh : public UnstructuredMesh {

public:
//----------------------------------------------------------------------------
// Constructors
XDGMesh() = default;
XDGMesh(pugi::xml_node node);
XDGMesh(hid_t group);
XDGMesh(const std::string& filename, double length_multiplier = 1.0);
XDGMesh(std::shared_ptr<xdg::XDG> external_xdg);

static const std::string mesh_lib_type;

//----------------------------------------------------------------------------
// Methods

//! Get the underlying XDG instance
//!
//! \return Shared pointer to the XDG instance
const std::shared_ptr<xdg::XDG>& xdg_instance() const { return xdg_; }

//! Check whether a bin index is valid
//!
//! \param[in] bin Bin index to check
//! \return True if the bin index is in [0, n_bins())
bool bin_is_valid(int bin) const { return bin >= 0 && bin < n_bins(); }

//! Convert a mesh bin index to an XDG MeshID
//!
//! \param[in] bin Bin index to convert
//! \return XDG MeshID corresponding to the bin
xdg::MeshID bin_to_mesh_id(int bin) const;

//! Convert an XDG MeshID to a mesh bin index
//!
//! \param[in] id XDG MeshID to convert
//! \return Bin index corresponding to the MeshID, or -1 if invalid
int mesh_id_to_bin(xdg::MeshID id) const;

//! Get the name of the underlying mesh library
//!
//! \return Name of the mesh library ("moab" or "libmesh")
std::string mesh_library() const;

//----------------------------------------------------------------------------
// Overridden Methods

//! Perform any preparation needed to support use in mesh filters
void prepare_for_point_location() override;

Position sample_element(int32_t bin, uint64_t* seed) const override;

void bins_crossed(Position r0, Position r1, const Direction& u,
vector<int>& bins, vector<double>& lengths) const override;

int get_bin(Position r) const override;

int n_bins() const override;

int n_surface_bins() const override;

std::pair<vector<double>, vector<double>> plot(
Position plot_ll, Position plot_ur) const override;

std::string library() const override;

//! Add a score to the mesh instance
void add_score(const std::string& score) override {};

//! Remove all scores from the mesh instance
void remove_scores() override {};

//! Set data for a score
void set_score_data(const std::string& score, const vector<double>& values,
const vector<double>& std_dev) override {};

//! Write the mesh with any current tally data
void write(const std::string& base_filename) const override;

Position centroid(int bin) const override;

int n_vertices() const override;

Position vertex(int id) const override;

std::vector<int> connectivity(int id) const override;

//! Get the volume of a mesh bin
//
//! \param[in] bin Bin to return the volume for
//! \return Volume of the bin
double volume(int bin) const override;

//! Get the distance to the nearest boundary for a given position and
//! direction \param[in] g GeometryState object containing position and
//! direction \return NextMeshCell struct containing distance, face index, and
//! next indices
NextMeshCell distance_to_bin_boundary(GeometryState& g) const;

//! Get the distance to the nearest boundary for a given position and
//! direction \param[in] r Position to check \param[in] u Direction to check
//! \return Distance to the nearest boundary
NextMeshCell distance_to_bin_boundary(
int bin, const Position& r, const Direction& u) const;
Comment on lines +111 to +121
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not defined/used


private:
void initialize() override;

//----------------------------------------------------------------------------
// Private data members
std::shared_ptr<xdg::XDG> xdg_; //!< XDG instance
xdg::MeshLibrary mesh_library_ {
xdg::MeshLibrary::LIBMESH}; //!< Mesh library type
};

} // namespace openmc

#endif // OPENMC_XDG_ENABLED

#endif // OPENMC_XDG_H
1 change: 1 addition & 0 deletions openmc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from openmc.search import *
from openmc.polynomial import *
from openmc.tracks import *
from openmc.xdg import *
from .config import *

# Import a few names from the model module
Expand Down
2 changes: 2 additions & 0 deletions openmc/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,8 @@ def mesh(self, mesh):
self.bins = list(range(len(mesh.volumes)))
else:
self.bins = []
elif isinstance(mesh, openmc.XDGMesh):
self.bins = []
else:
self.bins = list(mesh.indices)

Expand Down
3 changes: 3 additions & 0 deletions openmc/lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
def _dagmc_enabled():
return c_bool.in_dll(_dll, "DAGMC_ENABLED").value

def _xdg_enabled():
return c_bool.in_dll(_dll, "XDG_ENABLED").value

def _coord_levels():
return c_int.in_dll(_dll, "n_coord_levels").value

Expand Down
Loading