# Python API Reference

A superfície suportada para usuários é a API Python do módulo `pulsim`.

## Fluxo principal de uso

1. `YamlParser` carrega netlist e opções.
2. Ajuste fino de `SimulationOptions` em runtime.
3. `Simulator` executa DC/transiente/periódico.
4. `SimulationResult` entrega sinais e telemetria.

## Tipos principais

| Tipo | Papel |
| --- | --- |
| `YamlParserOptions`, `YamlParser` | Parse/validação de YAML `pulsim-v1`. |
| `Circuit` | Grafo/circuito pronto para simulação. |
| `SimulationOptions` | Configuração completa da simulação. |
| `Simulator` | Execução de `dc_operating_point`, `run_transient`, `run_periodic_shooting`, `run_harmonic_balance`. |
| `SimulationResult` | Sinais (`time`, `states`), eventos, telemetria e resumos de perdas/térmico. |

As APIs de transiente em Python (`Simulator.run_transient`, `run_transient_streaming`, `run_transient_shared` e `ps.run_transient`) aplicam perfil robusto por padrão para reduzir falhas de convergência.

## Compatibilidade de migração

- `ps.run_transient(...)` permanece disponível para compatibilidade procedural.
- A superfície canônica para novas integrações é `YamlParser` + `SimulationOptions` + `Simulator`.
- Em casos de migração YAML, prefira `simulation.step_mode` em vez de
  `simulation.adaptive_timestep`/`simulation.backend`.

## Exemplo completo

```python
import pulsim as ps

parser = ps.YamlParser(ps.YamlParserOptions())
circuit, options = parser.load("benchmarks/circuits/buck_converter.yaml")

options.newton_options.num_nodes = int(circuit.num_nodes())
options.newton_options.num_branches = int(circuit.num_branches())
options.linear_solver = ps.LinearSolverStackConfig.defaults()
options.integrator = ps.Integrator.TRBDF2
options.step_mode = ps.StepMode.Variable

sim = ps.Simulator(circuit, options)
result = sim.run_transient(circuit.initial_state())

print("success:", result.success)
print("steps:", result.total_steps)
print("newton_total:", result.newton_iterations_total)
print("linear_fallbacks:", result.linear_solver_telemetry.total_fallbacks)
print("backend_caps:", ps.backend_capabilities())
```

## Atalho recomendado para transiente

Para uso direto em notebook, `ps.run_transient(...)` agora aplica fallback automático
de robustez por padrão:

- retry com `dt` menor e mais iterações de Newton;
- regularização automática (bleeders + clamp de não linearidades) em caso de falha persistente.

Você pode desativar:

```python
times, states, ok, msg = ps.run_transient(
    ckt, t0, t1, dt, x0,
    robust=False,
    auto_regularize=False,
)
```

## Enums importantes

- `Integrator`: `Trapezoidal`, `BDF1..BDF5`, `TRBDF2`, `RosenbrockW`, `SDIRK2`
- `ControlUpdateMode`: `Auto`, `Continuous`, `Discrete`
- `LinearSolverKind`: `SparseLU`, `EnhancedSparseLU`, `KLU`, `GMRES`, `BiCGSTAB`, `CG`
- `PreconditionerKind`: `None_`, `Jacobi`, `ILU0`, `ILUT`, `AMG` (quando disponível)
- `SolverStatus`, `DCStrategy`, `SimulationEventType`, `FallbackReasonCode`

## Configurações que mais importam

### Solver linear

- `LinearSolverStackConfig.order`
- `LinearSolverStackConfig.fallback_order`
- `LinearSolverStackConfig.auto_select`
- `IterativeSolverConfig.preconditioner`, `max_iterations`, `tolerance`

### Newton e convergência

- `NewtonOptions.max_iterations`
- `NewtonOptions.enable_limiting`
- `NewtonOptions.max_voltage_step` / `max_current_step`

### Timestep e integrador

- `SimulationOptions.step_mode` (`StepMode.Fixed` ou `StepMode.Variable`)
- `SimulationOptions.control_mode`
- `SimulationOptions.control_sample_time`
- `SimulationOptions.formulation_mode` (`FormulationMode.ProjectedWrapper` ou `FormulationMode.Direct`)
- `SimulationOptions.direct_formulation_fallback`
- `SimulationOptions.integrator`
- `SimulationOptions.adaptive_timestep`
- `SimulationOptions.timestep_config`
- `SimulationOptions.lte_config`

`SimulationOptions.transient_backend` e `SimulationOptions.sundials` permanecem
apenas para migração/diagnóstico de legado; o caminho suportado usa core nativo
com `step_mode` + `formulation_mode`.

### Controle em malha fechada

```python
import pulsim as ps

options.control_mode = ps.ControlUpdateMode.Auto
options.control_sample_time = 0.0  # 0 => auto/continuous path
```

Semântica:

- `Auto`: usa `control_sample_time` se `> 0`; caso contrário tenta inferir por frequência PWM.
- `Continuous`: força atualização contínua de controle.
- `Discrete`: aplica amostragem global para blocos PI/PID.

### Térmico e perdas

- `SimulationOptions.enable_losses`
- `SimulationOptions.switching_energy`
- `SimulationOptions.thermal`
- `SimulationOptions.thermal_devices`

## Resultados para análise

Campos úteis de `SimulationResult`:

- `time`, `states`
- `events`
- `success`, `final_status`, `message`
- `newton_iterations_total`, `timestep_rejections`
- `linear_solver_telemetry`, `fallback_trace`
- `loss_summary`, `thermal_summary`
- `component_electrothermal` (deterministic per-component loss + temperature telemetry)

## Electrothermal Result Example

```python
result = sim.run_transient(circuit.initial_state())

for item in result.component_electrothermal:
    print(item.component_name, item.total_loss, item.peak_temperature)
```

`component_electrothermal` inclui todos os componentes elétricos não virtuais, com
campos térmicos determinísticos mesmo quando a porta térmica não está habilitada.

For full YAML + Python electrothermal setup (global thermal block, component thermal ports, strict/non-strict parser behavior), see
[Electrothermal Workflow](electrothermal-workflow.md).
