add wrf sub-package

This commit is contained in:
wyq 2022-07-27 15:43:19 +08:00
parent e26a83feff
commit 2438d06065
16 changed files with 429 additions and 22 deletions

View File

@ -1,32 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<MeteoInfo File="milconfig.xml" Type="configurefile">
<Path OpenPath="D:\Working\MIScript\Jython\mis\meteo\interpolation">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\LaSW"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo\wrf"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\chart"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\chart\axis"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\common_math\stats"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\common_math"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\array"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/>
<Path OpenPath="D:\Working\MIScript\Jython\mis\traj\TrajStat">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\taylor"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\text"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\volume"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo\interpolation"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\satellite"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\grads"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\satellite\himawari"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\LaSW"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo\wrf"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo\calc"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\traj"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\traj\TrajStat"/>
</Path>
<File>
<OpenedFiles>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\volume\volumeplot_perspective.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\volume\volumeplot_perspective_2.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\meteo\interpolation\log_interpolate_1d_1.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\LaSW\typhoon_map_slice.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\traj\TrajStat\plot_pscf_3d.py"/>
</OpenedFiles>
<RecentFiles>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\volume\volumeplot_perspective.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\volume\volumeplot_perspective_2.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\meteo\interpolation\log_interpolate_1d_1.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\LaSW\typhoon_map_slice.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\traj\TrajStat\plot_pscf_3d.py"/>
</RecentFiles>
</File>
<Font>
@ -34,5 +34,5 @@
</Font>
<LookFeel DockWindowDecorated="true" LafDecorated="true" Name="FlatDarkLaf"/>
<Figure DoubleBuffering="true"/>
<Startup MainFormLocation="-7,0" MainFormSize="1417,799"/>
<Startup MainFormLocation="-7,0" MainFormSize="1344,736"/>
</MeteoInfo>

View File

View File

@ -119,13 +119,15 @@ class DimDataFile(object):
return None
v = np.array(attr.getValues())
return v
@property
def variables(self):
"""
Get all variables.
"""
return self._variables
@property
def varnames(self):
"""
Get all variable names.

View File

@ -30,7 +30,7 @@ def __getimage(src):
elif isinstance(src, Graphic):
return src.getShape().getImage()
elif isinstance(src, MILayer):
return src.layer.getImage()
return src._layer.getImage()
elif isinstance(src, NDArray):
return ImageUtil.createImage(src.asarray())
return None
@ -40,7 +40,7 @@ def __getreturn(src, dst):
src.getShape().setImage(dst)
return src
elif isinstance(src, MILayer):
src.layer.setImage(dst)
src._layer.setImage(dst)
return src
elif isinstance(src, NDArray):
r = ImageUtil.imageRead(dst)

View File

@ -1,5 +1,5 @@
from .meteo import *
from . import wrf
from .wrf import *
from . import constants
from .calc import *
from .interpolate import *

View File

@ -0,0 +1,11 @@
from destag import *
from g_slp import *
from g_rh import *
from g_pressure import *
from g_geoht import *
__all__ = destag.__all__
__all__ += g_slp.__all__
__all__ += g_rh.__all__
__all__ += g_pressure.__all__
__all__ += g_geoht.__all__

View File

@ -0,0 +1,42 @@
__all__ = ['destagger']
def destagger(var, stagger_dim):
"""
Return the variable data array on the unstaggered grid.
This function destaggers the variable by taking the average of the
values located on either side of the grid box.
:param var: (*array*) A variable on a staggered grid.
:param stagger_dim: (*int*) The dimension index to destagger.
Negative values can be used to choose dimensions referenced
from the right hand side (-1 is the rightmost dimension).
:returns: (*array*) The destaggered variable data array.
"""
var_shape = var.shape
num_dims = var.ndim
stagger_dim_size = var_shape[stagger_dim]
# Dynamically building the range slices to create the appropriate
# number of ':'s in the array accessor lists.
# For example, for a 3D array, the calculation would be
# result = .5 * (var[:,:,0:stagger_dim_size-2]
# + var[:,:,1:stagger_dim_size-1])
# for stagger_dim=2. So, full slices would be used for dims 0 and 1, but
# dim 2 needs the special slice.
full_slice = slice(None)
slice1 = slice(0, stagger_dim_size - 1, 1)
slice2 = slice(1, stagger_dim_size, 1)
# default to full slices
dim_ranges_1 = [full_slice] * num_dims
dim_ranges_2 = [full_slice] * num_dims
# for the stagger dim, insert the appropriate slice range
dim_ranges_1[stagger_dim] = slice1
dim_ranges_2[stagger_dim] = slice2
result = .5*(var[tuple(dim_ranges_1)] + var[tuple(dim_ranges_2)])
return result

View File

@ -0,0 +1,209 @@
from util import either
from destag import destagger
from .. import constants
import warnings
__all__ = ['get_geopt', 'get_stag_geopt', 'get_height', 'get_stag_height', 'get_height_agl']
def _get_geoht(wrfin, timeidx, height=True, msl=True, stag=False):
"""Return the geopotential or geopotential height.
If *height* is False, then geopotential is returned in units of
[m2 s-2]. If *height* is True, then geopotential height is
returned in units of [m]. If *msl* is True, then geopotential height
is return as Mean Sea Level (MSL). If *msl* is False, then geopotential
height is returned as Above Ground Level (AGL).
This functions extracts the necessary variables from the NetCDF file
object in order to perform the calculation.
Args:
wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \
iterable): WRF-ARW NetCDF
data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile`
or an iterable sequence of the aforementioned types.
timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The
desired time index. This value can be a positive integer,
negative integer, or
:data:`wrf.ALL_TIMES` (an alias for None) to return
all times in the file or sequence. The default is 0.
height (:obj:`bool`, optional): Set to True to return geopotential
height instead of geopotential. Default is True.
msl (:obj:`bool`, optional): Set to True to return geopotential height
as Mean Sea Level (MSL). Set to False to return the
geopotential height as Above Ground Level (AGL) by subtracting
the terrain height. Default is True.
stag (:obj:`bool`, optional): Set to True to use the vertical
staggered grid, rather than the mass grid. Default is False.
Returns:
:class:`DimArray`
"""
varname = either("PH", "GHT")(wrfin)
if varname == "PH":
ph = wrfin["PH"][timeidx]
phb = wrfin["PHB"][timeidx]
hgt = wrfin["HGT"][timeidx]
geopt = ph + phb
if not stag:
geopt_unstag = destagger(geopt, -3)
else:
geopt_unstag = geopt
else:
geopt_unstag = wrfin["GHT"][timeidx] * constants.g
hgt = wrfin["HGT_M"][timeidx]
if stag:
warnings.warn("file contains no vertically staggered geopotential "
"height variable, returning unstaggered result "
"instead")
if height:
if msl:
return geopt_unstag / constants.g
else:
# Due to broadcasting with multifile/multitime, the 2D terrain
# array needs to be reshaped to a 3D array so the right dims
# line up
new_dims = list(hgt.shape)
new_dims.insert(-2, 1)
hgt = hgt.reshape(new_dims)
return (geopt_unstag / constants.g) - hgt
else:
return geopt_unstag
def get_geopt(wrfin, timeidx=0):
"""Return the geopotential.
The geopotential is returned in units of [m2 s-2].
This functions extracts the necessary variables from the NetCDF file
object in order to perform the calculation.
Args:
wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \
iterable): WRF-ARW NetCDF
data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile`
or an iterable sequence of the aforementioned types.
timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The
desired time index. This value can be a positive integer,
negative integer, or
:data:`wrf.ALL_TIMES` (an alias for None) to return
all times in the file or sequence. The default is 0.
Returns:
:class:`DimArray`
"""
return _get_geoht(wrfin, timeidx, False, True)
def get_height(wrfin, timeidx=0, msl=True):
"""Return the geopotential height.
If *msl* is True, then geopotential height is returned as Mean Sea Level
(MSL). If *msl* is False, then geopotential height is returned as
Above Ground Level (AGL) by subtracting the terrain height.
This functions extracts the necessary variables from the NetCDF file
object in order to perform the calculation.
Args:
wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \
iterable): WRF-ARW NetCDF
data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile`
or an iterable sequence of the aforementioned types.
timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The
desired time index. This value can be a positive integer,
negative integer, or
:data:`wrf.ALL_TIMES` (an alias for None) to return
all times in the file or sequence. The default is 0.
msl (:obj:`bool`, optional): Set to True to return geopotential height
as Mean Sea Level (MSL). Set to False to return the
geopotential height as Above Ground Level (AGL) by subtracting
the terrain height. Default is True.
Returns:
:class:`DimArray` or :class:`numpy.ndarray`: The
geopotential height (m).
"""
return _get_geoht(wrfin, timeidx, True, msl)
def get_stag_geopt(wrfin, timeidx=0):
"""Return the geopotential for the vertically staggered grid.
The geopotential is returned in units of [m2 s-2].
This functions extracts the necessary variables from the NetCDF file
object in order to perform the calculation.
Args:
wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \
iterable): WRF-ARW NetCDF
data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile`
or an iterable sequence of the aforementioned types.
timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The
desired time index. This value can be a positive integer,
negative integer, or
:data:`wrf.ALL_TIMES` (an alias for None) to return
all times in the file or sequence. The default is 0.
Returns:
:class:`DimArray` or :class:`numpy.ndarray`: The
geopotential (m).
"""
return _get_geoht(wrfin, timeidx, False, True, stag=True)
def get_stag_height(wrfin, timeidx=0, msl=True):
"""Return the geopotential height for the vertically staggered grid.
If *msl* is True, then geopotential height is returned as Mean Sea Level
(MSL). If *msl* is False, then geopotential height is returned as
Above Ground Level (AGL) by subtracting the terrain height.
This functions extracts the necessary variables from the NetCDF file
object in order to perform the calculation.
Args:
wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \
iterable): WRF-ARW NetCDF
data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile`
or an iterable sequence of the aforementioned types.
timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The
desired time index. This value can be a positive integer,
negative integer, or
:data:`wrf.ALL_TIMES` (an alias for None) to return
all times in the file or sequence. The default is 0.
msl (:obj:`bool`, optional): Set to True to return geopotential height
as Mean Sea Level (MSL). Set to False to return the
geopotential height as Above Ground Level (AGL) by subtracting
the terrain height. Default is True.
Returns:
:class:`DimArray` or :class:`numpy.ndarray`: The
geopotential height (m).
"""
return _get_geoht(wrfin, timeidx, True, msl, stag=True)
def get_height_agl(wrfin, timeidx=0):
"""Return the geopotential height (AGL).
The geopotential height is returned as Above Ground Level (AGL) by
subtracting the terrain height.
This functions extracts the necessary variables from the NetCDF file
object in order to perform the calculation.
Args:
wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \
iterable): WRF-ARW NetCDF
data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile`
or an iterable sequence of the aforementioned types.
timeidx (:obj:`int` or :data:`wrf.ALL_TIMES`, optional): The
desired time index. This value can be a positive integer,
negative integer, or
:data:`wrf.ALL_TIMES` (an alias for None) to return
all times in the file or sequence. The default is 0.
Returns:
:class:`DimArray` or :class:`numpy.ndarray`: The
geopotential height (m).
"""
return _get_geoht(wrfin, timeidx, True, False)

View File

@ -0,0 +1,19 @@
__all__ = ['get_pressure']
def get_pressure(wrfin, timeidx=0):
"""
Return the pressure in the specified units.
This function extracts the necessary variables from the NetCDF file
object in order to perform the calculation.
:param wrfin: (*DimDataFile*) Data file.
:param timeidx: (*int*) Time index.
:returns: (*array*) Pressure (hPa).
"""
p = wrfin['P'][timeidx]
pb = wrfin['PB'][timeidx]
pres = (p + pb) * 0.01
return pres

View File

@ -0,0 +1,48 @@
from .. import constants
from ..calc.thermo import relative_humidity_from_specific_humidity, temperature_from_potential_temperature
__all__ = ['get_rh', 'get_rh2m']
def get_rh(wrfin, timeidx=0):
"""
Return the relative humidity.
This functions extracts the necessary variables from the NetCDF file
object in order to perform the calculation.
:param wrfin: (*DimDataFile*) Data file.
:param timeidx: (*int*) Time index.
:returns: (*array*) Relative humidity.
"""
t = wrfin['T'][timeidx,:,:,:]
p = wrfin['P'][timeidx,:,:,:]
pb = wrfin['PB'][timeidx,:,:,:]
qvapor = wrfin['QVAPOR'][timeidx,:,:,:]
full_t = t + constants.T_BASE
full_p = p + pb
qvapor[qvapor < 0] = 0.
tk = temperature_from_potential_temperature(full_p * 0.01, full_t)
rh = relative_humidity_from_specific_humidity(full_p * 0.01, tk, qvapor)
return rh
def get_rh2m(wrfin, timeidx=0):
"""
Return the 2m relative humidity.
This functions extracts the necessary variables from the NetCDF file
object in order to perform the calculation.
:param wrfin: (*DimDataFile*) Data file.
:param timeidx: (*int*) Time index.
:returns: (*array*) Relative humidity.
"""
t2 = wrfin['T2'][timeidx,:,:]
psfc = wrfin['PSFC'][timeidx,:,:]
q2 = wrfin['Q2'][timeidx,:,:]
q2[q2 < 0] = 0.
rh = relative_humidity_from_specific_humidity(psfc * 0.01, t2, q2)
return rh

View File

@ -0,0 +1,37 @@
from org.meteoinfo.math.meteo import MeteoMath
from mipylib.numeric.core import DimArray
from .. import constants
from ..calc.thermo import temperature_from_potential_temperature
from destag import destagger
__all__ = ['get_slp']
def get_slp(wrfin, timeidx=0, units='hPa'):
"""
Return the sea level pressure in the specified units.
This function extracts the necessary variables from the NetCDF file
object in order to perform the calculation.
:param wrfin: (*DimDataFile*) Data file.
:param timeidx: (*int*) Time index.
:param units: (*string*) The desired units.
:returns: (*array*) Sea level pressure.
"""
t = wrfin['T'][timeidx,:,:,:]
p = wrfin['P'][timeidx,:,:,:]
pb = wrfin['PB'][timeidx,:,:,:]
qvapor = wrfin['QVAPOR'][timeidx,:,:,:]
ph = wrfin['PH'][timeidx,:,:,:]
phb = wrfin['PHB'][timeidx,:,:,:]
full_t = t + constants.T_BASE
full_p = p + pb
qvapor[qvapor < 0] = 0.
full_ph = (ph + phb) / constants.g
destag_ph = destagger(full_ph, -3)
tk = temperature_from_potential_temperature(full_p * 0.01, full_t)
slp = MeteoMath.calSeaPrs(destag_ph._array, tk._array, full_p._array, qvapor._array)
return DimArray(slp, dims=t.dims[1:])

View File

@ -0,0 +1,39 @@
# Helper utilities for metadata
class either(object):
"""A callable class that determines which variable is present in the
file.
This is used in situations where the same variable type has different names
depending on the type of file used. For example, in a WRF output file,
'P' is used for pressure, whereas in a met_em file, pressure is named
'PRES'.
Methods:
__call__(wrfin): Return the variable that is present in the file.
Args:
wrfin (:class:`netCDF4.Dataset`, :class:`Nio.NioFile`, or an \
iterable): WRF-ARW NetCDF
data as a :class:`netCDF4.Dataset`, :class:`Nio.NioFile`
or an iterable sequence of the aforementioned types.
Returns:
:obj:`str`: The variable name that is present in the file.
Attributes:
varnames (sequence): A sequence of possible variable names.
"""
def __init__(self, *varnames):
"""Initialize an :class:`either` object.
Args:
*varnames (sequence): A sequence of possible variable names.
"""
self.varnames = varnames
def __call__(self, wrfin):
for varname in self.varnames:
if varname in wrfin.varnames:
return varname
raise ValueError("{} are not valid variable names".format(
self.varnames))

View File

@ -8,7 +8,7 @@
from org.meteoinfo.math.meteo import MeteoMath
from mipylib.numeric.core import NDArray, DimArray
import constants as constants
from .calc.thermo import relative_humidity_from_specific_humidity, temperature_from_potential_temperature
from pylib.mipylib.meteolib.calc.thermo import relative_humidity_from_specific_humidity, temperature_from_potential_temperature
__all__ = [
'destagger','get_slp','get_rh','get_rh2m'