# How to Troubleshoot Ansys Simulation Convergence for High-Frequency Cavity Designs in SQuADDS

> Troubleshoot Ansys simulation convergence for high-frequency cavity designs in SQuADDS by adjusting key parameters, switching solvers, and monitoring simulation plans for faster, accurate results.

- Repository: [Levenson-Falk Lab/squadds](https://github.com/lfl-lab/squadds)
- Tags: how-to-guide
- Published: 2026-03-06

---

**You can resolve Ansys HFSS convergence issues in SQuADDS by adjusting the `max_delta_f`, `pct_refinement`, and `solution_order` parameters via the `update_simulation_setup` method in `AnsysSimulator`, switching from iterative to direct solvers when stagnation occurs, and monitoring the rich-console simulation plan printed by `_run_simulation`.**

High-frequency cavity simulations in SQuADDS rely on the `AnsysSimulator` class to orchestrate Ansys HFSS eigenmode and loss-of-mode (LOM) analyses. When simulations fail to converge—showing warnings like "Maximum number of passes reached" or stagnant frequency values—you need precise control over mesh refinement and solver settings. This guide explains how to troubleshoot Ansys simulation convergence for high-frequency cavity designs in SQuADDS using the actual source code architecture.

## How Convergence Is Controlled in SQuADDS

The `AnsysSimulator` class in [`squadds/simulations/ansys_simulator.py`](https://github.com/lfl-lab/squadds/blob/main/squadds/simulations/ansys_simulator.py) serves as the high-level wrapper that builds Metal designs, configures HFSS setups, and executes simulations. Convergence behavior is dictated by two default configuration dictionaries and the `update_simulation_setup` helper method.

### Core Components Governing Convergence

| Component | Role | Source Location |
|-----------|------|-----------------|
| **`AnsysSimulator`** | Wraps the HFSS interface, builds geometries, and executes eigenmode/LOM sweeps with progress displayed via `rich.Console`. | [[`squadds/simulations/ansys_simulator.py`](https://github.com/lfl-lab/squadds/blob/main/squadds/simulations/ansys_simulator.py)](https://github.com/lfl-lab/squadds/blob/master/squadds/simulations/ansys_simulator.py), lines 52‑86 |
| **`default_eigenmode_options`** | Baseline eigenmode setup controlling mesh refinement, adaptive passes, basis order, and frequency limits. | [[`ansys_simulator.py`](https://github.com/lfl-lab/squadds/blob/main/ansys_simulator.py)](https://github.com/lfl-lab/squadds/blob/master/squadds/simulations/ansys_simulator.py), lines 52‑68 |
| **`default_lom_options`** | Baseline loss-of-mode setup for qubit capacitance extraction and material properties. | [[`ansys_simulator.py`](https://github.com/lfl-lab/squadds/blob/main/ansys_simulator.py)](https://github.com/lfl-lab/squadds/blob/master/squadds/simulations/ansys_simulator.py), lines 69‑86 |
| **`update_simulation_setup`** | Runtime API allowing users to tweak `max_passes`, `pct_refinement`, and other HFSS parameters without rebuilding the design. | [[`ansys_simulator.py`](https://github.com/lfl-lab/squadds/blob/main/ansys_simulator.py)](https://github.com/lfl-lab/squadds/blob/master/squadds/simulations/ansys_simulator.py), lines 13‑66 |
| **`_run_simulation`** | Orchestrates HFSS calls via `simulate_whole_device` and `simulate_single_design`, printing a "Simulation Plan" table showing exact parameters. | [[`ansys_simulator.py`](https://github.com/lfl-lab/squadds/blob/main/ansys_simulator.py)](https://github.com/lfl-lab/squadds/blob/master/squadds/simulations/ansys_simulator.py), lines 70‑129 |
| **`get_freq` / `get_freq_Q_kappa`** | Utilities running EPR analysis, generating convergence plots, and extracting resonant frequency, Q-factor, and κ-linewidth. | [[`squadds/simulations/utils.py`](https://github.com/lfl-lab/squadds/blob/main/squadds/simulations/utils.py)](https://github.com/lfl-lab/squadds/blob/master/squadds/simulations/utils.py), lines 49‑109 |

### Critical Convergence Parameters

SQuADDS exposes four levers that directly impact HFSS convergence:

1. **Pass Limits** – **`max_passes`** (default 30) and **`min_passes`** (default 1) bound the number of adaptive mesh refinements.
2. **Mesh Refinement** – **`pct_refinement`** (default 30%) and **`max_delta_f`** (default 0.02 GHz) drive the refinement criteria between passes.
3. **Solution Order** – **`solution_order`** defaults to `"High"`, forcing higher-order finite-element basis functions.
4. **Solver Type** – **`solver_type`** defaults to `"Iterative"` but can be swapped to `"Direct"` when the iterative solver stagnates.

All parameters live inside dictionaries injected into HFSS via the `AnsysSimulator` constructor and modifiable through `update_simulation_setup`.

## Common Convergence Failure Modes and Fixes

The following table maps specific HFSS warning messages to root causes and concrete SQuADDS API calls.

| Symptom | Root Cause | Fix via `update_simulation_setup` |
|---------|-----------|-----------------------------------|
| **"Maximum number of passes reached"** with frequency still drifting | `max_delta_f` too lenient; mesh insufficiently refined. | ```python\nsim.update_simulation_setup(\n    target="all",\n    max_delta_f=0.005,\n    pct_refinement=50\n)\n``` |
| **Frequency oscillates non-monotonically** between passes | Insufficient basis order for high-Q cavity; iterative solver instability. | ```python\nsim.update_simulation_setup(\n    target="all",\n    solution_order="Very High",\n    solver_type="Direct"\n)\n``` |
| **"Mesh refinement failed"** error | `pct_refinement` percentage too high for tiny gap features. | ```python\nsim.update_simulation_setup(\n    target="all",\n    pct_refinement=20\n)\n``` |
| **Excessive runtime with minimal improvement** | `max_passes` set unnecessarily high; early termination preferable. | ```python\nsim.update_simulation_setup(\n    target="all",\n    max_passes=15\n)\n``` |
| **Zero Q-factor or κ = 0** | Material permittivity not properly set (silicon default ε_r = 11.45). Ensure `setMaterialProperties` executes. | Run simulation normally; [`utils.py`](https://github.com/lfl-lab/squadds/blob/main/utils.py) automatically calls `setMaterialProperties` during EPR analysis. |

After each adjustment, inspect the rich-console table printed by `_run_simulation` (lines 70‑129) to verify the exact parameters being passed to HFSS.

## Step-by-Step Troubleshooting Workflow

This reproducible snippet demonstrates how to instantiate the simulator, inspect current settings, tighten convergence for a 10 GHz cavity, and extract results.

```python

# 1. Import and instantiate (requires Analyzer and design dict)

from squadds.simulations.ansys_simulator import AnsysSimulator

sim = AnsysSimulator(analyzer=my_analyzer, design_options=device_options)

# 2. Inspect current eigenmode configuration

sim.get_simulation_setup(target="all")  # Mirrors _run_simulation output

# 3. Tighten convergence for high-frequency cavity

sim.update_simulation_setup(
    target="cavity",          # Isolate changes to cavity only

    max_passes=40,            # Allow more adaptive passes

    max_delta_f=0.003,        # Stricter frequency tolerance (GHz)

    pct_refinement=45,        # Finer mesh per pass

    solution_order="Very High",
    solver_type="Iterative"
)

# 4. Execute simulation synchronously

results = sim.simulate(run_async=False)  # Returns pandas.DataFrame

# 5. Extract resonant frequency

freq_ghz = results["freq"].iloc[0] / 1e9
print(f"Cavity resonant frequency ≈ {freq_ghz:.3f} GHz")

```

**Key implementation details:**

- **Line 12** calls `get_simulation_setup`, which echoes the table generated by `_run_simulation`, showing live parameter values.
- **Lines 15‑22** demonstrate targeting only the cavity setup via `target="cavity"` (use `"all"` to affect both cavity and qubit).
- **Line 25** runs the simulation blocking-synchronous; set `run_async=True` for non-blocking execution with Future objects.

## Key Source Files for Deep Debugging

When troubleshooting requires source-level inspection, reference these files in the [lfl-lab/squadds](https://github.com/lfl-lab/squadds) repository:

| File | Purpose | Critical Functions |
|------|---------|-------------------|
| [`squadds/simulations/ansys_simulator.py`](https://github.com/lfl-lab/squadds/blob/main/squadds/simulations/ansys_simulator.py) | Core simulator class holding default convergence settings and the `update_simulation_setup` API. | `AnsysSimulator.__init__`, `update_simulation_setup`, `_run_simulation` |
| [`squadds/simulations/utils.py`](https://github.com/lfl-lab/squadds/blob/main/squadds/simulations/utils.py) | EPR analysis helpers and material property setters. | `get_freq`, `get_freq_Q_kappa`, `setMaterialProperties` |
| [`squadds/simulations/simulator.py`](https://github.com/lfl-lab/squadds/blob/main/squadds/simulations/simulator.py) | Abstract base class defining the minimal interface. | `Simulator` (abstract base) |
| [`squadds/core/analysis.py`](https://github.com/lfl-lab/squadds/blob/main/squadds/core/analysis.py) | Supplies the `Analyzer` object that determines single vs. coupled system configurations. | `Analyzer.selected_system` |
| [`squadds/components/coupled_systems.py`](https://github.com/lfl-lab/squadds/blob/main/squadds/components/coupled_systems.py) | Implements `QubitCavity` geometry classes fed to HFSS. | `QubitCavity` geometry builders |
| [`tests/mvp_test.py`](https://github.com/lfl-lab/squadds/blob/main/tests/mvp_test.py) | Minimal verification test for sanity-checking convergence tweaks. | End-to-end simulation test |

## Summary

- **Adjust convergence parameters programmatically** using `update_simulation_setup` in [`squadds/simulations/ansys_simulator.py`](https://github.com/lfl-lab/squadds/blob/main/squadds/simulations/ansys_simulator.py) rather than manual HFSS GUI edits.
- **Tighten `max_delta_f` and increase `pct_refinement`** when frequency values drift across the default 30 passes.
- **Switch `solver_type` to `"Direct"`** if the iterative solver produces non-monotonic frequency oscillations.
- **Monitor the rich-console table** printed by `_run_simulation` to confirm parameter propagation.
- **Validate geometry** in [`squadds/components/coupled_systems.py`](https://github.com/lfl-lab/squadds/blob/main/squadds/components/coupled_systems.py) when mesh refinement fails on small features.

## Frequently Asked Questions

### How do I know if my SQuADDS simulation has actually converged?

Check the rich-console output generated by `_run_simulation` in [`ansys_simulator.py`](https://github.com/lfl-lab/squadds/blob/main/ansys_simulator.py). A converged run shows `max_delta_f` dropping below your threshold (default 0.02 GHz) before reaching `max_passes`. Additionally, call `get_freq` from [`utils.py`](https://github.com/lfl-lab/squadds/blob/main/utils.py) with plotting enabled to visualize frequency stabilization across passes.

### Why does my high-Q cavity simulation return a zero Q-factor?

Zero Q-factor indicates missing material loss tangents or permittivity values. The `setMaterialProperties` function in [`squadds/simulations/utils.py`](https://github.com/lfl-lab/squadds/blob/main/squadds/simulations/utils.py) automatically configures silicon (ε_r = 11.45) and other substrates during EPR analysis. Ensure your simulation actually executes through the EPR stage rather than stopping after the eigenmode solve.

### Can I use different convergence settings for the qubit and cavity in the same simulation?

Yes. Pass `target="cavity"` or `target="qubit"` to `update_simulation_setup` instead of `target="all"`. This updates only the respective entry in the internal setup dictionaries, allowing you to apply stricter `max_delta_f` for high-frequency cavities while keeping faster, looser settings for the qubit LOM analysis.

### What is the difference between `simulate_whole_device` and `simulate_single_design`?

`simulate_whole_device` runs the complete coupled qubit-cavity system through HFSS and EPR analysis, while `simulate_single_design` handles individual geometry variants. Both are called internally by `AnsysSimulator._run_simulation` (lines 70‑129) depending on whether your `Analyzer` configuration specifies a single or coupled system.