ObjectNat 0.2.5__tar.gz → 0.2.7__tar.gz

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.

Files changed (29) hide show
  1. {objectnat-0.2.5 → objectnat-0.2.7}/PKG-INFO +31 -28
  2. {objectnat-0.2.5 → objectnat-0.2.7}/README.md +28 -23
  3. {objectnat-0.2.5 → objectnat-0.2.7}/pyproject.toml +4 -5
  4. {objectnat-0.2.5 → objectnat-0.2.7}/src/objectnat/_api.py +1 -0
  5. objectnat-0.2.7/src/objectnat/_version.py +1 -0
  6. {objectnat-0.2.5 → objectnat-0.2.7}/src/objectnat/methods/isochrones.py +1 -1
  7. {objectnat-0.2.5 → objectnat-0.2.7}/src/objectnat/methods/living_buildings_osm.py +4 -6
  8. objectnat-0.2.7/src/objectnat/methods/noise/__init__.py +3 -0
  9. objectnat-0.2.7/src/objectnat/methods/noise/noise_exceptions.py +14 -0
  10. objectnat-0.2.7/src/objectnat/methods/noise/noise_init_data.py +10 -0
  11. objectnat-0.2.7/src/objectnat/methods/noise/noise_reduce.py +155 -0
  12. objectnat-0.2.7/src/objectnat/methods/noise/noise_sim.py +418 -0
  13. {objectnat-0.2.5 → objectnat-0.2.7}/src/objectnat/methods/provision/provision.py +15 -8
  14. {objectnat-0.2.5 → objectnat-0.2.7}/src/objectnat/methods/provision/provision_exceptions.py +4 -4
  15. {objectnat-0.2.5 → objectnat-0.2.7}/src/objectnat/methods/provision/provision_model.py +106 -88
  16. objectnat-0.2.7/src/objectnat/methods/utils/__init__.py +0 -0
  17. objectnat-0.2.7/src/objectnat/methods/utils/geom_utils.py +79 -0
  18. {objectnat-0.2.5 → objectnat-0.2.7}/src/objectnat/methods/visibility_analysis.py +63 -43
  19. objectnat-0.2.5/src/objectnat/_version.py +0 -1
  20. objectnat-0.2.5/src/objectnat/utils/__init__.py +0 -1
  21. objectnat-0.2.5/src/objectnat/utils/utils.py +0 -19
  22. {objectnat-0.2.5 → objectnat-0.2.7}/LICENSE.txt +0 -0
  23. {objectnat-0.2.5 → objectnat-0.2.7}/src/objectnat/__init__.py +0 -0
  24. {objectnat-0.2.5 → objectnat-0.2.7}/src/objectnat/_config.py +0 -0
  25. {objectnat-0.2.5 → objectnat-0.2.7}/src/objectnat/methods/__init__.py +0 -0
  26. {objectnat-0.2.5 → objectnat-0.2.7}/src/objectnat/methods/balanced_buildings.py +0 -0
  27. {objectnat-0.2.5 → objectnat-0.2.7}/src/objectnat/methods/cluster_points_in_polygons.py +0 -0
  28. {objectnat-0.2.5 → objectnat-0.2.7}/src/objectnat/methods/coverage_zones.py +0 -0
  29. {objectnat-0.2.5 → objectnat-0.2.7}/src/objectnat/methods/provision/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ObjectNat
3
- Version: 0.2.5
3
+ Version: 0.2.7
4
4
  Summary: ObjectNat is an open-source library created for geospatial analysis created by IDU team
5
5
  License: BSD-3-Clause
6
6
  Author: DDonnyy
@@ -12,14 +12,12 @@ Classifier: Programming Language :: Python :: 3.10
12
12
  Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Requires-Dist: geopandas (>=0.14.3,<0.15.0)
15
- Requires-Dist: iduedu (>=0.2.0,<0.3.0)
16
- Requires-Dist: joblib (>=1.4.2,<2.0.0)
15
+ Requires-Dist: iduedu (>=0.2.2,<0.3.0)
17
16
  Requires-Dist: networkx (>=3.3,<4.0)
18
- Requires-Dist: numpy (>=1.23.5,<2.0.0)
17
+ Requires-Dist: numpy (>=1.26.4,<2.0.0)
19
18
  Requires-Dist: pandarallel (>=1.6.5,<2.0.0)
20
19
  Requires-Dist: pandas (>=2.2.0,<3.0.0)
21
20
  Requires-Dist: population-restorator (>=0.2.3,<0.3.0)
22
- Requires-Dist: pulp (>=2.8.0,<3.0.0)
23
21
  Requires-Dist: scikit-learn (>=1.4.0,<2.0.0)
24
22
  Requires-Dist: tqdm (>=4.66.2,<5.0.0)
25
23
  Description-Content-Type: text/markdown
@@ -43,45 +41,52 @@ Description-Content-Type: text/markdown
43
41
 
44
42
  ## Features and how to use
45
43
 
46
- 1. **[City graph from OSM (IduEdu)](./examples/get_any_graph.ipynb)** - Functions to assemble a road, pedestrian,
47
- and public transport graph from OpenStreetMap (OSM) and creating Intermodal graph.
44
+ 1. **[City graph from OSM (IduEdu)](./examples/get_any_graph.ipynb)** - Functions to assemble a road, pedestrian, and public transport graph
45
+ from OpenStreetMap (OSM) and creating Intermodal graph.
48
46
 
49
47
  <img src="https://github.com/user-attachments/assets/8dc98da9-8462-415e-8cc8-bdfca788e206" alt="IntermodalGraph" height="250">
50
48
 
51
- 2. **[Adjacency matrix](./examples/calculate_adjacency_matrix.ipynb)** - Calculate adjacency matrix based on the provided
52
- graph and edge weight type (time or distance). The intermodal graph can be obtained using the previous example.
49
+ 2. **[Adjacency matrix](./examples/calculate_adjacency_matrix.ipynb)** - Calculate adjacency matrix based on the provided graph and edge weight type
50
+ (time or distance). The intermodal graph can be obtained using the previous example.
53
51
 
54
52
  3. **[Isochrones,transport accessibility](./examples/isochrone_generator.ipynb)** - Function for generating isochrones to
55
- analyze transportation accessibility from specified starting coordinates. Isochrones can be constructed based on
56
- pedestrian, automobile, or public transport graphs, or a combination thereof.
53
+ analyze transportation accessibility from specified starting coordinates. Isochrones can be constructed based on
54
+ pedestrian, automobile, or public transport graphs, or a combination thereof.
57
55
 
58
56
  <img src="https://github.com/user-attachments/assets/37f308a5-db56-497d-b080-4edef3584fe5" alt="isochrones" height="250">
59
57
 
60
58
  4. **[Population restoration](./examples/restore_population.ipynb)** - Function for resettling population into the provided
61
- layer of residential buildings. This function distributes people among dwellings based on the total city population
62
- and the living area of each house.
63
- 5. **[Service provision](./examples/calculate_provision.ipynb)** - Function for calculating the provision of residential
64
- buildings and population with services.
59
+ layer of residential buildings. This function distributes people among dwellings based on the total city population
60
+ and the living area of each house.
61
+ 5. **[Service provision](./examples/calculate_provision.ipynb)** - Function for calculating the provision of residential buildings and population
62
+ with services.
65
63
 
66
64
  <img src="https://github.com/user-attachments/assets/5f2b3c55-9a02-4d70-80f4-503b77023eda" alt="ProvisionSchools" height="250">
67
65
 
68
66
  6. **[Visibility analysis](./examples/visibility_analysis.ipynb)** - Function to get a quick estimate of visibility from a
69
- given point(s) to buildings within a given distance. Also, there is a visibility catchment area calculator for a
70
- large
71
- urban area. This function is designed to work with at least 1000 points spaced 10-20 meters apart for optimal
72
- results. Points can be generated using a road graph and random point distribution along edges.
67
+ given point(s) to buildings within a given distance. Also, there is a visibility catchment area calculator for a large
68
+ urban area. This function is designed to work with at least 1000 points spaced 10-20 meters apart for optimal
69
+ results. Points can be generated using a road graph and random point distribution along edges.
73
70
 
74
71
  <img src="https://github.com/user-attachments/assets/2927ac86-01e8-4b0e-9ea8-72ad81c13cf5" alt="visibility-from-point" height="250">
75
72
 
76
73
  <img src="https://github.com/user-attachments/assets/b5b0d4b3-a02f-4ade-8772-475703cd6435" alt="visibility-catchment-area" height="250">
77
-
78
- 7. **[Point clusterization](./examples/point_clusterization.ipynb)** - Function to generate cluster polygons for given
79
- points based on a specified minimum distance and minimum points per cluster. Optionally, calculate the relative ratio
80
- between types of services within the clusters.
74
+
75
+ 7. **[Noise simulation](./examples/noise_simulation.ipynb)** - Simulates noise propagation from a set of source points
76
+ considering obstacles, trees, and environmental factors.
77
+ **[Detailed information in Wiki](https://github.com/DDonnyy/ObjectNat/wiki/Noise-simulation)**
78
+
79
+ <img src="https://github.com/user-attachments/assets/dd185867-67c4-4d03-8905-d06dd1d36fb3" alt="noise_sim" height="250">
80
+
81
+ 8. **[Point clusterization](./examples/point_clusterization.ipynb)** - Function to generate cluster polygons for given
82
+ points based on a specified minimum distance and minimum points per cluster. Optionally, calculate the relative ratio
83
+ between types of services within the clusters.
81
84
 
82
85
  <img src="https://github.com/user-attachments/assets/2a9ad722-87d2-4954-9612-5ac3765aa824" alt="service-clusterization" height="250">
83
86
 
84
- 8. **[Living buildings from OSM](./examples/download_buildings_from_osm.ipynb)** - This function downloads building geometries from OpenStreetMap (OSM) for a specified territory and assigns attributes to each building. Specifically, it determines whether a building is residential (`is_living` attribute) and estimates the approximate number of inhabitants (`approximate_pop` attribute).
87
+ 9. **[Living buildings from OSM](./examples/download_buildings_from_osm.ipynb)** - This function downloads building geometries from OpenStreetMap (OSM)
88
+ for a specified territory and assigns attributes to each building. Specifically, it determines whether a building
89
+ is residential (`is_living` attribute) and estimates the approximate number of inhabitants (`approximate_pop` attribute).
85
90
 
86
91
  <img src="https://github.com/user-attachments/assets/d60dcd85-1a2e-4342-aae4-561aeda18858" alt="Living buildings" height="250">
87
92
 
@@ -104,10 +109,8 @@ config.set_overpass_url('http://your.overpass-api.de/interpreter/URL')
104
109
  ```
105
110
  ## Contacts
106
111
 
107
- - [NCCR](https://actcognitive.org/) - National
108
- Center for Cognitive Research
109
- - [IDU](https://idu.itmo.ru/) - Institute of
110
- Design and Urban Studies
112
+ - [NCCR](https://actcognitive.org/) - National Center for Cognitive Research
113
+ - [IDU](https://idu.itmo.ru/) - Institute of Design and Urban Studies
111
114
  - [Natalya Chichkova](https://t.me/nancy_nat) - project manager
112
115
  - [Danila Oleynikov (Donny)](https://t.me/ddonny_dd) - lead software engineer
113
116
 
@@ -17,45 +17,52 @@
17
17
 
18
18
  ## Features and how to use
19
19
 
20
- 1. **[City graph from OSM (IduEdu)](./examples/get_any_graph.ipynb)** - Functions to assemble a road, pedestrian,
21
- and public transport graph from OpenStreetMap (OSM) and creating Intermodal graph.
20
+ 1. **[City graph from OSM (IduEdu)](./examples/get_any_graph.ipynb)** - Functions to assemble a road, pedestrian, and public transport graph
21
+ from OpenStreetMap (OSM) and creating Intermodal graph.
22
22
 
23
23
  <img src="https://github.com/user-attachments/assets/8dc98da9-8462-415e-8cc8-bdfca788e206" alt="IntermodalGraph" height="250">
24
24
 
25
- 2. **[Adjacency matrix](./examples/calculate_adjacency_matrix.ipynb)** - Calculate adjacency matrix based on the provided
26
- graph and edge weight type (time or distance). The intermodal graph can be obtained using the previous example.
25
+ 2. **[Adjacency matrix](./examples/calculate_adjacency_matrix.ipynb)** - Calculate adjacency matrix based on the provided graph and edge weight type
26
+ (time or distance). The intermodal graph can be obtained using the previous example.
27
27
 
28
28
  3. **[Isochrones,transport accessibility](./examples/isochrone_generator.ipynb)** - Function for generating isochrones to
29
- analyze transportation accessibility from specified starting coordinates. Isochrones can be constructed based on
30
- pedestrian, automobile, or public transport graphs, or a combination thereof.
29
+ analyze transportation accessibility from specified starting coordinates. Isochrones can be constructed based on
30
+ pedestrian, automobile, or public transport graphs, or a combination thereof.
31
31
 
32
32
  <img src="https://github.com/user-attachments/assets/37f308a5-db56-497d-b080-4edef3584fe5" alt="isochrones" height="250">
33
33
 
34
34
  4. **[Population restoration](./examples/restore_population.ipynb)** - Function for resettling population into the provided
35
- layer of residential buildings. This function distributes people among dwellings based on the total city population
36
- and the living area of each house.
37
- 5. **[Service provision](./examples/calculate_provision.ipynb)** - Function for calculating the provision of residential
38
- buildings and population with services.
35
+ layer of residential buildings. This function distributes people among dwellings based on the total city population
36
+ and the living area of each house.
37
+ 5. **[Service provision](./examples/calculate_provision.ipynb)** - Function for calculating the provision of residential buildings and population
38
+ with services.
39
39
 
40
40
  <img src="https://github.com/user-attachments/assets/5f2b3c55-9a02-4d70-80f4-503b77023eda" alt="ProvisionSchools" height="250">
41
41
 
42
42
  6. **[Visibility analysis](./examples/visibility_analysis.ipynb)** - Function to get a quick estimate of visibility from a
43
- given point(s) to buildings within a given distance. Also, there is a visibility catchment area calculator for a
44
- large
45
- urban area. This function is designed to work with at least 1000 points spaced 10-20 meters apart for optimal
46
- results. Points can be generated using a road graph and random point distribution along edges.
43
+ given point(s) to buildings within a given distance. Also, there is a visibility catchment area calculator for a large
44
+ urban area. This function is designed to work with at least 1000 points spaced 10-20 meters apart for optimal
45
+ results. Points can be generated using a road graph and random point distribution along edges.
47
46
 
48
47
  <img src="https://github.com/user-attachments/assets/2927ac86-01e8-4b0e-9ea8-72ad81c13cf5" alt="visibility-from-point" height="250">
49
48
 
50
49
  <img src="https://github.com/user-attachments/assets/b5b0d4b3-a02f-4ade-8772-475703cd6435" alt="visibility-catchment-area" height="250">
51
-
52
- 7. **[Point clusterization](./examples/point_clusterization.ipynb)** - Function to generate cluster polygons for given
53
- points based on a specified minimum distance and minimum points per cluster. Optionally, calculate the relative ratio
54
- between types of services within the clusters.
50
+
51
+ 7. **[Noise simulation](./examples/noise_simulation.ipynb)** - Simulates noise propagation from a set of source points
52
+ considering obstacles, trees, and environmental factors.
53
+ **[Detailed information in Wiki](https://github.com/DDonnyy/ObjectNat/wiki/Noise-simulation)**
54
+
55
+ <img src="https://github.com/user-attachments/assets/dd185867-67c4-4d03-8905-d06dd1d36fb3" alt="noise_sim" height="250">
56
+
57
+ 8. **[Point clusterization](./examples/point_clusterization.ipynb)** - Function to generate cluster polygons for given
58
+ points based on a specified minimum distance and minimum points per cluster. Optionally, calculate the relative ratio
59
+ between types of services within the clusters.
55
60
 
56
61
  <img src="https://github.com/user-attachments/assets/2a9ad722-87d2-4954-9612-5ac3765aa824" alt="service-clusterization" height="250">
57
62
 
58
- 8. **[Living buildings from OSM](./examples/download_buildings_from_osm.ipynb)** - This function downloads building geometries from OpenStreetMap (OSM) for a specified territory and assigns attributes to each building. Specifically, it determines whether a building is residential (`is_living` attribute) and estimates the approximate number of inhabitants (`approximate_pop` attribute).
63
+ 9. **[Living buildings from OSM](./examples/download_buildings_from_osm.ipynb)** - This function downloads building geometries from OpenStreetMap (OSM)
64
+ for a specified territory and assigns attributes to each building. Specifically, it determines whether a building
65
+ is residential (`is_living` attribute) and estimates the approximate number of inhabitants (`approximate_pop` attribute).
59
66
 
60
67
  <img src="https://github.com/user-attachments/assets/d60dcd85-1a2e-4342-aae4-561aeda18858" alt="Living buildings" height="250">
61
68
 
@@ -78,10 +85,8 @@ config.set_overpass_url('http://your.overpass-api.de/interpreter/URL')
78
85
  ```
79
86
  ## Contacts
80
87
 
81
- - [NCCR](https://actcognitive.org/) - National
82
- Center for Cognitive Research
83
- - [IDU](https://idu.itmo.ru/) - Institute of
84
- Design and Urban Studies
88
+ - [NCCR](https://actcognitive.org/) - National Center for Cognitive Research
89
+ - [IDU](https://idu.itmo.ru/) - Institute of Design and Urban Studies
85
90
  - [Natalya Chichkova](https://t.me/nancy_nat) - project manager
86
91
  - [Danila Oleynikov (Donny)](https://t.me/ddonny_dd) - lead software engineer
87
92
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "ObjectNat"
3
- version = "0.2.5"
3
+ version = "0.2.7"
4
4
  description = "ObjectNat is an open-source library created for geospatial analysis created by IDU team"
5
5
  license = "BSD-3-Clause"
6
6
  authors = ["DDonnyy <63115678+DDonnyy@users.noreply.github.com>"]
@@ -10,16 +10,14 @@ packages = [{ include = "objectnat", from = "src" }]
10
10
 
11
11
  [tool.poetry.dependencies]
12
12
  python = ">=3.10,<3.13"
13
- numpy = "^1.23.5"
13
+ numpy = "^1.26.4"
14
14
  pandas = "^2.2.0"
15
15
  geopandas = "^0.14.3"
16
16
  tqdm = "^4.66.2"
17
17
  pandarallel = "^1.6.5"
18
18
  networkx = "^3.3"
19
- pulp = "^2.8.0"
20
19
  population-restorator = "^0.2.3"
21
- iduedu = "^0.2.0"
22
- joblib = "^1.4.2"
20
+ iduedu = "^0.2.2"
23
21
  scikit-learn = "^1.4.0"
24
22
 
25
23
 
@@ -44,6 +42,7 @@ max-locals = 20
44
42
  extension-pkg-allow-list = ["networkit"]
45
43
  disable = [
46
44
  "duplicate-code",
45
+ "too-many-positional-arguments",
47
46
  "missing-module-docstring",
48
47
  "missing-function-docstring",
49
48
  "too-many-locals",
@@ -6,6 +6,7 @@ from .methods.cluster_points_in_polygons import get_clusters_polygon
6
6
  from .methods.coverage_zones import get_isochrone_zone_coverage, get_radius_zone_coverage
7
7
  from .methods.isochrones import get_accessibility_isochrones
8
8
  from .methods.living_buildings_osm import download_buildings
9
+ from .methods.noise import simulate_noise
9
10
  from .methods.provision.provision import clip_provision, get_service_provision, recalculate_links
10
11
  from .methods.visibility_analysis import (
11
12
  calculate_visibility_catchment_area,
@@ -0,0 +1 @@
1
+ VERSION = "0.2.7"
@@ -57,7 +57,7 @@ def get_accessibility_isochrones(
57
57
  >>> from iduedu import get_intermodal_graph
58
58
  >>> graph = get_intermodal_graph(polygon=my_territory_polygon)
59
59
  >>> points = gpd.GeoDataFrame(geometry=[Point(30.33, 59.95)], crs=4326).to_crs(graph.graph['crs'])
60
- >>> isochrones, pt_stops, pt_routes = get_accessibility_isochrones(points,weight_value=15, weight_type="time_min", graph_nx=my_graph)
60
+ >>> isochrones, stops, routes = get_accessibility_isochrones(points,15,weight_type="time_min", graph_nx=graph)
61
61
 
62
62
  """
63
63
 
@@ -7,8 +7,6 @@ from shapely import MultiPolygon, Polygon
7
7
 
8
8
  from objectnat import config
9
9
 
10
- from ..utils import get_utm_crs_for_4326_gdf
11
-
12
10
  logger = config.logger
13
11
 
14
12
 
@@ -75,9 +73,9 @@ def eval_population(source: gpd.GeoDataFrame, population_column: str, area_per_p
75
73
  if "building:levels" not in source.columns:
76
74
  raise RuntimeError("No 'building:levels' column in provided GeoDataFrame")
77
75
  df = source.copy()
78
- local_utm_crs = get_utm_crs_for_4326_gdf(source.to_crs(4326))
79
- df["area"] = df.to_crs(local_utm_crs.to_epsg()).geometry.area.astype(float)
80
- df["building:levels_is_real"] = df["building:levels"].apply(lambda x: False if pd.isna(x) else True)
76
+ local_crs = source.estimate_utm_crs()
77
+ df["area"] = df.to_crs(local_crs).geometry.area.astype(float)
78
+ df["building:levels_is_real"] = df["building:levels"].apply(lambda x: not pd.isna(x))
81
79
  df["building:levels"] = df["building:levels"].fillna(1)
82
80
  df["building:levels"] = pd.to_numeric(df["building:levels"], errors="coerce")
83
81
  df = df.dropna(subset=["building:levels"])
@@ -128,7 +126,7 @@ def download_buildings(
128
126
  Returns
129
127
  -------
130
128
  gpd.GeoDataFrame or None
131
- A GeoDataFrame containing building geometries and attributes, or None if no buildings are found or an error occurs.
129
+ A GeoDataFrame containing building geometries and attributes, or None if no buildings are found.
132
130
 
133
131
  Examples
134
132
  --------
@@ -0,0 +1,3 @@
1
+ from .noise_sim import simulate_noise
2
+ from .noise_reduce import dist_to_target_db,green_noise_reduce_db
3
+ from .noise_exceptions import InvalidStepError
@@ -0,0 +1,14 @@
1
+ class InvalidStepError(ValueError):
2
+ def __init__(self, source_noise_db, target_noise_db, db_sim_step, div_, *args):
3
+ if args:
4
+ self.message = args[0]
5
+ else:
6
+ self.message = (
7
+ f"The difference between `source_noise_db`({source_noise_db}) and `target_noise_db`({target_noise_db})"
8
+ f" is not divisible by the step size ({db_sim_step}, remainder = {div_})"
9
+ )
10
+
11
+ def __str__(self):
12
+ if self.message:
13
+ return self.message
14
+ return "The difference between `source_noise_db` and `target_noise_db` is not divisible by the step size"
@@ -0,0 +1,10 @@
1
+ import pandas as pd
2
+
3
+ data = {
4
+ 30: {63: 0, 125: 0.0002, 250: 0.0009, 500: 0.003, 1000: 0.0075, 2000: 0.014, 4000: 0.025, 8000: 0.064},
5
+ 20: {63: 0, 125: 0.0003, 250: 0.0011, 500: 0.0028, 1000: 0.0052, 2000: 0.0096, 4000: 0.025, 8000: 0.083},
6
+ 10: {63: 0, 125: 0.0004, 250: 0.001, 500: 0.002, 1000: 0.0039, 2000: 0.01, 4000: 0.035, 8000: 0.125},
7
+ 0: {63: 0, 125: 0.0004, 250: 0.0008, 500: 0.0017, 1000: 0.0049, 2000: 0.017, 4000: 0.058, 8000: 0.156},
8
+ }
9
+
10
+ air_resist_ratio = pd.DataFrame(data)
@@ -0,0 +1,155 @@
1
+ import numpy as np
2
+ from scipy.optimize import fsolve
3
+
4
+ from objectnat import config
5
+
6
+ from .noise_init_data import air_resist_ratio
7
+
8
+ logger = config.logger
9
+
10
+
11
+ def get_air_resist_ratio(temp, freq, check_temp_freq=False):
12
+ if check_temp_freq:
13
+ if temp > max(air_resist_ratio.columns) or temp < min(air_resist_ratio.columns):
14
+ logger.warning(
15
+ f"The specified temperature of {temp}°C is outside the tabulated data range. "
16
+ f"The air resistance coefficient for these values may be inaccurate. "
17
+ f"Recommended temperature range: {min(air_resist_ratio.columns)}°C "
18
+ f"to {max(air_resist_ratio.columns)}°C."
19
+ )
20
+
21
+ if freq > max(air_resist_ratio.index) or freq < min(air_resist_ratio.index):
22
+ logger.warning(
23
+ f"The specified geometric mean frequency of {freq} Hz is outside the tabulated data range."
24
+ f" The air resistance coefficient for these values may be inaccurate."
25
+ f" Recommended frequency range: {min(air_resist_ratio.index)} Hz to {max(air_resist_ratio.index)} Hz."
26
+ )
27
+
28
+ def get_nearest_values(array, value):
29
+ sorted_array = sorted(array)
30
+ if value in sorted_array:
31
+ return [value]
32
+ if value > max(sorted_array):
33
+ return [sorted_array[-1]]
34
+ if value < min(sorted_array):
35
+ return [sorted_array[0]]
36
+
37
+ for i, val in enumerate(sorted_array):
38
+ if value < val:
39
+ return sorted_array[max(i - 1, 0)], sorted_array[i]
40
+ return sorted_array[-2], sorted_array[-1]
41
+
42
+ nearest_temp = get_nearest_values(air_resist_ratio.columns, temp)
43
+ nearest_freq = get_nearest_values(air_resist_ratio.index, freq)
44
+
45
+ if len(nearest_temp) == 1 and len(nearest_freq) == 1:
46
+ return air_resist_ratio.loc[nearest_freq[0], nearest_temp[0]]
47
+
48
+ if len(nearest_temp) == 2 and len(nearest_freq) == 2:
49
+ freq1, freq2 = nearest_freq
50
+ temp1, temp2 = nearest_temp
51
+
52
+ coef_temp1_freq1 = air_resist_ratio.loc[freq1, temp1]
53
+ coef_temp1_freq2 = air_resist_ratio.loc[freq2, temp1]
54
+ coef_temp2_freq1 = air_resist_ratio.loc[freq1, temp2]
55
+ coef_temp2_freq2 = air_resist_ratio.loc[freq2, temp2]
56
+
57
+ weight_temp1 = (temp2 - temp) / (temp2 - temp1)
58
+ weight_temp2 = (temp - temp1) / (temp2 - temp1)
59
+ weight_freq1 = (freq2 - freq) / (freq2 - freq1)
60
+ weight_freq2 = (freq - freq1) / (freq2 - freq1)
61
+
62
+ coef_freq1 = coef_temp1_freq1 * weight_temp1 + coef_temp2_freq1 * weight_temp2
63
+ coef_freq2 = coef_temp1_freq2 * weight_temp1 + coef_temp2_freq2 * weight_temp2
64
+
65
+ final_coef = coef_freq1 * weight_freq1 + coef_freq2 * weight_freq2
66
+
67
+ return final_coef
68
+
69
+ if len(nearest_temp) == 2 and len(nearest_freq) == 1:
70
+ temp1, temp2 = nearest_temp
71
+ freq1 = nearest_freq[0]
72
+
73
+ coef_temp1 = air_resist_ratio.loc[freq1, temp1]
74
+ coef_temp2 = air_resist_ratio.loc[freq1, temp2]
75
+
76
+ weight_temp1 = (temp2 - temp) / (temp2 - temp1)
77
+ weight_temp2 = (temp - temp1) / (temp2 - temp1)
78
+
79
+ return coef_temp1 * weight_temp1 + coef_temp2 * weight_temp2
80
+
81
+ if len(nearest_temp) == 1 and len(nearest_freq) == 2:
82
+ temp1 = nearest_temp[0]
83
+ freq1, freq2 = nearest_freq
84
+
85
+ coef_freq1 = air_resist_ratio.loc[freq1, temp1]
86
+ coef_freq2 = air_resist_ratio.loc[freq2, temp1]
87
+
88
+ weight_freq1 = (freq2 - freq) / (freq2 - freq1)
89
+ weight_freq2 = (freq - freq1) / (freq2 - freq1)
90
+
91
+ return coef_freq1 * weight_freq1 + coef_freq2 * weight_freq2
92
+
93
+
94
+ def dist_to_target_db(
95
+ init_noise_db, target_noise_db, geometric_mean_freq_hz, air_temperature, return_desc=False, check_temp_freq=False
96
+ ) -> float | str:
97
+ """
98
+ Calculates the distance required for a sound wave to decay from an initial noise level to a target noise level,
99
+ based on the geometric mean frequency of the sound and the air temperature. Optionally, can return a description
100
+ of the sound propagation behavior.
101
+
102
+ Args:
103
+ init_noise_db (float): The initial noise level of the source in decibels (dB). This is the starting sound
104
+ intensity.
105
+ target_noise_db (float): The target noise level in decibels (dB), representing the level to which the sound
106
+ decays over distance.
107
+ geometric_mean_freq_hz (float): The geometric mean frequency of the sound (in Hz). This frequency influences
108
+ the attenuation of sound over distance. Higher frequencies decay faster than lower ones.
109
+ air_temperature (float): The temperature of the air in degrees Celsius. This influences the air's resistance
110
+ to sound propagation.
111
+ return_desc (bool, optional): If set to `True`, the function will return a description of the sound decay
112
+ process instead of the calculated distance.
113
+ check_temp_freq (bool, optional): If `True`, the function will check whether the temperature and frequency
114
+ are within valid ranges.
115
+
116
+ Returns:
117
+ float or str: If `return_desc` is `False`, the function returns the distance (in meters) over which the sound
118
+ decays from `init_noise_db` to `target_noise_db`. If `return_desc` is `True`, a descriptive string is returned
119
+ explaining the calculation and the conditions.
120
+ """
121
+
122
+ def equation(r):
123
+ return l - l_ist + 20 * np.log10(r) + k * r
124
+
125
+ l_ist = init_noise_db
126
+ l = target_noise_db
127
+ k = get_air_resist_ratio(air_temperature, geometric_mean_freq_hz, check_temp_freq)
128
+ initial_guess = 1
129
+ r_solution = fsolve(equation, initial_guess)
130
+ if return_desc:
131
+ string = (
132
+ f"Noise level of {init_noise_db} dB "
133
+ f"with a geometric mean frequency of {geometric_mean_freq_hz} Hz "
134
+ f"at an air temperature of {air_temperature}°C decays to {target_noise_db} dB "
135
+ f"over a distance of {r_solution[0]} meters. Air resistance coefficient: {k}."
136
+ )
137
+ return string
138
+ return r_solution[0]
139
+
140
+
141
+ def green_noise_reduce_db(geometric_mean_freq_hz, r_tree) -> float:
142
+ """
143
+ Calculates the amount of noise reduction (in dB) provided by vegetation of a given thickness at a specified
144
+ geometric mean frequency. The function models the reduction based on the interaction of the sound with trees or
145
+ vegetation.
146
+
147
+ Args:
148
+ geometric_mean_freq_hz (float): The geometric mean frequency of the sound (in Hz).
149
+ r_tree (float): The thickness or density of the vegetation (in meters).
150
+
151
+ Returns:
152
+ float: The noise reduction (in dB) achieved by the vegetation. This value indicates how much quieter the sound
153
+ will be after passing through or interacting with the vegetation of the specified thickness.
154
+ """
155
+ return round(0.08 * r_tree * ((geometric_mean_freq_hz ** (1 / 3)) / 8), 1)