fram-core 0.0.0__py3-none-any.whl → 0.1.0a1__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/METADATA +41 -0
- fram_core-0.1.0a1.dist-info/RECORD +100 -0
- {fram_core-0.0.0.dist-info → fram_core-0.1.0a1.dist-info}/WHEEL +1 -2
- fram_core-0.1.0a1.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,183 @@
|
|
|
1
|
+
"""Contain class describing transmission of Power commodity between nodes."""
|
|
2
|
+
|
|
3
|
+
from framcore.attributes import Arrow, AvgFlowVolume, Conversion, Cost, FlowVolume, Loss, Proportion
|
|
4
|
+
from framcore.components import Component, Flow
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Transmission(Component):
|
|
8
|
+
"""
|
|
9
|
+
Transmission component representing a transmission line. Subclass of Component.
|
|
10
|
+
|
|
11
|
+
An object of this class represents one transmission line where power flows one direction (the other direction is
|
|
12
|
+
represented by another Transmission object). However, the actual measured power being sent can be higher than the
|
|
13
|
+
amount being recieved because of loss. One Transmission object therefore represents the viewpoints of both the
|
|
14
|
+
sender and the reciever of power on this specific line.
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
from_node: str,
|
|
21
|
+
to_node: str,
|
|
22
|
+
max_capacity: FlowVolume = None,
|
|
23
|
+
min_capacity: FlowVolume | None = None,
|
|
24
|
+
loss: Loss | None = None,
|
|
25
|
+
tariff: Cost | None = None,
|
|
26
|
+
ramp_up: Proportion | None = None,
|
|
27
|
+
ramp_down: Proportion | None = None,
|
|
28
|
+
ingoing_volume: AvgFlowVolume | None = None,
|
|
29
|
+
outgoing_volume: AvgFlowVolume | None = None,
|
|
30
|
+
) -> None:
|
|
31
|
+
"""Initialize object of the Transmission class. Perform type checks and convert arguments to expressions."""
|
|
32
|
+
super().__init__()
|
|
33
|
+
|
|
34
|
+
self._check_type(from_node, str)
|
|
35
|
+
self._check_type(to_node, str)
|
|
36
|
+
self._check_type(max_capacity, FlowVolume)
|
|
37
|
+
self._check_type(min_capacity, (FlowVolume, type(None)))
|
|
38
|
+
self._check_type(loss, (Loss, type(None)))
|
|
39
|
+
self._check_type(tariff, (Cost, type(None)))
|
|
40
|
+
self._check_type(ramp_up, (Proportion, type(None)))
|
|
41
|
+
self._check_type(ramp_down, (Proportion, type(None)))
|
|
42
|
+
self._check_type(ingoing_volume, (AvgFlowVolume, type(None)))
|
|
43
|
+
self._check_type(outgoing_volume, (AvgFlowVolume, type(None)))
|
|
44
|
+
|
|
45
|
+
self._from_node = from_node
|
|
46
|
+
self._to_node = to_node
|
|
47
|
+
self._max_capacity = max_capacity
|
|
48
|
+
self._min_capacity = min_capacity
|
|
49
|
+
self._loss = loss
|
|
50
|
+
self._tariff = tariff
|
|
51
|
+
self._ramp_up = ramp_up
|
|
52
|
+
self._ramp_down = ramp_down
|
|
53
|
+
|
|
54
|
+
if outgoing_volume is None:
|
|
55
|
+
outgoing_volume = AvgFlowVolume()
|
|
56
|
+
|
|
57
|
+
if ingoing_volume is None:
|
|
58
|
+
ingoing_volume = AvgFlowVolume()
|
|
59
|
+
|
|
60
|
+
self._outgoing_volume: AvgFlowVolume = outgoing_volume
|
|
61
|
+
self._ingoing_volume: AvgFlowVolume = ingoing_volume
|
|
62
|
+
|
|
63
|
+
def get_from_node(self) -> str:
|
|
64
|
+
"""Get the from node of the transmission line."""
|
|
65
|
+
return self._from_node
|
|
66
|
+
|
|
67
|
+
def set_from_node(self, node: str) -> None:
|
|
68
|
+
"""Set the from node of the transmission line."""
|
|
69
|
+
self._check_type(node, str)
|
|
70
|
+
self._from_node = node
|
|
71
|
+
|
|
72
|
+
def get_to_node(self) -> str:
|
|
73
|
+
"""Get the to node of the transmission line."""
|
|
74
|
+
return self._to_node
|
|
75
|
+
|
|
76
|
+
def set_to_node(self, node: str) -> None:
|
|
77
|
+
"""Set the to node of the transmission line."""
|
|
78
|
+
self._check_type(node, str)
|
|
79
|
+
self._to_node = node
|
|
80
|
+
|
|
81
|
+
def get_max_capacity(self) -> FlowVolume:
|
|
82
|
+
"""Get the maximum capacity (before losses) of the transmission line."""
|
|
83
|
+
return self._max_capacity
|
|
84
|
+
|
|
85
|
+
def get_min_capacity(self) -> FlowVolume:
|
|
86
|
+
"""Get the minimum capacity (before losses) of the transmission line."""
|
|
87
|
+
return self._min_capacity
|
|
88
|
+
|
|
89
|
+
def set_min_capacity(self, value: FlowVolume | None) -> None:
|
|
90
|
+
"""Set the minimum capacity (before losses) of the transmission line."""
|
|
91
|
+
self._check_type(value, (FlowVolume, type(None)))
|
|
92
|
+
self._min_capacity = value
|
|
93
|
+
|
|
94
|
+
def get_outgoing_volume(self) -> AvgFlowVolume:
|
|
95
|
+
"""Get the outgoing (before losses) flow volume of the transmission line."""
|
|
96
|
+
return self._outgoing_volume
|
|
97
|
+
|
|
98
|
+
def get_ingoing_volume(self) -> AvgFlowVolume:
|
|
99
|
+
"""Get the ingoing (after losses) flow volume of the transmission line."""
|
|
100
|
+
return self._ingoing_volume
|
|
101
|
+
|
|
102
|
+
def get_loss(self) -> Loss | None:
|
|
103
|
+
"""Get the loss of the transmission line."""
|
|
104
|
+
return self._loss
|
|
105
|
+
|
|
106
|
+
def set_loss(self, loss: Loss | None) -> None:
|
|
107
|
+
"""Set the loss of the transmission line."""
|
|
108
|
+
self._check_type(loss, (Loss, type(None)))
|
|
109
|
+
self._loss = loss
|
|
110
|
+
|
|
111
|
+
def get_tariff(self) -> Cost | None:
|
|
112
|
+
"""Get the tariff of the transmission line."""
|
|
113
|
+
return self._tariff
|
|
114
|
+
|
|
115
|
+
def set_tariff(self, tariff: Cost | None) -> None:
|
|
116
|
+
"""Set the tariff of the transmission line."""
|
|
117
|
+
self._check_type(tariff, (Cost, type(None)))
|
|
118
|
+
self._tariff = tariff
|
|
119
|
+
|
|
120
|
+
def get_ramp_up(self) -> Proportion | None:
|
|
121
|
+
"""Get the ramp up profile level of the transmission line."""
|
|
122
|
+
return self._ramp_up
|
|
123
|
+
|
|
124
|
+
def set_ramp_up(self, value: Proportion | None) -> None:
|
|
125
|
+
"""Set the ramp up of the transmission line."""
|
|
126
|
+
self._check_type(value, (Proportion, type(None)))
|
|
127
|
+
self._ramp_up = value
|
|
128
|
+
|
|
129
|
+
def get_ramp_down(self) -> Proportion | None:
|
|
130
|
+
"""Get the ramp down of the transmission line."""
|
|
131
|
+
return self._ramp_down
|
|
132
|
+
|
|
133
|
+
def set_ramp_down(self, value: Proportion | None) -> None:
|
|
134
|
+
"""Set the ramp down of the transmission line."""
|
|
135
|
+
self._check_type(value, (Proportion, type(None)))
|
|
136
|
+
self._ramp_down = value
|
|
137
|
+
|
|
138
|
+
"""Implementation of Component interface"""
|
|
139
|
+
|
|
140
|
+
def _get_simpler_components(self, base_name: str) -> dict[str, Component]:
|
|
141
|
+
return {base_name + "_Flow": self._create_flow()}
|
|
142
|
+
|
|
143
|
+
def _replace_node(self, old: str, new: str) -> None:
|
|
144
|
+
if old == self._from_node:
|
|
145
|
+
self._from_node = new
|
|
146
|
+
if old == self._to_node:
|
|
147
|
+
self._to_node = new
|
|
148
|
+
|
|
149
|
+
def _create_flow(self) -> Flow:
|
|
150
|
+
arrow_volumes: dict[Arrow, FlowVolume] = dict()
|
|
151
|
+
|
|
152
|
+
flow = Flow(
|
|
153
|
+
main_node=self._from_node,
|
|
154
|
+
max_capacity=self._max_capacity,
|
|
155
|
+
volume=self._outgoing_volume,
|
|
156
|
+
arrow_volumes=arrow_volumes,
|
|
157
|
+
# ramp_up=self._ramp_up, # TODO
|
|
158
|
+
# ramp_down=self._ramp_up, # TODO
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
outgoing_arrow = Arrow(
|
|
162
|
+
node=self._from_node,
|
|
163
|
+
is_ingoing=False,
|
|
164
|
+
conversion=Conversion(value=1),
|
|
165
|
+
)
|
|
166
|
+
flow.add_arrow(outgoing_arrow)
|
|
167
|
+
arrow_volumes[outgoing_arrow] = self._outgoing_volume
|
|
168
|
+
|
|
169
|
+
# TODO: Extend Loss to support more fetures, such as quadratic losses? Needs loss param in Arrow to do this
|
|
170
|
+
|
|
171
|
+
ingoing_arrow = Arrow(
|
|
172
|
+
node=self._to_node,
|
|
173
|
+
is_ingoing=True,
|
|
174
|
+
conversion=Conversion(value=1),
|
|
175
|
+
loss=self._loss,
|
|
176
|
+
)
|
|
177
|
+
flow.add_arrow(ingoing_arrow)
|
|
178
|
+
arrow_volumes[ingoing_arrow] = self._ingoing_volume
|
|
179
|
+
|
|
180
|
+
if self._tariff is not None:
|
|
181
|
+
flow.add_cost_term("tariff", self._tariff)
|
|
182
|
+
|
|
183
|
+
return flow
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from framcore.attributes import AvgFlowVolume, Cost, FlowVolume
|
|
2
|
+
from framcore.components import Component
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class _PowerPlant(Component):
|
|
6
|
+
"""
|
|
7
|
+
PowerPlant parent class component representing a power plant. Subclass of Component.
|
|
8
|
+
|
|
9
|
+
This class models a powerplant with various attributes such as power node,
|
|
10
|
+
capacity, VOC levels and profile, and production.
|
|
11
|
+
|
|
12
|
+
Functions that are dependent on commodity nodes other than power are defined in the spesific power plant components.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
power_node: str,
|
|
18
|
+
max_capacity: FlowVolume,
|
|
19
|
+
min_capacity: FlowVolume | None,
|
|
20
|
+
voc: Cost | None = None,
|
|
21
|
+
production: AvgFlowVolume | None = None,
|
|
22
|
+
) -> None:
|
|
23
|
+
"""Initialize the class."""
|
|
24
|
+
super().__init__()
|
|
25
|
+
|
|
26
|
+
self._check_type(power_node, str)
|
|
27
|
+
self._check_type(max_capacity, FlowVolume)
|
|
28
|
+
self._check_type(min_capacity, (FlowVolume, type(None)))
|
|
29
|
+
self._check_type(voc, (Cost, type(None)))
|
|
30
|
+
self._check_type(production, (AvgFlowVolume, type(None)))
|
|
31
|
+
|
|
32
|
+
self._power_node = power_node
|
|
33
|
+
self._max_capacity = max_capacity
|
|
34
|
+
self._min_capacity = min_capacity
|
|
35
|
+
self._voc = voc
|
|
36
|
+
|
|
37
|
+
if not production:
|
|
38
|
+
production = AvgFlowVolume()
|
|
39
|
+
|
|
40
|
+
self._production = production
|
|
41
|
+
|
|
42
|
+
def get_max_capacity(self) -> FlowVolume:
|
|
43
|
+
"""Get the capacity of the power unit."""
|
|
44
|
+
return self._max_capacity
|
|
45
|
+
|
|
46
|
+
def get_production(self) -> AvgFlowVolume:
|
|
47
|
+
"""Get the production volume of the power unit."""
|
|
48
|
+
return self._production
|
|
49
|
+
|
|
50
|
+
def get_min_capacity(self) -> FlowVolume | None:
|
|
51
|
+
"""Get the minimum capacity of the power unit."""
|
|
52
|
+
return self._min_capacity
|
|
53
|
+
|
|
54
|
+
def set_min_capacity(self, value: FlowVolume | None) -> None:
|
|
55
|
+
"""Set the minimum capacity of the power unit."""
|
|
56
|
+
self._check_type(value, (FlowVolume, type(None)))
|
|
57
|
+
self._min_capacity = value
|
|
58
|
+
|
|
59
|
+
def get_power_node(self) -> str:
|
|
60
|
+
"""Get the power node of the power unit."""
|
|
61
|
+
return self._power_node
|
|
62
|
+
|
|
63
|
+
def set_power_node(self, power_node: str) -> None:
|
|
64
|
+
"""Set the power node of the power unit."""
|
|
65
|
+
self._check_type(power_node, str)
|
|
66
|
+
self._power_node = power_node
|
|
67
|
+
|
|
68
|
+
def get_voc(self) -> Cost | None:
|
|
69
|
+
"""Get the variable operating cost (VOC) level of the power unit."""
|
|
70
|
+
return self._voc
|
|
71
|
+
|
|
72
|
+
def set_voc(self, voc: Cost | None) -> None:
|
|
73
|
+
"""Set the variable operating cost (VOC) level of the power unit."""
|
|
74
|
+
self._check_type(voc, (Cost, type(None)))
|
|
75
|
+
self._voc = voc
|
|
76
|
+
|
|
77
|
+
"""Implementation of Component interface"""
|
|
78
|
+
|
|
79
|
+
def _replace_node(self, old: str, new: str) -> None:
|
|
80
|
+
if old == self._power_node:
|
|
81
|
+
self._power_node = new
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# ruff: noqa: I001
|
|
2
|
+
|
|
3
|
+
from framcore.components.Component import Component
|
|
4
|
+
from framcore.components.Node import Node
|
|
5
|
+
from framcore.components.Flow import Flow
|
|
6
|
+
from framcore.components.Demand import Demand
|
|
7
|
+
from framcore.components.HydroModule import HydroModule
|
|
8
|
+
from framcore.components.Thermal import Thermal
|
|
9
|
+
from framcore.components.Transmission import Transmission
|
|
10
|
+
from framcore.components.wind_solar import Solar, Wind
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"Component",
|
|
14
|
+
"Demand",
|
|
15
|
+
"Flow",
|
|
16
|
+
"HydroModule",
|
|
17
|
+
"Node",
|
|
18
|
+
"Solar",
|
|
19
|
+
"Thermal",
|
|
20
|
+
"Transmission",
|
|
21
|
+
"Wind",
|
|
22
|
+
]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from framcore.attributes import Arrow, AvgFlowVolume, Conversion, Cost, FlowVolume
|
|
2
|
+
from framcore.components import Flow
|
|
3
|
+
from framcore.components._PowerPlant import _PowerPlant
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class _WindSolar(_PowerPlant):
|
|
7
|
+
"""
|
|
8
|
+
Wind and Solar class component representing a wind and solar power plant. Subclass of PowerPlant.
|
|
9
|
+
|
|
10
|
+
This class models a wind or solarpower plant with various attributes inherited from the parent class PowerPlant.
|
|
11
|
+
|
|
12
|
+
Capacity can be provided directly or as parts (level or profile). Max and min capacity profiles are set
|
|
13
|
+
to be equal as the capacity_profile for these technologytypes since it does not have a max or min.
|
|
14
|
+
|
|
15
|
+
The functions _get_fingerprints, _get_nodes og _get_flow are defines in this
|
|
16
|
+
subclass since other subclases are dependent on fuel and emission nodes.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
power_node: str,
|
|
22
|
+
max_capacity: FlowVolume,
|
|
23
|
+
voc: Cost | None = None,
|
|
24
|
+
production: AvgFlowVolume | None = None,
|
|
25
|
+
) -> None:
|
|
26
|
+
"""Initialize the Wind and Solar class."""
|
|
27
|
+
super().__init__(
|
|
28
|
+
power_node=power_node,
|
|
29
|
+
max_capacity=max_capacity,
|
|
30
|
+
min_capacity=None,
|
|
31
|
+
voc=voc,
|
|
32
|
+
production=production,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
"""Implementation of Component interface"""
|
|
36
|
+
|
|
37
|
+
def _get_simpler_components(self, base_name: str) -> dict[str, Flow]:
|
|
38
|
+
return {base_name + "_Flow": self._create_flow()}
|
|
39
|
+
|
|
40
|
+
def _create_flow(self) -> Flow:
|
|
41
|
+
flow = Flow(
|
|
42
|
+
main_node=self._power_node,
|
|
43
|
+
max_capacity=self._max_capacity,
|
|
44
|
+
volume=self._production,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
flow.add_arrow(Arrow(node=self._power_node, is_ingoing=True, conversion=Conversion(value=1)))
|
|
48
|
+
|
|
49
|
+
if self._voc:
|
|
50
|
+
flow.add_cost_term("VOC", self._voc)
|
|
51
|
+
else:
|
|
52
|
+
flow.set_min_capacity(self._max_capacity)
|
|
53
|
+
flow.set_exogenous()
|
|
54
|
+
|
|
55
|
+
return flow
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class Wind(_WindSolar):
|
|
59
|
+
"""Wind power component."""
|
|
60
|
+
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Solar(_WindSolar):
|
|
65
|
+
"""Solar power component."""
|
|
66
|
+
|
|
67
|
+
pass
|
framcore/curves/Curve.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Curve interface."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
|
|
5
|
+
from numpy.typing import NDArray
|
|
6
|
+
|
|
7
|
+
from framcore import Base
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Curve(Base, ABC):
|
|
11
|
+
"""Curve interface class."""
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def get_unique_name(self) -> str | None:
|
|
15
|
+
"""Return unique name of curve."""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def get_x_axis(self, is_float32: bool) -> NDArray:
|
|
20
|
+
"""
|
|
21
|
+
Get array of x axis values.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
is_float32 (bool): Flag for converting the array of values to numpy float32.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
NDArray: Numpy array of values.
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
@abstractmethod
|
|
33
|
+
def get_y_axis(self, is_float32: bool) -> NDArray:
|
|
34
|
+
"""
|
|
35
|
+
Get array of y axis values.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
is_float32 (bool): Flag for converting the array of values to numpy float32.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
NDArray: Numpy array of values.
|
|
42
|
+
|
|
43
|
+
"""
|
|
44
|
+
pass
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from numpy.typing import NDArray
|
|
7
|
+
|
|
8
|
+
from framcore.curves import Curve
|
|
9
|
+
from framcore.fingerprints import Fingerprint
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from framcore.loaders import CurveLoader
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class LoadedCurve(Curve):
|
|
16
|
+
"""
|
|
17
|
+
Represents a curve loaded from a CurveLoader.
|
|
18
|
+
|
|
19
|
+
Attributes
|
|
20
|
+
----------
|
|
21
|
+
_curve_id : str
|
|
22
|
+
Identifier for the curve.
|
|
23
|
+
_loader : CurveLoader
|
|
24
|
+
Loader instance used to retrieve curve data.
|
|
25
|
+
_reference_period : Any
|
|
26
|
+
Reference period for the curve (currently not set).
|
|
27
|
+
|
|
28
|
+
Methods
|
|
29
|
+
-------
|
|
30
|
+
get_unique_name()
|
|
31
|
+
Returns the unique name of the curve.
|
|
32
|
+
get_x_axis(precision=None)
|
|
33
|
+
Returns the x-axis data.
|
|
34
|
+
get_y_axis(precision=None)
|
|
35
|
+
Returns the y-axis data.
|
|
36
|
+
get_x_unit()
|
|
37
|
+
Returns the unit for the x-axis.
|
|
38
|
+
get_y_unit()
|
|
39
|
+
Returns the unit for the y-axis.
|
|
40
|
+
get_loader()
|
|
41
|
+
Returns the loader instance.
|
|
42
|
+
get_fingerprint()
|
|
43
|
+
Returns the fingerprint of the curve.
|
|
44
|
+
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def __init__(self, curve_id: str, loader: CurveLoader) -> None:
|
|
48
|
+
"""
|
|
49
|
+
Initialize a LoadedCurve instance.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
curve_id : str
|
|
54
|
+
Identifier for the curve.
|
|
55
|
+
loader : CurveLoader
|
|
56
|
+
Loader instance used to retrieve curve data.
|
|
57
|
+
|
|
58
|
+
"""
|
|
59
|
+
self._curve_id = curve_id
|
|
60
|
+
self._loader = loader
|
|
61
|
+
|
|
62
|
+
# TODO: get from loader
|
|
63
|
+
self._reference_period = None
|
|
64
|
+
|
|
65
|
+
def __repr__(self) -> str:
|
|
66
|
+
"""Return a string representation of the LoadedCurve instance."""
|
|
67
|
+
return f"{type(self).__name__}(curve_id={self._curve_id},loader={self._loader},x_unit={self.get_x_unit()}),y_unit={self.get_y_unit()}),"
|
|
68
|
+
|
|
69
|
+
def get_unique_name(self) -> str:
|
|
70
|
+
"""
|
|
71
|
+
Return the unique name of the curve.
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
75
|
+
str
|
|
76
|
+
The unique name for the curve.
|
|
77
|
+
|
|
78
|
+
"""
|
|
79
|
+
return self._curve_id
|
|
80
|
+
|
|
81
|
+
def get_x_axis(self, is_float32: bool) -> NDArray:
|
|
82
|
+
"""
|
|
83
|
+
Get x axis values of the curve as a numpy array.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
is_float32 (bool): Flag for converting the array of values to numpy float32.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
NDArray: Numpy array of x axis values.
|
|
90
|
+
|
|
91
|
+
"""
|
|
92
|
+
x_axis = self._loader.get_x_axis(self._curve_id)
|
|
93
|
+
if is_float32:
|
|
94
|
+
x_axis = x_axis.astype(np.float32)
|
|
95
|
+
return x_axis
|
|
96
|
+
|
|
97
|
+
def get_y_axis(self, is_float32: bool) -> NDArray:
|
|
98
|
+
"""
|
|
99
|
+
Get y axis values of the curve as a numpy array.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
is_float32 (bool): Flag for converting the array of values to numpy float32.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
NDArray: Numpy array of y axis values.
|
|
106
|
+
|
|
107
|
+
"""
|
|
108
|
+
y_axis = self._loader.get_y_axis(self._curve_id)
|
|
109
|
+
if is_float32:
|
|
110
|
+
y_axis = y_axis.astype(np.float32)
|
|
111
|
+
return y_axis
|
|
112
|
+
|
|
113
|
+
def get_x_unit(self) -> str:
|
|
114
|
+
"""
|
|
115
|
+
Return the unit for the x-axis.
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
str
|
|
120
|
+
The unit for the x-axis.
|
|
121
|
+
|
|
122
|
+
"""
|
|
123
|
+
return self._loader.get_x_unit(self._curve_id)
|
|
124
|
+
|
|
125
|
+
def get_y_unit(self) -> str:
|
|
126
|
+
"""
|
|
127
|
+
Return the unit for the y-axis.
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
-------
|
|
131
|
+
str
|
|
132
|
+
The unit for the y-axis.
|
|
133
|
+
|
|
134
|
+
"""
|
|
135
|
+
return self._loader.get_y_unit(self._curve_id)
|
|
136
|
+
|
|
137
|
+
def get_loader(self) -> CurveLoader:
|
|
138
|
+
"""
|
|
139
|
+
Return the loader instance used to retrieve curve data.
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
CurveLoader
|
|
144
|
+
The loader instance associated with this curve.
|
|
145
|
+
|
|
146
|
+
"""
|
|
147
|
+
return self._loader
|
|
148
|
+
|
|
149
|
+
def get_fingerprint(self) -> Fingerprint:
|
|
150
|
+
"""
|
|
151
|
+
Return the fingerprint of the curve.
|
|
152
|
+
|
|
153
|
+
The method is not implemented yet.
|
|
154
|
+
"""
|
|
155
|
+
raise NotImplementedError("Not implemented yet.")
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# framcore/events/__init__.py
|
|
2
|
+
|
|
3
|
+
from framcore.events.events import (
|
|
4
|
+
get_event_handler,
|
|
5
|
+
set_event_handler,
|
|
6
|
+
send_debug_event,
|
|
7
|
+
send_error_event,
|
|
8
|
+
send_event,
|
|
9
|
+
send_info_event,
|
|
10
|
+
send_warning_event,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"get_event_handler",
|
|
15
|
+
"send_debug_event",
|
|
16
|
+
"send_error_event",
|
|
17
|
+
"send_event",
|
|
18
|
+
"send_info_event",
|
|
19
|
+
"send_warning_event",
|
|
20
|
+
"set_event_handler",
|
|
21
|
+
]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Event system.
|
|
3
|
+
|
|
4
|
+
All code in the core use these functions to communicate events.
|
|
5
|
+
|
|
6
|
+
Calling systems (e.g. workflow codes) can get events by hooking into SEND_EVENT_CHANNEL.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
_EVENT_HANDLER = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def set_event_handler(handler: object | None) -> None:
|
|
13
|
+
"""Set event handler if any."""
|
|
14
|
+
if handler is not None and (not hasattr(handler, "handle_event") or not callable(handler.handle_event)):
|
|
15
|
+
message = "Given handler does not implement handle_event."
|
|
16
|
+
raise ValueError(message)
|
|
17
|
+
global _EVENT_HANDLER # noqa: PLW0603 # TODO: unsafe?
|
|
18
|
+
_EVENT_HANDLER = handler
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_event_handler() -> object | None:
|
|
22
|
+
"""Get event handler if any."""
|
|
23
|
+
return _EVENT_HANDLER
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def send_event(sender: object, event_type: str, **kwargs: dict[str, object]) -> None:
|
|
27
|
+
"""All events in core should use this."""
|
|
28
|
+
if _EVENT_HANDLER is None:
|
|
29
|
+
print(event_type, kwargs)
|
|
30
|
+
else:
|
|
31
|
+
_EVENT_HANDLER.handle_event(sender, event_type, **kwargs)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def send_warning_event(sender: object, message: str) -> None:
|
|
35
|
+
"""Use this to send warning event."""
|
|
36
|
+
send_event(sender, "warning", message=message)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def send_error_event(sender: object, message: str, exception_type_name: str, traceback: str) -> None:
|
|
40
|
+
"""Use this to send error event."""
|
|
41
|
+
send_event(sender, "error", message=message, exception_type_name=exception_type_name, traceback=traceback)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def send_info_event(sender: object, message: str) -> None:
|
|
45
|
+
"""Use this to send info event."""
|
|
46
|
+
send_event(sender, "info", message=message)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def send_debug_event(sender: object, message: str) -> None:
|
|
50
|
+
"""Use this to send debug event."""
|
|
51
|
+
send_event(sender, "debug", message=message)
|