Experiments¶
spicefault.experiments.experiment
¶
The experiment: a circuit, its normal variation, faults and operating conditions, simulated as one deterministic set of samples.
Sample
dataclass
¶
Definition of one simulation. fault_index 0 is the fault-free circuit.
Realisation
dataclass
¶
A sample turned into a netlist, with the values drawn for it.
SampleResult
dataclass
¶
A simulated sample. Its draws come from sample_stream(seed, *seed_key).
ExperimentResult
dataclass
¶
to_frame()
¶
One row per sample: its definition, its status and the realised parameters.
Experiment
dataclass
¶
What is simulated, under which conditions, with which faults and which uncertainty.
Each fault is simulated samples times and the fault-free circuit
healthy_samples times (samples by default), under every operating condition.
The values of a sample are drawn from a stream that depends only on the seed and
on the key of the sample, which seeding defines (see seeding.seed_key): by
default (fault index, replica). The result therefore does not depend on the number
of workers. The operating condition is never part of the key, so one drawn circuit
is observed under all the conditions.
sampling chooses how the circuits of a population are drawn: random, each from
its own independent stream; lhs, a Latin hypercube; or sobol, a scrambled Sobol
sequence (see experiments.sampling). The last two decide the points of each
population jointly, through the quantile function of every variation, and their
samples are not independent.
With a design, the circuits are not drawn: each row of the design is a circuit
with the parameter values it gives, simulated without and with each fault, under
every condition. There are then no variations and no sample counts to give.
waveform_points
property
¶
Points of the stored waveforms; None if no condition stores one.
measurement_columns
property
¶
The measurement columns of the table: those of every condition, once each.
waveform_for(condition_index)
¶
The waveform stored for a condition: its own, or that of the experiment.
columns_for(condition_index)
¶
The measurement columns that a condition fills.
plan()
¶
Every sample, in a fixed order: by fault (healthy first), replica and condition.
realise(sample)
¶
Draw the circuit, inject the fault, then set the operating condition.
parameter_targets()
¶
The parameters whose value every sample records: those drawn or designed.
faults_overlapping_tolerance()
¶
How many parametric fault conditions lie partly inside the tolerance band.
metadata()
¶
Everything needed to regenerate the samples, as JSON-serialisable data.
from_metadata(metadata, netlist, **overrides)
classmethod
¶
Rebuild an experiment from its record and the netlist of its circuit.
What a record cannot carry must be passed again as keyword arguments: custom
or joint variations (variations), custom measurements (measurements) and
a backend other than the built-in ones (simulator). The netlist must be the
one the record was made with.
check_picklable()
¶
Worker processes receive a copy of the experiment, so it must be picklable.
measure(result, condition_index=None)
¶
The measurements of a successful simulation, by name.
nominal(fault=None)
¶
The nominal circuit, simulated and measured under each operating condition.
No variation is drawn: the circuit has the values of its netlist. It is the
reference of an experiment, such as the nominal gain against which a gain
error is defined. With fault, a fault or the identifier of one of the
experiment, it is the nominal circuit with that fault. See evaluate, of
which this is the case with no values given.
evaluate(parameters, fault=None)
¶
The circuit with the given parameter values, simulated and measured under each operating condition.
parameters maps (component, parameter) to a value; what is not given keeps
the value of the netlist. Nothing is drawn. With fault, a fault or the
identifier of one of the experiment, it is injected after the values are set,
as in a sample. This is what an external algorithm needs to drive the circuit:
an optimiser, or a sensitivity method that supplies its own points.
Returns {condition name: SampleResult}, with the measurements of the condition
and the complete simulation result. These are not samples of the plan:
sample_id and replica are -1. As in a run, a simulation that fails is
returned with its status, not raised.
run(workers=1)
¶
Simulate every sample and keep the results in memory.
A simulation that fails is recorded with its status; it does not stop the run.
spicefault.experiments.design
¶
Designed samples: circuits whose parameter values are chosen, not drawn.
A design is a table of parameter values, one row per circuit. An experiment that is given one simulates those circuits with the same engine as drawn ones, so they are resumable, keep their failed simulations and end in a dataset. What they are not is a random sample: a proportion over chosen circuits is not a probability, and the dataset says that its samples were designed.
Design
dataclass
¶
Parameter values of the circuits to simulate.
targets are the (component, parameter) pairs and values one row per circuit, in
the order of targets. names optionally labels each row; the label is stored in
the column design_point. kind and description say how the design was made
and are recorded with the dataset.
corners(variations, circuit, limit=1024, nominal=True)
¶
The corners of the band of a set of variations: every combination of the lowest and the highest value of each parameter, and the nominal circuit first.
Each variation must be bounded (a tolerance, a uniform or log-uniform range, a
truncated normal). n parameters give 2^n corners; more than limit is refused,
since the count doubles with every parameter. Rows are named by the side of each
parameter, such as -+-, and nominal.
The extremes of a measurement over the corners are its extremes over the band only if it is monotonic in each parameter there. A response with a maximum or a minimum inside the band (a resonance, a notch, a compensated error) has its worst case where no corner is, and corners will not show it.
spicefault.experiments.campaign
¶
Campaign: an experiment simulated to disk, in chunks, resumable, with every simulation accounted for.
ValidationReport
dataclass
¶
Problems found before running. Errors prevent the run; warnings do not.
Campaign
¶
A systematic set of simulations written to a dataset: the fault-free circuit and
every fault, samples times each, under every operating condition.
Without faults it is a Monte Carlo study of the healthy population: samples
circuits drawn from the variations. With faults, each one is injected into
samples drawn circuits (samples_per_fault is the same argument under the name
it has always had), and healthy_samples sets the size of the fault-free
population. FaultCampaign is this class.
It takes the arguments of Experiment, or an experiment already built through
from_experiment. The results go to
out_dir as a dataset: samples.parquet, waveforms.npy if a waveform is
declared, and manifest.json. waveforms.npy has one row per sample of the
conditions that store a waveform; the manifest names them under
waveform_conditions when they are not all of them.
validate(simulate=True)
¶
Check that the definitions fit the circuit, without running the campaign.
Every variation is drawn once, and every fault and operating condition is
applied to the circuit. With simulate, the nominal fault-free circuit is
also simulated under each condition and measured: a campaign whose healthy
circuit does not simulate is not worth starting.
run(workers=1, resume=True, chunk=2000, progress=True, validate=True)
¶
Simulate every pending sample and write the dataset; returns its folder.
An interrupted run continues after the last complete chunk when launched again
with the same definitions; with resume=False it starts from the beginning.
A finished campaign is not run again. Individual failures are recorded and do
not stop the run.
status()
¶
Samples completed (simulated successfully), failed and still pending.
summary()
¶
One row per fault: samples simulated, successful, and the count of each status.
failures()
¶
The samples that did not give a usable result, with status and message.
dataset()
¶
The finished campaign as a Dataset.
load(drop_failed=True)
¶
(samples, waveforms, manifest) of the finished campaign.
simulate_sample(sample, experiment)
¶
One row of the dataset, and the waveform if one is stored for its condition.
Nothing that happens here stops the campaign: a simulation that fails, an output
that cannot be measured, or an error while building the netlist is recorded in
the row with its status. elapsed_s is the only column that is not reproducible.
spicefault.experiments.seeding
¶
Random streams of an experiment.
Every sample has its own stream, derived from the master seed and a key that identifies the sample. Nothing else feeds the draws, so a sample is the same whatever the number of workers, the order of execution or the chunking.
sample_stream(seed, *key)
¶
Independent stream for the sample identified by key, whatever the execution order.
text_key(text)
¶
A stable 64-bit integer for a piece of text, the same on every platform and run.
seed_key(scheme, fault_index, fault_id, replica)
¶
Key of the stream of one sample.
positional: (fault index, replica). The stream of a fault depends on its place in the fault list: adding or reordering faults changes the samples of the others.content: (hash of the fault identifier, replica). A fault has the same samples in every experiment that contains it.common: (replica,). Replica r is the same drawn circuit for every fault and for the healthy case (common random numbers): comparisons between conditions are paired, and the conditions are no longer statistically independent.
spicefault.experiments.sampling
¶
Sampling designs that choose the points of a population jointly.
By default every sample of an experiment draws from its own independent stream. A Latin hypercube or a Sobol sequence instead decides the points of a whole population together, so that they cover the space more evenly and a mean is estimated with fewer simulations. The design is a function of the seed, the population and its size only, and a sample reads its row: the result still does not depend on the number of workers or on the order of execution.
The points of such a design are not independent. Intervals that assume independence (binomial, order statistics) are not valid for them; the uncertainty of an estimate comes from independent replications of the whole design, with different seeds.
latin_hypercube(rng, n, d)
¶
[n, d] points in (0, 1): each column has exactly one point in each of the n equal strata, at a random place inside it, and the strata are paired at random between columns.
sobol(rng, n, d)
¶
[n, d] points of a scrambled Sobol sequence, from SciPy.
The sequence is balanced when n is a power of two. Its points depend on the version of SciPy, which is recorded with the experiment.
uniforms(method, seed, key, n, d)
¶
The design of the population identified by key: [n, d] numbers in (0, 1).
record(method)
¶
What a dataset keeps about how its samples were chosen.
spicefault.experiments.engine
¶
Parallel, resumable execution of a list of independent simulation tasks.
The application supplies the tasks and a worker(task, context) function returning
(row, waveform): row is a dict of scalars describing the simulation and its
results, waveform a 1-D array or None. The worker must be a module-level function
and derive any random numbers from the task itself (see seeding.sample_stream),
so the results do not depend on the number of processes.
run_chunks(tasks, worker, context, parts_dir, n_points=None, workers=1, chunk=2000, progress=True)
¶
Simulate tasks in chunks, one pair of files per chunk; finished chunks are kept.
This is what makes a long campaign resumable: a chunk is written only once it is
complete, and a chunk already on disk is not simulated again. Rows get a
sample_id equal to the position of their task. With n_points, waveforms are
stored as float32 [n, n_points], with NaN where the worker returned none.
elapsed_so_far(parts_dir)
¶
Seconds spent on the complete chunks of a campaign, over all its runs.
run_campaign(tasks, worker, context, out_dir, config, n_points=None, workers=1, chunk=2000, progress=True, summary=None, files=None, user_metadata=None, waveform_rows=None)
¶
Simulate every task and write the dataset to out_dir.
config is whatever defines the campaign; it must be JSON-serialisable and is
written to metadata.json. If a previous run on the same folder and configuration
was interrupted, it resumes after the last complete chunk. summary adds
application counts, computed from the samples, to the manifest. files are text
files to keep with the dataset, by name, such as the source netlist. With
waveform_rows, one flag per task, only the waveforms of the flagged tasks are
kept in waveforms.npy.