StochasticPrograms.jl - DIfficulties with vector @uncertain inputs

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:

  1. 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

  1. Using the @container_scenario macro 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)

2 Likes