File: demo3-ncepclim.rb

package info (click to toggle)
ruby-netcdf 0.6.6-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 1,184 kB
  • ctags: 882
  • sloc: ansic: 3,968; ruby: 1,661; makefile: 9; csh: 6
file content (178 lines) | stat: -rw-r--r-- 4,374 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# 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