From 1e38e1f4f33e442cb38574e03b7a97e1aacead6f Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Mon, 19 Dec 2016 14:01:01 +0100 Subject: [PATCH 1/6] fix: make sync a no-opt on local data fixes #380 by avoiding to overwrite data with partial data from disk --- qcodes/data/data_set.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/qcodes/data/data_set.py b/qcodes/data/data_set.py index 31c5a0bb1a4e..ff080b6ed6c0 100644 --- a/qcodes/data/data_set.py +++ b/qcodes/data/data_set.py @@ -386,15 +386,7 @@ def sync(self): # could find a robust and intuitive way to make modifications to the # version on the DataServer from the main copy) if not self.is_live_mode: - # LOCAL DataSet - just read it in - # Compare timestamps to avoid overwriting unsaved data - if self.last_store > self.last_write: - return True - try: - self.read() - except IOError: - # if no files exist, they probably haven't been created yet. - pass + # LOCAL DataSet - no need to sync just use local data return False # TODO - for remote live plotting, maybe set some timestamp # threshold and call it static after it's been dormant a long time? From 90df00c47f4471715a9eb56880b8c1989d3695b2 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Mon, 9 Jan 2017 09:43:30 +0100 Subject: [PATCH 2/6] Fix: data_manager defaults to true So need to change the default in this test --- qcodes/tests/test_loop.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py index e238e702eb9f..c040950ca8f4 100644 --- a/qcodes/tests/test_loop.py +++ b/qcodes/tests/test_loop.py @@ -79,7 +79,7 @@ def test_background_and_datamanager(self): # you can only do in-memory loops if you set data_manager=False # TODO: this is the one place we don't do quiet=True - test that we # really print stuff? - data = self.loop.run(location=self.location, background=True) + data = self.loop.run(location=self.location, background=True, data_manager=True) self.check_empty_data(data) # wait for process to finish (ensures that this was run in the bg, From 70353af3d8e1ea72957af2d175200062decd4fb0 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Mon, 9 Jan 2017 09:44:41 +0100 Subject: [PATCH 3/6] Fix: syncing data from a background process Will no longer work so update the relevant test --- qcodes/tests/test_loop.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py index c040950ca8f4..c1f46cdbb3b8 100644 --- a/qcodes/tests/test_loop.py +++ b/qcodes/tests/test_loop.py @@ -118,6 +118,9 @@ def test_local_instrument(self): self.check_loop_data(data) def test_background_no_datamanager(self): + # We don't support syncing data from a background process + # if not using a datamanager. See warning in ActiveLoop.run() + # So we expect the data to be empty even after running. data = self.loop.run(location=self.location, background=True, data_manager=False, @@ -127,7 +130,7 @@ def test_background_no_datamanager(self): self.loop.process.join() data.sync() - self.check_loop_data(data) + self.check_empty_data(data) def test_foreground_and_datamanager(self): data = self.loop.run(location=self.location, background=False, From c1798816c58f8f1f9310609ebcf8590dffafdd8f Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Thu, 12 Jan 2017 14:33:07 +0100 Subject: [PATCH 4/6] Fix: move ArrayGetter into qcodes so it can be used in tests --- docs/examples/toymodel.py | 35 +---------------------------------- qcodes/instrument/mock.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/docs/examples/toymodel.py b/docs/examples/toymodel.py index 1e117150ff68..fb28c353b4aa 100644 --- a/docs/examples/toymodel.py +++ b/docs/examples/toymodel.py @@ -4,7 +4,7 @@ from qcodes import MockInstrument, MockModel, Parameter, Loop, DataArray from qcodes.utils.validators import Numbers - +from qcodes.instrument.mock import ArrayGetter class AModel(MockModel): def __init__(self): @@ -147,36 +147,3 @@ def get(self): array = data.arrays[self.measured_param.full_name] return (array, array.mean()) - -class ArrayGetter(Parameter): - """ - Example parameter that just returns a single array - - TODO: in theory you can make this same Parameter with - name, label & shape (instead of names, labels & shapes) and altered - setpoints (not wrapped in an extra tuple) and this mostly works, - but when run in a loop it doesn't propagate setpoints to the - DataSet. We could track down this bug, but perhaps a better solution - would be to only support the simplest and the most complex Parameter - forms (ie cases 1 and 5 in the Parameter docstring) and do away with - the intermediate forms that make everything more confusing. - """ - def __init__(self, measured_param, sweep_values, delay): - name = measured_param.name - super().__init__(names=(name,)) - self._instrument = getattr(measured_param, '_instrument', None) - self.measured_param = measured_param - self.sweep_values = sweep_values - self.delay = delay - self.shapes = ((len(sweep_values),),) - set_array = DataArray(parameter=sweep_values.parameter, - preset_data=sweep_values) - self.setpoints = ((set_array,),) - if hasattr(measured_param, 'label'): - self.labels = (measured_param.label,) - - def get(self): - loop = Loop(self.sweep_values, self.delay).each(self.measured_param) - data = loop.run_temp() - array = data.arrays[self.measured_param.full_name] - return (array,) diff --git a/qcodes/instrument/mock.py b/qcodes/instrument/mock.py index 5bf8df500a5b..9d29d66925f7 100644 --- a/qcodes/instrument/mock.py +++ b/qcodes/instrument/mock.py @@ -3,6 +3,9 @@ from datetime import datetime from .base import Instrument +from .parameter import Parameter +from qcodes import Loop +from qcodes.data.data_array import DataArray from qcodes.process.server import ServerManager, BaseServer from qcodes.utils.nested_attrs import _NoDefault @@ -279,3 +282,36 @@ def _delattr(self, attr): See NestedAttrAccess for details. """ self.ask('method_call', 'delattr', attr) + +class ArrayGetter(Parameter): + """ + Example parameter that just returns a single array + + TODO: in theory you can make this same Parameter with + name, label & shape (instead of names, labels & shapes) and altered + setpoints (not wrapped in an extra tuple) and this mostly works, + but when run in a loop it doesn't propagate setpoints to the + DataSet. We could track down this bug, but perhaps a better solution + would be to only support the simplest and the most complex Parameter + forms (ie cases 1 and 5 in the Parameter docstring) and do away with + the intermediate forms that make everything more confusing. + """ + def __init__(self, measured_param, sweep_values, delay): + name = measured_param.name + super().__init__(names=(name,)) + self._instrument = getattr(measured_param, '_instrument', None) + self.measured_param = measured_param + self.sweep_values = sweep_values + self.delay = delay + self.shapes = ((len(sweep_values),),) + set_array = DataArray(parameter=sweep_values.parameter, + preset_data=sweep_values) + self.setpoints = ((set_array,),) + if hasattr(measured_param, 'label'): + self.labels = (measured_param.label,) + + def get(self): + loop = Loop(self.sweep_values, self.delay).each(self.measured_param) + data = loop.run_temp() + array = data.arrays[self.measured_param.full_name] + return (array,) \ No newline at end of file From 70c985ad9579430d67cf4957305e59b5d9f997e0 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Thu, 12 Jan 2017 14:33:33 +0100 Subject: [PATCH 5/6] Fix: add tests for #380 --- qcodes/tests/test_loop.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py index c1f46cdbb3b8..19776e70b938 100644 --- a/qcodes/tests/test_loop.py +++ b/qcodes/tests/test_loop.py @@ -13,6 +13,7 @@ from qcodes.data.io import DiskIO from qcodes.data.data_array import DataArray from qcodes.data.manager import get_data_manager +from qcodes.instrument.mock import ArrayGetter from qcodes.instrument.parameter import Parameter, ManualParameter from qcodes.process.helpers import kill_processes from qcodes.process.qcodes_process import QcodesProcess @@ -205,6 +206,16 @@ def test_enqueue(self): loop.run_temp() self.assertFalse(hasattr(loop, 'process')) + def test_sync_no_overwrite(self): + # Test fix for 380, this tests that the setpoints are not incorrectly + # overwritten by data_set.sync() for this to happen with the original code + # the delay must be larger than the write period otherwise sync is a no opt. + + loop = Loop(self.gates.chan1.sweep(0, 1, 1), delay=0.1).each(ArrayGetter(self.meter.amplitude, + self.gates.chan2[0:1:1], 0.000001)) + data = loop.get_data_set(name='testsweep', write_period=0.01) + _ = loop.with_bg_task(data.sync).run() + assert not np.isnan(data.chan2).any() def sleeper(t): time.sleep(t) From 12b48de0a8c6025773fefbc3348e374ff2b8803d Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Thu, 12 Jan 2017 14:35:40 +0100 Subject: [PATCH 6/6] Doc: example notebook change ArrayGetter import --- docs/examples/Measure without a Loop.ipynb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/examples/Measure without a Loop.ipynb b/docs/examples/Measure without a Loop.ipynb index ec26dcff0b99..828db49fce49 100644 --- a/docs/examples/Measure without a Loop.ipynb +++ b/docs/examples/Measure without a Loop.ipynb @@ -379,7 +379,8 @@ }, "outputs": [], "source": [ - "from toymodel import AModel, MockGates, MockSource, MockMeter, AverageAndRaw, ArrayGetter\n", + "from toymodel import AModel, MockGates, MockSource, MockMeter, AverageAndRaw\n", + "from qcodes.instrument.mock import ArrayGetter\n", "\n", "# now create this \"experiment\", note that all these are instruments \n", "model = AModel()\n",