drude-smith-test1 / index.html
holyhigh666's picture
Rename DrudeSmith_fromGemini.html to index.html
a2b43d8 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interactive Drude-Smith Model Visualization</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Plotly.js -->
<script src='https://cdn.plot.ly/plotly-latest.min.js'></script>
<!-- Font Awesome for Icons (Optional, but nice for UI) -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<style>
/* Custom Styles (if needed) */
.slider-thumb::-webkit-slider-thumb {
appearance: none; /* Override default look */
width: 16px; /* Set a specific slider handle width */
height: 16px; /* Set a specific slider handle height */
background: #3b82f6; /* Blue background */
border-radius: 50%; /* Circular thumb */
cursor: pointer; /* Cursor on hover */
}
.slider-thumb::-moz-range-thumb {
width: 16px;
height: 16px;
background: #3b82f6;
border-radius: 50%;
cursor: pointer;
border: none; /* Remove Firefox border */
}
/* Style for active state */
.tab-button.active {
border-color: #3b82f6;
color: #3b82f6;
font-weight: 600;
}
/* Minor layout adjustments */
#plotDiv {
min-height: 500px; /* Ensure plot has enough vertical space */
}
</style>
</head>
<body class="bg-gradient-to-br from-gray-100 to-blue-100 font-sans antialiased">
<div class="container mx-auto p-4 md:p-8">
<header class="text-center mb-8">
<h1 class="text-3xl md:text-4xl font-bold text-gray-800 mb-2">Drude-Smith Model Visualization</h1>
<p class="text-md md:text-lg text-gray-600">Explore the complex conductivity σ*(ω) = σ'(ω) + iσ''(ω)</p>
</header>
<div class="flex flex-col md:flex-row gap-8">
<!-- Controls Panel -->
<aside class="md:w-1/3 lg:w-1/4 bg-white p-6 rounded-xl shadow-lg border border-gray-200">
<h2 class="text-xl font-semibold text-gray-700 mb-6 border-b pb-2">Parameters</h2>
<div class="space-y-5">
<!-- DC Conductivity (sigma0) -->
<div>
<label for="sigma0" class="flex items-center text-sm font-medium text-gray-700 mb-1">
<i class="fas fa-plug fa-fw mr-2 text-blue-500"></i> DC Conductivity (σ₀) <span class="ml-auto font-mono text-blue-600" id="sigma0Value">1000</span> S/m
</label>
<input type="range" id="sigma0" min="1" max="10000" value="1000" step="1" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer slider-thumb range-lg dark:bg-gray-700">
</div>
<!-- Relaxation Time (tau0) -->
<div>
<label for="tau0" class="flex items-center text-sm font-medium text-gray-700 mb-1">
<i class="fas fa-stopwatch fa-fw mr-2 text-green-500"></i> Relaxation Time (τ₀) <span class="ml-auto font-mono text-green-600" id="tau0Value">20</span> fs
</label>
<input type="range" id="tau0" min="1" max="200" value="20" step="1" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer slider-thumb range-lg dark:bg-gray-700">
</div>
<!-- Backscattering Parameter (c1) -->
<div>
<label for="c1" class="flex items-center text-sm font-medium text-gray-700 mb-1">
<i class="fas fa-arrow-left fa-fw mr-2 text-red-500"></i> 1st Order Parameter (c₁) <span class="ml-auto font-mono text-red-600" id="c1Value">-0.5</span>
</label>
<input type="range" id="c1" min="-1" max="0" value="-0.5" step="0.01" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer slider-thumb range-lg dark:bg-gray-700">
<p class="text-xs text-gray-500 mt-1">Controls first scattering event memory (-1: full backscattering, 0: Drude).</p>
</div>
<!-- Second Order Parameter (c2) -->
<div>
<label for="c2" class="flex items-center text-sm font-medium text-gray-700 mb-1">
<i class="fas fa-arrows-left-right fa-fw mr-2 text-purple-500"></i> 2nd Order Parameter (c₂) <span class="ml-auto font-mono text-purple-600" id="c2Value">0.1</span>
</label>
<input type="range" id="c2" min="-0.5" max="0.5" value="0.1" step="0.01" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer slider-thumb range-lg dark:bg-gray-700">
<p class="text-xs text-gray-500 mt-1">Introduces higher-order scattering effects.</p>
</div>
<!-- Model Selection -->
<div class="pt-4 border-t mt-6">
<h3 class="text-sm font-medium text-gray-700 mb-2">Models to Display:</h3>
<div class="flex flex-wrap gap-2">
<label class="inline-flex items-center cursor-pointer">
<input type="checkbox" id="showDrude" class="form-checkbox h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" checked>
<span class="ml-2 text-sm text-gray-600">Drude (c₁=0, c₂=0)</span>
</label>
<label class="inline-flex items-center cursor-pointer">
<input type="checkbox" id="showDS1" class="form-checkbox h-4 w-4 text-red-600 border-gray-300 rounded focus:ring-red-500" checked>
<span class="ml-2 text-sm text-gray-600">Drude-Smith 1st (c₁)</span>
</label>
<label class="inline-flex items-center cursor-pointer">
<input type="checkbox" id="showDS2" class="form-checkbox h-4 w-4 text-purple-600 border-gray-300 rounded focus:ring-purple-500">
<span class="ml-2 text-sm text-gray-600">Drude-Smith 2nd (c₁, c₂)</span>
</label>
</div>
</div>
<!-- Plot Type Selection -->
<div class="pt-4 border-t mt-6">
<h3 class="text-sm font-medium text-gray-700 mb-2">Plot Type:</h3>
<div class="flex border border-gray-300 rounded-md overflow-hidden">
<button id="plotConductivityBtn" class="tab-button flex-1 py-1 px-3 text-sm text-gray-600 border-r border-gray-300 focus:outline-none active">
Conductivity (σ)
</button>
<button id="plotPermittivityBtn" class="tab-button flex-1 py-1 px-3 text-sm text-gray-600 focus:outline-none">
Permittivity (ε)
</button>
</div>
<div id="epsilonInfControls" class="mt-3 hidden">
<label for="epsilonInf" class="flex items-center text-sm font-medium text-gray-700 mb-1">
<i class="fas fa-infinity fa-fw mr-2 text-indigo-500"></i> High-Freq. Permittivity (ε<sub></sub>) <span class="ml-auto font-mono text-indigo-600" id="epsilonInfValue">1.0</span>
</label>
<input type="range" id="epsilonInf" min="0.1" max="20" value="1.0" step="0.1" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer slider-thumb range-lg dark:bg-gray-700">
</div>
</div>
</div>
</aside>
<!-- Plot Area -->
<main class="md:w-2/3 lg:w-3/4 bg-white p-4 rounded-xl shadow-lg border border-gray-200 flex flex-col">
<div id="plotDiv" class="flex-grow">
<!-- Plotly chart will be rendered here -->
</div>
<div class="text-xs text-center text-gray-500 mt-2">
Frequency range: 1 GHz to 100 THz (log scale)
</div>
</main>
</div>
<!-- Explanation Section (Optional) -->
<section class="mt-10 p-6 bg-white rounded-xl shadow-lg border border-gray-200">
<h3 class="text-lg font-semibold text-gray-700 mb-3">Model Explanation</h3>
<div class="text-sm text-gray-600 space-y-2">
<p>The Drude model describes free electron conductivity. The Drude-Smith model extends this by incorporating carrier localization or preferential back-scattering, common in disordered materials or nanostructures.</p>
<p><strong>Complex Conductivity:</strong> σ*(ω) = σ'(ω) + iσ''(ω)</p>
<p><strong>Drude Model:</strong> σ*(ω) = σ₀ / (1 - iωτ₀)</p>
<p><strong>Drude-Smith (1st Order):</strong> σ*(ω) = [σ₀ / (1 - iωτ₀)] * [1 + c₁ / (1 - iωτ₀)]</p>
<p><strong>Drude-Smith (2nd Order):</strong> σ*(ω) = [σ₀ / (1 - iωτ₀)] * [1 + c₁ / (1 - iωτ₀) + c₂ / (1 - iωτ₀)²]</p>
<p>Where: σ₀ is DC conductivity, τ₀ is relaxation time, ω is angular frequency (2πf), c₁ (-1 ≤ c₁ ≤ 0) is the first scattering persistence parameter, and c₂ accounts for subsequent scattering memory.</p>
<p><strong>Complex Permittivity:</strong> ε*(ω) = ε<sub></sub> + i σ*(ω) / (ωε₀), where ε<sub></sub> is the high-frequency permittivity constant and ε₀ is the vacuum permittivity (≈ 8.854 × 10⁻¹² F/m).</p>
</div>
</section>
</div>
<script>
// --- DOM Elements ---
const sigma0Slider = document.getElementById('sigma0');
const tau0Slider = document.getElementById('tau0');
const c1Slider = document.getElementById('c1');
const c2Slider = document.getElementById('c2');
const epsilonInfSlider = document.getElementById('epsilonInf');
const sigma0ValueSpan = document.getElementById('sigma0Value');
const tau0ValueSpan = document.getElementById('tau0Value');
const c1ValueSpan = document.getElementById('c1Value');
const c2ValueSpan = document.getElementById('c2Value');
const epsilonInfValueSpan = document.getElementById('epsilonInfValue');
const showDrudeCheckbox = document.getElementById('showDrude');
const showDS1Checkbox = document.getElementById('showDS1');
const showDS2Checkbox = document.getElementById('showDS2');
const plotConductivityBtn = document.getElementById('plotConductivityBtn');
const plotPermittivityBtn = document.getElementById('plotPermittivityBtn');
const epsilonInfControls = document.getElementById('epsilonInfControls');
const plotDiv = document.getElementById('plotDiv');
// --- Constants ---
const EPSILON0 = 8.854187817e-12; // Vacuum permittivity (F/m)
// --- State ---
let currentPlotType = 'conductivity'; // 'conductivity' or 'permittivity'
// --- Complex Number Math ---
// Simple complex number representation: { re: real_part, im: imaginary_part }
function complexAdd(z1, z2) {
return { re: z1.re + z2.re, im: z1.im + z2.im };
}
function complexSubtract(z1, z2) {
return { re: z1.re - z2.re, im: z1.im - z2.im };
}
function complexMultiply(z1, z2) {
return {
re: z1.re * z2.re - z1.im * z2.im,
im: z1.re * z2.im + z1.im * z2.re
};
}
function complexDivide(z1, z2) {
const denominator = z2.re * z2.re + z2.im * z2.im;
if (denominator === 0) return { re: NaN, im: NaN }; // Avoid division by zero
return {
re: (z1.re * z2.re + z1.im * z2.im) / denominator,
im: (z1.im * z2.re - z1.re * z2.im) / denominator
};
}
function complexScalarMultiply(scalar, z) {
return { re: scalar * z.re, im: scalar * z.im };
}
// --- Model Calculations ---
function calculateModels(omega, sigma0, tau0, c1, c2) {
const wtau = omega * tau0;
const denominator_term = { re: 1, im: -wtau }; // (1 - iωτ₀)
// Drude Model Calculation
const sigma_drude = complexDivide({ re: sigma0, im: 0 }, denominator_term);
// Drude-Smith 1st Order
// σ_ds1 = σ_drude * (1 + c1 / (1 - iωτ₀))
// = σ_drude * (1 + c1 * conj(denominator_term) / |denominator_term|^2)
// Let term1 = c1 / (1 - iωτ₀)
const term1_ds1 = complexDivide({ re: c1, im: 0 }, denominator_term);
const bracket_ds1 = complexAdd({ re: 1, im: 0 }, term1_ds1);
const sigma_ds1 = complexMultiply(sigma_drude, bracket_ds1);
// Drude-Smith 2nd Order
// σ_ds2 = σ_ds1 + σ_drude * (c2 / (1 - iωτ₀)^2)
// Let term2 = c2 / (1 - iωτ₀)^2
const denominator_term_sq = complexMultiply(denominator_term, denominator_term);
const term2_ds2 = complexDivide({ re: c2, im: 0 }, denominator_term_sq);
const addition_ds2 = complexMultiply(sigma_drude, term2_ds2);
const sigma_ds2 = complexAdd(sigma_ds1, addition_ds2);
return {
drude: sigma_drude,
ds1: sigma_ds1,
ds2: sigma_ds2
};
}
// --- Plotting ---
function updatePlot() {
// Get current parameter values
const sigma0 = parseFloat(sigma0Slider.value);
const tau0_fs = parseFloat(tau0Slider.value);
const c1 = parseFloat(c1Slider.value);
const c2 = parseFloat(c2Slider.value);
const epsilonInf = parseFloat(epsilonInfSlider.value);
// Convert tau0 from fs to s
const tau0 = tau0_fs * 1e-15;
// Update value displays
sigma0ValueSpan.textContent = sigma0.toFixed(0);
tau0ValueSpan.textContent = tau0_fs.toFixed(0);
c1ValueSpan.textContent = c1.toFixed(2);
c2ValueSpan.textContent = c2.toFixed(2);
epsilonInfValueSpan.textContent = epsilonInf.toFixed(1);
// Frequency range (log scale)
const numPoints = 200;
const freq_min_hz = 1e9; // 1 GHz
const freq_max_hz = 100e12; // 100 THz
const log_freq_min = Math.log10(freq_min_hz);
const log_freq_max = Math.log10(freq_max_hz);
const freq_hz = [];
const omega = [];
for (let i = 0; i < numPoints; i++) {
const log_f = log_freq_min + (log_freq_max - log_freq_min) * i / (numPoints - 1);
const f = Math.pow(10, log_f);
freq_hz.push(f);
omega.push(2 * Math.PI * f);
}
// Calculate model data
const sigma_drude_real = []; const sigma_drude_imag = [];
const sigma_ds1_real = []; const sigma_ds1_imag = [];
const sigma_ds2_real = []; const sigma_ds2_imag = [];
const epsilon_drude_real = []; const epsilon_drude_imag = [];
const epsilon_ds1_real = []; const epsilon_ds1_imag = [];
const epsilon_ds2_real = []; const epsilon_ds2_imag = [];
for (let i = 0; i < numPoints; i++) {
const w = omega[i];
const models = calculateModels(w, sigma0, tau0, c1, c2);
// Conductivity Data
sigma_drude_real.push(models.drude.re);
sigma_drude_imag.push(models.drude.im);
sigma_ds1_real.push(models.ds1.re);
sigma_ds1_imag.push(models.ds1.im);
sigma_ds2_real.push(models.ds2.re);
sigma_ds2_imag.push(models.ds2.im);
// Permittivity Data: ε*(ω) = ε_inf + i * σ*(ω) / (ω * ε₀)
// i * σ*(ω) = i * (σ' + iσ'') = iσ' - σ'' = -σ'' + iσ'
// So, ε*(ω) = ε_inf + (-σ'' + iσ') / (ω * ε₀)
// ε'(ω) = ε_inf - σ''(ω) / (ω * ε₀)
// ε''(ω) = σ'(ω) / (ω * ε₀)
const factor = w * EPSILON0;
if (factor > 1e-20) { // Avoid division by zero / very small numbers at low freq if w=0
epsilon_drude_real.push(epsilonInf - models.drude.im / factor);
epsilon_drude_imag.push(models.drude.re / factor);
epsilon_ds1_real.push(epsilonInf - models.ds1.im / factor);
epsilon_ds1_imag.push(models.ds1.re / factor);
epsilon_ds2_real.push(epsilonInf - models.ds2.im / factor);
epsilon_ds2_imag.push(models.ds2.re / factor);
} else { // Handle low frequency limit or w=0 case
// At w=0, sigma'' -> 0, sigma' -> sigma0. Epsilon'' diverges (sigma'/w*eps0)
// Epsilon' should approach some limit related to sigma''/w, which involves derivatives, or simply becomes very large negative if sigma'' starts positive.
// For practical plotting, push NaN or handle appropriately. Let's push NaN for simplicity near zero freq.
epsilon_drude_real.push(NaN); epsilon_drude_imag.push(NaN);
epsilon_ds1_real.push(NaN); epsilon_ds1_imag.push(NaN);
epsilon_ds2_real.push(NaN); epsilon_ds2_imag.push(NaN);
}
}
// Prepare Plotly traces
const traces = [];
const showDrude = showDrudeCheckbox.checked;
const showDS1 = showDS1Checkbox.checked;
const showDS2 = showDS2Checkbox.checked;
const freq_display = freq_hz.map(f => f / 1e9); // Display frequency in GHz
if (currentPlotType === 'conductivity') {
if (showDrude) {
traces.push({ x: freq_display, y: sigma_drude_real, mode: 'lines', name: "σ' (Drude)", line: { color: 'rgb(59, 130, 246)', width: 2 } }); // blue-500
traces.push({ x: freq_display, y: sigma_drude_imag, mode: 'lines', name: "σ'' (Drude)", line: { color: 'rgb(59, 130, 246)', dash: 'dash', width: 2 } });
}
if (showDS1) {
traces.push({ x: freq_display, y: sigma_ds1_real, mode: 'lines', name: "σ' (DS1)", line: { color: 'rgb(239, 68, 68)', width: 2 } }); // red-500
traces.push({ x: freq_display, y: sigma_ds1_imag, mode: 'lines', name: "σ'' (DS1)", line: { color: 'rgb(239, 68, 68)', dash: 'dash', width: 2 } });
}
if (showDS2) {
traces.push({ x: freq_display, y: sigma_ds2_real, mode: 'lines', name: "σ' (DS2)", line: { color: 'rgb(168, 85, 247)', width: 2 } }); // purple-500
traces.push({ x: freq_display, y: sigma_ds2_imag, mode: 'lines', name: "σ'' (DS2)", line: { color: 'rgb(168, 85, 247)', dash: 'dash', width: 2 } });
}
} else { // Permittivity
if (showDrude) {
traces.push({ x: freq_display, y: epsilon_drude_real, mode: 'lines', name: "ε' (Drude)", line: { color: 'rgb(59, 130, 246)', width: 2 } });
traces.push({ x: freq_display, y: epsilon_drude_imag, mode: 'lines', name: "ε'' (Drude)", line: { color: 'rgb(59, 130, 246)', dash: 'dash', width: 2 } });
}
if (showDS1) {
traces.push({ x: freq_display, y: epsilon_ds1_real, mode: 'lines', name: "ε' (DS1)", line: { color: 'rgb(239, 68, 68)', width: 2 } });
traces.push({ x: freq_display, y: epsilon_ds1_imag, mode: 'lines', name: "ε'' (DS1)", line: { color: 'rgb(239, 68, 68)', dash: 'dash', width: 2 } });
}
if (showDS2) {
traces.push({ x: freq_display, y: epsilon_ds2_real, mode: 'lines', name: "ε' (DS2)", line: { color: 'rgb(168, 85, 247)', width: 2 } });
traces.push({ x: freq_display, y: epsilon_ds2_imag, mode: 'lines', name: "ε'' (DS2)", line: { color: 'rgb(168, 85, 247)', dash: 'dash', width: 2 } });
}
}
// Plotly Layout
const yAxisTitle = currentPlotType === 'conductivity' ? 'Conductivity (S/m)' : 'Relative Permittivity';
const layout = {
title: `Complex ${currentPlotType.charAt(0).toUpperCase() + currentPlotType.slice(1)} vs Frequency`,
xaxis: {
title: 'Frequency (GHz)',
type: 'log',
autorange: true,
// range: [Math.log10(freq_min_hz / 1e9), Math.log10(freq_max_hz / 1e9)], // Use GHz for range
tickformat: '.1s', // Format ticks like 1G, 10G, 100G, 1T, 10T etc.
exponentformat: 'SI'
},
yaxis: {
title: yAxisTitle,
autorange: true,
exponentformat: 'SI' // Use SI prefix for large/small numbers
// Consider 'type: log' for y-axis if needed, but linear shows negative values better.
},
margin: { l: 60, r: 30, b: 50, t: 50 },
hovermode: 'x unified', // Show hover info for all traces at a given x
legend: {
// x: 1.05,
// y: 1,
traceorder: 'normal', // Keep legend order same as trace order
font: {
size: 10
},
bgcolor: 'rgba(255,255,255,0.8)' // Semi-transparent background
},
showlegend: true,
plot_bgcolor: 'rgba(249, 250, 251, 0.8)', // Light background inside plot area
paper_bgcolor: 'rgba(255, 255, 255, 0)', // Transparent background outside plot area
};
// Use Plotly.react for efficient updates
Plotly.react(plotDiv, traces, layout, {responsive: true});
}
// --- Event Listeners ---
[sigma0Slider, tau0Slider, c1Slider, c2Slider, epsilonInfSlider].forEach(slider => {
slider.addEventListener('input', updatePlot);
});
[showDrudeCheckbox, showDS1Checkbox, showDS2Checkbox].forEach(checkbox => {
checkbox.addEventListener('change', updatePlot);
});
plotConductivityBtn.addEventListener('click', () => {
if (currentPlotType !== 'conductivity') {
currentPlotType = 'conductivity';
plotConductivityBtn.classList.add('active', 'bg-blue-50');
plotPermittivityBtn.classList.remove('active', 'bg-blue-50');
epsilonInfControls.classList.add('hidden');
updatePlot();
}
});
plotPermittivityBtn.addEventListener('click', () => {
if (currentPlotType !== 'permittivity') {
currentPlotType = 'permittivity';
plotPermittivityBtn.classList.add('active', 'bg-blue-50');
plotConductivityBtn.classList.remove('active', 'bg-blue-50');
epsilonInfControls.classList.remove('hidden');
updatePlot();
}
});
// --- Initial Plot ---
// Ensure active class is set correctly on initial load
plotConductivityBtn.classList.add('active', 'bg-blue-50');
updatePlot();
// Optional: Resize plot on window resize
window.addEventListener('resize', () => {
Plotly.Plots.resize(plotDiv);
});
</script>
</body>
</html>