Class: NumRu::GrADS_Gridded

Inherits:
Object
  • Object
show all
Defined in:
lib/numru/gphys/grads_gridded.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ctlfilename, mode = "r") ⇒ GrADS_Gridded

Returns a new instance of GrADS_Gridded.



320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
# File 'lib/numru/gphys/grads_gridded.rb', line 320

def initialize(ctlfilename, mode="r")

  case(mode)
  when /^r/
    @mode = 'rb'
  when /^w/
    @mode = 'wb'
  else
    raise ArgumentError, "Unsupported IO mode: #{mode}"
  end

#    @ctlfile = File.open(ctlfilename, mode)
  @options = {    # initialization
    "yrev"=>nil, 
    "zrev"=>nil,
    "sequential"=>nil,
    "byteswapped"=>nil,
    "template"=>nil,
    "big_endian"=>nil,
    "little_endian"=>nil,
    "cray_32bit_ieee"=>nil,
    "365_day_calendar"=>nil,
    "pdef"=>nil,
    "edef"=>nil,
  }

  case(@mode)
  when('rb')
    if (File.exists?(ctlfilename))
      @ctlfile = File.open(ctlfilename, mode)
      parse_ctl
    else
      raise "File #{ctlfilename} does not exist."
    end
  when('wb')
    @ctlfile = File.open(ctlfilename, mode)
    
    @dimensions = []
    @variables = []
    
    #<attributes>
    @dset = nil
#      @title = nil
    @title = ""
    @undef = nil
    @fileheader_len = 0
    
    #<internal control parameters>
    @define_mode = true
    @ctl_dumped = false
  else
    raise ArgumentError, "Unsupported IO mode: #{@mode}"
  end
end

Instance Attribute Details

#ctlfileObject (readonly)

Returns the value of attribute ctlfile.



704
705
706
# File 'lib/numru/gphys/grads_gridded.rb', line 704

def ctlfile
  @ctlfile
end

#dimensionsObject

Returns the value of attribute dimensions.



703
704
705
# File 'lib/numru/gphys/grads_gridded.rb', line 703

def dimensions
  @dimensions
end

#dsetObject

Returns the value of attribute dset.



703
704
705
# File 'lib/numru/gphys/grads_gridded.rb', line 703

def dset
  @dset
end

#titleObject

Returns the value of attribute title.



703
704
705
# File 'lib/numru/gphys/grads_gridded.rb', line 703

def title
  @title
end

#undefObject

Returns the value of attribute undef.



703
704
705
# File 'lib/numru/gphys/grads_gridded.rb', line 703

def undef
  @undef
end

#variablesObject

Returns the value of attribute variables.



703
704
705
# File 'lib/numru/gphys/grads_gridded.rb', line 703

def variables
  @variables
end

Class Method Details

.create(ctlfilename, noclobber = false, share = false) ⇒ Object



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/numru/gphys/grads_gridded.rb', line 298

def create(ctlfilename,noclobber=false,share=false)
  #if(noclobber)
  #  raise "noclobber = true is not supported."
  #end
  if(share)
    raise "share = true is not supported."
  end
  #if (File.exists?(ctlfilename))
  if(noclobber && File.exists?(ctlfilename))
    print "#{ctlfilename} already exists.\n"
    print "overwrite #{ctlfilename} (y/n)? "
    ans = gets[0].chr
    if ans != "y"
      raise "#{ctlfilename} already exists."
    end
  end

#      GrADS_Gridded.new(ctlfilename, "w+")
  GrADS_Gridded.new(ctlfilename, "w")
end

Instance Method Details

#att_namesObject



471
472
473
474
# File 'lib/numru/gphys/grads_gridded.rb', line 471

def att_names
  ary = ["dset","title","undef"]
  ary
end

#closeObject



375
376
377
# File 'lib/numru/gphys/grads_gridded.rb', line 375

def close
  @ctlfile.close
end

#ctlfilenameObject

obsolete



733
734
735
# File 'lib/numru/gphys/grads_gridded.rb', line 733

def ctlfilename # obsolete
  @ctlfile.path
end

#def_var(name = "noname", nlev = 0, option = "99", description = "") ⇒ Object



415
416
417
418
# File 'lib/numru/gphys/grads_gridded.rb', line 415

def def_var(name="noname",nlev=0,option="99",description="")
  @variables.push({:name=>name.to_s, :nlev=>nlev.to_s,
                   :option=>option.to_s, :description=>description.to_s})
end

#dim_namesObject

def fill=

def each_dim
def each_var
def each_att


459
460
461
462
463
# File 'lib/numru/gphys/grads_gridded.rb', line 459

def dim_names
  ary = Array.new()
  @dimensions.each{|dim| ary.push(dim[:name])}
  ary
end

#get(name, z, t, lonlat = nil, ens = nil) ⇒ Object



550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
# File 'lib/numru/gphys/grads_gridded.rb', line 550

def get(name, z, t, lonlat=nil, ens=nil)

# t:    [0,1,2,..] : record number
# time: [0,1/24,2/24,...] days since 00:00Z01jan2000 : Numeric with units
# date: [00:00Z01jan2000,01:00Z01jan2000,...] : DateTime class

  if ( @options["template"] )

    ary_time = get_dim(@dimensions[3])
    start_date = @dimensions[3][:startdatetime]

    if @options["365_day_calendar"] == true
      calendar = "365_day" 
    else
      calendar = nil
    end
    units = Units["#{dimensions[3][:increment_units]} since #{start_date.strftime('%Y-%m-%d %H:%M:%S')}"]
    target_date = (UNumeric[ary_time[t],units.to_s]).to_datetime(0.1,calendar)

    # substitute DSET by the target file name
    # and determine first record in the target file (="init_xxxx")

    init_year = start_date.year
    init_month = start_date.month
    init_day = start_date.day
    init_hour = start_date.hour
    init_min = start_date.min

    @dset_r = @dset.dup
    if ( @dset_r =~ /%y[24]/ )
      init_year = target_date.year
      init_month = 1  if !( @dset_r =~ /%m[12]/ )
      init_day = 1    if !( @dset_r =~ /%d[12]/ )
      init_hour = 0   if !( @dset_r =~ /%h[12]/ )
      init_min = 0 if !( @dset_r =~ /%n2/ )
      @dset_r.gsub!( /%y2/, sprintf("%02d",init_year%100) )
      @dset_r.gsub!( /%y4/, sprintf("%04d",init_year) )
    end
    if ( @dset_r =~ /%m[12]/ )
      init_month = target_date.month
      init_day = 1    if !( @dset_r =~ /%d[12]/ )
      init_hour = 0   if !( @dset_r =~ /%h[12]/ )
      init_min = 0 if !( @dset_r =~ /%n2/ )
      @dset_r.gsub!( /%m1/, sprintf("%d",init_month) )
      @dset_r.gsub!( /%m2/, sprintf("%02d",init_month) )
    end
    if ( @dset_r =~ /%d[12]/ )
      init_day = target_date.day
      init_hour = 0   if !( @dset_r =~ /%h[12]/ )
      init_min = 0 if !( @dset_r =~ /%n2/ )
      @dset_r.gsub!( /%d1/, sprintf("%d",init_day) )
      @dset_r.gsub!( /%d2/, sprintf("%02d",init_day) )
    end
    if ( @dset_r =~ /%h[12]/ )
      init_hour = target_date.hour
      init_min = 0 if !( @dset_r =~ /%n2/ )
      @dset_r.gsub!( /%h1/, sprintf("%d",init_hour) )
      @dset_r.gsub!( /%h2/, sprintf("%02d",init_hour) )
    end
    if ( @dset_r =~ /%n2/ )
      init_min = target_date.min
      @dset_r.gsub!( /%n2/, sprintf("%02d",init_min) )
    end
    if ( ens && @dset_r =~ /%e(\d+)/ )
      @dset_r.gsub!( /%e(\d+)/, sprintf("%0#{$1}d",ens) )
    end

    # find t in the first record in the target file (="init_t")
    # and determine the record number in the target file

    init_date = DateTime.new(init_year,init_month,init_day,init_hour,init_min)
    init_time = UNumeric.from_date(init_date,units,calendar).val

    init_t = t
    while init_t > 0
      time = ary_time[init_t-1]
      break if time < init_time
      init_t = init_t - 1
    end

    t_in_target_file = t - init_t

    start_byte = start_byte(name, z, t_in_target_file, 0)
    @datafile = File.open(@dset_r,"rb")
  else
    start_byte = start_byte(name, z, t, ens)
    @datafile = File.open(@dset,"rb")
  end

  @x_len = @dimensions[0][:len]
  @y_len = @dimensions[1][:len]

  if(lonlat)
    if !(lonlat.is_a?(Array) || lonlat.is_a?(NArray))
      raise "lonlat must be given Array or NArray"
    end
    lon_str = lonlat[0]
    lon_end = lonlat[1]
    lat_str = lonlat[2]
    lat_end = lonlat[3]
    
    if( @map[name][:xytranspose] )
      @datafile.pos = start_byte + @y_len*lon_str*@map[name][:byte]
      readdata = @datafile.read(@y_len*(lon_end-lon_str+1)*@map[name][:byte])

      if( readdata == nil )
        raise "File Read Error: #{@datafile.path}, " +
          "#{@x_len*(lat_end-lat_str+1)*@map[name][:byte]} bytes " +
          "at #{@datafile.pos} bytes\n" +
          "specified by #{@ctlfile.path}, #{name} ( z=#{z}, t=#{t} ) (Perhaps there is a mismatch between the control and data files)"
      end

      ary = NArray.to_na(readdata, @map[name][:type], @y_len, lon_end-lon_str+1)

      ary = convert_endian_read(ary)
      ary = ary[lat_str..lat_end,true].transpose
    else
      @datafile.pos = start_byte + @x_len*lat_str*@map[name][:byte]
      readdata = @datafile.read(@x_len*(lat_end-lat_str+1)*@map[name][:byte])

      if( readdata == nil )
        raise "File Read Error: #{@datafile.path}, " +
          "#{@x_len*(lat_end-lat_str+1)*@map[name][:byte]} bytes " +
          "at #{@datafile.pos} bytes\n" +
          "specified by #{@ctlfile.path}, #{name} ( z=#{z}, t=#{t} ) (Perhaps there is a mismatch between the control and data files)"
      end

      ary = NArray.to_na(readdata, @map[name][:type], @x_len, lat_end-lat_str+1)

      ary = convert_endian_read(ary)
      ary = ary[lon_str..lon_end,true]
    end
  else
    @datafile.pos = start_byte
    readdata = @datafile.read(@x_len*@y_len*@map[name][:byte])

    if( readdata == nil )
      raise "File Read Error: #{@datafile.path}, " +
        "#{@x_len*(lat_end-lat_str+1)*@map[name][:byte]} bytes " +
        "at #{@datafile.pos} bytes\n" +
        "specified by #{@ctlfile.path}, #{name} ( z=#{z}, t=#{t} ) (Perhaps there is a mismatch between the control and data files)"
    end

    ary = NArray.to_na(readdata, @map[name][:type], @dimensions[0][:len],@dimensions[1][:len])

    ary = convert_endian_read(ary)
    ary = ary.transpose if ( @map[name][:xytranspose] )
  end

  @datafile.close
  ary
end

#get_alldimObject



724
725
726
727
728
729
730
731
# File 'lib/numru/gphys/grads_gridded.rb', line 724

def get_alldim 
  ax = Hash.new
  @dimensions.each{|dim|
    name = dim[:name]
    ax[name] = get_dim(dim)
  }
  return ax
end

#get_att(key = nil) ⇒ Object

def att



436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
# File 'lib/numru/gphys/grads_gridded.rb', line 436

def get_att( key=nil )
  case(key)
  when("dset")
    att = @dset
  when("title")
    att = @title
  when "undef"
    att = @undef
  else
    if (@options.has_key?(key))
      att = @options[key]
    else
      raise "Invalid/unsupported option: "+key
    end
  end
  att
end

#get_dim(dim) ⇒ Object



706
707
708
709
710
711
712
713
714
715
716
717
718
# File 'lib/numru/gphys/grads_gridded.rb', line 706

def get_dim(dim)
  name = dim[:name]
    if (dim[:levels])
      var_dim = NArray.to_na(dim[:levels])
    elsif (dim[:start] && dim[:increment] && dim[:len])
      var_dim = NArray.float(dim[:len]).indgen!*dim[:increment]+dim[:start]
    else
      raise "cannot define dimension "+name
    end
    var_dim = var_dim[-1..0] if (name == 'y' && @options["yrev"])
    var_dim = var_dim[-1..0] if (name == 'z' && @options["zrev"])
  return var_dim
end

#inspectObject



508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
# File 'lib/numru/gphys/grads_gridded.rb', line 508

def inspect
  str = <<EOS
#{self.class}
file: #{@ctlfile.path}
DSET #{@dset}
OPTIONS #{@options.inspect}
XDIM #{@dimensions[0].inspect}
YDIM #{@dimensions[1].inspect}
ZDIM #{@dimensions[2].inspect}
TDIM #{@dimensions[3].inspect}
EOS
  if ( @options["edef"] )
    str += <<EOS
EDEF #{@dimensions[4].inspect}
EOS
  end
  str += <<EOS
VARS
#{@variables.collect{|i| "  "+i[:name]+"\t"+i[:nlev].to_s+"\t"+i[:option].to_s+
     "\t"+i[:description]}.join("\n")}
ENDVARS
EOS
  return str
end

#nattsObject



391
392
393
# File 'lib/numru/gphys/grads_gridded.rb', line 391

def natts
  2
end

#ndimsObject



383
384
385
# File 'lib/numru/gphys/grads_gridded.rb', line 383

def ndims
  @options["edef"] ? 5 : 4
end

#nvarsObject



387
388
389
# File 'lib/numru/gphys/grads_gridded.rb', line 387

def nvars
  @variables.length
end

#pathObject



379
380
381
# File 'lib/numru/gphys/grads_gridded.rb', line 379

def path
  @ctlfile.path
end

#put(ary) ⇒ Object



533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
# File 'lib/numru/gphys/grads_gridded.rb', line 533

def put(ary)

  if( ary.class == NArrayMiss )
    raise "UNDEF is not specified" if @undef == nil
    ary = ary.to_na(@undef)
  end

  ary = convert_endian_write(ary)

  raise "DSET is not  specified" if @dset == nil

  putfile = File.open(@dset,"wb")
  putfile << ary.to_s
  putfile.close

end

#put_att(key, value) ⇒ Object



395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'lib/numru/gphys/grads_gridded.rb', line 395

def put_att(key,value)
  case key
  when "dset"
    @dset = value
  when "title"
    @title = value
  when "undef"
    @undef = value
  else
    if ! (value.is_a?(TrueClass) || value.is_a?(NilClass) )
      raise ArgumentError, "2nd arg: not a true nor nil" 
    end
    if (@options.has_key?(key))
      @options[key] = value
    else
      raise "Invalid/unsupported option: "+key
    end
  end
end

#to_ctlObject



476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
# File 'lib/numru/gphys/grads_gridded.rb', line 476

def to_ctl
  if( !@dimensions[3][:spec] ) 
    start = generate_starttime(@dimensions[3][:startdatetime])
    increment = generate_timeincrement(@dimensions[3][:increment],@dimensions[3][:increment_units])
    @dimensions[3][:spec] = "#{start} #{increment}"
  end
  @title = "<no title>" if @title==""
  @undef = -999.0 if @undef==nil
  ctl = <<EOS
DSET    #{if @dset[0]=="/" then @dset else "^"+@dset end}
TITLE   #{@title}
UNDEF   #{@undef}
OPTIONS #{op=""; @options.each{|key,val| op += key+" " if(val)}; op}
XDEF    #{@dimensions[0][:len]} #{@dimensions[0][:flag]} #{@dimensions[0][:spec]}
YDEF    #{@dimensions[1][:len]} #{@dimensions[1][:flag]} #{@dimensions[1][:spec]}
ZDEF    #{@dimensions[2][:len]} #{@dimensions[2][:flag]} #{@dimensions[2][:spec]}
TDEF    #{@dimensions[3][:len]} #{@dimensions[3][:flag]} #{@dimensions[3][:spec]}
EOS
  if ( @options["edef"] )
  ctl += <<EOS
EDEF    #{@dimensions[4][:len]} #{@dimensions[4][:flag]} #{@dimensions[4][:spec]}
EOS
  end
  ctl += <<EOS
VARS    #{nvars}
#{@variables.collect{|i| i[:name]+" "+i[:nlev].to_s+" "+i[:option].to_s+
     " "+i[:description]}.join("\n")}
ENDVARS
EOS
  return ctl
end

#var(varname = nil) ⇒ Object



420
421
422
# File 'lib/numru/gphys/grads_gridded.rb', line 420

def var( varname=nil )
  GrADSVar.new(self,varname)
end

#var_namesObject



465
466
467
468
469
# File 'lib/numru/gphys/grads_gridded.rb', line 465

def var_names
  ary = Array.new()
  @variables.each{|dim| ary.push(dim[:name])}
  ary
end

#varnamesObject



720
721
722
# File 'lib/numru/gphys/grads_gridded.rb', line 720

def varnames
  @variables.collect{|i| i[:name]}
end

#vars(names = nil) ⇒ Object

return all if names==nil

Raises:

  • (TypeError)


424
425
426
427
428
429
430
431
432
433
# File 'lib/numru/gphys/grads_gridded.rb', line 424

def vars( names=nil )   # return all if names==nil
#    if names == nil
#      vars = (0..nvars()-1).collect{ |varid| id2var(varid) }
#    else
    raise TypeError, "names is not an array" if ! names.is_a?(Array)
    vars = names.collect{|name| var(name)}
    raise ArgumentError, "One or more variables do not exist" if vars.include?(nil)
#    end
  vars
end