def update_crop_parameters(self): """Function to update certain crop parameters for current time step (equivalent to lines 97-163 in compute_crop_calendar) """ pd = np.copy(self.var.PlantingDateAdj) hd = np.copy(self.var.HarvestDateAdj) hd[hd < pd] += 365 sd = self.var._modelTime.currTime.timetuple().tm_yday # Update certain crop parameters if using GDD mode if (self.var.CalendarType == 2): cond1 = ((self.var.GrowingSeason) & (self.var._modelTime.doy == pd)) pd[np.logical_not(cond1)] = 0 hd[np.logical_not(cond1)] = 0 max_harvest_date = int(np.max(hd)) if (max_harvest_date > 0): # Dimension (day,crop,lat,lon) day_idx = np.arange(sd, max_harvest_date + 1)[:, None, None, None] * np.ones_like( self.var.PlantingDate)[None, :, :, :] growing_season_idx = ((day_idx >= pd) & (day_idx <= hd)) # Extract weather data for first growing season tmin = vos.netcdf2NumPyTimeSlice( self.var.tmpFileNC, self.var.tmnVarName, self.var._modelTime.currTime, self.var._modelTime.currTime + datetime.timedelta(int(max_harvest_date - sd)), cloneMapFileName=self.var.cloneMap, LatitudeLongitude=True) tmax = vos.netcdf2NumPyTimeSlice( self.var.tmpFileNC, self.var.tmxVarName, self.var._modelTime.currTime, self.var._modelTime.currTime + datetime.timedelta(int(max_harvest_date - sd)), cloneMapFileName=self.var.cloneMap, LatitudeLongitude=True) # broadcast to crop dimension tmax = tmax[:, None, :, :] * np.ones( (self.var.nCrop))[None, :, None, None] tmin = tmin[:, None, :, :] * np.ones( (self.var.nCrop))[None, :, None, None] # for convenience tupp = self.var.Tupp[None, :, :, :] * np.ones( (tmin.shape[0]))[:, None, None, None] tbase = self.var.Tbase[None, :, :, :] * np.ones( (tmin.shape[0]))[:, None, None, None] # calculate GDD according to the various methods if self.var.GDDmethod == 1: tmean = ((tmax + tmin) / 2) tmean = np.clip(tmean, self.var.Tbase, self.var.Tupp) elif self.var.GDDmethod == 2: tmax = np.clip(tmax, self.var.Tbase, self.var.Tupp) tmin = np.clip(tmin, self.var.Tbase, self.var.Tupp) tmean = ((tmax + tmin) / 2) elif self.var.GDDmethod == 3: tmax = np.clip(tmax, self.var.Tbase, self.var.Tupp) tmin = np.clip(tmin, None, self.var.Tupp) tmean = ((tmax + tmin) / 2) tmean = np.clip(tmean, self.var.Tbase, None) tmean[np.logical_not(growing_season_idx)] = 0 tbase[np.logical_not(growing_season_idx)] = 0 GDD = (tmean - tbase) GDDcum = np.cumsum(GDD, axis=0) # 1 - Calendar days from sowing to maximum canopy cover maxcanopy_idx = np.copy(day_idx) maxcanopy_idx[np.logical_not( GDDcum > self.var.MaxCanopy)] = 999 # maxcanopy_idx[np.logical_not(GDDcum > self.var.MaxCanopy)] = np.nan maxcanopy_idx = np.nanmin(maxcanopy_idx, axis=0) MaxCanopyCD = (maxcanopy_idx - pd + 1) self.var.MaxCanopyCD[cond1] = MaxCanopyCD[cond1] # 2 - Calendar days from sowing to end of vegetative growth canopydevend_idx = np.copy(day_idx) canopydevend_idx[np.logical_not( GDDcum > self.var.CanopyDevEnd)] = 999 # canopydevend_idx[np.logical_not(GDDcum > self.var.CanopyDevEnd)] = np.nan canopydevend_idx = np.nanmin(canopydevend_idx, axis=0) CanopyDevEndCD = canopydevend_idx - pd + 1 self.var.CanopyDevEndCD[cond1] = CanopyDevEndCD[cond1] # 3 - Calendar days from sowing to start of yield formation histart_idx = np.copy(day_idx) histart_idx[np.logical_not(GDDcum > self.var.HIstart)] = 999 # histart_idx[np.logical_not(GDDcum > self.var.HIstart)] = np.nan histart_idx = np.nanmin(histart_idx, axis=0) HIstartCD = histart_idx - pd + 1 self.var.HIstartCD[cond1] = HIstartCD[cond1] # 4 - Calendar days from sowing to end of yield formation hiend_idx = np.copy(day_idx) hiend_idx[np.logical_not(GDDcum > self.var.HIend)] = 999 # hiend_idx[np.logical_not(GDDcum > self.var.HIend)] = np.nan hiend_idx = np.nanmin(hiend_idx, axis=0) HIendCD = hiend_idx - pd + 1 self.var.HIendCD[cond1] = HIendCD[cond1] # Duration of yield formation in calendar days self.var.YldFormCD[cond1] = (self.var.HIendCD - self.var.HIstartCD)[cond1] cond11 = (cond1 & (self.var.CropType == 3)) # 1 Calendar days from sowing to end of flowering floweringend_idx = np.copy(day_idx) floweringend_idx[np.logical_not( GDDcum > self.var.FloweringEnd)] = 999 # floweringend_idx[np.logical_not(GDDcum > self.var.FloweringEnd)] = np.nan floweringend_idx = np.nanmin(floweringend_idx, axis=0) FloweringEnd = floweringend_idx - pd + 1 # 2 Duration of flowering in calendar days self.var.FloweringCD[cond11] = (FloweringEnd - self.var.HIstartCD)[cond11] # Harvest index growth coefficient self.calculate_HIGC() # Days to linear HI switch point self.calculate_HI_linear()
def compute_crop_calendar(self): # "Time from sowing to end of vegetative growth period" cond1 = (self.var.Determinant == 1) self.var.CanopyDevEnd = np.copy(self.var.Senescence) self.var.CanopyDevEnd[cond1] = ( np.round(self.var.HIstart + (self.var.Flowering / 2)))[cond1] # "Time from sowing to 10% canopy cover (non-stressed conditions) self.var.Canopy10Pct = np.round(self.var.Emergence + (np.log(0.1 / self.var.CC0) / self.var.CGC)) # "Time from sowing to maximum canopy cover (non-stressed conditions) self.var.MaxCanopy = np.round(self.var.Emergence + (np.log( (0.25 * self.var.CCx * self.var.CCx / self.var.CC0) / (self.var.CCx - (0.98 * self.var.CCx))) / self.var.CGC)) # "Time from sowing to end of yield formation" self.var.HIend = self.var.HIstart + self.var.YldForm cond2 = (self.var.CropType == 3) # TODO: declare these in __init__ arr_zeros = np.zeros_like(self.var.CropType) self.var.FloweringEnd = np.copy(arr_zeros) self.var.FloweringEndCD = np.copy(arr_zeros) self.var.FloweringCD = np.copy(arr_zeros) self.var.FloweringEnd[cond2] = (self.var.HIstart + self.var.Flowering)[cond2] self.var.FloweringEndCD[cond2] = self.var.FloweringEnd[cond2] self.var.FloweringCD[cond2] = self.var.Flowering[cond2] # Mode = self.var.CalendarType # if Mode == 1: if self.var.CalendarType == 1: # "Duplicate calendar values (needed to minimise if-statements when # switching between GDD and CD runs) self.var.EmergenceCD = np.copy( self.var.Emergence) # only used in this function self.var.Canopy10PctCD = np.copy( self.var.Canopy10Pct) # only used in this function self.var.MaxRootingCD = np.copy( self.var.MaxRooting) # only used in this function self.var.SenescenceCD = np.copy( self.var.Senescence) # only used in this function self.var.MaturityCD = np.copy( self.var.Maturity) # only used in this function self.var.MaxCanopyCD = np.copy(self.var.MaxCanopy) self.var.CanopyDevEndCD = np.copy(self.var.CanopyDevEnd) self.var.HIstartCD = np.copy(self.var.HIstart) self.var.HIendCD = np.copy(self.var.HIend) self.var.YldFormCD = np.copy(self.var.YldForm) self.var.FloweringEndCD = np.copy( self.var.FloweringEnd) # only used in this function self.var.FloweringCD = np.copy(self.var.Flowering) # Pre-compute cumulative GDD during growing season if (self.var.CalendarType == 1 & self.var.SwitchGDD) | (self.var.CalendarType == 2): pd = np.copy(self.var.PlantingDate) hd = np.copy(self.var.HarvestDate) sd = self.var._modelTime.startTime.timetuple().tm_yday # NEW: isLeapYear1 = calendar.isleap(self.var._modelTime.startTime.year) isLeapYear2 = calendar.isleap(self.var._modelTime.startTime.year + 1) if isLeapYear1: pd[pd >= 60] += 1 hd[(hd > pd) & (hd >= 60)] += 1 if isLeapYear2: hd[(hd < pd) & (hd >= 60)] += 1 hd[hd < pd] += 365 # already accounted for leap years so this should be OK cond = sd > pd pd[cond] += 365 hd[cond] += 365 # OLD: # # if start day of simulation is greater than planting day the # # first complete growing season will not be until the # # following year # pd[sd > pd] += 365 # hd[sd > pd] += 365 # # if start day is less than or equal to planting day, but # # harvest day is less than planting day, the harvest day will # # occur in the following year # hd[((sd <= pd) & (hd < pd))] += 365 # # adjust values for leap year # isLeapYear1 = calendar.isleap(self.var._modelTime.startTime.year) # isLeapYear2 = calendar.isleap(self.var._modelTime.startTime.year + 1) # pd[(isLeapYear1 & (pd >= 60))] += 1 # TODO: check these # hd[(isLeapYear1 & (hd >= 60))] += 1 # pd[(isLeapYear2 & (pd >= 425))] += 1 # hd[(isLeapYear2 & (hd >= 425))] += 1 max_harvest_date = int(np.max(hd)) day_idx = np.arange( sd, max_harvest_date + 1)[:, None, None, None] * np.ones_like( self.var.PlantingDate)[None, :, :, :] growing_season_idx = ((day_idx >= pd) & (day_idx <= hd)) # Extract weather data for first growing season tmin = vos.netcdf2NumPyTimeSlice( self.var.tmpFileNC, self.var.tmnVarName, self.var._modelTime.startTime, self.var._modelTime.startTime + datetime.timedelta(int(max_harvest_date - sd)), cloneMapFileName=self.var.cloneMap, LatitudeLongitude=True) tmax = vos.netcdf2NumPyTimeSlice( self.var.tmpFileNC, self.var.tmxVarName, self.var._modelTime.startTime, self.var._modelTime.startTime + datetime.timedelta(int(max_harvest_date - sd)), cloneMapFileName=self.var.cloneMap, LatitudeLongitude=True) # broadcast to crop dimension tmax = tmax[:, None, :, :] * np.ones( (self.var.PlantingDate.shape[0]))[None, :, None, None] tmin = tmin[:, None, :, :] * np.ones( (self.var.PlantingDate.shape[0]))[None, :, None, None] # for convenience tupp = self.var.Tupp[None, :, :, :] * np.ones( (tmin.shape[0]))[:, None, None, None] tbase = self.var.Tbase[None, :, :, :] * np.ones( (tmin.shape[0]))[:, None, None, None] # calculate GDD according to the various methods if self.var.GDDmethod == 1: tmean = ((tmax + tmin) / 2) tmean = np.clip(tmean, self.var.Tbase, self.var.Tupp) elif self.var.GDDmethod == 2: tmax = np.clip(tmax, self.var.Tbase, self.var.Tupp) tmin = np.clip(tmin, self.var.Tbase, self.var.Tupp) tmean = ((tmax + tmin) / 2) elif self.var.GDDmethod == 3: tmax = np.clip(tmax, self.var.Tbase, self.var.Tupp) tmin = np.clip(tmin, None, self.var.Tupp) tmean = ((tmax + tmin) / 2) tmean = np.clip(tmean, self.var.Tbase, None) tmean[np.logical_not(growing_season_idx)] = 0 tbase[np.logical_not(growing_season_idx)] = 0 GDD = (tmean - tbase) GDDcum = np.cumsum(GDD, axis=0) # "Check if converting crop calendar to GDD mode" # if Mode == 1 & self.var.SwitchGDD: if self.var.CalendarType == 1 & self.var.SwitchGDD: # Find GDD equivalent for each crop calendar variable m, n, p = pd.shape # crop,lat,lon I, J, K = np.ogrid[:m, :n, :p] emergence_idx = pd + self.var.EmergenceCD # crop,lat,lon self.var.Emergence = GDDcum[emergence_idx, I, J, K] canopy10pct_idx = pd + self.var.Canopy10PctCD self.var.Canopy10Pct = GDDcum[canopy10pct_idx, I, J, K] maxrooting_idx = pd + self.var.MaxRootingCD self.var.MaxRooting = GDDcum[maxrooting_idx, I, J, K] maxcanopy_idx = pd + self.var.MaxCanopyCD self.var.MaxCanopy = GDDcum[maxcanopy_idx, I, J, K] canopydevend_idx = pd + self.var.CanopyDevEndCD self.var.CanopyDevEnd = GDDcum[canopydevend_idx, I, J, K] senescence_idx = pd + self.var.SenescenceCD self.var.Senescence = GDDcum[senescence_idx, I, J, K] maturity_idx = pd + self.var.MaturityCD self.var.Maturity = GDDcum[maturity_idx, I, J, K] histart_idx = pd + self.var.HIstartCD self.var.HIstart = GDDcum[histart_idx, I, J, K] hiend_idx = pd + self.var.HIendCD self.var.HIend = GDDcum[hiend_idx, I, J, K] yldform_idx = pd + self.var.YldFormCD self.var.YldForm = GDDcum[yldform_idx, I, J, K] cond2 = (self.var.CropType == 3) floweringend_idx = pd + self.var.FloweringEndCD self.var.FloweringEnd[cond2] = GDDcum[floweringend_idx, I, J, K][cond2] self.var.Flowering[cond2] = (self.var.FloweringEnd - self.var.HIstart)[cond2] # "Convert CGC to GDD mode" # self.var.CGC_CD = self.var.CGC self.var.CGC = (np.log( (((0.98 * self.var.CCx) - self.var.CCx) * self.var.CC0) / (-0.25 * (self.var.CCx**2)))) / ( -(self.var.MaxCanopy - self.var.Emergence)) # "Convert CDC to GDD mode" # self.var.CDC_CD = self.var.CDC tCD = self.var.MaturityCD - self.var.SenescenceCD tCD[tCD <= 0] = 1 tGDD = self.var.Maturity - self.var.Senescence tGDD[tGDD <= 0] = 5 self.var.CDC = (self.var.CCx / tGDD) * np.log(1 + ( (1 - self.var.CCi / self.var.CCx) / 0.05)) # "Set calendar type to GDD mode" self.var._configuration.cropOptions['CalendarType'] = "2" # elif Mode == 2: elif self.var.CalendarType == 2: # "Find calendar days [equivalent] for some variables" # "1 Calendar days from sowing to maximum canopy cover" # # TODO: check this indexing # day_idx = np.arange(0, GDD.shape[0])[:,None,None,None] * np.ones((self.var.nCrop, self.var.nLon, self.var.nLat))[None,:,:,:] # pd,hd = self.var.adjust_planting_and_harvesting_date(self.var.modelTime.startTime) maxcanopy_idx = np.copy(day_idx) maxcanopy_idx[np.logical_not( GDDcum > self.var.MaxCanopy)] = 999 # maxcanopy_idx[np.logical_not(GDDcum > self.var.MaxCanopy)] = np.nan maxcanopy_idx = np.nanmin(maxcanopy_idx, axis=0) self.var.MaxCanopyCD = maxcanopy_idx - pd + 1 # "2 Calendar days from sowing to end of vegetative growth" canopydevend_idx = np.copy(day_idx) canopydevend_idx[np.logical_not( GDDcum > self.var.CanopyDevEnd)] = 999 # canopydevend_idx[np.logical_not(GDDcum > self.var.CanopyDevEnd)] = np.nan canopydevend_idx = np.nanmin(canopydevend_idx, axis=0) self.var.CanopyDevEndCD = canopydevend_idx - pd + 1 # "3 Calendar days from sowing to start of yield formation" histart_idx = np.copy(day_idx) histart_idx[np.logical_not(GDDcum > self.var.HIstart)] = 999 # histart_idx[np.logical_not(GDDcum > self.var.HIstart)] = np.nan histart_idx = np.nanmin(histart_idx, axis=0) self.var.HIstartCD = histart_idx - pd + 1 # "4 Calendar days from sowing to end of yield formation" hiend_idx = np.copy(day_idx) hiend_idx[np.logical_not(GDDcum > self.var.HIend)] = 999 # hiend_idx[np.logical_not(GDDcum > self.var.HIend)] = np.nan hiend_idx = np.nanmin(hiend_idx, axis=0) self.var.HIendCD = hiend_idx - pd + 1 # "Duration of yield formation in calendar days" self.var.YldFormCD = self.var.HIendCD - self.var.HIstartCD cond1 = (self.var.CropType == 3) # "1 Calendar days from sowing to end of flowering" floweringend_idx = np.copy(day_idx) floweringend_idx[np.logical_not( GDDcum > self.var.FloweringEnd)] = 999 # floweringend_idx[np.logical_not(GDDcum > self.var.FloweringEnd)] = np.nan floweringend_idx = np.nanmin(floweringend_idx, axis=0) FloweringEnd = floweringend_idx - pd + 1 # "2 Duration of flowering in calendar days" self.var.FloweringCD[cond1] = (FloweringEnd - self.var.HIstartCD)[cond1]