public static double computeAvgCurrentMovements(TWorld w, TClima clima) { long i, j; long movements, count; movements = 0; count = 0; for (j = 0; j < 180; j++) { for (i = 0; i < 360; i++) { if ((clima.surfaceTransfer[i, j] != Constants.NONE) && (w.isOcean[i, j])) { movements = movements + 1; count = count + 1; } } } if (count != 0) { return(movements / count); } else { return(0); } }
public static void moveSteamDown(TClima clima, TWorld w, TSolarSurface s, int l, long i, long j) { double transferSteam, maxSteam, transferEnergy; // recalculate temperature clima.T_atmosphere[l, i, j] = statechanges.thermicGradient(w, clima, l * TMdlConst.distance_atm_layers, clima.T_atmosphere[0, i, j], i, j); if (clima.steam[l, i, j] == 0) { return; } // how much steam could stay in the upper layer l maxSteam = statechanges.maxWaterInSteam(clima, w, l, i, j); // how much steam has to be transferred down transferSteam = (clima.steam[l, i, j] - maxSteam) * (1 / TSimConst.steam_hours); if (transferSteam < 0) { return; } // energy which is given back to atmosphere transferEnergy = transferSteam * TPhysConst.grav_acc * TMdlConst.distance_atm_layers; // let's move it dowm clima.energy_atmosphere[i, j] = clima.energy_atmosphere[i, j] + transferEnergy; clima.steam[l, i, j] = clima.steam[l, i, j] - transferSteam; clima.steam[l - 1, i, j] = clima.steam[l - 1, i, j] + transferSteam; }
public static void absorbCO2(TClima clima, TWorld w, TSolarSurface s, long i, long j) { double absorption, rain_times; if (clima.isIce[i, j] || clima.co2_tons[i, j] == 0 || !statechanges.isInSunlight(i, j, s)) { return; } if (w.isOcean[i, j]) { // absorption scaled over 12 h per day and over 3 quarters of earth surface absorption = TSimConst.co2_absorption_ocean / (365 / 12 / 15 * TSimConst.degree_step) / (360 * 180 * 3 / 4); } else { // absorption scaled over 12 h per day and over 1 quarter of earth surface absorption = TSimConst.co2_absorption_vegetation / (365 / 12 / 15 * TSimConst.degree_step) / (360 * 180 * 1 / 4); // jungle absorbs more than desert rain_times = clima.rain_times[i, j]; if (rain_times > 5) { rain_times = 5; } absorption = absorption * rain_times; } clima.co2_tons[i, j] = clima.co2_tons[i, j] - absorption; if (clima.co2_tons[i, j] < 0) { clima.co2_tons[i, j] = 0; } }
public static bool isDesert(TWorld w, TClima clima, long i, long j) { double T; T = Conversion.KtoC(clima.T_ocean_terr[i, j]); return((T >= 50) && (clima.water_surface[i, j] < 1)); }
public static long computeIceCoverage(TClima clima, short direction) { long i, j; long iceCoverage; iceCoverage = 0; for (j = 0; j < 180; j++) { for (i = 0; i < 360; i++) { if (clima.isIce[i, j]) { if ((direction == Constants.NORTH) && (j < 90)) { iceCoverage = iceCoverage + 1; } else if ((direction == Constants.SOUTH) && (j >= 90)) { iceCoverage = iceCoverage + 1; } else if (direction == Constants.NONE) { iceCoverage = iceCoverage + 1; } } } } return(iceCoverage); }
public static void moveSteamUp(TClima clima, TWorld w, TSolarSurface s, int l, long i, long j) { double availableSteam, maxSteam, transferEnergy, evaporationPct; // let's compute first the temperature on the upper layer based on the thermic gradient clima.T_atmosphere[l, i, j] = statechanges.thermicGradient(w, clima, l * TMdlConst.distance_atm_layers, clima.T_atmosphere[0, i, j], i, j); // we do not add altitude here, as altitude is already in clima.T_atmosphere[0, i, j] // if there is ice on ground or no steam to push up we exit if (clima.isIce[i, j] || clima.steam[l - 1, i, j] == 0) { return; } evaporationPct = statechanges.evaporatePercentage(clima, clima.T_atmosphere[l - 1, i, j], i, j); if (evaporationPct == 0) { return; } // how much steam could stay in the upper layer l? maxSteam = statechanges.maxWaterInSteam(clima, w, l, i, j); // how much steam is available for transfer availableSteam = Math.Min(clima.steam[l - 1, i, j], maxSteam) * (1 / TSimConst.steam_hours) * evaporationPct; // is there enough energy to perform the transfer to the upper layer? transferEnergy = availableSteam * TPhysConst.grav_acc * TMdlConst.distance_atm_layers; if (clima.energy_atmosphere[i, j] > transferEnergy) { // let's move it up clima.energy_atmosphere[i, j] = clima.energy_atmosphere[i, j] - transferEnergy; clima.steam[l - 1, i, j] = clima.steam[l - 1, i, j] - availableSteam; clima.steam[l, i, j] = clima.steam[l, i, j] + availableSteam; } }
public static void computeAvgWaterSurface(TWorld w, TClima clima) { long i, j, count; double avg; for (j = 0; j < 180; j++) { avg = 0; count = 0; for (i = 0; i < 360; i++) { if ((!w.isOcean[i, j]) && (clima.water_surface[i, j] > 0)) { avg = avg + clima.water_surface[i, j]; count++; } } if (count != 0) { clima.avgWaterSurface[j] = avg / count; } else { clima.avgWaterSurface[j] = 0; } } }
public static double thermicGradient(TWorld w, TClima clima, double elevation, double T_initial, long i, long j) { double altitude; double Result; if (elevation <= 0) { Result = T_initial; } if (elevation > TSimConst.max_atmosphere_height) { elevation = TSimConst.max_atmosphere_height; } if (clima.humidity[i, j] < 0) { throw new Exception("Humidity is negative in thermicGradient(...)"); } Result = T_initial - Math.Abs(elevation) / 100 * (1 - clima.humidity[i, j] * (TSimConst.thermic_gradient_dry - TSimConst.thermic_gradient_wet)); // outer atmospheric layers might reach zero absolute if (Result < 0) { Result = 0; } return(Result); }
public static bool isJungle(TWorld w, TClima clima, long i, long j) { double T; T = Conversion.KtoC(clima.T_ocean_terr[i, j]); return((clima.water_surface[i, j] <= TSimConst.paint_river_pct * clima.avgWaterSurface[j]) && (T >= 25) && (T < 50) && (clima.rain_times[i, j] > 2)); }
public static void updateOutgoingEnergyOnCellGrid(TClima clima, TWorld w, TSolarSurface sSurface, double earthInclination, int i, int j) { updateTemperature(clima, w, i, j); exchangeEnergyBetweenAtmAndTerrain(clima, w, i, j); updateTemperature(clima, w, i, j); radiateEnergyIntoSpace(clima, w, i, j); updateTemperature(clima, w, i, j); }
public static void WaterOrIce(TClima clima, TWorld w, long i, long j) { clima.isIce[i, j] = (clima.T_ocean_terr[i, j] <= TPhysConst.kT_ice); if (!w.isOcean[i, j]) { clima.isIce[i, j] = clima.isIce[i, j] && (clima.water_surface[i, j] > 0); } }
public static void plotTemperature(TClima clima, TWorld w, int i, int j, bool output) { energyfunctions.updateTemperature(clima, w, i, j); if (output) { Console.WriteLine("T atmosphere : " + Conversion.KtoC(clima.T_atmosphere[0, i, j])); Console.WriteLine("T ocean/terrain : " + Conversion.KtoC(clima.T_ocean_terr[i, j])); Console.WriteLine(); } }
public static void TestConversion() { TClima clima = new TClima(); TWorld world = new TWorld(); Console.WriteLine("Init world"); initmodel.initWorld(world, ""); Console.WriteLine("Init clima"); initmodel.initClima(world, clima, 16, 16); Console.WriteLine("Test of Conversion routines"); Console.WriteLine(); Console.WriteLine("0 grad Celsius in Kelvin " + Conversion.CtoK(0)); Console.WriteLine("-273.15 grad Celsius in Kelvin " + Conversion.CtoK(-273.15)); Console.WriteLine(); Console.WriteLine("0 grad Kelvin in Celsius " + Conversion.KtoC(0)); Console.WriteLine("273.16 grad Kelvin in Celsius " + Conversion.KtoC(273.16)); Console.WriteLine("373.16 grad Kelvin in Celsius " + Conversion.KtoC(373.16)); Console.WriteLine(); Console.WriteLine("Longitude 180 deg W on grid " + Conversion.LonToX(-180)); Console.WriteLine("Longitude 179 deg W on grid " + Conversion.LonToX(-179)); Console.WriteLine("Longitude 1 deg W on grid " + Conversion.LonToX(-1)); Console.WriteLine("Longitude 0.3 deg W on grid " + Conversion.LonToX(-0.3)); Console.WriteLine("Longitude Greenwich on grid " + Conversion.LonToX(0)); Console.WriteLine("Longitude 0.3 deg E on grid " + Conversion.LonToX(0.3)); Console.WriteLine("Longitude 1 deg E on grid " + Conversion.LonToX(1)); Console.WriteLine("Longitude 179 deg E on grid " + Conversion.LonToX(179)); Console.WriteLine("Longitude 180 deg E on grid " + Conversion.LonToX(180)); Console.WriteLine(); Console.WriteLine("Latitudine North Pole on grid " + Conversion.LatToY(90)); Console.WriteLine("Latitudine 89.5 deg on grid " + Conversion.LatToY(89.3)); Console.WriteLine("Latitudine 89 deg on grid " + Conversion.LatToY(89)); Console.WriteLine("Latitudine 88.3 deg on grid " + Conversion.LatToY(88.3)); Console.WriteLine("Latitudine 88 deg on grid " + Conversion.LatToY(88)); Console.WriteLine("Latitudine Poschiavo on grid " + Conversion.LatToY(45)); Console.WriteLine("Latitudine 0.3 deg on grid " + Conversion.LatToY(0.3)); Console.WriteLine("Latitudine equator on grid " + Conversion.LatToY(0)); Console.WriteLine("Latitudine -0.3 deg on grid " + Conversion.LatToY(-0.3)); Console.WriteLine("Latitudine -88 deg on grid " + Conversion.LatToY(-88)); Console.WriteLine("Latitudine -89 deg on grid " + Conversion.LatToY(-89)); Console.WriteLine("Latitudine -89.5 deg on grid " + Conversion.LatToY(-89.3)); Console.WriteLine("Latitudine south pole on grid " + Conversion.LatToY(-90)); Console.WriteLine(); Console.WriteLine(); Console.WriteLine("Converting twice 90 deg lat N : " + Conversion.YtoLat(Conversion.LatToY(90))); Console.WriteLine("Converting twice 0 deg lat : " + Conversion.YtoLat(Conversion.LatToY(0))); Console.WriteLine("Converting twice 90 deg lat S: " + Conversion.YtoLat(Conversion.LatToY(-90))); Console.WriteLine(); Console.WriteLine("Converting twice 180 deg lat W : " + Conversion.XtoLon(Conversion.LonToX(-180))); Console.WriteLine("Converting twice 0 deg lat : " + Conversion.XtoLon(Conversion.LonToX(0))); Console.WriteLine("Converting twice 180 deg lat E: " + Conversion.XtoLon(Conversion.LonToX(180))); }
public static void clearRain(TClima clima) { long i, j; for (j = 0; j < 180; j++) { for (i = 0; i < 360; i++) { clima.rain[i, j] = false; } } }
public static void updateTemperature(TClima clima, TWorld w, int i, int j) { double divAtmosphere, divOcean, divTerrain, weight; if (w.isOcean[i, j]) { weight = TPhysConst.weight_on_surface_at_sea_level; } else { weight = statechanges.weightOnAltitudeProQuadrateMeter(w.elevation[i, j], i, j, w); } divAtmosphere = (TPhysConst.cp_air * weight * w.area_of_degree_squared[j]); if (divAtmosphere != 0) { clima.T_atmosphere[0, i, j] = clima.energy_atmosphere[i, j] / divAtmosphere; } else { throw new Exception("divAtmosphere is zero!"); } if (w.isOcean[i, j]) { divOcean = (TPhysConst.cp_water * Math.Abs(w.elevation[i, j]) * w.area_of_degree_squared[j] * TPhysConst.density_water) + (TPhysConst.cp_earth * (w.elevation[i, j] + TSimConst.earth_crust_height) * w.area_of_degree_squared[j] * TPhysConst.density_earth); if (divOcean != 0) { clima.T_ocean_terr[i, j] = clima.energy_ocean_terr[i, j] / divOcean; } else { clima.T_ocean_terr[i, j] = 0; } } else { // terrain divTerrain = TPhysConst.cp_earth * (w.elevation[i, j] + TSimConst.earth_crust_height) * w.area_of_degree_squared[j] * TPhysConst.density_earth; if (divTerrain != 0) { clima.T_ocean_terr[i, j] = clima.energy_ocean_terr[i, j] / divTerrain; } else { throw new Exception("divTerrain is zero!"); } } }
static void TestTwoDays() { double[,] tmpGrid = new double[360, 180]; short[,] wind = new short[360, 180]; double[,] T_atmosphere = new double[360, 180]; TWorld world = new TWorld(); Debug.WriteLine("Init World"); initmodel.initWorld(world); TClima clima = new TClima(); Debug.WriteLine("Init Clima"); initmodel.initClima(world, clima, 16, 16); TTime t = new TTime(); TSolarSurface s = new TSolarSurface(); Debug.WriteLine("Init time and solar surface"); initmodel.initTime(t, s); Debug.WriteLine("Initial conditions created"); Debug.WriteLine("Simulating 3 days of weather including energy cycle, winds,"); Debug.WriteLine("marine currents, steam generation and rain"); for (int day = 170; day < 173; day++) { Debug.Write("Simulating day = " + day + " "); for (int hour = 0; hour < 24; hour++) { Debug.Write("."); riverandlakes.clearRain(clima); double earthInclination = energyfunctions.computeEarthDeclination(day); for (int j = 0; j < 180; j++) { for (int i = 0; i < 360; i++) { energyfunctions.updateIncomingEnergyOnCellGrid(clima, world, s, earthInclination, i, j); watercycle.formSteam(clima, world, s, i, j, t.day); } } flux.moveEnergy(clima, clima.energy_atmosphere, tmpGrid, T_atmosphere, wind, flux.WIND, world, true); #if TODO flux.moveEnergy(clima, clima.energy_ocean_terr, tmpGrid, clima.T_ocean_terr, clima.surfaceTransfer, flux.SURFACE_AND_MARINE_CURRENT, world, true); //printPlanet(2000, day, hour, clima, world, true, false); watercycle.moveSteam(clima.wind, clima.steam, tmpGrid); #endif } } }
public static void updateIncomingEnergyOnCellGrid(TClima clima, TWorld w, TSolarSurface sSurface, double earthInclination, int i, int j) { double energyIn; if (statechanges.isInSunlight(i, j, sSurface)) { energyIn = computeEnergyFromSunOnSquare(i, j, earthInclination, clima, w); spreadEnergyOnAtmosphereAndTerrain(clima, energyIn, i, j); updateTemperature(clima, w, i, j); } radiateTerrestrialEnergy(clima, w, i, j); updateTemperature(clima, w, i, j); }
public static void mainSimDayLoop(TWorld world, TClima clima, TSolarSurface s, TTime t, double[,] tmpGrid, double earthDeclination) { #if TODO computeSolarSurface(s, t, earthDeclination); increasePopulation(clima, 1); printEarthStatus(t.year, t.day, Round(t.hour), clima, world); printPlanet(t.year, t.day, Round(t.hour), clima, world, false, true); if (t.day % TSimConst.decrease_rain_times == 0) { decreaseRainTimes(clima); } #endif throw new NotImplementedException(); }
public static void formCO2(TClima clima, TWorld w, long i, long j) { if (!TSimConst.population) { return; } if (!TSimConst.energy_source_oil) { return; } clima.co2_tons[i, j] = clima.co2_tons[i, j] + TSimConst.co2_production_per_human_per_year / (365 / 24 / 15 * TSimConst.degree_step) * clima.population[i, j]; }
public static void increasePopulation(TClima clima, long days) { double base_, exp, factor; base_ = 1; exp = 1 + (TSimConst.population_increase_pct * days / 365); factor = (double)Math.Pow((double)base_, (double)exp); for (int j = 0; j < 180; j++) { for (int i = 0; i < 360; i++) { clima.population[i, j] = clima.population[i, j] * factor; } } }
public static void decreaseRainTimes(TClima clima) { long i, j; for (j = 0; j < 180; j++) { for (i = 0; i < 360; i++) { if (clima.rain_times[i, j] > 0) { clima.rain_times[i, j]--; } } } }
public static double computeAvgHumidity(TWorld w, TClima clima) { long i, j; double humidity; humidity = 0; for (j = 0; j < 180; j++) { for (i = 0; i < 360; i++) { humidity = humidity + statechanges.computeHumidity(clima, w, i, j); } } return(humidity / (360 * 180)); }
public static double computeAvgSteamOnAir(TClima clima) { long l, i, j; double steam; steam = 0; for (l = 0; l <= TMdlConst.atmospheric_layers - 1; l++) { for (j = 0; j < 180; j++) { for (i = 0; i < 360; i++) { steam = steam + clima.steam[l, i, j]; } } } return(steam / (360 * 180 * TMdlConst.atmospheric_layers)); }
public static double computeAvgRain(TClima clima) { long i, j; long rainC; rainC = 0; for (j = 0; j < 180; j++) { for (i = 0; i < 360; i++) { if (clima.rain[i, j]) { rainC++; } } } return(rainC / (360 * 180)); }
public static void radiateEnergyIntoSpace(TClima clima, TWorld w, int i, int j) { double energy_radiated, finalEnergy; energy_radiated = computeRadiatedEnergyIntoSpace(clima, w, i, j); if (energy_radiated < 0) { throw new Exception("Energy radiated into space is negative"); } finalEnergy = clima.energy_atmosphere[i, j] - energy_radiated; if (finalEnergy < 0) { return; } clima.energy_atmosphere[i, j] = finalEnergy; }
public static void rainSteam(TClima clima, TWorld w, long i, long j) { double availableSteam, maxWaterInAir, thermicEnergy; maxWaterInAir = statechanges.maxWaterInSteam(clima, w, 0, i, j); availableSteam = (clima.steam[0, i, j] - maxWaterInAir) * (1 / TSimConst.rain_hours); if (availableSteam < 0) { clima.rain[i, j] = false; } else { // drop the exceeding steam in rain if (!w.isOcean[i, j]) { clima.water_surface[i, j] = clima.water_surface[i, j] + availableSteam; } clima.rain_times[i, j]++; clima.rain[i, j] = true; clima.steam[0, i, j] = clima.steam[0, i, j] - availableSteam; // assumption: thermic energy and potential energy of clouds // are given back to terrain as energy of movement if ((TPhysConst.kT_boil - clima.T_atmosphere[0, i, j]) > 0) { thermicEnergy = availableSteam * TPhysConst.cp_steam * (TPhysConst.kT_boil - clima.T_atmosphere[0, i, j]); } else { thermicEnergy = 0; } // give the thermic energy and potential energy to the terrain and atmosphere // clima.energy_atmosphere[i, j] = clima.energy_atmosphere[i, j] + potEnergy; clima.energy_ocean_terr[i, j] = clima.energy_ocean_terr[i, j] + thermicEnergy; } // compute humidity statechanges.computeHumidity(clima, w, i, j); }
public static void exchangeEnergyBetweenAtmAndTerrain(TClima clima, TWorld w, int i, int j) { double energy_moved, finalEnergy; if (clima.T_ocean_terr[i, j] > clima.T_atmosphere[0, i, j]) { // radiate energy from terrain to atmosphere energy_moved = TPhysConst.stefan_boltzmann * Math.Pow(clima.T_ocean_terr[i, j], 4) * w.area_of_degree_squared[j] * TSimConst.hour_step * (1 / TSimConst.exchange_atm_terr); if (energy_moved < 0) { throw new Exception("Energy radiated from terrain to atmosphere is negative"); } finalEnergy = clima.energy_ocean_terr[i, j] - energy_moved; if (finalEnergy < 0) { return; } clima.energy_ocean_terr[i, j] = finalEnergy; clima.energy_atmosphere[i, j] = clima.energy_atmosphere[i, j] + energy_moved; } else { // radiate energy from atmosphere to terrain energy_moved = TPhysConst.stefan_boltzmann * Math.Pow(clima.T_atmosphere[0, i, j], 4) * w.area_of_degree_squared[j] * TSimConst.hour_step * (1 / TSimConst.exchange_atm_terr); if (energy_moved < 0) { throw new Exception("Energy radiated from atmosphere to terrain is negative"); } finalEnergy = clima.energy_atmosphere[i, j] - energy_moved; if (finalEnergy < 0) { return; } clima.energy_atmosphere[i, j] = finalEnergy; clima.energy_ocean_terr[i, j] = clima.energy_ocean_terr[i, j] + energy_moved; } }
public static double computeAvgWindMovements(TClima clima) { long i, j; long movements; movements = 0; for (j = 0; j < 180; j++) { for (i = 0; i < 360; i++) { if (clima.wind[0, i, j] != Constants.NONE) { movements = movements + 1; } } } return(movements / (360 * 180)); }
public static double computeHumidity(TClima clima, TWorld w, long i, long j) { double maxWater; maxWater = 0; clima.humidity[i, j] = 0; for (int l = 0; l < TMdlConst.atmospheric_layers; l++) { clima.humidity[i, j] = clima.humidity[i, j] + clima.steam[l, i, j]; maxWater = maxWater + maxWaterInSteam(clima, w, l, i, j); } clima.humidity[i, j] = clima.humidity[i, j] / maxWater; if (clima.humidity[i, j] > 1) { clima.humidity[i, j] = 1; } return(clima.humidity[i, j]); }
public static double computeRadiatedEnergyIntoSpace(TClima clima, TWorld w, int i, int j) { double isolation, co2_isolation; co2_isolation = clima.co2_tons[i, j] / 1E7; // where it is red on plot it is 1 if (co2_isolation > 1) { co2_isolation = 1; } isolation = clima.humidity[i, j] * TSimConst.cloud_isolation_pct + TSimConst.co2_isolation_pct * co2_isolation; if (isolation > 1) { isolation = 1; } return((1 - isolation) * TPhysConst.stefan_boltzmann * Math.Pow(clima.T_atmosphere[0, i, j], 4) * w.area_of_degree_squared[j] * TSimConst.hour_step * (1 / TSimConst.radiation_hours)); }