From ab7c21897fc88d3aa1129f5e9562ab90f25b4d24 Mon Sep 17 00:00:00 2001 From: wyq Date: Wed, 30 Nov 2022 23:30:36 +0800 Subject: [PATCH] add get_dbz function in wrf package --- ...mons_commons_math4_legacy_4_0_SNAPSHOT.xml | 6 +- ...commons_math4_legacy_core_4_0_SNAPSHOT.xml | 6 +- ...ns_math4_legacy_exception_4_0_SNAPSHOT.xml | 6 +- ...s_statistics_distribution_1_0_SNAPSHOT.xml | 6 +- ...ationtech_proj4j_proj4j_1_1_6_SNAPSHOT.xml | 6 +- .../java/org/meteoinfo/chart/jogl/GLPlot.java | 16 +- .../org/meteoinfo/chart/jogl/MapGLPlot.java | 4 + .../org/meteoinfo/geo/mapview/MapView.java | 3 - meteoinfo-lab/milconfig.xml | 41 +++-- .../pylib/mipylib/meteolib/wrf/__init__.py | 4 +- .../pylib/mipylib/meteolib/wrf/g_dbz.py | 66 +++++++ .../pylib/mipylib/numeric/core/_ndarray.py | 17 ++ .../mipylib/numeric/core/numeric$py.class | Bin 149244 -> 149047 bytes .../pylib/mipylib/numeric/core/numeric.py | 7 +- .../mipylib/numeric/stats/stats$py.class | Bin 37469 -> 37462 bytes .../pylib/mipylib/numeric/stats/stats.py | 2 +- .../pylib/mipylib/plotlib/_figure$py.class | Bin 41577 -> 41578 bytes .../pylib/mipylib/plotlib/_figure.py | 2 +- .../pylib/mipylib/plotlib/miplot$py.class | Bin 106570 -> 106569 bytes meteoinfo-lab/pylib/mipylib/plotlib/miplot.py | 2 +- .../org/meteoinfo/lab/gui/FrmAppsManager.java | 11 +- .../java/org/meteoinfo/lab/gui/FrmMain.java | 8 +- .../java/org/meteoinfo/math/meteo/WRF.java | 163 ++++++++++++++++++ .../org/meteoinfo/ndarray/ArrayDouble.java | 8 +- .../org/meteoinfo/ndarray/ArrayFloat.java | 8 +- .../java/org/meteoinfo/ndarray/ArrayInt.java | 4 +- .../java/org/meteoinfo/ndarray/ArrayLong.java | 8 +- .../org/meteoinfo/ndarray/ArrayShort.java | 14 +- 28 files changed, 334 insertions(+), 84 deletions(-) create mode 100644 meteoinfo-lab/pylib/mipylib/meteolib/wrf/g_dbz.py create mode 100644 meteoinfo-math/src/main/java/org/meteoinfo/math/meteo/WRF.java diff --git a/.idea/libraries/Maven__org_apache_commons_commons_math4_legacy_4_0_SNAPSHOT.xml b/.idea/libraries/Maven__org_apache_commons_commons_math4_legacy_4_0_SNAPSHOT.xml index 867e4dbb..5e48bd23 100644 --- a/.idea/libraries/Maven__org_apache_commons_commons_math4_legacy_4_0_SNAPSHOT.xml +++ b/.idea/libraries/Maven__org_apache_commons_commons_math4_legacy_4_0_SNAPSHOT.xml @@ -1,13 +1,13 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_commons_commons_math4_legacy_core_4_0_SNAPSHOT.xml b/.idea/libraries/Maven__org_apache_commons_commons_math4_legacy_core_4_0_SNAPSHOT.xml index 209b23fb..d397b347 100644 --- a/.idea/libraries/Maven__org_apache_commons_commons_math4_legacy_core_4_0_SNAPSHOT.xml +++ b/.idea/libraries/Maven__org_apache_commons_commons_math4_legacy_core_4_0_SNAPSHOT.xml @@ -1,13 +1,13 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_commons_commons_math4_legacy_exception_4_0_SNAPSHOT.xml b/.idea/libraries/Maven__org_apache_commons_commons_math4_legacy_exception_4_0_SNAPSHOT.xml index 8e7f2e45..b172e846 100644 --- a/.idea/libraries/Maven__org_apache_commons_commons_math4_legacy_exception_4_0_SNAPSHOT.xml +++ b/.idea/libraries/Maven__org_apache_commons_commons_math4_legacy_exception_4_0_SNAPSHOT.xml @@ -1,13 +1,13 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_commons_commons_statistics_distribution_1_0_SNAPSHOT.xml b/.idea/libraries/Maven__org_apache_commons_commons_statistics_distribution_1_0_SNAPSHOT.xml index 48d52414..dc25306e 100644 --- a/.idea/libraries/Maven__org_apache_commons_commons_statistics_distribution_1_0_SNAPSHOT.xml +++ b/.idea/libraries/Maven__org_apache_commons_commons_statistics_distribution_1_0_SNAPSHOT.xml @@ -1,13 +1,13 @@ - + - + - + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_locationtech_proj4j_proj4j_1_1_6_SNAPSHOT.xml b/.idea/libraries/Maven__org_locationtech_proj4j_proj4j_1_1_6_SNAPSHOT.xml index 8d2ba86b..599ba0fc 100644 --- a/.idea/libraries/Maven__org_locationtech_proj4j_proj4j_1_1_6_SNAPSHOT.xml +++ b/.idea/libraries/Maven__org_locationtech_proj4j_proj4j_1_1_6_SNAPSHOT.xml @@ -1,13 +1,13 @@ - + - + - + \ No newline at end of file diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/GLPlot.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/GLPlot.java index ec191552..5dcb1277 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/GLPlot.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/GLPlot.java @@ -2499,13 +2499,17 @@ public class GLPlot extends Plot { } else { boolean isDraw = true; if (graphic instanceof GraphicCollection3D) { - GraphicCollection3D gg = (GraphicCollection3D) graphic; - if (gg.isAllQuads()) { - this.drawQuadsPolygons(gl, gg); - isDraw = false; - } else if (gg.isAllTriangle()) { - this.drawTrianglePolygons(gl, gg); + if (graphic.getNumGraphics() == 0) { isDraw = false; + } else { + GraphicCollection3D gg = (GraphicCollection3D) graphic; + if (gg.isAllQuads()) { + this.drawQuadsPolygons(gl, gg); + isDraw = false; + } else if (gg.isAllTriangle()) { + this.drawTrianglePolygons(gl, gg); + isDraw = false; + } } } if (isDraw) { diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/MapGLPlot.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/MapGLPlot.java index 88a99c3d..ac0a48ec 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/MapGLPlot.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/MapGLPlot.java @@ -3,6 +3,7 @@ package org.meteoinfo.chart.jogl; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2; import org.meteoinfo.chart.ChartText; +import org.meteoinfo.chart.graphic.GraphicCollection3D; import org.meteoinfo.chart.graphic.GraphicProjectionUtil; import org.meteoinfo.chart.plot.MapGridLine; import org.meteoinfo.chart.plot.MapGridLine3D; @@ -64,6 +65,9 @@ public class MapGLPlot extends GLPlot { super.addGraphic(graphic); } else { Graphic nGraphic = GraphicProjectionUtil.projectClipGraphic(graphic, proj, this.projInfo); + if (nGraphic instanceof GraphicCollection3D) { + ((GraphicCollection3D) nGraphic).setUsingLight(((GraphicCollection3D) graphic).isUsingLight()); + } super.addGraphic(nGraphic); } } diff --git a/meteoinfo-geo/src/main/java/org/meteoinfo/geo/mapview/MapView.java b/meteoinfo-geo/src/main/java/org/meteoinfo/geo/mapview/MapView.java index ca067906..5d292761 100644 --- a/meteoinfo-geo/src/main/java/org/meteoinfo/geo/mapview/MapView.java +++ b/meteoinfo-geo/src/main/java/org/meteoinfo/geo/mapview/MapView.java @@ -7848,9 +7848,6 @@ public class MapView extends JPanel implements IWebMapPanel { this._scaleX = scale; this._scaleY = scale; PointD center = (PointD)this._drawExtent.getCenterPoint().clone(); - //PointD center = (PointD) this._viewExtent.getCenterPoint().clone(); - //center.X -= g.getTransform().getTranslateX(); - //center.Y -= g.getTransform().getTranslateY(); double xlen = width / scale * 0.5; double ylen = height / scale * 0.5; this._drawExtent.minX = center.X - xlen; diff --git a/meteoinfo-lab/milconfig.xml b/meteoinfo-lab/milconfig.xml index 385b8d4e..d8cf59bc 100644 --- a/meteoinfo-lab/milconfig.xml +++ b/meteoinfo-lab/milconfig.xml @@ -1,33 +1,32 @@ - - - - - - - - - - - + + + + + + + + + + + + - - + + - - - - + + + - - - - + + + diff --git a/meteoinfo-lab/pylib/mipylib/meteolib/wrf/__init__.py b/meteoinfo-lab/pylib/mipylib/meteolib/wrf/__init__.py index 74bb9851..043a1696 100644 --- a/meteoinfo-lab/pylib/mipylib/meteolib/wrf/__init__.py +++ b/meteoinfo-lab/pylib/mipylib/meteolib/wrf/__init__.py @@ -3,9 +3,11 @@ from g_slp import * from g_rh import * from g_pressure import * from g_geoht import * +from g_dbz import * __all__ = destag.__all__ __all__ += g_slp.__all__ __all__ += g_rh.__all__ __all__ += g_pressure.__all__ -__all__ += g_geoht.__all__ \ No newline at end of file +__all__ += g_geoht.__all__ +__all__ += g_dbz.__all__ \ No newline at end of file diff --git a/meteoinfo-lab/pylib/mipylib/meteolib/wrf/g_dbz.py b/meteoinfo-lab/pylib/mipylib/meteolib/wrf/g_dbz.py new file mode 100644 index 00000000..15443ace --- /dev/null +++ b/meteoinfo-lab/pylib/mipylib/meteolib/wrf/g_dbz.py @@ -0,0 +1,66 @@ +from org.meteoinfo.math.meteo import WRF +import mipylib.numeric as np +from .. import constants +from ..calc.thermo import temperature_from_potential_temperature + +__all__ = ['get_dbz'] + +def get_dbz(wrfin, timeidx=0, use_varint=False, use_liqskin=False): + """Return the simulated radar reflectivity. + 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. + use_varint (:obj:`bool`, optional): When set to False, + the intercept parameters are assumed constant + (as in MM5's Reisner-2 bulk microphysical scheme). + When set to True, the variable intercept + parameters are used as in the more recent version of Reisner-2 + (based on Thompson, Rasmussen, and Manning, 2004, Monthly weather + Review, Vol. 132, No. 2, pp. 519-542.). + use_liqskin (:obj:`bool`, optional): When set to True, frozen particles + that are at a temperature above freezing are assumed to scatter + as a liquid particle. Set to False to disable. + Returns: + :class:`xarray.DataArray` or :class:`numpy.ndarray`: The simulated + radar reflectivity. + If xarray is enabled and the *meta* parameter is True, then the result + will be a :class:`xarray.DataArray` object. Otherwise, the result will + be a :class:`numpy.ndarray` object with no metadata. + """ + t = wrfin["T"][timeidx] + p = wrfin["P"][timeidx] + pb = wrfin["PB"][timeidx] + qv = wrfin["QVAPOR"][timeidx] + qr = wrfin["QRAIN"][timeidx] + + if wrfin.varnames.contains("QSNOW"): + qs = wrfin["QSNOW"][timeidx] + else: + qs = np.zeros(qv.shape, qv.dtype) + + if wrfin.varnames.contains("QGRAUP"): + qg = wrfin["QGRAUP"][timeidx] + else: + qg = np.zeros(qv.shape, qv.dtype) + + full_t = t + constants.T_BASE + full_p = p + pb + tk = temperature_from_potential_temperature(full_p * 0.01, full_t) + + # If qsnow is not all 0, set sn0 to 1 + sn0 = 1 if qs.any() else 0 + ivarint = 1 if use_varint else 0 + iliqskin = 1 if use_liqskin else 0 + + dbz = WRF.calcDBZ(full_p._array, tk._array, qv._array, qr._array, qs._array, qg._array, + sn0, ivarint, iliqskin) + return np.DimArray(dbz, dims=t.dims) \ No newline at end of file diff --git a/meteoinfo-lab/pylib/mipylib/numeric/core/_ndarray.py b/meteoinfo-lab/pylib/mipylib/numeric/core/_ndarray.py index bec60957..c2706185 100644 --- a/meteoinfo-lab/pylib/mipylib/numeric/core/_ndarray.py +++ b/meteoinfo-lab/pylib/mipylib/numeric/core/_ndarray.py @@ -574,6 +574,23 @@ class NDArray(object): r = NDArray(ArrayMath.inValues(self._array, other)) return r + def any(self, axis=None): + """ + Test whether any array element along a given axis evaluates to True. + + :param axis: (*int*) Axis along which a logical OR reduction is performed. + The default (axis = None) is to perform a logical OR over all the + dimensions of the input array. + + :returns: (*array_like*) Any result + """ + if axis is None: + return ArrayMath.any(self._array) + else: + if axis < 0: + axis += self.ndim + return NDArray(ArrayMath.any(self._array, axis)) + def contains_nan(self): """ Check if the array contains nan value. diff --git a/meteoinfo-lab/pylib/mipylib/numeric/core/numeric$py.class b/meteoinfo-lab/pylib/mipylib/numeric/core/numeric$py.class index 11336b1b8410282dc6826bbc4c9169b82f3f8828..48e119891ca8a2e3a38f69cc2807e2a347f35c8e 100644 GIT binary patch delta 14991 zcmZ{rcR*A}*T(nU-FvqwZ2@CLLTVkTdu1W0jJ#+76L0{iLe$4LPnKNhFIcH`rFUMH(M_X6*?QAPytV%1b zG}4&1c2eiTjji64!e z7)(Lza6*$nZtujOdQM1)6Q3(kGwr8U;∇6%ai`LRgmaZnt}ujYCp+08xU@Z&|E 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 delta 14961 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 diff --git a/meteoinfo-lab/pylib/mipylib/numeric/core/numeric.py b/meteoinfo-lab/pylib/mipylib/numeric/core/numeric.py index 4bd053fa..1d133260 100644 --- a/meteoinfo-lab/pylib/mipylib/numeric/core/numeric.py +++ b/meteoinfo-lab/pylib/mipylib/numeric/core/numeric.py @@ -1166,12 +1166,7 @@ def any(x, axis=None): if isinstance(x, list): x = array(x) - if axis is None: - return ArrayMath.any(x._array) - else: - if axis < 0: - axis += x.ndim - return NDArray(ArrayMath.any(x._array, axis)) + return x.any(axis) def all(x, axis=None): """ diff --git a/meteoinfo-lab/pylib/mipylib/numeric/stats/stats$py.class b/meteoinfo-lab/pylib/mipylib/numeric/stats/stats$py.class index 2a227d40228e676e80579e1edb0b489765d34ad5..c61257566212f9fda88fdc131dfefd828b308006 100644 GIT binary patch delta 44 zcmcb+gz4H6rVYGI+zcEHii`{_$@xX8o8_4r!Z=!vtK2kWWRRO25FxsGPsBn?04jYA A;Q#;t delta 44 zcmcb%gz4@QrVYGILM+MoMX4MNii`~Gd8N6jMVZN)C72q*SergJ+V*Uo8?n<807$wI Ap#T5? diff --git a/meteoinfo-lab/pylib/mipylib/numeric/stats/stats.py b/meteoinfo-lab/pylib/mipylib/numeric/stats/stats.py index b69a5c14..34348f65 100644 --- a/meteoinfo-lab/pylib/mipylib/numeric/stats/stats.py +++ b/meteoinfo-lab/pylib/mipylib/numeric/stats/stats.py @@ -10,7 +10,7 @@ from org.meteoinfo.math.stats import StatsUtil from org.meteoinfo.ndarray.math import ArrayMath from org.meteoinfo.ndarray import Array -from ..core import numeric as np +from .. import core as np from collections import namedtuple import warnings diff --git a/meteoinfo-lab/pylib/mipylib/plotlib/_figure$py.class b/meteoinfo-lab/pylib/mipylib/plotlib/_figure$py.class index 237bd57e03f35aa2692cefc75487af63be65b88d..d8d9766b85f1cf26fca83a5b8ebb7ef8b4dd7c31 100644 GIT binary patch delta 33 pcmaEPgz420rVXOnjPoapX%{nQZtm3HD9+k)NbuXw&Gyb(@c{5h4cPzy delta 31 ncmaELgz4oGrVXOnjPoXoX%}zq(%vY}+RP}YDzVwYSt}j@%V-M; diff --git a/meteoinfo-lab/pylib/mipylib/plotlib/_figure.py b/meteoinfo-lab/pylib/mipylib/plotlib/_figure.py index 00976fd3..72273e16 100644 --- a/meteoinfo-lab/pylib/mipylib/plotlib/_figure.py +++ b/meteoinfo-lab/pylib/mipylib/plotlib/_figure.py @@ -504,7 +504,7 @@ class Figure(GLChartPanel): """ Set MouseMode. - :param mm: (*string*) MouseMode string [zoom_in | zoom_out | pan | identifer + :param mm: (*string*) MouseMode string [zoom_in | zoom_out | pan | identifier | rotate | select]. """ mm = MouseMode.valueOf(mm.upper()) diff --git a/meteoinfo-lab/pylib/mipylib/plotlib/miplot$py.class b/meteoinfo-lab/pylib/mipylib/plotlib/miplot$py.class index 3a08a90b939f284ca4ca96831685f6a56f59b429..7baa6fbfc064cdcdbefc452c88b8a885a2bcf359 100644 GIT binary patch delta 46 zcmX?gfbHY~whg|P{JvZYK;W2?qL8SNn^-XUyrtvjd6scbEXTIB9%!oBR>SC}0sxS0 B5sm-= delta 49 zcmX?kfbG-)whg|P0)AWyK;W2?qL7%UkegUA`JAQW=DC(}PAv7il?|K!S8xAc&FG~9 E0K-2L#{d8T diff --git a/meteoinfo-lab/pylib/mipylib/plotlib/miplot.py b/meteoinfo-lab/pylib/mipylib/plotlib/miplot.py index 64228ad1..4d68dd57 100644 --- a/meteoinfo-lab/pylib/mipylib/plotlib/miplot.py +++ b/meteoinfo-lab/pylib/mipylib/plotlib/miplot.py @@ -846,7 +846,7 @@ def axes3dgl(*args, **kwargs): def axes3d_map(*args, **kwargs): """ - Add an map 3d axes with JOGL to the figure. + Add a map 3d axes with JOGL to the figure. :returns: The axes. """ diff --git a/meteoinfo-lab/src/main/java/org/meteoinfo/lab/gui/FrmAppsManager.java b/meteoinfo-lab/src/main/java/org/meteoinfo/lab/gui/FrmAppsManager.java index beab0e08..75d431d7 100644 --- a/meteoinfo-lab/src/main/java/org/meteoinfo/lab/gui/FrmAppsManager.java +++ b/meteoinfo-lab/src/main/java/org/meteoinfo/lab/gui/FrmAppsManager.java @@ -8,6 +8,8 @@ import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; @@ -204,9 +206,12 @@ public class FrmAppsManager extends javax.swing.JDialog { File fs[] = f.listFiles(); for (File ff : fs) { if (ff.isDirectory()) { - Application plugin = this.readPyApp(ff.getName(), "loadApp.py"); - if (plugin != null) { - plugins.add(plugin); + Path loadApp = Paths.get(ff.getPath(), "loadApp.py"); + if (loadApp.toFile().isFile()) { + Application plugin = this.readPyApp(ff.getName(), "loadApp.py"); + if (plugin != null) { + plugins.add(plugin); + } } } } diff --git a/meteoinfo-lab/src/main/java/org/meteoinfo/lab/gui/FrmMain.java b/meteoinfo-lab/src/main/java/org/meteoinfo/lab/gui/FrmMain.java index 21d88c64..84aebc61 100644 --- a/meteoinfo-lab/src/main/java/org/meteoinfo/lab/gui/FrmMain.java +++ b/meteoinfo-lab/src/main/java/org/meteoinfo/lab/gui/FrmMain.java @@ -157,8 +157,12 @@ public class FrmMain extends javax.swing.JFrame implements IApplication { if (this.startupPath.endsWith("meteoinfo-lab")) { Path path = new File(this.startupPath).toPath(); path = path.getParent(); - path = path.resolve(Paths.get("auxdata", "toolbox")); - toolboxPath = path.toString(); + Path toolPath = path.getParent(); + toolPath = toolPath.resolve(Paths.get("toolbox")); + if (!toolPath.toFile().isDirectory()) { + toolPath = path.resolve(Paths.get("auxdata", "toolbox")); + } + toolboxPath = toolPath.toString(); } String appConfFn = toolboxPath + File.separator + "apps.xml"; if (new File(appConfFn).exists()) { diff --git a/meteoinfo-math/src/main/java/org/meteoinfo/math/meteo/WRF.java b/meteoinfo-math/src/main/java/org/meteoinfo/math/meteo/WRF.java new file mode 100644 index 00000000..a427f61f --- /dev/null +++ b/meteoinfo-math/src/main/java/org/meteoinfo/math/meteo/WRF.java @@ -0,0 +1,163 @@ +/* + * Calculation algorithm for WRF model output + */ +package org.meteoinfo.math.meteo; + +import org.meteoinfo.ndarray.Array; +import org.meteoinfo.ndarray.Index3D; + +public class WRF { + //constants + public static final double GAMMA_SEVEN = 720.; + public static final double RHOWAT = 1000.; + public static final double RHO_R = RHOWAT; + public static final double RHO_S = 100.; + public static final double RHO_G = 400.; + public static final double ALPHA = 0.224; + public static final double CELKEL = 273.15; + public static final double PI = 3.141592653589793; + public static final double RD = 287.04; + + /** + * Computes equivalent reflectivity factor (in dBZ) at + * each model grid point. + * + * @param prs Pressure + * @param tmk Temperature + * @param qvp Water vapor mixing ratio + * @param qra Rain water mixing ratio + * @param qsn Snow mixing ratio + * @param qgr Graupel mixing ratio + * @param sn0 Whether snow mixing ratio is not all 0 + * @param ivarint The variable intercept parameter + * @param iliqskin The frozen particles parameter + * @return Calculated dBZ array + */ + public static Array calcDBZ(Array prs, Array tmk, Array qvp, Array qra, Array qsn, Array qgr, + int sn0, int ivarint, int iliqskin) { + int[] shape = prs.getShape(); + int nz = shape[0]; int ny = shape[1]; int nx = shape[2]; + int i, j, k; + double temp_c, virtual_t, gonv, ronv, sonv, factor_g, factor_r, factor_s, + factorb_g, factorb_s, rhoair, z_e; + + //Constants used to calculate variable intercepts + double R1 = 1.E-15; + double RON = 8.E6; + double RON2 = 1.E10; + double SON = 2.E7; + double GON = 5.E7; + double RON_MIN = 8.E6; + double RON_QR0 = 0.00010; + double RON_DELQR0 = 0.25 * RON_QR0; + double RON_CONST1R = (RON2-RON_MIN)*0.5; + double RON_CONST2R = (RON2+RON_MIN)*0.5; + + //Constant intercepts + double RN0_R = 8.E6; + double RN0_S = 2.E7; + double RN0_G = 4.E6; + + //Force all Q arrays to be 0.0 or greater. + Index3D index = (Index3D) Index3D.factory(shape); + for (k = 0; k < nz; k++) { + for (j = 0; j < ny; j++) { + for (i = 0; i < nx; i++) { + index.set(k, j, i); + if (qvp.getDouble(index) < 0.0) { + qvp.setDouble(index, 0.0); + } + if (qra.getDouble(index) < 0.0) { + qra.setDouble(index, 0.0); + } + if (qsn.getDouble(index) < 0.0) { + qsn.setDouble(index, 0.0); + } + if (qgr.getDouble(index) < 0.0) { + qgr.setDouble(index, 0.0); + } + } + } + } + + //Input pressure is Pa, but we need hPa in calculations + if (sn0 == 0) { + for (k = 0; k < nz; k++) { + for (j = 0; j < ny; j++) { + for (i = 0; i < nx; i++) { + index.set(k, j, i); + if (tmk.getDouble(index) < CELKEL) { + qsn.setDouble(index, qra.getDouble(index)); + qra.setDouble(index, 0.); + } + } + } + } + } + + factor_r = GAMMA_SEVEN * 1.E18 * Math.pow((1.0 / (PI * RHO_R)), 1.75); + factor_s = GAMMA_SEVEN * 1.E18 * Math.pow((1.0 / (PI * RHO_S)), 1.75) * + Math.pow((RHO_S / RHOWAT), 2) * ALPHA; + factor_g = GAMMA_SEVEN * 1.E18 * Math.pow((1.0 / (PI * RHO_G)), 1.75) * + Math.pow((RHO_G / RHOWAT), 2) * ALPHA; + + Array dbz = Array.factory(prs.getDataType(), shape); + for (k = 0; k < nz; k++) { + for (j = 0; j < ny; j++) { + for (i = 0; i < nx; i++) { + index.set(k, j, i); + virtual_t = tmk.getDouble(index) * (0.622 + qvp.getDouble(index)) / + (0.622 * (1. + qvp.getDouble(index))); + rhoair = prs.getDouble(index) / (RD * virtual_t); + + //Adjust factor for brightband, where snow or graupel particle + //scatters like liquid water (alpha=1.0) because it is assumed to + //have a liquid skin. + if (iliqskin == 1 && tmk.getDouble(index) > CELKEL) { + factorb_s = factor_s / ALPHA; + factorb_g = factor_g / ALPHA; + } else { + factorb_s = factor_s; + factorb_g = factor_g; + } + + //Calculate variable intercept parameters + if (ivarint == 1) { + temp_c = Math.min(-0.001, tmk.getDouble(index) - CELKEL); + sonv = Math.min(2.0E8, 2.0E6 * Math.exp(-0.12 * temp_c)); + + gonv = GON; + if (qgr.getDouble(index) > R1) { + gonv = 2.38 * Math.pow(PI * RHO_G / (rhoair * qgr.getDouble(index)), 0.92); + gonv = Math.max(1.E4, Math.min(gonv, GON)); + } + + ronv = RON2; + if (qra.getDouble(index) > R1) { + ronv = RON_CONST1R * Math.tanh((RON_QR0 - qra.getDouble(index)) / RON_DELQR0) + RON_CONST2R; + } + + } else { + ronv = RN0_R; + sonv = RN0_S; + gonv = RN0_G; + } + + //Total equivalent reflectivity factor (z_e, in mm^6 m^-3) is + //the sum of z_e for each hydrometeor species: + z_e = factor_r * Math.pow(rhoair * qra.getDouble(index), 1.75) / Math.pow(ronv, .75) + + factorb_s * Math.pow(rhoair * qsn.getDouble(index), 1.75) / Math.pow(sonv, .75) + + factorb_g * Math.pow(rhoair * qgr.getDouble(index), 1.75) / Math.pow(gonv, .75); + + //Adjust small values of Z_e so that dBZ is no lower than -30 + z_e = Math.max(z_e, .001); + + //Convert to dBZ + dbz.setDouble(index, 10. * Math.log10(z_e)); + } + } + } + + return dbz; + } +} diff --git a/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayDouble.java b/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayDouble.java index 546d7f96..9262c99d 100644 --- a/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayDouble.java +++ b/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayDouble.java @@ -228,14 +228,14 @@ public class ArrayDouble extends Array { * not legal, throw ForbiddenConversionException */ public boolean getBoolean(Index i) { - throw new ForbiddenConversionException(); + return storageD[i.currentElement()] != 0; } /** * not legal, throw ForbiddenConversionException */ public void setBoolean(Index i, boolean value) { - throw new ForbiddenConversionException(); + storageD[i.currentElement()] = value ? 1 : 0; } /** @@ -336,11 +336,11 @@ public class ArrayDouble extends Array { } public boolean getBoolean(int index) { - throw new ForbiddenConversionException(); + return storageD[index] != 0; } public void setBoolean(int index, boolean value) { - throw new ForbiddenConversionException(); + storageD[index] = value ? 1 : 0; } public String getString(int index) { diff --git a/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayFloat.java b/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayFloat.java index 53adb578..fc941d29 100644 --- a/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayFloat.java +++ b/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayFloat.java @@ -233,14 +233,14 @@ public class ArrayFloat extends Array { * not legal, throw ForbiddenConversionException */ public boolean getBoolean(Index i) { - throw new ForbiddenConversionException(); + return storage[i.currentElement()] != 0; } /** * not legal, throw ForbiddenConversionException */ public void setBoolean(Index i, boolean value) { - throw new ForbiddenConversionException(); + storage[i.currentElement()] = value ? 1 : 0; } /** @@ -341,11 +341,11 @@ public class ArrayFloat extends Array { } public boolean getBoolean(int index) { - throw new ForbiddenConversionException(); + return storage[index] != 0; } public void setBoolean(int index, boolean value) { - throw new ForbiddenConversionException(); + storage[index] = value ? 1 : 0; } public String getString(int index) { diff --git a/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayInt.java b/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayInt.java index 4b4d9cfb..294778f1 100644 --- a/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayInt.java +++ b/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayInt.java @@ -248,14 +248,14 @@ public class ArrayInt extends Array { * not legal, throw ForbiddenConversionException */ public boolean getBoolean(Index i) { - throw new ForbiddenConversionException(); + return storage[i.currentElement()] != 0; } /** * not legal, throw ForbiddenConversionException */ public void setBoolean(Index i, boolean value) { - throw new ForbiddenConversionException(); + storage[i.currentElement()] = value ? 1 : 0; } /** diff --git a/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayLong.java b/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayLong.java index a2530261..7e47c5e1 100644 --- a/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayLong.java +++ b/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayLong.java @@ -238,14 +238,14 @@ public class ArrayLong extends Array { * not legal, throw ForbiddenConversionException */ public boolean getBoolean(Index i) { - throw new ForbiddenConversionException(); + return storage[i.currentElement()] != 0; } /** * not legal, throw ForbiddenConversionException */ public void setBoolean(Index i, boolean value) { - throw new ForbiddenConversionException(); + storage[i.currentElement()] = value ? 1 : 0; } /** @@ -348,11 +348,11 @@ public class ArrayLong extends Array { } public boolean getBoolean(int index) { - throw new ForbiddenConversionException(); + return storage[index] != 0; } public void setBoolean(int index, boolean value) { - throw new ForbiddenConversionException(); + storage[index] = value ? 1 : 0; } public String getString(int index) { diff --git a/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayShort.java b/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayShort.java index 860542e4..a2478e4a 100644 --- a/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayShort.java +++ b/meteoinfo-ndarray/src/main/java/org/meteoinfo/ndarray/ArrayShort.java @@ -243,18 +243,12 @@ public class ArrayShort extends Array { storage[i.currentElement()] = (short) value; } - /** - * not legal, throw ForbiddenConversionException - */ public boolean getBoolean(Index i) { - throw new ForbiddenConversionException(); + return storage[i.currentElement()] != 0; } - /** - * not legal, throw ForbiddenConversionException - */ public void setBoolean(Index i, boolean value) { - throw new ForbiddenConversionException(); + storage[i.currentElement()] = value ? (short) 1 : 0; } /** @@ -362,11 +356,11 @@ public class ArrayShort extends Array { } public boolean getBoolean(int index) { - throw new ForbiddenConversionException(); + return storage[index] != 0; } public void setBoolean(int index, boolean value) { - throw new ForbiddenConversionException(); + storage[index] = value ? (short)1 : 0; } public String getString(int index) {