Esempio n. 1
0
    def calculate_custom_limit_state_w_conversion(
            self, variables: dict, inventory_type: str = "building"):
        """Computes limit state probabilities.

        Args:
            variables (dict): A dictionary of variables.
            inventory_type (str): A type of inventory.

        Returns:
            dict: Limit state probabilities for custom expression fragilities.

        """
        output = FragilityCurveSet._initialize_limit_states(inventory_type)
        limit_state = list(output.keys())
        index = 0

        if len(self.fragility_curves) <= 4:
            for fragility_curve in self.fragility_curves:
                probability = fragility_curve.compute_custom_limit_state_probability(
                    variables)
                output[limit_state[index]] = AnalysisUtil.update_precision(
                    probability)  # round to default digits
                index += 1
        else:
            raise ValueError(
                "We can only handle fragility curves with less than 4 limit states."
            )

        return output
Esempio n. 2
0
    def calculate_limit_state(self,
                              hazard_values: dict = {},
                              inventory_type: str = "building",
                              **kwargs):
        """WIP computation of limit state probabilities accounting for custom expressions.

        Args:
            hazard_values (dict): A dictionary with hazard values to compute probability.
            inventory_type (str): An inventory type.
            **kwargs: Keyword arguments.

        Returns:
            OrderedDict: Limit state probabilities.

        """
        output = FragilityCurveSet._initialize_limit_states(inventory_type)
        limit_state = list(output.keys())
        index = 0

        if len(self.fragility_curves) <= 4:
            for fragility_curve in self.fragility_curves:
                probability = fragility_curve.solve_curve_expression(
                    hazard_values, self.curve_parameters, **kwargs)
                output[limit_state[index]] = AnalysisUtil.update_precision(
                    probability)  # round to default digits
                index += 1
        else:
            raise ValueError(
                "We can only handle fragility curves with less than 4 limit states."
            )

        return output
Esempio n. 3
0
    def _4ls_to_5ds(limit_states):
        """

        Args:
            limit_states (dict): Limit states.

        Returns:
            dict: Damage states.

        """
        limit_states = AnalysisUtil.float_dict_to_decimal(limit_states)
        damage_states = AnalysisUtil.float_dict_to_decimal({
            "DS_0": 0.0,
            "DS_1": 0.0,
            "DS_2": 0.0,
            "DS_3": 0.0,
            "DS_4": 0.0
        })

        small_overlap = FragilityCurveSet.is_there_small_overlap(limit_states)

        if small_overlap:
            ds_overlap = FragilityCurveSet.adjust_for_small_overlap(
                small_overlap, limit_states, damage_states)

            damage_states['DS_0'] = ds_overlap[0]
            damage_states['DS_1'] = ds_overlap[1]
            damage_states['DS_2'] = ds_overlap[2]
            damage_states['DS_3'] = ds_overlap[3]
            damage_states['DS_4'] = ds_overlap[4]

        else:
            damage_states['DS_0'] = 1 - limit_states["LS_0"]
            damage_states['DS_1'] = limit_states["LS_0"] - limit_states["LS_1"]
            damage_states['DS_2'] = limit_states["LS_1"] - limit_states["LS_2"]
            damage_states['DS_3'] = limit_states["LS_2"] - limit_states["LS_3"]
            damage_states['DS_4'] = limit_states["LS_3"]

        return damage_states
Esempio n. 4
0
    def _1ls_to_4ds(limit_states):
        """

        Args:
            limit_states (dict): Limit states.

        Returns:
            dict: Damage states.

        """
        limit_states = AnalysisUtil.float_dict_to_decimal(limit_states)
        damage_states = dict()
        damage_states['DS_0'] = 1 - limit_states["LS_0"]
        damage_states['DS_1'] = 0
        damage_states['DS_2'] = 0
        damage_states['DS_3'] = limit_states["LS_0"]

        return damage_states
Esempio n. 5
0
    def calculate_limit_state_w_conversion(self,
                                           hazard,
                                           period: float = 0.0,
                                           std_dev: float = 0.0,
                                           inventory_type: str = "building",
                                           **kwargs):
        """Computes limit state probabilities.

        Args:
            hazard (float): Hazard value to compute probability for.
            period (float): Period of the structure, if applicable.
            std_dev (float): Standard deviation.
            inventory_type (str): A type of inventory.
            **kwargs: Keyword arguments.

        Returns:
            dict: Limit state probabilities.

        """
        output = FragilityCurveSet._initialize_limit_states(inventory_type)
        limit_state = list(output.keys())
        index = 0

        if len(self.fragility_curves) <= 4:
            for fragility_curve in self.fragility_curves:
                probability = fragility_curve.solve_curve_expression(
                    hazard, period, std_dev, **kwargs)
                output[limit_state[index]] = AnalysisUtil.update_precision(
                    probability)  # round to default digits
                index += 1
        else:
            raise ValueError(
                "We can only handle fragility curves with less than 4 limit states."
            )

        return output
Esempio n. 6
0
def test_get_exposure_from_hazard_values(hazard_vals, hazard_type, expected):
    hazard_exposure = AnalysisUtil.get_exposure_from_hazard_values(hazard_vals, hazard_type)
    assert hazard_exposure == expected
Esempio n. 7
0
    def get_damage(self, node_dataset, link_dataset, tornado_dataset,
                   tornado_id):
        """

        Args:
            node_dataset (obj): Node dataset.
            link_dataset (obj): Link dataset.
            tornado_dataset (obj): Tornado dataset.
            tornado_id (str): Tornado id.

        """
        self.set_tornado_variables(tornado_dataset)
        self.set_node_variables(node_dataset)

        # get fragility curves set - tower for transmission, pole for distribution
        fragility_set_tower = FragilityCurveSet(
            self.fragilitysvc.get_dfr3_set(self.fragility_tower_id))
        assert fragility_set_tower.id == self.fragility_tower_id
        fragility_set_pole = FragilityCurveSet(
            self.fragilitysvc.get_dfr3_set(self.fragility_pole_id))
        assert fragility_set_pole.id == self.fragility_pole_id

        # network test
        node_id_validation = NetworkUtil.validate_network_node_ids(
            node_dataset, link_dataset, self.fromnode_fld_name,
            self.tonode_fld_name, self.nodenwid_fld_name)
        if node_id_validation is False:
            print(
                "ID in from or to node field doesn't exist in the node dataset"
            )
            os.exit(0)

        # getting network graph and node coordinates
        is_directed_graph = True

        graph, node_coords = NetworkUtil.create_network_graph_from_field(
            link_dataset, self.fromnode_fld_name, self.tonode_fld_name,
            is_directed_graph)

        # reverse the graph to acculate the damage to next to node
        graph = nx.DiGraph.reverse(graph, copy=True)

        # check the connection as a list
        connection_sets = []
        if is_directed_graph:
            connection_sets = list(nx.weakly_connected_components(graph))
        else:
            connection_sets = list(nx.connected_components(graph))

        # check the first node of the each network line, this first node should lead each separated network
        # also convert connection set to list
        first_node_list = []
        connection_list = []
        for c in connection_sets:
            connection_list.append(list(c))
            first_node_list.append(list(c)[0])

        intersection_list = []
        poly_list = []
        totalcost2repair = []
        totalpoles2repair = []
        totaltime2repair = []

        # construct guid field
        guid_list = []
        nodenwid_list = []
        for node_feature in node_dataset:
            # get guid colum
            guid_fld_val = ''
            if self.guid_fldname.lower() in node_feature['properties']:
                guid_fld_val = node_feature['properties'][
                    self.guid_fldname.lower()]
            elif self.guid_fldname in node_feature['properties']:
                guid_fld_val = node_feature['properties'][self.guid_fldname]
            guid_list.append(guid_fld_val)

            # get nodenwid colum
            nodenwid_fld_val = ''
            if self.nodenwid_fld_name.lower() in node_feature['properties']:
                nodenwid_fld_val = int(
                    node_feature['properties'][self.nodenwid_fld_name.lower()])
            elif self.nodenwid_fld_name in node_feature['properties']:
                nodenwid_fld_val = int(
                    node_feature['properties'][self.nodenwid_fld_name])
            nodenwid_list.append(nodenwid_fld_val)

        for z in range(self.nmcs):
            nodedam = [
                0
            ] * self.nnode  # placeholder for recording number of damaged pole for each node
            noderepair = [
                0
            ] * self.nnode  # placeholder for recording repair cost for each node
            poles2repair = [
                0
            ] * self.nnode  # placeholder for recording total number of poles to repair
            cost2repairpath = [
                0
            ] * self.nnode  # placeholder for recording total repair cost for the network
            time2repairpath = [
                0
            ] * self.nnode  # placeholder for recording total repair time for the network
            nodetimerep = [0] * self.nnode
            hazardval = [[
                0
            ]] * self.nnode  # placeholder for recording hazard values
            demandtypes = [[
                ""
            ]] * self.nnode  # placeholder for recording demand types
            demandunits = [[
                ""
            ]] * self.nnode  # placeholder for recording demand units

            # iterate link
            for line_feature in link_dataset:
                ndamage = 0  # number of damaged poles in each link
                repaircost = 0  # repair cost value
                repairtime = 0  # repair time value
                to_node_val = ""
                linetype_val = ""
                tor_hazard_values = [0]  # random wind speed in EF
                demand_types = [""]
                demand_units = [""]

                if self.tonode_fld_name.lower() in line_feature['properties']:
                    to_node_val = line_feature['properties'][
                        self.tonode_fld_name.lower()]
                elif self.tonode_fld_name in line_feature['properties']:
                    to_node_val = line_feature['properties'][
                        self.tonode_fld_name]

                if self.linetype_fld_name in line_feature['properties']:
                    linetype_val = line_feature['properties'][
                        self.linetype_fld_name]
                elif self.linetype_fld_name.lower(
                ) in line_feature['properties']:
                    linetype_val = line_feature['properties'][
                        self.linetype_fld_name.lower()]

                line = shape(line_feature['geometry'])

                # iterate tornado
                for tornado_feature in tornado_dataset:
                    resistivity_probability = 0  # resistivity value at the point of windSpeed
                    random_resistivity = 0  # random resistivity value between 0 and one

                    sim_fld_val = ""
                    ef_fld_val = ""

                    # get EF rating and simulation number column
                    if self.tornado_sim_field_name.lower(
                    ) in tornado_feature['properties']:
                        sim_fld_val = int(tornado_feature['properties'][
                            self.tornado_sim_field_name.lower()])
                    elif self.tornado_sim_field_name in tornado_feature[
                            'properties']:
                        sim_fld_val = int(tornado_feature['properties'][
                            self.tornado_sim_field_name])

                    if self.tornado_ef_field_name.lower(
                    ) in tornado_feature['properties']:
                        ef_fld_val = tornado_feature['properties'][
                            self.tornado_ef_field_name.lower()]
                    elif self.tornado_ef_field_name in tornado_feature[
                            'properties']:
                        ef_fld_val = tornado_feature['properties'][
                            self.tornado_ef_field_name]

                    if sim_fld_val == "" or ef_fld_val == "":
                        print(
                            "unable to convert tornado simulation field value to integer"
                        )
                        sys.exit(0)

                    # get Tornado EF polygon
                    # assumes that the polygon is not a multipolygon
                    poly = shape(tornado_feature['geometry'])
                    poly_list.append(poly)

                    # loop for ef ranges
                    for f in range(self.tornado_ef_rate):
                        npoles = 0  # number of poles in tornado ef box
                        poleresist = 0  # pole's resistance value
                        # setting EF rate value string to match in the tornado dataset's attribute table
                        ef_content = "EF" + str(f)

                        # compute the intersections between link line and ef polygon
                        # also figure out the length of the line that ovelapped with EF box

                        # compute the intersection between tornado polygon and line
                        if sim_fld_val == z and ef_fld_val.lower(
                        ) == ef_content.lower():
                            if poly is not None and line is not None:
                                if poly.intersects(line):
                                    intersection = poly.intersection(line)
                                    any_point = None
                                    intersection_length = intersection.length
                                    if intersection.length > 0:
                                        # print(intersection.__class__.__name__)
                                        # calculate the length of intersected line
                                        # since this is a geographic, it has to be projected to meters to be calcuated
                                        inter_length_meter = GeoUtil.calc_geog_distance_from_linestring(
                                            intersection)
                                        if isinstance(intersection,
                                                      MultiLineString):
                                            intersection_list.append(
                                                intersection)
                                            for inter_line in intersection.geoms:
                                                any_point = inter_line.centroid
                                                break
                                        elif isinstance(
                                                intersection, LineString):
                                            intersection_list.append(
                                                intersection)
                                            any_point = intersection.centroid

                                            # also, random point can be possible
                                            # by changing the following lines value 0.5
                                            # any_point = intersection.interpolate(0.5, normalized=True)

                                    if any_point is not None:
                                        # check if any_point is in the polygon
                                        if poly.contains(any_point) is False:
                                            # this is very hardly happen but should be needed just in case
                                            any_point = poly.centroid

                                    # check if the line is tower or transmission
                                    if linetype_val.lower(
                                    ) == self.line_transmission:
                                        fragility_set_used = fragility_set_tower
                                    else:
                                        fragility_set_used = fragility_set_pole

                                    values_payload = [{
                                        "demands": [
                                            x.lower() for x in
                                            fragility_set_used.demand_types
                                        ],
                                        "units": [
                                            x.lower() for x in
                                            fragility_set_used.demand_units
                                        ],
                                        "loc":
                                        str(any_point.coords[0][1]) + "," +
                                        str(any_point.coords[0][0])
                                    }]

                                    h_vals = self.hazardsvc.post_tornado_hazard_values(
                                        tornado_id, values_payload,
                                        self.get_parameter('seed'))
                                    tor_hazard_values = AnalysisUtil.update_precision_of_lists(
                                        h_vals[0]["hazardValues"])
                                    demand_types = h_vals[0]["demands"]
                                    demand_units = h_vals[0]["units"]
                                    hval_dict = dict()
                                    j = 0
                                    for d in h_vals[0]["demands"]:
                                        hval_dict[d] = tor_hazard_values[j]
                                        j += 1
                                    if isinstance(
                                            fragility_set_used.
                                            fragility_curves[0], DFR3Curve):
                                        inventory_args = fragility_set_used.construct_expression_args_from_inventory(
                                            tornado_feature)
                                        resistivity_probability = \
                                            fragility_set_used.calculate_limit_state(
                                                hval_dict,
                                                inventory_type=fragility_set_used.inventory_type, **inventory_args)
                                    else:
                                        raise ValueError(
                                            "One of the fragilities is in deprecated format. This should not happen. "
                                            "If you are seeing this please report the issue."
                                        )

                                    # randomly generated capacity of each poles ; 1 m/s is 2.23694 mph
                                    poleresist = resistivity_probability.get(
                                        'LS_0') * 2.23694
                                    npoles = int(
                                        round(inter_length_meter /
                                              self.pole_distance))
                                    repairtime_list = []

                                    for k in range(npoles):
                                        repair_time = 0
                                        random_resistivity = random.uniform(
                                            0, 1)

                                        if random_resistivity <= poleresist:
                                            ndamage += 1
                                            # following codes can't be converted from matlab to python
                                            # however, the cross product <=3 or == 24 almost doesn't happen
                                            # since the time and cost differs when it is pole or tower,
                                            # this could be changed by see if it is tower or pole
                                            # if numpy.cross(k, z) <= 3 or numpy.cross(k, z) == 24:
                                            if linetype_val.lower(
                                            ) == self.line_transmission:
                                                mu = self.mut
                                                sigma = self.sigmat
                                                tmu = self.tmut
                                                tsigma = self.tsigmat
                                            else:
                                                mu = self.mud
                                                sigma = self.sigmad
                                                tmu = self.tmud
                                                tsigma = self.tsigmad

                                            repairtime_list.append(
                                                numpy.random.normal(
                                                    tmu, tsigma))

                                    for k in range(ndamage):
                                        repaircost += numpy.random.lognormal(
                                            mu, sigma)

                                    # max of the repair time among different poles is taken
                                    # as the repair time for that line
                                    if len(repairtime_list) > 0:
                                        repairtime = max(repairtime_list)
                noderepair[to_node_val - 1] = repaircost
                nodedam[to_node_val - 1] = ndamage
                nodetimerep[to_node_val - 1] = repairtime
                hazardval[to_node_val - 1] = tor_hazard_values
                demandtypes[to_node_val - 1] = demand_types
                demandunits[to_node_val - 1] = demand_units

            # Calculate damage and repair cost based on network
            for i in range(len(first_node_list)):
                for j in range(len(connection_list[i])):
                    # print(connection_list[i][j], first_node_list[i])
                    pathij = list(
                        nx.all_simple_paths(graph, connection_list[i][j],
                                            first_node_list[i]))
                    poler = 0
                    coster = 0
                    timer = []
                    # print(pathij)
                    if len(pathij) > 0:
                        for k in range(len(pathij)):
                            for var1 in range(len(pathij[k])):
                                poler = poler + nodedam[pathij[k][var1]]
                                coster = coster + noderepair[pathij[k][var1]]
                                # max of the time for different lines is taken as the repair time for that path.
                                # -- path is constituted of different lines.
                                timer.append(nodetimerep[pathij[k][var1]])
                    poles2repair[connection_list[i][j]] = poler
                    cost2repairpath[connection_list[i][j]] = coster
                    if len(timer) > 0:
                        time2repairpath[connection_list[i][j]] = max(timer)
                    else:
                        time2repairpath[connection_list[i][j]] = 0
            totalcost2repair.append(cost2repairpath)
            totalpoles2repair.append(poles2repair)
            totaltime2repair.append(time2repairpath)

        # create guid field from node dataset

        # calculate mean and standard deviation
        meanpoles = numpy.mean(numpy.asarray(totalpoles2repair), axis=0)
        stdpoles = numpy.std(numpy.asarray(totalpoles2repair), axis=0)
        meancost = numpy.mean(numpy.asarray(totalcost2repair), axis=0)
        stdcost = numpy.std(numpy.asarray(totalcost2repair), axis=0)
        meantime = numpy.mean(numpy.asarray(totaltime2repair), axis=0)
        stdtime = numpy.std(numpy.asarray(totaltime2repair), axis=0)

        # create result
        ds_results = []
        damage_results = []

        for i in range(len(meanpoles)):
            ds_result = dict()
            damage_result = dict()

            ds_result['guid'] = guid_list[i]
            ds_result["meanpoles"] = meanpoles[i]
            ds_result["stdpoles"] = stdpoles[i]
            ds_result["meancost"] = meancost[i]
            ds_result["stdcost"] = stdcost[i]
            ds_result["meantime"] = meantime[i]
            ds_result["stdtime"] = stdtime[i]
            ds_result[
                'haz_expose'] = AnalysisUtil.get_exposure_from_hazard_values(
                    hazardval[i], "tornado")

            damage_result['guid'] = guid_list[i]
            damage_result["fragility_tower_id"] = self.fragility_tower_id
            damage_result["fragility_pole_id"] = self.fragility_pole_id
            damage_result["hazardtype"] = "Tornado"
            damage_result['hazardvals'] = hazardval[i]
            damage_result['demandtypes'] = demandtypes[i]
            damage_result['demandunits'] = demandunits[i]

            ds_results.append(ds_result)
            damage_results.append(damage_result)

        return ds_results, damage_results