cdo 1.3.6 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/gemspec +1 -1
  3. data/lib/cdo.rb +176 -73
  4. data/test/test_cdo.rb +233 -151
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae07b4039ff9ecbaea1bdea8a4d50c83b63bdd5d65c6b87f5d0c8f67632dc937
4
- data.tar.gz: 23d76998b8cd25d1b0ba6619651c255c33920e104181912ccdbe588bfb580e08
3
+ metadata.gz: 2085dbda68e564e4449b83e69c840dcfc817b60adfe2010c597eeb795eade50d
4
+ data.tar.gz: 34c2082c1ed7de54cb889dde3cd8fe3d3e8e9ba7abd6f20f655bd6d5478e0905
5
5
  SHA512:
6
- metadata.gz: d870e95cb67677c2f00aa707ce458ee314c7767c857c9085c65a7e838eba6b5e00e40c2c529b1c603b9444562de3e85f2cae812386516261460ff842660aa50e
7
- data.tar.gz: 70d7277e46d3c12175fe9168a86aa60e60f0d8837a3d36a94906ce9c3ac725d7c2f8428fc8e841f8d5fbba1c92f7fd4f5bf2e2ba6bbbcda6935815507ac21f42
6
+ metadata.gz: 38f8689cf9674697d64c9958df35c85177e86c08d6becaa808cc13a56c460fcbce6a6f57c43ca376c129c531c26a1b09dbae38a07c1557e36ec1746f4365ca50
7
+ data.tar.gz: 71d527c68c39531e5b3c8007a05fa0b46989efa4b49da2a4e3738ced45d60137d32071bfe77a2da11273a6a716f0c9e17484a4676680825f480633289521f921
data/gemspec CHANGED
@@ -3,7 +3,7 @@ $:.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'
6
+ s.version = '1.4.0'
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.files = ["lib/cdo.rb","gemspec","LICENSE"]
9
9
  s.test_file = "test/test_cdo.rb"
data/lib/cdo.rb CHANGED
@@ -2,6 +2,8 @@ require 'pp'
2
2
  require 'open3'
3
3
  require 'logger'
4
4
  require 'stringio'
5
+ require 'json'
6
+ require 'tempfile'
5
7
 
6
8
  class Hash
7
9
  alias :include? :has_key?
@@ -12,17 +14,25 @@ class Cdo
12
14
 
13
15
  # hardcoded fallback list of output operators - from 1.8.0 there is an
14
16
  # options for this: --operators_no_output
15
- NoOutputOperators = %w[cdiread cmor codetab conv_cmor_table diff diffc diffn diffp
16
- diffv dump_cmor_table dumpmap filedes ggstat ggstats gmtcells gmtxyz gradsdes
17
- griddes griddes2 gridverify info infoc infon infop infos infov map ncode
18
- ncode ndate ngridpoints ngrids nlevel nmon npar ntime nvar nyear output
19
- outputarr outputbounds outputboundscpt outputcenter outputcenter2
20
- outputcentercpt outputext outputf outputfld outputint outputkey outputsrv
21
- outputtab outputtri outputts outputvector outputvrml outputxyz pardes partab
22
- partab2 seinfo seinfoc seinfon seinfop showcode showdate showformat showlevel
23
- showltype showmon showname showparam showstdname showtime showtimestamp
24
- showunit showvar showyear sinfo sinfoc sinfon sinfop sinfov
25
- spartab specinfo tinfo vardes vct vct2 verifygrid vlist zaxisdes]
17
+ # this list works for cdo-1.6.4
18
+ NoOutputOperators = %w[cdiread cmor codetab conv_cmor_table diff diffc diffn
19
+ diffp diffv dump_cmor_table dumpmap filedes gmtcells gmtxyz gradsdes griddes
20
+ griddes2 gridverify info infoc infon infop infos infov map ncode ndate
21
+ ngridpoints ngrids nlevel nmon npar ntime nvar nyear output outputarr
22
+ outputbounds outputboundscpt outputcenter outputcenter2 outputcentercpt
23
+ outputext outputf outputfld outputint outputkey outputsrv outputtab outputtri
24
+ outputts outputvector outputvrml outputxyz pardes partab partab2 seinfo
25
+ seinfoc seinfon seinfop showattribute showatts showattsglob showattsvar
26
+ showcode showdate showformat showgrid showlevel showltype showmon showname
27
+ showparam showstdname showtime showtimestamp showunit showvar showyear sinfo
28
+ sinfoc sinfon sinfop sinfov spartab specinfo tinfo vardes vct vct2 verifygrid
29
+ vlist xinfon zaxisdes]
30
+ TwoOutputOperators = %w[trend samplegridicon mrotuv eoftime
31
+ eofspatial eof3dtime eof3dspatial eof3d eof complextorect complextopol]
32
+ MoreOutputOperators = %w[distgrid eofcoeff eofcoeff3d intyear scatter splitcode
33
+ splitday splitgrid splithour splitlevel splitmon splitname splitparam splitrec
34
+ splitseas splitsel splittabnum splitvar splityear splityearmon splitzaxis]
35
+
26
36
 
27
37
  attr_accessor :cdo, :returnCdf, :forceOutput, :env, :debug, :logging, :logFile
28
38
  attr_reader :operators, :filetypes
@@ -32,6 +42,7 @@ class Cdo
32
42
  returnFalseOnError: false,
33
43
  forceOutput: true,
34
44
  env: {},
45
+ tempdir: Dir.tmpdir,
35
46
  logging: false,
36
47
  logFile: StringIO.new,
37
48
  debug: false,
@@ -41,20 +52,30 @@ class Cdo
41
52
  @cdo = ENV.has_key?('CDO') ? ENV['CDO'] : cdo
42
53
 
43
54
  @operators = getOperators(@cdo)
55
+ @noOutputOperators = @operators.select {|op,io| 0 == io}.keys
56
+
44
57
  @returnCdf = returnCdf
45
58
  @forceOutput = forceOutput
46
59
  @env = env
47
60
  @debug = ENV.has_key?('DEBUG') ? true : debug
48
- @noOutputOperators = getNoOuputOperators(@cdo) # operators without output files (write to stdout)
49
61
  @returnNilOnError = returnNilOnError
50
62
 
51
- @filetypes = getFiletypes
52
63
  @returnFalseOnError = returnFalseOnError
53
64
 
65
+ @tempStore = CdoTempfileStore.new(tempdir)
54
66
  @logging = logging
55
67
  @logFile = logFile
56
68
  @logger = Logger.new(@logFile,'a')
57
69
  @logger.level = Logger::INFO
70
+
71
+ @config = getFeatures
72
+
73
+ # create methods to descibe what can be done with the binary
74
+ @config.each {|k,v|
75
+ self.class.send :define_method, k.tr('-','_') do
76
+ v
77
+ end
78
+ }
58
79
  end
59
80
 
60
81
  private # {{{
@@ -73,9 +94,13 @@ class Cdo
73
94
  end
74
95
 
75
96
  # collect the complete list of possible operators
76
- def getOperators(path2cdo)
97
+ def getOperators(path2cdo) #{{{
98
+ operators = {}
99
+
100
+ # little side note: the option --operators_no_output works in 1.8.0 and
101
+ # 1.8.2, but not in 1.9.0, from 1.9.1 it works again
77
102
  case
78
- when version <= '1.7.0' then
103
+ when version < '1.7.2' then
79
104
  cmd = path2cdo + ' 2>&1'
80
105
  help = IO.popen(cmd).readlines.map {|l| l.chomp.lstrip}
81
106
  if 5 >= help.size
@@ -84,38 +109,77 @@ class Cdo
84
109
  exit
85
110
  end
86
111
 
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 }
112
+ _operators = help[(help.index("Operators:")+1)..help.index(help.find {|v|
113
+ v =~ /CDO version/
114
+ }) - 2].join(' ').split
115
+
116
+ # build up operator inventory
117
+ # default is 1 output stream
118
+ _operators.each {|op| operators[op] = 1 }
119
+ operators.each {|op,_|
120
+ operators[op] = 0 if NoOutputOperators.include?(op)
121
+ operators[op] = 2 if TwoOutputOperators.include?(op)
122
+ operators[op] = -1 if MoreOutputOperators.include?(op)
123
+ }
124
+
125
+ when (version < '1.8.0' or '1.9.0' == version) then
126
+ cmd = "#{path2cdo} --operators"
127
+ _operators = IO.popen(cmd).readlines.map {|l| l.split(' ').first }
128
+
129
+ _operators.each {|op| operators[op] = 1 }
130
+ operators.each {|op,_|
131
+ operators[op] = 0 if NoOutputOperators.include?(op)
132
+ operators[op] = 2 if TwoOutputOperators.include?(op)
133
+ operators[op] = -1 if MoreOutputOperators.include?(op)
134
+ }
135
+
136
+
137
+ when version < '1.9.3' then
138
+
139
+ cmd = "#{path2cdo} --operators"
140
+ _operators = IO.popen(cmd).readlines.map {|l| l.split(' ').first }
141
+ cmd = "#{path2cdo} --operators_no_output"
142
+ _operatorsNoOutput = IO.popen(cmd).readlines.map {|l| l.split(' ').first }
143
+
144
+ # build up operator inventory
145
+ _operators.each {|op| operators[op] = 1 }
146
+ _operatorsNoOutput.each {|op| operators[op] = 0}
147
+ operators.each {|op,_|
148
+ operators[op] = 0 if _operatorsNoOutput.include?(op)
149
+ operators[op] = 2 if TwoOutputOperators.include?(op)
150
+ operators[op] = -1 if MoreOutputOperators.include?(op)
151
+ }
152
+
91
153
  else
92
154
  cmd = "#{path2cdo} --operators"
93
155
  operators = {}
94
156
  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 }
157
+ lineContent = line.chomp.split(' ')
158
+ name = lineContent[0]
159
+ iCounter, oCounter = lineContent[-1][1..-1].split('|')
160
+ operators[name] = oCounter.to_i
99
161
  }
100
162
  end
101
163
  return operators
102
- end
164
+ end #}}}
103
165
 
104
- def getNoOuputOperators(path2cdo)
105
- if version > '1.8.0' and version < '1.9.0' then
106
- puts 'CMD:'+path2cdo+' --operators_no_output' if @debug
107
- IO.popen(path2cdo+' --operators_no_output').readlines.map{|line| line.split(' ')[0]}.flatten
108
- else
109
- NoOutputOperators
110
- end
111
- end
166
+ # get meta-data about the CDO installation
167
+ def getFeatures
168
+ config = {}
169
+ config.default(false)
112
170
 
113
- # get supported IO filetypes form the binary
114
- def getFiletypes
115
- _, _, stderr, _ = Open3.popen3(@cdo + " -V")
116
- supported = stderr.readlines.map(&:chomp)
171
+ if version > '1.9.3' then
172
+ config.merge!(JSON.parse(IO.popen(@cdo + " --config all").read.chomp))
173
+ config.each {|k,v| config[k] = ('yes' == v) ? true : false}
174
+ else
175
+ _, _, stderr, _ = Open3.popen3(@cdo + " -V")
176
+ supported = stderr.readlines.map(&:chomp)
117
177
 
118
- supported.grep(/(Filetypes)/)[0].split(':')[1].split.map(&:downcase)
178
+ supported.grep(/(Filetypes)/)[0].split(':')[1].split.map(&:downcase).each {|ftype|
179
+ config["has-#{ftype}"] = true
180
+ }
181
+ end
182
+ config
119
183
  end
120
184
 
121
185
  # Execute the given cdo call and return all outputs
@@ -174,18 +238,25 @@ class Cdo
174
238
  autoSplit: nil)
175
239
  options = options.to_s
176
240
 
177
- options << '-f nc' if options.empty? and ( \
178
- ( returnCdf ) or \
179
- ( not returnArray.nil? ) or \
180
- ( not returnMaArray.nil?) \
181
- )
182
- #
241
+ # switch netcdf output if data of filehandles are requested as output
242
+ options << ' -f nc' if ( \
243
+ ( returnCdf ) or \
244
+ ( not returnArray.nil? ) or \
245
+ ( not returnMaArray.nil?) \
246
+ )
247
+
183
248
  # setup basic operator execution command
184
249
  cmd = "#{@cdo} -O #{options} -#{operatorName}#{operatorParameters} #{input} "
185
250
 
186
251
  # use an empty hash for non-given environment
187
252
  env = {} if env.nil?
188
253
 
254
+ # list of all output streams
255
+ outputs = []
256
+
257
+ # just collect given output(s)
258
+ outputs << output unless output.nil?
259
+
189
260
  case output
190
261
  when $stdout
191
262
  retvals = _call(cmd,env)
@@ -204,13 +275,18 @@ class Cdo
204
275
  end
205
276
  end
206
277
  else
278
+ # if operators was not called with output-forcing given, take the global switch
207
279
  force = @forceOutput if force.nil?
280
+
208
281
  if force or not File.exists?(output.to_s)
209
- # create a tempfile if output is not given
210
- output = MyTempfile.path if output.nil?
282
+ # create tempfile(s) according to the number of output streams needed
283
+ # if output argument is missing
284
+ if output.nil? then
285
+ operators[operatorName].times { outputs << @tempStore.newFile}
286
+ end
211
287
 
212
288
  #finalize the execution command
213
- cmd << "#{output}"
289
+ cmd << "#{outputs.join(' ')}"
214
290
 
215
291
  retvals = _call(cmd,env)
216
292
 
@@ -222,20 +298,25 @@ class Cdo
222
298
  end
223
299
  end
224
300
  else
225
- warn "Use existing file '#{output}'" if @debug
301
+ warn "Use existing file(s) '#{outputs.join(' ')}'" if @debug
226
302
  end
227
303
  end
228
304
 
305
+ # return data arrays instead - this is for now limitted to fields of the
306
+ # first output file. number from the second need only one addition line, so
307
+ # I think this is sufficient
229
308
  if not returnArray.nil?
230
- readArray(output,returnArray)
309
+ readArray(outputs[0],returnArray)
231
310
  elsif not returnMaArray.nil?
232
- readMaArray(output,returnMaArray)
311
+ readMaArray(outputs[0],returnMaArray)
233
312
  elsif returnCdf or @returnCdf
234
- readCdf(output)
313
+ retval = outputs.map{|f| readCdf(f)}
314
+ return 1 == retval.size ? retval[0] : retval
235
315
  elsif /^split/.match(operatorName)
236
316
  Dir.glob("#{output}*")
237
317
  else
238
- output
318
+ return outputs[0] if outputs.size == 1
319
+ return outputs
239
320
  end
240
321
  end
241
322
 
@@ -295,17 +376,20 @@ class Cdo
295
376
  return File.open(@logFile).readlines
296
377
  end
297
378
  end
379
+
298
380
  # print the loggin messaged
299
381
  def showLog
300
382
  puts collectLogs
301
383
  end
302
384
 
385
+ # check if the CDO binary is present and works
303
386
  def hasCdo(path=@cdo)
304
387
  executable = system("#{path} -V >/dev/null 2>&1")
305
388
  fullpath = File.exists?(path) and File.executable?(path)
306
389
 
307
390
  return (executable or fullpath)
308
391
  end
392
+
309
393
  # check if cdo backend is working
310
394
  def check
311
395
  return false unless hasCdo
@@ -316,6 +400,7 @@ class Cdo
316
400
  return true
317
401
  end
318
402
 
403
+ # return CDO version string
319
404
  def version(verbose=false)
320
405
  info = IO.popen("#{@cdo} -V 2>&1").readlines
321
406
  if verbose then
@@ -359,8 +444,9 @@ class Cdo
359
444
  end
360
445
  end
361
446
 
362
- def noOutputOps
363
- getNoOuputOperators(@cdo)
447
+ # remove tempfiles created from this or previous runs
448
+ def cleanTempDir
449
+ @tempStore.cleanTempDir
364
450
  end
365
451
  # }}}
366
452
 
@@ -392,33 +478,50 @@ class Cdo
392
478
 
393
479
  end
394
480
  #
395
- # Helper module for easy temp file handling
396
- module MyTempfile
397
- require 'tempfile'
398
- @@_tempfiles = []
399
- @@persistent_tempfiles = false
400
- @@N = 10000000
401
-
402
- def MyTempfile.setPersist(value)
403
- @@persistent_tempfiles = value
481
+ # Helper module for easy temp file handling {{{
482
+ class CdoTempfileStore
483
+ # base for persitent temp files - just for debugging
484
+ N = 10000000
485
+
486
+ def initialize(dir=Dir.tmpdir)
487
+ @dir = dir
488
+ @tag = 'Cdorb'
489
+ @persistent_tempfiles = false
490
+
491
+ # storage for filenames in order to prevent too early removement
492
+ @_tempfiles = []
493
+
494
+ # make sure the tempdir ie really there
495
+ Dir.mkdir(@dir) unless Dir.exists?(@dir)
404
496
  end
405
497
 
406
- def MyTempfile.path
407
- unless @@persistent_tempfiles
408
- t = Tempfile.new(self.class.to_s)
409
- @@_tempfiles << t
410
- @@_tempfiles << t.path
498
+ def setPersist(value)
499
+ @persistent_tempfiles = value
500
+ end
501
+
502
+ def newFile
503
+ unless @persistent_tempfiles
504
+ t = Tempfile.new(@tag,@dir)
505
+ @_tempfiles << t
506
+ @_tempfiles << t.path
411
507
  t.path
412
508
  else
413
- t = "_"+rand(@@N).to_s
414
- @@_tempfiles << t
509
+ t = "_"+rand(N).to_s
510
+ @_tempfiles << t
415
511
  t
416
512
  end
417
513
  end
418
514
 
419
- def MyTempfile.showFiles
420
- @@_tempfiles.each {|f| print(f+" ") if f.kind_of? String}
515
+ def showFiles
516
+ @_tempfiles.each {|f| print(f+" ") if f.kind_of? String}
421
517
  end
422
- end
423
518
 
424
- #vim:fdm=marker
519
+ def cleanTempDir
520
+ # filter by name, realfile and ownership
521
+ Dir.entries(@dir).map {|f| "#@dir/#{f}"}.find_all {|file|
522
+ File.file?(file) and File.owned?(file) and file.include?(@tag)
523
+ }.each {|f| File.unlink(f)}
524
+ end
525
+ end #}}}
526
+
527
+ # vim: fdm=marker
@@ -18,6 +18,7 @@ class TestCdo < Minitest::Test
18
18
 
19
19
  def setup
20
20
  @cdo = Cdo.new
21
+ @tempStore = CdoTempfileStore.new
21
22
  end
22
23
 
23
24
  def test_cdo
@@ -82,7 +83,7 @@ class TestCdo < Minitest::Test
82
83
  end
83
84
  def test_CDO_version
84
85
  assert("1.4.3.1" < @cdo.version,"Version too low: #{@cdo.version}")
85
- assert("1.7.1" < @cdo.version,"Version too low: #{@cdo.version}")
86
+ assert("1.6.3" < @cdo.version,"Version too low: #{@cdo.version}")
86
87
  assert("3.0" > @cdo.version,"Version too high: #{@cdo.version}")
87
88
  end
88
89
  def test_args
@@ -264,23 +265,25 @@ class TestCdo < Minitest::Test
264
265
  assert_nil(@cdo.diffv(:input => ["-stdatm,0",fileB]).last)
265
266
  end
266
267
 
267
- def test_filetypes
268
- assert(@cdo.filetypes.find{|ft| /^grb/.match(ft)},"GRIB support missing")
269
- assert(@cdo.filetypes.include?("nc4"),"NETCDF4 support missing")
270
- assert(@cdo.filetypes.include?("ext"),"EXTRA support missing")
271
- assert_raises ArgumentError do
272
- @cdo.filetypes("foo")
273
- end
268
+ def test_features
269
+ assert_equal(true,@cdo.has_srv)
270
+ assert_equal(true,@cdo.has_ieg)
271
+ assert_equal(true,@cdo.has_ext)
274
272
  end
275
273
 
276
274
  def test_noOutputOps
277
- %w[griddes griddes2 gridverify info infoc infon infop infos infov map ncode
278
- ncode ndate ngridpoints ngrids nlevel nmon npar ntime nvar nyear output
275
+ operators = @cdo.operators
276
+ %w[griddes griddes2 gridverify info infoc infon infop infos infov map
279
277
  outputarr outputbounds outputboundscpt outputcenter outputcenter2
280
278
  outputcentercpt outputext outputf outputfld outputint outputkey outputsrv
281
279
  outputtab outputtri outputts outputvector outputvrml outputxyz pardes partab].each {|op|
282
- assert(@cdo.noOutputOps.include?(op))
280
+ assert(operators.include?(op),"Operator '#{op}' cannot be found!")
281
+ assert_equal(0,operators[op],"Operator '#{op}' has a non-zero output counter!")
283
282
  }
283
+ # just a rought estimation
284
+ opsCounf = @cdo.operators.select {|_,c| 0 == c}.size
285
+ assert(opsCounf > 50)
286
+ assert(opsCounf < 200)
284
287
  end
285
288
 
286
289
  def test_output_set_to_nil
@@ -311,59 +314,226 @@ class TestCdo < Minitest::Test
311
314
  }
312
315
  end
313
316
 
317
+ def test_operators_with_multiple_output_files
318
+ assert_equal(1,@cdo.operators['topo'],'wrong output counter for "topo"')
319
+ assert_equal(0,@cdo.operators['sinfo'],'wrong output counter for "sinfo"')
320
+ assert_equal(0,@cdo.operators['ngridpoints'],'wrong output counter for "sinfo"') if @cdo.version > '1.6.4'
321
+
322
+ assert_equal(-1,@cdo.operators['splitsel'],'wrong output counter for "splitsel"')
323
+ assert_equal(2,@cdo.operators['trend'],'wrong output counter for "trend"')
324
+ # create input for eof
325
+ #
326
+ # check automatic generation ot two tempfiles
327
+ aFile, bFile = @cdo.trend(input: "-addc,7 -mulc,44 -for,1,100")
328
+ assert_equal(51.0,@cdo.outputkey('value',input: aFile)[-1].to_f)
329
+ assert_equal(44.0,@cdo.outputkey('value',input: bFile)[-1].to_f)
330
+ # check usage of 'returnCdf' with these operators
331
+ aFile, bFile = @cdo.trend(input: "-addc,7 -mulc,44 -for,1,100",returnCdf: true)
332
+ assert_equal(51.0, aFile.var('for').get.flatten[0],"got wrong value from cdf handle")
333
+ assert_equal(44.0, bFile.var('for').get.flatten[0],"got wrong value from cdf handle")
334
+
335
+ avar = @cdo.trend(input: "-addc,7 -mulc,44 -for,1,100",returnArray: 'for').flatten[0]
336
+ assert_equal(51.0, avar,"got wrong value from narray")
337
+ end
338
+ def test_tempdir
339
+ # manual set path
340
+ tag = 'tempRb'
341
+ tempPath = Dir.pwd+'/'+tag
342
+ pp Dir.glob("#{tempPath}/*").size
343
+ assert_equal(0,Dir.glob("#{tempPath}/*").size)
344
+ cdo = Cdo.new(tempdir: tempPath)
345
+ cdo.topo('r10x10',options: '-f nc')
346
+ assert_equal(1,Dir.glob("#{tempPath}/*").size)
347
+ cdo.topo('r10x10',options: '-f nc')
348
+ cdo.topo('r10x10',options: '-f nc')
349
+ assert_equal(3,Dir.glob("#{tempPath}/*").size)
350
+ cdo.topo('r10x10',options: '-f nc')
351
+ cdo.topo('r10x10',options: '-f nc')
352
+ assert_equal(5,Dir.glob("#{tempPath}/*").size)
353
+ cdo.cleanTempDir
354
+ assert_equal(0,Dir.glob("#{tempPath}/*").size)
355
+ end
356
+
357
+ def test_returnArray
358
+ temperature = @cdo.stdatm(0,:returnCdf => true).var('T').get.flatten[0]
359
+ assert(1.7 < temperature,"Temperature to low!")
360
+ assert_raises ArgumentError do
361
+ @cdo.stdatm(0,:returnArray => 'TT')
362
+ end
363
+ temperature = @cdo.stdatm(0,:returnArray => 'T')
364
+ assert_equal(288.0,temperature.flatten[0])
365
+ pressure = @cdo.stdatm(0,1000,:options => '-b F64',:returnArray => 'P')
366
+ assert_equal("1013.25 898.543456035875",pressure.flatten.to_a.join(' '))
367
+ end
368
+ def test_returnMaArray
369
+ @cdo.debug = @@debug
370
+ topo = @cdo.topo(:returnMaArray => 'topo')
371
+ assert_equal(-1890.0,topo.mean.round)
372
+ bathy = @cdo.setrtomiss(0,10000,
373
+ :input => @cdo.topo(:options => '-f nc'),:returnMaArray => 'topo')
374
+ assert_equal(-3386.0,bathy.mean.round)
375
+ oro = @cdo.setrtomiss(-10000,0,
376
+ :input => @cdo.topo(:options => '-f nc'),:returnMaArray => 'topo')
377
+ assert_equal(1142.0,oro.mean.round)
378
+ bathy = @cdo.remapnn('r2x2',:input => @cdo.topo(:options => '-f nc'), :returnMaArray => 'topo')
379
+ assert_equal(-4298.0,bathy[0,0])
380
+ assert_equal(-2669.0,bathy[1,0])
381
+ ta = @cdo.remapnn('r2x2',:input => @cdo.topo(:options => '-f nc'))
382
+ tb = @cdo.subc(-2669.0,:input => ta)
383
+ withMask = @cdo.div(:input => ta+" "+tb,:returnMaArray => 'topo')
384
+ assert(-8.0e+33 > withMask[1,0])
385
+ assert(0 < withMask[0,0])
386
+ assert(0 < withMask[0,1])
387
+ assert(0 < withMask[1,1])
388
+ end
389
+ def test_combine
390
+ ofile0, ofile1 = @tempStore.newFile, @tempStore.newFile
391
+ @cdo.fldsum(:input => @cdo.stdatm(25,100,250,500,875,1400,2100,3000,4000,5000,:options => "-f nc"),:output => ofile0)
392
+ @cdo.fldsum(:input => "-stdatm,25,100,250,500,875,1400,2100,3000,4000,5000",:options => "-f nc",:output => ofile1)
393
+ @cdo.returnCdf = true
394
+ @tempStore.showFiles
395
+ diff = @cdo.sub(:input => [ofile0,ofile1].join(' ')).var('T').get
396
+ assert_equal(0.0,diff.min)
397
+ assert_equal(0.0,diff.max)
398
+ @cdo.returnCdf = false
399
+ end
400
+
401
+ def test_returnCdf
402
+ ofile = rand(0xfffff).to_s + '_test_returnCdf.nc'
403
+ vals = @cdo.stdatm(25,100,250,500,875,1400,2100,3000,4000,5000,:output => ofile,:options => "-f nc")
404
+ assert_equal(ofile,vals)
405
+ @cdo.returnCdf = true
406
+ vals = @cdo.stdatm(25,100,250,500,875,1400,2100,3000,4000,5000,:output => ofile,:options => "-f nc")
407
+ assert_equal(["lon","lat","level","P","T"],vals.var_names)
408
+ assert_equal(276,vals.var("T").get.flatten.mean.floor)
409
+ @cdo.returnCdf = false
410
+ vals = @cdo.stdatm(25,100,250,500,875,1400,2100,3000,4000,5000,:output => ofile,:options => "-f nc")
411
+ assert_equal(ofile,vals)
412
+ FileUtils.rm(ofile)
413
+ end
414
+ def test_simple_returnCdf
415
+ ofile0, ofile1 = @tempStore.newFile, @tempStore.newFile
416
+ sum = @cdo.fldsum(:input => @cdo.stdatm(0,:options => "-f nc"),
417
+ :returnCdf => true).var("P").get
418
+ assert_equal(1013.25,sum.min)
419
+ sum = @cdo.fldsum(:input => @cdo.stdatm(0,:options => "-f nc"),:output => ofile0)
420
+ assert_equal(ofile0,sum)
421
+ test_returnCdf
422
+ end
423
+ def test_readCdf
424
+ input = "-settunits,days -setyear,2000 -for,1,4"
425
+ cdfFile = @cdo.copy(:options =>"-f nc",:input=>input)
426
+ cdf = @cdo.readCdf(cdfFile)
427
+ assert_empty(['lon','lat','for','time'] - cdf.var_names)
428
+ end
429
+ def test_combine
430
+ ofile0, ofile1 = @tempStore.newFile, @tempStore.newFile
431
+ @cdo.fldsum(:input => @cdo.stdatm(25,100,250,500,875,1400,2100,3000,4000,5000,:options => "-f nc"),:output => ofile0)
432
+ @cdo.fldsum(:input => "-stdatm,25,100,250,500,875,1400,2100,3000,4000,5000",:options => "-f nc",:output => ofile1)
433
+ @cdo.returnCdf = true
434
+ @tempStore.showFiles
435
+ diff = @cdo.sub(:input => [ofile0,ofile1].join(' ')).var('T').get
436
+ assert_equal(0.0,diff.min)
437
+ assert_equal(0.0,diff.max)
438
+ @cdo.returnCdf = false
439
+ end
440
+ def test_readArray
441
+ @cdo.debug = @@debug
442
+ assert_equal([40,80],@cdo.readArray(@cdo.sellonlatbox(-10,10,-20,20,:input => '-topo',:options => '-f nc'), 'topo').shape)
443
+ end
444
+ def test_env
445
+ oTag = 'test_env_with_splitlevel_'
446
+ levels = [0,10,100]
447
+ expected = levels.map {|l| "test_env_with_splitlevel_000#{l.to_s.rjust(3,'0')}"}
448
+ # clean up first
449
+ rm(Dir.glob(oTag+'*'))
450
+
451
+ # oType = grb (default)
452
+ ofiles = expected.map {|f| f += '.grb'}
453
+ @cdo.splitlevel(input: "-stdatm,0,10,100",output: oTag)
454
+ assert_equal(ofiles,Dir.glob(oTag+'*').sort)
455
+ rm(ofiles)
456
+
457
+ # oType = nc, from cdo options
458
+ ofiles = expected.map {|f| f += '.nc'}
459
+ @cdo.splitlevel(input: "-stdatm,0,10,100",output: oTag,options: '-f nc')
460
+ assert_equal(ofiles,Dir.glob(oTag+'*').sort)
461
+ rm(ofiles)
462
+
463
+ # oType = nc, from input type
464
+ ofiles = expected.map {|f| f += '.nc'}
465
+ @cdo.splitlevel(input: @cdo.stdatm(0,10,100,options: '-f nc'),output: oTag)
466
+ assert_equal(ofiles,Dir.glob(oTag+'*').sort)
467
+ rm(ofiles)
468
+
469
+ # oType = nc, from input ENV
470
+ ofiles = expected.map {|f| f += '.nc2'}
471
+ @cdo.env = {'CDO_FILE_SUFFIX' => '.nc2'}
472
+ @cdo.splitlevel(input: @cdo.stdatm(0,10,100,options: '-f nc'),output: oTag)
473
+ assert_equal(ofiles,Dir.glob(oTag+'*').sort)
474
+ rm(ofiles)
475
+
476
+ # oType = nc, from input ENV setting for each call
477
+ ofiles = expected.map {|f| f += '.nc4'}
478
+ @cdo.splitlevel(input: @cdo.stdatm(0,10,100,options: '-f nc'),output: oTag,env: {'CDO_FILE_SUFFIX' => '.nc4'})
479
+ assert_equal(ofiles,Dir.glob(oTag+'*').sort)
480
+ rm(ofiles)
481
+ end
482
+ def test_log
483
+ cmd = '-fldmean -mul -random,r20x20 -topo,r20x20'
484
+ # logging without a real file
485
+ @cdo = Cdo.new( returnNilOnError: true)
486
+ @cdo.debug = false
487
+ @cdo.logging = true
488
+ @cdo.topo
489
+ @cdo.temp
490
+ @cdo.sinfov(input: cmd)
491
+ puts @cdo.showLog
492
+ @cdo.sinfov(input: '-top')
493
+ @cdo.topo
494
+ puts @cdo.showLog
495
+ # use a use definded file for looging
496
+ @cdo = Cdo.new(logFile: 'test.log',logging: true, returnNilOnError: true)
497
+ @cdo.topo
498
+ @cdo.temp
499
+ @cdo.sinfov(input: cmd)
500
+ puts @cdo.showLog
501
+ end
314
502
  if @@maintainermode then
315
503
  require 'unifiedPlot'
316
504
 
505
+ def test_system_tempdir
506
+ # automatic path
507
+ tempPath = Dir.tmpdir
508
+ tag = 'Cdorb'
509
+ pattern = "#{tempPath}/#{tag}*"
510
+ cdo = Cdo.new
511
+ assert_equal(0,Dir.glob(pattern).size)
512
+ cdo.topo('r10x10')
513
+ assert_equal(1,Dir.glob(pattern).size)
514
+ cdo.topo('r10x10')
515
+ cdo.topo('r10x10',options: '-f nc')
516
+ assert_equal(3,Dir.glob(pattern).size)
517
+ cdo.topo('r10x10',options: '-f nc')
518
+ cdo.topo('r10x10',options: '-f nc')
519
+ cdo.topo('r10x10',options: '-f nc')
520
+ cdo.topo('r10x10')
521
+ cdo.topo('r10x10',options: '-f nc')
522
+ cdo.topo('r10x10',options: '-f nc')
523
+ cdo.topo('r10x10',options: '-f nc')
524
+ cdo.topo('r10x10')
525
+ cdo.topo('r10x10',options: '-f nc')
526
+ assert_equal(12,Dir.glob(pattern).size)
527
+ cdo.cleanTempDir()
528
+ assert_equal(0,Dir.glob(pattern).size)
529
+ end
317
530
  def test_longChain
318
531
  ifile = "-enlarge,global_0.3 -settaxis,2000-01-01 -expr,'t=sin(for*3.141529/180.0)' -for,1,10"
319
532
  t = @cdo.fldmax(input: "-div -sub -timmean -seltimestep,2,3 #{ifile} -seltimestep,1 #{ifile} -gridarea #{ifile}",returnArray: "t")
320
533
  assert_equal(8.981299259858133e-09,t[0])
321
534
  end
322
- def test_returnArray
323
- temperature = @cdo.stdatm(0,:options => '-f nc',:returnCdf => true).var('T').get.flatten[0]
324
- assert_raises ArgumentError do
325
- @cdo.stdatm(0,:options => '-f nc',:returnArray => 'TT')
326
- end
327
- temperature = @cdo.stdatm(0,:options => '-f nc',:returnArray => 'T')
328
- assert_equal(288.0,temperature.flatten[0])
329
- pressure = @cdo.stdatm(0,1000,:options => '-f nc -b F64',:returnArray => 'P')
330
- assert_equal("1013.25 898.543456035875",pressure.flatten.to_a.join(' '))
331
- end
332
- def test_returnMaArray
333
- @cdo.debug = @@debug
334
- topo = @cdo.topo(:options => '-f nc',:returnMaArray => 'topo')
335
- assert_equal(-1890.0,topo.mean.round)
336
- bathy = @cdo.setrtomiss(0,10000,
337
- :input => @cdo.topo(:options => '-f nc'),:returnMaArray => 'topo')
338
- assert_equal(-3386.0,bathy.mean.round)
339
- oro = @cdo.setrtomiss(-10000,0,
340
- :input => @cdo.topo(:options => '-f nc'),:returnMaArray => 'topo')
341
- assert_equal(1142.0,oro.mean.round)
342
- bathy = @cdo.remapnn('r2x2',:input => @cdo.topo(:options => '-f nc'), :returnMaArray => 'topo')
343
- assert_equal(-4298.0,bathy[0,0])
344
- assert_equal(-2669.0,bathy[1,0])
345
- ta = @cdo.remapnn('r2x2',:input => @cdo.topo(:options => '-f nc'))
346
- tb = @cdo.subc(-2669.0,:input => ta)
347
- withMask = @cdo.div(:input => ta+" "+tb,:returnMaArray => 'topo')
348
- assert(-8.0e+33 > withMask[1,0])
349
- assert(0 < withMask[0,0])
350
- assert(0 < withMask[0,1])
351
- assert(0 < withMask[1,1])
352
- end
353
- def test_combine
354
- ofile0, ofile1 = MyTempfile.path, MyTempfile.path
355
- @cdo.fldsum(:input => @cdo.stdatm(25,100,250,500,875,1400,2100,3000,4000,5000,:options => "-f nc"),:output => ofile0)
356
- @cdo.fldsum(:input => "-stdatm,25,100,250,500,875,1400,2100,3000,4000,5000",:options => "-f nc",:output => ofile1)
357
- @cdo.returnCdf = true
358
- MyTempfile.showFiles
359
- diff = @cdo.sub(:input => [ofile0,ofile1].join(' ')).var('T').get
360
- assert_equal(0.0,diff.min)
361
- assert_equal(0.0,diff.max)
362
- @cdo.returnCdf = false
363
- end
364
-
365
535
  def test_tempfile
366
- ofile0, ofile1 = MyTempfile.path, MyTempfile.path
536
+ ofile0, ofile1 = @tempStore.newFile, @tempStore.newFile
367
537
  assert(ofile0 != ofile1, "Found equal tempfiles!")
368
538
  # Tempfile should not disappeare even if the GC was started
369
539
  puts ofile0
@@ -371,35 +541,6 @@ class TestCdo < Minitest::Test
371
541
  GC.start
372
542
  assert(File.exist?(ofile0))
373
543
  end
374
-
375
- def test_returnCdf
376
- ofile = rand(0xfffff).to_s + '_test_returnCdf.nc'
377
- vals = @cdo.stdatm(25,100,250,500,875,1400,2100,3000,4000,5000,:output => ofile,:options => "-f nc")
378
- assert_equal(ofile,vals)
379
- @cdo.returnCdf = true
380
- vals = @cdo.stdatm(25,100,250,500,875,1400,2100,3000,4000,5000,:output => ofile,:options => "-f nc")
381
- assert_equal(["lon","lat","level","P","T"],vals.var_names)
382
- assert_equal(276,vals.var("T").get.flatten.mean.floor)
383
- @cdo.returnCdf = false
384
- vals = @cdo.stdatm(25,100,250,500,875,1400,2100,3000,4000,5000,:output => ofile,:options => "-f nc")
385
- assert_equal(ofile,vals)
386
- FileUtils.rm(ofile)
387
- end
388
- def test_simple_returnCdf
389
- ofile0, ofile1 = MyTempfile.path, MyTempfile.path
390
- sum = @cdo.fldsum(:input => @cdo.stdatm(0,:options => "-f nc"),
391
- :returnCdf => true).var("P").get
392
- assert_equal(1013.25,sum.min)
393
- sum = @cdo.fldsum(:input => @cdo.stdatm(0,:options => "-f nc"),:output => ofile0)
394
- assert_equal(ofile0,sum)
395
- test_returnCdf
396
- end
397
- def test_readCdf
398
- input = "-settunits,days -setyear,2000 -for,1,4"
399
- cdfFile = @cdo.copy(:options =>"-f nc",:input=>input)
400
- cdf = @cdo.readCdf(cdfFile)
401
- assert_empty(['lon','lat','for','time'] - cdf.var_names)
402
- end
403
544
  def test_selIndexListFromIcon
404
545
  input = "~/data/icon/oce.nc"
405
546
  end
@@ -456,71 +597,12 @@ class TestCdo < Minitest::Test
456
597
  {:y => vFm1s,:style => 'points',:title => 'fillmiss2'}],
457
598
  plotConf: {:yrange => '[0:1]'},title: 'r10x1') if @@show
458
599
  end
459
- end
460
-
461
- def test_env
462
- oTag = 'test_env_with_splitlevel_'
463
- levels = [0,10,100]
464
- expected = levels.map {|l| "test_env_with_splitlevel_000#{l.to_s.rjust(3,'0')}"}
465
- # clean up first
466
- rm(Dir.glob(oTag+'*'))
467
-
468
- # oType = grb (default)
469
- ofiles = expected.map {|f| f += '.grb'}
470
- @cdo.splitlevel(input: "-stdatm,0,10,100",output: oTag)
471
- assert_equal(ofiles,Dir.glob(oTag+'*').sort)
472
- rm(ofiles)
473
-
474
- # oType = nc, from cdo options
475
- ofiles = expected.map {|f| f += '.nc'}
476
- @cdo.splitlevel(input: "-stdatm,0,10,100",output: oTag,options: '-f nc')
477
- assert_equal(ofiles,Dir.glob(oTag+'*').sort)
478
- rm(ofiles)
479
-
480
- # oType = nc, from input type
481
- ofiles = expected.map {|f| f += '.nc'}
482
- @cdo.splitlevel(input: @cdo.stdatm(0,10,100,options: '-f nc'),output: oTag)
483
- assert_equal(ofiles,Dir.glob(oTag+'*').sort)
484
- rm(ofiles)
485
-
486
- # oType = nc, from input ENV
487
- ofiles = expected.map {|f| f += '.nc2'}
488
- @cdo.env = {'CDO_FILE_SUFFIX' => '.nc2'}
489
- @cdo.splitlevel(input: @cdo.stdatm(0,10,100,options: '-f nc'),output: oTag)
490
- assert_equal(ofiles,Dir.glob(oTag+'*').sort)
491
- rm(ofiles)
492
600
 
493
- # oType = nc, from input ENV setting for each call
494
- ofiles = expected.map {|f| f += '.nc4'}
495
- @cdo.splitlevel(input: @cdo.stdatm(0,10,100,options: '-f nc'),output: oTag,env: {'CDO_FILE_SUFFIX' => '.nc4'})
496
- assert_equal(ofiles,Dir.glob(oTag+'*').sort)
497
- rm(ofiles)
498
- end
499
- def test_log
500
- cmd = '-fldmean -mul -random,r20x20 -topo,r20x20'
501
- # logging without a real file
502
- @cdo = Cdo.new( returnNilOnError: true)
503
- @cdo.debug = false
504
- @cdo.logging = true
505
- @cdo.topo
506
- @cdo.temp
507
- @cdo.sinfov(input: cmd)
508
- puts @cdo.showLog
509
- @cdo.sinfov(input: '-top')
510
- @cdo.topo
511
- puts @cdo.showLog
512
- # use a use definded file for looging
513
- @cdo = Cdo.new(logFile: 'test.log',logging: true, returnNilOnError: true)
514
- @cdo.topo
515
- @cdo.temp
516
- @cdo.sinfov(input: cmd)
517
- puts @cdo.showLog
518
- end
519
- def test_noOutputOps
520
- c = Cdo.new
521
- opsCounf = c.noOutputOps.size
522
- assert(opsCounf > 50)
523
- assert(opsCounf < 200)
601
+ # opendap test - broken since 1.9.0
602
+ def test_opendap
603
+ ifile = 'https://www.esrl.noaa.gov/psd/thredds/dodsC/Datasets/cpc_global_precip/precip.1979.nc'
604
+ @cdo.sinfov(input: ifile)
605
+ end if @@debug
524
606
  end
525
607
  end
526
608
 
@@ -584,10 +666,10 @@ end
584
666
  # @cdo.expr("'t=#{TEMP_EXPR['geopotheight']}'", :input => ifile, :output => tempFile)
585
667
  #
586
668
  #
587
- # # TIPS: I often work with temporary files and for getting rid of handling them manually the MyTempfile module can be used:
669
+ # # TIPS: I often work with temporary files and for getting rid of handling them manually the CdoTempfileStore module can be used:
588
670
  # # Simply include the following methods into you scripts and use tfile for any temporary variable
589
671
  # def tfile
590
- # MyTempfile.path
672
+ # CdoTempfileStore.path
591
673
  # end
592
674
  # # As an example, the computation of simple atmospherric density could look like
593
675
  # presFile, tempFile = tfile, tfile
@@ -596,6 +678,6 @@ end
596
678
  # @cdo.chainCall("setname,#{rho} -divc,#{C_R} -div",in: [presFile,tempFile].join(' '), out: densityFile)
597
679
  #
598
680
  # # For debugging, it is helpfull, to avoid the automatic cleanup at the end of the scripts:
599
- # MyTempfile.setPersist(true)
681
+ # CdoTempfileStore.setPersist(true)
600
682
  # # creates randomly names files. Switch on debugging with
601
683
  # @cdo.Debug = true
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.6
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ralf Mueller
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-03 00:00:00.000000000 Z
11
+ date: 2018-09-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: unifiedPlot