An end-to-end walkthrough¶
A directory of vendor models with no provenance, to a green CI badge. Every transcript here is real output; you can reproduce all of it.
Setup¶
pip install git+https://github.com/nickharris808/physics-lint.git \
git+https://github.com/nickharris808/sparam-lint.git \
git+https://github.com/nickharris808/maxwell-lint.git \
git+https://github.com/nickharris808/touchstone-tools.git
physics-lint doctor # confirm all three checkers imported
For models to look at, the labelled corpus works as a stand-in for your folder:
git clone https://huggingface.co/datasets/nickh007/sparam-conformance
mkdir models && cp sparam-conformance/data/{passive_line,active_gain,ferrite_isolator}.s2p models/
Step 1 — prove the checker still works¶
Before trusting a clean report, establish that the thing producing it can still produce a dirty one.
$ sparam-lint --self-test
negative control
[REJECTED] passivity
[REJECTED] reciprocity
[REJECTED] energy_conservation
[REJECTED] positive_real_z0
[REJECTED] group_delay_nonneg
battery discriminates: True
Five networks built to violate one law each, each rejected. If any law failed to
reject its own violator this exits 3, and no verdict from that run is worth
anything.
Do this first, every time. It costs a second.
Step 2 — check everything at once¶
$ sparam-lint --quiet models/*.s2p
--quiet prints only the files with violations; clean ones are still counted in
the summary. Two of the three fail, and the two failures are completely
different in kind.
The first is a genuine defect:
── models/active_gain.s2p
[FAIL] passivity largest singular value 2.882175 > 1 at 25.1429 GHz -- this network produces more power than is put into it
[FAIL] energy_conservation worst row power 8.023758 > 1 at 18.9524 GHz -- driving one port yields more power out than in
2 of 5 laws FAILED
This network is not physically realizable as a passive device.
The second is not:
── models/ferrite_isolator.s2p
[FAIL] reciprocity normalized asymmetry 1.382e+00 > 1e-06 at 18.9524 GHz -- S is not symmetric; if the medium is reciprocal this indicates a port-ordering or transpose error
1 of 5 laws FAILED
S is not symmetric. That is a defect in a reciprocal medium and correct behaviour in a non-reciprocal one -- a ferrite isolator or circulator fails this by design. No other law failed.
3 file(s), 2 with violations
Notice the tool changes what it concludes based on which law failed. A ferrite isolator is real, buyable hardware; telling its owner the model is "not physically realizable" would be false. Energy and causality failures license that statement — reciprocity alone does not.
This is the judgement call the tool will not make for you. The right response to the isolator is to record that non-reciprocity is expected for that file, not to switch the law off. Suppressing reciprocity to quiet one isolator also goes blind to the transposed-reshape bug the law exists to catch.
Step 3 — act on it programmatically¶
$ sparam-lint --json models/*.s2p | python3 -c '
import json,sys
for f in json.load(sys.stdin)["files"]:
bad = [law["law"] for law in f.get("laws", []) if not law["passed"]]
print(f["file"], "->", ", ".join(bad) or "clean")
'
models/active_gain.s2p -> passivity, energy_conservation
models/ferrite_isolator.s2p -> reciprocity
models/passive_line.s2p -> clean
One file emits a flat object; several emit an envelope with a summary. The
presence of files is how a consumer tells them apart.
Step 4 — fix what is fixable¶
Say the isolator arrived referenced to 75 Ω and your stack expects 50 Ω.
touchstone-tools re-references it without going near a physics verdict:
$ touchstone-tools info models/ferrite_isolator.s2p
ferrite_isolator.s2p: 2-port S, 64 points, 1-40 GHz, z0=50Ω
max |entry| 0.944061
max |S - S^T| 9.252e-01 (reported, not judged)
$ touchstone-tools renorm models/ferrite_isolator.s2p iso75.s2p --z0 75
wrote iso75.s2p (2-port S, 64 points, z0=75Ω, RI)
info reports the asymmetry and stops — it will not tell you whether that is a
defect, because that is a question about the device. The split between the two
libraries is deliberate.
Step 5 — put it in CI¶
name: Physics
on: [pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: nickharris808/physics-lint-action@v1
id: lint
with:
files: 'models/**/*.s*p'
sarif-file: physics.sarif
continue-on-error: true
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: ${{ steps.lint.outputs.sarif }}
Expect the first run to be red, and read it before reacting. A repository that has never had a physics check almost always contains something that fails one. Sort them by the step-2 distinction: energy and causality failures are defects, reciprocity on a non-reciprocal part is not.
Narrow the glob or exclude the file, and say why in the commit message. Do not
set fail-on-error: false globally to cope with one file — that turns the whole
check into decoration.
Step 6 — grade your own checker, if you have one¶
If you maintain a validation tool of your own, the corpus grades it:
$ cd sparam-conformance
$ python score.py --checker your_adapter:check
false passes : 0 <- must be 0
false fails : 0
errors : 0
verdict : CONFORMING
Three verdicts, not two. CONFORMING needs zero false passes and every law
reported on every case. A checker that never reported a law is INCOMPLETE and
exits 1 — it did not look, and the corpus cannot certify what it never saw.
What you have now, and what you do not¶
You have ruled out a class of failure that is otherwise invisible and that simulators propagate silently, with a check that proved it still discriminates before it ran.
You have not established that any of those models is accurate. Every law here is a necessary condition; a passive model of entirely the wrong structure passes all of them. See what this proves.