openmc icon indicating copy to clipboard operation
openmc copied to clipboard

Stop depletion between each timestep

Open pshriwise opened this issue 5 years ago • 7 comments

Today @paulromano and I were discussing the fact that it would be nice to be able to halt depletion calculations between time steps to examine or modify reaction rates, material compositions, etc. using the Python CAPI. Making the Integrator classes iterable seems like it would be really useful for this purpose.

For example, in an MSR model one might want to remove fission products between each step.

for result in integrator:
    remove_fission_products(result)

pshriwise avatar Aug 05 '20 23:08 pshriwise

This would be a great feature! We might already support something kind of like this through https://github.com/openmc-dev/openmc/blob/a7076138f2dba72217de60b9239bd6857251db06/openmc/deplete/abc.py#L835-L841

This is called for every step that isn't the first step in a restart calculation, so something like

class MSRIntegrator(PredictorIntegrator):
    def _get_bos_data_from_operator(self, step, power, bos_conc):
        conc = self._remove_fission_products(bos_conc)
        return super()._get_bos_data_from_operator(step, power, conc)

Granted, this would require a new integrator for each scheme, which could get cumbersome. Maybe supplying a function that modifies the BOS concentrations?

drewejohnson avatar Aug 06 '20 13:08 drewejohnson

I was also thinking it would be nice to be able to call integrate multiple times. This might involve moving some of the arguments that are currently on the constructor to integrate instead. Maybe something like:

op = openmc.deplete.Operator(...)

x = SomeIntegrator(op)
x.integrate(timesteps1, power1)
# do something interesting
...
x.integrate(timesteps2, power2)

paulromano avatar Aug 06 '20 14:08 paulromano

I was thinking of updating the Integrate.__iter__ method s.t. it would yield a Results object and concentrations at each step, but I like @paulromano's suggestion for it's fine-grain control. Perhaps some combination of the two?

op = openmc.deplete.Operator(...)

x = SomeIntegrator(op)

x.add_timestep(dt, power)

for step in x:
    do_something_interesting(op, step)
    if continue_depletion(op, step):
        x.add_timestep(dt, power)

And for a standard depletion run, something like:

op = openmc.deplete.Operator(...)

x = SomeIntegrator(op)

x.add_timesteps(dts, powers)

x.integrate_all()

Is that a little too convoluted?

pshriwise avatar Aug 06 '20 14:08 pshriwise

At the standpoint of user, the multiple callings of integrate could be considered as follows,

op1 = openmc.deplete.Operator(...)

x1 = SomeIntegrator(op1)

x1.integrate(timesteps1, power1)

# fission product processing or even fuel shuffle

res1 = openmc.deplete.ResultsList.from_hdf5("depletion_results.h5")

op2 = openmc.deplete.Operator(..., previous_results=res1)

x2 = SomeIntegrator(op2)

x2.integrate(timesteps2, power2)

Am I following your thoughts? May be the saving and loading results file could be removed via returning the results to integrate,

res1 = x1.integrate(timesteps1, power1)

res1_corrected = res1.someprocess()

res2 = x1.integrate(timesteps2, power2, res1_corrected)

rockfool avatar Aug 06 '20 16:08 rockfool

I think supporting something like a one-step integrate and multi-step integrate_all (name TBD) could be done pretty easily. Then you could perform some actions like @pshriwise is interested in with

prev_res = None
for dt, power in zip(time_steps, powers):
    prev_res = x.integrate(dt, power, prev_res=prev_res)
    prev_res = do_stuff(prev_res)

Or to maintain the one-shot approach

x.integrate_all(time_steps, powers)

But just to confuse potential users, currently Integrator.integrate does all the time steps, meaning some deprecation / warning period where integrate actually does a single step is tricky

A couple things to be wary of

  • Units on time step. Converting from days to seconds isn't too bad, but we also support burnup which, while not difficult, is something that x.integrate would have to interpret. Or we say these methods only support time steps of seconds and provide some way to convert between burnup
  • Units on power (W, W/mass) and the new source_rates for normalization. Not a difficult conversion, but something that we currently support and should probably continue to support
  • Final EOL transport solution. With this loop, we would have to provide ample documentation and methods (x.solve_eol?) that just re-run a solution w/o depletion

drewejohnson avatar Aug 07 '20 15:08 drewejohnson

Hey guys, does #1884 solve this (or at least the intent of it)? The crux of the ticket is we would like a way to do the following:

Integrator.integrate(...)
# do stuff
Integrator.integrate(...)

After #1884 we can do this with:

model.deplete(...)
# do stuff
model.deplete(...)

Where # do stuff can be move rods, modify materials through the C-API, whatever.

nelsonag avatar Oct 07 '21 20:10 nelsonag

As one more option, I made a gist not long ago showing how this can be done using ResultsList.export_to_materials.

paulromano avatar Mar 02 '22 04:03 paulromano