def bdg_spinup(self, start_date='19010101', end_date='19030101'): """SPINUP SOIL POOLS - generate soil OM and Organic nutrients inputs for soil spinup - Side effect - Start soil water pools pools """ assert self.filled, "The gridcell has no input data" self.budget_spinup = True def find_co2(year): for i in self.co2_data: if int(i.split('\t')[0]) == year: return float(i.split('\t')[1].strip()) def find_index(start, end): result = [] num = np.arange(self.ssize) ind = np.arange(self.sind, self.eind + 1) for r, i in zip(num, ind): if i == start: result.append(r) for r, i in zip(num, ind): if i == end: result.append(r) return result # Define start and end dates start = cftime.real_datetime(int(start_date[:4]), int(start_date[4:6]), int(start_date[6:])) end = cftime.real_datetime(int(end_date[:4]), int(end_date[4:6]), int(end_date[6:])) # Check dates sanity assert start < end, "start > end" assert start >= self.start_date assert end <= self.end_date # Define time index start_index = int(cftime.date2num(start, self.time_unit, self.calendar)) end_index = int(cftime.date2num(end, self.time_unit, self.calendar)) lb, hb = find_index(start_index, end_index) steps = np.arange(lb, hb + 1) day_indexes = np.arange(start_index, end_index + 1) # Catch climatic input and make conversions temp = self.tas[lb:hb + 1] - 273.15 # ! K to °C prec = self.pr[lb:hb + 1] * 86400 # kg m-2 s-1 to mm/day # transforamando de Pascal pra mbar (hPa) p_atm = self.ps[lb:hb + 1] * 0.01 # W m-2 to mol m-2 s-1 ! 0.5 converts RSDS to PAR ipar = self.rsds[lb:hb + 1] * 0.5 / 2.18e5 ru = self.rhs[lb:hb + 1] / 100.0 year0 = start.year co2 = find_co2(year0) count_days = start.dayofyr - 2 loop = 0 next_year = 0 wo = [] llo = [] cwdo = [] rlo = [] lnco = [] sto = self.vp_sto cleaf = self.vp_cleaf cwood = self.vp_cwood croot = self.vp_croot dcl = self.vp_dcl dca = self.vp_dca dcf = self.vp_dcf uptk_costs = np.zeros(npls, order='F') for step in range(steps.size): loop += 1 count_days += 1 # CAST CO2 ATM CONCENTRATION days = 366 if m.leap(year0) == 1 else 365 if count_days == days: count_days = 0 year0 = cftime.num2date(day_indexes[step], self.time_unit, self.calendar).year co2 = find_co2(year0) next_year = (find_co2(year0 + 1) - co2) / days elif loop == 1 and count_days < days: year0 = start.year next_year = (find_co2(year0 + 1) - co2) / \ (days - count_days) co2 += next_year self.soil_temp = st.soil_temp(self.soil_temp, temp[step]) out = model.daily_budget( self.pls_table, self.wp_water_upper_mm, self.wp_water_lower_mm, self.soil_temp, temp[step], p_atm[step], ipar[step], ru[step], self.sp_available_n, self.sp_available_p, self.sp_snc[:4].sum(), self.sp_so_p, self.sp_snc[4:].sum(), co2, sto, cleaf, cwood, croot, dcl, dca, dcf, uptk_costs, self.wmax_mm, step) # Create a dict with the function output daily_output = catch_out_budget(out) runoff = self._update_pool(prec[step], daily_output['evavg']) # UPDATE vegetation pools wo.append( np.float64(self.wp_water_upper_mm + self.wp_water_lower_mm)) llo.append(daily_output['litter_l']) cwdo.append(daily_output['cwd']) rlo.append(daily_output['litter_fr']) lnco.append(daily_output['lnc']) f = np.array def x(a): return a * 0.75 return x(f(wo).mean()), x(f(llo).mean()), x(f(cwdo).mean()), x( f(rlo).mean()), x(f(lnco).mean(axis=0, ))
def run_caete(self, start_date, end_date, spinup=0, fix_co2=None): """ start_date [str] "yyyymmdd" Start model execution end_date [str] "yyyymmdd" End model execution spinup [int] Number of repetitions in spinup. 0 for no spinup fix_co2 [Float] Fixed value for ATM [CO2] [int] Fixed value for ATM [CO2] [str] "yyyy" Corresponding year of an ATM [CO2] This function run the fortran subroutines and manage data flux. It is the proper CAETÊ-DVM execution in the start_date - end_date period """ assert self.filled, "The gridcell has no input data" assert not fix_co2 or type( fix_co2 ) == str or fix_co2 > 0, "A fixed value for ATM[CO2] must be a positive number greater than zero or a proper string " def find_co2(year): for i in self.co2_data: if int(i.split('\t')[0]) == year: return float(i.split('\t')[1].strip()) def find_index(start, end): result = [] num = np.arange(self.ssize) ind = np.arange(self.sind, self.eind + 1) for r, i in zip(num, ind): if i == start: result.append(r) for r, i in zip(num, ind): if i == end: result.append(r) return result # Define start and end dates (read actual arguments) start = cftime.real_datetime(int(start_date[:4]), int(start_date[4:6]), int(start_date[6:])) end = cftime.real_datetime(int(end_date[:4]), int(end_date[4:6]), int(end_date[6:])) # Check dates sanity assert start < end, "start > end" assert start >= self.start_date assert end <= self.end_date # Define time index start_index = int(cftime.date2num(start, self.time_unit, self.calendar)) end_index = int(cftime.date2num(end, self.time_unit, self.calendar)) lb, hb = find_index(start_index, end_index) steps = np.arange(lb, hb + 1) day_indexes = np.arange(start_index, end_index + 1) spin = 1 if spinup == 0 else spinup # Catch climatic input and make conversions temp = self.tas[lb:hb + 1] - 273.15 # ! K to °C prec = self.pr[lb:hb + 1] * 86400 # kg m-2 s-1 to mm/day # transforamando de Pascal pra mbar (hPa) p_atm = self.ps[lb:hb + 1] * 0.01 # W m-2 to mol m-2 s-1 ! 0.5 converts RSDS to PAR ipar = self.rsds[lb:hb + 1] * 0.5 / 2.18e5 ru = self.rhs[lb:hb + 1] / 100.0 year0 = start.year co2 = find_co2(year0) count_days = start.dayofyr - 2 loop = 0 next_year = 0.0 fix_co2_p = False if fix_co2 is None: fix_co2_p = False elif type(fix_co2) == int or type(fix_co2) == float: co2 = fix_co2 fix_co2_p = True elif type(fix_co2) == str: assert type( int(fix_co2) ) == int, "The string(\"yyyy\") for the fix_co2 argument must be an year between 1901-2016" co2 = find_co2(int(fix_co2)) fix_co2_p = True for s in range(spin): self._allocate_output(steps.size) for step in range(steps.size): if fix_co2_p: pass else: loop += 1 count_days += 1 # CAST CO2 ATM CONCENTRATION days = 366 if m.leap(year0) == 1 else 365 if count_days == days: count_days = 0 year0 = cftime.num2date(day_indexes[step], self.time_unit, self.calendar).year co2 = find_co2(year0) next_year = (find_co2(year0 + 1) - co2) / days elif loop == 1 and count_days < days: year0 = start.year next_year = (find_co2(year0 + 1) - co2) / \ (days - count_days) co2 += next_year # if step == 0: # #print('1st day') # Update soil temperature self.soil_temp = st.soil_temp(self.soil_temp, temp[step]) # INFLATe VARS sto = np.zeros(shape=(3, npls), order='F') cleaf = np.zeros(npls, order='F') cwood = np.zeros(npls, order='F') croot = np.zeros(npls, order='F') dcl = np.zeros(npls, order='F') dca = np.zeros(npls, order='F') dcf = np.zeros(npls, order='F') uptk_costs = np.zeros(npls, order='F') sto[0, self.vp_lsid] = self.vp_sto[0, :] sto[1, self.vp_lsid] = self.vp_sto[1, :] sto[2, self.vp_lsid] = self.vp_sto[2, :] # Just Check the integrity of the data assert self.vp_lsid.size == self.vp_cleaf.size, 'different shapes' c = 0 for n in self.vp_lsid: cleaf[n] = self.vp_cleaf[c] cwood[n] = self.vp_cwood[c] croot[n] = self.vp_croot[c] dcl[n] = self.vp_dcl[c] dca[n] = self.vp_dca[c] dcf[n] = self.vp_dcf[c] uptk_costs[n] = self.sp_uptk_costs[c] c += 1 ton = self.sp_organic_n + self.sp_sorganic_n top = self.sp_organic_p + self.sp_sorganic_p out = model.daily_budget( self.pls_table, self.wp_water_upper_mm, self.wp_water_lower_mm, self.soil_temp, temp[step], p_atm[step], ipar[step], ru[step], self.sp_available_n, self.sp_available_p, ton, top, self.sp_organic_p, co2, sto, cleaf, cwood, croot, dcl, dca, dcf, uptk_costs, self.wmax_mm, step) del sto, cleaf, cwood, croot, dcl, dca, dcf, uptk_costs # Create a dict with the function output daily_output = catch_out_budget(out) self.vp_lsid = np.where(daily_output['ocpavg'] > 0.0)[0] self.vp_ocp = daily_output['ocpavg'][self.vp_lsid] self.ls[step] = self.vp_lsid.size # UPDATE STATE VARIABLES # WATER CWM self.runom[step] = self._update_pool(prec[step], daily_output['evavg']) # UPDATE vegetation pools ! ABLE TO USE SPARSE MATRICES self.vp_cleaf = daily_output['cleafavg_pft'][self.vp_lsid] self.vp_cwood = daily_output['cawoodavg_pft'][self.vp_lsid] self.vp_croot = daily_output['cfrootavg_pft'][self.vp_lsid] self.vp_dcl = daily_output['delta_cveg'][0][self.vp_lsid] self.vp_dca = daily_output['delta_cveg'][1][self.vp_lsid] self.vp_dcf = daily_output['delta_cveg'][2][self.vp_lsid] self.vp_sto = daily_output['stodbg'][:, self.vp_lsid] self.sp_uptk_costs = daily_output['npp2pay'][self.vp_lsid] # Plant uptake and Carbon costs of nutrient uptake self.nupt[:, step] = daily_output['nupt'] self.pupt[:, step] = daily_output['pupt'] for i in range(3): self.storage_pool[i, step] = np.sum(self.vp_ocp * self.vp_sto[i]) # OUTPUTS for SOIL CWM self.litter_l[step] = daily_output['litter_l'] self.cwd[step] = daily_output['cwd'] self.litter_fr[step] = daily_output['litter_fr'] self.lnc[:, step] = daily_output['lnc'] wtot = self.wp_water_upper_mm + self.wp_water_lower_mm s_out = soil_dec.carbon3(self.soil_temp, wtot / self.wmax_mm, self.litter_l[step], self.cwd[step], self.litter_fr[step], self.lnc[:, step], self.sp_csoil, self.sp_snc) soil_out = catch_out_carbon3(s_out) # Organic C N & P self.sp_csoil = soil_out['cs'] self.sp_snc = soil_out['snc'] # INCLUDE MINERALIZED NUTRIENTS self.sp_available_p += soil_out['pmin'] self.sp_available_n += soil_out['nmin'] # NUTRIENT DINAMICS # Inorganic N self.sp_in_n += self.sp_available_n + self.sp_so_n self.sp_so_n = soil_dec.sorbed_n_equil(self.sp_in_n) self.sp_available_n = soil_dec.solution_n_equil(self.sp_in_n) self.sp_in_n -= self.sp_so_n + self.sp_available_n # Inorganic P self.sp_in_p += self.sp_available_p + self.sp_so_p self.sp_so_p = soil_dec.sorbed_p_equil(self.sp_in_p) self.sp_available_p = soil_dec.solution_p_equil(self.sp_in_p) self.sp_in_p -= self.sp_so_p + self.sp_available_p # Sorbed P if self.pupt[1, step] > 0.05: rwarn( f"Puptk_SO > soP_max - 729 | in spin{s}, step{step} - {self.pupt[1, step]}" ) self.pupt[1, step] = 0.0 if self.pupt[1, step] > self.sp_so_p: rwarn( f"Puptk_SO > soP_pool - 731 | in spin{s}, step{step} - {self.pupt[1, step]}" ) self.sp_so_p -= self.pupt[1, step] t1 = np.all(self.sp_snc > 0.0) if not t1: self.snc[np.where(self.snc < 0)] = 0.0 # ORGANIC nutrients uptake # N if self.nupt[1, step] < 0.0: rwarn( f"NuptkO < 0 - 745 | in spin{s}, step{step} - {self.nupt[1, step]}" ) self.nupt[1, step] = 0.0 if self.nupt[1, step] > 0.8: rwarn( f"NuptkO > max - 749 | in spin{s}, step{step} - {self.nupt[1, step]}" ) self.nupt[1, step] = 0.0 total_on = self.sp_snc[:4].sum() frsn = [i / total_on for i in self.sp_snc[:4]] for i, fr in enumerate(frsn): self.sp_snc[i] -= self.nupt[1, step] * fr self.sp_organic_n = self.sp_snc[:2].sum() self.sp_sorganic_n = self.sp_snc[2:4].sum() # P if self.pupt[2, step] < 0.0: rwarn( f"PuptkO < 0 - 759 | in spin{s}, step{step} - {self.pupt[2, step]}" ) self.pupt[2, step] = 0.0 if self.pupt[2, step] > 0.1: rwarn( f"PuptkO < max - 763 | in spin{s}, step{step} - {self.pupt[2, step]}" ) self.pupt[2, step] = 0.0 total_op = self.sp_snc[4:].sum() frsp = [i / total_op for i in self.sp_snc[4:]] for i, fr in enumerate(frsp): self.sp_snc[i + 4] -= self.pupt[2, step] * fr self.sp_organic_p = self.sp_snc[4:6].sum() self.sp_sorganic_p = self.sp_snc[6:].sum() # Raise some warnings if self.sp_organic_n < 0.0: rwarn(f"ON negative in spin{s}, step{step}") if self.sp_sorganic_n < 0.0: rwarn(f"SON negative in spin{s}, step{step}") if self.sp_organic_p < 0.0: rwarn(f"OP negative in spin{s}, step{step}") if self.sp_sorganic_p < 0.0: rwarn(f"SOP negative in spin{s}, step{step}") # CALCULATE THE EQUILIBTIUM IN SOIL POOLS # Soluble and inorganic pools if self.pupt[0, step] > 2.5: rwarn( f"Puptk > max - 786 | in spin{s}, step{step} - {self.pupt[0, step]}" ) self.pupt[0, step] = 0.0 self.sp_available_p -= self.pupt[0, step] if self.nupt[0, step] > 2.5: rwarn( f"Nuptk > max - 792 | in spin{s}, step{step} - {self.nupt[0, step]}" ) self.nupt[0, step] = 0.0 self.sp_available_n -= self.nupt[0, step] # END SOIL NUTRIENT DYNAMICS # # # Process (cwm) & store (np.array) outputs self.carbon_costs[self.vp_lsid, step] = self.sp_uptk_costs self.emaxm.append(daily_output['epavg']) self.tsoil.append(self.soil_temp) self.photo[step] = daily_output['phavg'] self.aresp[step] = daily_output['aravg'] self.npp[step] = daily_output['nppavg'] self.lai[step] = daily_output['laiavg'] self.rcm[step] = daily_output['rcavg'] self.f5[step] = daily_output['f5avg'] self.evapm[step] = daily_output['evavg'] self.wsoil[step] = self.wp_water_upper_mm self.swsoil[step] = self.wp_water_lower_mm self.rm[step] = daily_output['rmavg'] self.rg[step] = daily_output['rgavg'] self.wue[step] = daily_output['wueavg'] self.cue[step] = daily_output['cueavg'] self.cdef[step] = daily_output['c_defavg'] self.vcmax[step] = daily_output['vcmax'] self.specific_la[step] = daily_output['specific_la'] self.cleaf[step] = daily_output['cp'][0] self.cawood[step] = daily_output['cp'][1] self.cfroot[step] = daily_output['cp'][2] self.hresp[step] = soil_out['hr'] self.csoil[:, step] = soil_out['cs'] self.inorg_n[step] = self.sp_in_n self.inorg_p[step] = self.sp_in_p self.sorbed_n[step] = self.sp_so_n self.sorbed_p[step] = self.sp_so_p self.snc[:, step] = soil_out['snc'] self.nmin[step] = self.sp_available_n self.pmin[step] = self.sp_available_p self.area[self.vp_lsid, step] = self.vp_ocp self.lim_status[:, self.vp_lsid, step] = daily_output[ 'limitation_status'][:, self.vp_lsid] self.uptake_strategy[:, self.vp_lsid, step] = daily_output[ 'uptk_strat'][:, self.vp_lsid] if s > 0: while True: if sv.is_alive(): sleep(0.5) else: break self.flush_data = self._flush_output('spin', (start_index, end_index)) sv = Thread(target=self._save_output, args=(self.flush_data, )) sv.start() while True: if sv.is_alive(): sleep(0.5) else: break return None
def bdg_spinup(self, start_date='19010101', end_date='19030101'): """SPINUP VEGETATION""" assert self.filled, "The gridcell has no input data" self.budget_spinup = True def find_co2(year): for i in self.co2_data: if int(i.split('\t')[0]) == year: return float(i.split('\t')[1].strip()) def find_index(start, end): result = [] num = np.arange(self.ssize) ind = np.arange(self.sind, self.eind + 1) for r, i in zip(num, ind): if i == start: result.append(r) for r, i in zip(num, ind): if i == end: result.append(r) return result # Define start and end dates start = cftime.real_datetime(int(start_date[:4]), int(start_date[4:6]), int(start_date[6:])) end = cftime.real_datetime(int(end_date[:4]), int(end_date[4:6]), int(end_date[6:])) # Check dates sanity assert start < end, "start > end" assert start >= self.start_date assert end <= self.end_date # Define time index start_index = int(cftime.date2num(start, self.time_unit, self.calendar)) end_index = int(cftime.date2num(end, self.time_unit, self.calendar)) lb, hb = find_index(start_index, end_index) steps = np.arange(lb, hb + 1) day_indexes = np.arange(start_index, end_index + 1) # Catch climatic input and make conversions temp = self.tas[lb:hb + 1] - 273.15 # ! K to °C prec = self.pr[lb:hb + 1] * 86400 # kg m-2 s-1 to mm/day # transforamando de Pascal pra mbar (hPa) p_atm = self.ps[lb:hb + 1] * 0.01 # W m-2 to mol m-2 s-1 ! 0.5 converts RSDS to PAR ipar = self.rsds[lb:hb + 1] * 0.5 / 2.18e5 ru = self.rhs[lb:hb + 1] / 100.0 year0 = start.year co2 = find_co2(year0) count_days = start.dayofyr - 2 loop = 0 next_year = 0 wo = [] llo = [] cwdo = [] rlo = [] lnco = [] sto = self.vp_sto cleaf = self.vp_cleaf cwood = self.vp_cwood croot = self.vp_croot csap = self.vp_csap cheart = self.vp_cheart dcl = self.vp_dcl dca = self.vp_dca dcf = self.vp_dcf uptk_costs = np.zeros(npls, order='F') for step in range(steps.size): loop += 1 count_days += 1 # CAST CO2 ATM CONCENTRATION days = 366 if utl.leap(year0) == 1 else 365 if count_days == days: count_days = 0 year0 = cftime.num2date(day_indexes[step], self.time_unit, self.calendar).year co2 = find_co2(year0) next_year = (find_co2(year0 + 1) - co2) / days elif loop == 1 and count_days < days: year0 = start.year next_year = (find_co2(year0 + 1) - co2) / \ (days - count_days) co2 += next_year if step == lb: #first day (csap and cheart just for initialization) cleaf = cleaf cwood = cwood croot = croot csap = cwood * 0.05 cheart = cwood * 0.95 print('lb0', 'csap 1=', csap, 'cheart 1=', cheart, 'cwood 1=', cwood) else: # csap and cheart calculated by allometric restrictions cleaf = cleaf croot = croot csap = csap cheart = cheart cwood = csap + cheart print('lb dif. 0', 'csap 1=', csap, 'cheart 1=', cheart, 'cwood 1=', cwood) self.soil_temp = st.soil_temp(self.soil_temp, temp[step]) self.wfim = np.zeros(npls, order='F') + self.wp_water self.gfim = np.zeros(npls, order='F') + self.wp_ice self.sfim = np.zeros(npls, order='F') + self.wp_snow print('SPINUPPPPPP') out = model.daily_budget( self.pls_table, self.wfim, self.gfim, self.sfim, self.soil_temp, temp[step], prec[step], p_atm[step], ipar[step], ru[step], self.sp_available_n, self.sp_available_p, self.sp_snc[:4].sum(), self.sp_so_p, self.sp_snc[4:].sum(), co2, sto, cleaf, cwood, croot, csap, cheart, dcl, dca, dcf, uptk_costs) self.wfim = None self.gfim = None self.sfim = None # Create a dict with the function output daily_output = catch_out_budget(out) self.wp_water = daily_output['wp'][0] self.wp_ice = daily_output['wp'][1] self.wp_snow = daily_output['wp'][2] # UPDATE vegetation pools wo.append(self.wp_water) llo.append(daily_output['litter_l']) cwdo.append(daily_output['cwd']) rlo.append(daily_output['litter_fr']) lnco.append(daily_output['lnc']) f = np.array def x(a): return a * 0.75 return x(f(wo).mean()), x(f(llo).mean()), x(f(cwdo).mean()), x( f(rlo).mean()), x(f(lnco).mean(axis=0, ))