Skip to content

FIT mode now creates platform with no hardware memory. - #1624

Open
lballerio wants to merge 2 commits into
mainfrom
hardware_insensitive_platform_for_fit
Open

FIT mode now creates platform with no hardware memory.#1624
lballerio wants to merge 2 commits into
mainfrom
hardware_insensitive_platform_for_fit

Conversation

@lballerio

@lballerio lballerio commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

We noticed that when executing only FIT operation (e.g. though qq fit command) Qibocal was building the platform using the state of platform_folder (e.g. the ones in qibolab_platforms_qrc) and not the state saved in the experiment_data_folder.
We fix this issue in the PR, also avoiding to construct the Hardware sensitive fields of the Platform for operations that do not include data acquisition.

Also, Completed object now always requires a path:Path input an is no more optional, as I think it should be.

Note

Discuss about eventual tests to add.

linked to Qibolab #1535.

@lballerio
lballerio requested a review from RoyStegeman July 21, 2026 13:58
@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.18519% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.41%. Comparing base (4d5df4d) to head (91ee78e).

Files with missing lines Patch % Lines
src/qibocal/auto/output.py 40.00% 3 Missing ⚠️
src/qibocal/auto/task.py 83.33% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #1624   +/-   ##
=======================================
  Coverage   91.41%   91.41%           
=======================================
  Files         148      148           
  Lines       11841    11851   +10     
=======================================
+ Hits        10824    10834   +10     
  Misses       1017     1017           
Flag Coverage Δ
unittests 91.41% <85.18%> (+<0.01%) ⬆️

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

Files with missing lines Coverage Δ
src/qibocal/auto/execute.py 88.88% <100.00%> (+0.09%) ⬆️
src/qibocal/auto/history.py 92.53% <100.00%> (-0.22%) ⬇️
src/qibocal/auto/runcard.py 97.67% <ø> (ø)
src/qibocal/calibration/platform.py 95.55% <100.00%> (+1.26%) ⬆️
src/qibocal/cli/update.py 97.14% <100.00%> (ø)
src/qibocal/auto/task.py 96.31% <83.33%> (-0.64%) ⬇️
src/qibocal/auto/output.py 97.69% <40.00%> (-2.31%) ⬇️

... and 4 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@lballerio
lballerio marked this pull request as ready for review July 22, 2026 09:47
@lballerio
lballerio requested review from a team July 22, 2026 09:47

@RoyStegeman RoyStegeman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Some comments. The main one being a bug the line below: while running qq fit, dummy_hardware will be True instead of None.

platform = create_dummy() if dummy_hardware is None else create_platform(platform_name)

Comment thread src/qibocal/calibration/platform.py Outdated
Comment on lines +5 to +6
from qibolab._core.dummy.platform import create_dummy
from qibolab._core.platform.platform import PARAMETERS

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is not part of the public API, meaning qibolab can change this without warning, so we should not use it in qibocal

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok I'll find a solution.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

in order to address this point, I opened Qibolab #1535 and then corrected the import in e47d647.

Comment thread src/qibocal/calibration/platform.py Outdated
Comment on lines +77 to +79
rather than the platform definition. If a ``platform_name`` is provided, the hardware
configuration is loaded from that platform; otherwise, a dummy hardware
configuration is used so that acquisition-related fields are still present

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If a platform_name is provided, the hardware
configuration is loaded from that platform; otherwise, a dummy hardware
is used

According to this the boolean dummy_hardware is not needed, but depends on whether a platform_name is provided. Although platform_name can't be None, so the docstring is not very clear.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

addressed in e47d647

Comment thread src/qibocal/calibration/platform.py Outdated

The platform is rebuilt from the configuration saved in the experiment history,
using the ``parameters.json`` and ``calibration.json`` files stored in the data folder
rather than the platform definition. If a ``platform_name`` is provided, the hardware

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think by "the platform definition" you mean the QIBOLAB_PLATFORMS environment variable. If so, please write that. If you meant something else, please clarify.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

addressed in e47d647

create_dummy() if dummy_hardware is None else create_platform(platform_name)
)
platform.parameters = parameters
platform.name = platform_name

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why do we need to overwrite the name?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That action is only effective when platform is a DummyPlatform, I've decided to overwrite to propagate the name even for dummy platforms, maybe you need later in the code and I didn't want to create confusion by printing dummy (or whatever name DummyPlatform has).

Comment thread src/qibocal/auto/execute.py Outdated


def check_overlap_in_input_qubits(targets: np.typing.ArrayLike):
def check_overlap_in_input_qubits(targets: list):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The first thing this function does is call targ = np.asarray(targets) so the previous type should have been correct.

@lballerio lballerio Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

it's true, but also we call this function after casting self.targets as Target types. which indeed is always a list.
I assumed a more strict typehint since still list is an ArrayLike.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

addressed in e47d647

Comment thread src/qibocal/calibration/platform.py Outdated
)

platform = (
create_dummy() if dummy_hardware is None else create_platform(platform_name)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
create_dummy() if dummy_hardware is None else create_platform(platform_name)
create_dummy() if dummy_hardware is True else create_platform(platform_name)

Or maybe if platform_name is None; see comment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes, thanks!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

addressed in e47d647

Comment thread src/qibocal/auto/execute.py Outdated
else CalibrationPlatform.from_datafolder(
folder_path=output,
platform_name=self.platform.name,
dummy_hardware=False,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
dummy_hardware=False,
dummy_hardware=True,

I think? Since in this case you're just fitting.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes thanks for pointing out

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

addressed in e47d647

Comment thread src/qibocal/auto/task.py Outdated
Comment on lines +239 to +243
if self.path is not None:
self._data.save(self.path)
self._data.save(self.path)

def dump_results(self):
"""Dumping results."""
if self.path is not None:
self._results.save(self.path)
self._results.save(self.path)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

self._data and self._results can still be None, in which case calling None.save will raise an error.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes you are right, thanks

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

addressed in e47d647

@alecandido

Copy link
Copy Markdown
Member

The proposal is fine by me. Possibly, we just want to eventually exclude platform access from the Protocol.fit invocation, and have qq fit to just work without creating any platform, not even a dummy one. But, for the time being, this is a much faster workaround. And seemingly solid.

Also, Completed object now always requires a path:Path input an is no more optional, as I think it should be.

This is a more complicated situation. The original design was meant to avoid passing paths everywhere, since disk I/O can be quite annoying in a HPC-like infrastructure. Because of the non-locality of the storage, and also the recommended folders access.

However, we may even forget this part now, and decide to always work with paths. This happened accidentally, because the original design was violated (following the frequent quick & dirty approach), but we could even decide to systematically reconsider the initial assumptions.
In principle, if we need performance (no disk I/O) and using a temporary scratch-like folder, we could also deal with at high-level, with an in-memory filesystem, and copying the results folder out of scratch at the desired time - e.g. at the end of the workload, or with intermediate "backups".

Whatever it is done here it is fine and acceptable. But let's keep this in mind, and redesign together.

Comment thread src/qibocal/cli/update.py
@@ -25,15 +25,21 @@ def update(path: pathlib.Path, skip_qubits: list[QubitId] | None):
platform_name = json.loads((path / META).read_text())["platform"]

platform_path = locate_platform(platform_name)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

(qpu165) roy.stegeman@dalma:~/calibration$ qq update /home/users/roy.stegeman/calibration/results/tuna5/260804/17-19-51-cryoscope-0
Traceback (most recent call last):
  File "/nfs/users/roy.stegeman/.venvs/qpu165/bin/qq", line 8, in <module>
    sys.exit(command())
  File "/nfs/users/roy.stegeman/.venvs/qpu165/lib/python3.10/site-packages/click/core.py", line 1514, in __call__
    return self.main(*args, **kwargs)
  File "/nfs/users/roy.stegeman/.venvs/qpu165/lib/python3.10/site-packages/click/core.py", line 1435, in main
    rv = self.invoke(ctx)
  File "/nfs/users/roy.stegeman/.venvs/qpu165/lib/python3.10/site-packages/click/core.py", line 1902, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/nfs/users/roy.stegeman/.venvs/qpu165/lib/python3.10/site-packages/click/core.py", line 1298, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/nfs/users/roy.stegeman/.venvs/qpu165/lib/python3.10/site-packages/click/core.py", line 853, in invoke
    return callback(*args, **kwargs)
  File "/nfs/users/roy.stegeman/github/qibocal/src/qibocal/cli/_base.py", line 145, in update
    updating(folder, skip_qubits)
  File "/nfs/users/roy.stegeman/github/qibocal/src/qibocal/cli/update.py", line 27, in update
    platform_path = locate_platform(platform_name)
  File "/nfs/users/roy.stegeman/github/qibolab/src/qibolab/_core/platform/load.py", line 81, in locate_platform
    return _search(name, paths)
  File "/nfs/users/roy.stegeman/github/qibolab/src/qibolab/_core/platform/load.py", line 56, in _search
    raise ValueError(
ValueError: Platform tuna5 not found. Check $QIBOLAB_PLATFORMS environment variable.

Sine no path is passed to locate_platform it will _search in the default _platforms_paths(), which is still
PLATFORMS_PATH = "QIBOLAB_PLATFORMS"

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Reconstructs platforms from saved experiment data for FIT-only workflows, avoiding live hardware state.

Changes:

  • Adds platform reconstruction from serialized parameters and calibration.
  • Makes task output paths mandatory.
  • Updates execution and fitting flows to use stored experiment state.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/qibocal/calibration/platform.py Adds data-folder platform reconstruction.
src/qibocal/auto/execute.py Selects live or saved platform by execution mode.
src/qibocal/auto/output.py Uses saved platforms during offline fitting.
src/qibocal/auto/task.py Requires task paths and validates fitting data.
src/qibocal/auto/history.py Makes generated task paths mandatory.
src/qibocal/auto/runcard.py Uses the executor’s configured output path.
src/qibocal/cli/update.py Loads updated platforms from serialized output.
tests/test_output.py Adapts output tests to the executor API.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +108 to +110
"""This function builds a ``CalibrationPlatform`` object which is sentitive of the hardware,
so it needs information about the clusters and its connection. Has to be used for acquisition.
"""
Comment on lines +258 to +259
# but also we need the params saved in the datafolder, since in the
# platform folder might been changed.
self.platform
if ExecutionMode.ACQUIRE in mode
else CalibrationPlatform.from_datafolder(
folder_path=output,
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.

qq fit uses the QIBOLAB_PLATFORM, while it should load the platform from the results folder

4 participants