Repository navigation
Releases
v0.11.0
Added
CITATION.cff: cite the original pysrim paper (Ostrouchov, Zhang, Weber 2018, JOSS); every git author and co-author is listed inCITATION.cffand the package metadata.- New documentation front page (
docs/index.md) with two routes: a Python route (install, the boron reference case) and an agent route (install the skill, give it a task), and four sidebar sections (Get started, Gallery, Guides, Reference). - Example gallery (
docs/gallery.md) with a picture and its code for every entry; the pictures are rebuilt bydocs/gallery/make.py, and the entries that run SRIM need an installed SRIM. - First-simulation page (
docs/first-simulation.md) replaces the 2018 tutorial. - Agent guide (
docs/agents.md): how an AI coding agent uses the pysrim2 skill, with example prompts. - Examples page (
docs/examples.md) lists the example scripts and notebooks. - Regenerated API reference (
docs/api/), one page per part of the library. - Citing page (
docs/citing.md) with the BibTeX entry and the SRIM citation, and a citing section in the README. - The documentation is built in CI (
docsjob,sphinx-build -W), so a warning fails the build as it does on Read the Docs.
v0.10.0
Added
- Beam distributions in
run.yamlandRunSpec:ion.energy_keV,ion.angle_degandion.azimuth_degtake a number or a distribution (Gaussian, uniform, triangular, log-normal, histogram file or inline, or a Python function),ion.positionsets the start position, andbeam:chooses exact or binned mode;--setand scan keys reach into the distributions. Runs without distributions are unchanged. - Exact mode of a distributed run (
beam.mode: exact, the default) samples every ion from the distributions and writes SRIM'sTRIM.DAT, so oneTRIM.run()runs exactly that beam (calculation 1 and 2 become SRIM 4 and 5); the histogram files it used are copied to the run folder'sbeam/folder. Up to 99 999 ions per run. An in-place run (srim_directory=) never deletes aTRIM.DATorbeam/file that pysrim2 did not write, and an exact run there is refused if such aTRIM.DATwould be overwritten. - Binned beams in scans (
beam.mode: binned): each scan point with a binned beam runs as one SRIM run per bin, the ions split over the bins by apportionment, in beam batches for precision targets andbatch_ions; the bins' results are merged back into one result per point. Exact distributed points with more than 99 999 ions needbatch_ions: 99999. - Point folders of batched scan points record their units (
run.yaml,units.csv, andbeam_bins.csvfor binned beams), andsrim.beam.open_results(point_dir)re-opens a finished batched point as one merged result. - Documentation for beam distributions:
docs/beam.md(both modes, every shape, histogram files, Python functions, seeds, results and limits), an example script (examples/scripts/beam_energy_spread.py), a notebook (examples/notebooks/Beam.ipynb), beam sections indocs/run-spec.md,docs/scans.mdanddocs/dataframes.md, and an agent-skill section (skills/pysrim2/SKILL.md, section 8). srim.beam.run_beam(spec)runs a distributed run spec (one TRIM run for an exact beam of up to 99 999 ions, else a one-point scan that splits exact beams into units and runs binned beams per bin) and returns the results;srim.beam.sampled_ions(results)reads the sampled ions back from TRIM.DAT, andsrim.beam.plot_beam(results, parameter)draws the defined density over the sampled beam or the bins (matplotlib, theplotextra).pysrim2 runaccepts distributed specs and prints where the results are.
Changed
- The scan cache key and point id cover beam distributions: their definitions, histogram content (not only the file path) and the source of Python-function distributions, so a changed distribution never reuses an old run. Specs without distributions keep their keys.
v0.9.0
Changed
-
TRIM.run()andSR.run()now run in an isolated directory by default. Every run works in its own private copy of the SRIM install (hard links for the read-only files, so a copy adds well under 15 % of SRIM's size; real copies of what SRIM writes) under<data dir>/runs(orwork_dir=); the installed SRIM directory is never written to, so any number of runs, scripts, scans or users can run at the same time. On Linux each run also gets its own clone of the wine prefix, so cleaning up after a failure only stops that run's wine processes. The returnedResultspoints at the run directory (results.directory); passoutput_dir=to get the output files andrun.yamlin a folder of your choice (the run directory is then removed unlesskeep=True);run_dir=reuses asrim.rundir.RunDir. A failed run keeps its directory for debugging and names it in the error.
Migration: code that read outputs from the SRIM directory afterrun()(TRIM.copy_output_files(srim_dir(), dest),Results(srim_dir())) must use the returned results instead:TRIM.copy_output_files(results.directory, dest)orrun(output_dir=dest). Passingsrim_directory=explicitly keeps the old in-place behaviour, now under an exclusive file lock (a second run waits and prints a message after 5 s;lock_timeout=limits the wait). -
TRIM.copy_output_filescopies the files that SRIM writes to itsSRIM Outputssubfolder instead of moving them, so aResultsof the source (the onerun()returned) keeps working afterwards. -
pysrim2 runuses an isolated run directory too, so several can run at once. -
Runs no longer change the process working directory (the input writers take a
directory=argument and SRIM is started withcwd=), sorun()is safe in threads. Underxvfb-runevery run claims its own display number (-n, via lock files<tmp>/.pysrim2-xvfb-<N>.lock) instead of racing with-a; an X server that fails to start is retried up to three times. -
Run directories without
output_dir=are deleted automatically once unused for 7 days (PYSRIM2_RUN_RETENTION_DAYS, 0 keeps them; failed runs too);Results.close()/with trim.run() as results:delete one at once;pysrim2 clean runs [--older-than DAYS] [--dry-run]andpysrim2 doctor(size of the run directories) manage them. OpenResultskeep their run directory alive (shared lock) and pruning skips folders younger than a minute; leftovers that cannot be deleted are reported with a warning, and files shared with the SRIM install (hard links) never have their mode changed. -
Reading outputs from the installed SRIM directory (
Results(srim_dir()),TRIM.copy_output_files(srim_dir(), ...)) after isolated runs gives a one-timeUserWarningexplaining the 0.9.0 change. -
Nothing is ever created in the installed SRIM directory: the lock for in-place runs lives in
<data dir>/locks/, and copying the install waits for an in-place run that is writing; an in-place run in a read-only SRIM directory fails with a clear message. Relativework_dir=is made absolute.
Added
Documentation
- New pages
docs/scans.md(scan concepts, extractors and their columns and units, precision, the result table, cache, backends, live views, exit codes, tmux over SSH) anddocs/concurrency.md(isolated run directories, locks, migration from 0.8, one cache for several scans).docs/cli.mdlists the new commands. - A scan notebook (
examples/notebooks/Scan.ipynb), an example scan (examples/scripts/angle_energy_scan.pyandscan.yaml, run by the tests with real SRIM) and a scans section in the agent skill (skills/pysrim2/SKILL.md, section 7).
Scan definition and extractors
srim.scan.Scan(base, grid=, points=, extract=, ions=, seed=, batch_ions=)defines a parameter scan: a cartesiangridand/or zippedpointsover dotted keys (ion.energy_keV,target[0].thickness_nm),points()with a stable id per point (spec_hash), and ascan:section inrun.yamlread byScan.from_yaml/ written byScan.to_yaml.srim.scan.Precisiondescribes a precision goal forions=. Errors name the dotted key;number_ionsandseedare not scan parameters.srim.scan.extract: extractors turn a run's outputs into scan columns (register,get,available,resolve,combine) with predefinedimplant_summary,vacancy_at(depth_nm),peak_vacancy_depth,sputter_yield,backscattered_fraction,transmitted_fraction,ions_in_layer(layer_index)andenergy_to_recoils.srim.scanprecision targets:Scan(..., ions=Precision(target=, rel=|abs=, min_ions=, max_ions=, batch_ions=))runs each point in batches of ions (batch seeds derived from the point seed) until the target's standard error (<value>_err, the batch-means estimator) reaches the goal; the value is the extractors applied to all batches merged. A point that reachesmax_ionsfirst has statusmax_ionsand a warning; a stopped point keeps the estimate of its finished batches.batch_finishedevents report each decision.srim.scan.ScanResult: one row per scan point (parameters,id, values with<value>_err,n_ions,seeds,status,error,pathrelative tobase_dir=, so exports hold no host paths) withto_parquet,to_csv(a folder withscan.csvandmetadata.yaml),to_hdf5andplot(x, y, hue)(matplotlib, error bars from<value>_err).- New optional extra
pysrim2[plot](matplotlib) forScanResult.plot;pysrim2[all]includes it.
Running a scan
- A scan folder holds a
.pysrim2-scanmarker (written byrun_scanandprepare_slurm) and a running scan holds.scan.lock: a secondrun_scanin the same folder raisessrim.scan.ScanBusybefore it writes anything. srim.scan.run_scan(scan, workers=, scan_dir=, on_event=, stop_event=, retries=)runs the points of a scan in worker processes (workersdefaults to the CPU count minus one; each worker reuses one private run directory). It writes a scan folder (scan.yaml,points/<id>/with the outputs andrun.yaml,result/) and returns theScanResult. A failed point is retried once with the same seed, then reported with its error (points/<id>/error.log) while the scan goes on. Progress and results arrive as JSON-safe events (srim.scan.events:scan_started,point_started,point_finished,point_failed,worker_stats, ...) from one thread, in order. Ctrl-C (orstop_event) stops scheduling, kills the running SRIM runs (also children that ignore SIGTERM) and keeps the finished points; the others get statusstoppedand apoint_stoppedevent. Workers stop with their parent (POSIX: a killed scan leaves no SRIM running; its run directories are pruned by later scans). Workers that keep dying stop the scan with an error. Python extractors may be passed as callables:scan.yamlstores them aspython:<module>:<name>references, which read back for module-level functions (lambdas raise a clear error when the file is read).backend="container"runs each unit in its own container (the next item).srim.scan.Scan(..., batch_ions=N)(YAMLscan.batch_ions) splits a point with a fixed ion count into batches ofNions, each an independent run with its own derived seed, spread over the workers; the point's values and<value>_errare the batch-means estimate, as for a precision target, and each batch is cached. The default (None) keeps one run per point. Not allowed with a precision target.srim.scan.run_scan(..., pause_event=): while the event is set no new unit starts (running units finish, a stop still works); each change is reported as ascan_pausedevent (ScanPaused,paused).srim.scan.run_batches(spec, n_ions, batch_ions, seed)runs a calculation as batches with deterministic recorded seeds (derive_seed) and returnsMergedResults(per-ion tables concatenated with globalionnumbers and abatchcolumn, depth profiles merged as ion-count-weighted means, collisions streamed), usable likeResultsby the extractors and exports.
Result cache
srim.scanresult cache:run_scan(..., cache=)keeps every finished SRIM run (its output folder withrun.yaml) in<scan folder>/cache(or$PYSRIM2_CACHE, or the folder given;cache=Falseturns it off), keyed bysrim.scan.cache_key(spec, seed): a SHA-256 of the run spec that writesTRIM.IN(number_ionsincluded) and the seed, never of provenance. A rerun, or another scan that needs the same runs, reuses them without computing them again (point_cachedevents; statuscached); a precision rerun with a tighter goal runs only its new batches; two scans that need the same run compute it once (per-key locks, so the second waits and reuses it). Entries are written atomically, failed runs are never stored, and an entry made with another SRIM build is computed again and replaced by the new run. A point all of whose runs come from the cache has statuscached(a precision point that stops atmax_ionskeeps that status).srim.scan.clear_cache(path)empties a pysrim2 cache folder: it removes only the cache's own entries and keeps its lock files, and it warns about anything else it finds.pysrim2 scan cleanis the command-line form.
Backends
srim.scan.run_scan(..., backend="container", image=, runtime=)runs every unit in its own container of the pysrim2 image (Podman or Docker, found likepysrim2 install;PYSRIM2_IMAGEor the release image). Events, results and cache are the same as for the local back end. The worker that runs a unit removes its container when the scan is stopped, and a Docker run gets the seccomp profile that wine needs. Without a container runtime the scan fails before any worker starts. A customrunner=is not allowed with this back end. Containers run with--platform linux/amd64(the image is amd64-only) and--network=none.- Job folders:
srim.scan.backends.run_job(dir)andpysrim2 run-job DIRrun the units of a folde...
v0.8.0
All SRIM outputs as pandas DataFrames (incl. per-ion positions, trajectories, backscattered/transmitted/sputtered atoms and full cascades), editable run.yaml run specs with pysrim2 run, and export to Parquet/HDF5/CSV.
Added
-
CI reports, informationally, the
RANGE_3Ddigest of the same spec and seed on Linux (wine), Windows and in the container (therepro-reportjob compares Linux and Windows; the container digest is listed separately); same-platform reruns are asserted identical (tests/integration/test_reproducibility.py). Observed: Linux (wine) and the container are bit-identical, native Windows gives the same summary but different per-ion detail (seedocs/run-spec.md). -
.df(a pandas DataFrame, first columndepth_A, columns named with SRIM units) and.metadataonIoniz,Vacancy,NoVacancy,EnergyToRecoils,PhononsandRange;Results.to_dataframes(include=None)returns them as a dict. -
srim.output.Range3DreadsRANGE_3D.txt(per-ion final positions) into a DataFrame with columnsion,depth_A,y_A,z_A;Results.range3dholds it (Noneif the file is absent) andResults.to_dataframes()includes it. -
Range.summaryreturns the range and straggling values SRIM prints in theRANGE.txtheader (depth, lateral, radial, skewness, kurtosis).srim.analysis.implant_summary(df)computes the same quantities from the per-ion positions ofRange3D(standard deviations withddof=1). -
srim.output.EXYZ,Backscat,TransmitandSputterreadEXYZ.txt,BACKSCAT.txt,TRANSMIT.txtandSPUTTER.txtinto DataFrames (ion,atomic_number,energy_eV,depth_A,y_A,z_A,cos_x,cos_y,cos_z; EXYZ:ion,energy_keV,depth_A,y_A,z_A,electronic_stopping_eV_per_A,last_recoil_energy_eV);Results.exyz,.backscat,.transmit,.sputterhold them (Noneif absent; parsed on first access, streaming, so large files are cheap to open) andto_dataframes()returns them. A zero-byte event file gives an empty frame and a warning. They replace the stubs. EXYZ parser based on work by philis-johan. Fixtures generated with real SRIM intest_files/outputs-0.8/. -
Collision.iter_events()streamsCOLLISON.txtline by line as flat event dicts (ion,kind=ionfor a collision of the primary ion orrecoilfor a cascade recoil,energy_keV,depth_A,y_A,z_A,atom,recoil_energy_eV,target_displacements,target_vacancies,target_replacements,target_interstitials, plusatomic_number,electronic_stopping_eV_per_A,vacancy,replacement);Collision.dfcollects them into a DataFrame chunk-wise.Results.collision(lazy,Noneif absent) andResults.to_dataframes(include=["collision"])expose them;to_dataframes()leavescollisionout by default (opt-in like the exports, sinceCOLLISON.txtcan be several GB). -
Results.to_parquet(directory),.to_hdf5(path)and.to_csv(directory)export the tables (optionally selected withinclude=;collisiononly on request) with metadata: the table's.metadata, pysrim2 version, export time and an optional runspec(sourceis the file name only; Parquet: schema keypysrim2; HDF5: node attributepysrim2; CSV:metadata.yaml).Collision.to_parquet(path, chunk_rows=100_000)(also achunk_rowsargument of theResults.to_*methods) andCollision.to_csvstream the cascade events in chunks, so memory stays small for hugeCOLLISON.txtfiles. New optional extraspysrim2[parquet](pyarrow) andpysrim2[hdf5](PyTables);Collision.metadata. Thespecargument of the exports accepts aRunSpec(stored as its mapping) or a dict; anything else raisesTypeError. -
run.yaml:srim.spec.RunSpec(andIonSpec,LayerSpec,ElementSpec) describes a run with units in the key names (energy_keV,thickness_nm,density_g_cm3,angle_deg, ...), validates it with errors naming the dotted key (SpecError), and round-trips to a byte-identicalTRIM.IN.TRIM.to_spec(),TRIM.from_spec(),TRIM.to_yaml(),TRIM.from_yaml(); the seed is always recorded.TRIM.run()writesrun.yamlwith provenance (pysrim2 version, SRIM SHA-256, platform, backend, start/end time, host) next to the outputs (write_spec=Falseto skip),TRIM.copy_output_filescopies it, andResults.specis the defaultspecof theto_parquet/to_hdf5/to_csvexports (no host name). Seedocs/run-spec.md. -
Documentation: new pages
docs/dataframes.md(every column,Range.summary,implant_summary,iter_events),docs/export.md, and a full schema reference indocs/run-spec.md; the README shows.dfandimplant_summary. -
pysrim2 run run.yaml [--set dotted.key=value ...] [--output DIR]runs TRIM from a run spec (values converted by the schema; outputs andrun.yamlcopied toDIR, default./srim-output-<UTC timestamp>), andpysrim2 import TRIM.IN [-o run.yaml]turns an existingTRIM.INinto a run spec. Exit codes indocs/cli.md. -
Example notebooks rewritten on the 0.8.0 API (default SRIM location,
.dftables,implant_summary,Collision.iter_events()/.df, Parquet export,run.yamlwithTRIM.from_specandpysrim2 run), with small ion counts and no committed outputs;Regular SRIM Calculation.ipynbis nowRegular_SRIM_Calculation.ipynb, andKTaO3.ipynbis merged intoSiC.ipynb. Asrim-marked test (tests/integration/test_run_notebooks.py, nbclient) executes them; a static test checks that they are valid and import existing names. -
examples/scripts/run_yaml_example/(arun.yamland README forpysrim2 run run.yaml --set ion.energy_keV=30); the agent skill andexamples/agents/README.mdteach.df,implant_summary, event tables, cascades withiter_events()and chunked export, andrun.yaml.
Changed
- A
Layerwithout a name is now named after its elements (Si+C, or the formula forLayer.from_formula("SiC", ...); the same default for a layer withoutname:inrun.yaml) instead of the textNone. This changes the layer name written toTRIM.IN(andrun.yaml) for unnamed layers compared with 0.7.0.
Fixed
-
The
.dfelement columns of Kinchin-Pease tables (vacancies_<element>_...,absorbed_<element>_...) are named after the element for single-element targets instead of1; the header of those tables lists no symbols, so they are read from the target section. Multi-element targets keep the numbers. -
A zero-byte
RANGE_3D.txtgives an emptyRange3Dframe (same columns) and a warning, like the event files, instead of raising.Range3Dalso warns when a line in the data section cannot be parsed (a truncated final line is still ignored silently). -
The reference example's "lateral straggle" (341.6 A for the boron case) was the root mean square of the radial distance, not what SRIM calls lateral straggling; the example and skill now report SRIM's definitions (lateral straggle 241.8 A, radial straggle 154.9 A).
-
Results.range3dalso findsRANGE_3D.txtin theSRIM Outputssubfolder. -
A table header whose element names cannot be read now warns before the element columns fall back to
1,2, ...; theVacancy.knock_onsdocs give the correct unit (knock-ons per Angstrom per ion). -
Collision(COLLISON.txt) now parses every ion: the file is decoded as cp437 and split on SRIM's box-drawing column separators, so numbers no longer fail with glued separator characters (508 of 1000 ions of the SiC-C fixture raisedValueError/IndexError). Cascades without a summary line and stray recoil lines are handled; the per-ion dict API is unchanged. -
pysrim2 installexits 130 with a[skip] ... cancelledline on Ctrl-C during a step instead of printing a traceback.
v0.7.0
pysrim2 can now set up SRIM itself: uv tool install pysrim2 && pysrim2 install on Windows and Linux, or the ghcr.io/fsibt/pysrim2 container (Podman/Docker).
Added
- Documentation for the installer, the container, the command line and the agent skill (
docs/installation.rst,container.md,cli.md,agents.md); the README andAGENTS.mddescribe the 0.7.0 setup. Example scripts for the current API inexamples/scripts/(reference case, multilayer damage profile, stopping table) and an agent example inexamples/agents/. pysrim2 install [COMPONENT ...](with--dry-runand--yes) andpysrim2 doctor [--json]set up and check SRIM.srim.installer.install_srim()downloads SRIM-2013 from pinned sources and verifies its checksum.srim.installer.winesets up a private wine prefix with the VB5 runtime and OCX components for SRIM on Linux; it never touches~/.wineor$WINEPREFIX.pysrim2 install runtime|imageinstalls a container runtime (Podman preferred; Docker Desktop is never installed by pysrim2) and pulls theghcr.io/fsibt/pysrim2image;pysrim2 doctorchecks both.- Integration tests that run real TRIM/SR (
pytest -m srim). - SRIM location defaults to pysrim2's data directory (override with
PYSRIM2_SRIM_DIR); an existing/tmp/srimis still used. - Container image
ghcr.io/fsibt/pysrim2(linux/amd64: pysrim2, SRIM-2013 and wine, non-root) built and tested by CI. Run it as its default user (do not pass-u). - Agent skill
pysrim2(skills/pysrim2/SKILL.mdwith a runnable example, shipped inside the wheel):pysrim2 install skill [--agent claude|all] [--scope user|project]copies it to~/.claude/skills/,<project>/.claude/skills/(and~/.agents/skills/for--agent all); it never overwrites a differing skill it did not write unless--yes.skillis part of the defaultpysrim2 installset andpysrim2 doctorchecks an installed copy is current.
Changed
- Linux: pysrim2 always runs SRIM in its own private wine prefix. If you used pysrim with
/tmp/srimand~/.wine, runpysrim2 install wineonce (an existing/tmp/srimis still found). - The source distribution no longer includes
CLAUDE.md,docs/superpowers/,.github/ortests/. - The
srim.plotfunctions take aResultsobject and read its attributes; passing a dict no longer works.
Fixed
TRIM.run()/SR.run()no longer print Mesa/EGL ("MESA-EGL", "pci id for fd") warnings; xvfb/EGL noise is dropped from both stdout and stderr and EGL/Mesa logging is turned down in wine's environment.pysrim2 install runtimeshows the Windows "open a new terminal" hint only when no Podman machine exists;pysrim2 install --dry-runno longer names podman in the pull command when no runtime is installed.- Wine setup always runs its own pinned, checksum-verified winetricks instead of one found on
PATH(old copies do not know the OCX verbs). pysrim2 install wineno longer hangs when a wine driver host crashes (openSUSE, wine 11): the USB/controller/Bluetooth drivers and Mono/Gecko prompts are disabled throughWINEDLLOVERRIDES, wine's crash debugger is emptied, and a wineserver that does not exit within 60 s is stopped.pysrim2 install wineno longer hangs afterwinebootfinishes: wine output is captured in a temporary file, so the backgroundwineservercannot keep a pipe open (same forTRIM.run()/SR.run()stderr).TRIM.run()andSR.run()no longer print xvfb's "X connection to :N broken" line when SRIM exits under wine; other stderr output is kept and shown after the run. A failing run raisessrim.srim.SRIMProcessError(asubprocess.CalledProcessError) whose message includes that stderr.pysrim2 installprints[ok] <step>: installed(with the SRIM directory forsrim) after each step succeeds.- A failed or interrupted (Ctrl-C)
pysrim2 install winestops the private prefix's wineserver instead of leaving wine processes running. pysrim2 installprints a line as each long sub-step starts (wine prefix, winetricks, VB5 runtime, SRIM download/verify/unpack) instead of staying silent for minutes.pysrim2 doctorandpysrim2 installno longer suggest "pysrim2 install wine" on distributions without known package commands; they point to the WineHQ download page instead.pysrim2 install wineknows the package commands for openSUSE (zypper) and Arch (pacman, untested).- SRIM and the wine setup run under a 1024x768x24 virtual screen; the default 8-bit
xvfb-runscreen madewineboothang on wine 11. - Container image: Docker 29's built-in seccomp profile makes 32-bit wine fail ("socket: Function not implemented"); pysrim2 ships Docker's current default profile as
srim/data/seccomp-docker.json(pysrim2 install imagecopies it to the data directory and prints thedocker run --security-opt seccomp=...line). Podman is the default and needs no profile (its hint uses:Zon the/datamount). pysrim2 install vb5(Windows) puts the Visual Basic 5 runtime and OCX controls next to SRIM so TRIM starts on native Windows.- Wine setup finds
wineserverwhere Ubuntu installs it. TRIM.run()andSR.run()delete old output first and raiseSRIMRunErrorif SRIM wrote no result, so a crash never returns a previous run's data.- Winetricks downloads go to pysrim2's own cache instead of
~/.cache/winetricks. TRIM.runandSR.runread their results correctly whensrim_directoryis a relative path.- SR output ranges in
kmare parsed instead of raisingSRIMOutputParseError. - Parsing SRIM output no longer prints debug output to stdout.
Removed
- The obsolete
costrouc/pysrimDocker example (examples/docker/), the historical Docker benchmark page (docs/benchmarks.rst),examples/input/and unused generated files inexamples/images/.
v0.6.0
Changes since pysrim 0.5.10. See
changes from pysrim for credits and details.
Added
- Run SRIM under
xvfb-run -awhen it is available, so no display is needed (Jan Mayer). - Parse SRIM output written with comma decimal separators (philis-johan, MrRobot2211).
- Support the
m(metre) length unit in SR output (Angus Hollands). SRIMOutputParseErrorfor unknown units in SR output.- GitHub Actions: lint, test matrix (Python 3.11 to 3.15 on Linux, Windows and macOS), build, and a trusted-publishing release workflow.
- Ruff configuration and pre-commit hooks.
- Documentation: change list relative to pysrim, changelog page,
AGENTS.md.
Changed
- The distribution is renamed to
pysrim2; the import namesrimis unchanged. It cannot be installed alongsidepysrim. - Requires Python 3.11 or newer.
- Packaging uses
pyproject.toml, hatchling and uv (Angus Hollands). - Wine is detected with
shutil.whichthrough a shared launch helper (Mirochill). - Code formatted with ruff.
- Documentation uses the furo theme, is built with uv, and is hosted at https://pysrim2.readthedocs.io.
- README and installation instructions rewritten for pysrim2.
Fixed
- Removed the
distutilsimport so the package imports on Python 3.12 and later (lievcm). - Regular expressions use raw strings, removing invalid escape sequence warnings (lievcm).
- Ion energies with a leading or trailing decimal point (such as
.3 keV) are parsed (Mirochill, George Apostolopoulos, SimonF24). - Positive
autosaveintervals are accepted (Mirochill). - The sputtered output setting is honoured independently of ranges (Mirochill).
- The element database file is closed after loading.
- Undefined names: the
NotImpementedErrortypo inSRIM_Output._read_target, and missingnumpyimport andfolderargument insrim.plot. - Plot functions read
Resultsattributes instead of subscriptingResults. - Docstring markup errors that produced Sphinx warnings.
Removed
- Support for Python versions before 3.11.
setup.py,setup.cfg, the conda recipe,install.sh,default.nix, GitLab CI and the old Dockerfiles. A container image and a SRIM installer for wine are planned.
Versions up to and including 0.5.10 were released as pysrim by Chris Ostrouchov.
SRIM-2013 (third-party, non-commercial use only)
SRIM-2013 -- Copyright SRIM.com (James F. Ziegler), www.srim.org. All Rights Reserved.
This release redistributes the unmodified SRIM-2013 archive (srim.2013.zip). From
SRIM's own legal notice (srim/Data/LEGAL.rtf, attached):
"SRIM may be copied and distributed freely. However, no commercial use may be
made of the code, the associated files, or of its results ... without a
written license from SRIM.org."
"...this program and its associated files ... are to be used solely for
experimental uses and are not to be sold, distributed to a commercial
organization, or be commercially exploited in any manner."
By downloading or using SRIM you accept SRIM.com's disclaimer and user agreement
in LEGAL.rtf. SRIM is NOT covered by pysrim2's MIT license and is provided "as is"
without warranty. If you work for a commercial organization, obtain SRIM and a
license from SRIM.org instead of using this copy.
pysrim2 downloads this file automatically (pysrim2 install srim) and verifies
its SHA-256 checksum (see SHA256SUMS).