diff --git a/docs/changes/newsfragments/6487.improved b/docs/changes/newsfragments/6487.improved new file mode 100644 index 00000000000..e516aeefac6 --- /dev/null +++ b/docs/changes/newsfragments/6487.improved @@ -0,0 +1 @@ +Parameters registered in a qcodes Measurement are now snapshotted and stored in the resulting dataset under `dataset.snapshot["parameters"]` diff --git a/docs/examples/DataSet/Working with snapshots.ipynb b/docs/examples/DataSet/Working with snapshots.ipynb index e918d3696dd..8ea736c4990 100644 --- a/docs/examples/DataSet/Working with snapshots.ipynb +++ b/docs/examples/DataSet/Working with snapshots.ipynb @@ -86,15 +86,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'__class__': 'qcodes.instrument.parameter.Parameter',\n", + "{'__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'p',\n", " 'inter_delay': 0,\n", " 'label': 'Parameter P',\n", " 'name': 'p',\n", " 'post_delay': 0,\n", " 'raw_value': 123,\n", - " 'ts': '2019-06-21 13:10:37',\n", + " 'ts': '2024-10-08 14:04:12',\n", " 'unit': 'kg',\n", + " 'validators': [],\n", " 'value': 123}\n" ] } @@ -157,14 +158,15 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'__class__': 'qcodes.instrument.parameter.Parameter',\n", + "{'__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'q',\n", " 'inter_delay': 0,\n", " 'label': 'Parameter Q',\n", " 'name': 'q',\n", " 'post_delay': 0,\n", " 'ts': None,\n", - " 'unit': 'A'}\n" + " 'unit': 'A',\n", + " 'validators': []}\n" ] } ], @@ -210,8 +212,9 @@ "text": [ "{ '__class__': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'functions': {},\n", + " 'label': 'instr',\n", " 'name': 'instr',\n", - " 'parameters': { 'IDN': { '__class__': 'qcodes.instrument.parameter.Parameter',\n", + " 'parameters': { 'IDN': { '__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'instr_IDN',\n", " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'instrument_name': 'instr',\n", @@ -222,9 +225,23 @@ " 'raw_value': None,\n", " 'ts': None,\n", " 'unit': '',\n", + " 'validators': [''],\n", " 'vals': '',\n", " 'value': None},\n", - " 'gain': { '__class__': 'qcodes.instrument.parameter.Parameter',\n", + " 'fixed_parameter': { '__class__': 'qcodes.parameters.parameter.Parameter',\n", + " 'full_name': 'instr_fixed_parameter',\n", + " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", + " 'instrument_name': 'instr',\n", + " 'inter_delay': 0,\n", + " 'label': 'fixed_parameter',\n", + " 'name': 'fixed_parameter',\n", + " 'post_delay': 0,\n", + " 'raw_value': 5,\n", + " 'ts': '2024-10-08 14:04:12',\n", + " 'unit': '',\n", + " 'validators': [],\n", + " 'value': 5},\n", + " 'gain': { '__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'instr_gain',\n", " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'instrument_name': 'instr',\n", @@ -233,11 +250,12 @@ " 'name': 'gain',\n", " 'post_delay': 0,\n", " 'raw_value': 11,\n", - " 'ts': '2019-06-21 13:10:37',\n", + " 'ts': '2024-10-08 14:04:12',\n", " 'unit': 'V',\n", + " 'validators': [''],\n", " 'vals': '',\n", " 'value': 11},\n", - " 'input': { '__class__': 'qcodes.instrument.parameter.Parameter',\n", + " 'input': { '__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'instr_input',\n", " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'instrument_name': 'instr',\n", @@ -246,11 +264,12 @@ " 'name': 'input',\n", " 'post_delay': 0,\n", " 'raw_value': 0,\n", - " 'ts': '2019-06-21 13:10:37',\n", + " 'ts': '2024-10-08 14:04:12',\n", " 'unit': 'V',\n", + " 'validators': [''],\n", " 'vals': '',\n", " 'value': 0},\n", - " 'output': { '__class__': 'qcodes.instrument.parameter.Parameter',\n", + " 'output': { '__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'instr_output',\n", " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'instrument_name': 'instr',\n", @@ -259,8 +278,9 @@ " 'name': 'output',\n", " 'post_delay': 0,\n", " 'raw_value': 0,\n", - " 'ts': '2019-06-21 13:10:37',\n", + " 'ts': '2024-10-08 14:04:12',\n", " 'unit': 'V',\n", + " 'validators': [''],\n", " 'vals': '',\n", " 'value': 0}},\n", " 'submodules': {}}\n" @@ -329,11 +349,12 @@ "output_type": "stream", "text": [ "{'components': {},\n", - " 'default_measurement': [],\n", + " 'config': None,\n", " 'instruments': {'instr': {'__class__': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'functions': {},\n", + " 'label': 'instr',\n", " 'name': 'instr',\n", - " 'parameters': {'IDN': {'__class__': 'qcodes.instrument.parameter.Parameter',\n", + " 'parameters': {'IDN': {'__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'instr_IDN',\n", " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'instrument_name': 'instr',\n", @@ -341,18 +362,35 @@ " 'label': 'IDN',\n", " 'name': 'IDN',\n", " 'post_delay': 0,\n", - " 'raw_value': {'firmware': None,\n", - " 'model': 'instr',\n", - " 'serial': None,\n", - " 'vendor': None},\n", - " 'ts': '2019-06-21 13:10:37',\n", + " 'raw_value': {'firmware': 'NA',\n", + " 'model': '\",\n", + " 'serial': 'NA',\n", + " 'vendor': 'QCoDeS'},\n", + " 'ts': '2024-10-08 14:04:12',\n", " 'unit': '',\n", + " 'validators': [''],\n", " 'vals': '',\n", - " 'value': {'firmware': None,\n", - " 'model': 'instr',\n", - " 'serial': None,\n", - " 'vendor': None}},\n", - " 'gain': {'__class__': 'qcodes.instrument.parameter.Parameter',\n", + " 'value': {'firmware': 'NA',\n", + " 'model': '\",\n", + " 'serial': 'NA',\n", + " 'vendor': 'QCoDeS'}},\n", + " 'fixed_parameter': {'__class__': 'qcodes.parameters.parameter.Parameter',\n", + " 'full_name': 'instr_fixed_parameter',\n", + " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", + " 'instrument_name': 'instr',\n", + " 'inter_delay': 0,\n", + " 'label': 'fixed_parameter',\n", + " 'name': 'fixed_parameter',\n", + " 'post_delay': 0,\n", + " 'raw_value': 5,\n", + " 'ts': '2024-10-08 '\n", + " '14:04:12',\n", + " 'unit': '',\n", + " 'validators': [],\n", + " 'value': 5},\n", + " 'gain': {'__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'instr_gain',\n", " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'instrument_name': 'instr',\n", @@ -361,12 +399,14 @@ " 'name': 'gain',\n", " 'post_delay': 0,\n", " 'raw_value': 11,\n", - " 'ts': '2019-06-21 13:10:37',\n", + " 'ts': '2024-10-08 14:04:12',\n", " 'unit': 'V',\n", + " 'validators': [''],\n", " 'vals': '',\n", " 'value': 11},\n", - " 'input': {'__class__': 'qcodes.instrument.parameter.Parameter',\n", + " 'input': {'__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'instr_input',\n", " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'instrument_name': 'instr',\n", @@ -375,12 +415,14 @@ " 'name': 'input',\n", " 'post_delay': 0,\n", " 'raw_value': 0,\n", - " 'ts': '2019-06-21 13:10:37',\n", + " 'ts': '2024-10-08 14:04:12',\n", " 'unit': 'V',\n", + " 'validators': [''],\n", " 'vals': '',\n", " 'value': 0},\n", - " 'output': {'__class__': 'qcodes.instrument.parameter.Parameter',\n", + " 'output': {'__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'instr_output',\n", " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'instrument_name': 'instr',\n", @@ -389,22 +431,25 @@ " 'name': 'output',\n", " 'post_delay': 0,\n", " 'raw_value': 0,\n", - " 'ts': '2019-06-21 '\n", - " '13:10:37',\n", + " 'ts': '2024-10-08 '\n", + " '14:04:12',\n", " 'unit': 'V',\n", + " 'validators': [''],\n", " 'vals': '',\n", " 'value': 0}},\n", " 'submodules': {}}},\n", - " 'parameters': {'p': {'__class__': 'qcodes.instrument.parameter.Parameter',\n", + " 'parameters': {'p': {'__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'p',\n", " 'inter_delay': 0,\n", " 'label': 'Parameter P',\n", " 'name': 'p',\n", " 'post_delay': 0,\n", " 'raw_value': 456,\n", - " 'ts': '2019-06-21 13:10:37',\n", + " 'ts': '2024-10-08 14:04:12',\n", " 'unit': 'kg',\n", + " 'validators': [],\n", " 'value': 456}}}\n" ] } @@ -419,13 +464,15 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Saving snapshot next to the measurement data\n", + "## Saving snapshots next to the measurement data\n", "\n", "With the power of the station object, it is now possible to conveniently associate the snapshot information with the measured data.\n", "\n", "In order to do so, a station needs to be created, and then that station needs to be provided to the `Measurement` object. If no station is explicitly provided, the `Measurement` object will use the default station, `Station.default` (refer to `Measurement` and `Station` objects docstrings for more information). At the moment the new measurement run is started, a snapshot of the whole station will be taken, and added next to the measured data.\n", "\n", - "Note that the snapshot gets stored in a JSON format (an automatic convertion from python dictionary to JSON takes place). This is done in order to ensure that the snapshot can be read in environments other than python. JSON is an extemely popular data format, and all platforms/environments/languages/frameworks have means to read JSON-formatted data." + "The measured dataset also automatically snapshots the parameters involved in the measurement and stores it alongside the station snapshot.\n", + "\n", + "Note that these snapshots get stored in a JSON format (an automatic convertion from python dictionary to JSON takes place). This is done in order to ensure that the snapshot can be read in environments other than python. JSON is an extemely popular data format, and all platforms/environments/languages/frameworks have means to read JSON-formatted data." ] }, { @@ -456,7 +503,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 10, @@ -473,17 +520,9 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Starting experimental run with id: 5\n" - ] - } - ], + "outputs": [], "source": [ "with measurement.run() as data_saver:\n", " input_value = 111\n", @@ -510,7 +549,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now we have a dataset that contains data from the measurement run. It also contains the snapshot.\n", + "Now we have a dataset that contains data from the measurement run. It also contains the station and parameters snapshots.\n", "\n", "In order to access the snapshot, use the `DataSet`'s properties called `snapshot` and `snapshot_raw`. As their docstrings declare, the former returns the snapshot of the run as a python dictionary, while the latter returns it as JSON string (in other words, in exactly the same format as it is stored in the experiments database)." ] @@ -562,7 +601,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Finally, let's pretty-print the snapshot. Notice that the values of the `input` and `output` parameters of the `instr` instrument have `0`s as values, and not `111` and `222` that were set during the measurement run." + "Finally, let's pretty-print the snapshot. Notice that the values of the `input` and `output` parameters of the `instr` instrument have `0`s as values, and not `111` and `222` that were set during the measurement run.\n", + "\n", + "Also note that the `station` top-level-key contains the station snapshot, while the `parameters` top-level-key contains a snapshot of all the measurement parameters." ] }, { @@ -574,12 +615,41 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'station': {'components': {},\n", - " 'default_measurement': [],\n", + "{'parameters': {'input': {'__class__': 'qcodes.parameters.parameter.Parameter',\n", + " 'full_name': 'instr_input',\n", + " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", + " 'instrument_name': 'instr',\n", + " 'inter_delay': 0,\n", + " 'label': 'Gate input',\n", + " 'name': 'input',\n", + " 'post_delay': 0,\n", + " 'raw_value': 0,\n", + " 'ts': '2024-10-08 14:04:12',\n", + " 'unit': 'V',\n", + " 'validators': [''],\n", + " 'vals': '',\n", + " 'value': 0},\n", + " 'output': {'__class__': 'qcodes.parameters.parameter.Parameter',\n", + " 'full_name': 'instr_output',\n", + " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", + " 'instrument_name': 'instr',\n", + " 'inter_delay': 0,\n", + " 'label': 'Gate output',\n", + " 'name': 'output',\n", + " 'post_delay': 0,\n", + " 'raw_value': 0,\n", + " 'ts': '2024-10-08 14:04:12',\n", + " 'unit': 'V',\n", + " 'validators': [''],\n", + " 'vals': '',\n", + " 'value': 0}},\n", + " 'station': {'components': {},\n", + " 'config': None,\n", " 'instruments': {'instr': {'__class__': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'functions': {},\n", + " 'label': 'instr',\n", " 'name': 'instr',\n", - " 'parameters': {'IDN': {'__class__': 'qcodes.instrument.parameter.Parameter',\n", + " 'parameters': {'IDN': {'__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'instr_IDN',\n", " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'instrument_name': 'instr',\n", @@ -587,19 +657,36 @@ " 'label': 'IDN',\n", " 'name': 'IDN',\n", " 'post_delay': 0,\n", - " 'raw_value': {'firmware': None,\n", - " 'model': 'instr',\n", - " 'serial': None,\n", - " 'vendor': None},\n", - " 'ts': '2019-06-21 '\n", - " '13:10:37',\n", + " 'raw_value': {'firmware': 'NA',\n", + " 'model': '\",\n", + " 'serial': 'NA',\n", + " 'vendor': 'QCoDeS'},\n", + " 'ts': '2024-10-08 '\n", + " '14:04:12',\n", " 'unit': '',\n", + " 'validators': [''],\n", " 'vals': '',\n", - " 'value': {'firmware': None,\n", - " 'model': 'instr',\n", - " 'serial': None,\n", - " 'vendor': None}},\n", - " 'gain': {'__class__': 'qcodes.instrument.parameter.Parameter',\n", + " 'value': {'firmware': 'NA',\n", + " 'model': '\",\n", + " 'serial': 'NA',\n", + " 'vendor': 'QCoDeS'}},\n", + " 'fixed_parameter': {'__class__': 'qcodes.parameters.parameter.Parameter',\n", + " 'full_name': 'instr_fixed_parameter',\n", + " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", + " 'instrument_name': 'instr',\n", + " 'inter_delay': 0,\n", + " 'label': 'fixed_parameter',\n", + " 'name': 'fixed_parameter',\n", + " 'post_delay': 0,\n", + " 'raw_value': 5,\n", + " 'ts': '2024-10-08 '\n", + " '14:04:12',\n", + " 'unit': '',\n", + " 'validators': [],\n", + " 'value': 5},\n", + " 'gain': {'__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'instr_gain',\n", " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'instrument_name': 'instr',\n", @@ -609,13 +696,15 @@ " 'name': 'gain',\n", " 'post_delay': 0,\n", " 'raw_value': 11,\n", - " 'ts': '2019-06-21 '\n", - " '13:10:37',\n", + " 'ts': '2024-10-08 '\n", + " '14:04:12',\n", " 'unit': 'V',\n", + " 'validators': [''],\n", " 'vals': '',\n", " 'value': 11},\n", - " 'input': {'__class__': 'qcodes.instrument.parameter.Parameter',\n", + " 'input': {'__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'instr_input',\n", " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'instrument_name': 'instr',\n", @@ -625,13 +714,15 @@ " 'name': 'input',\n", " 'post_delay': 0,\n", " 'raw_value': 0,\n", - " 'ts': '2019-06-21 '\n", - " '13:10:37',\n", + " 'ts': '2024-10-08 '\n", + " '14:04:12',\n", " 'unit': 'V',\n", + " 'validators': [''],\n", " 'vals': '',\n", " 'value': 0},\n", - " 'output': {'__class__': 'qcodes.instrument.parameter.Parameter',\n", + " 'output': {'__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'instr_output',\n", " 'instrument': 'qcodes.instrument_drivers.mock_instruments.DummyInstrument',\n", " 'instrument_name': 'instr',\n", @@ -641,22 +732,25 @@ " 'name': 'output',\n", " 'post_delay': 0,\n", " 'raw_value': 0,\n", - " 'ts': '2019-06-21 '\n", - " '13:10:37',\n", + " 'ts': '2024-10-08 '\n", + " '14:04:12',\n", " 'unit': 'V',\n", + " 'validators': [''],\n", " 'vals': '',\n", " 'value': 0}},\n", " 'submodules': {}}},\n", - " 'parameters': {'p': {'__class__': 'qcodes.instrument.parameter.Parameter',\n", + " 'parameters': {'p': {'__class__': 'qcodes.parameters.parameter.Parameter',\n", " 'full_name': 'p',\n", " 'inter_delay': 0,\n", " 'label': 'Parameter P',\n", " 'name': 'p',\n", " 'post_delay': 0,\n", " 'raw_value': 456,\n", - " 'ts': '2019-06-21 13:10:37',\n", + " 'ts': '2024-10-08 14:04:12',\n", " 'unit': 'kg',\n", + " 'validators': [],\n", " 'value': 456}}}}\n" ] } @@ -669,7 +763,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that the snapshot that we have just loaded from the dataset is almost the same as the snapshot that we directly obtained from the station above. The only difference is that the snapshot loaded from the dataset has a top-level `station` field. If you do not trust me, have a look at the following `assert` statement for the proof." + "Note that the snapshot that we have just loaded from the dataset is almost the same as the snapshot that we directly obtained from the station above. One difference is that the snapshot loaded from the dataset has a top-level `station` field. It also has a top-level `parameters` field. If you do not trust me, have a look at the following `assert` statement for the proof." ] }, { @@ -678,14 +772,7 @@ "metadata": {}, "outputs": [], "source": [ - "assert {\"station\": snapshot_of_station} == snapshot_of_run" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Comparing how two DataSets were taken" + "assert snapshot_of_station == snapshot_of_run[\"station\"]" ] }, { @@ -698,20 +785,9 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "measurement = Measurement(experiment, station)\n", "\n", @@ -721,17 +797,9 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Starting experimental run with id: 6\n" - ] - } - ], + "outputs": [], "source": [ "instr.gain(400) # Oops!\n", "with measurement.run() as data_saver:\n", @@ -752,7 +820,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The `diff_param_values` function tells us about the parameters that changed betw" + "The `diff_param_values` function tells us about the parameters that changed between the two snapshots" ] }, { @@ -761,27 +829,14 @@ "metadata": {}, "outputs": [], "source": [ - "from qcodes.utils.metadata import diff_param_values" + "from qcodes.utils import diff_param_values" ] }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{('instr', 'output'): (0, 222),\n", - " ('instr', 'gain'): (11, 400),\n", - " ('instr', 'input'): (0, 111)}" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "diff_param_values(dataset.snapshot, bad_dataset.snapshot).changed" ] @@ -810,7 +865,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.4" + "version": "3.11.8" }, "toc": { "base_numbering": 1, diff --git a/src/qcodes/dataset/data_set.py b/src/qcodes/dataset/data_set.py index 231eee60fc8..a2230f450aa 100644 --- a/src/qcodes/dataset/data_set.py +++ b/src/qcodes/dataset/data_set.py @@ -329,7 +329,7 @@ def prepare( parent_datasets: Sequence[Mapping[Any, Any]] = (), write_in_background: bool = False, ) -> None: - self.add_snapshot(json.dumps({"station": snapshot}, cls=NumpyJSONEncoder)) + self.add_snapshot(json.dumps(snapshot, cls=NumpyJSONEncoder)) if interdeps == InterDependencies_(): raise RuntimeError("No parameters supplied") diff --git a/src/qcodes/dataset/data_set_in_memory.py b/src/qcodes/dataset/data_set_in_memory.py index 14ff4002373..3685256da21 100644 --- a/src/qcodes/dataset/data_set_in_memory.py +++ b/src/qcodes/dataset/data_set_in_memory.py @@ -421,7 +421,7 @@ def prepare( if not self.pristine: raise RuntimeError("Cannot prepare a dataset that is not pristine.") - self.add_snapshot(json.dumps({"station": snapshot}, cls=NumpyJSONEncoder)) + self.add_snapshot(json.dumps(snapshot, cls=NumpyJSONEncoder)) if interdeps == InterDependencies_(): raise RuntimeError("No parameters supplied") diff --git a/src/qcodes/dataset/measurements.py b/src/qcodes/dataset/measurements.py index 110b959e91c..97e8d50286b 100644 --- a/src/qcodes/dataset/measurements.py +++ b/src/qcodes/dataset/measurements.py @@ -549,6 +549,7 @@ def __init__( in_memory_cache: bool | None = None, dataset_class: DataSetType = DataSetType.DataSet, parent_span: trace.Span | None = None, + registered_parameters: Sequence[ParameterBase] | None = None, ) -> None: if in_memory_cache is None: in_memory_cache = qc.config.dataset.in_memory_cache @@ -577,6 +578,7 @@ def __init__( self._in_memory_cache = in_memory_cache self._parent_span = parent_span self.ds: DataSetProtocol + self._registered_parameters = registered_parameters @staticmethod def _calculate_write_period( @@ -661,9 +663,15 @@ def __enter__(self) -> DataSaver: station = self.station if station is not None: - snapshot = station.snapshot() + snapshot = {"station": station.snapshot()} else: snapshot = {} + if self._registered_parameters is not None: + parameter_snapshot = { + param.short_name: param.snapshot() + for param in self._registered_parameters + } + snapshot["parameters"] = parameter_snapshot self.ds.prepare( snapshot=snapshot, @@ -803,6 +811,7 @@ def __init__( self._shapes: Shapes | None = None self._parent_datasets: list[dict[str, str]] = [] self._extra_log_info: str = "" + self._registered_parameters: list[ParameterBase] = [] @property def parameters(self) -> dict[str, ParamSpecBase]: @@ -926,7 +935,6 @@ def register_parameter( f"Can not register object of type {type(parameter)}. Can only " "register a QCoDeS Parameter." ) - paramtype = self._infer_paramtype(parameter, paramtype) # default to numeric if paramtype is None: @@ -981,6 +989,7 @@ def register_parameter( raise RuntimeError( f"Does not know how to register a parameter of type {type(parameter)}" ) + self._registered_parameters.append(parameter) return self @@ -1034,6 +1043,7 @@ def _register_parameter( setpoints: setpoints_type | None, basis: setpoints_type | None, paramtype: str, + metadata: dict[str, Any] | None = None, ) -> T: """ Update the interdependencies object with a new group @@ -1278,9 +1288,9 @@ def unregister_parameter(self, parameter: setpoints_type) -> None: running this measurement """ if isinstance(parameter, ParameterBase): - param = str_or_register_name(parameter) + param_name = str_or_register_name(parameter) elif isinstance(parameter, str): - param = parameter + param_name = parameter else: raise ValueError( "Wrong input type. Must be a QCoDeS parameter or" @@ -1288,13 +1298,27 @@ def unregister_parameter(self, parameter: setpoints_type) -> None: ) try: - paramspec: ParamSpecBase = self._interdeps[param] + paramspec: ParamSpecBase = self._interdeps[param_name] except KeyError: return self._interdeps = self._interdeps.remove(paramspec) - log.info(f"Removed {param} from Measurement.") + # Must follow interdeps removal, because interdeps removal may error + if isinstance(parameter, ParameterBase): + try: + self._registered_parameters.remove(parameter) + except ValueError: + return + elif isinstance(parameter, str): + with_parameters_removed = [ + param + for param in self._registered_parameters + if parameter not in (param.name, param.register_name) + ] + self._registered_parameters = with_parameters_removed + + log.info(f"Removed {param_name} from Measurement.") def add_before_run(self: T, func: Callable[..., Any], args: Sequence[Any]) -> T: """ @@ -1412,6 +1436,7 @@ def run( in_memory_cache=in_memory_cache, dataset_class=dataset_class, parent_span=parent_span, + registered_parameters=self._registered_parameters, ) diff --git a/tests/dataset/test_snapshot.py b/tests/dataset/test_snapshot.py index b706b849356..607f992b493 100644 --- a/tests/dataset/test_snapshot.py +++ b/tests/dataset/test_snapshot.py @@ -43,7 +43,9 @@ def test_station_snapshot_during_measurement( measurement.register_parameter(dac.ch1) measurement.register_parameter(dmm.v1, setpoints=[dac.ch1]) - + snapshot_of_parameters = { + parameter.short_name: parameter.snapshot() for parameter in (dac.ch1, dmm.v1) + } with measurement.run() as data_saver: data_saver.add_result((dac.ch1, 7), (dmm.v1, 5)) @@ -53,7 +55,10 @@ def test_station_snapshot_during_measurement( json_snapshot_from_dataset = data_saver.dataset.get_metadata("snapshot") # type: ignore[attr-defined] snapshot_from_dataset = json.loads(json_snapshot_from_dataset) - expected_snapshot = {"station": snapshot_of_station} + expected_snapshot = { + "station": snapshot_of_station, + "parameters": snapshot_of_parameters, + } assert expected_snapshot == snapshot_from_dataset # 2. Test `snapshot_raw` property