diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7fe3e1557b6..877ec68338e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,6 @@ jobs: mpi: [n, y] omp: [n, y] dagmc: [n] - ncrystal: [n] libmesh: [n] event: [n] vectfit: [n] @@ -45,10 +44,6 @@ jobs: python-version: "3.11" mpi: y omp: y - - ncrystal: y - python-version: "3.11" - mpi: n - omp: n - libmesh: y python-version: "3.11" mpi: y @@ -66,7 +61,7 @@ jobs: omp: n mpi: y name: "Python ${{ matrix.python-version }} (omp=${{ matrix.omp }}, - mpi=${{ matrix.mpi }}, dagmc=${{ matrix.dagmc }}, ncrystal=${{ matrix.ncrystal }}, + mpi=${{ matrix.mpi }}, dagmc=${{ matrix.dagmc }}, libmesh=${{ matrix.libmesh }}, event=${{ matrix.event }} vectfit=${{ matrix.vectfit }})" @@ -75,7 +70,6 @@ jobs: PHDF5: ${{ matrix.mpi }} OMP: ${{ matrix.omp }} DAGMC: ${{ matrix.dagmc }} - NCRYSTAL: ${{ matrix.ncrystal }} EVENT: ${{ matrix.event }} VECTFIT: ${{ matrix.vectfit }} LIBMESH: ${{ matrix.libmesh }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 385ce85aaaf..461abe508ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,6 @@ option(OPENMC_USE_DAGMC "Enable support for DAGMC (CAD) geometry" option(OPENMC_USE_LIBMESH "Enable support for libMesh unstructured mesh tallies" OFF) option(OPENMC_USE_MPI "Enable MPI" OFF) option(OPENMC_USE_MCPL "Enable MCPL" OFF) -option(OPENMC_USE_NCRYSTAL "Enable support for NCrystal scattering" OFF) option(OPENMC_USE_UWUW "Enable UWUW" OFF) message(STATUS "OPENMC_USE_OPENMP ${OPENMC_USE_OPENMP}") @@ -48,7 +47,6 @@ message(STATUS "OPENMC_USE_DAGMC ${OPENMC_USE_DAGMC}") message(STATUS "OPENMC_USE_LIBMESH ${OPENMC_USE_LIBMESH}") message(STATUS "OPENMC_USE_MPI ${OPENMC_USE_MPI}") message(STATUS "OPENMC_USE_MCPL ${OPENMC_USE_MCPL}") -message(STATUS "OPENMC_USE_NCRYSTAL ${OPENMC_USE_NCRYSTAL}") message(STATUS "OPENMC_USE_UWUW ${OPENMC_USE_UWUW}") # Warnings for deprecated options @@ -120,23 +118,6 @@ macro(find_package_write_status pkg) endif() endmacro() -#=============================================================================== -# NCrystal Scattering Support -#=============================================================================== - -if(OPENMC_USE_NCRYSTAL) - if(NOT DEFINED "NCrystal_DIR") - #Invocation of "ncrystal-config --show cmakedir" is needed to find NCrystal - #when it is installed from Python wheels: - execute_process( - COMMAND "ncrystal-config" "--show" "cmakedir" - OUTPUT_VARIABLE "NCrystal_DIR" OUTPUT_STRIP_TRAILING_WHITESPACE - ) - endif() - find_package(NCrystal 3.8.0 REQUIRED) - message(STATUS "Found NCrystal: ${NCrystal_DIR} (version ${NCrystal_VERSION})") -endif() - #=============================================================================== # DAGMC Geometry Support - need DAGMC/MOAB #=============================================================================== @@ -372,6 +353,7 @@ list(APPEND libopenmc_SOURCES src/mgxs.cpp src/mgxs_interface.cpp src/ncrystal_interface.cpp + src/ncrystal_load.cpp src/nuclide.cpp src/output.cpp src/particle.cpp @@ -548,11 +530,6 @@ if (OPENMC_USE_MCPL) target_link_libraries(libopenmc MCPL::mcpl) endif() -if(OPENMC_USE_NCRYSTAL) - target_compile_definitions(libopenmc PRIVATE NCRYSTAL) - target_link_libraries(libopenmc NCrystal::NCrystal) -endif() - #=============================================================================== # Log build info that this executable can report later #=============================================================================== diff --git a/CODEOWNERS b/CODEOWNERS index 6d452e36653..c77366de78d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -60,7 +60,8 @@ Dockerfile @shimwell src/random_ray/ @jtramm # NCrystal interface -src/ncrystal_interface.cpp @marquezj +src/ncrystal_interface.cpp @marquezj @tkittel +src/ncrystal_load.cpp @marquezj @tkittel # MCPL interface src/mcpl_interface.cpp @ebknudsen diff --git a/cmake/OpenMCConfig.cmake.in b/cmake/OpenMCConfig.cmake.in index 21c55230334..5cab4790abc 100644 --- a/cmake/OpenMCConfig.cmake.in +++ b/cmake/OpenMCConfig.cmake.in @@ -8,19 +8,6 @@ if(@OPENMC_USE_DAGMC@) find_package(DAGMC REQUIRED HINTS @DAGMC_DIR@) endif() -if(@OPENMC_USE_NCRYSTAL@) - if(NOT DEFINED "NCrystal_DIR") - #Invocation of "ncrystal-config --show cmakedir" is needed to find NCrystal - #when it is installed from Python wheels: - execute_process( - COMMAND "ncrystal-config" "--show" "cmakedir" - OUTPUT_VARIABLE "NCrystal_DIR" OUTPUT_STRIP_TRAILING_WHITESPACE - ) - endif() - find_package(NCrystal REQUIRED) - message(STATUS "Found NCrystal: ${NCrystal_DIR} (version ${NCrystal_VERSION})") -endif() - if(@OPENMC_USE_LIBMESH@) include(FindPkgConfig) list(APPEND CMAKE_PREFIX_PATH @LIBMESH_PREFIX@) diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index bb54594defb..0aa561ee3d7 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -284,13 +284,13 @@ Prerequisites * NCrystal_ library for defining materials with enhanced thermal neutron transport - Adding this option allows the creation of materials from NCrystal, which - replaces the scattering kernel treatment of ACE files with a modular, - on-the-fly approach. To use it `install - `_ NCrystal and - turn on the option in the CMake configuration step:: - - cmake -DOPENMC_USE_NCRYSTAL=on .. + OpenMC supports the creation of materials from NCrystal, which replaces + the scattering kernel treatment of ACE files with a modular, on-the-fly + approach. OpenMC does not need any particular build option to use this, + but NCrystal must be installed on the system. Refer to `NCrystal + documentation + `_ for how this is + achieved. * libMesh_ mesh library framework for numerical simulations of partial differential equations @@ -393,12 +393,6 @@ OPENMC_USE_MCPL Turns on support for reading MCPL_ source files and writing MCPL source points and surface sources. (Default: off) -OPENMC_USE_NCRYSTAL - Turns on support for NCrystal materials. NCrystal must be `installed - `_ and `initialized - `_. - (Default: off) - OPENMC_USE_LIBMESH Enables the use of unstructured mesh tallies with libMesh_. (Default: off) diff --git a/include/openmc/ncrystal_interface.h b/include/openmc/ncrystal_interface.h index 22422e378cf..e9bd8ae79b9 100644 --- a/include/openmc/ncrystal_interface.h +++ b/include/openmc/ncrystal_interface.h @@ -1,10 +1,7 @@ #ifndef OPENMC_NCRYSTAL_INTERFACE_H #define OPENMC_NCRYSTAL_INTERFACE_H -#ifdef NCRYSTAL -#include "NCrystal/NCrystal.hh" -#endif - +#include "openmc/ncrystal_load.h" #include "openmc/particle.h" #include // for uint64_t @@ -17,28 +14,25 @@ namespace openmc { // Constants //============================================================================== -extern "C" const bool NCRYSTAL_ENABLED; - //! Energy in [eV] to switch between NCrystal and ENDF constexpr double NCRYSTAL_MAX_ENERGY {5.0}; //============================================================================== -// Wrapper class an NCrystal material +// Wrapper class for an NCrystal material //============================================================================== class NCrystalMat { public: //---------------------------------------------------------------------------- // Constructors - NCrystalMat() = default; + NCrystalMat() = default; // empty object explicit NCrystalMat(const std::string& cfg); //---------------------------------------------------------------------------- // Methods -#ifdef NCRYSTAL - //! Return configuration string - std::string cfg() const; + //! Return configuration string: + const std::string& cfg() const { return cfg_; } //! Get cross section from NCrystal material // @@ -52,25 +46,21 @@ class NCrystalMat { void scatter(Particle& p) const; //! Whether the object holds a valid NCrystal material - operator bool() const; -#else + operator bool() const { return !cfg_.empty(); } - //---------------------------------------------------------------------------- - // Trivial methods when compiling without NCRYSTAL - std::string cfg() const { return ""; } - double xs(const Particle& p) const { return -1.0; } - void scatter(Particle& p) const {} - operator bool() const { return false; } -#endif + NCrystalMat clone() const + { + NCrystalMat c; + c.cfg_ = cfg_; + c.proc_ = proc_.clone(); + return c; + } private: //---------------------------------------------------------------------------- // Data members (only present when compiling with NCrystal support) -#ifdef NCRYSTAL - std::string cfg_; //!< NCrystal configuration string - std::shared_ptr - ptr_; //!< Pointer to NCrystal material object -#endif + std::string cfg_; //!< NCrystal configuration string + NCrystalScatProc proc_; //!< NCrystal scatter process }; //============================================================================== diff --git a/include/openmc/ncrystal_load.h b/include/openmc/ncrystal_load.h new file mode 100644 index 00000000000..d85f240906c --- /dev/null +++ b/include/openmc/ncrystal_load.h @@ -0,0 +1,127 @@ +//! \file ncrystal_load.h +//! \brief Helper class taking care of loading NCrystal at runtime. + +#ifndef OPENMC_NCRYSTAL_LOAD_H +#define OPENMC_NCRYSTAL_LOAD_H + +#include // for swap +#include // for function +#include // for shared_ptr +#include // for move + +namespace NCrystalVirtualAPI { + +// NOTICE: Do NOT make ANY changes in the NCrystalVirtualAPI::VirtAPI_Type1_v1 +// class, it is required to stay exactly constant over time and compatible with +// the same definition used to compile the NCrystal library! But changes to +// white space, comments, and formatting is of course allowed. This API was +// introduced in NCrystal 4.1.0. + +//! Abstract base class for NCrystal interface which must be declared exactly as +// it is in NCrystal itself. + +class VirtAPI_Type1_v1 { +public: + // Note: neutron must be an array of length 4 with values {ekin,ux,uy,uz} + class ScatterProcess; + virtual const ScatterProcess* createScatter(const char* cfgstr) const = 0; + virtual const ScatterProcess* cloneScatter(const ScatterProcess*) const = 0; + virtual void deallocateScatter(const ScatterProcess*) const = 0; + virtual double crossSectionUncached( + const ScatterProcess&, const double* neutron) const = 0; + virtual void sampleScatterUncached(const ScatterProcess&, + std::function& rng, double* neutron) const = 0; + // Plumbing: + static constexpr unsigned interface_id = 1001; + virtual ~VirtAPI_Type1_v1() = default; + VirtAPI_Type1_v1() = default; + VirtAPI_Type1_v1(const VirtAPI_Type1_v1&) = delete; + VirtAPI_Type1_v1& operator=(const VirtAPI_Type1_v1&) = delete; + VirtAPI_Type1_v1(VirtAPI_Type1_v1&&) = delete; + VirtAPI_Type1_v1& operator=(VirtAPI_Type1_v1&&) = delete; +}; + +} // namespace NCrystalVirtualAPI + +namespace openmc { + +using NCrystalAPI = NCrystalVirtualAPI::VirtAPI_Type1_v1; + +//! Function which locates and loads NCrystal at runtime using the virtual API +std::shared_ptr load_ncrystal_api(); + +//! Class encapsulating exactly the parts of NCrystal needed by OpenMC + +class NCrystalScatProc final { +public: + //! Empty constructor which does not load NCrystal + NCrystalScatProc() {} + + //! Load NCrystal and instantiate a scattering process + //! \param cfgstr NCrystal cfg-string defining the material. + NCrystalScatProc(const char* cfgstr) + : api_(load_ncrystal_api()), p_(api_->createScatter(cfgstr)) + {} + + // Note: Neutron state array is {ekin,ux,uy,uz} + + //! Returns total scattering cross section in units of barns per atom. + //! \param neutron_state array {ekin,ux,uy,uz} with ekin (eV) and direction. + double cross_section(const double* neutron_state) const + { + return api_->crossSectionUncached(*p_, neutron_state); + } + + //! Returns total scattering cross section in units of barns per atom. + //! \param rng function returning random numbers in the unit interval + //! \param neutron_state array {ekin,ux,uy,uz} with ekin (eV) and direction. + void scatter(std::function& rng, double* neutron_state) const + { + api_->sampleScatterUncached(*p_, rng, neutron_state); + } + + //! Clones the object which is otherwise move-only + NCrystalScatProc clone() const + { + NCrystalScatProc c; + if (p_) { + c.api_ = api_; + c.p_ = api_->cloneScatter(p_); + } + return c; + } + + // Plumbing (move-only semantics, but supports explicit clone): + NCrystalScatProc(const NCrystalScatProc&) = delete; + NCrystalScatProc& operator=(const NCrystalScatProc&) = delete; + + NCrystalScatProc(NCrystalScatProc&& o) : api_(std::move(o.api_)), p_(nullptr) + { + std::swap(p_, o.p_); + } + + NCrystalScatProc& operator=(NCrystalScatProc&& o) + { + if (p_) { + api_->deallocateScatter(p_); + p_ = nullptr; + } + std::swap(api_, o.api_); + std::swap(p_, o.p_); + return *this; + } + + ~NCrystalScatProc() + { + if (p_) + api_->deallocateScatter(p_); + } + +private: + std::shared_ptr api_; + const NCrystalAPI::ScatterProcess* p_ = nullptr; +}; + +} // namespace openmc + +#endif diff --git a/openmc/lib/__init__.py b/openmc/lib/__init__.py index 5fe35b9745d..15642b42be3 100644 --- a/openmc/lib/__init__.py +++ b/openmc/lib/__init__.py @@ -40,9 +40,6 @@ def _dagmc_enabled(): return c_bool.in_dll(_dll, "DAGMC_ENABLED").value -def _ncrystal_enabled(): - return c_bool.in_dll(_dll, "NCRYSTAL_ENABLED").value - def _coord_levels(): return c_int.in_dll(_dll, "n_coord_levels").value diff --git a/openmc/material.py b/openmc/material.py index 41780ce3607..b104b374e6c 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -429,7 +429,11 @@ def from_ncrystal(cls, cfg, **kwargs) -> Material: """ - import NCrystal + try: + import NCrystal + except ModuleNotFoundError as e: + raise RuntimeError('The .from_ncrystal method requires' + ' NCrystal to be installed.') from e nc_mat = NCrystal.createInfo(cfg) def openmc_natabund(Z): diff --git a/src/material.cpp b/src/material.cpp index 3ba9ab96c00..a1937aca459 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -368,7 +368,7 @@ Material& Material::clone() mat->name_ = name_; mat->nuclide_ = nuclide_; mat->element_ = element_; - mat->ncrystal_mat_ = ncrystal_mat_; + mat->ncrystal_mat_ = ncrystal_mat_.clone(); mat->atom_density_ = atom_density_; mat->density_ = density_; mat->density_gpcc_ = density_gpcc_; diff --git a/src/ncrystal_interface.cpp b/src/ncrystal_interface.cpp index b39f62d9020..935d2b8850a 100644 --- a/src/ncrystal_interface.cpp +++ b/src/ncrystal_interface.cpp @@ -7,89 +7,34 @@ namespace openmc { //============================================================================== -// Constants +// NCrystalMat implementation //============================================================================== -#ifdef NCRYSTAL -const bool NCRYSTAL_ENABLED = true; -#else -const bool NCRYSTAL_ENABLED = false; -#endif - -//============================================================================== -// NCrystal wrapper class for the OpenMC random number generator -//============================================================================== - -#ifdef NCRYSTAL -class NCrystalRNGWrapper : public NCrystal::RNGStream { -public: - constexpr NCrystalRNGWrapper(uint64_t* seed) noexcept : openmc_seed_(seed) {} - -protected: - double actualGenerate() override - { - return std::max( - std::numeric_limits::min(), prn(openmc_seed_)); - } - -private: - uint64_t* openmc_seed_; -}; -#endif - -//============================================================================== -// NCrystal implementation -//============================================================================== - -NCrystalMat::NCrystalMat(const std::string& cfg) -{ -#ifdef NCRYSTAL - cfg_ = cfg; - ptr_ = NCrystal::FactImpl::createScatter(cfg); -#else - fatal_error("Your build of OpenMC does not support NCrystal materials."); -#endif -} - -#ifdef NCRYSTAL -std::string NCrystalMat::cfg() const -{ - return cfg_; -} +NCrystalMat::NCrystalMat(const std::string& cfg) : cfg_(cfg), proc_(cfg.c_str()) +{} double NCrystalMat::xs(const Particle& p) const { // Calculate scattering XS per atom with NCrystal, only once per material - NCrystal::CachePtr dummy_cache; - auto nc_energy = NCrystal::NeutronEnergy {p.E()}; - return ptr_->crossSection(dummy_cache, nc_energy, {p.u().x, p.u().y, p.u().z}) - .get(); + double neutron_state[4] = {p.E(), p.u().x, p.u().y, p.u().z}; + return proc_.cross_section(neutron_state); } void NCrystalMat::scatter(Particle& p) const { - NCrystalRNGWrapper rng(p.current_seed()); // Initialize RNG - // create a cache pointer for multi thread physics - NCrystal::CachePtr dummy_cache; - auto nc_energy = NCrystal::NeutronEnergy {p.E()}; - auto outcome = ptr_->sampleScatter( - dummy_cache, rng, nc_energy, {p.u().x, p.u().y, p.u().z}); - + // Scatter with NCrystal, using the OpenMC RNG stream: + uint64_t* seed = p.current_seed(); + std::function rng = [&seed]() { return prn(seed); }; + double neutron_state[4] = {p.E(), p.u().x, p.u().y, p.u().z}; + proc_.scatter(rng, neutron_state); // Modify attributes of particle - p.E() = outcome.ekin.get(); + p.E() = neutron_state[0]; Direction u_old {p.u()}; - p.u() = - Direction(outcome.direction[0], outcome.direction[1], outcome.direction[2]); + p.u() = Direction(neutron_state[1], neutron_state[2], neutron_state[3]); p.mu() = u_old.dot(p.u()); p.event_mt() = ELASTIC; } -NCrystalMat::operator bool() const -{ - return ptr_.get(); -} -#endif - //============================================================================== // Functions //============================================================================== diff --git a/src/ncrystal_load.cpp b/src/ncrystal_load.cpp new file mode 100644 index 00000000000..b69f3a27f4e --- /dev/null +++ b/src/ncrystal_load.cpp @@ -0,0 +1,151 @@ +#include "openmc/ncrystal_load.h" + +#include // for isspace +#include // for strtoul +#include // for shared_ptr +#include // for mutex, lock_guard +#include + +#include +#include // for popen, pclose + +#include "openmc/error.h" + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include // for LoadLibrary, GetProcAddress +#else +#include // for dlopen, dlsym, dlerror +#endif + +namespace openmc { +namespace { + +struct NCrystalConfig { + std::string shlibpath; + unsigned long intversion = 0; + std::string symbol_namespace; +}; + +NCrystalConfig query_ncrystal_config() +{ +#ifdef _WIN32 + FILE* pipe = _popen("ncrystal-config --show " + "intversion shlibpath namespace", + "r"); +#else + FILE* pipe = popen("ncrystal-config --show " + "intversion shlibpath namespace 2>/dev/null", + "r"); +#endif + if (!pipe) + return {}; // failure + auto readLine = [pipe](std::string& tgt) -> bool { + // Read line and discard trailing whitespace (including newline chars). + char buffer[4096]; + if (fgets(buffer, sizeof(buffer), pipe) == NULL) + return false; + tgt = buffer; + while (!tgt.empty() && std::isspace(tgt.back())) + tgt.pop_back(); + return true; + }; + auto parseIntVersion = [](const std::string& s) { + char* str_end = nullptr; + unsigned long v = std::strtoul(s.c_str(), &str_end, 10); + return (v >= 2002000 && v < 999999999 && str_end == s.c_str() + s.size()) + ? v + : 0; + }; + + NCrystalConfig res; + if (!readLine(res.shlibpath) || + !(res.intversion = parseIntVersion(res.shlibpath)) || + !readLine(res.shlibpath) || res.shlibpath.empty() || + !readLine(res.symbol_namespace)) { + res.intversion = 0; // failure + } + +#ifdef _WIN32 + auto returnCode = _pclose(pipe); +#else + auto returnCode = pclose(pipe); +#endif + if (returnCode == 0 && res.intversion >= 2002000) + return res; + return {}; // failure +} + +struct NCrystalAPIDB { + std::mutex mtx; + std::shared_ptr api; + using FctSignature = void* (*)(int); + FctSignature ncrystal_access_virtapi_fct = nullptr; +}; + +void* load_virtapi_raw(unsigned interface_id, NCrystalAPIDB& db) +{ + if (!db.ncrystal_access_virtapi_fct) { + auto cfg = query_ncrystal_config(); + if (!(cfg.intversion >= 4001000)) { + // This is the most likely error message people will see: + fatal_error("Could not locate a functioning and recent enough" + " NCrystal installation (required since geometry" + " contains NCrystal materials)."); + } +#ifdef _WIN32 + auto handle = LoadLibrary(cfg.shlibpath.c_str()); +#else + dlerror(); // clear previous errors + void* handle = dlopen(cfg.shlibpath.c_str(), RTLD_LOCAL | RTLD_LAZY); +#endif + if (!handle) + fatal_error("Loading of the NCrystal library failed"); + + std::string symbol = + fmt::format("ncrystal{}_access_virtual_api", cfg.symbol_namespace); + +#ifdef _WIN32 + void* addr = (void*)(intptr_t)GetProcAddress(handle, symbol.c_str()); + if (!addr) + fatal_error("GetProcAddress(" + "ncrystal_access_virtual_api) failed"); +#else + dlerror(); // clear previous errors + void* addr = dlsym(handle, symbol.c_str()); + if (!addr) + fatal_error("dlsym(ncrystal_access_virtual_api) failed"); +#endif + db.ncrystal_access_virtapi_fct = + reinterpret_cast(addr); + } + + void* result = (*db.ncrystal_access_virtapi_fct)(interface_id); + if (!result) + fatal_error("NCrystal installation does not support required interface."); + + return result; +} + +NCrystalAPIDB& get_ncrystal_api_db() +{ + static NCrystalAPIDB db; + return db; +} +} // namespace + +std::shared_ptr load_ncrystal_api() +{ + auto& db = get_ncrystal_api_db(); + std::lock_guard lock(db.mtx); + if (!db.api) { + void* raw_api = load_virtapi_raw(NCrystalAPI::interface_id, db); + if (!raw_api) + fatal_error("Problems loading NCrystal."); + db.api = *reinterpret_cast*>(raw_api); + } + return db.api; +} +} // namespace openmc diff --git a/src/output.cpp b/src/output.cpp index 63e7fe55331..e20868efbb1 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -314,7 +314,6 @@ void print_build_info() std::string profiling(n); std::string coverage(n); std::string mcpl(n); - std::string ncrystal(n); std::string uwuw(n); #ifdef PHDF5 @@ -332,9 +331,6 @@ void print_build_info() #ifdef OPENMC_MCPL mcpl = y; #endif -#ifdef NCRYSTAL - ncrystal = y; -#endif #ifdef USE_LIBPNG png = y; #endif @@ -362,7 +358,6 @@ void print_build_info() fmt::print("DAGMC support: {}\n", dagmc); fmt::print("libMesh support: {}\n", libmesh); fmt::print("MCPL support: {}\n", mcpl); - fmt::print("NCrystal support: {}\n", ncrystal); fmt::print("Coverage testing: {}\n", coverage); fmt::print("Profiling flags: {}\n", profiling); fmt::print("UWUW support: {}\n", uwuw); diff --git a/src/source.cpp b/src/source.cpp index 2116809f2dd..c1b4ce260a3 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -4,7 +4,7 @@ #define HAS_DYNAMIC_LINKING #endif -#include // for move +#include // for move #ifdef HAS_DYNAMIC_LINKING #include // for dlopen, dlsym, dlclose, dlerror diff --git a/tests/regression_tests/ncrystal/test.py b/tests/regression_tests/ncrystal/test.py index e1c1e5ed6f0..8da05e1cfd7 100644 --- a/tests/regression_tests/ncrystal/test.py +++ b/tests/regression_tests/ncrystal/test.py @@ -6,12 +6,13 @@ import openmc import openmc.lib import pytest +import shutil from tests.testing_harness import PyAPITestHarness pytestmark = pytest.mark.skipif( - not openmc.lib._ncrystal_enabled(), - reason="NCrystal materials are not enabled.") + not shutil.which('ncrystal-config'), + reason="NCrystal is not installed.") def pencil_beam_model(cfg, E0, N): diff --git a/tools/ci/gha-install.py b/tools/ci/gha-install.py index 1eb9a55b4dc..1cc792f8d78 100644 --- a/tools/ci/gha-install.py +++ b/tools/ci/gha-install.py @@ -3,7 +3,7 @@ import subprocess -def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrystal=False): +def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False): # Create build directory and change to it shutil.rmtree('build', ignore_errors=True) os.mkdir('build') @@ -40,9 +40,6 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrys libmesh_path = os.environ.get('HOME') + '/LIBMESH' cmake_cmd.append('-DCMAKE_PREFIX_PATH=' + libmesh_path) - if ncrystal: - cmake_cmd.append('-DOPENMC_USE_NCRYSTAL=ON') - # Build in coverage mode for coverage testing cmake_cmd.append('-DOPENMC_ENABLE_COVERAGE=on') @@ -59,11 +56,10 @@ def main(): mpi = (os.environ.get('MPI') == 'y') phdf5 = (os.environ.get('PHDF5') == 'y') dagmc = (os.environ.get('DAGMC') == 'y') - ncrystal = (os.environ.get('NCRYSTAL') == 'y') libmesh = (os.environ.get('LIBMESH') == 'y') # Build and install - install(omp, mpi, phdf5, dagmc, libmesh, ncrystal) + install(omp, mpi, phdf5, dagmc, libmesh) if __name__ == '__main__': main() diff --git a/tools/ci/gha-install.sh b/tools/ci/gha-install.sh index 50f110ed4e6..d8a3a7600e4 100755 --- a/tools/ci/gha-install.sh +++ b/tools/ci/gha-install.sh @@ -14,12 +14,9 @@ if [[ $DAGMC = 'y' ]]; then ./tools/ci/gha-install-dagmc.sh fi -# Install NCrystal if needed -if [[ $NCRYSTAL = 'y' ]]; then - pip install 'ncrystal>=4.0.0' - #Basic quick verification: - nctool --test -fi +# Install NCrystal and verify installation +pip install 'ncrystal>=4.1.0' +nctool --test # Install vectfit for WMP generation if needed if [[ $VECTFIT = 'y' ]]; then diff --git a/tools/ci/gha-script.sh b/tools/ci/gha-script.sh index 4733907eb25..c7c634ffa33 100755 --- a/tools/ci/gha-script.sh +++ b/tools/ci/gha-script.sh @@ -14,10 +14,5 @@ if [[ $EVENT == 'y' ]]; then args="${args} --event " fi -# Check NCrystal installation -if [[ $NCRYSTAL = 'y' ]]; then - nctool --test -fi - # Run regression and unit tests pytest --cov=openmc -v $args tests