def test_skimming_single_origin(self):

        origin = 1

        # graph
        g = Graph()
        g.load_from_disk(test_graph)
        g.set_graph(cost_field="distance", skim_fields=None)
        # g.block_centroid_flows = False
        # None implies that only the cost field will be skimmed

        # skimming results
        res = SkimResults()
        res.prepare(g)
        aux_result = MultiThreadedNetworkSkimming()
        aux_result.prepare(g, res)

        a = skimming_single_origin(origin, g, res, aux_result, 0)
        tot = np.sum(res.skims.distance[origin, :])
        if tot > 10e10:
            self.fail(
                "Skimming was not successful. At least one np.inf returned.")

        if a != origin:
            self.fail("Skimming returned an error: " + a)
    def test_network_skimming(self):
        # graph
        g = Graph()
        g.load_from_disk(test_graph)
        g.set_graph(cost_field="distance", skim_fields=None)
        # None implies that only the cost field will be skimmed

        # skimming results
        res = SkimResults()
        res.prepare(g)

        aux_res = MultiThreadedNetworkSkimming()
        aux_res.prepare(g, res)
        _ = skimming_single_origin(26, g, res, aux_res, 0)

        skm = NetworkSkimming(g, res)
        skm.execute()

        tot = np.nanmax(res.skims.distance[:, :])

        if tot > 10e10:
            self.fail(
                "Skimming was not successful. At least one np.inf returned.")

        if skm.report:
            self.fail("Skimming returned an error:" + str(skm.report))
    def test_skimming_single_origin(self):

        g = Graph()
        g.load_from_disk(test_graph)
        g.set_graph(cost_field="distance")
        g.set_skimming("distance")

        origin = np.random.choice(g.centroids[:-1], 1)[0]

        # skimming results
        res = SkimResults()
        res.prepare(g)
        aux_result = MultiThreadedNetworkSkimming()
        aux_result.prepare(g, res)

        a = skimming_single_origin(origin, g, res, aux_result, 0)
        tot = np.sum(res.skims.distance[origin, :])
        if tot > 10e10:
            self.fail(
                "Skimming was not successful. At least one np.inf returned for origin {}."
                .format(origin))

        if a != origin:
            self.fail("Skimming returned an error: {} for origin {}".format(
                a, origin))
    def test_network_skimming(self):
        # graph
        g = Graph()
        g.load_from_disk(test_graph)
        g.set_graph(cost_field='distance', skim_fields=None)
        # None implies that only the cost field will be skimmed

        # skimming results
        res = SkimResults()
        res.prepare(g)

        aux_res = MultiThreadedNetworkSkimming()
        aux_res.prepare(g, res)
        a = skimming_single_origin(26, g, res, aux_res, 0)

        skm = NetworkSkimming(g, res)
        skm.execute()

        tot = np.nanmax(res.skims.distance[:, :])

        if tot > 10e10:
            self.fail('Skimming was not successful. At least one np.inf returned.')

        if skm.report:
            self.fail('Skimming returned an error:' + str(skm.report))
Example #5
0
    def test_set_pce(self):
        mat_name = AequilibraeMatrix().random_name()
        g = Graph()
        g.load_from_disk(test_graph)
        g.set_graph(cost_field="distance")

        # Creates the matrix for assignment
        args = {
            "file_name": os.path.join(gettempdir(), mat_name),
            "zones": g.num_zones,
            "matrix_names": ["cars", "trucks"],
            "index_names": ["my indices"],
        }

        matrix = AequilibraeMatrix()
        matrix.create_empty(**args)

        matrix.index[:] = g.centroids[:]
        matrix.cars.fill(1.1)
        matrix.trucks.fill(2.2)
        matrix.computational_view()

        tc = TrafficClass(graph=g, matrix=matrix)

        self.assertIsInstance(tc.results, AssignmentResults, 'Results have the wrong type')
        self.assertIsInstance(tc._aon_results, AssignmentResults, 'Results have the wrong type')

        with self.assertRaises(ValueError):
            tc.set_pce('not a number')
        tc.set_pce(1)
        tc.set_pce(3.9)
Example #6
0
    def test_execute(self):
        # Loads and prepares the graph
        g = Graph()
        g.load_from_disk(test_graph)
        g.set_graph(cost_field='distance', skim_fields=None)
        # None implies that only the cost field will be skimmed

        # Prepares the matrix for assignment
        args = {
            'file_name': '/tmp/my_matrix.aem',
            'zones': g.num_zones,
            'matrix_names': ['cars', 'trucks'],
            'index_names': ['my indices']
        }

        matrix = AequilibraeMatrix()
        matrix.create_empty(**args)

        matrix.index[:] = g.centroids[:]
        matrix.cars.fill(1)
        matrix.trucks.fill(2)
        matrix.computational_view(['cars'])

        # Performs assignment
        res = AssignmentResults()
        res.prepare(g, matrix)

        assig = allOrNothing(matrix, g, res)
        assig.execute()

        res.save_to_disk('/tmp/link_loads.aed')
        res.save_to_disk('/tmp/link_loads.csv')

        matrix.computational_view()
        # Performs assignment
        res = AssignmentResults()
        res.prepare(g, matrix)

        assig = allOrNothing(matrix, g, res)
        assig.execute()
        res.save_to_disk('/tmp/link_loads_2_classes.aed')
        res.save_to_disk('/tmp/link_loads_2_classes.csv')
    def test_execute(self):
        # Loads and prepares the graph
        g = Graph()
        g.load_from_disk(test_graph)
        g.set_graph(cost_field="distance", skim_fields=None)
        # None implies that only the cost field will be skimmed

        # Prepares the matrix for assignment
        args = {
            "file_name": os.path.join(gettempdir(), "my_matrix.aem"),
            "zones": g.num_zones,
            "matrix_names": ["cars", "trucks"],
            "index_names": ["my indices"],
        }

        matrix = AequilibraeMatrix()
        matrix.create_empty(**args)

        matrix.index[:] = g.centroids[:]
        matrix.cars.fill(1)
        matrix.trucks.fill(2)
        matrix.computational_view(["cars"])

        # Performs assignment
        res = AssignmentResults()
        res.prepare(g, matrix)

        assig = allOrNothing(matrix, g, res)
        assig.execute()

        res.save_to_disk(os.path.join(gettempdir(), "link_loads.aed"))
        res.save_to_disk(os.path.join(gettempdir(), "link_loads.csv"))

        matrix.computational_view()
        # Performs assignment
        res = AssignmentResults()
        res.prepare(g, matrix)

        assig = allOrNothing(matrix, g, res)
        assig.execute()
        res.save_to_disk(os.path.join(gettempdir(), "link_loads_2_classes.aed"))
        res.save_to_disk(os.path.join(gettempdir(), "link_loads_2_classes.csv"))
    def test_execute(self):
        # Loads and prepares the graph
        g = Graph()
        g.load_from_disk(test_graph)
        g.set_graph(cost_field='distance', skim_fields=None)
        # None implies that only the cost field will be skimmed

        # Prepares the matrix for assignment
        args = {'file_name': os.path.join(gettempdir(),'my_matrix.aem'),
                'zones': g.num_zones,
                'matrix_names': ['cars', 'trucks'],
                'index_names': ['my indices']}

        matrix = AequilibraeMatrix()
        matrix.create_empty(**args)

        matrix.index[:] = g.centroids[:]
        matrix.cars.fill(1)
        matrix.trucks.fill(2)
        matrix.computational_view(['cars'])

        # Performs assignment
        res = AssignmentResults()
        res.prepare(g, matrix)

        assig = allOrNothing(matrix, g, res)
        assig.execute()

        res.save_to_disk(os.path.join(gettempdir(),'link_loads.aed'))
        res.save_to_disk(os.path.join(gettempdir(),'link_loads.csv'))

        matrix.computational_view()
        # Performs assignment
        res = AssignmentResults()
        res.prepare(g, matrix)

        assig = allOrNothing(matrix, g, res)
        assig.execute()
        res.save_to_disk(os.path.join(gettempdir(),'link_loads_2_classes.aed'))
        res.save_to_disk(os.path.join(gettempdir(),'link_loads_2_classes.csv'))
class TestPathResults(TestCase):
    def test_prepare(self):
        # graph
        self.g = Graph()
        self.g.load_from_disk(test_graph)
        self.g.set_graph(cost_field="distance")

        self.r = PathResults()
        try:
            self.r.prepare(self.g)
        except Exception as err:
            self.fail("Path result preparation failed - {}".format(
                err.__str__()))

    def test_reset(self):
        self.test_prepare()
        try:
            self.r.reset()
        except Exception as err:
            self.fail("Path result resetting failed - {}".format(
                err.__str__()))

    def test_update_trace(self):
        self.test_prepare()
        try:
            self.r.reset()
        except Exception as err:
            self.fail("Path result resetting failed - {}".format(
                err.__str__()))

        path_computation(origin, dest, self.g, self.r)

        if list(self.r.path) != [53, 52, 13]:
            self.fail("Path computation failed. Wrong sequence of links")

        if list(self.r.path_nodes) != [5, 168, 166, 27]:
            self.fail("Path computation failed. Wrong sequence of path nodes")

        if list(self.r.milepost) != [0, 341, 1398, 2162]:
            self.fail("Path computation failed. Wrong milepost results")
Example #10
0
class TestPathResults(TestCase):
    def test_prepare(self):
        # graph
        self.g = Graph()
        self.g.load_from_disk(test_graph)
        self.g.set_graph(cost_field='distance', skim_fields=None)

        self.r = PathResults()
        try:
            self.r.prepare(self.g)
        except:
            self.fail('Path result preparation failed')


    def test_reset(self):
        self.test_prepare()
        try:
            self.r.reset()
        except:
            self.fail('Path result resetting failed')

    def test_update_trace(self):
        self.test_prepare()
        try:
            self.r.reset()
        except:
            self.fail('Path result resetting failed')

        path_computation(origin, dest, self.g, self.r)

        if list(self.r.path) != [53, 52, 13]:
            self.fail('Path computation failed. Wrong sequence of links')

        if list(self.r.path_nodes) != [5, 168, 166, 27]:
            self.fail('Path computation failed. Wrong sequence of path nodes')

        if list(self.r.milepost) != [0, 341, 1398, 2162]:
            self.fail('Path computation failed. Wrong milepost results')
class TestPathResults(TestCase):
    def test_prepare(self):
        # graph
        self.g = Graph()
        self.g.load_from_disk(test_graph)
        self.g.set_graph(cost_field='distance', skim_fields=None)

        self.r = PathResults()
        try:
            self.r.prepare(self.g)
        except:
            self.fail('Path result preparation failed')


    def test_reset(self):
        self.test_prepare()
        try:
            self.r.reset()
        except:
            self.fail('Path result resetting failed')

    def test_update_trace(self):
        self.test_prepare()
        try:
            self.r.reset()
        except:
            self.fail('Path result resetting failed')

        path_computation(origin, dest, self.g, self.r)

        if list(self.r.path) != [53, 52, 13]:
            self.fail('Path computation failed. Wrong sequence of links')

        if list(self.r.path_nodes) != [5, 168, 166, 27]:
            self.fail('Path computation failed. Wrong sequence of path nodes')

        if list(self.r.milepost) != [0, 341, 1398, 2162]:
            self.fail('Path computation failed. Wrong milepost results')
class DesireLinesProcedure(WorkerThread):
    def __init__(self, parentThread, layer, id_field, matrix, matrix_hash, dl_type):
        WorkerThread.__init__(self, parentThread)
        self.layer = layer
        self.id_field = id_field
        self.matrix = matrix
        self.dl_type = dl_type
        self.error = None
        self.matrix_hash = matrix_hash
        self.report = []
        self.nodes_to_indices = {matrix.index[x]: x for x in range(matrix.zones)}
        self.python_version = (8 * struct.calcsize("P"))

        if error:
            self.error = 'Scipy and/or Numpy not installed'
            self.report.append(self.error)
        self.procedure = "ASSIGNMENT"

    def doWork(self):
        if self.error is None:
            # In case we have only one class

            unnasigned = 0
            classes = self.matrix.matrix_view.shape[2]

            layer = get_vector_layer_by_name(self.layer)
            idx = layer.fieldNameIndex(self.id_field)
            feature_count = layer.featureCount()
            self.emit(SIGNAL("desire_lines"), ('job_size_dl', feature_count))

            all_centroids = {}
            P = 0
            for feat in layer.getFeatures():
                P += 1
                self.emit(SIGNAL("desire_lines"), ('jobs_done_dl', P))
                self.emit(SIGNAL("desire_lines"), ('text_dl',"Loading Layer Features: " + str(P) + "/" + str(feature_count)))
                geom = feat.geometry()
                if geom is not None:
                    point = list(geom.centroid().asPoint())
                    centroid_id = feat.attributes()[idx]
                    all_centroids[centroid_id] = point

            #Creating resulting layer
            EPSG_code = int(layer.crs().authid().split(":")[1])

            desireline_layer = QgsVectorLayer("LineString?crs=epsg:" + str(EPSG_code), self.dl_type, "memory")
            dlpr = desireline_layer.dataProvider()
            fields = [QgsField("link_id", QVariant.Int),
                              QgsField("A_Node", QVariant.Int),
                              QgsField("B_Node", QVariant.Int),
                              QgsField("direct", QVariant.Int),
                              QgsField("distance",  QVariant.Double)]
            for f in self.matrix.view_names:
                fields.extend([QgsField(f + '_ab',  QVariant.Double),
                              QgsField(f + '_ba',  QVariant.Double),
                              QgsField(f + '_tot',  QVariant.Double)])

            dlpr.addAttributes(fields)
            desireline_layer.updateFields()

            if self.dl_type == "DesireLines":
                self.emit(SIGNAL("desire_lines"), ('text_dl',"Creating Desire Lines"))
                self.emit(SIGNAL("desire_lines"), ('job_size_dl', self.matrix.zones ** 2 / 2))

                desireline_link_id = 1
                q = 0
                all_features = []
                for i in range(self.matrix.zones):
                    a_node = self.matrix.index[i]
                    if a_node in all_centroids.keys():
                        if np.sum(self.matrix.matrix_view[i, :, :]) + np.sum(self.matrix.matrix_view[:, i, :]) > 0:
                            columns_with_filled_cells = np.nonzero(np.sum(self.matrix.matrix_view[i, :, :], axis=1))
                            for j in columns_with_filled_cells[0]:
                                if np.sum(self.matrix.matrix_view[i, j, :]) + np.sum(self.matrix.matrix_view[j, i, :]) > 0:
                                    b_node = self.matrix.index[j]
                                    if a_node in all_centroids.keys() and b_node in all_centroids.keys():
                                        a_point = all_centroids[a_node]
                                        a_point = QgsPoint(a_point[0], a_point[1])
                                        b_point = all_centroids[b_node]
                                        b_point = QgsPoint(b_point[0], b_point[1])
                                        dist = QgsGeometry().fromPoint(a_point).distance(QgsGeometry().fromPoint(b_point))
                                        feature = QgsFeature()
                                        feature.setGeometry(QgsGeometry.fromPolyline([a_point, b_point]))
                                        attrs = [desireline_link_id, int(a_node), int(b_node), 0, dist]
                                        for c in range(classes):
                                            attrs.extend([float(self.matrix.matrix_view[i, j, c]),
                                                          float(self.matrix.matrix_view[j, i, c]),
                                                           float(self.matrix.matrix_view[i, j, c]) +
                                                          float(self.matrix.matrix_view[j, i, c])])

                                        feature.setAttributes(attrs)
                                        all_features.append(feature)
                                        desireline_link_id += 1
                                    else:
                                        tu = (a_node, b_node, np.sum(self.matrix.matrix_view[i, j, :]),
                                              np.sum(self.matrix.matrix_view[j, i, :]))
                                        self.report.append('No centroids available to depict flow between node {0} and node'
                                                           '{1}. Total AB flow was equal to {2} and total BA flow was '
                                                           'equal to {3}'.format(*tu))
                                        unnasigned += np.sum(self.matrix.matrix_view[i, j, :]) + \
                                                      np.sum(self.matrix.matrix_view[j, i, :])
                    else:
                        tu = (a_node, np.sum(self.matrix.matrix_view[i, :, :]))
                        self.report.append('No centroids available to depict flows from node {0} to all the others.'
                                           'Total flow from this zone is equal to {1}'.format(*tu))
                        unnasigned += np.sum(self.matrix.matrix_view[i, :, :])


                    q += self.matrix.zones
                    self.emit(SIGNAL("desire_lines"), ('jobs_done_dl', q))
                if unnasigned > 0:
                    self.report.append('Total non assigned flows (not counting intrazonals):' + str(unnasigned))

                if desireline_link_id > 1:
                    a = dlpr.addFeatures(all_features)
                    self.result_layer = desireline_layer
                else:
                    self.report.append('Nothing to show')

            elif self.dl_type == "DelaunayLines":

                self.emit(SIGNAL("desire_lines"), ('text_dl', "Building Delaunay dataset"))
                points = []
                node_id_in_delaunay_results = {}
                i = 0
                self.emit(SIGNAL("desire_lines"), ('job_size_dl', len(all_centroids)))
                for k, v in all_centroids.iteritems():
                    self.emit(SIGNAL("desire_lines"), ('jobs_done_dl', i))
                    points.append(v)
                    node_id_in_delaunay_results[i] = k
                    i += 1

                self.emit(SIGNAL("desire_lines"), ('text_dl', "Computing Delaunay Triangles"))
                tri = Delaunay(np.array(points))

                # We process all the triangles to only get each edge once
                self.emit(SIGNAL("desire_lines"), ('text_dl', "Building Delaunay Network: Collecting Edges"))
                edges = []
                if self.python_version == 32:
                    all_edges = tri.vertices
                else:
                    all_edges = tri.simplices

                self.emit(SIGNAL("desire_lines"), ('job_size_dl', len(all_edges)))
                for j, triangle in enumerate(all_edges):
                    self.emit(SIGNAL("desire_lines"), ('jobs_done_dl', j))
                    links = list(itertools.combinations(triangle, 2))
                    for i in links:
                        edges.append([min(i[0],i[1]), max(i[0],i[1])])

                self.emit(SIGNAL("desire_lines"), ('text_dl', "Building Delaunay Network: Getting unique edges"))
                edges = OrderedDict((str(x), x) for x in edges).values()

                # Writing Delaunay layer
                self.emit(SIGNAL("desire_lines"), ('text_dl', "Building Delaunay Network: Assembling Layer"))

                desireline_link_id = 1
                data = []
                dl_ids_on_links = {}
                self.emit(SIGNAL("desire_lines"), ('job_size_dl', len(edges)))
                for j, edge in enumerate(edges):
                    self.emit(SIGNAL("desire_lines"), ('jobs_done_dl', j))
                    a_node = node_id_in_delaunay_results[edge[0]]
                    a_point = all_centroids[a_node]
                    a_point = QgsPoint(a_point[0], a_point[1])
                    b_node = node_id_in_delaunay_results[edge[1]]
                    b_point = all_centroids[b_node]
                    b_point = QgsPoint(b_point[0], b_point[1])
                    dist = QgsGeometry().fromPoint(a_point).distance(QgsGeometry().fromPoint(b_point))
                    line = []
                    line.append(desireline_link_id)
                    line.append(a_node)
                    line.append(b_node)
                    line.append(dist)
                    line.append(dist)
                    line.append(0)
                    data.append(line)
                    dl_ids_on_links[desireline_link_id] = [a_node, b_node, 0, dist]
                    desireline_link_id += 1

                self.emit(SIGNAL("desire_lines"), ('text_dl', "Building graph"))
                network = np.asarray(data)
                del data

                #types for the network
                self.graph = Graph()
                itype = self.graph.default_types('int')
                ftype = self.graph.default_types('float')
                all_types = [itype, itype, itype, ftype, ftype, np.int8]
                all_titles = ['link_id', 'a_node', 'b_node', 'distance_ab', 'distance_ba', 'direction']
                dt = [(t, d) for t, d in zip(all_titles, all_types)]
                self.graph.network = np.zeros(network.shape[0], dtype=dt)

                for k, t in enumerate(dt):
                    self.graph.network[t[0]] = network[:, k].astype(t[1])
                del network

                self.graph.type_loaded = 'NETWORK'
                self.graph.status = 'OK'
                self.graph.network_ok = True
                try:
                    self.graph.prepare_graph(self.matrix.index.astype(np.int64))
                    self.graph.set_graph(cost_field='distance', skim_fields=False, block_centroid_flows=False)

                    self.results = AssignmentResults()
                    self.results.prepare(self.graph, self.matrix)
                    self.emit(SIGNAL("desire_lines"), ('text_dl', "Assigning demand"))
                    self.emit(SIGNAL("desire_lines"), ('job_size_dl', self.matrix.index.shape[0]))

                    assigner = allOrNothing(self.matrix, self.graph, self.results)
                    assigner.execute()
                    self.report = assigner.report
                    self.emit(SIGNAL("desire_lines"), ('text_dl', "Collecting results"))
                    link_loads = self.results.save_to_disk()
                    self.emit(SIGNAL("desire_lines"), ('text_dl', "Building resulting layer"))
                    features = []
                    max_edges = len(edges)
                    self.emit(SIGNAL("desire_lines"), ('job_size_dl', max_edges))

                    for i, link_id in enumerate(link_loads.index):
                        self.emit(SIGNAL("desire_lines"), ('jobs_done_dl', i))
                        a_node, b_node, direct, dist = dl_ids_on_links[link_id]

                        attr = [int(link_id), a_node, b_node, direct, dist]

                        a_point = all_centroids[a_node]
                        a_point = QgsPoint(a_point[0], a_point[1])
                        b_point = all_centroids[b_node]
                        b_point = QgsPoint(b_point[0], b_point[1])

                        feature = QgsFeature()
                        feature.setGeometry(QgsGeometry.fromPolyline([a_point, b_point]))

                        for c in self.matrix.view_names:
                            attr.extend([float(link_loads.data[c + '_ab'][i]),
                                         float(link_loads.data[c + '_ba'][i]),
                                         float(link_loads.data[c + '_tot'][i])])
                        feature.setAttributes(attr)
                        features.append(feature)
                    a = dlpr.addFeatures(features)
                    self.result_layer = desireline_layer
                except ValueError as error:
                    self.report = [error.message]

        self.emit(SIGNAL("desire_lines"), ('finished_desire_lines_procedure', 0))
Example #13
0
class TestGraph(TestCase):
    def test_create_from_geography(self):
        self.graph = Graph()
        self.graph.create_from_geography(
            test_network,
            "link_id",
            "dir",
            "distance",
            centroids=centroids,
            skim_fields=[],
            anode="A_NODE",
            bnode="B_NODE",
        )
        self.graph.set_graph(cost_field="distance", block_centroid_flows=True)

    def test_load_network_from_csv(self):
        pass

    def test_prepare_graph(self):
        self.test_create_from_geography()
        self.graph.prepare_graph(centroids)

        reference_graph = Graph()
        reference_graph.load_from_disk(test_graph)
        if not np.array_equal(self.graph.graph, reference_graph.graph):
            self.fail("Reference graph and newly-prepared graph are not equal")

    def test_set_graph(self):
        self.test_prepare_graph()
        self.graph.set_graph(cost_field="distance", block_centroid_flows=True)
        if self.graph.num_zones != centroids.shape[0]:
            self.fail("Number of centroids not properly set")
        if self.graph.num_links != 222:
            self.fail("Number of links not properly set")
        if self.graph.num_nodes != 93:
            self.fail("Number of nodes not properly set - " + str(self.graph.num_nodes))

    def test_save_to_disk(self):
        self.test_create_from_geography()
        self.graph.save_to_disk(join(path_test, "aequilibrae_test_graph.aeg"))
        self.graph_id = self.graph.__id__
        self.graph_version = self.graph.__version__

    def test_load_from_disk(self):
        self.test_save_to_disk()
        reference_graph = Graph()
        reference_graph.load_from_disk(test_graph)

        new_graph = Graph()
        new_graph.load_from_disk(join(path_test, "aequilibrae_test_graph.aeg"))

        comparisons = [
            ("Graph", new_graph.graph, reference_graph.graph),
            ("b_nodes", new_graph.b_node, reference_graph.b_node),
            ("Forward-Star", new_graph.fs, reference_graph.fs),
            ("cost", new_graph.cost, reference_graph.cost),
            ("centroids", new_graph.centroids, reference_graph.centroids),
            ("skims", new_graph.skims, reference_graph.skims),
            ("link ids", new_graph.ids, reference_graph.ids),
            ("Network", new_graph.network, reference_graph.network),
            ("All Nodes", new_graph.all_nodes, reference_graph.all_nodes),
            (
                "Nodes to indices",
                new_graph.nodes_to_indices,
                reference_graph.nodes_to_indices,
            ),
        ]

        for comparison, newg, refg in comparisons:
            if not np.array_equal(newg, refg):
                self.fail(
                    "Reference %s and %s created and saved to disk are not equal"
                    % (comparison, comparison)
                )

        comparisons = [
            ("nodes", new_graph.num_nodes, reference_graph.num_nodes),
            ("links", new_graph.num_links, reference_graph.num_links),
            ("zones", new_graph.num_zones, reference_graph.num_zones),
            (
                "block through centroids",
                new_graph.block_centroid_flows,
                reference_graph.block_centroid_flows,
            ),
            ("Graph ID", new_graph.__id__, self.graph_id),
            ("Graph Version", new_graph.__version__, self.graph_version),
        ]

        for comparison, newg, refg in comparisons:
            if newg != refg:
                self.fail(
                    "Reference %s and %s created and saved to disk are not equal"
                    % (comparison, comparison)
                )

    def test_reset_single_fields(self):
        pass

    def test_add_single_field(self):
        pass

    def test_available_skims(self):
        self.test_set_graph()
        if self.graph.available_skims() != ["distance"]:
            self.fail("Skim availability with problems")
Example #14
0
class TestGraph(TestCase):
    def test_create_from_geography(self):
        self.graph = Graph()
        self.graph.create_from_geography(
            test_network,
            "link_id",
            "dir",
            "distance",
            centroids=centroids,
            skim_fields=[],
            anode="A_NODE",
            bnode="B_NODE",
        )
        self.graph.set_graph(cost_field="distance")
        self.graph.set_blocked_centroid_flows(block_centroid_flows=True)
        self.graph.set_skimming("distance")

    def test_prepare_graph(self):
        self.test_create_from_geography()
        self.graph.prepare_graph(centroids)

        reference_graph = Graph()
        reference_graph.load_from_disk(test_graph)
        if not np.array_equal(self.graph.graph, reference_graph.graph):
            self.fail("Reference graph and newly-prepared graph are not equal")

    def test_set_graph(self):
        self.test_prepare_graph()
        self.graph.set_graph(cost_field="distance")
        self.graph.set_blocked_centroid_flows(block_centroid_flows=True)
        if self.graph.num_zones != centroids.shape[0]:
            self.fail("Number of centroids not properly set")
        if self.graph.num_links != 222:
            self.fail("Number of links not properly set")
        if self.graph.num_nodes != 93:
            self.fail("Number of nodes not properly set - " +
                      str(self.graph.num_nodes))

    def test_save_to_disk(self):
        self.test_create_from_geography()
        self.graph.save_to_disk(join(path_test, "aequilibrae_test_graph.aeg"))
        self.graph_id = self.graph.__id__
        self.graph_version = self.graph.__version__

    def test_load_from_disk(self):
        self.test_save_to_disk()
        reference_graph = Graph()
        reference_graph.load_from_disk(test_graph)

        new_graph = Graph()
        new_graph.load_from_disk(join(path_test, "aequilibrae_test_graph.aeg"))

        comparisons = [
            ("Graph", new_graph.graph, reference_graph.graph),
            ("b_nodes", new_graph.b_node, reference_graph.b_node),
            ("Forward-Star", new_graph.fs, reference_graph.fs),
            ("cost", new_graph.cost, reference_graph.cost),
            ("centroids", new_graph.centroids, reference_graph.centroids),
            ("skims", new_graph.skims, reference_graph.skims),
            ("link ids", new_graph.ids, reference_graph.ids),
            ("Network", new_graph.network, reference_graph.network),
            ("All Nodes", new_graph.all_nodes, reference_graph.all_nodes),
            ("Nodes to indices", new_graph.nodes_to_indices,
             reference_graph.nodes_to_indices),
        ]

        for comparison, newg, refg in comparisons:
            if not np.array_equal(newg, refg):
                self.fail(
                    "Reference %s and %s created and saved to disk are not equal"
                    % (comparison, comparison))

        comparisons = [
            ("nodes", new_graph.num_nodes, reference_graph.num_nodes),
            ("links", new_graph.num_links, reference_graph.num_links),
            ("zones", new_graph.num_zones, reference_graph.num_zones),
            ("block through centroids", new_graph.block_centroid_flows,
             reference_graph.block_centroid_flows),
            ("Graph ID", new_graph.__id__, self.graph_id),
            ("Graph Version", new_graph.__version__, self.graph_version),
        ]

        for comparison, newg, refg in comparisons:
            if newg != refg:
                self.fail(
                    "Reference %s and %s created and saved to disk are not equal"
                    % (comparison, comparison))

    def test_available_skims(self):
        self.test_set_graph()
        if self.graph.available_skims() != ["distance"]:
            self.fail("Skim availability with problems")

    def test_exclude_links(self):
        p = Project()
        p.load(siouxfalls_project)
        p.network.build_graphs()

        g = p.network.graphs['c']  # type: Graph

        # excludes a link before any setting or preparation
        g.exclude_links([12])

        g.set_graph('distance')
        r1 = PathResults()
        r1.prepare(g)
        r1.compute_path(1, 14)
        self.assertEqual(list(r1.path), [2, 6, 10, 34])

        # We exclude one link that we know was part of the last shortest path
        g.exclude_links([10])
        r2 = PathResults()
        r2.prepare(g)
        r2.compute_path(1, 14)
        self.assertEqual(list(r2.path), [2, 7, 36, 34])

        p.conn.close()
Example #15
0
class TrafficAssignmentDialog(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, iface):
        QtWidgets.QDialog.__init__(self)
        self.iface = iface
        self.setupUi(self)
        self.path = standard_path()
        self.output_path = None
        self.temp_path = None
        self.error = None
        self.report = None
        self.method = {}
        self.matrices = OrderedDict()
        self.skims = []
        self.matrix = None
        self.graph = Graph()
        self.results = AssignmentResults()
        self.block_centroid_flows = None
        self.worker_thread = None

        # Signals for the matrix_procedures tab
        self.but_load_new_matrix.clicked.connect(self.find_matrices)

        # Signals from the Network tab
        self.load_graph_from_file.clicked.connect(self.load_graph)

        # Signals for the algorithm tab
        self.progressbar0.setVisible(False)
        self.progressbar0.setValue(0)
        self.progress_label0.setVisible(False)

        self.do_assignment.clicked.connect(self.run)
        self.cancel_all.clicked.connect(self.exit_procedure)
        self.select_output_folder.clicked.connect(self.choose_folder_for_outputs)

        self.cb_choose_algorithm.addItem('All-Or-Nothing')
        self.cb_choose_algorithm.currentIndexChanged.connect(self.changing_algorithm)

        # slots for skim tab
        self.but_build_query.clicked.connect(partial(self.build_query, 'select link'))

        self.changing_algorithm()

        # path file
        self.path_file = OutputType()

        # Queries
        tables = [self.select_link_list, self.list_link_extraction]
        for table in tables:
            table.setColumnWidth(0, 280)
            table.setColumnWidth(1, 40)
            table.setColumnWidth(2, 150)
            table.setColumnWidth(3, 40)

        self.graph_properties_table.setColumnWidth(0, 190)
        self.graph_properties_table.setColumnWidth(1, 240)

        # critical link
        self.but_build_query.clicked.connect(partial(self.build_query, 'select link'))
        self.do_select_link.stateChanged.connect(self.set_behavior_special_analysis)
        self.tot_crit_link_queries = 0
        self.critical_output = OutputType()

        # link flow extraction
        self.but_build_query_extract.clicked.connect(partial(self.build_query, 'Link flow extraction'))
        self.do_extract_link_flows.stateChanged.connect(self.set_behavior_special_analysis)
        self.tot_link_flow_extract = 0
        self.link_extract = OutputType()

        # Disabling resources not yet implemented
        self.do_select_link.setEnabled(False)
        self.but_build_query.setEnabled(False)
        self.select_link_list.setEnabled(False)
        self.skim_list_table.setEnabled(False)

        self.do_extract_link_flows.setEnabled(False)
        self.but_build_query_extract.setEnabled(False)
        self.list_link_extraction.setEnabled(False)
        self.new_matrix_to_assign()

        self.table_matrix_list.setColumnWidth(0, 135)
        self.table_matrix_list.setColumnWidth(1, 135)
        self.table_matrices_to_assign.setColumnWidth(0, 125)
        self.table_matrices_to_assign.setColumnWidth(1, 125)
        self.skim_list_table.setColumnWidth(0, 70)
        self.skim_list_table.setColumnWidth(1, 490)

    def choose_folder_for_outputs(self):
        new_name = GetOutputFolderName(self.path, 'Output folder for traffic assignment')
        if new_name:
            self.output_path = new_name
            self.lbl_output.setText(new_name)
        else:
            self.output_path = None
            self.lbl_output.setText(new_name)

    def load_graph(self):
        self.lbl_graphfile.setText('')

        file_types = ["AequilibraE graph(*.aeg)"]
        default_type = '.aeg'
        box_name = 'Traffic Assignment'
        graph_file, _ = GetOutputFileName(self, box_name, file_types, default_type, self.path)

        if graph_file is not None:
            self.graph.load_from_disk(graph_file)

            fields = list(set(self.graph.graph.dtype.names) - set(self.graph.required_default_fields))
            self.minimizing_field.addItems(fields)
            self.update_skim_list(fields)
            self.lbl_graphfile.setText(graph_file)

            cores = get_parameter_chain(['system', 'cpus'])
            self.results.set_cores(cores)

            # show graph properties
            def centers_item(qt_item):
                cell_widget = QWidget()
                lay_out = QHBoxLayout(cell_widget)
                lay_out.addWidget(qt_item)
                lay_out.setAlignment(Qt.AlignCenter)
                lay_out.setContentsMargins(0, 0, 0, 0)
                cell_widget.setLayout(lay_out)
                return cell_widget

            items = [['Graph ID', self.graph.__id__],
                     ['Number of links', self.graph.num_links],
                     ['Number of nodes', self.graph.num_nodes],
                     ['Number of centroids', self.graph.num_zones]]

            self.graph_properties_table.clearContents()
            self.graph_properties_table.setRowCount(5)
            for i, item in enumerate(items):
                self.graph_properties_table.setItem(i, 0, QTableWidgetItem(item[0]))
                self.graph_properties_table.setItem(i, 1, QTableWidgetItem(str(item[1])))

            self.graph_properties_table.setItem(4, 0, QTableWidgetItem('Block flows through centroids'))
            self.block_centroid_flows = QCheckBox()
            self.block_centroid_flows.setChecked(self.graph.block_centroid_flows)
            self.graph_properties_table.setCellWidget(4, 1, centers_item(self.block_centroid_flows))
        else:
            self.graph = Graph()
        self.set_behavior_special_analysis()

    def changing_algorithm(self):
        if self.cb_choose_algorithm.currentText() == 'All-Or-Nothing':
            self.method['algorithm'] = 'AoN'

    def run_thread(self):
        self.worker_thread.assignment.connect(self.signal_handler)
        # QObject.connect(self.worker_thread, SIGNAL("assignment"), self.signal_handler)
        self.worker_thread.start()
        self.exec_()

    def job_finished_from_thread(self):
        self.report = self.worker_thread.report
        self.produce_all_outputs()

        self.exit_procedure()

    def run(self):
        if self.check_data():
            self.set_output_names()
            self.progress_label0.setVisible(True)
            self.progressbar0.setVisible(True)
            self.progressbar0.setRange(0, self.graph.num_zones)
            try:
                if self.method['algorithm'] == 'AoN':
                    self.worker_thread = allOrNothing(self.matrix, self.graph, self.results)
                self.run_thread()
            except ValueError as error:
                qgis.utils.iface.messageBar().pushMessage("Input error", error.message, level=3)
        else:
            qgis.utils.iface.messageBar().pushMessage("Input error", self.error, level=3)

    def set_output_names(self):
        self.path_file.temp_file = os.path.join(self.temp_path, 'path_file.aed')
        self.path_file.output_name = os.path.join(self.output_path, 'path_file')
        self.path_file.extension = 'aed'

        if self.do_path_file.isChecked():
            self.results.setSavePathFile(save=True, path_result=self.path_file.temp_file)

        self.link_extract.temp_file = os.path.join(self.temp_path, 'link_extract')
        self.link_extract.output_name = os.path.join(self.output_path, 'link_extract')
        self.link_extract.extension = 'aed'

        self.critical_output.temp_file = os.path.join(self.temp_path, 'critical_output')
        self.critical_output.output_name = os.path.join(self.output_path, 'critical_output')
        self.critical_output.extension = 'aed'

    def check_data(self):
        self.error = None

        self.change_graph_settings()

        if not self.graph.num_links:
            self.error = 'Graph was not loaded'
            return False

        self.matrix = None
        if not self.prepare_assignable_matrices():
            return False

        if self.matrix is None:
            self.error = 'Demand matrix missing'
            return False

        if self.output_path is None:
            self.error = 'Parameters for output missing'
            return False

        self.temp_path = os.path.join(self.output_path, 'temp')
        if not os.path.exists(self.temp_path):
            os.makedirs(self.temp_path)

        self.results.prepare(self.graph, self.matrix)
        return True

    def load_assignment_queries(self):
        # First we load the assignment queries
        query_labels = []
        query_elements = []
        query_types = []
        if self.tot_crit_link_queries:
            for i in range(self.tot_crit_link_queries):
                links = eval(self.select_link_list.item(i, 0).text())
                query_type = self.select_link_list.item(i, 1).text()
                query_name = self.select_link_list.item(i, 2).text()

                for l in links:
                    d = directions_dictionary[l[1]]
                    lk = self.graph.ids[(self.graph.graph['link_id'] == int(l[0])) &
                                        (self.graph.graph['direction'] == d)]

                query_labels.append(query_name)
                query_elements.append(lk)
                query_types.append(query_type)

        self.critical_queries = {'labels': query_labels,
                                 'elements': query_elements,
                                 ' type': query_types}

    def signal_handler(self, val):
        if val[0] == 'zones finalized':
            self.progressbar0.setValue(val[1])
        elif val[0] == 'text AoN':
            self.progress_label0.setText(val[1])
        elif val[0] == 'finished_threaded_procedure':
            self.job_finished_from_thread()

    # TODO: Write code to export skims
    def produce_all_outputs(self):

        extension = 'aed'
        if not self.do_output_to_aequilibrae.isChecked():
            extension = 'csv'
            if self.do_output_to_sqlite.isChecked():
                extension = 'sqlite'

        # Save link flows to disk
        self.results.save_to_disk(os.path.join(self.output_path, 'link_flows.' + extension), output='loads')

        # save Path file if that is the case
        if self.do_path_file.isChecked():
            if self.method['algorithm'] == 'AoN':
                if self.do_output_to_sqlite.isChecked():
                    self.results.save_to_disk(file_name=os.path.join(self.output_path, 'path_file.' + extension),
                                              output='path_file')

        # Saves output skims
        if self.skim_list_table.rowCount() > 0:
            self.results.skims.copy(os.path.join(self.output_path, 'skims.aem'))

        # if self.do_select_link.isChecked():
        #     if self.method['algorithm'] == 'AoN':
        #         del(self.results.critical_links['results'])
        #         self.results.critical_links = None
        #
        #         shutil.move(self.critical_output.temp_file + '.aep', self.critical_output.output_name)
        #         shutil.move(self.critical_output.temp_file + '.aed', self.critical_output.output_name[:-3] + 'aed')
        #
        # if self.do_extract_link_flows.isChecked():
        #     if self.method['algorithm'] == 'AoN':
        #         del(self.results.link_extraction['results'])
        #         self.results.link_extraction = None
        #
        #         shutil.move(self.link_extract.temp_file + '.aep', self.link_extract.output_name)
        #         shutil.move(self.link_extract.temp_file + '.aed', self.link_extract.output_name[:-3] + 'aed')

    # Procedures related to critical analysis. Not yet fully implemented
    def build_query(self, purpose):
        if purpose == 'select link':
            button = self.but_build_query
            message = 'Select Link Analysis'
            table = self.select_link_list
            counter = self.tot_crit_link_queries
        else:
            button = self.but_build_query_extract
            message = 'Link flow extraction'
            table = self.list_link_extraction
            counter = self.tot_link_flow_extract

        button.setEnabled(False)
        dlg2 = LoadSelectLinkQueryBuilderDialog(self.iface, self.graph.graph, message)
        dlg2.exec_()

        if dlg2.links is not None:
            table.setRowCount(counter + 1)
            text = ''
            for i in dlg2.links:
                text = text + ', (' + only_str(i[0]) + ', "' + only_str(i[1]) + '")'
            text = text[2:]
            table.setItem(counter, 0, QTableWidgetItem(text))
            table.setItem(counter, 1, QTableWidgetItem(dlg2.query_type))
            table.setItem(counter, 2, QTableWidgetItem(dlg2.query_name))
            del_button = QPushButton('X')
            del_button.clicked.connect(partial(self.click_button_inside_the_list, purpose))
            table.setCellWidget(counter, 3, del_button)
            counter += 1

        if purpose == 'select link':
            self.tot_crit_link_queries = counter

        elif purpose == 'Link flow extraction':
            self.tot_link_flow_extract = counter

        button.setEnabled(True)

    def click_button_inside_the_list(self, purpose):
        if purpose == 'select link':
            table = self.select_link_list
        else:
            table = self.list_link_extraction

        button = self.sender()
        index = self.select_link_list.indexAt(button.pos())
        row = index.row()
        table.removeRow(row)

        if purpose == 'select link':
            self.tot_crit_link_queries -= 1
        elif purpose == 'Link flow extraction':
            self.tot_link_flow_extract -= 1

    def set_behavior_special_analysis(self):
        if self.graph.num_links < 1:
            behavior = False
        else:
            behavior = True

        self.do_path_file.setEnabled(behavior)

        # This line of code turns off the features of select link analysis and link flow extraction while these
        # features are still being developed
        behavior = False

        self.do_select_link.setEnabled(behavior)
        self.do_extract_link_flows.setEnabled(behavior)

        self.but_build_query.setEnabled(behavior * self.do_select_link.isChecked())
        self.select_link_list.setEnabled(behavior * self.do_select_link.isChecked())

        self.list_link_extraction.setEnabled(behavior * self.do_extract_link_flows.isChecked())
        self.but_build_query_extract.setEnabled(behavior * self.do_extract_link_flows.isChecked())

    def update_skim_list(self, skims):
        self.skim_list_table.clearContents()
        self.skim_list_table.setRowCount(len(skims))

        for i, skm in enumerate(skims):
            self.skim_list_table.setItem(i, 1, QTableWidgetItem(skm))
            chb = QCheckBox()
            my_widget = QWidget()
            lay_out = QHBoxLayout(my_widget)
            lay_out.addWidget(chb)
            lay_out.setAlignment(Qt.AlignCenter)
            lay_out.setContentsMargins(0, 0, 0, 0)
            my_widget.setLayout(lay_out)

            self.skim_list_table.setCellWidget(i, 0, my_widget)

    # All Matrix loading and assignables selection
    def update_matrix_list(self):
        self.table_matrix_list.clearContents()
        self.table_matrix_list.clearContents()
        self.table_matrix_list.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table_matrix_list.setRowCount(len(self.matrices.keys()))

        for i, data_name in enumerate(self.matrices.keys()):
            self.table_matrix_list.setItem(i, 0, QTableWidgetItem(data_name))

            cbox = QComboBox()
            for idx in self.matrices[data_name].index_names:
                cbox.addItem(str(idx))
            self.table_matrix_list.setCellWidget(i, 1, cbox)

    def find_matrices(self):
        dlg2 = LoadMatrixDialog(self.iface)
        dlg2.show()
        dlg2.exec_()
        if dlg2.matrix is not None:
            matrix_name = dlg2.matrix.file_path
            matrix_name = os.path.splitext(os.path.basename(matrix_name))[0]
            matrix_name = self.find_non_conflicting_name(matrix_name, self.matrices)
            self.matrices[matrix_name] = dlg2.matrix
            self.update_matrix_list()

            row_count = self.table_matrices_to_assign.rowCount()
            new_matrix = list(self.matrices.keys())[-1]

            for i in range(row_count):
                cb = self.table_matrices_to_assign.cellWidget(i, 0)
                cb.insertItem(-1, new_matrix)

    def find_non_conflicting_name(self, data_name, dictio):
        if data_name in dictio:
            i = 1
            new_data_name = data_name + '_' + str(i)
            while new_data_name in dictio:
                i += 1
                new_data_name = data_name + '_' + str(i)
            data_name = new_data_name
        return data_name

    def changed_assignable_matrix(self, mi):
        chb = self.sender()
        mat_name = chb.currentText()

        table = self.table_matrices_to_assign
        for row in range(table.rowCount()):
            if table.cellWidget(row, 0) == chb:
                break

        if len(mat_name) == 0:
            if row + 1 < table.rowCount():
                self.table_matrices_to_assign.removeRow(row)
        else:
            mat_cores = self.matrices[mat_name].names
            cbox2 = QComboBox()
            cbox2.addItems(mat_cores)
            self.table_matrices_to_assign.setCellWidget(row, 1, cbox2)

            if row + 1 == table.rowCount():
                self.new_matrix_to_assign()

    def new_matrix_to_assign(self):
        # We edit ALL the combo boxes to have the current list of matrices
        row_count = self.table_matrices_to_assign.rowCount()
        self.table_matrices_to_assign.setRowCount(row_count + 1)

        cbox = QComboBox()
        cbox.addItems(list(self.matrices.keys()))
        cbox.addItem('')
        cbox.setCurrentIndex(cbox.count() - 1)
        cbox.currentIndexChanged.connect(self.changed_assignable_matrix)
        self.table_matrices_to_assign.setCellWidget(row_count, 0, cbox)

    def prepare_assignable_matrices(self):
        table = self.table_matrices_to_assign
        idx = self.graph.centroids
        mat_names = []
        if table.rowCount() > 1:
            for row in range(table.rowCount() - 1):
                mat = table.cellWidget(row, 0).currentText()
                core = table.cellWidget(row, 1).currentText()

                mat_index = self.matrices[mat].index
                if not np.array_equal(idx, mat_index):
                    no_zones = [item for item in mat_index if item not in idx]
                    # We only return an error if the matrix has too many centroids
                    if no_zones:
                        self.error = 'Assignable matrix has centroids that do not exist in the network: {}'.format(
                            ','.join([str(x) for x in no_zones]))
                        return False
                if core in mat_names:
                    self.error = 'Assignable matrices cannot have same names'
                    return False
                mat_names.append(only_str(core))

            self.matrix = AequilibraeMatrix()
            self.matrix.create_empty(file_name=self.matrix.random_name(),
                                     zones=idx.shape[0],
                                     matrix_names=mat_names)
            self.matrix.index[:] = idx[:]

            for row in range(table.rowCount() - 1):
                mat = table.cellWidget(row, 0).currentText()
                core = table.cellWidget(row, 1).currentText()
                src_mat = self.matrices[mat].matrix[core]
                dest_mat = self.matrix.matrix[core]

                rows = src_mat.shape[0]
                cols = src_mat.shape[1]
                dest_mat[:rows, :cols] = src_mat[:, :]

                # Inserts cols and rows that don;t exist
                if rows != self.matrix.zones:
                    src_index = list(self.matrices[mat].index[:])
                    for i, row in enumerate(idx):
                        if row not in src_index:
                            dest_mat[i + 1:, :] = dest_mat[i:-1, :]
                            dest_mat[i, :] = 0

                if cols != self.matrix.zones:
                    for j, col in enumerate(idx):
                        if col not in src_index:
                            dest_mat[:, j + 1:] = dest_mat[:, j:-1]
                            dest_mat[:, j] = 0

            self.matrix.computational_view()
        else:
            self.error = 'You need to have at least one matrix to assign'
            return False

        return True

    def change_graph_settings(self):
        skims = []
        table = self.skim_list_table
        for i in range(table.rowCount()):
            for chb in table.cellWidget(i, 0).findChildren(QCheckBox):
                if chb.isChecked():
                    skims.append(only_str(table.item(i, 1).text()))

        if len(skims) == 0:
            skims = False

        self.graph.set_graph(cost_field=self.minimizing_field.currentText(),
                             skim_fields=skims,
                             block_centroid_flows=self.block_centroid_flows.isChecked())

    def exit_procedure(self):
        self.close()
        if self.report:
            dlg2 = ReportDialog(self.iface, self.report)
            dlg2.show()
            dlg2.exec_()
class TestAllOrNothing(TestCase):
    def setUp(self) -> None:
        self.mat_name = AequilibraeMatrix().random_name()
        self.g = Graph()
        self.g.load_from_disk(test_graph)
        self.g.set_graph(cost_field="distance")

        # Creates the matrix for assignment
        args = {
            "file_name": os.path.join(gettempdir(), self.mat_name),
            "zones": self.g.num_zones,
            "matrix_names": ["cars", "trucks"],
            "index_names": ["my indices"],
        }

        matrix = AequilibraeMatrix()
        matrix.create_empty(**args)

        matrix.index[:] = self.g.centroids[:]
        matrix.cars.fill(1.1)
        matrix.trucks.fill(2.2)

        # Exports matrix to OMX in order to have two matrices to work with
        matrix.export(os.path.join(gettempdir(), "my_matrix.omx"))
        matrix.close()

    def test_skimming_on_assignment(self):
        matrix = AequilibraeMatrix()
        matrix.load(os.path.join(gettempdir(), self.mat_name))
        matrix.computational_view(["cars"])

        res = AssignmentResults()

        res.prepare(self.g, matrix)

        self.g.set_skimming([])
        self.g.set_blocked_centroid_flows(True)
        assig = allOrNothing(matrix, self.g, res)
        assig.execute()

        if res.skims.distance.sum() > 0:
            self.fail(
                "skimming for nothing during assignment returned something different than zero"
            )

        self.g.set_skimming("distance")
        res.prepare(self.g, matrix)

        assig = allOrNothing(matrix, self.g, res)
        assig.execute()
        if res.skims.distance.sum() != 2914644.0:
            self.fail("skimming during assignment returned the wrong value")
        matrix.close()

    def test_execute(self):
        # Loads and prepares the graph

        car_loads = []
        two_class_loads = []

        for extension in ["omx", "aem"]:
            matrix = AequilibraeMatrix()
            if extension == 'omx':
                mat_name = os.path.join(gettempdir(), "my_matrix." + extension)
            else:
                mat_name = self.mat_name
            matrix.load(mat_name)

            matrix.computational_view(["cars"])

            # Performs assignment
            res = AssignmentResults()
            res.prepare(self.g, matrix)

            assig = allOrNothing(matrix, self.g, res)
            assig.execute()
            car_loads.append(res.link_loads)
            res.save_to_disk(
                os.path.join(gettempdir(),
                             "link_loads_{}.aed".format(extension)))
            res.save_to_disk(
                os.path.join(gettempdir(),
                             "link_loads_{}.csv".format(extension)))

            matrix.computational_view()
            # Performs assignment
            res = AssignmentResults()
            res.prepare(self.g, matrix)

            assig = allOrNothing(matrix, self.g, res)
            assig.execute()
            two_class_loads.append(res.link_loads)
            res.save_to_disk(
                os.path.join(gettempdir(),
                             "link_loads_2_classes_{}.aed".format(extension)))
            res.save_to_disk(
                os.path.join(gettempdir(),
                             "link_loads_2_classes_{}.csv".format(extension)))
            matrix.close()

        load_diff = two_class_loads[0] - two_class_loads[1]
        if load_diff.max() > 0.0000000001 or load_diff.max() < -0.0000000001:
            self.fail(
                "Loads for two classes differ for OMX and AEM matrix types")

        load_diff = car_loads[0] - car_loads[1]
        if load_diff.max() > 0.0000000001 or load_diff.max() < -0.0000000001:
            self.fail(
                "Loads for a single class differ for OMX and AEM matrix types")
Example #17
0
class TestPathResults(TestCase):
    def setUp(self) -> None:
        # graph
        self.g = Graph()
        self.g.load_from_disk(test_graph)
        self.g.set_graph(cost_field="distance")

        self.r = PathResults()
        try:
            self.r.prepare(self.g)
        except Exception as err:
            self.fail("Path result preparation failed - {}".format(err.__str__()))

    def test_reset(self):
        self.r.compute_path(dest, origin)
        self.r.reset()

        self.assertEqual(self.r.path, None, 'Fail to reset the Path computation object')
        self.assertEqual(self.r.path_nodes, None, 'Fail to reset the Path computation object')
        self.assertEqual(self.r.path_link_directions, None, 'Fail to reset the Path computation object')
        self.assertEqual(self.r.milepost, None, 'Fail to reset the Path computation object')
        self.assertEqual(self.r.predecessors.max(), -1, 'Fail to reset the Path computation object')
        self.assertEqual(self.r.predecessors.min(), -1, 'Fail to reset the Path computation object')
        self.assertEqual(self.r.connectors.max(), -1, 'Fail to reset the Path computation object')
        self.assertEqual(self.r.connectors.min(), -1, 'Fail to reset the Path computation object')
        self.assertEqual(self.r.skims.max(), np.inf, 'Fail to reset the Path computation object')
        self.assertEqual(self.r.skims.min(), np.inf, 'Fail to reset the Path computation object')

        new_r = PathResults()
        with self.assertRaises(ValueError):
            new_r.reset()

    def test_compute_paths(self):

        path_computation(origin, dest, self.g, self.r)

        if list(self.r.path) != [53, 52, 13]:
            self.fail("Path computation failed. Wrong sequence of links")

        if list(self.r.path_nodes) != [5, 168, 166, 27]:
            self.fail("Path computation failed. Wrong sequence of path nodes")

        if list(self.r.milepost) != [0, 341, 1398, 2162]:
            self.fail("Path computation failed. Wrong milepost results")

        self.r.compute_path(origin, dest)

        if list(self.r.path) != [53, 52, 13]:
            self.fail("Path computation failed. Wrong sequence of links")

        if list(self.r.path_nodes) != [5, 168, 166, 27]:
            self.fail("Path computation failed. Wrong sequence of path nodes")

        if list(self.r.milepost) != [0, 341, 1398, 2162]:
            self.fail("Path computation failed. Wrong milepost results")

        if list(self.r.path_link_directions) != [-1, -1, -1]:
            self.fail("Path computation failed. Wrong link directions")

        self.r.compute_path(dest, origin)
        if list(self.r.path_link_directions) != [1, 1, 1]:
            self.fail("Path computation failed. Wrong link directions")

    def test_update_trace(self):
        self.r.compute_path(origin, dest - 1)

        self.r.update_trace(dest)

        if list(self.r.path) != [53, 52, 13]:
            self.fail("Path computation failed. Wrong sequence of links")

        if list(self.r.path_nodes) != [5, 168, 166, 27]:
            self.fail("Path computation failed. Wrong sequence of path nodes")

        if list(self.r.milepost) != [0, 341, 1398, 2162]:
            self.fail("Path computation failed. Wrong milepost results")

        if list(self.r.path_link_directions) != [-1, -1, -1]:
            self.fail("Path computation failed. Wrong link directions")
Example #18
0
class DesireLinesProcedure(WorkerThread):
    def __init__(self, parentThread, layer, id_field, matrix, dl_type):
        WorkerThread.__init__(self, parentThread)
        self.layer = layer
        self.id_field = id_field
        self.matrix = matrix
        self.dl_type = dl_type
        self.error = None
        if error:
            self.error = 'Scipy and/or Numpy not installed'
        self.procedure = "ASSIGNMENT"

    def doWork(self):
        if self.error is None:
            layer = get_vector_layer_by_name(self.layer)
            idx = layer.fieldNameIndex(self.id_field)
            matrix = self.matrix

            featcount = layer.featureCount()
            self.emit(SIGNAL("ProgressMaxValue(PyQt_PyObject)"),
                      (0, featcount))

            P = 0
            points = []
            point_ids = []
            for feat in layer.getFeatures():
                P += 1
                self.emit(SIGNAL("ProgressValue(PyQt_PyObject)"), (0, int(P)))
                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Loading Layer Features: " + str(P) + "/" +
                           str(featcount)))

                geom = feat.geometry()
                if geom is not None:
                    point = list(geom.centroid().asPoint())
                    points.append(point)
                    point_ids.append(feat.attributes()[idx])

            points = np.array(points)
            self.emit(SIGNAL("ProgressValue(PyQt_PyObject)"), (0, featcount))

            self.emit(
                SIGNAL("ProgressText (PyQt_PyObject)"),
                (0, "Preparing consistency check Matrix Vs. Zoning layer"))

            vector1 = np.nonzero(np.sum(matrix, axis=0))[0]
            vector2 = np.nonzero(np.sum(matrix, axis=1))[0]
            nonzero = np.hstack((vector1, vector2))

            self.emit(SIGNAL("ProgressValue(PyQt_PyObject)"),
                      (0, nonzero.shape[0]))
            for i, zone in enumerate(nonzero):
                if zone not in point_ids:
                    self.error = 'Zone ' + str(
                        zone) + ' with positive flow not in zoning file'
                    break
                self.emit(SIGNAL("ProgressMaxValue(PyQt_PyObject)"),
                          (0, i + 1))
            self.emit(SIGNAL("ProgressValue(PyQt_PyObject)"),
                      (0, nonzero.shape[0]))

        if self.error is None:

            #Creating resulting layer
            EPSG_code = int(layer.crs().authid().split(":")[1])

            desireline_layer = QgsVectorLayer(
                "LineString?crs=epsg:" + str(EPSG_code), self.dl_type,
                "memory")
            dlpr = desireline_layer.dataProvider()
            dlpr.addAttributes([
                QgsField("link_id", QVariant.Int),
                QgsField("A_Node", QVariant.Int),
                QgsField("B_Node", QVariant.Int),
                QgsField("direct", QVariant.Int),
                QgsField("length", QVariant.Double),
                QgsField("AB_FLOW", QVariant.Double),
                QgsField("BA_FLOW", QVariant.Double),
                QgsField("TOT_FLOW", QVariant.Double)
            ])
            desireline_layer.updateFields()

            if self.dl_type == "DesireLines":
                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Creating Desire Lines"))
                self.emit(SIGNAL("ProgressMaxValue(PyQt_PyObject)"),
                          (0, self.matrix.shape[0] * self.matrix.shape[1] / 2))

                #We create the dictionary with point information
                all_points = {}
                point_ids = np.array(point_ids).astype(np.int)
                for i in range(point_ids.shape[0]):
                    all_points[point_ids[i]] = points[i]

                # We are assuming that the matrix is square here. Maybe we could add more general code layer
                desireline_link_id = 1
                q = 0
                all_features = []
                for i in range(self.matrix.shape[0]):
                    for j in xrange(i + 1, self.matrix.shape[1]):
                        q += 1
                        self.emit(SIGNAL("ProgressValue(PyQt_PyObject)"),
                                  (0, q))
                        if self.matrix[i, j] + self.matrix[j, i] > 0:
                            a_node = i
                            a_point = QgsPoint(all_points[a_node][0],
                                               all_points[a_node][1])
                            b_node = j
                            b_point = QgsPoint(all_points[b_node][0],
                                               all_points[b_node][1])
                            dist = QgsGeometry().fromPoint(a_point).distance(
                                QgsGeometry().fromPoint(b_point))
                            feature = QgsFeature()
                            feature.setGeometry(
                                QgsGeometry.fromPolyline([a_point, b_point]))
                            feature.setAttributes([
                                desireline_link_id, a_node, b_node, 0, dist,
                                float(self.matrix[i, j]),
                                float(self.matrix[j, i]),
                                float(self.matrix[i, j] + self.matrix[j, i])
                            ])
                            all_features.append(feature)

                            desireline_link_id += 1
                a = dlpr.addFeatures(all_features)
                self.result_layer = desireline_layer

            elif self.dl_type == "DelaunayLines":
                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Computing Delaunay Triangles"))
                tri = Delaunay(points)

                #We process all the triangles to only get each edge once
                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Building Delaunay Network: Collecting Edges"))
                edges = []
                for triangle in tri.simplices:
                    links = list(itertools.combinations(triangle, 2))

                    for i in links:
                        l = [min(i[0], i[1]), max(i[0], i[1])]
                        if l not in edges:
                            edges.append(l)

                #Writing Delaunay layer
                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Building Delaunay Network: Assembling Layer"))
                desireline_link_id = 1
                data = []
                for edge in edges:
                    a_node = edge[0]
                    a_point = QgsPoint(points[a_node][0], points[a_node][1])
                    b_node = edge[1]
                    b_point = QgsPoint(points[b_node][0], points[b_node][1])
                    dist = QgsGeometry().fromPoint(a_point).distance(
                        QgsGeometry().fromPoint(b_point))
                    line = []
                    line.append(desireline_link_id)
                    line.append(point_ids[a_node])
                    line.append(point_ids[b_node])
                    line.append(dist)
                    line.append(dist)
                    line.append(0)
                    data.append(line)
                    desireline_link_id += 1

                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Building graph"))
                network = np.asarray(data)
                del data

                #types for the network
                all_types = [
                    np.int64, np.int64, np.int64, np.float64, np.float64,
                    np.int64
                ]
                all_titles = [
                    'link_id', 'a_node', 'b_node', 'length_ab', 'length_ba',
                    'direction'
                ]
                dt = [(t, d) for t, d in zip(all_titles, all_types)]

                self.graph = Graph()
                self.graph.network = np.zeros(network.shape[0], dtype=dt)

                for k, t in enumerate(dt):
                    self.graph.network[t[0]] = network[:, k].astype(t[1])
                del network

                # Here we transform the network to go from node 1 to N
                max_node = max(np.max(self.graph.network['a_node']),
                               np.max(self.graph.network['b_node']))
                max_node = max(max_node, self.matrix.shape[0],
                               self.matrix.shape[1]) + 1
                self.hash = np.zeros(max_node, np.int)

                # Checks if any zone from the matrix is not present in the areas/node layer
                t1 = np.sum(self.matrix, axis=0)
                t2 = np.sum(self.matrix, axis=1)

                if t1.shape[0] > t2.shape[0]:
                    t2.resize(t1.shape)
                elif t2.shape[0] > t1.shape[0]:
                    t1.resize(t2.shape)
                totals = t1 + t2

                all_nodes = np.bincount(self.graph.network['a_node'])
                for i in range(totals.shape[0]):
                    if totals[i]:
                        if not all_nodes[i]:
                            qgis.utils.iface.messageBar().pushMessage(
                                "Matrix has demand for zones that do not exist "
                                "in the zones/nodes provided. Demand for those"
                                "ones were ignored. e.g. " + str(i),
                                '',
                                level=3)
                            break

                h = 1
                for i in range(self.graph.network.shape[0]):
                    a_node = self.graph.network['a_node'][i]
                    if self.hash[a_node] == 0:
                        self.hash[a_node] = h
                        h += 1

                    b_node = self.graph.network['b_node'][i]
                    if self.hash[b_node] == 0:
                        self.hash[b_node] = h
                        h += 1

                    self.graph.network['a_node'][i] = self.hash[a_node]
                    self.graph.network['b_node'][i] = self.hash[b_node]
                # End of network transformation

                #Now we transform the matrix appropriately
                self.matrix = reblocks_matrix(self.matrix, self.hash, h)

                self.graph.type_loaded = 'NETWORK'
                self.graph.status = 'OK'
                self.graph.network_ok = True
                self.graph.prepare_graph()

                self.graph.set_graph(h - 1,
                                     cost_field='length',
                                     block_centroid_flows=False)
                self.results = AssignmentResults()
                self.results.prepare(self.graph)
                self.results.set_cores(1)

                # Do the assignment
                all_or_nothing(self.matrix, self.graph, self.results)

                f = self.results.link_loads[:, 0]
                link_loads = np.zeros((f.shape[0] + 1, 2))
                for i in range(f.shape[0] - 1):
                    direction = self.graph.graph['direction'][i]
                    link_id = self.graph.graph['link_id'][i]
                    flow = f[i]
                    if direction == 1:
                        link_loads[link_id, 0] = flow
                    else:
                        link_loads[link_id, 1] = flow

                desireline_link_id = 1
                for edge in edges:
                    a_node = edge[0]
                    a_point = QgsPoint(points[a_node][0], points[a_node][1])
                    b_node = edge[1]
                    b_point = QgsPoint(points[b_node][0], points[b_node][1])
                    dist = QgsGeometry().fromPoint(a_point).distance(
                        QgsGeometry().fromPoint(b_point))
                    feature = QgsFeature()
                    feature.setGeometry(
                        QgsGeometry.fromPolyline([a_point, b_point]))
                    feature.setAttributes([
                        desireline_link_id, point_ids[a_node],
                        point_ids[b_node], 0, dist,
                        float(link_loads[desireline_link_id, 0]),
                        float(link_loads[desireline_link_id, 1]),
                        float(link_loads[desireline_link_id, 0] +
                              link_loads[desireline_link_id, 1])
                    ])
                    a = dlpr.addFeatures([feature])
                    desireline_link_id += 1
                self.result_layer = desireline_layer

        self.emit(SIGNAL("finished_threaded_procedure( PyQt_PyObject )"), True)
Example #19
0
class TestGraph(TestCase):

    def test_create_from_geography(self):
        self.graph = Graph()
        self.graph.create_from_geography(
            test_network, 'link_id', 'dir', 'distance', centroids=centroids, skim_fields = [], anode="A_NODE",
            bnode="B_NODE")
        self.graph.set_graph(cost_field='distance', block_centroid_flows=True)

    def test_load_network_from_csv(self):
        pass

    def test_prepare_graph(self):
        self.test_create_from_geography()
        self.graph.prepare_graph(centroids)

        reference_graph = Graph()
        reference_graph.load_from_disk(test_graph)
        if not np.array_equal(self.graph.graph, reference_graph.graph):
            self.fail('Reference graph and newly-prepared graph are not equal')

    def test_set_graph(self):
        self.test_prepare_graph()
        self.graph.set_graph(cost_field='distance',block_centroid_flows=True)
        if self.graph.num_zones != centroids.shape[0]:
            self.fail('Number of centroids not properly set')
        if self.graph.num_links != 222:
            self.fail('Number of links not properly set')
        if self.graph.num_nodes != 93:
            self.fail('Number of nodes not properly set - ' + str(self.graph.num_nodes))

    def test_save_to_disk(self):
        self.test_create_from_geography()
        self.graph.save_to_disk(join(path_test, 'aequilibrae_test_graph.aeg'))
        self.graph_id = self.graph.__id__
        self.graph_version = self.graph.__version__

    def test_load_from_disk(self):
        self.test_save_to_disk()
        reference_graph = Graph()
        reference_graph.load_from_disk(test_graph)

        new_graph = Graph()
        new_graph.load_from_disk(join(path_test, 'aequilibrae_test_graph.aeg'))

        comparisons = [('Graph', new_graph.graph, reference_graph.graph),
                       ('b_nodes', new_graph.b_node, reference_graph.b_node),
                       ('Forward-Star', new_graph.fs, reference_graph.fs),
                       ('cost', new_graph.cost, reference_graph.cost),
                       ('centroids', new_graph.centroids, reference_graph.centroids),
                       ('skims', new_graph.skims, reference_graph.skims),
                       ('link ids', new_graph.ids, reference_graph.ids),
                       ('Network', new_graph.network, reference_graph.network),
                       ('All Nodes', new_graph.all_nodes, reference_graph.all_nodes),
                       ('Nodes to indices', new_graph.nodes_to_indices, reference_graph.nodes_to_indices)]

        for comparison, newg, refg in comparisons:
            if not np.array_equal(newg, refg):
                self.fail('Reference %s and %s created and saved to disk are not equal' %(comparison, comparison))

        comparisons = [('nodes', new_graph.num_nodes, reference_graph.num_nodes),
                       ('links', new_graph.num_links, reference_graph.num_links),
                       ('zones', new_graph.num_zones, reference_graph.num_zones),
                       ('block through centroids', new_graph.block_centroid_flows, reference_graph.block_centroid_flows),
                       ('Graph ID', new_graph.__id__, self.graph_id),
                       ('Graph Version', new_graph.__version__, self.graph_version)]

        for comparison, newg, refg in comparisons:
            if newg != refg:
                self.fail('Reference %s and %s created and saved to disk are not equal' %(comparison, comparison))

    def test_reset_single_fields(self):
        pass

    def test_add_single_field(self):
        pass

    def test_available_skims(self):
        self.test_set_graph()
        if self.graph.available_skims() != ['distance']:
            self.fail('Skim availability with problems')
Example #20
0
class ImpedanceMatrixDialog(QtGui.QDialog, FORM_CLASS):
    def __init__(self, iface):
        QDialog.__init__(self)
        self.iface = iface
        self.setupUi(self)

        self.result = SkimResults()
        self.validtypes = integer_types + float_types
        self.tot_skims = 0
        self.name_skims = 0
        self.graph = None
        self.skimmeable_fields = []
        self.skim_fields = []
        self.error = None
        # FIRST, we connect slot signals

        # For loading a new graph
        self.load_graph_from_file.clicked.connect(
            self.loaded_new_graph_from_file)

        # For adding skims
        # self.bt_add_skim.clicked.connect(self.add_to_skim_list)
        self.but_adds_to_links.clicked.connect(self.append_to_list)
        self.but_removes_from_links.clicked.connect(self.removes_fields)

        self.do_dist_matrix.clicked.connect(self.run_skimming)

        # SECOND, we set visibility for sections that should not be shown when the form opens (overlapping items)
        #        and re-dimension the items that need re-dimensioning
        self.hide_all_progress_bars()
        self.available_skims_table.setColumnWidth(0, 245)
        self.skim_list.setColumnWidth(0, 245)
        self.available_skims_table.setEditTriggers(
            QtGui.QAbstractItemView.NoEditTriggers)
        self.skim_list.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)

        # loads default path from parameters
        self.path = standard_path()

    def removes_fields(self):
        table = self.available_skims_table
        final_table = self.skim_list

        for i in final_table.selectedRanges():
            old_fields = [
                final_table.item(row, 0).text()
                for row in xrange(i.topRow(),
                                  i.bottomRow() + 1)
            ]

            for row in xrange(i.bottomRow(), i.topRow() - 1, -1):
                final_table.removeRow(row)

            counter = table.rowCount()
            for field in old_fields:
                table.setRowCount(counter + 1)
                item1 = QTableWidgetItem(field)
                item1.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
                table.setItem(counter, 0, item1)
                counter += 1

    def append_to_list(self):
        table = self.available_skims_table
        final_table = self.skim_list

        for i in table.selectedRanges():
            new_fields = [
                table.item(row, 0).text()
                for row in xrange(i.topRow(),
                                  i.bottomRow() + 1)
            ]

            for f in new_fields:
                self.skim_fields.append(f.encode('utf-8'))
            for row in xrange(i.bottomRow(), i.topRow() - 1, -1):
                table.removeRow(row)

            counter = final_table.rowCount()
            for field in new_fields:
                final_table.setRowCount(counter + 1)
                item1 = QTableWidgetItem(field)
                item1.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
                final_table.setItem(counter, 0, item1)
                counter += 1

    def hide_all_progress_bars(self):
        self.progressbar.setVisible(False)
        self.progress_label.setVisible(False)
        self.progressbar.setValue(0)
        self.progress_label.setText('')

    def loaded_new_graph_from_file(self):
        file_types = ["AequilibraE graph(*.aeg)"]

        new_name, file_type = GetOutputFileName(self, 'Graph file', file_types,
                                                ".aeg", self.path)
        self.cb_minimizing.clear()
        self.available_skims_table.clearContents()
        self.block_paths.setChecked(False)
        self.graph = None
        if new_name is not None:
            self.graph_file_name.setText(new_name)
            self.graph = Graph()
            self.graph.load_from_disk(new_name)

            self.block_paths.setChecked(self.graph.block_centroid_flows)
            graph_fields = list(self.graph.graph.dtype.names)
            self.skimmeable_fields = self.graph.available_skims()

            self.available_skims_table.setRowCount(len(self.skimmeable_fields))
            for q in self.skimmeable_fields:
                self.cb_minimizing.addItem(q)
                self.available_skims_table.setItem(0, 0, QTableWidgetItem(q))

    def browse_outfile(self):
        self.imped_results = None
        new_name, extension = GetOutputFileName(
            self, 'AequilibraE impedance computation', matrix_export_types,
            '.aem', self.path)
        if new_name is not None:
            self.imped_results = new_name.encode('utf-8')

    def run_thread(self):
        self.do_dist_matrix.setVisible(False)
        self.progressbar.setRange(0, self.graph.num_zones)
        QObject.connect(self.worker_thread, SIGNAL("skimming"),
                        self.signal_handler)
        self.worker_thread.start()
        self.exec_()

    def signal_handler(self, val):
        if val[0] == 'zones finalized':
            self.progressbar.setValue(val[1])
        elif val[0] == 'text skimming':
            self.progress_label.setText(val[1])
        elif val[0] == 'finished_threaded_procedure':
            self.finished_threaded_procedure()

    def finished_threaded_procedure(self):
        self.report = self.worker_thread.report
        self.result.skims.export(self.imped_results)
        self.exit_procedure()

    def run_skimming(self):  # Saving results

        if self.error is None:
            self.browse_outfile()
            cost_field = self.cb_minimizing.currentText().encode('utf-8')

            # We prepare the graph to set all nodes as centroids
            if self.rdo_all_nodes.isChecked():
                self.graph.prepare_graph(self.graph.all_nodes)

            self.graph.set_graph(
                cost_field=cost_field,
                skim_fields=self.skim_fields,
                block_centroid_flows=self.block_paths.isChecked())

            self.result.prepare(self.graph)

            self.funding1.setVisible(False)
            self.funding2.setVisible(False)
            self.progressbar.setVisible(True)
            self.progress_label.setVisible(True)
            self.worker_thread = NetworkSkimming(self.graph, self.result)
            try:
                self.run_thread()
            except ValueError as error:
                qgis.utils.iface.messageBar().pushMessage("Input error",
                                                          error.message,
                                                          level=3)
        else:
            qgis.utils.iface.messageBar().pushMessage("Error:",
                                                      self.error,
                                                      level=3)

    def check_inputs(self):
        self.error = None
        if self.rdo_all_nodes.isChecked() and self.block_paths.isChecked():
            self.error = 'It is not possible to trace paths between all nodes while blocking flows through centroids'

        if self.graph is None:
            self.error = 'No graph loaded'

        if len(self.skim_fields) < 1:
            self.error = 'No skim fields provided'

    def exit_procedure(self):
        self.close()
        if self.report:
            dlg2 = ReportDialog(self.iface, self.report)
            dlg2.show()
            dlg2.exec_()
Example #21
0
class DesireLinesProcedure(WorkerThread):
    def __init__(self, parentThread, layer: str, id_field: int, matrix: AequilibraeMatrix, matrix_hash: dict,
                 dl_type: str) -> None:
        WorkerThread.__init__(self, parentThread)
        self.layer = layer
        self.id_field = id_field
        self.matrix = matrix
        self.dl_type = dl_type
        self.error = None
        self.matrix_hash = matrix_hash
        self.report = []
        self.logger = logging.getLogger('aequilibrae')
        self.nodes_to_indices = {matrix.index[x]: x for x in range(matrix.zones)}
        self.python_version = (8 * struct.calcsize("P"))

        if error:
            self.error = 'Scipy and/or Numpy not installed'
            self.report.append(self.error)
        self.procedure = "ASSIGNMENT"

    def doWork(self):
        if self.error is None:
            # In case we have only one class
            unnasigned = 0
            classes = self.matrix.matrix_view.shape[2]

            layer = get_vector_layer_by_name(self.layer)
            idx = layer.dataProvider().fieldNameIndex(self.id_field)
            feature_count = layer.featureCount()
            self.desire_lines.emit(('job_size_dl', feature_count))

            all_centroids = {}
            for P, feat in enumerate(layer.getFeatures()):
                geom = feat.geometry()
                if geom is not None:
                    point = list(geom.centroid().asPoint())
                    centroid_id = feat.attributes()[idx]
                    all_centroids[centroid_id] = point
                self.desire_lines.emit(('jobs_done_dl', P))
                self.desire_lines.emit(('text_dl', "Loading Layer Features: " + str(P) + "/" + str(feature_count)))

            # Creating resulting layer
            EPSG_code = int(layer.crs().authid().split(":")[1])

            desireline_layer = QgsVectorLayer("LineString?crs=epsg:" + str(EPSG_code), self.dl_type, "memory")
            dlpr = desireline_layer.dataProvider()
            base_dl_fields = [QgsField("link_id", QVariant.Int),
                              QgsField("A_Node", QVariant.Int),
                              QgsField("B_Node", QVariant.Int),
                              QgsField("direct", QVariant.Int),
                              QgsField("distance", QVariant.Double)]

            if self.dl_type == "DesireLines":
                items = []
                for i, j in all_centroids.items():
                    items.append((i, j[0], j[1]))
                coords = np.array(items)

                coord_index = np.zeros((self.matrix.index[:].max().astype(np.int64) + 1, 2))
                coord_index[coords[:, 0].astype(np.int64), 0] = coords[:, 1]
                coord_index[coords[:, 0].astype(np.int64), 1] = coords[:, 2]

                self.desire_lines.emit(('text_dl', "Manipulating matrix indices"))
                zones = self.matrix.index[:].shape[0]
                a = np.array(self.matrix.index[:], np.int64)
                ij, ji = np.meshgrid(a, a, sparse=False, indexing='ij')
                ij = ij.flatten()
                ji = ji.flatten()

                arrays = [ij, ji]

                self.desire_lines.emit(('text_dl', "Collecting all matrices"))
                self.desire_lines.emit(('job_size_dl', len(self.matrix.view_names)))

                total_mat = np.zeros((zones, zones), np.float64)
                for i, mat in enumerate(self.matrix.view_names):
                    arrays.append(self.matrix.matrix[mat].flatten())
                    total_mat += self.matrix.matrix[mat]
                    self.desire_lines.emit(('jobs_done_dl', i + 1))

                # Eliminates the cells for which we don't have geography
                self.desire_lines.emit(('text_dl', "Filtering zones with no geography available"))
                zones_with_no_geography = [x for x in self.matrix.index[:] if x not in all_centroids]
                if zones_with_no_geography:
                    self.desire_lines.emit(('job_size_dl', len(zones_with_no_geography)))
                for k, z in enumerate(zones_with_no_geography):
                    i = self.matrix.matrix_hash[z]
                    t = np.nansum(total_mat[i, :]) + np.nansum(total_mat[:, i])
                    unnasigned += t
                    self.report.append(
                        'Zone {} does not have a corresponding centroid/zone. Total flow {}'.format(z, t))
                    total_mat[i, :] = 0
                    total_mat[:, i] = 0
                    self.desire_lines.emit(('jobs_done_dl', k + 1))

                self.desire_lines.emit(('text_dl', "Filtering down to OD pairs with flows"))
                field_names = [x for x in self.matrix.view_names]
                nonzero = np.nonzero(total_mat.flatten())
                arrays = np.vstack(arrays).transpose()
                arrays = arrays[nonzero, :]
                arrays = arrays.reshape(arrays.shape[1], arrays.shape[2])

                base_types = [(x, np.float64) for x in ['from', 'to']]
                base_types = base_types + [(x + '_AB', np.float64) for x in field_names]

                dtypes_ab = [(x, np.int64) for x in ['from', 'to']] + [(x + '_AB', float) for x in field_names]
                dtypes_ba = [(x, np.int64) for x in ['to', 'from']] + [(x + '_BA', float) for x in field_names]

                ab_mat = np.array(arrays[arrays[:, 0] > arrays[:, 1], :])
                ba_mat = np.array(arrays[arrays[:, 0] < arrays[:, 1], :])

                flows_ab = ab_mat.view(base_types)
                flows_ab = flows_ab.reshape(flows_ab.shape[:-1])
                flows_ab = flows_ab.astype(dtypes_ab)

                flows_ba = ba_mat.view(base_types)
                flows_ba = flows_ba.reshape(flows_ba.shape[:-1])
                flows_ba = flows_ba.astype(dtypes_ba)

                defaults1 = {x + '_AB': 0.0 for x in field_names}
                defaults = {x + '_BA': 0.0 for x in field_names}
                defaults = {**defaults, **defaults1}

                self.desire_lines.emit(('text_dl', "Concatenating AB & BA flows"))
                flows = rfn.join_by(['from', 'to'], flows_ab, flows_ba, jointype='outer', defaults=defaults,
                                    usemask=True, asrecarray=True)
                flows = flows.filled()
                flows_ab = 0
                flows_ba = 0

                for f in flows.dtype.names[2:]:
                    base_dl_fields.extend([QgsField(f, QVariant.Double)])

                dlpr.addAttributes(base_dl_fields)
                desireline_layer.updateFields()

                self.desire_lines.emit(('text_dl', "Creating Desire Lines"))
                self.desire_lines.emit(('job_size_dl', flows.shape[0]))
                all_features = []
                for i, rec in enumerate(flows):
                    a_node = rec[0]
                    b_node = rec[1]

                    a_point = QgsPointXY(*all_centroids[a_node])
                    b_point = QgsPointXY(*all_centroids[b_node])
                    dist = QgsGeometry().fromPointXY(a_point).distance(
                        QgsGeometry().fromPointXY(b_point))
                    feature = QgsFeature()
                    feature.setGeometry(QgsGeometry.fromPolylineXY([a_point, b_point]))

                    attrs = [i + 1, int(a_node), int(b_node), 0, dist]
                    attrs.extend([float(x) for x in list(rec)[2:]])
                    feature.setAttributes(attrs)
                    all_features.append(feature)
                    self.desire_lines.emit(('jobs_done_dl', i))
                if unnasigned > 0:
                    self.report.append('Total non assigned flows (not counting intrazonals):' + str(unnasigned))

                if flows.shape[0] > 1:
                    a = dlpr.addFeatures(all_features)
                    self.result_layer = desireline_layer
                else:
                    self.report.append('Nothing to show')

            elif self.dl_type == "DelaunayLines":

                for f in self.matrix.view_names:
                    base_dl_fields.extend([QgsField(f + '_ab', QVariant.Double),
                                           QgsField(f + '_ba', QVariant.Double),
                                           QgsField(f + '_tot', QVariant.Double)])

                dlpr.addAttributes(base_dl_fields)
                desireline_layer.updateFields()

                self.desire_lines.emit(('text_dl', "Building Delaunay dataset"))
                points = []
                node_id_in_delaunay_results = {}
                i = 0
                self.desire_lines.emit(('job_size_dl', len(all_centroids)))
                for k, v in all_centroids.items():
                    self.desire_lines.emit(('jobs_done_dl', i))
                    points.append(v)
                    node_id_in_delaunay_results[i] = k
                    i += 1

                self.desire_lines.emit(('text_dl', "Computing Delaunay Triangles"))
                tri = Delaunay(np.array(points))

                # We process all the triangles to only get each edge once
                self.desire_lines.emit(('text_dl', "Building Delaunay Network: Collecting Edges"))
                edges = []
                if self.python_version == 32:
                    all_edges = tri.vertices
                else:
                    all_edges = tri.simplices

                self.desire_lines.emit(('job_size_dl', len(all_edges)))

                for j, triangle in enumerate(all_edges):
                    self.desire_lines.emit(('jobs_done_dl', j))
                    links = list(itertools.combinations(triangle, 2))
                    for i in links:
                        edges.append([min(i[0], i[1]), max(i[0], i[1])])

                self.desire_lines.emit(('text_dl', "Building Delaunay Network: Getting unique edges"))
                edges = OrderedDict((str(x), x) for x in edges).values()

                # Writing Delaunay layer
                self.desire_lines.emit(('text_dl', "Building Delaunay Network: Assembling Layer"))

                desireline_link_id = 1
                data = []
                dl_ids_on_links = {}
                self.desire_lines.emit(('job_size_dl', len(edges)))
                for j, edge in enumerate(edges):
                    self.desire_lines.emit(('jobs_done_dl', j))
                    a_node = node_id_in_delaunay_results[edge[0]]
                    a_point = all_centroids[a_node]
                    a_point = QgsPointXY(a_point[0], a_point[1])
                    b_node = node_id_in_delaunay_results[edge[1]]
                    b_point = all_centroids[b_node]
                    b_point = QgsPointXY(b_point[0], b_point[1])
                    dist = QgsGeometry().fromPointXY(a_point).distance(QgsGeometry().fromPointXY(b_point))
                    line = []
                    line.append(desireline_link_id)
                    line.append(a_node)
                    line.append(b_node)
                    line.append(dist)
                    line.append(dist)
                    line.append(0)
                    data.append(line)
                    dl_ids_on_links[desireline_link_id] = [a_node, b_node, 0, dist]
                    desireline_link_id += 1

                self.desire_lines.emit(('text_dl', "Building graph"))
                network = np.asarray(data)
                del data

                # types for the network
                self.graph = Graph()
                itype = self.graph.default_types('int')
                ftype = self.graph.default_types('float')
                all_types = [itype, itype, itype, ftype, ftype, np.int8]
                all_titles = ['link_id', 'a_node', 'b_node', 'distance_ab', 'distance_ba', 'direction']
                dt = [(t, d) for t, d in zip(all_titles, all_types)]
                self.graph.network = np.zeros(network.shape[0], dtype=dt)

                for k, t in enumerate(dt):
                    self.graph.network[t[0]] = network[:, k].astype(t[1])
                del network

                self.graph.type_loaded = 'NETWORK'
                self.graph.status = 'OK'
                self.graph.network_ok = True
                self.graph.prepare_graph(self.matrix.index.astype(np.int64))
                self.graph.set_graph(cost_field='distance', skim_fields=False, block_centroid_flows=False)

                self.results = AssignmentResults()
                self.results.prepare(self.graph, self.matrix)
                self.desire_lines.emit(('text_dl', "Assigning demand"))
                self.desire_lines.emit(('job_size_dl', self.matrix.index.shape[0]))

                assigner = allOrNothing(self.matrix, self.graph, self.results)
                assigner.execute()
                self.report = assigner.report
                print(self.results.link_loads)
                self.desire_lines.emit(('text_dl', "Collecting results"))
                self.desire_lines.emit(('text_dl', "Building resulting layer"))
                features = []
                max_edges = len(edges)
                self.desire_lines.emit(('job_size_dl', max_edges))
                link_loads = self.results.save_to_disk()
                for i, link_id in enumerate(link_loads.index):
                    self.desire_lines.emit(('jobs_done_dl', i))
                    a_node, b_node, direct, dist = dl_ids_on_links[link_id]

                    attr = [int(link_id), a_node, b_node, direct, dist]

                    a_point = all_centroids[a_node]
                    a_point = QgsPointXY(a_point[0], a_point[1])
                    b_point = all_centroids[b_node]
                    b_point = QgsPointXY(b_point[0], b_point[1])

                    feature = QgsFeature()
                    feature.setGeometry(QgsGeometry.fromPolylineXY([a_point, b_point]))

                    for c in self.matrix.view_names:
                        attr.extend([float(link_loads.data[c + '_ab'][i]),
                                     float(link_loads.data[c + '_ba'][i]),
                                     float(link_loads.data[c + '_tot'][i])])
                    feature.setAttributes(attr)
                    features.append(feature)
                a = dlpr.addFeatures(features)
                self.result_layer = desireline_layer

        self.desire_lines.emit(('finished_desire_lines_procedure', 0))
Example #22
0
class TestGraph(TestCase):
    def test_create_from_geography(self):
        self.graph = Graph()
        self.graph.create_from_geography(test_network,
                                         'link_id',
                                         'dir',
                                         'distance',
                                         centroids=centroids,
                                         skim_fields=[],
                                         anode="A_NODE",
                                         bnode="B_NODE")
        self.graph.set_graph(cost_field='distance', block_centroid_flows=True)

    def test_load_network_from_csv(self):
        pass

    def test_prepare_graph(self):
        self.test_create_from_geography()
        self.graph.prepare_graph(centroids)

        reference_graph = Graph()
        reference_graph.load_from_disk(test_graph)
        if not np.array_equal(self.graph.graph, reference_graph.graph):
            self.fail('Reference graph and newly-prepared graph are not equal')

    def test_set_graph(self):
        self.test_prepare_graph()
        self.graph.set_graph(cost_field='distance', block_centroid_flows=True)
        if self.graph.num_zones != centroids.shape[0]:
            self.fail('Number of centroids not properly set')
        if self.graph.num_links != 222:
            self.fail('Number of links not properly set')
        if self.graph.num_nodes != 93:
            self.fail('Number of nodes not properly set - ' +
                      str(self.graph.num_nodes))

    def test_save_to_disk(self):
        self.test_create_from_geography()
        self.graph.save_to_disk(join(path_test, 'aequilibrae_test_graph.aeg'))
        self.graph_id = self.graph.__id__
        self.graph_version = self.graph.__version__

    def test_load_from_disk(self):
        self.test_save_to_disk()
        reference_graph = Graph()
        reference_graph.load_from_disk(test_graph)

        new_graph = Graph()
        new_graph.load_from_disk(join(path_test, 'aequilibrae_test_graph.aeg'))

        comparisons = [
            ('Graph', new_graph.graph, reference_graph.graph),
            ('b_nodes', new_graph.b_node, reference_graph.b_node),
            ('Forward-Star', new_graph.fs, reference_graph.fs),
            ('cost', new_graph.cost, reference_graph.cost),
            ('centroids', new_graph.centroids, reference_graph.centroids),
            ('skims', new_graph.skims, reference_graph.skims),
            ('link ids', new_graph.ids, reference_graph.ids),
            ('Network', new_graph.network, reference_graph.network),
            ('All Nodes', new_graph.all_nodes, reference_graph.all_nodes),
            ('Nodes to indices', new_graph.nodes_to_indices,
             reference_graph.nodes_to_indices)
        ]

        for comparison, newg, refg in comparisons:
            if not np.array_equal(newg, refg):
                self.fail(
                    'Reference %s and %s created and saved to disk are not equal'
                    % (comparison, comparison))

        comparisons = [
            ('nodes', new_graph.num_nodes, reference_graph.num_nodes),
            ('links', new_graph.num_links, reference_graph.num_links),
            ('zones', new_graph.num_zones, reference_graph.num_zones),
            ('block through centroids', new_graph.block_centroid_flows,
             reference_graph.block_centroid_flows),
            ('Graph ID', new_graph.__id__, self.graph_id),
            ('Graph Version', new_graph.__version__, self.graph_version)
        ]

        for comparison, newg, refg in comparisons:
            if newg != refg:
                self.fail(
                    'Reference %s and %s created and saved to disk are not equal'
                    % (comparison, comparison))

    def test_reset_single_fields(self):
        pass

    def test_add_single_field(self):
        pass

    def test_available_skims(self):
        self.test_set_graph()
        if self.graph.available_skims() != ['distance']:
            self.fail('Skim availability with problems')
class DesireLinesProcedure(WorkerThread):
    def __init__(self, parentThread, layer, id_field, matrix, matrix_hash,
                 dl_type):
        WorkerThread.__init__(self, parentThread)
        self.layer = layer
        self.id_field = id_field
        self.matrix = matrix
        self.dl_type = dl_type
        self.error = None
        self.matrix_hash = matrix_hash
        self.report = []
        self.python_version = (8 * struct.calcsize("P"))

        if error:
            self.error = 'Scipy and/or Numpy not installed'
        self.procedure = "ASSIGNMENT"

    def doWork(self):
        if self.error is None:
            layer = get_vector_layer_by_name(self.layer)
            idx = layer.fieldNameIndex(self.id_field)
            matrix = self.matrix

            matrix_nodes = max(self.matrix_hash.values()) + 1
            featcount = layer.featureCount()
            self.emit(SIGNAL("ProgressMaxValue(PyQt_PyObject)"),
                      (0, featcount))

            all_centroids = {}
            P = 0
            for feat in layer.getFeatures():
                P += 1
                self.emit(SIGNAL("ProgressValue(PyQt_PyObject)"), (0, int(P)))
                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Loading Layer Features: " + str(P) + "/" +
                           str(featcount)))

                geom = feat.geometry()
                if geom is not None:
                    point = list(geom.centroid().asPoint())
                    centroid_id = feat.attributes()[idx]
                    all_centroids[centroid_id] = point

                    if centroid_id not in self.matrix_hash.keys():
                        self.matrix_hash[centroid_id] = matrix_nodes
                        matrix_nodes += 1
            reverse_hash = {v: k for k, v in self.matrix_hash.iteritems()}

            #Creating resulting layer
            EPSG_code = int(layer.crs().authid().split(":")[1])

            desireline_layer = QgsVectorLayer(
                "LineString?crs=epsg:" + str(EPSG_code), self.dl_type,
                "memory")
            dlpr = desireline_layer.dataProvider()
            dlpr.addAttributes([
                QgsField("link_id", QVariant.Int),
                QgsField("A_Node", QVariant.Int),
                QgsField("B_Node", QVariant.Int),
                QgsField("direct", QVariant.Int),
                QgsField("length", QVariant.Double),
                QgsField("ab_flow", QVariant.Double),
                QgsField("ba_flow", QVariant.Double),
                QgsField("tot_flow", QVariant.Double)
            ])
            desireline_layer.updateFields()

            if self.dl_type == "DesireLines":
                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Creating Desire Lines"))
                self.emit(SIGNAL("ProgressMaxValue(PyQt_PyObject)"),
                          (0, self.matrix.shape[0] * self.matrix.shape[1] / 2))

                desireline_link_id = 1
                q = 0
                all_features = []
                for i in range(self.matrix.shape[0]):
                    if np.sum(self.matrix[i, :]) > 0:
                        a_node = reverse_hash[i]
                        for j in xrange(i + 1, self.matrix.shape[1]):
                            q += 1
                            b_node = reverse_hash[j]
                            self.emit(SIGNAL("ProgressValue(PyQt_PyObject)"),
                                      (0, q))
                            if self.matrix[i, j] + self.matrix[j, i] > 0:
                                if a_node in all_centroids.keys(
                                ) and b_node in all_centroids.keys():
                                    a_point = all_centroids[a_node]
                                    a_point = QgsPoint(a_point[0], a_point[1])
                                    b_point = all_centroids[b_node]
                                    b_point = QgsPoint(b_point[0], b_point[1])
                                    dist = QgsGeometry().fromPoint(
                                        a_point).distance(
                                            QgsGeometry().fromPoint(b_point))
                                    feature = QgsFeature()
                                    feature.setGeometry(
                                        QgsGeometry.fromPolyline(
                                            [a_point, b_point]))
                                    feature.setAttributes([
                                        desireline_link_id,
                                        int(a_node),
                                        int(b_node), 0, dist,
                                        float(self.matrix[i, j]),
                                        float(self.matrix[j, i]),
                                        float(self.matrix[i, j] +
                                              self.matrix[j, i])
                                    ])
                                    all_features.append(feature)
                                    desireline_link_id += 1
                                else:
                                    tu = (a_node, b_node, self.matrix[i, j],
                                          self.matrix[j, i])
                                    self.report.append(
                                        'No centroids available to depict flow between node {0} and node {1}. AB flow was equal to {2} and BA flow was equal to {3}'
                                        .format(*tu))
                    else:
                        q += self.matrix.shape[1]
                        self.emit(SIGNAL("ProgressValue(PyQt_PyObject)"),
                                  (0, q))

                if desireline_link_id > 1:
                    a = dlpr.addFeatures(all_features)
                    self.result_layer = desireline_layer
                else:
                    self.error = 'Nothing to show'

            elif self.dl_type == "DelaunayLines":

                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Computing Delaunay Triangles"))
                points = []
                seccond_relation = {}
                i = 0
                for k, v in all_centroids.iteritems():
                    points.append(v)
                    seccond_relation[i] = k
                    i += 1

                tri = Delaunay(np.array(points))

                #We process all the triangles to only get each edge once
                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Building Delaunay Network: Collecting Edges"))
                edges = []
                if self.python_version == 32:
                    all_edges = tri.vertices
                else:
                    all_edges = tri.simplices

                for triangle in all_edges:
                    links = list(itertools.combinations(triangle, 2))
                    for i in links:
                        l = [min(i[0], i[1]), max(i[0], i[1])]
                        if l not in edges:
                            edges.append(l)

                #Writing Delaunay layer
                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Building Delaunay Network: Assembling Layer"))

                desireline_link_id = 1
                data = []
                dl_link_ids = {}
                for edge in edges:
                    a_node = seccond_relation[edge[0]]
                    a_point = all_centroids[a_node]
                    a_point = QgsPoint(a_point[0], a_point[1])
                    b_node = seccond_relation[edge[1]]
                    b_point = all_centroids[b_node]
                    b_point = QgsPoint(b_point[0], b_point[1])
                    dist = QgsGeometry().fromPoint(a_point).distance(
                        QgsGeometry().fromPoint(b_point))
                    line = []
                    line.append(desireline_link_id)
                    line.append(self.matrix_hash[a_node])
                    line.append(self.matrix_hash[b_node])
                    line.append(dist)
                    line.append(dist)
                    line.append(0)
                    data.append(line)
                    if a_node not in dl_link_ids.keys():
                        dl_link_ids[a_node] = {}
                    dl_link_ids[a_node][b_node] = desireline_link_id
                    desireline_link_id += 1

                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Building graph"))
                network = np.asarray(data)
                del data

                #types for the network
                all_types = [
                    np.int64, np.int64, np.int64, np.float64, np.float64,
                    np.int64
                ]
                all_titles = [
                    'link_id', 'a_node', 'b_node', 'length_ab', 'length_ba',
                    'direction'
                ]
                dt = [(t, d) for t, d in zip(all_titles, all_types)]

                self.graph = Graph()
                self.graph.network = np.zeros(network.shape[0], dtype=dt)

                for k, t in enumerate(dt):
                    self.graph.network[t[0]] = network[:, k].astype(t[1])
                del network

                self.graph.type_loaded = 'NETWORK'
                self.graph.status = 'OK'
                self.graph.network_ok = True
                self.graph.prepare_graph()

                self.graph.set_graph(matrix_nodes,
                                     cost_field='length',
                                     block_centroid_flows=False)
                self.results = AssignmentResults()
                self.results.prepare(self.graph)
                # self.results.set_cores(1)

                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Assigning demand"))
                # Do the assignment
                #self.all_or_nothing(self.matrix, self.graph, self.results)
                self.report = all_or_nothing(self.matrix, self.graph,
                                             self.results)

                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Collecting results"))
                f = self.results.link_loads

                link_loads = np.zeros((f.shape[0] + 1, 2))
                self.emit(SIGNAL("ProgressMaxValue(PyQt_PyObject)"),
                          (0, f.shape[0] - 1))
                for i in range(f.shape[0] - 1):
                    self.emit(SIGNAL("ProgressValue(PyQt_PyObject)"), (0, i))
                    direction = self.graph.graph['direction'][i]
                    link_id = self.graph.graph['link_id'][i]
                    flow = f[i]
                    if direction == 1:
                        link_loads[link_id, 0] = flow
                    else:
                        link_loads[link_id, 1] = flow

                self.emit(SIGNAL("ProgressText (PyQt_PyObject)"),
                          (0, "Building resulting layer"))
                features = []
                max_edges = len(edges)
                self.emit(SIGNAL("ProgressMaxValue(PyQt_PyObject)"),
                          (0, max_edges))

                for i, edge in enumerate(edges):
                    self.emit(SIGNAL("ProgressValue(PyQt_PyObject)"), (0, i))
                    a_node = seccond_relation[edge[0]]
                    a_point = all_centroids[a_node]
                    a_point = QgsPoint(a_point[0], a_point[1])
                    b_node = seccond_relation[edge[1]]
                    b_point = all_centroids[b_node]
                    b_point = QgsPoint(b_point[0], b_point[1])
                    dist = QgsGeometry().fromPoint(a_point).distance(
                        QgsGeometry().fromPoint(b_point))

                    feature = QgsFeature()
                    feature.setGeometry(
                        QgsGeometry.fromPolyline([a_point, b_point]))
                    desireline_link_id = dl_link_ids[a_node][b_node]
                    feature.setAttributes([
                        desireline_link_id, a_node, b_node, 0, dist,
                        float(link_loads[desireline_link_id, 0]),
                        float(link_loads[desireline_link_id, 1]),
                        float(link_loads[desireline_link_id, 0] +
                              link_loads[desireline_link_id, 1])
                    ])
                    features.append(feature)
                a = dlpr.addFeatures(features)
                self.result_layer = desireline_layer

        self.emit(SIGNAL("finished_threaded_procedure( PyQt_PyObject )"), True)
Example #24
0
class ImpedanceMatrixDialog(QtGui.QDialog, Ui_Impedance_Matrix):
    def __init__(self, iface):
        QDialog.__init__(self)
        self.iface = iface
        self.setupUi(self)

        self.result = PathResults()
        self.validtypes = integer_types + float_types
        self.tot_skims = 0
        self.name_skims = 0
        self.skimmeable_fields = []
        self.skim_fields = []
        # FIRST, we connect slot signals

        #For loading a new graph
        self.load_graph_from_file.clicked.connect(
            self.loaded_new_graph_from_file)

        # For adding skims
        self.bt_add_skim.clicked.connect(self.add_to_skim_list)
        self.skim_list.doubleClicked.connect(self.slotDoubleClicked)

        # RUN skims
        self.select_result.clicked.connect(self.browse_outfile)

        self.do_dist_matrix.clicked.connect(self.run_skimming)

        # SECOND, we set visibility for sections that should not be shown when the form opens (overlapping items)
        #        and re-dimension the items that need re-dimensioning
        self.HideAllProgressBars()
        self.skim_list.setColumnWidth(0, 567)

        # loads default path from parameters
        self.path = standard_path()

    def HideAllProgressBars(self):
        self.progressbar.setVisible(False)
        self.progress_label.setVisible(False)
        self.progressbar.setValue(0)
        self.progress_label.setText('')

    def loaded_new_graph_from_file(self):
        file_types = "AequilibraE graph(*.aeg)"
        if len(self.graph_file_name.text()) > 0:
            newname = QFileDialog.getOpenFileName(None, 'Result file',
                                                  self.graph_file_name.text(),
                                                  file_types)
        else:
            newname = QFileDialog.getOpenFileName(None, 'Result file',
                                                  self.path, file_types)

        self.cb_minimizing.clear()
        self.cb_skims.clear()
        self.all_centroids.setText('')
        self.block_paths.setChecked(False)
        if newname is not None:
            self.graph_file_name.setText(newname)
            self.graph = Graph()
            self.graph.load_from_disk(newname)

            self.all_centroids.setText(str(self.graph.centroids))
            if self.graph.block_centroid_flows:
                self.block_paths.setChecked(True)
            graph_fields = list(self.graph.graph.dtype.names)
            self.skimmeable_fields = [
                x for x in graph_fields if x not in [
                    'link_id',
                    'a_node',
                    'b_node',
                    'direction',
                    'id',
                ]
            ]

            for q in self.skimmeable_fields:
                self.cb_minimizing.addItem(q)
                self.cb_skims.addItem(q)

    def add_to_skim_list(self):
        if self.cb_skims.currentIndex() >= 0:
            self.tot_skims += 1
            self.skim_list.setRowCount(self.tot_skims)
            self.skim_list.setItem(
                self.tot_skims - 1, 0,
                QtGui.QTableWidgetItem((self.cb_skims.currentText())))
            self.skim_fields.append(self.cb_skims.currentText())
            self.cb_skims.removeItem(self.cb_skims.currentIndex())

    def slotDoubleClicked(self, mi):
        row = mi.row()
        if row > -1:
            self.cb_skims.addItem(self.skim_list.item(row, 0).text())
            self.skim_fields.pop(row)
            self.skim_list.removeRow(row)
            self.tot_skims -= 1

    def browse_outfile(self):
        file_types = "Comma-Separated files(*.csv)"
        if self.npy_res.isChecked():
            file_types = "Numpy Binnary Array(*.npy)"

        if len(self.imped_results.text()) > 0:
            newname = QFileDialog.getSaveFileName(None, 'Result file',
                                                  self.imped_results.text(),
                                                  file_types)
        else:
            newname = QFileDialog.getSaveFileName(None, 'Result file',
                                                  self.path, file_types)

        self.imped_results.setText('')
        if newname != None:
            self.imped_results.setText(newname)

    def runThread(self):

        QObject.connect(self.workerThread,
                        SIGNAL("ProgressValue( PyQt_PyObject )"),
                        self.ProgressValueFromThread)
        QObject.connect(self.workerThread,
                        SIGNAL("ProgressText( PyQt_PyObject )"),
                        self.ProgressTextFromThread)
        QObject.connect(self.workerThread,
                        SIGNAL("ProgressMaxValue( PyQt_PyObject )"),
                        self.ProgressRangeFromThread)

        QObject.connect(self.workerThread,
                        SIGNAL("FinishedThreadedProcedure( PyQt_PyObject )"),
                        self.FinishedThreadedProcedure)

        self.workerThread.start()
        self.exec_()

    # VAL and VALUE have the following structure: (bar/text ID, value)
    def ProgressRangeFromThread(self, val):
        self.progressbar.setRange(0, val[1])

    def ProgressValueFromThread(self, val):
        self.progressbar.setValue(val[1])

    def ProgressTextFromThread(self, val):
        self.progress_label.setText(val[1])

    def FinishedThreadedProcedure(self, val):
        if self.workerThread.error is not None:
            qgis.utils.iface.messageBar().pushMessage(
                "Assignment did NOT run correctly",
                self.workerThread.error,
                level=3)
        else:
            mat = self.workerThread.skim_matrices
            mat[mat >
                1e308] = np.inf  # We treat the "infinity" that should have been treated within the Cython code

            if self.npy_res.isChecked():
                np.save(self.imped_results.text(), mat)
                q = open(self.imped_results.text() + '.csv', 'w')
                for l in self.skim_fields:
                    print >> q, l
                q.flush()
                q.close()
            if self.csv_res.isChecked():
                q = open(self.imped_results.text(), 'w')
                text = 'Origin,Destination,' + self.cb_minimizing.currentText()
                for l in self.skim_fields:
                    text = text + ',' + l
                print >> q, text
                for i in range(mat.shape[0]):
                    if np.sum(mat[i, :, :]) > 0:
                        for j in range(mat.shape[1]):
                            if np.sum(mat[i, j, :]) > 0:
                                text = str(i) + ',' + str(j)
                                s = 0
                                for k in range(mat.shape[2]):
                                    if mat[i, j, k] != np.inf:
                                        s += mat[i, j, k]
                                        text = text + ',' + str(mat[i, j, k])
                                    else:
                                        text += ','
                                if s > 0:
                                    print >> q, text
                    q.flush()
                q.close()
        self.close()

    def run_skimming(self):  # Saving results
        centroids = int(self.all_centroids.text())
        cost_field = self.cb_minimizing.currentText()
        block_paths = False
        if self.block_paths.isChecked():
            block_paths = True

        if centroids > 0:
            self.graph.set_graph(centroids, cost_field, self.skim_fields,
                                 block_paths)
            self.result.prepare(self.graph)
        else:
            qgis.utils.iface.messageBar().pushMessage(
                "Nothing to run.", 'Number of centroids set to zero', level=3)

        if len(self.imped_results.text()) == 0:
            qgis.utils.iface.messageBar().pushMessage(
                "Cannot run.", 'No output file provided', level=3)
        else:
            self.funding1.setVisible(False)
            self.funding2.setVisible(False)
            self.progressbar.setVisible(True)
            self.progress_label.setVisible(True)
            self.workerThread = ComputeDistMatrix(
                qgis.utils.iface.mainWindow(), self.graph, self.result)
            self.runThread()