def calcPET(lat, time, tmin, tmax, tmean): ''' Calculates Potential Evapotranspiration using Hargreaves equation (Hargreaves and Samani, 1985) ''' latrad = pt.deg2rad(lat) #Latitude to radians dayofyear = pd.Series(time).dt.day.values etrad = [] pet = [] # Calculate ET radiation for x in np.nditer(dayofyear): soldec = pt.sol_dec(x) #Solar declination sha = pt.sunset_hour_angle(latrad, soldec) #Sunset hour aingle ird = pt.inv_rel_dist_earth_sun( x) #Inverse relative distance Earth-Sun etrad.append(pt.et_rad(latrad, soldec, sha, ird)) #Extraterrestrial radiation # Calculate PET using hargreaves for x in range(0, len(etrad)): pet.append(pt.hargreaves(tmin[x], tmax[x], tmean[x], etrad[x])) pet = np.array(pet) return (pet)
def hargreaves(self, day, tmax, tmin, tmean, latitude, precipitation, Kc, Ef): def calculate_extraterrestial_radiation(latitude, day): # Calculate solar declination solar_declination = pyeto.sol_dec(day) # Calculate sunset hour angle sunset_hour_angle = pyeto.sunset_hour_angle(latitude, solar_declination) # Calculate inverse relative distance earth-sun inverse_relative_distance = pyeto.inv_rel_dist_earth_sun(day) # Calculate extraterrestial radiation extraterrestial_radiation = pyeto.et_rad(latitude, solar_declination, sunset_hour_angle, inverse_relative_distance) return extraterrestial_radiation # Calculate extraterrestial radiation extraterrestial_radiation = calculate_extraterrestial_radiation(latitude, day) # Calculate evapotranspiration ETo = pyeto.hargreaves(tmin, tmax, tmean, extraterrestial_radiation) # Predict irrigation prediction = (ETo * Kc - precipitation) / Ef return prediction > 0
f_tmax = os.path.join(inpath,'wc2.0_30s_tmax','wc2.0_30s_tmax_'+str(month).zfill(2)+'.tif') #print('Loading tmax:',f_tmax) f=gdal.Open(f_tmax) rasterband = f.GetRasterBand(1) tmax = rasterband.ReadAsArray(yoff=i,win_ysize=1) #f.close() f_tmin = os.path.join(inpath,'wc2.0_30s_tmin','wc2.0_30s_tmin_'+str(month).zfill(2)+'.tif') #print('Loading tmin:',f_tmax) f=gdal.Open(f_tmin) rasterband = f.GetRasterBand(1) tmin = rasterband.ReadAsArray(yoff=i,win_ysize=1) #f.close() # pyeto gives mm/day, multiply by monthdays to get mm/month pet_timeslice[month-1,:] = pyeto.hargreaves(tmin,tmax,tavg, et_rad)*monthdays[month-1] # Sum over months to get mm/year, and write out pet = pet_timeslice.sum(0,keepdims=True) f_out.variables['pet'][i,:] = pet[0,:] #print(rasterband) # Also write data out to tiff format #rasterband.WriteArray(pet,yoff=i) # Close tif datasets #f1 = None #f2 = None print('done')
def exec(self): log.info('[START] {}'.format("exec")) try: if (platform.system() == 'Windows'): # 옵션 설정 sysOpt = { # 시작/종료 시간 'srtDate': '2020-09-01', 'endDate': '2020-09-03' # 경도 최소/최대/간격 , 'lonMin': 0, 'lonMax': 360, 'lonInv': 0.5 # 위도 최소/최대/간격 , 'latMin': -90, 'latMax': 90, 'latInv': 0.5 } else: # 옵션 설정 sysOpt = { # 시작/종료 시간 # 'srtDate': globalVar['srtDate'] # , 'endDate': globalVar['endDate'] } # globalVar['outPath'] = 'F:/Global Temp/aski' modelList = ['MRI-ESM2-0'] for i, modelInfo in enumerate(modelList): log.info("[CHECK] modelInfo : {}".format(modelInfo)) inpFile = '{}/{}/{} ssp585 2015-2100_*.nc'.format( globalVar['inpPath'], serviceName, modelInfo) fileList = sorted(glob.glob(inpFile)) dsData = xr.open_mfdataset(fileList) # dsData = dsData.sel(lon=slice(120, 150), time=slice('2015-01', '2016-12')) # dsData = dsData.sel(lat=slice(50, 50), lon=slice(120, 120), time=slice('2015-01', '2015-12')) # 월별 시간 변환 dsData['time'] = pd.to_datetime(pd.to_datetime( dsData['time'].values).strftime("%Y-%m"), format='%Y-%m') # 단위 설정 dsData['tasmin'].attrs['units'] = 'degC' dsData['tasmax'].attrs['units'] = 'degC' dsData['tas'].attrs['units'] = 'degC' # 단위 환산을 위한 매월 마지막 날 계산 lon1D = dsData['lon'].values lat1D = dsData['lat'].values time1D = dsData['time'].values timeEndMonth = [] timeYear = dsData['time.year'].values timeMonth = dsData['time.month'].values for i in range(0, len(timeYear)): timeEndMonth.append( calendar.monthrange(timeYear[i], timeMonth[i])[1]) latRad1D = pyeto.deg2rad(dsData['lat']) # 2022.08.13 doy 순서 변경 # 시작 순서 1, 32, ... dayOfYear1D = dsData['time.dayofyear'] latRad3D = np.tile( np.transpose(np.tile(latRad1D, (len(lon1D), 1))), (len(time1D), 1, 1)) dayOfYear3D = np.transpose( np.tile(dayOfYear1D, (len(lon1D), len(lat1D), 1))) timeEndMonth3D = np.transpose( np.tile(timeEndMonth, (len(lon1D), len(lat1D), 1))) tmpData = xr.Dataset( { 'timeEndMonth': (('time', 'lat', 'lon'), (timeEndMonth3D).reshape( len(time1D), len(lat1D), len(lon1D))), 'latRad': (('time', 'lat', 'lon'), (latRad3D).reshape( len(time1D), len(lat1D), len(lon1D))) # , 'dayOfYear': (('time', 'lat', 'lon'), (dayOfYear3D).reshape(len(time1D), len(lat1D), len(lon1D))) , 'doy': (('time', 'lat', 'lon'), (dayOfYear3D).reshape( len(time1D), len(lat1D), len(lon1D))) }, coords={ 'lat': lat1D, 'lon': lon1D, 'time': time1D }) # 마지막 순서 31, 59, ... # tmpData['dayOfYear'] = tmpData['doy'] tmpData['dayOfYear'] = tmpData['doy'] + timeEndMonth3D # ******************************************************************************************** # FAO-56 Penman-Monteith 방법 # ******************************************************************************************** # https://pyeto.readthedocs.io/en/latest/fao56_penman_monteith.html 매뉴얼 참조 # 1 W/m2 = 1 J/m2를 기준으로 MJ/day 변환 # dsData['rsdsMJ'] = dsData['rsds'] * 86400 / (10 ** 6) dsData['rsdsMJ'] = dsData['rsds'] * 2592000 / (10**6) # 섭씨 to 켈빈 dsData['tasKel'] = dsData['tas'] + 273.15 dsData['tasminKel'] = dsData['tasmin'] + 273.15 dsData['tasmaxKel'] = dsData['tasmax'] + 273.15 dsData['svp'] = svp_from_t(dsData['tas']) dsData['svpMax'] = svp_from_t(dsData['tasmax']) dsData['svpMin'] = svp_from_t(dsData['tasmin']) tmpData['solDec'] = sol_dec(tmpData['dayOfYear']) tmpData['sha'] = sunset_hour_angle(tmpData['latRad'], tmpData['solDec']) tmpData['dayLightHour'] = daylight_hours(tmpData['sha']) tmpData['ird'] = inv_rel_dist_earth_sun(tmpData['dayOfYear']) # tmpData['etRad'] = et_rad(tmpData['latRad'], tmpData['solDec'], tmpData['sha'], tmpData['ird']) tmpData['etRad'] = dsData['rsdsMJ'] tmpData['csRad'] = fao.cs_rad(altitude=1.5, et_rad=tmpData['etRad']) dsData['deltaSvp'] = delta_svp(dsData['tas']) # 대기 온도 1.5 m 가정 psy = fao.psy_const(atmos_pres=fao.atm_pressure(altitude=15)) dsData['avp'] = fao.avp_from_rhmin_rhmax( dsData['svpMax'], dsData['svpMin'], dsData['hurs'].min(), dsData['hurs'].max()) niSwRad = pyeto.net_in_sol_rad(dsData['rsdsMJ'], albedo=0.23) niLwRad = net_out_lw_rad(dsData['tasminKel'], dsData['tasmaxKel'], dsData['rsdsMJ'], tmpData['csRad'], dsData['avp']) dsData['net_rad'] = fao.net_rad(ni_sw_rad=niSwRad, no_lw_rad=niLwRad) # 2022.08.13 # 상수 # shfData = 0.336 # 이전, 현재 대기온도를 통해 계산 timeList = dsData['time'].values shfDataL1 = xr.Dataset() for i, timeInfo in enumerate(timeList): prevYmd = (pd.to_datetime(timeInfo) + pd.DateOffset(months=-1)).strftime('%Y-%m-%d') nowYmd = pd.to_datetime(timeInfo).strftime('%Y-%m-%d') prevData = dsData['tas'].interp( time=prevYmd, method='nearest', kwargs={'fill_value': 'extrapolate'}) nowData = dsData['tas'].interp( time=nowYmd, method='nearest', kwargs={'fill_value': 'extrapolate'}) shfData = pyeto.monthly_soil_heat_flux2( prevData, nowData).rename('shf') shfData['time'] = pd.to_datetime(timeInfo) if (i == 0): shfDataL1 = shfData else: shfDataL1 = xr.concat([shfDataL1, shfData], dim='time') dsData = xr.merge([dsData, shfDataL1]) # Daily eto # faoRes = fao.fao56_penman_monteith(dsData['net_rad'], dsData['tasKel'], dsData['sfcWind'], dsData['svp'], dsData['avp'], dsData['deltaSvp'], psy, shf = 0) # Monthly eto faoRes = fao.fao56_penman_monteith(dsData['net_rad'], dsData['tasKel'], dsData['sfcWind'], dsData['svp'], dsData['avp'], dsData['deltaSvp'], psy, shf=dsData['shf']) # ******************************************************************************************** # Hargreaves 방법 # ******************************************************************************************** # https://xclim.readthedocs.io/en/stable/indicators_api.html 매뉴얼 참조 # harRes = xclim.indices.potential_evapotranspiration( dsData['tasmin'], dsData['tasmax'], dsData['tas'], dsData['lat'], method='hargreaves85') # 1 kg/m2/s = 86400 mm/day를 기준으로 mm/month 변환 # harResL1 = harRes * 86400.0 * tmpData['timeEndMonth'] # https://pyeto.readthedocs.io/en/latest/thornthwaite.html 매뉴얼 참조 harRes = pyeto.hargreaves(dsData['tasmin'], dsData['tasmax'], dsData['tas'], tmpData['etRad']) harResL1 = harRes # ******************************************************************************************** # Thornthwaite 방법 # ******************************************************************************************** # https://xclim.readthedocs.io/en/stable/indicators_api.html 매뉴얼 참조 # thwRes = xclim.indices.potential_evapotranspiration(dsData['tasmin'], dsData['tasmax'], dsData['tas'], dsData['lat'], method ='thornthwaite48') # 1 kg/m2/s = 86400 mm/day를 기준으로 mm/month 변환 # thwResL1 = thwRes * 86400.0 * tmpData['timeEndMonth'] dsData['tasAdj'] = xr.where((dsData['tas'] >= 0), dsData['tas'], 0) dsData['heatIdx'] = (dsData['tasAdj'] / 5.0)**1.514 sumHeatIdx = dsData['heatIdx'].groupby('time.year').sum( skipna=True) sumHeatIdxData = xr.Dataset() timeList = dsData['time'].values for i, timeInfo in enumerate(timeList): iYear = int(pd.to_datetime(timeInfo).strftime('%Y')) selHeatIdx = sumHeatIdx.sel(year=iYear).rename( {'year': 'time'}) selHeatIdx['time'] = timeInfo if (i == 0): sumHeatIdxData = selHeatIdx else: sumHeatIdxData = xr.concat( [sumHeatIdxData, selHeatIdx], dim='time') # 2022.08.15 # dsData['thwConst'] = (6.75e-07 * dsData['heatIdx'] ** 3) - (7.71e-05 * dsData['heatIdx'] ** 2) + (1.792e-02 * dsData['heatIdx']) + 0.49239 # thwRes = 1.6 * (tmpData['dayLightHour'] / 12.0) * (tmpData['timeEndMonth'] / 30.0) * ((10.0 * dsData['tasAdj'] / dsData['heatIdx']) ** dsData['thwConst']) * 10.0 dsData['thwConst'] = (6.75e-07 * sumHeatIdxData**3) - ( 7.71e-05 * sumHeatIdxData**2) + (1.792e-02 * sumHeatIdxData) + 0.49239 thwRes = 1.6 * (tmpData['dayLightHour'] / 12.0) * (tmpData['timeEndMonth'] / 30.0) * ( (10.0 * dsData['tasAdj'] / sumHeatIdxData) **dsData['thwConst']) * 10.0 # 0보다 작은 경우 0으로 대체 thwRes = xr.where((thwRes >= 0), thwRes, 0) # ******************************************************************************************** # 데이터 병합 # ******************************************************************************************** etoData = xr.Dataset( { 'hargreaves': (('time', 'lat', 'lon'), (harResL1.values).reshape( len(time1D), len(lat1D), len(lon1D))), 'thornthwaite': (('time', 'lat', 'lon'), (thwRes.values).reshape( len(time1D), len(lat1D), len(lon1D))), 'penman-monteith': (('time', 'lat', 'lon'), (faoRes.values).reshape( len(time1D), len(lat1D), len(lon1D))) }, coords={ 'lat': lat1D, 'lon': lon1D, 'time': time1D }) # NetCDF 파일 저장 saveFile = '{}/{}/{}_eto.nc'.format(globalVar['outPath'], serviceName, modelInfo) os.makedirs(os.path.dirname(saveFile), exist_ok=True) etoData.to_netcdf(saveFile) log.info('[CHECK] saveFile : {}'.format(saveFile)) except Exception as e: log.error("Exception : {}".format(e)) raise e finally: log.info('[END] {}'.format("exec"))
def _compute_ref_eto(day_ds, lat): return pyeto.hargreaves( day_ds['TminD'], day_ds['TabsD'], day_ds['TmaxD'], _compute_solar_radiation(pd.to_datetime(day_ds.time.values), lat))
def test_hargreaves(self): # Tested against worked example from "Estimating Evapotranspiration # from weather data" by Vishal K. Mehta, Arghyam/Cornell University, # Nov 2, 2006. eto = pyeto.hargreaves(tmin=28, tmax=38, tmean=35, et_rad=38.93715) self.assertAlmostEqual(eto, 6.1, 1)