def __init__(self, graph: Graph, matrix: Matrix) -> None: if not np.array_equal(matrix.index, graph.centroids): raise ValueError("Matrix and graph do not have compatible sets of centroids.") self.graph = graph self.matrix = matrix self.pce = 1 self.mode = graph.mode self.class_flow: np.array self.results = AssignmentResults() self.results.prepare(self.graph, self.matrix) self.results.reset() self._aon_results = AssignmentResults() self._aon_results.prepare(self.graph, self.matrix)
def test_set_cores(self): a = AssignmentResults() a.set_cores(10) with self.assertRaises(ValueError): a.set_cores(1.3) a.set_cores(-2) self.assertEqual(a.cores, max(1, mp.cpu_count() - 2))
def test_set_cores(self): a = AssignmentResults() a.set_cores(10) with self.assertRaises(ValueError): a.set_cores(1.3) with self.assertRaises(ValueError): a.set_cores(-2)
def test_execute(self): # Loads and prepares the graph res1 = AssignmentResults() res1.prepare(self.g, self.matrix) assig1 = allOrNothing(self.matrix, self.g, res1) assig1.execute() res2 = AssignmentResults() res2.prepare(self.g, self.matrix2) assig2 = allOrNothing(self.matrix2, self.g, res2) assig2.execute() load1 = res1.get_load_results() load2 = res2.get_load_results() self.assertEqual(list(load1.matrix_tot * 2), list(load2.matrix_tot), "Something wrong with the AoN")
def __init__(self, graph: Graph, matrix: AequilibraeMatrix) -> None: """ Instantiates the class Args: graph (:obj:`Graph`): Class/mode-specific graph matrix (:obj:`AequilibraeMatrix`): Class/mode-specific matrix. Supports multiple user classes """ if not np.array_equal(matrix.index, graph.centroids): raise ValueError("Matrix and graph do not have compatible sets of centroids.") self.graph = graph self.matrix = matrix self.pce = 1 self.mode = graph.mode self.class_flow: np.array self.results = AssignmentResults() self.results.prepare(self.graph, self.matrix) self.results.reset() self._aon_results = AssignmentResults() self._aon_results.prepare(self.graph, self.matrix)
def __init__(self, name: str, graph: Graph, matrix: AequilibraeMatrix) -> None: """ Instantiates the class Args: name (:obj:`str`): UNIQUE class name. graph (:obj:`Graph`): Class/mode-specific graph matrix (:obj:`AequilibraeMatrix`): Class/mode-specific matrix. Supports multiple user classes """ if not np.array_equal(matrix.index, graph.centroids): raise ValueError( "Matrix and graph do not have compatible sets of centroids.") if matrix.matrix_view.dtype != graph.default_types('float'): raise TypeError( "Matrix's computational view need to be of type np.float64") self.graph = graph self.matrix = matrix self.pce = 1.0 self.vot = 1.0 self.mode = graph.mode self.class_flow: np.array self.results = AssignmentResults() self.results.prepare(self.graph, self.matrix) self.fixed_cost = np.zeros(graph.graph.shape[0], graph.default_types('float')) self.fixed_cost_field = '' self.fc_multiplier = 1.0 self.results.reset() self._aon_results = AssignmentResults() self._aon_results.prepare(self.graph, self.matrix) self.__id__ = name
class TrafficClass(): """Traffic class for equilibrium traffic assignment :: from aequilibrae.paths import TrafficClass tc = TrafficClass(graph, demand_matrix) tc.set_pce(1.3) """ def __init__(self, graph: Graph, matrix: AequilibraeMatrix) -> None: """ Instantiates the class Args: graph (:obj:`Graph`): Class/mode-specific graph matrix (:obj:`AequilibraeMatrix`): Class/mode-specific matrix. Supports multiple user classes """ if not np.array_equal(matrix.index, graph.centroids): raise ValueError( "Matrix and graph do not have compatible sets of centroids.") self.graph = graph self.matrix = matrix self.pce = 1 self.mode = graph.mode self.class_flow: np.array self.results = AssignmentResults() self.results.prepare(self.graph, self.matrix) self.results.reset() self._aon_results = AssignmentResults() self._aon_results.prepare(self.graph, self.matrix) self._id = uuid4().hex def set_pce(self, pce: Union[float, int]) -> None: """Sets Passenger Car equivalent Args: pce (:obj:`Union[float, int]`): PCE. Defaults to 1 if not set """ if not isinstance(pce, (float, int)): raise ValueError('PCE needs to be either integer or float ') self.pce = pce
class TrafficClass(): def __init__(self, graph: Graph, matrix: Matrix) -> None: if not np.array_equal(matrix.index, graph.centroids): raise ValueError("Matrix and graph do not have compatible sets of centroids.") self.graph = graph self.matrix = matrix self.pce = 1 self.mode = graph.mode self.class_flow: np.array self.results = AssignmentResults() self.results.prepare(self.graph, self.matrix) self.results.reset() self._aon_results = AssignmentResults() self._aon_results.prepare(self.graph, self.matrix) def set_pce(self, pce: Union[float, int]) -> None: if not isinstance(pce, (float, int)): raise ValueError('PCE needs to be either integer or float ') self.pce = pce
def test_skimming_on_assignment(self): res = AssignmentResults() res.prepare(self.g, self.matrix) self.g.set_skimming([]) self.g.set_blocked_centroid_flows(True) assig = allOrNothing(self.matrix, self.g, res) assig.execute() if res.skims.distance.sum() > 0: self.fail( "skimming for nothing during assignment returned something different than zero" ) res.prepare(self.g, self.matrix) assig = allOrNothing(self.matrix, self.g, res) assig.execute()
def __init__(self, assig_spec, algorithm) -> None: WorkerThread.__init__(self, None) self.algorithm = algorithm self.rgap_target = assig_spec.rgap_target self.max_iter = assig_spec.max_iter self.cores = assig_spec.cores self.assig = assig_spec # type: TrafficAssignment if None in [ assig_spec.classes, assig_spec.vdf, assig_spec.capacity_field, assig_spec.time_field, assig_spec.vdf_parameters, ]: all_par = 'Traffic classes, VDF, VDF_parameters, capacity field & time_field' raise Exception( "Parameter missing. Setting the algorithm is the last thing to do " f"when assigning. Check if you have all of these: {all_par}") self.traffic_classes = assig_spec.classes # type: List[TrafficClass] self.num_classes = len(assig_spec.classes) self.cap_field = assig_spec.capacity_field self.time_field = assig_spec.time_field self.vdf = assig_spec.vdf self.vdf_parameters = assig_spec.vdf_parameters self.iter = 0 self.rgap = np.inf self.stepsize = 1.0 self.conjugate_stepsize = 0.0 self.fw_class_flow = 0 # rgap can be a bit wiggly, specifying how many times we need to be below target rgap is a quick way to # ensure a better result. We might want to demand that the solution is that many consecutive times below. self.steps_below_needed_to_terminate = 1 self.steps_below = 0 # if this is one, we do not have a new direction and will get stuck. Make it 1. self.conjugate_direction_max = 0.99999 # if FW stepsize is zero, we set it to the corresponding MSA stepsize and then need to not make # the step direction conjugate to the previous direction. self.do_fw_step = False self.do_conjugate_step = False # BFW specific stuff self.betas = np.array([1.0, 0.0, 0.0]) # Instantiates the arrays that we will use over and over self.capacity = assig_spec.capacity self.free_flow_tt = assig_spec.free_flow_tt self.fw_total_flow = assig_spec.total_flow self.congested_time = assig_spec.congested_time self.vdf_der = np.array(assig_spec.congested_time, copy=True) self.congested_value = np.array(assig_spec.congested_time, copy=True) self.step_direction = {} # type: Dict[AssignmentResults] self.previous_step_direction = {} # type: Dict[AssignmentResults] self.pre_previous_step_direction = {} # type: Dict[AssignmentResults] for c in self.traffic_classes: r = AssignmentResults() r.prepare(c.graph, c.matrix) self.step_direction[c.mode] = r if self.algorithm in ['cfw', 'bfw']: for c in self.traffic_classes: r = AssignmentResults() r.prepare(c.graph, c.matrix) self.previous_step_direction[c.mode] = r r = AssignmentResults() r.prepare(c.graph, c.matrix) self.step_direction[c.mode] = r r = AssignmentResults() r.prepare(c.graph, c.matrix) self.pre_previous_step_direction[c.mode] = r
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))
class TrafficClass(): """Traffic class for equilibrium traffic assignment :: from aequilibrae.paths import TrafficClass tc = TrafficClass(graph, demand_matrix) tc.set_pce(1.3) """ def __init__(self, name: str, graph: Graph, matrix: AequilibraeMatrix) -> None: """ Instantiates the class Args: name (:obj:`str`): UNIQUE class name. graph (:obj:`Graph`): Class/mode-specific graph matrix (:obj:`AequilibraeMatrix`): Class/mode-specific matrix. Supports multiple user classes """ if not np.array_equal(matrix.index, graph.centroids): raise ValueError( "Matrix and graph do not have compatible sets of centroids.") if matrix.matrix_view.dtype != graph.default_types('float'): raise TypeError( "Matrix's computational view need to be of type np.float64") self.graph = graph self.matrix = matrix self.pce = 1.0 self.vot = 1.0 self.mode = graph.mode self.class_flow: np.array self.results = AssignmentResults() self.results.prepare(self.graph, self.matrix) self.fixed_cost = np.zeros(graph.graph.shape[0], graph.default_types('float')) self.fixed_cost_field = '' self.fc_multiplier = 1.0 self.results.reset() self._aon_results = AssignmentResults() self._aon_results.prepare(self.graph, self.matrix) self.__id__ = name def set_pce(self, pce: Union[float, int]) -> None: """Sets Passenger Car equivalent Args: pce (:obj:`Union[float, int]`): PCE. Defaults to 1 if not set """ if not isinstance(pce, (float, int)): raise ValueError('PCE needs to be either integer or float ') self.pce = pce def set_fixed_cost(self, field_name: str, multiplier=1): """Sets value of time Args: field_name (:obj:`str`): Name of the graph field with fixed costs for this class multiplier (:obj:`Union[float, int]`): Multiplier for the fixed cost. Defaults to 1 if not set """ self.fc_multiplier = float(multiplier) if field_name not in self.graph.graph.columns: raise ValueError('Field does not exist in the graph') self.fixed_cost_field = field_name if np.any(np.isnan(self.graph.graph[field_name].values)): logger.warning( f'Cost field {field_name} has NaN values. Converted to zero') if self.graph.graph[field_name].min() < 0: msg = f'Cost field {field_name} has negative values. That is not allowed' logger.error(msg) raise ValueError(msg) def set_vot(self, value_of_time: float) -> None: """Sets value of time Args: value_of_time (:obj:`Union[float, int]`): Value of time. Defaults to 1 if not set """ self.vot = float(value_of_time) def __setattr__(self, key, value): if key not in [ 'graph', 'matrix', 'pce', 'mode', 'class_flow', 'results', '_aon_results', '__id__', 'vot', 'fixed_cost', 'fc_multiplier', 'fixed_cost_field' ]: raise KeyError('Traffic Class does not have that element') self.__dict__[key] = value
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)
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))
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)
def test_set_save_path_file(self): a = AssignmentResults() # Never save by default self.assertEqual(a.save_path_file, False)