fram-core 0.1.0a1__py3-none-any.whl → 0.1.1__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.0a1.dist-info → fram_core-0.1.1.dist-info}/METADATA +6 -5
- fram_core-0.1.1.dist-info/RECORD +100 -0
- {fram_core-0.1.0a1.dist-info → fram_core-0.1.1.dist-info}/WHEEL +1 -1
- framcore/Base.py +22 -3
- framcore/Model.py +26 -9
- framcore/__init__.py +2 -1
- framcore/aggregators/Aggregator.py +30 -11
- framcore/aggregators/HydroAggregator.py +37 -25
- framcore/aggregators/NodeAggregator.py +65 -30
- framcore/aggregators/WindSolarAggregator.py +22 -30
- framcore/attributes/Arrow.py +6 -4
- framcore/attributes/ElasticDemand.py +13 -13
- framcore/attributes/ReservoirCurve.py +3 -17
- framcore/attributes/SoftBound.py +2 -5
- framcore/attributes/StartUpCost.py +14 -3
- framcore/attributes/Storage.py +17 -5
- framcore/attributes/TargetBound.py +2 -4
- framcore/attributes/__init__.py +2 -4
- framcore/attributes/hydro/HydroBypass.py +9 -2
- framcore/attributes/hydro/HydroGenerator.py +24 -7
- framcore/attributes/hydro/HydroPump.py +32 -10
- framcore/attributes/hydro/HydroReservoir.py +4 -4
- framcore/attributes/level_profile_attributes.py +250 -53
- framcore/components/Component.py +27 -3
- framcore/components/Demand.py +18 -4
- framcore/components/Flow.py +26 -4
- framcore/components/HydroModule.py +45 -4
- framcore/components/Node.py +32 -9
- framcore/components/Thermal.py +12 -8
- framcore/components/Transmission.py +17 -2
- framcore/components/wind_solar.py +25 -10
- framcore/curves/LoadedCurve.py +0 -9
- framcore/expressions/Expr.py +137 -36
- framcore/expressions/__init__.py +3 -1
- framcore/expressions/_get_constant_from_expr.py +14 -20
- framcore/expressions/queries.py +121 -84
- framcore/expressions/units.py +30 -3
- framcore/fingerprints/fingerprint.py +0 -1
- framcore/juliamodels/JuliaModel.py +13 -3
- framcore/loaders/loaders.py +0 -2
- framcore/metadata/ExprMeta.py +13 -7
- framcore/metadata/LevelExprMeta.py +16 -1
- framcore/metadata/Member.py +7 -7
- framcore/metadata/__init__.py +1 -1
- framcore/querydbs/CacheDB.py +1 -1
- framcore/solvers/Solver.py +21 -6
- framcore/solvers/SolverConfig.py +4 -4
- framcore/timeindexes/AverageYearRange.py +9 -2
- framcore/timeindexes/ConstantTimeIndex.py +7 -2
- framcore/timeindexes/DailyIndex.py +14 -2
- framcore/timeindexes/FixedFrequencyTimeIndex.py +105 -53
- framcore/timeindexes/HourlyIndex.py +14 -2
- framcore/timeindexes/IsoCalendarDay.py +5 -3
- framcore/timeindexes/ListTimeIndex.py +103 -23
- framcore/timeindexes/ModelYear.py +8 -2
- framcore/timeindexes/ModelYears.py +11 -2
- framcore/timeindexes/OneYearProfileTimeIndex.py +10 -2
- framcore/timeindexes/ProfileTimeIndex.py +14 -3
- framcore/timeindexes/SinglePeriodTimeIndex.py +1 -1
- framcore/timeindexes/TimeIndex.py +16 -3
- framcore/timeindexes/WeeklyIndex.py +14 -2
- framcore/{expressions → timeindexes}/_time_vector_operations.py +76 -2
- framcore/timevectors/ConstantTimeVector.py +12 -16
- framcore/timevectors/LinearTransformTimeVector.py +20 -3
- framcore/timevectors/ListTimeVector.py +18 -14
- framcore/timevectors/LoadedTimeVector.py +1 -8
- framcore/timevectors/ReferencePeriod.py +13 -3
- framcore/timevectors/TimeVector.py +26 -12
- framcore/utils/__init__.py +0 -1
- framcore/utils/get_regional_volumes.py +21 -3
- framcore/utils/get_supported_components.py +1 -1
- framcore/utils/global_energy_equivalent.py +22 -5
- framcore/utils/isolate_subnodes.py +12 -3
- framcore/utils/loaders.py +7 -7
- framcore/utils/node_flow_utils.py +4 -4
- framcore/utils/storage_subsystems.py +3 -4
- fram_core-0.1.0a1.dist-info/RECORD +0 -100
- {fram_core-0.1.0a1.dist-info → fram_core-0.1.1.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -8,7 +8,7 @@ from framcore.timevectors.TimeVector import TimeVector # NB! full import path n
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class ListTimeVector(TimeVector):
|
|
11
|
-
"""
|
|
11
|
+
"""TimeVector with a numpy array of values paired with a timeindex."""
|
|
12
12
|
|
|
13
13
|
def __init__(
|
|
14
14
|
self,
|
|
@@ -37,18 +37,13 @@ class ListTimeVector(TimeVector):
|
|
|
37
37
|
Raises:
|
|
38
38
|
ValueError: When both is_max_level and is_zero_one_profile is not None. This would mean the TimeVector
|
|
39
39
|
represents both a level and a profile, which is not allowed.
|
|
40
|
+
ValueError: When the shape of the vector does not match the number of periods in the timeindex.
|
|
40
41
|
|
|
41
42
|
"""
|
|
42
|
-
if
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
# )
|
|
43
|
+
if vector.shape != (timeindex.get_num_periods(),):
|
|
44
|
+
msg = f"Vector shape {vector.shape} does not match number of periods {timeindex.get_num_periods()} of timeindex ({timeindex})."
|
|
45
|
+
raise ValueError(msg)
|
|
46
|
+
|
|
52
47
|
self._timeindex = timeindex
|
|
53
48
|
self._vector = vector
|
|
54
49
|
self._unit = unit
|
|
@@ -56,7 +51,16 @@ class ListTimeVector(TimeVector):
|
|
|
56
51
|
self._is_max_level = is_max_level
|
|
57
52
|
self._is_zero_one_profile = is_zero_one_profile
|
|
58
53
|
|
|
59
|
-
|
|
54
|
+
self._check_type(timeindex, TimeIndex)
|
|
55
|
+
self._check_type(vector, np.ndarray)
|
|
56
|
+
self._check_type(unit, (str, type(None)))
|
|
57
|
+
self._check_type(is_max_level, (bool, type(None)))
|
|
58
|
+
self._check_type(is_zero_one_profile, (bool, type(None)))
|
|
59
|
+
self._check_type(reference_period, (ReferencePeriod, type(None)))
|
|
60
|
+
|
|
61
|
+
self._check_is_level_or_profile()
|
|
62
|
+
|
|
63
|
+
def __eq__(self, other: object) -> None:
|
|
60
64
|
"""Check equality between two ListTimeVector objects."""
|
|
61
65
|
if not isinstance(other, ListTimeVector):
|
|
62
66
|
return NotImplemented
|
|
@@ -73,9 +77,9 @@ class ListTimeVector(TimeVector):
|
|
|
73
77
|
"""Return hash of ListTimeVector object."""
|
|
74
78
|
return hash((self._timeindex, self._vector.tobytes(), self._unit, self._is_max_level, self._is_zero_one_profile, self._reference_period))
|
|
75
79
|
|
|
76
|
-
def __repr__(self) -> str:
|
|
80
|
+
def __repr__(self) -> str:
|
|
77
81
|
"""Return the string representation of the ListTimeVector."""
|
|
78
|
-
return f"ListTimeVector(timeindex={self._timeindex}, vector={self._vector}, unit={self._unit})"
|
|
82
|
+
return f"ListTimeVector(timeindex={self._timeindex}, vector={self._vector}, unit={self._unit}, reference_period={self._reference_period})"
|
|
79
83
|
|
|
80
84
|
def get_vector(self, is_float32: bool) -> NDArray:
|
|
81
85
|
"""Get the vector of the TimeVector as a numpy array."""
|
|
@@ -30,19 +30,12 @@ class LoadedTimeVector(TimeVector):
|
|
|
30
30
|
self._loader = loader
|
|
31
31
|
self._check_type(self._vector_id, str)
|
|
32
32
|
self._check_type(self._loader, TimeVectorLoader)
|
|
33
|
-
|
|
34
33
|
self._is_max_level = self._loader.is_max_level(self._vector_id)
|
|
35
34
|
self._is_zero_one_profile = self._loader.is_zero_one_profile(self._vector_id)
|
|
36
35
|
self._unit = self._loader.get_unit(self._vector_id)
|
|
37
36
|
self._reference_period = self._loader.get_reference_period(self._vector_id)
|
|
38
37
|
|
|
39
|
-
|
|
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)
|
|
38
|
+
self._check_is_level_or_profile()
|
|
46
39
|
|
|
47
40
|
def __repr__(self) -> str:
|
|
48
41
|
"""Overwrite string representation of LoadedTimeVector objects."""
|
|
@@ -5,15 +5,25 @@ class ReferencePeriod(Base):
|
|
|
5
5
|
"""ReferencePeriod class represents a period of one or more years."""
|
|
6
6
|
|
|
7
7
|
def __init__(self, start_year: int, num_years: int) -> None:
|
|
8
|
-
"""
|
|
8
|
+
"""
|
|
9
|
+
Initialize a ReferencePeriod with the start year and number of years.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
start_year (int): The first year in the reference period. Must be a positive integer.
|
|
13
|
+
num_years (int): The number of years in the reference period. Must be a positive non-zero integer.
|
|
14
|
+
|
|
15
|
+
"""
|
|
9
16
|
self._check_type(start_year, int)
|
|
10
17
|
self._check_type(num_years, int)
|
|
18
|
+
|
|
11
19
|
if start_year < 0:
|
|
12
20
|
message = f"start_year must be a positive integer. Got {start_year}."
|
|
13
21
|
raise ValueError(message)
|
|
14
|
-
|
|
15
|
-
|
|
22
|
+
|
|
23
|
+
if num_years <= 0:
|
|
24
|
+
message = f"num_years must be a positive non-zero integer. Got {num_years}."
|
|
16
25
|
raise ValueError(message)
|
|
26
|
+
|
|
17
27
|
self._start_year = start_year
|
|
18
28
|
self._num_years = num_years
|
|
19
29
|
|
|
@@ -16,7 +16,7 @@ if TYPE_CHECKING:
|
|
|
16
16
|
|
|
17
17
|
# TODO: Floating point precision
|
|
18
18
|
class TimeVector(Base, ABC):
|
|
19
|
-
"""TimeVector interface class."""
|
|
19
|
+
"""TimeVector interface class for defining timeseries data."""
|
|
20
20
|
|
|
21
21
|
def __init__(self) -> None:
|
|
22
22
|
"""Initialize the TimeVector class."""
|
|
@@ -50,12 +50,9 @@ class TimeVector(Base, ABC):
|
|
|
50
50
|
@abstractmethod
|
|
51
51
|
def is_max_level(self) -> bool | None:
|
|
52
52
|
"""
|
|
53
|
-
|
|
53
|
+
Whether the TimeVector represents the maximum level, average level given a reference period, or not a level at all.
|
|
54
54
|
|
|
55
|
-
|
|
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.
|
|
55
|
+
See LevelProfile for a description of Level (max or avg) and Profile (max one or mean one), and their formats.
|
|
59
56
|
|
|
60
57
|
"""
|
|
61
58
|
pass
|
|
@@ -63,12 +60,9 @@ class TimeVector(Base, ABC):
|
|
|
63
60
|
@abstractmethod
|
|
64
61
|
def is_zero_one_profile(self) -> bool | None:
|
|
65
62
|
"""
|
|
66
|
-
|
|
63
|
+
Whether the TimeVector represents a profile with values between 0 and 1, a profile with average 1 over a given reference period, or is not a profile.
|
|
67
64
|
|
|
68
|
-
|
|
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.
|
|
65
|
+
See LevelProfile for a description of Level (max or avg) and Profile (max one or mean one), and their formats.
|
|
72
66
|
|
|
73
67
|
"""
|
|
74
68
|
pass
|
|
@@ -90,5 +84,25 @@ class TimeVector(Base, ABC):
|
|
|
90
84
|
|
|
91
85
|
@abstractmethod
|
|
92
86
|
def get_loader(self) -> TimeVectorLoader | None:
|
|
93
|
-
"""
|
|
87
|
+
"""
|
|
88
|
+
Get the TimeVectorLoader of the TimeVector if self has one.
|
|
89
|
+
|
|
90
|
+
TimeVectors can store timeseries data in Loaders that point to databases. Data is only retrieved and cached when the TimeVector is queried.
|
|
91
|
+
"""
|
|
94
92
|
pass
|
|
93
|
+
|
|
94
|
+
"""
|
|
95
|
+
Checks that the TimeVector is either a level or a profile.
|
|
96
|
+
|
|
97
|
+
Raises:
|
|
98
|
+
ValueError: If both is_max_level and is_zero_one_profile are None or both are not None.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
def _check_is_level_or_profile(self) -> None:
|
|
102
|
+
"""Ensure that the TimeVector is either a level or a profile."""
|
|
103
|
+
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):
|
|
104
|
+
message = (
|
|
105
|
+
f"Invalid input arguments for {self}: Must have exactly one 'non-None' value for "
|
|
106
|
+
"is_max_level and is_zero_one_profile. A TimeVector is either a level or a profile."
|
|
107
|
+
)
|
|
108
|
+
raise ValueError(message)
|
framcore/utils/__init__.py
CHANGED
|
@@ -176,11 +176,11 @@ def _get_vector(
|
|
|
176
176
|
# TODO: More options: node_category, consumption_category, production_category, with_trade_partners
|
|
177
177
|
|
|
178
178
|
|
|
179
|
-
def _check_category(category, flow_id, flow_info) -> None:
|
|
179
|
+
def _check_category(category: str, flow_id: str, flow_info: FlowInfo) -> None:
|
|
180
180
|
pass
|
|
181
181
|
|
|
182
182
|
|
|
183
|
-
def get_regional_volumes(
|
|
183
|
+
def get_regional_volumes( # noqa C901
|
|
184
184
|
db: Model | QueryDB,
|
|
185
185
|
commodity: str,
|
|
186
186
|
node_category: str,
|
|
@@ -191,7 +191,25 @@ def get_regional_volumes(
|
|
|
191
191
|
unit: str,
|
|
192
192
|
is_float32: bool = True,
|
|
193
193
|
) -> RegionalVolumes:
|
|
194
|
-
"""
|
|
194
|
+
"""
|
|
195
|
+
Calculate aggregated production, consumption, import and export for member in node_category.
|
|
196
|
+
|
|
197
|
+
Decompose the model components into nodes and flows. Analyze the flows to determine their contribution to production, consumption, import, and export if
|
|
198
|
+
they are associated with the specified commodity. Group these contributions based on the provided node_category, production_category, and
|
|
199
|
+
consumption_category metadata.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
db (Model | QueryDB): Model or QueryDB to use
|
|
203
|
+
commodity (str): Commodity to consider
|
|
204
|
+
node_category (str): Meta key for node category to group the results by
|
|
205
|
+
production_category (str): Meta key for production category to group the results by
|
|
206
|
+
consumption_category (str): Meta key for consumption category to group the results by
|
|
207
|
+
data_period (SinglePeriodTimeIndex): Consider results for this data period
|
|
208
|
+
scenario_period (FixedFrequencyTimeIndex): Consider results for this scenario period
|
|
209
|
+
unit (str): Unit to use for the results
|
|
210
|
+
is_float32 (bool): Use float32 for calculations and results if True
|
|
211
|
+
|
|
212
|
+
"""
|
|
195
213
|
db = _load_model_and_create_model_db(db)
|
|
196
214
|
|
|
197
215
|
if not isinstance(is_float32, bool):
|
|
@@ -6,7 +6,7 @@ def get_supported_components(
|
|
|
6
6
|
supported_types: tuple[type[Component]],
|
|
7
7
|
forbidden_types: tuple[type[Component]],
|
|
8
8
|
) -> dict[str, Component]:
|
|
9
|
-
"""Return simplified version of components in compliance with specified component types."""
|
|
9
|
+
"""Return simplified version of components in compliance with specified component types.See description in Component."""
|
|
10
10
|
output: dict[str, Component] = {}
|
|
11
11
|
errors: list[str] = []
|
|
12
12
|
|
|
@@ -11,23 +11,31 @@ def get_hydro_downstream_energy_equivalent(
|
|
|
11
11
|
power_node: str | None = None,
|
|
12
12
|
) -> Expr:
|
|
13
13
|
"""
|
|
14
|
-
Get the sum downstream energy equivalent for a hydro module.
|
|
14
|
+
Get the expression for the sum downstream energy equivalent for a hydro module.
|
|
15
|
+
|
|
16
|
+
- If power node is given, only count downstream energy equivalents that are connected to the power node.
|
|
17
|
+
- Energy equivalents are collected from hydro generators downstream, and the main topology follows the release_to attribute.
|
|
18
|
+
- Transport pumps are included in the downstream topology, but counted as negative energy equivalents.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
data (dict[str, Component | TimeVector | Curve | Expr]): The dict containing the components.
|
|
22
|
+
module_name (str): The name of the hydro module to start from.
|
|
23
|
+
power_node (str): Optional power node to filter energy equivalents.
|
|
15
24
|
|
|
16
|
-
Either count all downstream energy equivalents, or only those that are connected to the given power_node.
|
|
17
25
|
"""
|
|
18
26
|
if data[module_name].get_pump() and data[module_name].get_pump().get_from_module() == module_name: # transport pump
|
|
19
27
|
pump_power_node = data[module_name].get_pump().get_power_node()
|
|
20
28
|
pump_to = data[module_name].get_pump().get_to_module()
|
|
21
29
|
energy_equivalent = get_hydro_downstream_energy_equivalent(data, pump_to, power_node) # continue downstream of pump_to module
|
|
22
30
|
if power_node in (pump_power_node, None):
|
|
23
|
-
return energy_equivalent - data[module_name].get_pump().
|
|
31
|
+
return energy_equivalent - data[module_name].get_pump().get_energy_equivalent().get_level() # pumps has negative energy equivalents
|
|
24
32
|
return energy_equivalent
|
|
25
33
|
|
|
26
34
|
energy_equivalent = 0
|
|
27
35
|
if data[module_name].get_generator(): # hydro generator
|
|
28
36
|
module_power_node = data[module_name].get_generator().get_power_node()
|
|
29
37
|
if power_node in (module_power_node, None):
|
|
30
|
-
energy_equivalent += data[module_name].get_generator().
|
|
38
|
+
energy_equivalent += data[module_name].get_generator().get_energy_equivalent().get_level()
|
|
31
39
|
if data[module_name].get_release_to(): # continue from release_to module
|
|
32
40
|
release_to = data[module_name].get_release_to()
|
|
33
41
|
energy_equivalent += get_hydro_downstream_energy_equivalent(data, release_to, power_node)
|
|
@@ -35,7 +43,16 @@ def get_hydro_downstream_energy_equivalent(
|
|
|
35
43
|
|
|
36
44
|
|
|
37
45
|
def set_global_energy_equivalent(data: dict[str, Component | TimeVector | Curve | Expr], metakey_energy_eq_downstream: str) -> None:
|
|
38
|
-
"""
|
|
46
|
+
"""
|
|
47
|
+
Loop through data dict and set the downstream energy equivalent for all HydroModules.
|
|
48
|
+
|
|
49
|
+
Send a warning event if a HydroModule has no downstream energy equivalents.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
data (dict[str, Component | TimeVector | Curve | Expr]): The dict containing the components.
|
|
53
|
+
metakey_energy_eq_downstream (str): The meta key to use for storing the downstream energy equivalent.
|
|
54
|
+
|
|
55
|
+
"""
|
|
39
56
|
for module_name, module in data.items():
|
|
40
57
|
if isinstance(module, HydroModule) and module.get_reservoir():
|
|
41
58
|
energy_equivalent = get_hydro_downstream_energy_equivalent(data, module_name)
|
|
@@ -22,11 +22,20 @@ def _is_member(node: Node, meta_key: str, members: set[str]) -> bool:
|
|
|
22
22
|
return value in members
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
def isolate_subnodes(model: Model, commodity: str, meta_key: str, members: list[str]) -> None:
|
|
25
|
+
def isolate_subnodes(model: Model, commodity: str, meta_key: str, members: list[str]) -> None: # noqa: PLR0915, C901
|
|
26
26
|
"""
|
|
27
|
-
|
|
27
|
+
For components in model, delete all nodes of commodity except member nodes, and their flows and boundary nodes.
|
|
28
|
+
|
|
29
|
+
- Keep member nodes and all flows between them.
|
|
30
|
+
- Set boundary nodes exogenous and keep boundary flows into or out from member nodes.
|
|
31
|
+
- Delete all other nodes of commodity and all other flows pointing to them.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
model (Model): Model to modify
|
|
35
|
+
commodity (str): Commodity of nodes to consider
|
|
36
|
+
meta_key (str): Meta key to use to identify members
|
|
37
|
+
members (List[str]): List of meta key values identifying member nodes
|
|
28
38
|
|
|
29
|
-
Boudary nodes are set exogenous and all flows pointing to them except boundary flows into or out from member nodes.
|
|
30
39
|
"""
|
|
31
40
|
t = time()
|
|
32
41
|
|
framcore/utils/loaders.py
CHANGED
|
@@ -20,12 +20,12 @@ def add_loaders_if(loaders: set, value: object | None) -> None:
|
|
|
20
20
|
|
|
21
21
|
def add_loaders(loaders: set[Loader], model: Model) -> None:
|
|
22
22
|
"""Add all loaders stored in Model to loaders set."""
|
|
23
|
-
from framcore import Model
|
|
24
|
-
from framcore.components import Component, Flow, Node
|
|
25
|
-
from framcore.curves import Curve
|
|
26
|
-
from framcore.expressions import Expr
|
|
27
|
-
from framcore.timevectors import TimeVector
|
|
28
|
-
from framcore.utils import get_supported_components
|
|
23
|
+
from framcore import Model
|
|
24
|
+
from framcore.components import Component, Flow, Node
|
|
25
|
+
from framcore.curves import Curve
|
|
26
|
+
from framcore.expressions import Expr
|
|
27
|
+
from framcore.timevectors import TimeVector
|
|
28
|
+
from framcore.utils import get_supported_components
|
|
29
29
|
|
|
30
30
|
_check_type(loaders, "loaders", set)
|
|
31
31
|
_check_type(model, "model", Model)
|
|
@@ -53,7 +53,7 @@ def add_loaders(loaders: set[Loader], model: Model) -> None:
|
|
|
53
53
|
|
|
54
54
|
def replace_loader_path(loaders: set[Loader], old: Path, new: Path) -> None:
|
|
55
55
|
"""Replace old path with new for all loaders using old path."""
|
|
56
|
-
from framcore.loaders import FileLoader
|
|
56
|
+
from framcore.loaders import FileLoader
|
|
57
57
|
|
|
58
58
|
_check_type(loaders, "loaders", set)
|
|
59
59
|
|
|
@@ -56,7 +56,7 @@ def get_node_to_commodity(data: dict[str, object]) -> dict[str, str]:
|
|
|
56
56
|
return out
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
def get_flow_infos(flow: Flow, node_to_commodity: dict[str, str]) -> list[FlowInfo]:
|
|
59
|
+
def get_flow_infos(flow: Flow, node_to_commodity: dict[str, str]) -> list[FlowInfo]: # noqa: C901
|
|
60
60
|
"""Get flow infos from analysis of all its arrows."""
|
|
61
61
|
_check_type(flow, Flow)
|
|
62
62
|
_check_type(node_to_commodity, dict)
|
|
@@ -149,8 +149,8 @@ def get_flow_infos(flow: Flow, node_to_commodity: dict[str, str]) -> list[FlowIn
|
|
|
149
149
|
|
|
150
150
|
|
|
151
151
|
def get_component_to_nodes(data: Model | dict[str, object]) -> dict[str, set[str]]:
|
|
152
|
-
"""For each str key in data where value is a
|
|
153
|
-
from framcore import Model
|
|
152
|
+
"""For each str key in data where value is a Component find all Node id str in data directly connected to the Component."""
|
|
153
|
+
from framcore import Model
|
|
154
154
|
|
|
155
155
|
_check_type(data, Model | dict)
|
|
156
156
|
|
|
@@ -184,7 +184,7 @@ def get_component_to_nodes(data: Model | dict[str, object]) -> dict[str, set[str
|
|
|
184
184
|
|
|
185
185
|
def get_transports_by_commodity(data: Model | dict[str, object], commodity: str) -> dict[str, tuple[str, str]]:
|
|
186
186
|
"""Return dict with key component_id and value (from_node_id, to_node_id) where both nodes belong to given commodity."""
|
|
187
|
-
from framcore import Model
|
|
187
|
+
from framcore import Model
|
|
188
188
|
|
|
189
189
|
_check_type(data, Model | dict)
|
|
190
190
|
_check_type(commodity, str)
|
|
@@ -8,7 +8,7 @@ from framcore.utils import get_supported_components
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
# TODO: Finish implementation, test and demo
|
|
11
|
-
def get_storage_subsystems(domain_components: dict[str, Component] | Model) -> dict[str, set[str]]:
|
|
11
|
+
def get_storage_subsystems(domain_components: dict[str, Component] | Model) -> dict[str, set[str]]: # noqa: D103
|
|
12
12
|
if isinstance(domain_components, Model):
|
|
13
13
|
domain_components = {k: v for k, v in domain_components.get_data() if isinstance(v, Component)}
|
|
14
14
|
|
|
@@ -21,12 +21,11 @@ def get_storage_subsystems(domain_components: dict[str, Component] | Model) -> d
|
|
|
21
21
|
abstract_subsystems, __ = get_one_commodity_storage_subsystems(graph, include_boundaries=True)
|
|
22
22
|
|
|
23
23
|
# TODO: Use Component.get_top_level to lift abstract_subsystems back to domain_components
|
|
24
|
-
|
|
24
|
+
return abstract_subsystems
|
|
25
25
|
|
|
26
|
-
return domain_subsystems
|
|
27
26
|
|
|
28
27
|
|
|
29
|
-
def get_one_commodity_storage_subsystems(
|
|
28
|
+
def get_one_commodity_storage_subsystems( # noqa: C901
|
|
30
29
|
graph: dict[str, Node | Flow],
|
|
31
30
|
include_boundaries: bool,
|
|
32
31
|
) -> dict[str, tuple[str, set[str], set[str]]]:
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
framcore/Base.py,sha256=2MP0T1HAjU3gqkSvdGnbvd3t1JZmdXGCcwueETIhrrs,5326
|
|
2
|
-
framcore/Model.py,sha256=TraN6dRQoJgm4veePEVszpdGAMGiTJA1dKSG4s_DtZg,2580
|
|
3
|
-
framcore/__init__.py,sha256=5Ryn1oUwtxaPX95dfleE5GVYo9_QSBAwMG8UiUNrg74,128
|
|
4
|
-
framcore/aggregators/Aggregator.py,sha256=n9jL4iAGk_N0An80BJNntkYYaXaQzGW1xGD3oFjUYzk,6473
|
|
5
|
-
framcore/aggregators/HydroAggregator.py,sha256=ubV16QcJ63Uh8g_HzSexsHDFdUszODpBiEfaUhWZ8ko,47174
|
|
6
|
-
framcore/aggregators/NodeAggregator.py,sha256=Zz4D1H42EmDU0jgYJtAR4C0_eRDN6nacLA3guRt_r2M,20716
|
|
7
|
-
framcore/aggregators/WindSolarAggregator.py,sha256=3cHIxYZixTIH8kmkuR8GL6eROd8oU7z5txRVCMOvOrg,19620
|
|
8
|
-
framcore/aggregators/__init__.py,sha256=ZoBqilfv0XhFkYVROBPQhJHzSY1IcvhJmJ_FOo_Z5Pw,426
|
|
9
|
-
framcore/aggregators/_utils.py,sha256=EoRLeGmPC2ds-egPdvDewtaYbRozi6Psyf9DD1PRajk,8337
|
|
10
|
-
framcore/attributes/Arrow.py,sha256=7P5xpXD6MdlIuERGQn9f0ia4-tQVYNiSP6CfMbX3K7Q,10863
|
|
11
|
-
framcore/attributes/ElasticDemand.py,sha256=sG5wUTw17PQA_8YESaPMnRjUbr7nm6mSmkmuHoGlqJU,3024
|
|
12
|
-
framcore/attributes/ReservoirCurve.py,sha256=EVzCMPM5OELB9U9_BAYmDOEFF4Pd6LwwmDOzRpkRVME,813
|
|
13
|
-
framcore/attributes/SoftBound.py,sha256=7bW6KlSsKFvh8F6UPjC5PoLMGI7gClNo-dQrwAQHD5k,417
|
|
14
|
-
framcore/attributes/StartUpCost.py,sha256=WLZ8mcQWdSyyA0GKIJ2rhMbAU17pHAREBP1Tb-3_4rU,1831
|
|
15
|
-
framcore/attributes/Storage.py,sha256=x6njOhmkR3VvFI3Umn1Jjjd4F6yHWx-ZNNOYYv0lcZs,5335
|
|
16
|
-
framcore/attributes/TargetBound.py,sha256=DHl8CCPynhrcRqTHPhFo9HddhEt489mGqrqUHQPkPhg,433
|
|
17
|
-
framcore/attributes/__init__.py,sha256=SPzgyK4TQSMJ5tWOUmYfUpvWliCbQF8AVQkf6JeEGos,1552
|
|
18
|
-
framcore/attributes/hydro/HydroBypass.py,sha256=ZiAfOiukGvlckCRIlccFqjnAwLiGn1SnN1uqtSgN9H4,1342
|
|
19
|
-
framcore/attributes/hydro/HydroGenerator.py,sha256=ed0jMP808qchxkc4mXrVdtSO0LAGY6ihrjLN8xvdzN0,3207
|
|
20
|
-
framcore/attributes/hydro/HydroPump.py,sha256=Yi54d259CzKpcu44hhWoX3ZxTBqhzlWun1WC5pGfVKw,5915
|
|
21
|
-
framcore/attributes/hydro/HydroReservoir.py,sha256=7rYu530BTX9dJmTYrd_02uPddj290E-ziiZzjh_3Q3k,879
|
|
22
|
-
framcore/attributes/hydro/__init__.py,sha256=isOSLP2TdHOaPcr16EXIkdtx80LVe8ztFPiuGJPC4ao,381
|
|
23
|
-
framcore/attributes/level_profile_attributes.py,sha256=hZEBy_yjTJ4BIDM0qiNsQeO7Kcvr1CNMlv8Oyck7lkM,23340
|
|
24
|
-
framcore/components/Component.py,sha256=GT_scqmDwSE8eLB3ZHcDMGfenRbko7xj4cenm_6Io-Q,3820
|
|
25
|
-
framcore/components/Demand.py,sha256=vUP3hWobtk_Qe7ZGD2bXkLR_9zhaGrB8tKu3SvcvQp0,5399
|
|
26
|
-
framcore/components/Flow.py,sha256=wuqKZ76uIw-OfdEVC-55wok7PmoeRs7KEAR-o2wUC6A,5887
|
|
27
|
-
framcore/components/HydroModule.py,sha256=qpu0Fo4bFJs9kgwHtfwlInOX2UvwB1khdvRHWFWgmYQ,11352
|
|
28
|
-
framcore/components/Node.py,sha256=Kh8Glu0M0UjmEpJhlATXD9xqc7QZEd5HxFdE2EVT58s,2280
|
|
29
|
-
framcore/components/Thermal.py,sha256=MY0iOD870NSptZWpynKUEd8CuLt50s3_265GIiMG4Qc,7666
|
|
30
|
-
framcore/components/Transmission.py,sha256=DlVrkKT8rNTUyQXaO3375S1zKfE1OOkl3QYGB7BhhMU,6842
|
|
31
|
-
framcore/components/_PowerPlant.py,sha256=zDJ5LtYQN2GLa__BaqCLz54mZJil3dOYjICMPurh-U8,2787
|
|
32
|
-
framcore/components/__init__.py,sha256=0N4UMrYi7cYYaZHMIS6HSOli2jEbtct6LsZ0JcwGz5A,568
|
|
33
|
-
framcore/components/wind_solar.py,sha256=YsIPMZQEP81tijneFkeMEfprttu7lX7T5loVmSjSM90,2060
|
|
34
|
-
framcore/curves/Curve.py,sha256=89CsAJpCa_GkQtsBGclUcK8D3ttCyYhs583-_6zE0is,934
|
|
35
|
-
framcore/curves/LoadedCurve.py,sha256=8DiyLeJzydx6Q6MNQonxNGujl3zPma3vINDUN7E8_As,3891
|
|
36
|
-
framcore/curves/__init__.py,sha256=BnzdAZVjPwJcjduramRPPX6NJag-g6aKXPho2PwmGco,170
|
|
37
|
-
framcore/events/__init__.py,sha256=O3lOZukd_ixwbkoOmf2ei_--lKJLVXvyhSHjUDfaXEE,401
|
|
38
|
-
framcore/events/events.py,sha256=mNcHUjWraKyb-gwxeKr5ryOtcN8dCKptRWIYgcxM1p4,1683
|
|
39
|
-
framcore/expressions/Expr.py,sha256=I3m8cy-PNomN6p9088QQf1c4Egei5XEj7JoxwqZC0cY,20614
|
|
40
|
-
framcore/expressions/__init__.py,sha256=J8bNtWRfIpwIi6yZIjFazQXU9ymJbKsYLqPlMUoH028,628
|
|
41
|
-
framcore/expressions/_get_constant_from_expr.py,sha256=bqq-_xRhOrly6GB9Z868icgNqxrrUzobN1zXCq8B6lg,16596
|
|
42
|
-
framcore/expressions/_time_vector_operations.py,sha256=kIMmQYR-U2aAxB5KPWx-zaqLvjvlmiwa2yCnmeNvvRY,29031
|
|
43
|
-
framcore/expressions/_utils.py,sha256=mtruqnHcwpkIufbTFjJvT3iUfN98gN51SQ9e9hS9cUc,2123
|
|
44
|
-
framcore/expressions/queries.py,sha256=PLJVL0CJoJp3okIYyG1QOrR3s9HHfBdZdxuCzrCBHa0,16258
|
|
45
|
-
framcore/expressions/units.py,sha256=9X243DutWfkCbRNzy65frQNKN8tlLLzLvWYtiEyhHcg,6863
|
|
46
|
-
framcore/fingerprints/__init__.py,sha256=YpIj-t6DRrSOmdidchC4qjLHSoZwsdkf9980nHUsnsw,256
|
|
47
|
-
framcore/fingerprints/fingerprint.py,sha256=-e8aweHfPj8VURJqEra14xydVw3E1heB17LWcPFzIZo,9191
|
|
48
|
-
framcore/juliamodels/JuliaModel.py,sha256=S-W_t4Pv-xuzz6lrULmxNPu0No6Zs1CPpb9WW3ECZK0,6596
|
|
49
|
-
framcore/juliamodels/__init__.py,sha256=2ia9EGUQAZD0_f2o0NWdhD0d2z80K_bweohnGNfnpGA,124
|
|
50
|
-
framcore/loaders/__init__.py,sha256=iwlnauyXhH_BAuVIKVmX2vMvU94i_bXI57CE82eM7VA,209
|
|
51
|
-
framcore/loaders/loaders.py,sha256=EYqKeItQS5-zI-n-yOJf_7C_Ojo5VBk143f76joINYA,11254
|
|
52
|
-
framcore/metadata/Div.py,sha256=fIIB9W9fVJEUNzqIWXOJ9ZN3tWE8dB8ap2BdULT2fJw,2428
|
|
53
|
-
framcore/metadata/ExprMeta.py,sha256=zM5u7TXnImEIIVQbUGmcz74LbvNybMIkRYB4913cdiE,1556
|
|
54
|
-
framcore/metadata/LevelExprMeta.py,sha256=AcE4DfJLtMFY69A8H7hzKYSR454O6Z9JTpOQpNnqG1I,567
|
|
55
|
-
framcore/metadata/Member.py,sha256=7dcjqNWCcoGlOqXtqCBXYeN4z_5cIPBFUngcBVKAeas,1877
|
|
56
|
-
framcore/metadata/Meta.py,sha256=P9ESFJlrxxhcY9PNSnnccrsLBulu1v3Kir6agzSrv0I,1173
|
|
57
|
-
framcore/metadata/__init__.py,sha256=rf2oJ5SjlmdD4Fk0svPxHbNZlnzUdt-FPyjjhA8wbhc,350
|
|
58
|
-
framcore/populators/Populator.py,sha256=SraN4QOTsA3yXEVG4z9ohWfPKokssl3uvDJPGh56lrU,4077
|
|
59
|
-
framcore/populators/__init__.py,sha256=jE6tHIvTaPTWcD-yVpBOjDBxI3xFqJh0QASfQexBLCE,119
|
|
60
|
-
framcore/querydbs/CacheDB.py,sha256=vzLEJM8SsvQYMXDE_TdjzicHM6yfJJefzp6u-Qyneys,1707
|
|
61
|
-
framcore/querydbs/ModelDB.py,sha256=XD4jHlmRQHqF7L2euDIMrPZREhr3SXgv0UnqkADLzRw,1039
|
|
62
|
-
framcore/querydbs/QueryDB.py,sha256=IV96mtslktpJMrdxgrwQetVx4R1HAP1GxtKgx9WLPZA,1233
|
|
63
|
-
framcore/querydbs/__init__.py,sha256=oPX2sqAMoEMxWL9b_sRg4z4Q_b80iDm_jk-W_qmpEME,231
|
|
64
|
-
framcore/solvers/Solver.py,sha256=dtxguoJAYHQCFsDXU9bbCZJGEaFJhS4Bpk-JGvI2g_o,1302
|
|
65
|
-
framcore/solvers/SolverConfig.py,sha256=E181Jm9mJvEb2wMN7zE2AUzHwhQp_OLiKfSK6bEGF8s,10585
|
|
66
|
-
framcore/solvers/__init__.py,sha256=q9HLYJkRdvJeFgAM1NBGIaFI8APmsZCDTy1AkIKw_Zs,179
|
|
67
|
-
framcore/timeindexes/AverageYearRange.py,sha256=nAc-GxtPm9Hm-aEkDCkaKIfB4WC8jUJ_jgbPZjKi838,834
|
|
68
|
-
framcore/timeindexes/ConstantTimeIndex.py,sha256=mufAI-lqdKyRw7kOzYZW1RbH9MfMfCNKnJPK7Em_3jk,601
|
|
69
|
-
framcore/timeindexes/DailyIndex.py,sha256=SqKfnCisENPlt9gU7FTmjP7D_F3wNcLULqyyEoe5Cas,644
|
|
70
|
-
framcore/timeindexes/FixedFrequencyTimeIndex.py,sha256=7DI_TRfaVCr2o402Mz4Wd1oOjluE1Xfr1-ItUrhPGbg,31479
|
|
71
|
-
framcore/timeindexes/HourlyIndex.py,sha256=Xvqo41KZHIl1bsh0g1uSmH5TLG80UUt9vm3ZArNWa08,648
|
|
72
|
-
framcore/timeindexes/IsoCalendarDay.py,sha256=5zffRr-uIg_mrwraBUWjD1LwhiYNU0pAl6-oGgQgvl8,991
|
|
73
|
-
framcore/timeindexes/ListTimeIndex.py,sha256=XsYXkGG-wA6uPo-50zkp_R1_l9SII8dq7S_kGV060vY,8389
|
|
74
|
-
framcore/timeindexes/ModelYear.py,sha256=Yh8jKizsRLNJRkkjCGQbxMETkDOMZq2zPEXNSmbAbqc,699
|
|
75
|
-
framcore/timeindexes/ModelYears.py,sha256=ACNNNFeM6MycYNAQnYVVdXrjhqCgtdQ7DHyCXPimbzI,718
|
|
76
|
-
framcore/timeindexes/OneYearProfileTimeIndex.py,sha256=HzjILknONIbGdw6rN_Ro5_r4ywFDXMoMP1bEgVzGuHo,773
|
|
77
|
-
framcore/timeindexes/ProfileTimeIndex.py,sha256=Da_A-4NO8vgu9Z6Uax6rjKL0D03KnDCnroI5L90ZauU,1302
|
|
78
|
-
framcore/timeindexes/SinglePeriodTimeIndex.py,sha256=mM-dHDEHdEOgaRLHQ2Q6NbjDoz9wYl3rC46EkLeHQpI,1447
|
|
79
|
-
framcore/timeindexes/TimeIndex.py,sha256=kLQMiAi6ddQfzdKxyQbNRxmocwRmiLWz7SxUxCZ8wbw,2552
|
|
80
|
-
framcore/timeindexes/WeeklyIndex.py,sha256=fZr0OMDKc5yUlsMa--D7d8FxWg-fkeHH5oclXP_a4mI,648
|
|
81
|
-
framcore/timeindexes/__init__.py,sha256=2LmQFuMR1DffqHk5O2zd8o9g8QsazxSSykxOE7WGP4o,1351
|
|
82
|
-
framcore/timevectors/ConstantTimeVector.py,sha256=S9fMSna_xOzJwu_Q9B_wNJtm9QYlEC3DmbkutOtMofU,6012
|
|
83
|
-
framcore/timevectors/LinearTransformTimeVector.py,sha256=fcXQJ0Sn-m1K56j-5p78p1sFwxrEvgjq00x-THevTF4,4189
|
|
84
|
-
framcore/timevectors/ListTimeVector.py,sha256=rQyCY2o7BsutS6kSFnV-CVzgoJCIPccmUugoeo-cwoI,5324
|
|
85
|
-
framcore/timevectors/LoadedTimeVector.py,sha256=Igg045J6oFF8ocSUC1khbA98y_niww759FLFa-umzXk,4493
|
|
86
|
-
framcore/timevectors/ReferencePeriod.py,sha256=eB7DQYIsyq273D7jQEG_-b-x3S5mpY8pCkATik5DKE8,1456
|
|
87
|
-
framcore/timevectors/TimeVector.py,sha256=yH68GReHw19VjScOWBf9u0krRPlHzmOnbvDAyM-pLno,2598
|
|
88
|
-
framcore/timevectors/__init__.py,sha256=Wd3gXGatwpbe2yMKSCq7O9My5wbveuK23iYO2ykkUIk,603
|
|
89
|
-
framcore/utils/__init__.py,sha256=9M80LjgkJQ53Lbe5jiRro2tHUR4MQp2JPGiKF57wOr4,1222
|
|
90
|
-
framcore/utils/get_regional_volumes.py,sha256=QqQ3Ik8VIHFomEIA3krcGJkeyDZFecbaNRtIm7_n8KE,14956
|
|
91
|
-
framcore/utils/get_supported_components.py,sha256=F1AxTFuh4pLQTCwg8oYBhus0HOhKjkKYiRf9Ok1ttB4,1856
|
|
92
|
-
framcore/utils/global_energy_equivalent.py,sha256=R3I1XVIIaYkagr_BPuKaAj9eS7gNzaff5v1tk7hzQuY,2614
|
|
93
|
-
framcore/utils/isolate_subnodes.py,sha256=iRiqgTU_c6W1jLmIBGO7fQoK_abPA3N8beGJbroC2V8,6527
|
|
94
|
-
framcore/utils/loaders.py,sha256=8llunmOC6XkbqNXSxL1XVNipGj7OpjIZ-2AyJUj-5v8,3320
|
|
95
|
-
framcore/utils/node_flow_utils.py,sha256=4Z6eB4oUqhOWWeHFNYRZY0c0UQlJ8tM9duYvLzkJQ3k,7800
|
|
96
|
-
framcore/utils/storage_subsystems.py,sha256=PmkV9rhiVUrmPz1zsyKcEwjJzYUkXQUcGM511tttsXc,4158
|
|
97
|
-
fram_core-0.1.0a1.dist-info/METADATA,sha256=3PisZPX4tBGbm57LLFn_qEmV70e9HqsiMwBxO3sms1c,1204
|
|
98
|
-
fram_core-0.1.0a1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
99
|
-
fram_core-0.1.0a1.dist-info/licenses/LICENSE.md,sha256=fxh4ZxuR8dM2HDs-pIUitPrJdxQ4fEFh1GvEYZA2m1E,1075
|
|
100
|
-
fram_core-0.1.0a1.dist-info/RECORD,,
|
|
File without changes
|