Capabilities of OpenMC

We are looking to see if we can use OpenMC for irradiation experiment analysis for ATR and TREAT reactors at INL. I was wondering if someone could quickly answer what requirements OpenMC would be able to satisfy and what could not.

|F.1|The software shall provide depletion/activation of isotopes specified by the user for the following reactions: (n,fission), (n,γ), (n,alpha), (n,p), and (n,xn’).|
|F.2|The software shall track isotopic depletion and transmutation of materials in user specified regions.|
|F.3|The software shall be able to accurately calculate an eigenvalue (keff) for the geometric configuration for the ATR, ATRC, and TREAT.|
|F.4|The software shall allow for the reactor operating cycle simulation and changes in conditions such as reactor power, shutdown, rotating movement of control shims and axial movement of control shims.|
|F.5|The software shall be able to calculate the energy deposition from prompt and delayed neutrons and photons as the result of fission in various user specified regions within the reactor.|
|F.6|The software shall calculate fission density in a fueled region of interest|
|F.7|The software shall allow for the user to input compositions for irradiated fuel elements and experiments.|
|F.8|The software shall be able to calculate the neutron flux for multiple user specified energy bins for a geometric configuration similar to the ATR.|
|F.9|The software shall provide results for eigenvalue and neutron/photon heating rate tallies with statistical uncertainty. |
|F.10|The software shall allow the development of ATR, ATRC, and TREAT to support efficient analysis. |
|F.11|The software shall calculate neutron kinetics parameters.|
|F.12|The software shall Doppler broaden neutron cross sections.|

1 Like

Hey @nukespud and welcome to the community! Glad to hear you’re interested in the possibility of using OpenMC. To address each of these requirements:

OpenMC has a depletion capability that satisfies this. Notably, there is a lot of flexibility in how depletion chains are created including specifying which reactions should be accounted for (see the reactions argument to Chain.from_endf). For cross-code comparisons, see this paper.

Depletion is done based on materials and you can mark any material to be depletable or not (including materials with no fuel).

No problem here – I’ve run an autoconverted ATR OpenMC model before based on the MCNP model in ICSBEP.

When running a depletion simulation, you can specify a time-varying power level as well as cooling periods where there is no power. We don’t have a super straightforward way to make geometry modifications in the middle of a depletion simulation, but it can be done by running successive depletion simulations, making the geometry changes manually in between.

No problem with this one. We wrote an ANS transactions paper (requires login) that goes over some energy deposition comparisons to Serpent/MCNP. Some more documentation on energy deposition here.

We have an extensive tally system that handles this.

User’s guide section on how to input material compositions.

This can be done with an EnergyFilter.

All user-specified and global tallies (e.g., k-effective) are reported with the statistical uncertainty.

Through our Python API, you can do some really sophisticated analysis. I’d encourage you to check out the list of example Jupyter notebooks that should give a good sense of what’s possible.

This is the one area that OpenMC is currently lacking. There have been a few developmental branches where such capabilities were added but they never made it back to the main branch. If this is a showstopper for you guys, I’d be happy to discuss this further and see how we could work together to get such capabilities in the code.

Our Python API includes an openmc.data module for processing, manipulating, and inspecting nuclear data. If you have an ENDF file, you can easily create an HDF5 data file for OpenMC with cross sections at multiple temperatures as follows:

h1 = openmc.data.IncidentNeutron.from_endf(
    'n-001_H_001.endf',
    temperatures=[300., 400., 500.]
)
h1.export_to_hdf5('H1.h5')

There has also been a lot of R&D on a fundamentally different representation of of cross section data called the windowed multipole format that allows cross sections to be calculated at any energy and temperature at runtime without storing the cross sections in pregenerated tables. We have windowed multipole data available for ENDF/B-VII.1 and expect to have data for ENDF/B-VIII.0 in the near-term as well. In general, you can find pregenerated HDF5 files for the major nuclear data libraries at Official Data Libraries | OpenMC.

Let me know if you have further questions.

3 Likes

This is a great list. Thank you so much for the time. What would it take to do geometry changes between time steps. How much effort would be to rotate and translate geometry between time steps.

You should be able to do it today by running each timestep as its own depletion simulation, and then in between timesteps make the required geometry changes. Hopefully the geometry changes you’re imagining don’t result in any changes in the volume of depletable materials? If so, it might be a little more complicated. We have an open issue on Github discussing the design of a built-in capability to be able to perform arbitrary logic between timesteps that you might find interesting; feel free to chime in if you have thoughts or potential user requirements for such a capability.

@paulromano I need to replace the most burned fuel elements with the least burned fuel elements for an optimal in-core fuel management study, but I didn’t see anywhere in the documentation that I could map the reaction rate of inner fuel elements with the new one or least burned elements during the depletion calculation.

Could you kindly give me some idea how I should proceed now?

@ayaz I’m not sure I understand where the reaction rates come in. It sounds like you need to change material compositions in between depletion steps, is that right?

I thought that changing the reaction rate between depletion steps would be easy.

Yes that’s exactly what I’m looking for, @paulromano

@paulromano Could you help me here to change the composition of the material at different lattice position in the middle of depletion process?

@ayaz I put together an example here showing how you could run a depletion calculation and change a material composition in the middle.

1 Like

Dear Paul, I was trying to follow up on this capability of oepnmc of changing material composition during the depletion process, but I’m not sure I get the purpose of example. The nuclide you’re trying to get rid continues to be produced after the initial time-step anyway, as it should be. If one wanted to remove it completely at every timestep ,what would be the more straightforward way? thanks

@lorenzo In that case you would have to run a loop where each iteration of the loop runs a single depletion timestep and then makes the needed material change.

@paulromano Thank you for your answer.
I would do something like this:

time_steps = [1.0]*5
integrator = openmc.deplete.PredictorIntegrator(op, [time_steps[0]] , timestep_units='d', power=power)
integrator.integrate()
results = openmc.deplete.ResultsList.from_hdf5('depletion_results.h5')
for i,t in enumerate(time_steps[1:]):
      model.materials = results.export_to_materials(i+1)
      do materials modification on model.materials
      op = openmc.deplete.Operator(model, chain_file, prev_results=results)
      integrator = openmc.deplete.PredictorIntegrator(op, [t], timestep_units='d', power=power)
      integrator.integrate()
      results = openmc.deplete.ResultsList.from_hdf5('depletion_results.h5')

However if I want, for example, to remove fission products completely before running an iteration I do not find better ways than remove them directly from the chain xml file.

Dear Paul,
I just noticed that the the above written script wouldn’t’ work either since any modification to the material file after the first iteration is not red by the deplete algorithm, but only the ResultsList file does. So if want to do material modification and restart from the last step I would need to modify the ResultsList, but I don’t think it’s possible. Could you please tell me what you had in mind? thanks

Perhaps the issue is this:

Here you’re using the index i+1, but at each iteration you’re running a single depletion calculation, so you really should be using index 1 every time rather than i+1. Or to say it another way, the ResultsList that you are getting doesn’t get extended at each iteration – it is only the results for a single iteration.

Hi Paul and thank you again for your answer.
I think I don’t have fully understood what a modification to the material definition does during a restart. I tried the pincell depletion example, where fuel material is U235 only, modified like this:

# Previous Model definition not reported 
chain_file = '/mounted/depletion/chain_simple.xml'
op = openmc.deplete.Operator(model, chain_file)
power = 40.0e3
time_steps = [1.0]*1
integrator = openmc.deplete.PredictorIntegrator(op, time_steps , timestep_units='d', power=power)
integrator.integrate()
# Remove U235 and add U238 and restart
results = openmc.deplete.ResultsList.from_hdf5('depletion_results.h5')
model.materials[0].remove_nuclide("U235")
model.materials[0].add_nuclide("U238")
op = openmc.deplete.Operator(model, chain_file, results)
integrator = openmc.deplete.PredictorIntegrator(op, time_steps, power, timestep_units='d')
integrator.integrate()

Even if removing completely U235 and adding U238, k_eff remains the same and when I look at the different nuclides atoms evolution I notice that U235 doesn’t get removed and U238 is there before the addition to the material:

results = openmc.deplete.ResultsList.from_hdf5('depletion_results.h5')
time, n_U235 = results.get_atoms('1', 'U235')
time, n_U238 = results.get_atoms('1', 'U238')
n_U235
array([5.36611007e+25, 5.36609892e+25, 5.36608776e+25])
n_U238
array([4188790.20478639, 4188789.59534922, 4188788.98467082])

@lorenzo For a change in the model to be reflected in the next depletion step, you should not supply the previous results. If you pass previous results, it will preferentially use the material composition from the previous results, not from the modified model that you’re passing. So, in your loop here, just instantiate the operator as:

op = openmc.deplete.Operator(model, chain_file)

@paulromano thank you, but without providing the previous result file, the depletion will restart from zero.

The above line will update the model, which is passed to the new depletion operator. So, even though the new depletion integration appears to be starting from zero time, it’s using the already-depleted materials from the previous depletion.

Thank you very much Paul, this absolutely makes sense!