1
0
Fork 0

Clean up the code, impement relative humidity (and related to that dew point) and better implement arid climates

This commit is contained in:
Erik Hofman 2020-11-08 10:28:23 +01:00
parent 1ae2e4c4cd
commit 3384a85650
2 changed files with 270 additions and 186 deletions

View file

@ -34,8 +34,18 @@
#include "climate.hxx" #include "climate.hxx"
// Based on "World Map of the Köppen-Geiger climate classification" // Based on "World Map of the Köppen-Geiger climate classification"
// The map is provided with a spatial resolution of 0.5 degree (3km). // The map is provided with a spatial resolution of approx. 10x10km per pixel.
// http://koeppen-geiger.vu-wien.ac.at/present.htm // http://koeppen-geiger.vu-wien.ac.at/present.htm
//
// References:
// * Teuling, A. J.: Technical note: Towards a continuous classification of
// climate usingbivariate colour mapping, Hydrol. Earth Syst. Sci., 15,
// 30713075, https://doi.org/10.5194/hess-15-3071-2011, 2011.
//
// * Lawrence, Mark G., 2005: The relationship between relative humidity and
// the dewpoint temperature in moist air: A simple conversion and
// applications. Bull. Amer. Meteor. Soc., 86, 225-233.
// doi: http://dx.doi.org/10.1175/BAMS-86-2-225
FGClimate::FGClimate(const SGGeod& position) FGClimate::FGClimate(const SGGeod& position)
{ {
@ -75,11 +85,11 @@ void FGClimate::update(const SGGeod& position)
if (fabs(_prev_lat - _adj_latitude_deg) > _epsilon || if (fabs(_prev_lat - _adj_latitude_deg) > _epsilon ||
fabs(_prev_lon - _adj_longitude_deg) > _epsilon) fabs(_prev_lon - _adj_longitude_deg) > _epsilon)
{ {
_autumn = false; _is_autumn = false;
if ((latitude_deg*_sun_latitude_deg < 0.0) // autumn + spring if ((latitude_deg*_sun_latitude_deg < 0.0) // autumn + spring
&& (_adj_latitude_deg > _prev_lat)) // autumn && (_adj_latitude_deg > _prev_lat)) // autumn
{ {
_autumn = true; _is_autumn = true;
} }
_prev_lat = _adj_latitude_deg; _prev_lat = _adj_latitude_deg;
@ -88,20 +98,22 @@ void FGClimate::update(const SGGeod& position)
update_day_factor(); update_day_factor();
update_season_factor(); update_season_factor();
// from lat/lon to screen coordinates
double x = 180.0 + longitude_deg;
double y = 90.0 + latitude_deg;
_col = static_cast<int>(x * _image_width/360.0);
_row = static_cast<int>(y * _image_height/180.0);
osg::Vec4f color; osg::Vec4f color;
if (image) { if (image)
color = image->getColor(_col, _row); {
// from lat/lon to screen coordinates
double x = 180.0 + longitude_deg;
double y = 90.0 + latitude_deg;
double s, t;
s = static_cast<int>(x * static_cast<double>(_image_width)/360.0);
t = static_cast<int>(y * static_cast<double>(_image_height)/180.0);
color = image->getColor(s, t);
} }
// convert from color shades to koppen-classicfication // convert from color shades to koppen-classicfication
_classicfication = static_cast<int>( 255.0*color[0]/4.0 ); _classicfication = static_cast<int>( 255.0f*color[0]/4.0f );
if (_classicfication == 0) set_ocean(); if (_classicfication == 0) set_ocean();
else if (_classicfication < 5) set_tropical(); else if (_classicfication < 5) set_tropical();
@ -111,6 +123,9 @@ void FGClimate::update(const SGGeod& position)
else if (_classicfication < 32) set_polar(); else if (_classicfication < 32) set_polar();
else set_ocean(); else set_ocean();
// Mark G. Lawrence:
_dew_point = _temperature_gl - ((100.0 - 100.0*_relative_humidity)/5.0);
set_environment(); set_environment();
#if REPORT_TO_CONSOLE #if REPORT_TO_CONSOLE
@ -119,31 +134,27 @@ void FGClimate::update(const SGGeod& position)
} }
} }
// returns 0.0 for night up to 1.0 for noon // _day_noon returns 0.0 for night up to 1.0 for noon
void FGClimate::update_day_factor() void FGClimate::update_day_factor()
{ {
// noon is when lon == 180.0 // noon is when lon == 180.0
_day_noon = fabs(_adj_longitude_deg - 180.0)/180.0; _day_noon = fabs(_adj_longitude_deg - 180.0)/180.0;
} }
// The seasons are currently based purely on where the sun's perpendicular // _season_summer returns 0.0 for winter up to 1.0 for summer
// (perp.) rays strike the earth. Winter (perp. Rays moving from 23.5 S to // _season_transistional returns 0.0 for early autumn/late spring up to
// equator), Spring (perp. Rays moving from the equator to 23.5 N), Summer // 1.0 for late autumn/early spring
// (perp. Rays moving from 23.5 N to equator) and Fall (perp. Rays moving // to distinguish between the two use the _autumn flag.
// from equator to 23.5 S).
// returns 0.0 for winter up to 1.0 for summer
void FGClimate::update_season_factor() void FGClimate::update_season_factor()
{ {
double latitude_deg = pos.getLatitudeDeg(); double latitude_deg = pos.getLatitudeDeg();
double sign = latitude_deg >= 0.0 ? 1.0 : -1.0; // hemisphere double sign = latitude_deg >= 0.0 ? 1.0 : -1.0; // hemisphere
_season_summer = (23.5 + sign*_sun_latitude_deg)/(2.0*23.5); _season_summer = (23.5 + sign*_sun_latitude_deg)/(2.0*23.5);
_season_winter = 2.0*(1.0 - _season_summer) - 1.0; _season_transistional = 2.0*(1.0 - _season_summer) - 1.0;
if (_season_winter < 0.0) _season_winter = 0.0; if (_season_transistional < 0.0) _season_transistional = 0.0;
else if (_season_winter > 1.0) _season_winter = 1.0; else if (_season_transistional > 1.0) _season_transistional = 1.0;
double fact_lat = 6.0 - 12.0*fabs(latitude_deg)/90.0;
_season_winter *= (0.5 - 0.5*sin(atan(SGD_2PI*fact_lat)));
} }
@ -179,6 +190,9 @@ void FGClimate::set_ocean()
// steady winds // steady winds
_wind = 3.0; _wind = 3.0;
// no autumn
_has_autumn = false;
// average precipitation // average precipitation
_total_annual_precipitation = 990.0; // global _total_annual_precipitation = 990.0; // global
double avg_precipitation = 100.0 - (_total_annual_precipitation/25.0); double avg_precipitation = 100.0 - (_total_annual_precipitation/25.0);
@ -191,50 +205,62 @@ void FGClimate::set_tropical()
{ {
// weather // weather
_total_annual_precipitation = 3000.0; _total_annual_precipitation = 3000.0;
// double avg_precipitation = 100.0 - (_total_annual_precipitation/25.0);
double day = _day_noon; double day = _day_noon;
double summer = _season_summer; double summer = _season_summer;
double winter = 1.0 - summer; double winter = 1.0 - summer;
double temp_equator_max = 31.0;
double temp_equator_min = 23.0;
double temp_equator = season_even(day, temp_equator_min, temp_equator_max);
// winter temperatures are three-quarter of the summer temperatures
_temperature_sl = season_even(summer, 0.75*temp_equator, temp_equator);
_temperature_gl = _temperature_sl;
// relative humidity based on latitude
double latitude_deg = pos.getLatitudeDeg();
double fact_lat = fabs(latitude_deg)/90.0;
_relative_humidity = season_even(fact_lat, 0.1, 0.8);
// wind based on latitude (0.0 - 15 degrees) // wind based on latitude (0.0 - 15 degrees)
fact_lat = std::max(abs(latitude_deg), 15.0)/15.0; double latitude_deg = pos.getLatitudeDeg();
_wind = 3.0*fact_lat*fact_lat; double fact_lat = std::max(abs(latitude_deg), 15.0)/15.0;
double wind = 3.0*fact_lat*fact_lat;
double temp_night = _temperature_sl;
double temp_day = _temperature_sl;
double precipitation = _precipitation;
double relative_humidity = _relative_humidity;
switch(_classicfication) switch(_classicfication)
{ {
case 1: // Af: equatorial, fully humid case 1: // Af: equatorial, fully humid
_precipitation = season_even(winter, 150.0, 280.0); temp_night = triangular(summer, 20.0, 22.5);
temp_day = triangular(summer, 29.5, 32.5);
precipitation = season_even(winter, 150.0, 280.0);
relative_humidity = season_even(summer, 0.75, 0.85);
break; break;
case 2: // Am: equatorial, monsoonal case 2: // Am: equatorial, monsoonal
_precipitation = season_even(summer, 75.0, 320.0); temp_night = triangular(summer, 17.5, 22.5);
_wind *= 2.0*_precipitation/320.0; temp_day = triangular(summer, 27.5, 32.5);
precipitation = season_even(summer, 75.0, 320.0);
relative_humidity = season_even(summer, 0.75, 0.85);
wind *= 2.0*_precipitation/320.0;
break; break;
case 3: // As: equatorial, summer dry case 3: // As: equatorial, summer dry
_precipitation = season_even(0.5*summer + 0.5 - 0.5*_season_winter , 35.0, 150.0); temp_night = season_long_high(summer, 15.0, 22.5);
_wind *= 2.0*_precipitation/350.0; temp_day = triangular(summer, 27.5, 35.0);
precipitation = season_even(0.5*summer + 0.5 - 0.5*_season_transistional , 35.0, 150.0);
relative_humidity = season_even(summer, 0.60, 0.80);
wind *= 2.0*_precipitation/350.0;
break; break;
case 4: // Aw: equatorial, winter dry case 4: // Aw: equatorial, winter dry
_precipitation = season_even(summer, 10.0, 230.0); temp_night = season_long_high(summer, 15.0, 22.5);
_wind *= 2.0*_precipitation/230.0; temp_day = triangular(summer, 27.5, 35.0);
precipitation = season_even(summer, 10.0, 230.0);
relative_humidity = season_even(summer, 0.60, 0.80);
wind *= 2.0*_precipitation/230.0;
break; break;
default: default:
break; break;
} }
_temperature_gl = season_even(day, temp_night, temp_day);
_temperature_mean = 0.5*(temp_night + temp_day);
_temperature_sl = _temperature_gl;
_relative_humidity = relative_humidity;
_precipitation = precipitation;
_has_autumn = false;
_wind = wind;
} }
// https://en.wikipedia.org/wiki/Desert_climate // https://en.wikipedia.org/wiki/Desert_climate
@ -242,42 +268,55 @@ void FGClimate::set_tropical()
void FGClimate::set_dry() void FGClimate::set_dry()
{ {
double day = _day_noon; double day = _day_noon;
double summer = _season_summer; double summer = _season_summer;
double winter = 1.0 - summer;
double temp_mean_summer = 32.0;
double temp_day_summer = 41.0;
double temp_night_summer = 2.0*temp_mean_summer - temp_day_summer;
double temp_day_winter = temp_day_summer - temp_night_summer;
double temp_night_winter = 0.0;
double temp_winter = season_even(day, temp_night_winter, temp_day_winter);
double temp_summer = season_even(day, temp_night_summer, temp_day_summer);
_temperature_gl = season_even(summer, temp_winter, temp_summer);
if (_classicfication == 6 || _classicfication == 8) { // cold arid
_temperature_mean -= 14.0;
_temperature_gl -= 14.0;
}
_temperature_sl = _temperature_gl;
double temp_mean_winter = 0.5*(temp_day_winter + temp_night_winter);
_temperature_mean = season_even(summer, temp_mean_winter, temp_mean_summer);
// low relative humidity
_relative_humidity = 0.25;
// steady winds
_wind = 3.0;
_total_annual_precipitation = 100.0; _total_annual_precipitation = 100.0;
if (_classicfication == 5 || _classicfication == 6) { // steppe if (_classicfication == 5 || _classicfication == 6) { // steppe
_total_annual_precipitation *= 2.0; _total_annual_precipitation *= 2.0;
} }
double avg_precipitation = _total_annual_precipitation/12.0; double temp_night = _temperature_sl;
_precipitation = winter*2.0*avg_precipitation; double temp_day = _temperature_sl;
double precipitation = _precipitation;
double relative_humidity = _relative_humidity;
switch(_classicfication)
{
case 5: // BSh: arid, steppe, hot arid
temp_night = season_long_high(summer, 10.0, 22.0);
temp_day = triangular(summer, 27.5, 35.0);
precipitation = season_long_low(summer, 8.0, 117.0);
relative_humidity = season_long_low(summer, 0.20, 0.30);
break;
case 6: // BSk: arid, steppe, cold arid
temp_night = season_even(summer, -14.0, 12.0);
temp_day = season_even(summer, 0.0, 30.0);
precipitation = season_even(summer, 15.0, 34.0);
relative_humidity = season_even(summer, 0.48, 0.67);
break;
case 7: // BWh: arid, desert, hot arid
temp_night = season_even(summer, 7.5, 22.0);
temp_day = season_even(summer, 22.5, 37.5);
precipitation = monsoonal(summer, 3.0, 18.0);
relative_humidity = monsoonal(summer, 0.25, 0.55);
break;
case 8: // BWk: arid, desert, cold arid
temp_night = season_even(summer, -15.0, 15.0);
temp_day = season_even(summer, -2.0, 30.0);
precipitation = linear(summer, 4.0, 14.0);
relative_humidity = linear(summer, 0.45, 0.61);
break;
default:
break;
}
_temperature_gl = season_even(day, temp_night, temp_day);
_temperature_mean = 0.5*(temp_night + temp_day);
_temperature_sl = _temperature_gl;
_relative_humidity = relative_humidity;
_precipitation = precipitation;
_has_autumn = false;
_wind = 3.0;
} }
// https://en.wikipedia.org/wiki/Temperate_climate // https://en.wikipedia.org/wiki/Temperate_climate
@ -288,152 +327,177 @@ void FGClimate::set_temperate()
double summer = _season_summer; double summer = _season_summer;
double winter = 1.0 - summer; double winter = 1.0 - summer;
double temp_min = _temperature_sl; double temp_night = _temperature_sl;
double temp_max = _temperature_sl; double temp_day = _temperature_sl;
double precipitation = _precipitation; double precipitation = _precipitation;
double relative_humidity = _relative_humidity; double relative_humidity = _relative_humidity;
switch(_classicfication) switch(_classicfication)
{ {
case 9: // Cfa: warm temperature, fully humid hot summer case 9: // Cfa: warm temperature, fully humid hot summer
temp_min = season_even(summer, -3.0, 20.0); temp_night = season_even(summer, -3.0, 20.0);
temp_max = season_even(summer, 10.0, 33.0); temp_day = season_even(summer, 10.0, 33.0);
precipitation = season_even(summer, 60.0, 123.0); precipitation = season_even(summer, 60.0, 123.0);
relative_humidity = season_even(summer, 0.6, 0.9); relative_humidity = season_even(summer, 0.65, 0.80);
break; break;
case 10: // Cfb: warm temperature, fully humid, warm summer case 10: // Cfb: warm temperature, fully humid, warm summer
temp_min = season_even(summer, -3.0, 10.0); temp_night = season_even(summer, -3.0, 10.0);
temp_max = season_even(summer, 5.0, 25.0); temp_day = season_even(summer, 5.0, 25.0);
precipitation = linear(0.5*(summer + _season_winter), 44.0, 88.0); precipitation = linear(0.5*(summer+_season_transistional), 44.0, 88.0);
relative_humidity = 0.8; relative_humidity = season_even(summer, 0.68, 0.87);
break; break;
case 11: // Cfc: warm temperature, fully humid, cool summer case 11: // Cfc: warm temperature, fully humid, cool summer
temp_min = season_long_low(summer, -3.0, 8.0); temp_night = season_long_low(summer, -3.0, 8.0);
temp_max = season_long_low(summer, 2.0, 14.0); temp_day = season_long_low(summer, 2.0, 14.0);
precipitation = season_even(winter, 44.0, 88.0); precipitation = season_even(winter, 44.0, 88.0);
relative_humidity = 0.8; relative_humidity = season_even(summer, 0.70, 0.85);
break; break;
case 12: // Csa: warm temperature, summer dry, hot summer case 12: // Csa: warm temperature, summer dry, hot summer
temp_min = season_even(summer, 2.0, 16.0); temp_night = season_even(summer, 2.0, 16.0);
temp_max = season_even(summer, 12.0, 33.0); temp_day = season_even(summer, 12.0, 33.0);
precipitation = season_long_low(summer, 25.0, 70.0); precipitation = season_long_low(winter, 25.0, 70.0);
relative_humidity = season_even(winter, 0.58, 0.72);
break; break;
case 13: // Csb: warm temperature, summer dry, warm summer case 13: // Csb: warm temperature, summer dry, warm summer
temp_min = linear(summer, -4.0, 10.0); temp_night = linear(summer, -4.0, 10.0);
temp_max = linear(summer, 6.0, 27.0); temp_day = linear(summer, 6.0, 27.0);
precipitation = season_short(winter, 25.0, 120.0); precipitation = season_short(winter, 25.0, 120.0);
relative_humidity = season_even(winter, 0.50, 0.72);
break; break;
case 14: // Csc: warm temperature, summer dry, cool summer case 14: // Csc: warm temperature, summer dry, cool summer
temp_min = season_even(summer, -4.0, 5.0); temp_night = season_even(summer, -4.0, 5.0);
temp_max = season_even(summer, 5.0, 16.0); temp_day = season_even(summer, 5.0, 16.0);
precipitation = season_even(summer, 60.0, 95.0); precipitation = season_even(winter, 60.0, 95.0);
relative_humidity = season_even(winter, 0.55, 0.75);
break; break;
case 15: // Cwa: warm temperature, winter dry, hot summer case 15: // Cwa: warm temperature, winter dry, hot summer
temp_min = season_even(summer, 4.0, 20.0); temp_night = season_even(summer, 4.0, 20.0);
temp_max = season_long_low(summer, 15.0, 30.0); temp_day = season_long_low(summer, 15.0, 30.0);
precipitation = season_long_low(summer, 10.0, 320.0); precipitation = season_long_low(summer, 10.0, 320.0);
relative_humidity = season_even(summer, 0.60, 0.79);
break; break;
case 16: // Cwb: warm temperature, winter dry, warm summer case 16: // Cwb: warm temperature, winter dry, warm summer
temp_min = season_even(summer, 1.0, 13.0); temp_night = season_even(summer, 1.0, 13.0);
temp_max = season_long_low(summer, 15.0, 27.0); temp_day = season_long_low(summer, 15.0, 27.0);
precipitation = season_long_low(summer, 10.0, 250.0); precipitation = season_long_low(summer, 10.0, 250.0);
relative_humidity = season_even(summer, 0.58, 0.72);
break; break;
case 17: // Cwc: warm temperature, winter dry, cool summer case 17: // Cwc: warm temperature, winter dry, cool summer
temp_min = season_long_high(winter, -9.0, 6.0); temp_night = season_long_high(summer, -9.0, 6.0);
temp_max = season_long_high(winter, 6.0, 17.0); temp_day = season_long_high(summer, 6.0, 17.0);
precipitation = season_long_low(summer, 10.0, 200.0); precipitation = season_long_low(summer, 10.0, 200.0);
relative_humidity = season_even(summer, 0.50, 0.58);
break; break;
default: default:
break; break;
} }
_temperature_gl = season_even(day, temp_min, temp_max); _temperature_gl = season_even(day, temp_night, temp_day);
_temperature_mean = 0.5*(temp_night + temp_day);
_temperature_sl = _temperature_gl; _temperature_sl = _temperature_gl;
_temperature_mean = 0.5*(temp_min + temp_max);
_precipitation = precipitation;
_relative_humidity = relative_humidity; _relative_humidity = relative_humidity;
_precipitation = precipitation;
_has_autumn = true;
_wind = 3.0; _wind = 3.0;
} }
// https://en.wikipedia.org/wiki/Continental_climate
void FGClimate::set_continetal() void FGClimate::set_continetal()
{ {
double day = _day_noon; double day = _day_noon;
double summer = _season_summer; double summer = _season_summer;
double winter = 1.0 - summer;
double temp_max = _temperature_sl; double temp_day = _temperature_sl;
double temp_min = _temperature_sl; double temp_night = _temperature_sl;
double precipitation = _precipitation;
double relative_humidity = _relative_humidity;
switch(_classicfication) switch(_classicfication)
{ {
case 18: // Dfa: snow, fully humid, hot summer case 18: // Dfa: snow, fully humid, hot summer
temp_min = season_even(summer, -15.0, 13.0); temp_night = season_even(summer, -15.0, 13.0);
temp_max = season_even(summer, -5.0, 30.0); temp_day = season_even(summer, -5.0, 30.0);
_precipitation = season_even(summer, 25.0, 65.0); precipitation = season_even(summer, 25.0, 65.0);
relative_humidity = season_even(summer, 0.68, 0.72);
break; break;
case 19: // Dfb: snow, fully humid, warm summer, warm summer case 19: // Dfb: snow, fully humid, warm summer, warm summer
temp_min = season_even(summer, -17.5, 10.0); temp_night = season_even(summer, -17.5, 10.0);
temp_max = season_even(summer, -7.5, 25.0); temp_day = season_even(summer, -7.5, 25.0);
_precipitation = season_even(summer, 30.0, 70.0); precipitation = season_even(summer, 30.0, 70.0);
relative_humidity = season_even(summer, 0.69, 0.81);
break; break;
case 20: // Dfc: snow, fully humid, cool summer, cool summer case 20: // Dfc: snow, fully humid, cool summer, cool summer
temp_min = season_even(summer, -30.0, 4.0); temp_night = season_even(summer, -30.0, 4.0);
temp_max = season_even(summer, -20.0, 15.0); temp_day = season_even(summer, -20.0, 15.0);
_precipitation = season_even(summer, 22.0, 68.0); precipitation = season_even(summer, 22.0, 68.0);
_precipitation = 50.0 - 25.0*summer; relative_humidity = season_even(summer, 0.70, 0.88);
break; break;
case 21: // Dfd: snow, fully humid, extremely continetal case 21: // Dfd: snow, fully humid, extremely continetal
temp_min = season_short(summer, -45.0, 4.0); temp_night = season_short(summer, -45.0, 4.0);
temp_max = season_short(summer, -35.0, 10.0); temp_day = season_short(summer, -35.0, 10.0);
_precipitation = season_long_low(summer, 7.5, 45.0); precipitation = season_long_low(summer, 7.5, 45.0);
relative_humidity = season_long_low(summer, 0.80, 0.90);
break; break;
case 22: // Dsa: snow, summer dry, hot summer case 22: // Dsa: snow, summer dry, hot summer
temp_min = season_even(summer, -10.0, 10.0); temp_night = season_even(summer, -10.0, 10.0);
temp_max = season_even(summer, 0.0, 30.0); temp_day = season_even(summer, 0.0, 30.0);
_precipitation = season_long_high(summer, 2.0, 70.0); precipitation = season_long_high(winter, 2.0, 70.0);
relative_humidity = season_long_high(winter, 0.48, 0.58);
break; break;
case 23: // Dsb: snow, summer dry, warm summer case 23: // Dsb: snow, summer dry, warm summer
temp_min = season_even(summer, -15.0, 6.0); temp_night = season_even(summer, -15.0, 6.0);
temp_max = season_even(summer, -4.0, 25.0); temp_day = season_even(summer, -4.0, 25.0);
_precipitation = season_long_high(summer, 12.0, 73.0); precipitation = season_long_high(winter, 12.0, 73.0);
relative_humidity = season_long_high(winter, 0.50, 0.68);
break; break;
case 24: // Dsc: snow, summer dry, cool summer case 24: // Dsc: snow, summer dry, cool summer
temp_min = season_even(summer, -27.5, 2.0); temp_night = season_even(summer, -27.5, 2.0);
temp_max = season_even(summer, -4.0, 15.0); temp_day = season_even(summer, -4.0, 15.0);
_precipitation = season_long_low(summer, 32.5, 45.0); precipitation = season_long_low(summer, 32.5, 45.0);
relative_humidity = season_long_low(summer, 0.50, 0.60);
break; break;
case 25: // Dsd: snow, summer dry, extremely continetal case 25: // Dsd: snow, summer dry, extremely continetal
temp_min = season_even(summer, -11.5, -6.5); temp_night = season_even(summer, -11.5, -6.5);
temp_max = season_even(summer, 14.0, 27.0); temp_day = season_even(summer, 14.0, 27.0);
_precipitation = season_long_low(summer, 5.0, 90.0); precipitation = season_long_low(summer, 5.0, 90.0);
relative_humidity = season_long_low(summer, 0.48, 0.62);
break; break;
case 26: // Dwa: snow, winter dry, hot summer case 26: // Dwa: snow, winter dry, hot summer
temp_min = season_even(summer, -18.0, 16.5); temp_night = season_even(summer, -18.0, 16.5);
temp_max = season_even(summer, -5.0, 25.0); temp_day = season_even(summer, -5.0, 25.0);
_precipitation = season_long_low(summer, 5.0, 180.0); precipitation = season_long_low(summer, 5.0, 180.0);
relative_humidity = season_long_low(summer, 0.60, 0.68);
break; break;
case 27: // Dwb: snow, winter dry, warm summer case 27: // Dwb: snow, winter dry, warm summer
temp_min = season_even(summer, -28.0, 10.0); temp_night = season_even(summer, -28.0, 10.0);
temp_max = season_even(summer, -12.5, 22.5); temp_day = season_even(summer, -12.5, 22.5);
_precipitation = season_long_low(summer, 10.0, 140.0); precipitation = season_long_low(summer, 10.0, 140.0);
relative_humidity = season_long_low(summer, 0.60, 0.72);
break; break;
case 28: // Dwc: snow, winter dry, cool summer case 28: // Dwc: snow, winter dry, cool summer
temp_min = season_even(summer, -33.0, 5.0); temp_night = season_even(summer, -33.0, 5.0);
temp_max = season_even(summer, -20.0, 20.0); temp_day = season_even(summer, -20.0, 20.0);
_precipitation = season_long_low(summer, 10.0, 110.0); precipitation = season_long_low(summer, 10.0, 110.0);
relative_humidity = season_long_low(summer, 0.60, 0.78);
break; break;
case 29: // Dwd: snow, winter dry, extremely continetal case 29: // Dwd: snow, winter dry, extremely continetal
temp_min = season_even(summer, -57.5, 0.0); temp_night = season_even(summer, -57.5, 0.0);
temp_max = season_even(summer, -43.0, 15.0); temp_day = season_even(summer, -43.0, 15.0);
_precipitation = season_even(summer, 8.0, 63.0); precipitation = season_even(summer, 8.0, 63.0);
relative_humidity = 0.80;
break; break;
default: default:
break; break;
} }
_temperature_gl = season_even(day, temp_min, temp_max); _temperature_gl = season_even(day, temp_night, temp_day);
_temperature_mean = 0.5*(temp_night + temp_day);
_temperature_sl = _temperature_gl; _temperature_sl = _temperature_gl;
_temperature_mean = 0.5*(temp_min + temp_max); _relative_humidity = relative_humidity;
_precipitation = _precipitation; _precipitation = precipitation;
_has_autumn = true;
_wind = 3.0; _wind = 3.0;
double fact_lat = pow(fabs(pos.getLatitudeDeg())/90.0, 2.5); double fact_lat = pow(fabs(pos.getLatitudeDeg())/90.0, 2.5);
@ -446,33 +510,36 @@ void FGClimate::set_polar()
double summer = _season_summer; double summer = _season_summer;
// polar climate also occurs high in the mountains // polar climate also occurs high in the mountains
double temp_max = _temperature_sl; double temp_day = _temperature_sl;
double temp_min = _temperature_sl; double temp_night = _temperature_sl;
double precipitation = _precipitation;
double relative_humidity = _relative_humidity;
switch(_classicfication) switch(_classicfication)
{ {
case 30: // EF: polar frost case 30: // EF: polar frost
temp_min = season_long_low(summer, -35.0, -6.0); temp_night = season_long_low(summer, -35.0, -6.0);
temp_max = season_long_low(summer, -32.5, 0.0); temp_day = season_long_low(summer, -32.5, 0.0);
_precipitation = season_even(summer, 50.0, 80.0); precipitation = season_even(summer, 50.0, 80.0);
relative_humidity = season_even(summer, 0.65, 0.75);
break; break;
case 31: // ET: polar tundra case 31: // ET: polar tundra
temp_min = season_even(summer, -30.0, 0.0); temp_night = season_even(summer, -30.0, 0.0);
temp_max = season_even(summer, -22.5, 8.0); temp_day = season_even(summer, -22.5, 8.0);
_precipitation = season_even(summer, 15.0, 45.0); precipitation = season_even(summer, 15.0, 45.0);
relative_humidity = season_even(summer, 0.60, 0.88);
break; break;
default: default:
break; break;
} }
_temperature_gl = season_even(day, temp_min, temp_max); _temperature_gl = season_even(day, temp_night, temp_day);
_temperature_mean = 0.5*(temp_night + temp_day);
_temperature_sl = _temperature_gl; _temperature_sl = _temperature_gl;
_temperature_mean = 0.5*(temp_min + temp_max); _relative_humidity = relative_humidity;
_precipitation = _precipitation; _precipitation = precipitation;
_has_autumn = false;
_wind = 3.0; _wind = 3.0;
double fact_lat = pow(fabs(pos.getLatitudeDeg())/90.0, 2.5);
_relative_humidity = season_even(fact_lat, 0.1, 0.8);
} }
void FGClimate::set_environment() void FGClimate::set_environment()
@ -505,6 +572,7 @@ void FGClimate::set_environment()
_snow_thickness = pow(snow_fact, 2.0); _snow_thickness = pow(snow_fact, 2.0);
_ice_cover = pow(fact_lat, 2.5); _ice_cover = pow(fact_lat, 2.5);
// less than 20 mm/month of precipitation is considered dry.
if (_precipitation < 20.0 && _total_annual_precipitation < 240.0) if (_precipitation < 20.0 && _total_annual_precipitation < 240.0)
{ {
_dust_cover = 0.3 - 0.3*sqrtf(_precipitation/20.0); _dust_cover = 0.3 - 0.3*sqrtf(_precipitation/20.0);
@ -514,11 +582,13 @@ void FGClimate::set_environment()
else else
{ {
double wetness = _precipitation - 20.0; double wetness = _precipitation - 20.0;
wetness = 12.0*wetness/_total_annual_precipitation; wetness = std::min(12.0*wetness/_total_annual_precipitation, 1.0);
_dust_cover = 0.0;
_wetness = pow(wetness, 3.0); _wetness = pow(wetness, 3.0);
_lichen_cover = 0.0; double cover = std::min(_total_annual_precipitation, 990.0)/990.0;
_dust_cover = 0.0; _lichen_cover = 0.5*pow(wetness*cover, 1.5);
} }
if (_environment_adjust) if (_environment_adjust)
@ -529,8 +599,8 @@ void FGClimate::set_environment()
fgSetDouble("/environment/surface/dust-cover-factor", _dust_cover); fgSetDouble("/environment/surface/dust-cover-factor", _dust_cover);
fgSetDouble("/environment/surface/wetness-set", _wetness); fgSetDouble("/environment/surface/wetness-set", _wetness);
fgSetDouble("/environment/surface/lichen-cover-factor", _lichen_cover); fgSetDouble("/environment/surface/lichen-cover-factor", _lichen_cover);
if (_autumn) if (_has_autumn && _is_autumn)
fgSetDouble("/environment/season", 2.0*_season_winter); fgSetDouble("/environment/season", 2.0*_season_transistional);
else else
fgSetDouble("/environment/season", 0.0); fgSetDouble("/environment/season", 0.0);
} }
@ -543,6 +613,15 @@ double FGClimate::linear(double val, double min, double max)
return min + val*diff; return min + val*diff;
} }
// google: y=1-abs(-1+2*x)
// low season is around 0.0 and 1.0, high season around 0.5
double FGClimate::triangular(double val, double min, double max)
{
double diff = max-min;
val = 1.0 - fabs(-1.0 + 2*val);
return min + val*diff;
}
// google: y =0.5-0.5*atan(cos(x)) // google: y =0.5-0.5*atan(cos(x))
// the short low season is round 0.0, the short high season around 1.0 // the short low season is round 0.0, the short high season around 1.0
double FGClimate::season_short(double val, double min, double max) double FGClimate::season_short(double val, double min, double max)
@ -569,12 +648,12 @@ double FGClimate::season_long_low(double val, double min, double max)
} }
// google: y=0.5+0.5*cos(x^1.5) // google: y=0.5+0.5*cos(x^1.5)
// 2.145 = pow(SGD_PI, 1.0/1.5) // 2.14503 = pow(SGD_PI, 1.0/1.5)
// the long high season is around 0.0, the short low season around 1.0 // the long high season is around 0.0, the short low season around 1.0
double FGClimate::season_long_high(double val, double min, double max) double FGClimate::season_long_high(double val, double min, double max)
{ {
double diff = max-min; double diff = max-min;
return min + diff*(0.5 + 0.5*cos(pow(2.145*val, 1.5))); return max + diff*(0.5 + 0.5*cos(pow(2.14503 - 2.14503*val, 1.5)));
} }
// goole: y=cos(atan(x*x)) // goole: y=cos(atan(x*x))
@ -642,13 +721,13 @@ void FGClimate::report()
std::cout << "===============================================" << std::endl; std::cout << "===============================================" << std::endl;
std::cout << "Climate report for:" << std::endl; std::cout << "Climate report for:" << std::endl;
std::cout << " Date: " << sgTimeFormatTime(t) << " GMT" << std::endl; std::cout << " Date: " << sgTimeFormatTime(t) << " GMT" << std::endl;
std::cout << " Sun Latitude: " << _sun_latitude_deg << " deggrees" std::cout << " Sun latitude: " << _sun_latitude_deg << " deg."
<< std::endl; << std::endl;
std::cout << " Sun Longitude: " << _sun_longitude_deg << " deggrees" std::cout << " Sun longitude: " << _sun_longitude_deg << " deg."
<< std::endl; << std::endl;
std::cout << " Viewer Latitude: " << pos.getLatitudeDeg() << " deggrees" std::cout << " Viewer latitude: " << pos.getLatitudeDeg() << " deg."
<< " (adjusted: " << _adj_latitude_deg << ")" << std::endl; << " (adjusted: " << _adj_latitude_deg << ")" << std::endl;
std::cout << " Viewer Longitude: " << pos.getLongitudeDeg() << " deggrees" std::cout << " Viewer longitude: " << pos.getLongitudeDeg() << " deg."
<< " (adjusted: " << _adj_longitude_deg << ")" << std::endl; << " (adjusted: " << _adj_longitude_deg << ")" << std::endl;
std::cout << std::endl; std::cout << std::endl;
std::cout << " Köppen classification: " << koppen_str[_classicfication] std::cout << " Köppen classification: " << koppen_str[_classicfication]
@ -659,18 +738,22 @@ void FGClimate::report()
<< std::endl; << std::endl;
std::cout << " Daytime....(0.0 = night .. 1.0 = day): " << _day_noon std::cout << " Daytime....(0.0 = night .. 1.0 = day): " << _day_noon
<< std::endl; << std::endl;
std::cout << " Seal level temperature: " << _temperature_sl << " deg. C." std::cout << " Sea level temperature: " << _temperature_sl << " deg. C."
<< std::endl; << std::endl;
std::cout << " Ground temperature: " << _temperature_gl << " deg. C." std::cout << " Ground temperature: " << _temperature_gl << " deg. C."
<< std::endl; << std::endl;
std::cout << " Monthly Precipitation: " << _precipitation << " mm" std::cout << " Mean temperature: " << _temperature_mean << " deg. C."
<< std::endl; << std::endl;
std::cout << " Annual precipitation: " << _total_annual_precipitation std::cout << " Months precipitation: " << _precipitation << " mm"
<< std::endl;
std::cout << " Annual precipitation: " << _total_annual_precipitation
<< " mm" << std::endl; << " mm" << std::endl;
std::cout << " Rel. humidity: "<< _relative_humidity*100.0 << " %"
<< std::endl;
std::cout << " Dew point: " << _dew_point << " deg. C." << std::endl; std::cout << " Dew point: " << _dew_point << " deg. C." << std::endl;
std::cout << " Wind: " << _wind << " km/h" << std::endl << std::endl; std::cout << " Wind: " << _wind << " km/h" << std::endl << std::endl;
std::cout << " Snow level: " << _snow_level << " meters" << std::endl; std::cout << " Snow level: " << _snow_level << " m." << std::endl;
std::cout << " Snow Thickness.(0.0 = thin .. 1.0 = thick): " std::cout << " Snow thickness.(0.0 = thin .. 1.0 = thick): "
<< _snow_thickness << std::endl; << _snow_thickness << std::endl;
std::cout << " Ice cover......(0.0 = none .. 1.0 = thick): " << _ice_cover std::cout << " Ice cover......(0.0 = none .. 1.0 = thick): " << _ice_cover
<< std::endl; << std::endl;
@ -681,7 +764,8 @@ void FGClimate::report()
std::cout << " Lichen cover...(0.0 = none .. 1.0 = mossy): " std::cout << " Lichen cover...(0.0 = none .. 1.0 = mossy): "
<< _lichen_cover << std::endl; << _lichen_cover << std::endl;
std::cout << " Season (0.0 = summer .. 1.0 = late autumn): " std::cout << " Season (0.0 = summer .. 1.0 = late autumn): "
<< _season_winter << std::endl; << ((_has_autumn && _is_autumn) ? _season_transistional : 0.0)
<< std::endl;
std::cout << "===============================================" << std::endl; std::cout << "===============================================" << std::endl;
} }
#endif // REPORT_TO_CONSOLE #endif // REPORT_TO_CONSOLE

View file

@ -29,7 +29,7 @@
// #include <simgear/structure/SGReferenced.hxx> // #include <simgear/structure/SGReferenced.hxx>
#include <simgear/math/SGGeod.hxx> #include <simgear/math/SGGeod.hxx>
#define REPORT_TO_CONSOLE false #define REPORT_TO_CONSOLE 0
/* /*
* Update environment parameters based on the Köppen-Geiger climate * Update environment parameters based on the Köppen-Geiger climate
@ -63,6 +63,7 @@ private:
#endif #endif
// interpolate val (from 0.0 to 1.0) between min and max // interpolate val (from 0.0 to 1.0) between min and max
double linear(double val, double min, double max); double linear(double val, double min, double max);
double triangular(double val, double min, double max);
double season_short(double val, double min, double max); double season_short(double val, double min, double max);
double season_even(double val, double min, double max); double season_even(double val, double min, double max);
double season_long_low(double val, double min, double max); double season_long_low(double val, double min, double max);
@ -98,11 +99,10 @@ private:
double _day_noon = 1.0; double _day_noon = 1.0;
double _season_summer = 1.0; double _season_summer = 1.0;
double _season_winter = 0.0; double _season_transistional = 0.0;
bool _autumn = false; bool _has_autumn = false;
bool _is_autumn = false;
int _col = 0; // screen coordinates
int _row = 0;
int _classicfication = 0; // Köppen-Geiger classicfication int _classicfication = 0; // Köppen-Geiger classicfication
// environment // environment