# Characterise a junction model with an IV curve

Run a complete .IV model, read voltage/current coordinates and bias order, then check the model assumptions and numerical reference before accepting its behaviour.

## Compatibility

2.9 target; frozen maintained-source Windows candidate

Published guidance with release-applicability limits. Confirm package applicability before following this guide.

**KB-IV-001 · hold**: The realistic-gap RTYPE=0 diagnostic remains outside accepted numerical results. The artificial high-gap reference is a teaching control, not a physical workaround for a calibrated junction.

**KB-IV-002 · supported path**: Distinguish IV helper timing from the enclosing job settings. The general effective_settings record does not establish the internal IV step or averaging window.

[Download Complete IV reference controls and gap diagnostic (ZIP)](/_functions/kbExample?name=josim-iv-reference.zip)

Includes: iv_rsj.cir, iv_refined.cir, iv_gap_check.cir, run_iv.py, README.txt.

## Start with a model and a declared purpose

Use .IV when you want the behaviour of one named junction model in the internally generated helper circuit. It is distinct from .OP/.DC equilibria and from a transient circuit experiment you write yourself. The checked helper uses an area-one junction and its own stepped current source; it does not characterise every component of a larger submitted circuit.

The complete download contains two artificial reference inputs, one realistic-gap diagnostic and the standard-library study client. The reference has IC = 100 µA, RN = 10 Ω, CAP = 0 and RTYPE = 0, with deliberately artificial VG = 100 mV. This keeps the sampled reference away from the unresolved gap-region behaviour. It is a numerical control, not a calibrated process model. Do not change a real junction gap to make it match an equation.

iv_gap_check.cir retains the 2.8 mV gap comparison that remains unresolved under KB-IV-001. Its software run can complete while failing the reference check. The related diagnostic guide records that limit. These two purposes remain separate throughout the instructions.

## Run the reference in JoSIM®-Pro

1. Extract all four teaching files to a writable folder. Open iv_rsj.cir and keep its complete .MODEL, .OPTION, .IV and .END statements together.
2. Check the normal licence status and choose Run simulation from the saved netlist tab. The .IV output token requests curve.csv. In the checked default-output setup it is written beside the input; a configured native output directory supplies the containing directory instead.
3. Read the current task verdict and select the current IV run. Inspect the I(IIV) chart. Its horizontal coordinate is V(BIV), displayed in mV; the vertical quantity is current, displayed in µA. Raw CSV and retained arrays use volts and amperes.
4. Keep the source and current curve together. For a second run, copy the complete input to a fresh working folder or use a separate native output directory so earlier results remain identifiable.

![Native JoSIM IV chart for the artificial high-gap RSJ control: voltage V(BIV) in mV against current I(IIV) in µA, with 81 retained points.](https://static.wixstatic.com/media/31de30_67c249dbbce14c869c7406d96ed45379~mv2.png)

The actual native 20-interval reference run retains 81 voltage/current pairs. This uses the explicitly artificial high-gap model; it is not the held 2.8 mV diagnostic.

## Refine the bias grid without changing the question

1. Open iv_refined.cir in a separate working generation and run it normally. Its only model-study change is 40 intervals per branch instead of 20.
2. Confirm 161 finite pairs and preserve their original order. Both positive and negative extrema occur twice; zero occurs once between the positive and negative excursions.
3. The final current is one negative interval, not zero: -20 µA for 20 intervals and -10 µA for 40. Do not infer a final zero endpoint or sort away the branch sequence.
4. Compare sampled features on the appropriate branches. A denser bias grid may reveal a missed feature or problem. It does not prove time integration, settling, noise averaging or physical calibration is converged.

![The same artificial high-gap reference with 40 bias intervals per branch and 161 retained points. This is bias-grid refinement, not a smaller helper time step.](https://static.wixstatic.com/media/31de30_85efd23dccc4412284824baf00915f2e~mv2.png)

The native 40-interval reference run contains 161 points. The helper time step is unchanged; the two curves illustrate a bias-resolution comparison.

## Understand what each point means

In the exercised implementation, each IV point is produced by an internal transient helper with a 50 fs time step and 1 ns stop time. The reported voltage is the mean of the latter half of the helper voltage samples. The current is the requested bias amplitude. These implementation values are source-qualified for this candidate, not general configurable .IV arguments.

The current-index order is 1…N, N…1, 0…−N and −N…−1, multiplied by Imax/N. That produces 4N+1 rows, including repeated extrema. The native CSV header is V(BIV),I(IIV), in that order. In the GUI retained container, a member historically called TimeArray holds the IV voltage coordinates; its name does not make them seconds.

The run record includes iv_characterization fields for model, maximum current, steps per branch, points and axis units. Its general effective_settings timing can describe the enclosing job rather than the fixed helper (KB-IV-002). Do not use those general fields as proof of a changed IV integration step.

## Check the artificial RSJ reference

For the constant-resistance, zero-capacitance, noiseless reference, the long-time average is V = sign(I) R sqrt(I² − IC²) above the critical current, and zero on the subcritical branch. The study checks points with |I| ≥ 2 IC using 1% relative difference plus a conservative finite-window allowance 2 Φ0 / 0.5 ns, about 8.27 µV. It also checks small voltage for |I| ≤ 0.8 IC. These are stated teaching checks, not a universal solver-accuracy tolerance.

Both artificial reference grids pass this check; their maximum high-bias relative difference from the analytical relation is approximately 0.382%. A separate 370 µA transient comparison improves for the high-gap control when its authored time step changes from 50 fs to 12.5 fs. The realistic-gap comparison remains outside the same reference check. Matching one simple control does not qualify a physical device.

## Run both checked grids from Python

Select your actual Python, compatible JoSIM CLI and existing issued JoSIM licence. From the extracted teaching folder, run the complete command below. The client creates isolated per-study configuration that references the licence path; it does not copy licence contents or change installed settings. It refuses an existing result directory, retains private solver logs and checks current output, order and the declared reference.

```text
$ErrorActionPreference = 'Stop'
$python = 'python'
$josim = 'C:\Program Files\SUN Magnetics\JoSIM-Pro\bin\josim-pro-cli.exe'
$licence = 'C:\Program Files\SUN Magnetics\Licenses\sm_license_jpro.txt'
& $python .\run_iv.py --josim $josim --licence $licence --results .\iv-study-001
if ($LASTEXITCODE -ne 0) { throw 'IV study failed a process, format or numerical check; retain its logs and review before accepting the curve.' }
Get-Content -LiteralPath .\iv-study-001\study.json
```

## Recognise and recover from a rejected request

1. For a missing model, correct the .IV model name or restore the complete .MODEL input. The checked native and CLI rejection preserved an earlier curve; rerunning the valid input into a separate generation recovered.
2. Use a positive integer step count and a finite nonnegative maximum current. Zero/fractional steps and negative maximum current were rejected in the CLI checks without replacing prior output.
3. Use an explicit supported CSV destination. Quoted filenames containing spaces were checked. An actual CSV input/output collision was rejected and the source preserved.
4. If a numerical comparison fails, retain the model, raw curve and logs. Check the resistance law, capacitance, temperature/noise and averaging assumptions. Do not widen the threshold or alter real device parameters solely to obtain a passing label.

## Save iv_rsj.cir

```text
* Artificial high-gap RSJ reference control, not a calibrated device
.MODEL RSJ JJ(RTYPE=0 VG=100m CAP=0 IC=100u RN=10 R0=10)
.OPTION SEED=321
.IV RSJ 400u curve.csv 20
.END
```

## Save iv_refined.cir

```text
* Same artificial high-gap control with twice the bias-grid resolution
.MODEL RSJ JJ(RTYPE=0 VG=100m CAP=0 IC=100u RN=10 R0=10)
.OPTION SEED=321
.IV RSJ 400u curve.csv 40
.END
```

## Save iv_gap_check.cir

```text
* Diagnostic only: the constant-resistance reference is held under KB-IV-001
.MODEL RSJ JJ(RTYPE=0 VG=2.8m CAP=0 IC=100u RN=10 R0=10)
.OPTION SEED=321
.IV RSJ 400u gap-curve.csv 40
.END
```

## Save run_iv.py

```text
"""Run the two supplied IV grids in fresh folders and check their RSJ reference."""
import argparse
import csv
import hashlib
import json
import math
import os
from pathlib import Path
import shutil
import subprocess
import sys

PHI0 = 2.067833848e-15
IC = 100e-6
RN = 10.0
MAX_CURRENT = 400e-6
TAIL_SECONDS = 0.5e-9


def sha(path):return hashlib.sha256(path.read_bytes()).hexdigest()


def schedule(steps):
    return [i*MAX_CURRENT/steps for i in
            [*range(1,steps+1), *range(steps,0,-1), *range(0,-steps-1,-1), *range(-steps,0)]]


def read_curve(path, steps):
    with path.open(encoding='utf-8-sig',newline='') as stream:
        reader=csv.reader(stream)
        if next(reader,None)!=['V(BIV)','I(IIV)']:
            raise ValueError('Expected the native IV voltage/current header, not transient time data.')
        rows=[[float(x) for x in row] for row in reader if row]
    expected=schedule(steps)
    if len(rows)!=4*steps+1 or any(len(row)!=2 or not all(math.isfinite(x) for x in row) for row in rows):
        raise ValueError('IV sample count or finite two-column shape differs from the teaching contract.')
    if any(abs(row[1]-i)>1e-15 for row,i in zip(rows,expected)):
        raise ValueError('IV bias order differs; retain the original branch order and repeated extrema.')
    return rows


def reference_checks(rows):
    high=[]
    sub=[]
    allowance=2*PHI0/TAIL_SECONDS
    for voltage,current in rows:
        if abs(current)>=2*IC-1e-15:
            expected=math.copysign(RN*math.sqrt(current*current-IC*IC),current)
            difference=abs(voltage-expected)
            # A teaching acceptance check: 1% relative plus a conservative
            # two-phase-period finite-window allowance, not a general error bound.
            if difference>0.01*abs(expected)+allowance:
                raise ValueError('High-bias RSJ average differs from this teaching reference check.')
            high.append((difference,difference/abs(expected)))
        if abs(current)<=0.8*IC+1e-15:
            if abs(voltage)>1e-8:
                raise ValueError('Subcritical teaching voltage is not close to zero.')
            sub.append(abs(voltage))
    return {'max_high_bias_abs_difference_V':max(x[0] for x in high),
            'max_high_bias_relative_difference':max(x[1] for x in high),
            'max_subcritical_abs_voltage_V':max(sub),
            'finite_window_allowance_V':allowance}


def main():
    parser=argparse.ArgumentParser(description=__doc__)
    parser.add_argument('--josim',type=Path,required=True)
    parser.add_argument('--licence',type=Path,required=True)
    parser.add_argument('--results',type=Path,required=True)
    args=parser.parse_args()
    root=args.results.resolve()
    created=False
    receipt={'schema':'sunmagnetics-iv-study/1','status':'failed','cases':[]}
    try:
        if root.exists():raise ValueError('Choose a new results directory; preserve the existing study.')
        binary=args.josim.resolve();licence=args.licence.resolve()
        if not binary.is_file() or not licence.is_file():raise ValueError('Select an existing JoSIM executable and issued JoSIM licence.')
        source=Path(__file__).resolve().parent
        names=('iv_rsj.cir','iv_refined.cir')
        for name in names:
            if not (source/name).is_file():raise ValueError('Restore the complete teaching inputs beside run_iv.py.')
        root.mkdir(parents=True);created=True
        home=root/'home/.josimpro';home.mkdir(parents=True)
        (home/'config.ini').write_text('[General]\nLicenseLocation='+str(licence)+'\n',encoding='utf-8')
        env=os.environ.copy();env['USERPROFILE']=str(home.parent)
        env['PATH']=str(binary.parent)+os.pathsep+env.get('PATH','')
        receipt.update(executable_name=binary.name,executable_sha256=sha(binary),inputs={n:sha(source/n) for n in names})
        curves=[]
        for steps,name in zip((20,40),names):
            case=root/('points-'+str(steps));case.mkdir()
            shutil.copyfile(source/name,case/name)
            try:
                run=subprocess.run([str(binary),'-P','17',str(case/name)],cwd=case,env=env,
                                   stdout=subprocess.PIPE,stderr=subprocess.STDOUT,timeout=90,
                                   creationflags=getattr(subprocess,'CREATE_NO_WINDOW',0))
            except subprocess.TimeoutExpired as error:
                (case/'solver.log').write_bytes(error.stdout or b'')
                raise ValueError('IV case exceeded 90 seconds; retain its generation and review its log.')
            (case/'solver.log').write_bytes(run.stdout)
            row={'steps_per_branch':steps,'exit_code':run.returncode,'status':'failed'}
            receipt['cases'].append(row)
            if run.returncode!=0:raise ValueError('JoSIM rejected an IV case; read its solver.log before retrying.')
            rows=read_curve(case/'curve.csv',steps)
            row.update(status='passed',rows=len(rows),reference=reference_checks(rows),curve_sha256=sha(case/'curve.csv'))
            curves.append(rows)
        receipt.update(status='passed',scope='Artificial VG=100m, overdamped noiseless RSJ control and two bias grids. This avoids the unresolved realistic-gap comparison in iv_gap_check.cir (KB-IV-001). Internal .IV helper time step is unchanged; no device-calibration or general convergence claim.',
                       axis_columns=['voltage_V','current_A'],source_inputs_preserved=all(sha(source/n)==h for n,h in receipt['inputs'].items()))
        (root/'study.json').write_text(json.dumps(receipt,indent=2)+'\n',encoding='utf-8')
        print(json.dumps({'status':'passed','rows':[len(c) for c in curves],
                          'max_relative_reference_difference':[r['reference']['max_high_bias_relative_difference'] for r in receipt['cases']]}))
        return 0
    except (OSError,ValueError,subprocess.SubprocessError) as error:
        receipt['reason']=str(error)
        if created:(root/'study.json').write_text(json.dumps(receipt,indent=2)+'\n',encoding='utf-8')
        print(str(error),file=sys.stderr)
        return 1


if __name__=='__main__':raise SystemExit(main())
```

## Keep the execution boundary explicit

Frozen maintained Windows JoSIM 2.9 CLI with normal licence: artificial high-gap constant-resistance reference, complete realistic-gap diagnostic, explicit transient comparisons and real validation/publication failures. No physical device calibration or acceptance of the held gap case. Seven relevant source files match the maintained NAS exactly; one file differs only in a separately reviewed admission-error message, outside IV execution.

Normal licensed Windows JoSIM 2.9 native Run, retained voltage/current arrays, current CSV, typed IV metadata, missing-model rejection/recovery and software completion of the unaccepted gap diagnostic. File opens are supplied at the production boundary; no physical picker/export-dialog or final-package claim.

No physical OS file-picker or plot-export Save dialog is qualified here. The realistic-gap diagnostic is deliberately not accepted as a numerical reference or shown as a validated result image. Final distributed 2.9, other platforms and complete GUI acceptance remain open.

## Sources and verification details

Recorded inputs/builds only. Complete walkthrough and final-package acceptance remain separate.

- VAL-038: Frozen maintained-source Windows JoSIM 2.9.0 / CPython 3.13.11. Frozen maintained Windows JoSIM 2.9 CLI with normal licence: artificial high-gap constant-resistance reference, complete realistic-gap diagnostic, explicit transient comparisons and real validation/publication failures. No physical device calibration or acceptance of the held gap case. Seven relevant source files match the maintained NAS exactly; one file differs only in a separately reviewed admission-error message, outside IV execution. The artificial 100 mV gap control isolates a numerical reference; it is not a physical workaround for the unresolved 2.8 mV gap comparison. No physical calibration or universal convergence claim.
- VAL-039: Frozen maintained-source Windows JoSIM GUI 2.9.0 with matching Clang runtime. Normal licensed Windows JoSIM 2.9 native Run, retained voltage/current arrays, current CSV, typed IV metadata, missing-model rejection/recovery and software completion of the unaccepted gap diagnostic. File opens are supplied at the production boundary; no physical picker/export-dialog or final-package claim. Current native IV data and typed characterization metadata are checked. General effective_settings timing differs from the fixed helper controls (KB-IV-002). Physical pickers/export-dialogs, other platforms and final packages remain pending.

- josim-iv-reference-coarse: Windows JoSIM 2.9 current-source native scenario, reviewed 4 November 2026. Artificial VG=100m reference, not a fabricated-device fit. Physical pickers/export dialogues and final-package visual review remain pending.
- josim-iv-reference-refined: Windows JoSIM 2.9 current-source native scenario, reviewed 4 November 2026. Artificial VG=100m reference, not a fabricated-device fit. Physical pickers/export dialogues and final-package visual review remain pending.

- josim-pro:docs/manual_source/sections/examples.tex: Device and model characterization with .IV; helper-circuit purpose and bias resolution
- josim-pro:docs/manual_source/sections/syntax.tex: .MODEL junction parameters, .IV and explicit .TRAN syntax; scope and model assumptions remain distinct
- josim-pro:docs/manual_source/sections/gui_simulation_results.tex: Current run selection and retained result interpretation
- validation:josim-iv-windows-20261104: VAL-038 and VAL-039: complete execution inputs, native voltage/current arrays, analytical controls and explicit KB-IV-001/002 limits

- The recipe uses an explicitly artificial high-gap control for an analytical check. The complete realistic-gap diagnostic remains available and unaccepted; it is not hidden by changing a tolerance.
- The native candidate and relevant numerical path are frozen. Seven selected files match maintained source exactly; one has an unrelated, precisely reviewed admission-error wording difference.
- Earlier RTYPE=1 and realistic-gap RTYPE=0 comparisons are retained separately. They do not establish a general solver defect, a calibrated device or an accepted numerical workaround.

## Related guides

- [An IV curve or run record does not match the expected model](/knowledge-base/josim-iv-result-checks)
- [RN, R0 and temperature give unexpected junction resistance](/knowledge-base/josim-junction-resistance)
