ruby-grads 1.0.0 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/grads/binary.rb +735 -0
- data/lib/grads/gridded.rb +30 -5
- data/ruby-grads.gemspec +2 -3
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95bceedf1ed3e79fdb745fcc31e9b4153475d69fd72377fed5c3a16384d610cd
|
4
|
+
data.tar.gz: 5aa72a291c3e54e6de246215187b2ca9bd2e074dfb1a3c26421a5dd37b47b9de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 425065b1cc532c8e9934f0e6cf812848edb5b5886f241361daf8252b18d1da8d0985ffaf979f885c47a411d2cf2c5a7ea55bb5694c42d56981979bb3f6a783c9
|
7
|
+
data.tar.gz: a189c6e9bc19933042aea13dd223616f252f362540c213a6715c2ec03b027bc00c44ca0bf8be5cc8efb7f3fae90ddc348650a79f317f0f68d642c61a375b9cbb
|
data/lib/grads/binary.rb
ADDED
@@ -0,0 +1,735 @@
|
|
1
|
+
#
|
2
|
+
#
|
3
|
+
#
|
4
|
+
# A library to read GrADS gridded data into CArray.
|
5
|
+
#
|
6
|
+
# TODO
|
7
|
+
# * options
|
8
|
+
#
|
9
|
+
# NOTE
|
10
|
+
# * 'dset' should be a file
|
11
|
+
#
|
12
|
+
# --- supported -------
|
13
|
+
# dset
|
14
|
+
# dtype
|
15
|
+
# title
|
16
|
+
# undef
|
17
|
+
# options
|
18
|
+
# pdef
|
19
|
+
# xdef
|
20
|
+
# ydef
|
21
|
+
# zdef
|
22
|
+
# tdef
|
23
|
+
# vectorpairs
|
24
|
+
# * comment
|
25
|
+
#
|
26
|
+
# --- not supported ---
|
27
|
+
# chsub
|
28
|
+
# fileheader
|
29
|
+
# theader
|
30
|
+
# tailerbytes
|
31
|
+
# xyheader
|
32
|
+
#
|
33
|
+
|
34
|
+
require "carray"
|
35
|
+
require "strscan"
|
36
|
+
|
37
|
+
module GrADS
|
38
|
+
end
|
39
|
+
|
40
|
+
class GrADS::Gridded
|
41
|
+
end
|
42
|
+
|
43
|
+
class GrADS::Gridded::Variable
|
44
|
+
|
45
|
+
def initialize (name, ctl)
|
46
|
+
@name = name
|
47
|
+
@dim = ctl.vardims[name]
|
48
|
+
@tsize = ctl.tsize
|
49
|
+
@dset = ctl.dset
|
50
|
+
@chunksize = ctl.chunksize
|
51
|
+
@offset = ctl.varoffsets[name]
|
52
|
+
@undef = ctl.undef
|
53
|
+
end
|
54
|
+
|
55
|
+
attr_reader :name, :dim, :size, :dset, :offset
|
56
|
+
|
57
|
+
def each_trange (trng=nil)
|
58
|
+
case trng
|
59
|
+
when NilClass, FalseClass
|
60
|
+
(0...@tsize).each do |t|
|
61
|
+
yield(t)
|
62
|
+
end
|
63
|
+
when Range
|
64
|
+
trng.each do |t|
|
65
|
+
yield(t)
|
66
|
+
end
|
67
|
+
else
|
68
|
+
t = trng
|
69
|
+
yield(t)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def tsize (trng=nil)
|
74
|
+
case trng
|
75
|
+
when NilClass, FalseClass
|
76
|
+
return @tsize
|
77
|
+
when Range
|
78
|
+
return trng.to_a.size
|
79
|
+
else
|
80
|
+
return 1
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def [] (*argv)
|
85
|
+
trng = argv.shift
|
86
|
+
buf = CArray.float(*@dim)
|
87
|
+
out = nil
|
88
|
+
open(@dset) { |io|
|
89
|
+
if tsize(trng) == 1
|
90
|
+
each_trange(trng) { |t|
|
91
|
+
io.seek(t * @chunksize + offset)
|
92
|
+
buf.load_binary(io)
|
93
|
+
out = buf[*argv]
|
94
|
+
}
|
95
|
+
else
|
96
|
+
outlist = []
|
97
|
+
i = 0
|
98
|
+
bind_ok = false
|
99
|
+
each_trange(trng) { |t|
|
100
|
+
t * @chunksize + offset
|
101
|
+
io.seek(t * @chunksize + offset)
|
102
|
+
buf.load_binary(io)
|
103
|
+
obj = buf[*argv].to_ca
|
104
|
+
if obj.is_a?(CArray)
|
105
|
+
outlist << obj
|
106
|
+
else
|
107
|
+
outlist << CA_FLOAT(obj)
|
108
|
+
bind_ok = true
|
109
|
+
end
|
110
|
+
i += 1
|
111
|
+
}
|
112
|
+
if bind_ok
|
113
|
+
out = CArray.bind(:float, outlist, 0)
|
114
|
+
else
|
115
|
+
out = CArray.merge(:float, outlist, 0)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
}
|
119
|
+
out[:eq, @undef] = UNDEF
|
120
|
+
return out
|
121
|
+
end
|
122
|
+
|
123
|
+
def to_ca
|
124
|
+
return self[]
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
class GrADS::Gridded
|
130
|
+
|
131
|
+
def initialize (ctl_file, radius: nil)
|
132
|
+
@ctl_file = ctl_file
|
133
|
+
@entries = scan_ctl_file(ctl_file)
|
134
|
+
@radius = radius
|
135
|
+
parse_entries(@entries)
|
136
|
+
end
|
137
|
+
|
138
|
+
attr_reader :ctl_file, :entries
|
139
|
+
attr_reader :dset, :title, :undef
|
140
|
+
attr_reader :pdef, :proj
|
141
|
+
attr_reader :isize, :jsize
|
142
|
+
attr_reader :xsize, :ysize, :zsize, :tsize
|
143
|
+
attr_reader :xaxis, :yaxis, :zaxis, :taxis
|
144
|
+
attr_reader :vectorpair
|
145
|
+
attr_reader :varnames, :vars, :vardims, :varoffsets
|
146
|
+
attr_reader :chunksize
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
def scan_ctl_file (ctl_file)
|
151
|
+
io = open(ctl_file, "r:ASCII-8BIT")
|
152
|
+
edefs = ""
|
153
|
+
vdefs = ""
|
154
|
+
headers = ""
|
155
|
+
while line = io.gets
|
156
|
+
case line
|
157
|
+
when /\A\s*vars/i
|
158
|
+
vdefs << line
|
159
|
+
while line = io.gets
|
160
|
+
vdefs << line
|
161
|
+
if line =~ /\A\s*endvars/i
|
162
|
+
break
|
163
|
+
end
|
164
|
+
end
|
165
|
+
when /\A\s*edef/i
|
166
|
+
raise "edef entry is not supported, sorry!"
|
167
|
+
edefs << line
|
168
|
+
while line = io.gets
|
169
|
+
ddefs << line
|
170
|
+
if line =~ /\A\s*endedef/i
|
171
|
+
break
|
172
|
+
end
|
173
|
+
end
|
174
|
+
else
|
175
|
+
headers << line
|
176
|
+
end
|
177
|
+
end
|
178
|
+
entries = scan_headers(headers)
|
179
|
+
entries["vars"] = scan_vars(vdefs)
|
180
|
+
return entries
|
181
|
+
end
|
182
|
+
|
183
|
+
def scan_headers (headers)
|
184
|
+
items = {}
|
185
|
+
buffer = ""
|
186
|
+
headers.each_line do |line|
|
187
|
+
case line
|
188
|
+
when /\A\s*\*/, /\A\s*\Z/
|
189
|
+
next
|
190
|
+
when /A\s*(dtype)\s*(.*)\Z/i
|
191
|
+
raise "data file is not GrADS gridded binary"
|
192
|
+
when /\A\s*(dset|title|undef|options|pdef|xdef|ydef|zdef|tdef|vectorpairs)\s*(.*)\Z/i
|
193
|
+
name = $1.downcase
|
194
|
+
if items[name]
|
195
|
+
items[name] = [items[name]]
|
196
|
+
items[name] << $2.rstrip
|
197
|
+
buffer = items[name].last
|
198
|
+
else
|
199
|
+
items[name] = $2.rstrip
|
200
|
+
buffer = items[name]
|
201
|
+
end
|
202
|
+
when /\A\s*(chsub|fileheader|theader|tailerbyts|xyheader)\s*(.*)\Z/i
|
203
|
+
raise "#{$1} entry is not supported, sorry"
|
204
|
+
else
|
205
|
+
line = line.chomp.sub(/\\\z/,'').rstrip
|
206
|
+
buffer.replace(buffer + " " + line)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
return items
|
210
|
+
end
|
211
|
+
|
212
|
+
def scan_vars (vars)
|
213
|
+
items = {:namelist=>[]}
|
214
|
+
nvars = nil
|
215
|
+
vars.each_line do |line|
|
216
|
+
case line
|
217
|
+
when /\A\s*\*/, /\A\s*\Z/
|
218
|
+
next
|
219
|
+
when /\A\s*vars\s+(\d+)/i
|
220
|
+
nvars = $1.to_i
|
221
|
+
when /\A\s*endvars/i
|
222
|
+
break
|
223
|
+
when /\A\s*(\w+)\s*(.*)\Z/
|
224
|
+
name = $1
|
225
|
+
list = $2
|
226
|
+
items[:namelist].push(name)
|
227
|
+
items[name] = list
|
228
|
+
end
|
229
|
+
end
|
230
|
+
if items[:namelist].size != nvars
|
231
|
+
raise "invalid vars number"
|
232
|
+
end
|
233
|
+
return items
|
234
|
+
end
|
235
|
+
|
236
|
+
def parse_entries (entries)
|
237
|
+
parse_dset(entries["dset"])
|
238
|
+
if entries.has_key?("title")
|
239
|
+
parse_title(entries["title"])
|
240
|
+
end
|
241
|
+
parse_undef(entries["undef"])
|
242
|
+
parse_options(*entries["options"])
|
243
|
+
if entries.has_key?("pdef")
|
244
|
+
parse_pdef(entries["pdef"])
|
245
|
+
parse_xdef(entries["xdef"], with_pdef = true)
|
246
|
+
parse_ydef(entries["ydef"], with_pdef = true)
|
247
|
+
else
|
248
|
+
parse_xdef(entries["xdef"], with_pdef = false)
|
249
|
+
parse_ydef(entries["ydef"], with_pdef = false)
|
250
|
+
end
|
251
|
+
parse_zdef(entries["zdef"])
|
252
|
+
parse_tdef(entries["tdef"])
|
253
|
+
if entries.has_key?("vectorpairs")
|
254
|
+
parse_vectorpairs(entries["vectorpairs"])
|
255
|
+
end
|
256
|
+
parse_vars(entries["vars"][:namelist], entries["vars"])
|
257
|
+
end
|
258
|
+
|
259
|
+
def parse_dset (line)
|
260
|
+
line.strip!
|
261
|
+
if line =~ /\A\^/
|
262
|
+
cwd = File.dirname(File.expand_path(@ctl_file))
|
263
|
+
@dset = File.join(cwd, line[1..-1])
|
264
|
+
else
|
265
|
+
@dset = line
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def parse_title (line)
|
270
|
+
@title = line
|
271
|
+
end
|
272
|
+
|
273
|
+
def parse_undef (line)
|
274
|
+
@undef = Float(line)
|
275
|
+
end
|
276
|
+
|
277
|
+
def parse_options (*lines)
|
278
|
+
# yrev o
|
279
|
+
# zrev o
|
280
|
+
# template x
|
281
|
+
# squential o
|
282
|
+
# 365_day_calendar ?
|
283
|
+
# byteswapped o
|
284
|
+
# big_endian o
|
285
|
+
# little_endian o
|
286
|
+
# cray_32bit_ieee ?
|
287
|
+
end
|
288
|
+
|
289
|
+
def parse_pdef (line)
|
290
|
+
list = line.split(/\s+/)
|
291
|
+
@pdef = list
|
292
|
+
@isize = list[0].to_i
|
293
|
+
@jsize = list[1].to_i
|
294
|
+
case list[2].downcase
|
295
|
+
when "nps", "sps"
|
296
|
+
parse_pdef_xps(list[2..-1])
|
297
|
+
when "lcc", "lccr"
|
298
|
+
parse_pdef_lcc(list[2..-1])
|
299
|
+
when "eta.u"
|
300
|
+
parse_pdef_eta_u(list[2..-1])
|
301
|
+
when "pse"
|
302
|
+
parse_pdef_pse(list[2..-1])
|
303
|
+
when "ops"
|
304
|
+
parse_pdef_ops(list[2..-1])
|
305
|
+
when "rotll", "rotllr"
|
306
|
+
parse_pdef_rotll(list[2..-1])
|
307
|
+
when "bilin"
|
308
|
+
parse_pdef_bilin(list[2..-1])
|
309
|
+
when "general"
|
310
|
+
parse_pdef_general(list[2..-1])
|
311
|
+
when "file"
|
312
|
+
parse_pdef_file(list[2..-1])
|
313
|
+
else
|
314
|
+
raise "pdef #{list[2].downcase} is not supported"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def parse_pdef_xps (args)
|
319
|
+
raise NotImplementedError, "not implemented"
|
320
|
+
end
|
321
|
+
|
322
|
+
def parse_pdef_lcc (args)
|
323
|
+
require "proj4r"
|
324
|
+
rlat = args[1].to_f
|
325
|
+
rlon = args[2].to_f
|
326
|
+
xi = args[3].to_f
|
327
|
+
yi = args[4].to_f
|
328
|
+
slat1 = args[5].to_f
|
329
|
+
slat2 = args[6].to_f
|
330
|
+
slon = args[7].to_f
|
331
|
+
dx = args[8].to_f
|
332
|
+
dy = args[9].to_f
|
333
|
+
slat0 = slat1 > 0 ? 90 : -90
|
334
|
+
if @radius
|
335
|
+
p @radius
|
336
|
+
proj = PROJ4::Proj.new %{
|
337
|
+
+ellps=sphere +a=#{@radius} +b=#{@radius} +proj=lcc \
|
338
|
+
+lat_1=#{slat1} +lat_2=#{slat2} +lon_0=#{slon}
|
339
|
+
}
|
340
|
+
else
|
341
|
+
proj = PROJ4::Proj.new %{
|
342
|
+
+ellps=sphere +proj=lcc \
|
343
|
+
+lat_1=#{slat1} +lat_2=#{slat2} +lon_0=#{slon}
|
344
|
+
}
|
345
|
+
end
|
346
|
+
rx, ry = proj.forward(rlon, rlat)
|
347
|
+
rx0 = rx - (xi-1)*dx
|
348
|
+
ry0 = ry - (yi-1)*dy
|
349
|
+
@forward = lambda { |lon, lat|
|
350
|
+
mx, my = proj.forward(lon, lat)
|
351
|
+
[(mx - rx0)/dx, (my - ry0)/dy]
|
352
|
+
}
|
353
|
+
@inverse = lambda { |fi, fj|
|
354
|
+
mx = fi*dx + rx0
|
355
|
+
my = fj*dy + ry0
|
356
|
+
proj.inverse(mx, my)
|
357
|
+
}
|
358
|
+
@xy = lambda {
|
359
|
+
x = CArray.float(xsize).seq(rx0, dx)
|
360
|
+
y = CArray.float(ysize).seq(ry0, dy)
|
361
|
+
[x[ysize,:%].to_ca, y[:%,xsize].to_ca]
|
362
|
+
}
|
363
|
+
end
|
364
|
+
|
365
|
+
def parse_pdef_eta_u (args)
|
366
|
+
raise NotImplementedError, "not implemented"
|
367
|
+
end
|
368
|
+
|
369
|
+
def parse_pdef_pse (args)
|
370
|
+
raise NotImplementedError, "not implemented"
|
371
|
+
end
|
372
|
+
|
373
|
+
def parse_pdef_ops (args)
|
374
|
+
raise NotImplementedError, "not implemented"
|
375
|
+
end
|
376
|
+
|
377
|
+
def parse_pdef_rotll (args)
|
378
|
+
raise NotImplementedError, "not implemented"
|
379
|
+
end
|
380
|
+
|
381
|
+
def parse_pdef_general (args)
|
382
|
+
raise NotImplementedError, "not implemented"
|
383
|
+
end
|
384
|
+
|
385
|
+
def parse_pdef_file (args)
|
386
|
+
raise NotImplementedError, "not implemented"
|
387
|
+
end
|
388
|
+
|
389
|
+
def parse_xdef (line, with_pdef=false)
|
390
|
+
list = line.split(/\s+/)
|
391
|
+
if with_pdef
|
392
|
+
@xsize = list[0].to_i
|
393
|
+
else
|
394
|
+
@isize = list[0].to_i
|
395
|
+
@xsize = @isize
|
396
|
+
end
|
397
|
+
case list[1]
|
398
|
+
when /linear/i
|
399
|
+
@xaxis = []
|
400
|
+
@xsize.times do |i|
|
401
|
+
@xaxis << list[2].to_f + i*list[3].to_f
|
402
|
+
end
|
403
|
+
when /levels/i
|
404
|
+
@xaxis = list[2..-1].map{|x| x.to_f}
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
def parse_ydef (line, with_pdef=false)
|
409
|
+
list = line.split(/\s+/)
|
410
|
+
if with_pdef
|
411
|
+
@ysize = list[0].to_i
|
412
|
+
else
|
413
|
+
@jsize = list[0].to_i
|
414
|
+
@ysize = @jsize
|
415
|
+
end
|
416
|
+
case list[1]
|
417
|
+
when /linear/i
|
418
|
+
@yaxis = []
|
419
|
+
@ysize.times do |i|
|
420
|
+
@yaxis << list[2].to_f + i*list[3].to_f
|
421
|
+
end
|
422
|
+
when /levels/i
|
423
|
+
@yaxis = list[2..-1].map{|y| y.to_f}
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
def parse_zdef (line)
|
428
|
+
list = line.split(/\s+/)
|
429
|
+
@zsize = list[0].to_i
|
430
|
+
case list[1]
|
431
|
+
when /linear/i
|
432
|
+
@zaxis = []
|
433
|
+
@zsize.times do |i|
|
434
|
+
@zaxis << list[2].to_f + i*list[3].to_f
|
435
|
+
end
|
436
|
+
when /levels/i
|
437
|
+
@zaxis = list[2..-1].map{|z| z.to_f}
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
def parse_tdef (line)
|
442
|
+
list = line.split(/\s+/)
|
443
|
+
@tsize = list[0].to_i
|
444
|
+
@inittime = DateTime.parse(list[2].sub(/z/i,' '))
|
445
|
+
@taxis = [@inittime]
|
446
|
+
case list[3]
|
447
|
+
when /\A(\d+)(mn|hr|dy|mo|yr)/
|
448
|
+
case $2
|
449
|
+
when "mn"
|
450
|
+
(1..@tsize-1).each do |i|
|
451
|
+
@taxis[i] = @taxis[i-1] + ($1.to_i).quo(1440)
|
452
|
+
end
|
453
|
+
when "hr"
|
454
|
+
(1..@tsize-1).each do |i|
|
455
|
+
@taxis[i] = @taxis[i-1] + ($1.to_i).quo(24)
|
456
|
+
end
|
457
|
+
when "dy"
|
458
|
+
(1..@tsize-1).each do |i|
|
459
|
+
@taxis[i] = @taxis[i-1] + $1.to_i
|
460
|
+
end
|
461
|
+
when "mn"
|
462
|
+
(1..@tsize-1).each do |i|
|
463
|
+
@taxis[i] = @taxis[i-1] >> $1.to_i
|
464
|
+
end
|
465
|
+
when "yr"
|
466
|
+
(1..@tsize-1).each do |i|
|
467
|
+
@taxis[i] = @taxis[i-1] >> (12*$1.to_i)
|
468
|
+
end
|
469
|
+
end
|
470
|
+
else
|
471
|
+
raise "invalid time increment"
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
def parse_vectorpairs (line)
|
476
|
+
list = line.split(/\s+/)
|
477
|
+
@vectorpair = list.map{|pair| pair.downcase.split(/\s*,\s*/)}
|
478
|
+
end
|
479
|
+
|
480
|
+
def parse_vars (namelist, hash)
|
481
|
+
@varnames = namelist
|
482
|
+
@vars = {}
|
483
|
+
@vardims = {}
|
484
|
+
@varoffsets = {}
|
485
|
+
@chunksize = 0
|
486
|
+
namelist.each do |name|
|
487
|
+
line = hash[name]
|
488
|
+
ss = StringScanner.new(line)
|
489
|
+
znum = ss.scan(/\A.*?\s+/).rstrip.to_i
|
490
|
+
units = ss.scan(/\A.*?\s+/).rstrip
|
491
|
+
desc = ss.rest
|
492
|
+
@vars[name] = [znum, units, desc]
|
493
|
+
if znum == 0
|
494
|
+
@vardims[name] = [@jsize,@isize]
|
495
|
+
else
|
496
|
+
@vardims[name] = [znum, @jsize,@isize]
|
497
|
+
end
|
498
|
+
@varoffsets[name] = @chunksize
|
499
|
+
@chunksize += 4 * @vardims[name].inject(1) {|s,d| s * d}
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
public
|
504
|
+
|
505
|
+
def inverse (fi, fj)
|
506
|
+
return @inverse[fi,fj]
|
507
|
+
end
|
508
|
+
|
509
|
+
def forward (rlon, rlat)
|
510
|
+
return @forward[rlon, rlat]
|
511
|
+
end
|
512
|
+
|
513
|
+
def lonlat
|
514
|
+
fi = CArray.float(xsize).seq
|
515
|
+
fj = CArray.float(ysize).seq
|
516
|
+
ii = fi[ysize,:%]
|
517
|
+
jj = fj[:%,xsize]
|
518
|
+
return @inverse[ii, jj]
|
519
|
+
end
|
520
|
+
|
521
|
+
def xy
|
522
|
+
return @xy[]
|
523
|
+
end
|
524
|
+
|
525
|
+
def var (name)
|
526
|
+
unless @varnames.include?(name)
|
527
|
+
raise "invalid variable name '#{name}'"
|
528
|
+
end
|
529
|
+
return Variable.new(name, self)
|
530
|
+
end
|
531
|
+
|
532
|
+
def template (ctl_file, &block)
|
533
|
+
asm = Writer.new(self)
|
534
|
+
asm.define(&block)
|
535
|
+
asm.write(ctl_file)
|
536
|
+
end
|
537
|
+
|
538
|
+
end
|
539
|
+
|
540
|
+
class GrADS::Gridded::Writer
|
541
|
+
|
542
|
+
def initialize (ctl = nil)
|
543
|
+
@dset = nil
|
544
|
+
@title = nil
|
545
|
+
@options = []
|
546
|
+
@vectorpairs = nil
|
547
|
+
@vars = []
|
548
|
+
@nt = 1
|
549
|
+
if ctl
|
550
|
+
e = ctl.entries
|
551
|
+
@undef = e["undef"]
|
552
|
+
@pdef = e["pdef"]
|
553
|
+
@xdef = e["xdef"]
|
554
|
+
@ydef = e["ydef"]
|
555
|
+
@zdef = e["zdef"]
|
556
|
+
@tdef = e["tdef"]
|
557
|
+
else
|
558
|
+
@undef = nil
|
559
|
+
@pdef = nil
|
560
|
+
@xdef = nil
|
561
|
+
@ydef = nil
|
562
|
+
@zdef = nil
|
563
|
+
@tdef = "1 linear 0z1jan2000"
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
private
|
568
|
+
|
569
|
+
def dset (arg)
|
570
|
+
@dset = arg
|
571
|
+
end
|
572
|
+
|
573
|
+
def title (arg)
|
574
|
+
@title = arg
|
575
|
+
end
|
576
|
+
|
577
|
+
def undef! (arg)
|
578
|
+
@undef = arg
|
579
|
+
end
|
580
|
+
|
581
|
+
def options (*args)
|
582
|
+
@options.push(*args)
|
583
|
+
end
|
584
|
+
|
585
|
+
def pdef (*args)
|
586
|
+
@pdef = args.join(" ")
|
587
|
+
end
|
588
|
+
|
589
|
+
def xdef (*args)
|
590
|
+
if args.size == 1 and
|
591
|
+
( args.first.is_a?(CArray) or args.first.is_a?(Array) )
|
592
|
+
ary = args.first
|
593
|
+
@xdef = [ary.length, "levels", ary.to_a.join("\n")].join(" ")
|
594
|
+
else
|
595
|
+
@xdef = args.join(" ")
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
def ydef (*args)
|
600
|
+
if args.size == 1 and
|
601
|
+
( args.first.is_a?(CArray) or args.first.is_a?(Array) )
|
602
|
+
ary = args.first
|
603
|
+
@ydef = [ary.length, "levels", ary.to_a.join("\n")].join(" ")
|
604
|
+
else
|
605
|
+
@ydef = args.join(" ")
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
def zdef (*args)
|
610
|
+
if args.size == 1 and
|
611
|
+
( args.first.is_a?(CArray) or args.first.is_a?(Array) )
|
612
|
+
ary = args.first
|
613
|
+
@zdef = [ary.length, "levels", ary.to_a.join("\n")].join(" ")
|
614
|
+
else
|
615
|
+
@zdef = args.join(" ")
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
def tdef (*args)
|
620
|
+
if args.size == 1 and
|
621
|
+
( args.first.is_a?(CArray) or args.first.is_a?(Array) )
|
622
|
+
ary = args.first
|
623
|
+
@tdef = [ary.length, "levels", ary.to_a.join("\n")].join(" ")
|
624
|
+
else
|
625
|
+
@tdef = args.join(" ")
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
def vectorpairs (args)
|
630
|
+
@vectorpairs = args.join(" ")
|
631
|
+
end
|
632
|
+
|
633
|
+
def var2d (name, obj, desc = "x")
|
634
|
+
@vars.push([name, 2, obj, desc])
|
635
|
+
if obj.rank == 3 and obj.dim0 > @nt
|
636
|
+
@nt = obj.dim0
|
637
|
+
end
|
638
|
+
end
|
639
|
+
|
640
|
+
def var3d (name, obj, desc = "x")
|
641
|
+
@vars.push([name, 3, obj, desc])
|
642
|
+
if obj.rank == 4 and obj.dim0 > @nt
|
643
|
+
@nt = obj.dim0
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
public
|
648
|
+
|
649
|
+
def define (&block)
|
650
|
+
instance_eval(&block)
|
651
|
+
end
|
652
|
+
|
653
|
+
def write (ctl_file)
|
654
|
+
open(ctl_file, "w") { |io|
|
655
|
+
if @dset
|
656
|
+
io.puts "dset #{@dset}"
|
657
|
+
else
|
658
|
+
raise "dset is required"
|
659
|
+
end
|
660
|
+
if @title
|
661
|
+
io.puts "title #{@title}"
|
662
|
+
end
|
663
|
+
io.puts "undef #{@undef}"
|
664
|
+
@options.each do |opt|
|
665
|
+
io.puts %{options #{opt}}
|
666
|
+
end
|
667
|
+
if @pdef
|
668
|
+
io.puts %{pdef #{@pdef}}
|
669
|
+
end
|
670
|
+
io.puts %{xdef #{@xdef}}
|
671
|
+
io.puts %{ydef #{@ydef}}
|
672
|
+
io.puts %{zdef #{@zdef}}
|
673
|
+
io.puts %{tdef #{@tdef}}
|
674
|
+
if @vectorpairs
|
675
|
+
io.puts %{vectorpairs #{@vectorpairs}}
|
676
|
+
end
|
677
|
+
|
678
|
+
if @dset =~ /\A\^/
|
679
|
+
cwd = File.dirname(File.expand_path(ctl_file))
|
680
|
+
dset = File.join(cwd, @dset[1..-1])
|
681
|
+
else
|
682
|
+
dset = @dset
|
683
|
+
end
|
684
|
+
|
685
|
+
io.puts %{vars #{@vars.size}}
|
686
|
+
@vars.each do |name, d, obj, desc|
|
687
|
+
case d
|
688
|
+
when 2
|
689
|
+
io.puts %{#{name} 1 99 #{desc}}
|
690
|
+
when 3
|
691
|
+
case obj.rank
|
692
|
+
when 3
|
693
|
+
io.puts %{#{name} #{obj.dim0} 99 #{desc} }
|
694
|
+
when 4
|
695
|
+
io.puts %{#{name} #{obj.dim1} 99 #{desc} }
|
696
|
+
else
|
697
|
+
raise "invalid size"
|
698
|
+
end
|
699
|
+
end
|
700
|
+
end
|
701
|
+
io.puts "endvars"
|
702
|
+
|
703
|
+
open(dset, "w") { |dat|
|
704
|
+
@nt.times do |i|
|
705
|
+
@vars.each do |name, d, obj, desc|
|
706
|
+
case d
|
707
|
+
when 2
|
708
|
+
case obj.rank
|
709
|
+
when 2
|
710
|
+
obj.float.dump_binary(dat)
|
711
|
+
when 3
|
712
|
+
obj[i,false].float.dump_binary(dat)
|
713
|
+
end
|
714
|
+
when 3
|
715
|
+
case obj.rank
|
716
|
+
when 3
|
717
|
+
obj.float.dump_binary(dat)
|
718
|
+
when 4
|
719
|
+
obj[i,false].float.dump_binary(dat)
|
720
|
+
end
|
721
|
+
end
|
722
|
+
end
|
723
|
+
end
|
724
|
+
}
|
725
|
+
}
|
726
|
+
|
727
|
+
|
728
|
+
end
|
729
|
+
|
730
|
+
def template (ctlfile, &block)
|
731
|
+
define(&block)
|
732
|
+
write(ctlfile)
|
733
|
+
end
|
734
|
+
|
735
|
+
end
|
data/lib/grads/gridded.rb
CHANGED
@@ -128,9 +128,10 @@ end
|
|
128
128
|
|
129
129
|
class GrADS::Gridded
|
130
130
|
|
131
|
-
def initialize (ctl_file)
|
131
|
+
def initialize (ctl_file, radius: nil)
|
132
132
|
@ctl_file = ctl_file
|
133
133
|
@entries = scan_ctl_file(ctl_file)
|
134
|
+
@radius = radius
|
134
135
|
parse_entries(@entries)
|
135
136
|
end
|
136
137
|
|
@@ -330,10 +331,17 @@ class GrADS::Gridded
|
|
330
331
|
dx = args[8].to_f
|
331
332
|
dy = args[9].to_f
|
332
333
|
slat0 = slat1 > 0 ? 90 : -90
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
334
|
+
if @radius
|
335
|
+
proj = PROJ4::Proj.new %{
|
336
|
+
+ellps=sphere +a=#{@radius} +b=#{@radius} +proj=lcc \
|
337
|
+
+lat_1=#{slat1} +lat_2=#{slat2} +lon_0=#{slon}
|
338
|
+
}
|
339
|
+
else
|
340
|
+
proj = PROJ4::Proj.new %{
|
341
|
+
+ellps=sphere +proj=lcc \
|
342
|
+
+lat_1=#{slat1} +lat_2=#{slat2} +lon_0=#{slon}
|
343
|
+
}
|
344
|
+
end
|
337
345
|
rx, ry = proj.forward(rlon, rlat)
|
338
346
|
rx0 = rx - (xi-1)*dx
|
339
347
|
ry0 = ry - (yi-1)*dy
|
@@ -346,6 +354,11 @@ class GrADS::Gridded
|
|
346
354
|
my = fj*dy + ry0
|
347
355
|
proj.inverse(mx, my)
|
348
356
|
}
|
357
|
+
@xy = lambda {
|
358
|
+
x = CArray.float(xsize).seq(rx0, dx)
|
359
|
+
y = CArray.float(ysize).seq(ry0, dy)
|
360
|
+
[x, y]
|
361
|
+
}
|
349
362
|
end
|
350
363
|
|
351
364
|
def parse_pdef_eta_u (args)
|
@@ -495,6 +508,18 @@ class GrADS::Gridded
|
|
495
508
|
def forward (rlon, rlat)
|
496
509
|
return @forward[rlon, rlat]
|
497
510
|
end
|
511
|
+
|
512
|
+
def lonlat
|
513
|
+
fi = CArray.float(xsize).seq
|
514
|
+
fj = CArray.float(ysize).seq
|
515
|
+
ii = fi[ysize,:%]
|
516
|
+
jj = fj[:%,xsize]
|
517
|
+
return @inverse[ii, jj]
|
518
|
+
end
|
519
|
+
|
520
|
+
def xy
|
521
|
+
return @xy[]
|
522
|
+
end
|
498
523
|
|
499
524
|
def var (name)
|
500
525
|
unless @varnames.include?(name)
|
data/ruby-grads.gemspec
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
|
2
2
|
Gem::Specification::new do |s|
|
3
|
-
version = "1.0.
|
3
|
+
version = "1.0.2"
|
4
4
|
|
5
5
|
files = Dir.glob("**/*") - [
|
6
|
-
Dir.glob("
|
6
|
+
Dir.glob("ruby-grads*.gem"),
|
7
7
|
].flatten
|
8
8
|
|
9
9
|
s.platform = Gem::Platform::RUBY
|
@@ -18,6 +18,5 @@ Gem::Specification::new do |s|
|
|
18
18
|
s.homepage = 'https://github.com/himotoyoshi/ruby-grads'
|
19
19
|
s.files = files
|
20
20
|
# s.extensions = [ "extconf.rb" ]
|
21
|
-
s.has_rdoc = false
|
22
21
|
s.required_ruby_version = ">= 1.8.1"
|
23
22
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-grads
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hiroki Motoyoshi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-10 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: " Library for driving GrADS from Ruby\n"
|
14
14
|
email: ''
|
@@ -19,6 +19,7 @@ files:
|
|
19
19
|
- README.md
|
20
20
|
- extconf.rb
|
21
21
|
- lib/grads.rb
|
22
|
+
- lib/grads/binary.rb
|
22
23
|
- lib/grads/command.rb
|
23
24
|
- lib/grads/gridded.rb
|
24
25
|
- lib/grads/lib/colorbar.rb
|