gridconnect 0.2.0__tar.gz → 0.2.2__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.
Files changed (45) hide show
  1. gridconnect-0.2.2/LICENSE +21 -0
  2. {gridconnect-0.2.0 → gridconnect-0.2.2}/PKG-INFO +3 -2
  3. {gridconnect-0.2.0 → gridconnect-0.2.2}/README.md +1 -1
  4. gridconnect-0.2.2/gridconnect/io/__init__.py +6 -0
  5. gridconnect-0.2.2/gridconnect/io/profiles.py +116 -0
  6. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/matching/data.py +30 -21
  7. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/network/loads.py +34 -36
  8. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect.egg-info/PKG-INFO +3 -2
  9. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect.egg-info/SOURCES.txt +1 -0
  10. {gridconnect-0.2.0 → gridconnect-0.2.2}/pyproject.toml +4 -2
  11. gridconnect-0.2.0/LICENSE +0 -25
  12. gridconnect-0.2.0/gridconnect/io/__init__.py +0 -5
  13. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/analysis/__init__.py +0 -0
  14. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/analysis/load_shifting.py +0 -0
  15. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/analysis/power_flow.py +0 -0
  16. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/analysis/power_proxy.py +0 -0
  17. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/analysis/reconfiguration.py +0 -0
  18. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/analysis/reinforcement.py +0 -0
  19. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/api/__init__.py +0 -0
  20. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/api/building_bus_matcher.py +0 -0
  21. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/api/manager.py +0 -0
  22. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/io/conversion.py +0 -0
  23. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/matching/__init__.py +0 -0
  24. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/matching/area.py +0 -0
  25. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/matching/buses.py +0 -0
  26. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/matching/config.py +0 -0
  27. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/matching/network.py +0 -0
  28. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/matching/splitting.py +0 -0
  29. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/network/__init__.py +0 -0
  30. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/network/snapshots.py +0 -0
  31. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/network/state.py +0 -0
  32. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/network/topology.py +0 -0
  33. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/plotting/__init__.py +0 -0
  34. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/plotting/building_bus_match.py +0 -0
  35. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/plotting/network.py +0 -0
  36. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/results/__init__.py +0 -0
  37. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/results/constraints.py +0 -0
  38. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/results/loads.py +0 -0
  39. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/results/reinforcement.py +0 -0
  40. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/results/snapshots.py +0 -0
  41. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect/utils/logger.py +0 -0
  42. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect.egg-info/dependency_links.txt +0 -0
  43. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect.egg-info/requires.txt +0 -0
  44. {gridconnect-0.2.0 → gridconnect-0.2.2}/gridconnect.egg-info/top_level.txt +0 -0
  45. {gridconnect-0.2.0 → gridconnect-0.2.2}/setup.cfg +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yoann Chiche
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,8 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gridconnect
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: A package for connecting building-scale load profiles to distribution networks and preparing simulation-ready network models.
5
5
  Author-email: Yoann Chiche <yoann.chiche@minesparis.psl.eu>
6
+ License-Expression: MIT
6
7
  Requires-Python: >=3.12
7
8
  Description-Content-Type: text/markdown
8
9
  License-File: LICENSE
@@ -105,7 +106,7 @@ data. Default paths are configurable through `BuildingBusMatchConfig` and
105
106
  | Input | Format | Required content |
106
107
  | --- | --- | --- |
107
108
  | Building data | District Parquet files | Building identifiers, geometry, usage, and floor area. |
108
- | Load profiles | `energy_model_<district>.parquet` | `datetime`, `building_id`, `name`, `main_usage`, `district`, and `electricity_need` (kW). |
109
+ | Load profiles | `energy_model_static_<district>.parquet` and `energy_model_hourly_<district>.parquet` (`building_eload` >= 0.6.0), or a single legacy `energy_model_<district>.parquet` | Static: `building_id`, `name`, `main_usage`, `district`, `total_electricity_need`, and `floor_area`. Hourly: `building_id`, `datetime`, and `electricity_need` (kW). A legacy file holds all of these columns. |
109
110
  | Building-to-bus connections | Parquet or DataFrame | The connection schema returned by `BuildingBusMatcher`. |
110
111
  | District areas | Parquet | District geometry used to resolve the feeder study area. |
111
112
  | ORE network geometries | Parquet | Low- and medium-voltage overhead and underground line geometries. |
@@ -77,7 +77,7 @@ data. Default paths are configurable through `BuildingBusMatchConfig` and
77
77
  | Input | Format | Required content |
78
78
  | --- | --- | --- |
79
79
  | Building data | District Parquet files | Building identifiers, geometry, usage, and floor area. |
80
- | Load profiles | `energy_model_<district>.parquet` | `datetime`, `building_id`, `name`, `main_usage`, `district`, and `electricity_need` (kW). |
80
+ | Load profiles | `energy_model_static_<district>.parquet` and `energy_model_hourly_<district>.parquet` (`building_eload` >= 0.6.0), or a single legacy `energy_model_<district>.parquet` | Static: `building_id`, `name`, `main_usage`, `district`, `total_electricity_need`, and `floor_area`. Hourly: `building_id`, `datetime`, and `electricity_need` (kW). A legacy file holds all of these columns. |
81
81
  | Building-to-bus connections | Parquet or DataFrame | The connection schema returned by `BuildingBusMatcher`. |
82
82
  | District areas | Parquet | District geometry used to resolve the feeder study area. |
83
83
  | ORE network geometries | Parquet | Low- and medium-voltage overhead and underground line geometries. |
@@ -0,0 +1,6 @@
1
+ """Input and output conversion helpers for GridConnect datasets.
2
+
3
+ The package provides conversion of serialized-geometry CSV input to GeoParquet
4
+ for the building-to-bus matching workflow, and reading of per-district building
5
+ energy profiles in both ``building_eload`` output layouts.
6
+ """
@@ -0,0 +1,116 @@
1
+ """Locate and read per-district building energy profiles.
2
+
3
+ ``building_eload`` >= 0.6.0 writes each district's output as separate
4
+ ``energy_model_static_<district>.parquet`` (one row per building) and
5
+ ``energy_model_hourly_<district>.parquet`` (one row per building and hour)
6
+ files. Earlier versions wrote a single denormalized
7
+ ``energy_model_<district>.parquet`` file. Both layouts are supported; the split
8
+ layout takes precedence when both are present.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import logging
14
+ from pathlib import Path
15
+
16
+ import polars as pl
17
+
18
+ STATIC_COLUMNS = (
19
+ "building_id",
20
+ "name",
21
+ "main_usage",
22
+ "district",
23
+ "total_electricity_need",
24
+ "floor_area",
25
+ )
26
+ HOURLY_COLUMNS = ("building_id", "datetime", "electricity_need")
27
+
28
+ logger = logging.getLogger(__name__)
29
+
30
+
31
+ def static_profile_path(profile_dir: str | Path, district: str) -> Path:
32
+ """Return the split-layout static profile path of one district."""
33
+ return Path(profile_dir) / f"energy_model_static_{district}.parquet"
34
+
35
+
36
+ def hourly_profile_path(profile_dir: str | Path, district: str) -> Path:
37
+ """Return the split-layout hourly profile path of one district."""
38
+ return Path(profile_dir) / f"energy_model_hourly_{district}.parquet"
39
+
40
+
41
+ def legacy_profile_path(profile_dir: str | Path, district: str) -> Path:
42
+ """Return the single-file (pre-0.6.0) profile path of one district."""
43
+ return Path(profile_dir) / f"energy_model_{district}.parquet"
44
+
45
+
46
+ def has_district_profiles(profile_dir: str | Path, district: str) -> bool:
47
+ """Return whether a directory holds profiles of one district in any layout."""
48
+ return (
49
+ static_profile_path(profile_dir, district).exists()
50
+ and hourly_profile_path(profile_dir, district).exists()
51
+ ) or legacy_profile_path(profile_dir, district).exists()
52
+
53
+
54
+ def scan_district_profiles(
55
+ profile_dir: str | Path, district: str
56
+ ) -> pl.LazyFrame | None:
57
+ """Lazily read one district's hourly profiles with per-building attributes.
58
+
59
+ Args:
60
+ profile_dir: Directory containing district profile files.
61
+ district: District identifier.
62
+
63
+ Returns:
64
+ Lazy frame with at least the ``HOURLY_COLUMNS`` and ``STATIC_COLUMNS``
65
+ columns, or ``None`` when no profile file exists for the district.
66
+ ``electricity_need`` is passed through in kW.
67
+
68
+ Raises:
69
+ ValueError: If a split-layout file lacks a required column.
70
+ """
71
+ static_file = static_profile_path(profile_dir, district)
72
+ hourly_file = hourly_profile_path(profile_dir, district)
73
+ if static_file.exists() and hourly_file.exists():
74
+ return _scan_split_profiles(static_file, hourly_file)
75
+
76
+ legacy_file = legacy_profile_path(profile_dir, district)
77
+ if legacy_file.exists():
78
+ return pl.scan_parquet(legacy_file)
79
+
80
+ if static_file.exists() or hourly_file.exists():
81
+ logger.warning(
82
+ "Incomplete split profiles for district %s in '%s': both '%s' and "
83
+ "'%s' are required.",
84
+ district,
85
+ profile_dir,
86
+ static_file.name,
87
+ hourly_file.name,
88
+ )
89
+ return None
90
+
91
+
92
+ def _scan_split_profiles(static_file: Path, hourly_file: Path) -> pl.LazyFrame:
93
+ """Join split-layout hourly rows to their static building attributes."""
94
+ static = pl.scan_parquet(static_file)
95
+ hourly = pl.scan_parquet(hourly_file)
96
+ for frame, columns, file in (
97
+ (static, STATIC_COLUMNS, static_file),
98
+ (hourly, HOURLY_COLUMNS, hourly_file),
99
+ ):
100
+ missing = sorted(set(columns).difference(frame.collect_schema().names()))
101
+ if missing:
102
+ raise ValueError(
103
+ f"'{file}' is missing required column(s): {', '.join(missing)}."
104
+ )
105
+
106
+ # Keep the join one-to-many even if several rows share a building_id.
107
+ static = static.select(STATIC_COLUMNS).unique(
108
+ subset="building_id", keep="first", maintain_order=True
109
+ )
110
+ return (
111
+ hourly.select(HOURLY_COLUMNS)
112
+ .join(static, on="building_id", how="inner")
113
+ # building_eload stores district as Categorical; downstream merges
114
+ # compare it against plain strings.
115
+ .with_columns(pl.col("district").cast(pl.String))
116
+ )
@@ -18,10 +18,13 @@ except ImportError: # pragma: no cover - optional runtime dependency
18
18
  import geopandas as gpd
19
19
  import numpy as np
20
20
  import pandas as pd
21
+ import polars as pl
21
22
  from shapely import wkb
22
23
  from shapely.geometry import Point
23
24
  from tqdm import tqdm
24
25
 
26
+ from gridconnect.io.profiles import scan_district_profiles
27
+
25
28
  KW_TO_MW = 1000.0
26
29
  REACTIVE_POWER_FACTOR = 0.3
27
30
 
@@ -284,13 +287,6 @@ class MatchingDataLoader:
284
287
  def _load_energy_profiles(self) -> pd.DataFrame:
285
288
  """Load and aggregate building energy profiles."""
286
289
  aggregated_frames: list[pd.DataFrame] = []
287
- columns = [
288
- "name",
289
- "building_id",
290
- "total_electricity_need",
291
- "electricity_need",
292
- "floor_area",
293
- ]
294
290
  for district_id in tqdm(
295
291
  self.district_ids,
296
292
  desc="Loading energy profiles",
@@ -298,24 +294,32 @@ class MatchingDataLoader:
298
294
  colour="green",
299
295
  disable=not logger.isEnabledFor(logging.DEBUG),
300
296
  ):
301
- file_path = self.profiles_dir / f"energy_model_{district_id}.parquet"
302
- if not file_path.exists():
297
+ profiles = scan_district_profiles(self.profiles_dir, district_id)
298
+ if profiles is None:
303
299
  logger.warning(
304
- "Energy profile file not found: '%s' (district %s).",
300
+ "Energy profile file(s) not found in '%s' (district %s).",
301
+ self.profiles_dir,
305
302
  district_id,
306
- file_path,
307
303
  )
308
304
  continue
309
- district_df = pd.read_parquet(file_path, columns=columns)
310
- if district_df.empty:
311
- continue
312
- aggregated = district_df.groupby(
313
- ["name", "building_id"], as_index=False
314
- ).agg(
315
- annual_energy_mwh=("total_electricity_need", "first"),
316
- peak_active_power_mw=("electricity_need", "max"),
317
- floor_area=("floor_area", "first"),
305
+ aggregated = (
306
+ profiles.with_columns(
307
+ pl.col(
308
+ "total_electricity_need", "electricity_need", "floor_area"
309
+ ).cast(pl.Float64)
310
+ )
311
+ .group_by(["name", "building_id"])
312
+ .agg(
313
+ annual_energy_mwh=pl.col("total_electricity_need").first(),
314
+ peak_active_power_mw=pl.col("electricity_need").max(),
315
+ floor_area=pl.col("floor_area").first(),
316
+ )
317
+ .sort(["name", "building_id"])
318
+ .collect()
319
+ .to_pandas()
318
320
  )
321
+ if aggregated.empty:
322
+ continue
319
323
  aggregated["annual_energy_mwh"] /= KW_TO_MW
320
324
  aggregated["peak_active_power_mw"] /= KW_TO_MW
321
325
  aggregated["peak_reactive_power_mvar"] = (
@@ -418,7 +422,12 @@ class MatchingDataLoader:
418
422
  crs=self.metric_crs,
419
423
  )
420
424
 
421
- df["geometry"] = df["geometry"].apply(lambda geom: wkb.loads(bytes(geom)))
425
+ # DuckDB guarantees no row order without ORDER BY, and bus ids below are
426
+ # positional: sort on row content so ids are stable across runs.
427
+ df["geometry"] = df["geometry"].map(bytes)
428
+ sort_columns = ["geometry"] + (["TENSION"] if "TENSION" in df.columns else [])
429
+ df = df.sort_values(sort_columns, kind="mergesort").reset_index(drop=True)
430
+ df["geometry"] = df["geometry"].apply(wkb.loads)
422
431
  df["geometry"] = df["geometry"].apply(
423
432
  lambda geom: (
424
433
  Point(geom.coords[-1])
@@ -17,6 +17,7 @@ import polars as pl
17
17
  from tqdm import tqdm
18
18
 
19
19
  from gridconnect.api.building_bus_matcher import CONNECTIONS_COLUMNS
20
+ from gridconnect.io.profiles import has_district_profiles, scan_district_profiles
20
21
  from gridconnect.results.loads import LoadProfiles
21
22
 
22
23
  CONNECTION_MATCH_KEYS = (
@@ -313,15 +314,16 @@ class NetworkLoadBuilder:
313
314
  unit="district",
314
315
  disable=not VERBOSE,
315
316
  ):
316
- file = profile_dir / f"energy_model_{district}.parquet"
317
- if not file.exists():
318
- file = (
319
- profile_dir
320
- / f"{self.network.name}"
321
- / f"energy_model_{district}.parquet"
317
+ district_dir = profile_dir
318
+ if not has_district_profiles(district_dir, district):
319
+ district_dir = profile_dir / f"{self.network.name}"
320
+ profiles = scan_district_profiles(district_dir, district)
321
+ if profiles is None:
322
+ logger.warning(
323
+ "Profile file(s) not found for district %s in '%s'.",
324
+ district,
325
+ district_dir,
322
326
  )
323
- if not file.exists():
324
- logger.warning("Profile file not found: %s.", file)
325
327
  continue
326
328
 
327
329
  district_buildings = (
@@ -332,12 +334,12 @@ class NetworkLoadBuilder:
332
334
  .drop_duplicates()
333
335
  .rename(columns={"cleabs": "name"})
334
336
  )
335
- dfs.append(self._import_profile(file, district_buildings))
337
+ dfs.append(self._import_profile(profiles, district_buildings))
336
338
 
337
339
  if not dfs:
338
340
  return pd.DataFrame(columns=LOAD_COLUMNS)
339
341
  logger.debug("Concatenating profile(s) read from files.")
340
- return pl.concat(dfs).to_pandas()
342
+ return pl.concat(dfs, how="vertical_relaxed").to_pandas()
341
343
 
342
344
  def _load_profiles_from_frame(
343
345
  self,
@@ -379,36 +381,32 @@ class NetworkLoadBuilder:
379
381
  )
380
382
  return filtered
381
383
 
382
- def _import_profile(self, file, building_pairs):
383
- """Read one parquet file and filter on exact (name, building_id) pairs."""
384
- try:
385
- if building_pairs.empty:
386
- return pd.DataFrame(columns=LOAD_COLUMNS)
387
-
388
- building_pairs = (
389
- pl.from_pandas(building_pairs)
390
- .lazy()
391
- .with_columns(pl.col("building_id").cast(pl.Int64))
392
- )
384
+ def _import_profile(
385
+ self, profiles: pl.LazyFrame, building_pairs: pd.DataFrame
386
+ ) -> pl.DataFrame:
387
+ """Filter one district's profiles on exact (name, building_id) pairs."""
388
+ if building_pairs.empty:
389
+ return pl.DataFrame(schema=LOAD_COLUMNS)
393
390
 
394
- df = (
395
- pl.scan_parquet(file)
396
- .with_columns(pl.col("building_id").cast(pl.Int64))
397
- .join(building_pairs, on=["name", "building_id"], how="inner")
398
- .select(LOAD_COLUMNS)
399
- .collect()
400
- ).with_columns(
401
- electricity_need=pl.col("electricity_need") / KW_TO_MW,
402
- )
391
+ building_pairs = (
392
+ pl.from_pandas(building_pairs)
393
+ .lazy()
394
+ .with_columns(pl.col("building_id").cast(pl.Int64))
395
+ )
403
396
 
404
- unique_buildings = len(df["building_id"].unique())
397
+ df = (
398
+ profiles.with_columns(pl.col("building_id").cast(pl.Int64))
399
+ .join(building_pairs, on=["name", "building_id"], how="inner")
400
+ .select(LOAD_COLUMNS)
401
+ .collect()
402
+ ).with_columns(
403
+ electricity_need=pl.col("electricity_need").cast(pl.Float64) / KW_TO_MW,
404
+ )
405
405
 
406
- logger.debug(f"Loaded {unique_buildings} profile(s) from '{file.name}'.")
407
- return df
406
+ unique_buildings = len(df["building_id"].unique())
408
407
 
409
- except FileNotFoundError as e:
410
- logger.error(f"Error importing profiles from '{file.name}': {e}.")
411
- return pd.DataFrame(columns=LOAD_COLUMNS)
408
+ logger.debug(f"Loaded {unique_buildings} profile(s).")
409
+ return df
412
410
 
413
411
  def format_profiles(
414
412
  self,
@@ -1,8 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gridconnect
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: A package for connecting building-scale load profiles to distribution networks and preparing simulation-ready network models.
5
5
  Author-email: Yoann Chiche <yoann.chiche@minesparis.psl.eu>
6
+ License-Expression: MIT
6
7
  Requires-Python: >=3.12
7
8
  Description-Content-Type: text/markdown
8
9
  License-File: LICENSE
@@ -105,7 +106,7 @@ data. Default paths are configurable through `BuildingBusMatchConfig` and
105
106
  | Input | Format | Required content |
106
107
  | --- | --- | --- |
107
108
  | Building data | District Parquet files | Building identifiers, geometry, usage, and floor area. |
108
- | Load profiles | `energy_model_<district>.parquet` | `datetime`, `building_id`, `name`, `main_usage`, `district`, and `electricity_need` (kW). |
109
+ | Load profiles | `energy_model_static_<district>.parquet` and `energy_model_hourly_<district>.parquet` (`building_eload` >= 0.6.0), or a single legacy `energy_model_<district>.parquet` | Static: `building_id`, `name`, `main_usage`, `district`, `total_electricity_need`, and `floor_area`. Hourly: `building_id`, `datetime`, and `electricity_need` (kW). A legacy file holds all of these columns. |
109
110
  | Building-to-bus connections | Parquet or DataFrame | The connection schema returned by `BuildingBusMatcher`. |
110
111
  | District areas | Parquet | District geometry used to resolve the feeder study area. |
111
112
  | ORE network geometries | Parquet | Low- and medium-voltage overhead and underground line geometries. |
@@ -17,6 +17,7 @@ gridconnect/api/building_bus_matcher.py
17
17
  gridconnect/api/manager.py
18
18
  gridconnect/io/__init__.py
19
19
  gridconnect/io/conversion.py
20
+ gridconnect/io/profiles.py
20
21
  gridconnect/matching/__init__.py
21
22
  gridconnect/matching/area.py
22
23
  gridconnect/matching/buses.py
@@ -1,5 +1,5 @@
1
1
  [build-system]
2
- requires = ["setuptools>=68", "wheel"]
2
+ requires = ["setuptools>=77", "wheel"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [tool.setuptools.packages.find]
@@ -8,7 +8,7 @@ include = ["gridconnect*"]
8
8
  [project]
9
9
  name = "gridconnect"
10
10
 
11
- version = "0.2.0"
11
+ version = "0.2.2"
12
12
  description = "A package for connecting building-scale load profiles to distribution networks and preparing simulation-ready network models."
13
13
 
14
14
  authors = [
@@ -17,6 +17,8 @@ authors = [
17
17
 
18
18
  readme = "README.md"
19
19
  requires-python = ">=3.12"
20
+ license = "MIT"
21
+ license-files = ["LICENSE"]
20
22
 
21
23
  dependencies = [
22
24
  "networkx",
gridconnect-0.2.0/LICENSE DELETED
@@ -1,25 +0,0 @@
1
- The MIT License (MIT)
2
- =====================
3
-
4
- - Copyright © `2026` `Yoann CHICHE`
5
-
6
- Permission is hereby granted, free of charge, to any person
7
- obtaining a copy of this software and associated documentation
8
- files (the “Software”), to deal in the Software without
9
- restriction, including without limitation the rights to use,
10
- copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- copies of the Software, and to permit persons to whom the
12
- Software is furnished to do so, subject to the following
13
- conditions:
14
-
15
- The above copyright notice and this permission notice shall be
16
- included in all copies or substantial portions of the Software.
17
-
18
- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
19
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25
- OTHER DEALINGS IN THE SOFTWARE.
@@ -1,5 +0,0 @@
1
- """Input and output conversion helpers for GridConnect datasets.
2
-
3
- The package currently provides conversion of serialized-geometry CSV input to
4
- GeoParquet for the building-to-bus matching workflow.
5
- """
File without changes