#!/usr/bin/perl -w # -*- perl -*- # # $Id: parse_synop,v 1.10 2003/08/20 22:29:08 eserte Exp $ # Author: Slaven Rezic # # Copyright (C) 2001 Slaven Rezic. All rights reserved. # This program is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # # Mail: slaven.rezic@berlin.de # WWW: http://www.rezic.de/eserte/ # # SMDL10 KAWN 260000 RRA # AAXX 26001 # 10384 32983 13401 10121 20102 30171 40231 52002 80001 333 30/// # 55300 81076 #$synop = "10384 32983 13401 10121 20102 30171 40231 52002 80001 333 30/// 55300 81076"; # SNDL10 KAWN 132200 RRA # AAXX 13221 # 10384 42973 11701 10143 20125 30160 40219 58003 80001 333 55300 # 81076 #$synop = "10384 42973 11701 10143 20125 30160 40219 58003 80001 333 55300 81076"; # SNDL10 KAWN 132300 RRA # AAXX 13231 # 10384 42973 01301 10127 20119 30160 40219 57002 333 55300 #$synop = "10384 42973 01301 10127 20119 30160 40219 57002 333 55300"; # # aus: http://www.uradio.ku.dk/~ct/eurovejr/ # Die Dateinamen heissen EURO # Es gibt Meldungen zu 0 - 6 - 12 - 18 Uhr # # SMDL01 EDZW 141800 # AAXX 14181 # ... # 10384 32970 01103 10179 20155 30137 40195 58001 # 333 10224 20100 31007 55300= use lib "$ENV{HOME}/lib/perl"; use strict; use vars qw(@data); BEGIN { @data = qw($wmo_station_number $precipitation_indicator $token $station_type_and_present_and_past_weather_indicator $cloud_base_of_lowest_cloud_seen $code $visibility $total_cloud_cover $wind_direction $wind_direction_compass $wind_speed $temperature $relative_humidity $dewpoint $station_pressure $seelevel_pressure $characteristics_of_pressure_tendency $three_hour_pressure_change $precipitation_amount $duration_over_which_precipitation_amount_measured $present_weather $present_weather_category $past_weather_type1 $past_weather_type2 $amount_of_low_middle_clouds_covering_sky $low_cloud_type $middle_cloud_type $high_cloud_type $date $time $twenty_four_hour_precipitation_in_mm $maximum_temperature_over_previous_24_hours $minimum_temperature_over_previous_24_hours $state_of_ground_with_snow_cover $snow_depth_in_cm @clouds $ground_condition $min_temp_5cm $sunshine_last_hour $sunshine_last_day $precipitation_amount2 $duration_over_which_precipitation_amount_measured2 $hoechste_windspitze_in_den_letzten_10_minuten $hoechste_windspitze_seit_dem_letzten_synoptischen_haupttermin $hoechstes_10_minuten_mittel_der_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin $mittlere_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin $niedrigstes_10_minuten_mittel_der_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin $windrichtung_in_grad $zeitpunkt_einer_rechtsdrehenden_aenderung_der_windrichtung $zeitpunkt_einer_rueckdrehenden_aenderung_der_windrichtung ); } use vars @data; use vars qw(@token); my($isodate, $synop, $wettermeldung2, $convert_whole_file, $outfile, $d); use Getopt::Long; if (!GetOptions("date=s" => \$isodate, "synop=s" => \$synop, "wettermeldung2" => \$wettermeldung2, "wholefile!" => \$convert_whole_file, "o=s" => \$outfile, "d!" => \$d, )) { die "usage"; } my $file = shift @ARGV; if ($convert_whole_file) { convert_whole_file($file, $outfile); } doit($file, $isodate, -synop => $synop, -wettermeldung2 => $wettermeldung2, -main => 1, ); sub doit { my($file, $isodate, %args) = @_; my $wettermeldung2 = $args{-wettermeldung2}; my $main = $args{-main}; my $synop = $args{-synop}; foreach (@data) { eval "undef $_"; die $@ if $@; } if (!defined $synop) { if (!$isodate) { SEARCH: { my(@lines) = split /\n/, `tail -10 $file`; for (my $i=$#lines; $i>=0; $i--) { if ($lines[$i] =~ /^\#/) { $synop = ""; #($date, $time) = get_date_time($lines[$i+1]); ($date, $time) = get_date_time2($lines[$i]); foreach my $j ($i+3 .. $#lines) { if ($lines[$j] =~ /^\s*$/) { last SEARCH; } $synop .= $lines[$j]; } last SEARCH; } } } if (!defined $synop) { die "Cannot find last synop in $file"; } } else { open(F,$file) or die "Can't open $file: $!"; FILE: while () { if (/^\#$isodate/) { ($date, $time) = get_date_time2($_);scalar ; #($date, $time) = get_date_time(scalar ); # WMO header scalar ; # ??? chomp($synop = scalar ); while () { chomp; if (/^\s*$/) { last FILE; } $synop .= $_; } last FILE; } } close F; if (!defined $synop) { die "Cannot find synop for $isodate"; } } } else { if (defined $isodate) { ($date, $time) = get_date_time2($isodate); } } @token = split /\s+/, $synop; eval { $wmo_station_number = shift @token; if (next_token()) { $precipitation_indicator = {0 => 'Precipitation in groups 1 and 3', 1 => 'Precipitation reported in group 1 only', 2 => 'Precipitation reported in group 3 only', 3 => 'Precipitation omitted, no precipitation', 4 => 'Precipitation omitted, no observation' }->{substr $token, 0, 1}; $station_type_and_present_and_past_weather_indicator = {1 => 'manned station -- weather group included', 2 => 'manned station -- omitted, no significant weather', 3 => 'manned station -- omitted, no weather observation', 4 => 'automated station -- weather group included (see automated weather codes 4677 and 4561)', 5 => 'automated station -- omitted, no significant weather', 6 => 'automated station -- omitted, no weather observation', 7 => 'automated station -- weather group included (see automated weather codes 4680 and 4531)', }->{substr $token, 1, 1}; $cloud_base_of_lowest_cloud_seen = {0 => '0 to 50 m', 1 => '50 to 100 m', 2 => '100 to 200 m', 3 => '200 to 300 m', 4 => '300 to 600 m', 5 => '600 to 1000 m', 6 => '1000 to 1500 m', 7 => '1500 to 2000 m', 8 => '2000 to 2500 m', 9 => 'above 2500 m', '/' => 'unknown', }->{substr $token, 2, 1}; $code = substr $token, 3, 2; if ($code eq '//') { $visibility = 'missing'; } elsif ($code == 0) { $visibility = 'less than 0.1 km'; } elsif ($code <= 50) { $visibility = sprintf "%.1f km", $code/10; } elsif ($code < 80) { $visibility = ($code-50) . " km"; } else { $visibility = {80=>'30 km', 81=>'35 km', 82=>'40 km', 83=>'45 km', 84=>'50 km', 85=>'55 km', 86=>'60 km', 87=>'65 km', 88=>'70 km', 89=>'greater than 70 km', 90=>'less than 0.05 km', 91=>'0.05 km', 92=>'0.2 km', 93=>'0.5 km', 94=>'1 km', 95=>'2 km', 96=>'4 km', 97=>'10 km', 98=>'20 km', 99=>'greater than 50 km', }->{$code}; } } goto PRINT if !next_token(); $total_cloud_cover = {0 => '0 eighths (clear)', 1 => '1/8th', 2 => '2/8ths', 3 => '3/8ths', 4 => '4/8ths', 5 => '5/8ths', 6 => '6/8ths', 7 => '7/8ths', 8 => '8/8ths (overcast)', 9 => 'sky obscured', '/' => 'no observation', }->{substr $token, 0, 1}; $wind_direction = substr($token, 1, 2); if ($wind_direction eq '//') { $wind_direction = 'no observation'; } else { $wind_direction*=10; if ($wind_direction < 22.5 || $wind_direction > 360-22.5) { $wind_direction_compass = 'N'; } elsif ($wind_direction < 22.5+45) { $wind_direction_compass = 'NE'; } elsif ($wind_direction < 22.5+45*2) { $wind_direction_compass = 'E'; } elsif ($wind_direction < 22.5+45*3) { $wind_direction_compass = 'SE'; } elsif ($wind_direction < 22.5+45*4) { $wind_direction_compass = 'S'; } elsif ($wind_direction < 22.5+45*5) { $wind_direction_compass = 'SW'; } elsif ($wind_direction < 22.5+45*6) { $wind_direction_compass = 'W'; } elsif ($wind_direction < 22.5+45*7) { $wind_direction_compass = 'NW'; } else { die "Häh wind_direction=$wind_direction ?"; } } $wind_speed = substr($token, 3, 2); if ($wind_speed eq "//") { $wind_speed = undef; } goto PRINT if !next_token(); if ($token =~ /^00(...)/) { $wind_speed = $1; $token = shift @token; } die "1 expected, not $token" if $token !~ /^1/; $temperature = substr($token,2,3)/10 * (substr($token,1,1)==1 ? -1 : 1) . " °C"; goto PRINT if !next_token(); die "2 expected, not $token" if $token !~ /^2/; my $_humidity = substr($token,2,3); if ($_humidity ne '//') { my $sign = substr $token, 1,1; if ($sign == 9) { $relative_humidity = substr($token,2,3) . " %"; } else { $dewpoint = substr($token,2,3)/10 * (substr($token,1,1)==1 ? -1 : 1) . " °C"; } } goto PRINT if !next_token(); die "3 expected, not $token" if $token !~ /^3/; $station_pressure = substr $token, 1, 4; if ($station_pressure !~ m|^////|) { if ($station_pressure =~ m|(.*)/$|) { $station_pressure = 1000 + $1; } else { $station_pressure = 1000 + $station_pressure/10; } $station_pressure-=1000 if $station_pressure>1200; $station_pressure .= " hPa"; } goto PRINT if !next_token(); die "4 expected, not $token" if $token !~ /^4/; my $_seelevel_pressure = substr $token, 1, 4; if ($_seelevel_pressure ne '////') { $code = substr $token, 1, 1; if ($code == 1 || $code == 2 || $code == 5 || $code == 7 || $code == 8) { die "nyi"; } else { $seelevel_pressure = substr $token, 1, 4; if ($seelevel_pressure =~ m|(.*)/$|) { $seelevel_pressure = 1000 + $1; } else { $seelevel_pressure = 1000 + $seelevel_pressure/10; } $seelevel_pressure-=1000 if $seelevel_pressure>1200; $seelevel_pressure .= " hPa"; } } goto PRINT if !next_token(); die "5 expected, not $token" if $token !~ /^5/; $code = substr $token, 1, 1; $characteristics_of_pressure_tendency = { 0 => 'Increasing, then decreasing -- resultant pressure same or higher', 1 => 'Increasing, then steady -- resultant pressure higher', 2 => 'Increasing steadily -- resultant pressure higher', 3 => 'Decreasing or steady, then increasing -- resultant pressure higher', 4 => 'Steady -- resultant pressure same', 5 => 'Decreasing, then increasing -- resultant pressure lower', 6 => 'Decreasing, then steady -- resultant pressure lower', 7 => 'Decreasing steadily -- resultant pressure lower', 8 => 'Increasing or steady, then decreasing -- resultant pressure lower', }->{$code}; $three_hour_pressure_change = substr($token, 2, 3)/10; goto PRINT if !next_token(); do { warn "6 expected, not $token" if $d; goto TOKEN7 } if !defined $token || $token !~ /^6/; ($precipitation_amount, $duration_over_which_precipitation_amount_measured) = handle_precipitation_amount($token); goto PRINT if !next_token(); TOKEN7: do { warn "7 expected, not $token" if $d; goto TOKEN8 } if !defined $token || $token !~ /^7/; $code = substr $token, 1, 2; $present_weather = { '00' => 'clear skies', '01' => 'clouds dissolving', '02' => 'state of sky unchanged', '03' => 'clouds developing', #Haze, smoke, dust or sand '04' => 'visibility reduced by smoke', '05' => 'haze', '06' => 'widespread dust in suspension not raised by wind', '07' => 'dust or sand raised by wind', '08' => 'well developed dust or sand whirls', '09' => 'dust or sand storm within sight but not at station', #Non-precipitation events '10' => 'mist', '11' => 'patches of shallow fog', '12' => 'continuous shallow fog', '13' => 'lightning visible, no thunder heard', '14' => 'precipitation within sight but not hitting ground', '15' => 'distant precipitation but not falling at station', '16' => 'nearby precipitation but not falling at station', '17' => 'thunderstorm but no precipitation falling at station', '18' => 'squalls within sight but no precipitation falling at station', '19' => 'funnel clouds within sight', #Precipitation within past hour but not at observation time '20' => 'drizzle', '21' => 'rain', '22' => 'snow', '23' => 'rain and snow', '24' => 'freezing rain', '25' => 'rain showers', '26' => 'snow showers', '27' => 'hail showers', '28' => 'fog', '29' => 'thunderstorms', #Duststorm, sandstorm, drifting or blowing snow '30' => 'slight to moderate duststorm, decreasing in intensity', '31' => 'slight to moderate duststorm, no change', '32' => 'slight to moderate duststorm, increasing in intensity', '33' => 'severe duststorm, decreasing in intensity', '34' => 'severe duststorm, no change', '35' => 'severe duststorm, increasing in intensity', '36' => 'slight to moderate drifting snow, below eye level', '37' => 'heavy drifting snow, below eye level', '38' => 'slight to moderate drifting snow, above eye level', '39' => 'heavy drifting snow, above eye level', #Fog or ice fog '40' => 'Fog at a distance', '41' => 'patches of fog', '42' => 'fog, sky visible, thinning', '43' => 'fog, sky not visible, thinning', '44' => 'fog, sky visible, no change', '45' => 'fog, sky not visible, no change', '46' => 'fog, sky visible, becoming thicker', '47' => 'fog, sky not visible, becoming thicker', '48' => 'fog, depositing rime, sky visible', '49' => 'fog, depositing rime, sky not visible', #Drizzle '50' => 'intermittent light drizzle', '51' => 'continuous light drizzle', '52' => 'intermittent moderate drizzle', '53' => 'continuous moderate drizzle', '54' => 'intermittent heavy drizzle', '55' => 'continuous heavy drizzle', '56' => 'light freezing drizzle', '57' => 'moderate to heavy freezing drizzle', '58' => 'light drizzle and rain', '59' => 'moderate to heavy drizzle and rain', #Rain '60' => 'intermittent light rain', '61' => 'continuous light rain', '62' => 'intermittent moderate rain', '63' => 'continuous moderate rain', '64' => 'intermittent heavy rain', '65' => 'continuous heavy rain', '66' => 'light freezing rain', '67' => 'moderate to heavy freezing rain', '68' => 'light rain and snow', '69' => 'moderate to heavy rain and snow', #Snow '70' => 'intermittent light snow', '71' => 'continuous light snow', '72' => 'intermittent moderate snow', '73' => 'continuous moderate snow', '74' => 'intermittent heavy snow', '75' => 'continuous heavy snow', '76' => 'diamond dust', '77' => 'snow grains', '78' => 'snow crystals', '79' => 'ice pellets', #Showers '80' => 'light rain showers', '81' => 'moderate to heavy rain showers', '82' => 'violent rain showers', '83' => 'light rain and snow showers', '84' => 'moderate to heavy rain and snow showers', '85' => 'light snow showers', '86' => 'moderate to heavy snow showers', '87' => 'light snow/ice pellet showers', '88' => 'moderate to heavy snow/ice pellet showers', '89' => 'light hail showers', '90' => 'moderate to heavy hail showers', #Thunderstorms '91' => 'thunderstorm in past hour, currently only light rain', '92' => 'thunderstorm in past hour, currently only moderate to heavy rain', '93' => 'thunderstorm in past hour, currently only light snow or rain/snow mix', '94' => 'thunderstorm in past hour, currently only moderate to heavy snow or rain/snow mix', '95' => 'light to moderate thunderstorm', '96' => 'light to moderate thunderstorm with hail', '97' => 'heavy thunderstorm', '98' => 'heavy thunderstorm with duststorm', '99' => 'heavy thunderstorm with hail', }->{$code}; if ($code < 4) { $present_weather_category = ''; } elsif ($code < 10) { $present_weather_category = 'Haze, smoke, dust or sand'; } else { $present_weather_category = { 1 => 'Non-precipitation events', 2 => 'Precipitation within past hour but not at observation time', 3 => 'Duststorm, sandstorm, drifting or blowing snow', 4 => 'Fog or ice fog', 5 => 'Drizzle', 6 => 'Rain', 7 => 'Snow', 8 => 'Showers', 9 => 'Thunderstorms', }->{substr $code, 0, 1}; } my %past_weather = ( '0' => 'cloud covering less than half of sky', '1' => 'cloud covering more than half of sky during part of period and more than half during part of period', '2' => 'cloud covering more than half of sky', '3' => 'sandstorm, duststorm or blowing snow', '4' => 'fog, or thick haze', '5' => 'drizzle', '6' => 'rain', '7' => 'snow or mixed rain and snow', '8' => 'showers', '9' => 'thunderstorms', ); $past_weather_type1 = $past_weather{substr $token, 3, 1}; $past_weather_type2 = $past_weather{substr $token, 4, 1}; goto PRINT if !next_token(); TOKEN8: do { warn "8 expected, not $token" if $d; goto NEXTTOKEN } if !defined $token || $token !~ /^8/; $amount_of_low_middle_clouds_covering_sky = substr $token, 1, 1; $low_cloud_type = { '0' => 'no low clouds', '1' => 'cumulus humulis or fractus (no vertical development)', '2' => 'cumulus mediocris or congestus (moderate vertical development)', '3' => 'cumulonimbus calvus (no outlines nor anvil)', '4' => 'stratocumulus cumulogenitus (formed by spreading of cumulus)', '5' => 'stratocumulus', '6' => 'stratus nebulosus (continuous sheet)', '7' => 'stratus or cumulus fractus (bad weather)', '8' => 'cumulus and stratocumulus (multilevel)', '9' => 'cumulonimbus with anvil', '/' => 'low clouds unobserved due to darkness or obscuration', }->{substr $token, 2, 1}; $middle_cloud_type = { '0' => 'no middle clouds', '1' => 'altostratus translucidous (mostly transparent)', '2' => 'altostratus opacus or nimbostratus', '3' => 'altocumulus translucidous (mostly transparent)', '4' => 'patches of altocumulus (irregular, lenticular)', '5' => 'bands of altocumulus', '6' => 'altocumulus cumulogenitus (formed by spreading of cumulus)', '7' => 'altocumulus (multilayers)', '8' => 'altocumulus castellanus (having cumuliform tufts)', '9' => 'altocumulus of a chaotic sky', '/' => 'middle clouds unobserved due to darkness or obscuration', }->{substr $token, 3, 1}; $high_cloud_type = { '0' => 'no high clouds', '1' => 'cirrus fibratus (wispy)', '2' => 'cirrus spissatus (dense in patches)', '3' => 'cirrus spissatus cumulogenitus (formed out of anvil)', '4' => 'cirrus unicus or fibratus (progressively invading sky)', '5' => 'bands of cirrus or cirrostratus invading sky (less than 45 degree above horizon)', '6' => 'bands of cirrus or cirrostratus invading sky (more than 45 degree above horizon)', '7' => 'cirrostratus covering whole sky', '8' => 'cirrostratus not covering sky but not invading', '9' => 'cirrocumulus ', '/' => 'high clouds unobserved due to darkness or obscuration', }->{substr $token, 4, 1}; }; warn $@ if $@; NEXTTOKEN: next_token(); ###################################################################### PRINT: if ($wettermeldung2) { my $ret = print_wettermeldung2_compatible('-print' => $main); return $ret; } else { printall(); } } # doit sub print_wettermeldung2_compatible { my(%args) = @_; (my $temperature = $temperature) =~ s/\s*°C//; (my $pressure = $seelevel_pressure) =~ s/\s*hPa//; require Met::Wind; my $wind_beaufort = Met::Wind::wind_velocity([$wind_speed, 'm/s'], 'beaufort'); local $^W = 0; my($date, $time) = gmtime2localtime($date, $time); my $ret = join("|", $date, $time, $temperature, $pressure, $wind_direction_compass, $wind_beaufort, "", # feuchtigkeit "", # mittl windg $twenty_four_hour_precipitation_in_mm, $present_weather, )."\n"; print $ret if $args{'-print'}; $ret; } sub printall { local $^W = 0; print "cloud_base_of_lowest_cloud_seen=$cloud_base_of_lowest_cloud_seen\n"; print "precipitation_indicator=$precipitation_indicator\n" if defined $precipitation_indicator; print "station_type_and_present_and_past_weather_indicator=$station_type_and_present_and_past_weather_indicator\n"; print "wmo_station_number=$wmo_station_number\n"; print "visibility=$visibility\n"; print "total_cloud_cover=$total_cloud_cover\n"; print "wind_direction=$wind_direction\n"; print "wind_direction_compass=$wind_direction_compass\n" if defined $wind_direction_compass; print "wind_speed=$wind_speed\n" if defined $wind_speed; print "temperature=$temperature\n"; if (defined $dewpoint) { print "dewpoint=$dewpoint\n"; } else { print "relative_humidity=$relative_humidity\n"; } print "station_pressure=$station_pressure\n"; print "seelevel_pressure=$seelevel_pressure\n"; print "characteristics_of_pressure_tendency=$characteristics_of_pressure_tendency\n"; print "three_hour_pressure_change=$three_hour_pressure_change\n"; print "precipitation_amount=$precipitation_amount over $duration_over_which_precipitation_amount_measured\n" if defined $precipitation_amount; print "precipitation_amount2=$precipitation_amount2 over $duration_over_which_precipitation_amount_measured2\n" if defined $precipitation_amount2; print "present_weather_category=$present_weather_category\n" if defined $present_weather_category; print "present_weather=$present_weather\n" if defined $present_weather; print "past_weather_type1=$past_weather_type1\n" if defined $past_weather_type1; print "past_weather_type2=$past_weather_type2\n" if defined $past_weather_type2; print "amount_of_low_middle_clouds_covering_sky=$amount_of_low_middle_clouds_covering_sky\n" if defined $amount_of_low_middle_clouds_covering_sky; print "low_cloud_type=$low_cloud_type\n" if defined $low_cloud_type; print "middle_cloud_type=$middle_cloud_type\n" if defined $middle_cloud_type; print "high_cloud_type=$high_cloud_type\n" if defined $high_cloud_type; print "maximum_temperature_over_previous_24_hours=$maximum_temperature_over_previous_24_hours °C\n" if defined $maximum_temperature_over_previous_24_hours; print "minimum_temperature_over_previous_24_hours=$minimum_temperature_over_previous_24_hours °C\n" if defined $minimum_temperature_over_previous_24_hours; print "state_of_ground_with_snow_cover=$state_of_ground_with_snow_cover\n" if defined $state_of_ground_with_snow_cover; print "snow_depth_in_cm=$snow_depth_in_cm\n" if defined $snow_depth_in_cm; print "twenty_four_hour_precipitation_in_mm=$twenty_four_hour_precipitation_in_mm\n" if defined $twenty_four_hour_precipitation_in_mm; my $cloud_i = 1; foreach my $cloud (@clouds) { print "cloud_coverage_of_layer $cloud_i=$cloud->{'cloud_coverage_of_layer'}/8\n"; print "genus_of_cloud=$cloud->{'genus_of_cloud'}\n"; print "height_of_cloud_base=$cloud->{'height_of_cloud_base'} m\n"; $cloud_i++; } print "ground_condition=$ground_condition\n" if defined $ground_condition; print "min_temp_5cm=$min_temp_5cm°C\n" if defined $min_temp_5cm; print "sunshine_last_hour=$sunshine_last_hour h\n" if defined $sunshine_last_hour; print "sunshine_last_day=$sunshine_last_day h\n" if defined $sunshine_last_day; print "hoechste_windspitze_in_den_letzten_10_minuten=$hoechste_windspitze_in_den_letzten_10_minuten\n" if defined $hoechste_windspitze_in_den_letzten_10_minuten; print "hoechste_windspitze_seit_dem_letzten_synoptischen_haupttermin=$hoechste_windspitze_seit_dem_letzten_synoptischen_haupttermin m/s\n" if defined $hoechste_windspitze_seit_dem_letzten_synoptischen_haupttermin; print "hoechstes_10_minuten_mittel_der_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin=$hoechstes_10_minuten_mittel_der_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin m/s\n" if defined $hoechstes_10_minuten_mittel_der_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin; print "mittlere_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin=$mittlere_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin m/s\n" if defined $mittlere_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin; print "niedrigstes_10_minuten_mittel_der_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin=$niedrigstes_10_minuten_mittel_der_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin m/s\n" if defined $niedrigstes_10_minuten_mittel_der_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin; print "windrichtung_in_grad=$windrichtung_in_grad °\n" if defined $windrichtung_in_grad; print "zeitpunkt_einer_rechtsdrehenden_aenderung_der_windrichtung=$zeitpunkt_einer_rechtsdrehenden_aenderung_der_windrichtung XXX\n" if defined $zeitpunkt_einer_rechtsdrehenden_aenderung_der_windrichtung; print "zeitpunkt_einer_rueckdrehenden_aenderung_der_windrichtung=$zeitpunkt_einer_rueckdrehenden_aenderung_der_windrichtung XXX\n" if defined $zeitpunkt_einer_rueckdrehenden_aenderung_der_windrichtung; } sub next_token { $token = shift @token; if (!defined $token) { return undef; } if ($token eq '333') { special_climatology_data(); undef; } 1; } sub special_climatology_data { while (next_token()) { if ($token =~ /^0/) { # Regionally developed data warn "Unhandled token $token (Regionale Angaben (derzeit nicht benutzt))"; } elsif ($token =~ /^1(.)(...)/) { my $sign; ($sign, $maximum_temperature_over_previous_24_hours) = ($1, $2); $maximum_temperature_over_previous_24_hours /= 10; if ($sign == 1) { $maximum_temperature_over_previous_24_hours *= -1; } } elsif ($token =~ /^2(.)(...)/) { my $sign; ($sign, $minimum_temperature_over_previous_24_hours) = ($1, $2); $minimum_temperature_over_previous_24_hours /= 10; if ($sign == 1) { $minimum_temperature_over_previous_24_hours *= -1; } } elsif ($token =~ /^3(.)(.)(..)/) { # Regionally developed data my($E,$sn,$tg) = ($1,$2,$3); $ground_condition = { 0 => "trocken", 1 => "feucht", 2 => "nass", 3 => "überflutet", 4 => "gefroren", 5 => "Glatteis oder Eisglätte (mindestens 50 % des Erdbodens bedeckend)", 6 => "loser, trockener Sand -- den Boden nicht vollständig bedeckend", 7 => "geschlossene dünne Sandschicht -- den Boden vollständig bedeckend", 8 => "geschlossene dicke Sandschicht -- den Boden vollständig bedeckend", 9 => "extrem trockener Boden mit Rissen", }->{$E}; if ($sn ne "/" && $tg ne "//") { $min_temp_5cm = $tg * ($sn == 1 ? -1 : +1); } } elsif ($token =~ /^4(.)(...)/) { my $E; ($E, $snow_depth_in_cm) = ($1, $2); $state_of_ground_with_snow_cover = { 0 => 'predominantly covered with ice', 1 => 'compact or wet snow covering less than half of ground', 2 => 'compact or wet snow covering more than half of ground but not completely covered', 3 => 'even layer of compact or wet snow covering entire ground', 4 => 'uneven layer of compact or wet snow covering entire ground', 5 => 'loose dry snow covering less than half of ground', 6 => 'loose dry snow covering more than half of ground but not completely covered', 7 => 'even layer of loose dry snow covering entire ground', 8 => 'uneven layer of loose dry snow covering entire ground', 9 => 'snow covering ground completely with deep drifts', }->{$E}; } elsif ($token =~ /^553(..)/) { if ($1 ne "//") { $sunshine_last_hour = $1/10; } } elsif ($token =~ /^55(...)/) { if ($1 ne "///") { $sunshine_last_day = $1/10; } if ($time ne '6.00') { warn "Token 55SSS found, but it's not 06:00 UTC, it's $time!" } } elsif ($token =~ /^5/) { my $this_token = $token; next_token(); warn "Unhandled tokens $this_token, $token" if $d; } elsif ($token =~ /^6/) { ($precipitation_amount2, $duration_over_which_precipitation_amount_measured2) = handle_precipitation_amount($token); } elsif ($token =~ /^7(....)/) { if ($1 eq "0000") { $twenty_four_hour_precipitation_in_mm = 0; } elsif ($1 eq "9999") { $twenty_four_hour_precipitation_in_mm = 0.05; # or less } else { $twenty_four_hour_precipitation_in_mm = $1/10; } } elsif ($token =~ /^8(.)(.)(..)/) { my($N,$C,$hh) = ($1,$2,$3); my $cloud_layer = {}; $cloud_layer->{'cloud_coverage_of_layer'} = $N; $cloud_layer->{'genus_of_cloud'} = { '0' => 'cirrus (Ci)', '1' => 'cirrocumulus (Cc)', '2' => 'cirrostratus (Cs)', '3' => 'altocumulus (Ac)', '4' => 'altostratus (As)', '5' => 'nimbostratus (Ns)', '6' => 'stratocumulus (Sc)', '7' => 'stratus (St)', '8' => 'cumulus (Cu)', '9' => 'cumulonimbus (Cb)', '/' => 'cloud not visible', }->{$C}; if ($hh <= 50) { $cloud_layer->{'height_of_cloud_base'} = $hh*30; } elsif ($hh <= 80) { $cloud_layer->{'height_of_cloud_base'} = ($hh-50)*300; } elsif ($hh <= 88) { $cloud_layer->{'height_of_cloud_base'} = 9000+($hh-80)*1500; } elsif ($hh == 89) { $cloud_layer->{'height_of_cloud_base'} = "greater than 21000 m"; } else { $cloud_layer->{'height_of_cloud_base'} = { '90' => '0 to 50 m', '91' => '50 to 100 m', '92' => '100 to 200 m', '93' => '200 to 300 m', '94' => '300 to 600 m', '95' => '600 to 1000 m', '96' => '1000 to 1500 m', '97' => '1500 to 2000 m', '98' => '2000 to 2500 m', '99' => 'above 2500 m', }->{$hh}; } push @clouds, $cloud_layer; } elsif ($token =~ /^9/) { besondere_wettererscheinungen($token); # warn "Unhandled token $token"; } else { warn "The token <$token> is unknown!"; } } } # XXX funktioniert nicht korrekt, wenn der Monat nicht stimmt! sub get_date_time { my($wmo_header) = @_; my($wmo_time) = $wmo_header =~ /\S+\s+\S+\s+(\S+)/; my($day,$h,$m) = $wmo_time =~ /^(..)(..)(..)$/; if (!defined $day) { die "Can't parse synop time $wmo_time"; } # Umrechung GMT => localtime my(@g) = gmtime; require Time::Local; my $gmtime = Time::Local::timegm(0,$m,$h,$day,$g[4],$g[5]); my(@l) = localtime $gmtime; my $date = sprintf "%02d.%02d.%04d", $l[3], $l[4]+1, $l[5]+1900; my $time = sprintf "%d.%02d", $l[2], $l[1]; ($date, $time); } # This uses the "comment" date header (#yyyy-mm-dd ...) sub get_date_time2 { my($comment_header) = @_; if ($comment_header =~ /^\#\s*(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})/) { my $date = sprintf "%02d.%02d.%04d", $3, $2, $1; my $time = sprintf "%d.%02d", $4, $5; ($date, $time); } else { warn "Can't parse $comment_header"; } } sub gmtime2localtime { my($date, $time) = @_; my($d,$m,$y,$H,$M) = split /\./, "$date.$time"; require Time::Local; my $t = Time::Local::timegm(0,$M,$H,$d,$m-1,$y-1900); my @l = localtime $t; (sprintf("%02d.%02d.%04d", $l[3], $l[4]+1, $l[5]+1900), sprintf("%d.%02d", $l[2], $l[1])); } sub handle_precipitation_amount { my $token = shift; my $code = substr $token, 1, 3; my $precipitation_amount; if ($code >= 991) { $precipitation_amount = ($code-990)/10; } elsif ($code == 990) { $precipitation_amount = 'trace'; } elsif ($code == 989) { $precipitation_amount = '989 or more mm'; } else { $precipitation_amount = int($code); } $code = substr $token, 4, 1; my $duration_over_which_precipitation_amount_measured = { 1 => '6 hours', 2 => '12 hours', 3 => '18 hours', 4 => '24 hours', 5 => '1 hour', 6 => '2 hours', 7 => '3 hours', 8 => '9 hours', 9 => '15 hours', '/' => '24 hours', }->{$code}; ($precipitation_amount, $duration_over_which_precipitation_amount_measured); } sub besondere_wettererscheinungen { my $token = shift; if ($token =~ /^910(..)/) { # >= 12.5 m/s $hoechste_windspitze_in_den_letzten_10_minuten = $1; } elsif ($token =~ /^911(..)/) { # >= 12.5 m/s $hoechste_windspitze_seit_dem_letzten_synoptischen_haupttermin = $1; } elsif ($token =~ /^912(..)/) { # >= 10.5 m/s $hoechstes_10_minuten_mittel_der_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin = $1; } elsif ($token =~ /^913(..)/) { $mittlere_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin = $1; } elsif ($token =~ /^914(..)/) { $niedrigstes_10_minuten_mittel_der_windgeschwindigkeit_seit_dem_letzten_synoptischen_haupttermin = $1; } elsif ($token =~ /^915(..)/) { $windrichtung_in_grad = $1*10; } elsif ($token =~ /^916(..)/) { $zeitpunkt_einer_rechtsdrehenden_aenderung_der_windrichtung = $1; } elsif ($token =~ /^917(..)/) { $zeitpunkt_einer_rueckdrehenden_aenderung_der_windrichtung = $1; } else { warn "Unhandled token $token"; } } sub convert_whole_file { # to something wettermeldung2 compatible # this is a slow unixish hack my($file, $outfile) = @_; my $since; if (defined $outfile && -w $outfile) { my($last) = `tail -1 $outfile`; my($d,$m,$y,$H,$M) = $last =~ /^(\d+)\D(\d+)\D(\d+)\D(\d+)\D(\d+)/; if (!defined $d) { $since = ""; } else { $since = sprintf "%04d-%02d-%02d %02d:%02d", $y,$m,$d,$H,$M; } } else { undef $outfile; } open(G, "grep '^#' $file|"); if (defined $outfile) { open(OUT, ">>$outfile") or die $!; } else { open(OUT, ">&STDOUT"); } while () { chomp; (my $date = $_) =~ s/^.//; next if (defined $since && $since ge $date); #my $line = `$^X $0 -wettermeldung2 -date '$date' $file`; my $line = doit($file, $date, -wettermeldung2 => 1); print OUT $line; } close OUT; close G; exit 0; } __END__