Passed
Pull Request — dev (#1220)
by Patrik
01:39
created

solph.flows._shared._max_shutdown_constraint()   A

Complexity

Conditions 1

Size

Total Lines 15
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 15
rs 10
c 0
b 0
f 0
cc 1
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
388
    .. automethod:: _startup_constraint
389
    .. automethod:: _max_startup_constraint
390
    .. automethod:: _shutdown_constraint
391
    .. automethod:: _max_shutdown_constraint
392
    .. automethod:: _min_uptime_constraint
393
    .. automethod:: _min_downtime_constraint
394
395
    positive_gradient_constraint
396
        .. math::
397
398
            P(t) \cdot Y_{status}(t)
399
            - P(t-1) \cdot Y_{status}(t-1)  \leq \
400
            \dot{P}_{up}(t), \\
401
            \forall t \in \textrm{TIMESTEPS}.
402
403
    negative_gradient_constraint
404
        .. math::
405
            P(t-1) \cdot Y_{status}(t-1)
406
            - P(t) \cdot Y_{status}(t) \leq \
407
            \dot{P}_{down}(t), \\
408
            \forall t \in \textrm{TIMESTEPS}.
409
    """
410
    m = block.parent_block()
411
412
    block.startup_constr = _startup_constraint(block)
413
    block.max_startup_constr = _max_startup_constraint(block)
414
    block.shutdown_constr = _shutdown_constraint(block)
415
    block.max_shutdown_constr = _max_shutdown_constraint(block)
416
    block.min_uptime_constr = _min_uptime_constraint(block)
417
    block.min_downtime_constr = _min_downtime_constraint(block)
418
419
    def _positive_gradient_flow_constraint(_):
420
        r"""Rule definition for positive gradient constraint."""
421
        for i, o in block.POSITIVE_GRADIENT_FLOWS:
422
            for index in range(1, len(m.TIMEINDEX) + 1):
423
                if m.TIMEINDEX[index][1] > 0:
424
                    lhs = (
425
                        m.flow[
426
                            i,
427
                            o,
428
                            m.TIMESTEPS[index],
429
                        ]
430
                        * block.status[i, o, m.TIMESTEPS[index]]
431
                        - m.flow[i, o, m.TIMESTEPS[index - 1]]
432
                        * block.status[i, o, m.TIMESTEPS[index - 1]]
433
                    )
434
                    rhs = block.positive_gradient[i, o, m.TIMEINDEX[index][1]]
435
                    block.positive_gradient_constr.add(
436
                        (
437
                            i,
438
                            o,
439
                            m.TIMESTEPS[index],
440
                        ),
441
                        lhs <= rhs,
442
                    )
443
                else:
444
                    lhs = block.positive_gradient[i, o, 0]
445
                    rhs = 0
446
                    block.positive_gradient_constr.add(
447
                        (
448
                            i,
449
                            o,
450
                            m.TIMESTEPS[index],
451
                        ),
452
                        lhs == rhs,
453
                    )
454
455
    block.positive_gradient_constr = Constraint(
456
        block.POSITIVE_GRADIENT_FLOWS, m.TIMESTEPS, noruleinit=True
457
    )
458
    block.positive_gradient_build = BuildAction(
459
        rule=_positive_gradient_flow_constraint
460
    )
461
462
    def _negative_gradient_flow_constraint(_):
463
        r"""Rule definition for negative gradient constraint."""
464
        for i, o in block.NEGATIVE_GRADIENT_FLOWS:
465
            for index in range(1, len(m.TIMESTEPS) + 1):
466
                if m.TIMESTEPS[index] > 0:
467
                    lhs = (
468
                        m.flow[
469
                            i,
470
                            o,
471
                            m.TIMESTEPS[index - 1],
472
                        ]
473
                        * block.status[i, o, m.TIMESTEPS[index - 1]]
474
                        - m.flow[
475
                            i,
476
                            o,
477
                            m.TIMESTEPS[index],
478
                        ]
479
                        * block.status[i, o, m.TIMESTEPS[index]]
480
                    )
481
                    rhs = block.negative_gradient[i, o, m.TIMESTEPS[index]]
482
                    block.negative_gradient_constr.add(
483
                        (
484
                            i,
485
                            o,
486
                            m.TIMESTEPS[index],
487
                        ),
488
                        lhs <= rhs,
489
                    )
490
                else:
491
                    lhs = block.negative_gradient[i, o, 0]
492
                    rhs = 0
493
                    block.negative_gradient_constr.add(
494
                        (
495
                            i,
496
                            o,
497
                            m.TIMESTEPS[index],
498
                        ),
499
                        lhs == rhs,
500
                    )
501
502
    block.negative_gradient_constr = Constraint(
503
        block.NEGATIVE_GRADIENT_FLOWS, m.TIMESTEPS, noruleinit=True
504
    )
505
    block.negative_gradient_build = BuildAction(
506
        rule=_negative_gradient_flow_constraint
507
    )
508
509
510
def _maximum_flow_constraint(block):
511
    r"""
512
    .. math::
513
        P(t) \leq max(i, o, t) \cdot P_{nom} \
514
            \cdot status(t), \\
515
        \forall t \in \textrm{TIMESTEPS}, \\
516
        \forall (i, o) \in \textrm{FIXED_CAPACITY_NONCONVEX_FLOWS}.
517
    """
518
    m = block.parent_block()
519
520
    def _maximum_flow_rule(_, i, o, t):
521
        """Rule definition for MILP maximum flow constraints."""
522
        expr = (
523
            block.status_nominal[i, o, t] * m.flows[i, o].max[t]
524
            >= m.flow[i, o, t]
525
        )
526
        return expr
527
528
    return Constraint(block.MIN_FLOWS, m.TIMESTEPS, rule=_maximum_flow_rule)
529
530
531
def _minimum_flow_constraint(block):
532
    r"""
533
    .. math::
534
        P(t) \geq min(i, o, t) \cdot P_{nom} \
535
            \cdot Y_{status}(t), \\
536
        \forall (i, o) \in \textrm{FIXED_CAPACITY_NONCONVEX_FLOWS}, \\
537
        \forall t \in \textrm{TIMESTEPS}.
538
    """
539
    m = block.parent_block()
540
541
    def _minimum_flow_rule(_, i, o, t):
542
        """Rule definition for MILP minimum flow constraints."""
543
        expr = (
544
            block.status_nominal[i, o, t] * m.flows[i, o].min[t]
545
            <= m.flow[i, o, t]
546
        )
547
        return expr
548
549
    return Constraint(block.MIN_FLOWS, m.TIMESTEPS, rule=_minimum_flow_rule)
550
551
552
def _startup_costs(block):
553
    r"""
554
    .. math::
555
        \sum_{i, o \in STARTUPFLOWS} \sum_t  Y_{startup}(t) \
556
        \cdot c_{startup}
557
    """
558
    startup_costs = 0
559
560
    if block.STARTUPFLOWS:
561
        m = block.parent_block()
562
563
        for i, o in block.STARTUPFLOWS:
564
            if valid_sequence(
565
                m.flows[i, o].nonconvex.startup_costs, len(m.TIMESTEPS)
566
            ):
567
                startup_costs += sum(
568
                    block.startup[i, o, t]
569
                    * m.flows[i, o].nonconvex.startup_costs[t]
570
                    for t in m.TIMESTEPS
571
                )
572
573
        block.startup_costs = Expression(expr=startup_costs)
574
575
    return startup_costs
576
577
578
def _shutdown_costs(block):
579
    r"""
580
    .. math::
581
        \sum_{SHUTDOWNFLOWS} \sum_t Y_{shutdown}(t) \
582
        \cdot c_{shutdown}
583
    """
584
    shutdown_costs = 0
585
586
    if block.SHUTDOWNFLOWS:
587
        m = block.parent_block()
588
589
        for i, o in block.SHUTDOWNFLOWS:
590
            if valid_sequence(
591
                m.flows[i, o].nonconvex.shutdown_costs,
592
                len(m.TIMESTEPS),
593
            ):
594
                shutdown_costs += sum(
595
                    block.shutdown[i, o, t]
596
                    * m.flows[i, o].nonconvex.shutdown_costs[t]
597
                    * m.tsam_weighting[t]
598
                    for t in m.TIMESTEPS
599
                )
600
601
        block.shutdown_costs = Expression(expr=shutdown_costs)
602
603
    return shutdown_costs
604
605
606 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...
607
    r"""
608
    .. math::
609
        \sum_{ACTIVITYCOSTFLOWS} \sum_t Y_{status}(t) \
610
        \cdot c_{activity}
611
    """
612
    activity_costs = 0
613
614
    if block.ACTIVITYCOSTFLOWS:
615
        m = block.parent_block()
616
617
        for i, o in block.ACTIVITYCOSTFLOWS:
618
            if valid_sequence(
619
                m.flows[i, o].nonconvex.activity_costs,
620
                len(m.TIMESTEPS),
621
            ):
622
                activity_costs += sum(
623
                    block.status[i, o, t]
624
                    * m.flows[i, o].nonconvex.activity_costs[t]
625
                    * m.tsam_weighting[t]
626
                    for t in m.TIMESTEPS
627
                )
628
629
        block.activity_costs = Expression(expr=activity_costs)
630
631
    return activity_costs
632
633
634 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...
635
    r"""
636
    .. math::
637
        \sum_{INACTIVITYCOSTFLOWS} \sum_t (1 - Y_{status}(t)) \
638
        \cdot c_{inactivity}
639
    """
640
    inactivity_costs = 0
641
642
    if block.INACTIVITYCOSTFLOWS:
643
        m = block.parent_block()
644
645
        for i, o in block.INACTIVITYCOSTFLOWS:
646
            if valid_sequence(
647
                m.flows[i, o].nonconvex.inactivity_costs,
648
                len(m.TIMESTEPS),
649
            ):
650
                inactivity_costs += sum(
651
                    (1 - block.status[i, o, t])
652
                    * m.flows[i, o].nonconvex.inactivity_costs[t]
653
                    * m.tsam_weighting[t]
654
                    for t in m.TIMESTEPS
655
                )
656
657
        block.inactivity_costs = Expression(expr=inactivity_costs)
658
659
    return inactivity_costs
660