cdo 1.3.4 → 1.3.6
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 +5 -5
- data/gemspec +4 -2
- data/lib/cdo.rb +27 -6
- data/test/test_cdo.rb +29 -13
- metadata +31 -4
- data/lib/cdo_lib.rb +0 -415
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ae07b4039ff9ecbaea1bdea8a4d50c83b63bdd5d65c6b87f5d0c8f67632dc937
|
4
|
+
data.tar.gz: 23d76998b8cd25d1b0ba6619651c255c33920e104181912ccdbe588bfb580e08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d870e95cb67677c2f00aa707ce458ee314c7767c857c9085c65a7e838eba6b5e00e40c2c529b1c603b9444562de3e85f2cae812386516261460ff842660aa50e
|
7
|
+
data.tar.gz: 70d7277e46d3c12175fe9168a86aa60e60f0d8837a3d36a94906ce9c3ac725d7c2f8428fc8e841f8d5fbba1c92f7fd4f5bf2e2ba6bbbcda6935815507ac21f42
|
data/gemspec
CHANGED
@@ -3,9 +3,9 @@ $:.unshift File.join(File.dirname(__FILE__),"..","lib")
|
|
3
3
|
|
4
4
|
spec = Gem::Specification.new do |s|
|
5
5
|
s.name = "cdo"
|
6
|
-
s.version = '1.3.
|
6
|
+
s.version = '1.3.6'
|
7
7
|
s.platform = Gem::Platform::RUBY
|
8
|
-
s.files = ["lib/cdo.rb","
|
8
|
+
s.files = ["lib/cdo.rb","gemspec","LICENSE"]
|
9
9
|
s.test_file = "test/test_cdo.rb"
|
10
10
|
s.description = "Easy access to the Climate Data operators"
|
11
11
|
s.summary = "Easy access to the Climate Data operators"
|
@@ -16,6 +16,8 @@ spec = Gem::Specification.new do |s|
|
|
16
16
|
s.required_ruby_version = ">= 1.9"
|
17
17
|
s.add_development_dependency('unifiedPlot')
|
18
18
|
s.add_development_dependency('minitest')
|
19
|
+
s.add_development_dependency('facets')
|
20
|
+
s.add_development_dependency('colorize')
|
19
21
|
s.add_development_dependency('rake')
|
20
22
|
end
|
21
23
|
|
data/lib/cdo.rb
CHANGED
@@ -3,6 +3,11 @@ require 'open3'
|
|
3
3
|
require 'logger'
|
4
4
|
require 'stringio'
|
5
5
|
|
6
|
+
class Hash
|
7
|
+
alias :include? :has_key?
|
8
|
+
end
|
9
|
+
|
10
|
+
|
6
11
|
class Cdo
|
7
12
|
|
8
13
|
# hardcoded fallback list of output operators - from 1.8.0 there is an
|
@@ -69,7 +74,8 @@ class Cdo
|
|
69
74
|
|
70
75
|
# collect the complete list of possible operators
|
71
76
|
def getOperators(path2cdo)
|
72
|
-
|
77
|
+
case
|
78
|
+
when version <= '1.7.0' then
|
73
79
|
cmd = path2cdo + ' 2>&1'
|
74
80
|
help = IO.popen(cmd).readlines.map {|l| l.chomp.lstrip}
|
75
81
|
if 5 >= help.size
|
@@ -78,12 +84,21 @@ class Cdo
|
|
78
84
|
exit
|
79
85
|
end
|
80
86
|
|
81
|
-
|
87
|
+
operators = help[(help.index("Operators:")+1)..help.index(help.find {|v| v =~ /CDO version/ }) - 2].join(' ').split
|
88
|
+
when version <= '1.9.1' then
|
89
|
+
cmd = "#{path2cdo} --operators"
|
90
|
+
operators = IO.popen(cmd).readlines.map {|l| l.split(' ').first }
|
82
91
|
else
|
83
|
-
cmd
|
84
|
-
|
85
|
-
|
92
|
+
cmd = "#{path2cdo} --operators"
|
93
|
+
operators = {}
|
94
|
+
IO.popen(cmd).readlines.map {|line|
|
95
|
+
lineContent = line.chomp.split(' ')
|
96
|
+
name = lineContent[0]
|
97
|
+
iCounter, oCounter = lineContent[-1].tr(')','').tr('(','').split('|')
|
98
|
+
operators[name] = { iStreams: iCounter.to_i, oStreams: oCounter.to_i }
|
99
|
+
}
|
86
100
|
end
|
101
|
+
return operators
|
87
102
|
end
|
88
103
|
|
89
104
|
def getNoOuputOperators(path2cdo)
|
@@ -285,9 +300,15 @@ class Cdo
|
|
285
300
|
puts collectLogs
|
286
301
|
end
|
287
302
|
|
303
|
+
def hasCdo(path=@cdo)
|
304
|
+
executable = system("#{path} -V >/dev/null 2>&1")
|
305
|
+
fullpath = File.exists?(path) and File.executable?(path)
|
306
|
+
|
307
|
+
return (executable or fullpath)
|
308
|
+
end
|
288
309
|
# check if cdo backend is working
|
289
310
|
def check
|
290
|
-
return false unless
|
311
|
+
return false unless hasCdo
|
291
312
|
|
292
313
|
retval = _call("#{@cdo} -V")
|
293
314
|
pp retval if @debug
|
data/test/test_cdo.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
$:.unshift File.join(File.dirname(__FILE__),"..","lib")
|
2
|
+
require 'cdo'
|
2
3
|
|
3
4
|
require 'minitest/autorun'
|
4
|
-
require 'cdo'
|
5
|
-
require 'pp'
|
6
5
|
|
7
6
|
|
8
7
|
#===============================================================================
|
@@ -15,6 +14,7 @@ class TestCdo < Minitest::Test
|
|
15
14
|
|
16
15
|
@@show = ENV.has_key?('SHOW')
|
17
16
|
@@maintainermode = ENV.has_key?('MAINTAINERMODE')
|
17
|
+
@@debug = ENV.has_key?('DEBUG')
|
18
18
|
|
19
19
|
def setup
|
20
20
|
@cdo = Cdo.new
|
@@ -25,6 +25,8 @@ class TestCdo < Minitest::Test
|
|
25
25
|
if ENV['CDO']
|
26
26
|
assert_equal(ENV['CDO'],@cdo.cdo)
|
27
27
|
else
|
28
|
+
pp DEFAULT_CDO_PATH
|
29
|
+
pp @cdo.cdo
|
28
30
|
assert_equal(DEFAULT_CDO_PATH,@cdo.cdo)
|
29
31
|
end
|
30
32
|
newCDO="#{ENV['HOME']}/local/bin/cdo-dev"
|
@@ -41,6 +43,14 @@ class TestCdo < Minitest::Test
|
|
41
43
|
def test_V
|
42
44
|
puts @cdo.version(verbose=true)
|
43
45
|
end
|
46
|
+
def test_hasCdo
|
47
|
+
assert(@cdo.hasCdo)
|
48
|
+
@cdo.cdo = 'cccccccc'
|
49
|
+
assert_equal( false, @cdo.hasCdo)
|
50
|
+
|
51
|
+
@cdo.cdo='/bin/cdo'
|
52
|
+
assert(@cdo.hasCdo) if File.exist?(@cdo.cdo)
|
53
|
+
end
|
44
54
|
def test_getOperators
|
45
55
|
%w[for random stdatm info showlevel sinfo remap geopotheight mask topo thicknessOfLevels].each {|op|
|
46
56
|
if ["thicknessOfLevels"].include?(op)
|
@@ -56,7 +66,7 @@ class TestCdo < Minitest::Test
|
|
56
66
|
end
|
57
67
|
|
58
68
|
def test_outputOperators
|
59
|
-
@cdo.debug =
|
69
|
+
@cdo.debug = @@debug
|
60
70
|
levels = @cdo.showlevel(:input => "-stdatm,0")
|
61
71
|
assert_equal([0,0].map(&:to_s),levels)
|
62
72
|
|
@@ -72,7 +82,7 @@ class TestCdo < Minitest::Test
|
|
72
82
|
end
|
73
83
|
def test_CDO_version
|
74
84
|
assert("1.4.3.1" < @cdo.version,"Version too low: #{@cdo.version}")
|
75
|
-
assert("1.
|
85
|
+
assert("1.7.1" < @cdo.version,"Version too low: #{@cdo.version}")
|
76
86
|
assert("3.0" > @cdo.version,"Version too high: #{@cdo.version}")
|
77
87
|
end
|
78
88
|
def test_args
|
@@ -84,7 +94,7 @@ class TestCdo < Minitest::Test
|
|
84
94
|
(1...info.size).each {|i| assert_equal(0.0,info[i].split[-1].to_f)}
|
85
95
|
end
|
86
96
|
def test_operator_options
|
87
|
-
@cdo.debug
|
97
|
+
@cdo.debug=@@debug
|
88
98
|
targetLevels = [0,10,50,100,200,400,1000]
|
89
99
|
levels = @cdo.showlevel(:input => " -stdatm,#{targetLevels.join(',')}")
|
90
100
|
[0,1].each {|i| assert_equal(targetLevels.join(' '),levels[i])}
|
@@ -92,7 +102,7 @@ class TestCdo < Minitest::Test
|
|
92
102
|
assert_equal(["P T"],names)
|
93
103
|
end
|
94
104
|
def test_chain
|
95
|
-
@cdo.debug =
|
105
|
+
@cdo.debug = @@debug
|
96
106
|
ofile = @cdo.setname('veloc',:input => " -copy -random,r1x1",:options => "-f nc")
|
97
107
|
assert_equal(["veloc"],@cdo.showname(:input => ofile))
|
98
108
|
end
|
@@ -127,6 +137,7 @@ class TestCdo < Minitest::Test
|
|
127
137
|
outs.clear
|
128
138
|
outs << @cdo.stdatm(0,10,20,:output => 'test_force')
|
129
139
|
mtime0 = File.stat(outs[-1]).mtime
|
140
|
+
sleep(1)
|
130
141
|
outs << @cdo.stdatm(0,10,20,:output => 'test_force')
|
131
142
|
mtime1 = File.stat(outs[-1]).mtime
|
132
143
|
assert(mtime0 != mtime1)
|
@@ -194,7 +205,7 @@ class TestCdo < Minitest::Test
|
|
194
205
|
end
|
195
206
|
|
196
207
|
def test_verticalLevels
|
197
|
-
@cdo.debug =
|
208
|
+
@cdo.debug = @@debug
|
198
209
|
targetThicknesses = [50.0, 100.0, 200.0, 300.0, 450.0, 600.0, 800.0, 1000.0, 1000.0, 1000.0]
|
199
210
|
sourceLevels = %W{25 100 250 500 875 1400 2100 3000 4000 5000}
|
200
211
|
thicknesses = @cdo.thicknessOfLevels(:input => "-selname,T #{@cdo.stdatm(*sourceLevels,:options => '-f nc')}")
|
@@ -212,7 +223,7 @@ class TestCdo < Minitest::Test
|
|
212
223
|
end
|
213
224
|
|
214
225
|
def test_errorException
|
215
|
-
@cdo.debug =
|
226
|
+
@cdo.debug = @@debug
|
216
227
|
# stdout operators get get wrong input
|
217
228
|
assert_raises ArgumentError do
|
218
229
|
@cdo.showname(:input => '-for,d')
|
@@ -303,6 +314,11 @@ class TestCdo < Minitest::Test
|
|
303
314
|
if @@maintainermode then
|
304
315
|
require 'unifiedPlot'
|
305
316
|
|
317
|
+
def test_longChain
|
318
|
+
ifile = "-enlarge,global_0.3 -settaxis,2000-01-01 -expr,'t=sin(for*3.141529/180.0)' -for,1,10"
|
319
|
+
t = @cdo.fldmax(input: "-div -sub -timmean -seltimestep,2,3 #{ifile} -seltimestep,1 #{ifile} -gridarea #{ifile}",returnArray: "t")
|
320
|
+
assert_equal(8.981299259858133e-09,t[0])
|
321
|
+
end
|
306
322
|
def test_returnArray
|
307
323
|
temperature = @cdo.stdatm(0,:options => '-f nc',:returnCdf => true).var('T').get.flatten[0]
|
308
324
|
assert_raises ArgumentError do
|
@@ -314,7 +330,7 @@ class TestCdo < Minitest::Test
|
|
314
330
|
assert_equal("1013.25 898.543456035875",pressure.flatten.to_a.join(' '))
|
315
331
|
end
|
316
332
|
def test_returnMaArray
|
317
|
-
@cdo.debug =
|
333
|
+
@cdo.debug = @@debug
|
318
334
|
topo = @cdo.topo(:options => '-f nc',:returnMaArray => 'topo')
|
319
335
|
assert_equal(-1890.0,topo.mean.round)
|
320
336
|
bathy = @cdo.setrtomiss(0,10000,
|
@@ -382,17 +398,17 @@ class TestCdo < Minitest::Test
|
|
382
398
|
input = "-settunits,days -setyear,2000 -for,1,4"
|
383
399
|
cdfFile = @cdo.copy(:options =>"-f nc",:input=>input)
|
384
400
|
cdf = @cdo.readCdf(cdfFile)
|
385
|
-
|
401
|
+
assert_empty(['lon','lat','for','time'] - cdf.var_names)
|
386
402
|
end
|
387
403
|
def test_selIndexListFromIcon
|
388
404
|
input = "~/data/icon/oce.nc"
|
389
405
|
end
|
390
406
|
def test_readArray
|
391
|
-
@cdo.debug =
|
407
|
+
@cdo.debug = @@debug
|
392
408
|
assert_equal([40,80],@cdo.readArray(@cdo.sellonlatbox(-10,10,-20,20,:input => '-topo',:options => '-f nc'), 'topo').shape)
|
393
409
|
end
|
394
410
|
def test_doc
|
395
|
-
@cdo.debug =
|
411
|
+
@cdo.debug = @@debug
|
396
412
|
@cdo.help(:remap)
|
397
413
|
@cdo.help(:infov)
|
398
414
|
@cdo.help(:topo)
|
@@ -400,7 +416,7 @@ class TestCdo < Minitest::Test
|
|
400
416
|
@cdo.help
|
401
417
|
end
|
402
418
|
def test_fillmiss
|
403
|
-
@cdo.debug =
|
419
|
+
@cdo.debug = @@debug
|
404
420
|
# check up-down replacement
|
405
421
|
rand = @cdo.setname('v',:input => '-random,r1x10 ', :options => ' -f nc',:output => '/tmp/rand.nc')
|
406
422
|
cdf = @cdo.openCdf(rand)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cdo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ralf Mueller
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-04-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: unifiedPlot
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: facets
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: colorize
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: rake
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -61,7 +89,6 @@ files:
|
|
61
89
|
- LICENSE
|
62
90
|
- gemspec
|
63
91
|
- lib/cdo.rb
|
64
|
-
- lib/cdo_lib.rb
|
65
92
|
- test/test_cdo.rb
|
66
93
|
homepage: https://code.zmaw.de/projects/cdo/wiki/Cdo%7Brbpy%7D
|
67
94
|
licenses:
|
@@ -83,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
110
|
version: '0'
|
84
111
|
requirements: []
|
85
112
|
rubyforge_project:
|
86
|
-
rubygems_version: 2.
|
113
|
+
rubygems_version: 2.7.4
|
87
114
|
signing_key:
|
88
115
|
specification_version: 4
|
89
116
|
summary: Easy access to the Climate Data operators
|
data/lib/cdo_lib.rb
DELETED
@@ -1,415 +0,0 @@
|
|
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
|