Beispiel #1
0
def evaluate(model, loader):

    model.eval()

    total_loss, metric = 0, SpanMetric()

    for words, *feats, trees, charts in loader:
        # mask out the lower left triangle
        word_mask = words.ne(args.pad_index)[:, 1:]
        mask = word_mask if len(words.shape) < 3 else word_mask.any(-1)
        mask = (mask.unsqueeze(1) & mask.unsqueeze(2)).triu_(1)

        s_feat = model(words, feats)
        loss, s_feat = model.loss(s_feat, charts, mask, require_marginals=True)
        chart_preds = model.decode(s_feat, mask)
        # since the evaluation relies on terminals,
        # the tree should be first built and then factorized
        preds = [
            Tree.build(tree, [(i, j, CHART.vocab[label])
                              for i, j, label in chart])
            for tree, chart in zip(trees, chart_preds)
        ]
        total_loss += loss.item()
        metric(
            [Tree.factorize(tree, args.delete, args.equal) for tree in preds],
            [Tree.factorize(tree, args.delete, args.equal) for tree in trees])
    total_loss /= len(loader)

    return total_loss, metric
Beispiel #2
0
    def merch_classes(self, tree: Tree):
        """
        Function used to calcule the different comercial volumes depending on the wood purposes
        That function is rdbh by initialize and process_plot Functions
        The data criteria to clasify the wood by different uses was obtained from:
            Doc.: Rodríguez F (2009). Cuantificación de productos forestales en la planificación forestal: Análisis de casos con cubiFOR. In Congresos Forestales
            Ref.: Rodríguez 2009
        """

        ht = tree.height  # total height as ht to simplify
        # class_conditions has different lists for each usage, following that: [wood_usage, hmin/ht, dmin, dmax]
        # [WOOD USE NAME , LOG RELATIVE LENGTH RESPECT TOTAL TREE HEIGHT, MINIMUM DIAMETER, MAXIMUM DIAMETER]
        class_conditions = [['saw_big', 2.5 / ht, 40, 200],
                            ['saw_small', 2.5 / ht, 25, 200],
                            ['saw_canter', 2.5 / ht, 15, 28],
                            ['chips', 1 / ht, 5, 1000000]]

        # usage and merch_list are a dictionary and a list that are returned from merch_calculation
        # to that function, we must send the following information: tree, class_conditions, and the name of our class on this model you are using
        usage, merch_list = TreeModel.merch_calculation(
            tree, class_conditions, PinusPinasterGalicia)

        counter = -1
        for k, i in usage.items():
            counter += 1
            tree.add_value(
                k, merch_list[counter])  # add merch_list values to each usage
Beispiel #3
0
    def grow(self, time: int, plot: Plot, old_tree: Tree, new_tree: Tree):
        """
        Function that run the diameter and height growing equations
        Source of diameter growing equation:
            Doc.: Calama R, Montero G (2005). Multilevel linear mixed model for tree diameter increment in stone pine (Pinus pinea): a calibrating approach. Silva Fenn, 39(1), 37-54
            Ref.: Calama and Montero, 2005
        Source for height/diameter equation: (process_plot)
            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 (Hdom_new): (process_plot)
            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
        """

        cat = 0  # cat = 1 if the analysis is for Catalonia; 0 for Spain in general
        if plot.si == 0:
            dbhg5 = 0
        else:
            dbhg5 = math.exp(2.2451 - 0.2615 * math.log(old_tree.dbh) -
                             0.0369 * plot.dominant_h -
                             0.1368 * math.log(plot.density) +
                             0.0448 * plot.si + 0.1984 *
                             (old_tree.dbh / plot.qm_dbh) - 0.5542 * cat +
                             0.0277 * cat * plot.si) - 1
        new_tree.sum_value("dbh", dbhg5)

        dbh_list.append([
            old_tree.dbh, new_tree.dbh
        ])  # that variable is needed to used dbh values on process_plot
Beispiel #4
0
    def grow(self, time: int, plot: Plot, old_tree: Tree, new_tree: Tree):
        """
        Function that run the diameter and height growing equations
        Source:
            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
        """
        if plot.si == 0:
            dbhg5: float = 0
        else:
            dbhg5: float = math.exp(
                -0.37110 + 0.2525 * math.log(old_tree.dbh * 10) +
                0.7090 * math.log((old_tree.cr + 0.2) / 1.2) +
                0.9087 * math.log(plot.si) -
                0.1545 * math.sqrt(plot.basal_area) - 0.0004 *
                (old_tree.bal * old_tree.bal / math.log(old_tree.dbh * 10)))
        new_tree.sum_value("dbh", dbhg5 / 10)

        if dbhg5 == 0:
            htg5: float = 0
        else:
            htg5: float = math.exp(3.1222 - 0.4939 * math.log(dbhg5 * 10) +
                                   1.3763 * math.log(plot.si) -
                                   0.0061 * old_tree.bal +
                                   0.1876 * math.log(old_tree.cr))
        new_tree.sum_value("height", htg5 / 100)
Beispiel #5
0
    def biomass(self, tree: Tree):
        """
        Function to calculate volume variables for each tree.
        That function is run by initialize and process_plot functions.
        Biomass equations:
            Doc.: Ruiz-Peinado R, del Rio M, Montero G (2011). New models for estimating the carbon sink capacity of Spanish softwood species. Forest Systems, 20(1), 176-188
            Ref.: Ruiz-Peinado et al, 2011
        """

        wsw = 0.0224 * (tree.dbh**1.923) * (tree.height**1.0193)
        if tree.dbh <= 22.5:
            Z = 0
        else:
            Z = 1
        wthickb = (0.247 * ((tree.dbh - 22.5)**2)) * Z
        wb2_7 = 0.0525 * (tree.dbh**2)
        wtbl = 21.927 + 0.0707 * (tree.dbh**2) - 2.827 * tree.height
        wr = 0.117 * (tree.dbh**2)
        wt = wsw + wb2_7 + wthickb + wtbl + wr

        tree.add_value('wsw', wsw)  # wsw = stem wood (Kg)
        # tree.add_value('wsb', wsb)  # wsb = stem bark (Kg)
        # tree.add_value('w_cork', w_cork)   # w_cork = fresh cork biomass (Kg)
        tree.add_value('wthickb',
                       wthickb)  # wthickb = Thick branches > 7 cm (Kg)
        # tree.add_value('wstb', wstb)  # wstb = wsw + wthickb, stem + branches >7 cm (Kg)
        tree.add_value('wb2_7', wb2_7)  # wb2_7 = branches (2-7 cm) (Kg)
        # tree.add_value('wb2_t', wb2_t)  # wb2_t = wb2_7 + wthickb; branches >2 cm (Kg)
        # tree.add_value('wthinb', wthinb)  # wthinb = Thin branches (2-0.5 cm) (Kg)
        # tree.add_value('wl', wl)  # wl = leaves (Kg)
        tree.add_value(
            'wtbl', wtbl)  # wtbl = wthinb + wl; branches <2 cm and leaves (Kg)
        # tree.add_value('wbl0_7', wbl0_7)  # wbl0_7 = wb2_7 + wthinb + wl; branches <7 cm and leaves (Kg)
        tree.add_value('wr', wr)  # wr = roots (Kg)
        tree.add_value('wt', wt)  # wt = biomasa total (Kg)
Beispiel #6
0
def predict(model, loader):
    model.eval()

    preds = {'trees': [], 'probs': []}
    for words, *feats, trees, charts in loader:
        word_mask = words.ne(args.pad_index)[:, 1:]
        mask = word_mask if len(words.shape) < 3 else word_mask.any(-1)
        mask = (mask.unsqueeze(1) & mask.unsqueeze(2)).triu_(1)

        s_feat = model(words, feats)
        s_feat = model.crf(s_feat, mask, require_marginals=True)
        chart_preds = model.decode(s_feat, mask)
        preds['trees'].extend([
            Tree.build(tree, [(i, j, CHART.vocab[label])
                              for i, j, label in chart])
            for tree, chart in zip(trees, chart_preds)
        ])

        if args.draw_pred:  ### draw trees here
            filter_delete = lambda x: [it for it in x if it not in args.delete]
            trees_fact = [
                Tree.factorize(tree, args.delete, args.equal)
                for tree in preds['trees']
            ]
            leaves = [filter_delete(tree.leaves()) for tree in trees]
            t = convert_to_viz_tree(tree=trees_fact[0], sen=leaves[0])

            draw_tree(t, res_path="./prediction")

    return preds
Beispiel #7
0
    def grow(self, time: int, plot: Plot, old_tree: Tree, new_tree: Tree):
        """
        Function that run the diameter and height growing equations
        Source:
            Doc.: Crecente-Campo F (2008). Modelo de crecimiento de árbol individual para Pinus radiata D. Don en Galicia. Univ Santiago de Compostela
            Ref.: Crecente-Campo, 2008
        """

        BALMOD = (1 - (1 - (old_tree.bal / plot.basal_area))) / plot.hart
        BAR = (
            old_tree.basal_area * 0.01
        ) / plot.basal_area  # is a basal area ratio (g/G, where g is the basal area of the tree (m2))

        ig = 0.3674 * (old_tree.dbh**2.651) * (plot.basal_area**(
            -0.7540)) * math.exp(-0.05207 * old_tree.tree_age -
                                 0.05291 * BALMOD - 102 * BAR)

        dbhg1 = ((ig / math.pi)**0.5) * 2
        new_tree.sum_value("dbh", dbhg1)  # annual diameter increment (cm)

        RBA_D = ((old_tree.basal_area * 0.01) / plot.basal_area)**(
            old_tree.dbh / plot.qm_dbh
        )  # a ratio basal area-diameter ([g/G]d/Dg)

        if plot.si == 0:
            htg1: float = 0
        else:
            htg1 = 0.05287 * (old_tree.height**(-0.5733)) * (
                old_tree.dbh**0.5437) * (plot.si**1.084) * math.exp(
                    -0.03242 * old_tree.tree_age - 50.87 * RBA_D)

        new_tree.sum_value("height", htg1)  # annual height increment (m)
    def grow(self, time: int, plot: Plot, old_tree: Tree, new_tree: Tree):
        """
        Function that run the diameter and height growing equations
        Source for diameter growing:
            Equation obtained from PHRAGON_2017_v1.cs, a model of Pinus halepensis useful for the old SiManFor version, developed for Aragón by Föra Forest Techonlogies and Diputación General de Aragón
         Source for height/diameter equation:
            Equation obtained from PHRAGON_2017_v1.cs, a model of Pinus halepensis useful for the old SiManFor version, developed for Aragón by Föra Forest Techonlogies and Diputación General de Aragón
        """
        if plot.si == 0:
            dbhg10 = 0
        else:
            dbhg10 = 0.906633 * math.exp(0.09701 * old_tree.dbh - 0.00111 * (
                    old_tree.dbh ** 2) - 0.05201 * plot.basal_area + 0.050652 * plot.si - 0.09366 * old_tree.bal / plot.basal_area)
            # dbhg5 = dbhg10*0.5  # that equation calculates diameter grow for 10 years, activate taht line if we want the calculation for 5 years
        # new_tree.sum_value("dbh", dbhg5)
        new_tree.sum_value("dbh", dbhg10)


        if dbhg10 == 0:
            ht = 0
        else:
            a = 2.5511
            b = pow(1.3, a)
            ht = pow(b + (pow(plot.dominant_h, a) - b) * (1 - math.exp(-0.025687 * new_tree.dbh)) / (
                    1 - math.exp(-0.025687 * plot.dominant_dbh)), 1/a)
        new_tree.add_value("height", ht)  # that equation calculates height using the new diameter; is not a growing equation
    def grow(self, time: int, plot: Plot, old_tree: Tree, new_tree: Tree):
        """
        Function that run the diameter and height growing equations
        Source:
            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
        """

        dbhg5: float = 0

        if plot.si == 0:
            dbhg5 = 0  # math.exp(0.2030 * math.log(old_tree.dbh * 10) + 0.4414 * math.log((old_tree.cr + 0.2) / 1.2) + 0.8379 * math.log(1) - 0.1295 * math.sqrt(plot.basal_area) - 0.0007 * math.pow(old_tree.ba_ha,2) / math.log(old_tree.dbh * 10))
        else:
            dbhg5 = math.exp(0.2030 * math.log(old_tree.dbh * 10) +
                             0.4414 * math.log((old_tree.cr + 0.2) / 1.2) +
                             0.8379 * math.log(plot.si) -
                             0.1295 * math.sqrt(plot.basal_area) -
                             0.0007 * math.pow(old_tree.bal, 2) /
                             math.log(old_tree.dbh * 10))

        new_tree.sum_value("dbh", dbhg5 / 10)

        if dbhg5 == 0:
            htg5 = 0
        else:
            htg5: float = math.exp(0.21603 + 0.40329 * math.log(dbhg5 / 2) -
                                   1.12721 * math.log(old_tree.dbh * 10) +
                                   1.18099 * math.log(old_tree.height * 100) +
                                   3.01622 * old_tree.cr)

        new_tree.sum_value("height", htg5 / 100)
Beispiel #10
0
    def grow(self, time: int, plot: Plot, old_tree: Tree, new_tree: Tree):
        """
        Function that run the diameter and height growing equations. Options:
        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
        b)  Doc.: Trasobares A, Pukkala T, Miina J (2004). Growth and yield model for uneven-aged mixtures of Pinus sylvestris L. and Pinus nigra Arn. in Catalonia, north-east Spain. Annals of forest science, 61(1), 9-24
            Ref.: Trasobares et al, 2002
        """
        # a) R2 muy malo para el dbhg5 --> 0.14; R2 --> 0.92 para htg5
        beta0 = 4.8413
        beta1 = -8.6610
        beta2 = -0.0054
        beta3 = -1.0160
        beta4 = 0.0545
        beta5 = -0.0035
        dbhg5: float = beta0 + beta1 / old_tree.dbh + beta2 * old_tree.bal + beta3 * math.log(
            plot.basal_area) + beta4 * plot.si + beta5 * plot.age
        new_tree.sum_value("dbh", dbhg5)

        beta6 = 0.4666
        beta7 = -0.4356
        beta8 = 0.0092
        htg5: float = 1.3 + (plot.dominant_h - 1.3) * (
            (dbhg5 / plot.dominant_dbh)**
            (beta6 + beta7 * (dbhg5 / plot.dominant_dbh) + beta8 * plot.si))
        new_tree.sum_value("height", htg5)
Beispiel #11
0
    def grow(self, time: int, plot: Plot, old_tree: Tree, new_tree: Tree):
        """
        Function that run the diameter and height growing equations
        Source for grow equation:
            Doc.: Adame P, Hynynen J, Canellas I, del Río M. (2008). Individual-tree diameter growth model for rebollo oak (Quercus pyrenaica Willd.) coppices. Forest Ecology and Management, 255(3-4), 1011-1022
            Ref.: Adame et al, 2007
        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
        """
        if plot.si == 0:
            dbhg10 = 0
        else:
            STR = 0  # su valor debe ser 1 cuando la masa esta en el estrato 1
            dbhg10 = math.exp(0.8351 + 0.1273 * math.log(old_tree.dbh) -
                              0.00006 * (old_tree.dbh**2) -
                              0.01216 * old_tree.bal - 0.00016 * plot.density -
                              0.03386 * plot.dominant_h + 0.04917 * plot.si -
                              0.1991 * STR) - 1
        new_tree.sum_value(
            "dbh", dbhg10)  # growing equation developed to 10 years period

        if dbhg10 == 0:
            htg10 = 0
        else:
            htg10: float = 1.3 + (
                3.099 - 0.00203 * plot.basal_area +
                1.02491 * plot.dominant_h * math.exp(-8.5052 / new_tree.dbh))
        new_tree.add_value(
            "height",
            htg10)  # ecuación de relación h/d, NO para el crecimiento
Beispiel #12
0
    def grow(self, time: int, plot: Plot, old_tree: Tree, new_tree: Tree):
        """
        Function that run the diameter and height growing equations
        Source for diameter growing:
            Doc.: Trasobares A, Tomé M, Miina J (2004). Growth and yield model for Pinus halepensis Mill. in Catalonia, north-east Spain. Forest ecology and management, 203(1-3), 49-62
            Ref.: Trasobares et al, 2004
         Source for height/diameter equation:
            Equation obtained from PHRAGON_2017_v1.cs, a model of Pinus halepensis useful for the old SiManFor version, developed for Aragón by Föra Forest Techonlogies and Diputación General de Aragón
        """
        BALthin = 0  # is not used on the simulation as the author says
        GI = 1  # stand growth index; difference between measured and predicted radius under bark values ~ 1
        beta1 = 1.8511
        beta2 = -3.9402
        beta3 = -0.0085
        beta4 = -0.1137
        beta5 = 0.0410
        beta6 = 0.5662
        dbhg10 = math.exp(beta1 + beta2 / old_tree.dbh +
                          beta3 * old_tree.dbh / GI + beta4 * old_tree.bal /
                          (math.log(old_tree.dbh + 1)) + beta5 * BALthin +
                          beta6 * math.log(GI))
        new_tree.sum_value("dbh", dbhg10)
        # new_tree.sum_value("dbh", dbhg10 / 2)  # that equation calculates diameter grow for 10 years, activate taht line if we want the calculation for 5 years

        a = 2.5511
        b = pow(1.3, a)
        ht = pow(
            b + (pow(plot.dominant_h, a) - b) *
            (1 - math.exp(-0.025687 * new_tree.dbh)) /
            (1 - math.exp(-0.025687 * plot.dominant_dbh)), 1 / a)
        new_tree.add_value(
            "height", ht
        )  # that equation calculates height using the new diameter; is not a growing equation
Beispiel #13
0
    def decode_node(self, node_latent, max_depth, full_label, is_leaf=False):
        if node_latent.shape[0] != 1:
            raise ValueError('Node decoding does not support batch_size > 1.')

        is_leaf_logit = self.leaf_classifier(node_latent)
        node_is_leaf = is_leaf_logit.item() > 0

        # use maximum depth to avoid potential infinite recursion
        if max_depth < 1:
            is_leaf = True

        # decode the current part box
        box = self.box_decoder(node_latent)

        if node_is_leaf or is_leaf:
            ret = Tree.Node(is_leaf=True, full_label=full_label, label=full_label.split('/')[-1])
            ret.set_from_box_quat(box.view(-1))
            return ret
        else:
            child_feats, child_sem_logits, child_exists_logit, edge_exists_logits = \
                    self.child_decoder(node_latent)

            child_sem_logits = child_sem_logits.cpu().numpy().squeeze()

            # children
            child_nodes = []
            child_idx = {}
            for ci in range(child_feats.shape[1]):
                if torch.sigmoid(child_exists_logit[:, ci, :]).item() > 0.5:
                    idx = np.argmax(child_sem_logits[ci, Tree.part_name2cids[full_label]])
                    idx = Tree.part_name2cids[full_label][idx]
                    child_full_label = Tree.part_id2name[idx]
                    child_nodes.append(self.decode_node(\
                            child_feats[:, ci, :], max_depth-1, child_full_label, \
                            is_leaf=(child_full_label not in Tree.part_non_leaf_sem_names)))
                    child_idx[ci] = len(child_nodes) - 1

            # edges
            child_edges = []
            nz_inds = torch.nonzero(torch.sigmoid(edge_exists_logits) > 0.5)    
            edge_from = nz_inds[:, 1]
            edge_to = nz_inds[:, 2]
            edge_type = nz_inds[:, 3]

            for i in range(edge_from.numel()):
                cur_edge_from = edge_from[i].item()
                cur_edge_to = edge_to[i].item()
                cur_edge_type = edge_type[i].item()

                if cur_edge_from in child_idx and cur_edge_to in child_idx:
                    child_edges.append({
                        'part_a': child_idx[cur_edge_from],
                        'part_b': child_idx[cur_edge_to],
                        'type': self.conf.edge_types[cur_edge_type]})

            node = Tree.Node(is_leaf=False, children=child_nodes, edges=child_edges, \
                    full_label=full_label, label=full_label.split('/')[-1])
            node.set_from_box_quat(box.view(-1))
            return node
Beispiel #14
0
    def grow(self, time: int, plot: Plot, old_tree: Tree, new_tree: Tree):
        """
        Function that rdbh the diameter and height growing equations
        """

        new_tree.sum_value("dbh", 0)

        new_tree.add_value("height", 0)
Beispiel #15
0
    def decode_node_diff(self, z, z_skip, obj_node):
        # DEL/SAME/LEAF
        ret = Tree.DiffNode('SAME')
        if len(obj_node.children) > 0:
            type_valid_ids = [0, 1, 3]
            for i, cnode in enumerate(obj_node.children):
                feat = torch.cat([
                    z, z_skip, cnode.box_feature, cnode.feature,
                    cnode.get_semantic_one_hot()
                ],
                                 dim=1)
                feat = self.node_diff_feature_extractor(feat)
                pred_type = self.node_diff_classifier(feat)
                pred_type = type_valid_ids[pred_type[
                    0, type_valid_ids].argmax().item()]
                if pred_type == 0:  # SAME
                    cdiff = self.decode_node_diff(z=feat,
                                                  z_skip=z_skip,
                                                  obj_node=cnode)
                    cdiff.box_diff = self.box_diff_decoder(feat)
                    ret.children.append(cdiff)
                elif pred_type == 1:  # DEL
                    cdiff = Tree.DiffNode('DEL')
                    ret.children.append(cdiff)
                else:  # LEAF
                    cdiff = Tree.DiffNode('LEAF')
                    cdiff.box_diff = self.box_diff_decoder(feat)
                    ret.children.append(cdiff)

        # ADD
        add_child_feats, add_child_sem_logits, add_child_exists_logits = self.add_child_decoder(
            z)

        feature_size = add_child_feats.size(2)
        num_part = add_child_feats.size(1)
        add_child_boxes = self.box_decoder(
            add_child_feats.view(-1, feature_size))
        add_child_sem_logits = add_child_sem_logits.cpu().numpy().squeeze()

        for i in range(num_part):
            if add_child_exists_logits[0, i].item() > 0:
                if obj_node.full_label not in Tree.part_non_leaf_sem_names:
                    print(
                        'WARNING: predicting nonzero children for a node with leaf semantics, ignoring the children'
                    )
                    continue
                cdiff = Tree.DiffNode('ADD')
                idx = np.argmax(add_child_sem_logits[
                    i, Tree.part_name2cids[obj_node.full_label]])
                idx = Tree.part_name2cids[obj_node.full_label][idx]
                child_full_label = Tree.part_id2name[idx]
                cdiff.subnode = self.decode_node(add_child_feats[:, i], self.conf.max_tree_depth, \
                        child_full_label, is_leaf=(child_full_label not in Tree.part_non_leaf_sem_names))
                ret.children.append(cdiff)

        return ret
Beispiel #16
0
    def biomass(self, tree: Tree):
        """
        Function to calculate volume variables for each tree.
        That function is run by initialize and process_plot functions.
        Biomass equations:
            Doc.: Ruiz-Peinado R, Montero G, del Rio M (2012). Biomass models to estimate carbon stocks for hardwood tree species. Forest systems, 21(1), 42-52
            Ref.: Ruiz-Peinado et al, 2012
        """

        wstb = 0.0261 * (tree.dbh**2) * tree.height
        wb2_7 = -0.0260 * (tree.dbh**2) + 0.536 * tree.height + 0.00538 * (
            tree.dbh**2) * tree.height
        wthinb = 0.898 * tree.dbh - 0.445 * tree.height
        wr = 0.143 * (tree.dbh**2)
        wt = wstb + wb2_7 + wthinb + wr

        # tree.add_value('wsw', wsw)  # wsw = stem wood (Kg)
        # tree.add_value('wsb', wsb)  # wsb = stem bark (Kg)
        # tree.add_value('w_cork', w_cork)   # w_cork = fresh cork biomass (Kg)
        # tree.add_value('wthickb', wthickb)  # wthickb = Thick branches > 7 cm (Kg)
        tree.add_value(
            'wstb', wstb)  # wstb = wsw + wthickb, stem + branches >7 cm (Kg)
        tree.add_value('wb2_7', wb2_7)  # wb2_7 = branches (2-7 cm) (Kg)
        # tree.add_value('wb2_t', wb2_t)  # wb2_t = wb2_7 + wthickb; branches >2 cm (Kg)
        tree.add_value('wthinb',
                       wthinb)  # wthinb = Thin branches (2-0.5 cm) (Kg)
        # tree.add_value('wb05', wb05)  # wb05 = thinniest branches (<0.5 cm) (Kg)
        # tree.add_value('wl', wl)  # wl = leaves (Kg)
        # tree.add_value('wtbl', wtbl)  # wtbl = wthinb + wl; branches <2 cm and leaves (Kg)
        # tree.add_value('wbl0_7', wbl0_7)  # wbl0_7 = wb2_7 + wthinb + wl; branches <7 cm and leaves (Kg)
        tree.add_value('wr', wr)  # wr = roots (Kg)
        tree.add_value('wt', wt)  # wt = biomasa total (Kg)
    def biomass(self, tree: Tree):
        """
        Function to calculate volume variables for each tree.
        That function is run by initialize and process_plot functions.
        Biomass equations:
            Doc.: Ruiz-Peinado R, del Rio M, Montero G (2011). New models for estimating the carbon sink capacity of Spanish softwood species. Forest Systems, 20(1), 176-188
            Ref.: Ruiz-Peinado et al. 2011
        """

        wsw = 0.0278 * (tree.dbh**2.115) * (tree.height**0.618)
        wb2_t = 0.000381 * (tree.dbh**3.141)
        wtbl = 0.0129 * (tree.dbh**2.320)
        wr = 0.00444 * (tree.dbh**2.804)
        wt = wsw + wb2_t + wtbl + wr

        tree.add_value('wsw', wsw)  # wsw = stem wood (Kg)
        # tree.add_value('wsb', wsb)  # wsb = stem bark (Kg)
        # tree.add_value('w_cork', w_cork)   # w_cork = fresh cork biomass (Kg)
        # tree.add_value('wthickb', wthickb)  # wthickb = Thick branches > 7 cm (Kg)
        # tree.add_value('wstb', wstb)  # wstb = wsw + wthickb, stem + branches >7 cm (Kg)
        # tree.add_value('wb2_7', wb2_7)  # wb2_7 = branches (2-7 cm) (Kg)
        tree.add_value('wb2_t',
                       wb2_t)  # wb2_t = wb2_7 + wthickb; branches >2 cm (Kg)
        # tree.add_value('wthinb', wthinb)  # wthinb = Thin branches (2-0.5 cm) (Kg)
        # tree.add_value('wb05', wb05)  # wb05 = thinniest branches (<0.5 cm) (Kg)
        # tree.add_value('wl', wl)  # wl = leaves (Kg)
        tree.add_value(
            'wtbl', wtbl)  # wtbl = wthinb + wl; branches <2 cm and leaves (Kg)
        # tree.add_value('wbl0_7', wbl0_7)  # wbl0_7 = wb2_7 + wthinb + wl; branches <7 cm and leaves (Kg)
        tree.add_value('wr', wr)  # wr = roots (Kg)
        tree.add_value('wt', wt)  # wt = biomasa total (Kg)
    def grow(self, time: int, plot: Plot, old_tree: Tree, new_tree: Tree):
        """
        Function that rdbh the diameter and height growing equations
        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
        """
        dbhg5: float = 1
        new_tree.sum_value("dbh", dbhg5)

        if dbhg5 == 0:
            htg5 = 0
        else:
            htg5: float = 1.732 * (new_tree.dbh**0.769)  # h/d equation
        new_tree.add_value("height", htg5)
    def vol(self, tree: Tree, plot: Plot):
        """
        Function to calculate volume variables for each tree.
        That function is run by initialize and process_plot functions.
        """

        hr = np.arange(0, 1, 0.001)  # that line stablish the integrate conditions for volume calculation
        dob = self.taper_equation_with_bark(tree, hr)  # diameter over bark using taper equation (cm)
        # dub = self.taper_equation_without_bark(tree, hr)  # diameter under/without bark using taper equation (cm)
        fwb = (dob / 20) ** 2  # radius^2 using dob (dm2)
        # fub = (dub / 20) ** 2  # radius^2 using dub (dm2)
        tree.add_value('vol', math.pi * tree.height * 10 * integrate.simps(fwb, hr))  # volume over bark using simpson integration (dm3)
        # tree.add_value('bole_vol', math.pi * tree.height * 10 * integrate.simps(fub, hr))  # volume under bark using simpson integration (dm3)
        # tree.add_value('bark_vol', tree.vol - tree.bole_vol)  # bark volume (dm3)
        tree.add_value('vol_ha', tree.vol * tree.expan / 1000)  # volume over bark per ha (m3/ha)
Beispiel #20
0
    def crown(self, tree: Tree, plot: Plot, func):
        """
        Function to calculate crown variables for each tree.
        That function is run by initialize and process_plot functions.
        Mean crown 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
        """

        if func == 'initialize':  # if that function is called from initilize, first we must check if that variables are available on the initial inventory
            if tree.lcw == 0:  # if the tree hasn't height maximum crown-width (m) value, it is calculated
                tree.add_value('lcw', (0.2416 + 0.0013*plot.qm_dbh)*tree.dbh - 0.0015*(tree.dbh**2))  # largest crown width (m)
        else:
            tree.add_value('lcw', (0.2416 + 0.0013*plot.qm_dbh)*tree.dbh - 0.0015*(tree.dbh**2))  # largest crown width (m)
Beispiel #21
0
    def decode_node(self, node_latent, max_depth, full_label, is_leaf=False):
        if node_latent.shape[0] != 1:
            raise ValueError('Node decoding does not support batch_size > 1.')

        is_leaf_logit = self.leaf_classifier(node_latent)
        node_is_leaf = is_leaf_logit.item() > 0

        # use maximum depth to avoid potential infinite recursion
        if max_depth < 1:
            is_leaf = True

        # decode the current part box
        box = self.box_decoder(node_latent)

        if node_is_leaf or is_leaf:
            ret = Tree.Node(is_leaf=True, \
                    full_label=full_label, label=full_label.split('/')[-1])
            ret.set_from_box_quat(box.view(-1))
            return ret
        else:
            child_feats, child_sem_logits, child_exists_logit = \
                    self.child_decoder(node_latent)

            child_sem_logits = child_sem_logits.cpu().numpy().squeeze()

            # children
            child_nodes = []
            for ci in range(child_feats.shape[1]):
                if child_exists_logit[:, ci, :].item() > 0:
                    if full_label not in Tree.part_non_leaf_sem_names:
                        print(
                            'WARNING: predicting nonzero children for a node with leaf semantics, ignoring the children'
                        )
                        continue
                    idx = np.argmax(
                        child_sem_logits[ci, Tree.part_name2cids[full_label]])
                    idx = Tree.part_name2cids[full_label][idx]
                    child_full_label = Tree.part_id2name[idx]
                    child_nodes.append(self.decode_node(\
                            child_feats[:, ci, :], max_depth-1, child_full_label, \
                            is_leaf=(child_full_label not in Tree.part_non_leaf_sem_names)))

            ret = Tree.Node(is_leaf=len(child_nodes) == 0, children=child_nodes, \
                    full_label=full_label, label=full_label.split('/')[-1])
            ret.set_from_box_quat(box.view(-1))
            return ret
Beispiel #22
0
    def merch_classes(self, tree: Tree):
        """
        Function used to calcule the different comercial volumes depending on the wood purposes
        That function is rdbh by initialize and process_plot Functions
        """
 
        ht = tree.height  # total height as ht to simplify
        # class_conditions has different lists for each usage, following that: [wood_usage, hmin/ht, dmin, dmax]
        # [WOOD USE NAME , LOG RELATIVE LENGTH RESPECT TOTAL TREE HEIGHT, MINIMUM DIAMETER, MAXIMUM DIAMETER]
        class_conditions = [] 

        # usage and merch_list are a dictionary and a list that are returned from merch_calculation
        # to that function, we must send the following information: tree, class_conditions, and the name of our class on this model you are using
        usage, merch_list = TreeModel.merch_calculation(tree, class_conditions, BasicTreeModel)

        counter = -1
        for k,i in usage.items():
            counter += 1
            tree.add_value(k, merch_list[counter])  # add merch_list values to each usage
Beispiel #23
0
    def grow(self, time: int, plot: Plot, old_tree: Tree, new_tree: Tree):
        """
        Function that run the diameter and height growing equations
        Source:
            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
        """

        ht: float = 129.0321 * ((old_tree.height / 129.0321)**(
            (plot.age / (plot.age + 5))**0.301881))
        new_tree.add_value(
            "height", ht
        )  # esta fórmula es para calcular la altura predicha, no para crecimiento

        # en principio esta era una ecuación h/d, así que es mejor calcular el diámetro con la altura total
        #dbh: float = - (math.log(
        #    1 - (1 - math.exp(-0.06160 * plot.dominant_dbh)) * (new_tree.height ** 1.067 - 1.3 ** 1.067) / (
        #                plot.dominant_h ** 1.067 - 1.3 ** 1.067))) / 0.06160
        new_tree.sum_value("dbh", 2.5)
Beispiel #24
0
    def grow(self, time: int, plot: Plot, old_tree: Tree, new_tree: Tree):
        """
        Function that run the diameter and height growing equations
        Source for diameter grow equation:
            Doc.: Sánchez-González M, del Río M, Cañellas I, Montero G (2006). Distance independent tree diameter growth model for cork oak stands. Forest Ecology and Management, 225(1-3), 262-270
            Ref.: Sánchez-González et al, 2006
            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
        Source for 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
        Source for cork grow equation:
            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
        """

        idu = 0.18 + 7.89/plot.density - 1.02/plot.si + 2.45/old_tree.dbh
        new_tree.sum_value('dbh', idu)  # annual diameter increment under cork (cm)


        h2 = 1.3 + (plot.dominant_h - 1.3)*((new_tree.dbh/plot.dominant_dbh)**0.4898)
        new_tree.add_value('height', h2)  # height/diameter equation result (m)


        t = old_tree.tree_age + 1  # years
        Xo1 = 0.5*(math.log(old_tree.bark) - 0.57*math.log(1 - math.exp(-0.04*old_tree.tree_age)))
        # Xo2 = math.sqrt((math.log(old_tree.bark) - 0.57*math.log(1 - math.exp(-0.04*old_tree.tree_age))**2 - 4*1.86*math.log(1 - math.exp(-0.04*old_tree.tree_age))))
        Xo = Xo1 # +- Xo2

        cork_2 = old_tree.bark*(((1 - math.exp(-0.04*t)) / (1 - math.exp(-0.04*old_tree.tree_age)))**((0.57+1.86)/Xo))
        new_tree.sum_value('bark', cork_2)
Beispiel #25
0
    def biomass(self, tree: Tree):
        """
        Function to calculate volume variables for each tree.
        That function is run by initialize and process_plot functions.
        Biomass equation:
            Doc.: Ruiz-Peinado R, del Rio M, Montero G (2011). New models for estimating the carbon sink capacity of Spanish softwood species. Forest Systems, 20(1), 176-188
            Ref.: Ruiz-Peinado et al, 2011
        """

        wsw = 0.0403 * (tree.dbh**1.838) * (tree.height**0.945
                                            )  # Stem wood (Kg)
        if tree.dbh <= 32.5:
            Z = 0
        else:
            Z = 1
        wthickb = (0.228 * ((tree.dbh - 32.5)**
                            2)) * Z  # wthickb = branches > 7 cm biomass (Kg)
        wb2_7 = 0.0521 * (tree.dbh**2
                          )  # wb2_7 = branches (2-7 cm) biomass (Kg)
        wtbl = 0.0720 * (tree.dbh**2
                         )  # Thin branches + Leaves (<2 cm) biomass (Kg)
        wr = 0.0189 * (tree.dbh**2.445)  # Roots biomass (Kg)
        wt = wsw + wb2_7 + wthickb + wtbl + wr  # Total biomass (Kg)

        tree.add_value('wsw', wsw)  # wsw = stem wood (Kg)
        # tree.add_value('wsb', wsb)  # wsb = stem bark (Kg)
        # tree.add_value('w_cork', w_cork)   # w_cork = fresh cork biomass (Kg)
        tree.add_value('wthickb',
                       wthickb)  # wthickb = Thick branches > 7 cm (Kg)
        # tree.add_value('wstb', wstb)  # wstb = wsw + wthickb, stem + branches >7 cm (Kg)
        tree.add_value('wb2_7', wb2_7)  # wb2_7 = branches (2-7 cm) (Kg)
        # tree.add_value('wb2_t', wb2_t)  # wb2_t = wb2_7 + wthickb; branches >2 cm (Kg)
        # tree.add_value('wthinb', wthinb)  # wthinb = Thin branches (2-0.5 cm) (Kg)
        # tree.add_value('wb05', wb05)  # wb05 = thinniest branches (<0.5 cm) (Kg)
        # tree.add_value('wl', wl)  # wl = leaves (Kg)
        tree.add_value(
            'wtbl', wtbl)  # wtbl = wthinb + wl; branches <2 cm and leaves (Kg)
        # tree.add_value('wbl0_7', wbl0_7)  # wbl0_7 = wb2_7 + wthinb + wl; branches <7 cm and leaves (Kg)
        tree.add_value('wr', wr)  # wr = roots (Kg)
        tree.add_value('wt', wt)  # wt = biomasa total (Kg)
Beispiel #26
0
def evaluate(model, loader):

    model.eval()

    total_loss, metric = 0, SpanMetric()

    for words, *feats, trees, charts in loader:
        # mask out the lower left triangle
        word_mask = words.ne(args.pad_index)[:, 1:]
        mask = word_mask if len(words.shape) < 3 else word_mask.any(-1)
        mask = (mask.unsqueeze(1) & mask.unsqueeze(2)).triu_(1)

        s_feat = model(words, feats)
        loss, s_feat = model.loss(s_feat, charts, mask, require_marginals=True)
        chart_preds = model.decode(s_feat, mask)
        # since the evaluation relies on terminals,
        # the tree should be first built and then factorized
        preds = [
            Tree.build(tree, [(i, j, CHART.vocab[label])
                              for i, j, label in chart])
            for tree, chart in zip(trees, chart_preds)
        ]
        total_loss += loss.item()

        if args.draw_pred:  ### draw trees here
            filter_delete = lambda x: [it for it in x if it not in args.delete]
            trees_fact = [
                Tree.factorize(tree, args.delete, args.equal) for tree in preds
            ]
            leaves = [filter_delete(tree.leaves()) for tree in trees]
            t = convert_to_viz_tree(tree=trees_fact[0], sen=leaves[0])

            draw_tree(t, res_path="./prediction")

        metric(
            [Tree.factorize(tree, args.delete, args.equal) for tree in preds],
            [Tree.factorize(tree, args.delete, args.equal) for tree in trees])
    total_loss /= len(loader)

    return total_loss, metric
Beispiel #27
0
    def vol(self, tree: Tree, plot: Plot):
        """
        Function to calculate volume variables for each tree.
        That function is run by initialize and process_plot functions.
        Volume under bark equation:
            Doc.: Amaral J, Tomé M (2006). Equações para estimação do volume e biomassa de duas espécies de carvalhos: Quercus suber e Quercus ilex. Publicações do GIMREF, 1-21
            Ref.: Amaral and Tomé (2006)
        """

        # hr = np.arange(0, 1, 0.001)  # that line stablish the integrate conditions for volume calculation
        # dob = self.taper_equation_with_bark(tree, hr)  # diameter over bark using taper equation (cm)
        # dub = self.taper_equation_without_bark(tree, hr)  # diameter under/without bark using taper equation (cm)
        # fwb = (dob / 20) ** 2  # radius^2 using dob (dm2)
        # fub = (dub / 20) ** 2  # radius^2 using dub (dm2)
        # tree.add_value('vol', math.pi * tree.height * 10 * integrate.simps(fwb, hr))  # volume over bark using simpson integration (dm3)
        # tree.add_value('bole_vol', math.pi * tree.height * 10 * integrate.simps(fub, hr))  # volume under bark using simpson integration (dm3)
        # tree.add_value('bark_vol', tree.vol - tree.bole_vol)  # bark volume (dm3)
        # tree.add_value('vol_ha', tree.vol * tree.expan / 1000)  # volume over bark per ha (m3/ha)
        tree.add_value('bole_vol', 0.000115*(tree.dbh**2.147335) * 1000)  # volume under bark (dm3)

        if isinstance(tree.bark, float) and isinstance(tree.h_uncork, float) and isinstance(tree.dbh_oc, float):
            tree.add_value('bark_vol', (tree.bark/100) * (tree.h_uncork*10) * ((tree.dbh + tree.dbh_oc) / 20))  # cork fresh volume (dm3)
    def crown(self, tree: Tree, plot: Plot, func):
        """
        Function to calculate crown variables for each tree.
        That function is run by initialize and process_plot functions.
        Crown equations:
            Equation obtained from PHRAGON_2017_v1.cs, a model of Pinus halepensis useful for the old SiManFor version, developed for Aragón by Föra Forest Techonlogies and Diputación General de Aragón
        """

        if func == 'initialize':  # if that function is called from initilize, first we must check if that variables are available on the initial inventory
            if tree.hcb == 0:  # if the tree hasn't basal crown (m) value, it is calculated
                tree.add_value('hcb', tree.height / (1 + math.exp(-0.82385 + 4.039408*plot.hart*
                                    0.01 - 0.01969*plot.si - 0.594323*tree.bal/plot.basal_area)))  # basal crown height (m) calculation
        else:
            tree.add_value('hcb', tree.height / (1 + math.exp(-0.82385 + 4.039408*plot.hart*
                                    0.01 - 0.01969*plot.si - 0.594323*tree.bal/plot.basal_area)))  # basal crown height (m) calculation
                
        tree.add_value('cr', 1 - tree.hcb / tree.height)  # crown ratio calculation (%)
        tree.add_value('lcw', 0.672001 * pow(tree.dbh, 0.880032) * pow(tree.height, -0.60344) * math.exp(0.057872 * tree.height))  # maximum crown-width (m) calculation
Beispiel #29
0
def predict(model, loader):
    model.eval()

    preds = {'trees': [], 'probs': []}
    for words, *feats, trees in loader:
        word_mask = words.ne(args.pad_index)[:, 1:]
        mask = word_mask if len(words.shape) < 3 else word_mask.any(-1)
        mask = (mask.unsqueeze(1) & mask.unsqueeze(2)).triu_(1)
        lens = mask[:, 0].sum(-1)
        s_feat = model(words, feats)
        s_span = model.crf(s_feat, mask, require_marginals=True)
        chart_preds = model.decode(s_span, mask)
        preds['trees'].extend([
            Tree.build(tree, [(i, j, CHART.vocab[label])
                              for i, j, label in chart])
            for tree, chart in zip(trees, chart_preds)
        ])
        if args.prob:
            preds['probs'].extend(
                [prob[:i - 1, 1:i].cpu() for i, prob in zip(lens, s_span)])

    return preds
Beispiel #30
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)