@@ -48,24 +48,30 @@ struct openmc_local_mcpl_particle_t {
48
48
49
49
typedef struct openmc_local_mcpl_particle_t mcpl_particle_repr_t ;
50
50
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);
63
70
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);
69
75
70
76
namespace openmc {
71
77
@@ -164,21 +170,6 @@ void append_error(std::string& existing_msg, const std::string& new_error)
164
170
existing_msg += new_error;
165
171
}
166
172
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
-
182
173
void initialize_mcpl_interface_impl ()
183
174
{
184
175
g_mcpl_init_attempted = true ;
@@ -264,7 +255,8 @@ void initialize_mcpl_interface_impl()
264
255
try {
265
256
g_mcpl_api = std::make_unique<McplApi>(g_mcpl_lib_handle);
266
257
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.
268
260
} catch (const std::runtime_error& e) {
269
261
append_error (g_mcpl_load_error_msg,
270
262
fmt::format (
@@ -297,16 +289,12 @@ inline void ensure_mcpl_ready_or_fatal()
297
289
{
298
290
initialize_mcpl_interface_if_needed ();
299
291
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'." );
310
298
}
311
299
}
312
300
@@ -352,14 +340,15 @@ vector<SourceSite> mcpl_source_sites(std::string path)
352
340
ensure_mcpl_ready_or_fatal ();
353
341
vector<SourceSite> sites;
354
342
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 ());
356
344
if (!mcpl_file) {
357
345
fatal_error (fmt::format (" MCPL: Could not open file '{}'. It might be "
358
346
" missing, inaccessible, or not a valid MCPL file." ,
359
347
path));
360
348
}
361
349
362
350
size_t n_particles_in_file = g_mcpl_api->hdr_nparticles (mcpl_file);
351
+ size_t n_skipped = 0 ;
363
352
if (n_particles_in_file > 0 ) {
364
353
sites.reserve (n_particles_in_file);
365
354
}
@@ -375,16 +364,28 @@ vector<SourceSite> mcpl_source_sites(std::string path)
375
364
if (p_repr->pdgcode == 2112 || p_repr->pdgcode == 22 ||
376
365
p_repr->pdgcode == 11 || p_repr->pdgcode == -11 ) {
377
366
sites.push_back (mcpl_particle_to_site (p_repr));
367
+ } else {
368
+ n_skipped++;
378
369
}
379
370
}
380
371
381
372
g_mcpl_api->close_file (mcpl_file);
382
373
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
+
383
383
if (sites.empty ()) {
384
384
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." ,
388
389
path, n_particles_in_file));
389
390
} else {
390
391
fatal_error (fmt::format (
@@ -394,7 +395,7 @@ vector<SourceSite> mcpl_source_sites(std::string path)
394
395
return sites;
395
396
}
396
397
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,
398
399
span<SourceSite> local_source_bank,
399
400
const vector<int64_t >& bank_index_all_ranks)
400
401
{
@@ -484,7 +485,7 @@ void write_mcpl_source_point(const char* filename, span<SourceSite> source_bank,
484
485
filename, extension));
485
486
}
486
487
487
- mcpl_outfile_handle_repr_t file_id = nullptr ;
488
+ mcpl_outfile_t * file_id = nullptr ;
488
489
489
490
if (mpi::master) {
490
491
file_id = g_mcpl_api->create_outfile (filename_.c_str ());
0 commit comments