From e7defd7e398e5836bde1a015ed52c9c2e703ff42 Mon Sep 17 00:00:00 2001
From: Shenyulu <59901836+shenyulu@users.noreply.github.com>
Date: Fri, 8 Nov 2024 21:19:11 +0800
Subject: [PATCH] fix: rename file in the `field`
---
README.md | 2 +-
docs/source/api_index/index.rst | 9 +
src/easyclimate/field/__init__.py | 1 +
src/easyclimate/field/mesoscale/__init__.py | 1 +
.../field/mesoscale/potential_intensity.py | 315 ++++++++++++++++++
...st_field_air_sea_interaction_index_amm.py} | 0
...ir_sea_interaction_index_atlantic_nino.py} | 0
...t_field_air_sea_interaction_index_enso.py} | 0
...t_field_air_sea_interaction_index_iobm.py} | 0
...st_field_air_sea_interaction_index_iod.py} | 0
...est_field_mesoscale_potential_intensity.py | 228 +++++++++++++
11 files changed, 555 insertions(+), 1 deletion(-)
create mode 100644 src/easyclimate/field/mesoscale/__init__.py
create mode 100644 src/easyclimate/field/mesoscale/potential_intensity.py
rename test/{test_air_sea_interaction_index_amm.py => test_field_air_sea_interaction_index_amm.py} (100%)
rename test/{test_air_sea_interaction_index_atlantic_nino.py => test_field_air_sea_interaction_index_atlantic_nino.py} (100%)
rename test/{test_air_sea_interaction_index_enso.py => test_field_air_sea_interaction_index_enso.py} (100%)
rename test/{test_air_sea_interaction_index_iobm.py => test_field_air_sea_interaction_index_iobm.py} (100%)
rename test/{test_air_sea_interaction_index_iod.py => test_field_air_sea_interaction_index_iod.py} (100%)
create mode 100644 test/test_field_mesoscale_potential_intensity.py
diff --git a/README.md b/README.md
index 89968f66..65e08cbc 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-
+
A line of code to analyze climate
diff --git a/docs/source/api_index/index.rst b/docs/source/api_index/index.rst
index 729491c3..f9370a8d 100644
--- a/docs/source/api_index/index.rst
+++ b/docs/source/api_index/index.rst
@@ -127,3 +127,12 @@ Ocean
easyclimate.field.ocean.oceanic_front
easyclimate.field.ocean.stability
easyclimate.field.ocean.thermal
+
+Mesoscale
+::::::::::::::::::::::::::::::::::::::::
+
+.. autosummary::
+ :toctree: generated/
+
+ easyclimate.field.mesoscale
+ easyclimate.field.mesoscale.potential_intensity
diff --git a/src/easyclimate/field/__init__.py b/src/easyclimate/field/__init__.py
index b6f5ab27..57f741b7 100644
--- a/src/easyclimate/field/__init__.py
+++ b/src/easyclimate/field/__init__.py
@@ -3,3 +3,4 @@
from . import land
from . import monsoon
from . import ocean
+from . import mesoscale
diff --git a/src/easyclimate/field/mesoscale/__init__.py b/src/easyclimate/field/mesoscale/__init__.py
new file mode 100644
index 00000000..b92b3c0f
--- /dev/null
+++ b/src/easyclimate/field/mesoscale/__init__.py
@@ -0,0 +1 @@
+from .potential_intensity import *
diff --git a/src/easyclimate/field/mesoscale/potential_intensity.py b/src/easyclimate/field/mesoscale/potential_intensity.py
new file mode 100644
index 00000000..972f06b4
--- /dev/null
+++ b/src/easyclimate/field/mesoscale/potential_intensity.py
@@ -0,0 +1,315 @@
+"""
+Potential intensity of TC
+"""
+
+import xarray as xr
+from ...core.utility import (
+ transfer_data_difference_units,
+ transfer_data_multiple_units,
+)
+from ...core.diagnosis import transfer_specific_humidity_2_mixing_ratio
+from typing import Literal
+
+from tcpyPI import pi
+from tcpyPI.utilities import pi_efficiency, pi_diseq_resid, decompose_pi
+
+__all__ = [
+ "calc_potential_intensity_Bister_Emanuel_2002",
+]
+
+
+def calc_potential_intensity_Bister_Emanuel_2002(
+ sst_data: xr.DataArray,
+ sst_data_units: Literal["celsius", "kelvin", "fahrenheit"],
+ surface_pressure_data: xr.DataArray,
+ surface_pressure_data_units: Literal["hPa", "Pa", "mbar"],
+ temperature_data: xr.DataArray,
+ temperature_data_units: Literal["celsius", "kelvin", "fahrenheit"],
+ specific_humidity_data: xr.DataArray,
+ specific_humidity_data_units: str,
+ vertical_dim: str,
+ vertical_dim_units: str,
+ CKCD: float = 0.9,
+ ascent_flag: bool = False,
+ diss_flag: bool = True,
+ V_reduc: float = 0.8,
+ ptop: float = 50,
+ miss_handle: bool = True,
+) -> xr.Dataset:
+ """
+ Calculate potential intensity of TC (tropical cyclone) according to the Bister and Emanuel (2002) algorithm.
+
+ This function calculates the maximum wind speed and mimimum central pressure achievable
+ in tropical cyclones, given a sounding and a sea surface temperature.
+
+ From Bister and Emanuel (1998) EQN. 21, PI may be computed directly via:
+
+ .. math::
+
+ V_{max}^{2} = \\frac{C_k}{C_D}(\\frac{T_{s} - T_{0}}{T_{0}})(h_0^* - h^*),
+
+ where :math:`C_k` and :math:`C_D` are the enthalpy and momentum surface exchange coefficients,
+ respectively; :math:`T_{s}` is the sea surface temperature; :math:`T_{0}` is the mean outflow temperature;
+ :math:`h_0^*` is the saturation moist static energy at the sea surface;
+ and :math:`h^*` is the moist static energy of the free troposphere.
+ The ratio :math:`\\frac{C_k}{C_D}` is an uncertain quantity typically taken
+ to be a constant (default is 0.9, see Emanuel 2003 and references therein).
+
+ Building on this definition, one can extract TC efficiency
+ and disequilibrium, and decompose the terms to determine their relative contributions to potential intensity.
+
+ The efficiency of TC PI is the Carnot efficiency. Typical values range between 50-70% in the tropics.
+
+ Each term in the PI equation may decomposed by taking the natural logarithm of both sides, arriving at (Wing et al. 2015; EQN. 2):
+
+ .. math::
+ 2*\\log(V_{max}) = \\log(\\frac{C_k}{C_D}) + \\log(\\frac{T_{s} - T_{0}}{T_{0}}) + \\log(h_0^* - h^*).
+
+ Note that the units of everything input to the functions (and particularly the temperatures) must match.
+
+ Parameters
+ ----------
+ sst_data: :py:class:`xarray.DataArray`.
+ The sea surface temperature data.
+ sst_data_units: :py:class:`str `.
+ The unit corresponding to `sst_data` value. Optional values are `celsius`, `kelvin`, `fahrenheit`.
+ surface_pressure_data: :py:class:`xarray.DataArray`.
+ Mean surface sea level pressure.
+ surface_pressure_data_units: :py:class:`str `.
+ The unit corresponding to `surface_pressure_data` value. Optional values are `hPa`, `Pa`, `mbar`.
+ temperature_data: :py:class:`xarray.DataArray`.
+ Atmospheric temperature.
+ temperature_data_units: :py:class:`str `.
+ The unit corresponding to `temperature_data` value. Optional values are `celsius`, `kelvin`, `fahrenheit`.
+ specific_humidity_data: :py:class:`xarray.DataArray`.
+ The Specific humidity of air.
+ specific_humidity_data_units: :py:class:`str `.
+ The unit corresponding to `specific_humidity` value. Optional values are `kg/kg`, `g/g`, `g/kg` and so on.
+ vertical_dim: :py:class:`str `.
+ Vertical coordinate dimension name.
+ vertical_dim_units: :py:class:`str `.
+ The unit corresponding to the vertical p-coordinate value. Optional values are `hPa`, `Pa`, `mbar`.
+ CKCD: :py:class:`float `, default 0.9.
+ Ratio of :math:`C_k` to :math:`C_D` (unitless number), i.e. the ratio of the exchange coefficients of enthalpy and
+ momentum flux (e.g. see Bister and Emanuel 1998, EQN. 17-18). More discussion on :math:`\\frac{C_k}{C_D}` is found in Emanuel (2003).
+ Default is 0.9 based on e.g. Wing et al. (2015).
+ ascent_flag: :py:class:`bool `, default False.
+ Adjustable constant fraction (unitless fraction) for buoyancy of displaced parcels,
+ where `True` is Reversible ascent (default) and `False` is Pseudo-adiabatic ascent.
+ V_reduc: :py:class:`float `, default 0.8.
+ Adjustable constant fraction (unitless fraction) for reduction of gradient winds to 10-m winds
+ see Emanuel (2000) and Powell (1980).
+ ptop: :py:class:`float `, default 50 **hPa**.
+ Pressure below which sounding is ignored (**hPa**).
+ miss_handle: :py:class:`bool `, default True.
+ Flag that determines how missing (NaN) values are handled in CAPE calculation.
+ - If `False` (BE02 default), NaN values in profile are ignored and PI is still calcuated.
+ - If `True`, given NaN values PI will be set to missing (with `IFLAG=3` in CAPE calculation).
+
+ .. note::
+ If any missing values are between the lowest valid level and ptop
+ then PI will automatically be set to missing (with `IFLAG=3` in CAPE calculation)
+
+ Returns
+ -------
+ - vmax: The maximum surface wind speed (m/s) reduced to reflect surface drag via :math:`V_{\\text{reduc}}`.
+ - pmin: The minimum central pressure (hPa)
+ - ifl: A flag value: A value of 1 means OK; a value of 0 indicates no convergence; a value of 2
+ means that the CAPE routine failed to converge; a value of 3 means the CAPE routine failed due to
+ missing data in the inputs.
+ - t0: The outflow temperature (K)
+ - otl: The outflow temperature level (hPa), defined as the level of neutral bouyancy
+ where the outflow temperature is found, i.e. where buoyancy is actually equal
+ to zero under the condition of an air parcel that is saturated at sea level pressure.
+ - eff: Tropical cyclone efficiency.
+ - diseq: Thermodynamic disequilibrium.
+ - lnpi: Natural :math:`\\log(\\text{Potential Intensity})`
+ - lneff: Natural :math:`\\log(\\text{Tropical Cyclone Efficiency})`
+ - lndiseq: Natural :math:`\\log(\\text{Thermodynamic Disequilibrium})`
+ - lnCKCD: Natural :math:`\\log(C_k/C_D)`
+
+ Reference
+ --------------
+ - https://github.com/dgilford/tcpyPI
+
+ - Bister, M., Emanuel, K.A. Dissipative heating and hurricane intensity. Meteorl. Atmos. Phys. 65, 233–240 (1998). https://doi.org/10.1007/BF01030791
+ - Bister, M., and K. A. Emanuel, Low frequency variability of tropical cyclone potential intensity, 1, Interannual to interdecadal variability, J. Geophys. Res., 107(D24), 4801, https://doi.org/10.1029/2001JD000776, 2002.
+ - Emanuel, K.: A Statistical Analysis of Tropical Cyclone Intensity, Mon. Weather Rev., 128, 1139–1152, https://doi.org/10.1175/1520-0493(2000)128<1139:ASAOTC>2.0.CO;2, 2000.
+ - Emanuel, K.: Tropical Cyclones, Annu. Rev. Earth Pl. Sc., 31, 75–104, https://doi.org/10.1146/annurev.earth.31.100901.141259, 2003.
+ - Gilford, D. M.: pyPI (v1.3): Tropical Cyclone Potential Intensity Calculations in Python, Geosci. Model Dev., 14, 2351–2369, https://doi.org/10.5194/gmd-14-2351-2021, 2021.
+ - Powell, M. D.: Evaluations of Diagnostic Marine Boundary-Layer Models Applied to Hurricanes, Mon. Weather Rev., 108, 757–766, https://doi.org/10.1175/1520-0493(1980)108<0757:EODMBL>2.0.CO;2, 1980.
+ - Wing, A. A., Emanuel, K., and Solomon, S.: On the factors affecting trends and variability in tropical cyclone potential intensity, Geophys. Res. Lett., 42, 8669–8677, https://doi.org/10.1002/2015GL066145, 2015.
+ """
+ # Transfer bool value to int value
+ ascent_flag = 1 if ascent_flag else 0
+ diss_flag = 1 if diss_flag else 0
+ miss_handle = 1 if miss_handle else 0
+
+ # Change the sea surface temperature data unit to `degC`
+ sst_data = transfer_data_difference_units(sst_data, sst_data_units, "celsius")
+
+ # Change the temperature data data unit to `degC`
+ temperature_data = transfer_data_difference_units(
+ temperature_data, temperature_data_units, "celsius"
+ )
+
+ # Change the surface pressure data unit to `hPa`
+ surface_pressure_data = transfer_data_multiple_units(
+ surface_pressure_data, surface_pressure_data_units, "hPa"
+ )
+
+ pressure_value = temperature_data[vertical_dim]
+ # Change the `pressure_value` unit to `hPa`
+ pressure_value = transfer_data_multiple_units(
+ pressure_value, vertical_dim_units, "hPa"
+ )
+
+ # transfer specific humidity to mixing ratio
+ mixing_ratio_data = transfer_specific_humidity_2_mixing_ratio(
+ specific_humidity_data=specific_humidity_data,
+ specific_humidity_data_units=specific_humidity_data_units,
+ )
+
+ # calculate PI over the whole data set using the xarray universal function
+ result = xr.apply_ufunc(
+ pi,
+ sst_data,
+ surface_pressure_data,
+ pressure_value,
+ temperature_data,
+ mixing_ratio_data,
+ kwargs=dict(
+ CKCD=CKCD,
+ ascent_flag=ascent_flag,
+ diss_flag=diss_flag,
+ V_reduc=V_reduc,
+ ptop=ptop,
+ miss_handle=miss_handle,
+ ),
+ input_core_dims=[
+ [],
+ [],
+ [
+ vertical_dim,
+ ],
+ [
+ vertical_dim,
+ ],
+ [
+ vertical_dim,
+ ],
+ ],
+ output_core_dims=[[], [], [], [], []],
+ vectorize=True,
+ )
+ vmax, pmin, ifl, t0, otl = result
+
+ # The analyses need SSTs are in kelvin
+ sst_data = transfer_data_difference_units(sst_data, "celsius", "kelvin")
+
+ # calculate efficiency
+ efficiency = xr.apply_ufunc(
+ pi_efficiency,
+ sst_data,
+ t0,
+ input_core_dims=[
+ [],
+ [],
+ ],
+ output_core_dims=[
+ [],
+ ],
+ vectorize=True,
+ )
+
+ diseq = xr.apply_ufunc(
+ pi_diseq_resid,
+ vmax,
+ sst_data,
+ t0,
+ kwargs=dict(CKCD=CKCD),
+ input_core_dims=[
+ [],
+ [],
+ [],
+ ],
+ output_core_dims=[
+ [],
+ ],
+ vectorize=True,
+ )
+
+ result1 = xr.apply_ufunc(
+ decompose_pi,
+ vmax,
+ sst_data,
+ t0,
+ kwargs=dict(CKCD=CKCD),
+ input_core_dims=[
+ [],
+ [],
+ [],
+ ],
+ output_core_dims=[
+ [],
+ [],
+ [],
+ [],
+ ],
+ vectorize=True,
+ )
+ lnpi, lneff, lndiseq, lnCKCD = result1
+
+ out_ds = xr.Dataset(
+ {
+ "vmax": vmax,
+ "pmin": pmin,
+ "ifl": ifl,
+ "t0": t0,
+ "otl": otl,
+ "eff": efficiency,
+ "diseq": diseq,
+ "lnpi": lnpi,
+ "lneff": lneff,
+ "lndiseq": lndiseq,
+ "lnCKCD": lnCKCD,
+ }
+ )
+
+ # add names and units
+ out_ds.vmax.attrs["standard_name"], out_ds.vmax.attrs["units"] = (
+ "Maximum Potential Intensity",
+ "m/s",
+ )
+ out_ds.pmin.attrs["standard_name"], out_ds.pmin.attrs["units"] = (
+ "Minimum Central Pressure",
+ "hPa",
+ )
+ out_ds.ifl.attrs["standard_name"] = "pyPI Flag"
+ out_ds.t0.attrs["standard_name"], out_ds.t0.attrs["units"] = (
+ "Outflow Temperature",
+ "K",
+ )
+ out_ds.otl.attrs["standard_name"], out_ds.otl.attrs["units"] = (
+ "Outflow Temperature Level",
+ "hPa",
+ )
+
+ out_ds.eff.attrs["standard_name"], out_ds.eff.attrs["units"] = (
+ "Tropical Cyclone Efficiency",
+ "unitless fraction",
+ )
+ out_ds.diseq.attrs["standard_name"], out_ds.diseq.attrs["units"] = (
+ "Thermodynamic Disequilibrium",
+ "J/kg",
+ )
+ out_ds.lnpi.attrs["standard_name"] = "Natural log(Potential Intensity)"
+ out_ds.lneff.attrs["standard_name"] = "Natural log(Tropical Cyclone Efficiency)"
+ out_ds.lndiseq.attrs["standard_name"] = "Natural log(Thermodynamic Disequilibrium)"
+ out_ds.lnCKCD.attrs["standard_name"], out_ds.lnCKCD.attrs["units"] = (
+ "Natural log(Ck/CD)",
+ "unitless constant",
+ )
+
+ # return the output as an xarray data structure
+ return out_ds
diff --git a/test/test_air_sea_interaction_index_amm.py b/test/test_field_air_sea_interaction_index_amm.py
similarity index 100%
rename from test/test_air_sea_interaction_index_amm.py
rename to test/test_field_air_sea_interaction_index_amm.py
diff --git a/test/test_air_sea_interaction_index_atlantic_nino.py b/test/test_field_air_sea_interaction_index_atlantic_nino.py
similarity index 100%
rename from test/test_air_sea_interaction_index_atlantic_nino.py
rename to test/test_field_air_sea_interaction_index_atlantic_nino.py
diff --git a/test/test_air_sea_interaction_index_enso.py b/test/test_field_air_sea_interaction_index_enso.py
similarity index 100%
rename from test/test_air_sea_interaction_index_enso.py
rename to test/test_field_air_sea_interaction_index_enso.py
diff --git a/test/test_air_sea_interaction_index_iobm.py b/test/test_field_air_sea_interaction_index_iobm.py
similarity index 100%
rename from test/test_air_sea_interaction_index_iobm.py
rename to test/test_field_air_sea_interaction_index_iobm.py
diff --git a/test/test_air_sea_interaction_index_iod.py b/test/test_field_air_sea_interaction_index_iod.py
similarity index 100%
rename from test/test_air_sea_interaction_index_iod.py
rename to test/test_field_air_sea_interaction_index_iod.py
diff --git a/test/test_field_mesoscale_potential_intensity.py b/test/test_field_mesoscale_potential_intensity.py
new file mode 100644
index 00000000..2b438b22
--- /dev/null
+++ b/test/test_field_mesoscale_potential_intensity.py
@@ -0,0 +1,228 @@
+"""
+pytest for field/mesoscale/potential_intensity
+"""
+
+import pytest
+
+import easyclimate as ecl
+import xarray as xr
+import numpy as np
+
+testdata_sst = xr.DataArray(
+ np.array([[28.861475, 28.552972], [29.157007, 28.649042]]),
+ dims=("lat", "lon"),
+ coords={"lat": np.array([2.5, 0.0]), "lon": np.array([-177.5, -175.0])},
+ attrs={"standard_name": "Sea Surface Temperature", "units": "degrees C"},
+)
+testdata_msl = xr.DataArray(
+ np.array([[1008.075708, 1008.171802], [1008.005922, 1008.088748]]),
+ dims=("lat", "lon"),
+ coords={"lat": np.array([2.5, 0.0]), "lon": np.array([-177.5, -175.0])},
+ attrs={"standard_name": "Mean Sea Level Pressure", "units": "hPa"},
+)
+testdata_t = xr.DataArray(
+ np.array(
+ [
+ [[27.353636, 27.222672], [27.21099, 26.938538]],
+ [[25.190057, 25.069938], [25.007941, 24.750216]],
+ [[23.092178, 22.964785], [22.902211, 22.671951]],
+ [[21.464064, 21.194161], [21.422638, 21.28721]],
+ [[20.135445, 19.904204], [20.2931, 20.135855]],
+ [[19.135903, 19.107665], [19.392363, 19.440976]],
+ [[18.297735, 18.37927], [18.58249, 18.641281]],
+ [[17.206641, 17.328192], [17.450027, 17.518263]],
+ [[15.9993, 16.088557], [16.159143, 16.248171]],
+ [[14.678321, 14.700328], [14.817254, 14.830638]],
+ [[13.276337, 13.264193], [13.373714, 13.333164]],
+ [[11.805724, 11.77128], [11.80218, 11.800547]],
+ [[10.245422, 10.189297], [10.17729, 10.205829]],
+ [[6.958592, 6.955302], [6.958394, 6.957223]],
+ [[3.667473, 3.660736], [3.809784, 3.702164]],
+ [[0.086626, 0.099989], [0.178932, 0.153677]],
+ [[-4.108487, -3.972281], [-3.976002, -3.855817]],
+ [[-8.5458, -8.51175], [-8.630228, -8.564163]],
+ [[-13.561634, -13.553428], [-13.84696, -13.798673]],
+ [[-20.077641, -19.99213], [-20.159432, -20.108628]],
+ [[-28.503128, -28.444674], [-28.420612, -28.401702]],
+ [[-38.741623, -38.853656], [-38.611279, -38.734565]],
+ [[-51.723332, -51.758043], [-51.649847, -51.732749]],
+ [[-67.683181, -67.657047], [-67.849234, -67.727188]],
+ [[-84.802469, -84.811532], [-84.599578, -84.656952]],
+ [[-82.980426, -83.06524], [-83.076922, -83.306107]],
+ [[-72.109836, -71.961065], [-72.277637, -72.140224]],
+ [[-65.229228, -65.242002], [-65.227432, -65.291973]],
+ [[-56.258264, -56.437082], [-55.930041, -56.037194]],
+ [[-51.276108, -51.220998], [-51.082832, -51.050359]],
+ [[-44.492267, -44.431645], [-44.665341, -44.653366]],
+ ]
+ ),
+ dims=("level", "lat", "lon"),
+ coords={
+ "level": np.array(
+ [
+ 1000.0,
+ 975.0,
+ 950.0,
+ 925.0,
+ 900.0,
+ 875.0,
+ 850.0,
+ 825.0,
+ 800.0,
+ 775.0,
+ 750.0,
+ 725.0,
+ 700.0,
+ 650.0,
+ 600.0,
+ 550.0,
+ 500.0,
+ 450.0,
+ 400.0,
+ 350.0,
+ 300.0,
+ 250.0,
+ 200.0,
+ 150.0,
+ 100.0,
+ 70.0,
+ 50.0,
+ 40.0,
+ 30.0,
+ 20.0,
+ 10.0,
+ ]
+ ),
+ "lat": np.array([2.5, 0.0]),
+ "lon": np.array([-177.5, -175.0]),
+ },
+ attrs={"standard_name": "Atmospheric Temperature", "units": "degrees C"},
+)
+testdata_q = xr.DataArray(
+ np.array(
+ [
+ [[1.752169e01, 1.739373e01], [1.755779e01, 1.747079e01]],
+ [[1.711666e01, 1.697109e01], [1.715569e01, 1.708690e01]],
+ [[1.677095e01, 1.662145e01], [1.673994e01, 1.663940e01]],
+ [[1.593267e01, 1.590978e01], [1.558633e01, 1.544861e01]],
+ [[1.473882e01, 1.455964e01], [1.387122e01, 1.373549e01]],
+ [[1.304239e01, 1.267559e01], [1.199529e01, 1.146268e01]],
+ [[1.127705e01, 1.066488e01], [1.025696e01, 9.864766e00]],
+ [[9.847610e00, 9.396217e00], [9.291184e00, 8.872944e00]],
+ [[8.918181e00, 8.675946e00], [8.745527e00, 8.273892e00]],
+ [[8.272269e00, 8.040189e00], [8.070926e00, 7.926245e00]],
+ [[7.787410e00, 7.493204e00], [7.475906e00, 7.490718e00]],
+ [[7.253088e00, 6.989394e00], [6.969766e00, 6.952205e00]],
+ [[6.702615e00, 6.516205e00], [6.319682e00, 6.375766e00]],
+ [[5.709916e00, 5.521406e00], [5.232806e00, 5.305737e00]],
+ [[4.398887e00, 4.284769e00], [4.266110e00, 4.302661e00]],
+ [[3.194687e00, 2.911649e00], [3.216351e00, 3.126061e00]],
+ [[2.166236e00, 1.930091e00], [2.258709e00, 2.104025e00]],
+ [[1.585033e00, 1.382272e00], [1.726041e00, 1.579070e00]],
+ [[1.132454e00, 9.975798e-01], [1.327680e00, 1.184414e00]],
+ [[7.866390e-01, 7.202522e-01], [8.988403e-01, 8.505270e-01]],
+ [[4.513145e-01, 4.453679e-01], [5.425988e-01, 5.050453e-01]],
+ [[2.165959e-01, 1.997725e-01], [2.575166e-01, 2.287391e-01]],
+ [[7.002809e-02, 6.306999e-02], [8.013048e-02, 6.932322e-02]],
+ [[1.401548e-02, 1.282958e-02], [1.460552e-02, 1.323063e-02]],
+ [[1.314765e-03, 1.300477e-03], [1.292135e-03, 1.284880e-03]],
+ [[1.717125e-03, 1.726488e-03], [1.672255e-03, 1.674200e-03]],
+ [[2.587957e-03, 2.586587e-03], [2.588366e-03, 2.586200e-03]],
+ [[2.572437e-03, 2.572403e-03], [2.572174e-03, 2.572327e-03]],
+ [[2.530370e-03, 2.530549e-03], [2.530676e-03, 2.530960e-03]],
+ [[2.556868e-03, 2.556884e-03], [2.555793e-03, 2.555478e-03]],
+ [[2.825350e-03, 2.825275e-03], [2.810023e-03, 2.809112e-03]],
+ ]
+ ),
+ dims=("level", "lat", "lon"),
+ coords={
+ "level": np.array(
+ [
+ 1000.0,
+ 975.0,
+ 950.0,
+ 925.0,
+ 900.0,
+ 875.0,
+ 850.0,
+ 825.0,
+ 800.0,
+ 775.0,
+ 750.0,
+ 725.0,
+ 700.0,
+ 650.0,
+ 600.0,
+ 550.0,
+ 500.0,
+ 450.0,
+ 400.0,
+ 350.0,
+ 300.0,
+ 250.0,
+ 200.0,
+ 150.0,
+ 100.0,
+ 70.0,
+ 50.0,
+ 40.0,
+ 30.0,
+ 20.0,
+ 10.0,
+ ]
+ ),
+ "lat": np.array([2.5, 0.0]),
+ "lon": np.array([-177.5, -175.0]),
+ },
+ attrs={"standard_name": "Specific Humidity", "units": "g/kg"},
+)
+
+
+def test_calc_potential_intensity_Bister_Emanuel_2002():
+ result_data = ecl.field.mesoscale.calc_potential_intensity_Bister_Emanuel_2002(
+ sst_data=testdata_sst,
+ sst_data_units="degC",
+ surface_pressure_data=testdata_msl,
+ surface_pressure_data_units="hPa",
+ temperature_data=testdata_t,
+ temperature_data_units="degC",
+ specific_humidity_data=testdata_q,
+ specific_humidity_data_units="g/kg",
+ vertical_dim="level",
+ vertical_dim_units="hPa",
+ )
+ result_data1 = result_data.vmax.data.flatten()[1:3]
+ result_data2 = result_data.pmin.data.flatten()[1:3]
+ result_data3 = result_data.ifl.data.flatten()[1:3]
+ result_data4 = result_data.t0.data.flatten()[1:3]
+ result_data5 = result_data.otl.data.flatten()[1:3]
+ result_data6 = result_data.eff.data.flatten()[1:3]
+ result_data7 = result_data.diseq.data.flatten()[1:3]
+ result_data8 = result_data.lnpi.data.flatten()[1:3]
+ result_data9 = result_data.lneff.data.flatten()[1:3]
+ result_data10 = result_data.lndiseq.data.flatten()[1:3]
+ result_data11 = result_data.lnCKCD.data.flatten()[1:3]
+
+ refer_data1 = np.array([90.93510812, 98.74747325])
+ refer_data2 = np.array([900.4934007, 882.44831663])
+ refer_data3 = np.array([1, 1])
+ refer_data4 = np.array([189.45530961, 189.75865991])
+ refer_data5 = np.array([80.81349033, 76.1947957])
+ refer_data6 = np.array([0.59247567, 0.5931131])
+ refer_data7 = np.array([15507.79821296, 18267.19889297])
+ refer_data8 = np.array([9.02029231, 9.18513163])
+ refer_data9 = np.array([-0.52344546, -0.52237017])
+ refer_data10 = np.array([9.64909829, 9.81286232])
+ refer_data11 = np.array([-0.10536052, -0.10536052])
+
+ assert np.isclose(result_data1, refer_data1).all()
+ assert np.isclose(result_data2, refer_data2).all()
+ assert np.isclose(result_data3, refer_data3).all()
+ assert np.isclose(result_data4, refer_data4).all()
+ assert np.isclose(result_data5, refer_data5).all()
+ assert np.isclose(result_data6, refer_data6).all()
+ assert np.isclose(result_data7, refer_data7).all()
+ assert np.isclose(result_data8, refer_data8).all()
+ assert np.isclose(result_data9, refer_data9).all()
+ assert np.isclose(result_data10, refer_data10).all()
+ assert np.isclose(result_data11, refer_data11).all()