Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hotfix/live plot #270

Merged
merged 6 commits into from
Jul 21, 2016
Merged
Show file tree
Hide file tree
Changes from 2 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
107 changes: 60 additions & 47 deletions qcodes/data/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,61 +128,74 @@ def match_save_range(self, group, file_exists, only_complete=True):
saved unless it contains no NaN values
"""
inner_setpoint = group.set_arrays[-1]
last_saved_index = (inner_setpoint.last_saved_index if file_exists
else None)
modified_range = inner_setpoint.modified_range
full_dim_data = (inner_setpoint, ) + group.data

# always return None if there are no modifications,
# even if there are last_saved_index inconsistencies
# so we don't do extra writing just to reshape the file
for array in full_dim_data:
if array.modified_range:
break
else:
return None

last_saved_index = inner_setpoint.last_saved_index

if last_saved_index is None or not file_exists:
return self._match_save_range_whole_file(
full_dim_data, only_complete)

# force overwrite if inconsistent last_saved_index
for array in group.data:
# force overwrite if inconsistent last_saved_index
if array.last_saved_index != last_saved_index:
last_saved_index = None

# find the modified_range that encompasses all modifications
amr = array.modified_range
if amr:
if modified_range:
modified_range = (min(modified_range[0], amr[0]),
max(modified_range[1], amr[1]))
else:
modified_range = amr

if only_complete and modified_range:
modified_range = self._get_completed_range(modified_range,
inner_setpoint.shape,
group.data)
if not modified_range:
return None

# calculate the range to save
if not modified_range:
# nothing to save
return None
if last_saved_index is None or last_saved_index >= modified_range[0]:
# need to overwrite - start save from 0
return (0, modified_range[1])
else:
# we can append! save only from last save to end of mods
return (last_saved_index + 1, modified_range[1])
return self._match_save_range_whole_file(
full_dim_data, only_complete)

def _get_completed_range(self, modified_range, shape, arrays):
"""
check the last data point to see if it's complete.
return self._match_save_range_incremental(
full_dim_data, last_saved_index, only_complete)

If it's not complete, back up one point so that we don't need
to rewrite this point later on when it *is* complete
def _match_save_range_whole_file(self, arrays, only_complete):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@giulioungaretti is this a warning you consider worthwhile to include? I suppose we could "fix" it by pulling this function out of the class (bad! makes it harder to read) or probably by turning this into a @staticmethod but to me that just seems distracting for not much benefit, so I'd vote to turn this warning off unless you have a strong opinion otherwise.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's super super important actually :D And to suppress the warning with @staticmethod is the way I would go ! It's very pythonic 🐍

For me it's a clear message that the method/function is pure, and has no relation to the state of the object but just a logical relation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I can see that argument... for my own part I would have preferred not to introduce a whole new concept (@staticmethod) just to signal this, but OK.

max_save = None
agg = (min if only_complete else max)
for array in arrays:
array_max = array.last_saved_index
if array_max is None:
array_max = -1
mr = array.modified_range
if mr:
array_max = max(array_max, mr[1])
max_save = (array_max if max_save is None else
agg(max_save, array_max))

if max_save >= 0:
return (0, max_save)
else:
return None

This should work for regular `Loop` data that comes in sequentially.
But if you have non-sequential data, such as a parallel simulation,
then you would want to look farther back.
"""
last_pt = modified_range[1]
indices = np.unravel_index(last_pt, shape)
def _match_save_range_incremental(self, arrays, last_saved_index,
only_complete):
mod_ranges = []
for array in arrays:
if np.isnan(array[indices]):
if last_pt == modified_range[0]:
mr = array.modified_range
if not mr:
if only_complete:
return None
else:
return (modified_range[0], last_pt - 1)
return modified_range
continue
mod_ranges.append(mr)

mod_range = mod_ranges[0]
agg = (min if only_complete else max)
for mr in mod_ranges[1:]:
mod_range = (min(mod_range[0], mr[0]),
agg(mod_range[1], mr[1]))

if last_saved_index >= mod_range[1]:
return (0, last_saved_index)
elif last_saved_index >= mod_range[0]:
return (0, mod_range[1])
else:
return (last_saved_index + 1, mod_range[1])

def group_arrays(self, arrays):
"""
Expand Down
9 changes: 9 additions & 0 deletions qcodes/instrument/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ def default_server_name(cls, **kwargs):
return model.name.replace('Model', 'MockInsts')
return 'MockInstruments'

def get_idn(self):
"""Shim for IDN parameter."""
return {
'vendor': None,
'model': type(self).__name__,
'serial': self.name,
'firmware': None
}

def write_raw(self, cmd):
"""
Low-level interface to ``model.write``.
Expand Down
53 changes: 32 additions & 21 deletions qcodes/tests/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,39 +126,50 @@ def test_match_save_range(self):
for lsi, start in [(None, 0), (0, 1), (1, 2), (2, 3), (3, 0), (4, 0)]:
data.x_set.last_saved_index = data.y.last_saved_index = lsi

# inconsistent modified_range: expands to greatest extent
# so these situations are identical
for xmr, ymr in ([(4, 4), (3, 3)], [(3, 4), None], [None, (3, 4)]):
# inconsistent modified_range: if only_complete is False, expands
# to greatest extent so these situations are identical
# if only_complete is True, only gets to the last common point
for xmr, ymr, last_common in (
[(4, 4), (3, 3), 3],
[(3, 4), None, None],
[None, (3, 4), None]):
data.x_set.modified_range = xmr
data.y.modified_range = ymr

save_range = formatter.match_save_range(group,
file_exists=False)
save_range = formatter.match_save_range(
group, file_exists=False, only_complete=False)
self.assertEqual(save_range, (0, 4))

save_range = formatter.match_save_range(group,
file_exists=True)
save_range = formatter.match_save_range(
group, file_exists=True, only_complete=False)
self.assertEqual(save_range, (start, 4))

# inconsistent last_saved_index: need to overwrite no matter what
save_all = formatter.match_save_range(group, file_exists=False)
save_inc = formatter.match_save_range(group, file_exists=True)
if last_common:
# if last_saved_index is greater than we would otherwise
# save, we still go up to last_saved_index (wouldn't want
# this write to delete data!)
last_save = max(last_common, lsi) if lsi else last_common
self.assertEqual(save_all, (0, last_save),
(lsi, xmr, ymr))
self.assertEqual(save_inc, (start, last_save),
(lsi, xmr, ymr))
else:
if lsi is None:
self.assertIsNone(save_all)
else:
self.assertEqual(save_all, (0, lsi))
self.assertIsNone(save_inc)

# inconsistent last_saved_index: need to overwrite if there are any
# modifications
data.x_set.last_saved_index = 1
data.y.last_saved_index = 2
data.x_set.modified_range = data.y.modified_range = (3, 4)
save_range = formatter.match_save_range(group, file_exists=True)
self.assertEqual(save_range, (0, 4))

# missing data point: don't write it unless only_complete is False
# but this will only back up one point!
data.y[4] = float('nan')
data.y[3] = float('nan')
data.x_set.last_saved_index = data.y.last_saved_index = 2

save_range = formatter.match_save_range(group, file_exists=True)
self.assertEqual(save_range, (3, 3))

save_range = formatter.match_save_range(group, file_exists=True,
only_complete=False)
self.assertEqual(save_range, (3, 4))


class TestGNUPlotFormat(TestCase):
def setUp(self):
Expand Down
8 changes: 8 additions & 0 deletions qcodes/tests/test_instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,14 @@ def test_mock_instrument(self):
gates.call('reset')
self.assertEqual(gates.get('chan0'), 0)

def test_mock_idn(self):
self.assertEqual(self.gates.IDN(), {
'vendor': None,
'model': 'MockGates',
'serial': 'gates',
'firmware': None
})

def test_mock_set_sweep(self):
gates = self.gates
gates.set('chan0step', 0.5)
Expand Down