You didn’t post an error, but I’m guessing it’s something like:
ERROR: An object of name generation is already attached to this model.
If this is intended, consider using the anonymous construction syntax,
e.g., x = @variable(model, [1:N], ...) where the name of the object does
not appear inside the macro.
If so, this is a problem with using @expression. I ran into a similar issue that was fixed (and I would’ve expected to resolve this one too).
Nevertheless, removing the expression and modifying your stage 2 constraint like so
@constraint(model, supply_demand_balance[t = time],
sum(getproperty(profile, s)[t] * capacity[s] for s in sources) + imports[t] - curtailed[t] == demand)
seems to fix the problem in the short term.
Addressing your question about @uncertain inputs, what you did seems to be a fine solution to me.
Not that either of these are necessarily better, but for the sake of demonstration, I usually try to stick with the default Scenario unless I have some reason not to and take one of the following approaches:
- not as easy to read but usually easy to assemble via copy/paste
ξ₁ = Scenario(; (source => val for (source, val) in zip(sources, [[0.5, 0.5], [0.1, 0.1], [0.5, 0.5]]))..., probability = 1/3)
ξ₂ = Scenario(; (source => val for (source, val) in zip(sources, [[0.1, 0.1], [0.3, 0.3], [0.5, 0.5]]))..., probability = 1/3)
ξ₃ = Scenario(; (source => val for (source, val) in zip(sources, [[0.0, 0.0], [0.7, 0.7], [0.3, 0.3]]))..., probability = 1/3)
in this case you would have @uncertain profile[s in sources] and your constraint becomes
@constraint(model, supply_demand_balance[t = time],
sum(profile[s][t] * capacity[s] for s in sources) + imports[t] - curtailed[t] == demand)
This works pretty well when I’ve already got the data in a conducive format, but I haven’t ever tried to extend it to uncertainties with more than 2 dimensions
- Using the
@container_scenariomacro which seems to be provided for this very kind of thing.
s₁ = Dict((:solar, 1) => 0.5, (:wind_offshore, 1) => 0.1, (:wind_onshore, 1) => 0.5,
(:solar, 2) => 0.5, (:wind_offshore, 2) => 0.1, (:wind_onshore, 2) => 0.5)
s₂ = Dict((:solar, 1) => 0.1, (:wind_offshore, 1) => 0.3, (:wind_onshore, 1) => 0.5,
(:solar, 2) => 0.1, (:wind_offshore, 2) => 0.3, (:wind_onshore, 2) => 0.5)
s₃ = Dict((:solar, 1) => 0.0, (:wind_offshore, 1) => 0.7, (:wind_onshore, 1) => 0.3,
(:solar, 2) => 0.0, (:wind_offshore, 2) => 0.7, (:wind_onshore, 2) => 0.3)
ξ₁ = @container_scenario([s = sources, t = time], s₁[s,t], probability = 1/3)
ξ₂ = @container_scenario([s = sources, t = time], s₂[s,t], probability = 1/3)
ξ₃ = @container_scenario([s = sources, t = time], s₃[s,t], probability = 1/3)
in which case you would have @uncertain profile[s in sources, t in time] and the constraint is
@constraint(model, supply_demand_balance[t = time],
sum(profile[s, t] * capacity[s] for s in sources) + imports[t] - curtailed[t] == demand)
(Note the slightly different indexing profile[s][t] vs profile[s, t] between the two)