From e4d4ee1cc877c08948f54015126bfbf8f202b620 Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Tue, 16 Sep 2025 11:53:32 -0500 Subject: [PATCH] Implement global disposal limits --- docs/src/format.md | 17 ++++--- docs/src/problem.md | 50 +++++++++++-------- src/instance/parse.jl | 12 +++-- src/instance/structs.jl | 1 + src/model/build.jl | 12 +++++ test/fixtures/boat_example.jl | 1 + test/fixtures/boat_example.json | 12 +++-- test/fixtures/boat_example/center_outputs.csv | 18 +++---- test/fixtures/boat_example/centers.csv | 6 +-- test/fixtures/boat_example/plant_outputs.csv | 4 +- test/fixtures/boat_example/plants.csv | 50 +++++++++---------- test/fixtures/simple.json | 12 +++-- test/src/instance/parse_test.jl | 1 + test/src/model/build_test.jl | 9 ++++ 14 files changed, 126 insertions(+), 79 deletions(-) diff --git a/docs/src/format.md b/docs/src/format.md index ad39ac9..a7cb518 100644 --- a/docs/src/format.md +++ b/docs/src/format.md @@ -1,6 +1,7 @@ # Input data format -RELOG accepts as input a JSON file with four sections: `parameters`, `products`, `centers` and `plants`. Below, we describe each section in more detail. +RELOG accepts as input a JSON file with four sections: `parameters`, `products`, +`centers` and `plants`. Below, we describe each section in more detail. ## Parameters @@ -24,11 +25,12 @@ RELOG accepts as input a JSON file with four sections: `parameters`, `products`, ## Products -| Key | Description | -| :------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transportation cost ($/km/tonne)` | The cost to transport this product. Must be a time series. | -| `transportation energy (J/km/tonne)` | The energy required to transport this product. Must be a time series. Optional. | -| `transportation emissions (tonne/km/tonne)` | A dictionary mapping the name of each greenhouse gas, produced to transport one tonne of this product along one kilometer, to the amount of gas produced (in tonnes). Must be a time series. Optional. | +| Key | Description | +| :------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `transportation cost ($/km/tonne)` | The cost to transport this product. Must be a time series. | +| `transportation energy (J/km/tonne)` | The energy required to transport this product. Must be a time series. Optional. | +| `transportation emissions (tonne/km/tonne)` | A dictionary mapping the name of each greenhouse gas, produced to transport one tonne of this product along one kilometer, to the amount of gas produced (in tonnes). Must be a time series. Optional. | +| `disposal limit (tonne)` | Global disposal limit for this product, per year, across all plants and centers. Entry may be `null` if unlimited. Note that individual plants and centers may also have their individual disposal limits for this product. | #### Example @@ -41,7 +43,8 @@ RELOG accepts as input a JSON file with four sections: `parameters`, `products`, "transportation emissions (tonne/km/tonne)": { "CO2": 0.052, "CH4": 0.003 - } + }, + "disposal limit (tonne)": 100.0, } } } diff --git a/docs/src/problem.md b/docs/src/problem.md index 0e932ec..5922ceb 100644 --- a/docs/src/problem.md +++ b/docs/src/problem.md @@ -5,8 +5,8 @@ The mathematical model employed by RELOG is based on three main components: 1. **Products and Materials:** Inputs and outputs for both manufacturing and - recycling plants. This include raw materials, whether virgin or recovered, and - final products, whether new or at their end-of-life. Each product has + recycling plants. This include raw materials, whether virgin or recovered, + and final products, whether new or at their end-of-life. Each product has associated transportation parameters, such as costs, energy and emissions. 2. **Manufacturing and Recycling Plants:** Facilities that take in specific @@ -48,23 +48,24 @@ The mathematical model employed by RELOG is based on three main components: ## Constants -| Symbol | Description | Unit | -| :-------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------ | -| $K^{\text{dist}}_{uv}$ | Distance between plants/centers $u$ and $v$ | km | -| $K^\text{cap}_{p}$ | Capacity of plant $p$, if the plant is open | tonne | -| $K^\text{disp-limit}_{pmt}$ | Maximum amount of material $m$ that can be disposed of at plant $p$ at time $t$ | tonne | -| $K^\text{mix}_{pmt}$ | If plant $p$ receives one tonne of input material at time $t$, then $K^\text{mix}_{pmt}$ is the amount of product $m$ in this mix. Must be between zero and one, and the sum of these amounts must equal to one. | tonne | -| $K^\text{output}_{pmt}$ | Amount of material $m$ produced by plant $p$ at time $t$ for each tonne of input material processed | tonne | -| $R^\text{tr}_{mt}$ | Cost to send material $m$ at time $t$ | \$/km-tonne | -| $R^\text{collect}_{cmt}$ | Cost of collecting material $m$ at center $c$ at time $t$ | \$/tonne | -| $R^\text{disp}_{umt}$ | Cost to dispose of material at plant/center $u$ at time $t$ | \$/tonne | -| $R^\text{fix}_{ut}$ | Fixed operating cost for plant/center $u$ at time $t$ | \$ | -| $R^\text{open}_{pt}$ | Cost to open plant $p$ at time $t$ | \$ | -| $R^\text{rev}_{ct}$ | Revenue for selling the input product of center $c$ at this center at time $t$ | \$/tonne | -| $R^\text{var}_{pt}$ | Cost to process one tonne of input material at plant $p$ at time $t$ | \$/tonne | -| $K^\text{out-fix}_{cmt}$ | Fixed amount of material $m$ collected at center $m$ at time $t$ | \$/tonne | -| $K^\text{out-var}_{c,m,i}$ | Factor used to calculate variable amount of material $m$ collected at center $m$. See `eq_z_collected` for more details. | -- | -| $K^\text{out-var-len}_{cm}$ | Length of the $K^\text{out-var}_{c,m,*}$ vector. | -- | +| Symbol | Description | Unit | +| :-------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------- | +| $K^{\text{dist}}_{uv}$ | Distance between plants/centers $u$ and $v$ | km | +| $K^\text{cap}_{p}$ | Capacity of plant $p$, if the plant is open | tonne | +| $K^\text{disp-limit}_{mt}$ | Maximum amount of material $m$ that can be disposed of (globally) at time $t$ | tonne | +| $K^\text{disp-limit}_{mut}$ | Maximum amount of material $m$ that can be disposed of at plant/center $u$ at time $t$ | tonne | +| $K^\text{mix}_{pmt}$ | If plant $p$ receives one tonne of input material at time $t$, then $K^\text{mix}_{pmt}$ is the amount of product $m$ in this mix. Must be between zero and one, and the sum of these amounts must equal to one. | tonne | +| $K^\text{output}_{pmt}$ | Amount of material $m$ produced by plant $p$ at time $t$ for each tonne of input material processed | tonne | +| $R^\text{tr}_{mt}$ | Cost to send material $m$ at time $t$ | \$/km-tonne | +| $R^\text{collect}_{cmt}$ | Cost of collecting material $m$ at center $c$ at time $t$ | \$/tonne | +| $R^\text{disp}_{umt}$ | Cost to dispose of material at plant/center $u$ at time $t$ | \$/tonne | +| $R^\text{fix}_{ut}$ | Fixed operating cost for plant/center $u$ at time $t$ | \$ | +| $R^\text{open}_{pt}$ | Cost to open plant $p$ at time $t$ | \$ | +| $R^\text{rev}_{ct}$ | Revenue for selling the input product of center $c$ at this center at time $t$ | \$/tonne | +| $R^\text{var}_{pt}$ | Cost to process one tonne of input material at plant $p$ at time $t$ | \$/tonne | +| $K^\text{out-fix}_{cmt}$ | Fixed amount of material $m$ collected at center $m$ at time $t$ | \$/tonne | +| $K^\text{out-var}_{c,m,i}$ | Factor used to calculate variable amount of material $m$ collected at center $m$. See `eq_z_collected` for more details. | -- | +| $K^\text{out-var-len}_{cm}$ | Length of the $K^\text{out-var}_{c,m,*}$ vector. | -- | ## Decision variables @@ -196,7 +197,7 @@ The goals is to minimize a linear objective function with the following terms: \end{align*} ``` -- Disposal limit at the plants (`eq_keep_open[p.name, t]`): +- Disposal limit at the plants (`eq_disposal_limit[p.name, m.name, t]`): ```math \begin{align*} @@ -255,3 +256,12 @@ The goals is to minimize a linear objective function with the following terms: & \forall c \in C, m \in M^+_c, t \in T \end{align*} ``` + +- Global disposal limit (`eq_disposal_limit[m.name, t]`) + +```math +\begin{align*} +& \sum_{p \in P} z^\text{disp}_{pmt} + \sum_{c \in C} z^\text{disp}_{cmt} \leq K^\text{disp-limit}_{mt} +& \forall m \in M, t \in T +\end{align*} +``` \ No newline at end of file diff --git a/src/instance/parse.jl b/src/instance/parse.jl index 1036229..a225bc8 100644 --- a/src/instance/parse.jl +++ b/src/instance/parse.jl @@ -20,9 +20,10 @@ function parse(json)::Instance error("Invalid distance metric: $distance_metric_str") end - timeseries(x::Union{Nothing,Number}) = repeat([x], time_horizon) - timeseries(x::Array) = x - timeseries(d::OrderedDict) = OrderedDict(k => timeseries(v) for (k, v) in d) + timeseries(::Nothing; null_val=nothing) = repeat([null_val], time_horizon) + timeseries(x::Number; null_val=nothing) = repeat([x], time_horizon) + timeseries(x::Array; null_val=nothing) = [xi === nothing ? null_val : xi for xi in x] + timeseries(d::OrderedDict; null_val=nothing) = OrderedDict(k => timeseries(v; null_val) for (k, v) in d) # Read products products = Product[] @@ -31,7 +32,8 @@ function parse(json)::Instance tr_cost = timeseries(pdict["transportation cost (\$/km/tonne)"]) tr_energy = timeseries(pdict["transportation energy (J/km/tonne)"]) tr_emissions = timeseries(pdict["transportation emissions (tonne/km/tonne)"]) - prod = Product(; name, tr_cost, tr_energy, tr_emissions) + disposal_limit = timeseries(pdict["disposal limit (tonne)"], null_val=Inf) + prod = Product(; name, tr_cost, tr_energy, tr_emissions, disposal_limit) push!(products, prod) products_by_name[name] = prod end @@ -51,7 +53,7 @@ function parse(json)::Instance outputs = [products_by_name[p] for p in cdict["outputs"]] operating_cost = timeseries(cdict["operating cost (\$)"]) prod_dict(key, null_val) = OrderedDict( - p => [v === nothing ? null_val : v for v in timeseries(cdict[key][p.name])] + p => timeseries(cdict[key][p.name]; null_val) for p in outputs ) fixed_output = prod_dict("fixed output (tonne)", 0.0) diff --git a/src/instance/structs.jl b/src/instance/structs.jl index ed276cf..4982c94 100644 --- a/src/instance/structs.jl +++ b/src/instance/structs.jl @@ -14,6 +14,7 @@ Base.@kwdef struct Product tr_cost::Vector{Float64} tr_energy::Vector{Float64} tr_emissions::OrderedDict{String,Vector{Float64}} + disposal_limit::Vector{Float64} end Base.@kwdef struct Center diff --git a/src/model/build.jl b/src/model/build.jl index 156d288..4238bb5 100644 --- a/src/model/build.jl +++ b/src/model/build.jl @@ -298,6 +298,18 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false @constraint(model, z_disp[c.name, m.name, t] <= c.disposal_limit[m][t]) end + # Global disposal limit + eq_disposal_limit = _init(model, :eq_disposal_limit) + for m in products, t in T + isfinite(m.disposal_limit[t]) || continue + eq_disposal_limit[m.name, t] = @constraint( + model, + sum(z_disp[p.name, m.name, t] for p in plants if m in keys(p.output)) + + sum(z_disp[c.name, m.name, t] for c in centers if m in c.outputs) <= + m.disposal_limit[t] + ) + end + if variable_names _set_names!(model) end diff --git a/test/fixtures/boat_example.jl b/test/fixtures/boat_example.jl index 1b01b2e..897f631 100644 --- a/test/fixtures/boat_example.jl +++ b/test/fixtures/boat_example.jl @@ -69,6 +69,7 @@ function run_boat_example() "transportation cost (\$/km/tonne)" => 0.30, "transportation energy (J/km/tonne)" => 7_500, "transportation emissions (tonne/km/tonne)" => dict("CO2" => 2.68), + "disposal limit (tonne)" => nothing, ) boat_factory = dict( diff --git a/test/fixtures/boat_example.json b/test/fixtures/boat_example.json index ecadb79..3419a60 100644 --- a/test/fixtures/boat_example.json +++ b/test/fixtures/boat_example.json @@ -12,28 +12,32 @@ "transportation energy (J/km/tonne)": 7500, "transportation emissions (tonne/km/tonne)": { "CO2": 2.68 - } + }, + "disposal limit (tonne)": null }, "Wood": { "transportation cost ($/km/tonne)": 0.3, "transportation energy (J/km/tonne)": 7500, "transportation emissions (tonne/km/tonne)": { "CO2": 2.68 - } + }, + "disposal limit (tonne)": null }, "NewBoat": { "transportation cost ($/km/tonne)": 0.3, "transportation energy (J/km/tonne)": 7500, "transportation emissions (tonne/km/tonne)": { "CO2": 2.68 - } + }, + "disposal limit (tonne)": null }, "UsedBoat": { "transportation cost ($/km/tonne)": 0.3, "transportation energy (J/km/tonne)": 7500, "transportation emissions (tonne/km/tonne)": { "CO2": 2.68 - } + }, + "disposal limit (tonne)": null } }, "centers": { diff --git a/test/fixtures/boat_example/center_outputs.csv b/test/fixtures/boat_example/center_outputs.csv index 2160955..7a50a3a 100644 --- a/test/fixtures/boat_example/center_outputs.csv +++ b/test/fixtures/boat_example/center_outputs.csv @@ -1,7 +1,7 @@ center,output product,year,amount collected (tonne),amount disposed (tonne),collection cost ($),disposal cost ($) NailFactory (Chicago),Nail,1,1.0,0.0,1000.0,0.0 NailFactory (Chicago),Nail,2,1.0,0.0,1000.0,0.0 -NailFactory (Chicago),Nail,3,1.0,-0.0,1000.0,-0.0 +NailFactory (Chicago),Nail,3,1.0,0.0,1000.0,0.0 NailFactory (Chicago),Nail,4,1.0,0.0,1000.0,0.0 NailFactory (Chicago),Nail,5,1.0,0.0,1000.0,0.0 NailFactory (Phoenix),Nail,1,1.0,0.0,1000.0,0.0 @@ -9,11 +9,11 @@ NailFactory (Phoenix),Nail,2,1.0,0.0,1000.0,0.0 NailFactory (Phoenix),Nail,3,1.0,0.0,1000.0,0.0 NailFactory (Phoenix),Nail,4,1.0,0.0,1000.0,0.0 NailFactory (Phoenix),Nail,5,1.0,0.0,1000.0,0.0 -NailFactory (Dallas),Nail,1,1.0,-0.0,1000.0,-0.0 +NailFactory (Dallas),Nail,1,1.0,0.0,1000.0,0.0 NailFactory (Dallas),Nail,2,1.0,-0.0,1000.0,-0.0 -NailFactory (Dallas),Nail,3,1.0,-0.0,1000.0,-0.0 -NailFactory (Dallas),Nail,4,1.0,0.0,1000.0,0.0 -NailFactory (Dallas),Nail,5,1.0,0.0,1000.0,0.0 +NailFactory (Dallas),Nail,3,1.0,0.0,1000.0,0.0 +NailFactory (Dallas),Nail,4,1.0,-0.0,1000.0,-0.0 +NailFactory (Dallas),Nail,5,1.0,-0.0,1000.0,-0.0 Forest (Chicago),Wood,1,100.0,100.0,0.0,0.0 Forest (Chicago),Wood,2,100.0,100.0,0.0,0.0 Forest (Chicago),Wood,3,100.0,100.0,0.0,0.0 @@ -43,17 +43,17 @@ Retail (Los Angeles),UsedBoat,1,0.0,0.0,0.0,0.0 Retail (Los Angeles),UsedBoat,2,0.0,0.0,0.0,0.0 Retail (Los Angeles),UsedBoat,3,0.0,0.0,0.0,0.0 Retail (Los Angeles),UsedBoat,4,0.0,0.0,0.0,0.0 -Retail (Los Angeles),UsedBoat,5,0.0,0.0,0.0,0.0 +Retail (Los Angeles),UsedBoat,5,-0.0,0.0,-0.0,0.0 Retail (Houston),UsedBoat,1,0.0,0.0,0.0,0.0 Retail (Houston),UsedBoat,2,0.0,0.0,0.0,0.0 Retail (Houston),UsedBoat,3,0.0,0.0,0.0,0.0 Retail (Houston),UsedBoat,4,0.0,0.0,0.0,0.0 -Retail (Houston),UsedBoat,5,0.0,0.0,0.0,0.0 +Retail (Houston),UsedBoat,5,-0.0,0.0,-0.0,0.0 Retail (Phoenix),UsedBoat,1,0.0,0.0,0.0,0.0 Retail (Phoenix),UsedBoat,2,0.0,0.0,0.0,0.0 Retail (Phoenix),UsedBoat,3,0.0,0.0,0.0,0.0 -Retail (Phoenix),UsedBoat,4,0.0,0.0,0.0,0.0 -Retail (Phoenix),UsedBoat,5,0.0,0.0,0.0,0.0 +Retail (Phoenix),UsedBoat,4,-0.0,0.0,-0.0,0.0 +Retail (Phoenix),UsedBoat,5,-0.0,0.0,-0.0,0.0 Retail (Philadelphia),UsedBoat,1,0.0,0.0,0.0,0.0 Retail (Philadelphia),UsedBoat,2,0.0,0.0,0.0,0.0 Retail (Philadelphia),UsedBoat,3,0.0,0.0,0.0,0.0 diff --git a/test/fixtures/boat_example/centers.csv b/test/fixtures/boat_example/centers.csv index b27c492..51fd605 100644 --- a/test/fixtures/boat_example/centers.csv +++ b/test/fixtures/boat_example/centers.csv @@ -43,16 +43,16 @@ Retail (Los Angeles),1,NewBoat,0.0,0.0,125000.0 Retail (Los Angeles),2,NewBoat,0.0,0.0,125000.0 Retail (Los Angeles),3,NewBoat,0.0,0.0,125000.0 Retail (Los Angeles),4,NewBoat,0.0,0.0,125000.0 -Retail (Los Angeles),5,NewBoat,0.0,0.0,125000.0 +Retail (Los Angeles),5,NewBoat,-0.0,0.0,125000.0 Retail (Houston),1,NewBoat,0.0,0.0,125000.0 Retail (Houston),2,NewBoat,0.0,0.0,125000.0 Retail (Houston),3,NewBoat,0.0,0.0,125000.0 Retail (Houston),4,NewBoat,0.0,0.0,125000.0 -Retail (Houston),5,NewBoat,0.0,0.0,125000.0 +Retail (Houston),5,NewBoat,-0.0,0.0,125000.0 Retail (Phoenix),1,NewBoat,0.0,0.0,125000.0 Retail (Phoenix),2,NewBoat,0.0,0.0,125000.0 Retail (Phoenix),3,NewBoat,0.0,0.0,125000.0 -Retail (Phoenix),4,NewBoat,0.0,0.0,125000.0 +Retail (Phoenix),4,NewBoat,-0.0,-0.0,125000.0 Retail (Phoenix),5,NewBoat,0.0,0.0,125000.0 Retail (Philadelphia),1,NewBoat,0.0,0.0,125000.0 Retail (Philadelphia),2,NewBoat,0.0,0.0,125000.0 diff --git a/test/fixtures/boat_example/plant_outputs.csv b/test/fixtures/boat_example/plant_outputs.csv index 643b13c..428cf1a 100644 --- a/test/fixtures/boat_example/plant_outputs.csv +++ b/test/fixtures/boat_example/plant_outputs.csv @@ -50,12 +50,12 @@ BoatFactory (San Jose),NewBoat,3,0.0,0.0,0.0 BoatFactory (San Jose),NewBoat,4,0.0,0.0,0.0 BoatFactory (San Jose),NewBoat,5,0.0,0.0,0.0 RecyclingPlant (Chicago),Nail,1,0.0,0.0,0.0 -RecyclingPlant (Chicago),Nail,2,0.0,0.0,0.0 +RecyclingPlant (Chicago),Nail,2,-0.0,0.0,0.0 RecyclingPlant (Chicago),Nail,3,0.0,0.0,0.0 RecyclingPlant (Chicago),Nail,4,0.0,0.0,0.0 RecyclingPlant (Chicago),Nail,5,0.0,0.0,0.0 RecyclingPlant (Chicago),Wood,1,0.0,0.0,0.0 -RecyclingPlant (Chicago),Wood,2,0.0,0.0,0.0 +RecyclingPlant (Chicago),Wood,2,-0.0,0.0,0.0 RecyclingPlant (Chicago),Wood,3,0.0,0.0,0.0 RecyclingPlant (Chicago),Wood,4,0.0,0.0,0.0 RecyclingPlant (Chicago),Wood,5,0.0,0.0,0.0 diff --git a/test/fixtures/boat_example/plants.csv b/test/fixtures/boat_example/plants.csv index 622fbf9..6511ad9 100644 --- a/test/fixtures/boat_example/plants.csv +++ b/test/fixtures/boat_example/plants.csv @@ -1,39 +1,39 @@ plant,year,operational?,input amount (tonne),opening cost ($),fixed operating cost ($),variable operating cost ($) -BoatFactory (Chicago),1,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Chicago),2,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Chicago),3,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Chicago),4,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Chicago),5,false,-0.0,0.0,0.0,-0.0 +BoatFactory (Chicago),1,false,0.0,0.0,0.0,0.0 +BoatFactory (Chicago),2,false,0.0,0.0,0.0,0.0 +BoatFactory (Chicago),3,false,0.0,0.0,0.0,0.0 +BoatFactory (Chicago),4,false,0.0,0.0,0.0,0.0 +BoatFactory (Chicago),5,false,0.0,0.0,0.0,0.0 BoatFactory (New York City),1,false,0.0,0.0,0.0,0.0 BoatFactory (New York City),2,false,0.0,0.0,0.0,0.0 BoatFactory (New York City),3,false,0.0,0.0,0.0,0.0 BoatFactory (New York City),4,false,0.0,0.0,0.0,0.0 BoatFactory (New York City),5,false,0.0,0.0,0.0,0.0 -BoatFactory (Los Angeles),1,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Los Angeles),2,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Los Angeles),3,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Los Angeles),4,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Los Angeles),5,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Houston),1,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Houston),2,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Houston),3,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Houston),4,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Houston),5,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Phoenix),1,false,-0.0,0.0,0.0,-0.0 -BoatFactory (Phoenix),2,false,-0.0,0.0,0.0,-0.0 +BoatFactory (Los Angeles),1,false,0.0,0.0,0.0,0.0 +BoatFactory (Los Angeles),2,false,0.0,0.0,0.0,0.0 +BoatFactory (Los Angeles),3,false,0.0,0.0,0.0,0.0 +BoatFactory (Los Angeles),4,false,0.0,0.0,0.0,0.0 +BoatFactory (Los Angeles),5,false,0.0,0.0,0.0,0.0 +BoatFactory (Houston),1,false,0.0,0.0,0.0,0.0 +BoatFactory (Houston),2,false,0.0,0.0,0.0,0.0 +BoatFactory (Houston),3,false,0.0,0.0,0.0,0.0 +BoatFactory (Houston),4,false,0.0,0.0,0.0,0.0 +BoatFactory (Houston),5,false,0.0,0.0,0.0,0.0 +BoatFactory (Phoenix),1,false,0.0,0.0,0.0,0.0 +BoatFactory (Phoenix),2,false,0.0,0.0,0.0,0.0 BoatFactory (Phoenix),3,false,0.0,0.0,0.0,0.0 -BoatFactory (Phoenix),4,false,-0.0,0.0,0.0,-0.0 +BoatFactory (Phoenix),4,false,0.0,0.0,0.0,0.0 BoatFactory (Phoenix),5,false,0.0,0.0,0.0,0.0 BoatFactory (Philadelphia),1,false,0.0,0.0,0.0,0.0 BoatFactory (Philadelphia),2,false,0.0,0.0,0.0,0.0 BoatFactory (Philadelphia),3,false,0.0,0.0,0.0,0.0 BoatFactory (Philadelphia),4,false,0.0,0.0,0.0,0.0 BoatFactory (Philadelphia),5,false,0.0,0.0,0.0,0.0 -BoatFactory (San Antonio),1,false,-0.0,0.0,0.0,-0.0 -BoatFactory (San Antonio),2,false,-0.0,0.0,0.0,-0.0 -BoatFactory (San Antonio),3,false,-0.0,0.0,0.0,-0.0 -BoatFactory (San Antonio),4,false,-0.0,0.0,0.0,-0.0 -BoatFactory (San Antonio),5,false,-0.0,0.0,0.0,-0.0 +BoatFactory (San Antonio),1,false,0.0,0.0,0.0,0.0 +BoatFactory (San Antonio),2,false,0.0,0.0,0.0,0.0 +BoatFactory (San Antonio),3,false,0.0,0.0,0.0,0.0 +BoatFactory (San Antonio),4,false,0.0,0.0,0.0,0.0 +BoatFactory (San Antonio),5,false,0.0,0.0,0.0,0.0 BoatFactory (San Diego),1,false,0.0,0.0,0.0,0.0 BoatFactory (San Diego),2,false,0.0,0.0,0.0,0.0 BoatFactory (San Diego),3,false,0.0,0.0,0.0,0.0 @@ -50,7 +50,7 @@ BoatFactory (San Jose),3,false,0.0,0.0,0.0,0.0 BoatFactory (San Jose),4,false,0.0,0.0,0.0,0.0 BoatFactory (San Jose),5,false,0.0,0.0,0.0,0.0 RecyclingPlant (Chicago),1,false,0.0,0.0,0.0,0.0 -RecyclingPlant (Chicago),2,false,0.0,0.0,0.0,0.0 +RecyclingPlant (Chicago),2,false,-0.0,0.0,0.0,-0.0 RecyclingPlant (Chicago),3,false,0.0,0.0,0.0,0.0 RecyclingPlant (Chicago),4,false,0.0,0.0,0.0,0.0 RecyclingPlant (Chicago),5,false,0.0,0.0,0.0,0.0 @@ -71,7 +71,7 @@ RecyclingPlant (Houston),4,false,0.0,0.0,0.0,0.0 RecyclingPlant (Houston),5,false,0.0,0.0,0.0,0.0 RecyclingPlant (Phoenix),1,false,0.0,0.0,0.0,0.0 RecyclingPlant (Phoenix),2,false,0.0,0.0,0.0,0.0 -RecyclingPlant (Phoenix),3,false,-0.0,0.0,0.0,-0.0 +RecyclingPlant (Phoenix),3,false,0.0,0.0,0.0,0.0 RecyclingPlant (Phoenix),4,false,0.0,0.0,0.0,0.0 RecyclingPlant (Phoenix),5,false,0.0,0.0,0.0,0.0 RecyclingPlant (Philadelphia),1,false,0.0,0.0,0.0,0.0 diff --git a/test/fixtures/simple.json b/test/fixtures/simple.json index 7956cf1..3c16406 100644 --- a/test/fixtures/simple.json +++ b/test/fixtures/simple.json @@ -11,7 +11,8 @@ "transportation emissions (tonne/km/tonne)": { "CO2": 0.052, "CH4": [0.003, 0.003, 0.003, 0.003] - } + }, + "disposal limit (tonne)": 1.0 }, "P2": { "transportation cost ($/km/tonne)": [0.015, 0.015, 0.015, 0.015], @@ -19,7 +20,8 @@ "transportation emissions (tonne/km/tonne)": { "CO2": [0.052, 0.052, 0.052, 0.052], "CH4": [0.003, 0.003, 0.003, 0.003] - } + }, + "disposal limit (tonne)": 2.0 }, "P3": { "transportation cost ($/km/tonne)": [0.015, 0.015, 0.015, 0.015], @@ -27,7 +29,8 @@ "transportation emissions (tonne/km/tonne)": { "CO2": [0.052, 0.052, 0.052, 0.052], "CH4": [0.003, 0.003, 0.003, 0.003] - } + }, + "disposal limit (tonne)": 5.0 }, "P4": { "transportation cost ($/km/tonne)": [0.015, 0.015, 0.015, 0.015], @@ -35,7 +38,8 @@ "transportation emissions (tonne/km/tonne)": { "CO2": [0.052, 0.052, 0.052, 0.052], "CH4": [0.003, 0.003, 0.003, 0.003] - } + }, + "disposal limit (tonne)": null } }, "centers": { diff --git a/test/src/instance/parse_test.jl b/test/src/instance/parse_test.jl index d16b497..99db37a 100644 --- a/test/src/instance/parse_test.jl +++ b/test/src/instance/parse_test.jl @@ -18,6 +18,7 @@ function instance_parse_test_1() @test p1.tr_energy == [0.12, 0.12, 0.12, 0.12] @test p1.tr_emissions == Dict("CO2" => [0.052, 0.052, 0.052, 0.052], "CH4" => [0.003, 0.003, 0.003, 0.003]) + @test p1.disposal_limit == [1.0, 1.0, 1.0, 1.0] @test instance.products_by_name["P1"] === p1 p2 = instance.products[2] p3 = instance.products[3] diff --git a/test/src/model/build_test.jl b/test/src/model/build_test.jl index 137bfae..db6c43f 100644 --- a/test/src/model/build_test.jl +++ b/test/src/model/build_test.jl @@ -109,4 +109,13 @@ function model_build_test() @test repr(model[:eq_disposal_limit]["C1", "P2", 1]) == "eq_disposal_limit[C1,P2,1] : z_disp[C1,P2,1] ≤ 0" @test ("C1", "P3", 1) ∉ keys(model[:eq_disposal_limit]) + + # Global disposal limit + @test repr(model[:eq_disposal_limit]["P1", 1]) == + "eq_disposal_limit[P1,1] : z_disp[C2,P1,1] ≤ 1" + @test repr(model[:eq_disposal_limit]["P2", 1]) == + "eq_disposal_limit[P2,1] : z_disp[C1,P2,1] ≤ 2" + @test repr(model[:eq_disposal_limit]["P3", 1]) == + "eq_disposal_limit[P3,1] : z_disp[L1,P3,1] + z_disp[C1,P3,1] ≤ 5" + @test ("P4", 1) ∉ keys(model[:eq_disposal_limit]) end