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 componentsToThreatIndex(self, rh_component, pcpn_component, leaf_wetness_component): """ Dollar Spot utilizes 3-day averages. Therefore, hourly data arrays must begin 72 hours before the expected first day in results. NOTE: input arrays must be in the same dimensions Arguments: rh_component: daily humidity component of threat index calculated using rhumComponent function pcpn_component: daily precipition component of threat index calculated using precipComponent function leaf_wetness_component: daily leaf wetness compnent calculated using wetnessComponent function 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: NumPy array containing threat index at each node. """ if self.debug: print '\ncalculating average threat index ...' print ' rhum component shape :', rh_component.shape print ' precip component shape :', pcpn_component.shape print 'wetness component shape :', leaf_wetness_component.shape # threat index = sum of RH, wetness and consecutive precip factors threat_index = rh_component + pcpn_component + leaf_wetness_component # average threat index over consecutive days offset = self.offsets.threat # should be 0 span = self.period.num_days # should be 3 or 7 days step = self.timesteps.threat # should be 1 day # get average threat over last 'span' days return funcs.calcTimespanAvg(threat_index, step, span, offset)
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 threatIndex(self, first_hour, temp, dewpt, rhum, pcpn, temp_units, pcpn_units): """ Brown Patch utilizes 24 hour averages and counts in order to calculate threat index. Therefore, your hourly data arrays must begin 24 hours before the expected first day in results. NOTE: One day is 24 hours ending at 7AM. Arguments: first_hour: first hour in data arrays (datetime.datetime) 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: 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: input arrays must : 1) have the same dimensions 2) be dtype=float 3) have mssing value == N.nan Returns: NumPy array with threat index for each node on each day """ mint, avgrh, rh95, wet_count = \ self.dailyReductions(temp, dewpt, rhum, pcpn, temp_units, pcpn_units) # convert avg daily rhum to an index (0,1) avgrh_factor = N.zeros(avgrh.shape, '<i2') avgrh_factor[N.where(avgrh >= 80)] = 1 # convert rhum > 95 count to index (0,1,2) rh95_factor = N.zeros(rh95.shape, '<i2') rh95_factor[N.where(rh95 > 4)] = 1 rh95_factor[N.where(rh95 >= 8)] = 2 # convert leaf wetness counts to an index (0,1) lwet_factor = N.zeros(wet_count.shape, '<i2') lwet_factor[N.where(wet_count >= 10)] = 1 # convert min temperature to an index (-4, -2, 1) mint_factor = N.empty(mint.shape, '<i2') mint_factor.fill(-2) # covers effect of low min temps in season # mint_factor = N.zeros(mint.shape, '<i2') # always count temps above 16 degrees C whether in season or not mint_factor[N.where(mint >= 16)] = 1 # adjust mint factor using season time span restrictions # first/last data day are used filter low min temps out of season # do this by filtering temps out of mint by setting them to -4 # but always count min temps above 16 degrees C (factor == 1) first_date = first_hour.date() last_date = first_date + datetime.timedelta(days=mint.shape[0] - 1) if first_date < self.season_start: if last_date < self.season_start: mint_factor[N.where(mint_factor != 1)] = -4 else: the_date = first_date index = 0 while the_date < self.season_start: index += 1 the_date += ONE_DAY # index is for season start mint_factor[N.where(mint_factor[:index, :, :] != 1)] = -4 elif last_date > self.season_end: if first_date > self.season_start: mint_factor[N.where(mint_factor != 1)] = -4 else: index = 0 the_date = last_date while the_date < self.season_start: the_date += ONE_DAY index += 1 # index is for season end mint_factor[N.where(mint_factor[index:, :, :] != 1)] = -4 # threat index is sum of avgrh, rh92, lwet and mint factors index = avgrh_factor + rh95_factor + lwet_factor + mint_factor # 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, 0)
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
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 threatIndex(self, temp, dewpt, pcpn, temp_units, pcpn_units): """ Anhtracnose utilizes 3-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 precip: hourly precipitation. Default is None dewpt: hourly dewpoint temperatures. Default is None temp_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. precip_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. Note: Must pass valid array for precip OR dewpt (not both). Either may be used estimate the leaf wetness variable that is required to calulate Anthracnose threat index. 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 mssing value == N.nan Returns: NumPy array contining daily threat index at each node. """ offset = self.config.offset # index of first iteration # number of hours to evaluate per iteration span = self.config.timespan # number of hours to increment b/w interations step = self.config.timestep if self.debug: print '\nAnthracnose.threatIndex :' print ' offset :', offset print ' span :', span print ' step :', step print ' temperature :', temp.shape, temp_units print ' dew point :', dewpt.shape print ' precip :', pcpn.shape, pcpn_units if temp.shape[0] < span: errmsg = 'Input arrays must contain at least %d hours of data.' raise ValueError, errmsg % span tmp_units = self.config.units.tmp if temp_units == tmp_units: tmp = temp else: tmp = convertUnits(temp, temp_units, tmp_units) # each day of interest needs average temp for previous 3 days avgt = funcs.calcTimespanAvg(tmp, step, span, offset, N.nan) if self.debug: print ' avgt shape :', avgt.shape avgt_nans = N.where(N.isnan(avgt)) # each day of interest needs average leaf wetness for previous 3 days leaf_wet = self.leafWetness(temp, dewpt, pcpn, tmp_units, pcpn_units) wet_count = funcs.countTimespanGT(leaf_wet, 0, step, span, offset) / 3. if self.debug: print 'wet_count shape :', wet_count.shape print ' wet_count min :', N.min(wet_count) print ' wet_count max :', N.max(wet_count) index = 4.0233 - (wet_count * 0.2283) - (avgt * 0.5308) - \ (wet_count**2 * 0.0013) + (avgt**2 * 0.0197) + \ (avgt * wet_count * 0.0155 ) # avoid issues with NimPy runtime warnings index[avgt_nans] = -99999. if self.debug: print ' index shape :', index.shape index[N.where(avgt < 0)] = -1 # prevent positive index @ temp < 0C if self.debug: print ' index < 0 :', len(N.where(index < 0)[0]) index[avgt_nans] = N.nan too_low = N.where(wet_count < 8) index[too_low] -= 3 if self.debug: print ' index < 8 :', len(too_low[0]) print ' index min :', N.nanmin(index) print ' index max :', N.nanmax(index) span = self.period.num_days if self.debug: print 'period.num_days :', span if span == 1: return index else: # get average threat over last 'span' consecutive days return funcs.calcTimespanAvg(index, 1, span, 0)