Skip to content
Merged
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
3 changes: 2 additions & 1 deletion docs/examples/Measure without a Loop.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
35 changes: 1 addition & 34 deletions docs/examples/toymodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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,)
10 changes: 1 addition & 9 deletions qcodes/data/data_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,15 +392,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?
Expand Down
36 changes: 36 additions & 0 deletions qcodes/instrument/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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,)
18 changes: 16 additions & 2 deletions qcodes/tests/test_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -79,7 +80,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,
Expand Down Expand Up @@ -118,6 +119,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,
Expand All @@ -127,7 +131,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,
Expand Down Expand Up @@ -202,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)
Expand Down