ruby-grads 1.0.0 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +67 -1
- data/Rakefile +14 -0
- data/bin/ncdef2ctl +107 -0
- data/lib/grads/binary.rb +735 -0
- data/lib/grads/command.rb +428 -11
- data/lib/grads/gridded.rb +83 -14
- data/lib/grads/lib/axis_xtime.rb +217 -0
- data/lib/grads/lib/makecpt.rb +24 -54
- data/lib/grads.rb +1 -0
- data/ruby-grads.gemspec +3 -3
- data/ruby-grads.gemspec~ +23 -0
- metadata +10 -5
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
|