D1S-UNED files#
Reaction file#
The complete API can be found at f4enix.input.d1suned.ReactionFile
Reaction files (default name ‘reac’) contain all the reaction pathways that should be considered during a D1S-UNED simulation. They are implemented in F4Enix as a simple list of single reactions.
from f4enix.input.d1suned import Reaction, ReactionFile
from f4enix.core.irradiation import Nuclide
# Generate a single reaction
reac = Reaction(Nuclide(1001, lib="91c"), 102, Nuclide(1002, lib="91c"), comment='fake reaction')
print(reac)
# It can also be generated from a formatted string
reac_str = "1001.92c 102 1002.92c # fake reaction"
reac2 = Reaction.from_text(reac_str)
print(reac2)
/home/docs/checkouts/readthedocs.org/user_builds/f4enix/envs/stable/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
parent: H1.91c
MT channel: 102
daughter: H2.91c
comment: fake reaction
parent: H1.92c
MT channel: 102
daughter: H2.92c
comment: # fake reaction
import tempfile
# A reaction file can be generated from a list of reactions and saved
reac_file = ReactionFile([reac])
outpath = tempfile.gettempdir()
reac_file.write(outpath)
# But more often is instantiated directly from an exisiting file
# Note that metastable elements have a '900' added to their zaid number
reac_file = ReactionFile.from_text('reac_fe')
reac_file
Parent MT Daughter Comment
26054.99c 102 26055 Fe55
26054.99c 103 25054 Mn54
26054.99c 107 24051 Cr51
26056.99c 105 25054 Mn54
26056.99c 103 25056 Mn56
26056.99c 16 26055 Fe55
26057.99c 28 25056 Mn56
26057.99c 104 25056 Mn56
26058.99c 102 26059 Fe59
26058.99c 105 25056 Mn56
78195.99c 304 78195900 Pt195m
# a convenient method is also provided to change the activation library to use
reac_file.change_lib('98c')
print(reac_file)
# and it is also possible to get a list of parents
print('Parent list:')
reac_file.get_parents()
Parent MT Daughter Comment
26054.98c 102 26055 Fe55
26054.98c 103 25054 Mn54
26054.98c 107 24051 Cr51
26056.98c 105 25054 Mn54
26056.98c 103 25056 Mn56
26056.98c 16 26055 Fe55
26057.98c 28 25056 Mn56
26057.98c 104 25056 Mn56
26058.98c 102 26059 Fe59
26058.98c 105 25056 Mn56
78195.98c 304 78195900 Pt195m
Parent list:
[Fe54.98c, Fe56.98c, Fe57.98c, Fe58.98c, Pt195.98c]
Note that the parents are Nuclide objects
parents = reac_file.get_parents()
print(type(parents[0]))
<class 'f4enix.core.irradiation.Nuclide'>
Irradiation file#
The complete API can be found at f4enix.input.d1suned.IrradiationFile`
Irradiation files contain information related to the time correction factors to be used in the D1S-UNED calculation.
from f4enix.input.d1suned import Irradiation, IrradiationFile
# generate a single irradiation from scratch
irr = Irradiation(Nuclide.from_formula("Fe59"), 1.8e3, ['4e3', '5e3'], comment='Fake irr')
print(irr)
Daughter: Fe59
lambda [1/s]: 1800.0
times: ('4e3', '5e3')
comment: Fake irr
import tempfile
# More often an existing irradiation file is parsed
irrad_file = IrradiationFile.from_text('irr_test')
# eliminate the last irradiation and save
irrad_file.irr_schedules = irrad_file.irr_schedules[:-1]
irrad_file.write(tempfile.gettempdir())
# get the list of irradiation schedules
irrad_file.irr_schedules
[['24051', '2.896e-07', '5.982e+00', '5.697e+00', 'Cr51'],
['25054', '2.570e-08', '5.881e+00', '1.829e+00', 'Mn54'],
['26055', '8.031e-09', '4.487e+00', '6.364e-01', 'Fe55'],
['27062', '7.702e-03', '1.336e+00', '1', 'Co62'],
['27062900', '8.305e-04', '4.151e-01', '1', 'Co62m']]
A reaction file can also be computed directly using the TCF_Computer class to calculate the time correction factors for the different nuclides at different irradiation scenarios.
from f4enix.core.irradiation import Pulse, TIME_UNITS, IrradiationScenario, Nuclide
pulses = (
[Pulse(1, 1e10, TIME_UNITS.DAY), Pulse(2, 0, TIME_UNITS.DAY)]*4
)
irr_scenario1 = IrradiationScenario(pulses)
pulses = (
[Pulse(1, 1e10, TIME_UNITS.DAY), Pulse(2, 0, TIME_UNITS.DAY)]*100
)
irr_scenario2 = IrradiationScenario(pulses)
daughter_nuclides = [Nuclide.from_formula("Co60"), Nuclide.from_formula("Cr51")]
irr_file2 = IrradiationFile.from_irradiation_schedules(
daughter_nuclides,
[irr_scenario1, irr_scenario2],
norm=1e10
)
irr_file2.irr_schedules
[['27060', '4.167e-09', '1.437e-03', '3.411e-02', 'Co60'],
['24051', '2.896e-07', '8.430e-02', '3.249e-01', 'Cr51']]
F4Enix also supports the use of IRS cards. The procedure to create an irrad file would be the same but nuclides using it should be flagged.
daughter_nuclides = [Nuclide.from_formula("irsCo60"), Nuclide.from_formula("Co60")]
irr_file3 = IrradiationFile.from_irradiation_schedules(
daughter_nuclides,
[irr_scenario1],
scale_IRS={'irsCo60': [0.5, 3, 10]}, # example of scaling IRS data
norm=1e10
)
irr_file3.irr_schedules
[['99927060', '4.167e-09', '7.183e-04', '4.310e-03', '1.437e-02', 'irsCo60'],
['27060', '4.167e-09', '1.437e-03', '1.437e-03', '1.437e-03', 'Co60']]
# auxiliary method to retrieve a specific irradiation
print(irrad_file.get_irrad('24051'))
# auxiliary method to get all daughters
print(irrad_file.get_daughters())
Daughter: Cr51
lambda [1/s]: 2.896e-07
times: ('5.982e+00', '5.697e+00')
comment: Cr51
[Cr51, Mn54, Fe55, Co62, Co62m]
You can also add/remove irradiation schedules and modify them:
new_times = {
"24051": ["5.982e+00", "5.697e+00"],
"25054": ["5.881e+00", "1.829e+00"],
"26055": ["4.487e+00", "6.364e-01"],
"27062": ["1.336e+00", "4.151e-01"],
"27062900": ["4.151e-01", "4.151e-01"],
}
irrad_file.add_irradiation_times(new_times)
print(irrad_file.get_irrad('24051'))
Daughter: Cr51
lambda [1/s]: 2.896e-07
times: ('5.982e+00', '5.697e+00', '5.982e+00', '5.697e+00')
comment: Cr51
irrad_file.irr_schedules[0].modify_time_val(3, 4.56)
print(irrad_file.get_irrad('24051'))
Daughter: Cr51
lambda [1/s]: 2.896e-07
times: ('5.982e+00', '5.697e+00', '5.982e+00', '4.560e+00')
comment: Cr51
irrad_file.remove_irradiation_time(3)
print(irrad_file.get_irrad('24051'))
Daughter: Cr51
lambda [1/s]: 2.896e-07
times: ('5.982e+00', '5.697e+00', '5.982e+00')
comment: Cr51
D1S MCNP input#
The D1S-UNED MCNP input is exactly the same as a normal MCNP input with a few
additional cards. In F4Enix is implemented as a child of the Input class
and it includes as attributes also an IrradiationFile and ReactionFile
objects. There are many ways to initialize this object and the simplest one
is when all text input files are aleady available and can be parsed.
from f4enix.input.d1suned import ReactionFile, IrradiationFile
from f4enix.input.MCNPinput import D1S_Input
# Simplest case, all text input are already present and can be parsed
d1s_inp = D1S_Input.from_input('d1stest.i', irrad_file='irr_test',
reac_file='reac_fe')
print(type(d1s_inp.reac_file))
print(type(d1s_inp.irrad_file))
<class 'f4enix.input.d1suned.ReactionFile'>
<class 'f4enix.input.d1suned.IrradiationFile'>
Nevertheless, F4Enix can also help in the automatic generation of irrad and react file. An example can be the following: let’s suppose that a number of daughters have been identified as the most important radioactive isotopes of interest for a specific SDDR computation. A reaction file can be built automatically that will include all the reactions available in a specific activation library that lead to one of the listed daughters. Only parents that are included in the materials of the MCNP input will be considered.
from f4enix.input.libmanager import LibManager
# Parse only the MCNP input and the irrad file containing the list of daughters
# to be considered
d1s_inp = D1S_Input.from_input('d1stest.i', irrad_file='irr_test')
print('Daughters:')
print(d1s_inp.irrad_file.get_daughters())
# generate the reaction file with the default Library Manager and the 99c lib.
lm = LibManager()
d1s_inp.get_reaction_file(lm, '99c')
d1s_inp.reac_file
Daughters:
[Cr51, Mn54, Fe55, Co62, Co62m, Fe59]
Parent MT Daughter Comment
24050.99c 102 24051 Cr50.99c -> Cr51
24052.99c 16 24051 Cr52.99c -> Cr51
25055.99c 16 25054 Mn55.99c -> Mn54
26054.99c 102 26055 Fe54.99c -> Fe55
26054.99c 103 25054 Fe54.99c -> Mn54
26054.99c 107 24051 Fe54.99c -> Cr51
26056.99c 105 25054 Fe56.99c -> Mn54
26056.99c 16 26055 Fe56.99c -> Fe55
26058.99c 102 26059 Fe58.99c -> Fe59
27059.99c 103 26059 Co59.99c -> Fe59
28058.99c 112 25054 Ni58.99c -> Mn54
28062.99c 107 26059 Ni62.99c -> Fe59
If no decision has been taken on which daughters should be considered, F4Enix also allows to have a list of all the possible reactions that are foreseen from a specified activation library where the parent isotope is listed an at least one material of the MCNP input.
# parse only the MNCP input
d1s_inp = D1S_Input.from_input('d1stest.i')
lm = LibManager()
# this is a list of reactions and can be directly used to initialize a reaction
# file if needed.
d1s_inp.get_potential_paths(lm, '98c')[:3]
[
parent: Al27.98c
MT channel: 107
daughter: Na24
comment: Al27.98c -> Na24,
parent: Cr50.98c
MT channel: 102
daughter: Cr51
comment: Cr50.98c -> Cr51,
parent: Cr52.98c
MT channel: 16
daughter: Cr51
comment: Cr52.98c -> Cr51]
Another common task could be to translate a d1s input (and reaction file) from a library to another. The first method to do this is a 1 to 1 conversion. This is also available also in a standard MCNP input. This works if the decay pathways of interest (reactions) are available in both libraries. This check is not performed by F4Enix!
d1s_inp = D1S_Input.from_input('d1stest.i', irrad_file='irr_test',
reac_file='reac_fe')
print('before:')
print(d1s_inp.materials['M1'].to_text()[-500:])
# this translates all activated zaid with old library 99c to the new 98c. Also
# the transport library is changed here, from 21c to 31c
new_lib = {'99c': '98c', '21c': '31c'}
lm = LibManager()
d1s_inp.translate(new_lib, lm)
# Check the translation (only a piece of a material)
print('\nafter:')
print(d1s_inp.materials['M1'].to_text()[-500:])
# Manually change also the library in the reaction file
d1s_inp.reac_file.change_lib('98c')
print('\nreac file:')
d1s_inp.reac_file
before:
AB(%)
74183.21c 3.377160E-7 $ WEIGHT(%) AB(%)
74184.21c 7.231040E-7 $ WEIGHT(%) AB(%)
74186.99c 6.709480E-7 $ WEIGHT(%) AB(%)
82206.21c 4.048800E-7 $ WEIGHT(%) AB(%)
82207.21c 3.712800E-7 $ WEIGHT(%) AB(%)
82208.21c 8.803200E-7 $ WEIGHT(%) AB(%)
83209.21c 1.660000E-6 $ WEIGHT(%) AB(%)
after:
%) 14.327
74184.31c 7.231040E-7 $ W-184 WEIGHT(%) 0.00096798 AB(%) 30.677
74186.98c 6.709480E-7 $ W-186 WEIGHT(%) 0.00096798 AB(%) 28.464
82206.31c 4.048800E-7 $ Pb-206 WEIGHT(%) 0.00076688 AB(%) 24.442
82207.31c 3.712800E-7 $ Pb-207 WEIGHT(%) 0.00076688 AB(%) 22.414
82208.31c 8.803200E-7 $ Pb-208 WEIGHT(%) 0.00076688 AB(%) 53.144
83209.31c 1.660000E-6 $ Bi-209 WEIGHT(%) 0.00077488 AB(%) 100.0
reac file:
Parent MT Daughter Comment
26054.98c 102 26055 Fe55
26054.98c 103 25054 Mn54
26054.98c 107 24051 Cr51
26056.98c 105 25054 Mn54
26056.98c 103 25056 Mn56
26056.98c 16 26055 Fe55
26057.98c 28 25056 Mn56
26057.98c 104 25056 Mn56
26058.98c 102 26059 Fe59
26058.98c 105 25056 Mn56
78195.98c 304 78195900 Pt195m
In addition to this, a new translating method has been defined for the
D1S_Input object. Let’s suppose that this is the first time a D1S-INPUT
is generated for a specific application. Once irradiation and reaction files
have been defined, the MCNP input can be translated specifying an activation
and a transport lib. The activation lib will be automatically assigned to
all parents indicated the reac file.
# reset everything to just one lib
d1s_inp.translate('31c', lm)
print('before:')
print(d1s_inp.materials['M1'].to_text()[2000:2500])
# smart translate
d1s_inp.smart_translate('99c', '00c', lm)
print('\nafter:')
print(d1s_inp.materials['M1'].to_text()[2000:2500])
before:
23050.31c 3.400000E-6 $ V-50 WEIGHT(%) 0.15475 AB(%) 0.25
23051.31c 1.356600E-3 $ V-51 WEIGHT(%) 0.15475 AB(%) 99.75
24050.31c 6.343700E-3 $ Cr-50 WEIGHT(%) 16.957 AB(%) 4.345
24052.31c 1.223320E-1 $ Cr-52 WEIGHT(%) 16.957 AB(%) 83.789
24053.31c 1.387150E-2 $ Cr-53 WEIGHT(%) 16.957 AB(%) 9.501
24054.31c 3.452900E-3 $ Cr-54 WEIGHT(%) 16.957 AB(%) 2.365
25055.31c 1.420000E-2
after:
23050.00c 3.400000E-6 $ V-50 WEIGHT(%) 0.15475 AB(%) 0.25
23051.00c 1.356600E-3 $ V-51 WEIGHT(%) 0.15475 AB(%) 99.75
24050.00c 6.343700E-3 $ Cr-50 WEIGHT(%) 16.957 AB(%) 4.345
24052.00c 1.223320E-1 $ Cr-52 WEIGHT(%) 16.957 AB(%) 83.789
24053.00c 1.387150E-2 $ Cr-53 WEIGHT(%) 16.957 AB(%) 9.501
24054.00c 3.452900E-3 $ Cr-54 WEIGHT(%) 16.957 AB(%) 2.365
25055.00c 1.420000E-2
/home/docs/checkouts/readthedocs.org/user_builds/f4enix/envs/stable/lib/python3.10/site-packages/f4enix/input/libmanager.py:446: UserWarning: The Default library 81c was used for zaid 1001
warnings.warn(MSG_DEFLIB.format(self.defaultlib, zaid))
To conclude, two other cards that are needed for a D1S-UNED run can be automatically generated using F4Enix. The PIKMT card and the FU card to track the contribution of parents/daughters/cells to a specific tally. If you provided irradiation/reaction files, you can automatically generate the daughters/fathers contribution in a tally respectively. You can also automatically add the SDDR dose function to an existing tally.
d1s_inp = D1S_Input.from_input('d1stest.i', irrad_file='irr_test',
reac_file='reac_fe')
# add a PIKMT card to the input based on reac file
d1s_inp.add_PIKMT_card()
print(d1s_inp.other_data['PIKMT'].card())
# Add a FU card to a tally
d1s_inp.add_track_contribution('F124', [26054, 74186], who='parent')
print(d1s_inp.other_data['F124'].card())
# Add a FU card to a tally for cell contributions
d1s_inp.add_track_contribution('F14', [200, 400], who='cell')
print(d1s_inp.other_data['F14'].card())
print(d1s_inp.other_data['FT14'].card())
# Add a FU card to a tally for daughter contributions
d1s_inp.add_track_contribution('F34', [28058, 28060, 73182], who='daughter')
# Add the DE/DF function for SDDR
d1s_inp.add_SDDR_dose_function("F34")
print(d1s_inp.other_data['F34'].card())
print(d1s_inp.other_data['DE34'].card())
print(d1s_inp.other_data['DF34'].card())
# Take all daugthers from the irradiation file and add them to a tally as userbins
d1s_inp.add_daughter_contribution_from_irr("F44")
print(d1s_inp.other_data['F44'].card())
# Take all parents from the reaction file and add them to a tally as userbins
d1s_inp.add_parent_contribution_from_reac("F54")
print(d1s_inp.other_data['F54'].card())
PIKMT
26054 0
26056 0
26057 0
26058 0
78195 0
c
C ---------------- Dose Calculation --------------------------------------------
C tally * ICF * DF * Sv/pSv * s/h
C [p/cm^2/#]* 1.0714e17 [#/s]) * [pSv/(p/cm^2)] * 1e-12 [Sv/pSv] * 3600 [s/h]
C ------------------------------------------------------------------------------
F124:p 10 11 12 13
FU124 0
-26054
-74186
c
c
C ---------------------- Gamma Flux Tallies ------------------------------------
C Tally * FM -> [p/cm^2/#] * [#/s] = [p/cc/s]
C ------------------------------------------------------------------------------
c Control gamma flux tally
F14:p 10
FU14 0
200
400
FT14 SCD
C
F34:p 11
FU34 0
28058
28060
73182
DE34 0.01 0.015 0.02 0.03 0.04 0.05
0.06 0.07 0.08 0.10 0.15 0.20
0.3 0.40.5 0.6 0.8 1.0
2.0 4.0 6.0 8.0 10.0
DF34 0.0485 0.1254 0.2050 0.2999 0.3381 0.3572
0.3780 0.4066 0.4399 0.5172 0.7523 1.0041
1.5083 1.9958 2.4657 2.9082 3.7269 4.4834
7.4896 12.0153 15.9873 19.9191 23.7600
C
F44:p 12
FU44 0
24051
25054
26055
27062
27062900
26059
C
F54:p 13
FU54 0
-26054.99c
-26056.99c
-26057.99c
-26058.99c
-78195.99c