# Plot global climatological temperature distribution
# from the NCEP reanalysis data.
# The data is downloaded if not found and the users wants.
######################################
### local functions ###
def nearest_index(na,val)
# returns the element of na nearest to val
# na is assumed to be 1d and monotonic
if(na[0] > na[-1]) then
reversed = true
na = na[-1..0]
else
reversed = false
end
w = (na.lt(val)).where
idx = [ (w.length==0 ? 0 : w.max), na.length-2 ].min
if ( na[idx+1]-val < val-na[idx] ) then
idx = idx+1
end
if reversed then
na = na[-1..0]
idx = na.length-1-idx
end
idx
end
#####################################
### main part ###
require "numru/dcl"
require "numru/netcdf"
include NumRu
filename = "air.mon.ltm.nc"
# < download if not found and the users wants >
if !(Dir.glob(filename)[0]) then
# file not found ==> download by ftp if the user wants
host = "ftp.cdc.noaa.gov"
path = "/Datasets/ncep.reanalysis.derived/pressure/"+filename
print "\n*** question ***\n",
" File "+filename+" is not in the current directory.\n",
" Would you like to download (ftp) it from "+host+"?\n",
" (y, n)> "
ans = gets
if ans =~ /^y/ then
print " What is your email address? (needed for anonymous ftp) > "
email = gets.chop!
require "net/ftp"
print " connecting...\n"
ftp = Net::FTP.open(host, "anonymous", email, nil)
size = ftp.size(path)
print " Size of the file is #{(size/1000)} kb. Would you really like to download?\n (y, n)> "
ans = gets
if ans =~ /^y/ then
print " now downloading...\n"
ftp.getbinaryfile(path, filename)
else
print " exit\n"
exit
end
else
print " exit\n"
exit
end
end
# < open the file and read axes >
file = NetCDF.open(filename)
var = file.var("air") # temperature
lon = file.var("lon")
lat = file.var("lat")
level = file.var("level")
time = file.var("time") # in hours
t = (time.get/720).round + 1 # --> in months
axes = [ lon, lat, level, time ]
axvals = [ lon.get, lat.get, level.get, t ]
axunits = [ lon.att("units").get.gsub("_",""),
lat.att("units").get.gsub("_",""),
level.att("units").get.gsub("_",""),
"months" ]
# < graphics >
#DCL.sglset('lbuff',false)
DCL.swlset('lwait',false)
DCL.gropn(1)
first = true
while true do
begin
## / select a 2D slice /
if (first) then
print <<-EOS
** select a slice **
List desired grid numbers of lonigutede, latitude, level, time
(set only two of them)
Example:
, , 850, 1
-- horizontal slice at 850hPa and January
135, , , 2
-- vertical slice at 135E and Feburary
EOS
DCL.grfrm
else
DCL.grfrm
print "Input next slice (C-d to quit)\n"
end
print "> "
slice = gets.chop!.split(",")
if slice.length!=4 then
raise("Slice must be 4 comma-split numerics")
end
slice.collect!{|e| # "collect!" replaces elements
if e =~ /^ *$/ then
nil
else
e.to_f
end
}
iax = []
start=[] ; last=[]
slice.each_index{|i|
if slice[i] == nil then
iax.push(i)
start.push(0) ; last.push(-1) # from the beginning to the end
else
idx = nearest_index( axvals[i], slice[i] )
start.push( idx ) ; last.push( idx )
end
}
if iax.length != 2 then
raise("Specify a 2D slice")
else
x = axvals[iax[0]]
iax[0]==2 ? xr=[x.max, x.min] : xr=[x.min, x.max]
xttl = axes[iax[0]].att("long_name").get
xunits = axunits[iax[0]]
y = axvals[iax[1]]
iax[1]==2 ? yr=[y.max, y.min] : yr=[y.min, y.max]
yttl = axes[iax[1]].att("long_name").get
yunits = axunits[iax[1]]
end
## / read the slice and plot /
v = var.get("start"=>start, "end"=>last)
shp=v.shape; shp.delete(1); v.reshape!(*shp) # delete dims of length==1
#Fig.inclpoint(x, y)
DCL.grswnd( xr[0], xr[1], yr[0], yr[1] )
DCL.grsvpt(0.2,0.9,0.2,0.9)
DCL.grstrf
DCL.ussttl(xttl," ",yttl," ")
DCL.usdaxs
DCL.uwsgxa(x)
DCL.uwsgya(y)
DCL.uelset("ltone",true)
DCL.uetone(v)
DCL.udcntz(v)
first = false
rescue
print "*Error* ", $!,"\n" # show the error message in ($!)
end
end
DCL.grcls
syntax highlighted by Code2HTML, v. 0.9.1