Completed
Push — dev ( 93e34e...2bb17a )
by Patrik
19s queued 11s
created

solph.flows._shared._min_uptime_constraint()   A

Complexity

Conditions 2

Size

Total Lines 48
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 21
dl 0
loc 48
rs 9.376
c 0
b 0
f 0
cc 2
nop 1
1
# -*- coding: utf-8 -*-
2
3
"""Creating sets, variables, constraints and parts of the objective function
4
for Flow objects with investment but without nonconvex option.
5
6
SPDX-FileCopyrightText: Uwe Krien <[email protected]>
7
SPDX-FileCopyrightText: Simon Hilpert
8
SPDX-FileCopyrightText: Cord Kaldemeyer
9
SPDX-FileCopyrightText: Patrik Schönfeldt
10
SPDX-FileCopyrightText: Birgit Schachler
11
SPDX-FileCopyrightText: jnnr
12
SPDX-FileCopyrightText: jmloenneberga
13
SPDX-FileCopyrightText: Johannes Kochems
14
15
SPDX-License-Identifier: MIT
16
17
"""
18
from pyomo.core import Binary
19
from pyomo.core import BuildAction
20
from pyomo.core import Constraint
21
from pyomo.core import Expression
22
from pyomo.core import NonNegativeReals
23
from pyomo.core import Set
24
from pyomo.core import Var
25
26
from oemof.solph._plumbing import valid_sequence
27
28
29
def sets_for_non_convex_flows(block, group):
30
    r"""Creates all sets for non-convex flows.
31
32
    MIN_FLOWS
33
        A subset of set FIXED_CAPACITY_NONCONVEX_FLOWS with the attribute `min`
34
        being not None in the first timestep.
35
    ACTIVITYCOSTFLOWS
36
        A subset of set FIXED_CAPACITY_NONCONVEX_FLOWS with the attribute
37
        `activity_costs` being not None.
38
    INACTIVITYCOSTFLOWS
39
        A subset of set FIXED_CAPACITY_NONCONVEX_FLOWS with the attribute
40
        `inactivity_costs` being not None.
41
    STARTUPFLOWS
42
        A subset of set FIXED_CAPACITY_NONCONVEX_FLOWS with the attribute
43
        `maximum_startups` or `startup_costs`
44
        being not None.
45
    MAXSTARTUPFLOWS
46
        A subset of set STARTUPFLOWS with the attribute
47
        `maximum_startups` being not None.
48
    SHUTDOWNFLOWS
49
        A subset of set FIXED_CAPACITY_NONCONVEX_FLOWS with the attribute
50
        `maximum_shutdowns` or `shutdown_costs`
51
        being not None.
52
    MAXSHUTDOWNFLOWS
53
        A subset of set SHUTDOWNFLOWS with the attribute
54
        `maximum_shutdowns` being not None.
55
    MINUPTIMEFLOWS
56
        A subset of set FIXED_CAPACITY_NONCONVEX_FLOWS with the attribute
57
        `minimum_uptime` being > 0.
58
    MINDOWNTIMEFLOWS
59
        A subset of set FIXED_CAPACITY_NONCONVEX_FLOWS with the attribute
60
        `minimum_downtime` being > 0.
61
    POSITIVE_GRADIENT_FLOWS
62
        A subset of set FIXED_CAPACITY_NONCONVEX_FLOWS with the attribute
63
        `positive_gradient` being not None.
64
    NEGATIVE_GRADIENT_FLOWS
65
        A subset of set FIXED_CAPACITY_NONCONVEX_FLOWS with the attribute
66
        `negative_gradient` being not None.
67
    """
68
    block.MIN_FLOWS = Set(
69
        initialize=[(g[0], g[1]) for g in group if g[2].min[0] is not None]
70
    )
71
    block.STARTUPFLOWS = Set(
72
        initialize=[
73
            (g[0], g[1])
74
            for g in group
75
            if g[2].nonconvex.startup_costs[0] is not None
76
            or g[2].nonconvex.maximum_startups is not None
77
        ]
78
    )
79
    block.MAXSTARTUPFLOWS = Set(
80
        initialize=[
81
            (g[0], g[1])
82
            for g in group
83
            if g[2].nonconvex.maximum_startups is not None
84
        ]
85
    )
86
    block.SHUTDOWNFLOWS = Set(
87
        initialize=[
88
            (g[0], g[1])
89
            for g in group
90
            if g[2].nonconvex.shutdown_costs[0] is not None
91
            or g[2].nonconvex.maximum_shutdowns is not None
92
        ]
93
    )
94
    block.MAXSHUTDOWNFLOWS = Set(
95
        initialize=[
96
            (g[0], g[1])
97
            for g in group
98
            if g[2].nonconvex.maximum_shutdowns is not None
99
        ]
100
    )
101
    block.MINUPTIMEFLOWS = Set(
102
        initialize=[
103
            (g[0], g[1])
104
            for g in group
105
            if g[2].nonconvex.minimum_uptime.max() > 0
106
        ]
107
    )
108
    block.MINDOWNTIMEFLOWS = Set(
109
        initialize=[
110
            (g[0], g[1])
111
            for g in group
112
            if g[2].nonconvex.minimum_downtime.max() > 0
113
        ]
114
    )
115
    block.NEGATIVE_GRADIENT_FLOWS = Set(
116
        initialize=[
117
            (g[0], g[1])
118
            for g in group
119
            if g[2].nonconvex.negative_gradient_limit[0] is not None
120
        ]
121
    )
122
    block.POSITIVE_GRADIENT_FLOWS = Set(
123
        initialize=[
124
            (g[0], g[1])
125
            for g in group
126
            if g[2].nonconvex.positive_gradient_limit[0] is not None
127
        ]
128
    )
129
    block.ACTIVITYCOSTFLOWS = Set(
130
        initialize=[
131
            (g[0], g[1])
132
            for g in group
133
            if g[2].nonconvex.activity_costs[0] is not None
134
        ]
135
    )
136
137
    block.INACTIVITYCOSTFLOWS = Set(
138
        initialize=[
139
            (g[0], g[1])
140
            for g in group
141
            if g[2].nonconvex.inactivity_costs[0] is not None
142
        ]
143
    )
144
145
146
def variables_for_non_convex_flows(block):
147
    r"""
148
    :math:`Y_{startup}` (binary) `NonConvexFlowBlock.startup`:
149
        Variable indicating startup of flow (component) indexed by
150
        STARTUPFLOWS
151
152
    :math:`Y_{shutdown}` (binary) `NonConvexFlowBlock.shutdown`:
153
        Variable indicating shutdown of flow (component) indexed by
154
        SHUTDOWNFLOWS
155
156
    :math:`\dot{P}_{up}` (continuous)
157
        `NonConvexFlowBlock.positive_gradient`:
158
        Variable indicating the positive gradient, i.e. the load increase
159
        between two consecutive timesteps, indexed by
160
        POSITIVE_GRADIENT_FLOWS
161
162
    :math:`\dot{P}_{down}` (continuous)
163
        `NonConvexFlowBlock.negative_gradient`:
164
        Variable indicating the negative gradient, i.e. the load decrease
165
        between two consecutive timesteps, indexed by
166
        NEGATIVE_GRADIENT_FLOWS
167
    """
168
    m = block.parent_block()
169
170
    if block.STARTUPFLOWS:
171
        block.startup = Var(block.STARTUPFLOWS, m.TIMESTEPS, within=Binary)
172
173
    if block.SHUTDOWNFLOWS:
174
        block.shutdown = Var(block.SHUTDOWNFLOWS, m.TIMESTEPS, within=Binary)
175
176
    if block.POSITIVE_GRADIENT_FLOWS:
177
        block.positive_gradient = Var(
178
            block.POSITIVE_GRADIENT_FLOWS,
179
            m.TIMESTEPS,
180
            within=NonNegativeReals,
181
        )
182
183
    if block.NEGATIVE_GRADIENT_FLOWS:
184
        block.negative_gradient = Var(
185
            block.NEGATIVE_GRADIENT_FLOWS,
186
            m.TIMESTEPS,
187
            within=NonNegativeReals,
188
        )
189
190
191
def _min_downtime_constraint(block):
192
    r"""
193
    .. math::
194
        (Y_{status}(t-1) - Y_{status}(t)) \
195
        \cdot t_{down,minimum} \\
196
        \leq t_{down,minimum} \
197
        - \sum_{n=0}^{t_{down,minimum}-1} Y_{status}(t+n) \\
198
        \forall t \in \textrm{TIMESTEPS} | \\
199
        t \neq \{0..t_{down,minimum}\} \cup \
200
        \{t\_max-t_{down,minimum}..t\_max\} , \\
201
        \forall (i,o) \in \textrm{MINDOWNTIMEFLOWS}.
202
        \\ \\
203
        Y_{status}(t) = Y_{status,0} \\
204
        \forall t \in \textrm{TIMESTEPS} | \\
205
        t = \{0..t_{down,minimum}\} \cup \
206
        \{t\_max-t_{down,minimum}..t\_max\} , \\
207
        \forall (i,o) \in \textrm{MINDOWNTIMEFLOWS}.
208
    """
209
    m = block.parent_block()
210
211
    def min_downtime_rule(_, i, o, t):
212
        """
213
        Rule definition for min-downtime constraints of non-convex flows.
214
        """
215
        if (
216
            m.flows[i, o].nonconvex.first_flexible_timestep
217
            < t
218
            < m.TIMESTEPS.at(-1)
219
        ):
220
            # We have a 2D matrix of constraints,
221
            # so testing is easier then just calling the rule for valid t.
222
223
            expr = 0
224
            expr += (
225
                block.status[i, o, t - 1] - block.status[i, o, t]
226
            ) * m.flows[i, o].nonconvex.minimum_downtime[t]
227
            expr += -m.flows[i, o].nonconvex.minimum_downtime[t]
228
            expr += sum(
229
                block.status[i, o, d]
230
                for d in range(
231
                    t,
232
                    min(
233
                        t + m.flows[i, o].nonconvex.minimum_downtime[t],
234
                        len(m.TIMESTEPS),
235
                    ),
236
                )
237
            )
238
            return expr <= 0
239
        else:
240
            return Constraint.Skip
241
242
    return Constraint(
243
        block.MINDOWNTIMEFLOWS, m.TIMESTEPS, rule=min_downtime_rule
244
    )
245
246
247
def _min_uptime_constraint(block):
248
    r"""
249
    .. math::
250
        (Y_{status}(t)-Y_{status}(t-1)) \cdot t_{up,minimum} \\
251
        \leq \sum_{n=0}^{t_{up,minimum}-1} Y_{status}(t+n) \\
252
        \forall t \in \textrm{TIMESTEPS} | \\
253
        t \neq \{0..t_{up,minimum}\} \cup \
254
        \{t\_max-t_{up,minimum}..t\_max\} , \\
255
        \forall (i,o) \in \textrm{MINUPTIMEFLOWS}.
256
        \\ \\
257
        Y_{status}(t) = Y_{status,0} \\
258
        \forall t \in \textrm{TIMESTEPS} | \\
259
        t = \{0..t_{up,minimum}\} \cup \
260
        \{t\_max-t_{up,minimum}..t\_max\} , \\
261
        \forall (i,o) \in \textrm{MINUPTIMEFLOWS}.
262
    """
263
    m = block.parent_block()
264
265
    def _min_uptime_rule(_, i, o, t):
266
        """
267
        Rule definition for min-uptime constraints of non-convex flows.
268
        """
269
        if (
270
            m.flows[i, o].nonconvex.first_flexible_timestep
271
            < t
272
            < m.TIMESTEPS.at(-1)
273
        ):
274
            # We have a 2D matrix of constraints,
275
            # so testing is easier then just calling the rule for valid t.
276
            expr = 0
277
            expr += (
278
                block.status[i, o, t] - block.status[i, o, t - 1]
279
            ) * m.flows[i, o].nonconvex.minimum_uptime[t]
280
            expr += -sum(
281
                block.status[i, o, u]
282
                for u in range(
283
                    t,
284
                    min(
285
                        t + m.flows[i, o].nonconvex.minimum_uptime[t],
286
                        len(m.TIMESTEPS),
287
                    ),
288
                )
289
            )
290
            return expr <= 0
291
        else:
292
            return Constraint.Skip
293
294
    return Constraint(block.MINUPTIMEFLOWS, m.TIMESTEPS, rule=_min_uptime_rule)
295
296
297 View Code Duplication
def _shutdown_constraint(block):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
298
    r"""
299
    .. math::
300
        Y_{shutdown}(t) \geq Y_{status}(t-1) - Y_{status}(t) \\
301
        \forall t \in \textrm{TIMESTEPS}, \\
302
        \forall \textrm{SHUTDOWNFLOWS}.
303
    """
304
    m = block.parent_block()
305
306
    def _shutdown_rule(_, i, o, t):
307
        """Rule definition for shutdown constraints of non-convex flows."""
308
        if t > m.TIMESTEPS.at(1):
309
            expr = (
310
                block.shutdown[i, o, t]
311
                >= block.status[i, o, t - 1] - block.status[i, o, t]
312
            )
313
        else:
314
            expr = (
315
                block.shutdown[i, o, t]
316
                >= m.flows[i, o].nonconvex.initial_status
317
                - block.status[i, o, t]
318
            )
319
        return expr
320
321
    return Constraint(block.SHUTDOWNFLOWS, m.TIMESTEPS, rule=_shutdown_rule)
322
323
324
def _startup_constraint(block):
325
    r"""
326
    .. math::
327
        Y_{startup}(t) \geq Y_{status}(t) - Y_{status}(t-1) \\
328
        \forall t \in \textrm{TIMESTEPS}, \\
329
        \forall \textrm{STARTUPFLOWS}.
330
    """
331
    m = block.parent_block()
332
333 View Code Duplication
    def _startup_rule(_, i, o, t):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
334
        """Rule definition for startup constraint of nonconvex flows."""
335
        if t > m.TIMESTEPS.at(1):
336
            expr = (
337
                block.startup[i, o, t]
338
                >= block.status[i, o, t] - block.status[i, o, t - 1]
339
            )
340
        else:
341
            expr = (
342
                block.startup[i, o, t]
343
                >= block.status[i, o, t]
344
                - m.flows[i, o].nonconvex.initial_status
345
            )
346
        return expr
347
348
    return Constraint(block.STARTUPFLOWS, m.TIMESTEPS, rule=_startup_rule)
349
350
351
def _max_startup_constraint(block):
352
    r"""
353
    .. math::
354
        \sum_{t \in \textrm{TIMESTEPS}} Y_{startup}(t) \leq \
355
            N_{start}(i,o)\\
356
        \forall (i,o) \in \textrm{MAXSTARTUPFLOWS}.
357
    """
358
    m = block.parent_block()
359
360
    def _max_startup_rule(_, i, o):
361
        """Rule definition for maximum number of start-ups."""
362
        lhs = sum(block.startup[i, o, t] for t in m.TIMESTEPS)
363
        return lhs <= m.flows[i, o].nonconvex.maximum_startups
364
365
    return Constraint(block.MAXSTARTUPFLOWS, rule=_max_startup_rule)
366
367
368
def _max_shutdown_constraint(block):
369
    r"""
370
    .. math::
371
        \sum_{t \in \textrm{TIMESTEPS}} Y_{startup}(t) \leq \
372
            N_{shutdown}(i,o)\\
373
        \forall (i,o) \in \textrm{MAXSHUTDOWNFLOWS}.
374
    """
375
    m = block.parent_block()
376
377
    def _max_shutdown_rule(_, i, o):
378
        """Rule definition for maximum number of start-ups."""
379
        lhs = sum(block.shutdown[i, o, t] for t in m.TIMESTEPS)
380
        return lhs <= m.flows[i, o].nonconvex.maximum_shutdowns
381
382
    return Constraint(block.MAXSHUTDOWNFLOWS, rule=_max_shutdown_rule)
383
384
385
def shared_constraints_for_non_convex_flows(block):
386
    r"""
387
    positive_gradient_constraint
388
        .. math::
389
390
            P(t) \cdot Y_{status}(t)
391
            - P(t-1) \cdot Y_{status}(t-1)  \leq \
392
            \dot{P}_{up}(t), \\
393
            \forall t \in \textrm{TIMESTEPS}.
394
395
    negative_gradient_constraint
396
        .. math::
397
            P(t-1) \cdot Y_{status}(t-1)
398
            - P(t) \cdot Y_{status}(t) \leq \
399
            \dot{P}_{down}(t), \\
400
            \forall t \in \textrm{TIMESTEPS}.
401
402
    Also creates:
403
404
    * :py:func:`startup_constraint`
405
    * :py:func:`max_startup_constraint`
406
    * :py:func:`shutdown_constraint`
407
    * :py:func:`max_shutdown_constraint`
408
    * :py:func:`min_uptime_constraint`
409
    * :py:func:`min_downtime_constraint`
410
    """
411
    m = block.parent_block()
412
413
    block.startup_constr = _startup_constraint(block)
414
    block.max_startup_constr = _max_startup_constraint(block)
415
    block.shutdown_constr = _shutdown_constraint(block)
416
    block.max_shutdown_constr = _max_shutdown_constraint(block)
417
    block.min_uptime_constr = _min_uptime_constraint(block)
418
    block.min_downtime_constr = _min_downtime_constraint(block)
419
420
    def _positive_gradient_flow_constraint(_):
421
        r"""Rule definition for positive gradient constraint."""
422
        for i, o in block.POSITIVE_GRADIENT_FLOWS:
423
            for index in range(1, len(m.TIMEINDEX) + 1):
424
                if m.TIMEINDEX[index][1] > 0:
425
                    lhs = (
426
                        m.flow[
427
                            i,
428
                            o,
429
                            m.TIMESTEPS[index],
430
                        ]
431
                        * block.status[i, o, m.TIMESTEPS[index]]
432
                        - m.flow[i, o, m.TIMESTEPS[index - 1]]
433
                        * block.status[i, o, m.TIMESTEPS[index - 1]]
434
                    )
435
                    rhs = block.positive_gradient[i, o, m.TIMEINDEX[index][1]]
436
                    block.positive_gradient_constr.add(
437
                        (
438
                            i,
439
                            o,
440
                            m.TIMESTEPS[index],
441
                        ),
442
                        lhs <= rhs,
443
                    )
444
                else:
445
                    lhs = block.positive_gradient[i, o, 0]
446
                    rhs = 0
447
                    block.positive_gradient_constr.add(
448
                        (
449
                            i,
450
                            o,
451
                            m.TIMESTEPS[index],
452
                        ),
453
                        lhs == rhs,
454
                    )
455
456
    block.positive_gradient_constr = Constraint(
457
        block.POSITIVE_GRADIENT_FLOWS, m.TIMESTEPS, noruleinit=True
458
    )
459
    block.positive_gradient_build = BuildAction(
460
        rule=_positive_gradient_flow_constraint
461
    )
462
463
    def _negative_gradient_flow_constraint(_):
464
        r"""Rule definition for negative gradient constraint."""
465
        for i, o in block.NEGATIVE_GRADIENT_FLOWS:
466
            for index in range(1, len(m.TIMESTEPS) + 1):
467
                if m.TIMESTEPS[index] > 0:
468
                    lhs = (
469
                        m.flow[
470
                            i,
471
                            o,
472
                            m.TIMESTEPS[index - 1],
473
                        ]
474
                        * block.status[i, o, m.TIMESTEPS[index - 1]]
475
                        - m.flow[
476
                            i,
477
                            o,
478
                            m.TIMESTEPS[index],
479
                        ]
480
                        * block.status[i, o, m.TIMESTEPS[index]]
481
                    )
482
                    rhs = block.negative_gradient[i, o, m.TIMESTEPS[index]]
483
                    block.negative_gradient_constr.add(
484
                        (
485
                            i,
486
                            o,
487
                            m.TIMESTEPS[index],
488
                        ),
489
                        lhs <= rhs,
490
                    )
491
                else:
492
                    lhs = block.negative_gradient[i, o, 0]
493
                    rhs = 0
494
                    block.negative_gradient_constr.add(
495
                        (
496
                            i,
497
                            o,
498
                            m.TIMESTEPS[index],
499
                        ),
500
                        lhs == rhs,
501
                    )
502
503
    block.negative_gradient_constr = Constraint(
504
        block.NEGATIVE_GRADIENT_FLOWS, m.TIMESTEPS, noruleinit=True
505
    )
506
    block.negative_gradient_build = BuildAction(
507
        rule=_negative_gradient_flow_constraint
508
    )
509
510
511
def maximum_flow_constraint(block):
512
    r"""
513
    .. math::
514
        P(t) \leq max(i, o, t) \cdot P_{nom} \
515
            \cdot status(t), \\
516
        \forall t \in \textrm{TIMESTEPS}, \\
517
        \forall (i, o) \in \textrm{FIXED_CAPACITY_NONCONVEX_FLOWS}.
518
    """
519
    m = block.parent_block()
520
521
    def _maximum_flow_rule(_, i, o, t):
522
        """Rule definition for MILP maximum flow constraints."""
523
        expr = (
524
            block.status_nominal[i, o, t] * m.flows[i, o].max[t]
525
            >= m.flow[i, o, t]
526
        )
527
        return expr
528
529
    return Constraint(block.MIN_FLOWS, m.TIMESTEPS, rule=_maximum_flow_rule)
530
531
532
def minimum_flow_constraint(block):
533
    r"""
534
    .. math::
535
        P(t) \geq min(i, o, t) \cdot P_{nom} \
536
            \cdot Y_{status}(t), \\
537
        \forall (i, o) \in \textrm{FIXED_CAPACITY_NONCONVEX_FLOWS}, \\
538
        \forall t \in \textrm{TIMESTEPS}.
539
    """
540
    m = block.parent_block()
541
542
    def _minimum_flow_rule(_, i, o, t):
543
        """Rule definition for MILP minimum flow constraints."""
544
        expr = (
545
            block.status_nominal[i, o, t] * m.flows[i, o].min[t]
546
            <= m.flow[i, o, t]
547
        )
548
        return expr
549
550
    return Constraint(block.MIN_FLOWS, m.TIMESTEPS, rule=_minimum_flow_rule)
551
552
553
def startup_costs(block):
554
    r"""
555
    .. math::
556
        \sum_{i, o \in STARTUPFLOWS} \sum_t  Y_{startup}(t) \
557
        \cdot c_{startup}
558
    """
559
    startup_costs = 0
560
561
    if block.STARTUPFLOWS:
562
        m = block.parent_block()
563
564
        for i, o in block.STARTUPFLOWS:
565
            if valid_sequence(
566
                m.flows[i, o].nonconvex.startup_costs, len(m.TIMESTEPS)
567
            ):
568
                startup_costs += sum(
569
                    block.startup[i, o, t]
570
                    * m.flows[i, o].nonconvex.startup_costs[t]
571
                    for t in m.TIMESTEPS
572
                )
573
574
        block.startup_costs = Expression(expr=startup_costs)
575
576
    return startup_costs
577
578
579 View Code Duplication
def shutdown_costs(block):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
580
    r"""
581
    .. math::
582
        \sum_{SHUTDOWNFLOWS} \sum_t Y_{shutdown}(t) \
583
        \cdot c_{shutdown}
584
    """
585
    shutdown_costs = 0
586
587
    if block.SHUTDOWNFLOWS:
588
        m = block.parent_block()
589
590
        for i, o in block.SHUTDOWNFLOWS:
591
            if valid_sequence(
592
                m.flows[i, o].nonconvex.shutdown_costs,
593
                len(m.TIMESTEPS),
594
            ):
595
                shutdown_costs += sum(
596
                    block.shutdown[i, o, t]
597
                    * m.flows[i, o].nonconvex.shutdown_costs[t]
598
                    * m.tsam_weighting[t]
599
                    for t in m.TIMESTEPS
600
                )
601
602
        block.shutdown_costs = Expression(expr=shutdown_costs)
603
604
    return shutdown_costs
605
606
607 View Code Duplication
def activity_costs(block):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
608
    r"""
609
    .. math::
610
        \sum_{ACTIVITYCOSTFLOWS} \sum_t Y_{status}(t) \
611
        \cdot c_{activity}
612
    """
613
    activity_costs = 0
614
615
    if block.ACTIVITYCOSTFLOWS:
616
        m = block.parent_block()
617
618
        for i, o in block.ACTIVITYCOSTFLOWS:
619
            if valid_sequence(
620
                m.flows[i, o].nonconvex.activity_costs,
621
                len(m.TIMESTEPS),
622
            ):
623
                activity_costs += sum(
624
                    block.status[i, o, t]
625
                    * m.flows[i, o].nonconvex.activity_costs[t]
626
                    * m.tsam_weighting[t]
627
                    for t in m.TIMESTEPS
628
                )
629
630
        block.activity_costs = Expression(expr=activity_costs)
631
632
    return activity_costs
633
634
635 View Code Duplication
def inactivity_costs(block):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
636
    r"""
637
    .. math::
638
        \sum_{INACTIVITYCOSTFLOWS} \sum_t (1 - Y_{status}(t)) \
639
        \cdot c_{inactivity}
640
    """
641
    inactivity_costs = 0
642
643
    if block.INACTIVITYCOSTFLOWS:
644
        m = block.parent_block()
645
646
        for i, o in block.INACTIVITYCOSTFLOWS:
647
            if valid_sequence(
648
                m.flows[i, o].nonconvex.inactivity_costs,
649
                len(m.TIMESTEPS),
650
            ):
651
                inactivity_costs += sum(
652
                    (1 - block.status[i, o, t])
653
                    * m.flows[i, o].nonconvex.inactivity_costs[t]
654
                    * m.tsam_weighting[t]
655
                    for t in m.TIMESTEPS
656
                )
657
658
        block.inactivity_costs = Expression(expr=inactivity_costs)
659
660
    return inactivity_costs
661