Coverage for python/gsfit/database_writers/tokamak_energy_mdsplus/map_results_to_database.py: 0%
122 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-14 15:25 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-14 15:25 +0000
1import typing
2from typing import TYPE_CHECKING
4import numpy as np
5import numpy.typing as npt
6from gsfit_rs.imas import equilibrium_paths as ep
7from scipy.constants import mu_0
9# from st40_database import GetData
11if TYPE_CHECKING:
12 from ...gsfit import Gsfit
13 from . import DatabaseWriterTokamakEnergyMDSplus
16# Pairs of (MDSplus node path, IMAS path) for everything which comes out of the `equilibrium` IDS
17# one value per time-slice. See the same tables in `tokamak_energy_mdsplus_new`; this writer maps
18# the same quantities onto the older MDSplus node layout.
19_TIME_SERIES_PATH_PAIRS: list[tuple[tuple[str, ...], typing.Any]] = [
20 # Two-d. `profiles_2d(0)` because GSFit solves on a single rectangular (R, Z) grid
21 (("TWO_D", "BR"), ep.time_slice[:].profiles_2d[0].b_field_r),
22 (("TWO_D", "BT"), ep.time_slice[:].profiles_2d[0].b_field_phi),
23 (("TWO_D", "BZ"), ep.time_slice[:].profiles_2d[0].b_field_z),
24 (("TWO_D", "MASK"), ep.time_slice[:].profiles_2d[0].mask),
25 (("TWO_D", "P"), ep.time_slice[:].profiles_2d[0].pressure),
26 (("TWO_D", "PSI"), ep.time_slice[:].profiles_2d[0].psi),
27 # Global
28 (("GLOBAL", "BETA_N"), ep.time_slice[:].global_quantities.beta_tor_norm),
29 (("GLOBAL", "BETA_P_1"), ep.time_slice[:].global_quantities.beta_pol_1),
30 (("GLOBAL", "BETA_P_2"), ep.time_slice[:].global_quantities.beta_pol_2),
31 (("GLOBAL", "BETA_P_3"), ep.time_slice[:].global_quantities.beta_pol_3),
32 (("GLOBAL", "BT_VAC_RGEO"), ep.time_slice[:].global_quantities.bt_vac_at_r_geo),
33 (("GLOBAL", "CHI_MAG"), ep.time_slice[:].constraints.chi_squared_reduced),
34 (("GLOBAL", "LI_1"), ep.time_slice[:].global_quantities.li_1),
35 (("GLOBAL", "LI_2"), ep.time_slice[:].global_quantities.li_2),
36 (("GLOBAL", "LI_3"), ep.time_slice[:].global_quantities.li_3),
37 (("GLOBAL", "DELTA_Z"), ep.time_slice[:].convergence.delta_z),
38 (("GLOBAL", "ELON"), ep.time_slice[:].boundary.elongation),
39 (("GLOBAL", "PHI_DIA"), ep.time_slice[:].constraints.diamagnetic_flux.reconstructed),
40 (("GLOBAL", "GS_ERROR"), ep.time_slice[:].convergence.grad_shafranov_deviation_value),
41 (("GLOBAL", "IP"), ep.time_slice[:].global_quantities.ip),
42 (("GLOBAL", "N_ITER"), ep.time_slice[:].convergence.iterations_n),
43 (("GLOBAL", "PSI_A"), ep.time_slice[:].global_quantities.psi_magnetic_axis),
44 (("GLOBAL", "PSI_B"), ep.time_slice[:].boundary.psi),
45 (("GLOBAL", "Q0"), ep.time_slice[:].global_quantities.q_axis),
46 (("GLOBAL", "Q95"), ep.time_slice[:].global_quantities.q_95),
47 (("GLOBAL", "R_CUR"), ep.time_slice[:].global_quantities.current_centre.r),
48 (("GLOBAL", "Z_CUR"), ep.time_slice[:].global_quantities.current_centre.z),
49 (("GLOBAL", "R_GEO"), ep.time_slice[:].boundary.geometric_axis.r),
50 (("GLOBAL", "Z_GEO"), ep.time_slice[:].boundary.geometric_axis.z),
51 (("GLOBAL", "R_MAG"), ep.time_slice[:].global_quantities.magnetic_axis.r),
52 (("GLOBAL", "Z_MAG"), ep.time_slice[:].global_quantities.magnetic_axis.z),
53 (("GLOBAL", "R_MINOR"), ep.time_slice[:].boundary.minor_radius),
54 (("GLOBAL", "V_LOOP"), ep.time_slice[:].global_quantities.v_loop),
55 (("GLOBAL", "VPLASMA"), ep.time_slice[:].global_quantities.volume),
56 (("GLOBAL", "W_MHD"), ep.time_slice[:].global_quantities.energy_mhd),
57 (("GLOBAL", "XPT_DIVERTED"), ep.time_slice[:].boundary.type),
58 # Plasma boundary
59 (("P_BOUNDARY", "RBND"), ep.time_slice[:].boundary.outline.r),
60 (("P_BOUNDARY", "ZBND"), ep.time_slice[:].boundary.outline.z),
61 (("P_BOUNDARY", "BOUNDING_R"), ep.time_slice[:].boundary.bounding.r),
62 (("P_BOUNDARY", "BOUNDING_Z"), ep.time_slice[:].boundary.bounding.z),
63 # Profiles, on the psi_norm grid
64 (("PROFILES", "RHO", "AREA"), ep.time_slice[:].profiles_1d.area),
65 (("PROFILES", "RHO", "AREA_PRIME"), ep.time_slice[:].profiles_1d.darea_dpsi),
66 (("PROFILES", "RHO", "F"), ep.time_slice[:].profiles_1d.f),
67 (("PROFILES", "RHO", "FF_PRIME"), ep.time_slice[:].profiles_1d.f_df_dpsi),
68 (("PROFILES", "RHO", "FLUX_TOR"), ep.time_slice[:].profiles_1d.phi),
69 (("PROFILES", "RHO", "P"), ep.time_slice[:].profiles_1d.pressure),
70 (("PROFILES", "RHO", "P_PRIME"), ep.time_slice[:].profiles_1d.dpressure_dpsi),
71 (("PROFILES", "RHO", "Q"), ep.time_slice[:].profiles_1d.q),
72 (("PROFILES", "RHO", "RHO_POL"), ep.time_slice[:].profiles_1d.rho_pol),
73 (("PROFILES", "RHO", "RHO_TOR"), ep.time_slice[:].profiles_1d.rho_tor),
74 (("PROFILES", "RHO", "VOL"), ep.time_slice[:].profiles_1d.volume),
75 (("PROFILES", "RHO", "VOL_PRIME"), ep.time_slice[:].profiles_1d.dvolume_dpsi),
76 (("PROFILES", "R_MIDPLANE", "P"), ep.time_slice[:].profiles_1d_r_midplane.pressure),
77 # Scrape off layer (SOL)
78 (("SOL", "HFS", "CONTOUR", "R"), ep.time_slice[:].sol.hfs.contour.r),
79 (("SOL", "HFS", "CONTOUR", "Z"), ep.time_slice[:].sol.hfs.contour.z),
80 (("SOL", "HFS", "STRIKE_POINT", "R"), ep.time_slice[:].sol.hfs.strike_point.r),
81 (("SOL", "HFS", "STRIKE_POINT", "Z"), ep.time_slice[:].sol.hfs.strike_point.z),
82 (("SOL", "LFS", "CONTOUR", "R"), ep.time_slice[:].sol.lfs.contour.r),
83 (("SOL", "LFS", "CONTOUR", "Z"), ep.time_slice[:].sol.lfs.contour.z),
84 (("SOL", "LFS", "STRIKE_POINT", "R"), ep.time_slice[:].sol.lfs.strike_point.r),
85 (("SOL", "LFS", "STRIKE_POINT", "Z"), ep.time_slice[:].sol.lfs.strike_point.z),
86]
88# The same, for quantities which are the same on every time-slice
89_TIME_INDEPENDENT_PATH_PAIRS: list[tuple[tuple[str, ...], typing.Any]] = [
90 (("TWO_D", "RGRID"), ep.time_slice[:].profiles_2d[0].grid.dim1),
91 (("TWO_D", "ZGRID"), ep.time_slice[:].profiles_2d[0].grid.dim2),
92 (("PROFILES", "RHO", "PSI_N"), ep.time_slice[:].profiles_1d.psi_norm),
93 (("PROFILES", "R_MIDPLANE", "R"), ep.time_slice[:].profiles_1d_r_midplane.r),
94]
97def _assign(results: typing.Any, mdsplus_path: tuple[str, ...], value: typing.Any) -> None:
98 """Assign `value` into the nested `results` object at `mdsplus_path`."""
99 node = results
100 for key in mdsplus_path[:-1]:
101 node = node[key]
102 node[mdsplus_path[-1]] = value
105def _n_points_per_time(padded: npt.NDArray[np.float64]) -> npt.NDArray[np.int32]:
106 """Number of real points in each row of a NaN-padded `[n_time, n_points]` array.
108 The IDS stores one contour per time-slice, each its own length; gathering over time pads the
109 short rows with NaN to make a rectangle. MDSplus needs that rectangle plus a separate count of
110 how much of each row is real. Contour coordinates are always finite, so a NaN can only be
111 padding.
112 """
113 n_points: npt.NDArray[np.int32] = np.isfinite(padded).sum(axis=1).astype(np.int32)
115 return n_points
118def map_results_to_database(
119 self: "DatabaseWriterTokamakEnergyMDSplus",
120 gsfit_controller: "Gsfit",
121) -> None:
122 """Map the results to MDSplus structure.
123 `gsfit_controller.results` is a `NestedDict` object, which is a 1:1 mapping to the MDSplus structure.
124 This function will mutate the `gsfit_controller` object.
125 """
127 # Take class object out of the `gsfit_controller` object
128 pulseNo = gsfit_controller.pulseNo
129 settings = gsfit_controller.settings
130 plasma = gsfit_controller.plasma
131 bp_probes = gsfit_controller.bp_probes
132 flux_loops = gsfit_controller.flux_loops
133 rogowski_coils = gsfit_controller.rogowski_coils
134 passives = gsfit_controller.passives
135 results = gsfit_controller.results
136 pressure_sensors = gsfit_controller.pressure_sensors
138 # Everything below comes out of the `equilibrium` IDS through the (MDSplus path, IMAS path)
139 # tables at the top of this file. `plasma.get` reads in place, so reading quantity by quantity
140 # costs nothing extra
142 for mdsplus_path, imas_path in _TIME_SERIES_PATH_PAIRS:
143 _assign(results, mdsplus_path, plasma.get(imas_path))
145 for mdsplus_path, imas_path in _TIME_INDEPENDENT_PATH_PAIRS:
146 _assign(results, mdsplus_path, np.asarray(plasma.get(imas_path))[0])
148 results["SOL"]["HFS"]["CONTOUR"]["N"] = _n_points_per_time(results["SOL"]["HFS"]["CONTOUR"]["R"])
149 results["SOL"]["LFS"]["CONTOUR"]["N"] = _n_points_per_time(results["SOL"]["LFS"]["CONTOUR"]["R"])
151 # The data dictionary defines `beta_tor` as a fraction, but this MDSplus node has always held a
152 # percentage, so the factor of 100 is put back here rather than changing what consumers read
153 results["GLOBAL"]["BETA_T"] = 100.0 * np.asarray(plasma.get(ep.time_slice[:].global_quantities.beta_tor))
155 # The rod current is not a data dictionary node. It is recovered from the vacuum toroidal
156 # field, `f_vac = r0 * b0 = mu_0 * i_rod / (2 * pi)`
157 r0 = plasma.get(ep.vacuum_toroidal_field.r0)
158 b0 = np.asarray(plasma.get(ep.vacuum_toroidal_field.b0))
159 results["GLOBAL"]["I_ROD"] = 2.0 * np.pi * r0 * b0 / mu_0
162 # Bp probes (note, this is all the sensors, both the ones we fit and the ones we don't)
163 bp_names = bp_probes.keys() # list of strings; len(bp_names) = n_sensors
164 bp_names = [bp_name.replace("P", "B_BPPROBE_") for bp_name in bp_names]
165 results["CONSTRAINTS"]["BPPROBE"]["NAME"] = np.array(bp_names) # MDSplus requires numpy objects, not lists of strings; shape = [n_sensors]
166 results["CONSTRAINTS"]["BPPROBE"]["CVALUE"] = bp_probes.get_array2(["*", "b", "calculated", "value"]) # shape = [n_time, n_sensors]
167 results["CONSTRAINTS"]["BPPROBE"]["INCLUDE"] = np.array(bp_probes.get_vec_bool(["*", "fit_settings", "include"])).astype(np.int32)
168 results["CONSTRAINTS"]["BPPROBE"]["MVALUE"] = bp_probes.get_array2(["*", "b", "measured", "value"]) # shape = [n_time, n_sensors]
169 results["CONSTRAINTS"]["BPPROBE"]["WEIGHT"] = bp_probes.get_array1(["*", "fit_settings", "weight"]) # shape = [n_sensors]
171 # Flux loops (note, this is all the sensors, both the ones we fit and the ones we don't)
172 fl_names = flux_loops.keys() # list of strings; len(fl_names) = n_sensors
173 fl_names = [fl_name.replace("L", "PSI_FLOOP_") for fl_name in fl_names]
174 results["CONSTRAINTS"]["FLOOP"]["NAME"] = np.array(fl_names) # MDSplus requires numpy objects, not lists of strings; shape = [n_sensors]
175 results["CONSTRAINTS"]["FLOOP"]["CVALUE"] = flux_loops.get_array2(["*", "psi", "calculated", "value"]) # shape = [n_time, n_sensors]
176 results["CONSTRAINTS"]["FLOOP"]["INCLUDE"] = np.array(flux_loops.get_vec_bool(["*", "fit_settings", "include"])).astype(np.int32)
177 results["CONSTRAINTS"]["FLOOP"]["MVALUE"] = flux_loops.get_array2(["*", "psi", "measured", "value"]) # shape = [n_time, n_sensors]
178 results["CONSTRAINTS"]["FLOOP"]["WEIGHT"] = flux_loops.get_array1(["*", "fit_settings", "weight"]) # shape = [n_sensors]
180 # Rogowski coils (note, this is all the sensors, both the ones we fit and the ones we don't)
181 rog_names = rogowski_coils.keys() # list of strings; len(rog_names) = n_sensors
182 rog_names = [f"I_ROG_{rog_name}" for rog_name in rog_names]
183 results["CONSTRAINTS"]["ROG"]["NAME"] = np.array(rog_names) # MDSplus requires numpy objects, not lists of strings; shape = [n_sensors]
184 results["CONSTRAINTS"]["ROG"]["CVALUE"] = rogowski_coils.get_array2(["*", "i", "calculated", "value"]) # shape = [n_time, n_sensors]
185 results["CONSTRAINTS"]["ROG"]["INCLUDE"] = np.array(rogowski_coils.get_vec_bool(["*", "fit_settings", "include"])).astype(np.int32)
186 results["CONSTRAINTS"]["ROG"]["MVALUE"] = rogowski_coils.get_array2(["*", "i", "measured", "value"]) # shape = [n_time, n_sensors]
187 results["CONSTRAINTS"]["ROG"]["WEIGHT"] = rogowski_coils.get_array1(["*", "fit_settings", "weight"]) # shape = [n_sensors]
189 # Plasma boundary
190 # The IDS stores each contour at its own length and the gather pads them into a rectangle;
191 # MDSplus wants the rectangle plus the count of real points in each row
192 results["P_BOUNDARY"]["NBND"] = _n_points_per_time(results["P_BOUNDARY"]["RBND"])
194 # Passives
195 for passive_name in passives.keys():
196 if passive_name == "IVC":
197 results["PASSIVES"]["IVC"]["DOF"]["EIG_01"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_01", "calculated"])
198 results["PASSIVES"]["IVC"]["DOF"]["EIG_01"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_01", "current_distribution"])
199 results["PASSIVES"]["IVC"]["DOF"]["EIG_02"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_02", "calculated"])
200 results["PASSIVES"]["IVC"]["DOF"]["EIG_02"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_02", "current_distribution"])
201 results["PASSIVES"]["IVC"]["DOF"]["EIG_03"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_03", "calculated"])
202 results["PASSIVES"]["IVC"]["DOF"]["EIG_03"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_03", "current_distribution"])
203 results["PASSIVES"]["IVC"]["DOF"]["EIG_04"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_04", "calculated"])
204 results["PASSIVES"]["IVC"]["DOF"]["EIG_04"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_04", "current_distribution"])
205 results["PASSIVES"]["IVC"]["DOF"]["EIG_05"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_05", "calculated"])
206 results["PASSIVES"]["IVC"]["DOF"]["EIG_05"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_05", "current_distribution"])
207 results["PASSIVES"]["IVC"]["DOF"]["EIG_06"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_06", "calculated"])
208 results["PASSIVES"]["IVC"]["DOF"]["EIG_06"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_06", "current_distribution"])
209 results["PASSIVES"]["IVC"]["DOF"]["EIG_07"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_07", "calculated"])
210 results["PASSIVES"]["IVC"]["DOF"]["EIG_07"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_07", "current_distribution"])
211 results["PASSIVES"]["IVC"]["DOF"]["EIG_08"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_08", "calculated"])
212 results["PASSIVES"]["IVC"]["DOF"]["EIG_08"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_08", "current_distribution"])
213 results["PASSIVES"]["IVC"]["DOF"]["EIG_09"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_09", "calculated"])
214 results["PASSIVES"]["IVC"]["DOF"]["EIG_09"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_09", "current_distribution"])
215 results["PASSIVES"]["IVC"]["DOF"]["EIG_10"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_10", "calculated"])
216 results["PASSIVES"]["IVC"]["DOF"]["EIG_10"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_10", "current_distribution"])
217 results["PASSIVES"]["IVC"]["DOF"]["EIG_11"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_11", "calculated"])
218 results["PASSIVES"]["IVC"]["DOF"]["EIG_11"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_11", "current_distribution"])
219 results["PASSIVES"]["IVC"]["DOF"]["EIG_12"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_12", "calculated"])
220 results["PASSIVES"]["IVC"]["DOF"]["EIG_12"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_12", "current_distribution"])
221 results["PASSIVES"]["IVC"]["DOF"]["EIG_13"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_13", "calculated"])
222 results["PASSIVES"]["IVC"]["DOF"]["EIG_13"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_13", "current_distribution"])
223 results["PASSIVES"]["IVC"]["DOF"]["EIG_14"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_14", "calculated"])
224 results["PASSIVES"]["IVC"]["DOF"]["EIG_14"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_14", "current_distribution"])
225 results["PASSIVES"]["IVC"]["DOF"]["EIG_15"]["CVALUE"] = passives.get_array1(["IVC", "dof", "eig_15", "calculated"])
226 results["PASSIVES"]["IVC"]["DOF"]["EIG_15"]["I_DIST"] = passives.get_array1(["IVC", "dof", "eig_15", "current_distribution"])
227 results["PASSIVES"]["IVC"]["GEOMETRY"]["ANGLE_1"] = passives.get_array1(["IVC", "geometry", "angle_1"])
228 results["PASSIVES"]["IVC"]["GEOMETRY"]["ANGLE_2"] = passives.get_array1(["IVC", "geometry", "angle_2"])
229 results["PASSIVES"]["IVC"]["GEOMETRY"]["D_R"] = passives.get_array1(["IVC", "geometry", "d_r"])
230 results["PASSIVES"]["IVC"]["GEOMETRY"]["D_Z"] = passives.get_array1(["IVC", "geometry", "d_z"])
231 results["PASSIVES"]["IVC"]["GEOMETRY"]["R"] = passives.get_array1(["IVC", "geometry", "r"])
232 results["PASSIVES"]["IVC"]["GEOMETRY"]["Z"] = passives.get_array1(["IVC", "geometry", "z"])
233 else:
234 results["PASSIVES"][passive_name]["DOF"]["CONSTANT_J"]["CVALUE"] = passives.get_array1(
235 [passive_name, "dof", "constant_current_density", "calculated"]
236 )
237 results["PASSIVES"][passive_name]["DOF"]["CONSTANT_J"]["I_DIST"] = passives.get_array1(
238 [passive_name, "dof", "constant_current_density", "current_distribution"]
239 )
240 results["PASSIVES"][passive_name]["GEOMETRY"]["ANGLE_1"] = passives.get_array1([passive_name, "geometry", "angle_1"])
241 results["PASSIVES"][passive_name]["GEOMETRY"]["ANGLE_2"] = passives.get_array1([passive_name, "geometry", "angle_2"])
242 results["PASSIVES"][passive_name]["GEOMETRY"]["D_R"] = passives.get_array1([passive_name, "geometry", "d_r"])
243 results["PASSIVES"][passive_name]["GEOMETRY"]["D_Z"] = passives.get_array1([passive_name, "geometry", "d_z"])
244 results["PASSIVES"][passive_name]["GEOMETRY"]["R"] = passives.get_array1([passive_name, "geometry", "r"])
245 results["PASSIVES"][passive_name]["GEOMETRY"]["Z"] = passives.get_array1([passive_name, "geometry", "z"])
247 # Scrape off layer (SOL)
249 if len(pressure_sensors.keys()) > 0:
250 results["CONSTRAINTS"]["PRESSURE"]["RECONSTRUCTED"] = pressure_sensors.get_array2(
251 ["*", "pressure", "calculated", "value"]
252 ) # shape = [n_time, n_points]
253 results["CONSTRAINTS"]["PRESSURE"]["MEASURED"] = pressure_sensors.get_array2(["*", "pressure", "measured", "value"]) # shape = [n_time, n_points]
254 results["CONSTRAINTS"]["PRESSURE"]["WEIGHT"] = pressure_sensors.get_array1(["*", "fit_settings", "weight"]) # shape = [n_points]
255 results["CONSTRAINTS"]["PRESSURE"]["POSITION"]["R"] = pressure_sensors.get_array1(["*", "geometry", "r"]) # shape = [n_points]
256 results["CONSTRAINTS"]["PRESSURE"]["POSITION"]["Z"] = pressure_sensors.get_array1(["*", "geometry", "z"]) # shape = [n_points]
257 results["CONSTRAINTS"]["PRESSURE"]["POSITION"]["PSI"] = pressure_sensors.get_array2(
258 ["*", "pressure", "calculated", "psi"]
259 ) # shape = [n_time, n_points]
261 # Store "WORKFLOW"
262 database_reader_method = settings["GSFIT_code_settings.json"]["database_reader"]["method"]
264 code_names = settings["GSFIT_code_settings.json"]["database_reader"][database_reader_method]["workflow"].keys()
266 for code_name in code_names:
267 pulseNo_json = settings["GSFIT_code_settings.json"]["database_reader"][database_reader_method]["workflow"][code_name]["pulseNo"]
268 if pulseNo_json is not None:
269 results["INPUT"]["WORKFLOW"][code_name]["PULSE"] = pulseNo_json
270 else:
271 results["INPUT"]["WORKFLOW"][code_name]["PULSE"] = pulseNo
273 run_name = settings["GSFIT_code_settings.json"]["database_reader"][database_reader_method]["workflow"][code_name]["run_name"]
274 results["INPUT"]["WORKFLOW"][code_name]["RUN"] = run_name
276 usage = settings["GSFIT_code_settings.json"]["database_reader"][database_reader_method]["workflow"][code_name]["usage"]
277 results["INPUT"]["WORKFLOW"][code_name]["USAGE"] = usage