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.
Files changed (103) hide show
  1. fram_core-0.1.0a2.dist-info/METADATA +42 -0
  2. fram_core-0.1.0a2.dist-info/RECORD +100 -0
  3. {fram_core-0.0.0.dist-info → fram_core-0.1.0a2.dist-info}/WHEEL +1 -2
  4. fram_core-0.1.0a2.dist-info/licenses/LICENSE.md +8 -0
  5. framcore/Base.py +142 -0
  6. framcore/Model.py +73 -0
  7. framcore/__init__.py +9 -0
  8. framcore/aggregators/Aggregator.py +153 -0
  9. framcore/aggregators/HydroAggregator.py +837 -0
  10. framcore/aggregators/NodeAggregator.py +495 -0
  11. framcore/aggregators/WindSolarAggregator.py +323 -0
  12. framcore/aggregators/__init__.py +13 -0
  13. framcore/aggregators/_utils.py +184 -0
  14. framcore/attributes/Arrow.py +305 -0
  15. framcore/attributes/ElasticDemand.py +90 -0
  16. framcore/attributes/ReservoirCurve.py +37 -0
  17. framcore/attributes/SoftBound.py +19 -0
  18. framcore/attributes/StartUpCost.py +54 -0
  19. framcore/attributes/Storage.py +146 -0
  20. framcore/attributes/TargetBound.py +18 -0
  21. framcore/attributes/__init__.py +65 -0
  22. framcore/attributes/hydro/HydroBypass.py +42 -0
  23. framcore/attributes/hydro/HydroGenerator.py +83 -0
  24. framcore/attributes/hydro/HydroPump.py +156 -0
  25. framcore/attributes/hydro/HydroReservoir.py +27 -0
  26. framcore/attributes/hydro/__init__.py +13 -0
  27. framcore/attributes/level_profile_attributes.py +714 -0
  28. framcore/components/Component.py +112 -0
  29. framcore/components/Demand.py +130 -0
  30. framcore/components/Flow.py +167 -0
  31. framcore/components/HydroModule.py +330 -0
  32. framcore/components/Node.py +76 -0
  33. framcore/components/Thermal.py +204 -0
  34. framcore/components/Transmission.py +183 -0
  35. framcore/components/_PowerPlant.py +81 -0
  36. framcore/components/__init__.py +22 -0
  37. framcore/components/wind_solar.py +67 -0
  38. framcore/curves/Curve.py +44 -0
  39. framcore/curves/LoadedCurve.py +155 -0
  40. framcore/curves/__init__.py +9 -0
  41. framcore/events/__init__.py +21 -0
  42. framcore/events/events.py +51 -0
  43. framcore/expressions/Expr.py +490 -0
  44. framcore/expressions/__init__.py +28 -0
  45. framcore/expressions/_get_constant_from_expr.py +483 -0
  46. framcore/expressions/_time_vector_operations.py +615 -0
  47. framcore/expressions/_utils.py +73 -0
  48. framcore/expressions/queries.py +423 -0
  49. framcore/expressions/units.py +207 -0
  50. framcore/fingerprints/__init__.py +11 -0
  51. framcore/fingerprints/fingerprint.py +293 -0
  52. framcore/juliamodels/JuliaModel.py +161 -0
  53. framcore/juliamodels/__init__.py +7 -0
  54. framcore/loaders/__init__.py +10 -0
  55. framcore/loaders/loaders.py +407 -0
  56. framcore/metadata/Div.py +73 -0
  57. framcore/metadata/ExprMeta.py +50 -0
  58. framcore/metadata/LevelExprMeta.py +17 -0
  59. framcore/metadata/Member.py +55 -0
  60. framcore/metadata/Meta.py +44 -0
  61. framcore/metadata/__init__.py +15 -0
  62. framcore/populators/Populator.py +108 -0
  63. framcore/populators/__init__.py +7 -0
  64. framcore/querydbs/CacheDB.py +50 -0
  65. framcore/querydbs/ModelDB.py +34 -0
  66. framcore/querydbs/QueryDB.py +45 -0
  67. framcore/querydbs/__init__.py +11 -0
  68. framcore/solvers/Solver.py +48 -0
  69. framcore/solvers/SolverConfig.py +272 -0
  70. framcore/solvers/__init__.py +9 -0
  71. framcore/timeindexes/AverageYearRange.py +20 -0
  72. framcore/timeindexes/ConstantTimeIndex.py +17 -0
  73. framcore/timeindexes/DailyIndex.py +21 -0
  74. framcore/timeindexes/FixedFrequencyTimeIndex.py +762 -0
  75. framcore/timeindexes/HourlyIndex.py +21 -0
  76. framcore/timeindexes/IsoCalendarDay.py +31 -0
  77. framcore/timeindexes/ListTimeIndex.py +197 -0
  78. framcore/timeindexes/ModelYear.py +17 -0
  79. framcore/timeindexes/ModelYears.py +18 -0
  80. framcore/timeindexes/OneYearProfileTimeIndex.py +21 -0
  81. framcore/timeindexes/ProfileTimeIndex.py +32 -0
  82. framcore/timeindexes/SinglePeriodTimeIndex.py +37 -0
  83. framcore/timeindexes/TimeIndex.py +90 -0
  84. framcore/timeindexes/WeeklyIndex.py +21 -0
  85. framcore/timeindexes/__init__.py +36 -0
  86. framcore/timevectors/ConstantTimeVector.py +135 -0
  87. framcore/timevectors/LinearTransformTimeVector.py +114 -0
  88. framcore/timevectors/ListTimeVector.py +123 -0
  89. framcore/timevectors/LoadedTimeVector.py +104 -0
  90. framcore/timevectors/ReferencePeriod.py +41 -0
  91. framcore/timevectors/TimeVector.py +94 -0
  92. framcore/timevectors/__init__.py +17 -0
  93. framcore/utils/__init__.py +36 -0
  94. framcore/utils/get_regional_volumes.py +369 -0
  95. framcore/utils/get_supported_components.py +60 -0
  96. framcore/utils/global_energy_equivalent.py +46 -0
  97. framcore/utils/isolate_subnodes.py +163 -0
  98. framcore/utils/loaders.py +97 -0
  99. framcore/utils/node_flow_utils.py +236 -0
  100. framcore/utils/storage_subsystems.py +107 -0
  101. fram_core-0.0.0.dist-info/METADATA +0 -5
  102. fram_core-0.0.0.dist-info/RECORD +0 -4
  103. 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
@@ -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,9 @@
1
+ # framcore/curves/__init__.py
2
+
3
+ from framcore.curves.Curve import Curve
4
+ from framcore.curves.LoadedCurve import LoadedCurve
5
+
6
+ __all__ = [
7
+ "Curve",
8
+ "LoadedCurve",
9
+ ]
@@ -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)