From 3384a856505cfc8f42ca52664e72541f61ba300e Mon Sep 17 00:00:00 2001 From: Erik Hofman Date: Sun, 8 Nov 2020 10:28:23 +0100 Subject: [PATCH] Clean up the code, impement relative humidity (and related to that dew point) and better implement arid climates --- src/Environment/climate.cxx | 446 +++++++++++++++++++++--------------- src/Environment/climate.hxx | 10 +- 2 files changed, 270 insertions(+), 186 deletions(-) diff --git a/src/Environment/climate.cxx b/src/Environment/climate.cxx index 3c0f97d97..568de59ae 100644 --- a/src/Environment/climate.cxx +++ b/src/Environment/climate.cxx @@ -34,8 +34,18 @@ #include "climate.hxx" // 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 +// +// References: +// * Teuling, A. J.: Technical note: Towards a continuous classification of +// climate usingbivariate colour mapping, Hydrol. Earth Syst. Sci., 15, +// 3071–3075, 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) { @@ -75,11 +85,11 @@ void FGClimate::update(const SGGeod& position) if (fabs(_prev_lat - _adj_latitude_deg) > _epsilon || fabs(_prev_lon - _adj_longitude_deg) > _epsilon) { - _autumn = false; + _is_autumn = false; if ((latitude_deg*_sun_latitude_deg < 0.0) // autumn + spring && (_adj_latitude_deg > _prev_lat)) // autumn { - _autumn = true; + _is_autumn = true; } _prev_lat = _adj_latitude_deg; @@ -88,20 +98,22 @@ void FGClimate::update(const SGGeod& position) update_day_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(x * _image_width/360.0); - _row = static_cast(y * _image_height/180.0); - osg::Vec4f color; - if (image) { - color = image->getColor(_col, _row); + if (image) + { + // from lat/lon to screen coordinates + double x = 180.0 + longitude_deg; + double y = 90.0 + latitude_deg; + double s, t; + + s = static_cast(x * static_cast(_image_width)/360.0); + t = static_cast(y * static_cast(_image_height)/180.0); + + color = image->getColor(s, t); } // convert from color shades to koppen-classicfication - _classicfication = static_cast( 255.0*color[0]/4.0 ); + _classicfication = static_cast( 255.0f*color[0]/4.0f ); if (_classicfication == 0) set_ocean(); else if (_classicfication < 5) set_tropical(); @@ -111,6 +123,9 @@ void FGClimate::update(const SGGeod& position) else if (_classicfication < 32) set_polar(); else set_ocean(); + // Mark G. Lawrence: + _dew_point = _temperature_gl - ((100.0 - 100.0*_relative_humidity)/5.0); + set_environment(); #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() { // noon is when lon == 180.0 _day_noon = fabs(_adj_longitude_deg - 180.0)/180.0; } -// The seasons are currently based purely on where the sun's perpendicular -// (perp.) rays strike the earth. Winter (perp. Rays moving from 23.5 S to -// equator), Spring (perp. Rays moving from the equator to 23.5 N), Summer -// (perp. Rays moving from 23.5 N to equator) and Fall (perp. Rays moving -// from equator to 23.5 S). -// returns 0.0 for winter up to 1.0 for summer +// _season_summer returns 0.0 for winter up to 1.0 for summer +// _season_transistional returns 0.0 for early autumn/late spring up to +// 1.0 for late autumn/early spring +// to distinguish between the two use the _autumn flag. void FGClimate::update_season_factor() { double latitude_deg = pos.getLatitudeDeg(); double sign = latitude_deg >= 0.0 ? 1.0 : -1.0; // hemisphere + _season_summer = (23.5 + sign*_sun_latitude_deg)/(2.0*23.5); - _season_winter = 2.0*(1.0 - _season_summer) - 1.0; - if (_season_winter < 0.0) _season_winter = 0.0; - else if (_season_winter > 1.0) _season_winter = 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))); + _season_transistional = 2.0*(1.0 - _season_summer) - 1.0; + if (_season_transistional < 0.0) _season_transistional = 0.0; + else if (_season_transistional > 1.0) _season_transistional = 1.0; } @@ -179,6 +190,9 @@ void FGClimate::set_ocean() // steady winds _wind = 3.0; + // no autumn + _has_autumn = false; + // average precipitation _total_annual_precipitation = 990.0; // global double avg_precipitation = 100.0 - (_total_annual_precipitation/25.0); @@ -191,50 +205,62 @@ void FGClimate::set_tropical() { // weather _total_annual_precipitation = 3000.0; -// double avg_precipitation = 100.0 - (_total_annual_precipitation/25.0); double day = _day_noon; double summer = _season_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) - fact_lat = std::max(abs(latitude_deg), 15.0)/15.0; - _wind = 3.0*fact_lat*fact_lat; + double latitude_deg = pos.getLatitudeDeg(); + 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) { 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; case 2: // Am: equatorial, monsoonal - _precipitation = season_even(summer, 75.0, 320.0); - _wind *= 2.0*_precipitation/320.0; + temp_night = triangular(summer, 17.5, 22.5); + 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; case 3: // As: equatorial, summer dry - _precipitation = season_even(0.5*summer + 0.5 - 0.5*_season_winter , 35.0, 150.0); - _wind *= 2.0*_precipitation/350.0; + temp_night = season_long_high(summer, 15.0, 22.5); + 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; case 4: // Aw: equatorial, winter dry - _precipitation = season_even(summer, 10.0, 230.0); - _wind *= 2.0*_precipitation/230.0; + temp_night = season_long_high(summer, 15.0, 22.5); + 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; 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 = wind; } // https://en.wikipedia.org/wiki/Desert_climate @@ -242,42 +268,55 @@ void FGClimate::set_tropical() void FGClimate::set_dry() { double day = _day_noon; - 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; if (_classicfication == 5 || _classicfication == 6) { // steppe _total_annual_precipitation *= 2.0; } - double avg_precipitation = _total_annual_precipitation/12.0; - _precipitation = winter*2.0*avg_precipitation; + double temp_night = _temperature_sl; + 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 @@ -288,152 +327,177 @@ void FGClimate::set_temperate() double summer = _season_summer; double winter = 1.0 - summer; - double temp_min = _temperature_sl; - double temp_max = _temperature_sl; + double temp_night = _temperature_sl; + double temp_day = _temperature_sl; double precipitation = _precipitation; double relative_humidity = _relative_humidity; switch(_classicfication) { case 9: // Cfa: warm temperature, fully humid hot summer - temp_min = season_even(summer, -3.0, 20.0); - temp_max = season_even(summer, 10.0, 33.0); + temp_night = season_even(summer, -3.0, 20.0); + temp_day = season_even(summer, 10.0, 33.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; case 10: // Cfb: warm temperature, fully humid, warm summer - temp_min = season_even(summer, -3.0, 10.0); - temp_max = season_even(summer, 5.0, 25.0); - precipitation = linear(0.5*(summer + _season_winter), 44.0, 88.0); - relative_humidity = 0.8; + temp_night = season_even(summer, -3.0, 10.0); + temp_day = season_even(summer, 5.0, 25.0); + precipitation = linear(0.5*(summer+_season_transistional), 44.0, 88.0); + relative_humidity = season_even(summer, 0.68, 0.87); break; case 11: // Cfc: warm temperature, fully humid, cool summer - temp_min = season_long_low(summer, -3.0, 8.0); - temp_max = season_long_low(summer, 2.0, 14.0); + temp_night = season_long_low(summer, -3.0, 8.0); + temp_day = season_long_low(summer, 2.0, 14.0); precipitation = season_even(winter, 44.0, 88.0); - relative_humidity = 0.8; + relative_humidity = season_even(summer, 0.70, 0.85); break; case 12: // Csa: warm temperature, summer dry, hot summer - temp_min = season_even(summer, 2.0, 16.0); - temp_max = season_even(summer, 12.0, 33.0); - precipitation = season_long_low(summer, 25.0, 70.0); + temp_night = season_even(summer, 2.0, 16.0); + temp_day = season_even(summer, 12.0, 33.0); + precipitation = season_long_low(winter, 25.0, 70.0); + relative_humidity = season_even(winter, 0.58, 0.72); break; case 13: // Csb: warm temperature, summer dry, warm summer - temp_min = linear(summer, -4.0, 10.0); - temp_max = linear(summer, 6.0, 27.0); + temp_night = linear(summer, -4.0, 10.0); + temp_day = linear(summer, 6.0, 27.0); precipitation = season_short(winter, 25.0, 120.0); + relative_humidity = season_even(winter, 0.50, 0.72); break; case 14: // Csc: warm temperature, summer dry, cool summer - temp_min = season_even(summer, -4.0, 5.0); - temp_max = season_even(summer, 5.0, 16.0); - precipitation = season_even(summer, 60.0, 95.0); + temp_night = season_even(summer, -4.0, 5.0); + temp_day = season_even(summer, 5.0, 16.0); + precipitation = season_even(winter, 60.0, 95.0); + relative_humidity = season_even(winter, 0.55, 0.75); break; case 15: // Cwa: warm temperature, winter dry, hot summer - temp_min = season_even(summer, 4.0, 20.0); - temp_max = season_long_low(summer, 15.0, 30.0); + temp_night = season_even(summer, 4.0, 20.0); + temp_day = season_long_low(summer, 15.0, 30.0); precipitation = season_long_low(summer, 10.0, 320.0); + relative_humidity = season_even(summer, 0.60, 0.79); break; case 16: // Cwb: warm temperature, winter dry, warm summer - temp_min = season_even(summer, 1.0, 13.0); - temp_max = season_long_low(summer, 15.0, 27.0); + temp_night = season_even(summer, 1.0, 13.0); + temp_day = season_long_low(summer, 15.0, 27.0); precipitation = season_long_low(summer, 10.0, 250.0); + relative_humidity = season_even(summer, 0.58, 0.72); break; case 17: // Cwc: warm temperature, winter dry, cool summer - temp_min = season_long_high(winter, -9.0, 6.0); - temp_max = season_long_high(winter, 6.0, 17.0); + temp_night = season_long_high(summer, -9.0, 6.0); + temp_day = season_long_high(summer, 6.0, 17.0); precipitation = season_long_low(summer, 10.0, 200.0); + relative_humidity = season_even(summer, 0.50, 0.58); break; default: 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_mean = 0.5*(temp_min + temp_max); - _precipitation = precipitation; _relative_humidity = relative_humidity; + _precipitation = precipitation; + _has_autumn = true; _wind = 3.0; + } +// https://en.wikipedia.org/wiki/Continental_climate void FGClimate::set_continetal() { double day = _day_noon; double summer = _season_summer; + double winter = 1.0 - summer; - double temp_max = _temperature_sl; - double temp_min = _temperature_sl; + double temp_day = _temperature_sl; + double temp_night = _temperature_sl; + double precipitation = _precipitation; + double relative_humidity = _relative_humidity; switch(_classicfication) { case 18: // Dfa: snow, fully humid, hot summer - temp_min = season_even(summer, -15.0, 13.0); - temp_max = season_even(summer, -5.0, 30.0); - _precipitation = season_even(summer, 25.0, 65.0); + temp_night = season_even(summer, -15.0, 13.0); + temp_day = season_even(summer, -5.0, 30.0); + precipitation = season_even(summer, 25.0, 65.0); + relative_humidity = season_even(summer, 0.68, 0.72); break; case 19: // Dfb: snow, fully humid, warm summer, warm summer - temp_min = season_even(summer, -17.5, 10.0); - temp_max = season_even(summer, -7.5, 25.0); - _precipitation = season_even(summer, 30.0, 70.0); + temp_night = season_even(summer, -17.5, 10.0); + temp_day = season_even(summer, -7.5, 25.0); + precipitation = season_even(summer, 30.0, 70.0); + relative_humidity = season_even(summer, 0.69, 0.81); break; case 20: // Dfc: snow, fully humid, cool summer, cool summer - temp_min = season_even(summer, -30.0, 4.0); - temp_max = season_even(summer, -20.0, 15.0); - _precipitation = season_even(summer, 22.0, 68.0); - _precipitation = 50.0 - 25.0*summer; + temp_night = season_even(summer, -30.0, 4.0); + temp_day = season_even(summer, -20.0, 15.0); + precipitation = season_even(summer, 22.0, 68.0); + relative_humidity = season_even(summer, 0.70, 0.88); break; case 21: // Dfd: snow, fully humid, extremely continetal - temp_min = season_short(summer, -45.0, 4.0); - temp_max = season_short(summer, -35.0, 10.0); - _precipitation = season_long_low(summer, 7.5, 45.0); + temp_night = season_short(summer, -45.0, 4.0); + temp_day = season_short(summer, -35.0, 10.0); + precipitation = season_long_low(summer, 7.5, 45.0); + relative_humidity = season_long_low(summer, 0.80, 0.90); break; case 22: // Dsa: snow, summer dry, hot summer - temp_min = season_even(summer, -10.0, 10.0); - temp_max = season_even(summer, 0.0, 30.0); - _precipitation = season_long_high(summer, 2.0, 70.0); + temp_night = season_even(summer, -10.0, 10.0); + temp_day = season_even(summer, 0.0, 30.0); + precipitation = season_long_high(winter, 2.0, 70.0); + relative_humidity = season_long_high(winter, 0.48, 0.58); break; case 23: // Dsb: snow, summer dry, warm summer - temp_min = season_even(summer, -15.0, 6.0); - temp_max = season_even(summer, -4.0, 25.0); - _precipitation = season_long_high(summer, 12.0, 73.0); + temp_night = season_even(summer, -15.0, 6.0); + temp_day = season_even(summer, -4.0, 25.0); + precipitation = season_long_high(winter, 12.0, 73.0); + relative_humidity = season_long_high(winter, 0.50, 0.68); break; case 24: // Dsc: snow, summer dry, cool summer - temp_min = season_even(summer, -27.5, 2.0); - temp_max = season_even(summer, -4.0, 15.0); - _precipitation = season_long_low(summer, 32.5, 45.0); + temp_night = season_even(summer, -27.5, 2.0); + temp_day = season_even(summer, -4.0, 15.0); + precipitation = season_long_low(summer, 32.5, 45.0); + relative_humidity = season_long_low(summer, 0.50, 0.60); break; case 25: // Dsd: snow, summer dry, extremely continetal - temp_min = season_even(summer, -11.5, -6.5); - temp_max = season_even(summer, 14.0, 27.0); - _precipitation = season_long_low(summer, 5.0, 90.0); + temp_night = season_even(summer, -11.5, -6.5); + temp_day = season_even(summer, 14.0, 27.0); + precipitation = season_long_low(summer, 5.0, 90.0); + relative_humidity = season_long_low(summer, 0.48, 0.62); break; case 26: // Dwa: snow, winter dry, hot summer - temp_min = season_even(summer, -18.0, 16.5); - temp_max = season_even(summer, -5.0, 25.0); - _precipitation = season_long_low(summer, 5.0, 180.0); + temp_night = season_even(summer, -18.0, 16.5); + temp_day = season_even(summer, -5.0, 25.0); + precipitation = season_long_low(summer, 5.0, 180.0); + relative_humidity = season_long_low(summer, 0.60, 0.68); break; case 27: // Dwb: snow, winter dry, warm summer - temp_min = season_even(summer, -28.0, 10.0); - temp_max = season_even(summer, -12.5, 22.5); - _precipitation = season_long_low(summer, 10.0, 140.0); + temp_night = season_even(summer, -28.0, 10.0); + temp_day = season_even(summer, -12.5, 22.5); + precipitation = season_long_low(summer, 10.0, 140.0); + relative_humidity = season_long_low(summer, 0.60, 0.72); break; case 28: // Dwc: snow, winter dry, cool summer - temp_min = season_even(summer, -33.0, 5.0); - temp_max = season_even(summer, -20.0, 20.0); - _precipitation = season_long_low(summer, 10.0, 110.0); + temp_night = season_even(summer, -33.0, 5.0); + temp_day = season_even(summer, -20.0, 20.0); + precipitation = season_long_low(summer, 10.0, 110.0); + relative_humidity = season_long_low(summer, 0.60, 0.78); break; case 29: // Dwd: snow, winter dry, extremely continetal - temp_min = season_even(summer, -57.5, 0.0); - temp_max = season_even(summer, -43.0, 15.0); - _precipitation = season_even(summer, 8.0, 63.0); + temp_night = season_even(summer, -57.5, 0.0); + temp_day = season_even(summer, -43.0, 15.0); + precipitation = season_even(summer, 8.0, 63.0); + relative_humidity = 0.80; break; default: 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_mean = 0.5*(temp_min + temp_max); - _precipitation = _precipitation; + _relative_humidity = relative_humidity; + _precipitation = precipitation; + _has_autumn = true; _wind = 3.0; double fact_lat = pow(fabs(pos.getLatitudeDeg())/90.0, 2.5); @@ -446,33 +510,36 @@ void FGClimate::set_polar() double summer = _season_summer; // polar climate also occurs high in the mountains - double temp_max = _temperature_sl; - double temp_min = _temperature_sl; + double temp_day = _temperature_sl; + double temp_night = _temperature_sl; + double precipitation = _precipitation; + double relative_humidity = _relative_humidity; switch(_classicfication) { case 30: // EF: polar frost - temp_min = season_long_low(summer, -35.0, -6.0); - temp_max = season_long_low(summer, -32.5, 0.0); - _precipitation = season_even(summer, 50.0, 80.0); + temp_night = season_long_low(summer, -35.0, -6.0); + temp_day = season_long_low(summer, -32.5, 0.0); + precipitation = season_even(summer, 50.0, 80.0); + relative_humidity = season_even(summer, 0.65, 0.75); break; case 31: // ET: polar tundra - temp_min = season_even(summer, -30.0, 0.0); - temp_max = season_even(summer, -22.5, 8.0); - _precipitation = season_even(summer, 15.0, 45.0); + temp_night = season_even(summer, -30.0, 0.0); + temp_day = season_even(summer, -22.5, 8.0); + precipitation = season_even(summer, 15.0, 45.0); + relative_humidity = season_even(summer, 0.60, 0.88); break; default: 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_mean = 0.5*(temp_min + temp_max); - _precipitation = _precipitation; + _relative_humidity = relative_humidity; + _precipitation = precipitation; + _has_autumn = false; _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() @@ -505,6 +572,7 @@ void FGClimate::set_environment() _snow_thickness = pow(snow_fact, 2.0); _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) { _dust_cover = 0.3 - 0.3*sqrtf(_precipitation/20.0); @@ -514,11 +582,13 @@ void FGClimate::set_environment() else { 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); - _lichen_cover = 0.0; - _dust_cover = 0.0; + double cover = std::min(_total_annual_precipitation, 990.0)/990.0; + _lichen_cover = 0.5*pow(wetness*cover, 1.5); } if (_environment_adjust) @@ -529,8 +599,8 @@ void FGClimate::set_environment() fgSetDouble("/environment/surface/dust-cover-factor", _dust_cover); fgSetDouble("/environment/surface/wetness-set", _wetness); fgSetDouble("/environment/surface/lichen-cover-factor", _lichen_cover); - if (_autumn) - fgSetDouble("/environment/season", 2.0*_season_winter); + if (_has_autumn && _is_autumn) + fgSetDouble("/environment/season", 2.0*_season_transistional); else fgSetDouble("/environment/season", 0.0); } @@ -543,6 +613,15 @@ double FGClimate::linear(double val, double min, double max) 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)) // 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) @@ -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) -// 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 double FGClimate::season_long_high(double val, double min, double max) { 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)) @@ -642,13 +721,13 @@ void FGClimate::report() std::cout << "===============================================" << std::endl; std::cout << "Climate report for:" << 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::cout << " Sun Longitude: " << _sun_longitude_deg << " deggrees" + std::cout << " Sun longitude: " << _sun_longitude_deg << " deg." << std::endl; - std::cout << " Viewer Latitude: " << pos.getLatitudeDeg() << " deggrees" + std::cout << " Viewer latitude: " << pos.getLatitudeDeg() << " deg." << " (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; std::cout << std::endl; std::cout << " Köppen classification: " << koppen_str[_classicfication] @@ -659,18 +738,22 @@ void FGClimate::report() << std::endl; std::cout << " Daytime....(0.0 = night .. 1.0 = day): " << _day_noon << std::endl; - std::cout << " Seal level temperature: " << _temperature_sl << " deg. C." + std::cout << " Sea level temperature: " << _temperature_sl << " deg. C." << std::endl; - std::cout << " Ground temperature: " << _temperature_gl << " deg. C." + std::cout << " Ground temperature: " << _temperature_gl << " deg. C." << std::endl; - std::cout << " Monthly Precipitation: " << _precipitation << " mm" + std::cout << " Mean temperature: " << _temperature_mean << " deg. C." << 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; + std::cout << " Rel. humidity: "<< _relative_humidity*100.0 << " %" + << std::endl; std::cout << " Dew point: " << _dew_point << " deg. C." << std::endl; std::cout << " Wind: " << _wind << " km/h" << std::endl << std::endl; - std::cout << " Snow level: " << _snow_level << " meters" << std::endl; - std::cout << " Snow Thickness.(0.0 = thin .. 1.0 = thick): " + std::cout << " Snow level: " << _snow_level << " m." << std::endl; + std::cout << " Snow thickness.(0.0 = thin .. 1.0 = thick): " << _snow_thickness << std::endl; std::cout << " Ice cover......(0.0 = none .. 1.0 = thick): " << _ice_cover << std::endl; @@ -681,7 +764,8 @@ void FGClimate::report() std::cout << " Lichen cover...(0.0 = none .. 1.0 = mossy): " << _lichen_cover << std::endl; 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; } #endif // REPORT_TO_CONSOLE diff --git a/src/Environment/climate.hxx b/src/Environment/climate.hxx index 34028c9f9..a6ff30bdb 100644 --- a/src/Environment/climate.hxx +++ b/src/Environment/climate.hxx @@ -29,7 +29,7 @@ // #include #include -#define REPORT_TO_CONSOLE false +#define REPORT_TO_CONSOLE 0 /* * Update environment parameters based on the Köppen-Geiger climate @@ -63,6 +63,7 @@ private: #endif // interpolate val (from 0.0 to 1.0) between min and 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_even(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 _season_summer = 1.0; - double _season_winter = 0.0; - bool _autumn = false; + double _season_transistional = 0.0; + bool _has_autumn = false; + bool _is_autumn = false; - int _col = 0; // screen coordinates - int _row = 0; int _classicfication = 0; // Köppen-Geiger classicfication // environment