############################################################

=begin
=method for class NumRu::GPhys and  NumRu::GphysFunc in libgphys-n.rb

==Index
* ((<class NumRu::NArray (methods added)>))
  * ((<cshift(n)>))
    $BMWAGA4BN$r(B n $B8D$:$i$7$?(B NArray $B%*%V%8%'%/%H$rJV$9(B.

* ((<class NumRu::GPhys (methods added)>))
  * ((<enhanced_strm_function(vname)>))
    $BFnKLIw$N%G!<%?$+$i<ANLN.@~4X?t$r7W;;(B. $BMQ$$$?<0$O(B...
    daily $B%G!<%?$7$+07$($J$$(B.
  * ((<strm_function_ncep(vname)>))
    $BFnKLIw$N%G!<%?$+$i<ANLN.@~4X?t$r7W;;(B. $BMQ$$$?<0$O(B...
    $B;~4VJ?6Q$r$H$C$?(B NCEP $B%G!<%?$7$+07$($J$$(B. ($B05NO<4$N8~$-$,(B NCEP $B8GM-(B.)
  * ((<theta(vname)>))
    $B29EY$+$i290L$r7W;;(B.
  * ((<p_bar(vname)>))
    $B290L$+$iEy290LLL$K1h$C$?05NO$NJ?6Q$r7W;;(B.
  * ((<cd_dp(v, k, dp)>))
    $B0l3,HyJ,$r7W;;(B. $BCf1{:9J,(B.
  * ((<fd_dp(v, k, dp)>))
    $B0l3,HyJ,$r7W;;(B. $BA0J}:9J,(B.
  * ((<bd_dp(v, k, dp)>))
    $B0l3,HyJ,$r7W;;(B. $B8eJ}:9J,(B.
  * ((<ape(vname)>))
    $B290L$+$iM-8z0LCV%(%M%k%.!<$r7W;;(B.    
  * ((<stspct_fft(vname)>))
    $B;~6u4V%9%Z%/%H%k$r7W;;(B.
  * ((<stspct_coh(vname)>))
    P-R $B%3%R!<%l%s%9$r7W;;(B.
  * ((<stspct_st_tr(vname)>))
    $B;~6u4V%9%Z%/%H%k$N$&$A(B, $BDj:_@.J,(B(standing wave) $B$H(B $B0\F0@.J,(B(traveling wave) $B$r7W;;(B.
  * ((<make_sfc_mask(p_gphys)>))
    $B0z?t$KM?$($?COI=LL05NO$N(B gphys $B%*%V%8%'%/%H$+$i(B,self $B$N(Bgphys $B%*%V%8%'%/%H$HF1$8G[Ns9=B$$r$b$D(B, 3 $B<!85$N%^%9%/(B gphys $B%*%V%8%'%/%H$r:n@.$9$k(B.
    $B<B:]$OCOLL2<$J$N$K(B, $B30Au$7$F$"$kItJ,$rGS=|$9$k$?$a$N%^%9%/$r:n@.(B.
  * ((<save(output, global_attr=nil, vname=nil, var_attr=nil, history=$history, new_vname=nil)>))
    GPhys $B%*%V%8%'%/%H$r(B netCDF $B%U%!%$%k$KJ]B8(B.
  * ((<add_lost_axes( lost )>))
    $B%G!<%?(B, $B:BI8<4A`:n5-O?$r$$$8$k(B
  * ((<set_lost_axes( lost )>))
    $B%G!<%?(B, $B:BI8<4A`:n5-O?$r$$$8$k(B
  * ((<rename(name)>))
    ((<rename(name)>)) $B$r(B gphys_class $B$rJV$9$h$&:FDj5A(B
  * ((<set_att(name,val)>))
    ((<set_att>)) $B$r(B gphys_class $B$rJV$9$h$&:FDj5A(B

* other meshod
  * ((<global_attr(nc_file)>))
    * nc_file $B$G;XDj$7$?(B netCDF $B%U%!%$%k$NBg0hB0@-$rJV$9(B
  * ((<mean_gphys>))
    * $B0z?t$K;XDj$7$?(B gphys $B%*%V%8%'%/%H72$NJ?6Q$r$H$k(B
  * ((<ask_overwrite>))
    * netCDF $B%U%!%$%k$K>e=q$-J]B8$7$F$h$$$+3NG'(B
=end
require "numru/ggraph"
require "numru/netcdf_miss"
require "date"
include NumRu

class NArray # NArray $B$X$NDI2C%a%=%C%I(B
  def cshift(n) # Fortran90 $B$N(B cshift$B$NBe$o$j(B
    #if(n > x.size) ...
    y = self.dup
    y[n..-1] = self[0..-1-n]
    y[0..n-1] = self[-n..-1]
    return y
  end
end

class NArray # for deep_copy
  def self._load(o); to_na(*Marshal::load(o)).ntoh; end
  def _dump(limit); Marshal::dump([hton.to_s, typecode, *shape]); end
end

=begin
module NumRu
  class NetCDFVar
     def get_with_miss_and_scaling2(*args) # make mask before scaling
      __interpret_missing_params if !defined?(@missval)
      packed_data = simple_get(*args)
      scaled_data = scaled_get(*args)
      sf = att('scale_factor')
      ao = att('add_offset')
      if @vmin || @vmax
	if sf && ao
	  csf = sf.get
	  cao = ao.get
	  vmin = (@vmin-cao)/csf if @vmin
	  vmax = (@vmax-cao)/csf if @vmax
	elsif
	  vmin = @vmin; vmax = @vmax
	end
	if vmin
	  mask = (packed_data >= vmin) 
	mask = mask.and(packed_data <= vmax) if vmax
	else
	  mask = (packed_data <= vmax)
	end
	data = NArrayMiss.to_nam(scaled_data, mask)
      elsif @missval	# only missing_value is present.
	eps = 1e-6
	missval = @missval[0].to_f
	vmin = missval - eps*missval
	vmax = missval + eps*missval
	mask = (packed_data <= vmin) 
	mask = mask.or(packed_data >= vmax)
	data = NArrayMiss.to_nam(scaled_data, mask)
      else
	data = scaled_data
      end
      data
    end

    def put_with_miss_after_scaling(data, *args)
      if data.is_a?( NArrayMiss )
	__interpret_missing_params if !defined?(@missval)
	if @missval
	  scaled_put_without_missval(data, *args)
	else
	  scaled_put(data.to_na, *args)
	end
      else
	scaled_put(data, *args)
      end
    end

    def scaled_put_without_missval(var,hash=nil)
      sf = att('scale_factor')
      ao = att('add_offset')
      if ( sf == nil && ao == nil ) then
	# no scaling --> just call put
	simple_put(var,hash)
      else
	if (sf != nil) 
	  csf = sf.get
	  if csf.is_a?(NArray) then  # --> should be a numeric
	    csf = csf[0]
	  elsif csf.is_a?(String)
	    raise TypeError, "scale_factor is not a numeric"
	  end
	  if(csf == 0) then; raise NetcdfError, "zero scale_factor"; end
	else
	  csf = 1.0      # assume 1 if not defined
	end
	if (ao != nil) 
	  cao = ao.get
	if cao.is_a?(NArray) then  # --> should be a numeric
	  cao = cao[0]
	elsif csf.is_a?(String)
	  raise NetcdfError, "add_offset is not a numeric"
	end
	else
	  cao = 0.0      # assume 0 if not defined
	end
	var = var.to_na( @missval[0]*csf + cao)
	simple_put( (var-cao)/csf, hash )
      end
    end  
  end
end
=end


#------------------------------------------------------------------------------#


class GPhys
  # gtstrm $B%a%=%C%I(B GPhys $B$KDI2C(B
  def strm_function_ncep_with_time(vname="strm")

  end

  # gtstrm $BMQ2<@A$1%a%=%C%I(B

#------------------------------------------------------------------------------#


  # gtstrm $B%a%=%C%I(B GPhys $B$KDI2C(B
  def strm_function_ncep(vname="strm")
    grid = self.grid
    
    lat = grid.axis(0).pos.val              # [90.0, 87.5, ... , -87.5, -90.0]
    ps  = grid.axis(1).pos.val*100          # [100000,  ... , 2000, 1000] milibar => N/m^2
    va_data = self.data
    strm = va_data.val.dup.fill!(0.0)
    mask = va_data.val.get_mask if va_data.val.is_a?(NArrayMiss)
    miss = self.data.get_att("missing_value")[0] if self.data.get_att("missing_value")

    axs = grid.shape[0]
    ays = grid.shape[1]

    pi = NMath::PI
    g  = UNumeric.new(9.81, "m.s-2")
    r  = UNumeric.new(6.37E6,"m") # radius of the planet6.370e6
    cos = Misc::EMath::cos(lat*pi*2.0/360.0)

    keisuu = 2*pi*r*cos/g

    # $BBf7A8x<0$K$h$k@QJ,(B
    (ays-1).downto(0){|j|
      if j == (ays-1) then
	strm[*([true] + [j, false])] = 0.5*(va_data.val[*([true] + [j, false])]+0)*ps[ays-1]
      else
	dp = (ps[j] - ps[j+1])
	strm[*([true] + [j, false])] = 0.5*(va_data.val[*([true] + [j, false])]+va_data.val[*([true] + [j+1, false])])*dp + strm[*([true] + [j+1, false])]
      end
    }
    strm = GPhys.new(grid, VArray.new(strm, va_data, vname)*keisuu)
    strm.units = "kg.s-1"
    strm.set_att("long_name", "Zonal mean mass stream function")
    strm.del_att("title")
    strm.del_att("var_desc")

    return strm
  end

#------------------------------------------------------------------------------#

  # gttheta $B%a%=%C%I(B GPhys $B$KDI2C(B
  def theta(vname)
    grid = self.grid
    
    lon = grid.axis(0).pos.val  # [0.0, 2.5, ... , -359.5, -360.0]
    lat = grid.axis(1).pos.val  # [90.0, 87.5, ... , -87.5, -90.0]
    ps  = grid.axis(2).pos.val  # [10, 20, ... , 1000]
    data = self.data.val        

    axs = grid.shape[0]
    ays = grid.shape[1]
    azs = grid.shape[2]

    # $B290L(B theta $B$N=i4|2=(B
#    theta = NArray.float(axs, ays, azs).fill!(0.0)
    theta = NArray.float(axs, ays, azs).fill!(0.0)

=begin
    # theta
    0.upto(axs-1) {|i|
      0.upto(ays-1){|j|
	0.upto(azs-1){|k|
	  t = data[i, j, k]
	  theta[i, j, k] = t*(1000.0/ps[k])**0.288
	}
      }
    }
=end

    # theta
    0.upto(azs-1){|k|
      t = data[true, true, k]
      theta[true, true, k] = t*(1000.0/ps[k])**0.288
    }

    gttheta = GPhys.new(grid, VArray.new(theta).rename(vname))
    return gttheta
  end

#------------------------------------------------------------------------------#

  def bvfreq(vname) # $B%V%i%s%H%P%$%5%i?6F0?t(B
   
    g = 9.8

    grid = self.grid
    
    lon = grid.axis(0).pos.val  # [0.0, 2.5, ... , -359.5, -360.0]
    lat = grid.axis(1).pos.val  # [90.0, 87.5, ... , -87.5, -90.0]
    ps  = grid.axis(2).pos.val  # [10, 20, ... , 1000]
    data = self.data.val        

    axs = grid.shape[0]
    ays = grid.shape[1]
    azs = grid.shape[2]

    bvfreq = NArray.float(axs, ays, azs).fill!(0.0)


    # brunt-vaisala
    0.upto(azs-1){|k|
    theta = data[true, true, k]
      if k == 0 then
	 bvfreq[true, true, k] = g/theta*(-data[true, true, k+1]+data[true, true, k])/(ps[k+1]-ps[k])
      elsif k == (azs-1) then
	 bvfreq[true, true, k] = g/theta*(-data[true, true, k]+data[true, true, k-1])/(ps[k]-ps[k-1])
      else
	 bvfreq[true, true, k] = g/theta*(-data[true, true, k+1]+data[true, true, k-1])/(ps[k+1]-ps[k-1])
      end
    }
    gtbrunt = GPhys.new(grid, VArray.new(bvfreq).rename(vname))
    return gtbrunt
  end

#------------------------------------------------------------------------------#

  # p_mean $B%a%=%C%I(B GPhys $B$KDI2C(B
  def p_bar(vname)
    theta_bar = self.mean(0, 1).data.val
    grid = self.grid
    
    lon = grid.axis(0).pos.val  # [0.0, 2.5, ... , -359.5, -360.0]
    lat = grid.axis(1).pos.val  # [90.0, 87.5, ... , -87.5, -90.0]
    ps  = grid.axis(2).pos.val  # [10, 20, ... , 1000]
    data = self.data.val        

    axs = grid.shape[0]
    ays = grid.shape[1]
    azs = grid.shape[2]

    # p_bar $B$N=i4|2=(B
    p_bar = NArray.float(axs, ays, azs).fill!(0.0)

    # p_bar
    0.upto(axs-1) {|i|
      0.upto(ays-1){|j|
	theta = data[i, j, true]
	0.upto(azs-1){|k|
	  if k == 0 then
	    p_bar[i, j, k] = 1.0 - ((ps[k] - (theta[k] - theta_bar[k])/(fd_dp(theta, k, ps[k+1]-ps[k])))/ps[k])
	  elsif k == (azs-1) then
	    p_bar[i, j, k] = 1.0 - ((ps[k] - (theta[k] - theta_bar[k])/(bd_dp(theta, k, ps[k]-ps[k-1])))/ps[k])
	  else
	    p_bar[i, j, k] = 1.0 - ((ps[k] - (theta[k] - theta_bar[k])/(cd_dp(theta, k, ps[k+1]-ps[k-1])))/ps[k])
	  end
	}
      }
    }

    gtpbar = GPhys.new(grid, VArray.new(p_bar).rename(vname))
    return gtpbar
  end

#------------------------------------------------------------------------------#

  def cd_dp(v, k, dp) # center 
    (v[k+1] - v[k-1])/(dp)
  end

#------------------------------------------------------------------------------#

  def fd_dp(v, k, dp) # forward
    (v[k+1] - v[k])/(dp) 
  end

#------------------------------------------------------------------------------#

  def bd_dp(v, k, dp) # backward
    (v[k] - v[k-1])/(dp) 
  end

#------------------------------------------------------------------------------#

  def ape(vname)
    grid = self.grid
    
    kappa = 0.288

    lon = grid.axis(0).pos.val  # [0.0, 2.5, ... , -359.5, -360.0]
    lat = grid.axis(1).pos.val  # [90.0, 87.5, ... , -87.5, -90.0]
    ps  = grid.axis(2).pos.val  # [10, 20, ... , 1000]
    date= grid.axis(3).pos.val  # [10, 20, ... , 1000]
    time  = grid.axis(4).pos.val  # [10, 20, ... , 1000]
    theta = self.data.val        

    axs = grid.shape[0]
    ays = grid.shape[1]
    azs = grid.shape[2]

    # theta $B$NJ?6QCM$r(B 3 $B<!85$K3HD%(B
    theta_bar1 = self.mean(0, 1).data.val
    theta_bar = NArray.float(axs, ays, azs).fill!(0.0)
    for i in 0..axs-1
      for j in 0..ays-1
	theta_bar[i, j, true] = theta_bar1
      end
    end

    # ps $B$r(B 3 $B<!85$K3HD%(B
    psn = NArray.sint(axs, ays, azs).fill!(0)
    for i in 0..axs-1
      for j in 0..ays-1
	psn[i, j, true] = ps
      end
    end

    # ape
    ape = theta_bar**2*psn**(kappa-1)*((theta-theta_bar)/theta_bar)**2

    gtape = GPhys.new(grid, VArray.new(ape).rename(vname))
    ngtape = gtape.integrate(0)
    ngtape = ngtape.integrate(0)
    ngtape = ngtape.integrate(0)
    return ngtape
  end

#------------------------------------------------------------------------------#

  def stspct_fft(vname)
  #------------------------------------------------------
  # $B=`Hw(B                                                 
  
    # $B%0%j%C%I>pJs<hF@(B   
    grid = self.grid    
    space = grid.axis(0).pos.val  # $B6u4V%0%j%C%I(B
    time  = grid.axis(1).pos.val  # $B;~4V%0%j%C%I(B
    axs = grid.shape[0] # $B6u4VJ}8~$N%G!<%??t(B
    ays = grid.shape[1] # $B;~4VJ}8~$N%G!<%??t(B

  #------------------------------------------------------
  # $B%9%Z%/%H%k7W;;(B

    # $BJ#AG6u4V%U!<%j%(78?t(B f_k(t) $B$r7W;;(B
    w = self.data.val                         # $B85%G!<%?(B w(x,t)
    f_k = NArray.complex(axs, ays).fill!(0.0)  # f_k $B$NH"$rMQ0U(B
    for i in 0..(axs-1)
      f_k[i,true] = FFTW.fftw(w[i, true], 1)/(ays/2)
    end

    # f_k(t) $B$N<BIt(B c_k, $B5uIt(B s_k $B$r<hF@(B
    c_k = f_k.real
    s_k = f_k.imag

    # c_k,s_k $B$N%Q%o!<%9%Z%/%H%k(B pc, ps $B$r5a$a$k(B.
    pwc = NArray.complex(axs, ays).fill!(0.0)  # P_w(c) $B$NH"$rMQ0U(B
    pws = NArray.complex(axs, ays).fill!(0.0)  # P_w(s) $B$NH"$rMQ0U(B
    for i in 0..(ays-1)
      pwc[true,i] = FFTW.fftw(c_k[true, i], 1)/(axs/2) # forward FT
      pws[true,i] = FFTW.fftw(s_k[true, i], 1)/(axs/2) # forward FT
    end

    pc = (pwc).abs**2/2.0
    ps = (pws).abs**2/2.0


    # $B%/%"%I%i%A%c!<%9%Z%/%H%k$r5a$a$k(B.
    qcs = (pwc.conj*pws).imag/2.0

    # $B%Q%o!<%9%Z%/%H%k(B    
    p_ww = (pc + ps - 2*qcs)/4.0     # $B@>?JGH$N%Q%o!<%9%Z%/%H%k(B
    p_we = (pc + ps + 2*qcs)/4.0     # $BEl?JGH$N%Q%o!<%9%Z%/%H%k(B
    p_ww = p_ww[-1..0, true]         # $BId9f$r5U8~$-$K(B

  #------------------------------------------------------
  # $B<4$N@_Dj(B

    if ays/2 == 0
      nays = (ays+1)/2
    else
      nays = ays/2
    end
    if axs/2 == 0
      naxs = (axs+1)/2
    else
      naxs = axs/2
    end

    axs = 2*naxs - 1

    stspct = NArray.float(axs, nays)
    stspct[0..naxs-2, true] = p_ww[(naxs)..-2, 0..(nays-1)]
    stspct[naxs-1, true] = p_ww[-1, 0..(nays-1)] + p_we[0, 0..(nays-1)] # $BGH?t(B 0
    stspct[naxs..-1, true] = p_we[1..naxs-1, 0..(nays-1)]
    stspct[true, 0] = 0 # $BGH?t(B 0, $B<~GH?t(B 0
    stspct[0, true] = 0 # $BGH?t(B 0, $B<~GH?t(B 0
    data = VArray.new(stspct).rename(vname)

    # $B<4$N@8@.(B
    aks = VArray.new(NArray.sfloat(axs).indgen!(0)-(naxs-1)).rename("wvn")
    aws = VArray.new(NArray.sfloat(nays).indgen!(0)/ays).rename("freq")

    xax = Axis.new().set_pos(aks)
    yax = Axis.new(true).set_cell_guess_bounds(aws).set_pos_to_center

    grid = Grid.new(xax, yax)

    # GPhys $B%*%V%8%'%/%H$r@8@.(B
    gtspw = GPhys.new(grid, data)
  
    gtspw.coord(0).set_att('units', '1')
    gtspw.coord(1).set_att('units', '1/DAY')
   
    return gtspw
  end

#------------------------------------------------------------------------------#

  def stspct_coh(vname)
    # $B%0%j%C%I>pJs<hF@(B   
    grid = self.grid    
    space = grid.axis(0).pos.val  # $B6u4V%0%j%C%I(B
    time  = grid.axis(1).pos.val  # $B;~4V%0%j%C%I(B
    axs = grid.shape[0] # $B6u4VJ}8~$N%G!<%??t(B
    ays = grid.shape[1] # $B;~4VJ}8~$N%G!<%??t(B

    # $BJ#AG6u4V%U!<%j%(78?t(B f_k(t) $B$r7W;;(B
    w = self.data.val                         # $B85%G!<%?(B w(x,t)
    f_k = NArray.complex(axs, ays).fill!(0.0)  # f_k $B$NH"$rMQ0U(B
    for i in 0..(axs-1)
      f_k[i,true] = FFTW.fftw(w[i, true], 1)/(ays/2)
    end

    # f_k(t) $B$N<BIt(B c_k, $B5uIt(B s_k $B$r<hF@(B
    c_k = f_k.real
    s_k = f_k.imag

    # c_k,s_k $B$N%Q%o!<%9%Z%/%H%k(B pc, ps $B$r5a$a$k(B.
    pwc = NArray.complex(axs, ays).fill!(0.0)  # P_w(c) $B$NH"$rMQ0U(B
    pws = NArray.complex(axs, ays).fill!(0.0)  # P_w(s) $B$NH"$rMQ0U(B
    for i in 0..(ays-1)
      pwc[true,i] = FFTW.fftw(c_k[true, i], 1)/(axs/2) # forward FT
      pws[true,i] = FFTW.fftw(s_k[true, i], 1)/(axs/2) # forward FT
    end

    pc = (pwc).abs**2/2.0            # C_k $B$N%Q%o!<%9%Z%/%H%k(B
    ps = (pws).abs**2/2.0            # S_k $B$N%Q%o!<%9%Z%/%H%k(B

    qcs = (pwc.conj*pws).imag/2.0    # $B%/%"%I%i%A%c!<%9%Z%/%H%k(B
    kcs = (pwc.conj*pws).real/2.0    # $B%3%9%Z%/%H%k(B

    # $B%Q%o!<%9%Z%/%H%k(B    
    p_ww = (pc + ps - 2*qcs)/4.0     # $B@>?JGH$N%Q%o!<%9%Z%/%H%k(B
    p_we = (pc + ps + 2*qcs)/4.0     # $BEl?JGH$N%Q%o!<%9%Z%/%H%k(B
    p_ww = p_ww[-1..0, true]         # $BId9f5U8~$-(B

    # P-R $B%3%R!<%l%s%9(B
    coh_cs = (kcs**2 + qcs**2)/pc/ps # C_k, C_s $B$N%3%R!<%l%s%9(B
    coh_pr = NMath::sqrt(1-(1-coh_cs**2)/4*pc*ps/p_ww/p_we)
                                     # P-R $B%3%R!<%l%s%9(B


    # $B0J2<(B, $B6u4V<4$,6v?t$N>l9g$H4q?t$N>l9g$GJ,$1$J$1$l$P$J$i$J$$(B.

    if ays/2 == 0
      nays = (ays+1)/2
    else
      nays = ays/2
    end
    if axs/2 == 0
      naxs = (axs+1)/2
    else
      naxs = axs/2
    end

    axs = 2*naxs - 1

    stspct = NArray.float(axs, nays)
    stspct[0..naxs-2, true] = p_ww[(naxs)..-2, 0..(nays-1)]
    stspct[naxs-1, true] = p_ww[-1, 0..(nays-1)] + p_we[0, 0..(nays-1)] # $BGH?t(B 0
    stspct[naxs..-1, true] = p_we[1..naxs-1, 0..(nays-1)]
    stspct[true, 0] = 0 # $BGH?t(B 0, $B<~GH?t(B 0
    stspct[0, true] = 0 # $BGH?t(B 0, $B<~GH?t(B 0
    data = VArray.new(stspct).rename(vname)

    # $B<4$N@8@.(B
    aks = VArray.new(NArray.sfloat(axs).indgen!(0)-(naxs-1)).rename("wvn")
    aws = VArray.new(NArray.sfloat(nays).indgen!(0)/ays).rename("freq")

    xax = Axis.new().set_pos(aks)
    yax = Axis.new(true).set_cell_guess_bounds(aws).set_pos_to_center

    grid = Grid.new(xax, yax)

    # GPhys $B%*%V%8%'%/%H$r@8@.(B
    gtspw = GPhys.new(grid, data)
    p gtspw.max
    return gtspw
  end

#------------------------------------------------------------------------------#

  def stspct_st_tr(vname)
    #!!$BCm0U(B !!#
    # $B>e5-$NE@$K4X$7$F=$@5$9$Y$7(B.

    # $B%0%j%C%I>pJs<hF@(B   
    grid = self.grid    
    space = grid.axis(0).pos.val  # $B6u4V%0%j%C%I(B
    time  = grid.axis(1).pos.val  # $B;~4V%0%j%C%I(B
    axs = grid.shape[0] # $B6u4VJ}8~$N%G!<%??t(B
    ays = grid.shape[1] # $B;~4VJ}8~$N%G!<%??t(B

    # $BJ#AG6u4V%U!<%j%(78?t(B f_k(t) $B$r7W;;(B
    w = self.data.val                         # $B85%G!<%?(B w(x,t)
    f_k = NArray.complex(axs, ays).fill!(0.0)  # f_k $B$NH"$rMQ0U(B
    for i in 0..(axs-1)
      f_k[i,true] = FFTW.fftw(w[i, true], 1)/(ays/2)
    end

    # f_k(t) $B$N<BIt(B c_k, $B5uIt(B s_k $B$r<hF@(B
    c_k = f_k.real
    s_k = f_k.imag

p c_k.abs.max
p s_k.abs.max
   
    # c_k,s_k $B$N%Q%o!<%9%Z%/%H%k(B pc, ps $B$r5a$a$k(B.
    pwc = NArray.complex(axs, ays).fill!(0.0)  # P_w(c) $B$NH"$rMQ0U(B
    pws = NArray.complex(axs, ays).fill!(0.0)  # P_w(s) $B$NH"$rMQ0U(B
    for i in 0..(ays-1)
      pwc[true,i] = FFTW.fftw(c_k[true, i], 1)/(axs/2) # forward FT
      pws[true,i] = FFTW.fftw(s_k[true, i], 1)/(axs/2) # forward FT
    end

    pc = (pwc).abs**2/2.0
    ps = (pws).abs**2/2.0

    qcs = (pwc.conj*pws).imag/2.0    # $B%/%"%I%i%A%c!<%9%Z%/%H%k(B
    kcs = (pwc.conj*pws).real/2.0    # $B%3%9%Z%/%H%k(B

    # $B%Q%o!<%9%Z%/%H%k(B    
    p_ww = (pc + ps - 2*qcs)/4.0     # $B@>?JGH$N%Q%o!<%9%Z%/%H%k(B
    p_we = (pc + ps + 2*qcs)/4.0     # $BEl?JGH$N%Q%o!<%9%Z%/%H%k(B

    # $BDj:_GH(B, $B0\F0GH$N%Q%o!<%9%Z%/%H%k(B
    var = ((pc-ps)**2)/4 + kcs**2
    p_st = NMath::sqrt(var)          # $BDj:_GH$N%Q%o!<%9%Z%/%H%k(B
    p_tr = (p_ww + p_we) - p_st      # $B0\F0GH$N%Q%o!<%9%Z%/%H%k(B
    p_tr = p_tr[-1..0, true]

    # $B0J2<(B, $B6u4V<4$,6v?t$N>l9g$H4q?t$N>l9g$GJ,$1$J$1$l$P$J$i$J$$(B.

    if ays/2 == 0
      nays = (ays+1)/2
    else
      nays = ays/2
    end
    if axs/2 == 0
      naxs = (axs+1)/2
    else
      naxs = axs/2
    end

    axs = 2*naxs - 1

    stspct = NArray.float(axs, nays)
    stspct[0..naxs-2, true] = p_tr[(naxs)..-2, 0..(nays-1)]
    stspct[naxs-1, true] = p_tr[-1, 0..(nays-1)] + p_st[0, 0..(nays-1)] # $BGH?t(B 0
    stspct[naxs..-1, true] = p_st[1..naxs-1, 0..(nays-1)]
    stspct[true, 0] = 0 # $BGH?t(B 0, $B<~GH?t(B 0
    stspct[0, true] = 0 # $BGH?t(B 0, $B<~GH?t(B 0
    data = VArray.new(stspct).rename(vname)

    # $B<4$N@8@.(B
    aks = VArray.new(NArray.sfloat(axs).indgen!(0)-(naxs-1)).rename("wvn")
    aws = VArray.new(NArray.sfloat(nays).indgen!(0)/ays).rename("freq")

    xax = Axis.new().set_pos(aks)
    yax = Axis.new(true).set_cell_guess_bounds(aws).set_pos_to_center

    grid = Grid.new(xax, yax)

    # GPhys $B%*%V%8%'%/%H$r@8@.(B
    gtspw = GPhys.new(grid, data)
    p gtspw.max
    return gtspw
  end

#------------------------------------------------------------------------------#

  def make_sfc_mask(p_gphys)

    raise ArgumentError,"Self GPhys rank must have dimentions, longitude, latitude, time ." if ! p_gphys.is_a?(GPhys) 
    raise ArgumentError,"Arg is not GPhys." if ! p_gphys.is_a?(GPhys) 
    raise ArgumentError,"Arg's dimention is not 2nd order" if ! p_gphys.rank==2

    missval = 6.0e24 # missing_value

    p_data = p_gphys.data.val
    data = self.data.val.dup
    grid = self.grid

    ps  = grid.axis(2).pos.val  # pressure
    axs = grid.shape[0]
    ays = grid.shape[1]
    azs = grid.shape[2]

    if self.rank == 3
      0.upto(azs-1) do |z|
	data[true,true,z] = ps[z]
	data[true,true,z] = (data[true,true,z].ge p_data)
      end
    else
      0.upto(azs-1) do |z|
	data[true,true,z,true] = ps[z]
	data[true,true,z,true] = (data[true,true,z,true].ge p_data/100)
      end
    end
    mask = data*missval
    gtmask = GPhys.new(grid, VArray.new(mask,
					{"long_name"=>"surface mask", 
					  "missing_value"=>missval, 
					  "valid_max"=>1.0e24, 
					  "valid_min"=>-6.0e36},
					"sfc_mask")
		       )
    return gtmask
  end

#------------------------------------------------------------------------------#

  # gphys $B%*%V%8%'%/%H$r(B nc $B%U%!%$%k$KJ]B8$9$k%a%=%C%I(B
  def save(output, global_attr=nil, vname=nil, var_attr=nil, history=$history, new_vname=nil)

    if !vname
      vname = self.data.name
    end

    if File.exist?(output)
      nc = NetCDF.open(output, 'a+')
    else
      nc = NetCDF.open(output, 'w')
    end
    GPhys::IO.write(nc, self)
    nc.close

    nc = NetCDF.open(output, "a+")
    nc.redef                      # define mode $B$K0\9T(B

    # $BBg0hB0@-IU2C(B
    global_attr.to_a.each {|attr| 
      nc.put_att(attr[0], attr[1]) if attr[1]
    } if global_attr
    # $BJQ?tL>JQ99(B
    if new_vname && vname
      nc.var(vname).name=new_vname 
      vname = new_vname
    end
    # $BJQ?tB0@-IU2C(B
    if var_attr
      var_attr.to_a.each {|attr|
	nc.var(vname).put_att(attr[0], attr[1])
      }   
    end  
    # history $BIU2C(B
    now_hist = global_attr["history"]
    if now_hist then
      hist = now_hist + "\n" + history
      nc.put_att("history", hist)
    else
      nc.put_att("history", history)
    end

    nc.close

    return "saved as #{output}"

  end

  # $B:BI8(B, $B%G!<%?A`:n%m%05-O?4X?t$NDj5A(B (Grid.lost_axes $B;2>H(B.) <$B$d$^$@M3$5$s$N%k!<%A%s$rGR<Z(B>
  def add_lost_axes( lost )
    GPhys.new( @grid.copy.add_lost_axes( lost.to_a ), @data)
  end
  def set_lost_axes( lost )
    GPhys.new( @grid.copy.set_lost_axes( lost.to_a ), @data)
  end

  # rename $B:FDj5A(B (gphys class $B$rJV$9(B)
  def rename(name)
    GPhys.new(@grid,@data.copy.rename(name))
  end

  # attribute $B:FDj5A(B (gphys class $BJV$9(B)
  def set_att(name,val)
    GPhys.new(@grid,@data.copy.set_att(name,val))
  end

end

def global_attr(ncfile)
  global_attr = Hash.new

  nc = NetCDF.open(ncfile, "r")
  nc.att_names.each do |attr| 
    global_attr[attr] = nc.att(attr).get
  end
  return global_attr
end



# $BF1$8<!859=B$$r$b$DJ#?t$N(B nc $B%U%!%$%k$r;XDj$7$?:]$K(B
# $BJ?6Q$7$?%*%V%8%'%/%H$rJV$9%a%=%C%I(B
# $B%U%!%$%kL>$K(B 1990-10 $B$N$h$&$JJ8;z$,F~$C$F$?>l9g(B, 
# $B7nJ?6Q%G!<%?$r85$K5(@aJ?6Q$r7W;;(B. ($BF|$K$A$N=E$_$r9MN8(B)
def mean_gphys(file, var)

  gphys_file = Array.new()
  dateary =    Array.new()
  
  leap_year =      [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
  non_leap_year  = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] 

  file.each_index{|i|
    temp = GPhys::NetCDF_IO.open(file[i], var)
    ym = file[i].scan(/(\d\d\d\d)-(\d\d)/)
    if ym[0]
      year = ym[0][0].to_i
      month = ym[0][-1].to_i
      leap_flag = Date::new(year).leap?
      if leap_flag
	date = leap_year[month - 1]
      else
	date = non_leap_year[month - 1]
      end
      gphys_file << temp*date
      dateary << date
    else
      temp = GPhys::NetCDF_IO.open(f, var)
      gphys_file << temp
    end
  }

  sum = gphys_file[0]

  1.upto(gphys_file.size-1) {|f|
    sum += gphys_file[f] 
  }

  if dateary
    p sumdate = NArray.to_na(dateary).sum.to_f
    gphys = sum/sumdate
  else
    p gphys = sum/file.size.to_f
  end
  return gphys
end

#  $B5l(B mean_gphys $BB-$7$??t$GJ?3j$9$k$@$1(B.
#
#def mean_gphys(file, var)
#
#  gphys_file = Array.new()
#
#  file.each {|f|
#  
#    temp = GPhys::NetCDF_IO.open(f, var)
#    gphys_file << temp
#
#  }
#
#  sum = gphys_file[0]#
#
#  1.upto(gphys_file.size-1) {|f|
#    sum += gphys_file[f] 
#  }
#
#  p gphys = sum/file.size.to_f
#  return gphys
#end

def ask_overwrite(output)
  
  if File.exist?(output) then
    
    print "\n"
    print %Q{the file name "#{output}" is already exists current directory.\n}
    print "Do you sure over write? (y/n)    "

    loop{
      flag = STDIN.gets.chomp

      if flag == "y" then
	break
      elsif flag == "n" then
	p "Bye."
	exit
      else
	print "please answer yes or no. (y/n)     "
      end

    }
    
  end
end

