348 lines
12 KiB
HTML
348 lines
12 KiB
HTML
|
|
<!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>
|