diff --git a/aosstower/level_b1/calc.py b/aosstower/level_b1/calc.py index 28bcda711c144603dc831988d4f0ae6eff3d4f21..ffb24cb2458b1a51318b699710efc73fd124dcc2 100644 --- a/aosstower/level_b1/calc.py +++ b/aosstower/level_b1/calc.py @@ -21,58 +21,54 @@ def knots_to_mps(knots): return knots * 0.51444 -def dewpoint(tempC, relhum): - """Algorithm from Tom Whittaker tempC is the temperature in degrees Celsius, - relhum is the relative humidity as a percentage. +def dewpoint(temp_c, relhum): + """Convert air temperature and relative humidity to dewpoint. - :param tempC: temperature in celsius + Algorithm from Tom Whittaker. + + :param temp_c: temperature in celsius :param relhum: relative humidity as a percentage """ - if tempC is None or relhum is None: + if temp_c is None or relhum is None: return NaN gasconst = 461.5 latheat = 2500800.0 - dp = 1.0 / (1.0 / (273.15 + tempC) - gasconst * np.log((0.0 + relhum) / 100) / (latheat - tempC * 2397.5)) + dp = 1.0 / (1.0 / (273.15 + temp_c) - gasconst * np.log((0.0 + relhum) / 100) / (latheat - temp_c * 2397.5)) if pd is not None and isinstance(dp, pd.Series): - return pd.concat([dp - 273.15, tempC], axis=1).min(axis=1) - return np.min(dp - 273.15, tempC) + return pd.concat([dp - 273.15, temp_c], axis=1).min(axis=1) + return np.min(dp - 273.15, temp_c) -def relhum(airTempK, dewpointTempK): - """Algorithm derived by David Hoese from the above - dewpoint(tempC, relhum) function, both parameters are in Kelvin units. +def relhum(air_temp_k, dewpoint_temp_k): + """Calculate relative humidity from air temperature and dewpoint temperature. - :param airTempK: air temperature in Kelvin - :param dewpointTempK: dewpoint temp in Kelvin + :param air_temp_k: air temperature in Kelvin + :param dewpoint_temp_k: dewpoint temp in Kelvin """ - if airTempK is None or dewpointTempK is None: + if air_temp_k is None or dewpoint_temp_k is None: return NaN gas_constant = 461.5 latheat = 2500800.0 # Only one section of the equation - latpart = latheat - (airTempK - 273.15) * 2397.5 - relativehum = 100 * math.e ** ((latpart / airTempK - latpart / dewpointTempK) / gas_constant) - - return relativehum + latpart = latheat - (air_temp_k - 273.15) * 2397.5 + return 100 * math.e ** ((latpart / air_temp_k - latpart / dewpoint_temp_k) / gas_constant) -def potentialtemp(airTempK, pressureMB): +def potentialtemp(air_temp_k, pressure_mb): """Algorithm from David Hoese to calculate potential temperature. - :param airTempK: air temperature in Kelvin - :param pressureMB: air pressure in millibars + :param air_temp_k: air temperature in Kelvin + :param pressure_mb: air pressure in millibars """ - if airTempK is None or pressureMB is None: + if air_temp_k is None or pressure_mb is None: return NaN - pT = airTempK * (pressureMB.max() / pressureMB) ** 0.286 - - return pT + return air_temp_k * (pressure_mb.max() / pressure_mb) ** 0.286 def altimeter(p, alt): @@ -108,44 +104,44 @@ def dir2txt(val): >>> dir2txt(359) 'N' """ - assert val >= 0 and val < 360, "'%s' out of range" % val - dirs = ("NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW") + if not (val >= 0 and val < 360): # noqa: PLR2004 + msg = f"'{val}' out of range" + raise ValueError(msg) + cardinal_dirs = ("NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW") - if (val >= 348.75 and val <= 360) or val >= 0 and val < 11.25: + if (val >= 348.75 and val <= 360) or val >= 0 and val < 11.25: # noqa: PLR2004 return "N" # 1/2 degree increment between the directions i = 11.25 - for dir in dirs: + for card_dir in cardinal_dirs: if val >= i and val < (i + 22.5): - return dir + return card_dir i += 22.5 return None def wind_vector_components(windspd, winddir): - """Decompose scalar or list/array polar wind direction and speed data - into the horizontal and vertical vector components and speed vector. + """Decompose polar wind direction and speed into the horizontal and vertical vector components and speed vector. Inputs can be scalar or arrays. """ dir_rad = np.deg2rad(winddir) spd_arr = np.array(windspd) - V_e = spd_arr * np.sin(dir_rad) - V_n = spd_arr * np.cos(dir_rad) - U_spd = np.sqrt(pow(V_e, 2) + pow(V_n, 2)) - return V_e, V_n, U_spd + v_e = spd_arr * np.sin(dir_rad) + v_n = spd_arr * np.cos(dir_rad) + u_spd = np.sqrt(pow(v_e, 2) + pow(v_n, 2)) + return v_e, v_n, u_spd def wind_vector_degrees(vector_east, vector_north): - """Re-compose horizontal (east/west) and vertical (north/south) vector - components into wind direction in degrees. + """Re-compose horizontal (east/west) and vertical (north/south) vector components into wind direction in degrees. Inputs can be scalar or arrays. """ rads = np.arctan2(vector_east, vector_north) winddir = np.rad2deg(rads) - if isinstance(winddir, (np.ndarray, Series)): + if isinstance(winddir, np.ndarray | Series): winddir[np.less(winddir, 0)] += 360 elif winddir < 0: winddir += 360 @@ -153,7 +149,7 @@ def wind_vector_degrees(vector_east, vector_north): def mean_wind_vector(windspd, winddir): - V_e, V_n, V_spd = wind_vector_components(windspd, winddir) - avg_dir = wind_vector_degrees(np.mean(V_e), np.mean(V_n)) + v_e, v_n, v_spd = wind_vector_components(windspd, winddir) + avg_dir = wind_vector_degrees(np.mean(v_e), np.mean(v_n)) - return avg_dir, np.mean(V_spd) + return avg_dir, np.mean(v_spd)