Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
},
{
"cell_type": "code",
"id": "73cdacc6c6d2",
"id": "36ec5c0e810c",
"metadata": {},
"source": [
"import os\n",
Expand All @@ -68,6 +68,7 @@
" default_capacitance_setup,\n",
" default_capacitance_sweep,\n",
" maxwell_matrix_interpretation,\n",
" pair_capacitances_fF_from_run_dir,\n",
")\n",
"\n",
"try:\n",
Expand Down Expand Up @@ -315,12 +316,14 @@
},
{
"cell_type": "code",
"id": "29c28b5d5b91",
"id": "463854c180d2",
"metadata": {},
"source": [
"RUN_ANSYS = os.environ.get(\"SQUADDS_RUN_ANSYS\") == \"1\"\n",
"CHECKPOINT_ROOT = Path(\"tutorials/runtime/drivenmodal_capacitance/checkpoints\")\n",
"\n",
"qubit_prepared = None\n",
"ncap_prepared = None\n",
"if RUN_ANSYS:\n",
" from squadds.simulations.drivenmodal.hfss_runner import run_drivenmodal_request\n",
"\n",
Expand Down Expand Up @@ -371,14 +374,27 @@
},
{
"cell_type": "code",
"id": "434a41d8979c",
"id": "16fa0a52a1ac",
"metadata": {},
"source": [
"qubit_q3d = capacitance_reference_summary(qubit_row, system_kind=\"qubit_claw\")\n",
"ncap_q3d = capacitance_reference_summary(ncap_row, system_kind=\"ncap\")\n",
"\n",
"qubit_drivenmodal_fF = qubit_q3d\n",
"ncap_drivenmodal_fF = ncap_q3d\n",
"extraction_freq_ghz = float(setup.freq_ghz)\n",
"if RUN_ANSYS:\n",
" qubit_drivenmodal_fF = pair_capacitances_fF_from_run_dir(\n",
" qubit_prepared[\"manifest\"][\"run_dir\"],\n",
" system_kind=\"qubit_claw\",\n",
" extraction_freq_ghz=extraction_freq_ghz,\n",
" )\n",
" ncap_drivenmodal_fF = pair_capacitances_fF_from_run_dir(\n",
" ncap_prepared[\"manifest\"][\"run_dir\"],\n",
" system_kind=\"ncap\",\n",
" extraction_freq_ghz=extraction_freq_ghz,\n",
" )\n",
"else:\n",
" qubit_drivenmodal_fF = qubit_q3d\n",
" ncap_drivenmodal_fF = ncap_q3d\n",
"\n",
"display(capacitance_comparison_table(drivenmodal_fF=qubit_drivenmodal_fF, q3d_fF=qubit_q3d))\n",
"display(capacitance_comparison_table(drivenmodal_fF=ncap_drivenmodal_fF, q3d_fF=ncap_q3d))\n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
},
{
"cell_type": "code",
"id": "bb8952e20cf8",
"id": "df2e21e15377",
"metadata": {},
"source": [
"import contextlib\n",
Expand All @@ -88,6 +88,7 @@
"from squadds import Analyzer, SQuADDS_DB\n",
"from squadds.simulations.drivenmodal import (\n",
" build_segmented_coupled_system_requests,\n",
" coupled_hamiltonian_from_prepared_runs,\n",
" coupled_reference_summary,\n",
" default_hamiltonian_setup,\n",
" hamiltonian_comparison_table,\n",
Expand Down Expand Up @@ -327,6 +328,29 @@
],
"execution_count": 5
},
{
"cell_type": "markdown",
"id": "d03429b1fd50",
"metadata": {},
"source": [
"## State-dependent Josephson inductance\n",
"\n",
"`LJ_bare_nH` is the linear Josephson inductance from the transmon design options\n",
"(`aedt_q3d_inductance` / `Lj` / `LJ`). The ground-state and excited-state\n",
"columns use the same workflow as `coupled_reference_summary(...)`: helper\n",
"`transmon_state_inductances(...)` in `squadds.simulations.drivenmodal.workflows`\n",
"builds a zero-temperature `scqubits.Transmon` with\n",
"$E_J$ from the bare $L_J$ and $E_C$ from the qubit shunt capacitance (via the\n",
"database `cross_to_ground` and `cross_to_claw` pair capacitances in fF).\n",
"It then evaluates the transmon `cos_phi_operator` in the ground and\n",
"first-excited eigenstates. The effective inductances are\n",
"$L_J^{(g)} = L_{J,\\mathrm{bare}} / \\langle \\cos\\phi \\rangle_g$ and\n",
"$L_J^{(e)} = L_{J,\\mathrm{bare}} / \\langle \\cos\\phi \\rangle_e$, matching how the\n",
"coupled driven-modal workflow assigns JJ terminations when it reduces the\n",
"exported multiport network.\n",
"\n"
]
},
{
"cell_type": "code",
"id": "e0d7888292b4",
Expand Down Expand Up @@ -398,12 +422,13 @@
},
{
"cell_type": "code",
"id": "3216de2f3281",
"id": "2b2059cb9dc6",
"metadata": {},
"source": [
"RUN_ANSYS = os.environ.get(\"SQUADDS_RUN_ANSYS\") == \"1\"\n",
"CHECKPOINT_ROOT = Path(\"tutorials/runtime/drivenmodal_combined_hamiltonian/checkpoints\")\n",
"\n",
"prepared_runs = None\n",
"if RUN_ANSYS:\n",
" from squadds.simulations.drivenmodal.hfss_runner import run_drivenmodal_request\n",
"\n",
Expand Down Expand Up @@ -477,17 +502,20 @@
},
{
"cell_type": "code",
"id": "95a29aa3ef87",
"id": "c0de0c9f51f4",
"metadata": {},
"source": [
"drivenmodal_hamiltonian = {\n",
" \"qubit_frequency_ghz\": reference[\"qubit_frequency_ghz\"],\n",
" \"anharmonicity_mhz\": reference[\"anharmonicity_mhz\"],\n",
" \"cavity_frequency_ghz\": reference[\"cavity_frequency_ghz\"],\n",
" \"kappa_mhz\": reference[\"kappa_mhz\"],\n",
" \"g_mhz\": reference[\"g_mhz\"],\n",
" \"chi_mhz\": float(\"nan\"),\n",
"}\n",
"if RUN_ANSYS:\n",
" drivenmodal_hamiltonian = coupled_hamiltonian_from_prepared_runs(prepared_runs)\n",
"else:\n",
" drivenmodal_hamiltonian = {\n",
" \"qubit_frequency_ghz\": reference[\"qubit_frequency_ghz\"],\n",
" \"anharmonicity_mhz\": reference[\"anharmonicity_mhz\"],\n",
" \"cavity_frequency_ghz\": reference[\"cavity_frequency_ghz\"],\n",
" \"kappa_mhz\": reference[\"kappa_mhz\"],\n",
" \"g_mhz\": reference[\"g_mhz\"],\n",
" \"chi_mhz\": float(\"nan\"),\n",
" }\n",
"\n",
"display(hamiltonian_comparison_table(drivenmodal=drivenmodal_hamiltonian, squadds=reference))\n",
"\n",
Expand Down
12 changes: 12 additions & 0 deletions squadds/simulations/drivenmodal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
y_to_s,
)
from .design import create_multiplanar_design, write_qiskit_layer_stack_csv
from .extractors import (
coupled_hamiltonian_from_prepared_runs,
hamiltonian_from_summary_json,
hamiltonian_from_summary_mapping,
pair_capacitances_fF_from_run_dir,
pair_capacitances_fF_from_y_frame,
)
from .hfss_data import network_from_parameter_dataframe, parameter_dataframe_to_tensor, write_touchstone_from_dataframe
from .layer_stack import LAYER_STACK_COLUMNS, build_layer_stack_dataframe, resolve_layer_stack
from .models import (
Expand Down Expand Up @@ -66,6 +73,10 @@
"capacitance_dataframe_from_y_sweep",
"capacitance_matrix_from_y",
"build_capacitance_request",
"hamiltonian_from_summary_json",
"hamiltonian_from_summary_mapping",
"pair_capacitances_fF_from_run_dir",
"pair_capacitances_fF_from_y_frame",
"create_multiplanar_design",
"CoupledSystemDrivenModalRequest",
"CoupledSystemDrivenModalResult",
Expand All @@ -90,6 +101,7 @@
"default_hamiltonian_setup",
"default_hamiltonian_sweep",
"default_layer_stack",
"coupled_hamiltonian_from_prepared_runs",
"network_from_parameter_dataframe",
"parameter_dataframe_to_tensor",
"combine_port_admittance_with_jj",
Expand Down
160 changes: 160 additions & 0 deletions squadds/simulations/drivenmodal/extractors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
"""Load driven-modal comparison values from exported solver artifacts."""

from __future__ import annotations

import json
from collections.abc import Mapping
from pathlib import Path
from typing import Any

import numpy as np
import pandas as pd

from squadds.simulations.drivenmodal.capacitance import (
capacitance_matrix_from_y,
maxwell_capacitance_dataframe,
)
from squadds.simulations.drivenmodal.hfss_data import parameter_dataframe_to_tensor
from squadds.simulations.drivenmodal.workflows import (
HAMILTONIAN_KEYS,
NCAP_CAPACITANCE_KEYS,
QUBIT_CLAW_CAPACITANCE_KEYS,
)


def _nearest_frequency_index(freqs_hz: np.ndarray, target_hz: float) -> int:
freqs = np.asarray(freqs_hz, dtype=float)
if freqs.size == 0:
raise ValueError("freqs_hz must be non-empty.")
return int(np.argmin(np.abs(freqs - target_hz)))


def _pair_fF_from_maxwell(maxwell: pd.DataFrame, row: str, col: str) -> float:
return abs(float(maxwell.loc[row, col])) * 1e15


def _pair_capacitances_from_maxwell(maxwell: pd.DataFrame, *, system_kind: str) -> dict[str, float]:
gnd = "ground"
if system_kind == "qubit_claw":
cross = "cross"
claw = "claw"
return {
"cross_to_ground": _pair_fF_from_maxwell(maxwell, cross, gnd),
"claw_to_ground": _pair_fF_from_maxwell(maxwell, claw, gnd),
"cross_to_claw": _pair_fF_from_maxwell(maxwell, cross, claw),
"cross_to_cross": _pair_fF_from_maxwell(maxwell, cross, cross),
"claw_to_claw": _pair_fF_from_maxwell(maxwell, claw, claw),
"ground_to_ground": _pair_fF_from_maxwell(maxwell, gnd, gnd),
}
if system_kind == "ncap":
top = "top"
bottom = "bottom"
return {
"top_to_top": _pair_fF_from_maxwell(maxwell, top, top),
"top_to_bottom": _pair_fF_from_maxwell(maxwell, top, bottom),
"top_to_ground": _pair_fF_from_maxwell(maxwell, top, gnd),
"bottom_to_bottom": _pair_fF_from_maxwell(maxwell, bottom, bottom),
"bottom_to_ground": _pair_fF_from_maxwell(maxwell, bottom, gnd),
"ground_to_ground": _pair_fF_from_maxwell(maxwell, gnd, gnd),
}
raise ValueError("system_kind must be 'qubit_claw' or 'ncap'.")


def pair_capacitances_fF_from_y_frame(
y_frame: pd.DataFrame,
*,
system_kind: str,
extraction_freq_ghz: float,
) -> dict[str, float]:
"""Convert a Y-parameter sweep table into the same six pair labels used by Q3D rows."""
if extraction_freq_ghz <= 0:
raise ValueError("extraction_freq_ghz must be positive.")
expected = QUBIT_CLAW_CAPACITANCE_KEYS if system_kind == "qubit_claw" else NCAP_CAPACITANCE_KEYS
if system_kind not in ("qubit_claw", "ncap"):
raise ValueError("system_kind must be 'qubit_claw' or 'ncap'.")
freqs_hz, y_matrices = parameter_dataframe_to_tensor(
y_frame,
matrix_size=2,
parameter_prefix="Y",
)
target_hz = extraction_freq_ghz * 1e9
idx = _nearest_frequency_index(freqs_hz, target_hz)
f_hz = float(freqs_hz[idx])
y_matrix = y_matrices[idx]
c_active = capacitance_matrix_from_y(f_hz, y_matrix)
node_names = ["cross", "claw"] if system_kind == "qubit_claw" else ["top", "bottom"]
maxwell = maxwell_capacitance_dataframe(c_active, node_names=node_names)
pairs = _pair_capacitances_from_maxwell(maxwell, system_kind=system_kind)
for key in expected:
if key not in pairs:
raise KeyError(f"Missing extracted key {key}.")
return pairs


def pair_capacitances_fF_from_run_dir(
run_dir: str | Path,
*,
system_kind: str,
extraction_freq_ghz: float,
) -> dict[str, float]:
"""Load ``artifacts/y_parameters.pkl`` and return pair capacitances in fF."""
y_path = Path(run_dir) / "artifacts" / "y_parameters.pkl"
if not y_path.is_file():
raise FileNotFoundError(
f"Missing Y-parameter export at {y_path}. "
"Run the Ansys driven-modal export so HFSS writes y_parameters.pkl under artifacts/."
)
y_frame = pd.read_pickle(y_path)
return pair_capacitances_fF_from_y_frame(
y_frame,
system_kind=system_kind,
extraction_freq_ghz=extraction_freq_ghz,
)


def hamiltonian_from_summary_mapping(extracted: Mapping[str, Any] | None) -> dict[str, float]:
"""Normalize a post-processing ``extracted`` record to ``HAMILTONIAN_KEYS``."""
if extracted is None:
raise ValueError("extracted must not be None.")

def as_float(key: str) -> float:
raw = extracted.get(key)
if raw is None:
return float("nan")
return float(raw)

return {key: as_float(key) for key in HAMILTONIAN_KEYS}


def hamiltonian_from_summary_json(summary_path: str | Path) -> dict[str, float]:
"""Read ``artifacts/summary.json`` written by coupled driven-modal post-processing."""
path = Path(summary_path)
if not path.is_file():
raise FileNotFoundError(f"Missing summary JSON at {path}.")
payload = json.loads(path.read_text(encoding="utf-8"))
extracted = payload.get("extracted")
return hamiltonian_from_summary_mapping(extracted)


def coupled_hamiltonian_from_prepared_runs(prepared_runs: Mapping[str, Any]) -> dict[str, float]:
"""Load extracted Hamiltonian metrics from the first available band ``summary.json``."""
band_preferences = ("resonator_band", "qubit_band", "bridge_band")
tried: list[str] = []
for band_name in band_preferences:
if band_name not in prepared_runs:
continue
manifest = prepared_runs[band_name].get("manifest")
if manifest is None:
raise KeyError(f"prepared_runs[{band_name!r}] is missing 'manifest'.")
run_dir = Path(manifest["run_dir"])
summary_path = run_dir / "artifacts" / "summary.json"
tried.append(str(summary_path))
if summary_path.is_file():
return hamiltonian_from_summary_json(summary_path)
detail = "\n - ".join(tried) if tried else "(no segmented band entries were present)."
raise FileNotFoundError(
"No coupled summary.json found in expected locations. Searched:\n - "
+ detail
+ "\nRun coupled post-processing so it writes summary.json next to y_parameters.pkl "
"(see tutorials/Tutorial-11_DrivenModal_Coupled_System_Postprocessing.py)."
)
Loading
Loading