Iterative models/ Dynamic sets

Dear All,

I am working on a power model that the output of the day 1 will be used as an input for the second day and it will continue for a month.
I tried to do this procedure for this goal. I defined a set: tt /1744/ and then defined adynamic set day1(tt) /124/. Day2(tt) /2548/…Day31(tt)/720744/
Alias (t,Day1(tt));
I have lots of parameters and variables depended on time (like: Loading for different days(t,x)) with many constraints.
After the model declaration and minimizing the objective for the first iteration(day). I would like to update some of my parameters and then use the “day2” for all the parameters. Something like this

solve model using MIP minimizing obj1; //for the first day//

then: Alias (t, Day2(tt)); // I already know I cant redefine a set but I do not have any clue how I should solve this issue//
Update some of the parameters

solve model using MIP minimizing obj1; //for the second day//

  • and same steps till the 31 days.



    Best,
    Leon

Hi Leon

Instead of having everything based on the hours, you make them depending on hours (124) and days (131).
You then loop over the days:

loop(day,
     assing parameter values from tables
     solve mymodel
     assign solution to other parameters
     )

e.g.
A parameter is also defined over days and hours

  table capacity(day,hours)
     1 2 3 4 5 ... 24
  1
...
31

Hope this helps
Renger

Thank you Renger. It solved my problem.
Before I post my question, I checked the GAMS world for any similar question and I saw your response to other people as well.
That is really kind of you.
Thank you again.

Hi all,

I have a similar problem. I want to solve a model interatively. In my model I have two sets: t (for time) and households. Most of my parameters depend on both sets(t,households) and some only on (households) like:

...
demand_electrical(t, household)
$LOAD  demand_electrical

volumeOfBufferTank (household)
$LOAD volumeOfBufferTank
...

I have several equations and variables that depend on both sets (t,households) but there are also some equations that only depend on (t).

My aim is to solve the model for each member of the set household with a loop statement. I have 2 questions regarding this:

  1. Do I have to change the index of the parameters, variables and equations? And if so how shall I do this considering that not all parameters depend on the same sets.
  2. Ho can I update the data in the loop statement? At the official GAMS docu the following example is used (https://www.gams.com/latest/docs/UG_FlowControl.html):
loop (i,
  problemdata = g(i);
  solve mymodel using lp maximizing profit;
  d(i) = profit.l;
);

What I do not understand is how to do the data update: problemdata = g(i).?

Peter,

You could introduce a dynamic subset of household and use that in the definition (not declaration!) of equations.

set h(household) 'dynamic subset of household';
[...]
variable x(t,household);
[...]
equation e(household);
[...]
e(h).. sum(t,x(t,h)) + ... =g= ...;

Now if you set h(household) = yes; the entire set household will be contained in subset h and you solve the entire model as you probably did before. To solve slices of the model for every household independently in a loop you could do:

h(household) = no;
loop(household,
  h(household) = yes;
  solve mymodel ...
  h(household) = no;
);

I hope this helps!

Fred

Thanks a lot Fred for your answer and help. I really appreciate the tremendous help in this forum :slight_smile:

it help me solve the problem. Now I want to not only run the model for every household for the entire optimization horizon (all t) but I want for every 288 timeslots to run run the optimization for every household for a horizon of 288 timeslots.

My questions are:

  1. In conventional programming you would use a nested loop for that. Is that also possible in GAMS?
  2. How can I tell GAMS to repeatedly optimize for 288 timeslots for every household? If I just use the conventional loop with a t index, then I will solve the model for every timeslot.

Peter,

Yes, you can use nested loops to implement that.
The following example creates a set of time slices and maps the slices to the original timeslots (not sure how many you have in total). Then you can basically use the same logic with dynamic subsets for the timeslots in your equations as illustrated before with the set households.

set tt 'super set of time steps' /t1*t8760/;
$eval tSlices ceil(card(tt)/288)
set tSlice          / ts1*ts%tSlices% /
    t(tt)           'dynamic subset of tt'
    map(tSlice,tt)  'mapping of time slice to time steps'
;
map(tSlice,tt) = (ord(tSlice)-1)*288 < ord(tt) and (ord(tSlice))*288 >= ord(tt);
option map:0:0:1; display map;

loop(tSlice,
  t(tt) = map(tSlice,tt); display t;
  loop(household,
    h(household) = yes;
    solve mymodel ...
    h(household) = no;
  );  
);

I hope this helps!

Fred

Thanks Fred for your answer,

I first of all wanted to try the mapping of the timeslots (without having the nested loop). However I have to admit that I don’t the code you posted so I just copied and pasted it in my model (I merely adjusted the number of time slots). The beginning of my model looks like this:

Set
    t timeslices
    household households;

$call gdxxrw data_5min_Jan_DayAhead_1HH.xlsx index=index!A1
$ife errorlevel<>0 $abort Problems running GDXXRW

$GDXIN 'data_5min_Jan_DayAhead_1HH.gdx';
$LOAD t
$LOAD household




set tt 'super set of time steps' /t1*t8928/;
$eval tSlices ceil(card(tt)/288)
set tSlice          / ts1*ts%tSlices% /
    t(tt)           'dynamic subset of tt'
    map(tSlice,tt)  'mapping of time slice to time steps'
;
map(tSlice,tt) = (ord(tSlice)-1)*288 < ord(tt) and (ord(tSlice))*288 >= ord(tt);
option map:0:0:1; display map;

Unfortunately it does not work and I get the following error message: " Domain list redefined - no previous domain list - * assumed when data was associated with this symbol" and the line “t(tt) ‘dynamic subset of tt’ " is marked. Then I tried to comment out the lines " t timeslices” and “$LOAD t” at the beginning (which were part of my inicial code and not part of the code you posted). After that I received many error messages stating that a set could not be found.

Peter,

Just pasting code that you don’t understand is probably not a good idea. In order to provide target-oriented help, it would be good to know what part of the code you do not understand.

I assumed that you have set of all timeslots. In my example this was tt. I dont know how many timeslots you actually have in total, so I just made up some number for my example (8760=hours per year).
My understanding was that you want to slice your entire time horizon into smaller parts of 288 timeslots each. With the 8928 time slots you have this would result in 31 such smaller parts or slices.

The following line computes this number 31 and stores it in a compile time variable:

$eval tSlices ceil(card(tt)/288)

You might want to consult the documentation if you are struggling with this part of the code:
https://www.gams.com/latest/docs/UG_GamsCall.html#UG_GamsCall_DoubleDashParametersEtc_CompileTimeVars
https://www.gams.com/latest/docs/UG_DollarControlOptions.html#DOLLAReval

Then a corresponding set for the time slices is declared:

set tSlice          / ts1*ts%tSlices% /

;

Apparently, you need to know which time slots are contained in which time slice. Therefore, a corresponding mapping is introduced and calculated.

set t(tt)           'dynamic subset of tt'
    map(tSlice,tt)  'mapping of time slice to time steps'
;
map(tSlice,tt) = (ord(tSlice)-1)*288 < ord(tt) and (ord(tSlice))*288 >= ord(tt);

That’s basically it.

You get an error because you already have a set t which you also load from data_5min_Jan_DayAhead_1HH.gdx. Not sure what is in this set. If this is your superset with all the time slots, you should adjust the set names accordingly. I guess you can figure that out yourself.

Best,
Fred

Thanks Fred for your answer,

there are still a few things that I do not understand.

$eval tSlices ceil(card(tt)/288)

why do we need a Compile-Time Variable here? You anyways specify the number of total timeslots. So the number of time slices can be computed based on this.

map(tSlice,tt) = (ord(tSlice)-1)*288 < ord(tt) and (ord(tSlice))*288 >= ord(tt);

I could not find a good description of the mapping operator. What is done in the statement “(ord(tSlice)-1)*288 < ord(tt) and (ord(tSlice))*288 >= ord(tt)”?


option map:0:0:1; display map;

The same question here. What does 0:0:1 mean?


Regarding my code I changed the name of the variable that I used before from t to t_a. This set (and all other parameters) are loaded from the file “data_5min_Jan_DayAhead_1HH.gdx.”

Set
    t_a timeslices
    household households;

$call gdxxrw data_5min_Jan_DayAhead_1HH.xlsx index=index!A1
$ife errorlevel<>0 $abort Problems running GDXXRW

$GDXIN 'data_5min_Jan_DayAhead_1HH.gdx';
$LOAD t_a
$LOAD household




set tt 'super set of time steps' /t1*t8928/;
$eval tSlices ceil(card(tt)/288)
set tSlice          / ts1*ts%tSlices% /
    t(tt)           'dynamic subset of tt'
    map(tSlice,tt)  'mapping of time slice to time steps'
;
map(tSlice,tt) = (ord(tSlice)-1)*288 < ord(tt) and (ord(tSlice))*288 >= ord(tt);
option map:0:0:1; display map;
....

I also load other parameters from that file and define variables.

...
Parameter


demand_heating(t, household)
$LOAD  demand_heating

demand_electrical(t, household)
$LOAD  demand_electrical

...

temperature_level_DHWTank.lo(t, household) = minimalDHWTankTemperature;
temperature_level_DHWTank.up(t, household) = maximalDHWTankTemperature;
...

If I run the model I get many error messages stating “Values for domain 1 are unknown - no checking possible” and “Set has not been initialized”.
My questin is whether I have to adjust the arguments for all those variables and parameters? For example shall I change “demand_electrical(t, household)” to “demand_electrical(tt, household)” or something like that?

Peter,

If you don’t share your model please don’t expect others to write code for you that works with your model out of the box!
Please find further comments below.

Actually what this line does is exactly that. It computes the number of time slices based on the number of total timeslots.
You could also enter this number manually and define

set tSlice          / ts1*ts31 /;



There is no mapping operator. map(tSlice,tt) is just a two dimensional set that maps time slots to time slices if the right hand side evaluates to true.
You could rewrite this as:

map(tSlice,tt)$[(ord(tSlice)-1)*288 < ord(tt) and (ord(tSlice))*288 >= ord(tt)] = yes;

Maybe that’s easier to understand. I guess you know about the ord operator. If not, please consult the documentation (https://www.gams.com/latest/docs/UG_OrderedSets.html#UG_OrderedSets_TheOrdOperator).

This just changes the formatting of the display statement in a way that I sometimes like better than the default (https://www.gams.com/latest/docs/UG_DisplayStatement.html#UG_DisplayStatement_LocalDisplayControl).

What is in the set you now define as t_a? Isn’t that the superset of timeslots? And if so, why does the explanatory text say ‘time slices’? In any case, you are defining super set tt of time slots and another set for time slices later again. That does not make sense to me. You need to understand the example first and then transfer it to your code and get the names consistent. Of course you get tons of errors if you declare parameters that are indexed with sets you did not (yet) declare.
As I said at the very beginning, if you don’t share your code or at least an executable example, it makes helping you difficult!

Fred