Simulation Workflow

Monata separates simulation setup from simulation execution. A simulation is described as data, submitted to an executor, then returned as a SimResult.

circuit + AnalysisSpec + optional corner/parameters
    -> SimTask
    -> Executor
    -> SimResult

Analysis Specifications

Analysis specs describe what to run. Creating a spec does not start a simulation.

from monata.sim.core import ACSpec, DCSpec, NoiseSpec, OPSpec, TranSpec

tran = TranSpec(stop=10e-9, step=10e-12)
ac = ACSpec(start=1e3, stop=1e9, points=100, variation="dec")
dc = DCSpec(source="Vin", start=0.0, stop=1.2, step=0.01)
op = OPSpec()
noise = NoiseSpec(output_node="out", input_source="Vin", start=1e3, stop=1e9, points=100)

The built-in ngspice-subprocess backend currently executes DCSpec, TranSpec, ACSpec, OPSpec, and NoiseSpec. Operating-point outputs use task-level output_names; noise outputs use NoiseSpec.output_node and NoiseSpec.input_source.

Simulation Tasks

SimTask is the unit of work. It combines the circuit, analysis, backend, and optional context such as corners or parameter overrides.

from monata.sim.core import SimTask

task = SimTask(
    circuit=circuit,
    analysis_spec=tran,
    simulator="ngspice-subprocess",
    output_names=["in", "out"],
    param_overrides={"w_p": 2e-6},
    osdi_paths=["models/bsimcmg.osdi"],
    metadata={"run": "nominal"},
)

For native ngspice execution, circuit must be a monata.netlist.Circuit. output_names is required for DC, transient, AC, and operating-point runs: the backend does not guess or enumerate nodes. DC and transient runs write v(name) vectors; AC runs write mag(v(name)) vectors; operating-point runs return one-row arrays for requested node voltages.

Noise is the exception to the task-level output rule. A NoiseSpec already names the output node and input source, so SimTask.output_names must be empty. Noise results return onoise_spectrum and inoise_spectrum waveforms aligned to sweep_var, with onoise_total and inoise_total in metadata. The input source must have an AC value in the netlist.

osdi_paths are loaded with ngspice pre_osdi commands before the analysis command.

param_overrides supports circuit-level .param overrides whose names are simple identifiers, plus structured native element overrides written as element.parameter targets such as R1.R or M1.W. A structured target must match an element in the native intermediate representation; otherwise the backend fails explicitly with metadata["reason"] == "unsupported_param_overrides".

Corner voltage overrides are applied through the same structured mutation path when the named source exists, for example {"VDD": 1.0} becomes a VDD.V source-value override. Process/model corner fields still require concrete model files or techlib projection before ngspice can execute them.

Executors

LocalExecutor dispatches tasks on the local machine. Use one task for a single run, or map many tasks for sweeps and corners.

from monata.sim.core import LocalExecutor

executor = LocalExecutor(max_workers=4)
future = executor.submit(task)
result = future.result()

For multiple independent tasks:

futures = executor.map(tasks)
results = [future.result() for future in futures]

Results

SimResult contains:

Field

Meaning

status

"ok" or "failed"

waveforms

named waveform arrays or backend output objects

sweep_var

x-axis values for swept data when available

corner

corner metadata when the run came from a corner matrix

metadata

backend-specific details

error_message

failure text when the task failed

Always check status before evaluating measurements.

if result.status != "ok":
    raise RuntimeError(result.error_message)

vout = result.waveforms["out"]

Common ngspice failure reasons include:

Reason

Meaning

simulator_missing

ngspice could not be found on PATH or under CONDA_PREFIX/bin

unsupported_analysis

the selected analysis is not implemented by the native backend

no_outputs_requested

output_names was empty for an analysis that requires task-level outputs

invalid_task

an output name, analysis field, OSDI path, or command token was invalid

model_missing

an OSDI or corner model file path did not exist

unsupported_param_overrides

a parameter or source override target was not found or could not be applied safely

unsupported_corner

a process/model corner field could not be projected to a concrete ngspice model reference

subprocess_failed

ngspice ran but exited non-zero

parser_failed

ngspice output could not be parsed into the requested outputs

Backend Selection

Keep backend selection close to the task or library technology configuration:

task = SimTask(
    circuit=circuit,
    analysis_spec=spec,
    simulator="ngspice-subprocess",
)

SimTask.simulator is resolved through Monata’s backend registry. Use ngspice-subprocess as the default stable local runner. Use ngspice-shared only when a compatible user-installed libngspice shared library is available in the runtime environment. Both runners preserve the same SimTask and SimResult contract and keep ngspice itself as an external runtime dependency.

Use the user guide for Monata concepts, and use the toolchain pages for backend-specific behavior: