Skip to content

Commit a066b8b

Browse files
authored
Merge pull request #7891 from esbenh4/esh/add_shapes_to_dataset_def
Improvement: added shapes to DatasetDefinition
2 parents 5c2cd2c + e6f8ba6 commit a066b8b

3 files changed

Lines changed: 157 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Enabled setting shape of Measurement in measurement_extensions.py. Added `shapes` to DataSetDefinition and use it in setup_measurement_isntances to set shape of measurement. Added new tests for new use cases.

src/qcodes/dataset/measurement_extensions.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from qcodes.parameters.parameter_base import ParameterBase
1717

1818
if TYPE_CHECKING:
19+
from qcodes.dataset.descriptions.versioning.rundescribertypes import Shapes
1920
from qcodes.dataset.experiment_container import Experiment
2021

2122
TRACER = trace.get_tracer(__name__)
@@ -37,6 +38,11 @@ class DataSetDefinition:
3738
experiment: Experiment | None = None
3839
"""An optional argument specifying which Experiment this dataset should be
3940
written to"""
41+
shapes: Shapes | None = None
42+
"""An optional dictionary from dependent parameter names to a tuple of
43+
integers describing the shape of the measurement. This is used to
44+
specify the shape of the dataset.
45+
See :class:`qcodes.dataset.measurements.Measurement.set_shapes`."""
4046
metadata: Mapping[str, Any] | None = None
4147
"""An optional dictionary of metadata that will be added to the dataset
4248
generated by this definition"""
@@ -69,6 +75,8 @@ def setup_measurement_instances(
6975
meas.register_parameter(param)
7076
for param in ds_def.dependent:
7177
meas.register_parameter(param, setpoints=ds_def.independent)
78+
if ds_def.shapes is not None:
79+
meas.set_shapes(ds_def.shapes)
7280
measurements.append(meas)
7381
return measurements
7482

tests/dataset/test_measurement_extensions.py

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
LinSweeper,
2222
datasaver_builder,
2323
dond_into,
24+
setup_measurement_instances,
2425
)
2526
from qcodes.parameters import Parameter, ParameterWithSetpoints
2627
from qcodes.validators import Arrays
@@ -490,3 +491,150 @@ def test_context_with_override_experiment(
490491

491492
assert datasets[0].exp_name == experiment2.name
492493
assert datasets[1].exp_name == experiment2.name
494+
495+
496+
def test_shapes_in_dataset_definition_with_scalar_params(
497+
default_params, default_database_and_experiment
498+
):
499+
"""Test that shapes specified in DataSetDefinition are stored on the dataset."""
500+
_ = default_database_and_experiment
501+
set1, set2, _, meas1, meas2, _ = default_params
502+
503+
expected_shapes = {
504+
meas1.register_name: (11, 11),
505+
meas2.register_name: (11, 11),
506+
}
507+
dataset_definition = [
508+
DataSetDefinition(
509+
name="dataset_with_shapes",
510+
independent=[set1, set2],
511+
dependent=[meas1, meas2],
512+
shapes=expected_shapes,
513+
),
514+
]
515+
with datasaver_builder(dataset_definition) as datasavers:
516+
for _ in LinSweeper(set1, 0, 10, 11, 0.001):
517+
sweep1 = LinSweep(set2, 0, 10, 11, 0.001)
518+
dond_into(datasavers[0], sweep1, meas1, meas2, additional_setpoints=(set1,))
519+
datasets = [datasaver.dataset for datasaver in datasavers]
520+
521+
assert datasets[0].description.shapes == expected_shapes
522+
523+
524+
def test_shapes_in_dataset_definition_with_pws(
525+
pws_params, default_database_and_experiment
526+
):
527+
"""Test that shapes for ParameterWithSetpoints are stored on the dataset."""
528+
_ = default_database_and_experiment
529+
pws1, set1 = pws_params
530+
531+
expected_shapes = {
532+
pws1.register_name: (11, 11),
533+
}
534+
dataset_definition = [
535+
DataSetDefinition(
536+
name="dataset_pws_shapes",
537+
independent=[set1],
538+
dependent=[pws1],
539+
shapes=expected_shapes,
540+
),
541+
]
542+
with datasaver_builder(dataset_definition) as datasavers:
543+
for _ in LinSweeper(set1, 0, 10, 11, 0.001):
544+
dond_into(datasavers[0], pws1, additional_setpoints=(set1,))
545+
datasets = [datasaver.dataset for datasaver in datasavers]
546+
547+
assert datasets[0].description.shapes == expected_shapes
548+
549+
550+
def test_shapes_none_by_default(default_params, default_database_and_experiment):
551+
"""Test that shapes is None when not specified in DataSetDefinition."""
552+
_ = default_database_and_experiment
553+
set1, _, _, meas1, _, _ = default_params
554+
555+
dataset_definition = [
556+
DataSetDefinition(
557+
name="dataset_no_shapes",
558+
independent=[set1],
559+
dependent=[meas1],
560+
),
561+
]
562+
with datasaver_builder(dataset_definition) as datasavers:
563+
for _ in LinSweeper(set1, 0, 5, 6, 0.001):
564+
datasavers[0].add_result((set1, set1()), (meas1, meas1()))
565+
datasets = [datasaver.dataset for datasaver in datasavers]
566+
567+
assert datasets[0].description.shapes is None
568+
569+
570+
def test_setup_measurement_instances_sets_shapes(
571+
default_params, default_database_and_experiment
572+
):
573+
"""Test that setup_measurement_instances correctly sets shapes on Measurement."""
574+
_ = default_database_and_experiment
575+
set1, _, _, meas1, _, _ = default_params
576+
577+
expected_shapes = {meas1.register_name: (5,)}
578+
dataset_definitions = [
579+
DataSetDefinition(
580+
name="test_shapes",
581+
independent=[set1],
582+
dependent=[meas1],
583+
shapes=expected_shapes,
584+
),
585+
]
586+
measurements = setup_measurement_instances(dataset_definitions)
587+
assert len(measurements) == 1
588+
assert measurements[0]._shapes == expected_shapes
589+
590+
591+
def test_setup_measurement_instances_no_shapes(
592+
default_params, default_database_and_experiment
593+
):
594+
"""Test that setup_measurement_instances leaves shapes as None when not specified."""
595+
_ = default_database_and_experiment
596+
set1, _, _, meas1, _, _ = default_params
597+
598+
dataset_definitions = [
599+
DataSetDefinition(
600+
name="test_no_shapes",
601+
independent=[set1],
602+
dependent=[meas1],
603+
),
604+
]
605+
measurements = setup_measurement_instances(dataset_definitions)
606+
assert len(measurements) == 1
607+
assert measurements[0]._shapes is None
608+
609+
610+
def test_shapes_with_multiple_datasets(default_params, default_database_and_experiment):
611+
"""Test shapes are correctly applied to multiple datasets independently."""
612+
_ = default_database_and_experiment
613+
set1, set2, set3, meas1, _, meas3 = default_params
614+
615+
shapes_1 = {meas1.register_name: (11, 11)}
616+
shapes_2 = {meas3.register_name: (11, 11)}
617+
dataset_definition = [
618+
DataSetDefinition(
619+
name="dataset_1",
620+
independent=[set1, set2],
621+
dependent=[meas1],
622+
shapes=shapes_1,
623+
),
624+
DataSetDefinition(
625+
name="dataset_2",
626+
independent=[set1, set3],
627+
dependent=[meas3],
628+
shapes=shapes_2,
629+
),
630+
]
631+
with datasaver_builder(dataset_definition) as datasavers:
632+
for _ in LinSweeper(set1, 0, 10, 11, 0.001):
633+
sweep1 = LinSweep(set2, 0, 10, 11, 0.001)
634+
sweep2 = LinSweep(set3, -10, 0, 11, 0.001)
635+
dond_into(datasavers[0], sweep1, meas1, additional_setpoints=(set1,))
636+
dond_into(datasavers[1], sweep2, meas3, additional_setpoints=(set1,))
637+
datasets = [datasaver.dataset for datasaver in datasavers]
638+
639+
assert datasets[0].description.shapes == shapes_1
640+
assert datasets[1].description.shapes == shapes_2

0 commit comments

Comments
 (0)