Skip to content

Commit adeec84

Browse files
keep allow running openmc for mcpl file with WARNING
1 parent 93e9522 commit adeec84

File tree

1 file changed

+50
-49
lines changed

1 file changed

+50
-49
lines changed

src/mcpl_interface.cpp

Lines changed: 50 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -48,24 +48,30 @@ struct openmc_local_mcpl_particle_t {
4848

4949
typedef struct openmc_local_mcpl_particle_t mcpl_particle_repr_t;
5050

51-
typedef void* mcpl_file_handle_repr_t;
52-
typedef void* mcpl_outfile_handle_repr_t;
53-
54-
typedef mcpl_file_handle_repr_t (*mcpl_open_file_fpt)(const char* filename);
55-
typedef uint64_t (*mcpl_hdr_nparticles_fpt)(
56-
mcpl_file_handle_repr_t file_handle);
57-
typedef const mcpl_particle_repr_t* (*mcpl_read_fpt)(
58-
mcpl_file_handle_repr_t file_handle);
59-
typedef void (*mcpl_close_file_fpt)(mcpl_file_handle_repr_t file_handle);
60-
61-
typedef mcpl_outfile_handle_repr_t (*mcpl_create_outfile_fpt)(
62-
const char* filename);
51+
// Opaque struct definitions replicating the MCPL C-API to ensure ABI
52+
// compatibility without including mcpl.h. These must be kept in sync.
53+
struct mcpl_file_t_ {
54+
void* internal;
55+
};
56+
struct mcpl_outfile_t_ {
57+
void* internal;
58+
};
59+
60+
typedef struct mcpl_file_t_ mcpl_file_t;
61+
typedef struct mcpl_outfile_t_ mcpl_outfile_t;
62+
63+
// Function pointer types for the dynamically loaded MCPL library
64+
typedef mcpl_file_t* (*mcpl_open_file_fpt)(const char* filename);
65+
typedef uint64_t (*mcpl_hdr_nparticles_fpt)(mcpl_file_t* file_handle);
66+
typedef const mcpl_particle_repr_t* (*mcpl_read_fpt)(mcpl_file_t* file_handle);
67+
typedef void (*mcpl_close_file_fpt)(mcpl_file_t* file_handle);
68+
69+
typedef mcpl_outfile_t* (*mcpl_create_outfile_fpt)(const char* filename);
6370
typedef void (*mcpl_hdr_set_srcname_fpt)(
64-
mcpl_outfile_handle_repr_t outfile_handle, const char* srcname);
65-
typedef void (*mcpl_add_particle_fpt)(mcpl_outfile_handle_repr_t outfile_handle,
66-
const mcpl_particle_repr_t* particle);
67-
typedef void (*mcpl_close_outfile_fpt)(
68-
mcpl_outfile_handle_repr_t outfile_handle);
71+
mcpl_outfile_t* outfile_handle, const char* srcname);
72+
typedef void (*mcpl_add_particle_fpt)(
73+
mcpl_outfile_t* outfile_handle, const mcpl_particle_repr_t* particle);
74+
typedef void (*mcpl_close_outfile_fpt)(mcpl_outfile_t* outfile_handle);
6975

7076
namespace openmc {
7177

@@ -164,21 +170,6 @@ void append_error(std::string& existing_msg, const std::string& new_error)
164170
existing_msg += new_error;
165171
}
166172

167-
void mcpl_library_cleanup()
168-
{
169-
g_mcpl_api.reset();
170-
if (g_mcpl_lib_handle) {
171-
#ifdef _WIN32
172-
FreeLibrary(g_mcpl_lib_handle);
173-
#else
174-
dlclose(g_mcpl_lib_handle);
175-
#endif
176-
g_mcpl_lib_handle = nullptr;
177-
}
178-
g_mcpl_successfully_loaded = false;
179-
g_mcpl_init_attempted = false;
180-
}
181-
182173
void initialize_mcpl_interface_impl()
183174
{
184175
g_mcpl_init_attempted = true;
@@ -264,7 +255,8 @@ void initialize_mcpl_interface_impl()
264255
try {
265256
g_mcpl_api = std::make_unique<McplApi>(g_mcpl_lib_handle);
266257
g_mcpl_successfully_loaded = true;
267-
std::atexit(mcpl_library_cleanup);
258+
// Do not call dlclose/FreeLibrary at exit. Leaking the handle is safer
259+
// and standard practice for libraries used for the application's lifetime.
268260
} catch (const std::runtime_error& e) {
269261
append_error(g_mcpl_load_error_msg,
270262
fmt::format(
@@ -297,16 +289,12 @@ inline void ensure_mcpl_ready_or_fatal()
297289
{
298290
initialize_mcpl_interface_if_needed();
299291
if (!g_mcpl_successfully_loaded) {
300-
fatal_error(fmt::format(
301-
"MCPL functionality is required, but the MCPL library is not available "
302-
"or failed to initialize. "
303-
"Please ensure MCPL is installed and its library can be found (e.g., via "
304-
"PATH on Windows, LD_LIBRARY_PATH on Linux, or DYLD_LIBRARY_PATH on "
305-
"macOS). "
306-
"You can often install MCPL with 'pip install mcpl'. "
307-
"Last error(s): {}",
308-
g_mcpl_load_error_msg.empty() ? "No specific error during load."
309-
: g_mcpl_load_error_msg));
292+
fatal_error("MCPL functionality is required, but the MCPL library is not "
293+
"available or failed to initialize. Please ensure MCPL is "
294+
"installed and its library can be found (e.g., via PATH on "
295+
"Windows, LD_LIBRARY_PATH on Linux, or DYLD_LIBRARY_PATH on "
296+
"macOS). You can often install MCPL with 'pip install mcpl' or "
297+
"'conda install mcpl'.");
310298
}
311299
}
312300

@@ -352,14 +340,15 @@ vector<SourceSite> mcpl_source_sites(std::string path)
352340
ensure_mcpl_ready_or_fatal();
353341
vector<SourceSite> sites;
354342

355-
mcpl_file_handle_repr_t mcpl_file = g_mcpl_api->open_file(path.c_str());
343+
mcpl_file_t* mcpl_file = g_mcpl_api->open_file(path.c_str());
356344
if (!mcpl_file) {
357345
fatal_error(fmt::format("MCPL: Could not open file '{}'. It might be "
358346
"missing, inaccessible, or not a valid MCPL file.",
359347
path));
360348
}
361349

362350
size_t n_particles_in_file = g_mcpl_api->hdr_nparticles(mcpl_file);
351+
size_t n_skipped = 0;
363352
if (n_particles_in_file > 0) {
364353
sites.reserve(n_particles_in_file);
365354
}
@@ -375,16 +364,28 @@ vector<SourceSite> mcpl_source_sites(std::string path)
375364
if (p_repr->pdgcode == 2112 || p_repr->pdgcode == 22 ||
376365
p_repr->pdgcode == 11 || p_repr->pdgcode == -11) {
377366
sites.push_back(mcpl_particle_to_site(p_repr));
367+
} else {
368+
n_skipped++;
378369
}
379370
}
380371

381372
g_mcpl_api->close_file(mcpl_file);
382373

374+
if (n_skipped > 0 && n_particles_in_file > 0) {
375+
double percent_skipped =
376+
100.0 * static_cast<double>(n_skipped) / n_particles_in_file;
377+
warning(fmt::format(
378+
"MCPL: Skipped {} of {} total particles ({:.1f}%) in file '{}' because "
379+
"their type is not supported by OpenMC.",
380+
n_skipped, n_particles_in_file, percent_skipped, path));
381+
}
382+
383383
if (sites.empty()) {
384384
if (n_particles_in_file > 0) {
385-
fatal_error(fmt::format("MCPL file '{}' contained {} particles, but none "
386-
"were of the supported types "
387-
"(neutron, photon, electron, positron).",
385+
fatal_error(fmt::format(
386+
"MCPL file '{}' contained {} particles, but none were of the supported "
387+
"types (neutron, photon, electron, positron). OpenMC cannot proceed "
388+
"without source particles.",
388389
path, n_particles_in_file));
389390
} else {
390391
fatal_error(fmt::format(
@@ -394,7 +395,7 @@ vector<SourceSite> mcpl_source_sites(std::string path)
394395
return sites;
395396
}
396397

397-
void write_mcpl_source_bank_internal(mcpl_outfile_handle_repr_t file_id,
398+
void write_mcpl_source_bank_internal(mcpl_outfile_t* file_id,
398399
span<SourceSite> local_source_bank,
399400
const vector<int64_t>& bank_index_all_ranks)
400401
{
@@ -484,7 +485,7 @@ void write_mcpl_source_point(const char* filename, span<SourceSite> source_bank,
484485
filename, extension));
485486
}
486487

487-
mcpl_outfile_handle_repr_t file_id = nullptr;
488+
mcpl_outfile_t* file_id = nullptr;
488489

489490
if (mpi::master) {
490491
file_id = g_mcpl_api->create_outfile(filename_.c_str());

0 commit comments

Comments
 (0)