Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 23 additions & 13 deletions mslib/msui/mpl_qtwidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,10 @@ def draw_flightpath_legend(self, flightpath_dict):


class SideViewPlotter(ViewPlotter):
_pres_maj = np.concatenate([np.arange(top * 10, top, -top) for top in (10000, 1000, 100, 10)] + [[10]])
_pres_min = np.concatenate([np.arange(top * 10, top, -top // 10) for top in (10000, 1000, 100, 10)] + [[10]])
_pres_maj = np.concatenate([np.arange(top * 10, top, -top) for top in (10000, 1000, 100, 10, 1, 0.1)] +
[[0.1]])
_pres_min = np.concatenate([np.arange(top * 10, top, -top // 10) for top in (10000, 1000, 100, 10, 1, 0.1)] +
[[0.1]])

def __init__(self, fig=None, ax=None, settings=None, numlabels=None, num_interpolation_points=None):
"""
Expand Down Expand Up @@ -427,37 +429,45 @@ def _determine_ticks_labels(self, typ):
# Compute the position of major and minor ticks. Major ticks are labelled.
major_ticks = self._pres_maj[(self._pres_maj <= self.p_bot) & (self._pres_maj >= self.p_top)]
minor_ticks = self._pres_min[(self._pres_min <= self.p_bot) & (self._pres_min >= self.p_top)]
labels = [f"{int(_x / 100)}"
if (_x / 100) - int(_x / 100) == 0 else f"{float(_x / 100)}" for _x in major_ticks]
if len(labels) > 20:
labels = ["" if x.split(".")[-1][0] in "975" else x for x in labels]
labels = [f"{_x / 100:.0f}" if _x / 100 >= 1 else (
f"{_x / 100:.1f}" if _x / 100 >= 0.1 else (
f"{_x / 100:.2f}" if _x / 100 >= 0.01 else (
f"{_x / 100:.3f}"))) for _x in major_ticks]
if len(labels) > 40:
labels = ["" if any(y in x for y in "9865") else x for x in labels]
elif len(labels) > 20:
labels = ["" if any(y in x for y in "975") else x for x in labels]
elif len(labels) > 10:
labels = ["" if x.split(".")[-1][0] in "9" else x for x in labels]
labels = ["" if "9" in x else x for x in labels]
ylabel = "pressure (hPa)"
elif typ == "pressure altitude":
bot_km = thermolib.pressure2flightlevel(self.p_bot * units.Pa).to(units.km).magnitude
top_km = thermolib.pressure2flightlevel(self.p_top * units.Pa).to(units.km).magnitude
ma_dist, mi_dist = 4, 1.0
ma_dist, mi_dist = 5, 1.0
if (top_km - bot_km) <= 20:
ma_dist, mi_dist = 1, 0.5
elif (top_km - bot_km) <= 40:
ma_dist, mi_dist = 2, 0.5
major_heights = np.arange(0, top_km + 1, ma_dist)
minor_heights = np.arange(0, top_km + 1, mi_dist)
elif (top_km - bot_km) <= 60:
ma_dist, mi_dist = 4, 1.0
major_heights = np.arange(0, top_km + 0.1, ma_dist)
minor_heights = np.arange(0, top_km + 0.1, mi_dist)
major_ticks = thermolib.flightlevel2pressure(major_heights * units.km).magnitude
minor_ticks = thermolib.flightlevel2pressure(minor_heights * units.km).magnitude
labels = major_heights
ylabel = "pressure altitude (km)"
elif typ == "flight level":
bot_km = thermolib.pressure2flightlevel(self.p_bot * units.Pa).to(units.km).magnitude
top_km = thermolib.pressure2flightlevel(self.p_top * units.Pa).to(units.km).magnitude
ma_dist, mi_dist = 50, 10
ma_dist, mi_dist = 100, 20
if (top_km - bot_km) <= 10:
ma_dist, mi_dist = 20, 10
elif (top_km - bot_km) <= 40:
ma_dist, mi_dist = 40, 10
major_fl = np.arange(0, 2132, ma_dist)
minor_fl = np.arange(0, 2132, mi_dist)
elif (top_km - bot_km) <= 60:
ma_dist, mi_dist = 50, 10
major_fl = np.arange(0, 3248, ma_dist)
minor_fl = np.arange(0, 3248, mi_dist)
major_ticks = thermolib.flightlevel2pressure(major_fl * units.hft).magnitude
minor_ticks = thermolib.flightlevel2pressure(minor_fl * units.hft).magnitude
labels = major_fl
Expand Down
1 change: 1 addition & 0 deletions mslib/msui/qt5/ui_sideview_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def setupUi(self, SideViewOptionsDialog):
self.sbPtop.setSizePolicy(sizePolicy)
self.sbPtop.setMinimum(0.0)
self.sbPtop.setMaximum(2132.0)
self.sbPtop.setDecimals(4)
self.sbPtop.setProperty("value", 200.0)
self.sbPtop.setObjectName("sbPtop")
self.horizontalLayout.addWidget(self.sbPtop)
Expand Down
11 changes: 6 additions & 5 deletions mslib/msui/sideview.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,15 +148,16 @@ def onTransparencyChanged(self, value):
self.line_transparency = value / 100

def setBotTopLimits(self, axis_type):
bot, top = {
"maximum": (0, 2132),
"pressure": (0.1, 1050),
"pressure altitude": (0, 65),
"flight level": (0, 2132),
bot, top, dec = {
"maximum": (0, 3248, 4),
"pressure": (0.0003, 1050, 4),
"pressure altitude": (0, 99.9, 1),
"flight level": (0, 3248, 0),
}[axis_type]
for button in (self.sbPbot, self.sbPtop):
button.setMinimum(bot)
button.setMaximum(top)
button.setDecimals(dec)

def setColour(self, which):
"""
Expand Down
24 changes: 13 additions & 11 deletions mslib/msui/ui/ui_sideview_options.ui
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@
<property name="suffix">
<string> hpa</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
Expand Down Expand Up @@ -168,7 +171,6 @@
<widget class="QGroupBox" name="groupBox_2">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
Expand Down Expand Up @@ -236,10 +238,10 @@
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
<enum>QFrame::Shadow::Raised</enum>
</property>
<widget class="QLabel" name="label_8">
<property name="geometry">
Expand Down Expand Up @@ -267,7 +269,7 @@
<number>80</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
<widget class="QLabel" name="label_10">
Expand Down Expand Up @@ -413,7 +415,7 @@
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
Expand Down Expand Up @@ -459,7 +461,7 @@
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
Expand Down Expand Up @@ -508,10 +510,10 @@
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
<enum>QSizePolicy::Policy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
Expand Down Expand Up @@ -606,7 +608,7 @@
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
Expand Down Expand Up @@ -815,10 +817,10 @@
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
</property>
</widget>
</item>
Expand Down
14 changes: 7 additions & 7 deletions mslib/utils/thermolib.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def omega_to_w(omega, p, t):
(51 * units.km, 270.65 * units.K, 66.9389 * units.Pa, 0.0028 * units.K / units.m),
(71 * units.km, 214.65 * units.K, 3.95642 * units.Pa, 0.002 * units.K / units.m),
(84.852 * units.km, 186.95 * units.K, 0.3734 * units.Pa, 0 * units.K / units.m),
(100 * units.km, 186.95 * units.K, 0.025641 * units.Pa, np.nan * units.K / units.m),
(100 * units.km, 186.95 * units.K, 0.0238725468 * units.Pa, np.nan * units.K / units.m),
]
_HEIGHT, _TEMPERATURE, _PRESSURE, _TEMPERATURE_GRADIENT = 0, 1, 2, 3

Expand Down Expand Up @@ -186,8 +186,8 @@ def flightlevel2pressure(height):
p[indices] = p0 * np.exp(-g * (height[indices] - z0) / (Rd * t0))

if np.isnan(p).any():
raise ValueError("flight level to pressure conversion not "
"implemented for z > 71km")
raise ValueError("flight level to pressure conversion not implemented for z >= 100km " +
str(np.max(height)))

return p if is_array else p[0]

Expand Down Expand Up @@ -238,8 +238,8 @@ def pressure2flightlevel(pressure):
z[indices] = z0 - (Rd * t0) / g * np.log(pressure[indices] / p0)

if np.isnan(z).any():
raise ValueError("pressure to flight level conversion not "
"implemented for p < 0.025641 Pa")
raise ValueError("pressure to flight level conversion not implemented for p <= 0.0238725468 Pa " +
str(np.min(pressure)))

return z if is_array else z[0]

Expand All @@ -264,8 +264,8 @@ def isa_temperature(height):
if ((i == 0) and (height < z0)) or (z0 <= height < z1):
return t0 - gamma * (height - z0)

raise ValueError("ISA temperature from flight level not "
"implemented for z > 100 km")
raise ValueError("ISA temperature from flight level not implemented for z >= 100 km " +
str(np.max(height)))


def convert_pressure_to_vertical_axis_measure(vertical_axis, pressure):
Expand Down
13 changes: 9 additions & 4 deletions tests/_test_utils/test_thermolib.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@


def test_flightlevel2pressure2flightlevel():
fs = (np.arange(1, 95000, 1000.) * units.m).to(units.hft)
fs = (np.arange(1, 99900, 100.) * units.m).to(units.hft)
ps = thermolib.flightlevel2pressure(fs)
fs_p = thermolib.pressure2flightlevel(ps).magnitude
assert fs.magnitude == pytest.approx(fs_p)
Expand All @@ -44,6 +44,10 @@ def test_pressure2flightlevel2pressure():
fs = thermolib.pressure2flightlevel(ps)
ps_p = thermolib.flightlevel2pressure(fs).magnitude
assert ps.magnitude == pytest.approx(ps_p)
ps = np.arange(0.024, 1, 0.001)[::-1] * units.Pa
fs = thermolib.pressure2flightlevel(ps)
ps_p = thermolib.flightlevel2pressure(fs).magnitude
assert ps.magnitude == pytest.approx(ps_p)


def test_flightlevel2pressure():
Expand All @@ -54,7 +58,7 @@ def test_flightlevel2pressure():
assert thermolib.flightlevel2pressure(1626.8966 * units.hft).magnitude == pytest.approx(80)
assert thermolib.flightlevel2pressure(1804.2727 * units.hft).magnitude == pytest.approx(40)
with pytest.raises(ValueError):
thermolib.flightlevel2pressure(102000 * units.m)
thermolib.flightlevel2pressure(100000 * units.m)


def test_pressure2flightlevel():
Expand All @@ -80,15 +84,16 @@ def test_isa_temperature():
assert thermolib.isa_temperature(700 * units.hft).magnitude == pytest.approx(217.986)
assert thermolib.isa_temperature(800 * units.hft).magnitude == pytest.approx(221.034)
assert thermolib.isa_temperature(1000 * units.hft).magnitude == pytest.approx(227.13)
with pytest.raises(ValueError):
thermolib.isa_temperature(100001 * units.m)
assert thermolib.isa_temperature(11000 * units.m).magnitude == pytest.approx(216.65)
assert thermolib.isa_temperature(20000 * units.m).magnitude == pytest.approx(216.65)
assert thermolib.isa_temperature(32000 * units.m).magnitude == pytest.approx(228.65)
assert thermolib.isa_temperature(47000 * units.m).magnitude == pytest.approx(270.65)
assert thermolib.isa_temperature(51000 * units.m).magnitude == pytest.approx(270.65)
assert thermolib.isa_temperature(71000 * units.m).magnitude == pytest.approx(214.65)
assert thermolib.isa_temperature(84852 * units.m).magnitude == pytest.approx(186.95)
assert thermolib.isa_temperature(99999 * units.m).magnitude == pytest.approx(186.95)
Copy link
Member

@ReimarBauer ReimarBauer Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this the same value pytest.approx(186.95) as the line before? Seeing that other checks show this pattern too. it looks like a range which gives the same result.

Is that 99999 a 99.999 with fractions? (I can't enter that in the UI)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conversion routine works from 0 to 99999m/99.999km (effectively for any number < 100km).
I changed the order of the tests to make this more apparent.

The SideView goes only to 99km as we add internally 1km to the selected top height to define the grid.
But this can be improved upon. I just changed the code to allow values up to 99.9km and changed the precision to be dependent on the type, ie for pressure_altitude, a single digit is allowed. 4 digits is only allowed for pressure, where this is necessary for the large altitudes.

I also adapted the code to allow smaller pressures, as previously above 99km the pressure could not be converted back to km.

with pytest.raises(ValueError):
thermolib.isa_temperature(100000 * units.m)


class TestConverter:
Expand Down
Loading