fram-core 0.0.0__py3-none-any.whl → 0.1.0a2__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.
- fram_core-0.1.0a2.dist-info/METADATA +42 -0
- fram_core-0.1.0a2.dist-info/RECORD +100 -0
- {fram_core-0.0.0.dist-info → fram_core-0.1.0a2.dist-info}/WHEEL +1 -2
- fram_core-0.1.0a2.dist-info/licenses/LICENSE.md +8 -0
- framcore/Base.py +142 -0
- framcore/Model.py +73 -0
- framcore/__init__.py +9 -0
- framcore/aggregators/Aggregator.py +153 -0
- framcore/aggregators/HydroAggregator.py +837 -0
- framcore/aggregators/NodeAggregator.py +495 -0
- framcore/aggregators/WindSolarAggregator.py +323 -0
- framcore/aggregators/__init__.py +13 -0
- framcore/aggregators/_utils.py +184 -0
- framcore/attributes/Arrow.py +305 -0
- framcore/attributes/ElasticDemand.py +90 -0
- framcore/attributes/ReservoirCurve.py +37 -0
- framcore/attributes/SoftBound.py +19 -0
- framcore/attributes/StartUpCost.py +54 -0
- framcore/attributes/Storage.py +146 -0
- framcore/attributes/TargetBound.py +18 -0
- framcore/attributes/__init__.py +65 -0
- framcore/attributes/hydro/HydroBypass.py +42 -0
- framcore/attributes/hydro/HydroGenerator.py +83 -0
- framcore/attributes/hydro/HydroPump.py +156 -0
- framcore/attributes/hydro/HydroReservoir.py +27 -0
- framcore/attributes/hydro/__init__.py +13 -0
- framcore/attributes/level_profile_attributes.py +714 -0
- framcore/components/Component.py +112 -0
- framcore/components/Demand.py +130 -0
- framcore/components/Flow.py +167 -0
- framcore/components/HydroModule.py +330 -0
- framcore/components/Node.py +76 -0
- framcore/components/Thermal.py +204 -0
- framcore/components/Transmission.py +183 -0
- framcore/components/_PowerPlant.py +81 -0
- framcore/components/__init__.py +22 -0
- framcore/components/wind_solar.py +67 -0
- framcore/curves/Curve.py +44 -0
- framcore/curves/LoadedCurve.py +155 -0
- framcore/curves/__init__.py +9 -0
- framcore/events/__init__.py +21 -0
- framcore/events/events.py +51 -0
- framcore/expressions/Expr.py +490 -0
- framcore/expressions/__init__.py +28 -0
- framcore/expressions/_get_constant_from_expr.py +483 -0
- framcore/expressions/_time_vector_operations.py +615 -0
- framcore/expressions/_utils.py +73 -0
- framcore/expressions/queries.py +423 -0
- framcore/expressions/units.py +207 -0
- framcore/fingerprints/__init__.py +11 -0
- framcore/fingerprints/fingerprint.py +293 -0
- framcore/juliamodels/JuliaModel.py +161 -0
- framcore/juliamodels/__init__.py +7 -0
- framcore/loaders/__init__.py +10 -0
- framcore/loaders/loaders.py +407 -0
- framcore/metadata/Div.py +73 -0
- framcore/metadata/ExprMeta.py +50 -0
- framcore/metadata/LevelExprMeta.py +17 -0
- framcore/metadata/Member.py +55 -0
- framcore/metadata/Meta.py +44 -0
- framcore/metadata/__init__.py +15 -0
- framcore/populators/Populator.py +108 -0
- framcore/populators/__init__.py +7 -0
- framcore/querydbs/CacheDB.py +50 -0
- framcore/querydbs/ModelDB.py +34 -0
- framcore/querydbs/QueryDB.py +45 -0
- framcore/querydbs/__init__.py +11 -0
- framcore/solvers/Solver.py +48 -0
- framcore/solvers/SolverConfig.py +272 -0
- framcore/solvers/__init__.py +9 -0
- framcore/timeindexes/AverageYearRange.py +20 -0
- framcore/timeindexes/ConstantTimeIndex.py +17 -0
- framcore/timeindexes/DailyIndex.py +21 -0
- framcore/timeindexes/FixedFrequencyTimeIndex.py +762 -0
- framcore/timeindexes/HourlyIndex.py +21 -0
- framcore/timeindexes/IsoCalendarDay.py +31 -0
- framcore/timeindexes/ListTimeIndex.py +197 -0
- framcore/timeindexes/ModelYear.py +17 -0
- framcore/timeindexes/ModelYears.py +18 -0
- framcore/timeindexes/OneYearProfileTimeIndex.py +21 -0
- framcore/timeindexes/ProfileTimeIndex.py +32 -0
- framcore/timeindexes/SinglePeriodTimeIndex.py +37 -0
- framcore/timeindexes/TimeIndex.py +90 -0
- framcore/timeindexes/WeeklyIndex.py +21 -0
- framcore/timeindexes/__init__.py +36 -0
- framcore/timevectors/ConstantTimeVector.py +135 -0
- framcore/timevectors/LinearTransformTimeVector.py +114 -0
- framcore/timevectors/ListTimeVector.py +123 -0
- framcore/timevectors/LoadedTimeVector.py +104 -0
- framcore/timevectors/ReferencePeriod.py +41 -0
- framcore/timevectors/TimeVector.py +94 -0
- framcore/timevectors/__init__.py +17 -0
- framcore/utils/__init__.py +36 -0
- framcore/utils/get_regional_volumes.py +369 -0
- framcore/utils/get_supported_components.py +60 -0
- framcore/utils/global_energy_equivalent.py +46 -0
- framcore/utils/isolate_subnodes.py +163 -0
- framcore/utils/loaders.py +97 -0
- framcore/utils/node_flow_utils.py +236 -0
- framcore/utils/storage_subsystems.py +107 -0
- fram_core-0.0.0.dist-info/METADATA +0 -5
- fram_core-0.0.0.dist-info/RECORD +0 -4
- fram_core-0.0.0.dist-info/top_level.txt +0 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from numpy.typing import NDArray
|
|
3
|
+
|
|
4
|
+
from framcore.fingerprints import Fingerprint
|
|
5
|
+
from framcore.loaders import TimeVectorLoader
|
|
6
|
+
from framcore.timeindexes import ConstantTimeIndex
|
|
7
|
+
from framcore.timevectors import ReferencePeriod
|
|
8
|
+
from framcore.timevectors.TimeVector import TimeVector # NB! full import path needed for inheritance to work
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LinearTransformTimeVector(TimeVector):
|
|
12
|
+
"""LinearTransformTimeVector(TimeVector). Immutable."""
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
timevector: TimeVector,
|
|
17
|
+
scale: float,
|
|
18
|
+
shift: float,
|
|
19
|
+
unit: str | None,
|
|
20
|
+
is_max_level: bool | None = None,
|
|
21
|
+
is_zero_one_profile: bool | None = None,
|
|
22
|
+
reference_period: ReferencePeriod | None = None,
|
|
23
|
+
) -> None:
|
|
24
|
+
"""
|
|
25
|
+
Transform timevector into scale * timevector + shift.
|
|
26
|
+
|
|
27
|
+
May also override unit, is_max_level, is_zero_one_profile and reference_period.
|
|
28
|
+
"""
|
|
29
|
+
self._check_type(timevector, TimeVector)
|
|
30
|
+
self._check_type(scale, float)
|
|
31
|
+
self._check_type(shift, float)
|
|
32
|
+
self._check_type(unit, (str, type(None)))
|
|
33
|
+
self._check_type(is_max_level, (bool, type(None)))
|
|
34
|
+
self._check_type(is_zero_one_profile, (bool, type(None)))
|
|
35
|
+
self._check_type(reference_period, (ReferencePeriod, type(None)))
|
|
36
|
+
self._timevector = timevector
|
|
37
|
+
self._scale = scale
|
|
38
|
+
self._shift = shift
|
|
39
|
+
self._unit = unit
|
|
40
|
+
self._is_max_level = is_max_level
|
|
41
|
+
self._is_zero_one_profile = is_zero_one_profile
|
|
42
|
+
self._reference_period = reference_period
|
|
43
|
+
|
|
44
|
+
def get_vector(self, is_float32: bool) -> NDArray:
|
|
45
|
+
"""Get the values of the TimeVector."""
|
|
46
|
+
vector = self._timevector.get_vector(is_float32)
|
|
47
|
+
if self._scale == 1.0 and self._shift == 0.0:
|
|
48
|
+
return vector
|
|
49
|
+
out = vector.copy()
|
|
50
|
+
if self._scale != 1.0:
|
|
51
|
+
np.multiply(out, self._scale, out=out)
|
|
52
|
+
if self._shift != 0.0:
|
|
53
|
+
np.add(out, self._shift, out=out)
|
|
54
|
+
return out
|
|
55
|
+
|
|
56
|
+
def get_fingerprint(self) -> Fingerprint:
|
|
57
|
+
"""Get the Fingerprint of the TimeVector."""
|
|
58
|
+
return self.get_fingerprint_default()
|
|
59
|
+
|
|
60
|
+
def get_timeindex(self) -> ConstantTimeIndex:
|
|
61
|
+
"""Get the TimeIndex of the TimeVector."""
|
|
62
|
+
return self._timevector.get_timeindex()
|
|
63
|
+
|
|
64
|
+
def is_constant(self) -> bool:
|
|
65
|
+
"""Check if the TimeVector is constant."""
|
|
66
|
+
return self._timevector.is_constant()
|
|
67
|
+
|
|
68
|
+
def is_max_level(self) -> bool | None:
|
|
69
|
+
"""Check if TimeVector is a level representing maximum Volume/Capacity."""
|
|
70
|
+
return self._is_max_level
|
|
71
|
+
|
|
72
|
+
def is_zero_one_profile(self) -> bool | None:
|
|
73
|
+
"""Check if TimeVector is a profile with values between zero and one."""
|
|
74
|
+
return self._is_zero_one_profile
|
|
75
|
+
|
|
76
|
+
def get_unit(self) -> str | None:
|
|
77
|
+
"""Get the unit of the TimeVector."""
|
|
78
|
+
return self._unit
|
|
79
|
+
|
|
80
|
+
def get_reference_period(self) -> ReferencePeriod | None:
|
|
81
|
+
"""Get the reference period of the TimeVector."""
|
|
82
|
+
return self._reference_period
|
|
83
|
+
|
|
84
|
+
def get_loader(self) -> TimeVectorLoader | None:
|
|
85
|
+
"""Call get_loader on underlying time vector."""
|
|
86
|
+
return self._timevector.get_loader()
|
|
87
|
+
|
|
88
|
+
def __eq__(self, other) -> bool: # noqa: ANN001
|
|
89
|
+
"""Check if self and other are equal."""
|
|
90
|
+
if not isinstance(other, type(self)):
|
|
91
|
+
return False
|
|
92
|
+
return (
|
|
93
|
+
self._timevector == other._timevector
|
|
94
|
+
and self._scale == other._scale
|
|
95
|
+
and self._shift == other._shift
|
|
96
|
+
and self._unit == other._unit
|
|
97
|
+
and self._is_max_level == other._is_max_level
|
|
98
|
+
and self._is_zero_one_profile == other._is_zero_one_profile
|
|
99
|
+
and self._reference_period == other._reference_period
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
def __hash__(self) -> int:
|
|
103
|
+
"""Compute the hash of the LinearTransformTimeVector."""
|
|
104
|
+
return hash(
|
|
105
|
+
(
|
|
106
|
+
self._timevector,
|
|
107
|
+
self._scale,
|
|
108
|
+
self._shift,
|
|
109
|
+
self._unit,
|
|
110
|
+
self._is_max_level,
|
|
111
|
+
self._is_zero_one_profile,
|
|
112
|
+
self._reference_period,
|
|
113
|
+
),
|
|
114
|
+
)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from numpy.typing import NDArray
|
|
3
|
+
|
|
4
|
+
from framcore.fingerprints import Fingerprint
|
|
5
|
+
from framcore.timeindexes import TimeIndex
|
|
6
|
+
from framcore.timevectors import ReferencePeriod
|
|
7
|
+
from framcore.timevectors.TimeVector import TimeVector # NB! full import path needed for inheritance to work
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ListTimeVector(TimeVector):
|
|
11
|
+
"""ListTimeVector class for TimeVectors with a numpy array of values. Subclass of TimeVector."""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
timeindex: TimeIndex,
|
|
16
|
+
vector: NDArray,
|
|
17
|
+
unit: str | None,
|
|
18
|
+
is_max_level: bool | None,
|
|
19
|
+
is_zero_one_profile: bool | None,
|
|
20
|
+
reference_period: ReferencePeriod | None = None,
|
|
21
|
+
) -> None:
|
|
22
|
+
"""
|
|
23
|
+
Initialize the ListTimeVector class.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
timeindex (TimeIndex): Index of timestamps for the vector.
|
|
27
|
+
vector (NDArray): Array of vector values.
|
|
28
|
+
unit (str | None): Unit of the values in the vector.
|
|
29
|
+
is_max_level (bool | None): Whether the vector represents the maximum level, average level given a
|
|
30
|
+
reference period, or not a level at all.
|
|
31
|
+
is_zero_one_profile (bool | None): Whether the vector represents aprofile with values between 0 and 1, a
|
|
32
|
+
profile with values averaging to 1 over a given reference period, or is
|
|
33
|
+
not a profile.
|
|
34
|
+
reference_period (ReferencePeriod | None, optional): Given reference period if the vector represents average
|
|
35
|
+
level or mean one profile. Defaults to None.
|
|
36
|
+
|
|
37
|
+
Raises:
|
|
38
|
+
ValueError: When both is_max_level and is_zero_one_profile is not None. This would mean the TimeVector
|
|
39
|
+
represents both a level and a profile, which is not allowed.
|
|
40
|
+
|
|
41
|
+
"""
|
|
42
|
+
if (is_max_level is not None and is_zero_one_profile is not None) or (is_max_level is None and is_zero_one_profile is None):
|
|
43
|
+
message = (
|
|
44
|
+
f"Input arguments for {self}: Must have exactly one 'non-None'"
|
|
45
|
+
"value for is_max_level and is_zero_one_profile. "
|
|
46
|
+
"A TimeVector is either a level or a profile."
|
|
47
|
+
)
|
|
48
|
+
raise ValueError(message)
|
|
49
|
+
# assert vector.shape == (timeindex.get_num_periods(),), (
|
|
50
|
+
# f"Vector shape {vector.shape} does not match timeindex num_periods {timeindex.get_num_periods()}"
|
|
51
|
+
# )
|
|
52
|
+
self._timeindex = timeindex
|
|
53
|
+
self._vector = vector
|
|
54
|
+
self._unit = unit
|
|
55
|
+
self._reference_period = reference_period
|
|
56
|
+
self._is_max_level = is_max_level
|
|
57
|
+
self._is_zero_one_profile = is_zero_one_profile
|
|
58
|
+
|
|
59
|
+
def __eq__(self, other):
|
|
60
|
+
"""Check equality between two ListTimeVector objects."""
|
|
61
|
+
if not isinstance(other, ListTimeVector):
|
|
62
|
+
return NotImplemented
|
|
63
|
+
return (
|
|
64
|
+
(self._timeindex == other._timeindex)
|
|
65
|
+
and np.array_equal(self._vector, other._vector)
|
|
66
|
+
and (self._unit == other._unit)
|
|
67
|
+
and (self._is_max_level == other._is_max_level)
|
|
68
|
+
and (self._is_zero_one_profile == other._is_zero_one_profile)
|
|
69
|
+
and (self._reference_period == other._reference_period)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def __hash__(self) -> int:
|
|
73
|
+
"""Return hash of ListTimeVector object."""
|
|
74
|
+
return hash((self._timeindex, self._vector.tobytes(), self._unit, self._is_max_level, self._is_zero_one_profile, self._reference_period))
|
|
75
|
+
|
|
76
|
+
def __repr__(self) -> str: # TODO: Also timeindex and reference_period
|
|
77
|
+
"""Return the string representation of the ListTimeVector."""
|
|
78
|
+
return f"ListTimeVector(timeindex={self._timeindex}, vector={self._vector}, unit={self._unit})"
|
|
79
|
+
|
|
80
|
+
def get_vector(self, is_float32: bool) -> NDArray:
|
|
81
|
+
"""Get the vector of the TimeVector as a numpy array."""
|
|
82
|
+
if is_float32:
|
|
83
|
+
return self._vector.astype(dtype=np.float32)
|
|
84
|
+
return self._vector
|
|
85
|
+
|
|
86
|
+
def get_timeindex(self) -> TimeIndex:
|
|
87
|
+
"""Get the TimeIndex of the TimeVector."""
|
|
88
|
+
return self._timeindex
|
|
89
|
+
|
|
90
|
+
def is_constant(self) -> bool:
|
|
91
|
+
"""Check if the TimeVector is constant."""
|
|
92
|
+
return False
|
|
93
|
+
|
|
94
|
+
def is_max_level(self) -> bool:
|
|
95
|
+
"""Check if TimeVector is a level representing maximum Volume/Capacity."""
|
|
96
|
+
return self._is_max_level
|
|
97
|
+
|
|
98
|
+
def is_zero_one_profile(self) -> bool:
|
|
99
|
+
"""Check if TimeVector is a profile with vector between zero and one."""
|
|
100
|
+
return self._is_zero_one_profile
|
|
101
|
+
|
|
102
|
+
def get_unit(self) -> str | None:
|
|
103
|
+
"""Get the unit of the TimeVector."""
|
|
104
|
+
return self._unit
|
|
105
|
+
|
|
106
|
+
def get_reference_period(self) -> ReferencePeriod | None:
|
|
107
|
+
"""Get the reference period of the TimeVector."""
|
|
108
|
+
return self._reference_period
|
|
109
|
+
|
|
110
|
+
def get_fingerprint(self) -> Fingerprint:
|
|
111
|
+
"""
|
|
112
|
+
Get the fingerprint of the ListTimeVector.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
Fingerprint: The fingerprint of the ListTimeVector, excluding the reference period.
|
|
116
|
+
|
|
117
|
+
"""
|
|
118
|
+
excludes = {"_reference_period"}
|
|
119
|
+
return self.get_fingerprint_default(excludes=excludes)
|
|
120
|
+
|
|
121
|
+
def get_loader(self) -> None:
|
|
122
|
+
"""Interface method Not applicable for this type. Return None."""
|
|
123
|
+
return
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from numpy.typing import NDArray
|
|
3
|
+
|
|
4
|
+
from framcore.fingerprints import Fingerprint
|
|
5
|
+
from framcore.loaders import TimeVectorLoader
|
|
6
|
+
from framcore.timeindexes import TimeIndex
|
|
7
|
+
from framcore.timevectors import ReferencePeriod
|
|
8
|
+
from framcore.timevectors.TimeVector import TimeVector # NB! full import path needed for inheritance to work
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LoadedTimeVector(TimeVector):
|
|
12
|
+
"""TimeVector which gets its data from a data source via a TimeVectorLoader. Subclass of TimeVector."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, vector_id: str, loader: TimeVectorLoader) -> None:
|
|
15
|
+
"""
|
|
16
|
+
Store vector id and loader in instance variables, get unit from loader.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
vector_id (str): Unique name of this vector.
|
|
20
|
+
loader (TimeVectorLoader): Object connected to a data source where vector_id is associated with a time
|
|
21
|
+
vector. The Loader object must also implement the TimeVectorLoader API.
|
|
22
|
+
|
|
23
|
+
Raises:
|
|
24
|
+
ValueError: When metadata in the TimeVectorLoader for both is_max_level and is_zero_one_profile for the
|
|
25
|
+
given vector_id is not None. This would mean the TimeVector represents both a level and a
|
|
26
|
+
profile, which is not allowed.
|
|
27
|
+
|
|
28
|
+
"""
|
|
29
|
+
self._vector_id = vector_id
|
|
30
|
+
self._loader = loader
|
|
31
|
+
self._check_type(self._vector_id, str)
|
|
32
|
+
self._check_type(self._loader, TimeVectorLoader)
|
|
33
|
+
|
|
34
|
+
self._is_max_level = self._loader.is_max_level(self._vector_id)
|
|
35
|
+
self._is_zero_one_profile = self._loader.is_zero_one_profile(self._vector_id)
|
|
36
|
+
self._unit = self._loader.get_unit(self._vector_id)
|
|
37
|
+
self._reference_period = self._loader.get_reference_period(self._vector_id)
|
|
38
|
+
|
|
39
|
+
if (self._is_max_level is not None and self._is_zero_one_profile is not None) or (self._is_max_level is None and self._is_zero_one_profile is None):
|
|
40
|
+
message = (
|
|
41
|
+
f"Values for {self._loader} is_max_level ({self._is_max_level}) and is_zero_one_profile"
|
|
42
|
+
f" ({self._is_zero_one_profile}) with time vector {self} Must have exactly one 'non-None' value."
|
|
43
|
+
" A TimeVector is either a level or a profile."
|
|
44
|
+
)
|
|
45
|
+
raise ValueError(message)
|
|
46
|
+
|
|
47
|
+
def __repr__(self) -> str:
|
|
48
|
+
"""Overwrite string representation of LoadedTimeVector objects."""
|
|
49
|
+
return f"{type(self).__name__}(vector_id={self._vector_id},loader={self._loader},unit={self._unit})"
|
|
50
|
+
|
|
51
|
+
def __eq__(self, other: object) -> bool:
|
|
52
|
+
"""Check equality between two LoadedTimeVector objects."""
|
|
53
|
+
if not isinstance(other, LoadedTimeVector):
|
|
54
|
+
return NotImplemented
|
|
55
|
+
return (self._vector_id == other._vector_id) and (self._loader == other._loader)
|
|
56
|
+
|
|
57
|
+
def __hash__(self) -> int:
|
|
58
|
+
"""Return hash of LoadedTimeVector object."""
|
|
59
|
+
return hash((self._vector_id, self._loader))
|
|
60
|
+
|
|
61
|
+
def get_vector(self, is_float32: bool) -> NDArray:
|
|
62
|
+
"""Get the vector of the TimeVector as a numpy array."""
|
|
63
|
+
vector = self._loader.get_values(self._vector_id)
|
|
64
|
+
if is_float32:
|
|
65
|
+
return vector.astype(np.float32)
|
|
66
|
+
return vector
|
|
67
|
+
|
|
68
|
+
def get_timeindex(self) -> TimeIndex:
|
|
69
|
+
"""
|
|
70
|
+
Get this time vectors index.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
TimeIndex: Object describing the index.
|
|
74
|
+
|
|
75
|
+
"""
|
|
76
|
+
return self._loader.get_index(self._vector_id)
|
|
77
|
+
|
|
78
|
+
def is_constant(self) -> bool:
|
|
79
|
+
"""Signify if this TimeVector is constant."""
|
|
80
|
+
return False
|
|
81
|
+
|
|
82
|
+
def get_unit(self) -> str:
|
|
83
|
+
"""Get the unit of this TimeVector."""
|
|
84
|
+
return self._unit
|
|
85
|
+
|
|
86
|
+
def get_loader(self) -> TimeVectorLoader:
|
|
87
|
+
"""Get the Loader this TimeVector retrieves its data from."""
|
|
88
|
+
return self._loader
|
|
89
|
+
|
|
90
|
+
def get_reference_period(self) -> ReferencePeriod | None:
|
|
91
|
+
"""Get the reference period which the data of this TimeVector is from."""
|
|
92
|
+
return self._reference_period
|
|
93
|
+
|
|
94
|
+
def is_max_level(self) -> bool | None:
|
|
95
|
+
"""Check if TimeVector is a level representing maximum Volume/Capacity."""
|
|
96
|
+
return self._loader.is_max_level(self._vector_id)
|
|
97
|
+
|
|
98
|
+
def is_zero_one_profile(self) -> bool | None:
|
|
99
|
+
"""Check if TimeVector is a profile with values between zero and one."""
|
|
100
|
+
return self._loader.is_zero_one_profile(self._vector_id)
|
|
101
|
+
|
|
102
|
+
def get_fingerprint(self) -> Fingerprint:
|
|
103
|
+
"""Get the Fingerprint of this TimeVector."""
|
|
104
|
+
return self._loader.get_fingerprint(self._vector_id)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from framcore import Base
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ReferencePeriod(Base):
|
|
5
|
+
"""ReferencePeriod class represents a period of one or more years."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, start_year: int, num_years: int) -> None:
|
|
8
|
+
"""Initialize a ReferencePeriod with the start year and number of years."""
|
|
9
|
+
self._check_type(start_year, int)
|
|
10
|
+
self._check_type(num_years, int)
|
|
11
|
+
if start_year < 0:
|
|
12
|
+
message = f"start_year must be a positive integer. Got {start_year}."
|
|
13
|
+
raise ValueError(message)
|
|
14
|
+
if num_years < 0:
|
|
15
|
+
message = f"num_years must be a positive integer. Got {num_years}."
|
|
16
|
+
raise ValueError(message)
|
|
17
|
+
self._start_year = start_year
|
|
18
|
+
self._num_years = num_years
|
|
19
|
+
|
|
20
|
+
def get_start_year(self) -> int:
|
|
21
|
+
"""Get the start_year from a ReferencePeriod instance."""
|
|
22
|
+
return self._start_year
|
|
23
|
+
|
|
24
|
+
def get_num_years(self) -> int:
|
|
25
|
+
"""Get the number of years in the ReferencePeriod."""
|
|
26
|
+
return self._num_years
|
|
27
|
+
|
|
28
|
+
def __eq__(self, other) -> bool: # noqa: ANN001
|
|
29
|
+
"""Check if self and other are equal."""
|
|
30
|
+
if not isinstance(other, type(self)):
|
|
31
|
+
return False
|
|
32
|
+
return self._start_year == other._start_year and self._num_years == other._num_years
|
|
33
|
+
|
|
34
|
+
def __hash__(self) -> int:
|
|
35
|
+
"""Compute hash value.."""
|
|
36
|
+
return hash(
|
|
37
|
+
(
|
|
38
|
+
self._start_year,
|
|
39
|
+
self._num_years,
|
|
40
|
+
),
|
|
41
|
+
)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from numpy.typing import NDArray
|
|
7
|
+
|
|
8
|
+
from framcore import Base
|
|
9
|
+
from framcore.fingerprints import Fingerprint
|
|
10
|
+
from framcore.timeindexes import TimeIndex
|
|
11
|
+
from framcore.timevectors import ReferencePeriod
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from framcore.loaders import TimeVectorLoader
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# TODO: Floating point precision
|
|
18
|
+
class TimeVector(Base, ABC):
|
|
19
|
+
"""TimeVector interface class."""
|
|
20
|
+
|
|
21
|
+
def __init__(self) -> None:
|
|
22
|
+
"""Initialize the TimeVector class."""
|
|
23
|
+
super().__init__()
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def __eq__(self, other) -> bool: # noqa: ANN001
|
|
27
|
+
"""Check if two TimeVectors are equal."""
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def __hash__(self) -> int:
|
|
32
|
+
"""Compute hash value."""
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
@abstractmethod
|
|
36
|
+
def get_vector(self, is_float32: bool) -> NDArray:
|
|
37
|
+
"""Get the values of the TimeVector."""
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def get_timeindex(self) -> TimeIndex | None:
|
|
42
|
+
"""Get the TimeIndex of the TimeVector."""
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def is_constant(self) -> bool:
|
|
47
|
+
"""Check if the TimeVector is constant."""
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
@abstractmethod
|
|
51
|
+
def is_max_level(self) -> bool | None:
|
|
52
|
+
"""
|
|
53
|
+
Check if TimeVector is a level representing max Volume/Capacity.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
True - vector is a level representing max Volume/Capacity.
|
|
57
|
+
False - vector is a level representing average Volume/Capacity over a given reference period.
|
|
58
|
+
None - vector is not a level.
|
|
59
|
+
|
|
60
|
+
"""
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
@abstractmethod
|
|
64
|
+
def is_zero_one_profile(self) -> bool | None:
|
|
65
|
+
"""
|
|
66
|
+
Check if TimeVector is a profile with values between zero and one.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
True - vector is a profile with values between zero and one.
|
|
70
|
+
False - vector is a profile where the mean value is 1 given a reference period.
|
|
71
|
+
None - vector is not a profile.
|
|
72
|
+
|
|
73
|
+
"""
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
@abstractmethod
|
|
77
|
+
def get_unit(self) -> str | None:
|
|
78
|
+
"""Get the unit of the TimeVector."""
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
@abstractmethod
|
|
82
|
+
def get_fingerprint(self) -> Fingerprint:
|
|
83
|
+
"""Get the fingerprint of the TimeVector."""
|
|
84
|
+
pass
|
|
85
|
+
|
|
86
|
+
@abstractmethod
|
|
87
|
+
def get_reference_period(self) -> ReferencePeriod | None:
|
|
88
|
+
"""Get the reference period of the TimeVector."""
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
@abstractmethod
|
|
92
|
+
def get_loader(self) -> TimeVectorLoader | None:
|
|
93
|
+
"""Get the TimeVectorLoader of the TimeVector if self has one."""
|
|
94
|
+
pass
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# framcore/timevectors/__init__.py
|
|
2
|
+
|
|
3
|
+
from framcore.timevectors.ReferencePeriod import ReferencePeriod
|
|
4
|
+
from framcore.timevectors.TimeVector import TimeVector
|
|
5
|
+
from framcore.timevectors.ConstantTimeVector import ConstantTimeVector
|
|
6
|
+
from framcore.timevectors.LinearTransformTimeVector import LinearTransformTimeVector
|
|
7
|
+
from framcore.timevectors.ListTimeVector import ListTimeVector
|
|
8
|
+
from framcore.timevectors.LoadedTimeVector import LoadedTimeVector
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"ConstantTimeVector",
|
|
12
|
+
"LinearTransformTimeVector",
|
|
13
|
+
"ListTimeVector",
|
|
14
|
+
"LoadedTimeVector",
|
|
15
|
+
"ReferencePeriod",
|
|
16
|
+
"TimeVector",
|
|
17
|
+
]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# framcore/lib/__init__.py
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from framcore.utils.get_supported_components import get_supported_components
|
|
5
|
+
from framcore.utils.node_flow_utils import (
|
|
6
|
+
FlowInfo,
|
|
7
|
+
get_component_to_nodes,
|
|
8
|
+
get_flow_infos,
|
|
9
|
+
get_node_to_commodity,
|
|
10
|
+
get_transports_by_commodity,
|
|
11
|
+
is_transport_by_commodity,
|
|
12
|
+
)
|
|
13
|
+
from framcore.utils.global_energy_equivalent import get_hydro_downstream_energy_equivalent, set_global_energy_equivalent
|
|
14
|
+
from framcore.utils.storage_subsystems import get_one_commodity_storage_subsystems
|
|
15
|
+
from framcore.utils.isolate_subnodes import isolate_subnodes
|
|
16
|
+
from framcore.utils.get_regional_volumes import get_regional_volumes, RegionalVolumes
|
|
17
|
+
from framcore.utils.loaders import add_loaders_if, add_loaders, replace_loader_path
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"FlowInfo",
|
|
21
|
+
"RegionalVolumes",
|
|
22
|
+
"add_loaders",
|
|
23
|
+
"add_loaders_if",
|
|
24
|
+
"get_component_to_nodes",
|
|
25
|
+
"get_flow_infos",
|
|
26
|
+
"get_hydro_downstream_energy_equivalent",
|
|
27
|
+
"get_node_to_commodity",
|
|
28
|
+
"get_one_commodity_storage_subsystems",
|
|
29
|
+
"get_regional_volumes",
|
|
30
|
+
"get_supported_components",
|
|
31
|
+
"get_transports_by_commodity",
|
|
32
|
+
"is_transport_by_commodity",
|
|
33
|
+
"isolate_subnodes",
|
|
34
|
+
"replace_loader_path",
|
|
35
|
+
"set_global_energy_equivalent",
|
|
36
|
+
]
|