Skip to content

Commit c48efb8

Browse files
committed
Change expected_impurities to excluded_impurities
Closes IMAS plasma composition surprising behaviour #1789 Parse all ions by default to avoid ignoring ions without the user knowing Update imas sim_test example correctly parse ions Slight change of error message Add comment for str(ion) cast Change default main_ion_symbols to None separate function to validate main_ions presence
1 parent 5127498 commit c48efb8

File tree

4 files changed

+74
-34
lines changed

4 files changed

+74
-34
lines changed

torax/_src/imas_tools/input/core_profiles.py

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ def profile_conditions_from_IMAS(
117117
def plasma_composition_from_IMAS(
118118
ids: ids_toplevel.IDSToplevel,
119119
t_initial: float | None = None,
120-
expected_impurities: Collection[str] | None = None,
121-
main_ions_symbols: Collection[str] = constants.HYDROGENIC_IONS,
120+
excluded_impurities: Collection[str] | None = None,
121+
main_ions_symbols: Collection[str] | None = None,
122122
) -> Mapping[str, Any]:
123123
"""Returns dict with args for plasma_composition config from a given ids.
124124
@@ -140,13 +140,12 @@ def plasma_composition_from_IMAS(
140140
initial time will be the time of the first time slice of the ids. Else all
141141
time slices will be shifted such that the first time slice has time =
142142
t_initial.
143-
expected_impurities: Optional arg to check that the input IDS contains the
144-
wanted impurity species and raise and error if not, or if its density is
145-
empty.
143+
excluded_impurities: Optional arg to specify which impurities from the IDS
144+
should not be parsed.
146145
main_ions_symbols: collection of ions to be used to define the main_ion
147-
mixture. If value is not the default one, will check that the given ions
148-
exist in the IDS and their density is filled. Default are hydrogenic ions
149-
H, D, T.
146+
mixture. If value is not None, will check that the given ions
147+
exist in the IDS and their density is filled. If not explicitly provided,
148+
will parse H, D, T as main ions.
150149
151150
Returns:
152151
The updated fields read from the IDS that can be used to completely or
@@ -155,12 +154,23 @@ def plasma_composition_from_IMAS(
155154
profiles_1d, rhon_array, time_array = loader.get_time_and_radial_arrays(
156155
ids, t_initial
157156
)
158-
# Check that the expected ions are present in the IDS
159-
ids_ions = [ion.name for ion in profiles_1d[0].ion if ion.density]
160-
if expected_impurities:
161-
_check_expected_ions_presence(ids_ions, expected_impurities)
162-
if main_ions_symbols is not constants.HYDROGENIC_IONS:
163-
_check_expected_ions_presence(ids_ions, main_ions_symbols)
157+
# Parse only ions with non empty density and not in excluded_impurities.
158+
if excluded_impurities:
159+
parsed_ions = [
160+
ion.name
161+
for ion in profiles_1d[0].ion
162+
if ion.density and ion.name not in excluded_impurities
163+
]
164+
else:
165+
parsed_ions = [ion.name for ion in profiles_1d[0].ion if ion.density]
166+
# main_ions_symbols not explicitly provided: no validation of main ions and
167+
# value set to hydrogenic ions.
168+
if main_ions_symbols is None:
169+
main_ions_symbols = constants.HYDROGENIC_IONS
170+
# main_ions_symbols explicitly provided: validate ions presence in IDS.
171+
else:
172+
_validate_main_ions_presence(parsed_ions, main_ions_symbols)
173+
_validate_ids_ions(parsed_ions)
164174

165175
Z_eff = (
166176
time_array,
@@ -177,7 +187,7 @@ def plasma_composition_from_IMAS(
177187
# that instead of using a try-except.
178188
# Case ids is plasma_profiles in early DDv4 releases.
179189
symbol = str(profiles_1d[0].ion[ion].label)
180-
if symbol in constants.ION_PROPERTIES_DICT.keys():
190+
if symbol in parsed_ions:
181191
# Fill main ions
182192
if symbol in main_ions_symbols:
183193
main_ion_density[symbol] = [
@@ -212,18 +222,38 @@ def plasma_composition_from_IMAS(
212222
}
213223

214224

215-
def _check_expected_ions_presence(
216-
ids_ions: list[str],
217-
expected_ions: Collection[str],
225+
def _validate_ids_ions(
226+
parsed_ions: list[str],
227+
) -> None:
228+
"""Checks if all parsed ions are recognized."""
229+
for ion in parsed_ions:
230+
# ion is casted to str to avoid issues with imas string types.
231+
if str(ion) not in constants.ION_PROPERTIES_DICT.keys():
232+
raise (
233+
KeyError(
234+
f"{ion} is present in the IDS but not a valid TORAX ion. Check"
235+
"typing or add the ion to the excluded_impurities."
236+
)
237+
)
238+
239+
240+
def _validate_main_ions_presence(
241+
parsed_ions: list[str],
242+
main_ion_symbols: Collection[str],
218243
) -> None:
219-
"""Checks that the expected_ions symbols are in the ids_ions."""
220-
for ion in expected_ions:
244+
"""Checks that items in main_ion_symbols are present in the IDS."""
245+
for ion in main_ion_symbols:
221246
if ion not in constants.ION_PROPERTIES_DICT.keys():
222-
raise (KeyError(f"{ion} is not a valid symbol of a TORAX valid ion."))
223-
if ion not in ids_ions:
247+
raise (
248+
KeyError(
249+
f"{ion} is not a valid symbol of a TORAX valid ion. Please"
250+
" check typing of main_ion_symbols."
251+
)
252+
)
253+
if ion not in parsed_ions:
224254
raise (
225255
ValueError(
226-
f"The expected ion {ion} cannot be found in the input"
256+
f"The expected main ion {ion} cannot be found in the input"
227257
" IDS or has no valid data. \n Please check that the IDS is"
228258
" properly filled"
229259
)

torax/_src/imas_tools/input/tests/core_profiles_test.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,9 @@ def test_imas_plasma_composition(self):
115115
path = "core_profiles_ddv4_iterhybrid_rampup_conditions.nc"
116116
core_profiles_in = loader.load_imas_data(path, "core_profiles")
117117
# Indivual ion info empty in the inital IDS so create fake ions data
118-
core_profiles_in.profiles_1d[0].ion.resize(3)
119-
core_profiles_in.profiles_1d[1].ion.resize(3)
120-
core_profiles_in.global_quantities.ion.resize(3)
118+
core_profiles_in.profiles_1d[0].ion.resize(4)
119+
core_profiles_in.profiles_1d[1].ion.resize(4)
120+
core_profiles_in.global_quantities.ion.resize(4)
121121
core_profiles_in.profiles_1d[0].ion[0].name = "D"
122122
core_profiles_in.profiles_1d[0].ion[0].density = [9e19, 3e19]
123123
core_profiles_in.profiles_1d[1].ion[0].density = [9e19, 3e19]
@@ -132,40 +132,47 @@ def test_imas_plasma_composition(self):
132132
core_profiles_in.profiles_1d[1].ion[2].density = (
133133
core_profiles_in.profiles_1d[1].electrons.density / 100
134134
)
135+
core_profiles_in.profiles_1d[0].ion[3].name = "He5"
136+
core_profiles_in.profiles_1d[1].ion[3].name = "He5"
137+
core_profiles_in.profiles_1d[0].ion[3].density = (
138+
core_profiles_in.profiles_1d[0].electrons.density / 100
139+
)
140+
core_profiles_in.profiles_1d[1].ion[3].density = (
141+
core_profiles_in.profiles_1d[1].electrons.density / 100
142+
)
135143

136-
with self.subTest(name="Missing expected impurity."):
144+
with self.subTest(name="Unrecognized impurity not excluded."):
137145
self.assertRaises(
138-
ValueError,
146+
KeyError,
139147
core_profiles.plasma_composition_from_IMAS,
140148
core_profiles_in,
141149
None,
142150
None,
143-
["Xe"],
144151
)
145152
with self.subTest(name="Missing expected main ion."):
146153
self.assertRaises(
147154
ValueError,
148155
core_profiles.plasma_composition_from_IMAS,
149156
core_profiles_in,
150157
None,
158+
["He5"],
151159
["H"],
152-
None,
153160
)
154-
with self.subTest(name="Invalid ion name."):
161+
with self.subTest(name="Invalid main ion name."):
155162
self.assertRaises(
156163
KeyError,
157164
core_profiles.plasma_composition_from_IMAS,
158165
core_profiles_in,
159166
None,
160-
None,
161167
["He5"],
168+
["De"],
162169
)
163170
with self.subTest(name="Test config is properly built."):
164171
plasma_composition_data = core_profiles.plasma_composition_from_IMAS(
165172
core_profiles_in,
166173
t_initial=None,
167174
main_ions_symbols=["D", "T"],
168-
expected_impurities=["Ne"],
175+
excluded_impurities=["He5"],
169176
)
170177
config["plasma_composition"] = plasma_composition_data
171178
config["plasma_composition"]["impurity"]["impurity_mode"] = "n_e_ratios"
17.1 KB
Binary file not shown.

torax/tests/test_data/test_imas_profiles_and_geo.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@
3333
)
3434
imas_data1 = core_profiles.profile_conditions_from_IMAS(imas_profiles1)
3535
imas_data2 = core_profiles.plasma_composition_from_IMAS(
36-
imas_profiles2, t_initial=0.0, expected_impurities=["He3", "Be"]
36+
imas_profiles2,
37+
t_initial=0.0,
38+
excluded_impurities=["Sn", "B"],
39+
main_ions_symbols=["D", "T"],
3740
)
3841

3942
CONFIG = copy.deepcopy(test_iterhybrid_predictor_corrector.CONFIG)

0 commit comments

Comments
 (0)