ObjectNat 1.2.0__py3-none-any.whl → 1.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ObjectNat might be problematic. Click here for more details.
- objectnat/__init__.py +9 -13
- objectnat/_version.py +1 -1
- objectnat/methods/coverage_zones/graph_coverage.py +98 -108
- objectnat/methods/coverage_zones/radius_voronoi_coverage.py +37 -45
- objectnat/methods/coverage_zones/stepped_coverage.py +126 -142
- objectnat/methods/isochrones/isochrones.py +262 -299
- objectnat/methods/noise/__init__.py +0 -1
- objectnat/methods/noise/noise_simulation.py +452 -440
- objectnat/methods/noise/noise_simulation_simplified.py +209 -135
- objectnat/methods/point_clustering/cluster_points_in_polygons.py +115 -116
- objectnat/methods/provision/provision.py +121 -110
- objectnat/methods/provision/provision_model.py +12 -1
- objectnat/methods/utils/graph_utils.py +306 -320
- objectnat/methods/visibility/visibility_analysis.py +470 -511
- objectnat-1.2.2.dist-info/METADATA +116 -0
- objectnat-1.2.2.dist-info/RECORD +33 -0
- {objectnat-1.2.0.dist-info → objectnat-1.2.2.dist-info}/WHEEL +1 -1
- {objectnat-1.2.0.dist-info → objectnat-1.2.2.dist-info/licenses}/LICENSE.txt +28 -28
- objectnat/methods/noise/noise_exceptions.py +0 -14
- objectnat-1.2.0.dist-info/METADATA +0 -148
- objectnat-1.2.0.dist-info/RECORD +0 -34
|
@@ -1,110 +1,121 @@
|
|
|
1
|
-
from typing import Tuple
|
|
2
|
-
|
|
3
|
-
import geopandas as gpd
|
|
4
|
-
import numpy as np
|
|
5
|
-
import pandas as pd
|
|
6
|
-
|
|
7
|
-
from objectnat import config
|
|
8
|
-
|
|
9
|
-
from .provision_model import Provision
|
|
10
|
-
|
|
11
|
-
logger = config.logger
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def get_service_provision(
|
|
15
|
-
buildings: gpd.GeoDataFrame,
|
|
16
|
-
adjacency_matrix: pd.DataFrame,
|
|
17
|
-
services: gpd.GeoDataFrame,
|
|
18
|
-
threshold: int,
|
|
19
|
-
buildings_demand_column: str = "demand",
|
|
20
|
-
services_capacity_column: str = "capacity",
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
links = links.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
"
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
1
|
+
from typing import Tuple
|
|
2
|
+
|
|
3
|
+
import geopandas as gpd
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
from objectnat import config
|
|
8
|
+
|
|
9
|
+
from .provision_model import Provision
|
|
10
|
+
|
|
11
|
+
logger = config.logger
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_service_provision(
|
|
15
|
+
buildings: gpd.GeoDataFrame,
|
|
16
|
+
adjacency_matrix: pd.DataFrame,
|
|
17
|
+
services: gpd.GeoDataFrame,
|
|
18
|
+
threshold: int,
|
|
19
|
+
buildings_demand_column: str = "demand",
|
|
20
|
+
services_capacity_column: str = "capacity",
|
|
21
|
+
pandarallel_init_kwargs: dict = None,
|
|
22
|
+
) -> Tuple[gpd.GeoDataFrame, gpd.GeoDataFrame, gpd.GeoDataFrame]:
|
|
23
|
+
"""Calculate load from buildings with demands on the given services using the distances matrix between them.
|
|
24
|
+
|
|
25
|
+
Parameters:
|
|
26
|
+
services (gpd.GeoDataFrame):
|
|
27
|
+
GeoDataFrame of services
|
|
28
|
+
adjacency_matrix (pd.DataFrame):
|
|
29
|
+
DataFrame representing the adjacency matrix
|
|
30
|
+
buildings (gpd.GeoDataFrame):
|
|
31
|
+
GeoDataFrame of demanded buildings
|
|
32
|
+
threshold (int):
|
|
33
|
+
Threshold value
|
|
34
|
+
buildings_demand_column (str):
|
|
35
|
+
column name of buildings demands
|
|
36
|
+
services_capacity_column (str):
|
|
37
|
+
column name of services capacity
|
|
38
|
+
pandarallel_init_kwargs (dict):
|
|
39
|
+
Dictionary of keyword arguments to pass to pandarallel
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
(Tuple[gpd.GeoDataFrame, gpd.GeoDataFrame, gpd.GeoDataFrame]): Tuple of GeoDataFrames representing provision
|
|
43
|
+
buildings, provision services, and provision links
|
|
44
|
+
"""
|
|
45
|
+
buildings = buildings.copy()
|
|
46
|
+
services = services.copy()
|
|
47
|
+
adjacency_matrix = adjacency_matrix.copy()
|
|
48
|
+
buildings["demand"] = buildings[buildings_demand_column]
|
|
49
|
+
services["capacity"] = services[services_capacity_column]
|
|
50
|
+
|
|
51
|
+
provision_buildings, provision_services, provision_links = Provision(
|
|
52
|
+
services=services,
|
|
53
|
+
demanded_buildings=buildings,
|
|
54
|
+
adjacency_matrix=adjacency_matrix,
|
|
55
|
+
threshold=threshold,
|
|
56
|
+
pandarallel_init_kwargs=pandarallel_init_kwargs,
|
|
57
|
+
).run()
|
|
58
|
+
return provision_buildings, provision_services, provision_links
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def clip_provision(
|
|
62
|
+
buildings: gpd.GeoDataFrame, services: gpd.GeoDataFrame, links: gpd.GeoDataFrame, selection_zone: gpd.GeoDataFrame
|
|
63
|
+
) -> Tuple[gpd.GeoDataFrame, gpd.GeoDataFrame, gpd.GeoDataFrame]:
|
|
64
|
+
|
|
65
|
+
assert selection_zone.crs == buildings.crs == services.crs == links.crs, (
|
|
66
|
+
f"CRS mismatch: buildings_crs:{buildings.crs}, "
|
|
67
|
+
f"links_crs:{links.crs} , "
|
|
68
|
+
f"services_crs:{services.crs}, "
|
|
69
|
+
f"selection_zone_crs:{selection_zone.crs}"
|
|
70
|
+
)
|
|
71
|
+
buildings = buildings.copy()
|
|
72
|
+
links = links.copy()
|
|
73
|
+
services = services.copy()
|
|
74
|
+
|
|
75
|
+
s = buildings.intersects(selection_zone.union_all())
|
|
76
|
+
buildings = buildings.loc[s[s].index]
|
|
77
|
+
links = links[links["building_index"].isin(buildings.index.tolist())]
|
|
78
|
+
services_to_keep = set(links["service_index"].tolist())
|
|
79
|
+
services.drop(list(set(services.index.tolist()) - services_to_keep), inplace=True)
|
|
80
|
+
return buildings, services, links
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def recalculate_links(
|
|
84
|
+
buildings: gpd.GeoDataFrame, services: gpd.GeoDataFrame, links: gpd.GeoDataFrame, new_max_dist: float
|
|
85
|
+
) -> tuple[gpd.GeoDataFrame, gpd.GeoDataFrame, gpd.GeoDataFrame]:
|
|
86
|
+
buildings = buildings.copy()
|
|
87
|
+
services = services.copy()
|
|
88
|
+
links = links.copy()
|
|
89
|
+
|
|
90
|
+
links_to_recalculate = links[links["distance"] > new_max_dist]
|
|
91
|
+
if len(links_to_recalculate) == 0:
|
|
92
|
+
logger.warning("To clip distance exceeds max links distance, returning full provision")
|
|
93
|
+
return buildings, services, links
|
|
94
|
+
|
|
95
|
+
links_to_keep = links[links["distance"] <= new_max_dist]
|
|
96
|
+
free_demand = links_to_recalculate.groupby("building_index").agg({"demand": list, "distance": list})
|
|
97
|
+
free_demand["distance"] = free_demand.apply(
|
|
98
|
+
lambda x: sum((x1 * x2) for x1, x2 in zip(x.demand, x.distance)), axis=1
|
|
99
|
+
)
|
|
100
|
+
free_demand["demand"] = free_demand["demand"].apply(sum)
|
|
101
|
+
free_demand = free_demand.reindex(buildings.index, fill_value=0)
|
|
102
|
+
new_sum_time = (buildings["supplied_demands_within"] + buildings["supplied_demands_without"]) * buildings[
|
|
103
|
+
"avg_dist"
|
|
104
|
+
] - free_demand["distance"]
|
|
105
|
+
|
|
106
|
+
buildings["demand_left"] = buildings["demand_left"] + free_demand["demand"]
|
|
107
|
+
buildings["supplied_demands_without"] = buildings["supplied_demands_without"] - free_demand["demand"]
|
|
108
|
+
buildings["avg_dist"] = new_sum_time / (
|
|
109
|
+
buildings["supplied_demands_without"] + buildings["supplied_demands_within"]
|
|
110
|
+
)
|
|
111
|
+
buildings["avg_dist"] = buildings.apply(
|
|
112
|
+
lambda x: np.nan if (x["demand"] == x["demand_left"]) else round(x["avg_dist"], 2), axis=1
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
free_capacity = links_to_recalculate.groupby("service_index").agg({"demand": "sum"})
|
|
116
|
+
free_capacity = free_capacity.reindex(services.index, fill_value=0)
|
|
117
|
+
services["capacity_left"] = services["capacity_left"] + free_capacity["demand"]
|
|
118
|
+
services["carried_capacity_without"] = services["carried_capacity_without"] - free_capacity["demand"]
|
|
119
|
+
services["service_load"] = services["service_load"] - free_capacity["demand"]
|
|
120
|
+
|
|
121
|
+
return buildings, services, links_to_keep
|
|
@@ -40,6 +40,7 @@ class Provision:
|
|
|
40
40
|
demanded_buildings: gpd.GeoDataFrame,
|
|
41
41
|
adjacency_matrix: pd.DataFrame,
|
|
42
42
|
threshold: int,
|
|
43
|
+
pandarallel_init_kwargs: dict = None,
|
|
43
44
|
):
|
|
44
45
|
self.services = self.ensure_services(services.copy())
|
|
45
46
|
self.demanded_buildings = self.ensure_buildings(demanded_buildings.copy())
|
|
@@ -48,7 +49,16 @@ class Provision:
|
|
|
48
49
|
).copy()
|
|
49
50
|
self.threshold = threshold
|
|
50
51
|
self.services.to_crs(self.demanded_buildings.crs, inplace=True)
|
|
51
|
-
|
|
52
|
+
|
|
53
|
+
if pandarallel_init_kwargs is None:
|
|
54
|
+
pandarallel_init_kwargs = {}
|
|
55
|
+
|
|
56
|
+
pandarallel_init_kwargs["use_memory_fs"] = pandarallel_init_kwargs.get(
|
|
57
|
+
"use_memory_fs", config.pandarallel_use_file_system
|
|
58
|
+
)
|
|
59
|
+
pandarallel_init_kwargs["progress_bar"] = pandarallel_init_kwargs.get("progress_bar", False)
|
|
60
|
+
pandarallel_init_kwargs["verbose"] = pandarallel_init_kwargs.get("verbose", 0)
|
|
61
|
+
pandarallel.initialize(**pandarallel_init_kwargs)
|
|
52
62
|
|
|
53
63
|
@staticmethod
|
|
54
64
|
def ensure_buildings(v: gpd.GeoDataFrame) -> gpd.GeoDataFrame:
|
|
@@ -91,6 +101,7 @@ class Provision:
|
|
|
91
101
|
import pandas as pd # pylint: disable=redefined-outer-name,reimported,import-outside-toplevel
|
|
92
102
|
|
|
93
103
|
c = services_table.loc[loc.name]["capacity_left"]
|
|
104
|
+
logger.debug(f"Capacity left: {c}")
|
|
94
105
|
p = 1 / loc / loc
|
|
95
106
|
p = p / p.sum()
|
|
96
107
|
threshold = p.quantile(best_houses)
|