@@ -11,13 +11,16 @@ enumerated list of options for defining, for example:
1111 a neutron, or a photon.
1212- Plasma heating may come from neutral beam injection, electron cyclotron heating,
1313 ion cyclotron heating, lower hybrid heating, alpha particles.
14+ - These may have alternative naming conventions supported through aliases
15+ (e.g., "235U" and "U_235" for Uranium 235).
1416
15- Identifiers are a list of possible valid labels. Each label has three
17+ Identifiers are a list of possible valid labels. Each label has up to four
1618representations:
1719
18201. An index (integer)
19212. A name (short string)
20223. A description (long string)
23+ 4. List of aliases (list of short strings)
2124
2225
2326Identifiers in IMAS-Python
@@ -44,6 +47,15 @@ the available identifiers is stored as ``imas.identifiers.identifiers``.
4447 print (csid.total.index)
4548 print (csid.total.description)
4649
50+ # Access identifiers with aliases (when available)
51+ mid = imas.identifiers.materials_identifier
52+ print (mid[" 235U" ].name) # Access by canonical name
53+ print (mid[" U_235" ].name) # Access by alias
54+
55+ # Both return the same object
56+ assert mid[" 235U" ].name is mid[" U_235" ].name
57+ assert mid[" 235U" ].name is mid.U_235.name
58+
4759 # Item access is also possible
4860 print (identifiers[" edge_source_identifier" ])
4961
@@ -64,8 +76,8 @@ Assigning identifiers in IMAS-Python
6476
6577IMAS-Python implements smart assignment of identifiers. You may assign an identifier
6678enum value (for example ``imas.identifiers.core_source_identifier.total ``), a
67- string (for example ``"total" ``) or an integer (for example ``"1" ``) to an
68- identifier structure (for example ``core_profiles.source[0].identifier ``) to set
79+ string (for example ``"total" `` or its alias), or an integer (for example ``"1" ``)
80+ to an identifier structure (for example ``core_profiles.source[0].identifier ``) to set
6981all three child nodes ``name ``, ``index `` and ``description `` in one go. See
7082below example:
7183
@@ -86,6 +98,20 @@ below example:
8698 # 3. Assign an integer. This looks up the index in the identifier enum:
8799 core_sources.source[0 ].identifier = 1
88100
101+ # Identifiers can still be assigned with the old alias name for backward compatibility:
102+ wallids = imas.IDSFactory().wall()
103+ wallids.description_ggd.resize(1 )
104+ wallids.description_ggd[0 ].material.resize(1 )
105+ wallids.description_ggd[0 ].material[0 ].grid_subset.resize(1 )
106+ mat = wallids.description_ggd[0 ].material[0 ].grid_subset[0 ].identifiers
107+ mat.names.extend([" " ] * 1 )
108+ mid = imas.identifiers.materials_identifier
109+ # Assign using canonical name
110+ mat.names[0 ] = " 235U"
111+ # Or assign using alias (equivalent to above)
112+ mat.names[0 ] = mid[" U_235" ].name
113+ mat.names[0 ] = mid.U_235.name
114+
89115 # Inspect the contents of the structure
90116 imas.util.inspect(core_sources.source[0 ].identifier)
91117
@@ -101,18 +127,78 @@ below example:
101127 imas.util.inspect(core_sources.source[1 ].identifier)
102128
103129
130+ Identifier aliases
131+ ------------------
132+
133+ Some identifiers may have multiple aliases defined in the Data Dictionary. Aliases are
134+ former names kept as an option to ensure better backward compatibility after a change
135+ and support multiple naming conventions. An identifier can have any number of
136+ comma-separated aliases.
137+
138+ Aliases can be accessed in the same ways as canonical names, and all aliases for an
139+ identifier point to the same object.
140+
141+ Aliases that begin with a number (e.g., 235U) cannot be accessed using dot notation
142+ (e.g., material_identifier.235U) due to Python's syntax restrictions. Instead, such
143+ aliases must be accessed using dictionary-style indexing, for example:
144+ material_identifier["235U"].
145+
146+ .. code-block :: python
147+ :caption: Working with identifier aliases
148+
149+ import imas
150+
151+ # Get materials identifier which has some aliases defined
152+ mid = imas.identifiers.materials_identifier
153+
154+ # Access by canonical name
155+ uranium235_by_name = mid[" 235U" ]
156+ print (f " Name: { uranium235_by_name.name} " )
157+ print (f " Aliases: { uranium235_by_name.aliases} " ) # List of all aliases
158+ print (f " First alias: { uranium235_by_name.alias} " ) # First alias for compatibility
159+ print (f " Index: { uranium235_by_name.index} " )
160+ print (f " Description: { uranium235_by_name.description} " )
161+
162+ # Access by any alias - all return the same object
163+ uranium235_by_alias1 = mid[" U_235" ].name
164+ uranium235_by_alias2 = mid[" Uranium_235" ].name
165+ print (f " Same objects: { uranium235_by_name is uranium235_by_alias1 is uranium235_by_alias2} " )
166+
167+ # You can also use attribute access for aliases (when valid Python identifiers)
168+ uranium235_by_attr = mid.U_235.name
169+ print (f " Same object: { uranium235_by_name is uranium235_by_attr} " )
170+
171+ # When assigning to IDS structures, alias works the following way
172+ wallids = imas.IDSFactory().wall()
173+ wallids.description_ggd.resize(1 )
174+ wallids.description_ggd[0 ].material.resize(1 )
175+ wallids.description_ggd[0 ].material[0 ].grid_subset.resize(1 )
176+ mat = wallids.description_ggd[0 ].material[0 ].grid_subset[0 ].identifiers
177+ mat.names.extend([" " ] * 1 )
178+ mat.indices.resize(1 )
179+ mat.descriptions.extend([" " ] * 1 )
180+ mat.indices[0 ] = 20
181+ mat.descriptions[0 ] = " Uranium 235 isotope"
182+
183+ # These assignments are all equivalent:
184+ mat.names[0 ] = " 235U" # canonical name
185+ mat.names[0 ] = mid[" 235U" ].name # enum value
186+ mat.names[0 ] = mid.U_235.name # enum value via alias
187+ mat.names[0 ] = mid[" U_235" ].name # enum value via alias
188+
104189 Compare identifiers
105190-------------------
106191
107192Identifier structures can be compared against the identifier enum as well. They
108193compare equal when:
109194
1101951. ``index `` is an exact match
111- 2. ``name `` is an exact match, or ``name `` is not filled in the IDS node
196+ 2. ``name `` is an exact match, or ``name `` matches an alias, or `` name `` is not filled in the IDS node
112197
113198The ``description `` does not have to match with the Data Dictionary definition,
114199but a warning is logged if the description in the IDS node does not match with
115- the Data Dictionary description:
200+ the Data Dictionary description. The comparison also takes aliases into account,
201+ so an identifier will match both its canonical name and any defined alias:
116202
117203.. code-block :: python
118204 :caption: Comparing identifiers
@@ -139,6 +225,15 @@ the Data Dictionary description:
139225 >> > core_sources.source[0 ].identifier.name = " totalX"
140226 >> > core_sources.source[0 ].identifier == csid.total
141227 False
228+ >> > # Alias comparison example with materials identifier
229+ >> > mid = imas.identifiers.materials_identifier
230+ >> > cxr = imas.IDSFactory().camera_x_rays()
231+ >> > mat = cxr.filter_window.material
232+ >> > mat.index = 20
233+ >> > mat.name = " U_235" # Using alias
234+ >> > # Compares equal to the canonical identifier even though name is alias
235+ >> > mat == mid[" 235U" ].name
236+ True
142237
143238
144239 .. seealso ::
0 commit comments