|
11 | 11 | from .microxs import get_microxs_and_flux, write_microxs_hdf5, read_microxs_hdf5 |
12 | 12 | from .results import Results |
13 | 13 | from ..checkvalue import PathLike |
| 14 | +from ..mpi import comm |
| 15 | +from openmc.lib import TemporarySession |
| 16 | +from openmc.utility_funcs import change_directory |
14 | 17 |
|
15 | 18 |
|
16 | 19 | def get_activation_materials( |
@@ -199,8 +202,10 @@ def run( |
199 | 202 | """ |
200 | 203 |
|
201 | 204 | if output_dir is None: |
| 205 | + # Create timestamped output directory and broadcast to all ranks for |
| 206 | + # consistency (different ranks may have slightly different times) |
202 | 207 | stamp = datetime.now().strftime('%Y-%m-%dT%H-%M-%S') |
203 | | - output_dir = Path(f'r2s_{stamp}') |
| 208 | + output_dir = Path(comm.bcast(f'r2s_{stamp}')) |
204 | 209 |
|
205 | 210 | # Set run_kwargs for the neutron transport step |
206 | 211 | if micro_kwargs is None: |
@@ -257,18 +262,19 @@ def step1_neutron_transport( |
257 | 262 |
|
258 | 263 | """ |
259 | 264 |
|
260 | | - output_dir = Path(output_dir) |
| 265 | + output_dir = Path(output_dir).resolve() |
261 | 266 | output_dir.mkdir(parents=True, exist_ok=True) |
262 | 267 |
|
263 | 268 | if self.method == 'mesh-based': |
264 | 269 | # Compute material volume fractions on the mesh |
265 | 270 | if mat_vol_kwargs is None: |
266 | 271 | mat_vol_kwargs = {} |
267 | | - self.results['mesh_material_volumes'] = mmv = \ |
268 | | - self.domains.material_volumes(self.neutron_model, **mat_vol_kwargs) |
| 272 | + self.results['mesh_material_volumes'] = mmv = comm.bcast( |
| 273 | + self.domains.material_volumes(self.neutron_model, **mat_vol_kwargs)) |
269 | 274 |
|
270 | 275 | # Save results to file |
271 | | - mmv.save(output_dir / 'mesh_material_volumes.npz') |
| 276 | + if comm.rank == 0: |
| 277 | + mmv.save(output_dir / 'mesh_material_volumes.npz') |
272 | 278 |
|
273 | 279 | # Create mesh-material filter based on what combos were found |
274 | 280 | domains = openmc.MeshMaterialFilter.from_volumes(self.domains, mmv) |
@@ -299,13 +305,16 @@ def step1_neutron_transport( |
299 | 305 | micro_kwargs.setdefault('path_statepoint', output_dir / 'statepoint.h5') |
300 | 306 | micro_kwargs.setdefault('path_input', output_dir / 'model.xml') |
301 | 307 |
|
302 | | - # Run neutron transport and get fluxes and micros |
303 | | - self.results['fluxes'], self.results['micros'] = get_microxs_and_flux( |
304 | | - self.neutron_model, domains, **micro_kwargs) |
| 308 | + # Run neutron transport and get fluxes and micros. Run via openmc.lib to |
| 309 | + # maintain a consistent parallelism strategy with the activation step. |
| 310 | + with TemporarySession(): |
| 311 | + self.results['fluxes'], self.results['micros'] = get_microxs_and_flux( |
| 312 | + self.neutron_model, domains, **micro_kwargs) |
305 | 313 |
|
306 | 314 | # Save flux and micros to file |
307 | | - np.save(output_dir / 'fluxes.npy', self.results['fluxes']) |
308 | | - write_microxs_hdf5(self.results['micros'], output_dir / 'micros.h5') |
| 315 | + if comm.rank == 0: |
| 316 | + np.save(output_dir / 'fluxes.npy', self.results['fluxes']) |
| 317 | + write_microxs_hdf5(self.results['micros'], output_dir / 'micros.h5') |
309 | 318 |
|
310 | 319 | def step2_activation( |
311 | 320 | self, |
@@ -457,15 +466,17 @@ def step3_photon_transport( |
457 | 466 | # photon model if it is different from the neutron model to account for |
458 | 467 | # potential material changes |
459 | 468 | if self.method == 'mesh-based' and different_photon_model: |
460 | | - self.results['mesh_material_volumes_photon'] = photon_mmv = \ |
461 | | - self.domains.material_volumes(self.photon_model, **mat_vol_kwargs) |
| 469 | + self.results['mesh_material_volumes_photon'] = photon_mmv = comm.bcast( |
| 470 | + self.domains.material_volumes(self.photon_model, **mat_vol_kwargs)) |
462 | 471 |
|
463 | 472 | # Save photon MMV results to file |
464 | | - photon_mmv.save(output_dir / 'mesh_material_volumes.npz') |
| 473 | + if comm.rank == 0: |
| 474 | + photon_mmv.save(output_dir / 'mesh_material_volumes.npz') |
465 | 475 |
|
466 | | - tally_ids = [tally.id for tally in self.photon_model.tallies] |
467 | | - with open(output_dir / 'tally_ids.json', 'w') as f: |
468 | | - json.dump(tally_ids, f) |
| 476 | + if comm.rank == 0: |
| 477 | + tally_ids = [tally.id for tally in self.photon_model.tallies] |
| 478 | + with open(output_dir / 'tally_ids.json', 'w') as f: |
| 479 | + json.dump(tally_ids, f) |
469 | 480 |
|
470 | 481 | self.results['photon_tallies'] = {} |
471 | 482 |
|
@@ -514,8 +525,9 @@ def step3_photon_transport( |
514 | 525 | time_index = len(self.results['depletion_results']) + time_index |
515 | 526 |
|
516 | 527 | # Run photon transport calculation |
517 | | - run_kwargs['cwd'] = Path(output_dir) / f'time_{time_index}' |
518 | | - statepoint_path = self.photon_model.run(**run_kwargs) |
| 528 | + photon_dir = Path(output_dir) / f'time_{time_index}' |
| 529 | + with TemporarySession(self.photon_model, cwd=photon_dir): |
| 530 | + statepoint_path = self.photon_model.run(**run_kwargs) |
519 | 531 |
|
520 | 532 | # Store tally results |
521 | 533 | with openmc.StatePoint(statepoint_path) as sp: |
|
0 commit comments