smoke-index/et-matrix.html

348 lines
12 KiB
HTML
Raw Normal View History

2026-07-18 10:10:38 +02:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Evapotranspiration Matrix | Arthur Ibay</title>
<style>
:root {
--bg: #1a1a1a;
--panel: #252525;
--text: #e0e0e0;
--accent: #00ff88;
--border: #444;
--font: 'Courier New', monospace;
}
* { box-sizing: border-box; }
body {
background-color: var(--bg);
color: var(--text);
font-family: var(--font);
line-height: 1.5;
margin: 0;
padding: 20px;
max-width: 900px;
margin: 0 auto;
}
header {
border-bottom: 2px solid var(--accent);
padding-bottom: 20px;
margin-bottom: 40px;
text-align: center;
}
.hero-img {
width: 100%;
max-width: 600px;
height: 300px;
object-fit: cover;
border-radius: 8px;
margin: 0 auto 30px auto;
display: block;
filter: contrast(1.2) saturate(0.8);
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}
h1 {
color: var(--accent);
font-size: 2.5em;
margin: 0;
letter-spacing: -1px;
}
h2 {
color: var(--accent);
font-size: 1.5em;
margin-top: 30px;
border-left: 4px solid var(--accent);
padding-left: 15px;
text-align: left;
}
.matrix-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
margin: 40px 0;
}
.input-panel {
background: var(--panel);
padding: 25px;
border-radius: 8px;
border: 1px solid var(--border);
}
.output-panel {
background: #000;
padding: 25px;
border-radius: 8px;
border: 1px solid var(--accent);
position: relative;
overflow: hidden;
}
.output-panel::before {
content: "";
position: absolute;
top: 0; left: 0; right: 0; height: 2px;
background: linear-gradient(90deg, transparent, var(--accent), transparent);
animation: scanline 4s infinite linear;
}
@keyframes scanline {
0% { top: 0; }
100% { top: 100%; }
}
label {
display: block;
margin-bottom: 8px;
color: var(--accent);
font-size: 0.9em;
text-transform: uppercase;
letter-spacing: 1px;
}
input[type="number"], select {
width: 100%;
background: #111;
border: 1px solid var(--border);
color: var(--accent);
padding: 10px;
font-family: var(--font);
font-size: 1em;
margin-bottom: 20px;
outline: none;
}
input:focus, select:focus {
border-color: var(--accent);
box-shadow: 0 0 10px rgba(0, 255, 136, 0.2);
}
button {
width: 100%;
background: var(--accent);
color: #000;
border: none;
padding: 15px;
font-family: var(--font);
font-weight: bold;
font-size: 1.1em;
cursor: pointer;
text-transform: uppercase;
letter-spacing: 2px;
transition: all 0.2s;
}
button:hover {
background: #fff;
box-shadow: 0 0 20px var(--accent);
}
.result-row {
display: flex;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid #333;
}
.result-val {
color: var(--accent);
font-weight: bold;
}
.data-source {
margin-top: 40px;
font-size: 0.8em;
opacity: 0.6;
border-top: 1px solid #333;
padding-top: 10px;
}
.spec-table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
.spec-table th, .spec-table td {
border: 1px solid #333;
padding: 10px;
text-align: left;
}
.spec-table th {
background: #111;
color: var(--accent);
}
.spec-table tr:hover {
background: #1a1a1a;
}
</style>
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
</head>
<body>
<header>
<img src="https://images.pexels.com/photos/11506881/pexels-photo-11506881.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"
alt="Cracked earth awaiting rain"
class="hero-img">
<h1>Evapotranspiration Matrix</h1>
<p>FAO-56 Penman-Monteith Implementation<br>Salt Lake City Baseline</p>
</header>
<section>
<h2>Input Parameters</h2>
<div class="matrix-grid">
<div class="input-panel">
<label>Air Temperature (°C)</label>
<input type="number" id="temp" placeholder="25.0" step="0.1">
<label>Relative Humidity (%)</label>
<input type="number" id="rh" placeholder="45" step="1">
<label>Wind Speed (m/s) @ 2m</label>
<input type="number" id="wind" placeholder="2.5" step="0.1">
<label>Solar Radiation (MJ/m²/day)</label>
<input type="number" id="rad" placeholder="20.5" step="0.1">
<label>Crop Coefficient (Kc)</label>
<select id="crop">
<option value="0.3">Alfalfa (Initial)</option>
<option value="1.15">Alfalfa (Mid-Season)</option>
<option value="0.9">Corn (Full Season)</option>
<option value="0.65">Lettuce (Early)</option>
<option value="1.2">Tomato (Peak)</option>
<option value="1.0">Reference Grass</option>
</select>
<button onclick="calculateET()">Compute Yield Loss</button>
</div>
<div class="output-panel">
<div class="result-row">
<span>Reference ET₀ (mm/day)</span>
<span class="result-val" id="res-et0">--.--</span>
</div>
<div class="result-row">
<span>Crop ETc (mm/day)</span>
<span class="result-val" id="res-etc">--.--</span>
</div>
<div class="result-row">
<span>Water Demand (L/m²/day)</span>
<span class="result-val" id="res-liters">--.--</span>
</div>
<div class="result-row">
<span>Vapor Pressure Deficit (kPa)</span>
<span class="result-val" id="res-vpd">--.--</span>
</div>
<div style="margin-top: 20px; border-top: 1px dashed #444; padding-top: 10px;">
<small>Status: <span id="status-text" style="color: #666">AWAITING INPUT</span></small>
</div>
</div>
</div>
</section>
<section>
<h2>Technical Specifications</h2>
<table class="spec-table">
<thead>
<tr>
<th>Parameter</th>
<th>Symbol</th>
<th>Units</th>
<th>Source</th>
</tr>
</thead>
<tbody>
<tr>
<td>Slope Vapor Pressure Curve</td>
<td>Δ</td>
<td>kPa °C⁻¹</td>
<td>Tetens Eq.</td>
</tr>
<tr>
<td>Psychrometric Constant</td>
<td>γ</td>
<td>kPa °C⁻¹</td>
<td>Standard Atmosphere</td>
</tr>
<tr>
<td>Net Radiation</td>
<td>Rₙ</td>
<td>MJ m⁻² day⁻¹</td>
<td>Allen et al. (1998)</td>
</tr>
<tr>
<td>Soil Heat Flux</td>
<td>G</td>
<td>MJ m⁻² day⁻¹</td>
<td>Daily Avg ≈ 0</td>
</tr>
</tbody>
</table>
<div class="data-source">
<p><strong>Grounded In:</strong> FAO Irrigation and Drainage Paper 56.<br>
<strong>Calibrated For:</strong> Utah Valley Microclimates (40°N, 111°W).</p>
<p style="opacity: 0.5; font-size: 0.7em;">This tool calculates potential evapotranspiration using the standardized Penman-Monteith equation. It does not predict poetry. It predicts thirst.</p>
</div>
</section>
<script>
// Constants
const R = 8.314; // J/mol·K
const M_w = 18.015; // g/mol
function calculateET() {
const T = parseFloat(document.getElementById('temp').value);
const RH = parseFloat(document.getElementById('rh').value);
const u2 = parseFloat(document.getElementById('wind').value);
const Rs = parseFloat(document.getElementById('rad').value);
const Kc = parseFloat(document.getElementById('crop').value);
if (isNaN(T) || isNaN(RH) || isNaN(u2) || isNaN(Rs)) {
document.getElementById('status-text').innerText = "ERROR: MISSING VARIABLES";
return;
}
document.getElementById('status-text').innerText = "COMPUTATION COMPLETE";
// 1. Saturation Vapor Pressure (Tetens Equation)
// es = 0.6108 * exp((17.27 * T) / (T + 237.3))
const es = 0.6108 * Math.exp((17.27 * T) / (T + 237.3));
// 2. Slope of vapor pressure curve (delta)
const delta = (4098 * es) / Math.pow((T + 237.3), 2);
// 3. Actual Vapor Pressure
const ea = es * (RH / 100);
// 4. Vapor Pressure Deficit
const vpd = es - ea;
// 5. Psychrometric constant (gamma)
// gamma = (Cp * P) / (epsilon * lambda)
// Simplified for sea level: gamma = 0.665 * 10^-3 kPa/K
const gamma = 0.000665;
// 6. Net Radiation (Rn)
// Approximation: Rn = (1 - alpha) * Rs - outgoing LW
// alpha (albedo) approx 0.23 for grass
// Outgoing LW simplified: sigma * T^4 * emissivity
// We'll use a simplified conversion factor for daily MJ -> mm H2O energy equiv
const albedo = 0.23;
const Rn = (Rs * (1 - albedo)) * 0.9; // Rough adjustment
// 7. Soil Heat Flux (G) - negligible for daily avg
const G = 0;
// 8. Penman-Monteith Numerator
// delta * (Rn - G) + rho * Cp * (es - ea) / r_a
// Simplified aerodynamic term: 900 / (T + 273) * u2 * (es - ea)
const aeroTerm = (900 / (T + 273)) * u2 * vpd;
const numerator = (delta * Rn) + aeroTerm;
// 9. Denominator
// delta + gamma * (1 + 0.34 * u2)
const denominator = delta + (gamma * (1 + 0.34 * u2));
// 10. ET0 (mm/day)
const ET0 = numerator / denominator;
// 11. Crop ETc
const ETc = ET0 * Kc;
// Update UI
document.getElementById('res-et0').innerText = ET0.toFixed(2);
document.getElementById('res-etc').innerText = ETc.toFixed(2);
document.getElementById('res-liters').innerText = ETc.toFixed(2); // 1mm = 1L/m2
document.getElementById('res-vpd').innerText = vpd.toFixed(2);
}
</script>
</body>
</html>