1e_inputs.gms 10.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ontext
This file is part of Backbone.

Backbone is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Backbone is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with Backbone.  If not, see <http://www.gnu.org/licenses/>.
$offtext

18
19
* Load updates made for BackBone
$gdxin  'input/inputData.gdx'
Juha Kiviluoma's avatar
Juha Kiviluoma committed
20
$loaddc grid
21
$loaddc node
Juha Kiviluoma's avatar
Juha Kiviluoma committed
22
$loaddc flow
23
$loaddc unittype
24
$loaddc unit
25
$loaddc unitUnittype
26
$loaddc fuel
27
$loaddc unitUnit_aggregate
Juha Kiviluoma's avatar
Juha Kiviluoma committed
28
29
$loaddc uFuel
$loaddc effLevelGroupUnit
30
31
32
$loaddc p_gn
$loaddc p_gnn
$loaddc p_gnu
Juha Kiviluoma's avatar
Juha Kiviluoma committed
33
$loaddc p_unit
34
$loaddc ts_unit
35
$loaddc p_nReserves
36
$loaddc p_nuReserves
37
$loaddc p_gnBoundaryPropertiesForStates
38
$loaddc p_gnPolicy
Juha Kiviluoma's avatar
Juha Kiviluoma committed
39
$loaddc p_uFuel
40
$loaddc flowUnit
Juha Kiviluoma's avatar
Juha Kiviluoma committed
41
42
$loaddc gngnu_fixedOutputRatio
$loaddc gngnu_constrainedOutputRatio
43
$loaddc emission
44
$loaddc p_fuelEmission
45
$loaddc ts_cf
46
$loaddc ts_fuelPriceChange
47
$loaddc ts_influx
48
$loaddc ts_nodeState
49
50
51
52
53
54
55
56
57
58
59
60
$gdxin

$ontext
 * Load stochastic scenarios
 $batinclude 'inc/gdxload_fluctuation.inc' wind
 $batinclude 'inc/gdxload_fluctuation.inc' solar
 $ifthen exist 'input/scenarios_hydro.gdx'
    $$gdxin 'input/scenarios_hydro.gdx'
 $endif
 $gdxin
$offtext

Topi Rasku's avatar
Topi Rasku committed
61
62
63
64
65
66
* Copy fuel time series data for all nodes
ts_fuelPriceChangenode(fuel, node, t) = ts_fuelPriceChange(fuel, t);

* Define unit aggregation sets
unit_aggregate(unit)$sum(unit_, unitUnit_aggregate(unit, unit_)) = yes; // Set of aggregate units
unit_noAggregate(unit)$(unit(unit) - unit_aggregate(unit) - sum(unit_, unitUnit_aggregate(unit_, unit))) = yes; // Set of units that are not aggregated into any aggregate, or are not aggregates themselves
67

Juha Kiviluoma's avatar
Juha Kiviluoma committed
68
* Process data for unit aggregations
Topi Rasku's avatar
Topi Rasku committed
69
70
p_gnu(grid, node, unit_aggregate(unit), 'maxGen') = sum(unit_$unitUnit_aggregate(unit, unit_), p_gnu(grid, node, unit_, 'maxGen')); // Aggregate maxGen as the sum of aggregated maxGen
p_gnu(grid, node, unit_aggregate(unit), 'maxCons') = sum(unit_$unitUnit_aggregate(unit, unit_), p_gnu(grid, node, unit_, 'maxCons')); // Aggregate maxCons as the sum of aggregated maxCons
71

Topi Rasku's avatar
Topi Rasku committed
72
* Generate unit related sets based on input data
Juha Kiviluoma's avatar
Juha Kiviluoma committed
73
74
75
gnu(grid, node, unit)$(p_gnu(grid, node, unit, 'maxGen') or p_gnu(grid, node, unit, 'maxCons')) = yes;
gnu_output(grid, node, unit)$p_gnu(grid, node, unit, 'maxGen') = yes;
gnu_input(grid, node, unit)$p_gnu(grid, node, unit, 'maxCons') = yes;
76
gn2gnu(grid_, node_input, grid, node, unit)$(gnu_input(grid_, node_input, unit) and gnu_output(grid, node, unit)) = yes;
77
nu(node, unit)$sum(grid, gnu(grid, node, unit)) = yes;
78
nuRescapable(restype, up_down, node, unit)$p_nuReserves(node, unit, restype, up_down) = yes;
79
unit_minload(unit)$[p_unit(unit, 'op00') > 0 and p_unit(unit, 'op00') < 1] = yes;   // If the first point is between 0 and 1, then the unit has a min load limit
Topi Rasku's avatar
Topi Rasku committed
80
81
82
unit_flow(unit)$sum(flow, flowUnit(flow, unit)) = yes;
unit_fuel(unit)$sum[ (fuel, node)$sum(t, ts_fuelPriceChangenode(fuel, node, t)), uFuel(unit, 'main', fuel) ] = yes;
unit_elec(unit)$sum(gnu(grid, node, unit), p_gnu('elec', node, unit, 'maxGen')) = yes;
83
unit_elec(unit)$sum(gnu(grid, node, unit), p_gnu('elec', node, unit, 'maxCons')) = yes;
Topi Rasku's avatar
Topi Rasku committed
84
85
86
87

* Assume values for critical unit related parameters, if not provided by input data
p_unit(unit, 'eff00')$(not p_unit(unit, 'eff00')) = 1; // If the unit does not have efficiency set, it is 1
p_unit(unit, 'unitCount')$(not p_unit(unit, 'unitCount')) = 1;  // In case number of units has not been defined it is 1.
88
p_unit(unit, 'outputCapacityTotal')$(not p_unit(unit, 'outputCapacityTotal')) = sum(gnu_output(grid, node, unit), p_gnu(grid, node, unit, 'maxGen'));  // By default add outputs in order to get the total capacity of the unit
Topi Rasku's avatar
Topi Rasku committed
89

90
91
92
* Generate node related sets based on input data // NOTE! These will need to change if p_gnn is required to work with only one row per link.
gn2n(grid, from_node, to_node)${p_gnn(grid, from_node, to_node, 'transferCap') OR p_gnn(grid, from_node, to_node, 'transferLoss')} = yes;
gn2n(grid, from_node, to_node)${p_gnn(grid, from_node, to_node, 'transferCapBidirectional') OR p_gnn(grid, to_node, from_node, 'transferCapBidirectional')} = yes;
93
94
gnn_boundState(grid, node, node_)$(p_gnn(grid, node, node_, 'boundStateOffset')) = yes;
gnn_state(grid, node, node_)$(p_gnn(grid, node, node_, 'diffCoeff') or gnn_boundState(grid, node, node_)) = yes;
95
96
97
gn_stateSlack(grid, node)$(sum((upwardSlack,   useConstantOrTimeSeries), p_gnBoundaryPropertiesForStates(grid, node,   upwardSlack, useConstantOrTimeSeries))) = yes;
gn_stateSlack(grid, node)$(sum((downwardSlack, useConstantOrTimeSeries), p_gnBoundaryPropertiesForStates(grid, node, downwardSlack, useConstantOrTimeSeries))) = yes;
gn_state(grid, node)$gn_stateSlack(grid, node) = yes;
98
gn_state(grid, node)$p_gn(grid, node, 'energyStoredPerUnitOfState') = yes;
99
gn_state(grid, node)$(sum((stateLimits, useConstantOrTimeSeries), p_gnBoundaryPropertiesForStates(grid, node, stateLimits, useConstantOrTimeSeries))) = yes;
100
gn_state(grid, node)$(sum(useConstantOrTimeSeries, p_gnBoundaryPropertiesForStates(grid, node, 'reference', useConstantOrTimeSeries))) = yes;
101
gn(grid, node)$(sum(unit, gnu(grid, node, unit) or gn_state(grid, node))) = yes;
Topi Rasku's avatar
Topi Rasku committed
102
103
node_spill(node)$(sum((grid, spillLimits, useConstantOrTimeSeries)$gn(grid, node), p_gnBoundaryPropertiesForStates(grid, node, spillLimits, useConstantOrTimeSeries))) = yes;

104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
* Generate the set of unique, symmetric transfer links
gn2n_bidirectional(grid, node, node_) = no;
gn2n_bidirectional(grid, node, node_)${p_gnn(grid, node, node_, 'transferCapBidirectional')} = yes;
loop(gn(grid, node),
    loop(gn2n(grid, node, node_)${gn2n(grid, node_,node)},
        gn2n_bidirectional(grid, node, node_)${not gn2n_bidirectional(grid, node_, node)} = yes;
    );
);
* Assume lacking parameters for bidirectional links, if input data found lacking.
loop(gn2n_bidirectional(grid, node, node_)${p_gnn(grid, node, node_, 'transferCapBidirectional')},
    // Replicate the bidirectional transfer capacity for the other direction as well for clarity, in case it's undefined. This affects the related data integrity check later.
    p_gnn(grid, node_, node, 'transferCapBidirectional')${not p_gnn(grid, node_, node, 'transferCapBidirectional')} = p_gnn(grid, node, node_, 'transferCapBidirectional');
    // Limit individual directional transfer capacities to the bidirectional capacity if not defined otherwise.
    p_gnn(grid, node, node_, 'transferCap')${not p_gnn(grid, node, node_, 'transferCap')} = p_gnn(grid, node, node_, 'transferCapBidirectional');
    p_gnn(grid, node_, node, 'transferCap')${not p_gnn(grid, node_, node, 'transferCap')} = p_gnn(grid, node, node_, 'transferCapBidirectional');
    // Fill in missing transfer losses
    // NOTE! One has to define 'transferCapBidirectional' for the direction with zero 'transferLoss', if asymmetric losses are desired.
    p_gnn(grid, node_, node, 'transferLoss')${not p_gnn(grid, node_, node, 'transferLoss')} = p_gnn(grid, node, node_, 'transferLoss');
);

Topi Rasku's avatar
Topi Rasku committed
124
* Assume values for critical node related parameters, if not provided by input data
125
p_gnBoundaryPropertiesForStates(gn(grid, node), param_gnBoundaryTypes, 'multiplier')$(not p_gnBoundaryPropertiesForStates(grid, node, param_gnBoundaryTypes, 'multiplier')) = 1; // If multiplier has not been set, set it to 1 by default
126
*p_gn(gn(grid, node), 'energyStoredPerUnitOfState')$(not p_gn(grid, node, 'energyStoredPerUnitOfState') and not p_gn(grid, node, 'boundAll')) = 1; // If unitConversion has not been set, default to 1; If the state is bound, there is no need for the term
127

128
* --- Perform various data checks, and abort if errors are detected -----------
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
* Check the integrity of node connection related data
count = 0;
loop(gn2n(grid, node, node_),
    count = count + 1; // Count the gn2n indeces to make finding the errors easier.
    // Check if the bidirectional transfer parameter exists for this link.
    if(p_gnn(grid, node, node_, 'transferCapBidirectional'),
        // Check for conflicting bidirectional transfer capacities.
        if(p_gnn(grid, node, node_, 'transferCapBidirectional') <> p_gnn(grid, node_, node, 'transferCapBidirectional'),
            put log '!!! Error occurred on gn2n link #' count;
            abort "Conflicting 'transferCapBidirectional' parameters!"
        );
        // Check for conflicting one-directional and bidirectional transfer capacities.
        if(p_gnn(grid, node, node_, 'transferCapBidirectional') < p_gnn(grid, node, node_, 'transferCap') OR (p_gnn(grid, node, node_, 'transferCapBidirectional') < p_gnn(grid, node_, node, 'transferCap')),
            put log '!!! Error occurred on gn2n link #' count;
            abort "Parameter 'transferCapBidirectional' must be greater than or equal to defined one-directional transfer capacities!"
        );
    );
);

148
* Check the integrity of efficiency approximation related data
149
tmp = 0; // Log the unit index for finding the error easier.
150
loop( unit,
151
    tmp = tmp + 1; // Increase the unit counter
152
153
154
155
156
    // Check that 'op' is defined correctly
    count = 0; // Initialize the previous op to zero
    loop( op,
        abort${p_unit(unit, op) + 1${not p_unit(unit, op)} < count} "param_unit 'op's must be defined as zero or positive and increasing!";
        count = p_unit(unit, op);
157
    );
158
159
    // Check that efficiency approximations have sufficient data
    loop( effLevelGroupUnit(effLevel, effSelector, unit),
160
161
162
163
164
165
166
        loop( op__${p_unit(unit, op__) = smax(op, p_unit(unit, op))}, // Loop over the 'op's to find the last defined data point.
            // Lambda  - Has been commented out, since it is ok to improve the efficiency curve by using extra lambda points.
            //loop( lambda${sameas(lambda, effSelector)}, // Loop over the lambdas to find the 'magnitude' of the approximation
                //display count_lambda, count_lambda2, unit.tl;
            //    if(ord(lambda) > ord(op__), put log '!!! Error occurred on unit ' unit.tl:25 ' with effLevel ' effLevel.tl:10 ' with effSelector ' lambda.tl:8); // Display unit that causes error
            //    abort${ord(lambda) > ord(op__)} "Order of the lambda approximation cannot exceed the number of efficiency data points!"
            // );
167
            // DirectOn
168
169
170
171
172
            loop( op_${p_unit(unit, op_) = smin(op${p_unit(unit, op)}, p_unit(unit, op))}, // Loop over the 'op's to find the first nonzero 'op' data point.
                if(effDirectOn(effSelector) AND ord(op__) = ord(op_) AND not p_unit(unit, 'section') AND not p_unit(unit, 'opFirstCross'),
                    put log '!!! Error occurred on unit #' tmp; // Display unit that causes error, NEEDS WORK
                    abort "directOn requires two efficiency data points with nonzero 'op' or 'section' or 'opFirstCross'!";
                );
173
174
175
            );
        );
    );
176
177
);