• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

blue-marble / gridpath / 13553759254

26 Feb 2025 09:30PM UTC coverage: 88.945% (+0.01%) from 88.935%
13553759254

push

github

anamileva
Fix tests

26013 of 29246 relevant lines covered (88.95%)

2.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.86
/gridpath/project/operations/cap_factor_limits.py
1
# Copyright 2016-2023 Blue Marble Analytics LLC.
2
#
3
# Licensed under the Apache License, Version 2.0 (the "License");
4
# you may not use this file except in compliance with the License.
5
# You may obtain a copy of the License at
6
#
7
#     http://www.apache.org/licenses/LICENSE-2.0
8
#
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS,
11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
# See the License for the specific language governing permissions and
13
# limitations under the License.
14

15
"""
16
The **gridpath.project.operations.cap_factor_limits** module is a project-level
17
module that adds to the formulation components that limit the minimum and maximum
18
cap factor of a project over a horizon.
19
"""
20

21
import csv
3✔
22
import os.path
3✔
23
from pyomo.environ import Set, Param, Constraint, Expression, Reals, value
3✔
24

25
from gridpath.auxiliary.db_interface import import_csv
3✔
26

27
Infinity = float("inf")
3✔
28
Negative_Infinity = float("-inf")
3✔
29

30

31
def add_model_components(
3✔
32
    m,
33
    d,
34
    scenario_directory,
35
    weather_iteration,
36
    hydro_iteration,
37
    availability_iteration,
38
    subproblem,
39
    stage,
40
):
41
    """
42
    The tables below list the Pyomo model components defined in the
43
    'gen_commit_bin' module followed below by the respective components
44
    defined in the 'gen_commit_lin" module.
45

46
    +-------------------------------------------------------------------------+
47
    | Sets                                                                    |
48
    +=========================================================================+
49
    | | :code:`CAP_FACTOR_LIMIT_PRJ_BT_HRZ`                                   |
50
    | | *Within*: :code:`PROJECTS*BLN_TYPE_HRZS`                              |
51
    |                                                                         |
52
    | Three-dimensional set with the project, horizon balancing type, and     |
53
    | horizon over which cap factor limits should be enforced.                |
54
    +-------------------------------------------------------------------------+
55

56
    +-------------------------------------------------------------------------+
57
    | Input Params                                                            |
58
    +=========================================================================+
59
    | | :code:`min_cap_factor`                                                |
60
    | | *Defined over*: :code:`CAP_FACTOR_LIMIT_PRJ_BT_HRZ`                   |
61
    | | *Within*: :code:`Reals`                                               |
62
    | | *Default*: :code:`Negative_Infinity`                                  |
63
    |                                                                         |
64
    | The project's minimum cap factor for this horizon balancing type and    |
65
    | horizon. It can be negative to allow us to limit storage (which is a    |
66
    | net load over the course of the horizon due to losses.                  |
67
    +-------------------------------------------------------------------------+
68
    | | :code:`max_cap_factor`                                                |
69
    | | *Defined over*: :code:`CAP_FACTOR_LIMIT_PRJ_BT_HRZ`                   |
70
    | | *Within*: :code:`Reals`                                               |
71
    | | *Default*: :code:`Infinity`                                           |
72
    |                                                                         |
73
    | The project's maximum cap factor for this horizon balancing type and    |
74
    | horizon. It can be negative to allow us to limit storage (which is a    |
75
    | net load over the course of the horizon due to losses.                  |
76
    +-------------------------------------------------------------------------+
77

78
    +-------------------------------------------------------------------------+
79
    | Constraints                                                             |
80
    +-------------------------------------------------------------------------+
81
    | | :code:`Min_Cap_Factor_Constraint`                                     |
82
    | | *Defined over*: :code:`CAP_FACTOR_LIMIT_PRJ_BT_HRZ`                   |
83
    |                                                                         |
84
    | Energy output from this project over this balancing type and horizon    |
85
    | must equal or exceed the minimum capacity factor multiplied by the      |
86
    | maximum possible output over this balancing type and horizon.           |
87
    +-------------------------------------------------------------------------+
88
    | | :code:`Max_Cap_Factor_Constraint`                                     |
89
    | | *Defined over*: :code:`CAP_FACTOR_LIMIT_PRJ_BT_HRZ`                   |
90
    |                                                                         |
91
    | Energy output from this project over this balancing type and horizon    |
92
    | must be less than or equal to the maximum capacity factor multiplied    |
93
    | by the maximum possible output over this balancing type and horizon.    |
94
    +-------------------------------------------------------------------------+
95

96
    """
97

98
    m.CAP_FACTOR_LIMIT_PRJ_BT_HRZ = Set(dimen=3, within=m.PROJECTS * m.BLN_TYPE_HRZS)
3✔
99

100
    m.min_cap_factor = Param(
3✔
101
        m.CAP_FACTOR_LIMIT_PRJ_BT_HRZ, within=Reals, default=Negative_Infinity
102
    )  # allow negative values, e.g. for storage (net power is <0 due to losses)
103

104
    m.max_cap_factor = Param(
3✔
105
        m.CAP_FACTOR_LIMIT_PRJ_BT_HRZ, within=Reals, default=Infinity
106
    )  # allow negative values, e.g. for storage (net power is <0 due to losses)
107

108
    def actual_power_provision_in_horizon_rule(mod, prj, bt, h):
3✔
109
        """ """
110
        return sum(
3✔
111
            mod.Project_Power_Provision_MW[prj, tmp]
112
            * mod.hrs_in_tmp[tmp]
113
            * mod.tmp_weight[tmp]
114
            for tmp in mod.TMPS_BY_BLN_TYPE_HRZ[bt, h]
115
        )
116

117
    m.Actual_Power_Provision_in_Horizon_Expression = Expression(
3✔
118
        m.CAP_FACTOR_LIMIT_PRJ_BT_HRZ, rule=actual_power_provision_in_horizon_rule
119
    )
120

121
    def possible_power_provision_in_horizon_rule(mod, prj, bt, h):
3✔
122
        return sum(
3✔
123
            mod.Capacity_MW[prj, mod.period[tmp]]
124
            * mod.hrs_in_tmp[tmp]
125
            * mod.tmp_weight[tmp]
126
            for tmp in mod.TMPS_BY_BLN_TYPE_HRZ[bt, h]
127
        )
128

129
    m.Possible_Power_Provision_in_Horizon_Expression = Expression(
3✔
130
        m.CAP_FACTOR_LIMIT_PRJ_BT_HRZ, rule=possible_power_provision_in_horizon_rule
131
    )
132

133
    def min_cap_factor_constraint_rule(mod, prj, bt, h):
3✔
134
        if mod.min_cap_factor[prj, bt, h] == Negative_Infinity:
3✔
135
            return Constraint.Skip
3✔
136
        else:
137
            return (
×
138
                mod.Actual_Power_Provision_in_Horizon_Expression[prj, bt, h]
139
                >= mod.min_cap_factor[prj, bt, h]
140
                * mod.Possible_Power_Provision_in_Horizon_Expression[prj, bt, h]
141
            )
142

143
    m.Min_Cap_Factor_Constraint = Constraint(
3✔
144
        m.CAP_FACTOR_LIMIT_PRJ_BT_HRZ,
145
        rule=min_cap_factor_constraint_rule,
146
    )
147

148
    def max_cap_factor_constraint_rule(mod, prj, bt, h):
3✔
149
        if mod.max_cap_factor[prj, bt, h] == Infinity:
3✔
150
            return Constraint.Skip
×
151
        else:
152
            return (
3✔
153
                mod.Actual_Power_Provision_in_Horizon_Expression[prj, bt, h]
154
                <= mod.max_cap_factor[prj, bt, h]
155
                * mod.Possible_Power_Provision_in_Horizon_Expression[prj, bt, h]
156
            )
157

158
    m.Max_Cap_Factor_Constraint = Constraint(
3✔
159
        m.CAP_FACTOR_LIMIT_PRJ_BT_HRZ,
160
        rule=max_cap_factor_constraint_rule,
161
    )
162

163

164
def load_model_data(
3✔
165
    m,
166
    d,
167
    data_portal,
168
    scenario_directory,
169
    weather_iteration,
170
    hydro_iteration,
171
    availability_iteration,
172
    subproblem,
173
    stage,
174
):
175
    """
176
    :param mod:
177
    :param data_portal:
178
    :param scenario_directory:
179
    :param subproblem:
180
    :param stage:
181
    :return:
182
    """
183
    input_file = os.path.join(
3✔
184
        scenario_directory,
185
        weather_iteration,
186
        hydro_iteration,
187
        availability_iteration,
188
        subproblem,
189
        stage,
190
        "inputs",
191
        "cap_factor_limits.tab",
192
    )
193

194
    if os.path.exists(input_file):
3✔
195
        data_portal.load(
3✔
196
            filename=input_file,
197
            index=m.CAP_FACTOR_LIMIT_PRJ_BT_HRZ,
198
            param=(
199
                m.min_cap_factor,
200
                m.max_cap_factor,
201
            ),
202
        )
203

204

205
def export_results(
3✔
206
    scenario_directory,
207
    weather_iteration,
208
    hydro_iteration,
209
    availability_iteration,
210
    subproblem,
211
    stage,
212
    m,
213
    d,
214
):
215
    """ """
216
    input_file = os.path.join(
3✔
217
        scenario_directory,
218
        weather_iteration,
219
        hydro_iteration,
220
        availability_iteration,
221
        subproblem,
222
        stage,
223
        "inputs",
224
        "cap_factor_limits.tab",
225
    )
226

227
    if os.path.exists(input_file):
3✔
228
        with open(
3✔
229
            os.path.join(
230
                scenario_directory,
231
                weather_iteration,
232
                hydro_iteration,
233
                availability_iteration,
234
                subproblem,
235
                stage,
236
                "results",
237
                "project_cap_factor_limits.csv",
238
            ),
239
            "w",
240
            newline="",
241
        ) as results_f:
242
            writer = csv.writer(results_f)
3✔
243
            writer.writerow(
3✔
244
                [
245
                    "project",
246
                    "balancing_type_horizon",
247
                    "horizon",
248
                    "min_cap_factor",
249
                    "max_cap_factor",
250
                    "actual_power_provision_mwh",
251
                    "possible_power_provision_mwh",
252
                ]
253
            )
254
            for prj, bt, h in sorted(m.CAP_FACTOR_LIMIT_PRJ_BT_HRZ):
3✔
255
                writer.writerow(
3✔
256
                    [
257
                        prj,
258
                        bt,
259
                        h,
260
                        (
261
                            None
262
                            if m.min_cap_factor[prj, bt, h] == Negative_Infinity
263
                            else m.min_cap_factor[prj, bt, h]
264
                        ),
265
                        (
266
                            None
267
                            if m.max_cap_factor[prj, bt, h] == Infinity
268
                            else m.max_cap_factor[prj, bt, h]
269
                        ),
270
                        value(
271
                            m.Actual_Power_Provision_in_Horizon_Expression[prj, bt, h]
272
                        ),
273
                        value(
274
                            m.Possible_Power_Provision_in_Horizon_Expression[prj, bt, h]
275
                        ),
276
                    ]
277
                )
278

279

280
# Database
281
###############################################################################
282

283

284
def import_results_into_database(
3✔
285
    scenario_id,
286
    weather_iteration,
287
    hydro_iteration,
288
    availability_iteration,
289
    subproblem,
290
    stage,
291
    c,
292
    db,
293
    results_directory,
294
    quiet,
295
):
296
    """
297
    :param scenario_id:
298
    :param c:
299
    :param db:
300
    :param results_directory:
301
    :param quiet:
302
    :return:
303
    """
304
    which_results = "project_cap_factor_limits"
3✔
305

306
    if os.path.exists(
3✔
307
        os.path.join(
308
            results_directory,
309
            weather_iteration,
310
            hydro_iteration,
311
            availability_iteration,
312
            subproblem,
313
            stage,
314
            "results",
315
            f"{which_results}.csv",
316
        )
317
    ):
318
        import_csv(
×
319
            conn=db,
320
            cursor=c,
321
            scenario_id=scenario_id,
322
            hydro_iteration=hydro_iteration,
323
            availability_iteration=availability_iteration,
324
            subproblem=subproblem,
325
            stage=stage,
326
            quiet=quiet,
327
            results_directory=results_directory,
328
            which_results=which_results,
329
        )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc