fram-core 0.0.0__py3-none-any.whl → 0.1.0__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.0.dist-info/METADATA +42 -0
  2. fram_core-0.1.0.dist-info/RECORD +100 -0
  3. {fram_core-0.0.0.dist-info → fram_core-0.1.0.dist-info}/WHEEL +1 -2
  4. fram_core-0.1.0.dist-info/licenses/LICENSE.md +8 -0
  5. framcore/Base.py +161 -0
  6. framcore/Model.py +90 -0
  7. framcore/__init__.py +10 -0
  8. framcore/aggregators/Aggregator.py +172 -0
  9. framcore/aggregators/HydroAggregator.py +849 -0
  10. framcore/aggregators/NodeAggregator.py +530 -0
  11. framcore/aggregators/WindSolarAggregator.py +315 -0
  12. framcore/aggregators/__init__.py +13 -0
  13. framcore/aggregators/_utils.py +184 -0
  14. framcore/attributes/Arrow.py +307 -0
  15. framcore/attributes/ElasticDemand.py +90 -0
  16. framcore/attributes/ReservoirCurve.py +23 -0
  17. framcore/attributes/SoftBound.py +16 -0
  18. framcore/attributes/StartUpCost.py +65 -0
  19. framcore/attributes/Storage.py +158 -0
  20. framcore/attributes/TargetBound.py +16 -0
  21. framcore/attributes/__init__.py +63 -0
  22. framcore/attributes/hydro/HydroBypass.py +49 -0
  23. framcore/attributes/hydro/HydroGenerator.py +100 -0
  24. framcore/attributes/hydro/HydroPump.py +178 -0
  25. framcore/attributes/hydro/HydroReservoir.py +27 -0
  26. framcore/attributes/hydro/__init__.py +13 -0
  27. framcore/attributes/level_profile_attributes.py +911 -0
  28. framcore/components/Component.py +136 -0
  29. framcore/components/Demand.py +144 -0
  30. framcore/components/Flow.py +189 -0
  31. framcore/components/HydroModule.py +371 -0
  32. framcore/components/Node.py +99 -0
  33. framcore/components/Thermal.py +208 -0
  34. framcore/components/Transmission.py +198 -0
  35. framcore/components/_PowerPlant.py +81 -0
  36. framcore/components/__init__.py +22 -0
  37. framcore/components/wind_solar.py +82 -0
  38. framcore/curves/Curve.py +44 -0
  39. framcore/curves/LoadedCurve.py +146 -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 +591 -0
  44. framcore/expressions/__init__.py +30 -0
  45. framcore/expressions/_get_constant_from_expr.py +477 -0
  46. framcore/expressions/_utils.py +73 -0
  47. framcore/expressions/queries.py +416 -0
  48. framcore/expressions/units.py +227 -0
  49. framcore/fingerprints/__init__.py +11 -0
  50. framcore/fingerprints/fingerprint.py +292 -0
  51. framcore/juliamodels/JuliaModel.py +171 -0
  52. framcore/juliamodels/__init__.py +7 -0
  53. framcore/loaders/__init__.py +10 -0
  54. framcore/loaders/loaders.py +405 -0
  55. framcore/metadata/Div.py +73 -0
  56. framcore/metadata/ExprMeta.py +56 -0
  57. framcore/metadata/LevelExprMeta.py +32 -0
  58. framcore/metadata/Member.py +55 -0
  59. framcore/metadata/Meta.py +44 -0
  60. framcore/metadata/__init__.py +15 -0
  61. framcore/populators/Populator.py +108 -0
  62. framcore/populators/__init__.py +7 -0
  63. framcore/querydbs/CacheDB.py +50 -0
  64. framcore/querydbs/ModelDB.py +34 -0
  65. framcore/querydbs/QueryDB.py +45 -0
  66. framcore/querydbs/__init__.py +11 -0
  67. framcore/solvers/Solver.py +63 -0
  68. framcore/solvers/SolverConfig.py +272 -0
  69. framcore/solvers/__init__.py +9 -0
  70. framcore/timeindexes/AverageYearRange.py +27 -0
  71. framcore/timeindexes/ConstantTimeIndex.py +22 -0
  72. framcore/timeindexes/DailyIndex.py +33 -0
  73. framcore/timeindexes/FixedFrequencyTimeIndex.py +814 -0
  74. framcore/timeindexes/HourlyIndex.py +33 -0
  75. framcore/timeindexes/IsoCalendarDay.py +33 -0
  76. framcore/timeindexes/ListTimeIndex.py +277 -0
  77. framcore/timeindexes/ModelYear.py +23 -0
  78. framcore/timeindexes/ModelYears.py +27 -0
  79. framcore/timeindexes/OneYearProfileTimeIndex.py +29 -0
  80. framcore/timeindexes/ProfileTimeIndex.py +43 -0
  81. framcore/timeindexes/SinglePeriodTimeIndex.py +37 -0
  82. framcore/timeindexes/TimeIndex.py +103 -0
  83. framcore/timeindexes/WeeklyIndex.py +33 -0
  84. framcore/timeindexes/__init__.py +36 -0
  85. framcore/timeindexes/_time_vector_operations.py +689 -0
  86. framcore/timevectors/ConstantTimeVector.py +131 -0
  87. framcore/timevectors/LinearTransformTimeVector.py +131 -0
  88. framcore/timevectors/ListTimeVector.py +127 -0
  89. framcore/timevectors/LoadedTimeVector.py +97 -0
  90. framcore/timevectors/ReferencePeriod.py +51 -0
  91. framcore/timevectors/TimeVector.py +108 -0
  92. framcore/timevectors/__init__.py +17 -0
  93. framcore/utils/__init__.py +35 -0
  94. framcore/utils/get_regional_volumes.py +387 -0
  95. framcore/utils/get_supported_components.py +60 -0
  96. framcore/utils/global_energy_equivalent.py +63 -0
  97. framcore/utils/isolate_subnodes.py +172 -0
  98. framcore/utils/loaders.py +97 -0
  99. framcore/utils/node_flow_utils.py +236 -0
  100. framcore/utils/storage_subsystems.py +106 -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,63 @@
1
+ from framcore.attributes.level_profile_attributes import (
2
+ AvgFlowVolume,
3
+ Coefficient,
4
+ Conversion,
5
+ Cost,
6
+ Efficiency,
7
+ Elasticity,
8
+ FlowVolume,
9
+ Hours,
10
+ LevelProfile,
11
+ Loss,
12
+ MaxFlowVolume,
13
+ ObjectiveCoefficient,
14
+ Price,
15
+ Proportion,
16
+ ReservePrice,
17
+ ShadowPrice,
18
+ StockVolume,
19
+ WaterValue,
20
+ )
21
+ from framcore.attributes.Arrow import Arrow
22
+ from framcore.attributes.ElasticDemand import ElasticDemand
23
+ from framcore.attributes.ReservoirCurve import ReservoirCurve
24
+ from framcore.attributes.SoftBound import SoftBound
25
+ from framcore.attributes.StartUpCost import StartUpCost
26
+ from framcore.attributes.TargetBound import TargetBound
27
+ from framcore.attributes.Storage import Storage
28
+ from framcore.attributes.hydro.HydroBypass import HydroBypass
29
+ from framcore.attributes.hydro.HydroGenerator import HydroGenerator
30
+ from framcore.attributes.hydro.HydroPump import HydroPump
31
+ from framcore.attributes.hydro.HydroReservoir import HydroReservoir
32
+
33
+ __all__ = [
34
+ "Arrow",
35
+ "AvgFlowVolume",
36
+ "Coefficient",
37
+ "Conversion",
38
+ "Cost",
39
+ "Efficiency",
40
+ "ElasticDemand",
41
+ "Elasticity",
42
+ "FlowVolume",
43
+ "Hours",
44
+ "HydroBypass",
45
+ "HydroGenerator",
46
+ "HydroPump",
47
+ "HydroReservoir",
48
+ "LevelProfile",
49
+ "Loss",
50
+ "MaxFlowVolume",
51
+ "ObjectiveCoefficient",
52
+ "Price",
53
+ "Proportion",
54
+ "ReservePrice",
55
+ "ReservoirCurve",
56
+ "ShadowPrice",
57
+ "SoftBound",
58
+ "StartUpCost",
59
+ "StockVolume",
60
+ "Storage",
61
+ "TargetBound",
62
+ "WaterValue",
63
+ ]
@@ -0,0 +1,49 @@
1
+ from framcore import Base
2
+ from framcore.attributes import AvgFlowVolume, FlowVolume
3
+ from framcore.fingerprints import Fingerprint
4
+
5
+
6
+ class HydroBypass(Base):
7
+ """HydroBypass represents a controlled water way from a HydroModule. Used to bypass main release of the HydroModule."""
8
+
9
+ def __init__(
10
+ self,
11
+ to_module: str | None,
12
+ capacity: FlowVolume | None = None,
13
+ ) -> None:
14
+ """
15
+ Initialize object.
16
+
17
+ Args:
18
+ to_module (str | None): Name of the HydroModule the water is released to.
19
+ capacity (FlowVolume | None, optional): Restrictions on the volume of water which can pass through the bypass at a given moment. Defaults to None.
20
+
21
+ """
22
+ super().__init__()
23
+
24
+ self._check_type(to_module, (str, type(None)))
25
+ self._check_type(capacity, (FlowVolume, type(None)))
26
+
27
+ self._to_module = to_module
28
+ self._capacity = capacity
29
+ self._volume = AvgFlowVolume()
30
+
31
+ def get_to_module(self) -> str | None:
32
+ """Get the name of the module to which the bypass leads."""
33
+ return self._to_module
34
+
35
+ def set_to_module(self, to_module: str) -> None:
36
+ """Set the name of the module to which the bypass leads."""
37
+ self._check_type(to_module, str)
38
+ self._to_module = to_module
39
+
40
+ def get_capacity(self) -> FlowVolume | None:
41
+ """Get the capacity of the bypass."""
42
+ return self._capacity
43
+
44
+ def get_volume(self) -> AvgFlowVolume:
45
+ """Get the volume of the bypass."""
46
+ return self._volume
47
+
48
+ def _get_fingerprint(self) -> Fingerprint:
49
+ return self.get_fingerprint_default(refs={"to_module": self._to_module})
@@ -0,0 +1,100 @@
1
+ from framcore import Base
2
+ from framcore.attributes import AvgFlowVolume, Conversion, Cost
3
+ from framcore.curves import Curve
4
+ from framcore.expressions import Expr, ensure_expr
5
+ from framcore.fingerprints import Fingerprint
6
+ from framcore.timevectors import TimeVector
7
+
8
+
9
+ class HydroGenerator(Base):
10
+ """
11
+ Produces power from the main release of a HydroModule.
12
+
13
+ Produces to a power node, and can have variable costs associated with operation. Other attributes are energy equivalent, PQ curve, nominal head
14
+ and tailwater elevation.
15
+
16
+ """
17
+
18
+ def __init__(
19
+ self,
20
+ power_node: str,
21
+ energy_equivalent: Conversion, # energy equivalent
22
+ pq_curve: Expr | str | Curve | None = None,
23
+ nominal_head: Expr | str | TimeVector | None = None,
24
+ tailwater_elevation: Expr | str | TimeVector | None = None,
25
+ voc: Cost | None = None,
26
+ production: AvgFlowVolume | None = None,
27
+ ) -> None:
28
+ """
29
+ Initialize a HydroGenerator with parameters.
30
+
31
+ Args:
32
+ power_node (str): Node to supply power to.
33
+ energy_equivalent (Conversion): Conversion factor of power produced to water released.
34
+ pq_curve (Expr | str | Curve | None, optional): Expression or curve describing the relationship produced power and water released. Defaults to None.
35
+ nominal_head (Expr | str | TimeVector | None, optional): Vertical distance between upstream and dowstream water level. Defaults to None.
36
+ tailwater_elevation (Expr | str | TimeVector | None, optional): Elevation at the surface where the water exits the turbine. Defaults to None.
37
+ voc (Cost | None, optional): Variable operational costs. Defaults to None.
38
+ production (AvgFlowVolume | None, optional): Result of power volume produced. Defaults to None.
39
+
40
+ """
41
+ super().__init__()
42
+
43
+ self._check_type(power_node, str)
44
+ self._check_type(energy_equivalent, Conversion)
45
+ self._check_type(pq_curve, (Expr, str, Curve, type(None)))
46
+ self._check_type(nominal_head, (Expr, str, TimeVector, type(None)))
47
+ self._check_type(tailwater_elevation, (Expr, str, TimeVector, type(None)))
48
+ self._check_type(voc, (Cost, type(None)))
49
+
50
+ self._power_node = power_node
51
+ self._energy_eq = energy_equivalent
52
+ self._pq_curve = ensure_expr(pq_curve)
53
+ self._nominal_head = ensure_expr(nominal_head, is_level=True)
54
+ self._tailwater_elevation = ensure_expr(tailwater_elevation, is_level=True)
55
+ self._voc = voc
56
+
57
+ if production is None:
58
+ production = AvgFlowVolume()
59
+ self._production: AvgFlowVolume = production
60
+
61
+ def get_power_node(self) -> str:
62
+ """Get the power node of the hydro generator."""
63
+ return self._power_node
64
+
65
+ def set_power_node(self, power_node: str) -> None:
66
+ """Set the power node of the pump unit."""
67
+ self._check_type(power_node, str)
68
+ self._power_node = power_node
69
+
70
+ def get_energy_equivalent(self) -> Conversion:
71
+ """Get the energy equivalent of the hydro generator."""
72
+ return self._energy_eq
73
+
74
+ def get_pq_curve(self) -> Expr | None:
75
+ """Get the PQ curve of the hydro generator."""
76
+ return self._pq_curve
77
+
78
+ def get_nominal_head(self) -> Expr | None:
79
+ """Get the nominal head of the hydro generator."""
80
+ return self._nominal_head
81
+
82
+ def get_tailwater_elevation(self) -> Expr | None:
83
+ """Get the tailwater elevation of the hydro generator."""
84
+ return self._tailwater_elevation
85
+
86
+ def get_voc(self) -> Cost | None:
87
+ """Get the variable operation and maintenance cost of the hydro generator."""
88
+ return self._voc
89
+
90
+ def set_voc(self, voc: Cost) -> None:
91
+ """Set the variable operation and maintenance cost of the hydro generator."""
92
+ self._check_type(voc, Cost)
93
+ self._voc = voc
94
+
95
+ def get_production(self) -> AvgFlowVolume:
96
+ """Get the generation of the hydro generator."""
97
+ return self._production
98
+
99
+ def _get_fingerprint(self) -> Fingerprint:
100
+ raise self.get_fingerprint_default(refs={"power_node": self._power_node})
@@ -0,0 +1,178 @@
1
+ from framcore import Base
2
+ from framcore.attributes import AvgFlowVolume, Conversion, FlowVolume
3
+ from framcore.expressions import Expr, ensure_expr
4
+ from framcore.fingerprints import Fingerprint
5
+ from framcore.timevectors import TimeVector
6
+
7
+
8
+ class HydroPump(Base):
9
+ """
10
+ Represent a pump associated with a HydroModule.
11
+
12
+ The HydroPump can consume power from a power Node to move water upstream between two HydroModules. It has a max power capacity, and mean energy
13
+ equivalent and water capacity. It can also describe the relationship between head and flow (Q), with min and max head and flow.
14
+
15
+ Results for water and power consumption are stored as AvgFlowVolume attributes.
16
+
17
+ """
18
+
19
+ def __init__(
20
+ self,
21
+ power_node: str,
22
+ from_module: str,
23
+ to_module: str,
24
+ water_capacity: FlowVolume,
25
+ energy_equivalent: Conversion,
26
+ power_capacity: FlowVolume | None = None,
27
+ head_min: Expr | str | TimeVector | None = None,
28
+ head_max: Expr | str | TimeVector | None = None,
29
+ q_min: Expr | str | TimeVector | None = None,
30
+ q_max: Expr | str | TimeVector | None = None,
31
+ ) -> None:
32
+ """
33
+ Initialize a HydroPump object parameters.
34
+
35
+ Args:
36
+ power_node (str): Node to take power from when operating.
37
+ from_module (str): Source HydroModule to move water from.
38
+ to_module (str): Destination HydroModule to move water to.
39
+ water_capacity (FlowVolume): Max pumped water volume given the mean energy equivalent and power capacity.
40
+ energy_equivalent (Conversion): Mean conversion factor between power consumed and volume of water moved.
41
+ power_capacity (FlowVolume | None, optional): Max power consumed. Defaults to None.
42
+ head_min (Expr | str | TimeVector | None, optional): Minimum elevation difference between upstream and downstream water level. Defaults to None.
43
+ head_max (Expr | str | TimeVector | None, optional): Maximum elevation difference between upstream and downstream water level. Defaults to None.
44
+ q_min (Expr | str | TimeVector | None, optional): Maximum water flow at head_min. Defaults to None.
45
+ q_max (Expr | str | TimeVector | None, optional): Maximum water flow at head_max. Defaults to None.
46
+
47
+ """
48
+ super().__init__()
49
+ self._check_type(power_node, str)
50
+ self._check_modules(from_module, to_module) # checks types and that they are not the same.
51
+ self._check_type(water_capacity, FlowVolume)
52
+ self._check_type(power_capacity, (FlowVolume, type(None)))
53
+ self._check_type(energy_equivalent, Conversion)
54
+ self._check_type(head_min, (Expr, str, TimeVector, type(None)))
55
+ self._check_type(head_max, (Expr, str, TimeVector, type(None)))
56
+ self._check_type(q_min, (Expr, str, TimeVector, type(None)))
57
+ self._check_type(q_max, (Expr, str, TimeVector, type(None)))
58
+
59
+ self._power_node = power_node
60
+ self._from_module = from_module
61
+ self._to_module = to_module
62
+ self._water_capacity = water_capacity
63
+ self._energy_eq = energy_equivalent
64
+ self._power_capacity = power_capacity
65
+
66
+ self._hmin = ensure_expr(head_min, is_level=True)
67
+ self._hmax = ensure_expr(head_max, is_level=True)
68
+ self._qmin = ensure_expr(q_min, is_flow=True, is_level=True)
69
+ self._qmax = ensure_expr(q_max, is_flow=True, is_level=True)
70
+
71
+ self._water_consumption = AvgFlowVolume()
72
+ self._power_consumption = AvgFlowVolume()
73
+
74
+ def get_water_capacity(self) -> FlowVolume:
75
+ """Get the capacity of the pump unit."""
76
+ return self._water_capacity
77
+
78
+ def get_power_capacity(self) -> FlowVolume:
79
+ """Get the capacity of the pump unit."""
80
+ return self._power_capacity
81
+
82
+ def get_power_node(self) -> str:
83
+ """Get the power node of the pump unit."""
84
+ return self._power_node
85
+
86
+ def set_power_node(self, power_node: str) -> None:
87
+ """Set the power node of the pump unit."""
88
+ self._check_type(power_node, str)
89
+ self._power_node = power_node
90
+
91
+ def get_from_module(self) -> str:
92
+ """Get the module from which the pump unit is pumping."""
93
+ return self._from_module
94
+
95
+ def get_to_module(self) -> str:
96
+ """Get the module to which the pump unit is pumping."""
97
+ return self._to_module
98
+
99
+ # TODO: should be split in two? Keep in mind we check that the to and from modules are not the same. So if we split this user might run into issues if
100
+ # trying to first set from_module to to_module then change to_module.
101
+ def set_modules(self, from_module: str, to_module: str) -> None:
102
+ """Set the modules for the pump unit."""
103
+ self._check_modules(from_module, to_module)
104
+ self._from_module = from_module
105
+ self._to_module = to_module
106
+
107
+ def get_water_consumption(self) -> FlowVolume:
108
+ """Get the water consumption of the pump unit."""
109
+ return self._water_consumption
110
+
111
+ def get_power_consumption(self) -> FlowVolume:
112
+ """Get the power consumption of the pump unit."""
113
+ return self._power_consumption
114
+
115
+ def _check_modules(self, from_module: str, to_module: str) -> None:
116
+ self._check_type(from_module, str)
117
+ self._check_type(to_module, str)
118
+ if from_module == to_module:
119
+ message = f"{self} cannot pump to and from the same module. Got {from_module} for both from_module and to_module."
120
+ raise ValueError(message)
121
+
122
+ def _check_base_module_name(self, base_name: str) -> None:
123
+ if base_name not in (self._from_module, self._to_module):
124
+ message = (
125
+ f"Module {base_name} has not been coupled correctly to its pump {self}. Pump is coupled to modules {self._from_module} and {self._to_module}"
126
+ )
127
+ raise RuntimeError(message)
128
+
129
+ # other parameters
130
+ def get_energy_equivalent(self) -> Conversion:
131
+ """Get the energy equivalent of hydro pump."""
132
+ return self._energy_eq
133
+
134
+ def set_energy_eq(self, energy_eq: Conversion) -> None:
135
+ """Set the energy equivalent."""
136
+ self._check_type(energy_eq, Conversion)
137
+ self._energy_eq = energy_eq
138
+
139
+ def get_head_min(self) -> Expr:
140
+ """Get min fall height of hydro pump."""
141
+ return self._head_min
142
+
143
+ def set_head_min(self, head_min: Expr | str | None) -> None:
144
+ """Set min fall height."""
145
+ self._head_min = ensure_expr(head_min)
146
+
147
+ def get_head_max(self) -> Expr:
148
+ """Get max fall height of hydro pump."""
149
+ return self._hmax
150
+
151
+ def set_head_max(self, hmax: Expr | str | None) -> None:
152
+ """Set max fall height."""
153
+ self._hmax = ensure_expr(hmax)
154
+
155
+ def get_q_min(self) -> Expr:
156
+ """Get Q min of hydro pump."""
157
+ return self._q_min
158
+
159
+ def set_qmin(self, q_min: Expr | str | None) -> None:
160
+ """Set Q min."""
161
+ self._q_min = ensure_expr(q_min)
162
+
163
+ def get_q_max(self) -> Expr:
164
+ """Get Q max of hydro pump."""
165
+ return self._q_max
166
+
167
+ def set_qmax(self, q_max: Expr | str | None) -> None:
168
+ """Set Q max."""
169
+ self._q_max = ensure_expr(q_max)
170
+
171
+ def _get_fingerprint(self) -> Fingerprint:
172
+ return self.get_fingerprint_default(
173
+ refs={
174
+ "power_node": self._power_node,
175
+ "from_module": self._from_module,
176
+ "to_module": self._to_module,
177
+ },
178
+ )
@@ -0,0 +1,27 @@
1
+ from framcore.attributes import ReservoirCurve, StockVolume
2
+ from framcore.attributes.Storage import Storage
3
+
4
+
5
+ class HydroReservoir(Storage):
6
+ """Represent a hydro reservoir of a HydroModule."""
7
+
8
+ def __init__(
9
+ self,
10
+ capacity: StockVolume,
11
+ reservoir_curve: ReservoirCurve = None,
12
+ volume: StockVolume | None = None,
13
+ ) -> None:
14
+ """
15
+ Initialize a HydroReservoir instance.
16
+
17
+ Args:
18
+ capacity (StockVolume): The maximum storage capacity of the reservoir.
19
+ reservoir_curve (ReservoirCurve, optional): The curve describing water level elevation to volume characteristics.
20
+ volume (StockVolume, optional): Volume of water in the reservoir.
21
+
22
+ """
23
+ super().__init__(
24
+ capacity=capacity,
25
+ reservoir_curve=reservoir_curve,
26
+ volume=volume,
27
+ )
@@ -0,0 +1,13 @@
1
+ # from framcore.attributes.hydro.Bypass import Bypass
2
+ # from framcore.attributes.hydro.Generator import Generator
3
+ # from framcore.attributes.hydro.Inflow import Inflow
4
+ # from framcore.attributes.hydro.Pump import Pump
5
+ # from framcore.attributes.hydro.Reservoir import Reservoir
6
+
7
+ # __all__ = [
8
+ # "Bypass",
9
+ # "Generator",
10
+ # "Inflow",
11
+ # "Pump",
12
+ # "Reservoir",
13
+ # ]