cdo 1.3.4 → 1.3.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +5 -5
  2. data/gemspec +4 -2
  3. data/lib/cdo.rb +27 -6
  4. data/test/test_cdo.rb +29 -13
  5. metadata +31 -4
  6. data/lib/cdo_lib.rb +0 -415
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 839669f481246fb63e5ad6b7871127ef6b1c710d
4
- data.tar.gz: fae0e2fa60efa590697c9cf73f0e1fc3db103cd8
2
+ SHA256:
3
+ metadata.gz: ae07b4039ff9ecbaea1bdea8a4d50c83b63bdd5d65c6b87f5d0c8f67632dc937
4
+ data.tar.gz: 23d76998b8cd25d1b0ba6619651c255c33920e104181912ccdbe588bfb580e08
5
5
  SHA512:
6
- metadata.gz: 12c44ad5bb29e96457a623d07060a87557f79b2ee9246faf1b0e477865ff5603219118260fa2db0623a149dda45f133db132980ddd18c41c44949dfb86c06fa0
7
- data.tar.gz: '02851b39cb5c9fd19941e0e85c594d01fdcd51349bf0df6255477fb92ae1ede816a42d438fe19ba077ed7dc1958bcfc38d789031186faf09361b76c43c97ddd3'
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.4'
6
+ s.version = '1.3.6'
7
7
  s.platform = Gem::Platform::RUBY
8
- s.files = ["lib/cdo.rb","lib/cdo_lib.rb"] + ["gemspec","LICENSE"]
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
- if version <= '1.7.0' then
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
- @operators = help[(help.index("Operators:")+1)..help.index(help.find {|v| v =~ /CDO version/ }) - 2].join(' ').split
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 = "#{path2cdo} --operators"
84
-
85
- @operators = IO.popen(cmd).readlines.map {|l| l.split(' ').first }
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 system("#@cdo -h 1>/dev/null 2>&1")
311
+ return false unless hasCdo
291
312
 
292
313
  retval = _call("#{@cdo} -V")
293
314
  pp retval if @debug
@@ -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 = true
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.8.1" < @cdo.version,"Version too low: #{@cdo.version}")
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=true
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 = true
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 = true
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 = true
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 = true
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
- assert_equal(['lon','lat','time','for'],cdf.var_names)
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 = true
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 = true
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 = true
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
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: 2017-09-06 00:00:00.000000000 Z
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.6.11
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
@@ -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