|
| 1 | +"""IMAS-Python example for custom conversion logic. |
| 2 | +
|
| 3 | +This example script loads a Data Entry (in Data Dictionary 3.38.1) created by |
| 4 | +DINA and converts the em_coupling IDS to DD 4.0.0. |
| 5 | +""" |
| 6 | + |
| 7 | +import imas |
| 8 | +from imas.ids_defs import IDS_TIME_MODE_INDEPENDENT |
| 9 | + |
| 10 | +input_uri = "imas:hdf5?path=/work/imas/shared/imasdb/ITER_SCENARIOS/3/105013/1" |
| 11 | +# An error is reported when there's already data at the output_uri! |
| 12 | +output_uri = "imas:hdf5?path=105013-1-converted" |
| 13 | +target_dd_version = "4.0.0" |
| 14 | + |
| 15 | + |
| 16 | +# Mapping of DD 3.38.1 em_coupling data to DD 4.0.0 |
| 17 | +# Map the name of the matrix in DD 3.38.1 to the identifier and coordinate URIs |
| 18 | +COUPLING_MAPS = { |
| 19 | + "field_probes_active": dict( |
| 20 | + coupling_quantity=2, |
| 21 | + rows_uri="#magnetics/b_field_pol_probe", |
| 22 | + columns_uri="#pf_active/coil", |
| 23 | + ), |
| 24 | + "field_probes_grid": dict( |
| 25 | + coupling_quantity=2, |
| 26 | + rows_uri="#magnetics/b_field_pol_probe", |
| 27 | + columns_uri="#pf_plasma/element", |
| 28 | + ), |
| 29 | + "field_probes_passive": dict( |
| 30 | + coupling_quantity=2, |
| 31 | + rows_uri="#magnetics/b_field_pol_probe", |
| 32 | + columns_uri="#pf_passive/loop", |
| 33 | + ), |
| 34 | + "mutual_active_active": dict( |
| 35 | + coupling_quantity=1, |
| 36 | + rows_uri="#pf_active/coil", |
| 37 | + columns_uri="#pf_active/coil", |
| 38 | + ), |
| 39 | + "mutual_grid_active": dict( |
| 40 | + coupling_quantity=1, |
| 41 | + rows_uri="#pf_plasma/element", |
| 42 | + columns_uri="#pf_active/coil", |
| 43 | + ), |
| 44 | + "mutual_grid_grid": dict( |
| 45 | + coupling_quantity=1, |
| 46 | + rows_uri="#pf_plasma/element", |
| 47 | + columns_uri="#pf_plasma/element", |
| 48 | + ), |
| 49 | + "mutual_grid_passive": dict( |
| 50 | + coupling_quantity=1, |
| 51 | + rows_uri="#pf_plasma/element", |
| 52 | + columns_uri="#pf_passive/loop", |
| 53 | + ), |
| 54 | + "mutual_loops_active": dict( |
| 55 | + coupling_quantity=1, |
| 56 | + rows_uri="#magnetics/flux_loop", |
| 57 | + columns_uri="#pf_active/coil", |
| 58 | + ), |
| 59 | + "mutual_loops_passive": dict( |
| 60 | + coupling_quantity=1, |
| 61 | + rows_uri="#magnetics/flux_loop", |
| 62 | + columns_uri="#pf_passive/loop", |
| 63 | + ), |
| 64 | + "mutual_loops_grid": dict( |
| 65 | + coupling_quantity=1, |
| 66 | + rows_uri="#magnetics/flux_loop", |
| 67 | + columns_uri="#pf_plasma/element", |
| 68 | + ), |
| 69 | + "mutual_passive_active": dict( |
| 70 | + coupling_quantity=1, |
| 71 | + rows_uri="#pf_passive/loop", |
| 72 | + columns_uri="#pf_active/coil", |
| 73 | + ), |
| 74 | + "mutual_passive_passive": dict( |
| 75 | + coupling_quantity=1, |
| 76 | + rows_uri="#pf_passive/loop", |
| 77 | + columns_uri="#pf_passive/loop", |
| 78 | + ), |
| 79 | +} |
| 80 | + |
| 81 | + |
| 82 | +with ( |
| 83 | + imas.DBEntry(input_uri, "r") as entry, |
| 84 | + imas.DBEntry(output_uri, "x", dd_version=target_dd_version) as out, |
| 85 | +): |
| 86 | + print("Loaded IMAS Data Entry:", input_uri) |
| 87 | + |
| 88 | + print("This data entry contains the following IDSs:") |
| 89 | + filled_idss = [] |
| 90 | + for idsname in entry.factory.ids_names(): |
| 91 | + occurrences = entry.list_all_occurrences(idsname) |
| 92 | + if occurrences: |
| 93 | + filled_idss.append(idsname) |
| 94 | + print(f"- {idsname}, occurrences: {occurrences}") |
| 95 | + print("") |
| 96 | + |
| 97 | + # Load and convert all IDSs (except em_coupling) with imas.convert_ids() |
| 98 | + # N.B. we know that the input URI doesn't have multiple occurrences, so |
| 99 | + # we do not need to worry about them: |
| 100 | + for idsname in filled_idss: |
| 101 | + if idsname == "em_coupling": |
| 102 | + continue |
| 103 | + |
| 104 | + print(f"Loading IDS: {idsname}...") |
| 105 | + ids = entry.get(idsname, autoconvert=False) |
| 106 | + print(f"Converting IDS {idsname} to DD {target_dd_version}...") |
| 107 | + ids4 = imas.convert_ids( |
| 108 | + ids, |
| 109 | + target_dd_version, |
| 110 | + provenance_origin_uri=input_uri, |
| 111 | + ) |
| 112 | + print(f"Storing IDS {idsname} to output data entry...") |
| 113 | + out.put(ids4) |
| 114 | + |
| 115 | + print("Conversion for em_coupling:") |
| 116 | + emc = entry.get("em_coupling", autoconvert=False) |
| 117 | + print("Using standard convert, this may log warnings about discarding data") |
| 118 | + emc4 = imas.convert_ids( |
| 119 | + emc, |
| 120 | + target_dd_version, |
| 121 | + provenance_origin_uri=input_uri, |
| 122 | + ) |
| 123 | + |
| 124 | + print("Starting custom conversion of the coupling matrices") |
| 125 | + for matrix_name, mapping in COUPLING_MAPS.items(): |
| 126 | + # Skip empty matrices |
| 127 | + if not emc[matrix_name].has_value: |
| 128 | + continue |
| 129 | + |
| 130 | + # Allocate a new coupling_matrix AoS element |
| 131 | + emc4.coupling_matrix.resize(len(emc4.coupling_matrix) + 1, keep=True) |
| 132 | + # And fill it |
| 133 | + |
| 134 | + emc4.coupling_matrix[-1].name = matrix_name |
| 135 | + # Assigning an integer to the identifier will automatically fill the |
| 136 | + # index/name/description. See documentation: |
| 137 | + # https://imas-python.readthedocs.io/en/latest/identifiers.html |
| 138 | + emc4.coupling_matrix[-1].quantity = mapping["coupling_quantity"] |
| 139 | + emc4.coupling_matrix[-1].rows_uri = [mapping["rows_uri"]] |
| 140 | + emc4.coupling_matrix[-1].columns_uri = [mapping["columns_uri"]] |
| 141 | + emc4.coupling_matrix[-1].data = emc[matrix_name].value |
| 142 | + # N.B. the original data has no error_upper/error_lower so we skip these |
| 143 | + # Store em_coupling IDS |
| 144 | + out.put(emc4) |
| 145 | + |
| 146 | + print("Generating pf_plasma IDS...") |
| 147 | + # N.B. This logic is specific to DINA |
| 148 | + # Create a new pf_plasma IDS and set basic properties |
| 149 | + pf_plasma = out.factory.pf_plasma() |
| 150 | + pf_plasma.ids_properties.homogeneous_time = IDS_TIME_MODE_INDEPENDENT |
| 151 | + pf_plasma.ids_properties.comment = "PF Plasma generated from equilibrium" |
| 152 | + |
| 153 | + equilibrium = entry.get("equilibrium", lazy=True, autoconvert=False) |
| 154 | + r = equilibrium.time_slice[0].profiles_2d[0].grid.dim1 |
| 155 | + z = equilibrium.time_slice[0].profiles_2d[0].grid.dim2 |
| 156 | + nr, nz = len(r), len(z) |
| 157 | + # Generate a pf_plasma element for each grid point: |
| 158 | + pf_plasma.element.resize(nr * nz) |
| 159 | + for ir, rval in enumerate(r): |
| 160 | + for iz, zval in enumerate(z): |
| 161 | + element = pf_plasma.element[ir * nr + iz] |
| 162 | + element.geometry.geometry_type = 2 # rectangle |
| 163 | + element.geometry.rectangle.r = rval |
| 164 | + element.geometry.rectangle.z = zval |
| 165 | + # Store pf_plasma IDS |
| 166 | + out.put(pf_plasma) |
| 167 | + |
| 168 | +print("Conversion finished") |
0 commit comments