diff --git a/aosstower/level_b1/__init__.py b/aosstower/level_b1/daily/__init__.py similarity index 100% rename from aosstower/level_b1/__init__.py rename to aosstower/level_b1/daily/__init__.py diff --git a/aosstower/level_b1/autoRun.bash b/aosstower/level_b1/daily/autoRun.bash similarity index 89% rename from aosstower/level_b1/autoRun.bash rename to aosstower/level_b1/daily/autoRun.bash index 2987a7c16ca6fe8208774095dda88da2460e9b46..fd01b48a8a126d31f7f7b6801f6a200737c763cc 100755 --- a/aosstower/level_b1/autoRun.bash +++ b/aosstower/level_b1/daily/autoRun.bash @@ -1,6 +1,6 @@ #!/usr/bin/env bash PYENV=~/anaconda3/envs/env -SCRIPT=/home/kgao/Code/curr_projects/ncGenerate/AossTower/aosstower/level_a0/autoRun.py +SCRIPT=/home/kgao/Code/curr_projects/ncGenerate/AossTower/aosstower/level_b1/autoRun.py ( flock -x -n 200 || exit $? $PYENV/bin/python $SCRIPT diff --git a/aosstower/level_b1/autoRun.py b/aosstower/level_b1/daily/autoRun.py similarity index 100% rename from aosstower/level_b1/autoRun.py rename to aosstower/level_b1/daily/autoRun.py diff --git a/aosstower/level_b1/bundle.py b/aosstower/level_b1/daily/bundle.py similarity index 100% rename from aosstower/level_b1/bundle.py rename to aosstower/level_b1/daily/bundle.py diff --git a/aosstower/level_b1/bundle.pyc b/aosstower/level_b1/daily/bundle.pyc similarity index 100% rename from aosstower/level_b1/bundle.pyc rename to aosstower/level_b1/daily/bundle.pyc diff --git a/aosstower/level_b1/daily/calc.py b/aosstower/level_b1/daily/calc.py new file mode 100644 index 0000000000000000000000000000000000000000..322c037ec41ac12a586544e4f247cff85f05b303 --- /dev/null +++ b/aosstower/level_b1/daily/calc.py @@ -0,0 +1,144 @@ +import math + +import numpy as np + +NaN = float('nan') +is_nan = lambda a: a != a + + +def dewpoint(tempC, relhum): + """ + Algorithm from Tom Whittaker tempC is the temperature in degrees Celsius, + relhum is the relative humidity as a percentage. + + :param tempC: temperature in celsius + :param relhum: relative humidity as a percentage + """ + if tempC 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)) + + return min(dp - 273.15, tempC) + + +def relhum(airTempK, dewpointTempK): + """ + Algorithm derived by David Hoese from the above + dewpoint(tempC, relhum) function, both parameters are in Kelvin units. + + :param airTempK: air temperature in Kelvin + :param dewpointTempK: dewpoint temp in Kelvin + """ + if airTempK == None or dewpointTempK == 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 + + +def potentialtemp(airTempK, pressureMB): + """ + Algorithm from David Hoese to calculate potential temperature. + + :param airTempK: air temperature in Kelvin + :param pressureMB: air pressure in millibars + """ + if airTempK == None or pressureMB == None: + return NaN + + pT = airTempK * (pressureMB.max() / pressureMB) ** .286 + + return pT + + +def altimeter(p, alt): + """Compute altimeter from pressure and altitude. + + Converted from code provided by TomW. + + :param p: pressure in hPa. + :param alt: altitude of the measurement in meters. + + :returns: altimeter in inHg + """ + n = .190284 + c1 = .0065 * pow(1013.25, n) / 288. + c2 = alt / pow((p - .3), n) + ff = pow(1. + c1 * c2, 1. / n) + return ((p - .3) * ff * 29.92 / 1013.25) + + +def dir2txt(val): + """Convert degrees [0, 360) to a textual representation. + + :param val: decimal degrees + + >>> dir2txt(0) + 'N' + >>> dir2txt(90) + 'E' + >>> dir2txt(180) + 'S' + >>> dir2txt(270) + 'W' + >>> 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 ((val >= 348.75 and val <= 360) or val >= 0 and val < 11.25): return "N" + + # 1/2 degree increment between the directions + i = 11.25; + for dir in dirs: + if val >= i and val < (i + 22.5): + return dir + i += 22.5 + + +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. + + 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 + + +def wind_vector_degrees(vector_east, vector_north): + """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): + winddir[np.less(winddir, 0)] += 360 + elif winddir < 0: + winddir += 360 + return winddir % 360 + + +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)) + + return avg_dir, np.mean(V_spd) diff --git a/aosstower/level_b1/nc.py b/aosstower/level_b1/daily/nc.py similarity index 100% rename from aosstower/level_b1/nc.py rename to aosstower/level_b1/daily/nc.py diff --git a/aosstower/level_b1/nc.pyc b/aosstower/level_b1/daily/nc.pyc similarity index 100% rename from aosstower/level_b1/nc.pyc rename to aosstower/level_b1/daily/nc.pyc diff --git a/aosstower/level_b1/test_cases.txt b/aosstower/level_b1/daily/test_cases.txt similarity index 100% rename from aosstower/level_b1/test_cases.txt rename to aosstower/level_b1/daily/test_cases.txt diff --git a/aosstower/schema.py b/aosstower/schema.py index c3f3437d89c9ae02b6a75f46d04feac57d325b00..b89f72beaa763037fde6ec8e6b043ce21fdde2c5 100644 --- a/aosstower/schema.py +++ b/aosstower/schema.py @@ -2,7 +2,7 @@ from numpy import float32 from collections import namedtuple -Var = namedtuple('Var', ['type', 'standard_name', 'name', 'description', 'units']) +Var = namedtuple('Var', ['type', 'standard_name', 'name', 'description', 'units', 'valid_min', 'valid_max']) database = dict( @@ -17,31 +17,44 @@ database = dict( 'air_pressure', 'box_pressure', 'Pressure inside the data logger enclosure', - 'hPa'), + 'hPa', + '850', + '1100'), paro_air_temp_period=Var( float32, '', 'paro_air_temp_period', '', - '1'), + '1', + '', + '' + ), paro_pressure_period=Var( float32, '', 'paro_pressure_period', '', - '1'), + '1', + '', + ''), paro_air_temp=Var( float32, 'air_temperature', 'paro_air_temp', '', - 'degC'), + 'degC', + '-50', + '50' + ), pressure=Var( float32, 'air_pressure', 'pressure', 'Air pressure as measured from the PAROSCI pressure sensor', - 'hPa'), + 'hPa', + '850', + '1100' + ), paro_cal_sig=Var( float32, '', @@ -53,111 +66,172 @@ database = dict( 'relative_humidity', 'box_rh', 'Relative humidity inside the data logger enclosure', - '%'), + '%', + '0', + '100' + ), box_air_temp=Var( float32, 'air_temperature', 'box_air_temp', 'Air temperature inside the data logger enclosure', - 'degC'), + 'degC', + '-50', + '50' + ), air_temp_2=Var( float32, 'air_temperature', 'air_temp_2', 'Auxillary air temperature', - 'degC'), + 'degC', + '-50', + '50', + ), air_temp_3=Var( float32, 'air_temperature', 'air_temp_3', 'Auxillary air temperature', - 'degC'), + 'degC', + '-50', + '50' + ), air_temp_4=Var( float32, 'air_temperature', 'air_temp_4', 'Auxillary air temperature', - 'degC'), + 'degC', + '-50', + '50' + ), air_temp_5=Var( float32, 'air_temperature', 'air_temp_5', 'Auxillary air temperature', - 'degC'), + 'degC', + '-50', + '50' + ), wind_speed=Var( float32, 'wind_speed', 'wind_speed', 'Wind speed', - 'm*s^-1'), + 'm*s^-1', + '0', + '50' + ), wind_dir=Var( float32, 'wind_direction', 'wind_dir', 'Wind direction', - 'degrees'), + 'degrees', + '0', + '360' + ), rh_shield_freq=Var( float32, '', 'rh_shield_freq', '', - 'hz'), + 'hz', + '', + '' + ), rh=Var( float32, 'relative_humidity', 'rh', 'Relative humidity', - '%'), + '%', + '0', + '100' + ), air_temp_6_3m=Var( float32, 'air_temperature', 'air_temp_6_3m', 'Air temperature 6.3m from tower base', - 'degC'), + 'degC', + '-50', + '50' + ), dewpoint=Var( float32, 'dewpoint_temperature', 'dewpoint', 'Calculated dewpoint temperature', - 'degC'), + 'degC', + '-50', + '50'), rtd_shield_freq=Var( float32, '', 'rtd_shied_freq', '', - ''), + '', + '', + '' + ), air_temp=Var( float32, 'air_temperature', 'air_temp', 'Air temperature', - 'degC'), + 'degC', + '-50', + '50' + ), solar_flux=Var( float32, 'solar_flux', 'solar_flux', 'Solar flux', - 'w*m^-2'), + 'w*m^-2', + '0', + '3000'), precip=Var( float32, '', 'precip', 'Precipitation', - 'mm'), + 'mm', + '0', + '254' + ), accum_precip=Var( float32, 'accumulated_precipitation', 'accum_precip', 'Precipitation accumulated since 0Z', - 'mm'), + 'mm', + '0', + '254' + ), altimeter=Var( float32, '', 'altimeter', '', - 'inHg') + 'inHg', + '', + '' + ), + gust=Var( + float32, + 'wind_speed_of_gust', + 'gust', + 'Wind gust over the previous 2 minutes', + 'm/s', + '0', + '50' + ) ) met_vars = {'air_temp', 'rh', 'solar_flux', 'pressure', 'precip', 'accum_precip', 'wind_speed', 'wind_dir'} -engr_vars = set(database.keys()) - met_vars \ No newline at end of file +engr_vars = set(database.keys()) - met_vars