precipitation generation - minor fix

This commit is contained in:
Azgaar 2021-08-21 23:05:15 +03:00
parent 01116addfc
commit 0de5b7c6cd

59
main.js
View file

@ -957,27 +957,32 @@ function calculateTemperatures() {
function generatePrecipitation() {
TIME && console.time("generatePrecipitation");
prec.selectAll("*").remove();
const cells = grid.cells;
const {cells, cellsX, cellsY} = grid;
cells.prec = new Uint8Array(cells.i.length); // precipitation array
const modifier = precInput.value / 100; // user's input
const cellsX = grid.cellsX,
cellsY = grid.cellsY;
const {winds} = options;
const MAX_PASSABLE_ELEVATION = 85;
let westerly = [],
easterly = [],
southerly = 0,
northerly = 0;
{
// latitude bands
// x4 = 0-5 latitude: wet through the year (rising zone)
// x2 = 5-20 latitude: wet summer (rising zone), dry winter (sinking zone)
// x1 = 20-30 latitude: dry all year (sinking zone)
// x2 = 30-50 latitude: wet winter (rising zone), dry summer (sinking zone)
// x3 = 50-60 latitude: wet all year (rising zone)
// x2 = 60-70 latitude: wet summer (rising zone), dry winter (sinking zone)
// x1 = 70-90 latitude: dry all year (sinking zone)
}
const lalitudeModifier = [4, 2, 2, 2, 1, 1, 2, 2, 2, 2, 3, 3, 2, 2, 1, 1, 1, 0.5]; // by 5d step
const isWest = tier => winds[tier] > 40 && winds[tier] < 140;
const isEast = tier => winds[tier] > 220 && winds[tier] < 320;
const isSouth = tier => winds[tier] > 100 && winds[tier] < 260;
const isNorth = tier => winds[tier] > 280 && winds[tier] < 80;
// latitude bands info
// x4 = 0-5 latitude: wet through the year (rising zone)
// x2 = 5-20 latitude: wet summer (rising zone), dry winter (sinking zone)
// x1 = 20-30 latitude: dry all year (sinking zone)
// x2 = 30-50 latitude: wet winter (rising zone), dry summer (sinking zone)
// x3 = 50-60 latitude: wet all year (rising zone)
// x2 = 60-70 latitude: wet summer (rising zone), dry winter (sinking zone)
// x1 = 70-90 latitude: dry all year (sinking zone)
const lalitudeModifier = [4, 2, 2, 2, 1, 1, 2, 2, 2, 2, 3, 3, 2, 2, 1, 1, 1, 0.5];
// difine wind directions based on cells latitude and prevailing winds there
d3.range(0, cells.i.length, cellsX).forEach(function (c, i) {
@ -985,15 +990,17 @@ function generatePrecipitation() {
const band = ((Math.abs(lat) - 1) / 5) | 0;
const latMod = lalitudeModifier[band];
const tier = (Math.abs(lat - 89) / 30) | 0; // 30d tiers from 0 to 5 from N to S
if (options.winds[tier] > 40 && options.winds[tier] < 140) westerly.push([c, latMod, tier]);
else if (options.winds[tier] > 220 && options.winds[tier] < 320) easterly.push([c + cellsX - 1, latMod, tier]);
if (options.winds[tier] > 100 && options.winds[tier] < 260) northerly++;
else if (options.winds[tier] > 280 || options.winds[tier] < 80) southerly++;
if (isWest(tier)) westerly.push([c, latMod, tier]);
else if (isEast(tier)) easterly.push([c + cellsX - 1, latMod, tier]);
if (isSouth(tier)) northerly++;
if (isNorth(tier)) southerly++;
});
// distribute winds by direction
if (westerly.length) passWind(westerly, 120 * modifier, 1, cellsX);
if (easterly.length) passWind(easterly, 120 * modifier, -1, cellsX);
const vertT = southerly + northerly;
if (northerly) {
const bandN = ((Math.abs(mapCoordinates.latN) - 1) / 5) | 0;
@ -1001,6 +1008,7 @@ function generatePrecipitation() {
const maxPrecN = (northerly / vertT) * 60 * modifier * latModN;
passWind(d3.range(0, cellsX, 1), maxPrecN, cellsX, cellsY);
}
if (southerly) {
const bandS = ((Math.abs(mapCoordinates.latS) - 1) / 5) | 0;
const latModS = mapCoordinates.latT > 60 ? d3.mean(lalitudeModifier) : lalitudeModifier[bandS];
@ -1010,18 +1018,21 @@ function generatePrecipitation() {
function passWind(source, maxPrec, next, steps) {
const maxPrecInit = maxPrec;
for (let first of source) {
if (first[0]) {
maxPrec = Math.min(maxPrecInit * first[1], 255);
first = first[0];
}
let humidity = maxPrec - cells.h[first]; // initial water amount
if (humidity <= 0) continue; // if first cell in row is too elevated cosdired wind dry
for (let s = 0, current = first; s < steps; s++, current += next) {
// no flux on permafrost
if (cells.temp[current] < -5) continue;
// water cell
if (cells.temp[current] < -5) continue; // no flux in permafrost
if (cells.h[current] < 20) {
// water cell
if (cells.h[current + next] >= 20) {
cells.prec[current + next] += Math.max(humidity / rand(10, 20), 1); // coastal precipitation
} else {
@ -1032,16 +1043,16 @@ function generatePrecipitation() {
}
// land cell
const precipitation = getPrecipitation(humidity, current, next);
const isPassable = cells.h[current + next] <= MAX_PASSABLE_ELEVATION;
const precipitation = isPassable ? getPrecipitation(humidity, current, next) : humidity;
cells.prec[current] += precipitation;
const evaporation = precipitation > 1.5 ? 1 : 0; // some humidity evaporates back to the atmosphere
humidity = Math.min(Math.max(humidity - precipitation + evaporation, 0), maxPrec);
humidity = isPassable ? Math.min(Math.max(humidity - precipitation + evaporation, 0), maxPrec) : 0;
}
}
}
function getPrecipitation(humidity, i, n) {
if (cells.h[i + n] > 85) return humidity; // 85 is max passable height
const normalLoss = Math.max(humidity / (10 * modifier), 1); // precipitation in normal conditions
const diff = Math.max(cells.h[i + n] - cells.h[i], 0); // difference in height
const mod = (cells.h[i + n] / 70) ** 2; // 50 stands for hills, 70 for mountains