Jump to content

Specific Process Knowledge/Lithography/EBeamLithography/thopesplaystuff

From LabAdviser
Revision as of 16:33, 2 September 2025 by Thope (talk | contribs) (Created page with "<!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <title>EBL Dose Simulator — Hello Kitty Theme</title> <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script> <style> :root{ --pink:#ffb6d5; --hotpink:#ff69b4; --accent:#fff0f6; --text:#333; --card:#fff; } body{ margin:0; font-family:Inter,...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

<!doctype html> <html lang="en"> <head>

 <meta charset="utf-8" />
 <meta name="viewport" content="width=device-width,initial-scale=1" />
 <title>EBL Dose Simulator — Hello Kitty Theme</title>
 <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
 <style>
   :root{
     --pink:#ffb6d5;
     --hotpink:#ff69b4;
     --accent:#fff0f6;
     --text:#333;
     --card:#fff;
   }
   body{
     margin:0;
     font-family:Inter,ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial;
     background: linear-gradient(180deg,var(--accent),#fff);
     color:var(--text);
   }
   header{
     display:flex;align-items:center;gap:16px;padding:18px 24px;background:var(--pink);box-shadow:0 6px 18px rgba(255,105,180,0.12);
   }
   .logo{
     width:64px;height:64px;border-radius:12px;background:linear-gradient(180deg,var(--hotpink),#ffd1ea);display:flex;align-items:center;justify-content:center;box-shadow:0 6px 10px rgba(0,0,0,0.06);
   }
   .logo svg{width:46px;height:46px}
   h1{font-size:20px;margin:0}
   .container{max-width:1100px;margin:20px auto;padding:18px}
   .grid{display:grid;grid-template-columns:320px 1fr;gap:18px}
   .card{background:var(--card);border-radius:12px;padding:14px;box-shadow:0 8px 22px rgba(0,0,0,0.06)}
   label{font-size:13px;display:block;margin-bottom:6px}
   .small{font-size:12px;color:#666}
   input[type=range]{width:100%}
   .row{display:flex;gap:12px;align-items:center}
   button{background:var(--hotpink);border:none;color:white;padding:8px 12px;border-radius:10px;cursor:pointer}
   footer{margin-top:18px;text-align:center;color:#777;font-size:13px}
   .muted{color:#666;font-size:13px}
   canvas{background:transparent}
 </style>

</head> <body>

 <header>

EBL Dose Simulator — Hello Kitty Theme

Simulate exposure dose including forward- and backscattered electrons (proximity effect)
 </header>
 <main class="container">
         <label for="widthSlider">Line width: 100 nm</label>
         <input id="widthSlider" type="range" min="10" max="400" value="100" step="1">
Change the width of the three parallel lines. Dose profile updates live.
         <label for="doseInput">Incident dose (a.u.):</label>
         <input id="doseInput" type="number" value="1" step="0.1" style="width:100%" />
This is a scale factor — relative units (a.u.).

         <label>Proximity function parameters</label>
A two-Gaussian point-spread function is used: narrow forward-scatter (σf) and broad backscatter (σb) with weight η.
           <label>Forward sigma (σf, nm): 5</label>
           <input id="sfSlider" type="range" min="1" max="30" value="5">
           <label>Backscatter sigma (σb, nm): 200</label>
           <input id="sbSlider" type="range" min="50" max="2000" value="200">
           <label>Backscatter weight (η): 0.4</label>
           <input id="etaSlider" type="range" min="0" max="0.9" step="0.01" value="0.4">

         <button id="resetBtn">Reset</button>
Tip: drag the line-width slider to see how proximity effects blur and add dose between lines.
       <canvas id="doseChart" height="220"></canvas>
         <label style="display:flex;gap:6px;align-items:center"><input id="showPattern" type="checkbox" checked> Show pattern</label>
         <label style="display:flex;gap:6px;align-items:center"><input id="showForward" type="checkbox" checked> Forward component</label>
         <label style="display:flex;gap:6px;align-items:center"><input id="showBack" type="checkbox" checked> Backscatter component</label>
   <footer>
Model: 1D cross-section of three parallel lines. Uses a two-Gaussian proximity function: PSF(r) = (1-η)*G(σf) + η*G(σb). Units are arbitrary — this is a relative-dose visualizer, useful for intuition and teaching.
   </footer>
 </main>

<script> // --- Configuration & utilities --- const LENGTH = 2000; // nm length of simulation window const DX = 1; // nm resolution const N = Math.floor(LENGTH/DX); const x = new Array(N).fill(0).map((_,i)=>i*DX);

function gaussian1d(sigma){

 const twiceVar = 2*sigma*sigma;
 const radius = Math.ceil(6*sigma/DX);
 const kernel = new Float64Array(radius*2+1);
 let sum = 0;
 for(let i=-radius;i<=radius;i++){
   const v = Math.exp(-(i*DX)*(i*DX)/twiceVar);
   kernel[i+radius]=v; sum+=v;
 }
 for(let i=0;i<kernel.length;i++) kernel[i]/=sum;
 return {kernel, radius};

}

function convolve(signal, kernel, radius){

 const out = new Float64Array(signal.length);
 for(let i=0;i<signal.length;i++){
   let s=0;
   for(let k=-radius;k<=radius;k++){
     const j=i+k;
     if(j<0||j>=signal.length) continue;
     s += signal[j]*kernel[k+radius];
   }
   out[i]=s;
 }
 return out;

}

function makePattern(lineWidth){

 // three parallel lines centered at 600, 1000, 1400 nm
 const centers = [600,1000,1400];
 const pat = new Float64Array(N);
 const half = lineWidth/2;
 for(let i=0;i<N;i++){
   const xi = x[i];
   for(const c of centers){
     if(Math.abs(xi-c) <= half) { pat[i]=1; break; }
   }
 }
 return pat;

}

// --- UI elements --- const widthSlider = document.getElementById('widthSlider'); const widthLabel = document.getElementById('widthLabel'); const doseInput = document.getElementById('doseInput'); const sfSlider = document.getElementById('sfSlider'); const sbSlider = document.getElementById('sbSlider'); const etaSlider = document.getElementById('etaSlider'); const sfLabel = document.getElementById('sfLabel'); const sbLabel = document.getElementById('sbLabel'); const etaLabel = document.getElementById('etaLabel'); const resetBtn = document.getElementById('resetBtn'); const showPattern = document.getElementById('showPattern'); const showForward = document.getElementById('showForward'); const showBack = document.getElementById('showBack');

// --- Chart --- const ctx = document.getElementById('doseChart').getContext('2d'); const chart = new Chart(ctx, {

 type: 'line',
 data: {
   labels: x,
   datasets: [
     {label:'Total dose', data: new Array(N).fill(0), tension:0.2, borderWidth:2, pointRadius:0, spanGaps:true},
     {label:'Pattern (direct)', data: new Array(N).fill(0), tension:0.2, borderWidth:1, pointRadius:0, borderDash:[4,4], hidden:!showPattern.checked},
     {label:'Forward scatter', data: new Array(N).fill(0), tension:0.2, borderWidth:1, pointRadius:0, hidden:!showForward.checked},
     {label:'Backscatter', data: new Array(N).fill(0), tension:0.2, borderWidth:1, pointRadius:0, hidden:!showBack.checked},
   ]
 },
 options: {
   animation:false,
   plugins:{legend:{position:'top'}},
   scales: {
     x:{display:true,title:{display:true,text:'x (nm)'}},
     y:{display:true,title:{display:true,text:'Relative dose (a.u.)'}}
   }
 }

});

function updateChart(total, pattern, forwardComp, backComp){

 chart.data.datasets[0].data = Array.from(total);
 chart.data.datasets[1].data = Array.from(pattern);
 chart.data.datasets[2].data = Array.from(forwardComp);
 chart.data.datasets[3].data = Array.from(backComp);
 chart.data.datasets[1].hidden = !showPattern.checked;
 chart.data.datasets[2].hidden = !showForward.checked;
 chart.data.datasets[3].hidden = !showBack.checked;
 chart.update('none');

}

function computeAndRender(){

 const w = Number(widthSlider.value);
 widthLabel.textContent = `${w} nm`;
 const doseScale = Number(doseInput.value) || 1;
 const sf = Number(sfSlider.value); sfLabel.textContent = sf;
 const sb = Number(sbSlider.value); sbLabel.textContent = sb;
 const eta = Number(etaSlider.value); etaLabel.textContent = eta;
 const pattern = makePattern(w);
 // forward kernel
 const {kernel: kf, radius: rf} = gaussian1d(sf);
 const {kernel: kb, radius: rb} = gaussian1d(sb);
 const forwardComp = convolve(pattern, kf, rf).map(v=>v*(1-eta)*doseScale);
 const backComp = convolve(pattern, kb, rb).map(v=>v*eta*doseScale);
 const total = new Float64Array(N);
 for(let i=0;i<N;i++) total[i]=forwardComp[i]+backComp[i];
 updateChart(total, pattern.map(v=>v*doseScale), forwardComp, backComp);

}

// --- events --- [widthSlider, doseInput, sfSlider, sbSlider, etaSlider].forEach(el=>el.addEventListener('input',computeAndRender)); [showPattern, showForward, showBack].forEach(el=>el.addEventListener('change',computeAndRender)); resetBtn.addEventListener('click',()=>{

 widthSlider.value=100; doseInput.value=1; sfSlider.value=5; sbSlider.value=200; etaSlider.value=0.4;
 computeAndRender();

});

// initial render computeAndRender(); </script> </body> </html>