diff --git a/docs/source/tutorials/Tutorial-10_DrivenModal_Capacitance_Extraction.ipynb b/docs/source/tutorials/Tutorial-10_DrivenModal_Capacitance_Extraction.ipynb index fe8e959e..ee387731 100644 --- a/docs/source/tutorials/Tutorial-10_DrivenModal_Capacitance_Extraction.ipynb +++ b/docs/source/tutorials/Tutorial-10_DrivenModal_Capacitance_Extraction.ipynb @@ -52,7 +52,7 @@ }, { "cell_type": "code", - "id": "73cdacc6c6d2", + "id": "36ec5c0e810c", "metadata": {}, "source": [ "import os\n", @@ -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", @@ -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", @@ -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", diff --git a/docs/source/tutorials/Tutorial-11_DrivenModal_Combined_Hamiltonian_Extraction.ipynb b/docs/source/tutorials/Tutorial-11_DrivenModal_Combined_Hamiltonian_Extraction.ipynb index 41cbbb79..3b86a376 100644 --- a/docs/source/tutorials/Tutorial-11_DrivenModal_Combined_Hamiltonian_Extraction.ipynb +++ b/docs/source/tutorials/Tutorial-11_DrivenModal_Combined_Hamiltonian_Extraction.ipynb @@ -75,7 +75,7 @@ }, { "cell_type": "code", - "id": "bb8952e20cf8", + "id": "df2e21e15377", "metadata": {}, "source": [ "import contextlib\n", @@ -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", @@ -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", @@ -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", @@ -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", diff --git a/squadds/simulations/drivenmodal/__init__.py b/squadds/simulations/drivenmodal/__init__.py index c09581c9..735a2209 100644 --- a/squadds/simulations/drivenmodal/__init__.py +++ b/squadds/simulations/drivenmodal/__init__.py @@ -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 ( @@ -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", @@ -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", diff --git a/squadds/simulations/drivenmodal/extractors.py b/squadds/simulations/drivenmodal/extractors.py new file mode 100644 index 00000000..49f4b558 --- /dev/null +++ b/squadds/simulations/drivenmodal/extractors.py @@ -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)." + ) diff --git a/tests/test_drivenmodal_extractors.py b/tests/test_drivenmodal_extractors.py new file mode 100644 index 00000000..1544df84 --- /dev/null +++ b/tests/test_drivenmodal_extractors.py @@ -0,0 +1,61 @@ +import json + +import numpy as np +import pandas as pd + +from squadds.simulations.drivenmodal.extractors import ( + coupled_hamiltonian_from_prepared_runs, + hamiltonian_from_summary_mapping, + pair_capacitances_fF_from_y_frame, +) + + +def test_pair_capacitances_fF_from_y_frame_qubit_claw_maps_maxwell_pairs(): + frame = pd.DataFrame( + { + "Y11": [1.0j * 1e-3, 2.0j * 1e-3], + "Y12": [3.0j * 1e-4, 4.0j * 1e-4], + "Y21": [3.0j * 1e-4, 4.0j * 1e-4], + "Y22": [2.0j * 1e-3, 3.0j * 1e-3], + }, + index=[5.0, 6.0], + ) + caps = pair_capacitances_fF_from_y_frame( + frame, + system_kind="qubit_claw", + extraction_freq_ghz=5.0, + ) + assert set(caps.keys()) == { + "cross_to_ground", + "claw_to_ground", + "cross_to_claw", + "cross_to_cross", + "claw_to_claw", + "ground_to_ground", + } + assert all(np.isfinite(v) for v in caps.values()) + assert all(v >= 0.0 for v in caps.values()) + + +def test_hamiltonian_from_summary_mapping_fills_hamiltonian_keys_with_nan_for_missing(): + row = hamiltonian_from_summary_mapping({"qubit_frequency_ghz": 4.0}) + assert row["qubit_frequency_ghz"] == 4.0 + assert np.isnan(row["chi_mhz"]) + + +def test_coupled_hamiltonian_from_prepared_runs_prefers_resonator_band_summary(tmp_path): + resonator = tmp_path / "res" + bridge = tmp_path / "bridge" + resonator.mkdir(parents=True) + bridge.mkdir(parents=True) + summary = {"extracted": {"qubit_frequency_ghz": 3.0, "chi_mhz": 0.1}} + (resonator / "artifacts").mkdir(parents=True, exist_ok=True) + (resonator / "artifacts" / "summary.json").write_text(json.dumps(summary), encoding="utf-8") + + prepared = { + "bridge_band": {"manifest": {"run_dir": str(bridge)}}, + "resonator_band": {"manifest": {"run_dir": str(resonator)}}, + } + out = coupled_hamiltonian_from_prepared_runs(prepared) + assert out["qubit_frequency_ghz"] == 3.0 + assert out["chi_mhz"] == 0.1 diff --git a/tutorials/Tutorial-10_DrivenModal_Capacitance_Extraction.ipynb b/tutorials/Tutorial-10_DrivenModal_Capacitance_Extraction.ipynb index fe8e959e..157f0550 100644 --- a/tutorials/Tutorial-10_DrivenModal_Capacitance_Extraction.ipynb +++ b/tutorials/Tutorial-10_DrivenModal_Capacitance_Extraction.ipynb @@ -52,8 +52,10 @@ }, { "cell_type": "code", - "id": "73cdacc6c6d2", + "execution_count": 1, + "id": "36ec5c0e810c", "metadata": {}, + "outputs": [], "source": [ "import os\n", "from pathlib import Path\n", @@ -68,6 +70,7 @@ " default_capacitance_setup,\n", " default_capacitance_sweep,\n", " maxwell_matrix_interpretation,\n", + " pair_capacitances_fF_from_run_dir,\n", ")\n", "\n", "try:\n", @@ -78,9 +81,7 @@ " print(obj)\n", "\n", "\n" - ], - "outputs": [], - "execution_count": 1 + ] }, { "cell_type": "markdown", @@ -108,8 +109,25 @@ }, { "cell_type": "code", + "execution_count": 2, "id": "b4207ed6d3fe", "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "design_options {'pos_x': '-1500um', 'pos_y': '1200um', 'orien...\n", + "cross_to_ground 174.13928\n", + "cross_to_claw 5.7759\n", + "Name: 3, dtype: object\n", + "design_options {'prime_width': '11.7um', 'prime_gap': '5.1um'...\n", + "top_to_bottom 36.28408\n", + "top_to_ground 29.22434\n", + "Name: 1, dtype: object\n" + ] + } + ], "source": [ "db = SQuADDS_DB()\n", "\n", @@ -131,15 +149,7 @@ "display(ncap_row[[\"design_options\", \"top_to_bottom\", \"top_to_ground\"]])\n", "\n", "\n" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": "design_options {'pos_x': '-1500um', 'pos_y': '1200um', 'orien...\ncross_to_ground 174.13928\ncross_to_claw 5.7759\nName: 3, dtype: object\ndesign_options {'prime_width': '11.7um', 'prime_gap': '5.1um'...\ntop_to_bottom 36.28408\ntop_to_ground 29.22434\nName: 1, dtype: object\n" - } - ], - "execution_count": 2 + ] }, { "cell_type": "markdown", @@ -195,8 +205,35 @@ }, { "cell_type": "code", + "execution_count": 3, "id": "d597e32f1e1e", "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " HFSS setup value\n", + "name DrivenModalSetup\n", + "freq_ghz 5.0\n", + "max_delta_s 0.005\n", + "max_passes 20\n", + "min_passes 2\n", + "min_converged 5\n", + "pct_refinement 30\n", + "basis_order -1\n", + " HFSS sweep value\n", + "start_ghz 1.0\n", + "stop_ghz 10.0\n", + "count 400\n", + "name DrivenModalSweep\n", + "type Interpolating\n", + "save_fields False\n", + "interpolation_tol 0.005\n", + "interpolation_max_solutions 400\n" + ] + } + ], "source": [ "setup = default_capacitance_setup(freq_ghz=5.0)\n", "sweep = default_capacitance_sweep(start_ghz=1.0, stop_ghz=10.0, count=400)\n", @@ -220,20 +257,28 @@ "display(pd.DataFrame([sweep.to_renderer_kwargs()]).T.rename(columns={0: \"HFSS sweep value\"}))\n", "\n", "\n" - ], + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "89b3ab5b0e75", + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", - "text": " HFSS setup value\nname DrivenModalSetup\nfreq_ghz 5.0\nmax_delta_s 0.005\nmax_passes 20\nmin_passes 2\nmin_converged 5\npct_refinement 30\nbasis_order -1\n HFSS sweep value\nstart_ghz 1.0\nstop_ghz 10.0\ncount 400\nname DrivenModalSweep\ntype Interpolating\nsave_fields False\ninterpolation_tol 0.005\ninterpolation_max_solutions 400\n" + "text": [ + " request ... metadata\n", + "0 qubit_claw ... {'hfss_target': 'junction', 'draw_inductor': F...\n", + "1 qubit_claw ... NaN\n", + "2 ncap ... NaN\n", + "3 ncap ... NaN\n", + "\n", + "[4 rows x 5 columns]\n" + ] } ], - "execution_count": 3 - }, - { - "cell_type": "code", - "id": "89b3ab5b0e75", - "metadata": {}, "source": [ "port_table = pd.DataFrame(\n", " [\n", @@ -245,20 +290,26 @@ "display(port_table)\n", "\n", "\n" - ], + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "49e706ca0211", + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", - "text": " request ... metadata\n0 qubit_claw ... {'hfss_target': 'junction', 'draw_inductor': F...\n1 qubit_claw ... NaN\n2 ncap ... NaN\n3 ncap ... NaN\n\n[4 rows x 5 columns]\n" + "text": [ + " request preset ... metal_z_coord_um substrate_z_coord_um\n", + "0 qubit_claw squadds_hfss_v1 ... 0.0 0.0\n", + "1 ncap squadds_hfss_v1 ... 0.0 0.0\n", + "\n", + "[2 rows x 10 columns]\n" + ] } ], - "execution_count": 4 - }, - { - "cell_type": "code", - "id": "49e706ca0211", - "metadata": {}, "source": [ "layer_stack_table = pd.DataFrame(\n", " [\n", @@ -269,15 +320,7 @@ "display(layer_stack_table)\n", "\n", "\n" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": " request preset ... metal_z_coord_um substrate_z_coord_um\n0 qubit_claw squadds_hfss_v1 ... 0.0 0.0\n1 ncap squadds_hfss_v1 ... 0.0 0.0\n\n[2 rows x 10 columns]\n" - } - ], - "execution_count": 5 + ] }, { "cell_type": "markdown", @@ -315,12 +358,16 @@ }, { "cell_type": "code", - "id": "29c28b5d5b91", + "execution_count": 6, + "id": "463854c180d2", "metadata": {}, + "outputs": [], "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", @@ -331,9 +378,7 @@ " print(\"NCap run directory:\", ncap_prepared[\"manifest\"][\"run_dir\"])\n", "\n", "\n" - ], - "outputs": [], - "execution_count": 6 + ] }, { "cell_type": "markdown", @@ -371,28 +416,33 @@ }, { "cell_type": "code", - "id": "434a41d8979c", + "execution_count": null, + "id": "16fa0a52a1ac", "metadata": {}, + "outputs": [], "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", - "\n", - "\n" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": " quantity drivenmodal_fF q3d_fF percent_error\n0 cross_to_ground 174.13928 174.13928 0.0\n1 claw_to_ground 97.22405 97.22405 0.0\n2 cross_to_claw 5.77590 5.77590 0.0\n3 cross_to_cross 174.13928 174.13928 0.0\n4 claw_to_claw 103.37057 103.37057 0.0\n5 ground_to_ground 335.31609 335.31609 0.0\n quantity drivenmodal_fF q3d_fF percent_error\n0 top_to_top 65.85844 65.85844 0.0\n1 top_to_bottom 36.28408 36.28408 0.0\n2 top_to_ground 29.22434 29.22434 0.0\n3 bottom_to_bottom 94.96956 94.96956 0.0\n4 bottom_to_ground 58.07364 58.07364 0.0\n5 ground_to_ground 124.18885 124.18885 0.0\n" - } - ], - "execution_count": 7 + "display(capacitance_comparison_table(drivenmodal_fF=ncap_drivenmodal_fF, q3d_fF=ncap_q3d))" + ] }, { "cell_type": "markdown", @@ -416,24 +466,6 @@ "\n" ] }, - { - "cell_type": "code", - "id": "e5499709e0fb", - "metadata": {}, - "source": [ - "display(maxwell_matrix_interpretation())\n", - "\n", - "\n" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": " entry ... do_not_add_again\n0 C[cross, cross] ... includes mutual capacitance to the claw\n1 C[cross, claw] ... use abs(...) only when naming pair capacitances\n2 cross_to_ground + cross_to_claw ... do not also add cross_to_cross\n\n[3 rows x 3 columns]\n" - } - ], - "execution_count": 8 - }, { "cell_type": "markdown", "id": "13c57ec2d46f", diff --git a/tutorials/Tutorial-10_DrivenModal_Capacitance_Extraction.py b/tutorials/Tutorial-10_DrivenModal_Capacitance_Extraction.py index d2f8a3f0..05531817 100644 --- a/tutorials/Tutorial-10_DrivenModal_Capacitance_Extraction.py +++ b/tutorials/Tutorial-10_DrivenModal_Capacitance_Extraction.py @@ -50,6 +50,7 @@ default_capacitance_setup, default_capacitance_sweep, maxwell_matrix_interpretation, + pair_capacitances_fF_from_run_dir, ) try: @@ -221,6 +222,8 @@ def display(obj): RUN_ANSYS = os.environ.get("SQUADDS_RUN_ANSYS") == "1" CHECKPOINT_ROOT = Path("tutorials/runtime/drivenmodal_capacitance/checkpoints") +qubit_prepared = None +ncap_prepared = None if RUN_ANSYS: from squadds.simulations.drivenmodal.hfss_runner import run_drivenmodal_request @@ -263,8 +266,21 @@ def display(obj): qubit_q3d = capacitance_reference_summary(qubit_row, system_kind="qubit_claw") ncap_q3d = capacitance_reference_summary(ncap_row, system_kind="ncap") -qubit_drivenmodal_fF = qubit_q3d -ncap_drivenmodal_fF = ncap_q3d +extraction_freq_ghz = float(setup.freq_ghz) +if RUN_ANSYS: + qubit_drivenmodal_fF = pair_capacitances_fF_from_run_dir( + qubit_prepared["manifest"]["run_dir"], + system_kind="qubit_claw", + extraction_freq_ghz=extraction_freq_ghz, + ) + ncap_drivenmodal_fF = pair_capacitances_fF_from_run_dir( + ncap_prepared["manifest"]["run_dir"], + system_kind="ncap", + extraction_freq_ghz=extraction_freq_ghz, + ) +else: + qubit_drivenmodal_fF = qubit_q3d + ncap_drivenmodal_fF = ncap_q3d display(capacitance_comparison_table(drivenmodal_fF=qubit_drivenmodal_fF, q3d_fF=qubit_q3d)) display(capacitance_comparison_table(drivenmodal_fF=ncap_drivenmodal_fF, q3d_fF=ncap_q3d)) diff --git a/tutorials/Tutorial-11_DrivenModal_Combined_Hamiltonian_Extraction.ipynb b/tutorials/Tutorial-11_DrivenModal_Combined_Hamiltonian_Extraction.ipynb index 41cbbb79..f647505b 100644 --- a/tutorials/Tutorial-11_DrivenModal_Combined_Hamiltonian_Extraction.ipynb +++ b/tutorials/Tutorial-11_DrivenModal_Combined_Hamiltonian_Extraction.ipynb @@ -75,8 +75,10 @@ }, { "cell_type": "code", - "id": "bb8952e20cf8", + "execution_count": 1, + "id": "df2e21e15377", "metadata": {}, + "outputs": [], "source": [ "import contextlib\n", "import io\n", @@ -88,6 +90,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", @@ -102,9 +105,7 @@ " print(obj)\n", "\n", "\n" - ], - "outputs": [], - "execution_count": 1 + ] }, { "cell_type": "markdown", @@ -134,8 +135,31 @@ }, { "cell_type": "code", + "execution_count": 2, "id": "a00d74e16210", "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " index_qc ... design_options\n", + "0 0 ... {'cavity_claw_options': {'coupler_type': 'CLT'...\n", + "1 0 ... {'cavity_claw_options': {'coupler_type': 'CLT'...\n", + "2 0 ... {'cavity_claw_options': {'coupler_type': 'CLT'...\n", + "3 0 ... {'cavity_claw_options': {'coupler_type': 'CLT'...\n", + "4 0 ... {'cavity_claw_options': {'coupler_type': 'CLT'...\n", + "\n", + "[5 rows x 31 columns]\n", + " index_qc cross_to_ground ... anharmonicity_MHz g_MHz\n", + "16088 1402 159.52633 ... -127.794520 50.116660\n", + "16093 1402 159.52633 ... -127.794520 50.150523\n", + "14776 1288 153.31148 ... -133.068055 51.685967\n", + "\n", + "[3 rows x 36 columns]\n" + ] + } + ], "source": [ "db = SQuADDS_DB()\n", "db.select_system([\"qubit\", \"cavity_claw\"])\n", @@ -164,15 +188,7 @@ "display(results.head(3))\n", "\n", "\n" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": " index_qc ... design_options\n0 0 ... {'cavity_claw_options': {'coupler_type': 'CLT'...\n1 0 ... {'cavity_claw_options': {'coupler_type': 'CLT'...\n2 0 ... {'cavity_claw_options': {'coupler_type': 'CLT'...\n3 0 ... {'cavity_claw_options': {'coupler_type': 'CLT'...\n4 0 ... {'cavity_claw_options': {'coupler_type': 'CLT'...\n\n[5 rows x 31 columns]\n index_qc cross_to_ground ... anharmonicity_MHz g_MHz\n16088 1402 159.52633 ... -127.794520 50.116660\n16093 1402 159.52633 ... -127.794520 50.150523\n14776 1288 153.31148 ... -133.068055 51.685967\n\n[3 rows x 36 columns]\n" - } - ], - "execution_count": 2 + ] }, { "cell_type": "markdown", @@ -239,8 +255,21 @@ }, { "cell_type": "code", + "execution_count": 3, "id": "400f338c3287", "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " band start_GHz stop_GHz points type\n", + "0 qubit_band 3.468333 4.468333 22000 Interpolating\n", + "1 bridge_band 4.468333 8.576342 4001 Fast\n", + "2 resonator_band 8.576342 9.576342 22000 Interpolating\n" + ] + } + ], "source": [ "reference = coupled_reference_summary(reference_row)\n", "\n", @@ -275,38 +304,55 @@ "display(sweep_table)\n", "\n", "\n" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": " band start_GHz stop_GHz points type\n0 qubit_band 3.468333 4.468333 22000 Interpolating\n1 bridge_band 4.468333 8.576342 4001 Fast\n2 resonator_band 8.576342 9.576342 22000 Interpolating\n" - } - ], - "execution_count": 3 + ] }, { "cell_type": "code", + "execution_count": 4, "id": "ff2703361b6d", "metadata": {}, - "source": [ - "display(pd.DataFrame([setup.to_renderer_kwargs()]).T.rename(columns={0: \"HFSS setup value\"}))\n", - "\n", - "\n" - ], "outputs": [ { "name": "stdout", "output_type": "stream", - "text": " HFSS setup value\nname DrivenModalSetup\nfreq_ghz 9.076342\nmax_delta_s 0.005\nmax_passes 20\nmin_passes 2\nmin_converged 7\npct_refinement 30\nbasis_order -1\n" + "text": [ + " HFSS setup value\n", + "name DrivenModalSetup\n", + "freq_ghz 9.076342\n", + "max_delta_s 0.005\n", + "max_passes 20\n", + "min_passes 2\n", + "min_converged 7\n", + "pct_refinement 30\n", + "basis_order -1\n" + ] } ], - "execution_count": 4 + "source": [ + "display(pd.DataFrame([setup.to_renderer_kwargs()]).T.rename(columns={0: \"HFSS setup value\"}))\n", + "\n", + "\n" + ] }, { "cell_type": "code", + "execution_count": 5, "id": "4784348d3697", "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " port ... metadata\n", + "0 feedline_input ... NaN\n", + "1 feedline_output ... NaN\n", + "2 jj ... {'hfss_target': 'junction', 'draw_inductor': F...\n", + "\n", + "[3 rows x 4 columns]\n" + ] + } + ], "source": [ "port_table = pd.DataFrame(\n", " [\n", @@ -317,20 +363,46 @@ "display(port_table)\n", "\n", "\n" - ], + ] + }, + { + "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", + "execution_count": 6, + "id": "e0d7888292b4", + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", - "text": " port ... metadata\n0 feedline_input ... NaN\n1 feedline_output ... NaN\n2 jj ... {'hfss_target': 'junction', 'draw_inductor': F...\n\n[3 rows x 4 columns]\n" + "text": [ + " EJ_GHz EC_GHz LJ_bare_nH LJ_ground_nH LJ_excited_nH\n", + "0 16.346151 0.118811 10.0 10.641689 12.209995\n" + ] } ], - "execution_count": 5 - }, - { - "cell_type": "code", - "id": "e0d7888292b4", - "metadata": {}, "source": [ "jj_table = pd.DataFrame(\n", " [\n", @@ -346,15 +418,7 @@ "display(jj_table)\n", "\n", "\n" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": " EJ_GHz EC_GHz LJ_bare_nH LJ_ground_nH LJ_excited_nH\n0 16.346151 0.118811 10.0 10.641689 12.209995\n" - } - ], - "execution_count": 6 + ] }, { "cell_type": "markdown", @@ -398,12 +462,15 @@ }, { "cell_type": "code", - "id": "3216de2f3281", + "execution_count": 7, + "id": "2b2059cb9dc6", "metadata": {}, + "outputs": [], "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", @@ -414,9 +481,7 @@ " print(f\"{band}: {prepared['manifest']['run_dir']}\")\n", "\n", "\n" - ], - "outputs": [], - "execution_count": 7 + ] }, { "cell_type": "markdown", @@ -477,30 +542,25 @@ }, { "cell_type": "code", - "id": "95a29aa3ef87", + "execution_count": null, + "id": "c0de0c9f51f4", "metadata": {}, + "outputs": [], "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", - "\n", - "display(hamiltonian_comparison_table(drivenmodal=drivenmodal_hamiltonian, squadds=reference))\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", - "\n" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": " quantity drivenmodal squadds percent_error\n0 qubit_frequency_ghz 3.968333 3.968333 0.0\n1 anharmonicity_mhz -127.794520 -127.794520 -0.0\n2 cavity_frequency_ghz 9.076342 9.076342 0.0\n3 kappa_mhz 0.299441 0.299441 0.0\n4 g_mhz 50.116660 50.116660 0.0\n5 chi_mhz NaN NaN NaN\n" - } - ], - "execution_count": 8 + "display(hamiltonian_comparison_table(drivenmodal=drivenmodal_hamiltonian, squadds=reference))" + ] }, { "cell_type": "markdown", diff --git a/tutorials/Tutorial-13_DrivenModal_Combined_Hamiltonian_Extraction.py b/tutorials/Tutorial-13_DrivenModal_Combined_Hamiltonian_Extraction.py index 2b405812..3f4c41b1 100644 --- a/tutorials/Tutorial-13_DrivenModal_Combined_Hamiltonian_Extraction.py +++ b/tutorials/Tutorial-13_DrivenModal_Combined_Hamiltonian_Extraction.py @@ -70,6 +70,7 @@ from squadds import Analyzer, SQuADDS_DB from squadds.simulations.drivenmodal import ( build_segmented_coupled_system_requests, + coupled_hamiltonian_from_prepared_runs, coupled_reference_summary, default_hamiltonian_setup, hamiltonian_comparison_table, @@ -237,6 +238,23 @@ def display(obj): display(port_table) +# %% [markdown] +# ## State-dependent Josephson inductance +# +# `LJ_bare_nH` is the linear Josephson inductance from the transmon design options +# (`aedt_q3d_inductance` / `Lj` / `LJ`). The ground-state and excited-state +# columns use the same workflow as `coupled_reference_summary(...)`: helper +# `transmon_state_inductances(...)` in `squadds.simulations.drivenmodal.workflows` +# builds a zero-temperature `scqubits.Transmon` with +# $E_J$ from the bare $L_J$ and $E_C$ from the qubit shunt capacitance (via the +# database `cross_to_ground` and `cross_to_claw` pair capacitances in fF). +# It then evaluates the transmon `cos_phi_operator` in the ground and +# first-excited eigenstates. The effective inductances are +# $L_J^{(g)} = L_{J,\mathrm{bare}} / \langle \cos\phi \rangle_g$ and +# $L_J^{(e)} = L_{J,\mathrm{bare}} / \langle \cos\phi \rangle_e$, matching how the +# coupled driven-modal workflow assigns JJ terminations when it reduces the +# exported multiport network. + # %% jj_table = pd.DataFrame( [ @@ -290,6 +308,7 @@ def display(obj): RUN_ANSYS = os.environ.get("SQUADDS_RUN_ANSYS") == "1" CHECKPOINT_ROOT = Path("tutorials/runtime/drivenmodal_combined_hamiltonian/checkpoints") +prepared_runs = None if RUN_ANSYS: from squadds.simulations.drivenmodal.hfss_runner import run_drivenmodal_request @@ -352,14 +371,17 @@ def display(obj): # same table is generated from the exported driven-modal network data. # %% -drivenmodal_hamiltonian = { - "qubit_frequency_ghz": reference["qubit_frequency_ghz"], - "anharmonicity_mhz": reference["anharmonicity_mhz"], - "cavity_frequency_ghz": reference["cavity_frequency_ghz"], - "kappa_mhz": reference["kappa_mhz"], - "g_mhz": reference["g_mhz"], - "chi_mhz": float("nan"), -} +if RUN_ANSYS: + drivenmodal_hamiltonian = coupled_hamiltonian_from_prepared_runs(prepared_runs) +else: + drivenmodal_hamiltonian = { + "qubit_frequency_ghz": reference["qubit_frequency_ghz"], + "anharmonicity_mhz": reference["anharmonicity_mhz"], + "cavity_frequency_ghz": reference["cavity_frequency_ghz"], + "kappa_mhz": reference["kappa_mhz"], + "g_mhz": reference["g_mhz"], + "chi_mhz": float("nan"), + } display(hamiltonian_comparison_table(drivenmodal=drivenmodal_hamiltonian, squadds=reference))