#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
=begin

鉛直 sigma 座標系のファイルを鉛直 p 座標系に変換する.
dcpam の出力したファイル
(lon, lat, sig, time 軸を持つ)
を入力することが前提.

= Usage

Sample:

  $ gpconv_sig2p \
      --var Temp.nc@Temp,time=1:2 \
      --ps Ps.nc@Ps,time=1:2 \
      --psave 1000 -o output.nc

* --var:        変換する変数 (gturl 形式)
* --ps:         地表面気圧 (gturl 形式)
* --psave:      平均地表面気圧 [hPa]. デフォルトは 1000
* -o, --output: 出力ファイル名. デフォルトは gphys.nc
* --input_ps_hpa:  平均値表面気圧の単位が hPa の場合のフラグ (デフォルトは off)

= 参考

* 補間，座標変換
  * http://ruby.gfd-dennou.org/products/gphys/Recipes/recipes_j/interpolation/index.htm

= ToDo

* lat_weight のコピー
* sig でなく sigm の値を使用するスイッチの実装 (SigmaDot など向け)
* SigmaDot の DPDt, w への変換
* 巨大ファイルへの対応
  * 将来的に必要があれば time でループを回すことを検討.
* p 軸に任意の値を指定できるようにする
  * 1000, 850, 500 hPa などを切り出すなど
* 補外の実装
* 軸の cut に対応 (現状では time=1 のような切り出しができない. time=1:1 で回避可能とは思われる)

= History

* 2014/02/18 Satoshi NODA   Created

=end

require "numru/gphys"
require "optparse"
include NumRu

DCL::gllset('LMISS', true)   # 欠損値を扱う
rmiss = 1e+10
DCL::glrset('RMISS', rmiss)

# default values
psave = 1000   # hPa
input_ps_hpa = false
gturl_ps  = ""
gturl_var = ""
output = "gphys.nc"

# parse commandline options
opt = OptionParser.new

opt.on('--psave VAL') {|v| psave = v.to_f}
opt.on('--input_ps_hpa') {|v| input_ps_hpa = true}
opt.on('--var VAL') {|v| gturl_var = v.to_s}
opt.on('--ps VAL') {|v| gturl_ps = v.to_s}
opt.on('-o VAL', '--output VAL') {|v| output = v.to_s}

opt.parse!(ARGV)

# check
if ARGV.size > 0
  raise "ERROR: invalid option: #{ARGV[0]}"
end

gp_var = GPhys::IO.open_gturl(gturl_var)
gp_ps  = GPhys::IO.open_gturl(gturl_ps)

# 座標系の作成
lon  = gp_var.axis("lon")
lat  = gp_var.axis("lat")
time = gp_var.axis("time")
nlon  = lon.pos.val.size
nlat  = lat.pos.val.size
ntime = time.pos.val.size

sig = gp_var.axis("sig")
na_sig = sig.pos.val
nz = na_sig.size

p na_p = na_sig * psave
va_p = VArray.new( na_p,
                   {"long_name"=>"pressure", "units"=>"hPa"},
                   "p" )
axis_p = Axis.new.set_pos(va_p)


### 座標変換

# 準備: 各格子点における気圧
na_data_p = gp_ps.val.reshape(nlon, nlat, 1, ntime) * na_sig.reshape(1, 1, nz, 1)
unless input_ps_hpa then
  na_data_p /= 100.0   # Pa -> hPa
end

data_p = VArray.new( na_data_p,
                     {"long_name"=>"pressure", "units"=>"hPa",
                       'missing_value'=>NArray[rmiss]},
                     "p" )
gp_p = GPhys.new( Grid.new(lon,lat,sig,time), data_p )

# 準備: 気圧を補助座標に指定
gp_var.set_assoc_coords([gp_p])

# 座標変換かつ補間
# interpolate メソッドの仕様により, 補外になる場所は欠損値になる.
gphys0 = gp_var.interpolate("sig"=>va_p)

# interpolate メソッドは, missing_value 属性を足してくれないようなので
# data に missing_value を含めるように作り直し
# attr だけ追加する方法はないものか?
data = VArray.new( gphys0.val,
                   {"long_name"=>gphys0.name, "units"=>gphys0.units.to_s,
                     'missing_value'=>NArray[rmiss]},
                   gphys0.name )
gphys = GPhys.new( Grid.new(lon,lat,axis_p,time), data)

# 出力
outfile = NetCDF.create(output)
GPhys::NetCDF_IO.write(outfile, gphys)
outfile.close

__END__

