def sdc_spinup(self, water, ll, cwd, rl, lnc): """SOIL POOLS SPINUP""" for x in range(100000): s_out = soil_dec.carbon3(self.soil_temp, water / self.wmax_mm, ll, cwd, rl, lnc, self.sp_csoil, self.sp_snc) soil_out = catch_out_carbon3(s_out) self.sp_csoil = soil_out['cs'] self.sp_snc = soil_out['snc']
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
from caete_module import soil_dec as funcs from caete_module import global_par as gp def zeroes(*args): return np.zeros(shape=args, dtype=np.float32) cl = zeroes(2) + 0.01 cs = zeroes(3) + 0.01 nmin = zeroes(1) + 0.02 plab = zeroes(1) + 0.003 lnr = zeroes(6) + np.random.random(6, ) * 0.001 header = ['hr', 'cl1', 'cl2', 'cs1', 'cs2', 'cs3'] # subroutine carbon3(tsoil,leaf_l,cwd,root_l,lnr,cl,cs,cl_out,cs_out,hr) # tsoil, leaf_l, cwd, root_l, lnr, cl, cs, cl_out, cs_out, hr with open('carbon3_test.csv', 'w') as fh: CSV_WRITER = csv.writer(fh, delimiter=',') CSV_WRITER.writerow(header) for x in range(100000): df = funcs.carbon3(20, 0.1, 0.1, 0.1, lnr, cl, cs) line = [df[-1], df[0][0], df[0][1], df[1][0], df[1][1], df[1][2]] CSV_WRITER.writerow(line) cl = df[0][:] cs = df[1][:] data = pd.read_csv('carbon3_test.csv') os.system('rm -rf carbon3_test.csv')