flood-adapt 0.3.9__py3-none-any.whl → 0.3.10__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.
Files changed (100) hide show
  1. flood_adapt/__init__.py +26 -22
  2. flood_adapt/adapter/__init__.py +9 -9
  3. flood_adapt/adapter/fiat_adapter.py +1541 -1541
  4. flood_adapt/adapter/interface/hazard_adapter.py +70 -70
  5. flood_adapt/adapter/interface/impact_adapter.py +36 -36
  6. flood_adapt/adapter/interface/model_adapter.py +89 -89
  7. flood_adapt/adapter/interface/offshore.py +19 -19
  8. flood_adapt/adapter/sfincs_adapter.py +1848 -1848
  9. flood_adapt/adapter/sfincs_offshore.py +193 -193
  10. flood_adapt/config/config.py +248 -248
  11. flood_adapt/config/fiat.py +219 -219
  12. flood_adapt/config/gui.py +331 -331
  13. flood_adapt/config/sfincs.py +481 -336
  14. flood_adapt/config/site.py +129 -129
  15. flood_adapt/database_builder/database_builder.py +2210 -2210
  16. flood_adapt/database_builder/templates/default_units/imperial.toml +9 -9
  17. flood_adapt/database_builder/templates/default_units/metric.toml +9 -9
  18. flood_adapt/database_builder/templates/green_infra_table/green_infra_lookup_table.csv +10 -10
  19. flood_adapt/database_builder/templates/infographics/OSM/config_charts.toml +90 -90
  20. flood_adapt/database_builder/templates/infographics/OSM/config_people.toml +57 -57
  21. flood_adapt/database_builder/templates/infographics/OSM/config_risk_charts.toml +121 -121
  22. flood_adapt/database_builder/templates/infographics/OSM/config_roads.toml +65 -65
  23. flood_adapt/database_builder/templates/infographics/OSM/styles.css +45 -45
  24. flood_adapt/database_builder/templates/infographics/US_NSI/config_charts.toml +126 -126
  25. flood_adapt/database_builder/templates/infographics/US_NSI/config_people.toml +60 -60
  26. flood_adapt/database_builder/templates/infographics/US_NSI/config_risk_charts.toml +121 -121
  27. flood_adapt/database_builder/templates/infographics/US_NSI/config_roads.toml +65 -65
  28. flood_adapt/database_builder/templates/infographics/US_NSI/styles.css +45 -45
  29. flood_adapt/database_builder/templates/infometrics/OSM/metrics_additional_risk_configs.toml +4 -4
  30. flood_adapt/database_builder/templates/infometrics/OSM/with_SVI/infographic_metrics_config.toml +143 -143
  31. flood_adapt/database_builder/templates/infometrics/OSM/with_SVI/infographic_metrics_config_risk.toml +153 -153
  32. flood_adapt/database_builder/templates/infometrics/OSM/without_SVI/infographic_metrics_config.toml +127 -127
  33. flood_adapt/database_builder/templates/infometrics/OSM/without_SVI/infographic_metrics_config_risk.toml +57 -57
  34. flood_adapt/database_builder/templates/infometrics/US_NSI/metrics_additional_risk_configs.toml +4 -4
  35. flood_adapt/database_builder/templates/infometrics/US_NSI/with_SVI/infographic_metrics_config.toml +191 -191
  36. flood_adapt/database_builder/templates/infometrics/US_NSI/with_SVI/infographic_metrics_config_risk.toml +153 -153
  37. flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config.toml +178 -178
  38. flood_adapt/database_builder/templates/infometrics/US_NSI/without_SVI/infographic_metrics_config_risk.toml +57 -57
  39. flood_adapt/database_builder/templates/infometrics/mandatory_metrics_config.toml +9 -9
  40. flood_adapt/database_builder/templates/infometrics/mandatory_metrics_config_risk.toml +65 -65
  41. flood_adapt/database_builder/templates/output_layers/bin_colors.toml +5 -5
  42. flood_adapt/database_builder.py +16 -16
  43. flood_adapt/dbs_classes/__init__.py +21 -21
  44. flood_adapt/dbs_classes/database.py +495 -684
  45. flood_adapt/dbs_classes/dbs_benefit.py +77 -76
  46. flood_adapt/dbs_classes/dbs_event.py +61 -59
  47. flood_adapt/dbs_classes/dbs_measure.py +112 -111
  48. flood_adapt/dbs_classes/dbs_projection.py +34 -34
  49. flood_adapt/dbs_classes/dbs_scenario.py +137 -137
  50. flood_adapt/dbs_classes/dbs_static.py +274 -273
  51. flood_adapt/dbs_classes/dbs_strategy.py +130 -129
  52. flood_adapt/dbs_classes/dbs_template.py +279 -278
  53. flood_adapt/dbs_classes/interface/database.py +107 -139
  54. flood_adapt/dbs_classes/interface/element.py +121 -121
  55. flood_adapt/dbs_classes/interface/static.py +47 -47
  56. flood_adapt/flood_adapt.py +1207 -1178
  57. flood_adapt/misc/database_user.py +16 -16
  58. flood_adapt/misc/exceptions.py +22 -0
  59. flood_adapt/misc/log.py +183 -183
  60. flood_adapt/misc/path_builder.py +54 -54
  61. flood_adapt/misc/utils.py +185 -185
  62. flood_adapt/objects/__init__.py +82 -82
  63. flood_adapt/objects/benefits/benefits.py +61 -61
  64. flood_adapt/objects/events/event_factory.py +135 -135
  65. flood_adapt/objects/events/event_set.py +88 -84
  66. flood_adapt/objects/events/events.py +234 -234
  67. flood_adapt/objects/events/historical.py +58 -58
  68. flood_adapt/objects/events/hurricane.py +68 -67
  69. flood_adapt/objects/events/synthetic.py +46 -50
  70. flood_adapt/objects/forcing/__init__.py +92 -92
  71. flood_adapt/objects/forcing/csv.py +68 -68
  72. flood_adapt/objects/forcing/discharge.py +66 -66
  73. flood_adapt/objects/forcing/forcing.py +150 -150
  74. flood_adapt/objects/forcing/forcing_factory.py +182 -182
  75. flood_adapt/objects/forcing/meteo_handler.py +93 -93
  76. flood_adapt/objects/forcing/netcdf.py +40 -40
  77. flood_adapt/objects/forcing/plotting.py +453 -429
  78. flood_adapt/objects/forcing/rainfall.py +98 -98
  79. flood_adapt/objects/forcing/tide_gauge.py +191 -191
  80. flood_adapt/objects/forcing/time_frame.py +90 -90
  81. flood_adapt/objects/forcing/timeseries.py +564 -564
  82. flood_adapt/objects/forcing/unit_system.py +580 -580
  83. flood_adapt/objects/forcing/waterlevels.py +108 -108
  84. flood_adapt/objects/forcing/wind.py +124 -124
  85. flood_adapt/objects/measures/measure_factory.py +92 -92
  86. flood_adapt/objects/measures/measures.py +529 -529
  87. flood_adapt/objects/object_model.py +74 -68
  88. flood_adapt/objects/projections/projections.py +103 -103
  89. flood_adapt/objects/scenarios/scenarios.py +22 -22
  90. flood_adapt/objects/strategies/strategies.py +89 -89
  91. flood_adapt/workflows/benefit_runner.py +579 -554
  92. flood_adapt/workflows/floodmap.py +85 -85
  93. flood_adapt/workflows/impacts_integrator.py +85 -85
  94. flood_adapt/workflows/scenario_runner.py +70 -70
  95. {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.10.dist-info}/LICENSE +674 -674
  96. {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.10.dist-info}/METADATA +866 -865
  97. flood_adapt-0.3.10.dist-info/RECORD +140 -0
  98. flood_adapt-0.3.9.dist-info/RECORD +0 -139
  99. {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.10.dist-info}/WHEEL +0 -0
  100. {flood_adapt-0.3.9.dist-info → flood_adapt-0.3.10.dist-info}/top_level.txt +0 -0
@@ -1,67 +1,68 @@
1
- from typing import ClassVar, List
2
-
3
- from pydantic import BaseModel
4
-
5
- from flood_adapt.objects.events.events import Event, Template
6
- from flood_adapt.objects.forcing import unit_system as us
7
- from flood_adapt.objects.forcing.forcing import (
8
- ForcingSource,
9
- ForcingType,
10
- )
11
- from flood_adapt.objects.forcing.time_frame import TimeFrame
12
-
13
- __all__ = ["HurricaneEvent", "TranslationModel", "TimeFrame"]
14
-
15
-
16
- class TranslationModel(BaseModel):
17
- """BaseModel describing the expected variables and data types for translation parameters of hurricane model."""
18
-
19
- eastwest_translation: us.UnitfulLength = us.UnitfulLength(
20
- value=0.0, units=us.UnitTypesLength.meters
21
- )
22
- northsouth_translation: us.UnitfulLength = us.UnitfulLength(
23
- value=0.0, units=us.UnitTypesLength.meters
24
- )
25
-
26
-
27
- class HurricaneEvent(Event):
28
- """BaseModel describing the expected variables and data types for parameters of HurricaneEvent that extend the parent class Event.
29
-
30
- Attributes
31
- ----------
32
- name : str
33
- The name of the event.
34
- description :
35
- The description of the event. Defaults to "".
36
- time : TimeFrame
37
- The time frame of the event.
38
- template : Template
39
- The template of the event. Defaults to Template.Hurricane.
40
- mode : Mode
41
- The mode of the event. Defaults to Mode.single_event.
42
- rainfall_multiplier : float
43
- The rainfall multiplier of the event. Defaults to 1.0.
44
- forcings : dict[ForcingType, list[IForcing]]
45
- The forcings of the event.
46
- track_name : str
47
- The name of the hurricane track.
48
- """
49
-
50
- ALLOWED_FORCINGS: ClassVar[dict[ForcingType, List[ForcingSource]]] = {
51
- ForcingType.RAINFALL: [
52
- ForcingSource.CONSTANT,
53
- ForcingSource.CSV,
54
- ForcingSource.SYNTHETIC,
55
- ForcingSource.TRACK,
56
- ],
57
- ForcingType.WIND: [ForcingSource.TRACK],
58
- ForcingType.WATERLEVEL: [ForcingSource.MODEL],
59
- ForcingType.DISCHARGE: [
60
- ForcingSource.CSV,
61
- ForcingSource.SYNTHETIC,
62
- ForcingSource.CONSTANT,
63
- ],
64
- }
65
- template: Template = Template.Hurricane
66
- hurricane_translation: TranslationModel = TranslationModel()
67
- track_name: str
1
+ from typing import ClassVar, List
2
+
3
+ from pydantic import BaseModel
4
+
5
+ from flood_adapt.objects.events.events import Event, Template
6
+ from flood_adapt.objects.forcing import unit_system as us
7
+ from flood_adapt.objects.forcing.forcing import (
8
+ ForcingSource,
9
+ ForcingType,
10
+ )
11
+ from flood_adapt.objects.forcing.time_frame import TimeFrame
12
+
13
+ __all__ = ["HurricaneEvent", "TranslationModel", "TimeFrame"]
14
+
15
+
16
+ class TranslationModel(BaseModel):
17
+ """BaseModel describing the expected variables and data types for translation parameters of hurricane model."""
18
+
19
+ eastwest_translation: us.UnitfulLength = us.UnitfulLength(
20
+ value=0.0, units=us.UnitTypesLength.meters
21
+ )
22
+ northsouth_translation: us.UnitfulLength = us.UnitfulLength(
23
+ value=0.0, units=us.UnitTypesLength.meters
24
+ )
25
+
26
+
27
+ class HurricaneEvent(Event):
28
+ """BaseModel describing the expected variables and data types for parameters of HurricaneEvent that extend the parent class Event.
29
+
30
+ Attributes
31
+ ----------
32
+ name : str
33
+ The name of the event.
34
+ description :
35
+ The description of the event. Defaults to "".
36
+ time : TimeFrame
37
+ The time frame of the event.
38
+ template : Template
39
+ The template of the event. Defaults to Template.Hurricane.
40
+ mode : Mode
41
+ The mode of the event. Defaults to Mode.single_event.
42
+ rainfall_multiplier : float
43
+ The rainfall multiplier of the event. Defaults to 1.0.
44
+ forcings : dict[ForcingType, list[IForcing]]
45
+ The forcings of the event.
46
+ track_name : str
47
+ The name of the hurricane track.
48
+ """
49
+
50
+ ALLOWED_FORCINGS: ClassVar[dict[ForcingType, List[ForcingSource]]] = {
51
+ ForcingType.RAINFALL: [
52
+ ForcingSource.CONSTANT,
53
+ ForcingSource.CSV,
54
+ ForcingSource.SYNTHETIC,
55
+ ForcingSource.TRACK,
56
+ ForcingSource.METEO,
57
+ ],
58
+ ForcingType.WIND: [ForcingSource.TRACK],
59
+ ForcingType.WATERLEVEL: [ForcingSource.MODEL],
60
+ ForcingType.DISCHARGE: [
61
+ ForcingSource.CSV,
62
+ ForcingSource.SYNTHETIC,
63
+ ForcingSource.CONSTANT,
64
+ ],
65
+ }
66
+ template: Template = Template.Hurricane
67
+ hurricane_translation: TranslationModel = TranslationModel()
68
+ track_name: str
@@ -1,50 +1,46 @@
1
- from typing import ClassVar, List
2
-
3
- from flood_adapt.objects.events.events import (
4
- Event,
5
- Template,
6
- )
7
- from flood_adapt.objects.forcing.forcing import (
8
- ForcingSource,
9
- ForcingType,
10
- )
11
-
12
-
13
- class SyntheticEvent(Event):
14
- """BaseModel describing the expected variables and data types for parameters of Synthetic that extend the parent class Event.
15
-
16
- Attributes
17
- ----------
18
- time : TimeFrame
19
- The time frame of the event.
20
- template : Template
21
- The template of the event. Defaults to Template.Synthetic.
22
- mode : Mode
23
- The mode of the event. Defaults to Mode.single_event.
24
- rainfall_multiplier : float
25
- The rainfall multiplier of the event. Defaults to 1.0.
26
- forcings : dict[ForcingType, list[IForcing]]
27
- The forcings of the event.
28
- """
29
-
30
- ALLOWED_FORCINGS: ClassVar[dict[ForcingType, List[ForcingSource]]] = {
31
- ForcingType.RAINFALL: [
32
- ForcingSource.CONSTANT,
33
- ForcingSource.CSV,
34
- ForcingSource.SYNTHETIC,
35
- ],
36
- ForcingType.WIND: [
37
- ForcingSource.CSV,
38
- ForcingSource.CONSTANT,
39
- ],
40
- ForcingType.WATERLEVEL: [
41
- ForcingSource.CSV,
42
- ForcingSource.SYNTHETIC,
43
- ],
44
- ForcingType.DISCHARGE: [
45
- ForcingSource.CSV,
46
- ForcingSource.SYNTHETIC,
47
- ForcingSource.CONSTANT,
48
- ],
49
- }
50
- template: Template = Template.Synthetic
1
+ from typing import ClassVar, List
2
+
3
+ from flood_adapt.objects.events.events import (
4
+ Event,
5
+ Template,
6
+ )
7
+ from flood_adapt.objects.forcing.forcing import (
8
+ ForcingSource,
9
+ ForcingType,
10
+ )
11
+
12
+
13
+ class SyntheticEvent(Event):
14
+ """BaseModel describing the expected variables and data types for parameters of Synthetic that extend the parent class Event.
15
+
16
+ Attributes
17
+ ----------
18
+ time : TimeFrame
19
+ The time frame of the event.
20
+ template : Template
21
+ The template of the event. Defaults to Template.Synthetic.
22
+ mode : Mode
23
+ The mode of the event. Defaults to Mode.single_event.
24
+ rainfall_multiplier : float
25
+ The rainfall multiplier of the event. Defaults to 1.0.
26
+ forcings : dict[ForcingType, list[IForcing]]
27
+ The forcings of the event.
28
+ """
29
+
30
+ ALLOWED_FORCINGS: ClassVar[dict[ForcingType, List[ForcingSource]]] = {
31
+ ForcingType.RAINFALL: [
32
+ ForcingSource.CONSTANT,
33
+ ForcingSource.SYNTHETIC,
34
+ ],
35
+ ForcingType.WIND: [
36
+ ForcingSource.CONSTANT,
37
+ ],
38
+ ForcingType.WATERLEVEL: [
39
+ ForcingSource.SYNTHETIC,
40
+ ],
41
+ ForcingType.DISCHARGE: [
42
+ ForcingSource.SYNTHETIC,
43
+ ForcingSource.CONSTANT,
44
+ ],
45
+ }
46
+ template: Template = Template.Synthetic
@@ -1,92 +1,92 @@
1
- from flood_adapt.objects.forcing.discharge import (
2
- DischargeConstant,
3
- DischargeCSV,
4
- DischargeSynthetic,
5
- )
6
- from flood_adapt.objects.forcing.forcing import ForcingSource, ForcingType, IForcing
7
- from flood_adapt.objects.forcing.meteo_handler import MeteoHandler
8
- from flood_adapt.objects.forcing.rainfall import (
9
- RainfallConstant,
10
- RainfallCSV,
11
- RainfallMeteo,
12
- RainfallNetCDF,
13
- RainfallSynthetic,
14
- RainfallTrack,
15
- )
16
- from flood_adapt.objects.forcing.tide_gauge import TideGauge, TideGaugeSource
17
- from flood_adapt.objects.forcing.time_frame import TimeFrame
18
- from flood_adapt.objects.forcing.timeseries import (
19
- BlockTimeseries,
20
- CSVTimeseries,
21
- GaussianTimeseries,
22
- ScsTimeseries,
23
- Scstype,
24
- ShapeType,
25
- SyntheticTimeseries,
26
- TimeseriesFactory,
27
- TriangleTimeseries,
28
- )
29
- from flood_adapt.objects.forcing.waterlevels import (
30
- SurgeModel,
31
- TideModel,
32
- WaterlevelCSV,
33
- WaterlevelGauged,
34
- WaterlevelModel,
35
- WaterlevelSynthetic,
36
- )
37
- from flood_adapt.objects.forcing.wind import (
38
- WindConstant,
39
- WindCSV,
40
- WindMeteo,
41
- WindNetCDF,
42
- WindSynthetic,
43
- WindTrack,
44
- )
45
-
46
- __all__ = [
47
- # Forcing
48
- "IForcing",
49
- "ForcingSource",
50
- "ForcingType",
51
- # Timeseries
52
- "ShapeType",
53
- "Scstype",
54
- "CSVTimeseries",
55
- "TimeseriesFactory",
56
- "SyntheticTimeseries",
57
- "BlockTimeseries",
58
- "ScsTimeseries",
59
- "GaussianTimeseries",
60
- "TriangleTimeseries",
61
- # TimeFrame
62
- "TimeFrame",
63
- # Discharge
64
- "DischargeConstant",
65
- "DischargeCSV",
66
- "DischargeSynthetic",
67
- # Waterlevels
68
- "WaterlevelCSV",
69
- "WaterlevelGauged",
70
- "WaterlevelModel",
71
- "WaterlevelSynthetic",
72
- "TideModel",
73
- "SurgeModel",
74
- "TideGauge",
75
- "TideGaugeSource",
76
- # Rainfall
77
- "RainfallConstant",
78
- "RainfallCSV",
79
- "RainfallSynthetic",
80
- "RainfallMeteo",
81
- "RainfallNetCDF",
82
- "RainfallTrack",
83
- # Wind
84
- "WindConstant",
85
- "WindCSV",
86
- "WindSynthetic",
87
- "WindMeteo",
88
- "WindNetCDF",
89
- "WindTrack",
90
- # Other
91
- "MeteoHandler",
92
- ]
1
+ from flood_adapt.objects.forcing.discharge import (
2
+ DischargeConstant,
3
+ DischargeCSV,
4
+ DischargeSynthetic,
5
+ )
6
+ from flood_adapt.objects.forcing.forcing import ForcingSource, ForcingType, IForcing
7
+ from flood_adapt.objects.forcing.meteo_handler import MeteoHandler
8
+ from flood_adapt.objects.forcing.rainfall import (
9
+ RainfallConstant,
10
+ RainfallCSV,
11
+ RainfallMeteo,
12
+ RainfallNetCDF,
13
+ RainfallSynthetic,
14
+ RainfallTrack,
15
+ )
16
+ from flood_adapt.objects.forcing.tide_gauge import TideGauge, TideGaugeSource
17
+ from flood_adapt.objects.forcing.time_frame import TimeFrame
18
+ from flood_adapt.objects.forcing.timeseries import (
19
+ BlockTimeseries,
20
+ CSVTimeseries,
21
+ GaussianTimeseries,
22
+ ScsTimeseries,
23
+ Scstype,
24
+ ShapeType,
25
+ SyntheticTimeseries,
26
+ TimeseriesFactory,
27
+ TriangleTimeseries,
28
+ )
29
+ from flood_adapt.objects.forcing.waterlevels import (
30
+ SurgeModel,
31
+ TideModel,
32
+ WaterlevelCSV,
33
+ WaterlevelGauged,
34
+ WaterlevelModel,
35
+ WaterlevelSynthetic,
36
+ )
37
+ from flood_adapt.objects.forcing.wind import (
38
+ WindConstant,
39
+ WindCSV,
40
+ WindMeteo,
41
+ WindNetCDF,
42
+ WindSynthetic,
43
+ WindTrack,
44
+ )
45
+
46
+ __all__ = [
47
+ # Forcing
48
+ "IForcing",
49
+ "ForcingSource",
50
+ "ForcingType",
51
+ # Timeseries
52
+ "ShapeType",
53
+ "Scstype",
54
+ "CSVTimeseries",
55
+ "TimeseriesFactory",
56
+ "SyntheticTimeseries",
57
+ "BlockTimeseries",
58
+ "ScsTimeseries",
59
+ "GaussianTimeseries",
60
+ "TriangleTimeseries",
61
+ # TimeFrame
62
+ "TimeFrame",
63
+ # Discharge
64
+ "DischargeConstant",
65
+ "DischargeCSV",
66
+ "DischargeSynthetic",
67
+ # Waterlevels
68
+ "WaterlevelCSV",
69
+ "WaterlevelGauged",
70
+ "WaterlevelModel",
71
+ "WaterlevelSynthetic",
72
+ "TideModel",
73
+ "SurgeModel",
74
+ "TideGauge",
75
+ "TideGaugeSource",
76
+ # Rainfall
77
+ "RainfallConstant",
78
+ "RainfallCSV",
79
+ "RainfallSynthetic",
80
+ "RainfallMeteo",
81
+ "RainfallNetCDF",
82
+ "RainfallTrack",
83
+ # Wind
84
+ "WindConstant",
85
+ "WindCSV",
86
+ "WindSynthetic",
87
+ "WindMeteo",
88
+ "WindNetCDF",
89
+ "WindTrack",
90
+ # Other
91
+ "MeteoHandler",
92
+ ]
@@ -1,68 +1,68 @@
1
- import csv
2
- from pathlib import Path
3
-
4
- import pandas as pd
5
-
6
-
7
- def read_csv(csvpath: Path) -> pd.DataFrame:
8
- """Read a timeseries file and return a pd.DataFrame.
9
-
10
- Parameters
11
- ----------
12
- csvpath : Path
13
- Path to the CSV file.
14
-
15
- Returns
16
- -------
17
- pd.DataFrame
18
- Dataframe with time as index and (a) data column(s).
19
- """
20
- num_columns = None
21
- has_header = None
22
- with open(csvpath, "r") as f:
23
- try:
24
- # read the first 1024 bytes to determine if there is a header
25
- has_header = csv.Sniffer().has_header(f.read(1024))
26
- except csv.Error:
27
- has_header = False
28
- f.seek(0)
29
- reader = csv.reader(f, delimiter=",")
30
- try:
31
- first_row = next(reader)
32
- num_columns = len(first_row) - 1 # subtract 1 for the index column
33
- except StopIteration:
34
- raise ValueError(f"The CSV file is empty: {csvpath}.")
35
-
36
- if has_header is None:
37
- raise ValueError(
38
- f"Could not determine if the CSV file has a header: {csvpath}."
39
- )
40
- if num_columns is None:
41
- raise ValueError(
42
- f"Could not determine the number of columns in the CSV file: {csvpath}."
43
- )
44
- elif num_columns < 1:
45
- raise ValueError(f"CSV file must have at least one data column: {csvpath}.")
46
- columns = [f"data_{i}" for i in range(num_columns)]
47
- dtype = {name: float for name in columns}
48
-
49
- df = pd.read_csv(
50
- csvpath,
51
- index_col=0,
52
- names=columns,
53
- header=0 if has_header else None,
54
- parse_dates=True,
55
- infer_datetime_format=True,
56
- dtype=dtype,
57
- )
58
-
59
- # Any index that cannot be converted to datetime will be NaT
60
- df.index = pd.to_datetime(df.index, errors="coerce")
61
- df.index.names = ["time"]
62
- if len(df.index) > 2:
63
- df.index.freq = pd.infer_freq(df.index)
64
-
65
- # Drop rows where the index is NaT
66
- df = df[~df.index.isna()]
67
-
68
- return df
1
+ import csv
2
+ from pathlib import Path
3
+
4
+ import pandas as pd
5
+
6
+
7
+ def read_csv(csvpath: Path) -> pd.DataFrame:
8
+ """Read a timeseries file and return a pd.DataFrame.
9
+
10
+ Parameters
11
+ ----------
12
+ csvpath : Path
13
+ Path to the CSV file.
14
+
15
+ Returns
16
+ -------
17
+ pd.DataFrame
18
+ Dataframe with time as index and (a) data column(s).
19
+ """
20
+ num_columns = None
21
+ has_header = None
22
+ with open(csvpath, "r") as f:
23
+ try:
24
+ # read the first 1024 bytes to determine if there is a header
25
+ has_header = csv.Sniffer().has_header(f.read(1024))
26
+ except csv.Error:
27
+ has_header = False
28
+ f.seek(0)
29
+ reader = csv.reader(f, delimiter=",")
30
+ try:
31
+ first_row = next(reader)
32
+ num_columns = len(first_row) - 1 # subtract 1 for the index column
33
+ except StopIteration:
34
+ raise ValueError(f"The CSV file is empty: {csvpath}.")
35
+
36
+ if has_header is None:
37
+ raise ValueError(
38
+ f"Could not determine if the CSV file has a header: {csvpath}."
39
+ )
40
+ if num_columns is None:
41
+ raise ValueError(
42
+ f"Could not determine the number of columns in the CSV file: {csvpath}."
43
+ )
44
+ elif num_columns < 1:
45
+ raise ValueError(f"CSV file must have at least one data column: {csvpath}.")
46
+ columns = [f"data_{i}" for i in range(num_columns)]
47
+ dtype = {name: float for name in columns}
48
+
49
+ df = pd.read_csv(
50
+ csvpath,
51
+ index_col=0,
52
+ names=columns,
53
+ header=0 if has_header else None,
54
+ parse_dates=True,
55
+ infer_datetime_format=True,
56
+ dtype=dtype,
57
+ )
58
+
59
+ # Any index that cannot be converted to datetime will be NaT
60
+ df.index = pd.to_datetime(df.index, errors="coerce")
61
+ df.index.names = ["time"]
62
+ if len(df.index) > 2:
63
+ df.index.freq = pd.infer_freq(df.index)
64
+
65
+ # Drop rows where the index is NaT
66
+ df = df[~df.index.isna()]
67
+
68
+ return df