Advanced data exploration¶
In the Explore with IMAS-Python training we have seen how to explore IMAS-Python data structures in an interactive way.
In this lesson, we will go a step further and look at methods to explore IMAS-Python data structures programmatically. This can be useful for, for example, writing plotting tools, analysis scripts, etc.
Exploring IDS (sub)structures¶
An IDS structure is a collection of IDS nodes (which could be structures, or arrays of
structures themselves). In IMAS-Python this is represented by the
IDSStructure class. You will find these classes in a
lot of places:
Data Dictionary IDSs is a special case of an IDS structure (implemented by class
IDSToplevel, which is a subclass ofIDSStructure).Data Dictionary structures, for example, the
ids_propertiesstructure that is present in every IDS.Data Dictionary arrays of structures (implemented by
IDSStructArray) containIDSStructures.
When you have an IDSStructure object, you can iterate over it to get all child nodes
that are contained in this structure. See the following example:
import imas
core_profiles = imas.IDSFactory().core_profiles()
# core_profiles is an IDS toplevel, which is also a structure:
print("Core profiles contains the following elements:")
for child_node in core_profiles:
print("-", child_node.metadata.name)
print()
print("Core profiles contains the following non-empty elements:")
# If you only want to loop over child nodes that have some data in them:
for filled_child_node in core_profiles.iter_nonempty_():
print("-", child_node.metadata.name)
Exercise 1: Explore structures¶
Load the training data for the
equilibriumIDS. You can refresh how to do this in the following section of the basic training material: Open an IMAS database entry.Loop over all non-empty child nodes of this IDS and print their name.
Print all child nodes of the
ids_propertiesstructure and their value.
import imas
import imas.training
# 1. Load the equilibrium IDS from the training data
entry = imas.training.get_training_db_entry()
equilibrium = entry.get("equilibrium")
# 2. Print non-empty child nodes
print("The following child nodes of the equilibrium IDS are filled:")
for child_node in equilibrium.iter_nonempty_():
print('-', child_node.metadata.name)
print()
# 3. Print child nodes of ids_properties
print("equilibrium/ids_properties has the following child nodes:")
for child_node in equilibrium.ids_properties:
print(f"- {child_node.metadata.name}: {child_node!r}")
Explore IDS data nodes and arrays of structures¶
Besides structures, IDSs contain arrays of structures, and data nodes. Arrays of
structures (modeled by IDSStructArray) are (as the
name applies) arrays containing IDSStructures. Data
nodes can contain scalar or array data of various types.
Some methods and properties are defined for all data nodes and arrays of structures:
len(<node>)Returns the length of the node:
For scalar numbers (
INT_0D,FLT_0DandCPX_0D) this will give an error.For strings (
STR_0D) this will give the length of the string.For arrays (
STR_1DandNDnumbers) this will give the length of the first dimension.
<node>.has_valueThis is
Truewhen a value is stored in the node.<node>.sizeGet the number of elements that are stored in the underlying data.
For scalar types (
*_0D) this is always 1.For 1D arrays, the
sizeis always the same as their length (seelen(<node>)).For ND arrays, the
sizeis equal tonp.prod(<node>.shape): the product of the array’s dimensions.
<node>.shapeGet the shape of the underlying data.
There are as many items as the rank of the data:
len(<node>.snape) == <node>.metadata.ndim.<node>.coordinatesGet access to the coordinate values. See the Using Data Dictionary metadata lesson for more details.
See also
You can find more details on IDS data node related classes and methods in the IMAS-Python Architecture documentation: IDS nodes
Apply a function to all nodes in an IDS¶
Before diving into the exercise and use this new knowledge, it is useful to know the
imas.util.visit_children() method. This method allows you to apply a method
to all nodes of an IDS. Additional keyword arguments can control whether you want to
include leaf nodes (data nodes) only, or also include structures and arrays of
structure. You can also choose between applying the function to filled nodes only (the
default) or all nodes, including empty ones.
See also
You can find more details in the API documentation:
imas.util.visit_children()
Exercise 2: Explore data nodes¶
Load the training data for the
equilibriumIDS.Create a function that prints the path, shape and size of an IDS node.
Use
visit_children()to apply the function to all non-empty nodes in the equilbrium IDS.Update your function such that it skips scalar (0D) IDS nodes. Apply the updated function to the equilibrium IDS.
Hint
Review IMAS-Python Architecture documentation for data node methods: IDS nodes
import imas
import imas.training
from imas.util import get_full_path
# 1. Load the training data equilibrium IDS
entry = imas.training.get_training_db_entry()
equilibrium = entry.get("equilibrium")
# 2. Function that prints the path, shape and size of an IDS node
def print_path_shape_size(node):
print(f"{get_full_path(node):40}: shape {node.shape} with total {node.size} items.")
# 3. Apply to equilibrium IDS
imas.util.visit_children(print_path_shape_size, equilibrium)
print()
# 4. Update function to skip 0D nodes
def print_path_shape_size_not0d(node):
if node.metadata.ndim == 0:
return
print(f"{get_full_path(node):40}: shape {node.shape} with total {node.size} items.")
# And apply to the equilibrium IDS
imas.util.visit_children(print_path_shape_size_not0d, equilibrium)