Class: Cdo

Inherits:
Object
  • Object
show all
Defined in:
lib/cdo.rb

Constant Summary collapse

NoOutputOperators =

hardcoded fallback list of output operators - from 1.8.0 there is an options for this: –operators_no_output this list works for cdo-1.6.4

%w[cdiread cmor codetab conv_cmor_table diff diffc diffn
diffp diffv dump_cmor_table dumpmap filedes gmtcells gmtxyz gradsdes griddes
griddes2 gridverify info infoc infon infop infos infov map ncode ndate
ngridpoints ngrids nlevel nmon npar ntime nvar nyear output outputarr
outputbounds outputboundscpt outputcenter outputcenter2 outputcentercpt
outputext outputf outputfld outputint outputkey outputsrv outputtab outputtri
outputts outputvector outputvrml outputxyz pardes partab partab2 seinfo
seinfoc seinfon seinfop showattribute showatts showattsglob showattsvar
showcode showdate showformat showgrid showlevel showltype showmon showname
showparam showstdname showtime showtimestamp showunit showvar showyear sinfo
sinfoc sinfon sinfop sinfov spartab specinfo tinfo vardes vct vct2 verifygrid
vlist xinfon zaxisdes]
TwoOutputOperators =
%w[trend samplegridicon mrotuv eoftime
eofspatial eof3dtime eof3dspatial eof3d eof complextorect complextopol]
MoreOutputOperators =
%w[distgrid eofcoeff eofcoeff3d intyear scatter splitcode
splitday splitgrid splithour splitlevel splitmon splitname splitparam splitrec
splitseas splitsel splittabnum splitvar splityear splityearmon splitzaxis]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(cdo: 'cdo', returnCdf: false, returnFalseOnError: false, forceOutput: true, env: {}, tempdir: Dir.tmpdir, logging: false, logFile: StringIO.new, debug: false, returnNilOnError: false) ⇒ Cdo

Returns a new instance of Cdo.



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/cdo.rb', line 40

def initialize(cdo: 'cdo',
               returnCdf: false,
               returnFalseOnError: false,
               forceOutput: true,
               env: {},
               tempdir: Dir.tmpdir,
               logging: false,
               logFile: StringIO.new,
               debug: false,
               returnNilOnError: false)

  # setup path to cdo executable
  @cdo = ENV.has_key?('CDO') ? ENV['CDO'] : cdo

  @operators              = getOperators(@cdo)
  @noOutputOperators      = @operators.select {|op,io| 0 == io}.keys

  @returnCdf              = returnCdf
  @forceOutput            = forceOutput
  @env                    = env
  @debug                  = ENV.has_key?('DEBUG') ? true : debug
  @returnNilOnError       = returnNilOnError

  @returnFalseOnError     = returnFalseOnError

  @tempStore              = CdoTempfileStore.new(tempdir)
  @logging                = logging
  @logFile                = logFile
  @logger                 = Logger.new(@logFile,'a')
  @logger.level           = Logger::INFO

  @config                 = getFeatures

  # create methods to descibe what can be done with the binary
  @config.each {|k,v|
    self.class.send :define_method, k.tr('-','_') do
      v
    end
  }
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *args, &block) ⇒ Object (private)

Implementation of operator calls using ruby’s meta programming skills

args is expected to look like

[opt1,...,optN,:input => iStream,:output => oStream, :options => ' ']
where iStream could be another CDO call (timmax(selname(Temp,U,V,ifile.nc))


328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
# File 'lib/cdo.rb', line 328

def method_missing(sym, *args, &block)
  operatorName = sym.to_s
  puts "Operator #{operatorName} is called" if @debug

  # exit eary on missing operator
  unless @operators.include?(operatorName)
    return false if @returnFalseOnError
    raise ArgumentError,"Operator #{operatorName} not found"
  end

  io, operatorParameters = Cdo.parseArgs(args)

  # mark calls for operators without output files
  io[:output] = $stdout if @noOutputOperators.include?(operatorName)

  _run(operatorName,operatorParameters,io)
end

Instance Attribute Details

#cdoObject

Returns the value of attribute cdo.



37
38
39
# File 'lib/cdo.rb', line 37

def cdo
  @cdo
end

#debugObject

Returns the value of attribute debug.



37
38
39
# File 'lib/cdo.rb', line 37

def debug
  @debug
end

#envObject

Returns the value of attribute env.



37
38
39
# File 'lib/cdo.rb', line 37

def env
  @env
end

#filetypesObject (readonly)

Returns the value of attribute filetypes.



38
39
40
# File 'lib/cdo.rb', line 38

def filetypes
  @filetypes
end

#forceOutputObject

Returns the value of attribute forceOutput.



37
38
39
# File 'lib/cdo.rb', line 37

def forceOutput
  @forceOutput
end

#logFileObject

Returns the value of attribute logFile.



37
38
39
# File 'lib/cdo.rb', line 37

def logFile
  @logFile
end

#loggingObject

Returns the value of attribute logging.



37
38
39
# File 'lib/cdo.rb', line 37

def logging
  @logging
end

#operatorsObject (readonly)

Returns the value of attribute operators.



38
39
40
# File 'lib/cdo.rb', line 38

def operators
  @operators
end

#returnCdfObject

Returns the value of attribute returnCdf.



37
38
39
# File 'lib/cdo.rb', line 37

def returnCdf
  @returnCdf
end

Instance Method Details

#boundaryLevels(args) ⇒ Object

compute vertical boundary levels from full levels



456
457
458
459
460
461
462
463
464
# File 'lib/cdo.rb', line 456

def boundaryLevels(args)
  ilevels         = self.showlevel(:input => args[:input])[0].split.map(&:to_f)
  bound_levels    = Array.new(ilevels.size+1)
  bound_levels[0] = 0
  (1..ilevels.size).each {|i|
    bound_levels[i] =bound_levels[i-1] + 2*(ilevels[i-1]-bound_levels[i-1])
  }
  bound_levels
end

#checkObject

check if cdo backend is working



394
395
396
397
398
399
400
401
# File 'lib/cdo.rb', line 394

def check
  return false unless hasCdo

  retval = _call("#{@cdo} -V")
  pp retval if @debug

  return true
end

#cleanTempDirObject

remove tempfiles created from this or previous runs



448
449
450
# File 'lib/cdo.rb', line 448

def cleanTempDir
  @tempStore.cleanTempDir
end

#collectLogsObject

collect logging messages



371
372
373
374
375
376
377
378
# File 'lib/cdo.rb', line 371

def collectLogs
  if @logger.instance_variable_get(:'@logdev').filename.nil?
    @logFile.rewind
    return @logFile.read
  else
    return File.open(@logFile).readlines
  end
end

#hasCdo(path = @cdo) ⇒ Object

check if the CDO binary is present and works



386
387
388
389
390
391
# File 'lib/cdo.rb', line 386

def hasCdo(path=@cdo)
  executable = system("#{path} -V >/dev/null 2>&1")
  fullpath   = File.exists?(path) and File.executable?(path)

  return (executable or fullpath)
end

#help(operator = nil) ⇒ Object

show Cdo’s built-in help for given operator



361
362
363
364
365
366
367
368
# File 'lib/cdo.rb', line 361

def help(operator=nil)
  if operator.nil?
    puts _call([@cdo,'-h'].join(' '))[:stderr]
  else
    operator = operator.to_s
    puts _call([@cdo,'-h',operator].join(' ')).values_at(:stdout,:stderr)
  end
end

#openCdf(iFile) ⇒ Object

return cdf handle opened in append more



420
421
422
423
# File 'lib/cdo.rb', line 420

def openCdf(iFile)
  loadCdf
  NumRu::NetCDF.open(iFile,'r+')
end

#readArray(iFile, varname) ⇒ Object

return narray for given variable name



426
427
428
429
430
431
432
433
434
# File 'lib/cdo.rb', line 426

def readArray(iFile,varname)
  filehandle = readCdf(iFile)
  if filehandle.var_names.include?(varname)
    # return the data array
    filehandle.var(varname).get
  else
    raise ArgumentError, "Cannot find variable '#{varname}'"
  end
end

#readCdf(iFile) ⇒ Object

return cdf handle to given file readonly



414
415
416
417
# File 'lib/cdo.rb', line 414

def readCdf(iFile)
  loadCdf
  NumRu::NetCDF.open(iFile)
end

#readMaArray(iFile, varname) ⇒ Object

return a masked array for given variable name



437
438
439
440
441
442
443
444
445
# File 'lib/cdo.rb', line 437

def readMaArray(iFile,varname)
  filehandle = readCdf(iFile)
  if filehandle.var_names.include?(varname)
    # return the data array
    filehandle.var(varname).get_with_miss
  else
    raise ArgumentError,"Cannot find variable '#{varname}'"
  end
end

#showLogObject

print the loggin messaged



381
382
383
# File 'lib/cdo.rb', line 381

def showLog
  puts collectLogs
end

#thicknessOfLevels(args) ⇒ Object

compute level thicknesses from given full levels



467
468
469
470
471
472
473
474
475
# File 'lib/cdo.rb', line 467

def thicknessOfLevels(args)
  bound_levels = self.boundaryLevels(args)
  delta_levels    = []
  bound_levels.each_with_index {|v,i|
    next if 0 == i
    delta_levels << v - bound_levels[i-1]
  }
  delta_levels
end

#version(verbose = false) ⇒ Object

return CDO version string



404
405
406
407
408
409
410
411
# File 'lib/cdo.rb', line 404

def version(verbose=false)
  info = IO.popen("#{@cdo} -V 2>&1").readlines
  if verbose then
    return info.join
  else
    return info.first.split(/version/i).last.strip.split(' ').first
  end
end