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

Feat/channelization further work #641

Merged

Conversation

jenshnielsen
Copy link
Collaborator

@jenshnielsen jenshnielsen commented Jun 16, 2017

A few additional changes on top of the channelization

  • Refactor instrument and instrumentchannel to inherit from instrumentbase, to avoid removing methods from channel
  • Convert the channels within a channel list to a named tuple, allowing them to be acesed as inst.channels.channelname
  • Add support for allowing channels to be one indexed
  • make sure that channels are included in print_readable_snapshot

@spauka @WilliamHPNielsen

Copy link
Contributor

@WilliamHPNielsen WilliamHPNielsen left a comment

Choose a reason for hiding this comment

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

Review of channel.py

Apart from these modest changes:

  • PEP8! Half the file has too long lines
  • Some comments are now obsolete

@@ -167,9 +140,10 @@ class ChannelList(Metadatable):

"""

def __init__(self, parent, name, chan_type: type, chan_list=None,
def __init__(self, parent: Instrument, name, chan_type: type, chan_list=None,
Copy link
Contributor

Choose a reason for hiding this comment

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

Either we use type annotations or we don't (and I guess we are moving towards using them), but we should not mix. Also, the __init__ function raises errors if chan_type and multichan_paramclass are not something which is more specific than type.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Why not, it's gradual typing after all ;) That aside it's easy to add them but the main benefit comes from annotating the chan_type because the linter has trouble figuring out that we are passing a Class and not an instance of a Class but sure it's easy to add the rest.

I am not sure that there is a better way of annotating that this is a Class not an instance of the Class. type(multichan_paramclass) is not what you are looking for at least.

oneindexed=self._oneindexed)
elif self._oneindexed:
if i < 1:
raise IndexError("1 indexed channel lists only support positive indexes")
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above.

@@ -206,9 +181,18 @@ def __getitem__(self, i):
i (int/slice): Either a single channel index or a slice of channels to get
"""
if isinstance(i, slice):
if self._oneindexed:
if i.start < 1 or i.stop < 1:
raise IndexError("1 indexed channel lists only support positive indexes")
Copy link
Contributor

Choose a reason for hiding this comment

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

Merriam-Webster allows for both forms, but I prefer "indices" over "indexes".

@@ -279,7 +264,7 @@ def index(self, obj):
Args:
obj(chan_type): The object to find in the channel list.
"""
return self._channels.index(obj)
return self._channels.index(obj) + self._oneindexed
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it's just me, but I would find self._channels.index(obj) + int(self._oneindexed) to be more obvious.

@@ -296,6 +281,11 @@ def insert(self, index, obj):
raise TypeError("All items in a channel list must be of the same type."
" Adding {} to a list of {}.".format(type(obj).__name__,
self._chan_type.__name__))
if self._oneindexed:
if index < 1:
raise IndexError("1 based channel lists only support positive indexes")
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above.

self.name = str(name)
self.parameters = {}
self.functions = {}
self.submodules = {}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why does the InstrumentBase have submodules? Does it need them? And if so, should it not be in the docstring and there be a add_submodule method?

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess we still need the submodules mentioned in the docstring.


print(self.name + ':')
print('{0:<{1}}'.format('\tparameter ', par_field_len) + 'value')
print('-'*80)
Copy link
Contributor

Choose a reason for hiding this comment

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

80 should probably be max_chars.

submodule.print_readable_snapshot(update, max_chars)

#
# shortcuts to parameters & setters & getters #
Copy link
Contributor

Choose a reason for hiding this comment

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

One space too many 😺


print(self.name + ':')
print('{0:<{1}}'.format('\tparameter ', par_field_len) + 'value')
print('-'*80)
Copy link
Contributor

Choose a reason for hiding this comment

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

This 80 character long line should probably be max_chars long.

@jenshnielsen
Copy link
Collaborator Author

Should check how this works with the QCodes Monitor

Copy link
Contributor

@WilliamHPNielsen WilliamHPNielsen left a comment

Choose a reason for hiding this comment

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

Re the changes: Soooo pretty 😃
Re monitor: Agreed.

@spauka
Copy link
Contributor

spauka commented Jun 20, 2017 via email

@jenshnielsen
Copy link
Collaborator Author

Im not sure, I don't particularly like it either but I fear that users will be very unhappy with a situation where chan[0] maps to channel 1 on an instrument

@spauka
Copy link
Contributor

spauka commented Jun 20, 2017 via email

@WilliamHPNielsen
Copy link
Contributor

Hmm... It's bit hard to be strongly in favour of either.

I don't see porting of code from one driver to the other ever happening easily, so I am not very concerned about that aspect of things. Instruments are in my experience always in a world of their own, and two boxes never quite behave the same way.

Having 1-indexed python lists are not nice, that is for sure. They are not too uncommon in the scientific world, though, with both Matlab/Octave and Mathematica indexing from 1, but I agree that python should be kept with one convention.

My main concern (and Jens' too, I suspect) is that users will immediately complain and/or make their own patching of the driver too be 1-indexed. And just before doing so, they will accidentally fry a sample by setting DAC channel 23 to 10 Volts using dac.channels[22]. Is there a good way to avoid that?

@nulinspiratie
Copy link
Contributor

nulinspiratie commented Jun 20, 2017 via email

@spauka
Copy link
Contributor

spauka commented Jun 20, 2017

@nulinspiratie there is already a method to address channels by name (i.e. dac.c0 or now dac.channels.c0 both work). If the indexing syntax changes to a dict, i.e. dac.channels['c0'] then slicing no longer makes sense (no way to do dac.channels[c2:c4])

The fact is that adding 1-indexing creates the opposite problem for python users. Someone coming in could very easily set c[20] thinking it addresses channel 21!

@nulinspiratie
Copy link
Contributor

@spauka Ah right, but why not override slicing in __getitem__? As I see it, you ideally want a single way to represent your channel, by its name. Accessing multiple channels through dac.channels['c2':'c4'] would feel more intuitive than first converting it to indices. One case where this makes sense is instruments that use channel letters instead of numbers. If you need to remember both a letter and a number for a channel, it can quickly get confusing.
I was thinking of something along the lines of

class ChannelList:
    def __getitem__(self, sliced):
        print(f'getting channels {sliced.start} to {sliced.stop}')

channel_list = ChannelList()
channel_list['chA':'chC']

which outputs: getting channels chA to chC

@jenshnielsen
Copy link
Collaborator Author

Agreed with @spauka and @WilliamHPNielsen to go for the simplest solution now and only support regular python lists/tuples if the need arises we can come up with a more clever solution

@jenshnielsen
Copy link
Collaborator Author

With regards to the monitor, Channel parameters are supported as well as regular parameters.

Namely you cannot pass a MultiChannelParameter to the monitor but that is no different from a regular MultiParameter. Each channel is rendered as a new instrument which is suboptimal but probably ok for now

@spauka
Copy link
Contributor

spauka commented Jun 22, 2017

self._submodules and add_submodule should also be part of instrument base, as there is the possibility for nested channel lists, for example in the driver for the Harvard DAC, the list of slots also contains a list of channels, meaning the add_submodule function is required in InstrumentChannel.

@jenshnielsen jenshnielsen force-pushed the feat/channelization_furter_work branch from 354b3cd to cc56d6a Compare June 22, 2017 11:08
@jenshnielsen
Copy link
Collaborator Author

rebased and pushed submodules up to instrumentbase I think this is ready to merge

Make it possible to get channels by name even when not locked
@jenshnielsen
Copy link
Collaborator Author

I changed it around a bit to make it possible to index channels by name without locking the channels, I think this is ready to be merged

@WilliamHPNielsen
Copy link
Contributor

If we mention submodules in the docstring for InstrumentBase, I am happy.

@jenshnielsen
Copy link
Collaborator Author

@WilliamHPNielsen done

Copy link
Contributor

@WilliamHPNielsen WilliamHPNielsen left a comment

Choose a reason for hiding this comment

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

Beautiful!

@jenshnielsen jenshnielsen merged commit 8dfa2ab into microsoft:master Jul 11, 2017
giulioungaretti pushed a commit that referenced this pull request Jul 11, 2017
Author: Jens Hedegaard Nielsen <jenshnielsen@gmail.com>

    Feat/channelization further work (#641)
Dominik-Vogel pushed a commit to Dominik-Vogel/Qcodes that referenced this pull request Aug 9, 2017
* fix: refactor Instrument to avoid removing methods from channels

* Include channels in print_readable_snaphoot

* Fix: make locked channels a named tuple

That way you can access the names on the channellist via names as soon as they are locked

* Fix: channels add support for indexing from 1

many instruments have hardware channels that are indexed and start at 1

* Fix linting errors in channel

* fix typo

* Move print readable snapshot to instrument class where it belongs

* Fix: more channel annotation

* Improve error message

* pprint limit line lenght of header to max char

* pep8 line lenght

* Fix: channel remove support for oneindexed channels

* improve type annotation

* Optional -> Union

* add channels to api docs

* fix: make submodules nested

* add submodule attributes to base

* Replace namedtuple by dict

Make it possible to get channels by name even when not locked

* Add submodule to docstring
peendebak pushed a commit to VandersypenQutech/Qcodes that referenced this pull request Aug 11, 2017
* fix: refactor Instrument to avoid removing methods from channels

* Include channels in print_readable_snaphoot

* Fix: make locked channels a named tuple

That way you can access the names on the channellist via names as soon as they are locked

* Fix: channels add support for indexing from 1

many instruments have hardware channels that are indexed and start at 1

* Fix linting errors in channel

* fix typo

* Move print readable snapshot to instrument class where it belongs

* Fix: more channel annotation

* Improve error message

* pprint limit line lenght of header to max char

* pep8 line lenght

* Fix: channel remove support for oneindexed channels

* improve type annotation

* Optional -> Union

* add channels to api docs

* fix: make submodules nested

* add submodule attributes to base

* Replace namedtuple by dict

Make it possible to get channels by name even when not locked

* Add submodule to docstring
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants