From e5bf0590a7506bfc3fb65a09de7d63cf362da7e6 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 14 Aug 2026 17:54:40 -0500 Subject: [PATCH] Replace exported C API error globals --- include/openmc/capi.h | 31 ++++++----- include/openmc/error.h | 18 ++----- openmc/lib/error.py | 42 +++++++++------ src/cell.cpp | 8 +-- src/cross_sections.cpp | 2 +- src/error.cpp | 51 +++++++++++-------- src/initialize.cpp | 10 ++-- src/main.cpp | 6 +-- src/material.cpp | 4 +- src/mesh.cpp | 16 +++--- src/tallies/tally.cpp | 3 +- tests/regression_tests/cpp_driver/driver.cpp | 2 +- .../regression_tests/dagmc/external/main.cpp | 6 +-- tests/regression_tests/external_moab/main.cpp | 6 +-- 14 files changed, 109 insertions(+), 96 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 6d2e7970343..7fb736a4f10 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -361,21 +361,24 @@ int openmc_properties_import(const char* filename); //! \return Error code int openmc_get_feature_enabled(const char* feature, bool* enabled); -// Error codes -extern int OPENMC_E_UNASSIGNED; -extern int OPENMC_E_ALLOCATE; -extern int OPENMC_E_OUT_OF_BOUNDS; -extern int OPENMC_E_INVALID_SIZE; -extern int OPENMC_E_INVALID_ARGUMENT; -extern int OPENMC_E_INVALID_TYPE; -extern int OPENMC_E_INVALID_ID; -extern int OPENMC_E_GEOMETRY; -extern int OPENMC_E_DATA; -extern int OPENMC_E_PHYSICS; -extern int OPENMC_E_WARNING; +//! Return the message associated with the most recent C API error. +//! +//! The returned pointer is valid until the next error message is set. +const char* openmc_get_err_msg(); -// Global variables -extern char openmc_err_msg[256]; +typedef enum OpenmcErrorCode { + OPENMC_E_WARNING = 1, + OPENMC_E_UNASSIGNED = -1, + OPENMC_E_ALLOCATE = -2, + OPENMC_E_OUT_OF_BOUNDS = -3, + OPENMC_E_INVALID_SIZE = -4, + OPENMC_E_INVALID_ARGUMENT = -5, + OPENMC_E_INVALID_TYPE = -6, + OPENMC_E_INVALID_ID = -7, + OPENMC_E_GEOMETRY = -8, + OPENMC_E_DATA = -9, + OPENMC_E_PHYSICS = -10 +} OpenmcErrorCode; #ifdef __cplusplus } diff --git a/include/openmc/error.h b/include/openmc/error.h index 1f6e15f49c5..8aa77827e68 100644 --- a/include/openmc/error.h +++ b/include/openmc/error.h @@ -18,20 +18,10 @@ namespace openmc { -inline void set_errmsg(const char* message) -{ - std::strcpy(openmc_err_msg, message); -} - -inline void set_errmsg(const std::string& message) -{ - std::strcpy(openmc_err_msg, message.c_str()); -} - -inline void set_errmsg(const std::stringstream& message) -{ - std::strcpy(openmc_err_msg, message.str().c_str()); -} +void set_errmsg(const char* message); +void set_errmsg(const std::string& message); +void set_errmsg(const std::stringstream& message); +const char* get_errmsg(); [[noreturn]] void fatal_error(const std::string& message, int err = -1); diff --git a/openmc/lib/error.py b/openmc/lib/error.py index dbe08e1ef8b..0c93a08f65c 100644 --- a/openmc/lib/error.py +++ b/openmc/lib/error.py @@ -1,39 +1,49 @@ -from ctypes import c_int, c_char +from ctypes import c_char_p from warnings import warn import openmc.exceptions as exc from . import _dll +OPENMC_E_WARNING = 1 +OPENMC_E_UNASSIGNED = -1 +OPENMC_E_ALLOCATE = -2 +OPENMC_E_OUT_OF_BOUNDS = -3 +OPENMC_E_INVALID_SIZE = -4 +OPENMC_E_INVALID_ARGUMENT = -5 +OPENMC_E_INVALID_TYPE = -6 +OPENMC_E_INVALID_ID = -7 +OPENMC_E_GEOMETRY = -8 +OPENMC_E_DATA = -9 +OPENMC_E_PHYSICS = -10 + +_dll.openmc_get_err_msg.restype = c_char_p + + def _error_handler(err, func, args): """Raise exception according to error code.""" - # Get error code corresponding to global constant. - def errcode(s): - return c_int.in_dll(_dll, s).value - # Get error message set by OpenMC library - errmsg = (c_char*256).in_dll(_dll, 'openmc_err_msg') - msg = errmsg.value.decode() + msg = _dll.openmc_get_err_msg().decode() # Raise exception type corresponding to error code - if err == errcode('OPENMC_E_ALLOCATE'): + if err == OPENMC_E_ALLOCATE: raise exc.AllocationError(msg) - elif err == errcode('OPENMC_E_OUT_OF_BOUNDS'): + elif err == OPENMC_E_OUT_OF_BOUNDS: raise exc.OutOfBoundsError(msg) - elif err == errcode('OPENMC_E_INVALID_ARGUMENT'): + elif err == OPENMC_E_INVALID_ARGUMENT: raise exc.InvalidArgumentError(msg) - elif err == errcode('OPENMC_E_INVALID_TYPE'): + elif err == OPENMC_E_INVALID_TYPE: raise exc.InvalidTypeError(msg) - if err == errcode('OPENMC_E_INVALID_ID'): + if err == OPENMC_E_INVALID_ID: raise exc.InvalidIDError(msg) - elif err == errcode('OPENMC_E_GEOMETRY'): + elif err == OPENMC_E_GEOMETRY: raise exc.GeometryError(msg) - elif err == errcode('OPENMC_E_DATA'): + elif err == OPENMC_E_DATA: raise exc.DataError(msg) - elif err == errcode('OPENMC_E_PHYSICS'): + elif err == OPENMC_E_PHYSICS: raise exc.PhysicsError(msg) - elif err == errcode('OPENMC_E_WARNING'): + elif err == OPENMC_E_WARNING: warn(msg) elif err < 0: if not msg: diff --git a/src/cell.cpp b/src/cell.cpp index 4a7e795761e..c9d6ecfcd5a 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -1338,7 +1338,7 @@ extern "C" int openmc_cell_set_temperature( int32_t index, double T, const int32_t* instance, bool set_contained) { if (index < 0 || index >= model::cells.size()) { - strcpy(openmc_err_msg, "Index in cells array is out of bounds."); + set_errmsg("Index in cells array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } @@ -1356,7 +1356,7 @@ extern "C" int openmc_cell_set_density( int32_t index, double density, const int32_t* instance, bool set_contained) { if (index < 0 || index >= model::cells.size()) { - strcpy(openmc_err_msg, "Index in cells array is out of bounds."); + set_errmsg("Index in cells array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } @@ -1374,7 +1374,7 @@ extern "C" int openmc_cell_get_temperature( int32_t index, const int32_t* instance, double* T) { if (index < 0 || index >= model::cells.size()) { - strcpy(openmc_err_msg, "Index in cells array is out of bounds."); + set_errmsg("Index in cells array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } @@ -1392,7 +1392,7 @@ extern "C" int openmc_cell_get_density( int32_t index, const int32_t* instance, double* density) { if (index < 0 || index >= model::cells.size()) { - strcpy(openmc_err_msg, "Index in cells array is out of bounds."); + set_errmsg("Index in cells array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } diff --git a/src/cross_sections.cpp b/src/cross_sections.cpp index c9088e4b7b1..f1c8c2c3ee7 100644 --- a/src/cross_sections.cpp +++ b/src/cross_sections.cpp @@ -210,7 +210,7 @@ void read_ce_cross_sections(const vector>& nuc_temps, const auto& temps = nuc_temps[i_nuc]; int err = openmc_load_nuclide(name.c_str(), temps.data(), temps.size()); if (err < 0) - throw std::runtime_error {openmc_err_msg}; + throw std::runtime_error {get_errmsg()}; already_read.insert(name); } diff --git a/src/error.cpp b/src/error.cpp index f99f5935f0f..ca0ffd6a8f3 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -12,32 +12,43 @@ #include // for setw #include -//============================================================================== -// Global variables / constants -//============================================================================== - -// Error codes -int OPENMC_E_UNASSIGNED {-1}; -int OPENMC_E_ALLOCATE {-2}; -int OPENMC_E_OUT_OF_BOUNDS {-3}; -int OPENMC_E_INVALID_SIZE {-4}; -int OPENMC_E_INVALID_ARGUMENT {-5}; -int OPENMC_E_INVALID_TYPE {-6}; -int OPENMC_E_INVALID_ID {-7}; -int OPENMC_E_GEOMETRY {-8}; -int OPENMC_E_DATA {-9}; -int OPENMC_E_PHYSICS {-10}; -int OPENMC_E_WARNING {1}; - -// Error message -char openmc_err_msg[256]; - //============================================================================== // Functions //============================================================================== namespace openmc { +namespace { + +std::string error_message; + +} // namespace + +void set_errmsg(const char* message) +{ + error_message = message; +} + +void set_errmsg(const std::string& message) +{ + error_message = message; +} + +void set_errmsg(const std::stringstream& message) +{ + error_message = message.str(); +} + +const char* get_errmsg() +{ + return error_message.c_str(); +} + +extern "C" const char* openmc_get_err_msg() +{ + return get_errmsg(); +} + #ifdef OPENMC_MPI void abort_mpi(int code) { diff --git a/src/initialize.cpp b/src/initialize.cpp index 9af4b638b4f..33dfeca0e51 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -258,7 +258,7 @@ int parse_command_line(int argc, char* argv[]) settings::verbosity = std::stoi(argv[i]); if (settings::verbosity > 10 || settings::verbosity < 1) { auto msg = fmt::format("Invalid verbosity: {}.", settings::verbosity); - strcpy(openmc_err_msg, msg.c_str()); + set_errmsg(msg); return OPENMC_E_INVALID_ARGUMENT; } @@ -283,7 +283,7 @@ int parse_command_line(int argc, char* argv[]) } else { auto msg = fmt::format("Unrecognized file after restart flag: {}.", filetype); - strcpy(openmc_err_msg, msg.c_str()); + set_errmsg(msg); return OPENMC_E_INVALID_ARGUMENT; } @@ -299,7 +299,7 @@ int parse_command_line(int argc, char* argv[]) if (filetype != "source") { std::string msg { "Second file after restart flag must be a source file"}; - strcpy(openmc_err_msg, msg.c_str()); + set_errmsg(msg); return OPENMC_E_INVALID_ARGUMENT; } @@ -325,7 +325,7 @@ int parse_command_line(int argc, char* argv[]) // Read number of threads if (i + 1 >= argc) { std::string msg {"Number of threads not specified."}; - strcpy(openmc_err_msg, msg.c_str()); + set_errmsg(msg); return OPENMC_E_INVALID_ARGUMENT; } i += 1; @@ -335,7 +335,7 @@ int parse_command_line(int argc, char* argv[]) int n_threads = std::stoi(argv[i]); if (n_threads < 1) { std::string msg {"Number of threads must be positive."}; - strcpy(openmc_err_msg, msg.c_str()); + set_errmsg(msg); return OPENMC_E_INVALID_ARGUMENT; } omp_set_num_threads(n_threads); diff --git a/src/main.cpp b/src/main.cpp index 88251ac7232..87a493882d9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,7 +25,7 @@ int main(int argc, char* argv[]) // This happens for the -h and -v flags return 0; } else if (err) { - fatal_error(openmc_err_msg); + fatal_error(openmc_get_err_msg()); } // start problem based on mode @@ -57,12 +57,12 @@ int main(int argc, char* argv[]) break; } if (err) - fatal_error(openmc_err_msg); + fatal_error(openmc_get_err_msg()); // Finalize and free up memory err = openmc_finalize(); if (err) - fatal_error(openmc_err_msg); + fatal_error(openmc_get_err_msg()); // If MPI is in use and enabled, terminate it #ifdef OPENMC_MPI diff --git a/src/material.cpp b/src/material.cpp index 21b11b8b9ce..52cc0ec87bd 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -1030,7 +1030,7 @@ void Material::set_densities( if (data::nuclide_map.find(nuc) == data::nuclide_map.end()) { int err = openmc_load_nuclide(nuc.c_str(), nullptr, 0); if (err < 0) - throw std::runtime_error {openmc_err_msg}; + throw std::runtime_error {get_errmsg()}; } nuclide_[i] = data::nuclide_map.at(nuc); @@ -1165,7 +1165,7 @@ void Material::add_nuclide(const std::string& name, double density) // If nuclide wasn't found, extend nuclide/density arrays int err = openmc_load_nuclide(name.c_str(), nullptr, 0); if (err < 0) - throw std::runtime_error {openmc_err_msg}; + throw std::runtime_error {get_errmsg()}; // Append new nuclide/density int i_nuc = data::nuclide_map[name]; diff --git a/src/mesh.cpp b/src/mesh.cpp index 4d6179fe8c2..46698a6e390 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -1455,7 +1455,7 @@ RegularMesh::RegularMesh(pugi::xml_node node) : StructuredMesh {node} } if (int err = set_grid()) { - fatal_error(openmc_err_msg); + fatal_error(get_errmsg()); } } @@ -1491,7 +1491,7 @@ RegularMesh::RegularMesh(hid_t group) : StructuredMesh {group} } if (int err = set_grid()) { - fatal_error(openmc_err_msg); + fatal_error(get_errmsg()); } } @@ -1658,7 +1658,7 @@ RectilinearMesh::RectilinearMesh(pugi::xml_node node) : StructuredMesh {node} grid_[2] = get_node_array(node, "z_grid"); if (int err = set_grid()) { - fatal_error(openmc_err_msg); + fatal_error(get_errmsg()); } } @@ -1671,7 +1671,7 @@ RectilinearMesh::RectilinearMesh(hid_t group) : StructuredMesh {group} read_dataset(group, "z_grid", grid_[2]); if (int err = set_grid()) { - fatal_error(openmc_err_msg); + fatal_error(get_errmsg()); } } @@ -1806,7 +1806,7 @@ CylindricalMesh::CylindricalMesh(pugi::xml_node node) origin_ = get_node_position(node, "origin"); if (int err = set_grid()) { - fatal_error(openmc_err_msg); + fatal_error(get_errmsg()); } } @@ -1819,7 +1819,7 @@ CylindricalMesh::CylindricalMesh(hid_t group) : PeriodicStructuredMesh {group} read_dataset(group, "origin", origin_); if (int err = set_grid()) { - fatal_error(openmc_err_msg); + fatal_error(get_errmsg()); } } @@ -2103,7 +2103,7 @@ SphericalMesh::SphericalMesh(pugi::xml_node node) origin_ = get_node_position(node, "origin"); if (int err = set_grid()) { - fatal_error(openmc_err_msg); + fatal_error(get_errmsg()); } } @@ -2117,7 +2117,7 @@ SphericalMesh::SphericalMesh(hid_t group) : PeriodicStructuredMesh {group} read_dataset(group, "origin", origin_); if (int err = set_grid()) { - fatal_error(openmc_err_msg); + fatal_error(get_errmsg()); } } diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index 0301e214582..5ffa1b074c6 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -756,7 +756,7 @@ void Tally::set_nuclides(const vector& nuclides) if (search == data::nuclide_map.end()) { int err = openmc_load_nuclide(nuc.c_str(), nullptr, 0); if (err < 0) - throw std::runtime_error {openmc_err_msg}; + throw std::runtime_error {get_errmsg()}; } nuclides_.push_back(data::nuclide_map.at(nuc)); } @@ -1510,7 +1510,6 @@ extern "C" int openmc_tally_set_nuclides( if (search == data::nuclide_map.end()) { int err = openmc_load_nuclide(word.c_str(), nullptr, 0); if (err < 0) { - set_errmsg(openmc_err_msg); return OPENMC_E_DATA; } } diff --git a/tests/regression_tests/cpp_driver/driver.cpp b/tests/regression_tests/cpp_driver/driver.cpp index a6c3e651037..3b866f6ff62 100644 --- a/tests/regression_tests/cpp_driver/driver.cpp +++ b/tests/regression_tests/cpp_driver/driver.cpp @@ -26,7 +26,7 @@ int main(int argc, char** argv) int err = openmc_init(argc, argv, nullptr); #endif if (err) - fatal_error(openmc_err_msg); + fatal_error(openmc_get_err_msg()); // create a new cell filter auto cell_filter = Filter::create(); diff --git a/tests/regression_tests/dagmc/external/main.cpp b/tests/regression_tests/dagmc/external/main.cpp index e78ab03fa2f..f97cbf2b419 100644 --- a/tests/regression_tests/dagmc/external/main.cpp +++ b/tests/regression_tests/dagmc/external/main.cpp @@ -25,7 +25,7 @@ int main(int argc, char* argv[]) // This happens for the -h and -v flags return EXIT_SUCCESS; } else if (openmc_err) { - fatal_error(openmc_err_msg); + fatal_error(openmc_get_err_msg()); } // Create DAGMC ptr @@ -106,12 +106,12 @@ int main(int argc, char* argv[]) // Run OpenMC openmc_err = openmc_run(); if (openmc_err) - fatal_error(openmc_err_msg); + fatal_error(openmc_get_err_msg()); // Deallocate memory openmc_err = openmc_finalize(); if (openmc_err) - fatal_error(openmc_err_msg); + fatal_error(openmc_get_err_msg()); #ifdef OPENMC_MPI MPI_Finalize(); diff --git a/tests/regression_tests/external_moab/main.cpp b/tests/regression_tests/external_moab/main.cpp index 6e3709b6a10..2528ee568ab 100644 --- a/tests/regression_tests/external_moab/main.cpp +++ b/tests/regression_tests/external_moab/main.cpp @@ -18,7 +18,7 @@ int main(int argc, char* argv[]) // This happens for the -h and -v flags return EXIT_SUCCESS; } else if (openmc_err) { - fatal_error(openmc_err_msg); + fatal_error(openmc_get_err_msg()); } // Create MOAB interface @@ -87,12 +87,12 @@ int main(int argc, char* argv[]) // Run OpenMC openmc_err = openmc_run(); if (openmc_err) - fatal_error(openmc_err_msg); + fatal_error(openmc_get_err_msg()); // Deallocate memory openmc_err = openmc_finalize(); if (openmc_err) - fatal_error(openmc_err_msg); + fatal_error(openmc_get_err_msg()); return EXIT_SUCCESS; }