#!/usr/bin/perl # # H2Odata.cgi for outputting water-vapor graphs of CMDL's Frost-Point Hygrometer data # # this file lives at /cmdl/www/ozwv/cgi-bin on vortex.cmdl.noaa.gov # # by: Mark Clark, March-September 2003 use CGI::Pretty qw( :all ); use CGI::Carp qw( fatalsToBrowser ); # Netscape 4.x - Mozilla/4.8 (Macintosh; U; PPC) # 7.x - Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 # Mozilla - Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.5) Gecko/20030916 # Mozilla/4.78 [en] (Windows NT 5.0; U) # Safari - Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85 # Opera - Opera/6.0 (Macintosh; PPC Mac OS X; U) [en] # IE - Mozilla/4.0 (compatible; MSIE 6.0; Window NT 5.0) $agent = user_agent; if ( $agent =~ /.+\/(\d\.\d)/i ) { $version = $1; if ( $agent =~ /(safari|netscape|opera|msie|konqueror)/i ) { $browser = $1 } elsif ( $agent =~ /(gecko)/i ) { $browser = 'Mozilla' } } use PGPLOT; $ENV{PGPLOT_FONT} = '/opt/pgplot/grfont.dat'; $ENV{PGPLOT_BACKGROUND} = 'white'; $ENV{PGPLOT_FOREGROUND} = 'black'; $title = 'NOAA\'s Stratospheric Water Vapor Data'; # get time of the starting of the page $now = localtime; @time = localtime(time); $now_year = $time[5] + 1900; # start html; print header; # set test flag parameter #if (param) { $test = param('test') } # check incoming parameters if (param) { # the one parameter/no value case if (param('keywords')) { ${param('keywords')} = 1 ; $test && print param('keywords'), " => ", ${param('keywords')}, '
'; } else { foreach $name (param) { if (param($name) eq '') { $$name = 1 ; #print '1 '; } else { $$name = param($name) ; #print 'non-null'; } $test && print "param $name ", param($name), " => $$name
"; } } } # setup the list of names available from the web %names = ( alert => 'Alert, Northwest Territories, CANADA', boulder => 'Boulder, Colorado, USA', brazil => 'Juazeiro do Norte, BRAZIL', cepex => 'Christmas Island, KIRIBATI', crows_landing => 'Crow\'s Landing, California, USA', daggett => 'Dagett, California, USA', edwards => 'Edwards AFB, California, USA', fairbanks => 'Fairbanks, Alaska, USA', fort_sumner => 'Fort Sumner, New Mexico, USA', # hilo => 'Hilo, Hawaii, USA', huntsville => 'Huntsville, Alabama, USA', iceland => 'Keflavik, ICELAND', laramie => 'Laramie, Wyoming, USA', kiruna => 'Kiruna, SWEDEN', # lauder => 'Lauder, NEW ZEALAND', mcmurdo => 'McMurdo Station, ANTARCTICA', # 'ny_alesund' => '', palestine => 'Palestine, Texas, USA', samoa => 'Pago Pago, American Samoa, USA', # 'san_cristobal' => 'San Cristobal, ECUADOR', sodankyla => 'Sodankyla, FINLAND', spole => 'South Pole Station, ANTARCTICA', # washington => 'Washington, D.C., USA', watukosek => 'Watukosek, INDONESIA', ); # JavaScript @stats = sort keys %names; foreach $s ( @stats ) { $S = ucfirst $s; $pwd = qx'pwd'; opendir DIR, "/owv/balloon/products/lev/water/$s/" or die "opendir failed - $!
"; $beg = 10000; $end = 0; $years = ''; $js = ''; $yr = $mon = $day = $hr = ''; foreach $file ( readdir DIR ) { if ( $file !~ /^\w\w(\d{4})(\d{2})(\d{2})/ ) { next } if ( $file =~ /\.bck$/ ) { next } if ( $file =~ /edt/ ) { next } ($yr, $mon, $day) = ($1, $2, $3); if ( $file =~ /\d{8}(\d{2})/ ) { $hr = $1 } if ( $yr < $beg ) { $beg = $yr } if ( $yr > $end ) { $end = $yr } $flights{$yr.$s} .= "'$file' "; } $years = "'Choose a year', " . $years . join ', ', $beg .. $end; for ( $i = $beg; $i <= $end; $i++ ) { unless ( $flights{$i.$s} ) { $years =~ s/\, $i//; next } $flights{$i.$s} = join ', ', ( sort (split ' ', $flights{$i.$s}) ); $flights{$i.$s} = "'Choose a flight', " . $flights{$i.$s}; $js .= "$S$i = new Array ($flights{$i.$s});\n "; $js2 .= " if ( value == '$s' && form.years.value == $i ) { for (var i = 0; i < $S$i.length; i++) { options[i] = new Option(name_to_date($S$i\[i]), $S$i\[i]) } } "; } $js0 .= "$S = new Array ($years);\n " . $js . "\n"; $js1 .= " if ( form.stations.value == '$s' ) { for ( var i = 0; i < $S.length; i++ ) { form.years.options[i] = new Option($S\[i], $S\[i]) } } "; if ( $s eq 'boulder' ) { @bdryrs = ('Choose a year', $beg .. $end) } } #function resize(form) { # var scale = form.size.value; # document.gif.width = scale/100 * 680; # document.gif.height = scale/100 * 850; #} #if ( $browser ne 'Opera' ) { # @sizes = qw(25 33 50 66 75 90 100 125); # print "% Image Size ", # popup_menu ( -name => 'size', # -values => \@sizes, # -default => '100', # -onChange => 'resize(this.form)') } #else { print "$brower
\n" } $JScript=< 0; i--) { options[i] = null; } $js2 } function change_dates(form) { var options = form.years.options; for (var i = options.length - 1; i > 0; i--) { options[i] = null; } $js1 options[0].selected = true; change_flights(form); } function get_image(form) { var value = form.flights.value; if ( value == 'Choose a flight' ) { return } var image = value.substr(0, value.length-4) + '.gif'; document.gif.src = '../dobson/gifs/h2o/' + image; type_change(form) } if ( (navigator.appName=="Netscape") ) { if ( parseInt(navigator.appVersion) <= 4 ) { alert('This page does not work properly in Netscape 4.x or earlier. Please try again with a newer browser.') } } else if ( (navigator.appName=="Opera") ) { if ( parseInt(navigator.appVersion) <= 6 ) { alert('This page may not work properly in Opera 6.x or earlier.') } } function type_change(form) { var types = form.types; if ( types[0].checked ) { var type = 'pdf' } else if ( types[1].checked ) { var type = 'ps' } else { var type = 'gif' } var flight = form.flights.value; var href = document.links.file.href; if ( flight != ' - ' ) { var file = flight.substr(0, flight.length-3) + type; // e.g.: 'bl20030410.lev' href = '../dobson/gifs/h2o/' + file; } else { var off; if ( href.search('pdf') != -1 ) { off = 3 } else if ( href.search(/\\.gif\$/) != -1 ) { off = 3 } else if ( href.search('ps') != -1 ) { off = 2 } href = href.substr(0, href.length-off) + type; } document.links.file.href = href; } END # generate a list of stations from the CGI parameters $default_stat = 1; foreach $stat (@stats) { if (param($stat) && defined $stat) { $$stat = 1 } if ($$stat) { push @stations, $stat; $default_stat = 0; } } if ($default_stat) { $boulder = 1; $stat = 'boulder' } unless (@stations) { # set parameters for graphs @stations = qw(boulder) } print start_html(-title => $title, -author => 'Mark Clark', -base => 'true', -bgcolor => '#FFFFFF', -meta => {'keywords' => 'Frost-Point Hygrometer graphing data near real-time Boulder Colorado', 'description' => 'The NOAA/CMDL/OZWV - near Real-Time water Vapor Graphing page.'}, -head => [ Link({-rel => 'shortcut icon', -href => '../dobson/gifs/H2O_icon.ico'}), Link({-rel => 'icon', -href => '../dobson/gifs/H2O_icon.png', -type => 'image/png'}) ], -script => $JScript); print "
Climate Monitoring and Diagnostics Laboratory
CMDL
CMDL CMDL OZWV U.S. Dept. of Commerce NOAA OAR CMDL OZWV

"; #print "user agent:
\n$agent
B $browser, V $version
\n"; @mon = qw(- Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); sub log10 { my $n = shift; if ( $n > 0) { return log ($n)/log (10) } else { return '' } } # high and low values for graphing - subject to change later $high = log10 20000; $low = log10 1; # number of days per normal month $nd[1]=$nd[3]=$nd[5]=$nd[7]=$nd[8]=$nd[10]=$nd[12]=31; $nd[4]=$nd[6]=$nd[9]=$nd[11]=30; # $nd[2] is determined elsewhere - deals with the Leap averageaverage problem. # months in the year @mos = qw(- January February March April May June July August September October November December); # number of cumulative days per month in a normal year $td[1] = 31; $td[2] = 59; $td[3] = 90; $td[4] = 120; $td[5] = 151; $td[6] = 181; $td[7] = 212; $td[8] = 243; $td[9] = 273; $td[10] = 304; $td[11] = 334; $td[12] = 365; # generate the graphs # colors : black 1 # red 2 # green 3 # blue 4 # light blue-green 5 # fuscia 6 # yellow 7 # reddish brown 8 # light green 9 # 10 # 11 # 12 # 13 # 14 # gray 15 # gray 16 # get directory information $gifdir = '/www/ozwv/dobson/gifs/h2o/'; foreach $stat (@stats) { $dir = "/owv/balloon/products/lev/water/$stat/"; opendir DIR, $dir or die "couldn't opendir $dir - !$
\n"; @dir = sort readdir DIR; foreach $file (@dir) { if ( $file =~ /^\./ ) { next } $name = $file; $test && print "$file
\n"; if ( $file =~ /(..)(\d{4})(\d{2})(\d{2})(\d{0,2})\.lev$/ ) { push @newdir, $file; # print " push
"; } else { next } ($stab, $yr, $mon, $day, $hr) = ($1, $2, $3, $4, $5); @alt = @Walt = @Oalt = @temp = @frost = @water = ''; undef @ozone; $alt = $temp = $ozone = $frost = $water = ''; $mina = $mino = $mint = $minw = 100000000; $gifname = $gifdir.$stab.$yr.$mon.$day.$hr.'.gif'; if ( $stab eq 'bl' ) { $bdr_recent = $stab.$yr.$mon.$day.$hr } # extract data (if necessary) if ( !(-e $gifname) || $regraph ) { # print "$gifname not found
"; open IN, $dir.$file or print "Couldn't open $dir$file - $!\n"; $test && print "reading $file
"; while ( ) { if ( /date/i && /launch/i && /(\d+ \w+ \d+)/ ) { $date{$file} = $1; if ( $hr ) { $time{$file} = " @ $hr" . 'UTC' } $test && print "$. -> date $file - $date{$file}
"; } # form = 1 # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #Level Press Alt Pottp Temp FtempV Hum Ftemp Water # Num hPa km K C C % C ppmv # 6 825.1 1.743 308.8 19.1 -7.8 14 999.99 9.99E+09 # form = 2 #Level Press Alt Pottp Temp FtempV Hum Ozone Ozone Ozone Ptemp O3 # DN O3 Res SwFtemp SwWater #Num hPa km K C C % mPa ppmv atmcm C 10^11/cc DU C ppmv # 0 1002.9 0.050 297.4 24.5 22.8 92 0.16 0.002 0.0000 37.4 0.389 33 23.91 2.96E+04 # form = 3 #Level Press Alt Pottp Temp FtempV Hum Ozone Ozone Ozone Ptemp O3 # DN O3 Res # Num hPa km K C C % mPa ppmv atmcm C 10^11/cc DU # 0 1005.1 0.000 301.2 28.5 22.1 69 100.00 0.995 0.0000 1000.0 240.080 285 # read to the end of the file $form = ''; if ( / Num / && / hPa / && / km / && / K / ) { @line = split; if ( $line[7] eq 'C' ) { $form = 1 } elsif ( $line[14] eq 'ppmv' ) { $form = 2 } elsif ( $line[7] eq 'mPa' ) { $form = 3 } while ( ) { unless ( / 999\.99 / || / 9\.99E+09 / ) { # get rid of invalid data # print "$_
"; @data = split; if ( $form == 1 ) { ($alt, $temp, $frost, $water) = ((@data)[2, 4, 7, 8]) } elsif ( $form == 2 ) { ($alt, $temp, $ozone, $frost, $water) = ((@data)[2, 4, 7, 13, 14]) } elsif ( $form == 3 ) { ($alt, $temp, $ozone ) = ((@data)[2, 4, 7 ]) } else { die "Unexpected format in $file
\n"; } if ( $regraph ) { if ( $alt < $mina ) { $mina = $alt } elsif ( $alt > $maxa ) { $maxa = $alt } if ( $ozone < $mino ) { $mino = $ozone } elsif ( $ozone > $maxo ) { $maxo = $ozone } if ( $temp < $mint ) { $mint = $temp } elsif ( $temp > $maxt ) { $maxt = $temp } if ( $water < $minw ) { $minw = $water } elsif ( $water > $maxw ) { $maxw = $water } } push @alt, $alt; push @temp, $temp; push @frost, $frost; if ( $ozone > 0 ) { push @ozone, $ozone; push @Oalt, $alt; } if ( $water > 0 ) { push @water, log10 $water; push @Walt, $alt; } $points++; # $test && print "alt $alt km, temp $temp C, frost $frost C, wv $water ppmv
"; # last; } # else { print "$_
";} # see the data that is being ignored } } } close IN; # $test && print "minalt $mina
maxalt $maxa
maxH2O $maxw
"; # $test && print "min T $mint
max T $maxt
"; $file =~ s/\.lev//; # Start PGPLOT # portrait mode $outgif = $gifdir.$file.'.gif/VGIF'; $outps = $gifdir.$file.'.ps/VCPS'; foreach $out ($outgif, $outps) { $test && print "$out
"; $test && print "pgbeg
"; if ( pgbeg(0, $out, 1, 1) == 1 ) { # scale the image a bit if ( $out eq $outgif ) { pgpap(6, 1.25) } # deal with line width to increase readability while scaling # pgqlw($lw); # default == 1 # if ( $out eq $outgif ) { pgslw($lw + 2) } # else { pgslw($lw) } # Generate the graph. pgsci(1); pgvstd; pgqch($char_ht); # Label the graph pgsch($char_ht); # set character height pgmtxt('T', # Top 2.2, # Displacement from top of viewport # 0.0, # Start at lefthand side of edge 0.5, # Start at 1/2 way along edge # 1.0, # Start at righthand side of edge 0.5, # Center from middle "$names{$stat} - $date{$name}$time{$name}"); pgmtxt('L', # Left side 2.5, # Displacement from top of viewport 0.5, # Start at 1/2 way along edge 0.5, # Center from middle 'Altitude (km)'); # set top line for Temp vs Alt pgsci(2); # RED pgsch(0.75); pgswin(-95, 35, 0, 34); pgbox( 'CMST', # X options 0, # Xtick 0, # NXsub '', # Yopt 0, 0); # Ytick, NYsub # Output the height/temp pairs pgsci(2); # RED pgpt($#alt, \@temp, \@alt, 20); pgsch($char_ht); pgmtxt('T', # Top -2.0, # Displacement from top of viewport 0.75, # Start at 3/4 way along edge 0.5, # Center from middle 'Temp (C)'); # Output the height/wv pairs if ( $#water > 0) { pgsci(4); # BLUE pgsch(0.75); # set window for WV vs Alt pgswin($low, $high, 0, 34); pgbox('BILNST', # X options 0, # Xtick 0, # NXsub '', # Yopt 0, 0); # Ytick, NYsub pgpt($#Walt, \@water, \@Walt, 20); pgsch($char_ht); pgmtxt('B', # Bottom 2.5, # Displacement from top of viewport 0.5, # Start at 1/2 way along edge 0.5, # Center from middle 'Water Vapor (ppmv)'); } # Output the height/ozone pairs if ( $#ozone > 0) { # set window for Temp vs Ozone pgsci(1); # BLACK pgsch(0.75); pgswin(0, 25, 0, 34); pgbox('BST', # X options 0, # Xtick 0, # NXsub '', # Yopt 0, 0); # Ytick, NYsub for ( $i = 5; $i <= 20; $i +=5 ) { pgmtxt('B', # Bottom -1.0, # Displacement from bottom of viewport $i/25, # Start at 1/2 way along edge 0.5, # Center from middle $i) } pgpt($#Oalt, \@ozone, \@Oalt, 20); pgsch($char_ht); pgmtxt('B', # Bottom -1.75, # Displacement from bottom of viewport 0.5, # Start at 1/2 way along edge 0.5, # Center from middle 'Ozone (mPa)'); } # Put in ownership tag pgsci(1); # BLACK pgsch(0.5); pgmtxt('B', # Bottom 7.5, # Displacement from top of viewport in units of char height 0.75, # Start at 3/4 way along edge 0.5, # Center from middle "(Generated courtesy of NOAA/CMDL)"); # set sides for Alt pgsci(1); # BLACK pgsch(0.75); pgswin(-95, 35, 0, 34); pgbox('BC', # X options 0, # Xtick 0, # NXsub 'BCMNSTV', # Yopt 0, 0); # Ytick, NYsub # Stop PGPLOT pgend; } else { print "

an error has occurred - unable to PGBEG!

\n" } # Generate PDF files if ( $out eq $outps ) { $pdf = "ps2pdf $gifdir$file.ps $gifdir$file.pdf"; print qx "$pdf"; } } } else { $test && print "$gifname already exists
"; } } } # show image print center(p); $name =~ s/\.lev//; print "
", img( { -src => "../dobson/gifs/h2o/$bdr_recent" . '.gif', -name => 'gif', -align => 'center', -border => '1', -alt => 'CMDL Water Vapor data'} ), p, "
", start_form(), "Choose file type
\n", radio_group( -name => 'types', -values => ['PDF', 'PS', 'GIF'], -rows => 3, -align =>'left', -onClick => 'type_change(this.form)'), "
", h4( a( { -href => "../dobson/gifs/h2o/$bdr_recent" . '.pdf', -name => 'file' }, 'Download this graph') ), "
", popup_menu ( -name => 'stations', -values => \@stats, -labels => \%names, -default => 'boulder', -onChange => 'change_dates(this.form)'), br, popup_menu ( -name => 'years', -values => \@bdryrs, -default => 'boulder', -onChange => 'change_flights(this.form)'), br, popup_menu ( -name => 'flights', -values => ' - ', -onChange => 'get_image(this.form)'), p, "
", end_form, ; print h4( blockquote("Water vapor, temperature, and ozone ('blue,' 'red,' and 'black' dots, respectively) are graphed versus altitude.", p, "Some graphs do not have water vapor values since some of the studies flew ozonesondes before and after watervapor sondes.", p, "(Graphs load automatically.)" ), ); print center( blockquote(hr), p, 'Data for particular stations/flights are available by contacting: ', a({-href => 'mailto:holger.voemel@noaa.gov'}, 'Dr. Holger Voemel'), p, 'If you have questions or comments about this page, please contact: ', a({-href => 'mailto:Gloria.Carbaugh@NOAA.gov'}, 'Gloria Carbaugh'), br, p, "
NOAA
Disclaimer
Privacy Notice

Climate Monitoring & Diagnostics Laboratory
Ozone & Water Vapor

325 Broadway R/CMDL1
Boulder, CO 80305
"); if ( $regraph ) { print "alt $mina $maxa
\n"; print "ozone $mino $maxo
\n"; print "temp $mint $maxt
\n"; print "water $minw $maxw
\n"; } print end_html; __END__ # end of html