#! /usr/bin/env python #-*- coding: utf-8 -*- """ 11-07-2023 adapted from modspa-parcel code @author: jeremy auclair Classes to load and store SAMIR parameters. """ from pandas import read_csv # to read csv parameter files from numpy import nan # to fill nan values import param # type: ignore class samir_parameters_LC: """ This class allows to store all the SAMIR parameters for one land cover class """ def __init__(self, csvLine, defaultClass, mode_init = 1): # List of parameters that will be optimised (and hence that are not read in the param csv file) self.optimList = [] if defaultClass: #print(csvLine) for v in csvLine.values(): if v == '': raise ValueError("All fields must be filled for the default value line") self.name = csvLine['ClassName'] self.number = int(csvLine['ClassNumber']) # Parameters for the NDVI - Fraction Cover relation if (csvLine['FminFC'] != "optim"): self.ndviFCminFC = param.Number(float(csvLine['FminFC']), bounds=(0., 1.)).default else: self.optimList.append("FminFC") if (csvLine['FmaxFC'] != "optim"): self.ndviFCmaxFC = param.Number(float(csvLine['FmaxFC']), bounds=(0., 1.)).default else: self.optimList.append("FmaxFC") if (csvLine['Fslope'] != "optim"): self.ndviFCslope = param.Number(float(csvLine['Fslope']), bounds=(0., 10)).default else: self.optimList.append("Fslope") if (csvLine['Foffset'] != "optim"): self.ndviFCoffset = param.Number(float(csvLine['Foffset']), bounds=(-1, 1)).default else: self.optimList.append("Foffset") if (csvLine['Plateau'] != "optim"): self.ndviPlateau = param.Number(int(float(csvLine['Plateau'])), bounds=(0, 365)).default else: self.optimList.append("Plateau") # Parameters for the NDVI -Kcb relation if (csvLine['KminKcb'] != "optim"): self.ndviKcbminKcb = param.Number(float(csvLine['KminKcb']), bounds=(0, 0.5)).default else: self.optimList.append("KminKcb") if (csvLine['KmaxKcb'] != "optim"): self.ndviKcbmaxKcb = param.Number(float(csvLine['KmaxKcb']), bounds=(0.5, 2)).default else: self.optimList.append("KmaxKcb") if (csvLine['Kslope'] != "optim"): self.ndviKcbslope = param.Number(float(csvLine['Kslope'])).default else: self.optimList.append("Kslope") if (csvLine['Koffset'] != "optim"): self.ndviKcboffset = param.Number(float(csvLine['Koffset'])).default else: self.optimList.append("Koffset") # Soil parameters if (csvLine['Zsoil'] != "optim"): self.Zsoil = param.Number(float(csvLine['Zsoil']), bounds=(100, 10000), doc = "Soil depth (in mm)").default else: self.optimList.append("Zsoil") if (csvLine['Ze'] != "optim"): self.Ze = param.Number(float(csvLine['Ze']), bounds=(1, self.Zsoil), doc = "Evaporative layer depth (in mm)").default else: self.optimList.append("Ze") if mode_init == 1 or mode_init == 3: if (csvLine['Init_RU'] != "optim"): self.Init_RU = param.Number(float(csvLine['Init_RU']), doc = "Filling rate of the available water").default else: self.optimList.append("Init_RU") else : self.Dei = param.Number(float(csvLine['Init_Dei']), bounds=(0, None), doc = "Initial Depletion of the evaporative layer (irrigation + precipitation) (in mm)").default self.Dep = param.Number(float(csvLine['Init_Dep']), bounds=(0, None), doc = "Initial Depletion of the evaporative layer (precipitation only) (in mm)").default self.Dr = param.Number(float(csvLine['Init_Dr']), bounds=(0, None), doc = "Initial Depletion of the root layer (in mm)").default self.Dd = param.Number(float(csvLine['Init_Dd']), bounds=(0, None), doc = "Initial Depletion of the deep layer (in mm)").default if (csvLine['DiffE'] != "optim"): self.DiffE = param.Number(float(csvLine['DiffE']), bounds=(0, 1000), doc = "Diffusion coefficient between evaporative and root layers (unitless)").default else: self.optimList.append("DiffE") if (csvLine['DiffR'] != "optim"): self.DiffR = param.Number(float(csvLine['DiffR']), bounds=(0, 1000), doc = "Diffusion coefficient between root and deep layers (unitless)").default else: self.optimList.append("DiffR") if (csvLine['REW'] != "optim"): self.REW = param.Number(float(csvLine['REW']), bounds=(-1000, 1000), doc = "Readily Evaporable Water (in mm)").default else: self.optimList.append("REW") if (csvLine['m'] != "optim"): self.m = param.Number(float(csvLine['m']), bounds=(0, 1), doc = "").default ## si utilise, REW minimum doit etre à 0 ? else: self.optimList.append("m") # Crop parameters if (csvLine['minZr'] != "optim"): if (csvLine['Ze'] != "optim") & (csvLine['Zsoil'] != "optim"): self.minZr = param.Number(float(csvLine['minZr']), bounds=(self.Ze, self.Zsoil), doc = "Minimum root depth (mm)").default else: self.minZr = param.Number(float(csvLine['minZr']), bounds=(1, 10000), doc = "Minimum root depth (mm)").default else: self.optimList.append("minZr") if (csvLine['maxZr'] != "optim"): if (csvLine['Zsoil'] != "optim"): self.maxZr = param.Number(float(csvLine['maxZr']), bounds=(0, self.Zsoil-1), doc = "Maximum root depth (mm)").default else: self.maxZr = param.Number(float(csvLine['maxZr']), bounds=(0, 10000-1), doc = "Maximum root depth (mm)").default else: self.optimList.append("maxZr") if (csvLine['p'] != "optim"): self.p = param.Number(float(csvLine['p']), bounds=(0, 1), doc = "Fraction of readily available water").default else: self.optimList.append("p") # Irrigation parameters self.irrigFW = param.Number(float(csvLine['FW']), bounds=(0, 100), doc = "% of soil wetted by irrigation").default self.Irrig_auto = param.Integer(int(float(csvLine['Irrig_auto'])), doc = "1 if the automatic irrigation mode is activated").default self.Irrig_man = param.Integer(int(float(csvLine['Irrig_man'])), doc = "1 if the manual irrigation mode is activated").default if (csvLine['Lame_max'] != "optim"): self.Lame_max = param.Number(float(csvLine['Lame_max']), doc = "Maximum of irrigation height for each irrigation event (in mm)").default else: self.optimList.append("Lame_max") if (csvLine['minDays'] != "optim"): self.irrigMinDays = param.Integer(int(float(csvLine['minDays'])), bounds=(0, None), doc = "Minimum number of days between two irrigation events").default else: self.optimList.append("minDays") if (csvLine['Kcbmin_start'] != "optim"): self.Kcbmin_start = param.Number(float(csvLine['Kcbmin_start']), bounds=(0, 1), doc = "Minimum Kcb value above which irrigation may start").default else: self.optimList.append("Kcbmin_start") if (csvLine['Kcbmax_stop'] != "optim"): self.Kcbmax_stop = param.Number(float(csvLine['Kcbmax_stop']), bounds=(0, 1), doc = "Fraction of peak Kcb value below which irrigation stops").default else: self.optimList.append("Kcbmax_stop") if (csvLine['Kcmax'] != "optim"): self.Kcmax = param.Number(float(csvLine['Kcmax']), bounds=(0, None), doc = "pas d'info").default else: self.optimList.append("Kcmax") if (csvLine['Fc_stop'] != "optim"): self.Fc_stop = param.Number(float(csvLine['Fc_stop']), bounds=(0, None), doc = "pas d'info").default else: self.optimList.append("Fc_stop") if (csvLine['Start_date_Irr'] != "optim"): self.Start_date_Irr = param.Number(int(float(csvLine['Start_date_Irr'])), bounds=(0, None), doc = "pas d'info").default else: self.optimList.append("Start_date_Irr") if (csvLine["p_trigger"] != "optim"): self.p_trigger = param.Number(float(csvLine['p_trigger']), bounds=(-1, 1), doc = "Fraction of water storage capacity below which irrigation is triggered").default else: self.optimList.append("Fc_stop") def setParam(self, paramName, value): # Soil parameters if paramName == "REW": self.REW = value elif paramName == "Init_RU": self.Init_RU = value elif paramName == "minZr": self.minZr = value elif paramName == "maxZr": self.maxZr = value elif paramName == "Ze": self.Ze = value elif paramName == "Zsoil": self.Zsoil = value elif paramName == "DiffR": self.DiffR = value elif paramName == "DiffE": self.DiffE = value # Irrigation parameters elif paramName == "Lame_max": self.Lame_max = value elif paramName == "minDays": self.irrigMinDays = value # Vegetation parameters elif paramName == "FminFC": self.ndviFCminFC = value elif paramName == "FmaxFC": self.ndviFCmaxFC = value elif paramName == "Fc_stop": self.Fc_stop = value elif paramName == "Kcmax": self.Kcmax = value elif paramName == "Kcbmin_start" : self.Kcbmin_start = value elif paramName == "Kcbmax_stop" : self.Kcbmax_stop = value elif paramName == "Plateau" : self.ndviPlateau = value elif paramName == "Fslope" : self.ndviFCslope = value elif paramName == "Foffset" : self.ndviFCoffset = value elif paramName == "KmaxKcb" : self.ndviKcbmaxKcb = value elif paramName == "KminKcb" : self.ndviKcbminKcb = value elif paramName == "Kslope" : self.ndviKcbslope = value elif paramName == "Koffset" : self.ndviKcboffset = value elif paramName == "m" : self.m = value elif paramName == "p" : self.p = value elif paramName == "p_trigger": self.p_trigger = value class samir_parameters: """ Load all parameters for multiples classes in one object. """ def __init__(self, paramFile, mode_init = 1): self.classes = {} # Read csv file with Pandas csvFile = read_csv(paramFile, header = None) # Index file for correct conversion to dictionnary csvFile.index = csvFile.iloc[:,0] csvFile.replace(nan, '', inplace = True) defaultClass = True # Loop on columns for column in csvFile.columns[1:]: # Convert pandas column to dictionnary line = csvFile[column].to_dict() #TODO : @VR+@CO Intoduire ici une verification des valeurs #!! notamment si min=max alors error_rel=0 #!! Ajouter la possibilité de configurer plusieurs land cover if defaultClass: defaultLine = line.copy() elif line['ClassName'] in ['error_rel','error_abs','min','max']: self.classes[line['ClassName']] ={} for k in line.keys(): if k != 'ClassName': if line[k] == '': line[k] = 0 self.classes[line['ClassName']][k] = float(line[k]) continue else: for k in line.keys(): if line[k] == '': line[k] = defaultLine[k] self.classes[line['ClassName']] = samir_parameters_LC(line, defaultClass, mode_init) defaultClass = False