diff --git a/.gitignore b/.gitignore index ef222c5..400f7a7 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ run.jl relog-web-legacy .vscode jobs +**/tmp diff --git a/docs/format.md b/docs/format.md index 7188c47..f609f34 100644 --- a/docs/format.md +++ b/docs/format.md @@ -63,21 +63,19 @@ ### Centers -| Key | Type | Description | -| :------------------------------ | ------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `latitude (deg)` | `float` | The latitude of the center. | -| `longitude (deg)` | `float` | The longitude of the center. | -| `input` | `str` | The name of the product this center takes as input. May be `null` if the center accept no input product. | -| `outputs` | `vec(str)` | List of output products collected by the center. May be `[]` if none. | -| `fixed output (tonne)` | `dict(str, mat(float, T, C))` | Dictionary mapping the name of each output product $p$ to a matrix $M$, where $M_{t,c}$ is the amount (in tonne) of output product component $c$ produced by the center at time $t$, regardless of how much input material the center received. | -| `variable output (tonne/tonne)` | `dict(str,mat(float, T, M, N))` | Dictionary mapping the name of each output product $p$ to a $(T \times m \times n)$ matrix $M$ that describes the amount (in tonnes) of output product component produced by the center, depending on how much input material the center received in prior years, where $T$ is the number of years, $m$ is the number of components of $p$ and $n$ is the number of components of the input product. For example, assume a 4-year simulation, and suppose both input product `P1` and output product `P2` have two components. If this field equals `{"P2": []} | - -to the amount of output generated, for each tonne of input material, and for each year after the input is received. For example, in a 4-year simulation, if this field equals to `{"P1": [0.1, 0.3, 0.6, 0.0]}` and the center receives 1.0, 2.0, 3.0 and 4.0 tonnes of input material in years 1, 2, 3 and 4, then the center will produce $1.0 * 0.1 = 0.1$ of P1 in the first year, $1.0 * 0.3 + 2.0 * 0.1 = 0.5$ the second year, $1.0 * 0.6 + 2.0 * 0.3 + 3.0 * 0.1 = 1.5$ in the third year, and $2.0 * 0.6 + 3.0 * 0.3 + 4.0 * 0.1 = 2.5$ in the final year. | -| `revenue ($/tonne)` | | Revenue generated by each tonne of input material sent to the center. If the center accepts no input, this should be `null` | -| `collection cost ($/tonne)` | | Dictionary mapping the name of each output product to the cost of collecting one tonne of the product. | -| `operating cost ($)` | | Fixed cost to operate the center for one year, regardless of amount of product received or generated. | -| `disposal limit (tonne)` | | Dictionary mapping the name of each output product to the maximum disposal amount allower per year of the product at the center. Entry may be `null` if unlimited. | -| `disposal cost ($/tonne)` | | Dictionary mapping the name of each output product to the cost to dispose one tonne of the product at the center. | +| Key | Type | Description | +| :------------------------------ | ------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `latitude (deg)` | `float` | The latitude of the center. | +| `longitude (deg)` | `float` | The longitude of the center. | +| `input` | `str` | The name of the product this center takes as input. May be `null` if the center accept no input product. | +| `outputs` | `vec(str)` | List of output products collected by the center. May be `[]` if none. | +| `fixed output (tonne)` | `dict(str, mat(float, T, C))` | Dictionary mapping the name of each output product $p$ to a matrix $M$, where $M_{t,c}$ is the amount (in tonne) of output product component $c$ produced by the center at time $t$, regardless of how much input material the center received. | +| `variable output (tonne/tonne)` | `dict(str,mat(float, T, M, N))` | Dictionary mapping the name of each output product $p$ to a $(T \times m \times n)$ matrix $M$ that describes the amount (in tonnes) of output product component produced by the center, depending on how much input material the center received in prior years, where $T$ is the number of years, $m$ is the number of components of $p$ and $n$ is the number of components of the input product. | +| `revenue ($/tonne)` | `vec(float, T)` | Revenue generated by each tonne of input material sent to the center. If the center accepts no input, this should be `null` | +| `collection cost ($/tonne)` | `dict(str,vec(float,T))` | Dictionary mapping the name of each output product to the cost of collecting one tonne of the product. | +| `operating cost ($)` | `vec(float,T)` | Fixed cost to operate the center for one year, regardless of amount of product received or generated. | +| `disposal limit (tonne)` | `dict(str,vec(float,T))` | Dictionary mapping the name of each output product to the maximum disposal amount allower per year of the product at the center. Entry may be `null` if unlimited. | +| `disposal cost ($/tonne)` | `dict(str,vec(float,T))` | Dictionary mapping the name of each output product to the cost to dispose one tonne of the product at the center. | ```json { @@ -198,20 +196,21 @@ to the amount of output generated, for each tonne of input material, and for eac ### Plants -| Key | Description | -| :----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -| `latitude (deg)` | The latitude of the plant, in degrees. | -| `longitude (deg)` | The longitude of the plant, in degrees. | -| `input mix (%)` | Dictionary mapping the name of each input product to the amount required (as a percentage). Must sum to 100%. | -| `output (tonne)` | Dictionary mapping the name of each output product to the amount produced (in tonne) for one tonne of input mix. | -| `processing emissions (tonne)` | A dictionary mapping the name of each greenhouse gas, produced to process each tonne of input, to the amount of gas produced (in tonne). | -| `storage cost ($/tonne)` | Dictionary mapping the name of each input product to the cost of storing the product for one year at the plant for later processing. | -| `storage limit (tonne)` | Dictionary mapping the name of each input product to the maximum amount allowed in storage at any time. May be `null` if unlimited. | -| `disposal cost ($/tonne)` | Dictionary mapping the name of each output product to the cost of disposing it at the plant. | -| `disposal limit (tonne)` | Dictionary mapping the name of each output product to the maximum amount allowed to be disposed of at the plant. May be `null` if unlimited. | -| `capacities` | List describing what plant sizes are allowed, and their characteristics. | +| Key | | Description | +| :----------------------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| `latitude (deg)` | `float` | The latitude of the plant, in degrees. | +| `longitude (deg)` | `float` | The longitude of the plant, in degrees. | +| `input mix (%)` | `dict(str,float)` | Dictionary mapping the name of each input product to the amount required (as a percentage). Must sum to 100%. | +| `output (tonne/tonne)` | `dict(str,dict(str,mat(float, T, M, N)))` | Dictionary of matrices describing the component outputs. | +| `processing emissions (tonne)` | `dict(str,vec(float,T))` | A dictionary mapping the name of each greenhouse gas, produced to process each tonne of input, to the amount of gas produced (in tonne). | +| `storage cost ($/tonne)` | `dict(str,vec(float,T))` | Dictionary mapping the name of each input product to the cost of storing the product for one year at the plant for later processing. | +| `storage limit (tonne)` | | Dictionary mapping the name of each input product to the maximum amount allowed in storage at any time. May be `null` if unlimited. | +| `disposal cost ($/tonne)` | | Dictionary mapping the name of each output product to the cost of disposing it at the plant. | +| `disposal limit (tonne)` | | Dictionary mapping the name of each output product to the maximum amount allowed to be disposed of at the plant. May be `null` if unlimited. | +| `capacities` | | List describing what plant sizes are allowed, and their characteristics. | -The entries in the `capacities` list should be dictionaries with the following keys: +The entries in the `capacities` list should be dictionaries with the following +keys: | Key | Description | | :---------------------------------- | :-------------------------------------------------------------------------------------------------- | diff --git a/src/instance/parse.jl b/src/instance/parse.jl index 44a71c5..b92ca2a 100644 --- a/src/instance/parse.jl +++ b/src/instance/parse.jl @@ -22,7 +22,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) + components = pdict["components"] + prod = Product(; name, tr_cost, tr_energy, tr_emissions, components) push!(products, prod) products_by_name[name] = prod end @@ -45,7 +46,19 @@ function parse(json)::Instance p => [v === nothing ? null_val : v for v in timeseries(cdict[key][p.name])] for p in outputs ) - fixed_output = prod_dict("fixed output (tonne)", 0.0) + to_array(x) = vcat(x'...) + prepend_time_dimension(x) = to_array(repeat([x], time_horizon)) + + fixed_output = Dict() + for p in outputs + m = to_array(cdict["fixed output (tonne)"][p.name]) + if ndims(m) == 1 + m = prepend_time_dimension(m) + end + @assert size(m) == (time_horizon, length(p.components)) + fixed_output[p] = m + end + var_output = prod_dict("variable output (tonne/tonne)", 0.0) collection_cost = prod_dict("collection cost (\$/tonne)", 0.0) disposal_limit = prod_dict("disposal limit (tonne)", Inf) diff --git a/src/instance/structs.jl b/src/instance/structs.jl index b1f0ece..85b3ec0 100644 --- a/src/instance/structs.jl +++ b/src/instance/structs.jl @@ -5,6 +5,7 @@ Base.@kwdef struct Product tr_cost::Vector{Float64} tr_energy::Vector{Float64} tr_emissions::OrderedDict{String,Vector{Float64}} + components::Vector{String} end Base.@kwdef struct Center @@ -13,7 +14,7 @@ Base.@kwdef struct Center longitude::Float64 input::Union{Product,Nothing} outputs::Vector{Product} - fixed_output::OrderedDict{Product,Vector{Float64}} + fixed_output::OrderedDict{Product,Array{Float64,2}} var_output::OrderedDict{Product,Vector{Float64}} revenue::Vector{Float64} collection_cost::OrderedDict{Product,Vector{Float64}} diff --git a/src/model/build.jl b/src/model/build.jl index 47d4992..6940d12 100644 --- a/src/model/build.jl +++ b/src/model/build.jl @@ -269,7 +269,10 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false sum( z_input[c.name, t-offset] * c.var_output[m][offset+1] for offset = 0:min(M - 1, t - 1) - ) + c.fixed_output[m][t] + ) + sum( + c.fixed_output[m][t,mi] + for mi in 1:length(m.components) + ) ) end diff --git a/test/fixtures/boat_example.jl b/test/fixtures/boat_example.jl index e059bfb..aadb843 100644 --- a/test/fixtures/boat_example.jl +++ b/test/fixtures/boat_example.jl @@ -32,7 +32,7 @@ function run_boat_example() nail_factory = dict( "input" => nothing, "outputs" => ["Nail"], - "fixed output (tonne)" => dict("Nail" => 1), + "fixed output (tonne)" => dict("Nail" => [1]), "variable output (tonne/tonne)" => dict("Nail" => 0), "revenue (\$/tonne)" => nothing, "collection cost (\$/tonne)" => dict("Nail" => 1000), @@ -44,7 +44,7 @@ function run_boat_example() forest = dict( "input" => nothing, "outputs" => ["Wood"], - "fixed output (tonne)" => dict("Wood" => 100), + "fixed output (tonne)" => dict("Wood" => [[100], [100], [100], [100], [100]]), "variable output (tonne/tonne)" => dict("Wood" => 0), "revenue (\$/tonne)" => nothing, "collection cost (\$/tonne)" => dict("Wood" => 250), @@ -56,7 +56,7 @@ function run_boat_example() retail = dict( "input" => "NewBoat", "outputs" => ["UsedBoat"], - "fixed output (tonne)" => dict("UsedBoat" => 0), + "fixed output (tonne)" => dict("UsedBoat" => [[0], [0], [0], [0], [0]]), "variable output (tonne/tonne)" => dict("UsedBoat" => [0.10, 0.25, 0.10]), "revenue (\$/tonne)" => 12_000, "collection cost (\$/tonne)" => dict("UsedBoat" => 100), @@ -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), + "components" => ["1"], ) boat_factory = dict( @@ -121,10 +122,8 @@ function run_boat_example() "initial capacity (tonne)" => 0, ) - lat_lon_dict(city_location) = dict( - "latitude (deg)" => city_location[1], - "longitude (deg)" => city_location[2], - ) + lat_lon_dict(city_location) = + dict("latitude (deg)" => city_location[1], "longitude (deg)" => city_location[2]) data = dict( "parameters" => parameters, @@ -132,36 +131,29 @@ function run_boat_example() dict("Nail" => prod, "Wood" => prod, "NewBoat" => prod, "UsedBoat" => prod), "centers" => merge( dict( - "NailFactory ($city_name)" => merge( - nail_factory, - lat_lon_dict(city_location) - ) for (city_name, city_location) in cities_b + "NailFactory ($city_name)" => + merge(nail_factory, lat_lon_dict(city_location)) for + (city_name, city_location) in cities_b ), dict( - "Forest ($city_name)" => merge( - forest, - lat_lon_dict(city_location) - ) for (city_name, city_location) in cities_b + "Forest ($city_name)" => merge(forest, lat_lon_dict(city_location)) + for (city_name, city_location) in cities_b ), dict( - "Retail ($city_name)" => merge( - retail, - lat_lon_dict(city_location) - ) for (city_name, city_location) in cities_a + "Retail ($city_name)" => merge(retail, lat_lon_dict(city_location)) + for (city_name, city_location) in cities_a ), ), "plants" => merge( dict( - "BoatFactory ($city_name)" => merge( - boat_factory, - lat_lon_dict(city_location) - ) for (city_name, city_location) in cities_a + "BoatFactory ($city_name)" => + merge(boat_factory, lat_lon_dict(city_location)) for + (city_name, city_location) in cities_a ), dict( - "RecyclingPlant ($city_name)" => merge( - recycling_plant, - lat_lon_dict(city_location) - ) for (city_name, city_location) in cities_a + "RecyclingPlant ($city_name)" => + merge(recycling_plant, lat_lon_dict(city_location)) for + (city_name, city_location) in cities_a ), ), ) @@ -186,4 +178,4 @@ function run_boat_example() RELOG.write_transportation_report(model, fixture("boat_example/transportation.csv")) return -end \ No newline at end of file +end diff --git a/test/fixtures/boat_example.json b/test/fixtures/boat_example.json index ecadb79..36eb542 100644 --- a/test/fixtures/boat_example.json +++ b/test/fixtures/boat_example.json @@ -12,28 +12,40 @@ "transportation energy (J/km/tonne)": 7500, "transportation emissions (tonne/km/tonne)": { "CO2": 2.68 - } + }, + "components": [ + "1" + ] }, "Wood": { "transportation cost ($/km/tonne)": 0.3, "transportation energy (J/km/tonne)": 7500, "transportation emissions (tonne/km/tonne)": { "CO2": 2.68 - } + }, + "components": [ + "1" + ] }, "NewBoat": { "transportation cost ($/km/tonne)": 0.3, "transportation energy (J/km/tonne)": 7500, "transportation emissions (tonne/km/tonne)": { "CO2": 2.68 - } + }, + "components": [ + "1" + ] }, "UsedBoat": { "transportation cost ($/km/tonne)": 0.3, "transportation energy (J/km/tonne)": 7500, "transportation emissions (tonne/km/tonne)": { "CO2": 2.68 - } + }, + "components": [ + "1" + ] } }, "centers": { @@ -43,7 +55,9 @@ "Nail" ], "fixed output (tonne)": { - "Nail": 1 + "Nail": [ + 1 + ] }, "variable output (tonne/tonne)": { "Nail": 0 @@ -68,7 +82,9 @@ "Nail" ], "fixed output (tonne)": { - "Nail": 1 + "Nail": [ + 1 + ] }, "variable output (tonne/tonne)": { "Nail": 0 @@ -93,7 +109,9 @@ "Nail" ], "fixed output (tonne)": { - "Nail": 1 + "Nail": [ + 1 + ] }, "variable output (tonne/tonne)": { "Nail": 0 @@ -118,7 +136,23 @@ "Wood" ], "fixed output (tonne)": { - "Wood": 100 + "Wood": [ + [ + 100 + ], + [ + 100 + ], + [ + 100 + ], + [ + 100 + ], + [ + 100 + ] + ] }, "variable output (tonne/tonne)": { "Wood": 0 @@ -143,7 +177,23 @@ "Wood" ], "fixed output (tonne)": { - "Wood": 100 + "Wood": [ + [ + 100 + ], + [ + 100 + ], + [ + 100 + ], + [ + 100 + ], + [ + 100 + ] + ] }, "variable output (tonne/tonne)": { "Wood": 0 @@ -168,7 +218,23 @@ "Wood" ], "fixed output (tonne)": { - "Wood": 100 + "Wood": [ + [ + 100 + ], + [ + 100 + ], + [ + 100 + ], + [ + 100 + ], + [ + 100 + ] + ] }, "variable output (tonne/tonne)": { "Wood": 0 @@ -193,7 +259,23 @@ "UsedBoat" ], "fixed output (tonne)": { - "UsedBoat": 0 + "UsedBoat": [ + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ] + ] }, "variable output (tonne/tonne)": { "UsedBoat": [ @@ -222,7 +304,23 @@ "UsedBoat" ], "fixed output (tonne)": { - "UsedBoat": 0 + "UsedBoat": [ + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ] + ] }, "variable output (tonne/tonne)": { "UsedBoat": [ @@ -251,7 +349,23 @@ "UsedBoat" ], "fixed output (tonne)": { - "UsedBoat": 0 + "UsedBoat": [ + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ] + ] }, "variable output (tonne/tonne)": { "UsedBoat": [ @@ -280,7 +394,23 @@ "UsedBoat" ], "fixed output (tonne)": { - "UsedBoat": 0 + "UsedBoat": [ + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ] + ] }, "variable output (tonne/tonne)": { "UsedBoat": [ @@ -309,7 +439,23 @@ "UsedBoat" ], "fixed output (tonne)": { - "UsedBoat": 0 + "UsedBoat": [ + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ] + ] }, "variable output (tonne/tonne)": { "UsedBoat": [ @@ -338,7 +484,23 @@ "UsedBoat" ], "fixed output (tonne)": { - "UsedBoat": 0 + "UsedBoat": [ + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ] + ] }, "variable output (tonne/tonne)": { "UsedBoat": [ @@ -367,7 +529,23 @@ "UsedBoat" ], "fixed output (tonne)": { - "UsedBoat": 0 + "UsedBoat": [ + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ] + ] }, "variable output (tonne/tonne)": { "UsedBoat": [ @@ -396,7 +574,23 @@ "UsedBoat" ], "fixed output (tonne)": { - "UsedBoat": 0 + "UsedBoat": [ + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ] + ] }, "variable output (tonne/tonne)": { "UsedBoat": [ @@ -425,7 +619,23 @@ "UsedBoat" ], "fixed output (tonne)": { - "UsedBoat": 0 + "UsedBoat": [ + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ] + ] }, "variable output (tonne/tonne)": { "UsedBoat": [ @@ -454,7 +664,23 @@ "UsedBoat" ], "fixed output (tonne)": { - "UsedBoat": 0 + "UsedBoat": [ + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ], + [ + 0 + ] + ] }, "variable output (tonne/tonne)": { "UsedBoat": [ diff --git a/test/fixtures/simple.json b/test/fixtures/simple.json index c5b7f1e..695d6a0 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] - } + }, + "components": ["1", "2"] }, "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] - } + }, + "components": ["1"] }, "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] - } + }, + "components": ["1"] }, "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] - } + }, + "components": ["1"] } }, "centers": { @@ -45,11 +49,11 @@ "input": "P1", "outputs": ["P2", "P3"], "fixed output (tonne)": { - "P2": [100, 50, 0, 0], - "P3": [20, 10, 0, 0] + "P2": [[100], [50], [0], [0]], + "P3": [[20], [10], [0], [0]] }, "variable output (tonne/tonne)": { - "P2": [0.20, 0.25, 0.12], + "P2": [0.2, 0.25, 0.12], "P3": [0.25, 0.25, 0.25] }, "revenue ($/tonne)": 12.0, @@ -76,7 +80,12 @@ "P1": 0 }, "fixed output (tonne)": { - "P1": [50, 60, 70, 80] + "P1": [ + [50, 5], + [60, 6], + [70, 7], + [80, 8] + ] }, "revenue ($/tonne)": null, "collection cost ($/tonne)": { diff --git a/test/fixtures/waste_example/example.json b/test/fixtures/waste_example/example.json new file mode 100644 index 0000000..efeb397 --- /dev/null +++ b/test/fixtures/waste_example/example.json @@ -0,0 +1,650 @@ +{ + "parameters": { + "time horizon (years)": 5, + "building period (years)": [1], + "distance metric": "Euclidean" + }, + "products": { + "Waste": { + "transportation cost ($/km/tonne)": 0.3, + "transportation energy (J/km/tonne)": 7500, + "transportation emissions (tonne/km/tonne)": { + "CO2": 2.68 + }, + "components": ["Film", "Paper", "Cardboard"] + }, + "Film Bale": { + "transportation cost ($/km/tonne)": 0.3, + "transportation energy (J/km/tonne)": 7500, + "transportation emissions (tonne/km/tonne)": { + "CO2": 2.68 + }, + "components": ["Film", "Paper", "Cardboard"] + }, + "Cardboard Bale": { + "transportation cost ($/km/tonne)": 0.3, + "transportation energy (J/km/tonne)": 7500, + "transportation emissions (tonne/km/tonne)": { + "CO2": 2.68 + }, + "components": ["Film", "Paper", "Cardboard"] + } + }, + "centers": { + "Collection Center (Chicago)": { + "input": null, + "outputs": ["Waste"], + "fixed output (tonne)": { + "Waste": [20, 100, 100] + }, + "variable output (tonne/tonne)": {}, + "revenue ($/tonne)": null, + "collection cost ($/tonne)": { + "Waste": 10 + }, + "operating cost ($)": 0, + "disposal limit (tonne)": { + "Waste": null + }, + "disposal cost ($/tonne)": { + "Waste": 0 + }, + "latitude (deg)": 41.881832, + "longitude (deg)": -87.623177 + }, + "Collection Center (Phoenix)": { + "input": null, + "outputs": ["Waste"], + "fixed output (tonne)": { + "Waste": [20, 100, 100] + }, + "variable output (tonne/tonne)": {}, + "revenue ($/tonne)": null, + "collection cost ($/tonne)": { + "Waste": 10 + }, + "operating cost ($)": 0, + "disposal limit (tonne)": { + "Waste": null + }, + "disposal cost ($/tonne)": { + "Waste": 0 + }, + "latitude (deg)": 33.448376, + "longitude (deg)": -112.074036 + }, + "Collection Center (Dallas)": { + "input": null, + "outputs": ["Waste"], + "fixed output (tonne)": { + "Waste": [20, 100, 100] + }, + "variable output (tonne/tonne)": {}, + "revenue ($/tonne)": null, + "collection cost ($/tonne)": { + "Waste": 10 + }, + "operating cost ($)": 0, + "disposal limit (tonne)": { + "Waste": null + }, + "disposal cost ($/tonne)": { + "Waste": 0 + }, + "latitude (deg)": 32.776664, + "longitude (deg)": -96.796988 + } + }, + "plants": { + "RecyclingPlant (Chicago)": { + "input mix (%)": { + "Waste": 100 + }, + "output (tonne)": { + "Film Bale": { + "Waste": [ + [0.98, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.02] + ] + }, + "Cardboard Bale": { + "Waste": [ + [0.0, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.75] + ] + } + }, + "processing emissions (tonne)": { + "CO2": 5 + }, + "storage cost ($/tonne)": { + "Waste": 500 + }, + "storage limit (tonne)": { + "Waste": 5 + }, + "disposal cost ($/tonne)": { + "Film Bale": -10, + "Cardboard Bale": -10 + }, + "disposal limit (tonne)": { + "Film Bale": null, + "Cardboard Bale": null + }, + "capacities": [ + { + "size (tonne)": 500, + "opening cost ($)": 100000, + "fixed operating cost ($)": 250000, + "variable operating cost ($/tonne)": 5 + }, + { + "size (tonne)": 1000, + "opening cost ($)": 2000000, + "fixed operating cost ($)": 500000, + "variable operating cost ($/tonne)": 5 + } + ], + "initial capacity (tonne)": 0, + "latitude (deg)": 41.881832, + "longitude (deg)": -87.623177 + }, + "RecyclingPlant (New York City)": { + "input mix (%)": { + "Waste": 100 + }, + "output (tonne)": { + "Film Bale": { + "Waste": [ + [0.98, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.02] + ] + }, + "Cardboard Bale": { + "Waste": [ + [0.0, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.75] + ] + } + }, + "processing emissions (tonne)": { + "CO2": 5 + }, + "storage cost ($/tonne)": { + "Waste": 500 + }, + "storage limit (tonne)": { + "Waste": 5 + }, + "disposal cost ($/tonne)": { + "Film Bale": -10, + "Cardboard Bale": -10 + }, + "disposal limit (tonne)": { + "Film Bale": null, + "Cardboard Bale": null + }, + "capacities": [ + { + "size (tonne)": 500, + "opening cost ($)": 100000, + "fixed operating cost ($)": 250000, + "variable operating cost ($/tonne)": 5 + }, + { + "size (tonne)": 1000, + "opening cost ($)": 2000000, + "fixed operating cost ($)": 500000, + "variable operating cost ($/tonne)": 5 + } + ], + "initial capacity (tonne)": 0, + "latitude (deg)": 40.712776, + "longitude (deg)": -74.005974 + }, + "RecyclingPlant (Los Angeles)": { + "input mix (%)": { + "Waste": 100 + }, + "output (tonne)": { + "Film Bale": { + "Waste": [ + [0.98, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.02] + ] + }, + "Cardboard Bale": { + "Waste": [ + [0.0, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.75] + ] + } + }, + "processing emissions (tonne)": { + "CO2": 5 + }, + "storage cost ($/tonne)": { + "Waste": 500 + }, + "storage limit (tonne)": { + "Waste": 5 + }, + "disposal cost ($/tonne)": { + "Film Bale": -10, + "Cardboard Bale": -10 + }, + "disposal limit (tonne)": { + "Film Bale": null, + "Cardboard Bale": null + }, + "capacities": [ + { + "size (tonne)": 500, + "opening cost ($)": 100000, + "fixed operating cost ($)": 250000, + "variable operating cost ($/tonne)": 5 + }, + { + "size (tonne)": 1000, + "opening cost ($)": 2000000, + "fixed operating cost ($)": 500000, + "variable operating cost ($/tonne)": 5 + } + ], + "initial capacity (tonne)": 0, + "latitude (deg)": 34.052235, + "longitude (deg)": -118.243683 + }, + "RecyclingPlant (Houston)": { + "input mix (%)": { + "Waste": 100 + }, + "output (tonne)": { + "Film Bale": { + "Waste": [ + [0.98, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.02] + ] + }, + "Cardboard Bale": { + "Waste": [ + [0.0, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.75] + ] + } + }, + "processing emissions (tonne)": { + "CO2": 5 + }, + "storage cost ($/tonne)": { + "Waste": 500 + }, + "storage limit (tonne)": { + "Waste": 5 + }, + "disposal cost ($/tonne)": { + "Film Bale": -10, + "Cardboard Bale": -10 + }, + "disposal limit (tonne)": { + "Film Bale": null, + "Cardboard Bale": null + }, + "capacities": [ + { + "size (tonne)": 500, + "opening cost ($)": 100000, + "fixed operating cost ($)": 250000, + "variable operating cost ($/tonne)": 5 + }, + { + "size (tonne)": 1000, + "opening cost ($)": 2000000, + "fixed operating cost ($)": 500000, + "variable operating cost ($/tonne)": 5 + } + ], + "initial capacity (tonne)": 0, + "latitude (deg)": 29.760427, + "longitude (deg)": -95.369804 + }, + "RecyclingPlant (Phoenix)": { + "input mix (%)": { + "Waste": 100 + }, + "output (tonne)": { + "Film Bale": { + "Waste": [ + [0.98, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.02] + ] + }, + "Cardboard Bale": { + "Waste": [ + [0.0, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.75] + ] + } + }, + "processing emissions (tonne)": { + "CO2": 5 + }, + "storage cost ($/tonne)": { + "Waste": 500 + }, + "storage limit (tonne)": { + "Waste": 5 + }, + "disposal cost ($/tonne)": { + "Film Bale": -10, + "Cardboard Bale": -10 + }, + "disposal limit (tonne)": { + "Film Bale": null, + "Cardboard Bale": null + }, + "capacities": [ + { + "size (tonne)": 500, + "opening cost ($)": 100000, + "fixed operating cost ($)": 250000, + "variable operating cost ($/tonne)": 5 + }, + { + "size (tonne)": 1000, + "opening cost ($)": 2000000, + "fixed operating cost ($)": 500000, + "variable operating cost ($/tonne)": 5 + } + ], + "initial capacity (tonne)": 0, + "latitude (deg)": 33.448376, + "longitude (deg)": -112.074036 + }, + "RecyclingPlant (Philadelphia)": { + "input mix (%)": { + "Waste": 100 + }, + "output (tonne)": { + "Film Bale": { + "Waste": [ + [0.98, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.02] + ] + }, + "Cardboard Bale": { + "Waste": [ + [0.0, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.75] + ] + } + }, + "processing emissions (tonne)": { + "CO2": 5 + }, + "storage cost ($/tonne)": { + "Waste": 500 + }, + "storage limit (tonne)": { + "Waste": 5 + }, + "disposal cost ($/tonne)": { + "Film Bale": -10, + "Cardboard Bale": -10 + }, + "disposal limit (tonne)": { + "Film Bale": null, + "Cardboard Bale": null + }, + "capacities": [ + { + "size (tonne)": 500, + "opening cost ($)": 100000, + "fixed operating cost ($)": 250000, + "variable operating cost ($/tonne)": 5 + }, + { + "size (tonne)": 1000, + "opening cost ($)": 2000000, + "fixed operating cost ($)": 500000, + "variable operating cost ($/tonne)": 5 + } + ], + "initial capacity (tonne)": 0, + "latitude (deg)": 39.952583, + "longitude (deg)": -75.165222 + }, + "RecyclingPlant (San Antonio)": { + "input mix (%)": { + "Waste": 100 + }, + "output (tonne)": { + "Film Bale": { + "Waste": [ + [0.98, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.02] + ] + }, + "Cardboard Bale": { + "Waste": [ + [0.0, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.75] + ] + } + }, + "processing emissions (tonne)": { + "CO2": 5 + }, + "storage cost ($/tonne)": { + "Waste": 500 + }, + "storage limit (tonne)": { + "Waste": 5 + }, + "disposal cost ($/tonne)": { + "Film Bale": -10, + "Cardboard Bale": -10 + }, + "disposal limit (tonne)": { + "Film Bale": null, + "Cardboard Bale": null + }, + "capacities": [ + { + "size (tonne)": 500, + "opening cost ($)": 100000, + "fixed operating cost ($)": 250000, + "variable operating cost ($/tonne)": 5 + }, + { + "size (tonne)": 1000, + "opening cost ($)": 2000000, + "fixed operating cost ($)": 500000, + "variable operating cost ($/tonne)": 5 + } + ], + "initial capacity (tonne)": 0, + "latitude (deg)": 29.424122, + "longitude (deg)": -98.493629 + }, + "RecyclingPlant (San Diego)": { + "input mix (%)": { + "Waste": 100 + }, + "output (tonne)": { + "Film Bale": { + "Waste": [ + [0.98, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.02] + ] + }, + "Cardboard Bale": { + "Waste": [ + [0.0, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.75] + ] + } + }, + "processing emissions (tonne)": { + "CO2": 5 + }, + "storage cost ($/tonne)": { + "Waste": 500 + }, + "storage limit (tonne)": { + "Waste": 5 + }, + "disposal cost ($/tonne)": { + "Film Bale": -10, + "Cardboard Bale": -10 + }, + "disposal limit (tonne)": { + "Film Bale": null, + "Cardboard Bale": null + }, + "capacities": [ + { + "size (tonne)": 500, + "opening cost ($)": 100000, + "fixed operating cost ($)": 250000, + "variable operating cost ($/tonne)": 5 + }, + { + "size (tonne)": 1000, + "opening cost ($)": 2000000, + "fixed operating cost ($)": 500000, + "variable operating cost ($/tonne)": 5 + } + ], + "initial capacity (tonne)": 0, + "latitude (deg)": 32.715736, + "longitude (deg)": -117.161087 + }, + "RecyclingPlant (Dallas)": { + "input mix (%)": { + "Waste": 100 + }, + "output (tonne)": { + "Film Bale": { + "Waste": [ + [0.98, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.02] + ] + }, + "Cardboard Bale": { + "Waste": [ + [0.0, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.75] + ] + } + }, + "processing emissions (tonne)": { + "CO2": 5 + }, + "storage cost ($/tonne)": { + "Waste": 500 + }, + "storage limit (tonne)": { + "Waste": 5 + }, + "disposal cost ($/tonne)": { + "Film Bale": -10, + "Cardboard Bale": -10 + }, + "disposal limit (tonne)": { + "Film Bale": null, + "Cardboard Bale": null + }, + "capacities": [ + { + "size (tonne)": 500, + "opening cost ($)": 100000, + "fixed operating cost ($)": 250000, + "variable operating cost ($/tonne)": 5 + }, + { + "size (tonne)": 1000, + "opening cost ($)": 2000000, + "fixed operating cost ($)": 500000, + "variable operating cost ($/tonne)": 5 + } + ], + "initial capacity (tonne)": 0, + "latitude (deg)": 32.776664, + "longitude (deg)": -96.796988 + }, + "RecyclingPlant (San Jose)": { + "input mix (%)": { + "Waste": 100 + }, + "output (tonne)": { + "Film Bale": { + "Waste": [ + [0.98, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.02] + ] + }, + "Cardboard Bale": { + "Waste": [ + [0.0, 0.0, 0.0], + [0.0, 0.02, 0.0], + [0.0, 0.0, 0.75] + ] + } + }, + "processing emissions (tonne)": { + "CO2": 5 + }, + "storage cost ($/tonne)": { + "Waste": 500 + }, + "storage limit (tonne)": { + "Waste": 5 + }, + "disposal cost ($/tonne)": { + "Film Bale": -10, + "Cardboard Bale": -10 + }, + "disposal limit (tonne)": { + "Film Bale": null, + "Cardboard Bale": null + }, + "capacities": [ + { + "size (tonne)": 500, + "opening cost ($)": 100000, + "fixed operating cost ($)": 250000, + "variable operating cost ($/tonne)": 5 + }, + { + "size (tonne)": 1000, + "opening cost ($)": 2000000, + "fixed operating cost ($)": 500000, + "variable operating cost ($/tonne)": 5 + } + ], + "initial capacity (tonne)": 0, + "latitude (deg)": 37.338208, + "longitude (deg)": -121.886329 + } + } +} diff --git a/test/src/RELOGT.jl b/test/src/RELOGT.jl index d61a7db..65d18de 100644 --- a/test/src/RELOGT.jl +++ b/test/src/RELOGT.jl @@ -32,4 +32,7 @@ function format() JuliaFormatter.format("$basedir/../fixtures", verbose = true) return end + +export format, runtests + end # module RELOGT diff --git a/test/src/instance/parse_test.jl b/test/src/instance/parse_test.jl index 07697c4..66fcaa3 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.components == ["1", "2"] @test instance.products_by_name["P1"] === p1 p2 = instance.products[2] p3 = instance.products[3] @@ -30,7 +31,7 @@ function instance_parse_test_1() @test c1.longitude == -87.623 @test c1.input === p1 @test c1.outputs == [p2, p3] - @test c1.fixed_output == Dict(p2 => [100, 50, 0, 0], p3 => [20, 10, 0, 0]) + @test c1.fixed_output == Dict(p2 => [100; 50; 0; 0;;], p3 => [20; 10; 0; 0;;]) @test c1.var_output == Dict(p2 => [0.2, 0.25, 0.12], p3 => [0.25, 0.25, 0.25]) @test c1.revenue == [12.0, 12.0, 12.0, 12.0] @test c1.operating_cost == [150.0, 150.0, 150.0, 150.0] diff --git a/test/src/model/build_test.jl b/test/src/model/build_test.jl index 137bfae..5d411b6 100644 --- a/test/src/model/build_test.jl +++ b/test/src/model/build_test.jl @@ -11,7 +11,6 @@ function model_build_test() z_input = model[:z_input] x = model[:x] obj = objective_function(model) - # print(model) @test obj.terms[y["L1", "C3", "P4", 1]] == ( 111.118 * 0.015 # transportation @@ -98,7 +97,8 @@ function model_build_test() "eq_z_collected[C1,P2,3] : -0.12 z_input[C1,1] - 0.25 z_input[C1,2] - 0.2 z_input[C1,3] + z_collected[C1,P2,3] = 0" @test repr(model[:eq_z_collected]["C1", "P2", 4]) == "eq_z_collected[C1,P2,4] : -0.12 z_input[C1,2] - 0.25 z_input[C1,3] - 0.2 z_input[C1,4] + z_collected[C1,P2,4] = 0" - + @test repr(model[:eq_z_collected]["C2", "P1", 1]) == "eq_z_collected[C2,P1,1] : z_collected[C2,P1,1] = 55" + # Centers: Collected products must be disposed or sent @test repr(model[:eq_balance]["C1", "P2", 1]) == "eq_balance[C1,P2,1] : -y[C1,L1,P2,1] - z_disp[C1,P2,1] + z_collected[C1,P2,1] = 0"