예제 #1
0
    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
예제 #2
0
    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)
예제 #3
0
    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)
예제 #4
0
    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
예제 #5
0
    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)
예제 #6
0
    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
예제 #7
0
    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
예제 #8
0
    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)
예제 #9
0
    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
예제 #10
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
예제 #11
0
    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()
예제 #12
0
    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()
예제 #13
0
    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()
예제 #14
0
    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()
예제 #15
0
    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()
예제 #16
0
    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()
예제 #17
0
    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()
예제 #18
0
    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()
예제 #19
0
    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()
예제 #20
0
    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
예제 #21
0
    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()
예제 #22
0
    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()
예제 #23
0
    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()
예제 #24
0
    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()
예제 #25
0
    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()
예제 #26
0
    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()
예제 #27
0
    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()
예제 #28
0
    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()