cdo 1.2.7 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/gemspec +2 -2
- data/lib/cdo.rb +204 -279
- data/lib/cdo_lib.rb +415 -0
- data/test/test_cdo.rb +180 -181
- metadata +3 -3
- data/lib/cdo_oo.rb +0 -301
data/lib/cdo_lib.rb
ADDED
@@ -0,0 +1,415 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'open3'
|
3
|
+
require 'logger'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
# Copyright (C) 2011-2013 Ralf Mueller, ralf.mueller@zmaw.de
|
7
|
+
# See COPYING file for copying and redistribution conditions.
|
8
|
+
#
|
9
|
+
# This program is free software; you can redistribute it and/or modify
|
10
|
+
# it under the terms of the GNU General Public License as published by
|
11
|
+
# the Free Software Foundation; version 2 of the License.
|
12
|
+
#
|
13
|
+
# This program is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
|
18
|
+
# ==============================================================================
|
19
|
+
# CDO calling mechnism
|
20
|
+
module Cdo
|
21
|
+
|
22
|
+
VERSION = "1.2.5"
|
23
|
+
@@file = StringIO.new
|
24
|
+
|
25
|
+
State = {
|
26
|
+
:debug => false,
|
27
|
+
:returnCdf => false,
|
28
|
+
:operators => [],
|
29
|
+
:forceOutput => true,
|
30
|
+
:env => {},
|
31
|
+
:log => false,
|
32
|
+
:logger => Logger.new(@@file),
|
33
|
+
}
|
34
|
+
State[:debug] = ENV.has_key?('DEBUG')
|
35
|
+
State[:logger].formatter = proc do |serverity, time, progname, msg|
|
36
|
+
msg
|
37
|
+
end
|
38
|
+
|
39
|
+
@@CDO = ENV['CDO'].nil? ? 'cdo' : ENV['CDO']
|
40
|
+
|
41
|
+
# Since cdo-1.5.4 undocumented operators are given with the -h option. For
|
42
|
+
# earlier version, they have to be provided manually
|
43
|
+
@@undocumentedOperators = %w[anomaly beta boxavg change_e5lsm change_e5mask
|
44
|
+
change_e5slm chisquare chvar cloudlayer cmd com command complextorect
|
45
|
+
covar0 covar0r daycount daylogs del29feb delday delete deltap deltap_fl
|
46
|
+
delvar diffv divcoslat dumplogo dumplogs duplicate eca_r1mm enlargegrid
|
47
|
+
ensrkhistspace ensrkhisttime eof3d eof3dspatial eof3dtime export_e5ml
|
48
|
+
export_e5res fc2gp fc2sp fillmiss fisher fldcovar fldrms fourier fpressure
|
49
|
+
gather gengrid geopotheight ggstat ggstats globavg gp2fc gradsdes
|
50
|
+
gridverify harmonic hourcount hpressure import_e5ml import_e5res
|
51
|
+
import_obs imtocomplex infos infov interpolate intgrid intgridbil
|
52
|
+
intgridtraj intpoint isosurface lmavg lmean lmmean lmstd log lsmean
|
53
|
+
meandiff2test mergegrid mod moncount monlogs mrotuv mrotuvb mulcoslat ncode
|
54
|
+
ncopy nmltest normal nvar outputbounds outputboundscpt outputcenter
|
55
|
+
outputcenter2 outputcentercpt outputkey outputtri outputvector outputvrml
|
56
|
+
pardup parmul pinfo pinfov pressure_fl pressure_hl read_e5ml remapcon1
|
57
|
+
remapdis1 retocomplex scalllogo scatter seascount select selgridname
|
58
|
+
seloperator selvar selzaxisname setrcaname setvar showvar sinfov smemlogo
|
59
|
+
snamelogo sort sortcode sortlevel sortname sorttaxis sorttimestamp sortvar
|
60
|
+
sp2fc specinfo spectrum sperclogo splitvar stimelogo studentt template1
|
61
|
+
template2 test test2 testdata thinout timcount timcovar tinfo transxy trms
|
62
|
+
tstepcount vardes vardup varmul varquot2test varrms vertwind write_e5ml
|
63
|
+
writegrid writerandom yearcount]
|
64
|
+
|
65
|
+
@@outputOperatorsPattern = /(diff|info|output|griddes|zaxisdes|show|ncode|ndate|nlevel|nmon|nvar|nyear|ntime|npar|gradsdes|pardes)/
|
66
|
+
|
67
|
+
private
|
68
|
+
def Cdo.getOperators(force=false)
|
69
|
+
# Do NOT compute anything, if it is not required
|
70
|
+
return State[:operators] unless (State[:operators].empty? or force)
|
71
|
+
cmd = @@CDO + ' 2>&1'
|
72
|
+
help = IO.popen(cmd).readlines.map {|l| l.chomp.lstrip}
|
73
|
+
if 5 >= help.size
|
74
|
+
warn "Operators could not get listed by running the CDO binary (#{@@CDO})"
|
75
|
+
pp help if Cdo.debug
|
76
|
+
exit
|
77
|
+
end
|
78
|
+
# in version 1.5.6 the output of '-h' has changed
|
79
|
+
State[:operators] = case
|
80
|
+
when Cdo.version < "1.5.6"
|
81
|
+
(help[help.index("Operators:")+1].split + @@undocumentedOperators).uniq
|
82
|
+
when Cdo.version <= "1.7.0"
|
83
|
+
help[(help.index("Operators:")+1)..help.index(help.find {|v| v =~ /CDO version/}) - 2].join(' ').split
|
84
|
+
else
|
85
|
+
IO.popen(@@CDO + ' --operators').readlines.map {|l| l.split(' ').first}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def Cdo.hasError(cmd,retvals)
|
90
|
+
if (State[:debug])
|
91
|
+
puts("RETURNCODE: #{retvals[:returncode]}")
|
92
|
+
end
|
93
|
+
if ( 0 != retvals[:returncode] )
|
94
|
+
puts("Error in calling:")
|
95
|
+
puts(">>> "+cmd+"<<<")
|
96
|
+
puts(retvals[:stderr])
|
97
|
+
return true
|
98
|
+
else
|
99
|
+
return false
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def Cdo.env=(envHash)
|
104
|
+
State[:env] = envHash
|
105
|
+
end
|
106
|
+
def Cdo.env; State[:env]; end
|
107
|
+
|
108
|
+
def Cdo.call(cmd)
|
109
|
+
if (State[:debug])
|
110
|
+
puts '# DEBUG ====================================================================='
|
111
|
+
pp Cdo.env unless Cdo.env.empty?
|
112
|
+
puts 'CMD: '
|
113
|
+
puts cmd
|
114
|
+
puts '# DEBUG ====================================================================='
|
115
|
+
end
|
116
|
+
stdin, stdout, stderr, wait_thr = Open3.popen3(Cdo.env,cmd)
|
117
|
+
|
118
|
+
{
|
119
|
+
:stdout => stdout.read,
|
120
|
+
:stderr => stderr.read,
|
121
|
+
:returncode => wait_thr.value.exitstatus
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
def Cdo.run(cmd,ofile='',options='',returnCdf=false,force=nil,returnArray=nil,returnMaArray=nil)
|
126
|
+
cmd = "#{@@CDO} -O #{options} #{cmd} "
|
127
|
+
case ofile
|
128
|
+
when $stdout
|
129
|
+
retvals = Cdo.call(cmd)
|
130
|
+
State[:logger].info(cmd+"\n") if State[:log]
|
131
|
+
unless hasError(cmd,retvals)
|
132
|
+
return retvals[:stdout].split($/).map {|l| l.chomp.strip}
|
133
|
+
else
|
134
|
+
raise ArgumentError,"CDO did NOT run successfully!"
|
135
|
+
end
|
136
|
+
else
|
137
|
+
force = State[:forceOutput] if force.nil?
|
138
|
+
if force or not File.exists?(ofile.to_s)
|
139
|
+
ofile = MyTempfile.path if ofile.nil?
|
140
|
+
cmd << "#{ofile}"
|
141
|
+
retvals = call(cmd)
|
142
|
+
State[:logger].info(cmd+"\n") if State[:log]
|
143
|
+
if hasError(cmd,retvals)
|
144
|
+
raise ArgumentError,"CDO did NOT run successfully!"
|
145
|
+
end
|
146
|
+
else
|
147
|
+
warn "Use existing file '#{ofile}'" if Cdo.debug
|
148
|
+
end
|
149
|
+
end
|
150
|
+
if not returnArray.nil?
|
151
|
+
Cdo.readArray(ofile,returnArray)
|
152
|
+
elsif not returnMaArray.nil?
|
153
|
+
Cdo.readMaArray(ofile,returnMaArray)
|
154
|
+
elsif returnCdf or State[:returnCdf]
|
155
|
+
Cdo.readCdf(ofile)
|
156
|
+
else
|
157
|
+
return ofile
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def Cdo.parseArgs(args)
|
162
|
+
# splitinto hash-like args and the rest
|
163
|
+
operatorArgs = args.reject {|a| a.class == Hash}
|
164
|
+
opts = operatorArgs.empty? ? '' : ',' + operatorArgs.join(',')
|
165
|
+
io = args.find {|a| a.class == Hash}
|
166
|
+
io = {} if io.nil?
|
167
|
+
args.delete_if {|a| a.class == Hash}
|
168
|
+
# join input streams together if possible
|
169
|
+
io[:input] = io[:input].join(' ') if io[:input].respond_to?(:join)
|
170
|
+
return [io,opts]
|
171
|
+
end
|
172
|
+
|
173
|
+
def Cdo.method_missing(sym, *args, &block)
|
174
|
+
## args is expected to look like [opt1,...,optN,:input => iStream,:output => oStream] where
|
175
|
+
# iStream could be another CDO call (timmax(selname(Temp,U,V,ifile.nc))
|
176
|
+
puts "Operator #{sym.to_s} is called" if State[:debug]
|
177
|
+
if getOperators.include?(sym.to_s)
|
178
|
+
io, opts = Cdo.parseArgs(args)
|
179
|
+
if @@outputOperatorsPattern.match(sym)
|
180
|
+
run(" -#{sym.to_s}#{opts} #{io[:input]} ",$stdout)
|
181
|
+
else
|
182
|
+
run(" -#{sym.to_s}#{opts} #{io[:input]} ",io[:output],io[:options],io[:returnCdf],io[:force],io[:returnArray],io[:returnMaArray])
|
183
|
+
end
|
184
|
+
else
|
185
|
+
raise ArgumentError,"Operator #{sym.to_s} not found"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def Cdo.loadCdf
|
190
|
+
begin
|
191
|
+
require "numru/netcdf_miss"
|
192
|
+
include NumRu
|
193
|
+
rescue LoadError
|
194
|
+
warn "Could not load ruby's netcdf bindings. Please install it."
|
195
|
+
raise
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def Cdo.getSupportedLibs(force=false)
|
200
|
+
return unless (State[:libs].nil? or force)
|
201
|
+
_, _, stderr, _ = Open3.popen3(@@CDO + " -V")
|
202
|
+
supported = stderr.readlines.map(&:chomp)
|
203
|
+
with = supported.grep(/(with|Features)/)[0].split(':')[1].split.map(&:downcase)
|
204
|
+
libs = supported.grep(/library version/).map {|l|
|
205
|
+
l.strip.split(':').map {|l|
|
206
|
+
l.split.first.downcase
|
207
|
+
}[0,2]
|
208
|
+
}
|
209
|
+
State[:libs] = {}
|
210
|
+
with.flatten.each {|k| State[:libs][k]=true}
|
211
|
+
libs.each {|lib,version| State[:libs][lib] = version}
|
212
|
+
end
|
213
|
+
|
214
|
+
public
|
215
|
+
def Cdo.debug=(value)
|
216
|
+
State[:debug] = value
|
217
|
+
end
|
218
|
+
def Cdo.debug
|
219
|
+
State[:debug]
|
220
|
+
end
|
221
|
+
def Cdo.forceOutput=(value)
|
222
|
+
State[:forceOutput] = value
|
223
|
+
end
|
224
|
+
def Cdo.forceOutput
|
225
|
+
State[:forceOutput]
|
226
|
+
end
|
227
|
+
def Cdo.log=(value)
|
228
|
+
State[:log] = value
|
229
|
+
end
|
230
|
+
|
231
|
+
def Cdo.log
|
232
|
+
State[:log]
|
233
|
+
end
|
234
|
+
|
235
|
+
def Cdo.version
|
236
|
+
cmd = @@CDO + ' 2>&1'
|
237
|
+
help = IO.popen(cmd).readlines.map {|l| l.chomp.lstrip}
|
238
|
+
regexp = %r{CDO version (\d.*), Copyright}
|
239
|
+
line = help.find {|v| v =~ regexp}
|
240
|
+
version = regexp.match(line)[1]
|
241
|
+
end
|
242
|
+
|
243
|
+
def Cdo.setReturnCdf(value=true)
|
244
|
+
if value
|
245
|
+
Cdo.loadCdf
|
246
|
+
end
|
247
|
+
State[:returnCdf] = value
|
248
|
+
end
|
249
|
+
|
250
|
+
def Cdo.unsetReturnCdf
|
251
|
+
setReturnCdf(false)
|
252
|
+
end
|
253
|
+
|
254
|
+
def Cdo.returnCdf
|
255
|
+
State[:returnCdf]
|
256
|
+
end
|
257
|
+
|
258
|
+
def Cdo.hasCdo?(bin=@@CDO)
|
259
|
+
return true if File.exists?(@@CDO) and File.executable?(@@CDO)
|
260
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each {|path|
|
261
|
+
return true if File.exists?([path,bin].join(File::SEPARATOR))
|
262
|
+
}
|
263
|
+
end
|
264
|
+
|
265
|
+
# test if @@CDO can be used
|
266
|
+
def Cdo.checkCdo
|
267
|
+
unless hasCdo?(@@CDO)
|
268
|
+
warn "Testing application #@@CDO is not available!"
|
269
|
+
exit 1
|
270
|
+
else
|
271
|
+
puts "Using CDO: #@@CDO"
|
272
|
+
puts IO.popen(@@CDO + " -V").readlines
|
273
|
+
end
|
274
|
+
return true
|
275
|
+
end
|
276
|
+
|
277
|
+
def Cdo.setCdo(cdo)
|
278
|
+
puts "Will use #{cdo} instead of #@@CDO" if Cdo.debug
|
279
|
+
@@CDO = cdo
|
280
|
+
Cdo.getOperators(true)
|
281
|
+
Cdo.getSupportedLibs(true)
|
282
|
+
end
|
283
|
+
|
284
|
+
def Cdo.getCdo
|
285
|
+
@@CDO
|
286
|
+
end
|
287
|
+
|
288
|
+
def Cdo.operators
|
289
|
+
Cdo.getOperators if State[:operators].empty?
|
290
|
+
State[:operators]
|
291
|
+
end
|
292
|
+
|
293
|
+
def Cdo.libs
|
294
|
+
getSupportedLibs
|
295
|
+
State[:libs]
|
296
|
+
end
|
297
|
+
|
298
|
+
def Cdo.hasLib?(lib)
|
299
|
+
return Cdo.libs.has_key?(lib)
|
300
|
+
return false
|
301
|
+
end
|
302
|
+
|
303
|
+
def Cdo.libsVersion(lib)
|
304
|
+
unless Cdo.hasLib?(lib)
|
305
|
+
raise ArgumentError, "Cdo does NOT have support for '#{lib}'"
|
306
|
+
else
|
307
|
+
if State[:libs][lib].kind_of? String
|
308
|
+
return State[:libs][lib]
|
309
|
+
else
|
310
|
+
warn "No version information available about '#{lib}'"
|
311
|
+
return false
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def Cdo.showlog
|
317
|
+
@@file.rewind
|
318
|
+
puts @@file.read
|
319
|
+
end
|
320
|
+
|
321
|
+
#==================================================================
|
322
|
+
# Addional operotors:
|
323
|
+
#------------------------------------------------------------------
|
324
|
+
def Cdo.boundaryLevels(args)
|
325
|
+
ilevels = Cdo.showlevel(:input => args[:input])[0].split.map(&:to_f)
|
326
|
+
bound_levels = Array.new(ilevels.size+1)
|
327
|
+
bound_levels[0] = 0
|
328
|
+
(1..ilevels.size).each {|i|
|
329
|
+
bound_levels[i] =bound_levels[i-1] + 2*(ilevels[i-1]-bound_levels[i-1])
|
330
|
+
}
|
331
|
+
bound_levels
|
332
|
+
end
|
333
|
+
|
334
|
+
def Cdo.thicknessOfLevels(args)
|
335
|
+
bound_levels = Cdo.boundaryLevels(args)
|
336
|
+
delta_levels = []
|
337
|
+
bound_levels.each_with_index {|v,i|
|
338
|
+
next if 0 == i
|
339
|
+
delta_levels << v - bound_levels[i-1]
|
340
|
+
}
|
341
|
+
delta_levels
|
342
|
+
end
|
343
|
+
|
344
|
+
def Cdo.readCdf(iFile)
|
345
|
+
Cdo.loadCdf unless State[:returnCdf]
|
346
|
+
NetCDF.open(iFile)
|
347
|
+
end
|
348
|
+
|
349
|
+
def Cdo.openCdf(iFile)
|
350
|
+
Cdo.loadCdf unless State[:returnCdf]
|
351
|
+
NetCDF.open(iFile,'r+')
|
352
|
+
end
|
353
|
+
|
354
|
+
def Cdo.readArray(iFile,varname)
|
355
|
+
filehandle = Cdo.readCdf(iFile)
|
356
|
+
if filehandle.var_names.include?(varname)
|
357
|
+
# return the data array
|
358
|
+
filehandle.var(varname).get
|
359
|
+
else
|
360
|
+
raise ArgumentError, "Cannot find variable '#{varname}'"
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
def Cdo.readMaArray(iFile,varname)
|
365
|
+
filehandle = Cdo.readCdf(iFile)
|
366
|
+
if filehandle.var_names.include?(varname)
|
367
|
+
# return the data array
|
368
|
+
filehandle.var(varname).get_with_miss
|
369
|
+
else
|
370
|
+
raise ArgumentError,"Cannot find variable '#{varname}'"
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
def Cdo.help(operator=nil)
|
375
|
+
if operator.nil?
|
376
|
+
puts Cdo.call([@@CDO,'-h'].join(' '))[:stderr]
|
377
|
+
else
|
378
|
+
operator = operator.to_s unless String == operator.class
|
379
|
+
if Cdo.operators.include?(operator)
|
380
|
+
puts Cdo.call([@@CDO,'-h',operator].join(' '))[:stdout]
|
381
|
+
else
|
382
|
+
puts "Unknown operator #{operator}"
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
# Helper module for easy temp file handling
|
389
|
+
module MyTempfile
|
390
|
+
require 'tempfile'
|
391
|
+
@@_tempfiles = []
|
392
|
+
@@persistent_tempfiles = false
|
393
|
+
@@N = 10000000
|
394
|
+
|
395
|
+
def MyTempfile.setPersist(value)
|
396
|
+
@@persistent_tempfiles = value
|
397
|
+
end
|
398
|
+
|
399
|
+
def MyTempfile.path
|
400
|
+
unless @@persistent_tempfiles
|
401
|
+
t = Tempfile.new(self.class.to_s)
|
402
|
+
@@_tempfiles << t
|
403
|
+
@@_tempfiles << t.path
|
404
|
+
t.path
|
405
|
+
else
|
406
|
+
t = "_"+rand(@@N).to_s
|
407
|
+
@@_tempfiles << t
|
408
|
+
t
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
def MyTempfile.showFiles
|
413
|
+
@@_tempfiles.each {|f| print(f+" ") if f.kind_of? String}
|
414
|
+
end
|
415
|
+
end
|
data/test/test_cdo.rb
CHANGED
@@ -9,91 +9,88 @@ require 'pp'
|
|
9
9
|
#===============================================================================
|
10
10
|
def rm(files); files.each {|f| FileUtils.rm(f) if File.exists?(f)};end
|
11
11
|
|
12
|
+
@show = ENV.has_key?('SHOW')
|
13
|
+
|
12
14
|
class TestCdo < Minitest::Test
|
13
15
|
|
14
16
|
DEFAULT_CDO_PATH = 'cdo'
|
15
17
|
|
18
|
+
def setup
|
19
|
+
@cdo = Cdo.new
|
20
|
+
end
|
21
|
+
|
16
22
|
def test_cdo
|
17
|
-
assert_equal(true
|
23
|
+
assert_equal(true,@cdo.check)
|
18
24
|
if ENV['CDO']
|
19
|
-
assert_equal(ENV['CDO']
|
25
|
+
assert_equal(ENV['CDO'],@cdo.cdo)
|
20
26
|
else
|
21
|
-
assert_equal(DEFAULT_CDO_PATH
|
27
|
+
assert_equal(DEFAULT_CDO_PATH,@cdo.cdo)
|
22
28
|
end
|
23
|
-
newCDO="#{ENV['HOME']}/local/bin/cdo"
|
29
|
+
newCDO="#{ENV['HOME']}/local/bin/cdo-dev"
|
24
30
|
if File.exist?(newCDO) then
|
25
|
-
Cdo.
|
26
|
-
assert_equal(true,
|
27
|
-
assert_equal(newCDO,
|
31
|
+
cdo = Cdo.new(:cdo => newCDO)
|
32
|
+
assert_equal(true,cdo.check)
|
33
|
+
assert_equal(newCDO,cdo.cdo)
|
28
34
|
end
|
29
35
|
end
|
30
36
|
def test_getOperators
|
31
37
|
%w[for random stdatm info showlevel sinfo remap geopotheight mask topo thicknessOfLevels].each {|op|
|
32
38
|
if ["thicknessOfLevels"].include?(op)
|
33
|
-
assert(
|
39
|
+
assert(@cdo.respond_to?(op),"Operator '#{op}' not found")
|
34
40
|
else
|
35
|
-
assert(
|
41
|
+
assert(@cdo.operators.include?(op),"Operator '#{op}' not found")
|
36
42
|
end
|
37
43
|
}
|
38
|
-
assert(
|
44
|
+
assert(@cdo.operators.include?('diff'),"Operator alias 'diff' is not callable")
|
39
45
|
end
|
40
46
|
def test_listAllOperators
|
41
|
-
|
47
|
+
assert(@cdo.operators.size > 700,"cound not find enough operators")
|
42
48
|
end
|
43
49
|
|
44
50
|
def test_outputOperators
|
45
|
-
|
46
|
-
levels =
|
51
|
+
@cdo.debug = true
|
52
|
+
levels = @cdo.showlevel(:input => "-stdatm,0")
|
47
53
|
assert_equal([0,0].map(&:to_s),levels)
|
48
54
|
|
49
|
-
info =
|
50
|
-
assert_equal("
|
55
|
+
info = @cdo.sinfo(:input => "-stdatm,0")
|
56
|
+
assert_equal("GRIB",info[0].split(':').last.strip)
|
51
57
|
|
52
|
-
values =
|
53
|
-
assert_equal(["1013.25", "288"],values)
|
54
|
-
values =
|
55
|
-
assert_equal(["1013.25", "271.913", "288", "240.591"],values)
|
56
|
-
values =
|
57
|
-
assert_equal(["0", "10000","0", "10000"],values)
|
58
|
+
values = @cdo.outputkey("value",:input => "-stdatm,0")
|
59
|
+
assert_equal(["1013.25", "288"],values[-2..-1])
|
60
|
+
values = @cdo.outputkey("value",:input => "-stdatm,0,10000")
|
61
|
+
assert_equal(["1013.25", "271.913", "288", "240.591"],values[-4..-1])
|
62
|
+
values = @cdo.outputkey("level",:input => "-stdatm,0,10000")
|
63
|
+
assert_equal(["0", "10000","0", "10000"],values[-4..-1])
|
58
64
|
end
|
59
65
|
def test_CDO_version
|
60
|
-
assert("1.4.3.1" <
|
66
|
+
assert("1.4.3.1" < @cdo.version,"Version too low: #{@cdo.version}")
|
67
|
+
assert("1.8.0" > @cdo.version,"Version too high: #{@cdo.version}")
|
61
68
|
end
|
62
69
|
def test_args
|
63
|
-
ofile0 =
|
64
|
-
ofile1 =
|
65
|
-
ofile2 =
|
66
|
-
ofile3 =
|
67
|
-
info =
|
70
|
+
ofile0 = @cdo.stdatm(0,20,40,80,200,230,400,600,1100)
|
71
|
+
ofile1 = @cdo.intlevel(0,10,50,100,500,1000, :input => ofile0)
|
72
|
+
ofile2 = @cdo.intlevel([0,10,50,100,500,1000],:input => ofile0)
|
73
|
+
ofile3 = @cdo.sub(:input => [ofile1,ofile2].join(' '))
|
74
|
+
info = @cdo.infon(:input => ofile3)
|
68
75
|
(1...info.size).each {|i| assert_equal(0.0,info[i].split[-1].to_f)}
|
69
76
|
end
|
70
77
|
def test_operator_options
|
71
|
-
|
78
|
+
@cdo.debug=true
|
72
79
|
targetLevels = [0,10,50,100,200,400,1000]
|
73
|
-
levels =
|
80
|
+
levels = @cdo.showlevel(:input => " -stdatm,#{targetLevels.join(',')}")
|
74
81
|
[0,1].each {|i| assert_equal(targetLevels.join(' '),levels[i])}
|
75
|
-
|
76
|
-
def test_CDO_options
|
77
|
-
names = Cdo.showname(:input => "-stdatm,0",:options => "-f nc")
|
82
|
+
names = @cdo.showname(:input => "-stdatm,0",:options => "-f nc")
|
78
83
|
assert_equal(["P T"],names)
|
79
|
-
|
80
|
-
if Cdo.hasLib?("sz")
|
81
|
-
ofile = Cdo.topo(:output => ofile,:options => "-z szip")
|
82
|
-
assert_equal(["GRIB SZIP"],Cdo.showformat(:input => ofile))
|
83
|
-
else
|
84
|
-
ofile = Cdo.topo
|
85
|
-
assert_equal(["GRIB"],Cdo.showformat(:input => ofile))
|
86
|
-
end
|
87
84
|
end
|
88
85
|
def test_chain
|
89
|
-
|
90
|
-
ofile =
|
91
|
-
assert_equal(["veloc"]
|
86
|
+
@cdo.debug = true
|
87
|
+
ofile = @cdo.setname('veloc',:input => " -copy -random,r1x1",:options => "-f nc")
|
88
|
+
assert_equal(["veloc"],@cdo.showname(:input => ofile))
|
92
89
|
end
|
93
90
|
|
94
91
|
def test_diff
|
95
|
-
diffv_ =
|
96
|
-
diff_ =
|
92
|
+
diffv_ = @cdo.diffn(:input => "-random,r1x1 -random,r1x1")
|
93
|
+
diff_ = @cdo.diffv(:input => "-random,r1x1 -random,r1x1")
|
97
94
|
return
|
98
95
|
|
99
96
|
assert_equal(diffv[1].split(' ')[-1],"random")
|
@@ -102,34 +99,29 @@ class TestCdo < Minitest::Test
|
|
102
99
|
assert_equal(diff[1].split(' ')[-3],"0.53060")
|
103
100
|
end
|
104
101
|
|
105
|
-
def test_operators
|
106
|
-
assert_includes(Cdo.operators,"infov")
|
107
|
-
assert_includes(Cdo.operators,"showlevel")
|
108
|
-
end
|
109
|
-
|
110
102
|
def test_bndLevels
|
111
|
-
ofile =
|
103
|
+
ofile = @cdo.stdatm(25,100,250,500,875,1400,2100,3000,4000,5000,:options => "-f nc")
|
112
104
|
assert_equal([0, 50.0, 150.0, 350.0, 650.0, 1100.0, 1700.0, 2500.0, 3500.0, 4500.0, 5500.0],
|
113
|
-
|
105
|
+
@cdo.boundaryLevels(:input => "-selname,T #{ofile}"))
|
114
106
|
assert_equal([50.0, 100.0, 200.0, 300.0, 450.0, 600.0, 800.0, 1000.0, 1000.0, 1000.0],
|
115
|
-
|
107
|
+
@cdo.thicknessOfLevels(:input => ofile))
|
116
108
|
end
|
117
109
|
|
118
110
|
def test_combine
|
119
111
|
ofile0, ofile1 = MyTempfile.path, MyTempfile.path
|
120
|
-
|
121
|
-
|
122
|
-
|
112
|
+
@cdo.fldsum(:input => @cdo.stdatm(25,100,250,500,875,1400,2100,3000,4000,5000,:options => "-f nc"),:output => ofile0)
|
113
|
+
@cdo.fldsum(:input => "-stdatm,25,100,250,500,875,1400,2100,3000,4000,5000",:options => "-f nc",:output => ofile1)
|
114
|
+
@cdo.returnCdf = true
|
123
115
|
MyTempfile.showFiles
|
124
|
-
diff =
|
116
|
+
diff = @cdo.sub(:input => [ofile0,ofile1].join(' ')).var('T').get
|
125
117
|
assert_equal(0.0,diff.min)
|
126
118
|
assert_equal(0.0,diff.max)
|
127
|
-
|
119
|
+
@cdo.returnCdf = false
|
128
120
|
end
|
129
121
|
|
130
122
|
def test_tempfile
|
131
123
|
ofile0, ofile1 = MyTempfile.path, MyTempfile.path
|
132
|
-
|
124
|
+
assert(ofile0 != ofile1, "Found equal tempfiles!")
|
133
125
|
# Tempfile should not disappeare even if the GC was started
|
134
126
|
puts ofile0
|
135
127
|
assert(File.exist?(ofile0))
|
@@ -139,49 +131,49 @@ class TestCdo < Minitest::Test
|
|
139
131
|
|
140
132
|
def test_returnCdf
|
141
133
|
ofile = rand(0xfffff).to_s + '_test_returnCdf.nc'
|
142
|
-
vals =
|
134
|
+
vals = @cdo.stdatm(25,100,250,500,875,1400,2100,3000,4000,5000,:output => ofile,:options => "-f nc")
|
143
135
|
assert_equal(ofile,vals)
|
144
|
-
|
145
|
-
vals =
|
136
|
+
@cdo.returnCdf = true
|
137
|
+
vals = @cdo.stdatm(25,100,250,500,875,1400,2100,3000,4000,5000,:output => ofile,:options => "-f nc")
|
146
138
|
assert_equal(["lon","lat","level","P","T"],vals.var_names)
|
147
139
|
assert_equal(276,vals.var("T").get.flatten.mean.floor)
|
148
|
-
|
149
|
-
vals =
|
140
|
+
@cdo.returnCdf = false
|
141
|
+
vals = @cdo.stdatm(25,100,250,500,875,1400,2100,3000,4000,5000,:output => ofile,:options => "-f nc")
|
150
142
|
assert_equal(ofile,vals)
|
151
143
|
FileUtils.rm(ofile)
|
152
144
|
end
|
153
145
|
def test_simple_returnCdf
|
154
146
|
ofile0, ofile1 = MyTempfile.path, MyTempfile.path
|
155
|
-
sum =
|
147
|
+
sum = @cdo.fldsum(:input => @cdo.stdatm(0,:options => "-f nc"),
|
156
148
|
:returnCdf => true).var("P").get
|
157
149
|
assert_equal(1013.25,sum.min)
|
158
|
-
sum =
|
150
|
+
sum = @cdo.fldsum(:input => @cdo.stdatm(0,:options => "-f nc"),:output => ofile0)
|
159
151
|
assert_equal(ofile0,sum)
|
160
152
|
test_returnCdf
|
161
153
|
end
|
162
154
|
def test_force
|
163
155
|
outs = []
|
164
156
|
# tempfiles
|
165
|
-
outs <<
|
166
|
-
outs <<
|
167
|
-
|
157
|
+
outs << @cdo.stdatm(0,10,20)
|
158
|
+
outs << @cdo.stdatm(0,10,20)
|
159
|
+
assert(outs[0] != outs[1])
|
168
160
|
|
169
161
|
# deticated output, force = true
|
170
162
|
outs.clear
|
171
|
-
outs <<
|
163
|
+
outs << @cdo.stdatm(0,10,20,:output => 'test_force')
|
172
164
|
mtime0 = File.stat(outs[-1]).mtime
|
173
|
-
outs <<
|
165
|
+
outs << @cdo.stdatm(0,10,20,:output => 'test_force')
|
174
166
|
mtime1 = File.stat(outs[-1]).mtime
|
175
|
-
|
167
|
+
assert(mtime0 != mtime1)
|
176
168
|
assert_equal(outs[0],outs[1])
|
177
169
|
FileUtils.rm('test_force')
|
178
170
|
outs.clear
|
179
171
|
|
180
172
|
# dedicated output, force = false
|
181
173
|
ofile = 'test_force_false'
|
182
|
-
outs <<
|
174
|
+
outs << @cdo.stdatm(0,10,20,:output => ofile,:force => false)
|
183
175
|
mtime0 = File.stat(outs[-1]).mtime
|
184
|
-
outs <<
|
176
|
+
outs << @cdo.stdatm(0,10,20,:output => ofile,:force => false)
|
185
177
|
mtime1 = File.stat(outs[-1]).mtime
|
186
178
|
assert_equal(mtime0,mtime1)
|
187
179
|
assert_equal(outs[0],outs[1])
|
@@ -190,10 +182,10 @@ class TestCdo < Minitest::Test
|
|
190
182
|
|
191
183
|
# dedicated output, global force setting
|
192
184
|
ofile = 'test_force_global'
|
193
|
-
|
194
|
-
outs <<
|
185
|
+
@cdo.forceOutput = false
|
186
|
+
outs << @cdo.stdatm(0,10,20,:output => ofile)
|
195
187
|
mtime0 = File.stat(outs[-1]).mtime
|
196
|
-
outs <<
|
188
|
+
outs << @cdo.stdatm(0,10,20,:output => ofile)
|
197
189
|
mtime1 = File.stat(outs[-1]).mtime
|
198
190
|
assert_equal(mtime0,mtime1)
|
199
191
|
assert_equal(outs[0],outs[1])
|
@@ -204,20 +196,20 @@ class TestCdo < Minitest::Test
|
|
204
196
|
def test_thickness
|
205
197
|
levels = "25 100 250 500 875 1400 2100 3000 4000 5000".split
|
206
198
|
targetThicknesses = [50.0, 100.0, 200.0, 300.0, 450.0, 600.0, 800.0, 1000.0, 1000.0, 1000.0]
|
207
|
-
assert_equal(targetThicknesses,
|
199
|
+
assert_equal(targetThicknesses, @cdo.thicknessOfLevels(:input => "-selname,T -stdatm,#{levels.join(',')}"))
|
208
200
|
end
|
209
201
|
|
210
202
|
def test_showlevels
|
211
203
|
sourceLevels = %W{25 100 250 500 875 1400 2100 3000 4000 5000}
|
212
204
|
assert_equal(sourceLevels,
|
213
|
-
|
205
|
+
@cdo.showlevel(:input => "-selname,T #{@cdo.stdatm(*sourceLevels,:options => '-f nc')}")[0].split)
|
214
206
|
end
|
215
207
|
|
216
208
|
def test_verticalLevels
|
217
|
-
|
209
|
+
@cdo.debug = true
|
218
210
|
targetThicknesses = [50.0, 100.0, 200.0, 300.0, 450.0, 600.0, 800.0, 1000.0, 1000.0, 1000.0]
|
219
211
|
sourceLevels = %W{25 100 250 500 875 1400 2100 3000 4000 5000}
|
220
|
-
thicknesses =
|
212
|
+
thicknesses = @cdo.thicknessOfLevels(:input => "-selname,T #{@cdo.stdatm(*sourceLevels,:options => '-f nc')}")
|
221
213
|
assert_equal(targetThicknesses,thicknesses)
|
222
214
|
end
|
223
215
|
|
@@ -231,31 +223,31 @@ class TestCdo < Minitest::Test
|
|
231
223
|
end
|
232
224
|
|
233
225
|
def test_returnArray
|
234
|
-
temperature =
|
235
|
-
|
236
|
-
|
226
|
+
temperature = @cdo.stdatm(0,:options => '-f nc',:returnCdf => true).var('T').get.flatten[0]
|
227
|
+
assert_raises ArgumentError do
|
228
|
+
@cdo.stdatm(0,:options => '-f nc',:returnArray => 'TT')
|
237
229
|
end
|
238
|
-
temperature =
|
230
|
+
temperature = @cdo.stdatm(0,:options => '-f nc',:returnArray => 'T')
|
239
231
|
assert_equal(288.0,temperature.flatten[0])
|
240
|
-
pressure =
|
232
|
+
pressure = @cdo.stdatm(0,1000,:options => '-f nc -b F64',:returnArray => 'P')
|
241
233
|
assert_equal("1013.25 898.543456035875",pressure.flatten.to_a.join(' '))
|
242
234
|
end
|
243
235
|
def test_returnMaArray
|
244
|
-
|
245
|
-
topo =
|
236
|
+
@cdo.debug = true
|
237
|
+
topo = @cdo.topo(:options => '-f nc',:returnMaArray => 'topo')
|
246
238
|
assert_equal(-1890.0,topo.mean.round)
|
247
|
-
bathy =
|
248
|
-
:input =>
|
239
|
+
bathy = @cdo.setrtomiss(0,10000,
|
240
|
+
:input => @cdo.topo(:options => '-f nc'),:returnMaArray => 'topo')
|
249
241
|
assert_equal(-3386.0,bathy.mean.round)
|
250
|
-
oro =
|
251
|
-
:input =>
|
242
|
+
oro = @cdo.setrtomiss(-10000,0,
|
243
|
+
:input => @cdo.topo(:options => '-f nc'),:returnMaArray => 'topo')
|
252
244
|
assert_equal(1142.0,oro.mean.round)
|
253
|
-
bathy =
|
245
|
+
bathy = @cdo.remapnn('r2x2',:input => @cdo.topo(:options => '-f nc'), :returnMaArray => 'topo')
|
254
246
|
assert_equal(-4298.0,bathy[0,0])
|
255
247
|
assert_equal(-2669.0,bathy[1,0])
|
256
|
-
ta =
|
257
|
-
tb =
|
258
|
-
withMask =
|
248
|
+
ta = @cdo.remapnn('r2x2',:input => @cdo.topo(:options => '-f nc'))
|
249
|
+
tb = @cdo.subc(-2669.0,:input => ta)
|
250
|
+
withMask = @cdo.div(:input => ta+" "+tb,:returnMaArray => 'topo')
|
259
251
|
assert(-8.0e+33 > withMask[1,0])
|
260
252
|
assert(0 < withMask[0,0])
|
261
253
|
assert(0 < withMask[0,1])
|
@@ -263,131 +255,123 @@ class TestCdo < Minitest::Test
|
|
263
255
|
end
|
264
256
|
|
265
257
|
def test_errorException
|
266
|
-
|
258
|
+
@cdo.debug = true
|
267
259
|
# stdout operators get get wrong input
|
268
|
-
|
269
|
-
|
260
|
+
assert_raises ArgumentError do
|
261
|
+
@cdo.showname(:input => '-for,d')
|
270
262
|
end
|
271
263
|
# non-existing operator
|
272
|
-
|
273
|
-
|
264
|
+
assert_raises ArgumentError do
|
265
|
+
@cdo.neverDefinedOperator()
|
274
266
|
end
|
275
267
|
# standard opertor get mis-spelled value
|
276
|
-
|
277
|
-
|
268
|
+
assert_raises ArgumentError do
|
269
|
+
@cdo.remapnn('r-10x10')
|
278
270
|
end
|
279
271
|
# standard operator get unexisting operator as input stream
|
280
|
-
|
281
|
-
|
272
|
+
assert_raises ArgumentError do
|
273
|
+
@cdo.remapnn('r10x10',:input => '-99topo')
|
282
274
|
end
|
283
275
|
# missing input stream
|
284
|
-
|
285
|
-
|
276
|
+
assert_raises ArgumentError do
|
277
|
+
@cdo.setname('setname')
|
286
278
|
end
|
287
279
|
# missing input stream for stdout-operator
|
288
|
-
|
289
|
-
|
280
|
+
assert_raises ArgumentError do
|
281
|
+
@cdo.showname
|
290
282
|
end
|
291
283
|
end
|
292
284
|
|
293
285
|
def test_inputArray
|
294
286
|
# check for file input
|
295
|
-
fileA =
|
296
|
-
fileB =
|
287
|
+
fileA = @cdo.stdatm(0)
|
288
|
+
fileB = @cdo.stdatm(0)
|
297
289
|
files = [fileA,fileB]
|
298
|
-
assert_equal(
|
299
|
-
|
300
|
-
assert_nil(
|
290
|
+
assert_equal(@cdo.diffv(:input => files.join(' ')),
|
291
|
+
@cdo.diffv(:input => files))
|
292
|
+
assert_nil(@cdo.diffv(:input => files).last)
|
301
293
|
# check for operator input
|
302
|
-
assert_nil(
|
294
|
+
assert_nil(@cdo.diffv(:input => ["-stdatm,0","-stdatm,0"]).last)
|
303
295
|
# check for operator input and files
|
304
|
-
assert_nil(
|
296
|
+
assert_nil(@cdo.diffv(:input => ["-stdatm,0",fileB]).last)
|
305
297
|
end
|
306
298
|
|
307
|
-
def
|
308
|
-
assert(
|
309
|
-
assert(
|
310
|
-
assert(
|
311
|
-
|
312
|
-
|
313
|
-
# assert_equal('1.10.0',Cdo.libsVersion("grib_api")) if Cdo.hasLib?("grib_api")
|
314
|
-
# Cdo.debug = true
|
315
|
-
# warn "Found magics support" if Cdo.libs.has_key?('magics')
|
316
|
-
# Cdo.setCdo('../../src/cdo')
|
317
|
-
# assert(Cdo.libs.has_key?('magics'),"Magics support is expected in the local development binary")
|
318
|
-
#end
|
319
|
-
assert_raise ArgumentError do
|
320
|
-
Cdo.libsVersion("foo")
|
299
|
+
def test_filetypes
|
300
|
+
assert(@cdo.filetypes.include?("grb"),"GRIB support missing")
|
301
|
+
assert(@cdo.filetypes.include?("nc4"),"NETCDF4 support missing")
|
302
|
+
assert(@cdo.filetypes.include?("ext"),"EXTRA support missing")
|
303
|
+
assert_raises ArgumentError do
|
304
|
+
@cdo.filetypes("foo")
|
321
305
|
end
|
322
306
|
end
|
323
307
|
|
324
308
|
def test_output_set_to_nil
|
325
|
-
assert_equal(String
|
326
|
-
assert_equal("File format: GRIB",
|
309
|
+
assert_equal(String,@cdo.topo(:output => nil).class)
|
310
|
+
assert_equal("File format: GRIB".tr(' ',''),@cdo.sinfov(:input => "-topo", :output => nil)[0].tr(' ',''))
|
327
311
|
end
|
328
312
|
|
329
|
-
if '
|
313
|
+
if 'luthien' == `hostname`.chomp then
|
330
314
|
def test_readCdf
|
331
315
|
input = "-settunits,days -setyear,2000 -for,1,4"
|
332
|
-
cdfFile =
|
333
|
-
cdf =
|
316
|
+
cdfFile = @cdo.copy(:options =>"-f nc",:input=>input)
|
317
|
+
cdf = @cdo.readCdf(cdfFile)
|
334
318
|
assert_equal(['lon','lat','time','for'],cdf.var_names)
|
335
319
|
end
|
336
320
|
def test_selIndexListFromIcon
|
337
321
|
input = "~/data/icon/oce.nc"
|
338
322
|
end
|
339
323
|
def test_readArray
|
340
|
-
|
341
|
-
assert_equal([
|
324
|
+
@cdo.debug = true
|
325
|
+
assert_equal([40,80],@cdo.readArray(@cdo.sellonlatbox(-10,10,-20,20,:input => '-topo',:options => '-f nc'), 'topo').shape)
|
342
326
|
end
|
343
327
|
def test_doc
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
328
|
+
@cdo.debug = true
|
329
|
+
@cdo.help(:remap)
|
330
|
+
@cdo.help(:infov)
|
331
|
+
@cdo.help(:topo)
|
332
|
+
@cdo.help(:notDefinedOP)
|
333
|
+
@cdo.help
|
350
334
|
end
|
351
335
|
def test_fillmiss
|
352
|
-
|
336
|
+
@cdo.debug = true
|
353
337
|
# check up-down replacement
|
354
|
-
rand =
|
355
|
-
cdf =
|
338
|
+
rand = @cdo.setname('v',:input => '-random,r1x10 ', :options => ' -f nc',:output => '/tmp/rand.nc')
|
339
|
+
cdf = @cdo.openCdf(rand)
|
356
340
|
vals = cdf.var('v').get
|
357
341
|
cdf.var('v').put(vals.sort)
|
358
342
|
cdf.sync
|
359
343
|
cdf.close
|
360
344
|
|
361
345
|
missRange = '0.3,0.8'
|
362
|
-
arOrg =
|
363
|
-
arFm =
|
364
|
-
arFm1s=
|
346
|
+
arOrg = @cdo.setrtomiss(missRange,:input => cdf.path,:returnMaArray => 'v')
|
347
|
+
arFm = @cdo.fillmiss(:input => "-setrtomiss,#{missRange} #{cdf.path}",:returnMaArray => 'v')
|
348
|
+
arFm1s= @cdo.fillmiss2(:input => "-setrtomiss,#{missRange} #{cdf.path}",:returnMaArray => 'v')
|
365
349
|
vOrg = arOrg[0,0..-1]
|
366
350
|
vFm = arFm[0,0..-1]
|
367
351
|
vFm1s = arFm1s[0,0..-1]
|
368
352
|
UnifiedPlot.linePlot([{:y => vOrg, :style => 'line',:title => 'org'},
|
369
353
|
{:y => vFm, :style => 'points',:title => 'fillmiss'},
|
370
354
|
{:y => vFm1s,:style => 'points',:title => 'fillmiss2'}],
|
371
|
-
plotConf: {:yrange => '[0:1]'},title: 'r1x10')
|
355
|
+
plotConf: {:yrange => '[0:1]'},title: 'r1x10') if @show
|
372
356
|
# check left-right replacement
|
373
|
-
rand =
|
374
|
-
cdf =
|
357
|
+
rand = @cdo.setname('v',:input => '-random,r10x1 ', :options => ' -f nc',:output => '/tmp/rand.nc')
|
358
|
+
cdf = @cdo.openCdf(rand)
|
375
359
|
vals = cdf.var('v').get
|
376
360
|
cdf.var('v').put(vals.sort)
|
377
361
|
cdf.sync
|
378
362
|
cdf.close
|
379
363
|
|
380
364
|
missRange = '0.3,0.8'
|
381
|
-
arOrg =
|
382
|
-
arFm =
|
383
|
-
arFm1s=
|
365
|
+
arOrg = @cdo.setrtomiss(missRange,:input => cdf.path,:returnMaArray => 'v')
|
366
|
+
arFm = @cdo.fillmiss(:input => "-setrtomiss,#{missRange} #{cdf.path}",:returnMaArray => 'v')
|
367
|
+
arFm1s= @cdo.fillmiss2(:input => "-setrtomiss,#{missRange} #{cdf.path}",:returnMaArray => 'v')
|
384
368
|
vOrg = arOrg[0..-1,0]
|
385
369
|
vFm = arFm[0..-1,0]
|
386
370
|
vFm1s = arFm1s[0..-1,0]
|
387
371
|
UnifiedPlot.linePlot([{:y => vOrg, :style => 'line',:title => 'org'},
|
388
372
|
{:y => vFm, :style => 'points',:title => 'fillmiss'},
|
389
373
|
{:y => vFm1s,:style => 'points',:title => 'fillmiss2'}],
|
390
|
-
plotConf: {:yrange => '[0:1]'},title: 'r10x1')
|
374
|
+
plotConf: {:yrange => '[0:1]'},title: 'r10x1') if @show
|
391
375
|
end
|
392
376
|
end
|
393
377
|
|
@@ -400,39 +384,54 @@ class TestCdo < Minitest::Test
|
|
400
384
|
|
401
385
|
# oType = grb (default)
|
402
386
|
ofiles = expected.map {|f| f += '.grb'}
|
403
|
-
|
387
|
+
@cdo.splitlevel(input: "-stdatm,0,10,100",output: oTag)
|
404
388
|
assert_equal(ofiles,Dir.glob(oTag+'*').sort)
|
405
389
|
rm(ofiles)
|
406
390
|
|
407
391
|
# oType = nc, from cdo options
|
408
392
|
ofiles = expected.map {|f| f += '.nc'}
|
409
|
-
|
393
|
+
@cdo.splitlevel(input: "-stdatm,0,10,100",output: oTag,options: '-f nc')
|
410
394
|
assert_equal(ofiles,Dir.glob(oTag+'*').sort)
|
411
395
|
rm(ofiles)
|
412
396
|
|
413
397
|
# oType = nc, from input type
|
414
398
|
ofiles = expected.map {|f| f += '.nc'}
|
415
|
-
|
399
|
+
@cdo.splitlevel(input: @cdo.stdatm(0,10,100,options: '-f nc'),output: oTag)
|
416
400
|
assert_equal(ofiles,Dir.glob(oTag+'*').sort)
|
417
401
|
rm(ofiles)
|
418
402
|
|
419
403
|
# oType = nc, from input ENV
|
420
404
|
ofiles = expected.map {|f| f += '.nc2'}
|
421
|
-
|
422
|
-
|
405
|
+
@cdo.env = {'CDO_FILE_SUFFIX' => '.nc2'}
|
406
|
+
@cdo.splitlevel(input: @cdo.stdatm(0,10,100,options: '-f nc'),output: oTag)
|
423
407
|
assert_equal(ofiles,Dir.glob(oTag+'*').sort)
|
424
408
|
rm(ofiles)
|
425
409
|
|
426
410
|
# oType = nc, from input ENV setting for each call
|
427
411
|
ofiles = expected.map {|f| f += '.nc2'}
|
428
|
-
|
412
|
+
@cdo.splitlevel(input: @cdo.stdatm(0,10,100,options: '-f nc'),output: oTag,env: {'CDO_FILE_SUFFIX' => '.nc2'})
|
429
413
|
assert_equal(ofiles,Dir.glob(oTag+'*').sort)
|
430
414
|
rm(ofiles)
|
431
415
|
end
|
432
416
|
def test_log
|
433
|
-
|
434
|
-
|
435
|
-
Cdo.
|
417
|
+
cmd = '-fldmean -mul -random,r20x20 -topo,r20x20'
|
418
|
+
# logging without a real file
|
419
|
+
@cdo = Cdo.new( returnNilOnError: true)
|
420
|
+
@cdo.debug = false
|
421
|
+
@cdo.logging = true
|
422
|
+
@cdo.topo
|
423
|
+
@cdo.temp
|
424
|
+
@cdo.sinfov(input: cmd)
|
425
|
+
puts @cdo.showLog
|
426
|
+
@cdo.sinfov(input: '-top')
|
427
|
+
@cdo.topo
|
428
|
+
puts @cdo.showLog
|
429
|
+
# use a use definded file for looging
|
430
|
+
@cdo = Cdo.new(logFile: 'test.log',logging: true, returnNilOnError: true)
|
431
|
+
@cdo.topo
|
432
|
+
@cdo.temp
|
433
|
+
@cdo.sinfov(input: cmd)
|
434
|
+
puts @cdo.showLog
|
436
435
|
end
|
437
436
|
end
|
438
437
|
|
@@ -440,30 +439,30 @@ end
|
|
440
439
|
# #
|
441
440
|
# # merge:
|
442
441
|
# # let files be an erray of valid filenames and ofile is a string
|
443
|
-
#
|
442
|
+
# @cdo.merge(:input => outvars.join(" "),:output => ofile)
|
444
443
|
# # or with multiple arrays:
|
445
|
-
#
|
444
|
+
# @cdo.merge(:input => [ifiles0,ifiles1].flatten.join(' '),:output => ofile)
|
446
445
|
# # selname:
|
447
446
|
# # lets grep out some variables from ifile:
|
448
447
|
# ["T","U","V"].each {|varname|
|
449
448
|
# varfile = varname+".nc"
|
450
|
-
#
|
449
|
+
# @cdo.selname(varname,:input => ifile,:output => varfile)
|
451
450
|
# }
|
452
451
|
# # a threaded version of this could look like:
|
453
452
|
# ths = []
|
454
453
|
# ["T","U","V"].each {|outvar|
|
455
454
|
# ths << Thread.new(outvar) {|ovar|
|
456
455
|
# varfile = varname+".nc"
|
457
|
-
#
|
456
|
+
# @cdo.selname(varname,:input => ifile,:output => varfile)
|
458
457
|
# }
|
459
458
|
# }
|
460
459
|
# ths.each {|th| th.join}
|
461
460
|
# # another example with sub:
|
462
|
-
#
|
461
|
+
# @cdo.sub(:input => [oldfile,newfile].join(' '), :output => diff)
|
463
462
|
#
|
464
463
|
# # It is possible too use the 'send' method
|
465
464
|
# operator = /grb/.match(File.extname(ifile)) ? :showcode : :showname
|
466
|
-
# inputVars =
|
465
|
+
# inputVars = @cdo.send(operator,:input => ifile)
|
467
466
|
# # show and info operators are writing to stdout. cdo.rb tries to collects this into arrays
|
468
467
|
# #
|
469
468
|
# # Same stuff with other operators:
|
@@ -473,15 +472,15 @@ end
|
|
473
472
|
# else
|
474
473
|
# warn "Wrong usage of variable identifier for '#{var}' (class #{var.class})!"
|
475
474
|
# end
|
476
|
-
#
|
475
|
+
# @cdo.send(operator,var,:input => @ifile, :output => varfile)
|
477
476
|
#
|
478
477
|
# # Pass an array for operators with multiple options:
|
479
478
|
# # Perform conservative remapping with pregenerated weights
|
480
|
-
#
|
479
|
+
# @cdo.remap([gridfile,weightfile],:input => copyfile,:output => outfile)
|
481
480
|
# # Create vertical height levels out of hybrid model levels
|
482
|
-
#
|
481
|
+
# @cdo.ml2hl([0,20,50,100,200,400,800,1200].join(','),:input => hybridlayerfile, :output => reallayerfile)
|
483
482
|
# # or use multiple arguments directly
|
484
|
-
#
|
483
|
+
# @cdo.remapeta(vctfile,orofile,:input => ifile,:output => hybridlayerfile)
|
485
484
|
#
|
486
485
|
# # the powerfull expr operator:
|
487
486
|
# # taken from the tutorial in https://code.zmaw.de/projects/cdo/wiki/Tutorial#The-_expr_-Operator
|
@@ -492,8 +491,8 @@ end
|
|
492
491
|
# TEMP_EXPR = lambda {|height| "213.0+75.0*exp(-#{height}/#{SCALEHEIGHT})"}
|
493
492
|
#
|
494
493
|
# # Create Pressure and Temperature out of a height field 'geopotheight' from ifile
|
495
|
-
#
|
496
|
-
#
|
494
|
+
# @cdo.expr("'p=#{PRES_EXPR['geopotheight']}'", :input => ifile, :output => presFile)
|
495
|
+
# @cdo.expr("'t=#{TEMP_EXPR['geopotheight']}'", :input => ifile, :output => tempFile)
|
497
496
|
#
|
498
497
|
#
|
499
498
|
# # TIPS: I often work with temporary files and for getting rid of handling them manually the MyTempfile module can be used:
|
@@ -503,11 +502,11 @@ end
|
|
503
502
|
# end
|
504
503
|
# # As an example, the computation of simple atmospherric density could look like
|
505
504
|
# presFile, tempFile = tfile, tfile
|
506
|
-
#
|
507
|
-
#
|
508
|
-
#
|
505
|
+
# @cdo.expr("'p=#{PRES_EXPR['geopotheight']}'", :input => ifile, :output => presFile)
|
506
|
+
# @cdo.expr("'t=#{TEMP_EXPR['geopotheight']}'", :input => ifile, :output => tempFile)
|
507
|
+
# @cdo.chainCall("setname,#{rho} -divc,#{C_R} -div",in: [presFile,tempFile].join(' '), out: densityFile)
|
509
508
|
#
|
510
509
|
# # For debugging, it is helpfull, to avoid the automatic cleanup at the end of the scripts:
|
511
510
|
# MyTempfile.setPersist(true)
|
512
511
|
# # creates randomly names files. Switch on debugging with
|
513
|
-
#
|
512
|
+
# @cdo.Debug = true
|