Topology

The Topology class holds the network graph plus origin, destination, observer, and obstacle point layers. It is owned by UNA and rebuilt on every Run* call.

class Topology(verbosity=1, num_threads=None)[source]

Bases: object

DESCRIPTION:

This is the main class for the Topology module. It contains the network and access points, as well as the logger for the module. It also contains methods for adding networks and access points.

Parameters:
  • verbosity (int)

  • num_threads (int)

origins: AccessPoints = None
destinations: AccessPoints = None
observer_points: AccessPoints = None
obstacles: AccessPoints = None
obstacle_arc_penalty_AB = None
obstacle_arc_penalty_BA = None
obstacle_node_penalty = None
access_points: AccessPoints = None
has_clusters: bool = False
cluster_masks: Dict[int, Polygon] = None
num_clusters: int = None
crs = None
logger: Logger = None
num_threads: int = 1
network: Network = None
AddNetwork(settings)[source]

DESCRIPTION:

This function adds a network to the topology from a given source file. It reads the network data, processes it to extract geometries and weights, and builds the topological representation of the network. The network cost can be either geometric (length of edges) or set by an attribute in the source data.

Parameters:
  • name. (Network cost can be either "Geometric" or set by attribute)

  • settings (Settings)

AddOrigins(settings)[source]
Parameters:

settings (Settings)

AddDestinations(settings)[source]
Parameters:

settings (Settings)

AddObservers(settings)[source]

Load a Point layer of observer points. These are passive counters: they snap to the network (edge by default, optionally node) and the flow engine writes per-point flow_AB / flow_BA / flow_total counters in an extra output file.

Observer points do NOT influence routing. They are not used by the accessibility engines.

Parameters:

settings (Settings)

AddObstacles(settings)[source]

Load a Point layer of obstacle points. Each obstacle adds a penalty (in the same units as network edge weights) to the cost of traversing its host edge or node. Used by both flow and accessibility engines.

Settings used:

obstacle_points_file obstacle_points_uid_column obstacle_points_penalty_column (REQUIRED column in file) obstacle_points_direction_column (‘both’|’AB’|’BA’; default ‘both’) obstacle_points_snap_to (“edge” | “node”)

Parameters:

settings (Settings)

get_obstacle_arc_penalties()[source]

Return (penalty_AB, penalty_BA) arrays of shape (n_edges,) — the per-arc obstacle penalty to add to each direction of every network edge. Combines edge-snapped and node-snapped obstacles (node penalties are added to arcs ENTERING the node, to avoid double-counting on traversal).

Returns (None, None) when no obstacles are loaded.

get_partial_edge_corrections(access_points, for_origins=False)[source]

Compute partial-edge obstacle corrections for origins or destinations.

When an obstacle sits on the same edge as an origin or destination, the full-arc penalty injected into the CSR may over- or under-count the cost for the partial traversal between the access point and the edge endpoint. This method returns per-point additive corrections that fix the terminal weights used during Dijkstra seeding (origins) or distance adjustment (destinations).

Only applies to edge-snapped obstacles. Node-snapped obstacles are fully handled by get_obstacle_arc_penalties() and need no correction here.

Parameters:
  • access_points – An AccessPoints instance (topology.origins or topology.destinations).

  • for_origins (bool) –

    True → point travels TOWARD the endpoint (seed weights).

    start-side uses BA penalty, end-side uses AB penalty.

    False → point is reached FROM the endpoint (terminal weights).

    start-side uses AB penalty, end-side uses BA penalty.

Returns:

(corr_start, corr_end) — float64 arrays of shape (n_points,), or (None, None) if no edge-snapped obstacles are loaded.

Crossing condition (same for origins and destinations):

start-side crossed ← obs.weight_to_start < point.weight_to_start end-side crossed ← obs.weight_to_end < point.weight_to_end

BuildClusters(n_clusters=10, search_radius=100, random_state=42, cluster_concave_ratio=0.23)[source]

DSCRIPTION:

We collect indeces for for network, origins and desintation.

Parameters:
  • n_clusters (int) – int = 10,

  • search_radius (float) – float = 100,

  • random_state (int) – int = 42,

  • cluster_concave_ratio (float) – float = 0.23

STEPS:
  1. Validate that network, origins and destinations are added before building clusters.

  2. Use KMeans clustering to group origins into n_clusters based on their coordinates.

BuildTurnPenalties(turn_angle_threshold=45.0, turn_penalty=32.0, store_zero_penalties=False)[source]

Delegate to Network.BuildTurnPenalties — see that method for full docs.

Parameters:
  • turn_angle_threshold (float)

  • turn_penalty (float)

  • store_zero_penalties (bool)

Return type:

None

BuildAccessPoints(source_file, cost_attribute='Count', default_cost=1, uid_attribute=None, label='Access points')[source]

DESCRIPTION:

We build access points and return them to variabe.

STEPS:

  1. Read the access point data from the source file and filter to keep only point geometries.

  2. Extract the geometry and cost/weight for each access point. If cost_attribute

  3. Build the AccessPoints object using the extracted geometries and weights.

  4. Join the access points to the network.

  5. Update the access points with the nearest edge information.

Returns:

Access points

Parameters:
  • source_file (str)

  • cost_attribute (str)

  • default_cost (float)

  • uid_attribute (str)

  • label (str)

Return type:

AccessPoints

Evaluate(raise_on_error=False)[source]

Runs spatial sanity checks on loaded layers.

Useful when CRS labels are missing or incorrect and geometry coordinates may not visually align. Does not rely on CRS metadata — all checks are based on the actual coordinate values.

Checks performed:
  1. bbox_overlap — network bounding box must intersect each

    point layer’s bounding box.

  2. coord_system — infers whether each layer looks like

    geographic (lon/lat, |x|≤180, |y|≤90) or projected, and warns when they differ.

  3. snap_distance — median distance from each access point to

    its snapped position on the network edge; large values (> 5 % of network extent) are a strong indicator of a CRS mismatch even when bboxes happen to overlap.

Parameters:

raise_on_error (bool) – bool If True, raises ValueError on the first failed check. Default False — all checks run and results are returned.

Returns:

{ ‘passed’: bool, ‘message’: str }, … }

Return type:

dict — { check_name

ExportNetworkNodes(output_file)[source]
Parameters:

output_file (str)

ExportNetworkNodesGradient(output_file)[source]

Export network nodes with gradient distances from origins.

Each column represents distances from a specific source origin node. network.node_gradient is expected to be a dict where:

key: source origin node ID value: np.array of distances to all network nodes (inf for unreachable)

Parameters:

output_file (str) – str - path to output file (.feather, .parquet, .geojson)

Parameters:

output_file (str)

ExportNetwork(output_file, geometry_column='geometry', keep_z=False, connected=False, export_filtered_edges=False)[source]
Parameters:
  • output_file (str)

  • geometry_column (str)

  • keep_z (bool)

  • connected (bool)

  • export_filtered_edges (bool)

ExportClusters(output_folder)[source]
Parameters:

output_folder (str)

classmethod from_pickle(path, verbosity=1)

Load a Topology previously saved via to_pickle. Re-attaches a fresh Logger so logging continues to work.

Parameters:
to_pickle(path)

Serialise the entire Topology (network arrays, origins, destinations, clusters, spatial indexes) to disk via pickle.

The Logger object is non-picklable on some setups; we drop it before saving and restore a fresh one on load.

Parameters:

path (str)

Return type:

None