Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OpenMC depletion settings to input file #177

Merged
merged 25 commits into from
Jan 19, 2023

Conversation

yardasol
Copy link
Contributor

@yardasol yardasol commented Nov 28, 2022

Summary of changes

This PR expands the inputfile JSON schema to enable specifying OpenMC depletion settings.
This PR also adds options to the inputfile JSON schema to specify timestep type (cumulative or stepwise) and units, as well as machinery to process these new inputs.
This PR also adds default values to the inputfile JSON schema, and a class to process these default values.

Specifically, this PR:

  • Adds, removes, or modifies the following input parameters:
    • Depcode
      • exec_path: adds a default value
        • sss2 for codename == "serpent"
        • openmc_deplete.py for codename == "openmc"
      • num_depsteps -> n_depletion_steps
      • For codename == 'openmc':
        • (new) -> chain_file_path
        • (new) -> depletion_settings
    • Simulation
      • db_name: adds a default value of saltproc_results.h5
      • restart_flag: adds a default value of false
      • adjust_geo: adds a default value of false
    • Reactor
      • dep_step_length_cumulative -> depletion_timesteps
      • (new) -> timestep_units
      • (new) -> timestep_type
  • Removes input variables from input files that are equal to their defaults
  • Adds machinery to SerpentDepcode.set_power_load() to enable use of the new time step parameters.
  • Consistency changes to related files and tests

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Required for Merging

  • I have read the CONTRIBUTING document.
  • My code follows the code style of this project.
  • My change requires a change to the documentation.
    • I have updated the documentation accordingly.
  • My change is a source code change
    • I have added/modified tests to cover my changes
    • I have explained why my change does not require new/modified tests
  • My change is a user-facing change
    • I have recorded my changes in the changelog for the upcoming release
  • My change is exclusively related to the repository (e.g. GitHub actions workflows, PR/issue templates, etc.)
    • I have verified or justified that my change will work as intended.
  • All new and existing tests passed.
    • CI tests pass
    • Local tests pass (including Serpent2 integration tests)

Associated Issues and PRs

Associated Developers

  • Dev: @

Checklist for Reviewers

Reviewers should use this link to get to the
Review Checklist before they begin their review.

@yardasol yardasol mentioned this pull request Dec 5, 2022
17 tasks
@yardasol yardasol force-pushed the openmc-depletion-settings branch 2 times, most recently from bec77b4 to a33d3c9 Compare December 6, 2022 17:29
@yardasol yardasol requested review from samgdotson, abachma2, munkm and LukeSeifert and removed request for samgdotson December 9, 2022 18:31
@yardasol yardasol marked this pull request as ready for review December 9, 2022 18:31
Copy link
Contributor

@LukeSeifert LukeSeifert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a few questions and pointed out a few typos I noticed, but overall looks good.

@@ -0,0 +1,21 @@
from jsonschema import Draft202012Validator, validators

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a comment here describing what this is used for

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean a doc string for extend_with_default?

saltproc/app.py Outdated
@@ -12,6 +12,7 @@

from saltproc import SerpentDepcode, OpenMCDepcode, Simulation, Reactor
from saltproc import Process, Sparger, Separator, Materialflow
from ._schema_default import DefaultValidatingValidator
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come this is ._schema_default instead of _schema_default?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is because _schema_default is not a module. Maybe @munkm can chime in.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it just means you're importing from the current directory. However, if it's a member of saltproc you should be able to do from saltproc._schema_default import DefaultValidatingValidator

Separately, is there a more descriptive or less self-referential name for this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, let me try DefaultFillingValidator

saltproc/app.py Outdated
except jsonschema.exceptions.ValidationError:
print("Your input file is improperly structured.\
Please see saltproc/tests/test.json for an example.")

j = obj
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not continue using obj instead of switching back to j notation?

saltproc/app.py Outdated Show resolved Hide resolved
saltproc/app.py Outdated Show resolved Hide resolved
saltproc/openmc_depcode.py Outdated Show resolved Hide resolved
saltproc/openmc_depcode.py Show resolved Hide resolved
@@ -63,12 +62,18 @@ def parse_arguments():
settings=settings,
tallies=tallies)

with open(args.depletion_settings) as f:
depletion_settings = {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like this line does anything

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does. It initializes the depletion_settings dictionary. I think we need to do this so we can get the value provided by depletion_settings = json.load(f) inside the with block on line 66-67 in openmc_deplete.py, but maybe I'm wrong?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You definitely do not need to do this, you're just overwriting an empty dictionary with another dictionary.

Suggested change
depletion_settings = {}

The situation would be different if you were, say, combining dictionaries. But that doesn't appear to be the case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay

Comment on lines 35 to 41
simulation = _create_simulation_object(object_input[1], depcode, 1, 1)
#db_path=str(
# cwd /
# 'serpent_data' /
# 'tap_reference_db.h5'))

reactor = _create_reactor_object(object_input[2])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding extra variables i.e. simulation_object = object_input[1], that way its clearer what is being pulled from object_input

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay

Comment on lines +25 to +28
old_db_path = simulation.db_path
simulation.db_path = str(Path(simulation.db_path).parents[1] / 'tap_reference_db.h5')
assert simulation.read_k_eds_delta(7) is False
simulation.db_path = old_db_path
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come the db_path needs to be updated here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency if we ever add more tests to test_simulation.py.

@yardasol
Copy link
Contributor Author

@abachma2 @munkm @samgdotson bump

Copy link
Contributor

@LukeSeifert LukeSeifert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have a few things I wasn't certain about, but overall looks good.

Comment on lines +44 to +59
Restart simulation from the step when it stopped?

:type:
``boolean``

:default:
``false``


.. _adjust_geo_property:

``adjust_geo``
--------------

:description:
switch to another geometry when keff drops below 1?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come these are questions? Also, switch should be capitalized

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are questions that the variable is the answer to. Maybe that is confusing though?

saltproc/app.py Outdated
try:
jsonschema.validate(instance=j, schema=v)
DefaultValidatingValidator(schema).validate(input_parameters)
#jsonschema.validate(instance=j, schema=v)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be removed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch/

saltproc/app.py Outdated
else:
raise ValueError(
f'{depcode_input["codename"]} '
'is not a supported depletion code')
f'{codename} is not a supported depletion code.'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see codename defined in this function, thought I do see depcode_input["codename"]. Consider changing back to match rest of if statement, or adding in a codename= statement prior to the if statements

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch

saltproc/app.py Outdated
Comment on lines 249 to 259
if codename == 'openmc':
depletion_settings = depcode_input.pop('depletion_settings')
chain_file_path = depcode_input.pop('chain_file_path')

depcode = depcode(**depcode_input)

if codename == 'openmc':
depcode.chain_file_path = chain_file_path
depcode.depletion_settings = depletion_settings

depcode_input['codename'] = codename
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come this moved from handling OpenMC and Serpent to only OpenMC? Also, the separation of the if statements here seems a bit strange. Can this be rewritten into a single if statement? Consider adding a bit more information to the docstring

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has to do with the SaltProc input file. For Serpent runs, the depcode_input dictionary consists exclusively of valid keyword arguments for the SerpentDepcode.__init__() function. However, if we are doing an OpenMC run, there are additional key-value pairs in the depcode_input dictionary (depletion_settings and chain_file_path) that will cause an error if we run depcode(**depcode_input) without removing them first. However, I now realize what I really should do is just add these variables as optional keyword arguments to OpenMCDepcode.__init__().

saltproc/app.py Outdated
Comment on lines 285 to 287
Process SaltProc reactor class input parameters based on the value and
data type of the `num_depsteps` parameter, and throw errors if the input
data type of the `n_depletion_steps` parameter, and throw errors if the input
parameters are incorrect.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider mentioning the added codename parameter in this docstring

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

saltproc/app.py Outdated Show resolved Hide resolved
"default": false}
},
"default": {},
"required": ["sim_name", "db_name"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come db_name is still required? It is given a default value

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.

Copy link
Contributor

@samgdotson samgdotson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly cosmetic changes. However, there is one issue where the "cumulative" case is confusing.

@@ -0,0 +1,21 @@
from jsonschema import Draft202012Validator, validators

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean a doc string for extend_with_default?

saltproc/app.py Outdated
@@ -12,6 +12,7 @@

from saltproc import SerpentDepcode, OpenMCDepcode, Simulation, Reactor
from saltproc import Process, Sparger, Separator, Materialflow
from ._schema_default import DefaultValidatingValidator
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it just means you're importing from the current directory. However, if it's a member of saltproc you should be able to do from saltproc._schema_default import DefaultValidatingValidator

Separately, is there a more descriptive or less self-referential name for this function?

@@ -30,22 +34,22 @@ def run():
simulation.check_restart()
# Run sequence
# Start sequence
for dep_step in range(len(msr.dep_step_length_cumulative)):
print("\n\n\nStep #%i has been started" % (dep_step + 1))
for step_idx in range(len(msr.depletion_timesteps)):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a difference between the step index and the step number? I would just call it step. Though this is purely a stylistic difference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just trying to be as explicit as possible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I don't see a difference but it doesn't hurt.

saltproc/app.py Outdated
Comment on lines 194 to 196
if depcode_input['codename'] == 'serpent':
depcode_input['template_input_file_path'] = str((
input_path /
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if depcode_input['codename'] == 'serpent':
depcode_input['template_input_file_path'] = str((
input_path /
if codename == 'serpent':
depcode_input['template_input_file_path'] = str((
input_path /

saltproc/app.py Outdated

depcode_input['codename'] = depcode_input['codename'].lower()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to be

Suggested change
depcode_input['codename'] = depcode_input['codename'].lower()
codename = depcode_input['codename'].lower()

?

saltproc/app.py Outdated
Comment on lines 310 to 311
ts = list(np.diff(depletion_timesteps))
depletion_timesteps = depletion_timesteps[0] + ts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ts = list(np.diff(depletion_timesteps))
depletion_timesteps = depletion_timesteps[0] + ts
depletion_timesteps = np.cumsum(depletion_timesteps)

I agree with @LukeSeifert that the expected result is unclear. Possibly use np.cumsum()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually coded improperly now that I look at it. What we are supposed to be doing here is converting a cumulative timeseries (1s, 3s, 5s) to a stepwise timeseries (1s, 2s, 2s). But I eneterd this wrong which explains why we were confused. I seem to be missing tests for this function as well so I'll add those

@@ -63,12 +62,18 @@ def parse_arguments():
settings=settings,
tallies=tallies)

with open(args.depletion_settings) as f:
depletion_settings = {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You definitely do not need to do this, you're just overwriting an empty dictionary with another dictionary.

Suggested change
depletion_settings = {}

The situation would be different if you were, say, combining dictionaries. But that doesn't appear to be the case.

def serpent_depcode(cwd):
"""SerpentDepcode object for unit tests"""
def serpent_runtime(cwd, tmpdir_factory):
"""SaltProc objects for Serpent unit tests"""
saltproc_input = str(cwd / 'serpent_data' / 'tap_input.json')
_, _, _, object_input = read_main_input(saltproc_input)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've discussed this before, I think. I don't like the practice of using underscores as variable names. They should have names, even if you're not using them. Also, consider that you might forget the return variables are for this function. Yes you could look it up, but why waste the energy?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I think I can address this in a way that satisfies both of us.

Comment on lines 35 to 41
simulation = _create_simulation_object(object_input[1], depcode, 1, 1)
#db_path=str(
# cwd /
# 'serpent_data' /
# 'tap_reference_db.h5'))

reactor = _create_reactor_object(object_input[2])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree

Copy link
Contributor

@LukeSeifert LukeSeifert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything looks good to me.

@yardasol
Copy link
Contributor Author

@samgdotson I made some changes based on your comments, and added some tests for additional code coverage. Let me know what you think

@yardasol
Copy link
Contributor Author

Looping @LukeSeifert back in because I added some new stuff.

Copy link
Contributor

@samgdotson samgdotson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making those other changes -- I'm curious about the nested functions.

Comment on lines +3 to +18
def extend_with_default(validator_class):
validate_properties = validator_class.VALIDATORS["properties"]

def set_defaults(validator, properties, instance, schema):
for property, subschema in properties.items():
if "default" in subschema:
instance.setdefault(property, subschema["default"])

for error in validate_properties(
validator, properties, instance, schema,
):
yield error

return validators.extend(
validator_class, {"properties" : set_defaults},
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't catch this before, but what is the purpose of having nested function definitions? Why not break this into two functions that can both be unit-tested?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure. I pulled this block of code from here

Copy link
Contributor Author

@yardasol yardasol Jan 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@samgdotson I actually created an issue to look into this as there is a bug that exists with the current setup.

@@ -30,22 +34,22 @@ def run():
simulation.check_restart()
# Run sequence
# Start sequence
for dep_step in range(len(msr.dep_step_length_cumulative)):
print("\n\n\nStep #%i has been started" % (dep_step + 1))
for step_idx in range(len(msr.depletion_timesteps)):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I don't see a difference but it doesn't hurt.

Copy link
Contributor

@samgdotson samgdotson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@samgdotson samgdotson merged commit 5b4e60c into arfc:master Jan 19, 2023
github-actions bot pushed a commit that referenced this pull request Jan 19, 2023
…epletion-settings

Add OpenMC depletion settings to input file 5b4e60c
github-actions bot pushed a commit to khurrumsaleem/saltproc that referenced this pull request Jan 24, 2023
…mc-depletion-settings

Add OpenMC depletion settings to input file 5b4e60c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature: Add machinery to specify depletion settings in the main input file.
3 participants