10#include <osgDB/ReadFile>
12#include <simgear/misc/sg_path.hxx>
13#include <simgear/math/SGVec3.hxx>
14#include <simgear/math/SGVec4.hxx>
15#include <simgear/timing/sg_time.hxx>
16#include <simgear/constants.h>
45#define HOUR (0.5/24.0)
46#define MONTH (1.0/12.0)
50 SGPath img_path =
globals->get_fg_root() /
"Geodata" /
"koppen-geiger.png";
52 image = osgDB::readImageFile(img_path.utf8Str());
55 _image_width =
static_cast<double>( image->s() );
56 _image_height =
static_cast<double>( image->t() );
57 _epsilon = 36.0/_image_width;
63 _monthNode =
fgGetNode(
"/sim/time/utc/month",
true);
64 _metarSnowLevelNode =
fgGetNode(
"/environment/params/metar-updates-snow-level",
true);
66 _positionLatitudeNode =
fgGetNode(
"/position/latitude-deg",
true);
67 _positionLongitudeNode=
fgGetNode(
"/position/longitude-deg",
true);
68 _gravityNode =
fgGetNode(
"/environment/gravitational-acceleration-mps2",
true);
73 _rootNode =
fgGetNode(
"/environment/climate",
true);
74 _rootNode->getNode(
"description",
true)->setStringValue(_description[_code]);
75 _rootNode->getNode(
"classification",
true)->setStringValue(_classification[_code]);
77 _tiedProperties.setRoot( _rootNode );
86 _tiedProperties.Tie(
"weather-update", &_weather_update);
87 _tiedProperties.Tie(
"pressure-hpa", &_gl.pressure);
88 _tiedProperties.Tie(
"pressure-sea-level-hpa", &_gl.pressure);
89 _tiedProperties.Tie(
"relative-humidity", &_gl.relative_humidity);
90 _tiedProperties.Tie(
"relative-humidity-sea-level", &_sl.relative_humidity);
91 _tiedProperties.Tie(
"dewpoint-degc", &_gl.dewpoint);
92 _tiedProperties.Tie(
"dewpoint-sea-level-degc", &_sl.dewpoint);
93 _tiedProperties.Tie(
"temperature-degc", &_gl.temperature);
94 _tiedProperties.Tie(
"temperature-sea-level-degc", &_sl.temperature);
95 _tiedProperties.Tie(
"temperature-mean-degc", &_gl.temperature_mean);
96 _tiedProperties.Tie(
"temperature-mean-sea-level-degc", &_sl.temperature_mean);
97 _tiedProperties.Tie(
"temperature-seawater-degc", &_sl.temperature_water);
98 _tiedProperties.Tie(
"precipitation-month-mm", &_gl.precipitation);
99 _tiedProperties.Tie(
"precipitation-annual-mm", & _gl.precipitation_annual);
100 _tiedProperties.Tie(
"snow-level-m", &_snow_level);
101 _tiedProperties.Tie(
"wind-speed-mps", &_wind_speed);
102 _tiedProperties.Tie(
"wind-direction-deg", &_wind_direction);
103 _tiedProperties.Tie(
"visibility-m", &_visibility_m);
104 _tiedProperties.Tie(
"elevation-m", &_elevation_m);
105 _tiedProperties.Tie(
"mist-fact", &_mist);
106 _tiedProperties.Tie(
"fog-fact", &_fog);
111 _tiedProperties.Untie();
116 _prev_lat = -99999.0;
117 _prev_lon = -99999.0;
122 _wind_direction = -99999.0;
124 _snow_level = -99999.0;
125 _snow_thickness = -99999.0;
126 _ice_cover = -99999.0;
127 _dust_cover = -99999.0;
129 _lichen_cover = -99999.0;
130 _inland_ice_cover =
false;
141 _sun_longitude_deg = l->get_sun_lon()*SGD_RADIANS_TO_DEGREES;
142 _sun_latitude_deg = l->get_sun_lat()*SGD_RADIANS_TO_DEGREES;
145 double latitude_deg = _positionLatitudeNode->getDoubleValue();
146 double longitude_deg = _positionLongitudeNode->getDoubleValue();
148 _adj_latitude_deg = latitude_deg - _sun_latitude_deg;
149 _adj_longitude_deg = _sun_longitude_deg - longitude_deg;
150 if (_adj_longitude_deg < 0.0) _adj_longitude_deg += 360.0;
151 else if (_adj_longitude_deg >= 360.0) _adj_longitude_deg -= 360.0;
153 double diff_pos = fabs(_prev_lat - _adj_latitude_deg) +
154 fabs(_prev_lon - _adj_longitude_deg);
155 if (diff_pos > _epsilon )
157 if (diff_pos > 1.0)
reinit();
159 double north = latitude_deg >= 0.0 ? 1.0 : -1.0;
161 _is_autumn = (_monthNode->getIntValue() > 6) ? 1.0 : 0.0;
163 _is_autumn = (_monthNode->getIntValue() <= 6) ? 1.0 : 0.0;
166 _prev_lat = _adj_latitude_deg;
167 _prev_lon = _adj_longitude_deg;
170 update_season_factor();
179 double x = 180.0 + longitude_deg;
180 double y = 90.0 + latitude_deg;
181 double xs = x * _image_width/360.0;
182 double yt = y * _image_height/180.0;
183 double rxs = round(xs);
184 double ryt = round(yt);
186 int s =
static_cast<int>(rxs);
187 int t =
static_cast<int>(ryt);
188 color = image->getColor(s, t);
191 _elevation_m = _gl.elevation_m = 5600.0*color[1];
192 _gl.precipitation_annual = 150.0 + 9000.0*color[2];
193 _code =
static_cast<int>(floorf(255.0f*color[0]/4.0f));
196 SG_LOG(SG_ENVIRONMENT, SG_WARN,
"Climate Koppen code exceeds the maximum");
200 if (_code == 0) set_ocean();
201 else if (_code < 5) set_tropical();
202 else if (_code < 9) set_dry();
203 else if (_code < 18) set_temperate();
204 else if (_code < 30) set_continetal();
205 else if (_code < 32) set_polar();
209 _rootNode->getNode(
"description")->setStringValue(_description[_code]);
210 _rootNode->getNode(
"classification")->setStringValue(_classification[_code]);
217 _gl.dewpoint = _gl.temperature - ((100.0 - _gl.relative_humidity)/5.0);
251void FGClimate::update_daylight()
253 double declination = _sun_latitude_deg*SGD_DEGREES_TO_RADIANS;
254 double latitude_deg = _positionLatitudeNode->getDoubleValue();
255 double latitude = latitude_deg*SGD_DEGREES_TO_RADIANS;
257 double fact = -tan(
latitude) * tan(declination);
258 if (fact > 1.0) fact = 1.0;
259 else if (fact < -1.0) fact = -1.0;
261 _day_light = acos(fact)/SGD_PI;
265void FGClimate::update_day_factor()
268 _day_noon = fabs(_adj_longitude_deg - 180.0)/180.0;
270 double adj_lon = _adj_longitude_deg;
271 if (adj_lon >= 180.0) adj_lon -= 360.0;
272 _daytime = 1.0 - (adj_lon + 180.0)/360.0;
279void FGClimate::update_season_factor()
281 double latitude_deg = _positionLatitudeNode->getDoubleValue();
282 double sign = latitude_deg >= 0.0 ? 1.0 : -1.0;
284 _season_summer = (23.5 + sign*_sun_latitude_deg)/(2.0*23.5);
286 _seasons_year = (_is_autumn > 0.05) ? 1.0-0.5*_season_summer : 0.5*_season_summer;
288 _season_transistional = 2.0*(1.0 - _season_summer) - 1.0;
289 if (_season_transistional < 0.0) _season_transistional = 0.0;
290 else if (_season_transistional > 1.0) _season_transistional = 1.0;
294void FGClimate::update_pressure()
297 double Tc = _gl.temperature ? _gl.temperature : 1e-9;
298 double Psat = exp(34.494 - 4924.99/(Tc+237.1))/pow(Tc + 105.0, 1.57);
301 double Pv = 0.01*_gl.relative_humidity*Psat;
304 static const double R0 = 8.314462618;
305 static const double P0 = 101325.0;
306 static const double T0 = 288.15;
307 static const double L = 0.0065;
308 static const double M = 0.0289654;
310 double h = _gl.elevation_m/1000.0;
311 double g = _gravityNode->getDoubleValue();
312 double P =
P0*pow(1.0 - L*h/T0, g*
M/(L*R0));
318 _gl.pressure = 0.01*(Pd+Psat);
323void FGClimate::update_wind()
325 double latitude_deg = _positionLatitudeNode->getDoubleValue();
326 if (latitude_deg > 60.0)
328 double val = 1.0 - (latitude_deg - 60.0)/30.0;
329 _set(_wind_direction, linear(val, 0.0, 90.0));
330 if (_code == 0) _wind_speed = linear(val, 6.0, 10.0);
332 else if (latitude_deg > 30.0)
334 double val = (latitude_deg - 30.0)/30.0;
335 _set(_wind_direction, linear(val, 180.0, 270.0));
336 if (_code == 0) _wind_speed = linear(val, 5.0, 10.0);
337 else _wind_speed = linear(1.0 - val, 3.0, 5.0);
339 else if (latitude_deg > 0)
341 double val = 1.0 - latitude_deg/30.0;
342 _set(_wind_direction, linear(val, 0.0, 90.0));
343 if (_code == 0) _wind_speed = triangular(val, 5.0, 7.0);
344 else _wind_speed = triangular(fabs(val - 0.5), 3.0, 5.0);
346 else if (latitude_deg > -30.0)
348 double val = -latitude_deg/30.0;
349 _set(_wind_direction, linear(val, 90.0, 180.0));
350 if (_code == 0) _wind_speed = triangular(val, 5.0, 7.0);
351 else _wind_speed = triangular(fabs(val - 0.5), 3.0, 5.0);
353 else if (latitude_deg > -60.0)
355 double val = 1.0 - (latitude_deg + 30.0)/30.0;
356 _set(_wind_direction, linear(val, -90.0, 0.0));
357 if (_code == 0) _wind_speed = linear(val, 5.0, 10.0);
358 else _wind_speed = linear(1.0 - val, 3.0, 6.0);
362 double val = (latitude_deg + 60.0)/30.0;
363 _wind_direction = linear(val, 90.0, 180.0);
364 if (_code == 0) _wind_speed = linear(1.0 - val, 5.0, 10.0);
367 if (_wind_direction < 0.0) _wind_direction += 360.0;
371void FGClimate::set_ocean()
373 double day = _day_noon;
374 double summer = _season_summer;
378 double temp_equator_night = triangular(season(summer,
MONTH), 17.5, 22.5);
379 double temp_equator_day = triangular(season(summer,
MONTH), 27.5, 32.5);
380 double temp_equator_mean = linear(_day_light, temp_equator_night, temp_equator_day);
381 double temp_equator = linear(daytime(day, 3.0*
HOUR), temp_equator_night, temp_equator_day);
382 double temp_sw_Am = triangular(season(summer, 2.0*
MONTH), 22.0, 27.5);
385 double temp_pole_night = sinusoidal(season(summer,
MONTH), -30.0, 0.0);
386 double temp_pole_day = sinusoidal(season(summer, 1.5*
MONTH), -22.5, 4.0);
387 double temp_pole_mean = linear(_day_light, temp_pole_night, temp_pole_day);
388 double temp_pole = linear(daytime(day, 3.0*
HOUR), temp_pole_night, temp_pole_day);
389 double temp_sw_ET = long_low(season(summer, 2.0*
MONTH), -27.5, -3.5);
392 double latitude_deg = _positionLatitudeNode->getDoubleValue();
393 double fact_lat = pow(fabs(latitude_deg)/90.0, 2.5);
394 double ifact_lat = 1.0 - fact_lat;
396 _set(_gl.temperature, linear(ifact_lat, temp_pole, temp_equator));
397 _set(_gl.temperature_mean, linear(ifact_lat, temp_pole_mean, temp_equator_mean));
398 _set(_gl.temperature_water, linear(ifact_lat, temp_sw_ET, temp_sw_Am));
401 _set(_gl.relative_humidity, triangular(fabs(fact_lat-0.5), 70.0, 87.0));
403 _set(_gl.precipitation_annual, 990.0);
404 _set(_gl.precipitation, 100.0 - (_gl.precipitation_annual/25.0));
406 _gl.has_autumn =
false;
411void FGClimate::set_tropical()
413 double day = _day_noon;
415 double summer = _season_summer;
416 double winter = -summer;
418 double hmin = sinusoidal(summer, 0.0, 0.36);
419 double hmax = sinusoidal(season(winter), 0.86, 1.0);
420 double humidity = linear(daytime(day, -9.0*
HOUR), hmin, hmax);
423 double latitude_deg = _positionLatitudeNode->getDoubleValue();
424 double fact_lat = std::max(
abs(latitude_deg), 15.0)/15.0;
425 double wind_speed = 3.0*fact_lat*fact_lat;
427 double temp_water = _gl.temperature_water;
428 double temp_night = _sl.temperature;
429 double temp_day = _sl.temperature;
430 double precipitation = _gl.precipitation;
431 double relative_humidity = _gl.relative_humidity;
435 temp_night = triangular(summer, 20.0, 22.5);
436 temp_day = triangular(summer, 29.5, 32.5);
437 temp_water = triangular(season(summer,
MONTH), 25.0, 27.5);
438 precipitation = sinusoidal(season(winter), 150.0, 280.0);
439 relative_humidity = triangular(humidity, 75.0, 85.0);
442 temp_night = triangular(season(summer,
MONTH), 17.5, 22.5);
443 temp_day = triangular(season(summer,
MONTH), 27.5, 32.5);
444 temp_water = triangular(season(summer,
MONTH), 22.0, 27.5);
445 precipitation = linear(season(summer,
MONTH), 45.0, 340.0);
446 relative_humidity = triangular(humidity, 75.0, 85.0);
447 wind_speed *= 2.0*_gl.precipitation/340.0;
450 temp_night = long_high(season(summer, .15*
MONTH), 15.0, 22.5);
451 temp_day = triangular(season(summer,
MONTH), 27.5, 35.0);
452 temp_water = triangular(season(summer, 2.0*
MONTH), 21.5, 26.5);
453 precipitation = sinusoidal(season(summer, 2.0*
MONTH), 35.0, 150.0);
454 relative_humidity = triangular(humidity, 60.0, 80.0);
455 wind_speed *= 2.0*_gl.precipitation/150.0;
458 temp_night = long_high(season(summer, 1.5*
MONTH), 15.0, 22.5);
459 temp_day = triangular(season(summer, 2.0*
MONTH), 27.5, 35.0);
460 temp_water = triangular(season(summer, 2.0*
MONTH), 21.5, 28.5);
461 precipitation = sinusoidal(season(summer, 2.0*
MONTH), 10.0, 230.0);
462 relative_humidity = triangular(humidity, 60.0, 80.0);
463 wind_speed *= 2.0*_gl.precipitation/230.0;
469 _set(_gl.temperature, linear(daytime(day, 3.0*
HOUR), temp_night, temp_day));
470 _set(_gl.temperature_mean, linear(_day_light, temp_night, temp_day));
471 _set(_gl.temperature_water, temp_water);
473 _set(_gl.relative_humidity, relative_humidity);
474 _set(_gl.precipitation, precipitation);
476 _gl.has_autumn =
false;
477 _wind_speed = wind_speed;
482void FGClimate::set_dry()
484 double day = _day_noon;
486 double summer = _season_summer;
487 double winter = -summer;
489 double hmin = sinusoidal(summer, 0.0, 0.36);
490 double hmax = sinusoidal(season(winter), 0.86, 1.0);
491 double humidity = linear(daytime(day, -9.0*
HOUR), hmin, hmax);
493 double temp_water = _gl.temperature_water;
494 double temp_night = _sl.temperature;
495 double temp_day = _sl.temperature;
496 double precipitation = _gl.precipitation;
497 double relative_humidity = _gl.relative_humidity;
501 temp_night = long_high(season(summer,
MONTH), 10.0, 22.0);
502 temp_day = triangular(season(summer, 2.0*
MONTH), 27.5, 35.0);
503 temp_water = triangular(season(summer, 2.5*
MONTH), 18.5, 28.5);
504 precipitation = long_low(season(summer, 2.0*
MONTH), 8.0, 117.0);
505 relative_humidity = triangular(humidity, 20.0, 30.0);
508 temp_night = sinusoidal(season(summer,
MONTH), -14.0, 12.0);
509 temp_day = sinusoidal(season(summer,
MONTH), 0.0, 30.0);
510 temp_water = sinusoidal(season(summer, 2.0*
MONTH), 5.0, 25.5);
511 precipitation = sinusoidal(season(summer,
MONTH), 15.0, 34.0);
512 relative_humidity = sinusoidal(humidity, 48.0, 67.0);
515 temp_night = sinusoidal(season(summer, 1.5*
MONTH), 7.5, 22.0);
516 temp_day = even(season(summer, 1.5*
MONTH), 22.5, 37.5);
517 temp_water = even(season(summer, 2.5*
MONTH), 15.5, 33.5);
518 precipitation = monsoonal(season(summer, 2.0*
MONTH), 3.0, 18.0);
519 relative_humidity = monsoonal(humidity, 25.0, 55.0);
522 temp_night = sinusoidal(season(summer,
MONTH), -15.0, 15.0);
523 temp_day = sinusoidal(season(summer,
MONTH), -2.0, 30.0);
524 temp_water = sinusoidal(season(summer, 2.0*
MONTH), 4.0, 26.5);
525 precipitation = linear(season(summer,
MONTH), 4.0, 14.0);
526 relative_humidity = linear(humidity, 45.0, 61.0);
532 _set(_gl.temperature, linear(daytime(day, 3.0*
HOUR), temp_night, temp_day));
533 _set(_gl.temperature_mean, linear(_day_light, temp_night, temp_day));
534 _set(_gl.temperature_water, temp_water);
536 _set(_gl.relative_humidity, relative_humidity);
537 _set(_gl.precipitation, precipitation);
538 _gl.has_autumn =
false;
542void FGClimate::set_temperate()
544 double day = _day_noon;
546 double summer = _season_summer;
547 double winter = -summer;
549 double hmin = sinusoidal(summer, 0.0, 0.36);
550 double hmax = sinusoidal(season(winter), 0.86, 1.0);
551 double humidity = linear(daytime(day, -9.0*
HOUR), hmin, hmax);
553 double temp_water = _gl.temperature_water;
554 double temp_night = _sl.temperature;
555 double temp_day = _sl.temperature;
556 double precipitation = _gl.precipitation;
557 double relative_humidity = _gl.relative_humidity;
561 temp_night = sinusoidal(season(summer, 1.5*
MONTH), -3.0, 20.0);
562 temp_day = sinusoidal(season(summer, 1.5*
MONTH), 10.0, 33.0);
563 temp_water = sinusoidal(season(summer, 2.5*
MONTH), 8.0, 28.5);
564 precipitation = sinusoidal(summer, 60.0, 140.0);
565 relative_humidity = sinusoidal(humidity, 65.0, 80.0);
568 temp_night = sinusoidal(season(summer, 1.5*
MONTH), -3.0, 10.0);
569 temp_day = sinusoidal(season(summer, 1.5*
MONTH), 5.0, 25.0);
570 temp_water = sinusoidal(season(summer, 2.5*
MONTH), 3.0, 20.5);
571 precipitation = sinusoidal(season(winter, 3.5*
MONTH), 65.0, 90.0);
572 relative_humidity = sinusoidal(humidity, 68.0, 87.0);
575 temp_night = long_low(season(summer, 1.5*
MONTH), -3.0, 8.0);
576 temp_day = long_low(season(summer, 1.5*
MONTH), 2.0, 14.0);
577 temp_water = long_low(season(summer, 2.5*
MONTH), 3.0, 11.5);
578 precipitation = linear(season(winter), 90.0, 200.0);
579 relative_humidity = long_low(humidity, 70.0, 85.0);
582 temp_night = sinusoidal(season(summer,
MONTH), 2.0, 16.0);
583 temp_day = sinusoidal(season(summer,
MONTH), 12.0, 33.0);
584 temp_water = sinusoidal(season(summer, 2.0*
MONTH), 10.0, 27.5);
585 precipitation = linear(season(winter), 25.0, 70.0);
586 relative_humidity = sinusoidal(humidity, 58.0, 72.0);
589 temp_night = linear(season(summer, 1.5*
MONTH), -4.0, 10.0);
590 temp_day = linear(season(summer, 1.5*
MONTH), 6.0, 27.0);
591 temp_water = linear(season(summer, 2.5*
MONTH), 4.0, 21.5);
592 precipitation = linear(season(winter), 25.0, 120.0);
593 relative_humidity = linear(humidity, 50.0, 72.0);
596 temp_night = sinusoidal(season(summer, 0.5*
MONTH), -4.0, 5.0);
597 temp_day = sinusoidal(season(summer, 0.5*
MONTH), 5.0, 16.0);
598 temp_water = sinusoidal(season(summer, 1.5*
MONTH), 3.0, 14.5);
599 precipitation = sinusoidal(season(winter, -
MONTH), 60.0, 95.0);
600 relative_humidity = sinusoidal(humidity, 55.0, 75.0);
603 temp_night = even(season(summer,
MONTH), 4.0, 20.0);
604 temp_day = long_low(season(summer,
MONTH), 15.0, 30.0);
605 temp_water = long_low(season(summer, 2.0*
MONTH), 7.0, 24.5);
606 precipitation = long_low(season(summer,
MONTH), 10.0, 320.0);
607 relative_humidity = sinusoidal(humidity, 60.0, 79.0);
610 temp_night = even(season(summer,
MONTH), 1.0, 13.0);
611 temp_day = long_low(season(summer,
MONTH), 15.0, 27.0);
612 temp_water = even(season(summer, 2.0*
MONTH), 5.0, 22.5);
613 precipitation = long_low(season(summer,
MONTH), 10.0, 250.0);
614 relative_humidity = sinusoidal(humidity, 58.0, 72.0);
617 temp_night = long_low(season(summer,
MONTH), -9.0, 6.0);
618 temp_day = long_high(season(summer,
MONTH), 6.0, 17.0);
619 temp_water = long_high(season(summer, 2.0*
MONTH), 8.0, 15.5);
620 precipitation = long_low(season(summer,
MONTH), 5.0, 200.0);
621 relative_humidity = long_high(humidity, 50.0, 58.0);
627 _set(_gl.temperature, linear(daytime(day, 3.0*
HOUR), temp_night, temp_day));
628 _set(_gl.temperature_mean, linear(_day_light, temp_night, temp_day));
629 _set(_gl.temperature_water, temp_water);
631 _set(_gl.relative_humidity, relative_humidity);
632 _set(_gl.precipitation, precipitation);
634 _gl.has_autumn =
true;
639void FGClimate::set_continetal()
641 double day = _day_noon;
643 double summer = _season_summer;
644 double winter = -summer;
646 double hmin = sinusoidal(summer, 0.0, 0.36);
647 double hmax = sinusoidal(season(winter), 0.86, 1.0);
648 double humidity = linear(daytime(day, -9.0*
HOUR), hmin, hmax);
650 double temp_water = _gl.temperature_water;
651 double temp_day = _sl.temperature;
652 double temp_night = _sl.temperature;
653 double precipitation = _gl.precipitation;
654 double relative_humidity = _gl.relative_humidity;
658 temp_night = sinusoidal(season(summer,
MONTH), -15.0, 13.0);
659 temp_day = sinusoidal(season(summer,
MONTH), -5.0, 30.0);
660 temp_water = sinusoidal(season(summer, 2.0*
MONTH), 0.0, 26.5);
661 precipitation = linear(season(summer,
MONTH), 30.0, 70.0);
662 relative_humidity = sinusoidal(humidity, 68.0, 72.0);
665 temp_night = sinusoidal(season(summer,
MONTH), -17.5, 10.0);
666 temp_day = sinusoidal(season(summer,
MONTH), -7.5, 25.0);
667 temp_water = sinusoidal(season(summer, 2.0*
MONTH), -2.0, 22.5);
668 precipitation = linear(season(summer,
MONTH), 30.0, 70.0);
669 relative_humidity = sinusoidal(humidity, 69.0, 81.0);
672 temp_night = sinusoidal(season(summer,
MONTH), -30.0, 4.0);
673 temp_day = sinusoidal(season(summer,
MONTH), -20.0, 15.0);
674 temp_water = sinusoidal(season(summer, 2.0*
MONTH), -10.0, 12.5);
675 precipitation = linear(season(summer, 1.5*
MONTH), 22.0, 68.0);
676 relative_humidity = sinusoidal(humidity, 70.0, 88.0);
680 temp_night = sinusoidal(season(summer,
MONTH), -45.0, 4.0);
681 temp_day = sinusoidal(season(summer,
MONTH), -35.0, 10.0);
682 temp_water = sinusoidal(season(summer, 2.0*
MONTH), -15.0, 8.5);
683 precipitation = long_low(season(summer, 1.5*
MONTH), 7.5, 45.0);
684 relative_humidity = sinusoidal(humidity, 80.0, 90.0);
687 temp_night = sinusoidal(season(summer, 1.5*
MONTH), -10.0, 10.0);
688 temp_day = sinusoidal(season(summer, 1.5*
MONTH), 0.0, 30.0);
689 temp_water = sinusoidal(season(summer, 3.5*
MONTH), 4.0, 24.5);
690 precipitation = long_high(season(winter, 2.0*
MONTH), 5.0, 65.0);
691 relative_humidity = sinusoidal(humidity, 48.0, 58.08);
694 temp_night = sinusoidal(season(summer, 1.5*
MONTH), -15.0, 6.0);
695 temp_day = sinusoidal(season(summer, 1.5*
MONTH), -4.0, 25.0);
696 temp_water = sinusoidal(season(summer, 2.5*
MONTH), 0.0, 19.5);
697 precipitation = long_high(season(winter, 2.0*
MONTH), 12.0, 65.0);
698 relative_humidity = sinusoidal(humidity, 50.0, 68.0);
701 temp_night = sinusoidal(season(summer,
MONTH), -27.5, 2.0);
702 temp_day = sinusoidal(season(summer,
MONTH), -4.0, 15.0);
703 temp_water = sinusoidal(season(summer, 2.0*
MONTH), 0.0, 12.5);
704 precipitation = long_low(season(summer,
MONTH), 32.5, 45.0);
705 relative_humidity = sinusoidal(humidity, 50.0, 60.0);
708 temp_night = sinusoidal(season(summer,
MONTH), -11.5, -6.5);
709 temp_day = sinusoidal(season(summer,
MONTH), 14.0, 27.0);
710 temp_water = sinusoidal(season(summer, 2.0*
MONTH), 8.0, 20.5);
711 precipitation = long_low(season(summer,
MONTH), 5.0, 90.0);
712 relative_humidity = sinusoidal(humidity, 48.0, 62.0);
715 temp_night = sinusoidal(season(summer,
MONTH), -18.0, 16.5);
716 temp_day = sinusoidal(season(summer,
MONTH), -5.0, 25.0);
717 temp_water = sinusoidal(season(summer, 2.0*
MONTH), 0.0, 23.5);
718 precipitation = long_low(season(summer, 1.5*
MONTH), 5.0, 180.0);
719 relative_humidity = sinusoidal(humidity, 60.0, 68.0);
722 temp_night = sinusoidal(season(summer,
MONTH), -28.0, 10.0);
723 temp_day = sinusoidal(season(summer,
MONTH), -12.5, 22.5);
724 temp_water = sinusoidal(season(summer, 2.0*
MONTH), -5.0, 18.5);
725 precipitation = long_low(season(summer, 1.5*
MONTH), 10.0, 140.0);
726 relative_humidity = sinusoidal(humidity, 60.0, 72.0);
729 temp_night = sinusoidal(season(summer,
MONTH), -33.0, 5.0);
730 temp_day = sinusoidal(season(summer,
MONTH), -20.0, 20.0);
731 temp_water = sinusoidal(season(summer, 2.0*
MONTH), -10.0, 16.5);
732 precipitation = long_low(season(summer, 1.5*
MONTH), 10.0, 110.0);
733 relative_humidity = sinusoidal(humidity, 60.0, 78.0);
736 temp_night = sinusoidal(season(summer,
MONTH), -57.5, 0.0);
737 temp_day = sinusoidal(season(summer,
MONTH), -43.0, 15.0);
738 temp_water = sinusoidal(season(summer, 2.0*
MONTH), -28.0, 11.5);
739 precipitation = sinusoidal(season(summer, 1.5*
MONTH), 8.0, 63.0);
740 relative_humidity = 80.0;
746 _set(_gl.temperature, linear(daytime(day, 3.0*
HOUR), temp_night, temp_day));
747 _set(_gl.temperature_mean, linear(_day_light, temp_night, temp_day));
748 _set(_gl.temperature_water, temp_water);
750 _set(_gl.relative_humidity, relative_humidity);
751 _set(_gl.precipitation, precipitation);
753 _gl.has_autumn =
true;
756void FGClimate::set_polar()
758 double day = _day_noon;
760 double summer = _season_summer;
761 double winter = -summer;
763 double hmin = sinusoidal(summer, 0.0, 0.36);
764 double hmax = sinusoidal(season(winter), 0.86, 1.0);
765 double humidity = linear(daytime(day, -9.0*
HOUR), hmin, hmax);
768 double temp_water = _gl.temperature_water;
769 double temp_day = _sl.temperature;
770 double temp_night = _sl.temperature;
771 double precipitation = _gl.precipitation;
772 double relative_humidity = _gl.relative_humidity;
776 temp_night = long_low(season(summer,
MONTH), -35.0, -6.0);
777 temp_day = long_low(season(summer,
MONTH), -32.5, 0.0);
778 temp_water = long_low(season(summer, 2.0*
MONTH), -27.5, -3.5);
779 precipitation = linear(season(summer, 2.5*
MONTH), 50.0, 80.0);
780 relative_humidity = long_low(humidity, 65.0, 75.0);
784 temp_night = sinusoidal(season(summer,
MONTH), -30.0, 0.0);
785 temp_day = sinusoidal(season(summer, 1.5*
MONTH), -22.5, 8.0);
786 temp_water = sinusoidal(season(summer, 2.0*
MONTH), -15.0, 5.0);
787 precipitation = sinusoidal(season(summer, 2.0*
MONTH), 15.0, 45.0);
788 relative_humidity = sinusoidal(humidity, 60.0, 88.0);
795 _set(_gl.temperature, linear(daytime(day, 3.0*
HOUR), temp_night, temp_day));
796 _set(_gl.temperature_mean, linear(_day_light, temp_night, temp_day));
797 _set(_gl.temperature_water, temp_water);
799 _set(_gl.relative_humidity, relative_humidity);
800 _set(_gl.precipitation, precipitation);
802 _gl.has_autumn =
true;
805void FGClimate::set_environment()
807 double snow_fact, precipitation;
809 _set(_snow_level, 1000.0*_sl.temperature_mean/9.8);
815 double humidity, diff_temp_dewpoint;
816 if (1 || !_weather_update)
818 humidity =
fgGetDouble(
"/environment/relative-humidity", 0.0);
819 diff_temp_dewpoint =
fgGetDouble(
"/environment/temperature-degc", 0.0) -
824 humidity = _gl.relative_humidity;
825 diff_temp_dewpoint = _gl.temperature - _gl.dewpoint;
828 _mist = pow(4.17*std::max(0.01*humidity-0.76, 0.0), 0.03);
829 _fog = exp(-1.842*diff_temp_dewpoint);
831 double val = 0.01*_mist + 0.99*_fog;
832 _visibility_m = _max_visibility_m*(1.0 - val);
835 if (_gl.precipitation < 60.0) {
840 precipitation = _gl.precipitation - 60.0;
841 precipitation = (precipitation > 240.0) ? 1.0 : precipitation/240.0;
844 if (_gl.temperature_mean > 5.0 || precipitation < 0.1) {
849 snow_fact = fabs(_gl.temperature_mean) - 5.0;
850 snow_fact = (snow_fact > 10.0) ? 1.0 : snow_fact/10.0;
851 snow_fact *= precipitation;
855 if (_is_autumn < 0.95 || _sl.temperature_mean > -2.0) {
856 _set(_ice_cover, 0.0);
858 _set(_ice_cover, std::min(-(_sl.temperature_water+2.0)/10.0, 1.0));
862 if (_gl.temperature_mean > 0.5) {
863 _inland_ice_cover =
false;
865 _inland_ice_cover =
true;
869 if (_gl.precipitation < 20.0 || _gl.precipitation_annual < 240.0)
871 _set(_dust_cover, 0.3 - 0.3*sqrtf(_gl.precipitation/20.0));
872 _set(_snow_thickness, 0.0);
873 _set(_lichen_cover, 0.0);
880 if (_gl.temperature_mean < 5.0)
882 double wetness = 12.0*_gl.precipitation/990.0;
883 wetness = pow(sin(atan(SGD_PI*wetness)), 2.0);
884 _snow_thickness = wetness;
886 _snow_thickness = 0.0;
889 if (_gl.temperature_mean > 0.0)
892 _wetness = 9.0*std::max(_gl.precipitation-50.0, 0.0)/990.0;
894 double diff = std::max(_gl.temperature - _gl.dewpoint, 2.5)/2.5;
895 _wetness = std::min(_wetness/diff, 1.0);
900 double cover = std::min(_gl.precipitation_annual, 990.0)/990.0;
901 _set(_lichen_cover, 0.5*pow(_wetness*cover, 1.5));
904 _rootNode->setDoubleValue(
"daytime-pct", _daytime*100.0);
905 _rootNode->setDoubleValue(
"daylight-pct", _day_light*100.0);
906 _rootNode->setDoubleValue(
"day-noon-pct", _day_noon*100.0);
907 _rootNode->setDoubleValue(
"season-summer-pct", _season_summer*100.0);
908 _rootNode->setDoubleValue(
"seasons-year-pct", _seasons_year*100.0);
909 _rootNode->setDoubleValue(
"season-autumn-pct", ((_gl.has_autumn && _is_autumn > 0.05) ? _season_transistional*100.0 : 0.0));
914 fgSetDouble(
"/environment/relative-humidity", _gl.relative_humidity);
915 fgSetDouble(
"/environment/dewpoint-sea-level-degc", _sl.dewpoint);
916 fgSetDouble(
"/environment/dewpoint-degc", _gl.dewpoint);
917 fgSetDouble(
"/environment/temperature-sea-level-degc", _sl.temperature);
918 fgSetDouble(
"/environment/temperature-degc", _gl.temperature);
919 fgSetDouble(
"/environment/wind-speed-mps", _wind_speed);
923 if (_environment_adjust)
925 if (!_metarSnowLevelNode->getBoolValue()) {
926 fgSetDouble(
"/environment/snow-level-m", _snow_level);
928 fgSetDouble(
"/environment/surface/snow-thickness-factor", _snow_thickness);
929 fgSetBool(
"/environment/surface/ice-cover", _inland_ice_cover);
930 fgSetDouble(
"/environment/sea/surface/ice-cover", _ice_cover);
931 fgSetDouble(
"/environment/surface/dust-cover-factor", _dust_cover);
932 fgSetDouble(
"/environment/surface/wetness-set", _wetness);
933 fgSetDouble(
"/environment/surface/lichen-cover-factor", _lichen_cover);
935 double season = 1.7*std::pow(_season_transistional, 4.0);
936 if (_gl.has_autumn && season > 0.01)
938 if (_is_autumn > 0.01) {
939 fgSetDouble(
"/environment/season", _is_autumn*season);
941 fgSetDouble(
"/environment/season", 1.5+0.25*season);
951 double latitude_deg = _positionLatitudeNode->getDoubleValue();
952 double desert_pct = std::min( fabs(latitude_deg-23.5)/23.5, 1.0);
953 fgSetDouble(
"/sim/rendering/desert", 0.1-0.2*desert_pct);
958 _environment_adjust = value;
960 if (_metarSnowLevelNode)
967 if (!_metarSnowLevelNode->getBoolValue()) {
970 fgSetDouble(
"/environment/surface/snow-thickness-factor", 0.0);
971 fgSetDouble(
"/environment/sea/surface/ice-cover", 0.0);
972 fgSetDouble(
"/environment/surface/dust-cover-factor", 0.0);
973 fgSetDouble(
"/environment/surface/wetness-set", 0.0);
974 fgSetDouble(
"/environment/surface/lichen-cover-factor", 0.0);
984 m << std::fixed << std::setprecision(0);
987 m << std::setw(2) << std::setfill(
'0') <<
fgGetInt(
"/sim/time/utc/day");
988 m << std::setw(2) << std::setfill(
'0') <<
fgGetInt(
"/sim/time/utc/hour");
989 m << std::setw(2) << std::setfill(
'0') <<
fgGetInt(
"/sim/time/utc/minute");
992 m << std::setw(3) << std::setfill(
'0') << _wind_direction;
993 m << std::setw(2) << std::setfill(
'0') << _wind_speed <<
"MPS ";
995 if (_gl.temperature < 0.0) {
996 m <<
"M" << std::setw(2) << std::setfill(
'0') << fabs(_gl.temperature);
998 m << std::setw(2) << std::setfill(
'0') << _gl.temperature;
1003 if (_gl.dewpoint < 0.0) {
1004 m <<
"M" << std::setw(2) << std::setfill(
'0') << fabs(_gl.dewpoint);
1006 m << std::setw(2) << std::setfill(
'0') << _gl.dewpoint;
1009 m <<
" Q" << _sl.pressure;
1013 char *rv = std::strncpy((
char*)&_metar, m.str().c_str(), 255);
1023 "Af",
"Am",
"As",
"Aw",
1024 "BSh",
"BSk",
"BWh",
"BWk",
1025 "Cfa",
"Cfb",
"Cfc",
1026 "Csa",
"Csb",
"Csc",
1027 "Cwa",
"Cwb",
"Cwc",
1028 "Dfa",
"Dfb",
"Dfc",
"Dfd",
1029 "Dsa",
"Dsb",
"Dsc",
"Dsd",
1030 "Dwa",
"Dwb",
"Dwc",
"Dwd",
1036 "Equatorial, fully humid",
1037 "Equatorial, monsoonal",
1038 "Equatorial, summer dry",
1039 "Equatorial, winter dry",
1040 "Arid, steppe, hot arid",
1041 "Arid, steppe, cold arid",
1042 "Arid, desert, hot arid",
1043 "Arid, desert, cold arid",
1044 "Warm temperature, fully humid hot summer",
1045 "Warm temperature, fully humid, warm summer",
1046 "Warm temperature, fully humid, cool summer",
1047 "Warm temperature, summer dry, hot summer",
1048 "Warm temperature, summer dry, warm summer",
1049 "Warm temperature, summer dry, cool summer",
1050 "Warm temperature, winter dry, hot summer",
1051 "Warm temperature, winter dry, warm summer",
1052 "Warm temperature, winter dry, cool summer",
1053 "Snow, fully humid, hot summer",
1054 "Snow, fully humid, warm summer",
1055 "Snow, fully humid, cool summer",
1056 "Snow, fully humid, extremely continetal",
1057 "Snow, summer dry, hot summer",
1058 "Snow, summer dry, warm summer",
1059 "Snow, summer dry, cool summer",
1060 "Snow, summer dry, extremely continetal",
1061 "Snow, winter dry, hot summer",
1062 "Snow, winter dry, warm summer",
1063 "Snow, winter dry, cool summer",
1064 "Snow, winter dry, extremely continetal",
1071double FGClimate::daytime(
double val,
double offset)
1073 val = fmod(fabs(_daytime - offset), 1.0);
1074 val = (val > 0.5) ? 2.0 - 2.0*val : 2.0*val;
1078double FGClimate::season(
double val,
double offset)
1080 val = (val >= 0.0) ? fmod(fabs(_seasons_year - offset), 1.0)
1081 : fmod(fabs(1.0 - _seasons_year + offset), 1.0);
1082 val = (val > 0.5) ? 2.0 - 2.0*val : 2.0*val;
1087double FGClimate::linear(
double val,
double min,
double max)
1089 double diff = max-
min;
1090 return min + val*diff;
1095double FGClimate::triangular(
double val,
double min,
double max)
1097 double diff = max-
min;
1098 val = 1.0 - fabs(-1.0 + 2.0*val);
1099 return min + val*diff;
1105double FGClimate::sinusoidal(
double val,
double min,
double max)
1107 double diff = max-
min;
1108 return min + diff*(0.5 - 0.5*cos(SGD_PI*val));
1113double FGClimate::even(
double val,
double min,
double max)
1115 double diff = max-
min;
1116 return min + diff*(0.5 - 0.6366*atan(cos(SGD_PI*val)));
1122double FGClimate::long_low(
double val,
double min,
double max)
1124 double diff = max-
min;
1125 return min + diff*(0.5 - 0.5*cos(pow(2.145*val, 1.5)));
1131double FGClimate::long_high(
double val,
double min,
double max)
1133 double diff = max-
min;
1134 return max - diff*(0.5 - 0.5*cos(pow(2.14503 - 2.14503*val, 1.5)));
1139double FGClimate::monsoonal(
double val,
double min,
double max)
1141 double diff = max-
min;
1142 val = 2.0*SGD_2PI*(1.0-val);
1143 return min + diff*cos(atan(val*val));
1150 printf(
"month:\t\t");
1151 for (
int month=0; month<12; ++month) {
1152 printf(
"%5i", month+1);
1155 printf(
"\nlinear:\t\t");
1156 for (
int month=0; month<12; ++month) {
1157 double val = (month > 6) ? (12 - month)/6.0 : month/6.0;
1158 _seasons_year = month/12.0;
1159 printf(
" %-3.2f", linear(season(val, offs), 0.0, 1.0) );
1162 printf(
"\ntriangular:\t");
1163 for (
int month=0; month<12; ++month) {
1164 double val = (month > 6) ? (12 - month)/6.0 : month/6.0;
1165 _seasons_year = month/12.0;
1166 printf(
" %-3.2f", triangular(season(val, offs), 0.0, 1.0) );
1169 printf(
"\neven:\t\t");
1170 for (
int month=0; month<12; ++month) {
1171 double val = (month > 6) ? (12 - month)/6.0 : month/6.0;
1172 _seasons_year = month/12.0;
1173 printf(
" %-3.2f", sinusoidal(season(val, offs), 0.0, 1.0) );
1176 printf(
"\nlong:\t\t");
1177 for (
int month=0; month<12; ++month) {
1178 double val = (month > 6) ? (12 - month)/6.0 : month/6.0;
1179 _seasons_year = month/12.0;
1180 printf(
" %-3.2f", even(season(val, offs), 0.0, 1.0) );
1183 printf(
"\nlong low:\t");
1184 for (
int month=0; month<12; ++month) {
1185 double val = (month > 6) ? (12 - month)/6.0 : month/6.0;
1186 _seasons_year = month/12.0;
1187 printf(
" %-3.2f", long_low(season(val, offs), 0.0, 1.0) );
1190 printf(
"\nlong high:\t");
1191 for (
int month=0; month<12; ++month) {
1192 double val = (month > 6) ? (12 - month)/6.0 : month/6.0;
1193 _seasons_year = month/12.0;
1194 printf(
" %-3.2f", long_high(season(val, offs), 0.0, 1.0) );
1197 printf(
"\nmonsoonal:\t");
1198 for (
int month=0; month<12; ++month) {
1199 double val = (month > 6) ? (12 - month)/6.0 : month/6.0;
1200 _seasons_year = month/12.0;
1201 printf(
" %-3.2f", monsoonal(season(val, offs), 0.0, 1.0) );
1206#if REPORT_TO_CONSOLE
1207void FGClimate::report()
1209 struct tm *t =
globals->get_time_params()->getGmt();
1211 std::cout <<
"===============================================" << std::endl;
1212 std::cout <<
"Climate report for:" << std::endl;
1213 std::cout <<
" Date: " << sgTimeFormatTime(t) <<
" GMT" << std::endl;
1214 std::cout <<
" Sun latitude: " << _sun_latitude_deg <<
" deg."
1216 std::cout <<
" Sun longitude: " << _sun_longitude_deg <<
" deg."
1218 std::cout <<
" Viewer latitude: "
1219 << _positionLatitudeNode->getDoubleValue() <<
" deg."
1220 <<
" (adjusted: " << _adj_latitude_deg <<
")" << std::endl;
1221 std::cout <<
" Viewer longitude: "
1222 << _positionLongitudeNode->getDoubleValue() <<
" deg."
1223 <<
" (adjusted: " << _adj_longitude_deg <<
")" << std::endl;
1224 std::cout << std::endl;
1225 std::cout <<
" Köppen classification: " << _classification[_code]
1227 std::cout <<
" Description: " << _description[_code]
1228 << std::endl << std::endl;
1229 std::cout <<
" Daylight: " << _day_light*100.0 <<
" %"
1231 std::cout <<
" Daytime: "<< _daytime*24.0 <<
" hours" << std::endl;
1232 std::cout <<
" Daytime...(0.0 = night .. 1.0 = noon): " << _day_noon
1234 std::cout <<
" Season (0.0 = winter .. 1.0 = summer): " << _season_summer
1236 std::cout <<
" Year (0.25 = spring .. 0.75 = autumn): " << _seasons_year
1237 << std::endl << std::endl;
1238 std::cout <<
" Dewpoint: " << _gl.dewpoint <<
" deg. C."
1240 std::cout <<
" Ground temperature: " << _gl.temperature <<
" deg. C."
1242 std::cout <<
" Sea level temperature: " << _sl.temperature <<
" deg. C."
1244 std::cout <<
" Ground Mean temp.: " << _gl.temperature_mean
1245 <<
" deg. C." << std::endl;
1246 std::cout <<
" Sea level mean temp.: " << _sl.temperature_mean
1247 <<
" deg. C." << std::endl;
1248 std::cout <<
" Seawater temperature: " << _sl.temperature_water
1249 <<
" deg. C." << std::endl;
1251 std::cout <<
" Months precipitation: " << _gl.precipitation <<
" mm"
1253 std::cout <<
" Annual precipitation: " << _gl.precipitation_annual <<
" mm"
1255 std::cout <<
" Relative humidity: " << _gl.relative_humidity <<
" %"
1257 std::cout <<
" Ground Air Pressure: " << _gl.pressure <<
" hPa"
1259 std::cout <<
" Sea level Air Pressure: " << _sl.pressure <<
" hPa"
1261 std::cout <<
" Wind speed: " << _wind_speed <<
" m/s = "
1262 << _wind_speed*SG_MPS_TO_KT <<
" kt" << std::endl;
1263 std::cout <<
" Wind direction: " << _wind_direction <<
" degrees"
1265 std::cout <<
" Snow level: " << _snow_level <<
" m." << std::endl;
1266 std::cout <<
" Inland water bodies ice cover: "
1267 << _inland_ice_cover ?
"yes" :
"no" << std::endl;
1268 std::cout <<
" Snow thickness.(0.0 = thin .. 1.0 = thick): "
1269 << _snow_thickness << std::endl;
1270 std::cout <<
" Ice cover......(0.0 = none .. 1.0 = thick): " << _ice_cover
1272 std::cout <<
" Dust cover.....(0.0 = none .. 1.0 = dusty): " << _dust_cover
1274 std::cout <<
" Wetness........(0.0 = dry .. 1.0 = wet): " << _wetness
1276 std::cout <<
" Lichen cover...(0.0 = none .. 1.0 = mossy): "
1277 << _lichen_cover << std::endl;
1278 std::cout <<
" Season (0.0 = summer .. 1.0 = late autumn): "
1279 << ((_gl.has_autumn && _is_autumn > 0.05) ? _season_transistional : 0.0)
1280 << std::endl << std::endl;
1281 std::cout <<
" METAR: " <<
get_metar() << std::endl;
1282 std::cout <<
"===============================================" << std::endl;
const char * get_metar() const
void setEnvironmentUpdate(bool value)
bool getEnvironmentUpdate() const
void update(double dt) override
Manage environment information.
virtual FGEnvironment getEnvironment() const
Get the environment information for the plane's current position.
Model the natural environment.
virtual bool set_live_update(bool live_update)
virtual void set_dewpoint_degc(double d)
virtual double get_relative_humidity() const
virtual void set_is_isa(bool isa)
virtual double get_dewpoint_sea_level_degc() const
virtual bool get_is_isa() const
virtual double get_temperature_sea_level_degc() const
virtual void set_elevation_ft(double elevation_ft)
virtual double get_pressure_sea_level_inhg() const
virtual void set_pressure_inhg(double p)
virtual void set_temperature_degc(double t)
#define MAX_CLIMATE_CLASSES
int fgGetInt(const char *name, int defaultValue)
Get an int value for a property.
const double P0(101325.0)
const double T0(15.+freezing)
const double inHg(101325.0/760 *1000 *inch)
bool fgSetDouble(const char *name, double defaultValue)
Set a double value for a property.
bool fgSetBool(char const *name, bool val)
Set a bool value for a property.
double fgGetDouble(const char *name, double defaultValue)
Get a double value for a property.
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.