def apply_harvest_stand_model(self, inventory: Inventory, model: StandModel, operation: Operation): result_inventory = Inventory() min = operation.get_variable('min_age') if operation.has('min_age') else 0 max = operation.get_variable('max_age') if operation.has('max_age') else 1000 for plot in inventory.plots: if min <= plot.age <= max: new_plot = Plot() new_plot.clone(plot) try: cut_criteria = CUTTYPES_DICT[operation.get_variable('cut_down')] model.apply_cut_down_model(plot, new_plot, cut_criteria, operation.get_variable('volumen'), operation.get_variable('time'), min, max) except Exception as e: Tools.print_log_line(str(e), logging.ERROR) result_inventory.add_plot(new_plot) return result_inventory
def merch_classes_plot(self, plot: Plot): """ Function to calculate the wood uses values to the plot. That function is run by initialize and process_plot functions. """ plot_trees: list[Tree] = plot.short_trees_on_list( 'dbh', DESC) # stablish an order to calculate tree variables plot_unwinding = plot_veneer = plot_saw_big = plot_saw_small = plot_saw_canter = plot_post = plot_stake = plot_chips = 0 for tree in plot_trees: # for each tree, we are going to add the simple values to the plot value # plot_unwinding += tree.unwinding # plot_veneer += tree.veneer plot_saw_big += tree.saw_big plot_saw_small += tree.saw_small plot_saw_canter += tree.saw_canter # plot_post += tree.post # plot_stake += tree.stake plot_chips += tree.chips # plot.add_value('UNWINDING', plot_unwinding/1000) # now, we add the plot value to each variable, changing the unit to m3 # plot.add_value('VENEER', plot_veneer/1000) plot.add_value('SAW_BIG', plot_saw_big / 1000) plot.add_value('SAW_SMALL', plot_saw_small / 1000) plot.add_value('SAW_CANTER', plot_saw_canter / 1000) # plot.add_value('POST', plot_post/1000) # plot.add_value('STAKE', plot_stake/1000) plot.add_value('CHIPS', plot_chips / 1000)
def P9010_distribution(self, plot: Plot, tree: Tree): """ That function is only needed on Pinus pinea model. It is needed to calculate the difference between the 90th and 10th percentiles from the diametric distribution (cm), which is a parameter useful on the h/d equation of Calama and Montero (2004). """ # That model includes this function because it is needed in orden to calculate the difference between 10 and 90 diametric distribution percentiles (cm) plot_trees: list[Tree] = plot.short_trees_on_list( 'dbh', DESC) # stablish an order to calculate tree variables P9010_list = [] for tree in plot_trees: # add all the trees dbh to a list P9010_list.append(tree.dbh) x = len(P9010_list) x_up = int(0.9 * x) x_down = int(0.1 * x) P9010_clean = P9010_list[ x_down: x_up] # reduce the list leaving the trees between 10% an 90% of diametric distribution P9010 = max(P9010_list) - min( P9010_list ) # obtain the difference between them, which is the value of P9010 return P9010 # that variable will return the difference between the 90th and 10th percentiles from the diametric distribution (cm)
def apply_initialize_stand_model(self, inventory: Inventory, model: StandModel, operation: Operation): result_inventory = Inventory() for plot in inventory.plots: new_plot = Plot() new_plot.clone(plot, True) try: model.initialize(new_plot) except Exception as e: Tools.print_log_line(str(e), logging.ERROR) # new_plot.recalculate() result_inventory.add_plot(new_plot) return result_inventory
def __init__(self, reader=None, date=datetime.now()): self.__date = date self.__plots = dict() self.__plots_to_print = dict() if reader is None: Tools.print_log_line( "No reader information, generated empty plots list", logging.WARNING) elif isinstance(reader, ExcelReader): reader.choose_sheet(PARCEL_CODE, True) for plot in reader: p = Plot(plot) self.__plots[p.id] = p self.__plots_to_print[p.id] = True reader.choose_sheet(TREE_CODE, True) for data in reader: tree = Tree(data) plot_id = tree.get_value('PLOT_ID') self.__plots[plot_id].add_tree(tree) elif isinstance(reader, JSONReader): reader.choose_sheet('plots', True) for plot in reader: p = Plot(plot) self.__plots[p.id] = p self.__plots_to_print[p.id] = True reader.choose_sheet('trees', True) for data in reader: tree = Tree(data) plot_id = tree.get_value('PLOT_ID', True) # True, it's in json format self.__plots[plot_id].add_tree(tree)
def merch_classes_plot(self, plot: Plot): """ Function to calculate the wood uses values to the plot. That function is run by initialize and process_plot functions. """ plot_trees: list[Tree] = plot.short_trees_on_list('dbh', DESC) # stablish an order to calculate tree variables plot_unwinding = plot_veneer = plot_saw_big = plot_saw_small = plot_saw_canter = plot_post = plot_stake = plot_chips = 0 for tree in plot_trees: # for each tree, we are going to add the simple values to the plot value
def biomass_plot(self, plot: Plot): """ Function to calculate the wood uses values to the plot. That function is run by initialize and process_plot functions. """ plot_trees: list[Tree] = plot.short_trees_on_list('dbh', DESC) # stablish an order to calculate tree variables plot_wsw = plot_wsb = plot_w_cork = plot_wthickb = plot_wstb = plot_wb2_7 = plot_wb2_t = plot_wthinb = plot_wl = plot_wtbl = plot_wbl0_7 = plot_wr = plot_wt = 0 for tree in plot_trees: # for each tree, we are going to add the simple values to the plot value
def biomass_plot(self, plot: Plot): """ Function to calculate the wood uses values to the plot. That function is run by initialize and process_plot functions. """ plot_trees: list[Tree] = plot.short_trees_on_list( 'dbh', DESC) # stablish an order to calculate tree variables plot_wsw = plot_wsb = plot_w_cork = plot_wthickb = plot_wstb = plot_wb2_7 = plot_wb2_t = plot_wthinb = plot_wl = plot_wtbl = plot_wbl0_7 = plot_wr = plot_wt = 0 for tree in plot_trees: # for each tree, we are going to add the simple values to the plot value # plot_wsw += tree.wsw # plot_wsb += tree.wsb # plot_w_cork += tree.w_cork # plot_wthickb += tree.wthickb plot_wstb += tree.wstb plot_wb2_7 += tree.wb2_7 # plot_wb2_t += tree.wb2_t plot_wthinb += tree.wthinb # plot_wl += tree.wl # plot_wtbl += tree.wtbl # plot_wbl0_7 += tree.wbl0_7 plot_wr += tree.wr plot_wt += tree.wt # plot.add_value('WSW', plot_wsw/1000) # Wsw # wsw = stem wood (Tn) # plot.add_value('WSB', plot_wsb/1000) # Wsb # wsb = stem bark (Tn) # plot.add_value('W_CORK', plot_w_cork/1000) # W Fresh Cork # w_cork = fresh cork biomass (Tn) # plot.add_value('WTHICKB', plot_wthickb/1000) # Wthickb # wthickb = Thick branches > 7 cm (Tn) plot.add_value( 'WSTB', plot_wstb / 1000) # Wstb # wstb = wsw + wthickb, stem + branches >7 cm (Tn) plot.add_value('WB2_7', plot_wb2_7 / 1000) # Wb2_7 # wb2_7 = branches (2-7 cm) (Tn) # plot.add_value('WB2_T', plot_wb2_t/1000) # Wb2_t # wb2_t = wb2_7 + wthickb; branches >2 cm (Tn) plot.add_value( 'WTHINB', plot_wthinb / 1000) # Wthinb # wthinb = Thin branches (2-0.5 cm) (Tn) # plot.add_value('WB05', plot_wb05) # wb05 = thinniest branches (<0.5 cm) (Kg) # plot.add_value('WL', plot_wl/1000) # Wl # wl = leaves (Tn) # plot.add_value('WTBL', plot_wtbl/1000) # Wtbl # wtbl = wthinb + wl; branches <2 cm and leaves (Tn) # plot.add_value('WBL0_7', plot_wbl0_7/1000) # Wbl0_7 # wbl0_7 = wb2_7 + wthinb + wl; branches <7 cm and leaves (Tn) plot.add_value('WR', plot_wr / 1000) # Wr # wr = roots (Tn) plot.add_value('WT', plot_wt / 1000) # Wt # wt = biomasa total (Tn)
def correct_plots(self, inventory, operation: Operation): if inventory is None: return min = operation.get_variable('min_age') if operation.has( 'min_age') else 0 max = operation.get_variable('max_age') if operation.has( 'max_age') else 1000 time = 0 for plot in inventory.plots: if min <= plot.age <= max: time = operation.get_variable('time') if plot.id not in self.__plots.keys(): new_plot = Plot() new_plot.clone(plot, True) new_plot.sum_value('AGE', time) self.__plots_to_print[plot.id] = False self.__plots[plot.id] = new_plot self.__plots[plot.id].sum_value('AGE', time) # self.__plots[plot.id].update_trees({'AGE': time}, 1) time = 0
def apply_tree_stand_model(self, inventory: Inventory, model: StandModel, operation: Operation): result_inventory = Inventory() min = operation.get_variable('min_age') if operation.has('min_age') else 0 max = operation.get_variable('max_age') if operation.has('max_age') else 1000 for plot in inventory.plots: if min <= plot.age <= max: new_plot = Plot() new_plot.clone(plot) try: model.apply_tree_model(plot, new_plot, operation.get_variable('time')) except Exception as e: Tools.print_log_line(str(e), logging.ERROR) result_inventory.add_plot(new_plot) return result_inventory
def process_plot(self, time: int, plot: Plot, trees: list): """ Function that update the trees information once the grow Function was executed The equations on that Function are the same that in "initialize" Function """ print('#----------------------------------------------------------------------------#') print(' BasicTreeModel model (xx) is running ') print('#----------------------------------------------------------------------------#') if time != '': print('BE CAREFUL! That model was developed to xx year execution, and you are trying to make a', time, 'years execution!') print('Please, change your execution conditions to the recommended (xx year execution). If not, the output values will be not correct.') try: # errors inside that construction will be annodbhced plot_trees: list[Tree] = plot.short_trees_on_list('dbh', DESC) # stablish an order to calculate tree variables bal: float = 0.0 for tree in plot_trees: # for each tree... if tree.status is None: # only update tree alive data #-----------------------------------BASAL AREA-----------------------------------------# tree.add_value('basal_area', math.pi * (tree.dbh / 2) ** 2) # normal (at 1.30m) section (cm2) calculation tree.add_value('bal', bal) # the first tree must receive 0 value (m2) tree.add_value('ba_ha', tree.basal_area * tree.expan / 10000) # basimetric area per ha (m2/ha) bal += tree.basal_area * tree.expan / 10000 # then, that value is acumulated tree.add_value('hd_ratio', tree.height * 100 / tree.dbh) # height/diameter ratio (%) calculation tree.add_value('normal_circumference', math.pi * tree.dbh) # normal (at 1.30m) circumference (cm) calculation #-----------------------------------FUNCTIONS-----------------------------------------# self.crown(tree, plot, 'process_plot') # activate crown variables calculation self.vol(tree, plot) # activate volume variables calculation self.merch_classes(tree) # activate wood uses variables calculation self.biomass(tree) # activate biomass variables calculation self.merch_classes_plot(plot) # activate wood uses (plot) variables calculation self.biomass_plot(plot) # activate biomass (plot) variables calculation except Exception: self.catch_model_exception()
def initialize(self, plot: Plot): """ Function that update the gaps on the information with the inventory data """ print('#----------------------------------------------------------------------------#') print(' BasicTreeModel model (xx) is running ') print('#----------------------------------------------------------------------------#') try: # errors inside that construction will be annodbhced plot_trees: list[Tree] = plot.short_trees_on_list('dbh', DESC) # stablish an order to calculate tree variables bal: float = 0 for tree in plot_trees: # for each tree... #-----------------------------------BASAL AREA-----------------------------------------# tree.add_value('bal', bal) # the first tree must receive 0 value (m2) tree.add_value('basal_area', math.pi * (tree.dbh / 2) ** 2) # normal (at 1.30m) section (cm2) calculation tree.add_value('ba_ha', tree.basal_area * tree.expan / 10000) # basimetric area per ha (m2/ha) bal += tree.basal_area * tree.expan / 10000 # then, that value is acumulated tree.add_value('hd_ratio', tree.height * 100 / tree.dbh) # height/diameter ratio (%) calculation tree.add_value('normal_circumference', math.pi * tree.dbh) # normal (at 1.30m) circumference (cm) calculation #-----------------------------------HEIGHT-----------------------------------------# if tree.height == 0: # if the tree hasn't height (m) value, it is calculated tree.add_value('height', ) #-----------------------------------FUNCTIONS-----------------------------------------# self.crown(tree, plot, 'initialize') # activate crown variables calculation self.vol(tree, plot) # activate volume variables calculation self.merch_classes(tree) # activate wood uses variables calculation self.biomass(tree) # activate biomass variables calculation self.merch_classes_plot(plot) # activate wood uses (plot) variables calculation self.biomass_plot(plot) # activate biomass (plot) variables calculation except Exception: self.catch_model_exception()
def initialize(self, plot: Plot): """ Function that update the gaps on the information with the inventory data Height/Diameter equation: Doc.: Saldaña AMC (2010). Bases para la gestión de masas naturales de Pinus halepensis Mill. en el Valle del Ebro (Doctoral dissertation, Universidad Politécnica de Madrid) Ref.: Saldaña, 2010 SI equation: a) Doc.: Saldaña AMC (2010). Bases para la gestión de masas naturales de Pinus halepensis Mill. en el Valle del Ebro (Doctoral dissertation, Universidad Politécnica de Madrid) Ref.: Saldaña, 2010 Doc.: Rojo A, Saldaña, AM, Barrio-Anta M, Notivol-Paíno E, Gorgoso-Varela JJ (2017). Site index curves for natural Aleppo pine forests in the central Ebro valley (Spain) Ref.: Rojo et al, 2017 b) Doc.: Montero G, Cañellas I, Ruiz-Peinado R (2002). Growth and yield models for Pinus halepensis Mill. Forest Systems, 10(1), 179-201 Ref.: Montero et al, 2002 """ print( '#----------------------------------------------------------------------------#' ) print( ' Pinus halepensis model (Cataluña) is running ' ) print( '#----------------------------------------------------------------------------#' ) try: # errors inside that construction will be announced #-----------------------------------SI-----------------------------------------# # a) t2 = 60 # age to calculate SI part1 = plot.dominant_h + 16.3229 + math.sqrt( (plot.dominant_h - 16.3229)**2 + 8185.244 * plot.dominant_h * (plot.age**(-1.3097))) part2 = plot.dominant_h - 16.3229 + math.sqrt( (plot.dominant_h - 16.3229)**2 + 8185.244 * plot.dominant_h * (plot.age**(-1.3097))) SI = (part1) / (2 + (8185.244 * (t2**(-1.3097)) / (part2))) # b) # SI = 1.521453 * ((1 - math.exp(-0.203954*plot.age))**(1 / 1.046295)) # calculated to 80 years plot.add_value('SI', SI) # Site Index (m) calculation plot_wt = 0 plot_trees: list[Tree] = plot.short_trees_on_list( 'dbh', DESC) # stablish an order to calculate tree variables bal: float = 0 for tree in plot_trees: # for each tree... #-----------------------------------BASAL AREA-----------------------------------------# tree.add_value('bal', bal) # the first tree must receive 0 value (m2) tree.add_value( 'basal_area', math.pi * (tree.dbh / 2)** 2) # normal (at 1.30m) section (cm2) calculation tree.add_value('ba_ha', tree.basal_area * tree.expan / 10000) # basimetric area per ha (m2/ha) bal += tree.basal_area * tree.expan / 10000 # then, that value is acumulated tree.add_value( 'hd_ratio', tree.height * 100 / tree.dbh) # height/diameter ratio (%) calculation tree.add_value( 'normal_circumference', math.pi * tree.dbh ) # normal (at 1.30m) circumference (cm) calculation #-----------------------------------HEIGHT-----------------------------------------# if tree.height == 0: # if the tree hasn't height (m) value, it is calculated tree.add_value( 'height', 1.3 + (plot.mean_h - 1.3) * math.exp(0.3532 * (1 - plot.qm_dbh / tree.dbh)) * math.exp(0.0315 * (tree.dbh / plot.qm_dbh - 1 / tree.dbh))) #-----------------------------------FUNCTIONS-----------------------------------------# # self.crown(tree, plot, 'initialize') # activate crown variables calculation self.vol(tree, plot) # activate volume variables calculation self.merch_classes( tree) # activate wood uses variables calculation self.biomass(tree) # activate biomass variables calculation self.merch_classes_plot( plot) # activate wood uses (plot) variables calculation self.biomass_plot( plot) # activate biomass (plot) variables calculation except Exception: self.catch_model_exception()
def initialize(self, plot: Plot): """ Function that update the gaps on the information with the inventory data Height/Diameter equation: Doc.: Lizarralde I (2008). Dinámica de rodales y competencia en las masas de pino silvestre (Pinus sylvestris L.) y pino negral (Pinus pinaster Ait.) de los Sistemas Central e Ibérico Meridional. Tesis Doctoral. 230 pp Ref.: Lizarralde 2008 SI equation: Doc.: Bravo-Oviedo A, del Río M, Montero G (2004). Site index curves and growth model for Mediterranean maritime pine (Pinus pinaster Ait.) in Spain. Forest Ecology and Management, 201(2-3), 187-197 Ref.: Bravo-Oviedo et al. 2004 """ print( '#----------------------------------------------------------------------------#' ) print( ' Pinus pinaster mesogeensis model (Sistema Ibérico Meridional) is running ' ) print( '#----------------------------------------------------------------------------#' ) try: # errors inside that construction will be announced #-----------------------------------SI-----------------------------------------# t = 80 # site index is defined as top height at a base age of 80 years, settíng this value with 't' plot.add_value( 'SI', math.exp(4.016 + (math.log(plot.dominant_h) - 4.016) * math.pow(t / plot.age, -0.5031)) ) # Site Index (m) calculation plot_trees: list[Tree] = plot.short_trees_on_list( 'dbh', DESC) # stablish an order to calculate tree variables bal: float = 0 for tree in plot_trees: # for each tree... #-----------------------------------BASAL AREA-----------------------------------------# tree.add_value('bal', bal) # the first tree must receive 0 value (m2) tree.add_value( 'basal_area', math.pi * (tree.dbh / 2)** 2) # normal (at 1.30m) section (cm2) calculation tree.add_value('ba_ha', tree.basal_area * tree.expan / 10000) # basimetric area per ha (m2/ha) bal += tree.basal_area * tree.expan / 10000 # then, that value is acumulated tree.add_value( 'hd_ratio', tree.height * 100 / tree.dbh) # height/diameter ratio (%) calculation tree.set_value( 'normal_circumference', math.pi * tree.dbh ) # normal (at 1.30m) circumference (cm) calculation #-----------------------------------HEIGHT-----------------------------------------# if tree.height == 0: # if the tree hasn't height (m) value, it is calculated tree.add_value( 'height', (13 + (32.3287 + 1.6688 * plot.dominant_h * 10 - 0.1279 * plot.qm_dbh * 10) * math.exp(-11.4522 / math.sqrt(tree.dbh * 10))) / 10) #-----------------------------------FUNCTIONS-----------------------------------------# self.crown( tree, plot, 'initialize') # activate crown variables calculation self.vol(tree, plot) # activate volume variables calculation self.merch_classes( tree) # activate wood uses variables calculation self.biomass(tree) # activate biomass variables calculation self.merch_classes_plot( plot) # activate wood uses (plot) variables calculation self.biomass_plot( plot) # activate biomass (plot) variables calculation except Exception: self.catch_model_exception()
def apply_grow_model(self, old_plot: Plot, new_plot: Plot, time: int): """ Function that includes the equations needed in the executions. BE CAREFUL!! Is not needed to store the new plot age on the 'AGE' variable, the simulator will do it by his own. Dominant Height equation: Doc.: del Río M, Montero G (2011). Modelo de simulación de claras en masas de Pinus sylvestris L. Monografias INIA: Forestal n. 3 Ref.: del Río and Montero, 2011 Basal Area Growth equation: Doc.: del Río M, Montero G (2011). Modelo de simulación de claras en masas de Pinus sylvestris L. Monografias INIA: Forestal n. 3 Ref.: del Río and Montero, 2011 Survive equation: Doc.: del Río M, Montero G (2011). Modelo de simulación de claras en masas de Pinus sylvestris L. Monografias INIA: Forestal n. 3 Ref.: del Río and Montero, 2011 Reineke Index equation (value): Doc.: del Río M, Montero G (2011). Modelo de simulación de claras en masas de Pinus sylvestris L. Monografias INIA: Forestal n. 3 Ref.: del Río and Montero, 2011 Site Index equation: Doc.: del Río M, Montero G (2011). Modelo de simulación de claras en masas de Pinus sylvestris L. Monografias INIA: Forestal n. 3 Ref.: del Río and Montero, 2011 Volume equation: Doc.: del Río M, Montero G (2011). Modelo de simulación de claras en masas de Pinus sylvestris L. Monografias INIA: Forestal n. 3 Ref.: del Río and Montero, 2011 """ print('#----------------------------------------------------------------------------#') print(' Pinus sylvestris "SILVES" model (Spain) is running ') print('#----------------------------------------------------------------------------#') if time != 5: print('BE CAREFUL! That model was developed to xx year execution, and you are trying to make a', time, 'years execution!') print('Please, change your execution conditions to the recommended (xx year execution). If not, the output values will be not correct.') try: # new_plot.add_value('AGE', old_plot.age + time) # store new age in database # BE CAREFUL!! Is not needed to store the new plot age on the 'AGE' variable, the simulator will do it by his own. # if you need to use the "actualised" age, just create another new variable to do it. new_age = old_plot.age + time # That line is not needed; at the start, old_plot and new_plot values are the same # new_plot.add_value('SI', old_plot.si) # store Site Index in database, constant value for each plot # Dominant Height parA17 = 1.9962 parB17 = 0.2642 parC17 = 0.46 parA29 = 3.1827 parB29 = 0.3431 parC29 = 0.3536 H0_17 = 10 * parA17 * pow(1 - math.exp(float(-1 * parB17 * new_age / 10)), 1 / parC17) # Dominant height at plot age if site index was 17 H0_29 = 10 * parA29 * pow(1 - math.exp(float(-1 * parB29 * new_age / 10)), 1 / parC29) # Dominant height at plot age if site index was 29 Dom_Height = H0_17 + (H0_29 - H0_17) * ( old_plot.si / 10 - 1.7 ) / 1.2 # Dominant height at plot age for actual site index new_plot.add_value('DOMINANT_H', Dom_Height) # store Dominant height in database # Basal Area parA0 = 5.103222 parB0 = 1.42706 parB1 = 0.388317 parB2 = -30.691629 parB3 = 1.034549 Basal_area = pow(old_plot.basal_area, old_plot.age/new_age) * math.exp(parA0*(1 - old_plot.age/new_age)) # basal area calculus new_plot.add_value('BASAL_AREA', Basal_area) # store basal area in database # Mortality parA0 = -2.34935 parA1 = 0.000000099 parA2 = 4.87390 TPH = pow( pow( old_plot.density, parA0) + parA1 * ( pow( new_age / 100, parA2) - pow( old_plot.age / 100, parA2 ) ), 1 / parA0 ) # density calculus; new value of trees per hectare new_plot.add_value('DENSITY', TPH) # store trees per hectare in database # VOLUME # Volume_W_Bark_new = math.exp(parB0 + parB1*old_plot.si/10 + parB2/old_plot.age + parB3*math.log(old_plot.basal_area)) # calculate new volume # Volume_W_Bark = math.exp(parB0 + parB1*old_plot.si/10 + parB2/new_age + parB3*(old_plot.age/new_age)*math.log(old_plot.basal_area) + parB3*parA0*(1 - old_plot.age/new_age)) # calculate new volume # new_plot.add_value('VOL', Volume_W_Bark) # store total stand volume with bark in database # as temporal solution, I used the vol equation changing the values to the new situation, because INIT and CUTS are using the same equation Volume_W_Bark_mix = math.exp(parB0 + parB1*old_plot.si/10 + parB2/new_age + parB3*math.log(new_plot.basal_area)) # calculate new volume new_plot.add_value('VOL', Volume_W_Bark_mix) # Mean Height parA0 = -1.155649 parA1 = 0.976772 H_mean = parA0 + parA1 * new_plot.dominant_h # calculus of mean height new_plot.add_value('MEAN_H', H_mean) # store mean height in database # QUADRATIC Mean Diameter: MTBA = new_plot.basal_area * 10000 / new_plot.density # Mean Tree Basal Area QMD = 2 * math.sqrt( MTBA / math.pi ) # Quadratic mean diameter new_plot.add_value('QM_DBH', QMD) # store quadratic mean diameter # Reineke Index Reineke = new_plot.density * pow(25 / new_plot.qm_dbh, -1.75) # Reineke density index new_plot.add_value('REINEKE', Reineke) # store Reineke index in database # Hart index Hart = 10000 / (new_plot.dominant_h * math.sqrt(new_plot.density)) # Hart index new_plot.add_value('HART', Hart) # Store Hart index in database except Exception: self.catch_model_exception()
def apply_cut_down_model( self, old_plot: Plot, new_plot: Plot, #cut_down, cut_criteria, volume, time, min_age, max_age): """ Function that includes the equations needed in the cuts. Harvest equations: Doc.: del Río M, Montero G (2011). Modelo de simulación de claras en masas de Pinus sylvestris L. Monografias INIA: Forestal n. 3 Ref.: del Río and Montero, 2011 """ # trimType values: ( ByTallest, BySmallest, Systematic ) --> Thinning types # cutDownType values: ( PercentOfTrees, Volume, Area ) --> Variable used to evaluate the thinning # volume ---> value: (% of "Variable" reduced after the thinning) print('#----------------------------------------------------------------------------#') print(' Pinus sylvestris "SILVES" model (Spain) is running ') print('#----------------------------------------------------------------------------#') if time != 0: print('BE CAREFUL! When you plan a HARVEST the time must be 0, and you wrote a', time, 'years for the harvest period!') print('Please, change your time value to 0 and run your scenario again.') try: value = volume # new_plot.add_value('VAR_9', value); # That line is not needed; at the start, old_plot and new_plot values are the same # new_plot.add_value('AGE', old_plot.age) # store new age in database, it is supposed to be the same # new_plot.add_value('SI', old_plot.si) # Dominant height at plot age for actual site index # DOMINANT Height --> nothing changes with time = 0 # parA17 = 1.9962 # parB17 = 0.2642 # parC17 = 0.46 # parA29 = 3.1827 # parB29 = 0.3431 # parC29 = 0.3536 # H0_17 = 10 * parA17 * pow( 1 - math.exp( -1 * parB17 * old_plot.age / 10 ), 1 / parC17 ) # H0_29 = 10 * parA29 * pow( 1 - math.exp( -1 * parB29 * old_plot.age / 10 ), 1 / parC29 ) # Dom_Height = H0_17 + ( H0_29 - H0_17 ) * ( old_plot.si / 10 - 1.7 ) / 1.2 # Dominant height at plot age for actual site index # new_plot.add_value('DOMINANT_H', Dom_Height) # store Dominant height in database # Parameter for Volume and Basal Area equations # parA0 = 5.103222 parB0 = 1.42706 parB1 = 0.388317 parB2 = -30.691629 parB3 = 1.034549 # Thinning parameters if cut_criteria == CUTTYPES_DICT['PERCENTOFTREES']: tpuN = value/100 # ratio of thinning trees per hectare and total before thinning TPH = (1 - tpuN)*old_plot.density # trees per hectare after thinning parC0 = 0.531019 parC1 = 0.989792 parC2 = 0.517850 QMD = parC0 + parC1*old_plot.qm_dbh + parC2*old_plot.qm_dbh*pow(tpuN, 2) # equation to calculate quadratic mean diameter MTBA = math.pi*pow(QMD/2, 2) # average mean basal area SBA = MTBA*TPH/10000 # trees per hectare Volume = math.exp(parB0 + parB1*old_plot.si/10 + parB2/old_plot.age + parB3*math.log(SBA)) # equation to calculate volume elif cut_criteria == CUTTYPES_DICT['AREA']: tpuBA = value/100 # ratio of thinning basal area and total before thinning SBA = (1 - tpuBA)*old_plot.basal_area # basal area after thinning parC0 = 0.144915 parC1 = 0.969819 parC2 = 0.678010 QMD = pow(parC0 + parC1*pow(old_plot.qm_dbh, 0.5) + parC2*tpuBA, 2) # equation to calculate quadratic mean diameter MTBA = math.pi*pow(QMD/2, 2) # average mean basal area TPH = SBA * 10000 / MTBA # trees per hectare Volume = math.exp(parB0 + parB1*old_plot.si/10 + parB2/old_plot.age + parB3*math.log(SBA)) # equation to calculate volume elif cut_criteria == CUTTYPES_DICT['VOLUME']: tpuVOL = value/100 # ratio of thinning volume and total before thinning Volume = ( 1 - tpuVOL )*old_plot.vol # volume after thinning ### Provided we do not have equations for thinning by volume, stimations are based on stimations by basal area parC0 = 0.144915 parC1 = 0.969819 parC2 = 0.678010 SBA = math.exp( -1*parB0 - parB1*old_plot.si/10 - parB2/old_plot.age + math.log(Volume)/parB3) # equation to calculate stand basal area tpuBA = 1 - SBA/old_plot.basal_area # ratio of thinning basal area and total before thinning QMD = pow(parC0 + parC1*pow(old_plot.qm_dbh, 0.5) + parC2*tpuBA, 2) # equation to calculate quadratic mean diameter MTBA = math.pi*pow(QMD/2, 2) # average mean basal area TPH = SBA*10000/MTBA # trees per hectare new_plot.add_value('DENSITY', TPH) # store trees per hectare in database new_plot.add_value('QM_DBH', QMD) # store quadratic mean diameter new_plot.add_value('BASAL_AREA', SBA) # store basal area in database new_plot.add_value('VOL', Volume) # store total stand volume with bark in database except Exception: self.catch_model_exception()
def initialize(self, plot: Plot): """ Function that update the gaps on the information with the inventory data Height/Diameter equation: Doc.: Diéguez-Aranda U, Rojo A, Castedo-Dorado F, et al (2009). Herramientas selvícolas para la gestión forestal sostenible en Galicia. Forestry, 82, 1-16 Ref.: Diéguez-Aranda et al, 2009 SI equation: Doc.: Barrio-Anta M, Diéguez-Aranda U (2005). Site quality of pedunculate oak (Quercus robur L.) stands in Galicia (northwest Spain). European Journal of Forest Research, 124(1), 19-28 Ref.: Barrio-Anta and Diéguez-Aranda, 2005 """ print( '#----------------------------------------------------------------------------#' ) print( ' Quercus robur model (Galicia) is running ' ) print( '#----------------------------------------------------------------------------#' ) try: # errors inside that construction will be announced #-----------------------------------SI-----------------------------------------# plot.add_value( 'SI', 129.0321 * ((plot.dominant_h / 129.0321)**((plot.age / 60)**0.301881)) ) # Site Index (m) calculation for 60 years as reference age plot_trees: list[Tree] = plot.short_trees_on_list( 'dbh', DESC) # stablish an order to calculate tree variables bal: float = 0 for tree in plot_trees: # for each tree... #-----------------------------------BASAL AREA-----------------------------------------# tree.add_value('bal', bal) # the first tree must receive 0 value (m2) tree.add_value( 'basal_area', math.pi * (tree.dbh / 2)** 2) # normal (at 1.30m) section (cm2) calculation tree.add_value('ba_ha', tree.basal_area * tree.expan / 10000) # basimetric area per ha (m2/ha) bal += tree.basal_area * tree.expan / 10000 # then, that value is acumulated tree.add_value( 'hd_ratio', tree.height * 100 / tree.dbh) # height/diameter ratio (%) calculation tree.add_value( 'normal_circumference', math.pi * tree.dbh ) # normal (at 1.30m) circumference (cm) calculation #-----------------------------------HEIGHT-----------------------------------------# if tree.height == 0: # if the tree hasn't height (m) value, it is calculated tree.add_value( 'height', (1.3**(1.067) + (plot.dominant_h**(1.067) - 1.3**(1.067)) * ((1 - math.exp(-0.06160 * tree.dbh)) / (1 - math.exp(-0.06160 * plot.dominant_dbh)))** (1 / 1.067))) #-----------------------------------FUNCTIONS-----------------------------------------# # self.crown(tree, plot, 'process_plot') # activate crown variables calculation self.vol(tree, plot) # activate volume variables calculation self.merch_classes( tree) # activate wood uses variables calculation self.biomass(tree) # activate biomass variables calculation self.merch_classes_plot( plot) # activate wood uses (plot) variables calculation self.biomass_plot( plot) # activate biomass (plot) variables calculation except Exception: self.catch_model_exception()
def initialize(self, plot: Plot): """ Function that update the gaps on the information with the inventory data SI equations: a) Doc.: Martín-Benito D, Gea-Izquierdo G, del Río M, Canellas I (2008). Long-term trends in dominant-height growth of black pine using dynamic models. Forest Ecology and Management, 256(5), 1230-1238 Ref.: Martín-Benito et al, 2008 b) Doc.: Palahí M, Grau JM (2003). Preliminary site index model and individual-tree growth and mortality models for black pine (Pinus nigra Arn.) in Catalonia (Spain). Forest Systems, 12(1), 137-148 Ref.: Palahí and Grau, 2003 Height-Diameter equation: a) Doc.: Palahí M, Grau JM (2003). Preliminary site index model and individual-tree growth and mortality models for black pine (Pinus nigra Arn.) in Catalonia (Spain). Forest Systems, 12(1), 137-148 Ref.: Palahí and Grau, 2003 """ print( '#----------------------------------------------------------------------------#' ) print( ' Pinus nigra model (Cataluña) is running ' ) print( '#----------------------------------------------------------------------------#' ) try: # errors inside that construction will be announced #-----------------------------------SI-----------------------------------------# # Empiezo calculando SI, necesario para el cálculo de la altura # a) en el cálculo de Xo, la raíz es negativa y peta el simulador --> en el paper explica que el modelo es viable a partir de 50 años # Xo = 0.5*(math.log(plot.dominant_h) + math.sqrt(- (math.log(plot.dominant_h))**2 + 4*43.73549*(plot.dominant_h**(-0.38048)))) # SI = math.exp(Xo)*math.exp((-43.73549*(plot.age**(-0.38048))) / Xo) # plot.add_value('SI', SI) # b) Utiliza diferencias de edades, y hay que introducir en h2 la edad a la que se quiere calcular el SI --> R2 = 0.98 # t2 y h2 son del momento al que se avanza; t1 y h1 los momentos presentes # es la del mismo estudio de donde se usan los crecimientos --> SE QUEDA ESTA DE MOMENTO t1 = plot.age t2 = 60 # --> t2 es la edad a la que se calcula el SI h1 = plot.dominant_h h2 = (t2**2) / (16.884 + t2 * (t1 / h1 - 0.033 * t1 - 16.884 / t1 + 0.033 * t2)) plot.add_value('SI', h2) # Site Index (m) calculation plot_trees: list[Tree] = plot.short_trees_on_list( 'dbh', DESC) # stablish an order to calculate tree variables bal: float = 0 for tree in plot_trees: # for each tree... #-----------------------------------BASAL AREA-----------------------------------------# tree.add_value('bal', bal) # the first tree must receive 0 value (m2) tree.add_value( 'basal_area', math.pi * (tree.dbh / 2)** 2) # normal (at 1.30m) section (cm2) calculation tree.add_value('ba_ha', tree.basal_area * tree.expan / 10000) # basimetric area per ha (m2/ha) bal += tree.basal_area * tree.expan / 10000 # then, that value is acumulated tree.add_value( 'hd_ratio', tree.height * 100 / tree.dbh) # height/diameter ratio (%) calculation tree.add_value( 'normal_circumference', math.pi * tree.dbh ) # normal (at 1.30m) circumference (cm) calculation #-----------------------------------HEIGHT-----------------------------------------# if tree.height == 0: # if the tree hasn't height (m) value, it is calculated beta6 = 0.4666 beta7 = -0.4356 beta8 = 0.0092 tree.add_value( 'height', 1.3 + (plot.dominant_h - 1.3) * ((tree.dbh / plot.dominant_dbh)** (beta6 + beta7 * (tree.dbh / plot.dominant_dbh) + beta8 * plot.si))) #-----------------------------------FUNCTIONS-----------------------------------------# # self.crown(tree, plot, 'initialize') # activate crown variables calculation self.vol(tree, plot) # activate volume variables calculation self.merch_classes( tree) # activate wood uses variables calculation self.biomass(tree) # activate biomass variables calculation self.merch_classes_plot( plot) # activate wood uses (plot) variables calculation self.biomass_plot( plot) # activate biomass (plot) variables calculation except Exception: self.catch_model_exception()
def initialize(self, plot: Plot): """ Function that update the gaps on the information with the inventory data Height/Diameter equation: Doc.: Lizarralde I (2008). Dinámica de rodales y competencia en las masas de pino silvestre (Pinus sylvestris L.) y pino negral (Pinus pinaster Ait.) de los Sistemas Central e Ibérico Meridional. Tesis Doctoral. 230 pp Ref.: Lizarralde 2008 SI equation: Doc.: Rojo A, Montero, G (1996). El pino silvestre en la Sierra de Guadarrama MAPA. Ref.: Rojo and Montero, 1996 Doc.: Bravo F, Montero G (2001). Site index estimation in Scots pine (Pinus sylvestris L.) using soil attributes. Forestry 74, 396‐406 Ref.: Bravo and Montero, 2001 """ print( '#----------------------------------------------------------------------------#' ) print( ' Pinus sylvestris model (Sistema Ibérico Meridional) is running ' ) print( '#----------------------------------------------------------------------------#' ) try: # errors inside that construction will be announced #-----------------------------------SI-----------------------------------------# # site index is defined as top height at a base age of 100 years plot.add_value('SI', (plot.dominant_h * 0.8534446) / (pow( (1 - math.exp(float(-0.270 * plot.age / 10))), 2.2779))) # Site Index (m) calculation plot_trees: list[Tree] = plot.short_trees_on_list( 'dbh', DESC) # stablish an order to calculate tree variables bal: float = 0 for tree in plot_trees: # for each tree... #-----------------------------------BASAL AREA-----------------------------------------# tree.add_value('bal', bal) # the first tree must receive 0 value (m2) tree.add_value( 'basal_area', math.pi * (tree.dbh / 2)** 2) # normal (at 1.30m) section (cm2) calculation tree.add_value('ba_ha', tree.basal_area * tree.expan / 10000) # basimetric area per ha (m2/ha) bal += tree.basal_area * tree.expan / 10000 # then, that value is acumulated tree.add_value( 'hd_ratio', tree.height * 100 / tree.dbh) # height/diameter ratio (%) calculation tree.add_value( 'normal_circumference', math.pi * tree.dbh ) # normal (at 1.30m) circumference (cm) calculation #-----------------------------------HEIGHT-----------------------------------------# if tree.height == 0: # if the tree hasn't height (m) value, it is calculated tree.add_value( 'height', (13 + (27.0392 + 1.4853 * plot.dominant_h * 10 - 0.1437 * plot.qm_dbh * 10) * math.exp(-8.0048 / math.sqrt(tree.dbh * 10))) / 10) #-----------------------------------FUNCTIONS-----------------------------------------# self.crown( tree, plot, 'initialize') # activate crown variables calculation self.vol(tree, plot) # activate volume variables calculation self.merch_classes( tree) # activate wood uses variables calculation self.biomass(tree) # activate biomass variables calculation self.merch_classes_plot( plot) # activate wood uses (plot) variables calculation self.biomass_plot( plot) # activate biomass (plot) variables calculation except Exception: self.catch_model_exception()
def apply_tree_model(self, inventory: Inventory, model: TreeModel, operation: Operation): result_inventory = Inventory() min = operation.get_variable('min_age') if operation.has('min_age') else 0 max = operation.get_variable('max_age') if operation.has('max_age') else 1000 for plot in inventory.plots: cut_pies_mayores = list() dead_pies_mayores = list() result_pies_mayores = list() add_pies_mayores = list() # aquí recojo árboles de masa añadida, con status = I if min <= plot.age <= max: new_plot = Plot() new_plot.clone(plot) search_criteria = SearchCriteria() search_criteria.add_criteria('status', None, EQUAL) source_trees = Tree.get_sord_and_order_tree_list(plot.trees, search_criteria=search_criteria) for tree in source_trees: survives_ratio: float = 0.0 try: survives_ratio = model.survives(operation.get_variable('time'), new_plot, tree) except Exception as e: Tools.print_log_line(str(e), logging.ERROR) if survives_ratio > 0: new_tree = Tree() new_tree.clone(tree) new_tree.add_value('expan', survives_ratio * new_tree.expan) new_tree_dead = Tree() new_tree_dead.clone(tree) new_tree_dead.add_value('status', 'M') new_tree_dead.add_value('expan', (1 - survives_ratio) * new_tree_dead.expan) try: model.grow(operation.get_variable('time'), new_plot, tree, new_tree) except Exception as e: Tools.print_log_line(str(e), logging.ERROR) #ActualizaDatosPieMayor(new_tree); #source_trees.update_tree(tree) result_pies_mayores.append(new_tree) dead_pies_mayores.append(new_tree_dead) # Aquí comienza el código correspondiente a la masa añadida (ingrowth) en las ejecuciones # Su funcionamiento, en principio, será similar a la función de supervivencia # Se añadirá el EXPAN que se considere a cada árbol directamente en las ejecuciones, y mostraremos en el output un "clon" de cada árbol con el valor del # EXPAN añadido, y con el status = I (Ingrowth) para poder identificarlo (como con árboles muertos) new_area_basimetrica: float = 0 distribution: float = 0 # creo esta variable, que estaba sin crear try: new_area_basimetrica = model.add_tree(operation.get_variable('time'), new_plot); except Exception as e: Tools.print_log_line(str(e), logging.ERROR) if new_area_basimetrica > 0: # si no se añade masa, se omite este paso try: distribution = model.new_tree_distribution(operation.get_variable('time'), new_plot, new_area_basimetrica) except Exception as e: Tools.print_log_line(str(e), logging.ERROR) order_criteria = OrderCriteria() order_criteria.add_criteria('dbh') # cambio add_variable por add_criteria tree_to_add: Tree = Tree.get_sord_and_order_tree_list(result_pies_mayores, order_criteria=order_criteria) sum_g = 0 # esta variable recoge el sumatorio de secciones normales de la parcela, para usar el valor en los cálculos posteriores for tree in tree_to_add: sum_g += tree.basal_area # * tree.expan --> no se multiplica por tree.expan if distribution == None: # si no existe una función de distribución # n_trees = len(tree_to_add) # calculamos el nº de árboles de la parcela --> ahora ya no hace falta, pero lo dejo de momento for tree in tree_to_add: # para los árboles que quiero añadir (todos los de la parcela serán modificados, en principio) # voy a añadir una parte proporcional a cada uno; duplico la lista de árboles para que en el output se añada la masa y además se pueda # mostrar que expan se ha añadido a cada árbol, tal cual se hace con los árboles muertos new_d_tree = Tree() # estos árboles serán los que se muestran sin status y pasan a la siguiente ejecución new_d_tree.clone(tree) new_d_tree.add_value('expan', (new_area_basimetrica*10000) / sum_g + new_d_tree.expan) ### hay que revisar este cálculo new_tree_add = Tree() # estos árboles serán los que se muestran con status = I new_tree_add.clone(tree) new_tree_add.add_value('status', 'I') # habría que conseguir que estos árboles aparecieran pintados en el output new_tree_add.add_value('expan', (new_area_basimetrica*10000) / sum_g) ### hay que revisar este cálculo result_pies_mayores.append(new_d_tree) # añado los árboles con EXPAN modificado a la lista add_pies_mayores.append(new_tree_add) # añado los árboles con status = I a una nueva lista # para los modelos en los que sí hay unas condiciones establecidas en new_tree_distribution, entonces se aplica lo siguiente else: # si existe una función de distribución definida por el usuario # var = 0 # acumulador del nº de árboles de cada CD --> ya no es necesario, lo silencio de momento sum_g = 0 # acumulador del sumatorio de secciones normales para cada CD count = 0 # contador para entrar en la posición de la lista que deseamos for tree in tree_to_add: # con este bucle añado el nº de árboles que hay para cada CD puesta por el usuario for k in distribution: # para cada CD puesta por el usuario if tree.dbh >= distribution[count][0] and tree.dbh < distribution[count][1]: # si se cumplen los límites de diámetro # var += 1 # añadimos 1 al nº de árboles que cumplen la condición sum_g += tree.basal_area # * tree.expan --> no se multiplica por tree.expan break # pasamos al siguiente árbol else: # si se deja de cumplir la condición de diámetro (los árboles están ordenados por dbh, de menor a mayor) # distribution[count].append(var) # añadimos el nº de árboles a la lista distribution[count].append(sum_g) # añadimos la suma de secciones normales por CD a la lista count += 1 # avanzamos una posición en la lista # var = 0 # comenzamos la cuenta desde 0 sum_g = 0 # comenzamos la cuenta desde 0 # distribution[count].append(var) # esto es necesario para añadir el valor a la última CD distribution[count].append(sum_g) # esto es necesario para añadir el valor a la última CD for tree in tree_to_add: # aquí se repartirá el valor del área basimétrica en las distintas clases diamétricas (propuestas en el modelo), de manera equitativa para cada árbol for k in distribution: # para cada CD if tree.dbh >= k[0] and tree.dbh < k[1]: # si se cumplen los límites de diámetro (ordenados de menor a mayor) new_d_tree = Tree() # estos árboles serán los que se muestran sin status y pasan a la siguiente ejecución new_d_tree.clone(tree) new_d_tree.add_value('expan', (k[2]*10000) / k[3] + new_d_tree.expan) # añadimos la parte proporcional del expan a cada árbol # OJO! Si hubiera que meter de nuevo el nº de pies en cada CD, entonces las posiciones de las listas variarían! new_tree_add = Tree() # estos árboles serán los que se muestran con status = I new_tree_add.clone(tree) new_tree_add.add_value('status', 'I') # habría que conseguir que estos árboles aparecieran pintados en el output new_tree_add.add_value('expan', (k[2]*10000) / k[3]) # añadimos la parte proporcional del expan a cada árbol result_pies_mayores.append(new_d_tree) # añado los árboles con EXPAN modificado a la lista add_pies_mayores.append(new_tree_add) # añado los árboles con status = I a una nueva lista break # salto al árbol siguiente result_pies_mayores.extend(cut_pies_mayores) # se añaden los pies cortados result_pies_mayores.extend(dead_pies_mayores) # se añaden los pies muertos result_pies_mayores.extend(add_pies_mayores) # añado árboles con status = I new_plot.add_trees(result_pies_mayores) # new_plot.recalculate() --> Spiros try: model.process_plot(operation.get_variable('time'), new_plot, result_pies_mayores) except Exception as e: Tools.print_log_line(str(e), logging.ERROR) new_plot.recalculate() result_inventory.add_plot(new_plot) else: Tools.print_log_line('Plot ' + str(plot.id) + ' was not added', logging.INFO) return result_inventory
def initialize(self, plot: Plot): """ Function that update the gaps on the information with the inventory data Reineke Index equation (value): Doc.: del Río M, Montero G (2011). Modelo de simulación de claras en masas de Pinus sylvestris L. Monografias INIA: Forestal n. 3 Ref.: del Río and Montero, 2011 Site Index equation: Doc.: del Río M, Montero G (2011). Modelo de simulación de claras en masas de Pinus sylvestris L. Monografias INIA: Forestal n. 3 Ref.: del Río and Montero, 2011 Volume equation: Doc.: del Río M, Montero G (2011). Modelo de simulación de claras en masas de Pinus sylvestris L. Monografias INIA: Forestal n. 3 Ref.: del Río and Montero, 2011 """ print('#----------------------------------------------------------------------------#') print(' Pinus sylvestris "SILVES" model (Spain) is running ') print('#----------------------------------------------------------------------------#') try: #-----------------------------------FIRST: calculate PLOT data by using TREE data-----------------------------------------# tree_expansion: float = 0.0 expansion_trees: list[Tree] = plot.short_trees_on_list('dbh', DESC) selection_trees = list() for tree in expansion_trees: if tree_expansion < 100: tree_expansion += tree.expan selection_trees.append(tree) else: break sum_expan: float = 0 sum_prod_basal_area_expan: float = 0 ## sum_edad: float = 0 sum_dbh_expan: float = 0 sum_dbh_2_expan: float = 0 max_dbh: float = 0 min_dbh: float = 9999 max_h: float = 0 min_h: float = 9999 max_ba: float = 0 min_ba: float = 9999 sum_height_expan: float = 0 sum_lcw_expan: float = 0 prod_lcw_lcw_expan: float = 0 # sum_canopy_cover: float = 0 # sum_vol_expan: float = 0 # sum_bole_vol_expan: float = 0 for tree in expansion_trees: sum_expan += tree.expan sum_prod_basal_area_expan += tree.basal_area * tree.expan ## sum_edad += tree.tree_age * tree.expan sum_dbh_expan += tree.dbh * tree.expan sum_dbh_2_expan += math.pow(tree.dbh, 2) * tree.expan max_dbh = tree.dbh if tree.dbh > max_dbh else max_dbh min_dbh = tree.dbh if tree.dbh < min_dbh else min_dbh max_h = tree.height if tree.height > max_h else max_h min_h = tree.height if tree.height < min_h else min_h max_ba = tree.basal_area if tree.basal_area > max_ba else max_ba min_ba = tree.basal_area if tree.basal_area < min_ba else min_ba sum_height_expan += tree.height * tree.expan # if tree.lcw != '': # sum_lcw_expan += tree.lcw * tree.expan # prod_lcw_lcw_expan += math.pow(tree.lcw, 2) * tree.expan # sum_canopy_cover += math.pi * (math.pow(tree.lcw, 2) / 4) * tree.expan # sum_vol_expan += tree.vol * tree.expan # sum_bole_vol_expan += tree.bole_vol * tree.expan plot.add_value('BASAL_AREA', sum_prod_basal_area_expan / 10000) plot.add_value('DOMINANT_H', plot.get_dominant_height(selection_trees)) plot.add_value('DENSITY', sum_expan) if sum_expan != 0: plot.add_value('MEAN_DBH', sum_dbh_expan / sum_expan) plot.add_value('QM_DBH', math.sqrt(sum_dbh_2_expan / sum_expan)) plot.add_value('DOMINANT_DBH', plot.get_dominant_diameter(selection_trees)) plot.add_value('DBH_MAX', max_dbh) plot.add_value('DBH_MIN', min_dbh) plot.add_value('BA_MAX', max_ba) plot.add_value('BA_MIN', min_ba) if sum_expan != 0: plot.add_value('MEAN_H', sum_height_expan / sum_expan) # plot.add_value('CROWN_MEAN_D', sum_lcw_expan / sum_expan) plot.add_value('MEAN_BA', sum_prod_basal_area_expan / sum_expan) plot.add_value('H_MAX', max_h) plot.add_value('H_MIN', min_h) plot.add_value('SEC_DOMINANTE', plot.get_dominant_section(selection_trees)) # if sum_expan != 0: # plot.add_value('CROWN_DOM_D', math.sqrt(prod_lcw_lcw_expan / sum_expan)) if plot.qm_dbh != 0: # plot.add_value('REINEKE', sum_expan * math.pow(25/plot.qm_dbh, -1.605)) plot.add_value('REINEKE', sum_expan * math.pow(25/plot.qm_dbh, -1.75)) else: plot.add_value('REINEKE', 0) if sum_expan != 0: if Plot.dominant_h != 0: plot.add_value('HART', 10000 / (plot.dominant_h * math.sqrt(sum_expan))) # plot.add_value('CANOPY_COVER', sum_canopy_cover / 10000) # plot.add_value('VOL', sum_vol_expan / 1000) # plot.add_value('BOLE_VOL', sum_bole_vol_expan / 1000) # if plot.vol > plot.bole_vol: # sometimes, only bole_vol is calculated # plot.bark_vol = plot.vol - plot.bole_vol #-----------------------------------SECOND: calculate PLOT data by using PLOT data-----------------------------------------# # Site Index parA = 0.8534446 parB = -0.27 parC = 0.439 SiteIndex = parA * plot.dominant_h / pow( 1 - math.exp( parB * plot.age / 10 ) , 1 / parC ) # equation for Site Index plot.add_value('SI', SiteIndex) # store Site Index in database IC = plot.si / 10 plot.add_value('QI', IC) # Initial Volume parB0 = 1.42706 parB1 = 0.388317 parB2 = -30.691629 parB3 = 1.034549 Volume_W_Bark = math.exp(parB0 + parB1*plot.si/10 + parB2/plot.age + parB3*math.log(plot.basal_area)) # equation for stand volumen plot.add_value('VOL', Volume_W_Bark) # store initial stand volume in database except Exception: self.catch_model_exception()
def initialize(self, plot: Plot): """ Function that update the gaps on the information with the inventory data Height/Diameter equation: Doc.: Adame P, del Río M, Canellas I (2008). A mixed nonlinear height–diameter model for pyrenean oak (Quercus pyrenaica Willd.). Forest ecology and management, 256(1-2), 88-98 Ref.: Adame et al, 2008 SI equation: Doc.: Adame P, Cañellas I, Roig S, del Río M (2006). Modelling dominant height growth and site index curves for rebollo oak (Quercus pyrenaica Willd.). Annals of Forest Science, 63(8), 929-940 Ref.: Adame et al, 2006 """ print( '#----------------------------------------------------------------------------#' ) print( ' Quercus pyrenaica model (Castilla y León) is running ' ) print( '#----------------------------------------------------------------------------#' ) try: # errors inside that construction will be announced #-----------------------------------SI-----------------------------------------# parA1 = 15.172 parA2 = -4.2126 parA3 = 0.1439 parA4 = 0.6711 H0 = plot.dominant_h t2 = 1 - math.exp(-parA3 * pow(60, parA4)) t1 = 1 - math.exp(-parA3 * pow(plot.age, parA4)) X = (math.log(H0) - parA1 * math.log(t1)) / (1 + parA2 * math.log(t1)) plot.add_value( 'SI', math.exp(X) * pow(t2, parA1 + parA2 * X) ) # Site Index (m) calculation to 60 years as reference plot_trees: list[Tree] = plot.short_trees_on_list( 'dbh', DESC) # stablish an order to calculate tree variables bal: float = 0 for tree in plot_trees: # for each tree... #-----------------------------------BASAL AREA-----------------------------------------# tree.add_value('bal', bal) # the first tree must receive 0 value (m2) tree.add_value( 'basal_area', math.pi * (tree.dbh / 2)** 2) # normal (at 1.30m) section (cm2) calculation tree.add_value('ba_ha', tree.basal_area * tree.expan / 10000) # basimetric area per ha (m2/ha) bal += tree.basal_area * tree.expan / 10000 # then, that value is acumulated tree.add_value( 'hd_ratio', tree.height * 100 / tree.dbh) # height/diameter ratio (%) calculation tree.add_value( 'normal_circumference', math.pi * tree.dbh ) # normal (at 1.30m) circumference (cm) calculation #-----------------------------------HEIGHT-----------------------------------------# if tree.height == 0: # if the tree hasn't height (m) value, it is calculated tree.add_value( 'height', 1.3 + (3.099 - 0.00203 * plot.basal_area + 1.02491 * plot.dominant_h * math.exp(-8.5052 / tree.dbh))) #-----------------------------------FUNCTIONS-----------------------------------------# # self.crown(tree, plot, 'initialize') # activate crown variables calculation self.vol(tree, plot) # activate volume variables calculation self.merch_classes( tree) # activate wood uses variables calculation self.biomass(tree) # activate biomass variables calculation self.merch_classes_plot( plot) # activate wood uses (plot) variables calculation self.biomass_plot( plot) # activate biomass (plot) variables calculation except Exception: self.catch_model_exception()
def initialize(self, plot: Plot): """ Function that update the gaps on the information with the inventory data Height/Diameter equation: Doc.: Calama R, Montero G (2004). Interregional nonlinear height diameter model with random coefficients for stone pine in Spain. Canadian Journal of Forest Research, 34(1), 150-163 Ref.: Calama and Montero, 2004 SI equation: a) Doc.: Calama R, Cañadas N, Montero G (2003). Inter-regional variability in site index models for even-aged stands of stone pine (Pinus pinea L.) in Spain. Annals of Forest Science, 60(3), 259-269 Ref.: Calama et al, 2003 b) Doc.: Casanueva GM, Ponce RA (2007). Patrón de crecimiento en altura dominante en masas naturales y artificiales de Pinus pinea L.: comparación a través de modelos dinámicos. Cuadernos de la SECF, (23) Ref.: Casanueva and Ponce, 2007 c) Doc.: Cañadas MN, Calama R, Güemes GCG (2005). Modelo de calidad de estación para Pinus pinea L. en las masas del sistema central (Valles del Tiétar y Alberche), mediante aplicación de la metodología propuesta por Goelz & Burk (1992). In Congresos Forestales Ref.: Cañadas et al, 2005 """ print( '#----------------------------------------------------------------------------#' ) print( ' Pinus pinea model (Sistema Central) is running ' ) print( '#----------------------------------------------------------------------------#' ) try: # errors inside that construction will be announced global P9010 # the explanation of that variable is on P9010_distribution function P9010 = 0 # define the variable that later we will use plot_trees: list[Tree] = plot.short_trees_on_list( 'dbh', DESC) # stablish an order to calculate tree variables bal: float = 0 for tree in plot_trees: # for each tree... #-----------------------------------BASAL AREA-----------------------------------------# tree.add_value('bal', bal) # the first tree must receive 0 value (m2) tree.add_value( 'basal_area', math.pi * (tree.dbh / 2)** 2) # normal (at 1.30m) section (cm2) calculation tree.add_value('ba_ha', tree.basal_area * tree.expan / 10000) # basimetric area per ha (m2/ha) bal += tree.basal_area * tree.expan / 10000 # then, that value is acumulated tree.add_value( 'hd_ratio', tree.height * 100 / tree.dbh) # height/diameter ratio (%) calculation tree.add_value( 'normal_circumference', math.pi * tree.dbh ) # normal (at 1.30m) circumference (cm) calculation if P9010 == 0: # condition needed to only calculate that variable once P9010 = self.P9010_distribution( plot, tree ) # that line is needed to activate the calculation of P9010, needed later #-----------------------------------HEIGHT-----------------------------------------# if tree.height == 0: # if the tree hasn't height (m) value, it is calculated K = 0 # 0 for Central Spain in general; 1 for Catalonia and West Andalusia tree.add_value( 'height', 1.3 + math.exp((1.7306 + 0.0882 * plot.dominant_h - 0.0062 * P9010 - 0.0936 * K) + (-25.2776 + 1.6999 * math.log(plot.density) + 4.743 * K) / (tree.dbh + 1))) #-----------------------------------FUNCTIONS-----------------------------------------# # self.crown(tree, plot, 'initialize') # activate crown variables calculation self.vol(tree, plot) # activate volume variables calculation self.merch_classes( tree) # activate wood uses variables calculation self.biomass(tree) # activate biomass variables calculation self.merch_classes_plot( plot) # activate wood uses (plot) variables calculation self.biomass_plot( plot) # activate biomass (plot) variables calculation #-----------------------------------SI - Dominant Height-----------------------------------------# # On this model, we didn't update height values on grow function, so Dominant Height was calculates by using the height values before the execution # In order to correct that value, we add the calculation methodology used on SIMANFOR project to update that value after the height values update plot.add_value( 'DOMINANT_H', -plot.dominant_h ) # Dominant Height is calculated befores process_plot, so we eliminate this value to recalculate it with tree_expansion: float = 0.0 # the new tree.height values selection_trees = list() for tree in plot_trees: # for each tree on the list (ordered by dbh), we calculate how many trees are needed to Dominant Height calculation if tree_expansion < 100: tree_expansion += tree.expan selection_trees.append(tree) else: break acumulate: float = 0 result: float = 0 for tree in selection_trees: # for each selected tree, we calculate the relative weight for each of them on the Dominant Height value if acumulate + tree.expan < 100: result += tree.height * tree.expan acumulate += tree.expan else: result += (100 - acumulate) * tree.height dom_h = result / 100 plot.add_value( 'DOMINANT_H', dom_h) # adding new Dominant Height value to the plot # a) T2 = 100 # Age when we want to obtain the Site Index (years) SI = math.exp(4.1437 + (math.log(plot.dominant_h) - 4.1437) * ((T2 / plot.age)**(-0.3935))) # b) #a = 0.005994 #m1 = 14.08433 #m2 = -12.0075 #Xo = (math.log(plot.dominant_h) - m1) / (m2 + math.log(1 - math.exp(-a * plot.age))) #t = 80 # Age when we want to obtain the Site Index (years) #SI = math.exp(m1 + m2 * Xo) * ((1 - math.exp(-a * t)) ** Xo) # c) #Hj = plot.dominant_h #tj = plot.age #ti = 80 # Age when we want to obtain the Site Index (years) #b1 = 0.252147664 #b2 = 1.225418697 #b3 = 0.498226472 #b4 = 0.785418166 #SI = 1.3 + (Hj - 1.3) * ((1 - math.exp(- b1 * ((Hj / tj) ** b2) * (tj ** b3) * ti)) / ( # 1 - math.exp(- b1 * ((Hj / tj) ** b2) * (tj ** b3) * tj)))**b4 plot.add_value('SI', SI) # Site Index (m) calculation except Exception: self.catch_model_exception()
def initialize(self, plot: Plot): """ Function that update the gaps on the information with the inventory data Height/Diameter equation: Doc.: Dorado FC, Diéguez-Aranda U, Anta MB, Rodríguez MS, von Gadow K (2006). A generalized height–diameter model including random components for radiata pine plantations in northwestern Spain. Forest Ecology and Management, 229(1-3), 202-213 Ref.: Dorado et al, 2006 SI equation: Doc.: Diéguez-Aranda U, Burkhart HE, Rodríguez-Soalleiro R (2005). Modeling dominant height growth of radiata pine (Pinus radiata D. Don) plantations in north-western Spain. Forest Ecology and Management, 215(1-3), 271-284 Ref.: Diéguez-Aranda et al, 2006 """ print( '#----------------------------------------------------------------------------#' ) print( ' Pinus radiata model (Galicia) is running ' ) print( '#----------------------------------------------------------------------------#' ) try: # errors inside that construction will be announced #-----------------------------------SI-----------------------------------------# t = 20 # desired age to SI (years) Lo = math.log(1 - math.exp(-0.06738 * plot.age)) Xo = 0.5 * (math.log(plot.dominant_h) + 1.755 * Lo + math.sqrt( (math.log(plot.dominant_h) + 1.755 * Lo)**2 - 4 * 12.44 * Lo)) SI = plot.dominant_h * ( (1 - math.exp(-0.06738 * t) / (1 - math.exp(-0.06738 * plot.age)))**(-1.755 + 12.44 / Xo)) # site index is defined as top height at a base age of 20 years plot.add_value('SI', SI) # Site Index (m) calculation plot_trees: list[Tree] = plot.short_trees_on_list( 'dbh', DESC) # stablish an order to calculate tree variables bal: float = 0 for tree in plot_trees: # for each tree... #-----------------------------------BASAL AREA-----------------------------------------# tree.add_value('bal', bal) # the first tree must receive 0 value (m2) tree.add_value( 'basal_area', math.pi * (tree.dbh / 2)** 2) # normal (at 1.30m) section (cm2) calculation tree.add_value('ba_ha', tree.basal_area * tree.expan / 10000) # basimetric area per ha (m2/ha) bal += tree.basal_area * tree.expan / 10000 # then, that value is acumulated tree.add_value( 'hd_ratio', tree.height * 100 / tree.dbh) # height/diameter ratio (%) calculation tree.add_value( 'normal_circumference', math.pi * tree.dbh ) # normal (at 1.30m) circumference (cm) calculation #-----------------------------------HEIGHT-----------------------------------------# if tree.height == 0: # if the tree hasn't height (m) value, it is calculated a = 0.0296 b = 1.633 tree.add_value( 'height', (1.3**b + (plot.dominant_h**b - 1.3**b) * (1 - math.exp(-a * tree.dbh)) / (1 - math.exp(-a * plot.dominant_diameter))**(1 / b))) #-----------------------------------FUNCTIONS-----------------------------------------# self.crown( tree, plot, 'initialize') # activate crown variables calculation self.vol(tree, plot) # activate volume variables calculation self.merch_classes( tree) # activate wood uses variables calculation self.biomass(tree) # activate biomass variables calculation self.merch_classes_plot( plot) # activate wood uses (plot) variables calculation self.biomass_plot( plot) # activate biomass (plot) variables calculation except Exception: self.catch_model_exception()
def process_plot(self, time: int, plot: Plot, trees: list): """ Function that update the trees information once the grow function was executed The equations on that function are the same that in "initialize" function """ print( '#----------------------------------------------------------------------------#' ) print( ' Pinus pinea model (Sistema Central) is running ' ) print( '#----------------------------------------------------------------------------#' ) if time != 5: print( 'BE CAREFUL! That model was developed to 5 year execution, and you are trying to make a', time, 'years execution!') print( 'Please, change your execution conditions to the recommended (5 year execution). If not, the output values will be not correct.' ) try: # errors inside that construction will be announced dbh_list.sort( reverse=True ) # we need to sort the list from higher to lower dbh, as plot_trees does it global P9010 # the explanation of that variable is on P9010_distribution function P9010 = 0 # leave the variable value as 0 to calculate it again on that execution count = 0 # counter needed to dbh_list plot_trees: list[Tree] = plot.short_trees_on_list( 'dbh', DESC) # stablish an order to calculate tree variables bal: float = 0.0 for tree in plot_trees: # for each tree... if tree.status is None: # only update tree alive data #-----------------------------------BASAL AREA-----------------------------------------# tree.add_value( 'basal_area', math.pi * (tree.dbh / 2)** 2) # normal (at 1.30m) section (cm2) calculation tree.add_value( 'bal', bal) # the first tree must receive 0 value (m2) tree.add_value('ba_ha', tree.basal_area * tree.expan / 10000) # basimetric area per ha (m2/ha) bal += tree.basal_area * tree.expan / 10000 # then, that value is acumulated if P9010 == 0: # condition needed to only calculate that variable once P9010 = self.P9010_distribution( plot, tree ) # that line is neede to activate the calculation of P9010, needed later # Hdom_new is a SI equation used to predict the Dominant Height 5 years later (execution) Hdom_new = math.exp( 4.1437 + (math.log(plot.dominant_h) - 4.1437) * pow( ((plot.age + 5) / plot.age), -0.3935) ) # that variable need to be calculated again only once K = 0 # 0 for Central Spain in general; 1 for Catalonia and West Andalusia old_height = 1.3 + math.exp( (1.7306 + 0.0882 * plot.dominant_h - 0.0062 * P9010 - 0.0936 * K) + (-25.2776 + 1.6999 * math.log(plot.density) + 4.743 * K) / (dbh_list[count][0] + 1) ) # height calculation before execution (m) new_height = 1.3 + math.exp( (1.7306 + 0.0882 * (Hdom_new) - 0.0062 * P9010 - 0.0936 * K) + (-25.2776 + 1.6999 * math.log(plot.density) + 4.743 * K) / (dbh_list[count][1] + 1) ) # height calculation after execution (m) ht = tree.height * new_height / old_height # obtaining the new height of the tree by comparing values tree.add_value('height', ht) # adding new tree height value (m) count += 1 # add 1 value to move the variable to the next tree position tree.add_value( 'hd_ratio', tree.height * 100 / tree.dbh) # height/diameter ratio (%) calculation tree.add_value( 'normal_circumference', math.pi * tree.dbh ) # normal (at 1.30m) circumference (cm) calculation #-----------------------------------FUNCTIONS-----------------------------------------# # self.crown(tree, plot, 'process_plot') # activate crown variables calculation self.vol(tree, plot) # activate volume variables calculation self.merch_classes( tree) # activate wood uses variables calculation self.biomass( tree) # activate biomass variables calculation self.merch_classes_plot( plot) # activate wood uses (plot) variables calculation self.biomass_plot( plot) # activate biomass (plot) variables calculation #-----------------------------------Dominant Height-----------------------------------------# # On this model, we didn't update height values on grow function, so Dominant Height was calculates by using the height values before the execution # In order to correct that value, we add the calculation methodology used on SIMANFOR project to update that value after the height values update plot.add_value( 'DOMINANT_H', -plot.dominant_h ) # Dominant Height is calculated befores process_plot, so we eliminate this value to recalculate it with tree_expansion: float = 0.0 # the new tree.height values selection_trees = list() for tree in plot_trees: # for each tree on the list (ordered by dbh), we calculate how many trees are needed to Dominant Height calculation if tree_expansion < 100: tree_expansion += tree.expan selection_trees.append(tree) else: break acumulate: float = 0 result: float = 0 for tree in selection_trees: # for each selected tree, we calculate the relative weight for each of them on the Dominant Height value if acumulate + tree.expan < 100: result += tree.height * tree.expan acumulate += tree.expan else: result += (100 - acumulate) * tree.height dom_h = result / 100 plot.add_value( 'DOMINANT_H', dom_h) # adding new Dominant Height value to the plot number = len(dbh_list) while number > 0: # that loop leaves the dbh_list empty to the next execution dbh_list.pop(0) number -= 1 except Exception: self.catch_model_exception()
def initialize(self, plot: Plot): """ Function that update the gaps on the information with the inventory data Height/Diameter equation: Doc.: Sánchez-González M, Cañellas I, Montero G (2007). Generalized height-diameter and crown diameter prediction models for cork oak forests in Spain. Forest Systems, 16(1), 76-88 Ref.: Sánchez-González et al, 2007 Doc.: Sánchez-González M, Calama R, Cañellas I, Montero G (2007). Management oriented growth models for multifunctional Mediterranean Forests: the case of Cork Oak (Quercus suber L.). In EFI proceedings (Vol. 56, pp. 71-84) Ref.: Sánchez-González et al, 2007 SI equation: Doc.: Sánchez-González M, Tomé M, Montero G (2005). Modelling height and diameter growth of dominant cork oak trees in Spain. Annals of Forest Science, 62(7), 633-643 Ref.: Sánchez-González et al, 2005 Doc.: Sánchez-González M, Calama R, Cañellas I, Montero G (2007). Management oriented growth models for multifunctional Mediterranean Forests: the case of Cork Oak (Quercus suber L.). In EFI proceedings (Vol. 56, pp. 71-84) Ref.: Sánchez-González et al, 2007 Dominant diameter equation: Doc.: Sánchez-González M, Tomé M, Montero G (2005). Modelling height and diameter growth of dominant cork oak trees in Spain. Annals of Forest Science, 62(7), 633-643 Ref.: Sánchez-González et al, 2005 Doc.: Sánchez-González M, Calama R, Cañellas I, Montero G (2007). Management oriented growth models for multifunctional Mediterranean Forests: the case of Cork Oak (Quercus suber L.). In EFI proceedings (Vol. 56, pp. 71-84) Ref.: Sánchez-González et al, 2007 """ print('#----------------------------------------------------------------------------#') print(' Quercus suber model (Cataluña) is running ') print('#----------------------------------------------------------------------------#') try: # errors inside that construction will be announced #-----------------------------------SI-----------------------------------------# # site index is defined as top height at a base age of 80 years t2 = 80 # age to estimate the SI and Dominant_diamter (years) SI = 20.7216 / ((1 - (1 - 20.7216/plot.dominant_h)*(plot.age/t2)) ** 1.4486) plot.add_value('SI', SI) # Site Index (m) calculation # a1 = math.log(1 - math.exp(-0.0063*plot.age)) # a2 = math.log(1 - math.exp(-0.0063*t2)) # dbh must be diameter under bark (cm) # DD = ((83.20 + 5.28*plot.si - 1.53*plot.dominant_h*100/plot.dominant_dbh)**(1 - a2/a1)) * (plot.dominant_dbh**(a2/a1)) # plot.add_value('DOMINANT_DBH', DD ) plot_trees: list[Tree] = plot.short_trees_on_list('dbh', DESC) # stablish an order to calculate tree variables bal: float = 0 for tree in plot_trees: # for each tree... #-----------------------------------DBH CALCULATION-----------------------------------------# if tree.dbh == 0: tree.add_value('dbh', tree.dbh_oc - tree.bark/10) # dbh under cork calculated if it is not at the initial inventory (cm) if tree.dbh_oc != 0 and tree.bark == 0: tree.add_value('bark', (tree.dbh_oc - tree.dbh)*10) # cork calculated using dbh outside and inside cork (mm) if tree.dbh_oc == 0: tree.add_value('dbh_oc', tree.dbh + tree.bark/10) # diameter outside bark calculation (cm) #-----------------------------------BASAL AREA-----------------------------------------# tree.add_value('bal', bal) # the first tree must receive 0 value (m2) tree.add_value('basal_area', math.pi * (tree.dbh / 2) ** 2) # normal (at 1.30m) section (cm2) calculation tree.add_value('ba_ha', tree.basal_area * tree.expan / 10000) # basimetric area per ha (m2/ha) bal += tree.basal_area * tree.expan / 10000 # then, that value is acumulated tree.add_value('hd_ratio', tree.height * 100 / tree.dbh) # height/diameter ratio (%) calculation tree.add_value('normal_circumference', math.pi * tree.dbh) # normal (at 1.30m) circumference (cm) calculation #-----------------------------------HEIGHT-----------------------------------------# if tree.height == 0: # if the tree hasn't height (m) value, it is calculated tree.add_value('height', 1.3 + (plot.dominant_h - 1.3)*((tree.dbh/plot.dominant_dbh)**0.4898)) #-----------------------------------FUNCTIONS-----------------------------------------# self.crown(tree, plot, 'initialize') # activate crown variables calculation self.vol(tree, plot) # activate volume variables calculation # self.merch_classes(tree) # activate wood uses variables calculation self.biomass(tree) # activate biomass variables calculation # self.merch_classes_plot(plot) # activate wood uses (plot) variables calculation self.biomass_plot(plot) # activate biomass (plot) variables calculation except Exception: self.catch_model_exception()
def initialize(self, plot: Plot): """ Function that update the gaps on the information with the inventory data Site Index equation: Doc.: Álvarez JG, González AD, Soalleiro R, Barrio-Anta M (2005). Ecoregional site index models for Pinus pinaster in Galicia (northwestern Spain). Annals of Forest Science, 62(2), 115-127 Ref.: Álvarez et al. (2005) Height/Diameter equation: Doc.: Diéguez-Aranda U, Rojo A, Castedo-Dorado F, et al (2009). Herramientas selvícolas para la gestión forestal sostenible en Galicia. Forestry, 82, 1-16 Ref.: Diéguez-Aranda et al, 2009 """ print( '#----------------------------------------------------------------------------#' ) print( ' Pinus pinaster atlantica model (Galicia) is running ' ) print( '#----------------------------------------------------------------------------#' ) try: # errors inside that construction will be annodbhced # site index is defined as top height at a base age of 20 years, setting this value with 't2' I = 0 # dummy variable which assumes a value of 0 for the interior ecoregion and 1 for the coastal ecoregion. t1 = plot.age t2 = 20 z = (0.1352 + 0.0276 * I) * ((plot.dominant_h / t1)**( 0.9831 + 0.0940 * I)) * (t1**(-0.2108 - 0.0929 * I)) SI = plot.dominant_h * (1 - math.exp(-z * t2)) / ( (1 - math.exp(-z * t1))**(1.4202 + 0.0801 * I)) plot.add_value('SI', SI) plot_trees: list[Tree] = plot.short_trees_on_list( 'dbh', DESC) # stablish an order to calculate tree variables bal: float = 0 for tree in plot_trees: # for each tree... #-----------------------------------BASAL AREA-----------------------------------------# tree.add_value('bal', bal) # the first tree must receive 0 value (m2) tree.add_value( 'basal_area', math.pi * (tree.dbh / 2)** 2) # normal (at 1.30m) section (cm2) calculation tree.add_value('ba_ha', tree.basal_area * tree.expan / 10000) # basimetric area per ha (m2/ha) bal += tree.basal_area * tree.expan / 10000 # then, that value is acumulated tree.add_value( 'hd_ratio', tree.height * 100 / tree.dbh) # height/diameter ratio (%) calculation tree.add_value( 'normal_circumference', math.pi * tree.dbh ) # normal (at 1.30m) circumference (cm) calculation #-----------------------------------HEIGHT-----------------------------------------# if tree.height == 0: # if the tree hasn't height (m) value, it is calculated I = 0 # dummy variable which assumes a value of 0 for the interior ecoregion and 1 for the coastal ecoregion. h = (1.3**(1.894 + 1.469 * I) + (plot.dominant_h**(1.894 + 1.469 * I) - 1.3** (1.894 + 1.469 * I)) * ((1 - math.exp(-(0.04611 - 0.04734 * I) * tree.dbh)) / (1 - math.exp(-(0.04611 - 0.04734 * I) * plot.dominant_dbh))))**(1 / 1.633) tree.add_value('height', h) #-----------------------------------FUNCTIONS-----------------------------------------# self.crown( tree, plot, 'initialize') # activate crown variables calculation self.vol(tree, plot) # activate volume variables calculation self.merch_classes( tree) # activate wood uses variables calculation self.biomass(tree) # activate biomass variables calculation self.merch_classes_plot( plot) # activate wood uses (plot) variables calculation self.biomass_plot( plot) # activate biomass (plot) variables calculation except Exception: self.catch_model_exception()
def initialize(self, plot: Plot): """ Function that update the gaps on the information with the inventory data Height/Diameter equation: Doc.: Bartelink HH (1997). Allometric relationships for biomass and leaf area of beech (Fagus sylvatica L). In Annales des sciences forestières (Vol. 54, No. 1, pp. 39-50). EDP Sciences Ref.: Bartelink, 1997 """ print( '#----------------------------------------------------------------------------#' ) print( ' Fagus sylvatica model (xx) is running ' ) print( '#----------------------------------------------------------------------------#' ) try: # errors inside that construction will be annodbhced plot_trees: list[Tree] = plot.short_trees_on_list( 'dbh', DESC) # stablish an order to calculate tree variables bal: float = 0 for tree in plot_trees: # for each tree... #-----------------------------------BASAL AREA-----------------------------------------# tree.add_value('bal', bal) # the first tree must receive 0 value (m2) tree.add_value( 'basal_area', math.pi * (tree.dbh / 2)** 2) # normal (at 1.30m) section (cm2) calculation tree.add_value('ba_ha', tree.basal_area * tree.expan / 10000) # basimetric area per ha (m2/ha) bal += tree.basal_area * tree.expan / 10000 # then, that value is acumulated tree.add_value( 'hd_ratio', tree.height * 100 / tree.dbh) # height/diameter ratio (%) calculation tree.add_value( 'normal_circumference', math.pi * tree.dbh ) # normal (at 1.30m) circumference (cm) calculation #-----------------------------------HEIGHT-----------------------------------------# if tree.height == 0: # if the tree hasn't height (m) value, it is calculated tree.add_value('height', 1.732 * (tree.dbh**0.769)) #-----------------------------------FUNCTIONS-----------------------------------------# # self.crown(tree, plot, 'initialize') # activate crown variables calculation self.vol(tree, plot) # activate volume variables calculation self.merch_classes( tree) # activate wood uses variables calculation self.biomass(tree) # activate biomass variables calculation self.merch_classes_plot( plot) # activate wood uses (plot) variables calculation self.biomass_plot( plot) # activate biomass (plot) variables calculation except Exception: self.catch_model_exception()