Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
240 changes: 43 additions & 197 deletions src/qcodes/dataset/measurements.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@
GroupedParameter,
ManualParameter,
MultiParameter,
Parameter,
ParameterBase,
ParameterSet,
ParameterWithSetpoints,
ParamSpecBase,
)
Expand Down Expand Up @@ -234,10 +234,6 @@ def add_result(self, *result_tuples: ResType) -> None:
legacy_results_dict.update(
self._unpack_arrayparameter(parameter_result)
)
elif isinstance(parameter_result[0], MultiParameter):
legacy_results_dict.update(
self._unpack_multiparameter(parameter_result)
)
else:
self_unpacked_parameter_results.extend(
parameter_result[0].unpack_self(parameter_result[1])
Expand Down Expand Up @@ -316,65 +312,6 @@ def _unpack_arrayparameter(

return res_dict

def _unpack_multiparameter(
self, partial_result: ResType
) -> dict[ParamSpecBase, npt.NDArray]:
"""
Unpack the `subarrays` and `setpoints` from a :class:`MultiParameter`
and into a standard results dict form and return that dict

"""

parameter, data = partial_result
parameter = cast("MultiParameter", parameter)

result_dict = {}

if parameter.setpoints is None:
raise RuntimeError(
f"{parameter.full_name} is an "
f"{type(parameter)} "
f"without setpoints. Cannot handle this."
)
for i in range(len(parameter.shapes)):
# if this loop runs, then 'data' is a Sequence
data = cast("Sequence[str | int | float | Any]", data)

shape = parameter.shapes[i]

try:
paramspec = self._interdeps._id_to_paramspec[parameter.full_names[i]]
except KeyError:
raise ValueError(
"Can not add result for parameter "
f"{parameter.names[i]}, "
"no such parameter registered "
"with this measurement."
)

result_dict.update({paramspec: np.array(data[i])})
if shape != ():
# array parameter like part of the multiparameter
# need to find setpoints too
fallback_sp_name = f"{parameter.full_names[i]}_setpoint"

sp_names: Sequence[str] | None
if (
parameter.setpoint_full_names is not None
and parameter.setpoint_full_names[i] is not None
):
sp_names = parameter.setpoint_full_names[i]
else:
sp_names = None

result_dict.update(
self._unpack_setpoints_from_parameter(
parameter, parameter.setpoints[i], sp_names, fallback_sp_name
)
)

return result_dict

def _unpack_setpoints_from_parameter(
self,
parameter: ParameterBase,
Expand Down Expand Up @@ -913,8 +850,15 @@ def _paramspecs_and_parameters_from_setpoints(
if setpoints is not None:
for setpoint in setpoints:
if isinstance(setpoint, ParameterBase):
paramspecs.append(setpoint.param_spec)
parameters.append(setpoint)
if isinstance(setpoint, MultiParameter):
specs, params = self._paramspecs_and_parameters_from_setpoints(
setpoint.full_names
)
paramspecs.extend(specs)
parameters.extend(params)
else:
paramspecs.append(setpoint.param_spec)
parameters.append(setpoint)
elif (
isinstance(setpoint, str)
and (
Expand All @@ -931,12 +875,26 @@ def _paramspecs_and_parameters_from_setpoints(
)
return paramspecs, parameters

@staticmethod
def _extend_paramspecs(paramspecs: list[ParamSpecBase], parameters: ParameterSet):
for param in parameters:
if not isinstance(param, MultiParameter):
paramspecs.append(param.param_spec)
else:
paramspecs.extend(p.param_spec for p in param.register_parameters)
return paramspecs

def _self_register_parameter(
self: Self,
parameter: ParameterBase,
setpoints: SetpointsType | None = None,
basis: SetpointsType | None = None,
) -> Self:
if isinstance(parameter, MultiParameter):
for mp_param in parameter.register_parameters:
self._self_register_parameter(mp_param, setpoints, basis)
return self

# It is important to preserve the order of the setpoints (and basis) arguments
# when building the dependency trees, as this order is implicitly used to assign
# the axis-order for multidimensional data variables where shape alone is
Expand All @@ -951,11 +909,11 @@ def _self_register_parameter(
)

# Append internal dependencies/inferences
dependency_paramspecs.extend(
[param.param_spec for param in parameter.depends_on]
dependency_paramspecs = self._extend_paramspecs(
dependency_paramspecs, parameter.depends_on
)
inference_paramspecs.extend(
[param.param_spec for param in parameter.is_controlled_by]
inference_paramspecs = self._extend_paramspecs(
inference_paramspecs, parameter.is_controlled_by
)

# Make ParamSpecTrees and extend interdeps
Expand All @@ -980,15 +938,11 @@ def _self_register_parameter(
log.info(f"Registered {parameter.register_name} in the Measurement.")

# Recursively register all other interdependent parameters related to this parameter
interdependent_parameters = list(
chain.from_iterable(
[
dependency_parameters,
inference_parameters,
parameter.depends_on,
parameter.is_controlled_by,
]
)
interdependent_parameters = chain(
dependency_parameters,
inference_parameters,
parameter.depends_on,
parameter.is_controlled_by,
)
for interdependent_parameter in interdependent_parameters:
if interdependent_parameter not in self._registered_parameters:
Expand Down Expand Up @@ -1036,14 +990,7 @@ def register_parameter(
case ArrayParameter():
paramtype = self._infer_paramtype(parameter, paramtype)
self._register_arrayparameter(parameter, setpoints, basis, paramtype)
case MultiParameter():
paramtype = self._infer_paramtype(parameter, paramtype)
self._register_multiparameter(
parameter,
setpoints,
basis,
paramtype,
)
self._registered_parameters.add(parameter)
case GroupedParameter():
paramtype = self._infer_paramtype(parameter, paramtype)
self._register_parameter(
Expand All @@ -1054,16 +1001,15 @@ def register_parameter(
basis,
paramtype,
)
case ParameterBase() | ParameterWithSetpoints():
if paramtype is not None:
parameter.paramtype = paramtype
self._registered_parameters.add(parameter)
case ParameterBase() | ParameterWithSetpoints() | MultiParameter():
parameter.paramtype = self._infer_paramtype(parameter, paramtype)
self._self_register_parameter(parameter, setpoints, basis)
case _:
raise ValueError(
f"Can not register object of type {type(parameter)}. Can only "
"register a QCoDeS Parameter."
)
self._registered_parameters.add(parameter)

return self

Expand Down Expand Up @@ -1096,6 +1042,12 @@ def _infer_paramtype(parameter: ParameterBase, paramtype: str | None) -> str:
return_paramtype: str
if paramtype is not None: # override with argument
return_paramtype = paramtype
elif isinstance(parameter, MultiParameter):
# No vals by default.
if any(shp for shp in parameter.shapes):
return_paramtype = "array"
else:
return_paramtype = "numeric"
elif isinstance(parameter.vals, vals.Arrays):
return_paramtype = "array"
elif isinstance(parameter, ArrayParameter):
Expand Down Expand Up @@ -1225,112 +1177,6 @@ def _register_arrayparameter(
paramtype,
)

def _register_parameter_with_setpoints(
self,
parameter: ParameterWithSetpoints,
setpoints: SetpointsType | None,
basis: SetpointsType | None,
paramtype: str,
) -> None:
"""
Register an ParameterWithSetpoints and the setpoints belonging to the
Parameter
"""
my_setpoints = list(setpoints) if setpoints else []
for sp in parameter.setpoints:
if not isinstance(sp, Parameter):
raise RuntimeError(
"The setpoints of a ParameterWithSetpoints must be a Parameter"
)
spname = sp.register_name
splabel = sp.label
spunit = sp.unit

self._register_parameter(
name=spname,
paramtype=paramtype,
label=splabel,
unit=spunit,
setpoints=None,
basis=None,
)

my_setpoints.append(spname)

self._register_parameter(
parameter.register_name,
parameter.label,
parameter.unit,
my_setpoints,
basis,
paramtype,
)

def _register_multiparameter(
self,
multiparameter: MultiParameter,
setpoints: SetpointsType | None,
basis: SetpointsType | None,
paramtype: str,
) -> None:
"""
Find the individual multiparameter components and their setpoints
and register those as individual parameters
"""
setpoints_lists = []
for i in range(len(multiparameter.shapes)):
shape = multiparameter.shapes[i]
name = multiparameter.full_names[i]
if shape == ():
my_setpoints = setpoints
else:
my_setpoints = list(setpoints) if setpoints else []
for j in range(len(shape)):
if (
multiparameter.setpoint_full_names is not None
and multiparameter.setpoint_full_names[i] is not None
):
spname = multiparameter.setpoint_full_names[i][j]
else:
spname = f"{name}_setpoint_{j}"
if (
multiparameter.setpoint_labels is not None
and multiparameter.setpoint_labels[i] is not None
):
splabel = multiparameter.setpoint_labels[i][j]
else:
splabel = ""
if (
multiparameter.setpoint_units is not None
and multiparameter.setpoint_units[i] is not None
):
spunit = multiparameter.setpoint_units[i][j]
else:
spunit = ""

self._register_parameter(
name=spname,
paramtype=paramtype,
label=splabel,
unit=spunit,
setpoints=None,
basis=None,
)

my_setpoints += [spname]

setpoints_lists.append(my_setpoints)

for i, expanded_setpoints in enumerate(setpoints_lists):
self._register_parameter(
multiparameter.full_names[i],
multiparameter.labels[i],
multiparameter.units[i],
expanded_setpoints,
basis,
paramtype,
)

def register_custom_parameter(
self: Self,
name: str,
Expand Down
Loading