Repository navigation
add continue feature for depletion - #3272
Conversation
1b9dbbd to
b5fe00b
Compare
|
Looks like it hit the |
pshriwise
left a comment
There was a problem hiding this comment.
A few things to address here:
- We'll want to make sure that the call to
Results.get_times()provides the same unis as the time steps passed to theIntegratorclass here. - The times coming from the
Resultsobject are points in time, notdt, so we'll need to take the diff of that array to make the comparison to the time steps passed for the continuation run. - Similar to the
get_timessituation, the array coming from theResults.get_source_rates()will include more values than the number of time steps and will need to be modified to make a valid comparison to the continuation source rates.
Possibly yes, but this is an error that can be reproduced locally easily enough. |
|
Turn out some of the tests were triggering the Here's my local version of the code # validate existing depletion steps are consistent with those passed to operator
if continue_timesteps:
completed_times = operator.prev_res.get_times(time_units=timestep_units)
completed_timesteps = completed_times[1:] - completed_times[:-1] # convert absolute t to dt
completed_source_rates = operator.prev_res.get_source_rates()
num_previous_steps_run = len(completed_timesteps)
if (np.array_equal(completed_timesteps, timesteps[:num_previous_steps_run])):
seconds = seconds[num_previous_steps_run:]
else:
print("timestep check failed")
print(f"timesteps given to continue run: {timesteps}")
print(f"found completed timesteps: {completed_timesteps}")
raise ValueError(
"You are attempting to continue a run in which the previous timesteps "
"do not have the same initial timesteps as those provided to the "
"Integrator. Please make sure you are using the correct timesteps."
)
if(np.array_equal(completed_source_rates, source_rates[:num_previous_steps_run])):
source_rates = source_rates[num_previous_steps_run:]
else:
print("source rate check failed")
print(f"SRs given to coninute run: {source_rates}")
print(f"completed SRs: {completed_source_rates}")
raise ValueError(
"You are attempting to continue a run in which the previous results "
"do not have the same initial source rates, powers, or power densities "
"as those provided to the Integrator. Please make sure you are using "
"the correct powers, power densities, or source rates and previous results file."
)I've added some print statements to get an idea of what the important variables look like during tests but I'm not totally sure why some tests are failing despite printing values that seem to be the same? I tested the I know we discussed some schemes might have more data in them than the |
|
As discussed today, I printed the non-sliced versions of the data above which clears up why the arrays appeared the same. E.g. we should actually do this to test if(np.array_equal(completed_source_rates, source_rates[:num_previous_steps_run])):
source_rates = source_rates[num_previous_steps_run:]
else:
print("source rate check failed")
print(f"Initial SRs given to coninute run: {source_rates[:num_previous_steps_run]}")
print(f"completed SRs: {completed_source_rates}")When I print what's actually compared in the if statements, we see This is due to the fact that certain integrators with sub-steps write out more source rates than are initially provided. I will work on looking into how to capture this case and test appropriately. |
| def get_source_rates(self) -> np.ndarray: | ||
| """ | ||
| .. versionadded:: 0.15.1 | ||
|
|
||
| Returns | ||
| ------- | ||
| numpy.ndarray | ||
| 1-D vector of source rates at each point in the depletion simulation | ||
| with the units originally defined by the user. | ||
|
|
||
| """ | ||
| source_rates = np.fromiter( | ||
| (r.source_rate for r in self), | ||
| dtype=self[0].source_rate.dtype, | ||
| count=len(self), | ||
| ) | ||
|
|
||
| return source_rates |
There was a problem hiding this comment.
It seems like when I print out the result of this function, it duplicates the final source rate (no matter the integrator chosen). When I change to count=len(self) -1, it prints what I would expect for the source_rates ndarray.
Thinking about this more, it kind of makes sense since get_times() returns an ndarray containing 0 as the first element. If there are N timesteps and N source rates given to the integrator, then in this case, count = len(self) -1 is the correct choice for this function.
Not sure if this is intended, but the final simulation "time" duplicates the system final source rate.
pshriwise
left a comment
There was a problem hiding this comment.
Looking good @lewisgross1296! Just a few line comments from me.
| _SECONDS_PER_MINUTE = 60 | ||
| _SECONDS_PER_HOUR = 60*60 | ||
| _SECONDS_PER_DAY = 24*60*60 | ||
| _SECONDS_PER_JULIAN_YEAR = 365.25*24*60*60 |
There was a problem hiding this comment.
looks like we lost a comment from the original line here
| (r.source_rate for r in self), | ||
| dtype=self[0].source_rate.dtype, | ||
| count=len(self)-1, | ||
| ) # Results duplicates the final source rate at the final simulation time |
There was a problem hiding this comment.
Let's move this comment above the code.
| ) # Results duplicates the final source rate at the final simulation time | |
| ) # Results duplicate the final source rate at the final simulation time |
| .. versionadded:: 0.12 | ||
| continue_timesteps : bool, optional | ||
| Whether or not to treat the current solve as a continuation of a | ||
| previous simulation. Defaults to `False`. If `True`, the timesteps |
There was a problem hiding this comment.
Let's explain the intended behavior for a False value as well here.
| # retrieved from operator.prev_res.get_source_rates(), then run a depletion simulations | ||
| # with only the new time steps and source rates provided |
There was a problem hiding this comment.
| # retrieved from operator.prev_res.get_source_rates(), then run a depletion simulations | |
| # with only the new time steps and source rates provided | |
| # retrieved from operator.prev_res.get_source_rates(), then run a depletion simulation | |
| # with only the new time steps and source rates provided |
Co-authored-by: Edgar-21 <84034227+Edgar-21@users.noreply.github.com> Co-authored-by: Connor Moreno <camoreno@wisc.edu>
…pdated doc strings
Co-authored-by: Patrick Shriwise <pshriwise@gmail.com> doc string and wrap match error message
08f658f to
020aff2
Compare
Co-authored-by: Patrick Shriwise <pshriwise@gmail.com>
7905cfc to
220f1a9
Compare
|
@connoramoreno @Edgar-21 @dean-krueger test are passing locally now, if you're good with the state of things, please 👍 and otherwise leave a review :) |
pshriwise
left a comment
There was a problem hiding this comment.
Thanks @lewisgross1296! Nice to have this option to continue depletion runs without input updates!
paulromano
left a comment
There was a problem hiding this comment.
Thanks @lewisgross1296! I ended up making a few simplifications. The only notable change is that I don't think continue_timesteps=True should be allowed if no prev_results is provided (silently changing the value of continue_timesteps). If the user asks to continue the run, it stands to reason they should be providing previous results as well. Let me know if you're OK with that.
Co-authored-by: Connor Moreno <camoreno@wisc.edu> Co-authored-by: Patrick Shriwise <pshriwise@gmail.com> Co-authored-by: Lewis Gross <ligross@cnerg-docker-04.neep.wisc.edu> Co-authored-by: Paul Romano <paul.k.romano@gmail.com>
Description
This PR closes #2871. To summarize the motivation, I'd like depletion restarts to be a bit easier for users. If you set up a depletion simulation that doesn't end up getting run all the way (think hitting max wall time on an HPC or some other interrupt), the burden then falls to the user to correctly determine what time steps were not run and to create a new script that picks up where the other one left off. In my own experience, it is easy to make a mistake and re-run a simulation that is not what I desired.
All we do here is add a
continue_timestepsflag (default toFalse) that adds a new logic block to theIntegratorclass. It would be useful in the above case and requires users to provide theIntegratorwith a set oftimestepsand one ofpower/power_density/source_ratethat matches what already exists in aprev_resultspassed to theOpperator.With this flag, the depletion restart python script can now be exactly the same as the initial script, just with a
continue_timesteps = Trueflag and aprev_resultsobject loaded from adepletion_statepoint.h5passed to theOperator. It could contain more timesteps at the end too, but the only requirement is that the data matches what is in theOperatorprovided to theIntegratorfor all the existing steps in the results.This PR does not eliminate any of the existing capability of the depletion API, so all the old use cases/syntax for restarts remain. The flag is optional and defaults to
Falseso no one will need to update past scripts with this change.Checklist
I have run clang-format (version 15) on any C++ source files (if applicable)