> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hardwave.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Steady-State Simulation

> Run single-point steady-state simulations and read scalar outputs in Hardwave

Steady-state simulation solves the graph once and returns a single value for every output port. Use it to answer questions like "at this supply voltage and load current, what does the system do?"

## Basic run

```python theme={null}
from hardwave.simulation import SimulationEngine, SimulationConfig
from hardwave.solvers import SimulationDomain

engine = SimulationEngine(graph)

result = engine.run(
    inputs={
        "ldo": {"load_current": 0.05},   # 50 mA load
    },
    config=SimulationConfig(domain=SimulationDomain.STEADY_STATE),
)

print(result.get_output("ldo",  "v_out"))        # 5.0
print(result.get_output("ldo",  "power_loss"))   # 0.35 W
print(result.get_output("load", "current"))      # 0.05
```

`SimulationDomain.STEADY_STATE` is the default domain. You can omit `config` for simple runs:

```python theme={null}
result = engine.run(inputs={"ctrl": {"temperature": 28.0}})
```

## Parameter sweeps

Run the engine repeatedly with different external inputs to sweep parameters:

```python theme={null}
print(f"{'Temp':>6}  {'Openness':>10}  {'Vent Angle':>12}")
print("-" * 34)
for T in [18.0, 22.0, 25.0, 27.5, 30.0, 35.0, 40.0]:
    r = engine.run(inputs={"ctrl": {"temperature": T}, "servo": {"load_torque": 0.0}})
    openness = r.get_output("ctrl",       "vent_state")
    angle    = r.get_output("pos_sensor", "vent_angle_deg")
    print(f"{T:>5.1f}°C  {openness:>10.0%}  {angle:>11.1f}°")
```

## Reading results

```python theme={null}
# Single scalar output
value = result.get_output("instance_id", "port_name")

# JSON-serializable dict
snapshot = result.to_dict()

# Diagnostics and warnings
for diag in result.diagnostics():
    print(diag)

warnings = result.get_warnings()
faults = result.get_faults()
```

To attach this snapshot to a cloud-saved graph for the dashboard **RESULTS** tab, see [Saving Graphs](/graphs/saving).

### Fault-aware components

`DCMotor` and `LiPoCell` emit runtime diagnostics when limits are exceeded. Check `health` and `fault_code` output ports, or filter `result.get_faults()`.

```python theme={null}
from hardwave.simulation import SimulationConfig, FaultMode

# Default: continue with degraded outputs after a fault
result = engine.run(inputs={...})

# Stop simulation on first FAULT (raises SimulationError)
result = engine.run(
    inputs={...},
    config=SimulationConfig(fault_mode=FaultMode.STOP),
)
```

## How execution works

`engine.run()` calls `graph.topological_order()` to get a safe evaluation sequence, then for each component:

1. Collects input values from upstream outputs, the `inputs` dict, or port defaults
2. Calls the component solver and runs `post_solve_diagnostics()`
3. Applies fault output degradation if the component is faulted
4. Stores outputs for downstream components

ODE components in steady-state use their algebraic `solve()` fallback (not the frozen ODE integrator state).

The result object wraps this output dict so you can query by `(instance_id, port_name)`.

## Next steps

<CardGroup cols={2}>
  <Card title="Component Faults" icon="triangle-exclamation" href="/guides/component-faults">
    Runtime warnings, faults, and health output ports
  </Card>

  <Card title="Transient Simulation" icon="chart-line" href="/simulation/transient">
    Step through time and collect time-series data
  </Card>

  <Card title="Solvers" icon="function" href="/simulation/solvers">
    Formula, ODE, lookup table, and ML solvers
  </Card>
</CardGroup>
