Skip to the content.

Cebule SDK integration

Cebule SDK (MQS) provides cloud quantum-chemistry and materials-property task types. qpubench models each task’s input and output as typed Pydantic schemas in src/qpubench/schemas/mirrors/mqsdk_cebule.py.

Revised 2026-07-08. This module was checked directly against the real SDK source — gitlab.com/mqsdk/python-sdk, specifically mqsdk/core/cebule.py’s TaskType enum, mqsdk/utils/tasks.py’s helper functions, and the notebooks/ examples — and turned up a real gap: MOL_MAP/QASM_GEN (below) do not appear in that TaskType enum, while fifteen other task types the SDK does expose (solvation, ab initio MD, geometry optimization, group-contribution/GNN property prediction) weren’t modeled at all. Both are now fixed — see “Task types” below for what’s confirmed vs. kept-with-caveat, and the new sections for each task family.


Task types

CebuleTaskEnvelope (max_processors, connected_task_id, connected_model_id, connected_dataset_id, notification_minutes_threshold) is common to every task below — confirmed directly against MQSCebule.create_task()’s signature. Tasks chain into a DAG via connected_task_id (e.g. GEOMETRY_OPTCOSMOSIGMASOLUBILITY).

CebuleTaskType What it does Confirmed against
COSMO Continuum solvation (dielectric constant + VDW radii) mqsdk/utils/tasks.py, notebooks/2_COSMO_task_Cebule.ipynb
SIGMA COSMO-SAC/-RS sigma profile, chained from a COSMO task mqsdk/utils/tasks.py
SOLUBILITY Solubility from one or more SIGMA results mqsdk/utils/tasks.py
BORN_OPPENHEIMER_MD Ab initio MD, Quantum-ESPRESSO-backed (periodic-capable) notebooks/3_BOMD_task_Cebule.ipynb
CAR_PARRINELLO_MD Ab initio MD, Quantum-ESPRESSO-backed (periodic-capable) notebooks/4_CPMD_task_Cebule.ipynb
FORCE_FIELD_MD Classical MD of a molecule (or polymer) in a solvent box scripts/md.py
GEOMETRY_OPT Force-field + semi-empirical geometry optimisation scripts/geometry.py
PERIODIC_GEOMETRY_OPT Geometry optimisation under periodic boundary conditions Enum only — no usage example found; fields inferred
GROUP_CONTRIBUTION Group-contribution property estimation, batchable over mixtures scripts/group_contribution.py
ATOM_ORDER Canonical atom ordering for a SMILES (+ optional geometry) mqsdk/utils/tasks.py
ACTIVITY_COEFFICIENT Enum only — no usage example found; not modeled beyond the envelope
GNN_DATASET_CREATE/_EXTEND/_GET/_DELETE, GNN_TRAIN, GNN_PREDICT Property-prediction GNN dataset/model lifecycle notebooks/6_GNN_task_HLGap_GeometryOpt.ipynb
TN_QC_OPT Tensor-network + quantum circuit hybrid VQE optimisation Confirmed in TaskType enum
COVO Correlation-optimised virtual orbital pre-processing Confirmed in TaskType enum
MOL_MAP (unconfirmed) Map a molecular geometry to a qubit Hamiltonian via constraint-based encoding Not found in TaskType enum — kept, see caveat above
QASM_GEN (unconfirmed) Generate OpenQASM 2.0 measurement circuits for a Hamiltonian Not found in TaskType enum — kept, see caveat above

Session pattern

import mqsdk, os

session = mqsdk.Cebule(os.environ["EMAIL"], os.environ["PASSWORD"])

# Most tasks: kwargs become the task's JSON input.
task = session.cebule.create_task(
    "H2O geometry opt", TaskType.GEOMETRY_OPT,
    smiles_list=["O"], force_field="mmff94", optimization_method="gfn2_xtb",
)

# BORN_OPPENHEIMER_MD / CAR_PARRINELLO_MD only: input= is a raw Quantum
# ESPRESSO input file (create_task allows input= OR **kwargs, not both).
task = session.cebule.create_task(
    "QE BOMD run", TaskType.BORN_OPPENHEIMER_MD, input=qe_input_text,
)

# Chain a follow-up task via connected_task_id:
cosmo_task = session.cebule.create_task(
    "COSMO opt", TaskType.COSMO,
    connected_task_id=task.id, method="dft", basis="6-31g**", dielec=78.0,
)

Set credentials in .env and reference them via BackendSpec.cebule():

from qpubench.schemas import BackendSpec
backend = BackendSpec.cebule(email_ref="EMAIL", password_ref="PASSWORD")

MOL_MAP (unconfirmed against current SDK source)

Maps a molecular geometry to a qubit Hamiltonian with constraint-based encoding.

from qpubench.schemas import MolMapInput, MolMapResult, MolecularGeometry

inp = MolMapInput(molecule=MolecularGeometry(
    geometry=[0.0, 0.0, 0.0, 0.0, 0.0, 0.7414],   # flat Å (x0,y0,z0,x1,y1,z1)
    symbols=["H", "H"],
    basis="sto3g",
))

# After calling session.cebule.create_task(…):
result = MolMapResult(
    mapped_hamiltonian=[[]],
    hf_state=[1, 1, 0, 0],
    mapping_matrix=[[]],
    num_qubits=4,
)

QASM_GEN (unconfirmed against current SDK source; fully documented on docs.mqs.dk)

The measurement method: evaluates the expectation value of a mapped Hamiltonian via a circuit-generation scheme that groups terms by computational basis state pairs rather than per-Pauli-string decomposition — generates OpenQASM 2.0 circuits, one per basis-state grouping. Explicitly documented as compatible with the output of either MOL_MAP or TN_QC_OPT (see below — it’s also usable inside TN_QC_OPT directly via measurement_method="grouped").

include_state_circuit defaults to False (corrected 2026-07-09 against the current docs.mqs.dk table).

from qpubench.schemas import QASMGenInput, QASMGenResult

inp = QASMGenInput(operator=[[]], include_state_circuit=True)   # override the False default explicitly

result = QASMGenResult(
    circuit_files=["OPENQASM 2.0; …", "OPENQASM 2.0; …"],
    postprocessing_instructions=[[1.0, -0.5], [-0.5, 1.0]],
)

# Convert each circuit to a CircuitSpec (QASM2)
specs = result.to_circuit_specs(num_qubits=4)

# Or wrap caller-supplied QASM3 transpilations
qasm3_specs = result.to_openqasm3_circuit_specs(num_qubits=4, qasm3_sources=[])

TN_QC_OPT

Hybrid tensor-network + quantum circuit VQE. opt_method defaults to "COBYLA" (corrected 2026-07-09 — was "BFGS" in an earlier revision of this doc). measurement_method ("pauli" default, or "grouped" — QASM_GEN’s own basis-state-pair grouping used internally) and optimization_mode ("both" default — jointly optimize θ/φ; "circuit" freezes θ for plain VQE over φ; "network" freezes φ for a classical-only θ search) were added 2026-07-09, confirmed real against the current docs.mqs.dk table.

from qpubench.schemas import TNQCOptInput, TNQCOptResult, SparsePauliObservable

inp = TNQCOptInput(
    h_coeff_values=[0.5, -0.3, 0.1],
    h_operators=["Z0", "X0 Z1", "Y1"],
    n_iterations=100,
    n_layers_network=3,
    n_layers_circuit=3,
    opt_method="COBYLA",
    backend="lightning.qubit",
    measurement_method="grouped",   # or "pauli"
    optimization_mode="both",        # or "circuit" / "network"
)

result = TNQCOptResult(
    vqe_energy=-1.136,
    phi=[0.1, -0.2, 0.3],       # optimised circuit parameters U(φ)
    theta=[0.5, -0.1, 0.2],     # optimised TN parameters U(θ)
    h_tn_opt_qubit=[0.5, -0.3, 0.1],
    qubit_operators=["Z0", "X0 Z1", "Y1"],
    function_calls=42,
    cost_history=[-0.9, -1.05, -1.136],
)

# Convert to SparsePauliObservable
obs = result.to_sparse_pauli_observable(num_qubits=2)

Wire AlgorithmSpec fields to the TN_QC_OPT parameters:

from qpubench.schemas import AlgorithmSpec

spec = AlgorithmSpec(
    name="TN_QC_OPT",
    optimizer="COBYLA",
    opt_maxiter=100,
    n_layers_network=3,
    n_layers_circuit=3,
)

COVO

Correlation-optimised virtual orbitals for plane-wave periodic systems.

from qpubench.schemas import COVOInput, COVOResult

inp = COVOInput(
    geometry=[0.0, 0.0, 0.0, 0.0, 0.0, 1.23],
    symbols=["B", "H"],
    cell_size=10.0,
    cutoff=200.0,
    n_virtual_orbitals=4,
)

result = COVOResult(
    one_electron_integrals=[[]],
    two_electron_integrals=[[[[]]]],
    hf_energy=-24.6,
    fci_energy=-24.7757,
    vqe_energy=-24.75,
    hamiltonian=[[]],
)

print(f"Correlation energy: {result.correlation_energy:.4f} Ha")
print(f"VQE error vs FCI:   {result.vqe_error:.4f} Ha")

Record fci_energy in VQAResult (computed outputs):

from qpubench.schemas import VQAConfig, VQAResult

vqa = VQAConfig(problem_type="chemistry", molecule="BH")
vqa_result = VQAResult(
    hf_energy=-24.6,
    fci_energy=-24.7757,      # from COVOResult
    final_eigenvalue=-24.75,
)

Solvation: COSMOSIGMASOLUBILITY

A real, chained pipeline confirmed against mqsdk/utils/tasks.py. COSMO computes continuum-solvation energetics for one molecule; SIGMA derives a screening-charge-density profile from a completed COSMO task; SOLUBILITY combines SIGMA profiles for a solute + solvent mixture into a solubility estimate. This is Cebule’s route to a solvent model (see examples/guides/create_solvent_model.py for the PySCF route).

from qpubench.schemas import CosmoInput, CosmoMethod, SigmaInput, SolubilityInput

# Step 1 — COSMO on the (already geometry-optimized) solute, chained via
# connected_task_id to a prior GEOMETRY_OPT task's ID.
cosmo = CosmoInput(
    connected_task_id="geometry-opt-task-id",
    basis="6-31g**",
    optimize=True,
    dielec=78.0,       # water
)

# Step 2 — sigma profile from the COSMO result.
sigma = SigmaInput(connected_task_id="cosmo-task-id", cosmo_method=CosmoMethod.COSMO_SAC)

# Step 3 — solubility from solute + solvent sigma profiles.
solubility = SolubilityInput(
    connected_task_id=["sigma-solute-id", "sigma-solvent-id"],
    temperature=298.15,
    melting_point=350.0,
    enthalpy_melting=20.0,
    sol_init=0.1,
    solv_composition=[1.0],
    change_heat_capacity_melting=5.0,   # required for cosmo-sac
)

Geometry: GEOMETRY_OPT / PERIODIC_GEOMETRY_OPT

from qpubench.schemas import GeometryOptInput, GeometryOptForceField, GeometryOptMethod

geo = GeometryOptInput(
    smiles_list=["O"],
    force_field=GeometryOptForceField.MMFF94,       # or GHEMICAL
    optimization_method=GeometryOptMethod.GFN2_XTB,  # or G_XTB, AM1, UMA
)

PeriodicGeometryOptInput is the periodic-cell counterpart — confirmed to exist in the SDK’s TaskType enum, but no usage example was found during this check, so its fields (cell_lengths, cell_angles, plus the same force_field/optimization_method choice) are inferred by analogy rather than confirmed. Verify against the live SDK before relying on exact names.


Ab initio MD: BORN_OPPENHEIMER_MD / CAR_PARRINELLO_MD

Both wrap Quantum ESPRESSO directly — the payload is a raw QE input file (&control/&system/&electrons or &ions namelists), not kwargs. The confirmed example notebooks use a periodic 8-water cell (ibrav/celldm lattice parameters), i.e. genuine periodic plane-wave DFT — a plane-wave alternative for periodic-system chemistry (e.g. the carbon-capture tutorial’s framework, examples/tutorials/carbon_capture_periodic_dft.py).

from qpubench.schemas import AbInitioMDInput, AbInitioMDMethod

bomd = AbInitioMDInput(
    method=AbInitioMDMethod.BORN_OPPENHEIMER,
    qe_input=open("h2o-periodic.in").read(),   # real QE input file text
)

Result is raw QE stdout text (AbInitioMDResult.stdout), not structured JSON — parse energies/forces yourself.

Classical MD: FORCE_FIELD_MD

from qpubench.schemas import ForceFieldMDInput

md = ForceFieldMDInput(
    smiles_primary="CCO",              # or a list of SMILES for a polymer chain
    copies_primary=1,
    smiles_list_secondary=["O"],
    copies_list_secondary=[500],
    temperature=298.15,
    box_length_nm=4.0,
    time_fs=10_000.0,
)

Materials properties: GROUP_CONTRIBUTION / ATOM_ORDER / ACTIVITY_COEFFICIENT

from qpubench.schemas import GroupContributionInput, AtomOrderInput

# Batchable over multiple mixtures — each inner list is one mixture's SMILES.
gc = GroupContributionInput(smiles_list=[["CCO", "O"], ["CCC", "O"]], gc_type="unifac")

atom_order = AtomOrderInput(smiles="CCO")   # or smiles=[...] + geometry=[...] for a polymer

ActivityCoefficientInput exists (confirmed in the TaskType enum) but no usage example was found — it currently carries no task-specific fields beyond the common envelope.


Property-prediction GNN: dataset + model lifecycle

from qpubench.schemas import (
    GNNDatasetCreateInput, GNNDatasetExtendInput, GNNMoleculeChunk,
    GNNTrainInput, GNNPredictInput,
)

create = GNNDatasetCreateInput(
    dataset_name="hlgap_dataset", includes_target_val=True,
    target_property="homo_lumo_gap",
)
extend = GNNDatasetExtendInput(
    connected_dataset_id="dataset-id",
    molecule_chunk=GNNMoleculeChunk(
        smiles=["CCO"], coords=[[0.0, 0.0, 0.0, 1.5, 0.0, 0.0]], target_val=[3.2],
    ),
)
train = GNNTrainInput(
    connected_dataset_id="dataset-id", model_name="hlgap_model",
    hyperparameters={"epochs": 75},
)
predict = GNNPredictInput(connected_dataset_id="pred-dataset-id", connected_model_id="model-id")

GNNTrainResult/GNNPredictResult model the fields the SDK’s own example notebook names (a mean-absolute-error training metric; predictions the notebook calls “effective hamiltonians”) without over-specifying a payload shape that wasn’t directly confirmed.


MolecularGeometry vs XenakisMolecule

Both represent molecular geometries but use different coordinate layouts:

Type Coordinates Usage
MolecularGeometry Flat list: [x0, y0, z0, x1, y1, z1, …] Cebule MOL_MAP, COVO
XenakisMolecule List of tuples: [(x0, y0, z0), (x1, y1, z1), …] Xenakis YAML config

Convert between them:

# XenakisMolecule → MolecularGeometry
from qpubench.schemas import MolecularGeometry, XenakisMolecule

xmol = XenakisMolecule(name="H2", symbols=["H","H"],
                        coordinates_angstrom=[(0,0,0), (0,0,0.7414)])
geom = MolecularGeometry(
    geometry=xmol.flat_coordinates(),
    symbols=xmol.symbols,
    basis=xmol.basis,
    multiplicity=xmol.multiplicity,
    charge=xmol.charge,
)

OpenQASM 3.0 and QASM_GEN output

Cebule’s QASM_GEN task outputs OpenQASM 2.0 strings. To use them with QASM3-aware backends, transpile each circuit and wrap with CircuitSpec.from_openqasm3():

from qpubench.schemas import CircuitSpec

# After transpiling QASM2 → QASM3 with your preferred tool
qasm3_source = transpile_to_qasm3(result.circuit_files[0])
spec = CircuitSpec.from_openqasm3(qasm3_source, num_qubits=4)

# Check
assert spec.openqasm3 is not None
assert spec.format.value == "qasm3"

The QASMGenResult.to_openqasm3_circuit_specs(num_qubits, qasm3_sources) helper wraps this in bulk.