Files
TRIMSP/TrimSP.html
T
Zaher Salman 93f0b1c4d5 Fix parIRL=1 crash: zero recoil cutoff makes the cascade diverge
parIRL=1 crashed the engine with SIGSEGV (CGI exitCode 139) at both GUI
defaults, so the sputtering path has never actually worked.

The first diagnosis blamed KO(600,MAXNL5,2) being shallower than the
2000-wide recoil lists. That is wrong: enlarging KO to 2000 does not help,
because the cascade overruns all of them. The real cause is parERC=0, which
is the GUI default and what tests/Si_1layer/Si_1layer_E19000.inp carries. The
primary knock-on test is IF(DEN(IV).LE.ERC) GO TO 6, so with no cutoff every
atom receiving any energy is respawned as a recoil on each cascade
generation; the branching ratio exceeds one and NREC1/NREC2 grow
geometrically (81, 153, 269, 455, 773, 1317, ...) instead of draining, so the
list-2/list-1 loop at label 83 never terminates. Forcing a real cutoff
converges, with a peak depth of only 103, so KO was left at 600.

fortran/trimspNL.F:
- Refuse parIRL>=1 with parERC<=0 after readGuiInput, before any transport
  work, with a message naming the field to change.
- The IF(NREC2.GT.2000) guard now stops non-zero instead of falling through
  into the out-of-bounds write loop, so any future non-convergent cascade
  fails cleanly instead of corrupting memory.

TrimSPlib.js / TrimSP.html, so this is caught before the engine is invoked:
- handleRecoilModeChange, wired to the parIRL widget, fills parERC with
  TRIMSP_MIN_RECOIL_CUTOFF = 0.02 when recoils are switched on with a cutoff
  of 0, and says so.
- A pre-run check refuses the run if the user then insists on parIRL=1 with
  parERC=0, reporting via the status bar and a transient warning and focusing
  parERC. Deliberately not wired to parERC, so retyping the cutoff is what
  insisting means and is not silently overridden; this also covers shared
  config links, which assign widget values directly.
- The parIRL tooltip documents the requirement.

Tests: tests/recoil-cutoff-test.js (12 cases) lifts the shipped cutoff code
out of TrimSPlib.js and runs it against a document stub. Verified against a
fresh build: parERC=0/parIRL=1 now exits 1 with the new message instead of
139, parERC=0.02 completes with parIRL=0 or 1, and parERC=0/parIRL=0 output
is unchanged (.rge byte-identical). tests/cgi-tests.sh 18/18.
2026-09-26 18:55:38 +02:00

511 lines
22 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="ZGUI.css">
<script src="TrimSPweb.js"></script>
<script>
// Electron exposes CommonJS module support; plain browsers do not.
// Load the Electron-specific helpers only for the standalone app.
if (typeof module !== 'undefined' && module.exports) {
document.write('<script src="TrimSPelec.js"><\/script>');
} else {
document.write('<script src="plotly.js"><\/script>');
}
</script>
<script src="TrimSPlib.js"></script>
<script src="myplots.js"></script>
<title>TRIMSP-NL Workbench</title>
</head>
<body onresize="resizePl()" onload="adjust_table();adjust_scans();">
<main class="app-shell">
<section class="app-card">
<nav class="tab" aria-label="Simulation workspace">
<button type="button" class="tablinks" onclick="openTab(event,'Layers')" id="btnLayers">Layers</button>
<button type="button" class="tablinks" onclick="openTab(event,'Scans')" id="btnScans">Scan</button>
<button type="button" class="tablinks" onclick="openTab(event,'Plots')" id="btnPlots">Results</button>
<button type="button" class="tablinks" onclick="openTab(event,'Other')" id="btnOther">Advanced</button>
<button type="button" class="help-button" onclick="showQuickStartHelp();"
title="Quick Start / Help" aria-label="Quick Start / Help">?</button>
<button type="button" class="help-button share-button" id="shareConfigButton"
onclick="copyWebConfigurationLink();" title="Copy configuration link"
aria-label="Copy configuration link">
<svg class="share-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
<circle cx="18" cy="5" r="2.5"></circle>
<circle cx="6" cy="12" r="2.5"></circle>
<circle cx="18" cy="19" r="2.5"></circle>
<path d="M8.2 10.8 15.8 6.2M8.2 13.2l7.6 4.6"></path>
</svg>
</button>
</nav>
<div class="main-action-bar" role="toolbar" aria-label="Simulation actions">
<div class="action-bar-title">
<img class="app-brand-icon" src="icon.png" alt="" aria-hidden="true">
<div>
<span class="action-bar-eyebrow">TRIMSP-NL Workbench</span>
<strong>Low-energy implantation simulation</strong>
</div>
</div>
<button type="button" class="run-action" id="runSimulationButton" onclick="startSim();">Run simulation</button>
</div>
<div id="Layers" class="tabcontent">
<div class="output-settings">
<label class="compact-field output-prefix" id="FileRow" for="fileNamePrefix">
<span>File prefix</span>
<input name="fileNamePrefix" id="fileNamePrefix" type="text" value="SrTiO3">
<input name="trimPath" id="trimPath" type="hidden">
</label>
<div class="compact-field output-folder" id="FolderRow">
<label for="workPath">Save folder</label>
<div class="field-with-action">
<input type="text" disabled id="workPath" name="workPath" title="Use Browse to select the save folder">
<input type="button" value="Browse" id="browseFolde" onclick="browseForFolder();">
<input type="file" id="folderPicker" hidden webkitdirectory directory>
</div>
</div>
</div>
<div class="layers-workspace">
<section class="settings-panel target-panel" aria-labelledby="targetPanelTitle">
<div class="section-heading">
<div>
<span class="section-eyebrow">Target</span>
<h2 id="targetPanelTitle">Layer stack</h2>
</div>
<label class="layer-count" for="numLayer">
<span>Layers</span>
<input name="numLayer" id="numLayer" type="number" step="1" min="1" max="100" value="1" onchange="adjust_table()">
</label>
</div>
<div class="layer-table-wrap">
<table id="LTable">
<tr><td><b>Layer</b></td><td><b>Composition</b></td><td><b>Density [g/cm<sup>3</sup>]</b></td><td><b>Thickness [Å]</b></td></tr>
</table>
</div>
</section>
<section class="settings-panel projectile-panel" aria-labelledby="projectilePanelTitle">
<div class="section-heading">
<div>
<span class="section-eyebrow">Beam</span>
<h2 id="projectilePanelTitle">Projectile</h2>
</div>
</div>
<div class="projectile-grid">
<label class="settings-field" for="ProjType"><span>Projectile</span>
<select name="ProjType" id="ProjType" onchange="ProjSmartDefaults()">
<option selected="selected" value="muon">muon</option>
<option value="Li-8">Li-8</option>
<option value="Be-11">Be-11</option>
<option value="B-12">B-12</option>
<option value="Mg-31">Mg-31</option>
<option value="H">H</option>
<option value="He">He</option>
<option value="Ar">Ar</option>
</select>
</label>
<label class="settings-field" for="numberProj"><span>Projectiles</span><input name="numberProj" id="numberProj" type="text" value="1000"></label>
<label class="settings-field" for="valEnergy"><span>Energy [eV]</span><input name="valEnergy" id="valEnergy" type="text" value="2000"></label>
<label class="settings-field" for="sigEnergy"><span>Energy sigma [eV]</span><input name="sigEnergy" id="sigEnergy" type="text" value="450"></label>
<label class="settings-field" for="valAngle"><span>Angle [deg]</span><input name="valAngle" id="valAngle" type="text" value="0"></label>
<label class="settings-field" for="sigAngle"><span>Angle sigma [deg]</span><input name="sigAngle" id="sigAngle" type="text" value="15"></label>
<label class="settings-field" for="z0"><span>Starting depth [Å]</span><input name="z0" id="z0" type="text" value="0"></label>
<label class="settings-field" for="dz"><span>Depth increment [Å]</span><input name="dz" id="dz" type="text" value="20"></label>
<label class="settings-field" for="rngType"><span>RNG</span>
<select name="rngType" id="rngType">
<option value="pcg32" selected="selected">PCG32</option>
<option value="ranlux">RANLUX</option>
<option value="xoshiro">xoshiro256**</option>
</select>
</label>
<label class="settings-field" for="ranSeed"><span>Seed</span><input name="ranSeed" id="ranSeed" type="text" value="78741"></label>
</div>
</section>
</div>
</div>
<div id="Scans" class="tabcontent">
<section class="settings-panel scan-panel" aria-labelledby="scanPanelTitle">
<div class="scan-heading">
<div>
<span class="section-eyebrow">Execution plan</span>
<h2 id="scanPanelTitle">Parameter scan</h2>
</div>
<label class="scan-enable" for="scanSeq">
<input type="checkbox" name="scanSeq" id="scanSeq" onchange="adjust_scans();">
<span>Enable scan</span>
</label>
</div>
<div id="ScansControls" hidden>
<div class="scan-controls-grid">
<label class="settings-field" for="scanType"><span>Sequence</span>
<select name="scanType" id="scanType" onchange="adjust_scans();">
<option value="scanLoop">Range</option>
<option value="scanVals">Set of values</option>
</select>
</label>
<label class="settings-field" for="comboScan"><span>Parameter</span>
<select name="comboScan" id="comboScan" onchange="updateScanSummary();">
<option value="EScan">Energy [eV]</option>
<option value="SigEScan">Energy sigma [eV]</option>
<option value="AngleScan">Angle [deg]</option>
<option value="SigAngleScan">Angle sigma [deg]</option>
<option value="NProjScan">Number of projectiles</option>
<option value="dScan">Thickness of layer # 1</option>
</select>
</label>
<label class="settings-field" for="scanThreads"><span>Workers</span>
<input name="scanThreads" id="scanThreads" type="number" min="1" step="1" value="" oninput="adjust_scans();">
</label>
</div>
<div id="ScansTable" class="scan-values-panel scan-range-grid">
<label class="settings-field" for="scanFrom"><span>From</span><input name="scanFrom" id="scanFrom" type="text" value="1000" oninput="updateScanSummary();"></label>
<label class="settings-field" for="scanStep"><span>Step</span><input name="scanStep" id="scanStep" type="text" value="2000" oninput="updateScanSummary();"></label>
<label class="settings-field" for="scanTo"><span>To</span><input name="scanTo" id="scanTo" type="text" value="14000" oninput="updateScanSummary();"></label>
</div>
<div id="ScansLine" class="scan-values-panel scan-list-grid" hidden>
<label class="settings-field" for="scanList"><span>Values, separated by commas</span><input name="scanList" id="scanList" type="text" value="1000" oninput="updateScanSummary();"></label>
<label class="settings-field" for="scanListdz"><span>Matching depth increments (optional)</span><input name="scanListdz" id="scanListdz" type="text" value="" oninput="updateScanSummary();"></label>
</div>
</div>
<div id="scanSummary" class="scan-summary" role="status" aria-live="polite">Single simulation using the Layers settings.</div>
</section>
</div>
<div id="Plots" class="tabcontent">
<div class="results-grid">
<section class="result-plot-panel" aria-label="Implantation profile plot">
<div id="plotRge" class="result-plot"><!-- Plotly chart will be drawn inside this DIV --></div>
</section>
<section class="result-plot-panel" aria-label="Stopping fraction plot">
<div id="plotFrac" class="result-plot"><!-- Plotly chart will be drawn inside this DIV --></div>
</section>
</div>
</div>
<div id="Other" class="tabcontent">
<div class="advanced-layout">
<section class="settings-panel advanced-parameters" aria-labelledby="advancedParametersTitle">
<div class="section-heading">
<div>
<span class="section-eyebrow">Transport model</span>
<h2 id="advancedParametersTitle">Advanced parameters</h2>
</div>
</div>
<table>
<tr>
<td class="tooltip">
EF
<span class="tooltiptext">
Cutoff energy of projectiles (in eV); must be
greater than zero. Used for low projectile energies
(< 1000 eV) and ESB = 0. EF should be of the order
of ~0.2 eV, but not above SBE (for sputtering
data). With increasing projectile energy, EF can be
increased to save computing time.
</span>
</td>
<td>
<input name="parEF" id="parEF" type="number" size="7" step="0.1" value="0.5">
</td>
<td class="tooltip">
KK0
<span class="tooltiptext">
Maximum order of weak (simultaneous) collisions between projectile and target atoms:
<ol>
<li value="0">No weak collisions included.</li>
<li value="1">???</li>
<li value="2">Sufficient for most calculations.</li>
<li value="3">Only useful for very heavy particles; increases computing time.</li>
<li value="4">Only useful for very heavy particles; increases computing time.</li>
</ol>
</span>
</td>
<td>
<input name="parKK0" id="parKK0" type="number" step="1" min="0" max="4" value="2">
</td>
</tr>
<tr>
<td class="tooltip">
ESB
<span class="tooltiptext">
Surface binding energy for projectiles (in eV).
This value is zero for the noble gases,
but ESB should be larger than zero if the projectile is an active
chemically species.
ESB = SBE for self-sputtering calculations.
</span>
</td>
<td>
<input name="parESB" id="parESB" type="number" size="7" step="0.1" value="0.0">
</td>
<td class="tooltip">
KK0R
<span class="tooltiptext">
Maximum order of weak (simultaneous) collisions between target atoms:
<ol>
<li value="0">No weak collisions included.</li>
<li value="1">???</li>
<li value="2">Sufficient for most calculations.</li>
<li value="3">Only useful for very heavy particles; increases computing time.</li>
<li value="4">Only useful for very heavy particles; increases computing time.</li>
</ol>
</span>
</td>
<td>
<input name="parKK0R" id="parKK0R" type="number" step="1" min="0" max="4" value="2">
</td>
</tr>
<tr>
<td class="tooltip">
SHEATH
<span class="tooltiptext">
Sheath potential (in eV);
typically 3 * kT (i.e., 3 * |projectile energy|).
</span>
</td>
<td>
<input name="parSHEATH" id="parSHEATH" type="number" size="7" step="0.1" value="0.0">
</td>
<td class="tooltip">
KDEE1
<span class="tooltiptext">
Inelastic energy loss model for projectiles:
<ol>
<li value="1">Nonlocal (Lindhard-Scharff).</li>
<li value="2">Local (Oen-Robinson).</li>
<li value="3">Equipartition of local and nonlocal models (i.e., options 1 & 2).</li>
<li value="4">Nonlocal (Anderson-Ziegler tables for hydrogen); must be used for hydrogen-like projectile with energies > 10 keV.</li>
<li value="5">Nonlocal (Ziegler tables for helium); must be used for helium-like projectiles with energies > 50 keV.</li>
</ol>
Note: options 1, 2, and 3 can only be used at energies below the stopping power maximum.
</span>
</td>
<td>
<input name="parKDEE1" id="parKDEE1" type="number" step="1" min="1" max="5" value="4">
</td>
</tr>
<tr>
<td class="tooltip">
ERC
<span class="tooltiptext">
Recoil cutoff energy (in eV);
usually equal to the surface binding energy.
</span>
</td>
<td>
<input name="parERC" id="parERC" type="number" size="7" step="0.1" value="0.0">
</td>
<td class="tooltip">
KDEE2
<span class="tooltiptext">
Inelastic energy loss for target atoms:
<ol>
<li value="1">Nonlocal (Lindhard-Scharff).</li>
<li value="2">Local (Oen-Robinson).</li>
<li value="3">Equipartition of local and nonlocal models (i.e., options 1 & 2).
</li>
</ol>
Note: options 1, 2, and 3 can only be used at energies below the stopping power maximum.
</span>
</td>
<td>
<input name="parKDEE2" id="parKDEE2" type="number" step="1" min="1" max="3" value="3">
</td>
</tr>
<tr>
<td class="tooltip">
RD
<span class="tooltiptext">
Depth (in Å) to which recoils are followed.
RD = 50 is usually sufficient for sputtering
(if the projectile energy is not too high).
Use RD = 100 * CW (i.e., the depth increment)
for following the full collision cascade.
</span>
</td>
<td>
<input name="parRD" id="parRD" type="number" size="7" step="0.1" value="50.0">
</td>
<td class="tooltip">
IPOT
<span class="tooltiptext">
Interaction potential between projectile and target atoms:
<ol>
<li value="1">Krypton-Carbon (Kr-C) potential.</li>
<li value="2">Molière potential.</li>
<li value="3">Ziegler-Biersack-Littmark (ZBL) potential.</li>
</ol>
</span>
</td>
<td>
<input name="parIPOT" id="parIPOT" type="number" step="1" min="1" max="3" value="2">
</td>
</tr>
<tr>
<td class="tooltip">
CA
<span class="tooltiptext">
Correction factor to the Firsov screening length for
collisions between projectile and target atoms
(only used in the application of the Molière potential);
usually on the order of ~1.0.
</span>
</td>
<td>
<input name="parCA" id="parCA" type="number" size="7" step="0.1" value="1.0">
</td>
<td class="tooltip">
IPOTR
<span class="tooltiptext">
Interaction potential between target atoms:
<ol>
<li value="1">Krypton-Carbon (Kr-C) potential.</li>
<li value="2">Molière potential.</li>
<li value="3">Ziegler-Biersack-Littmark (ZBL) potential.</li>
</ol>
</span>
</td>
<td>
<input name="parIPOTR" id="parIPOTR" type="number" step="1" min="0" max="3" value="1">
</td>
</tr>
<tr>
<td class="tooltip">
Stopping Power<br>Coefficients
<span class="tooltiptext">
Data source for the Varelas-Biersack parameterization of electronic
stopping cross-sections for proton-like projectiles implanted in
elemental targets:
<ol>
<li value="1">Table 1 in Anderson & Ziegler (1977).</li>
<li value="2">Table 3.1 in ICRU Report 49 (1993).</li>
<li value="3">Table II in McFadden et al. (2023) and McFadden et al. (unpublished).</li>
</ol>
Note: While option 3 contains the most up-to-date values, it currently
does not contain entries for every target element. For elements with
missing data, values from option 2 are taken instead.
</span>
</td>
<td>
<input name="flagSPC" id="flagSPC" type="number" step="1" min="1" max="3" value="2">
</td>
<td class="tooltip">
IRL
<span class="tooltiptext">
Collision recoils:
<ol>
<li value="0">
No recoils are generated (i.e., no sputtering effects);
used to speed up the calculation if only projectile ranges are of interest.
</li>
<li value="1">Calculate collision recoils. Requires a
parERC recoil cutoff above zero; 0.02 is filled in
automatically.</li>
</ol>
</span>
</td>
<td>
<input name="parIRL" id="parIRL" type="number" step="1" min="0" max="1" value="0" onchange="handleRecoilModeChange();">
</td>
</tr>
</table>
</section>
<aside class="reference-panel" aria-labelledby="referencePanelTitle">
<span class="section-eyebrow">Documentation</span>
<h2 id="referencePanelTitle">Reference &amp; citation</h2>
<p>
For model details, see W. Eckstein,
<i>Computer Simulation of Ion-Solid Interactions</i>, Springer Series
in Materials Science, Vol. 10 (Springer-Verlag, Berlin, 1991).
</p>
<a class="reference-link" href="https://doi.org/10.1007/978-3-642-73513-4">
doi.org/10.1007/978-3-642-73513-4
</a>
<div class="reference-divider"></div>
<span class="reference-label">TRIMSP-NL Workbench</span>
<p>
Z. Salman, R. M. L. McFadden, and T. Prokscha,
<i>Modernization and Statistical Validation of a Multilayer TRIM.SP
Code for Low-Energy Muon and Ion Implantation</i> (2026).
</p>
<a class="reference-link" href="https://doi.org/10.48550/arXiv.2609.00094">
doi.org/10.48550/arXiv.2609.00094
</a>
<p>
If you use this software in published work, please cite the relevant
TRIM.SP references and the TRIMSP-NL Workbench paper.
</p>
<div class="reference-divider"></div>
<span class="reference-label">Source repository</span>
<a class="reference-link" href="https://gitea.psi.ch/LMU/TRIMSP">
gitea.psi.ch/LMU/TRIMSP
</a>
</aside>
</div>
</div>
</section>
</main>
<div id="statusBar" class="status-bar">
<span class="status-item"><strong>Folder:</strong> <span id="statusWorkPath">-</span></span>
<span class="status-item"><strong>Backend:</strong> <span id="statusBackend">-</span></span>
<span class="status-item"><strong>Last save:</strong> <span id="statusLastSave">Not saved yet</span></span>
<span class="status-item"><strong>Run:</strong> <span id="statusRun">Idle</span></span>
<div class="status-progress">
<div class="status-progress-track">
<div id="pBar" class="status-progress-fill">0%</div>
</div>
</div>
<div id="webStatusActions" class="status-actions" hidden>
<a id="statusOutputLink" class="status-action-link" href="#" hidden>Outputs</a>
<button type="button" class="status-details-button" onclick="openWebRunDetails();">Details</button>
</div>
</div>
<dialog id="runDetailsDialog" class="run-details-dialog">
<div class="run-details-heading">
<div>
<span class="section-eyebrow">Web backend</span>
<h2>Run details</h2>
</div>
<button type="button" onclick="document.getElementById('runDetailsDialog').close();">Close</button>
</div>
<p class="run-details-note">CGI responses and TRIM.SP-NL output for this browser session.</p>
<pre id="webRunLog" class="run-details-log">No web requests have been made yet.</pre>
</dialog>
<dialog id="quickStartDialog" class="quick-start-dialog" aria-label="TRIMSP-NL Quick Start" aria-modal="false">
<div class="quick-start-dialog-header quick-start-drag-handle">
<strong>TRIMSP-NL Quick Start</strong>
<button type="button" onclick="closeQuickStartHelp();" aria-label="Close Quick Start">Close</button>
</div>
<iframe id="quickStartFrame" class="quick-start-frame" title="TRIMSP-NL Quick Start"></iframe>
</dialog>
</body>
<script>
let workPath = document.getElementById("workPath");
let webOrApp = amIWeb();
// If empty or undefined use local folder as default
if (workPath.value == '' || workPath.value == undefined ) {
if (webOrApp) {
workPath.value = '/tmp';
} else {
workPath.value = process.cwd();
}
}
if (typeof syncStatusBar === 'function') {
syncStatusBar();
}
// Open the default Layers tab
document.getElementById("btnLayers").click();
if (webOrApp) {
console.log('this script is not running in Node.js');
// Run as a web app
document.getElementById("FileRow").hidden = true;
document.getElementById("FolderRow").hidden = true;
document.getElementById("webStatusActions").hidden = false;
} else {
console.log('this script is running in Node.js');
// Run as standalone app
// Set up after first load (electron specific menu calls)
firstLoad();
}
</script>
</html>