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

Support for QM OPX1000 in 0.2 #1068

Merged
merged 15 commits into from
Oct 17, 2024
Merged

Support for QM OPX1000 in 0.2 #1068

merged 15 commits into from
Oct 17, 2024

Conversation

stavros11
Copy link
Member

@stavros11 stavros11 commented Oct 8, 2024

Ports #1045 to qibolab 0.2.

TODO:

  • Force offset set in program
  • Support amplified mode and expose via configs
  • Expose Octave LO output mode to configs (to switch between triggered and always_on)
  • Test on hardware

Copy link

codecov bot commented Oct 8, 2024

Codecov Report

Attention: Patch coverage is 0% with 160 lines in your changes missing coverage. Please review.

Project coverage is 50.55%. Comparing base (6087ba8) to head (4d00aeb).
Report is 20 commits behind head on main.

Files with missing lines Patch % Lines
src/qibolab/_core/instruments/qm/config/devices.py 0.00% 62 Missing ⚠️
src/qibolab/_core/instruments/qm/controller.py 0.00% 34 Missing ⚠️
...rc/qibolab/_core/instruments/qm/config/elements.py 0.00% 24 Missing ⚠️
src/qibolab/_core/instruments/qm/config/config.py 0.00% 16 Missing ⚠️
...qibolab/_core/instruments/qm/components/configs.py 0.00% 8 Missing ⚠️
src/qibolab/_core/instruments/qm/config/pulses.py 0.00% 6 Missing ⚠️
...c/qibolab/_core/instruments/qm/program/sweepers.py 0.00% 4 Missing ⚠️
...bolab/_core/instruments/qm/program/instructions.py 0.00% 3 Missing ⚠️
...rc/qibolab/_core/instruments/qm/config/__init__.py 0.00% 1 Missing ⚠️
...ibolab/_core/instruments/qm/program/acquisition.py 0.00% 1 Missing ⚠️
... and 1 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1068      +/-   ##
==========================================
- Coverage   51.95%   50.55%   -1.41%     
==========================================
  Files          63       63              
  Lines        2808     2886      +78     
==========================================
  Hits         1459     1459              
- Misses       1349     1427      +78     
Flag Coverage Δ
unittests 50.55% <0.00%> (-1.41%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@stavros11
Copy link
Member Author

Following qiboteam/qibolab_platforms_qrc#188, this should now be ready. I also confirmed that the qw11q that is controlled with the old OPX+ cluster still works: http://login.qrccluster.com:9000/jnGzYDzWTuyMrezsF-khoA==/

@stavros11 stavros11 marked this pull request as ready for review October 10, 2024 13:19
@stavros11 stavros11 requested review from alecandido and hay-k October 10, 2024 13:19
Copy link
Member

@alecandido alecandido left a comment

Choose a reason for hiding this comment

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

First round, still need to go through the details of the larger changes (config.py, devices.py, elements.py, controller.py).

In general, it is a bit larger change than what I expected at first, but still sufficiently localized.
We should be able to merge it soon.

@stavros11
Copy link
Member Author

In general, it is a bit larger change than what I expected at first, but still sufficiently localized. We should be able to merge it soon.

No rush in terms of merging. It is also larger and required more effort than what I also expected. But this is mainly because it ended up not only for adding OPX1000 support, but also supporting its new features and doing workarounds around various bugs with (I believe) the qm-qua pre-release (the TODO list in the first comment).

Two other things to note: I have changed a few type annotations from str to Literal[...]. Of course is not strictly required and does not affect execution, but I saw you using it in a few other places and I believe it is good to have here as well. It also contributes to the diff.

But a more important point to mention is about how OPX1000 controllers are exposed in terms of interface. This is more clearly visible in the platform, for example: https://github.com/qiboteam/qibolab_platforms_qrc/blob/7e2b2fb62300c9ba6e94f98c342597294cd4edab/qw5q_platinum/platform.py#L54
It was a bit hard for me to decide between:

DcChannel(device="con1/4", path="1")

and

DcChannel(device="con1", path="4/1")

The second is probably a bit better on the user end, since path is a more accurate description, however I finally opted for the first, because it was easier to handle in the driver. For OPX1000, each controller (here con1) has some front end modules (FEMs) and each FEM has ports, while for OPX+ we only have controllers and ports. Therefore, in terms of code, the analogue of an OPX+ controller (conX) is an OPX1000 FEM (conX/Y), which is why I decided to label it as device in the channels.

@alecandido
Copy link
Member

The second is probably a bit better on the user end, since path is a more accurate description, however I finally opted for the first, because it was easier to handle in the driver. For OPX1000, each controller (here con1) has some front end modules (FEMs) and each FEM has ports, while for OPX+ we only have controllers and ports. Therefore, in terms of code, the analogue of an OPX+ controller (conX) is an OPX1000 FEM (conX/Y), which is why I decided to label it as device in the channels.

Yes, I agree with your analysis and decision.

Essentially, it's about deciding whether a FEM is a device or a device's component. And that's ambiguous.

It may be a good time to ask ourselves what is actually defining a device, and why each port is not a device on its own.
I guess the main motivation is that we're managing one connection per device, or that devices are somehow parametrized. But I'm not sure myself, so we should try to agree on some definition.

Most likely, there was no problem until now, just because we were dealing with simpler devices (which at most had ports, or not even those).

Copy link
Member

@alecandido alecandido left a comment

Choose a reason for hiding this comment

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

Just minor suggestions, but in general it looks alright.

I'm still wondering whether we could simplify it a bit, since it may be quite nested at times (you could follow the story of max_voltage as a marker), but this would be a fully internal refactor - definitely not needed for this PR, and not even for a release.

def _to_port(channel: Channel) -> dict[str, tuple[str, int]]:
"""Convert a channel to the port dictionary required for the QUA config."""
return {"port": (channel.device, channel.port)}
def _to_port(channel: Channel) -> dict[Port, InOutType]:
Copy link
Member

Choose a reason for hiding this comment

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

Concerning the return type hint, in this case it works fine because you only have one element. But it would not scale for a dictionary with multiple (inhomogeneous) entries.

In general, the tool to define these kinds of type hints (without promoting them to an actual dataclass), is to use a TypedDict.
You can define it inline (functional style) or with a dataclass-like syntax. Still it will be a hint for a plain dict, it does not require different runtime classes.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the suggestion, good to know. I updated several type hints in this file to use this in 4d00aeb, let me know if you agree.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, exactly :)

Thanks!

Comment on lines 107 to 108
# default_factory=lambda: PortDict(DEFAULT_INPUTS)
# )
Copy link
Member

Choose a reason for hiding this comment

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

Dead code?

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for catching this. I decided to go with the original one (that is: not change in this PR), as I think the default value there was needed for something related to the mixer calibration. I just had to also add default offsets (see e4947d9) because qm-qua>1.2 fails without them.

@stavros11
Copy link
Member Author

@alecandido is there something wrong with pre-commit? It didn't complain to me locally. Other than that, if you are okay with the last changes we can probably merge. I did a quick test and it still works on hardware.

@alecandido
Copy link
Member

@alecandido is there something wrong with pre-commit? It didn't complain to me locally. Other than that, if you are okay with the last changes we can probably merge. I did a quick test and it still works on hardware.

Yes, it's broken because of a recent update (v3 -> v4) that propagated to the CI, but not all our hooks are supporting the update (it makes sense).

However, there is only one hook failing, that is already patched in main. I'm just waiting for them to release
PyCQA/docformatter#293
such that the bot will trigger to usual upgrade PRs...

For the time being, please ignore it.

@stavros11 stavros11 merged commit 946a04f into main Oct 17, 2024
25 of 28 checks passed
@stavros11 stavros11 deleted the opx1000-0.2 branch October 17, 2024 15:03
@alecandido alecandido added this to the Qibolab 0.2.1 milestone Oct 25, 2024
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.

3 participants