def leafWetnessFromTemps(temp, dewpt, temp_units='F'): # use dewpoint depression as a prozy for leaf wetness if temp_units == 'F': tdd = temp - dewpt else: tmp = convertUnits(temp, temp_units, 'F') dpt = convertUnits(dewpt, temp_units, 'F') tdd = tmp - dpt # need a wetness array filled with zeros for the entire time span wetness = N.zeros(tdd.shape, dtype='<i2') # array for track whether leaves were wet in a previous iteration last_wet = N.zeros(tdd.shape[1:], dtype='<i2') # need to process one time period per iteration for i in range(tdd.shape[0]): # leaves are wet at nodes with dew point depression less than 3 degrees where = N.where(tdd[i,:,:] < 3) wetness[i][where] = 1 # add nodes where leaves were wet on previous day wetness[i][N.where(last_wet == 1)] = 1 # track only where dewpoint criteria were met on this day last_wet.fill(0) # reset last_wet array to zeros first last_wet[where] = 1 return wetness
def threatIndex(self, temp, rhum, precip, tmp_units='C', pcpn_units='in'): """ Dollar Spot utilizes 3-day and 2-day averages and counts in order to calculate threat index. Therefore, hourly data arrays must begin 72 hours before the expected first day in results. NOTE: One day is 24 hours ending at 7AM. Arguments: temp: hourly temperatures rhum: hourly relative humidity precip: hourly precipitation tmp_units: units for temperature data. Default is 'C'. Calculations require degrees 'C' (Celsius). However, input data in degrees 'K' (Kelvin) or 'F' (Fahrenheit) may be passed and will be converted for use in the calculations. pcpn_units: units for precipitation data. Default is 'in'. Calculations require 'in' (inches of rainfall). However, input data in kilograms per square meter ('kg m**-2' or 'kg^m**-2') may be passed and will be converted to 'in' for use in the calculations. Argument types: 3D NumPy array : multiple days at multiple points 2D NumPy array : same day at multiple points 1D NumPy array : multiple days at single point NOTE: input arrays must : 1) have the same dimensions 2) be dtype=float 3) have missing value == numpy.nan Returns: NumPy array containing threat index at each node. """ if tmp_units == 'C': tmp = temp else: tmp = convertUnits(temp, tmp_units, 'C') if self.debug: print '\n\nDollarSpot.threatIndex ...' print ' hourly temp shape :', tmp.shape print ' hourly rhum shape :', rhum.shape print ' hourly precip shape :', precip.shape if pcpn_units == 'in': pcpn = precip else: pcpn = convertUnits(pcpn, pcpn_units, 'in') # calulate RH component of threat index rhum_component = self.rhumComponent(*self.rhumFactors(rhum, tmp, 'C')) # calculate component due to interaction of precip and avg temp precip_factors = self.precipFactors(pcpn, tmp, 'in', 'C') precip_component = self.precipComponent(*precip_factors[:-1]) # calculate wet_count factor of threat index wetness_component = \ self.wetnessComponent(*self.wetnessFactors(precip, tmp, 'in', 'C')) return self.componentsToThreatIndex(rhum_component, precip_component, wetness_component)
def mixingRatio(pressure, dewpt, p_units='hPa', t_units='K'): """ calculate mixing ratio arguments: pressure in millibars (hectopascals) dew point in degrees Kelvin """ dpt = convertUnits(dewpt, t_units, 'K') p = convertUnits(pressure, p_units, 'hPa') e = (0.0000000000253) * N.exp(-5420. / dpt) e_pressure = e / 100. return ((0.622 * e_pressure) / (p - e_pressure)) * 1000.
def windChill(speed, temp, s_units='mph', t_units='F'): t_type, t = asArray(temp) t = convertUnits(t, t_units, 'K') s_type, spd = asArray(speed) spd = convertUnits(spd, s_units, 'mph') if isinstance(t, N.ndarray): spd_factor = N.power(spd * 35.75, 0.16) tspd_factor = N.power(t * spd * 0.4276, 0.16) else: spd_factor = math.pow(spd * 35.75, 0.16) tspd_factor = math.pow(t * spd * 0.4276, 0.16) t_factor = t * 0.6215 return t_factor - spd_factor + tspd_factor + 35.74
def leafWetness(self, temp, dewpt, pcpn, temp_units, pcpn_units): # make sure that temperature and dew point units are correct tmp_units = self.config.units.tmp if temp_units == tmp_units: tmp = temp dpt = dewpt else: tmp = convertUnits(temp, temp_units, tmp_units) dpt = convertUnits(dewpt, temp_units, tmp_units) # dew point depression is one proxy for leaf wetness tdd = temp - dewpt # make sure that precip units are correct precip_units = self.config.units.pcpn if pcpn_units == precip_units: precip = pcpn else: precip = convertUnits(pcpn, pcpn_units, precip_units) # adjustment for minimum effective precipitation precip[N.where(precip < self.config.min_precip)] = 0 # precipitation is the other proxy # need a wetness array filled with zeros for the entire time span wetness = N.zeros(pcpn.shape, dtype='<i2') # array to track whether leaves were wet in a previous iteration last_wet = N.zeros(pcpn.shape[1:], dtype='<i2') # need to process one time period per iteration for i in range(tdd.shape[0]): # leaves are wet wherever precip is greater than zero pcpn_where = N.where(pcpn[i,:,:] > 0) wetness[i][pcpn_where] = 1 # also include nodes with dew point depression less than 3 degrees tdd_where = N.where(tdd[i,:,:] < 3) wetness[i][tdd_where] = 1 # add nodes whereever leaves were wet on the previous day wetness[i][N.where(last_wet == 1)] = 1 # track where only where wetness criteria wre met on this day last_wet.fill(0) # reset last_wet array to zeros first # track where precip criteria were met on this day last_wet[pcpn_where] = 1 # track where dewpoint criteria were met on this day last_wet[tdd_where] = 1 return wetness
def mapDataExtremes(self, variable, start_time, end_time, region, debug, **kwargs): lons, lats, data_units, data = \ self.timeSlice(variable, start_time, end_time, lonlat=True) map_units = kwargs.get('units', data_units) if map_units != data_units: data = convertUnits(data, data_units, map_units) options = self.mapOptions(variable, start_time, end_time, region) title_template = options['title'] arg_dict = { 'summary': 'Min', } options['title'] = title_template % arg_dict options['outputfile'] = \ self.mapFilepath(end_time, variable, region, **arg_dict) min_filepath = self.drawScatterMap(lons, lats, N.nanmin(data, axis=0), start_time, end_time, options, debug) arg_dict = { 'summary': 'Max', } options['title'] = title_template % arg_dict options['outputfile'] = \ self.mapFilepath(end_time, variable, region, **arg_dict) max_filepath = self.drawScatterMap(lons, lats, N.nanmax(data, axis=0), start_time, end_time, options, debug) return min_filepath, max_filepath
def mapDataTotals(self, variable, start_time, end_time, region, debug, **kwargs): lons, lats, data_units, data = \ self.timeSlice(variable, start_time, end_time, lonlat=True) map_units = kwargs.get('units', data_units) if map_units != data_units: data = convertUnits(data, data_units, map_units) options = self.mapOptions(variable, start_time, end_time, region) title_template = options['title'] if variable in ('pcpn', 'PCPN'): arg_dict = { 'summary': 'Accumulated', } else: arg_dict = { 'summary': 'Total', } options['title'] = title_template % arg_dict options['outputfile'] = \ self.mapFilepath(end_time, variable, region, **arg_dict) return self.drawScatterMap(lons, lats, N.nansum(data, axis=0), start_time, end_time, options, debug)
def potentialTemp(temp, pressure, t_units='K', p_units='hPa'): """ calculate theta (potential temperature) arguments: pressure in millibars (hectopascals) temperature in degrees Kelvin """ t_type, t = asArray(temp) t = convertUnits(t, t_units, 'K') if isinstance(t, N.ndarray): p_type, p = asArray(pressure) p = convertUnits(p, p_units, 'hPa') pt = t * N.power((1000. / p), 0.286) else: p = convertUnits(p, p_units, 'hPa') pt = t * math.pow((1000. / p), 0.286) return pt
def dptDepression(temp, rhum, temp_units='K'): t_type, t = asArray(temp) t = convertUnits(t, t_units, 'K') if isinstance(t, N.ndarray): rh_type, rh = asArray(rhum) dpt = dptFromRhumAndTemp(rh, t, 'K') return temp - dewpoint
def _postUnpack(self, dataset_path, data, **kwargs): to_units = kwargs.get('units', None) if to_units is not None: from_units = self.getDatasetUnits(dataset_path) if from_units is not None: data = convertUnits(data, from_units, to_units) return data
def tempToVaporPressure(temp, t_units='K'): # calcutate vapor pressure from temperature t_type, t = asArray(temp) t = convertUnits(t, t_units, 'K') if isinstance(t, N.ndarray): return E0 * N.exp(LRv * (T0inv - N.power(t, -1.0))) else: return E0 * N.exp(LRv * (T0inv - (1.0 / t)))
def dptFromRhum(rhum, temp, t_units='K'): rh_type, rh = asArray(rhum) # saturation vapor pressure (sat_vp) sat_vp = tempToVaporPressure(temp, t_units) if isinstance(rh, N.ndarray): # actual vapor pressure (vp) rh = filterRhum(rh, True) vp = (rh * sat_vp) / 100. # convert to Rhum and match imcoming units return convertUnits(N.power((T0inv - (N.log(vp / E0) / LRv)), -1.0), t_units) else: if rh <= 0: vp = N.nan else: vp = (rh * sat_vp) / 100. # convert to Rhum and match imcoming units return convertUnits(N.power((T0inv - (math.log(vp / E0) / LRv)), -1.0), t_units)
def vWind(speed, wdir, s_units='m/s'): """ calcualte v (Meridional Velocity) component of wind vector """ s_type, spd = asArray(speed) spd = convertUnits(spd, s_units, 'm/s') if isinstance(spd, N.ndarray): d_type, wdir = asArray(directon) return spd * -N.cos(N.radians(wdir)) else: return spd * -math.cos(math.radians(direction))
def windComponents(speed, wdir, s_units='m/s'): s_type, spd = asArray(speed) spd = convertUnits(spd, s_units, 'm/s') if isinstance(spd, N.ndarray): d_type, wdir = asArray(directon) u = spd * -N.sin(N.radians(wdir)) v = spd * -N.cos(N.radians(wdir)) else: u = spd * -math.sin(math.radians(direction)) v = spd * -math.cos(math.radians(direction)) return u, v
def heatIndex(temp, rhum, t_units='F'): """ calculate heat index using formulas laid out on NOAA web page http://www.hpc.ncep.noaa.gov/html/heatindex_equation.shtml arguments: temperature in degrees Fahrenheit humidity in (as a decimal number 0 to 100) """ t_type, t = asArray(temp) t = convertUnits(t, t_units, 'F') # sequence was input if isinstance(t, N.ndarray): rh_type, rh = asArray(rhum) # only temps above 80 F may have an associated Heat Index indexes = N.where(t >= 80.) if len(indexes) > 0 and len(indexes[0]) > 0: heat = N.array(t) rh80 = rh[indexes] rh80_sq = rh80 * rh80 t80 = t[indexes] t80_sq = t80 * t80 heat[indexes] = ( -42.379 + (2.04901523 * t80) + (10.14333127 * rh80) + (-0.22475541 * t80 * rh80) + (-6.83783e-03 * t80_sq) + (-5.481717e-02 * rh80_sq) + (1.22874e-03 * t80_sq * rh80) + (8.5282e-04 * t80 * rh80_sq) + (-1.99e-06 * t80_sq * rh80_sq)) lh_indexes = N.where(rh < 13. & t >= 80. & t <= 112.) if len(lh_indexes) > 0 and len(lh_indexes[0]) > 0: heat[lh_indexes] -= (((13. - rh[lh_indexes]) / 4.) * N.sqrt( (17. - N.absolute(t[lh_indexes] - 95.)) / 17.)) hh_indexes = N.where(rh > 85. & t >= 80. & t <= 87.) if len(hh_indexes) > 0 and len(hh_indexes[0]) > 0: heat[hh_indexes] += (((rh[hh_indexes] - 85.) / 10.) * ((87. - t[hh_indexes]) / 5.)) return heat # all temps are below 80 F else: return t # assume we got a single value if (t < 80): return t # only temps above 80 F may have an associated Heat Index rh80_sq = rhum * rhum t80_sq = t * t heat = (-42.379 + (2.04901523 * t) + (10.14333127 * rhum) + (-0.22475541 * t * rhum) + (-6.83783e-03 * t80_sq) + (-5.481717e-02 * rh80_sq) + (1.22874e-03 * t80_sq * rhum) + (8.5282e-04 * t * rh80_sq) + (-1.99e-06 * t80_sq * rh80_sq)) if rhum < 13. and t >= 80. and t <= 112.: heat -= (((13. - rhum) / 4.) * math.sqrt((17. - abs(t - 95.)) / 17.)) elif rhum > 85. and t >= 80. and t <= 87.: heat += (((rhum - 85.) / 10.) * ((87. - t) / 5.)) return heat
def leafWetness(precip, temp, dewpt, pcpn_units='in', temp_units='F'): if pcpn_units == 'in': pcpn = precip else: pcpn = convertUnits(precip, pcpn_units, 'in') # use dewpoint depression as a prozy for leaf wetness if temp_units == 'F': tdd = temp - dewpt else: tmp = convertUnits(temp, temp_units, 'F') dpt = convertUnits(dewpt, temp_units, 'F') tdd = tmp - dpt # need a wetness array filled with zeros for the entire time span wetness = N.zeros(pcpn.shape, dtype='<i2') # array to track whether leaves were wet in a previous iteration last_wet = N.zeros(pcpn.shape[1:], dtype='<i2') # need to process one time period per iteration for i in range(tdd.shape[0]): # leaves are wet wherever precip is greater than zero pcpn_where = N.where(pcpn[i,:,:] > 0) wetness[i][pcpn_where] = 1 # also include nodes with dew point depression less than 3 degrees tdd_where = N.where(tdd[i,:,:] < 3) wetness[i][tdd_where] = 1 # add nodes whereever leaves were wet on the previous day wetness[i][N.where(last_wet == 1)] = 1 # track where only where wetness criteria wre met on this day last_wet.fill(0) # reset last_wet array to zeros first # track where precip criteria were met on this day last_wet[pcpn_where] = 1 # track where dewpoint criteria were met on this day last_wet[tdd_where] = 1 return wetness
def updateDataGrids(factory, utc_time, filepath, debug): # get a reader for the grib file Class = factory.fileAccessorClass('grib', 'read') reader = Class(filepath, factory.grib_source) # update temp tmp_units, temp = extractData(factory, reader, 'TMP', debug) updateGridFile(factory, 'TMP', utc_time, temp, tmp_units, debug) # update dew point dpt_units, dewpt = extractData(factory, reader, 'DPT', debug) updateGridFile(factory, 'DPT', utc_time, dewpt, dpt_units, debug) # update humidity if dpt_units != tmp_units: dpt = convertUnits(dpt, dpt_units, tmp_units) rhum = N.around(rhumFromDpt(temp, dewpt, tmp_units), 2) updateGridFile(factory, 'RHUM', utc_time, rhum, '%', debug)
def equivPotentialTemp(temp, dewpt, pressure, t_units='K', p_units='hpa'): """ calculate theta e (equivalent potential temperature) arguments: pressure in millibars (hectopascals) temperature in degrees Kelvin dew point in degrees Kelvin """ t_type, t = asArray(temp) t = convertUnits(t, t_units, 'K') if isinstance(t, N.ndarray): dpt_type, dpt = asArray(dewpt) dpt = convertUnits(dpt, t_units, 'K') p_type, p = asArray(pressure) p = convertUnits(p, p_units, 'hPa') pt = t * N.power((1000. / p), 0.286) mix_ratio = mixingRatio(p, t, dpt) / 1000. ept = pt * N.exp((0.00000250 * mix_ratio) / (1005. * t)) else: dpt = convertUnits(dewpt, t_units, 'K') p = convertUnits(pressure, p_units, 'hPa') pt = t * math.pow((1000. / p), 0.286) mix_ratio = mixingRatio(p, t, d) / 1000. ept = pt * math.exp((0.00000250 * mix_ratio) / (1005. * t)) return ept
def threatIndex(self, temp, rhum, temp_units='F'): """ Pithium Blight utilizes 2-day averages and counts in order to calculate threat index. Therefore, hourly data arrays must begin at least 48 hours before the first day in results. NOTE: One day is 24 hours ending at 7AM. Arguments: temp: hourly temperatures rhum: hourly relative humidity temp_units: units for temperature array. Default is 'F'. Calculations require degrees 'F' (Fahrenheit). However, input data in degrees 'C' (Celsius) or 'K' (Kelvin) may be passed and will be converted to'F' for use in calculations. Supported types for temp and rhum data: 3D NumPy array : multiple days at multiple points 2D NumPy array : snme day at multiple points 1D NumPy array : multiple days at single point NOTE: temp and rhum arrays must : 1) have the same dimensions 2) be dtype=float 3) have mssing value == N.nan Returns: NumPy array containing daily threat index at each node. """ span = self.config.timespan # number of hours to evaluate per iteration step = self.config.timestep # number of hours to increment b/w interations if temp_units == 'F': tmp = temp else: tmp = convertUnits(temp, temp_units, 'F') maxt = funcs.calcTimespanMax(tmp, step, span) mint = funcs.calcTimespanMin(tmp, step, span) rh89 = funcs.countTimespanGT(rhum, 89, step, span) index = (maxt - 86) + (mint - 68) + (0.5 * (rh89 - 6)) # average threat index over consecutive days span = self.period.num_days # should be 3 or 7 days # get average threat over last 'span' days return funcs.calcTimespanAvg(index, 1, span, 0)
def rhumFactors(self, rhum, temp, tmp_units='C'): """ Calculate the threat factors contributed by the interaction of relative humidity and temperature. NOTE: input arrays must be dtype=float with missing value=NaN Arguments: rhum: hourly relative humidity temp: hourly temperature tmp_units: units for temperature data. Default is 'C'. Calculations require degrees 'C' (Celsius). However, input data in degrees 'K' (Kelvin) or 'F' (Fahrenheit) may be passed and will be converted for use in the calculations. Argument types: 3D NumPy array : multiple hours for multiple grid nodes 2D NumPy array : multiple hours at multple points 1D NumPy array : multiple hours at single point Returns : tuple tuple[0] tupke[1] """ if self.debug: print '\n in rhumFactors ...' # offset for humidity factors offset = self.offsets.rh_factors # should be 0 span = self.timespans.rh_factors # should be 24 hours step = self.timesteps.rh_factors # should be 24 hours # calculate daily avg temp for use in max_rh factor if tmp_units == 'C': tmp = temp else: tmp = convertUnits(temp, tmp_units, 'C') avgt = funcs.calcTimespanAvg(tmp, step, span, offset) if self.debug: print ' avg temp shape :', avgt.shape max_rh = funcs.calcTimespanMax(rhum, step, span, offset) if self.debug: print ' max rh shape :', max_rh.shape return max_rh, avgt, 'C' # avgt units
def leafWetnessFromPrecip(precip, pcpn_units='in'): if pcpn_units == 'in': pcpn = precip else: pcpn = convertUnits(precip, pcpn_units, 'in') # need empty wetness array for entire time span wetness = N.zeros(pcpn.shape, dtype='<i2') # track whether leaves were wet in an iteration last_wet = N.zeros(pcpn.shape[1:], dtype='<i2') # need to process one time period per iteration for i in range(pcpn.shape[0]): # leaves are wet wherever precip greater than zero where = N.where(pcpn[i,:,:] > 0) wetness[i][where] = 1 # add nodes whereever leaves were wet on the previous day wetness[i][N.where(last_wet == 1)] = 1 # track only where precip criteria were met on this day last_wet.fill(0) # reset last_wet array to zeros first last_wet[where] = 1 return wetness
def stressHours(self, temp, rhum, temp_units='F'): """ Heat Stress utilizes 12 hour data summaries to calculate daily stress hours. A "day" is 12 hours ending at 7AM. NOTE: Hourly data arrays must contain full 24 hour sequences beginning 12 hours before the expected first day in results. Arguments: temp: hourly temperatures for 24 hours rhum: hourly relative humidity 24 hours temp_units: units for temperature data. Default is 'F'. Calculations require degrees 'F' (Fahrenheit) However, input data in degrees 'C' (Celsius). or 'K' (Kelvin) may be passed and will be converted for use in the calculations. Argument types: 3D NumPy array : multiple days at multiple points 2D NumPy array : same day at multiple points 1D NumPy array : multiple days at single point NOTE: all arguments must be the same type and have the same dimensions Returns: NumPy array containing daily stress hours at each node. """ # number of hours to skip before starting iteration offset = self.config.offset # number of hours to evaluate per iteration span = self.config.timespan # number of hours to increment b/w interations step = self.config.timestep if temp_units == 'F': tmp = temp else: tmp = convertUnits(temp, temp_units, 'F') # need sum of temp and rhum for 2nd part of index trh = tmp + rhum # need to know the number of hours where tmp >= 70 & trh > 150 # so create a count array that is the same size as tmp & trh stress_hours = N.zeros(tmp.shape, dtype='<i2') # Need to create separate tmp stress and trh stress conditions # because NumPy cannot handle N.where(tmp >= 70 & trh > 150). # It often throws TypeError with message "truth value of an # array with more than one element is ambiguous" thresholds = self.config.stress_thresholds # filter annoying NumPy/SciPy warnings warnings.filterwarnings('ignore', "All-NaN axis encountered") warnings.filterwarnings('ignore', "All-NaN slice encountered") warnings.filterwarnings('ignore', "invalid value encountered in greater") warnings.filterwarnings('ignore', "invalid value encountered in greater_equal") # set nodes where temp threshold is met stress_hours[N.where(tmp >= thresholds.temp)] = 1 # now add nodes where trh threshold is met so that stress_hours[N.where(trh > thresholds.rhum)] += 1 # turn annoying NumPy/SciPy warnings back on warnings.resetwarnings() # stress_hours == 2 when N.where(tmp >= 70 & trh > 150) return countTimespanEQ(stress_hours, 2, step, span, offset)
print 'Repaired data for %s with data from grib file %s' % info # turn annoying numpy warnings back on before exiting warnings.resetwarnings() exit() reasons.append(' grib file for missing hour contains no valid data') else: reasons.append(' no grib file found for missing hour') prev_time = repair_time - ONE_HOUR success, info = factory.dataFromGrib(file_variable, prev_time, return_units=True) if success: units, data = info if len(N.where(N.isfinite(data))[0]) > 0: if units != grid_units: prev_data = convertUnits(data, units, grid_units) else: prev_data = data else: reasons.append( ' grib file for previous hour contains no valid data') else: reasons.append(' no grib file found for previous hour') next_time = repair_time + ONE_HOUR success, info = factory.dataFromGrib(file_variable, next_time, return_units=True) if success: units, data = info if len(N.where(N.isfinite(data))[0]) > 0:
def rhumComponent(self, max_rh, avg_temp, tmp_units='C'): """ Calculate a the threat factor contributed by the interaction of relative humidity and temperature. Arguments: rhum: daily maximum relative humidity avg_temp: daily average temprature for each day in max_rh. tmp_units: units for average temperature data. Default is 'C'. Calculations require degrees 'C' (Celsius). However, input data in degrees 'K' (Kelvin) or 'F' (Fahrenheit) may be passed and will be converted for use in the calculations. Argument types: 3D NumPy array : multiple hours for multiple grid nodes 2D NumPy array : multiple hours at multple points 1D NumPy array : multiple hours at single point NOTE: input arrays must : 1) be dtype=float 2) have missing value == NaN Returns : int NumPy array containing rh/temp component at each node. else: returns tuple = (rh_factor, avg_temp) [0] int NumPy array containing rh/temp factor at each node. [1] float NumPy array average temperature array used to calculate the rh factor (in degress C). """ if self.debug: print '\n in rhumComponent ...' print ' max_rh shape :', max_rh.shape print ' avgt shape :', avg_temp.shape if tmp_units == 'C': avgt = avg_temp else: avgt = convertUnits(avg_temp, tmp_units, 'C') # Need to create separate avg temp and max_rh components because # NumPy cannot handle N.where(max_rh > 90 & avg_temp > 25). It often # throws TypeError with message "ufunc 'bitwise_and' not supported # for the input types, and the inputs could not be safely coerced # to any supported types according to the casting rule ''safe''" # # daily average temp factor - 1 means condition was met avgt_factor = N.zeros(avgt.shape, '<i2') avgt_factor[N.where(avgt > 25)] = 1 # daily max_rh factor - 1 means condition was met maxrh_factor = N.zeros(max_rh.shape, '<i2') maxrh_factor[N.where(max_rh > 90)] = 1 # daily composite of max_rh and avg_temp factors # maxrh_avgt == 2 is where here max_rh > 90 & avg_temp > 25 maxrh_avgt = avgt_factor + maxrh_factor if self.debug: print ' maxrh & avgt shape :', maxrh_avgt.shape # RH componet is number of days that maxrh_avgt has value of 2 offset = self.offsets.maxrh_avgt_count # should be 0 span = self.timespans.maxrh_avgt_count # should be 7 days step = self.timesteps.maxrh_avgt_count # should be 1 # maxrh_avgt == 2 is where here max_rh > 90 & avg_temp > 25 maxrh_avgt_count = funcs.countTimespanEQ(maxrh_avgt, 2, step, span, offset, '<i2') if self.debug: print ' maxrh avgt count shape :', maxrh_avgt_count.shape num_nans = len(N.where(N.isnan(avgt))[0]) print ' maxrh_avgt_count NaN :', num_nans num_nodes = len(N.where(maxrh_avgt_count == 0)[0]) - num_nans print ' maxrh_avgt_count = 0 :', num_nodes for n in range(1, N.max(maxrh_avgt_count) + 1): num_nodes = len(N.where(maxrh_avgt_count == n)[0]) print ' maxrh_avgt_count = %d : %d' % (n, num_nodes) # RH componet is 1 where maxrh_avgt_count >= threshold threshold = self.count_thresholds.rh_component rh_component = N.zeros(maxrh_avgt_count.shape, dtype=float) # account for NaN in the original data # assumes all days have NaN at the same nodes nans = N.where(N.isnan(avgt[0, :, :])) for day in range(rh_component.shape[0]): rh_component[day][nans] = N.nan rh_component[N.where(maxrh_avgt_count >= threshold)] = 1 if self.debug: print ' rh_component shape :', maxrh_avgt_count.shape return rh_component
def consecPcpnAvgt(self, rain_count, avg_temp, tmp_units='C'): """ Utilizes daily rain counts to determine the number of consecutive days with precipitation. Input data must contain hourly precipitation for a minimum of 5 days before data reduction can begin. For example, 120 hours of data will return number of consectuive days with precip for 1 day, 144 hours will return results for 2 days, etc. Arguments: rain_count: daily count of hours with precipitation avg_temp: daily average temprature for same days as rain_count tmp_units: units for temperature data. Default is 'C'. Calculations require degrees 'C' (Celsius). However, input data in degrees 'K' (Kelvin) or 'F' (Fahrenheit) may be passed and will be converted for use in the calculations. Data argument types: 3D NumPy array : multiple days at multiple points 2D NumPy array : same day at multiple points 1D NumPy array : multiple days at single point NOTE: input arrays must : 1) have the same dimensions 2) be dtype=float 3) have missing value == N.nan Returns: 1) NumPy array containing counts of consecutive days of precipitation for each day at each node. 2) NumPy array containing average temperatures on days with precipitaton """ # capture avg_tmp for each consecutive day of rain if tmp_units == 'C': avgt = avg_temp else: avgt = convertUnits(avg_temp, tmp_units, 'C') if self.debug: print '\n in consecPcpnAvgt ...' print ' avgt shape :', avgt.shape # determine number of consecutive previous days with rain offset = self.offsets.consec_rain span = self.timespans.consec_rain step = self.timesteps.consec_rain threshold = self.count_thresholds.wet_count consec_rain = funcs.countTimespanGE(rain_count, threshold, step, span, offset, '<i2') if self.debug: print '\n in consecPcpnAvgt ...' print ' consec rain shape :', consec_rain.shape for day in range(consec_rain.shape[0]): print ' day :', day for n in range(threshold, span + 1): num_nodes = len(N.where(consec_rain[day, :, :] == n)[0]) print ' %d consec days rain : %d' % (n, num_nodes) # because consecutive rain is for the 5 previous days, # the result in consec_rain is 1 day too long consec_rain = consec_rain[1:, :, :] consec_avgt = N.zeros(consec_rain.shape, dtype=float) consec_avgt[N.where(N.isnan(consec_rain))] = N.nan avg_tmp_sum = N.zeros(consec_rain.shape[1:], dtype=float) for rain_day in range(offset, consec_rain.shape[0]): consec_days = 0 avg_tmp_sum.fill(0) avg_tmp_sum[N.where(N.isnan(consec_rain[rain_day, :, :]))] = N.nan # loop thru max previous days with rain for day_num in range(span): day = rain_day - day_num if day < 0: break count = day_num + 1 # look for nodes with rain where = N.where(consec_rain[day, :, :] >= count) if len(where[0]) > 0: # rain_found consec_days += 1 avg_tmp_sum[where] += avgt[day][where] # must have a least 2 consecutive days of rain if consec_days > 1: consec_avgt[rain_day][where] = \ avg_tmp_sum[where] / consec_days return consec_rain, consec_avgt
def repairOneHour(factory, manager, repair_time, variable, grib_region): success, info = factory.dataFromGrib(file_variable, repair_time, return_units=True) if success: units, data = info if len(N.where(N.isfinite(data))[0]) > 0: manager.open('a') manager.updateReanalysisData(reanalysis, file_variable, repair_time, data, units=units) manager.close() grib_filename = factory.gribFilename(repair_time, file_variable, grib_region) info = (repair_time.strftime('%Y-%m-%d:%H'), grib_filename) return 'Repaired data for %s with data from grib file %s' % info else: reasons.append(' grib file for missing hour contains no valid data') else: reasons.append(' no grib file found for missing hour') prev_time = repair_time - ONE_HOUR manager.open('r') grid_units = manager.datasetAttribute(file_variable, 'units') manager.close() success, info = factory.dataFromGrib(file_variable, prev_time, return_units=True) if success: units, data = info if len(N.where(N.isfinite(data))[0]) > 0: if units != grid_units: prev_data = convertUnits(data, units, grid_units) else: prev_data = data else: reasons.append(' grib file for previous hour contains no valid data') else: reasons.append(' no grib file found for previous hour') next_time = repair_time + ONE_HOUR success, info = factory.dataFromGrib(file_variable, next_time, return_units=True) if success: units, data = info if len(N.where(N.isfinite(data))[0]) > 0: if units != grid_units: next_data = convertUnits(data, units, grid_units) else: next_data = data else: reasons.append(' grib file for next hour contains no valid data') else: reasons.append(' no grib file found for next hour') if prev_data is None: prev_time = repair_time - ONE_HOUR manager.open('r') data = manager.dataForHour(file_variable, prev_time) manager.close() if len(N.where(N.isfinite(data))[0]) > 0: prev_data = data else: reasons.append(' grid file contains missing data for previous hour') if next_data is None: next_time = repair_time - ONE_HOUR manager.open('r') next_data = manager.dataForHour(file_variable, next_time) manager.close() if len(N.where(N.isfinite(data))[0]) > 0: next_data = data else: reasons.append(' grid file contains missing data for next hour') if prev_data is not None and next_data is not None: fudge = (prev_data + next_data) / 2. manager.open('a') manager.insertFudgedData(file_variable, repair_time, fudge) manager.close() msg = 'Data for %s @ %s was interpolated using data from previous and next hours' return msg % (file_variable, repair_time.strftime('%Y-%m-%d:%H')) return reasons
print 'ERROR : time in TMP file and DPT file are out of sync for' interval = (slice_start.strftime('%Y-%m-%d:%H'), slice_end.strftime('%Y-%m-%d:%H')) print ' interval %s to %s' % interval print 'Further processing is not possible' continue tmp_reader.open() tmp = tmp_reader.timeSlice('TMP', slice_start, slice_end) tmp_units = tmp_reader.datasetAttribute('TMP','units') tmp_reader.close() dpt_reader.open() dpt = dpt_reader.timeSlice('DPT', slice_start, slice_end) dpt_units = dpt_reader.datasetAttribute('DPT','units') dpt_reader.close() if dpt_units != tmp_units: dpt = convertUnits(dpt, dpt_units, tmp_units) rhum = N.around(rhumFromDpt(tmp, dpt, tmp_units), 2) num_hours = rhum.shape[0] manager.open('a') manager.updateReanalysisData(analysis, 'RHUM', slice_start, rhum) manager.close() if verbose: skip = ('end_time', 'start_time', 'timezone', 'tzinfo') print '\nUpdated time attributes for RHUM dataset :' manager.open('r') for time_key, hour in manager.timeAttributes('RHUM').items(): if not time_key in skip: print ' %s = %s' % (time_key, hour.strftime('%Y-%m-%d:%H'))
def precipFactors(self, pcpn, temp, pcpn_units='in', tmp_units='C', return_count=False): """ Calculate the individual threat factors contributed by the interaction of consecutive days of precipitation and the corresponding average temperature on those days. NOTE: input arrays must : 1) have the same dimensions 2) be dtype=float 3) have missing value = numpy.nan Arguments: pcpn: hourly precipitation temp: houry temprature pcpn_units: units for precipitation data. Default is 'in'. Calculations require 'in' (inches of rainfall). However, input data in kilograms per square meter ('kg m**-2' or 'kg^m**-2') may be passed and will be converted to 'in' for use in the calculations. tmp_units: units for temperature data. Default is 'C'. Calculations require degrees 'C' (Celsius). However, input data in degrees 'K' (Kelvin) or 'F' (Fahrenheit) may be passed and will be converted for use in the calculations. return_count: boolean, whete to include daily counts of hours with rain in results Argument types: 3D NumPy array : multiple hours for multiple grid nodes 2D NumPy array : multiple hours at multple points 1D NumPy array : multiple hours at single point Returns : tuple containing the following items tuple[0] = int NumPy array containing number of consecutive days of rain for each day at each node. tuple[1] float NumPy array containing the average temperature over the consecutive days of rain for each day at each node. tiple[2] units for average temperature data if return_count == Ture, tuple also includes: tuple[3] = int NumPy array containing the number of hours of rain for each day at each node. This array will contain 6 more days than the other arrays """ if pcpn_units == 'in': precip = pcpn else: precip = convertUnits(pcpn, pcpn_units, 'in') # adjustment for minimum effective precipitation precip[N.where(precip < self.config.min_precip)] = 0 if tmp_units == 'C': tmp = temp else: tmp = convertUnits(temp, tmp_units, 'C') if self.debug: print '\n in precipFactors ...' print ' precip shape :', pcpn.shape print ' temp shape :', tmp.shape # offset, time span and time step for avg temp and rain counts offset = self.offsets.rain_count span = self.timespans.rain_count step = self.timesteps.rain_count threshold = self.count_thresholds.rain_count # calculate the daily average temps for the days needed avg_temp = funcs.calcTimespanAvg(tmp, step, span, offset) # rain_count = number of hours with rain on each day rain_count = \ funcs.countTimespanGT(precip, threshold, step, span, offset) if self.debug: print ' average temp shape :', avg_temp.shape print ' rain count shape :', rain_count.shape # get a solver for consecutive days of rain and the average temp ndims = len(avg_temp.shape) if ndims == 3: solver = DollarSpot3D(self.period, self.debug) else: raise TypeError, '%dD arrays are not currently supported' % ndims # get counts of consecutive days of rain and the average temp # over those days consec_rain, consec_avgt = \ solver.consecPcpnAvgt(rain_count, avg_temp, 'C') if self.debug: print '\n solver results ...' print ' consec rain shape :', consec_rain.shape print ' consec avgt shape :', consec_avgt.shape results = [consec_rain, consec_avgt, 'C'] if return_count: result.append(rain_count) return tuple(results)
def dailyReductions(self, temp, dewpt, rhum, pcpn, temp_units, pcpn_units): """ Brown Patch utilizes 24 hour data reductions to calculate threat index. Therefore, hourly data arrays must begin 48 hours before the expected first day in results. NOTE: One day is 24 hours ending at 7AM. Arguments: temp: hourly temperatures. dewpt: hourly dewpoint temperatures. rhum: hourly relative humidity pcpn: hourly precipitation. temp_units: units for temperature and dew point arrays. Calculations require degrees 'C' (Celsius), however, input data in degrees 'K' (Kelvin) or 'F' (Fahrenheit) may be passed and will be converted to 'C' for use in the calculations. pcpn_units: units for precipitation data. Calculations require 'in' (inches of rainfall). Data in other units may be passed and will be converted to 'in' for use in the calculations. Argument types:ple days at multiple points 2D NumPy array : snme day at multiple points 1D NumPy array : multiple days at single point NOTE: input arrays must : 1) have the same dimensions 2) be dtype=float 3) have mssing value == N.nan Returns: NumPy arrays for the following daily reductions: 1) minimum temp 2) average rhum 3) num hours of leaf wetness """ # number of hours to skip before starting iteration offset = self.config.offset # number of hours to evaluate per iteration span = self.config.timespan # number of hours to increment b/w interations step = self.config.timestep # make sure that temperature and dew point units are correct tmp_units = self.config.units.tmp if temp_units == tmp_units: tmp = temp dpt = dewpt else: tmp = convertUnits(temp, temp_units, tmp_units) dpt = convertUnits(dewpt, temp_units, tmp_units) # calculate minimum daily temp mint = funcs.calcTimespanMin(tmp, step, span, offset, N.nan) if self.debug: print '\n in dailyReductions ...' print ' temp shape :', tmp.shape print ' min temp shape :', mint.shape # calculate average daily humidity avgrh = funcs.calcTimespanAvg(rhum, step, span, offset, N.nan) if self.debug: print ' avg humidity shape :', avgrh.shape # count daily rhum > threshold threshold = self.config.rh_threshold rh_count = funcs.countTimespanGT(rhum, threshold, step, span, offset) if self.debug: print ' rh threshold :', threshold print ' rh count shape :', rh_count.shape # get hourly leaf wetness leaf_wet = self.leafWetness(tmp, dpt, pcpn, tmp_units, pcpn_units) if self.debug: stats = (N.nanmin(leaf_wet), N.nanmean(leaf_wet), N.nanmedian(leaf_wet), N.nanmax(leaf_wet)) print ' leaf wet stats :', stats # count number of hours with leaf wetness wet_count = funcs.countTimespanGT(leaf_wet, 0, step, span, offset) if self.debug: print ' wet count :', wet_count.shape return mint, avgrh, rh_count, wet_count
def wetnessFactors(self, precip, temp, pcpn_units='in', tmp_units='C'): """ Calculate a the threat factor contributed by the interaction of leaf wetness and temperature. NOTE: inputs must be NumPy float arrays with the same dimensions and missing value = nan Arguments: precip: hourly precipitation temp: hourly temprature for same hours as precip tmp_units: units for temperature data. Default is 'C'. Calculations require degrees 'C' (Celsius). However, input data in degrees 'K' (Kelvin) or 'F' (Fahrenheit) may be passed and will be converted for use in the calculations. pcpn_units: units for precipitation data. Default is 'in'. Calculations require 'in' (inches of rainfall). However, input data in kilograms per square meter ('kg m**-2' or 'kg^m**-2') may be passed and will be converted to 'in' for use in the calculations. Argument types: 3D NumPy array : multiple hours for multiple grid nodes 2D NumPy array : multiple hours at multple points 1D NumPy array : multiple hours at single point Returns : tuple of arrays tuple[0] = int NumPy array daily count of hours with leaf wetness at each node. tuple[1] = float NumPy array average daily temp for each day in leaf wetnes array """ if self.debug: print '\n in wetnessFactors ...' # make sure that input precip is in the correct units if pcpn_units == 'in': pcpn = precip else: pcpn = convertUnits(precip, pcpn_units, 'C') if self.debug: print ' pcpn shape :', pcpn.shape # make sure that input temps are in the correct units if tmp_units == 'C': tmp = temp else: tmp = convertUnits(temp, tmp_units, 'C') if self.debug: print ' temp shape :', tmp.shape # get mask-like array with 1 in each hour with wetness leaf_wetness = leafWetnessFromPrecip(pcpn, 'in') if self.debug: print ' leaf wetness shape :', leaf_wetness.shape # offset, span, step for wet_count offset = self.offsets.wet_count # should skip first 4 days (96 hours) span = self.timespans.wet_count # should 3 days (72 hours) step = self.timesteps.wet_count # 24 hours threshold = self.count_thresholds.wet_count # count number of hours of leaf wetness per day wet_count = funcs.countTimespanEQ(leaf_wetness, threshold, step, span, offset, '<i2') if self.debug: print ' wetness count shape :', wet_count.shape span = 24 step = 24 wet_avgt = funcs.calcTimespanAvg(tmp, step, span, offset) if self.debug: print ' wetness avgt shape :', wet_avgt.shape if wet_count.shape[0] < wet_avgt.shape[0]: diff = wet_avgt.shape[0] - wet_count.shape[0] wet_avgt = wet_avgt[diff:, :, :] if self.debug: print '\n wetness avgt adjust to match wetness count' print ' new wetness avgt shape :', wet_avgt.shape return wet_count, wet_avgt