Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion pypact/input/inputdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,8 +427,18 @@ def _deserialize(self, f):
"""
self.reset()

lines = f.readlines()
lines = iter(f.readlines()) # Convert lines to an iterator
in_mass_section = False
irradiation_active = True # Flag to track if irradiation schedule is active
flux_set = False # Flag to ensure FLUX is set to a non-zero value before the first irradiation step

time_unit_to_seconds = {
"SECS": 1,
"MINS": 60,
"HOURS": 3600,
"DAYS": 86400,
"YEARS": 31536000
}

for line in lines:
line = line.strip()
Expand Down Expand Up @@ -458,3 +468,44 @@ def _deserialize(self, f):
if len(parts) != 2:
raise PypactInvalidOptionException("Invalid DENSITY line format.")
self.setDensity(float(parts[1]))

elif line.startswith("FLUX") and irradiation_active:
# Parse the FLUX line
parts = line.split()
if len(parts) != 2:
raise PypactInvalidOptionException("Invalid FLUX line format.")
fluxAmp = float(parts[1])

# Ensure FLUX is set to a non-zero value before the first irradiation step
if not flux_set and fluxAmp <= 0.0:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think you can do just decay in F-II without any ZERO keyword, but this needs to be confirmed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Looking into this and I think yes FISPACT does decay without the ZERO keyword. Just setting the FLUX to 0.0 and the material decays. What ZERO does in addition to setting FLUX to 0.0 is to switch from irradiation to cooling schedule. So I've added a build up of cooling schedule to this PR as well. Sorry for the scope creep.

https://fispact.ukaea.uk/wiki/Keyword:ZERO
https://fispact.ukaea.uk/wiki/Keyword:FLUX

raise PypactInvalidOptionException("FLUX must be set to a non-zero positive value before the first irradiation step.")
flux_set = True

# If FLUX is 0.0, skip TIME parsing
if fluxAmp == 0.0:
self.addIrradiation(0.0, fluxAmp)
continue

# Look ahead for the TIME line
next_line = next(lines, None)
if next_line and next_line.strip().startswith("TIME"):
time_parts = next_line.strip().split()
if len(time_parts) != 3:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I am not sure if it's as simple as that.

I need to re-read the documentation but I think you can have situations like:

TIME 0.1 YEARS ATOMS

and

TIME 60

and even when the ATOMS is on the next line, such as

TIME 0.1
ATOMS

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

confirming this is a situation I've just seen in the new test file I've added

FLUX 1.116E+10
ATOMS

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

All these cases are now covered and represented in the test suite input files

raise PypactInvalidOptionException("Invalid TIME line format.")
time_value = float(time_parts[1])
time_unit = time_parts[2]
if time_unit not in time_unit_to_seconds:
raise PypactInvalidOptionException(f"Unsupported TIME unit: {time_unit}")
# Convert time to seconds
timeInSecs = time_value * time_unit_to_seconds[time_unit]
# Add the irradiation schedule
self.addIrradiation(timeInSecs, fluxAmp)
else:
raise PypactInvalidOptionException("TIME line missing after FLUX line.")

elif line.startswith("ZERO"):
# Ensure FLUX is set to zero before using ZERO
if not flux_set or self._irradschedule[-1][1] != 0.0:
raise PypactInvalidOptionException("FLUX must be set to zero before using the ZERO keyword.")
# Stop processing irradiation schedule
irradiation_active = False
2 changes: 2 additions & 0 deletions reference/test.i
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ ATOMS
<< irradiation schedule >>
FLUX 1100000000000000.0
TIME 300.0 SECS
FLUX 42.0
TIME 200.0 SECS
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we're going to need a lot more test cases for this.
Unfortunately, the system tests are not available, but perhaps the workshops can provide some valuable test cases.

Copy link
Copy Markdown
Contributor Author

@shimwell shimwell May 23, 2025

Choose a reason for hiding this comment

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

Added 5 test input files from the workshop and added them to the test for irradiation and cooling schedule checking ✔️

ATOMS
<< end of irradiation >>
FLUX 0.0
Expand Down
18 changes: 18 additions & 0 deletions tests/input/inputfiletest.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,21 @@ def test_reading_in_density(self):
pp.from_file(ff, 'reference/test.i')

assert ff._density == 19.5


def test_reading_flux_and_time(self):
ff = pp.InputData()
pp.from_file(ff, 'reference/test.i')

# Expected irradiation schedule (time in seconds, flux amplitude)
expected_schedule = [
(300.0, 1.1e15),
(200.0, 42.0),
(0.0, 0.0),
]

# Assert the irradiation schedule matches the expected results
assert len(ff._irradschedule) == len(expected_schedule), "Irradiation schedule length mismatch"
for i, (time, flux) in enumerate(expected_schedule):
assert ff._irradschedule[i][0] == time, f"Time mismatch at index {i}"
assert ff._irradschedule[i][1] == flux, f"Flux mismatch at index {i}"