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

blue-marble / gridpath / 19641246021

24 Nov 2025 04:18PM UTC coverage: 89.057% (-0.004%) from 89.061%
19641246021

push

github

anamileva
Tweak to update-from-default-subscenario function

27531 of 30914 relevant lines covered (89.06%)

0.89 hits per line

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

96.92
/gridpath/project/operations/fix_commitment.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
This module exports the commitment variables that must be fixed in the next
17
stage and imports the commitment variables that were fixed in the previous
18
stage.
19
"""
20

21
from csv import writer
1✔
22
import os.path
1✔
23
from pandas import read_csv
1✔
24
from pyomo.environ import Set, Param, NonNegativeReals, Expression
1✔
25
import warnings
1✔
26

27

28
from gridpath.auxiliary.auxiliary import (
1✔
29
    get_required_subtype_modules,
30
    check_for_integer_subdirectories,
31
    subset_init_by_set_membership,
32
)
33
from gridpath.project.operations.common_functions import load_operational_type_modules
1✔
34

35

36
def add_model_components(
1✔
37
    m,
38
    d,
39
    scenario_directory,
40
    weather_iteration,
41
    hydro_iteration,
42
    availability_iteration,
43
    subproblem,
44
    stage,
45
):
46
    """
47
    The following Pyomo model components are defined in this module:
48

49
    +-------------------------------------------------------------------------+
50
    | Sets                                                                    |
51
    +=========================================================================+
52
    | | :code:`FNL_COMMIT_PRJS`                                               |
53
    |                                                                         |
54
    | The set of generators for which the current stage or any of the         |
55
    | previous stages is the final commitment stage.                          |
56
    +-------------------------------------------------------------------------+
57
    | | :code:`FXD_COMMIT_PRJS`                                               |
58
    |                                                                         |
59
    | The set of generators that have already had their commitment fixed in a |
60
    | prior commitment stage.                                                 |
61
    +-------------------------------------------------------------------------+
62
    | | :code:`FNL_COMMIT_PRJS_OPR_TMPS`                                      |
63
    |                                                                         |
64
    | Two-dimensional set of all final commitment projects and their          |
65
    | operational timepoints.                                                 |
66
    +-------------------------------------------------------------------------+
67
    | | :code:`FXD_COMMIT_PRJS_OPR_TMPS`                                      |
68
    |                                                                         |
69
    | Two-dimensional set of all fixed commitment projects and their          |
70
    | operational timepoints.                                                 |
71
    +-------------------------------------------------------------------------+
72

73
    |
74

75
    +-------------------------------------------------------------------------+
76
    | Input Params                                                            |
77
    +=========================================================================+
78
    | | :code:`fixed_commitment`                                              |
79
    | | *Defined over*: :code:`FXD_COMMIT_PRJ_OPR_TMPS`                       |
80
    |                                                                         |
81
    | This param describes the fixed commitment from the prior commitment     |
82
    | stage for each fixed commitment project and their operational           |
83
    | timepoints.                                                             |
84
    +-------------------------------------------------------------------------+
85

86
    |
87

88
    +-------------------------------------------------------------------------+
89
    | Expressions                                                             |
90
    +=========================================================================+
91
    | | :code:`Commitment`                                                    |
92
    | | *Defined over*: :code:`FNL_COMMIT_PRJ_OPR_TMPS`                       |
93
    |                                                                         |
94
    | Describes the commitment for all final commitment projects and their    |
95
    | operational timepoints. For the :code:`gen_commit_cap` operational      |
96
    | type, it describes the committed capacity in MW whereas for the         |
97
    | :code:`gen_commit_lin` and :code:`gen_commit_bin` operational types it  |
98
    | describes the binary commitment variable. This expression will be       |
99
    | exported so that the next stage's optimization can read it in through   |
100
    | the :code:`fixed_commitment` param and fix the commitment to this value.|
101
    +-------------------------------------------------------------------------+
102

103
    """
104

105
    # Dynamic Inputs
106

107
    required_operational_modules = get_required_subtype_modules(
1✔
108
        scenario_directory=scenario_directory,
109
        weather_iteration=weather_iteration,
110
        hydro_iteration=hydro_iteration,
111
        availability_iteration=availability_iteration,
112
        subproblem=subproblem,
113
        stage=stage,
114
        which_type="operational_type",
115
    )
116

117
    imported_operational_modules = load_operational_type_modules(
1✔
118
        required_operational_modules
119
    )
120

121
    # Sets
122
    ###########################################################################
123

124
    m.FNL_COMMIT_PRJS = Set()
1✔
125

126
    m.FXD_COMMIT_PRJS = Set()
1✔
127

128
    m.FNL_COMMIT_PRJ_OPR_TMPS = Set(
1✔
129
        dimen=2,
130
        initialize=lambda mod: subset_init_by_set_membership(
131
            mod=mod,
132
            superset="PRJ_OPR_TMPS",
133
            index=0,
134
            membership_set=mod.FNL_COMMIT_PRJS,
135
        ),
136
    )
137

138
    m.FXD_COMMIT_PRJ_OPR_TMPS = Set(
1✔
139
        dimen=2,
140
        initialize=lambda mod: subset_init_by_set_membership(
141
            mod=mod,
142
            superset="PRJ_OPR_TMPS",
143
            index=0,
144
            membership_set=mod.FXD_COMMIT_PRJS,
145
        ),
146
    )
147

148
    # Input Params
149
    ###########################################################################
150

151
    m.fixed_commitment = Param(m.FXD_COMMIT_PRJ_OPR_TMPS, within=NonNegativeReals)
1✔
152

153
    # Expressions
154
    ###########################################################################
155

156
    def commitment_rule(mod, g, tmp):
1✔
157
        """
158
        **Expression Name**: Commitment
159
        **Defined Over**: FNL_COMMIT_PRJ_OPR_TMPS
160
        """
161
        gen_op_type = mod.operational_type[g]
1✔
162
        return imported_operational_modules[gen_op_type].commitment_rule(mod, g, tmp)
1✔
163

164
    m.Commitment = Expression(m.FNL_COMMIT_PRJ_OPR_TMPS, rule=commitment_rule)
1✔
165

166

167
# Commitment Functions
168
###############################################################################
169

170

171
def fix_variables(
1✔
172
    m,
173
    d,
174
    scenario_directory,
175
    weather_iteration,
176
    hydro_iteration,
177
    availability_iteration,
178
    subproblem,
179
    stage,
180
):
181
    """
182
    This function fixes the commitment of all fixed commitment projects by
183
    running the :code:`fix_commitment` function in the appropriate operational
184
    module.
185

186
    :param m:
187
    :param d:
188
    :param scenario_directory:
189
    :param subproblem:
190
    :param stage:
191
    :return:
192
    """
193
    required_operational_modules = get_required_subtype_modules(
1✔
194
        scenario_directory=scenario_directory,
195
        weather_iteration=weather_iteration,
196
        hydro_iteration=hydro_iteration,
197
        availability_iteration=availability_iteration,
198
        subproblem=subproblem,
199
        stage=stage,
200
        which_type="operational_type",
201
    )
202

203
    imported_operational_modules = load_operational_type_modules(
1✔
204
        required_operational_modules
205
    )
206

207
    for g in m.FXD_COMMIT_PRJS:
1✔
208
        op_m = m.operational_type[g]
1✔
209
        imp_op_m = imported_operational_modules[op_m]
1✔
210
        if hasattr(imp_op_m, "fix_commitment"):
1✔
211
            for tmp in m.TMPS:
1✔
212
                imp_op_m.fix_commitment(m, g, tmp)
1✔
213

214

215
# Input-Output
216
###############################################################################
217

218

219
def load_model_data(
1✔
220
    m,
221
    d,
222
    data_portal,
223
    scenario_directory,
224
    weather_iteration,
225
    hydro_iteration,
226
    availability_iteration,
227
    subproblem,
228
    stage,
229
):
230
    """
231

232
    :param m:
233
    :param d:
234
    :param data_portal:
235
    :param scenario_directory:
236
    :param subproblem:
237
    :param stage:
238
    :return:
239
    """
240

241
    stages = check_for_integer_subdirectories(
1✔
242
        os.path.join(
243
            scenario_directory,
244
            weather_iteration,
245
            hydro_iteration,
246
            availability_iteration,
247
            subproblem,
248
        )
249
    )
250

251
    fixed_commitment_df = read_csv(
1✔
252
        os.path.join(
253
            scenario_directory,
254
            weather_iteration,
255
            hydro_iteration,
256
            availability_iteration,
257
            subproblem,
258
            "pass_through_inputs",
259
            "fixed_commitment.tab",
260
        ),
261
        sep="\t",
262
        dtype={"stage": str},
263
    )
264

265
    # FNL_COMMIT_PRJS
266
    def get_fnl_commit_prjs():
1✔
267
        """
268
        Get the list of generators for which the current stage is the final
269
        commitment stage or for which any of the previous stages was the
270
        final commitment stage.
271
        """
272
        fnl_commit_prjs = list()
1✔
273
        df = read_csv(
1✔
274
            os.path.join(
275
                scenario_directory,
276
                weather_iteration,
277
                hydro_iteration,
278
                availability_iteration,
279
                subproblem,
280
                stage,
281
                "inputs",
282
                "projects.tab",
283
            ),
284
            sep="\t",
285
            usecols=["project", "last_commitment_stage"],
286
            dtype={"last_commitment_stage": str},
287
        )
288

289
        for prj, s in zip(df["project"], df["last_commitment_stage"]):
1✔
290
            if s == ".":
1✔
291
                pass
1✔
292
            elif s == stage or stages.index(s) < stages.index(stage):
1✔
293
                fnl_commit_prjs.append(prj)
1✔
294

295
        return fnl_commit_prjs
1✔
296

297
    data_portal.data()["FNL_COMMIT_PRJS"] = {None: get_fnl_commit_prjs()}
1✔
298

299
    # FXD_COMMIT_PRJS
300
    fxd_commit_prjs = sorted(list(set(fixed_commitment_df["project"].tolist())))
1✔
301
    # Load data only if we have projects that have already been committed
302
    # Otherwise, leave uninitialized
303
    if len(fxd_commit_prjs) > 0:
1✔
304
        # For projects whose final commitment was in a prior stage, get the
305
        # fixed commitment of the previous stage (by project and timepoint)
306
        fixed_commitment_df["stage_index"] = fixed_commitment_df.apply(
1✔
307
            lambda row: stages.index(row["stage"]), axis=1
308
        )
309
        relevant_commitment_df = fixed_commitment_df[
1✔
310
            fixed_commitment_df["stage_index"] == stages.index(stage) - 1
311
        ]
312
        projects_timepoints = list(
1✔
313
            zip(relevant_commitment_df["project"], relevant_commitment_df["timepoint"])
314
        )
315
        fixed_commitment_dict = dict(
1✔
316
            zip(projects_timepoints, relevant_commitment_df["commitment"])
317
        )
318

319
        data_portal.data()["FXD_COMMIT_PRJS"] = {None: fxd_commit_prjs}
1✔
320
        data_portal.data()["FXD_COMMIT_PRJ_OPR_TMPS"] = {None: projects_timepoints}
1✔
321
        data_portal.data()["fixed_commitment"] = fixed_commitment_dict
1✔
322

323

324
def export_pass_through_inputs(
1✔
325
    scenario_directory,
326
    weather_iteration,
327
    hydro_iteration,
328
    availability_iteration,
329
    subproblem,
330
    stage,
331
    m,
332
):
333
    """
334
    This function exports the commitment for all final commitment projects,
335
    i.e. projects for which the current stage or any of the previous stages
336
    is the final commitment stage.
337

338
    :param scenario_directory:
339
    :param subproblem:
340
    :param stage:
341
    :param m:
342
    :return:
343
    """
344
    df = read_csv(
1✔
345
        os.path.join(
346
            scenario_directory,
347
            weather_iteration,
348
            hydro_iteration,
349
            availability_iteration,
350
            subproblem,
351
            stage,
352
            "inputs",
353
            "projects.tab",
354
        ),
355
        sep="\t",
356
        usecols=["project", "last_commitment_stage"],
357
    )
358

359
    final_commitment_stage_dict = dict(zip(df["project"], df["last_commitment_stage"]))
1✔
360

361
    with open(
1✔
362
        os.path.join(
363
            scenario_directory,
364
            weather_iteration,
365
            hydro_iteration,
366
            availability_iteration,
367
            subproblem,
368
            "pass_through_inputs",
369
            "fixed_commitment.tab",
370
        ),
371
        "a",
372
    ) as fixed_commitment_file:
373
        fixed_commitment_writer = writer(
1✔
374
            fixed_commitment_file, delimiter="\t", lineterminator="\n"
375
        )
376
        for g, tmp in m.FNL_COMMIT_PRJ_OPR_TMPS:
1✔
377
            commitment_value = m.Commitment[g, tmp].expr.value
1✔
378
            if commitment_value < 0:
1✔
379
                warnings.warn(
×
380
                    f"Commitment for ({g}, {tmp}) is "
381
                    f"{commitment_value}; changing to 0 in "
382
                    f"pass-through inputs to avoid data type error "
383
                    f"when loading into next stage. This is "
384
                    f"expected due to solver optimality tolerances."
385
                )
386
                commitment_value = 0
×
387
            fixed_commitment_writer.writerow(
1✔
388
                [
389
                    g,
390
                    tmp,
391
                    stage,
392
                    final_commitment_stage_dict[g],
393
                    commitment_value,
394
                ]
395
            )
396

397

398
def write_pass_through_file_headers(pass_through_directory):
1✔
399
    with open(
1✔
400
        os.path.join(pass_through_directory, "fixed_commitment.tab"),
401
        "w",
402
        newline="",
403
    ) as fixed_commitment_file:
404
        fixed_commitment_writer = writer(
1✔
405
            fixed_commitment_file, delimiter="\t", lineterminator="\n"
406
        )
407
        fixed_commitment_writer.writerow(
1✔
408
            [
409
                "project",
410
                "timepoint",
411
                "stage",
412
                "final_commitment_stage",
413
                "commitment",
414
            ]
415
        )
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