NumRu::GAnalysis::MetZ

Meterological analysis regarding vertical section, integration, etc.

Public Instance Methods

mass_strm_any(v, ps, w, wcoord, vs=nil, ws=nil) click to toggle source

mass stream function on any vertical coordinate

Similar to mass_strm_p, but it supports representation to have an arbitrary physical quantity, such as potential temperature, as the vertical coordinate (instead of pressure).

Applicable both to pressure- and sigma-coordinate input data

ARGUMENTS

  • v [GPhys] : meridional wind with a vertical dimension (p or sigma) It must have a latitudinal dimension too. Longitudinal and time dimensions are optional. If it has a longitudinal dimension, zonal mean is taken. The order of the dimensions is not restricted.

  • ps [GPhys] : surface pressure. Its must have the same grid as v but for the vertical dimension (ps.rank must be v.rank-1)

  • w [GPhys] : Grid-point values (at the same points as v) of the quantity used to represent the vertical coordinate. Its shape must be the same as that of v, as a matter of course.

  • wcoord [1D VArray] : Output vertical coordinate. It must have the same units as w.

  • vs [nil(default) or GPhys]: vs is not needed (neglected) when v has a sigma coordinate. It is an optional parameter to specify the surface values of v, when it is in the pressure coordinate. vs can be omitted (nil), even when v has a pressure coordinate; in that case, vs is set by interpolating v if ps is within the p range of v (e.g. when ps<=1000hPa), or it is naively extended (using the bottom values of v) if ps is out of the range (e.g. when ps>1000hPa). In other words, the current implementation assumes that v is available below the surface, as is customary for reanalysis data.

  • ws [nil(default) or GPhys]: same as vs but for the surface value of w.

# File ../../lib/numru/ganalysis/met_z.rb, line 182
def mass_strm_any(v, ps, w, wcoord, vs=nil, ws=nil)

  pascal = Units["Pa"]
  grav = Met.g.to_f

  #< check >

  raise(ArgumentError,"v.shape != w.shape")  if v.shape != w.shape
  raise(ArgumentError,"ps.rank != v.rank-1")  if ps.rank != v.rank-1
  raise(ArgumentError,"w.units !~wcoord.units") if w.units !~ wcoord.units

  #< preprare data >

  if zdim = Met.find_prs_d(v)   # substitution, not comparison
    # has a pressure coordinate
    pcv = v.coord(zdim)   # v's p coord
    pcv_val = pcv.val
    v_val = v.val             # should be NArray or NArrayMiss
    v_val = v_val.to_na if v_val.is_a?(NArrayMiss)
    w_val = w.val             # should be NArray or NArrayMiss
    w_val = w_val.to_na if w_val.is_a?(NArrayMiss)
    if pcv_val[0] > pcv_val[-1]
      # reverse the p coordinate to the increasing order
      pcv_val = pcv_val[-1..0]
      v_val = v_val[ *([true]*zdim + [-1..0,false]) ]
      w_val = w_val[ *([true]*zdim + [-1..0,false]) ]
    end

    pcv_val = pcv.units.convert2(pcv_val, pascal) if pcv.units!=pascal
    pcv_over_g = pcv_val / grav

    ps_val = ps.val
    ps_val = ps_val.to_na if ps_val.is_a?(NArrayMiss)
    ps_val = ps.units.convert2(ps_val, pascal) if ps.units!=pascal
    ps_over_g = ps_val / grav

    vs_val = vs && vs.val   # nil (default) or vs.val (if vs is given)
    vs_val = vs_val.to_na if vs_val.is_a?(NArrayMiss)

    ws_val = ws && ws.val   # nil (default) or ws.val (if ws is given)
    ws_val = ws_val.to_na if ws_val.is_a?(NArrayMiss)

    v_val, p_over_g, nzbound = GPhys.c_cap_by_boundary(v_val, zdim, 
                                     pcv_over_g, true, ps_over_g, vs_val)

    w_val, p_over_g, nzbound = GPhys.c_cap_by_boundary(w_val, zdim, 
                                     pcv_over_g, true, ps_over_g, ws_val)

  elsif zdim = SigmaCoord.find_sigma_d(v)  # substitution, not comparison
    # has a sigma coordnate
    sig = v.coord(zdim)
    nz = sig.length
    nzbound = nil
    ps = ps.convert_units(pascal) if ps.units != pascal
    sig_val = sig.val
    v_val = v.val    # should be NArray, not NArrayMiss (coz sigma)
    w_val = w.val
    p_over_g = SigmaCoord.sig_ps2p(ps.val/grav, sig_val, zdim)
  else
    raise ArgumentError, "v does not have a p or sigma coordinate."
  end

  #< cumulative vertical integration >
 
  wc_val = wcoord.val
  if wc_val[0] > wc_val[-1]
    # change it to the increasing order
    wc_val = wc_val[-1..0]
    wcoord = wcoord.copy.replace_val(wc_val)
  end

  rho_v_cum = GPhys.c_cum_integ_irreg(v_val, p_over_g, zdim, nzbound,
                                   wc_val, w_val)

  #< zonal mean & latitudinal factor >

  lam, phi, lond, latd = Planet.get_lambda_phi(v, false)

  if latd.nil?
    raise(ArgumentError, "v appears not having a latitudinal dimension")
  end
  if lond
    rho_v_cum = rho_v_cum.mean(lond)
    latd -= 1 if lond<latd
  end

  a_cos = NMath.cos(phi.val) * ( 2 * Math::PI * Planet.radius.to_f )
  latd.times{a_cos.newdim!(0)}
  (rho_v_cum.rank - latd -1).times{a_cos.newdim!(-1)}

  mstrm_val = rho_v_cum * a_cos

  #< make a GPhys >

  axes = Array.new
  for d in 0...v.rank
    case d
    when lond
      # lost by zonal mean
    when zdim
      wax = Axis.new().set_pos(wcoord)
      axes.push(wax)
    else
      axes.push(v.axis(d).copy)   # kept
    end
  end
  grid = Grid.new( *axes )

  units = Units["kg.m-1"]    # p/g*a : Pa / (m.s-2) * m = kg.m-1
  units *= v.units
  mstrm_va = VArray.new(mstrm_val, {"long_name"=>"mass stream function",
                          "units"=>units.to_s}, "mstrm")
  mstrm = GPhys.new(grid, mstrm_va)
  mstrm
end
mass_strm_p(v, ps, pcoord=nil, vs=nil) click to toggle source

Derive the mass stream function in the pressure coordinate

Applicable both to pressure- and sigma-coordinate input data (the output is always on the pressure coordinate).

ARGUMENTS

  • v [GPhys] : meridional wind with a vertical dimension (p or sigma) It must have a latitudinal dimension too. Longitudinal and time dimensions are optional. If it has a longitudinal dimension, zonal mean is taken. The order of the dimensions is not restricted.

  • ps [GPhys] : surface pressure. Its must have the same grid as v but for the vertical dimension (ps.rank must be v.rank-1)

  • pcoord [1D VArray](optional) : output vertical coordinate (set if nil)

  • vs [nil(default) or GPhys]: vs is not needed (neglected) when v has a sigma coordinate. It is an optional parameter to specify the surface values of v, when it is in the pressure coordinate. vs can be omitted (nil), even when v has a pressure coordinate; in that case, vs is set by interpolating v if ps is within the p range of v (e.g. when ps<=1000hPa), or it is naively extended (using the bottom values of v) if ps is out of the range (e.g. when ps>1000hPa). In other words, the current implementation assumes that v is available below the surface, as is customary for reanalysis data.

# File ../../lib/numru/ganalysis/met_z.rb, line 36
def mass_strm_p(v, ps, pcoord=nil, vs=nil)

  pascal = Units["Pa"]
  grav = Met.g.to_f

  #< consolidate the p or sigma coordinate input >

  if zdim = Met.find_prs_d(v)   # substitution, not comparison
    # has a pressure coordinate
    pcv = v.coord(zdim) # pcv is v's p coord, not pcoord from outside.
                        # This is used only to feed c_cap_by_boundary.
    pcoord = pcv.copy if pcoord.nil?  # if not given from outside, use pcv

    pcv_val = pcv.val
    v_val = v.val             # should be NArray or NArrayMiss
    v_val = v_val.to_na if v_val.is_a?(NArrayMiss)
    if pcv_val[0] > pcv_val[-1]
      # reverse the p coordinate to the increasing order
      pcv_val = pcv_val[-1..0]
      v_val = v_val[ *([true]*zdim + [-1..0,false]) ]
    end

    pcv_val = pcv.units.convert2(pcv_val, pascal) if pcv.units!=pascal
    pcv_over_g = pcv_val / grav

    ps_val = ps.val
    ps_val = ps_val.to_na if ps_val.is_a?(NArrayMiss)
    ps_val = ps.units.convert2(ps_val, pascal) if ps.units!=pascal
    ps_over_g = ps_val / grav

    vs_val = vs && vs.val   # nil (default) or vs.val (if vs is given)
    vs_val = vs_val.to_na if vs_val.is_a?(NArrayMiss)

    v_val, p_over_g, nzbound = GPhys.c_cap_by_boundary(v_val, zdim, 
                                     pcv_over_g, true, ps_over_g, vs_val)

  elsif zdim = SigmaCoord.find_sigma_d(v)  # substitution, not comparison
    # has a sigma coordnate
    sig = v.coord(zdim)
    unless pcoord
      pcoord = sig * 1000
      pcoord.units = "hPa"
      pcoord.name = "p"
      pcoord.long_name = "pressure"
      pcoord.put_att("standard_name","air_pressure")
      pcoord.put_att("positive","down")
    end
    nz = sig.length
    nzbound = nil
    ps = ps.convert_units(pascal) if ps.units != pascal
    sig_val = sig.val
    v_val = v.val    # should be NArray, not NArrayMiss (coz sigma)
    p_over_g = SigmaCoord.sig_ps2p(ps.val/grav, sig_val, zdim)
  else
    raise ArgumentError, "v does not have a p or sigma coordinate."
  end
  
  #< cumulative vertical integration >
 
  pc_val = pcoord.val
  if pc_val[0] > pc_val[-1]
    # change it to the increasing order
    pc_val = pc_val[-1..0]
    pcoord = pcoord.copy.replace_val(pc_val)
  end
  pc_val = pcoord.units.convert2(pc_val,pascal)

  pc_over_g = pc_val / grav

  rho_v_cum = GPhys.c_cum_integ_irreg(v_val, p_over_g, zdim, nzbound,
                                   pc_over_g, nil)

  #< zonal mean & latitudinal factor >

  lam, phi, lond, latd = Planet.get_lambda_phi(v, false)

  if latd.nil?
    raise(ArgumentError, "v appears not having a latitudinal dimension")
  end
  if lond
    rho_v_cum = rho_v_cum.mean(lond)
    latd -= 1 if lond<latd
  end

  a_cos = NMath.cos(phi.val) * ( 2 * Math::PI * Planet.radius.to_f )
  latd.times{a_cos.newdim!(0)}
  (rho_v_cum.rank - latd -1).times{a_cos.newdim!(-1)}

  mstrm_val = rho_v_cum * a_cos

  #< make a GPhys >

  axes = Array.new
  for d in 0...v.rank
    case d
    when lond
      # lost by zonal mean
    when zdim
      pax = Axis.new().set_pos(pcoord)
      axes.push(pax)
    else
      axes.push(v.axis(d).copy)   # kept
    end
  end
  grid = Grid.new( *axes )

  units = Units["kg.m-1"]    # p/g*a : Pa / (m.s-2) * m = kg.m-1
  units *= v.units
  mstrm_va = VArray.new(mstrm_val, {"long_name"=>"mass stream function",
                          "units"=>units.to_s}, "mstrm")
  mstrm = GPhys.new(grid, mstrm_va)
  mstrm
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.