Compare commits
28 Commits
feature/co
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 7dbc3cf90b | |||
| b7d16fee3e | |||
| eedf023b47 | |||
| 5eee29547c | |||
| 897717677f | |||
| 480547933b | |||
| 744b043461 | |||
| f4e97ff7f2 | |||
| f35c84abe9 | |||
| 003922ac70 | |||
| 4ce52b7420 | |||
| 157cd500ef | |||
| ca06db2870 | |||
| 5ac9ae2b62 | |||
| e4d4ee1cc8 | |||
| 67b1e5fd40 | |||
| 5ea3e10139 | |||
| 3f9d2f22f5 | |||
| 3d36caa507 | |||
| 17a870967b | |||
| 29999d006e | |||
| db7f1c8af5 | |||
| f940489693 | |||
| 40947190ad | |||
| 9e0f8c5796 | |||
|
5693ef2aa2
|
|||
|
bc05b49222
|
|||
|
3e54e767c4
|
1
.gitignore
vendored
@@ -16,3 +16,4 @@ run.jl
|
||||
relog-web-legacy
|
||||
.vscode
|
||||
jobs
|
||||
tmp
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
name = "RELOG"
|
||||
uuid = "7cafaa7a-b311-45f0-b313-80bf15b5e5e5"
|
||||
authors = ["Alinson S. Xavier <git@axavier.org>"]
|
||||
version = "0.1.0"
|
||||
version = "0.8.0"
|
||||
|
||||
[deps]
|
||||
CRC = "44b605c4-b955-5f2b-9b6d-d2bd01d3d205"
|
||||
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
|
||||
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
|
||||
Geodesy = "0ef565a4-170c-5f04-8de2-149903a85f3d"
|
||||
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
|
||||
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
|
||||
NearestNeighbors = "b8a86587-4115-5ab1-83bc-aa920d37bbce"
|
||||
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
|
||||
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
|
||||
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
|
||||
TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
|
||||
ZipFile = "a5390f91-8eb1-5f08-bee0-b1d1ffed6cea"
|
||||
|
||||
71
README.md
Normal file
@@ -0,0 +1,71 @@
|
||||
<h1 align="center">RELOG: Supply Chain Analysis and Optimization</h1>
|
||||
<p align="center">
|
||||
<a href="https://doi.org/10.5281/zenodo.4302341">
|
||||
<img src="https://zenodo.org/badge/DOI/10.5281/zenodo.4302341.svg">
|
||||
</a>
|
||||
<a href="https://github.com/ANL-CEEESA/RELOG/releases/">
|
||||
<img src="https://img.shields.io/github/v/release/ANL-CEEESA/RELOG?include_prereleases&label=pre-release">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
**RELOG** is an open-source package designed to optimize supply chains for
|
||||
forward, reverse and circular manufacturing. Using mixed-integer linear
|
||||
optimization, RELOG helps users determine strategic decisions such as:
|
||||
|
||||
- Where and when to build manufacturing and recycling plants
|
||||
- The size of these plants, when to expand them, and by how much
|
||||
- The sources for each plant's input materials and the destinations for their
|
||||
processed outputs
|
||||
- Whether to process input materials immediately or store them for later use
|
||||
|
||||
RELOG has been successfully applied in research at various laboratories and
|
||||
universities, focusing on areas like critical material recovery from spent NiMH
|
||||
and Li-Ion batteries, biomass processing for hydrogen production, and the
|
||||
recycling of electronics, plastics and solar PV materials, among others. See
|
||||
references for more details.
|
||||
|
||||
## Screenshots
|
||||
|
||||
<img src="https://raw.githubusercontent.com/ANL-CEEESA/RELOG/refs/heads/circular/docs/src/assets/relog.png" width="1000px"/>
|
||||
|
||||
## Documentation
|
||||
|
||||
See official documentation at: https://anl-ceeesa.github.io/RELOG/
|
||||
|
||||
## Authors
|
||||
|
||||
- **Alinson S. Xavier,** Argonne National Laboratory <axavier@anl.gov>
|
||||
- **Nwike Iloeje,** Argonne National Laboratory <ciloeje@anl.gov>
|
||||
- **Kavitha G. Menon,** Argonne National Laboratory
|
||||
- **John Atkins,** Argonne National Laboratory
|
||||
- **Kyle Sun,** Argonne National Laboratory
|
||||
- **Audrey Gallier,** Argonne National Laboratory
|
||||
|
||||
## License
|
||||
|
||||
```text
|
||||
RELOG: Reverse Logistics Optimization
|
||||
Copyright © 2020-2025, UChicago Argonne, LLC. All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
conditions and the following disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
```
|
||||
5
docs/Project.toml
Normal file
@@ -0,0 +1,5 @@
|
||||
[deps]
|
||||
BetterFileWatching = "c9fd44ac-77b5-486c-9482-9798bd063cc6"
|
||||
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
|
||||
RELOG = "a2afcdf7-cf04-4913-85f9-c0d81ddf2008"
|
||||
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
|
||||
26
docs/make.jl
Normal file
@@ -0,0 +1,26 @@
|
||||
using Documenter
|
||||
using RELOG
|
||||
using BetterFileWatching
|
||||
|
||||
function make()
|
||||
makedocs(
|
||||
sitename="RELOG",
|
||||
pages=[
|
||||
"Home" => "index.md",
|
||||
"User guide" => [
|
||||
"problem.md",
|
||||
"format.md",
|
||||
]
|
||||
],
|
||||
format = Documenter.HTML(
|
||||
assets=["assets/custom.css"],
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
function watch()
|
||||
make()
|
||||
watch_folder("src") do event
|
||||
make()
|
||||
end
|
||||
end
|
||||
36
docs/src/assets/custom.css
Normal file
@@ -0,0 +1,36 @@
|
||||
@media screen and (min-width: 1056px) {
|
||||
#documenter .docs-main {
|
||||
max-width: 65rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tbody, thead, pre {
|
||||
border: 1px solid rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
table td, th {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
table p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
table td code {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
table tr,
|
||||
table th {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
table tr:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: transparent;
|
||||
color: rgb(232, 62, 140);
|
||||
}
|
||||
BIN
docs/src/assets/ex_amount_produced.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
docs/src/assets/ex_emissions.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
docs/src/assets/ex_plant_cost_per_year.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
docs/src/assets/ex_plant_locations.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
docs/src/assets/ex_transportation.png
Normal file
|
After Width: | Height: | Size: 586 KiB |
BIN
docs/src/assets/ex_transportation_amount_distance.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
docs/src/assets/ex_transportation_emissions.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/src/assets/relog.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
249
docs/src/format.md
Normal file
@@ -0,0 +1,249 @@
|
||||
# Input data format
|
||||
|
||||
RELOG accepts as input a JSON file with five sections: `parameters`, `products`,
|
||||
`centers`, `plants` and `emissions`. Below, we describe each section in more
|
||||
detail.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Key | Description |
|
||||
| :------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `time horizon (years)` | Number of years in the simulation. |
|
||||
| `building period (years)` | List of years in which we are allowed to open new plants. For example, if this parameter is set to `[1,2,3]`, we can only open plants during the first three years. By default, this equals `[1]`; that is, plants can only be opened during the first year. |
|
||||
| `distance metric` | Metric used to compute distances between pairs of locations. Valid options are: `"Euclidean"`, for the straight-line distance between points; or `"driving"` for an approximated driving distance. If not specified, defaults to `"Euclidean"`. |
|
||||
|
||||
#### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"parameters": {
|
||||
"time horizon (years)": 4,
|
||||
"building period (years)": [1],
|
||||
"distance metric": "driving"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 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. |
|
||||
| `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
|
||||
|
||||
```json
|
||||
{
|
||||
"products": {
|
||||
"P1": {
|
||||
"transportation cost ($/km/tonne)": 0.015,
|
||||
"transportation energy (J/km/tonne)": 0.12,
|
||||
"transportation emissions (tonne/km/tonne)": {
|
||||
"CO2": 0.052,
|
||||
"CH4": 0.003
|
||||
},
|
||||
"disposal limit (tonne)": 100.0
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Centers
|
||||
|
||||
| Key | Description |
|
||||
| :------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `latitude (deg)` | The latitude of the center. |
|
||||
| `longitude (deg)` | The longitude of the center. |
|
||||
| `input` | The name of the product this center takes as input from the plants. May be `null` if the center accept no input product. |
|
||||
| `outputs` | List of output products collected by the center. May be `[]` if none. |
|
||||
| `fixed output (tonne)` | Dictionary mapping the name of each output product to the amount generated by this center each year, regardless of how much input the center receives. For example, if this field equals to `{"P1": [1.0, 2.0, 3.0, 4.0]}`, then this center generates 1.0, 2.0, 3.0 and 4.0 tonnes of P2 in years 1, 2, 3 and 4, respectively. |
|
||||
| `variable output (tonne/tonne)` | Dictionary mapping the name of each output product 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 allowed 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. |
|
||||
|
||||
```json
|
||||
{
|
||||
"centers": {
|
||||
"C1": {
|
||||
"latitude (deg)": 41.881,
|
||||
"longitude (deg)": -87.623,
|
||||
"input": "P1",
|
||||
"outputs": ["P2", "P3"],
|
||||
"fixed output (tonne)": {
|
||||
"P2": [100, 50, 0, 0],
|
||||
"P3": [20, 10, 0, 0]
|
||||
},
|
||||
"variable output (tonne/tonne)": {
|
||||
"P2": [0.12, 0.25, 0.12, 0.0],
|
||||
"P3": [0.25, 0.25, 0.25, 0.0]
|
||||
},
|
||||
"revenue ($/tonne)": [12.0, 12.0, 12.0, 12.0],
|
||||
"collection cost ($/tonne)": {
|
||||
"P2": [0.25, 0.25, 0.25, 0.25],
|
||||
"P3": [0.37, 0.37, 0.37, 0.37]
|
||||
},
|
||||
"operating cost ($)": [150.0, 150.0, 150.0, 150.0],
|
||||
"disposal limit (tonne)": {
|
||||
"P2": [0, 0, 0, 0],
|
||||
"P3": [null, null, null, null]
|
||||
},
|
||||
"disposal cost ($/tonne)": {
|
||||
"P2": [0.23, 0.23, 0.23, 0.23],
|
||||
"P3": [1.0, 1.0, 1.0, 1.0]
|
||||
}
|
||||
},
|
||||
"C2": {
|
||||
"latitude (deg)": 41.881,
|
||||
"longitude (deg)": -87.623,
|
||||
"input": null,
|
||||
"outputs": ["P4"],
|
||||
"variable output (tonne/tonne)": {
|
||||
"P4": [0, 0, 0, 0]
|
||||
},
|
||||
"fixed output (tonne)": {
|
||||
"P4": [50, 60, 70, 80]
|
||||
},
|
||||
"revenue ($/tonne)": null,
|
||||
"collection cost ($/tonne)": {
|
||||
"P4": [0.25, 0.25, 0.25, 0.25]
|
||||
},
|
||||
"operating cost ($)": [150.0, 150.0, 150.0, 150.0],
|
||||
"disposal limit (tonne)": {
|
||||
"P4": [null, null, null, null]
|
||||
},
|
||||
"disposal cost ($/tonne)": {
|
||||
"P4": [0, 0, 0, 0]
|
||||
}
|
||||
},
|
||||
"C3": {
|
||||
"latitude (deg)": 41.881,
|
||||
"longitude (deg)": -87.623,
|
||||
"input": "P1",
|
||||
"outputs": [],
|
||||
"variable output (tonne/tonne)": {},
|
||||
"constant output (tonne)": {},
|
||||
"revenue ($/tonne)": [12.0, 12.0, 12.0, 12.0],
|
||||
"collection cost ($/tonne)": {},
|
||||
"operating cost ($)": [150.0, 150.0, 150.0, 150.0],
|
||||
"disposal limit (tonne)": {},
|
||||
"disposal cost ($/tonne)": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 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. |
|
||||
| `initial capacity (tonne)` | Capacity already available. If the plant has not been built yet, this should be `0`. |
|
||||
|
||||
The entries in the `capacities` list should be dictionaries with the following
|
||||
keys:
|
||||
|
||||
| Key | Description |
|
||||
| :---------------------------------- | :-------------------------------------------------------------------------------------------------- |
|
||||
| `size (tonne)` | The size of the plant. |
|
||||
| `opening cost ($)` | The cost to open a plant of this size. |
|
||||
| `fixed operating cost ($)` | The cost to keep the plant open, even if the plant doesn't process anything. |
|
||||
| `variable operating cost ($/tonne)` | The cost that the plant incurs to process each tonne of input. Must be the same for all capacities. |
|
||||
|
||||
```json
|
||||
{
|
||||
"plants": {
|
||||
"L1": {
|
||||
"latitude (deg)": 41.881,
|
||||
"longitude (deg)": -87.623,
|
||||
"input mix (%)": {
|
||||
"P1": 95.3,
|
||||
"P2": 4.7
|
||||
},
|
||||
"output (tonne)": {
|
||||
"P3": 0.25,
|
||||
"P4": 0.12,
|
||||
"P5": 0.1
|
||||
},
|
||||
"processing emissions (tonne)": {
|
||||
"CO2": 0.1
|
||||
},
|
||||
"storage cost ($/tonne)": {
|
||||
"P1": 0.1,
|
||||
"P2": 0.1
|
||||
},
|
||||
"storage limit (tonne)": {
|
||||
"P1": 100,
|
||||
"P2": null
|
||||
},
|
||||
"disposal cost ($/tonne)": {
|
||||
"P3": 0,
|
||||
"P4": 0.86,
|
||||
"P5": 0.25,
|
||||
},
|
||||
"disposal limit (tonne)": {
|
||||
"P3": null,
|
||||
"P4": 1000.0,
|
||||
"P5": 1000.0
|
||||
},
|
||||
"capacities": [
|
||||
{
|
||||
"size": 100,
|
||||
"opening cost ($)": 500,
|
||||
"fixed operating cost ($)": 300,
|
||||
"variable operating cost ($/tonne)": 5.0
|
||||
},
|
||||
{
|
||||
"size": 500,
|
||||
"opening cost ($)": 1000.0,
|
||||
"fixed operating cost ($)": 400.0,
|
||||
"variable operating cost ($/tonne)": 5.0.
|
||||
}
|
||||
],
|
||||
"initial capacity (tonne)": 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Emissions
|
||||
|
||||
| Key | Description |
|
||||
| :------------------ | :------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `limit (tonne)` | Maximum amount of this greenhouse gas allowed to be emitted per year across the entire supply chain. Entry may be `null` if unlimited. |
|
||||
| `penalty ($/tonne)` | Penalty cost per tonne of this greenhouse gas emitted. |
|
||||
|
||||
#### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"emissions": {
|
||||
"CO2": {
|
||||
"limit (tonne)": 1000.0,
|
||||
"penalty ($/tonne)": 50.0
|
||||
},
|
||||
"CH4": {
|
||||
"limit (tonne)": null,
|
||||
"penalty ($/tonne)": 1200.0
|
||||
},
|
||||
"N2O": {
|
||||
"limit (tonne)": 10.0,
|
||||
"penalty ($/tonne)": 15000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
62
docs/src/index.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# RELOG -- Supply Chain Analysis and Optimization
|
||||
|
||||
**RELOG** is an open-source package designed to optimize supply chains for
|
||||
forward, reverse and circular manufacturing. Using mixed-integer linear
|
||||
optimization, RELOG helps users determine strategic decisions such as:
|
||||
|
||||
- Where and when to build manufacturing and recycling plants
|
||||
- The size of these plants, when to expand them, and by how much
|
||||
- The sources for each plant's input materials and the destinations for their
|
||||
processed outputs
|
||||
- Whether to process input materials immediately or store them for later use
|
||||
|
||||
RELOG has been successfully applied in research at various laboratories and
|
||||
universities, focusing on areas like critical material recovery from spent NiMH
|
||||
and Li-Ion batteries, biomass processing for hydrogen production, and the
|
||||
recycling of electronics, plastics and solar PV materials, among others. See
|
||||
references for more details.
|
||||
|
||||
## Screenshots
|
||||
```@raw html
|
||||
<center>
|
||||
<img src="assets/relog.png" width="1000px"/>
|
||||
</center>
|
||||
```
|
||||
|
||||
## Authors
|
||||
|
||||
- **Alinson S. Xavier,** Argonne National Laboratory <axavier@anl.gov>
|
||||
- **Nwike Iloeje,** Argonne National Laboratory <ciloeje@anl.gov>
|
||||
- **Kavitha G. Menon,** Argonne National Laboratory
|
||||
- **John Atkins,** Argonne National Laboratory
|
||||
- **Kyle Sun,** Argonne National Laboratory
|
||||
- **Audrey Gallier,** Argonne National Laboratory
|
||||
|
||||
## License
|
||||
|
||||
```text
|
||||
RELOG: Reverse Logistics Optimization
|
||||
Copyright © 2020-2025, UChicago Argonne, LLC. All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
conditions and the following disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
```
|
||||
415
docs/src/problem.md
Normal file
@@ -0,0 +1,415 @@
|
||||
# Mathematical problem definition
|
||||
|
||||
## Overview and assumptions
|
||||
|
||||
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 includes 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
|
||||
materials and produce certain products. The outputs can be sent to another
|
||||
plant for further processing, to a collection & distribution center for
|
||||
customer sale, or simply disposed of at landfill. Plants have associated
|
||||
costs (capital, fixed and operating), as well as various limits (processing
|
||||
capacity, storage and disposal limits).
|
||||
|
||||
3. **Collection and Distribution Centers:** Facilities that receive final
|
||||
products from the plants, sell them to customers, and then collect them back
|
||||
once they reach their end-of-life. Collected products can either be sent to a
|
||||
plant for recycling or disposed of at a local landfill. Centers have
|
||||
associated revenue and various costs, such as operating cost, collection cost
|
||||
and disposal cost. The amount of material collected by a center can either be
|
||||
a fixed rate per year, or depend on the amount of product sold at the center
|
||||
in previous years.
|
||||
|
||||
!!! note
|
||||
|
||||
- We assume that transportation costs, energy and emissions scale linearly with transportation distance and amount being transported. Distances between locations are calculated using either approximated driving distances (continental U.S. only) or straight-line distances.
|
||||
- Once a plant is opened, we assume that it remains open until the end of the planning horizon. Similarly, once a plant is expanded, its size cannot be reduced at a later time.
|
||||
- In addition to serving as a source of end-of-life products, centers can also serve as a source for virgin materials. In this case, the center does not receive any inputs from manufacturing or recycling plants, and it generates the desired material at a fixed rate. Collection cost, in this case, refers to the cost to produce the virgin material.
|
||||
- We assume that centers accept either no input product, or a single input product.
|
||||
|
||||
## Sets
|
||||
|
||||
| Symbol | Description |
|
||||
| :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| $C$ | Set of collection and distribution centers |
|
||||
| $P$ | Set of manufacturing and recycling plants |
|
||||
| $M$ | Set of products and materials |
|
||||
| $G$ | Set of greenhouse gases |
|
||||
| $M^+_u$ | Set of output products of plant/center $u$. |
|
||||
| $M^-_u$ | Set of input products of plant/center $u$. |
|
||||
| $T$ | Set of time periods in the planning horizon. We assume $T=\{1,\ldots,t^{max}\}.$ |
|
||||
| $E$ | Set of transportation edges. Specifically, $(u,v,m) \in E$ if $m$ is an output of $u$ and an input of $v$, where $m \in M$ and $u, v \in P \cup C$. |
|
||||
| $E^-(v)$ | Set of incoming edges for plant/center v. Specifically, edges $(u,m)$ such that $(u,v,m) \in E$. |
|
||||
| $E^+(u)$ | Set of outgoing edges for plant/center u. Specifically, edges $(v,m)$ such that $(u,v,m) \in E$. |
|
||||
|
||||
## Constants
|
||||
|
||||
| Symbol | Description | Unit |
|
||||
| :---------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------- |
|
||||
| $K^{\text{dist}}_{uv}$ | Distance between plants/centers $u$ and $v$ | km |
|
||||
| $K^\text{cap-init}_p$ | Initial capacity of plant $p$ | tonne |
|
||||
| $K^\text{cap-max}_p$ | Maximum capacity of plant $p$ | tonne |
|
||||
| $K^\text{cap-min}_p$ | Minimum capacity of plant $p$ | 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{em-limit}_{gt}$ | Maximum amount of greenhouse gas $g$ allowed to be emitted (globally) at time $t$ | tonne |
|
||||
| $K^\text{em-plant}_{gpt}$ | Amount of greenhouse gas $g$ released by plant $p$ at time $t$ for each tonne of input material processed | tonne/tonne |
|
||||
| $K^\text{em-tr}_{gmt}$ | Amount of greenhouse gas $g$ released by transporting 1 tonne of material $m$ over one km at time $t$ | tonne/km-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{out-fix}_{cmt}$ | Fixed amount of material $m$ collected at center $c$ at time $t$ | tonne |
|
||||
| $K^\text{out-var-len}_{cm}$ | Length of the $K^\text{out-var}_{c,m,*}$ vector. | -- |
|
||||
| $K^\text{out-var}_{cmi}$ | Factor used to calculate variable amount of material $m$ collected at center $c$. See `eq_z_collected` for more details. | -- |
|
||||
| $K^\text{output}_{pmt}$ | Amount of material $m$ produced by plant $p$ at time $t$ for each tonne of input material processed | tonne |
|
||||
| $K^\text{storage-limit}_{pm}$ | Maximum amount of material $m$ that can be stored at plant $p$ at any time | 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{em}_{gt}$ | Penalty cost per tonne of greenhouse gas $g$ emitted at time $t$ | \$/tonne |
|
||||
| $R^\text{expand}_{pt}$ | Cost to increase capacity of plant $p$ at time $t$ | \$/tonne |
|
||||
| $R^\text{fix-exp}_{pt}$ | Increase in fixed operational cost for plant $p$ at time $t$ for every additional tonne of capacity | \$/tonne |
|
||||
| $R^\text{fix-min}_{pt}$ | Fixed operating cost for plant $p$ at time $t$ at minimum capacity | \$ |
|
||||
| $R^\text{fix}_{ct}$ | Fixed operating cost for center $c$ at time $t$ | \$ |
|
||||
| $R^\text{open}_{pt}$ | Cost to open plant $p$ at time $t$, at minimum capacity | \$ |
|
||||
| $R^\text{rev}_{ct}$ | Revenue for selling the input product of center $c$ at this center at time $t$ | \$/tonne |
|
||||
| $R^\text{storage}_{pmt}$ | Cost to store one tonne of material $m$ at plant $p$ at time $t$ for one year | \$/tonne |
|
||||
| $R^\text{tr}_{mt}$ | Cost to send material $m$ at time $t$ | \$/km-tonne |
|
||||
| $R^\text{var}_{pt}$ | Cost to process one tonne of input material at plant $p$ at time $t$ | \$/tonne |
|
||||
|
||||
## Decision variables
|
||||
|
||||
| Symbol | JuMP name | Description | Unit |
|
||||
| :--------------------------- | :------------------------------------------- | :------------------------------------------------------------------------------------------------------ | :----- |
|
||||
| $x_{pt}$ | `x[p.name, t]` | One if plant $p$ is operational at time $t$ | binary |
|
||||
| $y_{uvmt}$ | `y[u.name, v.name, m.name, t]` | Amount of product $m$ sent from plant/center $u$ to plant/center $v$ at time $t$ | tonne |
|
||||
| $z^{\text{exp}}_{pt}$ | `z_exp[p.name, t]` | Extra capacity installed at plant $p$ at time $t$ above the minimum capacity | tonne |
|
||||
| $z^{\text{collected}}_{cmt}$ | `z_collected[c.name, m.name, t]` | Amount of material $m$ collected by center $c$ at time $t$ | tonne |
|
||||
| $z^{\text{disp}}_{umt}$ | `z_disp[u.name, m.name, t]` | Amount of product $m$ disposed of at plant/center $u$ at time $t$ | tonne |
|
||||
| $z^{\text{em-plant}}_{gpt}$ | `z_em_plant[g.name, p.name, t]` | Amount of greenhouse gas $g$ released by plant $p$ at time $t$ | tonne |
|
||||
| $z^{\text{em-tr}}_{guvmt}$ | `z_em_tr[g.name, u.name, v.name, m.name, t]` | Amount of greenhouse gas $g$ released at time $t$ due to transportation of material $m$ from $u$ to $v$ | tonne |
|
||||
| $z^{\text{input}}_{ut}$ | `z_input[u.name, t]` | Total amount received by plant/center $u$ at time $t$ | tonne |
|
||||
| $z^{\text{prod}}_{umt}$ | `z_prod[u.name, m.name, t]` | Amount of product $m$ produced by plant/center $u$ at time $t$ | tonne |
|
||||
| $z^{\text{storage}}_{pmt}$ | `z_storage[p.name, m.name, t]` | Amount of input material $m$ stored at plant $p$ at the end of time $t$ | tonne |
|
||||
| $z^{\text{process}}_{pt}$ | `z_process[p.name, t]` | Total amount of input material processed by plant $p$ at time $t$ | tonne |
|
||||
|
||||
## Objective function
|
||||
|
||||
The goal is to minimize a linear objective function with the following terms:
|
||||
|
||||
- Transportation costs, which depend on transportation distance
|
||||
$K^{\text{dist}}_{uv}$ and product-specific factor $R^\text{tr}_{mt}$:
|
||||
|
||||
```math
|
||||
\sum_{(u, v, m) \in E} \sum_{t \in T} K^{\text{dist}}_{uv} R^\text{tr}_{mt} y_{uvmt}
|
||||
```
|
||||
|
||||
- Center revenue, obtained by selling products received from manufacturing and
|
||||
recycling plants:
|
||||
|
||||
```math
|
||||
- \sum_{c \in C} \sum_{(p,m) \in E^-(c)} \sum_{t \in T} R^\text{rev}_{ct} y_{pcmt}
|
||||
```
|
||||
|
||||
- Center collection cost, incurred for each tonne of output material sent to a
|
||||
plant:
|
||||
|
||||
```math
|
||||
\sum_{c \in C} \sum_{(p,m) \in E^+(c)} \sum_{t \in T} R^\text{collect}_{cmt} y_{cpmt}
|
||||
```
|
||||
|
||||
- Center disposal cost, incurred when disposing of output material, instead of
|
||||
sending it to a plant:
|
||||
|
||||
```math
|
||||
\sum_{c \in C} \sum_{m \in M^+_c} \sum_{t \in T} R^\text{disp}_{cmt} z^\text{disp}_{cmt}
|
||||
```
|
||||
|
||||
- Center fixed operating cost, incurred for every time period, regardless of
|
||||
input or output amounts:
|
||||
|
||||
```math
|
||||
\sum_{c \in C} \sum_{t \in T} R^\text{fix}_{ct}
|
||||
```
|
||||
|
||||
- Plant disposal cost, incurred for each tonne of product discarded at the
|
||||
plant:
|
||||
|
||||
```math
|
||||
\sum_{p \in P} \sum_{m \in M^+_p} \sum_{t \in T} R^\text{disp}_{pmt} z^\text{disp}_{pmt}
|
||||
```
|
||||
|
||||
- Plant opening cost, incurred when the plant goes from non-operational at time
|
||||
$t-1$ to operational at time $t$. Never incurred if the plant is initially
|
||||
open:
|
||||
|
||||
```math
|
||||
\sum_{p \in P} \sum_{t \in T} R^\text{open}_{pt} \left(
|
||||
x_{pt} - x_{p,t-1}
|
||||
\right)
|
||||
```
|
||||
|
||||
- Plant fixed operating cost, incurred for every time period, regardless of
|
||||
input or output amounts, as long as the plant is operational. Depends on the
|
||||
size of the plant:
|
||||
|
||||
```math
|
||||
\sum_{p \in P} \sum_{t \in T} \left(
|
||||
R^\text{fix-min}_{pt} x_{pt} +
|
||||
R^\text{fix-exp}_{pt} z^\text{exp}_{pt}
|
||||
\right)
|
||||
```
|
||||
|
||||
- Plant expansion cost, incurred whenever plant capacity increases:
|
||||
|
||||
```math
|
||||
\sum_{p \in P} \sum_{t \in T} R^\text{expand}_{pt} \left(z^\text{exp}_{pt} - z^\text{exp}_{p,t-1} \right)
|
||||
```
|
||||
|
||||
- Plant variable operating cost, incurred for each tonne of input material
|
||||
received by the plant:
|
||||
|
||||
```math
|
||||
\sum_{p \in P} \sum_{(u,m) \in E^-(p)} \sum_{t \in T} R^\text{var}_{pt} y_{upmt}
|
||||
```
|
||||
|
||||
- Plant storage cost, incurred for each tonne of material stored at the plant:
|
||||
|
||||
```math
|
||||
\sum_{p \in P} \sum_{m \in M^-_p} \sum_{t \in T} R^\text{storage}_{pmt} z^{\text{storage}}_{pmt}
|
||||
```
|
||||
|
||||
- Emissions penalty cost, incurred for each tonne of greenhouse gas emitted:
|
||||
|
||||
```math
|
||||
\sum_{g \in G} \sum_{t \in T} R^\text{em}_{gt} \left(
|
||||
\sum_{p \in P} z^{\text{em-plant}}_{gpt} + \sum_{(u,v,m) \in E} z^{\text{em-tr}}_{guvmt}
|
||||
\right)
|
||||
```
|
||||
|
||||
## Constraints
|
||||
|
||||
- Definition of plant input (`eq_z_input[p.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^{\text{input}}_{pt} = \sum_{(u,m) \in E^-(p)} y_{upmt}
|
||||
& \forall p \in P, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Definition of plant processing (`eq_z_process[p.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^{\text{process}}_{pt} = z^{\text{input}}_{pt} + \sum_{m \in M^-_p} \left(z^{\text{storage}}_{p,m,t-1} - z^{\text{storage}}_{pmt}\right)
|
||||
& \forall p \in P, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Plant processing mix must have correct proportion
|
||||
(`eq_process_mix[p.name, m.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& \sum_{u : (u,m) \in E^-(p)} y_{upmt} + z^{\text{storage}}_{p,m,t-1} - z^{\text{storage}}_{pmt}
|
||||
= K^\text{mix}_{pmt} z^{\text{process}}_{pt}
|
||||
& \forall p \in P, m \in M^-_p, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Definition of amount produced by a plant (`eq_z_prod[p.name, m.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^\text{prod}_{pmt} = K^\text{output}_{pmt} z^{\text{process}}_{pt}
|
||||
& \forall p \in P, m \in M^+_p, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Material produced by a plant must be sent somewhere or disposed of
|
||||
(`eq_balance[p.name, m.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^\text{prod}_{pmt} = \sum_{v : (v,m) \in E^+(p)} y_{pvmt} + z^\text{disp}_{pmt}
|
||||
& \forall p \in P, m \in M^+_p, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Plant can only be expanded if the plant is open, and up to a certain amount
|
||||
(`eq_exp_ub[p.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^\text{exp}_{pt} \leq \left(K^\text{cap-max}_p - K^\text{cap-min}_p) x_{pt}
|
||||
& \forall p \in P, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Plant capacity cannot decrease over time (`eq_capacity_nondecreasing[p.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^\text{exp}_{pt} \geq z^\text{exp}_{p,t-1}
|
||||
& \forall p \in P, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Plant is initially open if initial capacity is positive:
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& x_{p,0} = \begin{cases}
|
||||
0 & \text{ if } K^\text{cap-init}_p = 0 \\
|
||||
1 & \text{otherwise}
|
||||
\end{cases}
|
||||
& \forall p \in P
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Calculation of initial plant expansion:
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^\text{exp}_{p,0} = K^\text{cap-init}_p - K^\text{cap-min}_p
|
||||
& \forall p \in P
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Plants cannot process more than their current capacity
|
||||
(`eq_process_limit[p.name,t]`)
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^\text{process}_{pt} \leq K^\text{cap-min}_p x_{pt} + z^\text{exp}_{pt}
|
||||
& \forall p \in P, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Storage limit at the plants (`eq_storage_limit[p.name, m.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^{\text{storage}}_{pmt} \leq K^\text{storage-limit}_{pm}
|
||||
& \forall p \in P, m \in M^-_p, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Disposal limit at the plants (`eq_disposal_limit[p.name, m.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^\text{disp}_{pmt} \leq K^\text{disp-limit}_{pmt}
|
||||
& \forall p \in P, m \in M^+_p, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Once a plant is built, it must remain open until the end of the planning
|
||||
horizon (`eq_keep_open[p.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& x_{pt} \geq x_{p,t-1}
|
||||
& \forall p \in P, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Definition of center input (`eq_z_input[c.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^\text{input}_{ct} = \sum_{u : (u,m) \in E^-(c)} y_{ucmt}
|
||||
& \forall c \in C, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Calculation of amount collected by the center
|
||||
(`eq_z_collected[c.name, m.name, t]`). In the equation below,
|
||||
$K^\text{out-var-len}$ is the length of the $K^\text{out-var}_{c,m,*}$ vector.
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^\text{collected}_{cmt}
|
||||
= \sum_{i=0}^{\min\{K^\text{out-var-len}_{cm}-1,t-1\}} K^\text{out-var}_{c,m,i+1} z^\text{input}_{c,t-i}
|
||||
+ K^\text{out-fix}_{cmt}
|
||||
& \forall c \in C, m \in M^+_c, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Products collected at centers must be sent somewhere or disposed of
|
||||
(`eq_balance[c.name, m.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^\text{collected}_{cmt} = \sum_{v : (v,m) \in E^+(c)} y_{cvmt} + z^\text{disp}_{cmt}
|
||||
& \forall c \in C, m \in M^+_c, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Disposal limit at the centers (`eq_disposal_limit[c.name, m.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^\text{disp}_{cmt} \leq K^\text{disp-limit}_{cmt}
|
||||
& \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*}
|
||||
```
|
||||
|
||||
- Computation of transportation emissions
|
||||
(`eq_emission_tr[g.name, u.name, v.name, m.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^{\text{em-tr}}_{guvmt} = K^{\text{dist}}_{uv} K^\text{em-tr}_{gmt} y_{uvmt}
|
||||
& \forall g \in G, (u, v, m) \in E, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Computation of plant emissions (`eq_emission_plant[g.name, p.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^{\text{em-plant}}_{gpt} = K^\text{em-plant}_{gpt} z^{\text{process}}_{pt}
|
||||
& \forall g \in G, p \in P, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Global emissions limit (`eq_emission_limit[g.name, t]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& \sum_{p \in P} z^{\text{em-plant}}_{gpt} + \sum_{(u,v,m) \in E} z^{\text{em-tr}}_{guvmt} \leq K^\text{em-limit}_{gt}
|
||||
& \forall g \in G, t \in T
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- All stored materials must be processed by the end of the time horizon
|
||||
(`eq_storage_final[p.name, m.name]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^{\text{storage}}_{p,m,t^{max}} = 0
|
||||
& \forall p \in P, m \in M^-_p
|
||||
\end{align*}
|
||||
```
|
||||
|
||||
- Initial storage is zero (`eq_storage_initial[p.name, m.name]`):
|
||||
|
||||
```math
|
||||
\begin{align*}
|
||||
& z^{\text{storage}}_{p,m,0} = 0
|
||||
& \forall p \in P, m \in M^-_p
|
||||
\end{align*}
|
||||
```
|
||||
292
docs/src/reports.md
Normal file
@@ -0,0 +1,292 @@
|
||||
# Solution reports
|
||||
|
||||
In addition to the full output format described in [data formats](format.md), RELOG can also generate a number of simplified reports in tabular data format (CSV), which can be more easily processed by spreadsheet software (such as Microsoft Excel), by data analysis libraries (such as Pandas) or by relational databases (such as SQLite).
|
||||
|
||||
In this page, we also illustrate what types of charts and visualizations can be produced from these tabular data files. The sample charts have been produced using Python, matplotlib, seaborn and geopandas.
|
||||
|
||||
## Plants report
|
||||
|
||||
Report showing plant costs, capacities, energy expenditure and utilization factors. Generated by `RELOG.write_plants_report(solution, filename)`.
|
||||
|
||||
| Column | Description
|
||||
|:--------------------------------------|:---------------|
|
||||
| `plant type` | Plant type.
|
||||
| `location name` | Location name.
|
||||
| `year` | What year this row corresponds to. This reports includes one row for each year.
|
||||
| `latitude (deg)` | Latitude of the plant.
|
||||
| `longitude (deg)` | Longitude of the plant.
|
||||
| `capacity (tonne)` | Capacity of the plant at this point in time.
|
||||
| `amount received (tonne)` | Amount of input material received by the plant this year.
|
||||
| `amount processed (tonne)` | Amount of input material processed by the plant this year.
|
||||
| `amount in storage (tonne)` | Amount of input material in storage at the end of the year.
|
||||
| `utilization factor (%)` | Amount processed by the plant this year divided by current plant capacity.
|
||||
| `energy (GJ)` | Amount of energy expended by the plant this year.
|
||||
| `opening cost ($)` | Amount spent opening the plant. This value is only positive if the plant became operational this year.
|
||||
| `expansion cost ($)` | Amount spent this year expanding the plant capacity.
|
||||
| `fixed operating cost ($)` | Amount spent for keeping the plant operational this year.
|
||||
| `variable operating cost ($)` | Amount spent this year to process the input material.
|
||||
| `storage cost ($)` | Amount spent this year on storage.
|
||||
| `total cost ($)` | Sum of all previous plant costs.
|
||||
|
||||
|
||||
### Sample charts
|
||||
|
||||
* Bar plot with total plant costs per year, grouped by plant type (in Python):
|
||||
```python
|
||||
import pandas as pd
|
||||
import seaborn as sns; sns.set()
|
||||
|
||||
data = pd.read_csv("plants_report.csv")
|
||||
sns.barplot(x="year",
|
||||
y="total cost ($)",
|
||||
hue="plant type",
|
||||
data=data.groupby(["plant type", "year"])
|
||||
.sum()
|
||||
.reset_index());
|
||||
```
|
||||
|
||||
```@raw html
|
||||
<img src="../assets/ex_plant_cost_per_year.png" width="500px"/>
|
||||
```
|
||||
|
||||
* Map showing plant locations (in Python):
|
||||
```python
|
||||
import pandas as pd
|
||||
import geopandas as gp
|
||||
|
||||
# Plot base map
|
||||
world = gp.read_file(gp.datasets.get_path('naturalearth_lowres'))
|
||||
ax = world.plot(color='white', edgecolor='50', figsize=(13,6))
|
||||
ax.set_ylim([23, 50])
|
||||
ax.set_xlim([-128, -65])
|
||||
|
||||
# Plot plant locations
|
||||
data = pd.read_csv("nimh_plants.csv")
|
||||
points = gp.points_from_xy(data["longitude (deg)"],
|
||||
data["latitude (deg)"])
|
||||
gp.GeoDataFrame(data, geometry=points).plot(ax=ax);
|
||||
```
|
||||
|
||||
```@raw html
|
||||
<img src="../assets/ex_plant_locations.png" width="1000px"/>
|
||||
```
|
||||
|
||||
## Plant outputs report
|
||||
|
||||
Report showing amount of products produced, sent and disposed of by each plant, as well as disposal costs. Generated by `RELOG.write_plant_outputs_report(solution, filename)`.
|
||||
|
||||
|
||||
| Column | Description
|
||||
|:--------------------------------------|:---------------|
|
||||
| `plant type` | Plant type.
|
||||
| `location name` | Location name.
|
||||
| `year` | What year this row corresponds to. This reports includes one row for each year.
|
||||
| `product name` | Product being produced.
|
||||
| `amount produced (tonne)` | Amount of product produced this year.
|
||||
| `amount sent (tonne)` | Amount of product produced by this plant and sent to another plant for further processing this year.
|
||||
| `amount disposed (tonne)` | Amount produced produced by this plant and immediately disposed of locally this year.
|
||||
| `disposal cost ($)` | Disposal cost for this year.
|
||||
|
||||
### Sample charts
|
||||
|
||||
* Bar plot showing total amount produced for each product, grouped by year (in Python):
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
import seaborn as sns; sns.set()
|
||||
|
||||
data = pd.read_csv("plant_outputs_report.csv")
|
||||
sns.barplot(x="amount produced (tonne)",
|
||||
y="product name",
|
||||
hue="year",
|
||||
data=data.groupby(["product name", "year"])
|
||||
.sum()
|
||||
.reset_index());
|
||||
```
|
||||
|
||||
```@raw html
|
||||
<img src="../assets/ex_amount_produced.png" width="500px"/>
|
||||
```
|
||||
|
||||
|
||||
## Plant emissions report
|
||||
|
||||
Report showing amount of emissions produced by each plant. Generated by `RELOG.write_plant_emissions_report(solution, filename)`.
|
||||
|
||||
| Column | Description
|
||||
|:--------------------------------------|:---------------|
|
||||
| `plant type` | Plant type.
|
||||
| `location name` | Location name.
|
||||
| `year` | Year.
|
||||
| `emission type` | Type of emission.
|
||||
| `amount (tonne)` | Amount of emission produced by the plant this year.
|
||||
|
||||
### Sample charts
|
||||
|
||||
* Bar plot showing total emission by plant type, grouped type of emissions (in Python):
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
import seaborn as sns; sns.set()
|
||||
|
||||
data = pd.read_csv("plant_emissions_report.csv")
|
||||
sns.barplot(x="plant type",
|
||||
y="emission amount (tonne)",
|
||||
hue="emission type",
|
||||
data=data.groupby(["plant type", "emission type"])
|
||||
.sum()
|
||||
.reset_index());
|
||||
```
|
||||
|
||||
```@raw html
|
||||
<img src="../assets/ex_emissions.png" width="500px"/>
|
||||
```
|
||||
|
||||
## Products report
|
||||
|
||||
Report showing primary product amounts, locations and marginal costs. Generated by `RELOG.write_products_report(solution, filename)`.
|
||||
|
||||
| Column | Description
|
||||
|:--------------------------------------|:---------------|
|
||||
| `product name` | Product name.
|
||||
| `location name` | Name of the collection center.
|
||||
| `latitude (deg)` | Latitude of the collection center.
|
||||
| `longitude (deg)` | Longitude of the collection center.
|
||||
| `year` | What year this row corresponds to. This reports includes one row for each year.
|
||||
| `amount (tonne)` | Amount of product available at this collection center.
|
||||
| `amount disposed (tonne)` | Amount of product disposed of at this collection center.
|
||||
| `marginal cost ($/tonne)` | Cost to process one additional tonne of this product coming from this collection center.
|
||||
|
||||
|
||||
## Transportation report
|
||||
|
||||
Report showing amount of product sent from initial locations to plants, and from one plant to another. Includes the distance between each pair of locations, amount-distance shipped, transportation costs and energy expenditure. Generated by `RELOG.write_transportation_report(solution, filename)`.
|
||||
|
||||
|
||||
| Column | Description
|
||||
|:--------------------------------------|:---------------|
|
||||
| `source type` | If product is being shipped from an initial location, equals `Origin`. If product is being shipped from a plant, equals plant type.
|
||||
| `source location name` | Name of the location where the product is being shipped from.
|
||||
| `source latitude (deg)` | Latitude of the source location.
|
||||
| `source longitude (deg)` | Longitude of the source location.
|
||||
| `destination type`| Type of plant the product is being shipped to.
|
||||
| `destination location name`| Name of the location where the product is being shipped to.
|
||||
| `destination latitude (deg)` | Latitude of the destination location.
|
||||
| `destination longitude (deg)` | Longitude of the destination location.
|
||||
| `product`| Product being shipped.
|
||||
| `year`| Year.
|
||||
| `distance (km)`| Distance between source and destination.
|
||||
| `amount (tonne)`| Total amount of product being shipped between the two locations this year.
|
||||
| `amount-distance (tonne-km)`| Total amount being shipped this year times distance.
|
||||
| `transportation cost ($)`| Cost to transport this amount of product between the two locations for this year.
|
||||
| `transportation energy (GJ)`| Energy expended transporting this amount of product between the two locations.
|
||||
|
||||
### Sample charts
|
||||
|
||||
* Bar plot showing total amount-distance for each product type, grouped by year (in Python):
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
import seaborn as sns; sns.set()
|
||||
|
||||
data = pd.read_csv("transportation_report.csv")
|
||||
sns.barplot(x="product",
|
||||
y="amount-distance (tonne-km)",
|
||||
hue="year",
|
||||
data=data.groupby(["product", "year"])
|
||||
.sum()
|
||||
.reset_index());
|
||||
```
|
||||
|
||||
```@raw html
|
||||
<img src="../assets/ex_transportation_amount_distance.png" width="500px"/>
|
||||
```
|
||||
|
||||
* Map of transportation lines (in Python):
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
import geopandas as gp
|
||||
from shapely.geometry import Point, LineString
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib import collections
|
||||
|
||||
# Plot base map
|
||||
world = gp.read_file(gp.datasets.get_path('naturalearth_lowres'))
|
||||
ax = world.plot(color='white', edgecolor='50', figsize=(14,7))
|
||||
ax.set_ylim([23, 50])
|
||||
ax.set_xlim([-128, -65])
|
||||
|
||||
# Draw transportation lines
|
||||
data = pd.read_csv("transportation_report.csv")
|
||||
lines = [[(row["source longitude (deg)"], row["source latitude (deg)"]),
|
||||
(row["destination longitude (deg)"], row["destination latitude (deg)"])
|
||||
] for (index, row) in data.iterrows()]
|
||||
ax.add_collection(collections.LineCollection(lines,
|
||||
linewidths=0.25,
|
||||
zorder=1,
|
||||
alpha=0.5,
|
||||
color="50"))
|
||||
|
||||
# Draw source points
|
||||
points = gp.points_from_xy(data["source longitude (deg)"],
|
||||
data["source latitude (deg)"])
|
||||
gp.GeoDataFrame(data, geometry=points).plot(ax=ax,
|
||||
color="0.5",
|
||||
markersize=1);
|
||||
|
||||
# Draw destination points
|
||||
points = gp.points_from_xy(data["destination longitude (deg)"],
|
||||
data["destination latitude (deg)"])
|
||||
gp.GeoDataFrame(data, geometry=points).plot(ax=ax,
|
||||
color="red",
|
||||
markersize=50);
|
||||
```
|
||||
|
||||
```@raw html
|
||||
<img src="../assets/ex_transportation.png" width="1000px"/>
|
||||
```
|
||||
|
||||
|
||||
## Transportation emissions report
|
||||
|
||||
Report showing emissions for each trip between initial locations and plants, and between pairs of plants. Generated by `RELOG.write_transportation_emissions_report(solution, filename)`.
|
||||
|
||||
| Column | Description
|
||||
|:--------------------------------------|:---------------|
|
||||
| `source type` | If product is being shipped from an initial location, equals `Origin`. If product is being shipped from a plant, equals plant type.
|
||||
| `source location name` | Name of the location where the product is being shipped from.
|
||||
| `source latitude (deg)` | Latitude of the source location.
|
||||
| `source longitude (deg)` | Longitude of the source location.
|
||||
| `destination type`| Type of plant the product is being shipped to.
|
||||
| `destination location name`| Name of the location where the product is being shipped to.
|
||||
| `destination latitude (deg)` | Latitude of the destination location.
|
||||
| `destination longitude (deg)` | Longitude of the destination location.
|
||||
| `product`| Product being shipped.
|
||||
| `year`| Year.
|
||||
| `distance (km)`| Distance between source and destination.
|
||||
| `shipped amount (tonne)`| Total amount of product being shipped between the two locations this year.
|
||||
| `shipped amount-distance (tonne-km)`| Total amount being shipped this year times distance.
|
||||
| `emission type` | Type of emission.
|
||||
| `emission amount (tonne)` | Amount of emission produced by transportation segment this year.
|
||||
|
||||
### Sample charts
|
||||
|
||||
* Bar plot showing total emission amount by emission type, grouped by type of product being transported (in Python):
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
import seaborn as sns; sns.set()
|
||||
|
||||
data = pd.read_csv("transportation_emissions_report.csv")
|
||||
sns.barplot(x="emission type",
|
||||
y="emission amount (tonne)",
|
||||
hue="product",
|
||||
data=data.groupby(["product", "emission type"])
|
||||
.sum()
|
||||
.reset_index());
|
||||
```
|
||||
|
||||
```@raw html
|
||||
<img src="../assets/ex_transportation_emissions.png" width="500px"/>
|
||||
```
|
||||
131
docs/src/usage.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# Usage
|
||||
|
||||
## 1. Installation
|
||||
|
||||
To use RELOG, the first step is to install the [Julia programming language](https://julialang.org/) on your machine. Note that RELOG was developed and tested with Julia 1.8 and may not be compatible with newer versions. After Julia is installed, launch the Julia console, then run:
|
||||
|
||||
```julia
|
||||
using Pkg
|
||||
Pkg.add(name="RELOG", version="0.7")
|
||||
```
|
||||
|
||||
## 2. Modeling the problem
|
||||
|
||||
The two main model components in RELOG are **products** and **plants**.
|
||||
|
||||
A **product** is any material that needs to be recycled, any intermediary product produced during the recycling process, or any product recovered at the end of the process. For example, in a NiMH battery recycling study case, products could include (i) the original batteries to be recycled; (ii) the cathode and anode parts of the battery; (iii) rare-earth elements and (iv) scrap metals.
|
||||
|
||||
- The model assumes that some products are initially available at user-specified locations (described by their latitude, longitude and the amount available), while other products only become available during the recycling process.
|
||||
|
||||
- Products that are initially available must be sent to a plant for processing during the same time period they became available.
|
||||
|
||||
- Transporting products from one location to another incurs a transportation cost (`$/km/tonne`), spends some amount of energy (`J/km/tonne`) and may generate multiple types of emissions (`tonne/tonne`). All these parameters are user-specified and may be product- and time-specific.
|
||||
|
||||
A **plant** is a facility that converts one type of product to another. RELOG assumes that each plant receives a single type of product as input and converts this input into multiple types of products. Multiple types of plants, with different inputs, outputs and performance characteristics, may be specified. In the NiMH battery recycling study case, for example, one type of plant could be a _disassembly plant_, which converts _batteries_ into _cathode_ and _anode_. Another type of plant could be _anode recycling plant_, which converts _anode_ into _rare-earth elements_ and _scrap metals_.
|
||||
|
||||
- To process each tonne of input material, plants incur a variable operating cost (`$/tonne`), spend some amount of energy (`GJ/tonne`), and produce multiple types of emissions (`tonne/tonne`). Plants also incur a fixed operating cost (`$`) regardless of the amount of material they process. All these parameters are user-specified and may be region- and time-specific.
|
||||
|
||||
- Plants can be built at user-specified potential locations. Opening a plant incurs a one-time opening cost (`$`) which may be region- and time-specific. Plants also have a limited capacity (in `tonne`), which indicates the maximum amount of input material they are able to process per year. When specifying potential locations for each type of plant, it is also possible to specify the minimum and maximum capacity of the plants that can be built at that particular location. Different plants sizes may have different opening costs and fixed operating costs. After a plant is built, it can be further expanded in the following years, up to its maximum capacity.
|
||||
|
||||
- Products received by a plant can be either processed immediately or stored for later processing. Plants have a maximum storage capacity (`tonne`). Storage costs (`$/tonne`) can also be specified.
|
||||
|
||||
- All products generated by a plant can either be sent to another plant for further processing, or disposed of locally for either a profit or a loss (`$/tonne`). To model environmental regulations, it is also possible to specify the maximum amount of each product that can be disposed of at each location.
|
||||
|
||||
All user parameters specified above must be provided to RELOG as a JSON file, which is fully described in the [data format page](format.md).
|
||||
|
||||
## 3. Running the optimization
|
||||
|
||||
After creating a JSON file describing the reverse manufacturing process and the input data, the following example illustrates how to use the package to find the optimal set of decisions:
|
||||
|
||||
```julia
|
||||
# Import package
|
||||
using RELOG
|
||||
|
||||
# Solve optimization problem
|
||||
solution = RELOG.solve("/home/user/instance.json")
|
||||
|
||||
# Write full solution in JSON format
|
||||
RELOG.write(solution, "solution.json")
|
||||
|
||||
# Write simplified reports in CSV format
|
||||
RELOG.write_plants_report(solution, "plants.csv")
|
||||
RELOG.write_transportation_report(solution, "transportation.csv")
|
||||
```
|
||||
|
||||
For a complete description of the file formats above, and for a complete list of available reports, see the [data format page](format.md).
|
||||
|
||||
## 4. What-If Analysis
|
||||
|
||||
Fundamentally, RELOG decides when and where to build plants based on a deterministic optimization problem that minimizes costs for a particular input file provided by the user. In practical situations, it may not be possible to perfectly estimate some (or most) entries in this input file in advance, such as costs, demands and emissions. In this situation, it may be interesting to evaluate how well does the facility location plan produced by RELOG work if costs, demands and emissions turn out to be different.
|
||||
|
||||
To simplify this what-if analysis, RELOG provides the `resolve` method, which updates a previous solution based on a new scenario, but keeps some of the previous decisions fixed. More precisely, given an optimal solution produced by RELOG and a new input file describing the new scenario, the `resolve` method reoptimizes the supply chain and produces a new solution which still builds the same set of plants as before, in exactly the same locations and with the same capacities, but that may now utilize the plants differently, based on the new data. For example, in the new solution, plants that were previously used at full capacity may now be utilized at half-capacity instead. As another example, regions that were previously served by a certain plant may now be served by a different one.
|
||||
|
||||
The following snippet shows how to use the method:
|
||||
|
||||
```julia
|
||||
# Import package
|
||||
using RELOG
|
||||
|
||||
# Optimize for the average scenario
|
||||
solution_avg, model_avg = RELOG.solve("input_avg.json", return_model=true)
|
||||
|
||||
# Write reports for the average scenario
|
||||
RELOG.write_plants_report(solution_avg, "plants_avg.csv")
|
||||
RELOG.write_transportation_report(solution_avg, "transportation_avg.csv")
|
||||
|
||||
# Re-optimize for the high-demand scenario, keeping plants fixed
|
||||
solution_high = RELOG.resolve(model_avg, "input_high.json")
|
||||
|
||||
# Write reports for the high-demand scenario
|
||||
RELOG.write_plants_report(solution_high, "plants_high.csv")
|
||||
RELOG.write_transportation_report(solution_high, "transportation_high.csv")
|
||||
```
|
||||
|
||||
To use the `resolve` method, the new input file should be very similar to the original one. Only the following entries are allowed to change:
|
||||
|
||||
- **Products:** Transportation costs, energy, emissions and initial amounts (latitude, longitude and amount).
|
||||
- **Plants:** Energy and emissions.
|
||||
- **Plant's location:** Latitude and longitude.
|
||||
- **Plant's storage:** Cost.
|
||||
- **Plant's capacity:** Opening cost, fixed operating cost and variable operating cost.
|
||||
|
||||
## 5. Advanced options
|
||||
|
||||
### 5.1 Changing the solver
|
||||
|
||||
By default, RELOG internally uses [HiGHS](https://github.com/ERGO-Code/HiGHS), an open-source and freely-available Mixed-Integer Linear Programming solver. For larger-scale test cases, a commercial solver such as Gurobi, CPLEX or XPRESS is recommended. The following snippet shows how to switch to Gurobi, for example:
|
||||
|
||||
```julia
|
||||
using RELOG, Gurobi, JuMP
|
||||
|
||||
gurobi = optimizer_with_attributes(
|
||||
Gurobi.Optimizer,
|
||||
"TimeLimit" => 3600,
|
||||
"MIPGap" => 0.001,
|
||||
)
|
||||
|
||||
RELOG.solve(
|
||||
"instance.json",
|
||||
output="solution.json",
|
||||
optimizer=gurobi,
|
||||
)
|
||||
```
|
||||
|
||||
### 5.2 Multi-period heuristics
|
||||
|
||||
For large-scale instances, it may be too time-consuming to find an exact optimal solution to the multi-period version of the problem. For these situations, RELOG includes a heuristic solution method, which proceeds as follows:
|
||||
|
||||
1. First, RELOG creates a single-period version of the problem, in which most values are replaced by their averages. This single-period problem is typically much easier to solve.
|
||||
|
||||
2. After solving the simplified problem, RELOG resolves the multi-period version of the problem, but considering only candidate plant locations that were selected by the optimal solution to the single-period version of the problem. All remaining candidate plant locations are removed.
|
||||
|
||||
To solve an instance using this heuristic, use the option `heuristic=true`, as shown below.
|
||||
|
||||
```julia
|
||||
using RELOG
|
||||
|
||||
solution = RELOG.solve(
|
||||
"/home/user/instance.json",
|
||||
heuristic=true,
|
||||
)
|
||||
```
|
||||
@@ -1,6 +1,12 @@
|
||||
module RELOG
|
||||
|
||||
_round(x::Number) = round(x, digits = 5)
|
||||
function _round(x::Number)
|
||||
if abs(x) < 1e-5
|
||||
return 0
|
||||
else
|
||||
return round(x, digits = 5)
|
||||
end
|
||||
end
|
||||
|
||||
include("instance/structs.jl")
|
||||
include("instance/parse.jl")
|
||||
|
||||
@@ -2,18 +2,29 @@ using JSON
|
||||
using OrderedCollections
|
||||
|
||||
function parsefile(path::String)::Instance
|
||||
return RELOG.parse(JSON.parsefile(path, dicttype = () -> OrderedDict()))
|
||||
return RELOG.parse(JSON.parsefile(path; dicttype = OrderedDict))
|
||||
end
|
||||
|
||||
function parse(json)::Instance
|
||||
# Read parameters
|
||||
time_horizon = json["parameters"]["time horizon (years)"]
|
||||
building_period = json["parameters"]["building period (years)"]
|
||||
distance_metric = json["parameters"]["distance metric"]
|
||||
|
||||
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)
|
||||
# Read distance metric
|
||||
distance_metric_str = lowercase(json["parameters"]["distance metric"])
|
||||
if distance_metric_str == "driving"
|
||||
distance_metric = KnnDrivingDistance()
|
||||
elseif distance_metric_str == "euclidean"
|
||||
distance_metric = EuclideanDistance()
|
||||
else
|
||||
error("Invalid distance metric: $distance_metric_str")
|
||||
end
|
||||
|
||||
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[]
|
||||
@@ -22,7 +33,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
|
||||
@@ -41,10 +53,8 @@ function parse(json)::Instance
|
||||
end
|
||||
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])]
|
||||
for p in outputs
|
||||
)
|
||||
prod_dict(key, null_val) =
|
||||
OrderedDict(p => timeseries(cdict[key][p.name]; null_val) for p in outputs)
|
||||
fixed_output = prod_dict("fixed output (tonne)", 0.0)
|
||||
var_output = prod_dict("variable output (tonne/tonne)", 0.0)
|
||||
collection_cost = prod_dict("collection cost (\$/tonne)", 0.0)
|
||||
@@ -100,6 +110,32 @@ function parse(json)::Instance
|
||||
)
|
||||
end
|
||||
|
||||
# Validate capacity count and duplicate if needed
|
||||
if length(capacities) == 0
|
||||
error("Plant '$name' must have at least one capacity defined")
|
||||
elseif length(capacities) == 1
|
||||
# Duplicate the single capacity
|
||||
push!(capacities, capacities[1])
|
||||
elseif length(capacities) > 2
|
||||
error(
|
||||
"Plant '$name' cannot have more than 2 capacities, got $(length(capacities))",
|
||||
)
|
||||
end
|
||||
|
||||
# Validate capacity sizes are non-decreasing
|
||||
if capacities[1].size > capacities[2].size
|
||||
error(
|
||||
"Plant '$name' capacity sizes must be non-decreasing: $(capacities[1].size) > $(capacities[2].size)",
|
||||
)
|
||||
end
|
||||
|
||||
# Validate variable operating costs are the same
|
||||
if capacities[1].var_operating_cost != capacities[2].var_operating_cost
|
||||
error(
|
||||
"Plant '$name' variable operating costs must be the same across all capacities",
|
||||
)
|
||||
end
|
||||
|
||||
plant = Plant(;
|
||||
name,
|
||||
latitude,
|
||||
@@ -118,6 +154,19 @@ function parse(json)::Instance
|
||||
plants_by_name[name] = plant
|
||||
end
|
||||
|
||||
# Read emissions
|
||||
emissions = Emissions[]
|
||||
emissions_by_name = OrderedDict{String,Emissions}()
|
||||
if haskey(json, "emissions")
|
||||
for (name, edict) in json["emissions"]
|
||||
limit = timeseries(edict["limit (tonne)"], null_val = Inf)
|
||||
penalty = timeseries(edict["penalty (\$/tonne)"])
|
||||
emission = Emissions(; name, limit, penalty)
|
||||
push!(emissions, emission)
|
||||
emissions_by_name[name] = emission
|
||||
end
|
||||
end
|
||||
|
||||
return Instance(;
|
||||
time_horizon,
|
||||
building_period,
|
||||
@@ -128,5 +177,7 @@ function parse(json)::Instance
|
||||
centers_by_name,
|
||||
plants,
|
||||
plants_by_name,
|
||||
emissions,
|
||||
emissions_by_name,
|
||||
)
|
||||
end
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
using OrderedCollections
|
||||
|
||||
abstract type DistanceMetric end
|
||||
|
||||
Base.@kwdef mutable struct KnnDrivingDistance <: DistanceMetric
|
||||
tree = nothing
|
||||
ratios = nothing
|
||||
end
|
||||
|
||||
mutable struct EuclideanDistance <: DistanceMetric end
|
||||
|
||||
Base.@kwdef struct Product
|
||||
name::String
|
||||
tr_cost::Vector{Float64}
|
||||
tr_energy::Vector{Float64}
|
||||
tr_emissions::OrderedDict{String,Vector{Float64}}
|
||||
disposal_limit::Vector{Float64}
|
||||
end
|
||||
|
||||
Base.@kwdef struct Center
|
||||
@@ -44,14 +54,22 @@ Base.@kwdef struct Plant
|
||||
initial_capacity::Float64
|
||||
end
|
||||
|
||||
Base.@kwdef struct Emissions
|
||||
name::String
|
||||
limit::Vector{Float64}
|
||||
penalty::Vector{Float64}
|
||||
end
|
||||
|
||||
Base.@kwdef struct Instance
|
||||
building_period::Vector{Int}
|
||||
centers_by_name::OrderedDict{String,Center}
|
||||
centers::Vector{Center}
|
||||
distance_metric::String
|
||||
distance_metric::DistanceMetric
|
||||
products_by_name::OrderedDict{String,Product}
|
||||
products::Vector{Product}
|
||||
time_horizon::Int
|
||||
plants::Vector{Plant}
|
||||
plants_by_name::OrderedDict{String,Plant}
|
||||
emissions_by_name::OrderedDict{String,Emissions}
|
||||
emissions::Vector{Emissions}
|
||||
end
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# RELOG: Reverse Logistics Optimization
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
using JuMP
|
||||
|
||||
function R_expand(p::Plant, t::Int)
|
||||
denominator = p.capacities[2].size - p.capacities[1].size
|
||||
if denominator == 0
|
||||
return 0.0
|
||||
end
|
||||
return (p.capacities[2].opening_cost[t] - p.capacities[1].opening_cost[t]) / denominator
|
||||
end
|
||||
|
||||
function R_fix_exp(p::Plant, t::Int)
|
||||
denominator = p.capacities[2].size - p.capacities[1].size
|
||||
if denominator == 0
|
||||
return 0.0
|
||||
end
|
||||
return (p.capacities[2].fix_operating_cost[t] - p.capacities[1].fix_operating_cost[t]) /
|
||||
denominator
|
||||
end
|
||||
|
||||
function build_model(instance::Instance; optimizer, variable_names::Bool = false)
|
||||
model = JuMP.Model(optimizer)
|
||||
centers = instance.centers
|
||||
@@ -8,6 +29,15 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false
|
||||
T = 1:instance.time_horizon
|
||||
model.ext[:instance] = instance
|
||||
|
||||
# Constants
|
||||
# -------------------------------------------------------------------------
|
||||
K_cap_min = Dict(p => p.capacities[1].size for p in plants)
|
||||
K_cap_max = Dict(p => p.capacities[2].size for p in plants)
|
||||
R_open = Dict((p, t) => p.capacities[1].opening_cost[t] for p in plants for t in T)
|
||||
R_fix_min =
|
||||
Dict((p, t) => p.capacities[1].fix_operating_cost[t] for p in plants for t in T)
|
||||
|
||||
|
||||
# Transportation edges
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@@ -60,7 +90,13 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false
|
||||
# Distances
|
||||
model.ext[:distances] = distances = Dict()
|
||||
for (p1, p2, m) in E
|
||||
d = _calculate_distance(p1.latitude, p1.longitude, p2.latitude, p2.longitude)
|
||||
d = _calculate_distance(
|
||||
p1.latitude,
|
||||
p1.longitude,
|
||||
p2.latitude,
|
||||
p2.longitude,
|
||||
instance.distance_metric,
|
||||
)
|
||||
distances[p1, p2, m] = d
|
||||
end
|
||||
|
||||
@@ -106,12 +142,50 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false
|
||||
z_input[c.name, t] = @variable(model, lower_bound = 0)
|
||||
end
|
||||
|
||||
# Plant expansion
|
||||
z_exp = _init(model, :z_exp)
|
||||
for p in plants
|
||||
z_exp[p.name, 0] = max(0, p.initial_capacity - K_cap_min[p])
|
||||
end
|
||||
for p in plants, t in T
|
||||
z_exp[p.name, t] = @variable(model, lower_bound = 0)
|
||||
end
|
||||
|
||||
# Total amount collected by the center
|
||||
z_collected = _init(model, :z_collected)
|
||||
for c in centers, m in c.outputs, t in T
|
||||
z_collected[c.name, m.name, t] = @variable(model, lower_bound = 0)
|
||||
end
|
||||
|
||||
# Amount of input material stored at plant at end of time period
|
||||
z_storage = _init(model, :z_storage)
|
||||
for p in plants
|
||||
for m in keys(p.input_mix)
|
||||
z_storage[p.name, m.name, 0] = 0 # Initial storage is zero
|
||||
end
|
||||
end
|
||||
for p in plants, m in keys(p.input_mix), t in T
|
||||
z_storage[p.name, m.name, t] = @variable(model, lower_bound = 0)
|
||||
end
|
||||
|
||||
# Total amount of input material processed by plant
|
||||
z_process = _init(model, :z_process)
|
||||
for p in plants, t in T
|
||||
z_process[p.name, t] = @variable(model, lower_bound = 0)
|
||||
end
|
||||
|
||||
# Transportation emissions by greenhouse gas
|
||||
z_em_tr = _init(model, :z_em_tr)
|
||||
for (p1, p2, m) in E, t in T, g in keys(m.tr_emissions)
|
||||
z_em_tr[g, p1.name, p2.name, m.name, t] = @variable(model, lower_bound = 0)
|
||||
end
|
||||
|
||||
# Plant emissions by greenhouse gas
|
||||
z_em_plant = _init(model, :z_em_plant)
|
||||
for p in plants, t in T, g in keys(p.emissions)
|
||||
z_em_plant[g, p.name, t] = @variable(model, lower_bound = 0)
|
||||
end
|
||||
|
||||
|
||||
# Objective function
|
||||
# -------------------------------------------------------------------------
|
||||
@@ -153,16 +227,18 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false
|
||||
|
||||
# Plants: Opening cost
|
||||
for p in plants, t in T
|
||||
add_to_expression!(
|
||||
obj,
|
||||
p.capacities[1].opening_cost[t],
|
||||
(x[p.name, t] - x[p.name, t-1]),
|
||||
)
|
||||
add_to_expression!(obj, R_open[p, t], (x[p.name, t] - x[p.name, t-1]))
|
||||
end
|
||||
|
||||
# Plants: Fixed operating cost
|
||||
for p in plants, t in T
|
||||
add_to_expression!(obj, p.capacities[1].fix_operating_cost[t], x[p.name, t])
|
||||
add_to_expression!(obj, R_fix_min[p, t], x[p.name, t])
|
||||
add_to_expression!(obj, R_fix_exp(p, t), z_exp[p.name, t])
|
||||
end
|
||||
|
||||
# Plants: Expansion cost
|
||||
for p in plants, t in T
|
||||
add_to_expression!(obj, R_expand(p, t), z_exp[p.name, t] - z_exp[p.name, t-1])
|
||||
end
|
||||
|
||||
# Plants: Variable operating cost
|
||||
@@ -174,6 +250,35 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false
|
||||
)
|
||||
end
|
||||
|
||||
# Plants: Storage cost
|
||||
for p in plants, m in keys(p.storage_cost), t in T
|
||||
add_to_expression!(obj, p.storage_cost[m][t], z_storage[p.name, m.name, t])
|
||||
end
|
||||
|
||||
# Emissions penalty cost
|
||||
for emission in instance.emissions, t in T
|
||||
# Plant emissions penalty
|
||||
for p in plants
|
||||
if emission.name in keys(p.emissions)
|
||||
add_to_expression!(
|
||||
obj,
|
||||
emission.penalty[t],
|
||||
z_em_plant[emission.name, p.name, t],
|
||||
)
|
||||
end
|
||||
end
|
||||
# Transportation emissions penalty
|
||||
for (p1, p2, m) in E
|
||||
if emission.name in keys(m.tr_emissions)
|
||||
add_to_expression!(
|
||||
obj,
|
||||
emission.penalty[t],
|
||||
z_em_tr[emission.name, p1.name, p2.name, m.name, t],
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@objective(model, Min, obj)
|
||||
|
||||
# Constraints
|
||||
@@ -189,13 +294,27 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false
|
||||
)
|
||||
end
|
||||
|
||||
# Plants: Must meet input mix
|
||||
eq_input_mix = _init(model, :eq_input_mix)
|
||||
for p in plants, m in keys(p.input_mix), t in T
|
||||
eq_input_mix[p.name, m.name, t] = @constraint(
|
||||
# Plants: Definition of total processing amount
|
||||
eq_z_process = _init(model, :eq_z_process)
|
||||
for p in plants, t in T
|
||||
eq_z_process[p.name, t] = @constraint(
|
||||
model,
|
||||
sum(y[src.name, p.name, m.name, t] for (src, m2) in E_in[p] if m == m2) ==
|
||||
z_input[p.name, t] * p.input_mix[m][t]
|
||||
z_process[p.name, t] ==
|
||||
z_input[p.name, t] + sum(
|
||||
z_storage[p.name, m.name, t-1] - z_storage[p.name, m.name, t] for
|
||||
m in keys(p.input_mix)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
# Plants: Processing mix must have correct proportion
|
||||
eq_process_mix = _init(model, :eq_process_mix)
|
||||
for p in plants, m in keys(p.input_mix), t in T
|
||||
eq_process_mix[p.name, m.name, t] = @constraint(
|
||||
model,
|
||||
sum(y[src.name, p.name, m.name, t] for (src, m2) in E_in[p] if m == m2) +
|
||||
z_storage[p.name, m.name, t-1] - z_storage[p.name, m.name, t] ==
|
||||
z_process[p.name, t] * p.input_mix[m][t]
|
||||
)
|
||||
end
|
||||
|
||||
@@ -204,7 +323,7 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false
|
||||
for p in plants, m in keys(p.output), t in T
|
||||
eq_z_prod[p.name, m.name, t] = @constraint(
|
||||
model,
|
||||
z_prod[p.name, m.name, t] == z_input[p.name, t] * p.output[m][t]
|
||||
z_prod[p.name, m.name, t] == z_process[p.name, t] * p.output[m][t]
|
||||
)
|
||||
end
|
||||
|
||||
@@ -219,11 +338,22 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false
|
||||
)
|
||||
end
|
||||
|
||||
# Plants: Capacity limit
|
||||
eq_capacity = _init(model, :eq_capacity)
|
||||
# Plants: Expansion upper bound
|
||||
eq_exp_ub = _init(model, :eq_exp_ub)
|
||||
for p in plants, t in T
|
||||
eq_capacity[p.name, t] =
|
||||
@constraint(model, z_input[p.name, t] <= p.capacities[1].size * x[p.name, t])
|
||||
eq_exp_ub[p.name, t] = @constraint(
|
||||
model,
|
||||
z_exp[p.name, t] <= (K_cap_max[p] - K_cap_min[p]) * x[p.name, t]
|
||||
)
|
||||
end
|
||||
|
||||
# Plants: Processing limit
|
||||
eq_process_limit = _init(model, :eq_process_limit)
|
||||
for p in plants, t in T
|
||||
eq_process_limit[p.name, t] = @constraint(
|
||||
model,
|
||||
z_process[p.name, t] <= K_cap_min[p] * x[p.name, t] + z_exp[p.name, t]
|
||||
)
|
||||
end
|
||||
|
||||
# Plants: Disposal limit
|
||||
@@ -240,6 +370,13 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false
|
||||
eq_keep_open[p.name, t] = @constraint(model, x[p.name, t] >= x[p.name, t-1])
|
||||
end
|
||||
|
||||
# Plants: Capacity cannot decrease over time
|
||||
eq_capacity_nondecreasing = _init(model, :eq_capacity_nondecreasing)
|
||||
for p in plants, t in T
|
||||
eq_capacity_nondecreasing[p.name, t] =
|
||||
@constraint(model, z_exp[p.name, t] >= z_exp[p.name, t-1])
|
||||
end
|
||||
|
||||
# Plants: Building period
|
||||
eq_building_period = _init(model, :eq_building_period)
|
||||
for p in plants, t in T
|
||||
@@ -268,7 +405,7 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false
|
||||
z_collected[c.name, m.name, t] ==
|
||||
sum(
|
||||
z_input[c.name, t-offset] * c.var_output[m][offset+1] for
|
||||
offset = 0:min(M - 1, t - 1)
|
||||
offset = 0:min(M-1, t-1)
|
||||
) + c.fixed_output[m][t]
|
||||
)
|
||||
end
|
||||
@@ -292,6 +429,69 @@ 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
|
||||
|
||||
# Transportation emissions
|
||||
eq_emission_tr = _init(model, :eq_emission_tr)
|
||||
for (p1, p2, m) in E, t in T, g in keys(m.tr_emissions)
|
||||
eq_emission_tr[g, p1.name, p2.name, m.name, t] = @constraint(
|
||||
model,
|
||||
z_em_tr[g, p1.name, p2.name, m.name, t] ==
|
||||
distances[p1, p2, m] * m.tr_emissions[g][t] * y[p1.name, p2.name, m.name, t]
|
||||
)
|
||||
end
|
||||
|
||||
# Plant emissions
|
||||
eq_emission_plant = _init(model, :eq_emission_plant)
|
||||
for p in plants, t in T, g in keys(p.emissions)
|
||||
eq_emission_plant[g, p.name, t] = @constraint(
|
||||
model,
|
||||
z_em_plant[g, p.name, t] == p.emissions[g][t] * z_process[p.name, t]
|
||||
)
|
||||
end
|
||||
|
||||
# Storage limit at plants
|
||||
eq_storage_limit = _init(model, :eq_storage_limit)
|
||||
for p in plants, m in keys(p.storage_limit), t in T
|
||||
if isfinite(p.storage_limit[m][t])
|
||||
eq_storage_limit[p.name, m.name, t] =
|
||||
@constraint(model, z_storage[p.name, m.name, t] <= p.storage_limit[m][t])
|
||||
end
|
||||
end
|
||||
|
||||
# All stored materials must be processed by end of time horizon
|
||||
eq_storage_final = _init(model, :eq_storage_final)
|
||||
for p in plants, m in keys(p.input_mix)
|
||||
eq_storage_final[p.name, m.name] =
|
||||
@constraint(model, z_storage[p.name, m.name, instance.time_horizon] == 0)
|
||||
end
|
||||
|
||||
# Global emissions limit
|
||||
eq_emission_limit = _init(model, :eq_emission_limit)
|
||||
for emission in instance.emissions, t in T
|
||||
isfinite(emission.limit[t]) || continue
|
||||
eq_emission_limit[emission.name, t] = @constraint(
|
||||
model,
|
||||
sum(
|
||||
z_em_plant[emission.name, p.name, t] for
|
||||
p in plants if emission.name in keys(p.emissions)
|
||||
) + sum(
|
||||
z_em_tr[emission.name, p1.name, p2.name, m.name, t] for
|
||||
(p1, p2, m) in E if emission.name in keys(m.tr_emissions)
|
||||
) <= emission.limit[t]
|
||||
)
|
||||
end
|
||||
|
||||
if variable_names
|
||||
_set_names!(model)
|
||||
end
|
||||
|
||||
@@ -1,11 +1,110 @@
|
||||
# RELOG: Reverse Logistics Optimization
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
using Geodesy
|
||||
using NearestNeighbors
|
||||
using DataFrames
|
||||
using CRC
|
||||
using ZipFile
|
||||
using Statistics
|
||||
using TimerOutputs
|
||||
|
||||
function _calculate_distance(source_lat, source_lon, dest_lat, dest_lon)::Float64
|
||||
crc32 = crc(CRC_32)
|
||||
|
||||
function _calculate_distance(
|
||||
source_lat,
|
||||
source_lon,
|
||||
dest_lat,
|
||||
dest_lon,
|
||||
::EuclideanDistance,
|
||||
)::Float64
|
||||
x = LLA(source_lat, source_lon, 0.0)
|
||||
y = LLA(dest_lat, dest_lon, 0.0)
|
||||
return round(euclidean_distance(x, y) / 1000.0, digits = 3)
|
||||
end
|
||||
|
||||
function _download_file(url, output, expected_crc32)::Nothing
|
||||
if isfile(output)
|
||||
return
|
||||
end
|
||||
mkpath(dirname(output))
|
||||
@info "Downloading: $url"
|
||||
fname = download(url)
|
||||
actual_crc32 = open(crc32, fname)
|
||||
expected_crc32 == actual_crc32 || error("CRC32 mismatch")
|
||||
cp(fname, output)
|
||||
return
|
||||
end
|
||||
|
||||
function _download_zip(url, outputdir, expected_output_file, expected_crc32)::Nothing
|
||||
if isfile(expected_output_file)
|
||||
return
|
||||
end
|
||||
mkpath(outputdir)
|
||||
@info "Downloading: $url"
|
||||
zip_filename = download(url)
|
||||
actual_crc32 = open(crc32, zip_filename)
|
||||
expected_crc32 == actual_crc32 || error("CRC32 mismatch")
|
||||
open(zip_filename) do zip_file
|
||||
zr = ZipFile.Reader(zip_file)
|
||||
for file in zr.files
|
||||
open(joinpath(outputdir, file.name), "w") do output_file
|
||||
write(output_file, read(file))
|
||||
end
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
function _calculate_distance(
|
||||
source_lat,
|
||||
source_lon,
|
||||
dest_lat,
|
||||
dest_lon,
|
||||
metric::KnnDrivingDistance,
|
||||
)::Float64
|
||||
if metric.tree === nothing
|
||||
basedir = joinpath(dirname(@__FILE__), "data")
|
||||
csv_filename = joinpath(basedir, "dist_driving.csv")
|
||||
|
||||
# Download pre-computed driving data
|
||||
@timeit "Download data" begin
|
||||
if !isfile(csv_filename)
|
||||
_download_zip(
|
||||
"https://axavier.org/RELOG/0.6/data/dist_driving_0b9a6ad6.zip",
|
||||
basedir,
|
||||
csv_filename,
|
||||
0x0b9a6ad6,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@timeit "Fit KNN model" begin
|
||||
df = DataFrame(CSV.File(csv_filename, missingstring = "NaN"))
|
||||
dropmissing!(df)
|
||||
coords = Matrix(df[!, [:source_lat, :source_lon, :dest_lat, :dest_lon]])'
|
||||
metric.ratios = Matrix(df[!, [:ratio]])
|
||||
metric.tree = KDTree(coords)
|
||||
end
|
||||
end
|
||||
|
||||
@timeit "Compute Euclidean distance" begin
|
||||
dist_euclidean = _calculate_distance(
|
||||
source_lat,
|
||||
source_lon,
|
||||
dest_lat,
|
||||
dest_lon,
|
||||
EuclideanDistance(),
|
||||
)
|
||||
end
|
||||
|
||||
@timeit "Predict driving distance" begin
|
||||
idxs, _ = knn(metric.tree, [source_lat, source_lon, dest_lat, dest_lon], 5)
|
||||
ratio_pred = mean(metric.ratios[idxs])
|
||||
dist_pred = round(dist_euclidean * ratio_pred, digits = 3)
|
||||
isfinite(dist_pred) || error("non-finite distance detected: $dist_pred")
|
||||
end
|
||||
|
||||
return dist_pred
|
||||
end
|
||||
|
||||
@@ -14,7 +14,7 @@ function fix(x::Float64, v::Float64; force)
|
||||
return abs(x - v) < 1e-6 || error("Value mismatch: $x != $v")
|
||||
end
|
||||
|
||||
function set_name(x::Number, n::String)
|
||||
function set_name(::Number, ::String)
|
||||
# nop
|
||||
end
|
||||
|
||||
@@ -45,3 +45,76 @@ function _set_names!(dict::Dict)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
_add_pwl_constraints(model, xvar, yvars, xpts, ypts)
|
||||
|
||||
Add piecewise-linear constraints to a JuMP model for multiple y variables.
|
||||
|
||||
Creates constraints y_i = f_i(x) where each f_i is a piecewise-linear function
|
||||
defined by the breakpoints (xpts, ypts[:, i]).
|
||||
|
||||
# Arguments
|
||||
- `model`: JuMP model
|
||||
- `xvar`: The x variable (JuMP variable)
|
||||
- `yvars`: Vector of y variables (JuMP variables)
|
||||
- `xpts`: Vector of x values for breakpoints (must be in non-decreasing order)
|
||||
- `ypts`: Matrix of y values where ypts[i, j] is the y value for the j-th variable
|
||||
at the i-th breakpoint
|
||||
|
||||
# Example
|
||||
```julia
|
||||
@variable(model, y1)
|
||||
@variable(model, y2)
|
||||
ypts_matrix = [1.5 2.0; 0.0 1.5; 3.0 0.5] # 3 breakpoints, 2 y variables
|
||||
_add_pwl_constraints(model, x, [y1, y2], [0.0, 1.0, 2.0], ypts_matrix, name="multiPWL")
|
||||
```
|
||||
"""
|
||||
function _add_pwl_constraints(model, xvar, yvars, xpts, ypts)
|
||||
# Input validation
|
||||
ypts isa AbstractMatrix || throw(ArgumentError("ypts must be a matrix"))
|
||||
length(xpts) == size(ypts, 1) ||
|
||||
throw(ArgumentError("xpts length must match number of rows in ypts"))
|
||||
length(yvars) == size(ypts, 2) ||
|
||||
throw(ArgumentError("Number of y variables must match number of columns in ypts"))
|
||||
length(xpts) >= 1 || throw(ArgumentError("At least one breakpoint is required"))
|
||||
|
||||
# Check that xpts is increasing
|
||||
for i = 2:length(xpts)
|
||||
xpts[i] > xpts[i-1] || throw(ArgumentError("xpts must be in increasing order"))
|
||||
end
|
||||
|
||||
n_points = length(xpts)
|
||||
n_yvars = length(yvars)
|
||||
|
||||
if n_points == 1
|
||||
# Single point case: y_j = ypts[1,j], x = xpts[1]
|
||||
@constraint(model, xvar == xpts[1])
|
||||
for j = 1:n_yvars
|
||||
@constraint(model, yvars[j] == ypts[1, j])
|
||||
end
|
||||
|
||||
elseif n_points == 2
|
||||
# Two points case: single linear segment for each y variable
|
||||
x1, x2 = xpts[1], xpts[2]
|
||||
|
||||
# Linear relationship for each y variable: y_j = y1_j + slope_j * (x-x1)
|
||||
for j = 1:n_yvars
|
||||
y1, y2 = ypts[1, j], ypts[2, j]
|
||||
slope = (y2 - y1) / (x2 - x1)
|
||||
@constraint(model, yvars[j] == y1 + slope * (xvar - x1))
|
||||
end
|
||||
else
|
||||
# Multiple segments case (3+ points): use SOS2 formulation
|
||||
λ = @variable(model, [1:n_points], lower_bound = 0, upper_bound = 1)
|
||||
@constraint(model, λ in SOS2())
|
||||
@constraint(model, sum(λ) == 1)
|
||||
@constraint(model, xvar == sum(xpts[i] * λ[i] for i = 1:n_points))
|
||||
for j = 1:n_yvars
|
||||
@constraint(model, yvars[j] == sum(ypts[i, j] * λ[i] for i = 1:n_points))
|
||||
end
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
@@ -8,6 +8,8 @@ using CSV
|
||||
function centers_report(model)::DataFrame
|
||||
df = DataFrame()
|
||||
df."center" = String[]
|
||||
df."latitude" = Float64[]
|
||||
df."longitude" = Float64[]
|
||||
df."year" = Int[]
|
||||
df."input product" = String[]
|
||||
df."input amount (tonne)" = Float64[]
|
||||
@@ -31,14 +33,16 @@ function centers_report(model)::DataFrame
|
||||
end
|
||||
push!(
|
||||
df,
|
||||
[
|
||||
c.name,
|
||||
t,
|
||||
input_name,
|
||||
_round(input),
|
||||
_round(revenue),
|
||||
_round(c.operating_cost[t]),
|
||||
],
|
||||
Dict(
|
||||
"center" => c.name,
|
||||
"latitude" => c.latitude,
|
||||
"longitude" => c.longitude,
|
||||
"year" => t,
|
||||
"input product" => input_name,
|
||||
"input amount (tonne)" => _round(input),
|
||||
"revenue (\$)" => _round(revenue),
|
||||
"operating cost (\$)" => _round(c.operating_cost[t]),
|
||||
),
|
||||
)
|
||||
end
|
||||
return df
|
||||
@@ -47,10 +51,13 @@ end
|
||||
function center_outputs_report(model)::DataFrame
|
||||
df = DataFrame()
|
||||
df."center" = String[]
|
||||
df."latitude" = Float64[]
|
||||
df."longitude" = Float64[]
|
||||
df."output product" = String[]
|
||||
df."year" = Int[]
|
||||
df."amount collected (tonne)" = Float64[]
|
||||
df."amount disposed (tonne)" = Float64[]
|
||||
df."disposal limit (tonne)" = Float64[]
|
||||
df."collection cost (\$)" = Float64[]
|
||||
df."disposal cost (\$)" = Float64[]
|
||||
|
||||
@@ -72,15 +79,18 @@ function center_outputs_report(model)::DataFrame
|
||||
end
|
||||
push!(
|
||||
df,
|
||||
[
|
||||
c.name,
|
||||
m.name,
|
||||
t,
|
||||
_round(collected),
|
||||
_round(disposed),
|
||||
_round(collection_cost),
|
||||
_round(disposal_cost),
|
||||
],
|
||||
Dict(
|
||||
"center" => c.name,
|
||||
"latitude" => c.latitude,
|
||||
"longitude" => c.longitude,
|
||||
"output product" => m.name,
|
||||
"year" => t,
|
||||
"amount collected (tonne)" => _round(collected),
|
||||
"amount disposed (tonne)" => _round(disposed),
|
||||
"disposal limit (tonne)" => _round(c.disposal_limit[m][t]),
|
||||
"collection cost (\$)" => _round(collection_cost),
|
||||
"disposal cost (\$)" => _round(disposal_cost),
|
||||
),
|
||||
)
|
||||
end
|
||||
return df
|
||||
|
||||
@@ -8,12 +8,20 @@ using CSV
|
||||
function plants_report(model)::DataFrame
|
||||
df = DataFrame()
|
||||
df."plant" = String[]
|
||||
df."latitude" = Float64[]
|
||||
df."longitude" = Float64[]
|
||||
df."initial capacity" = Float64[]
|
||||
df."current capacity" = Float64[]
|
||||
df."year" = Int[]
|
||||
df."operational?" = Bool[]
|
||||
df."input amount (tonne)" = Float64[]
|
||||
df."stored amount (tonne)" = Float64[]
|
||||
df."processed amount (tonne)" = Float64[]
|
||||
df."opening cost (\$)" = Float64[]
|
||||
df."fixed operating cost (\$)" = Float64[]
|
||||
df."variable operating cost (\$)" = Float64[]
|
||||
df."expansion cost (\$)" = Float64[]
|
||||
df."storage cost (\$)" = Float64[]
|
||||
|
||||
plants = model.ext[:instance].plants
|
||||
T = 1:model.ext[:instance].time_horizon
|
||||
@@ -21,23 +29,95 @@ function plants_report(model)::DataFrame
|
||||
for p in plants, t in T
|
||||
operational = JuMP.value(model[:x][p.name, t]) > 0.5
|
||||
input = value(model[:z_input][p.name, t])
|
||||
processed = value(model[:z_process][p.name, t])
|
||||
|
||||
# Calculate total stored amount across all input materials
|
||||
stored = sum(value(model[:z_storage][p.name, m.name, t]) for m in keys(p.input_mix))
|
||||
|
||||
# Calculate total storage cost
|
||||
storage_cost = sum(
|
||||
p.storage_cost[m][t] * value(model[:z_storage][p.name, m.name, t]) for
|
||||
m in keys(p.storage_cost)
|
||||
)
|
||||
|
||||
var_operating_cost = input * p.capacities[1].var_operating_cost[t]
|
||||
opening_cost = 0
|
||||
curr_capacity = 0
|
||||
expansion_cost = 0
|
||||
fix_operating_cost = 0
|
||||
|
||||
if value(model[:x][p.name, t]) > 0.5 && value(model[:x][p.name, t-1]) < 0.5
|
||||
opening_cost = p.capacities[1].opening_cost[t]
|
||||
end
|
||||
fix_operating_cost = (operational ? p.capacities[1].fix_operating_cost[t] : 0)
|
||||
var_operating_cost = input * p.capacities[1].var_operating_cost[t]
|
||||
|
||||
if operational
|
||||
curr_expansion = JuMP.value(model[:z_exp][p.name, t])
|
||||
prev_expansion = JuMP.value(model[:z_exp][p.name, t-1])
|
||||
curr_capacity = p.capacities[1].size + curr_expansion
|
||||
expansion_cost = R_expand(p, t) * (curr_expansion - prev_expansion)
|
||||
fix_operating_cost =
|
||||
p.capacities[1].fix_operating_cost[t] + R_fix_exp(p, t) * curr_expansion
|
||||
end
|
||||
|
||||
push!(
|
||||
df,
|
||||
[
|
||||
p.name,
|
||||
t,
|
||||
operational,
|
||||
_round(input),
|
||||
_round(opening_cost),
|
||||
_round(fix_operating_cost),
|
||||
_round(var_operating_cost),
|
||||
],
|
||||
Dict(
|
||||
"plant" => p.name,
|
||||
"latitude" => p.latitude,
|
||||
"longitude" => p.longitude,
|
||||
"initial capacity" => p.initial_capacity,
|
||||
"current capacity" => curr_capacity,
|
||||
"year" => t,
|
||||
"operational?" => operational,
|
||||
"input amount (tonne)" => _round(input),
|
||||
"stored amount (tonne)" => _round(stored),
|
||||
"processed amount (tonne)" => _round(processed),
|
||||
"opening cost (\$)" => _round(opening_cost),
|
||||
"fixed operating cost (\$)" => _round(fix_operating_cost),
|
||||
"variable operating cost (\$)" => _round(var_operating_cost),
|
||||
"expansion cost (\$)" => _round(expansion_cost),
|
||||
"storage cost (\$)" => _round(storage_cost),
|
||||
),
|
||||
)
|
||||
end
|
||||
return df
|
||||
end
|
||||
|
||||
function plant_inputs_report(model)::DataFrame
|
||||
df = DataFrame()
|
||||
df."plant" = String[]
|
||||
df."latitude" = Float64[]
|
||||
df."longitude" = Float64[]
|
||||
df."input product" = String[]
|
||||
df."year" = Int[]
|
||||
df."amount received (tonne)" = Float64[]
|
||||
df."current storage level (tonne)" = Float64[]
|
||||
df."storage limit (tonne)" = Float64[]
|
||||
df."storage cost (\$)" = Float64[]
|
||||
|
||||
plants = model.ext[:instance].plants
|
||||
T = 1:model.ext[:instance].time_horizon
|
||||
|
||||
for p in plants, m in keys(p.input_mix), t in T
|
||||
amount_received = sum(
|
||||
value(model[:y][src.name, p.name, m.name, t]) for
|
||||
(src, prod) in model.ext[:E_in][p] if prod == m
|
||||
)
|
||||
storage_level = value(model[:z_storage][p.name, m.name, t])
|
||||
storage_cost = p.storage_cost[m][t] * storage_level
|
||||
push!(
|
||||
df,
|
||||
Dict(
|
||||
"plant" => p.name,
|
||||
"latitude" => p.latitude,
|
||||
"longitude" => p.longitude,
|
||||
"input product" => m.name,
|
||||
"year" => t,
|
||||
"amount received (tonne)" => _round(amount_received),
|
||||
"current storage level (tonne)" => _round(storage_level),
|
||||
"storage limit (tonne)" => _round(p.storage_limit[m][t]),
|
||||
"storage cost (\$)" => _round(storage_cost),
|
||||
),
|
||||
)
|
||||
end
|
||||
return df
|
||||
@@ -46,10 +126,13 @@ end
|
||||
function plant_outputs_report(model)::DataFrame
|
||||
df = DataFrame()
|
||||
df."plant" = String[]
|
||||
df."latitude" = Float64[]
|
||||
df."longitude" = Float64[]
|
||||
df."output product" = String[]
|
||||
df."year" = Int[]
|
||||
df."amount produced (tonne)" = Float64[]
|
||||
df."amount disposed (tonne)" = Float64[]
|
||||
df."disposal limit (tonne)" = Float64[]
|
||||
df."disposal cost (\$)" = Float64[]
|
||||
|
||||
plants = model.ext[:instance].plants
|
||||
@@ -61,12 +144,62 @@ function plant_outputs_report(model)::DataFrame
|
||||
disposal_cost = p.disposal_cost[m][t] * disposed
|
||||
push!(
|
||||
df,
|
||||
[p.name, m.name, t, _round(produced), _round(disposed), _round(disposal_cost)],
|
||||
Dict(
|
||||
"plant" => p.name,
|
||||
"latitude" => p.latitude,
|
||||
"longitude" => p.longitude,
|
||||
"output product" => m.name,
|
||||
"year" => t,
|
||||
"amount produced (tonne)" => _round(produced),
|
||||
"amount disposed (tonne)" => _round(disposed),
|
||||
"disposal limit (tonne)" => _round(p.disposal_limit[m][t]),
|
||||
"disposal cost (\$)" => _round(disposal_cost),
|
||||
),
|
||||
)
|
||||
end
|
||||
return df
|
||||
end
|
||||
|
||||
function plant_emissions_report(model)::DataFrame
|
||||
df = DataFrame()
|
||||
df."plant" = String[]
|
||||
df."latitude" = Float64[]
|
||||
df."longitude" = Float64[]
|
||||
df."emission" = String[]
|
||||
df."year" = Int[]
|
||||
df."processed amount (tonne)" = Float64[]
|
||||
df."emission factor (tonne/tonne)" = Float64[]
|
||||
df."emissions amount (tonne)" = Float64[]
|
||||
|
||||
plants = model.ext[:instance].plants
|
||||
T = 1:model.ext[:instance].time_horizon
|
||||
|
||||
for p in plants, t in T, g in keys(p.emissions)
|
||||
processed_amount = JuMP.value(model[:z_process][p.name, t])
|
||||
processed_amount > 1e-3 || continue
|
||||
emissions = JuMP.value(model[:z_em_plant][g, p.name, t])
|
||||
emission_factor = p.emissions[g][t]
|
||||
push!(
|
||||
df,
|
||||
Dict(
|
||||
"plant" => p.name,
|
||||
"latitude" => p.latitude,
|
||||
"longitude" => p.longitude,
|
||||
"emission" => g,
|
||||
"year" => t,
|
||||
"processed amount (tonne)" => _round(processed_amount),
|
||||
"emission factor (tonne/tonne)" => _round(emission_factor),
|
||||
"emissions amount (tonne)" => _round(emissions),
|
||||
),
|
||||
)
|
||||
end
|
||||
return df
|
||||
end
|
||||
|
||||
write_plants_report(solution, filename) = CSV.write(filename, plants_report(solution))
|
||||
write_plant_inputs_report(solution, filename) =
|
||||
CSV.write(filename, plant_inputs_report(solution))
|
||||
write_plant_outputs_report(solution, filename) =
|
||||
CSV.write(filename, plant_outputs_report(solution))
|
||||
write_plant_emissions_report(solution, filename) =
|
||||
CSV.write(filename, plant_emissions_report(solution))
|
||||
|
||||
@@ -36,17 +36,57 @@ function transportation_report(model)::DataFrame
|
||||
end
|
||||
push!(
|
||||
df,
|
||||
[
|
||||
p1.name,
|
||||
p2.name,
|
||||
m.name,
|
||||
t,
|
||||
_round(amount),
|
||||
_round(distance),
|
||||
_round(tr_cost),
|
||||
_round(revenue),
|
||||
_round(collection_cost),
|
||||
],
|
||||
Dict(
|
||||
"source" => p1.name,
|
||||
"destination" => p2.name,
|
||||
"product" => m.name,
|
||||
"year" => t,
|
||||
"amount sent (tonne)" => _round(amount),
|
||||
"distance (km)" => _round(distance),
|
||||
"transportation cost (\$)" => _round(tr_cost),
|
||||
"center revenue (\$)" => _round(revenue),
|
||||
"center collection cost (\$)" => _round(collection_cost),
|
||||
),
|
||||
)
|
||||
end
|
||||
return df
|
||||
end
|
||||
|
||||
function transportation_emissions_report(model)::DataFrame
|
||||
df = DataFrame()
|
||||
df."source" = String[]
|
||||
df."destination" = String[]
|
||||
df."product" = String[]
|
||||
df."emission" = String[]
|
||||
df."year" = Int[]
|
||||
df."amount sent (tonne)" = Float64[]
|
||||
df."distance (km)" = Float64[]
|
||||
df."emission factor (tonne/km/tonne)" = Float64[]
|
||||
df."emission amount (tonne)" = Float64[]
|
||||
|
||||
E = model.ext[:E]
|
||||
distances = model.ext[:distances]
|
||||
T = 1:model.ext[:instance].time_horizon
|
||||
|
||||
for (p1, p2, m) in E, t in T, g in keys(m.tr_emissions)
|
||||
amount = value(model[:y][p1.name, p2.name, m.name, t])
|
||||
amount > 1e-3 || continue
|
||||
distance = distances[p1, p2, m]
|
||||
emission_factor = m.tr_emissions[g][t]
|
||||
emissions = value(model[:z_em_tr][g, p1.name, p2.name, m.name, t])
|
||||
push!(
|
||||
df,
|
||||
Dict(
|
||||
"source" => p1.name,
|
||||
"destination" => p2.name,
|
||||
"product" => m.name,
|
||||
"emission" => g,
|
||||
"year" => t,
|
||||
"amount sent (tonne)" => _round(amount),
|
||||
"distance (km)" => _round(distance),
|
||||
"emission factor (tonne/km/tonne)" => _round(emission_factor),
|
||||
"emission amount (tonne)" => _round(emissions),
|
||||
),
|
||||
)
|
||||
end
|
||||
return df
|
||||
@@ -54,3 +94,6 @@ end
|
||||
|
||||
write_transportation_report(solution, filename) =
|
||||
CSV.write(filename, transportation_report(solution))
|
||||
|
||||
write_transportation_emissions_report(solution, filename) =
|
||||
CSV.write(filename, transportation_emissions_report(solution))
|
||||
|
||||
51
test/fixtures/boat_example.jl
vendored
@@ -68,7 +68,9 @@ function run_boat_example()
|
||||
prod = dict(
|
||||
"transportation cost (\$/km/tonne)" => 0.30,
|
||||
"transportation energy (J/km/tonne)" => 7_500,
|
||||
"transportation emissions (tonne/km/tonne)" => dict("CO2" => 2.68),
|
||||
"transportation emissions (tonne/km/tonne)" =>
|
||||
dict("CO2" => 2.68, "NH4" => 1.02),
|
||||
"disposal limit (tonne)" => nothing,
|
||||
)
|
||||
|
||||
boat_factory = dict(
|
||||
@@ -121,10 +123,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 +132,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
|
||||
),
|
||||
),
|
||||
)
|
||||
@@ -180,10 +173,16 @@ function run_boat_example()
|
||||
mkpath(fixture("boat_example"))
|
||||
write_to_file(model, fixture("boat_example/model.lp"))
|
||||
RELOG.write_plants_report(model, fixture("boat_example/plants.csv"))
|
||||
RELOG.write_plant_inputs_report(model, fixture("boat_example/plant_inputs.csv"))
|
||||
RELOG.write_plant_outputs_report(model, fixture("boat_example/plant_outputs.csv"))
|
||||
RELOG.write_plant_emissions_report(model, fixture("boat_example/plant_emissions.csv"))
|
||||
RELOG.write_centers_report(model, fixture("boat_example/centers.csv"))
|
||||
RELOG.write_center_outputs_report(model, fixture("boat_example/center_outputs.csv"))
|
||||
RELOG.write_transportation_report(model, fixture("boat_example/transportation.csv"))
|
||||
RELOG.write_transportation_emissions_report(
|
||||
model,
|
||||
fixture("boat_example/tr_emissions.csv"),
|
||||
)
|
||||
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
24
test/fixtures/boat_example.json
vendored
@@ -11,29 +11,37 @@
|
||||
"transportation cost ($/km/tonne)": 0.3,
|
||||
"transportation energy (J/km/tonne)": 7500,
|
||||
"transportation emissions (tonne/km/tonne)": {
|
||||
"CO2": 2.68
|
||||
}
|
||||
"CO2": 2.68,
|
||||
"NH4": 1.02
|
||||
},
|
||||
"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
|
||||
}
|
||||
"CO2": 2.68,
|
||||
"NH4": 1.02
|
||||
},
|
||||
"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
|
||||
}
|
||||
"CO2": 2.68,
|
||||
"NH4": 1.02
|
||||
},
|
||||
"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
|
||||
}
|
||||
"CO2": 2.68,
|
||||
"NH4": 1.02
|
||||
},
|
||||
"disposal limit (tonne)": null
|
||||
}
|
||||
},
|
||||
"centers": {
|
||||
|
||||
162
test/fixtures/boat_example/center_outputs.csv
vendored
@@ -1,81 +1,81 @@
|
||||
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,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
|
||||
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,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
|
||||
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
|
||||
Forest (Chicago),Wood,4,100.0,100.0,0.0,0.0
|
||||
Forest (Chicago),Wood,5,100.0,100.0,0.0,0.0
|
||||
Forest (Phoenix),Wood,1,100.0,100.0,0.0,0.0
|
||||
Forest (Phoenix),Wood,2,100.0,100.0,0.0,0.0
|
||||
Forest (Phoenix),Wood,3,100.0,100.0,0.0,0.0
|
||||
Forest (Phoenix),Wood,4,100.0,100.0,0.0,0.0
|
||||
Forest (Phoenix),Wood,5,100.0,100.0,0.0,0.0
|
||||
Forest (Dallas),Wood,1,100.0,43.0,14250.0,0.0
|
||||
Forest (Dallas),Wood,2,100.0,43.0,14250.0,0.0
|
||||
Forest (Dallas),Wood,3,100.0,43.0,14250.0,0.0
|
||||
Forest (Dallas),Wood,4,100.0,43.0,14250.0,0.0
|
||||
Forest (Dallas),Wood,5,100.0,43.0,14250.0,0.0
|
||||
Retail (Chicago),UsedBoat,1,0.0,0.0,0.0,0.0
|
||||
Retail (Chicago),UsedBoat,2,0.0,0.0,0.0,0.0
|
||||
Retail (Chicago),UsedBoat,3,0.0,0.0,0.0,0.0
|
||||
Retail (Chicago),UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
Retail (Chicago),UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
Retail (New York City),UsedBoat,1,0.0,0.0,0.0,0.0
|
||||
Retail (New York City),UsedBoat,2,0.0,0.0,0.0,0.0
|
||||
Retail (New York City),UsedBoat,3,0.0,0.0,0.0,0.0
|
||||
Retail (New York City),UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
Retail (New York City),UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
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 (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 (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 (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
|
||||
Retail (Philadelphia),UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
Retail (Philadelphia),UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
Retail (San Antonio),UsedBoat,1,0.0,0.0,0.0,0.0
|
||||
Retail (San Antonio),UsedBoat,2,0.0,0.0,0.0,0.0
|
||||
Retail (San Antonio),UsedBoat,3,0.0,0.0,0.0,0.0
|
||||
Retail (San Antonio),UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
Retail (San Antonio),UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
Retail (San Diego),UsedBoat,1,0.0,0.0,0.0,0.0
|
||||
Retail (San Diego),UsedBoat,2,0.0,0.0,0.0,0.0
|
||||
Retail (San Diego),UsedBoat,3,0.0,0.0,0.0,0.0
|
||||
Retail (San Diego),UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
Retail (San Diego),UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
Retail (Dallas),UsedBoat,1,6.31579,0.0,631.57895,0.0
|
||||
Retail (Dallas),UsedBoat,2,22.93629,0.0,2293.62881,0.0
|
||||
Retail (Dallas),UsedBoat,3,31.7714,0.0,3177.13952,0.0
|
||||
Retail (Dallas),UsedBoat,4,33.80867,0.0,3380.86724,0.0
|
||||
Retail (Dallas),UsedBoat,5,34.54174,0.0,3454.17409,0.0
|
||||
Retail (San Jose),UsedBoat,1,0.0,0.0,0.0,0.0
|
||||
Retail (San Jose),UsedBoat,2,0.0,0.0,0.0,0.0
|
||||
Retail (San Jose),UsedBoat,3,0.0,0.0,0.0,0.0
|
||||
Retail (San Jose),UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
Retail (San Jose),UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
center,latitude,longitude,output product,year,amount collected (tonne),amount disposed (tonne),disposal limit (tonne),collection cost ($),disposal cost ($)
|
||||
NailFactory (Chicago),41.881832,-87.623177,Nail,1,1.0,0.0,Inf,1000.0,0.0
|
||||
NailFactory (Chicago),41.881832,-87.623177,Nail,2,1.0,0.0,Inf,1000.0,0.0
|
||||
NailFactory (Chicago),41.881832,-87.623177,Nail,3,1.0,0.0,Inf,1000.0,0.0
|
||||
NailFactory (Chicago),41.881832,-87.623177,Nail,4,1.0,0.0,Inf,1000.0,0.0
|
||||
NailFactory (Chicago),41.881832,-87.623177,Nail,5,1.0,0.0,Inf,1000.0,0.0
|
||||
NailFactory (Phoenix),33.448376,-112.074036,Nail,1,1.0,0.0,Inf,1000.0,0.0
|
||||
NailFactory (Phoenix),33.448376,-112.074036,Nail,2,1.0,0.0,Inf,1000.0,0.0
|
||||
NailFactory (Phoenix),33.448376,-112.074036,Nail,3,1.0,0.0,Inf,1000.0,0.0
|
||||
NailFactory (Phoenix),33.448376,-112.074036,Nail,4,1.0,0.0,Inf,1000.0,0.0
|
||||
NailFactory (Phoenix),33.448376,-112.074036,Nail,5,1.0,0.0,Inf,1000.0,0.0
|
||||
NailFactory (Dallas),32.776664,-96.796988,Nail,1,1.0,0.0,Inf,1000.0,0.0
|
||||
NailFactory (Dallas),32.776664,-96.796988,Nail,2,1.0,0.0,Inf,1000.0,0.0
|
||||
NailFactory (Dallas),32.776664,-96.796988,Nail,3,1.0,0.0,Inf,1000.0,0.0
|
||||
NailFactory (Dallas),32.776664,-96.796988,Nail,4,1.0,0.0,Inf,1000.0,0.0
|
||||
NailFactory (Dallas),32.776664,-96.796988,Nail,5,1.0,0.0,Inf,1000.0,0.0
|
||||
Forest (Chicago),41.881832,-87.623177,Wood,1,100.0,100.0,Inf,0.0,0.0
|
||||
Forest (Chicago),41.881832,-87.623177,Wood,2,100.0,100.0,Inf,0.0,0.0
|
||||
Forest (Chicago),41.881832,-87.623177,Wood,3,100.0,100.0,Inf,0.0,0.0
|
||||
Forest (Chicago),41.881832,-87.623177,Wood,4,100.0,100.0,Inf,0.0,0.0
|
||||
Forest (Chicago),41.881832,-87.623177,Wood,5,100.0,100.0,Inf,0.0,0.0
|
||||
Forest (Phoenix),33.448376,-112.074036,Wood,1,100.0,100.0,Inf,0.0,0.0
|
||||
Forest (Phoenix),33.448376,-112.074036,Wood,2,100.0,100.0,Inf,0.0,0.0
|
||||
Forest (Phoenix),33.448376,-112.074036,Wood,3,100.0,100.0,Inf,0.0,0.0
|
||||
Forest (Phoenix),33.448376,-112.074036,Wood,4,100.0,100.0,Inf,0.0,0.0
|
||||
Forest (Phoenix),33.448376,-112.074036,Wood,5,100.0,100.0,Inf,0.0,0.0
|
||||
Forest (Dallas),32.776664,-96.796988,Wood,1,100.0,43.0,Inf,14250.0,0.0
|
||||
Forest (Dallas),32.776664,-96.796988,Wood,2,100.0,43.0,Inf,14250.0,0.0
|
||||
Forest (Dallas),32.776664,-96.796988,Wood,3,100.0,43.0,Inf,14250.0,0.0
|
||||
Forest (Dallas),32.776664,-96.796988,Wood,4,100.0,43.0,Inf,14250.0,0.0
|
||||
Forest (Dallas),32.776664,-96.796988,Wood,5,100.0,43.0,Inf,14250.0,0.0
|
||||
Retail (Chicago),41.881832,-87.623177,UsedBoat,1,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Chicago),41.881832,-87.623177,UsedBoat,2,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Chicago),41.881832,-87.623177,UsedBoat,3,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Chicago),41.881832,-87.623177,UsedBoat,4,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Chicago),41.881832,-87.623177,UsedBoat,5,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (New York City),40.712776,-74.005974,UsedBoat,1,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (New York City),40.712776,-74.005974,UsedBoat,2,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (New York City),40.712776,-74.005974,UsedBoat,3,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (New York City),40.712776,-74.005974,UsedBoat,4,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (New York City),40.712776,-74.005974,UsedBoat,5,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Los Angeles),34.052235,-118.243683,UsedBoat,1,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Los Angeles),34.052235,-118.243683,UsedBoat,2,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Los Angeles),34.052235,-118.243683,UsedBoat,3,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Los Angeles),34.052235,-118.243683,UsedBoat,4,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Los Angeles),34.052235,-118.243683,UsedBoat,5,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Houston),29.760427,-95.369804,UsedBoat,1,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Houston),29.760427,-95.369804,UsedBoat,2,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Houston),29.760427,-95.369804,UsedBoat,3,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Houston),29.760427,-95.369804,UsedBoat,4,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Houston),29.760427,-95.369804,UsedBoat,5,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Phoenix),33.448376,-112.074036,UsedBoat,1,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Phoenix),33.448376,-112.074036,UsedBoat,2,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Phoenix),33.448376,-112.074036,UsedBoat,3,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Phoenix),33.448376,-112.074036,UsedBoat,4,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Phoenix),33.448376,-112.074036,UsedBoat,5,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Philadelphia),39.952583,-75.165222,UsedBoat,1,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Philadelphia),39.952583,-75.165222,UsedBoat,2,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Philadelphia),39.952583,-75.165222,UsedBoat,3,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Philadelphia),39.952583,-75.165222,UsedBoat,4,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Philadelphia),39.952583,-75.165222,UsedBoat,5,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (San Antonio),29.424122,-98.493629,UsedBoat,1,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (San Antonio),29.424122,-98.493629,UsedBoat,2,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (San Antonio),29.424122,-98.493629,UsedBoat,3,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (San Antonio),29.424122,-98.493629,UsedBoat,4,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (San Antonio),29.424122,-98.493629,UsedBoat,5,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (San Diego),32.715736,-117.161087,UsedBoat,1,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (San Diego),32.715736,-117.161087,UsedBoat,2,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (San Diego),32.715736,-117.161087,UsedBoat,3,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (San Diego),32.715736,-117.161087,UsedBoat,4,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (San Diego),32.715736,-117.161087,UsedBoat,5,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (Dallas),32.776664,-96.796988,UsedBoat,1,6.31579,0.0,0.0,631.57895,0.0
|
||||
Retail (Dallas),32.776664,-96.796988,UsedBoat,2,22.93629,0.0,0.0,2293.62881,0.0
|
||||
Retail (Dallas),32.776664,-96.796988,UsedBoat,3,31.7714,0.0,0.0,3177.13952,0.0
|
||||
Retail (Dallas),32.776664,-96.796988,UsedBoat,4,33.80867,0.0,0.0,3380.86724,0.0
|
||||
Retail (Dallas),32.776664,-96.796988,UsedBoat,5,34.54174,0.0,0.0,3454.17409,0.0
|
||||
Retail (San Jose),37.338208,-121.886329,UsedBoat,1,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (San Jose),37.338208,-121.886329,UsedBoat,2,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (San Jose),37.338208,-121.886329,UsedBoat,3,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (San Jose),37.338208,-121.886329,UsedBoat,4,0.0,0.0,0.0,0.0,0.0
|
||||
Retail (San Jose),37.338208,-121.886329,UsedBoat,5,0.0,0.0,0.0,0.0,0.0
|
||||
|
||||
|
162
test/fixtures/boat_example/centers.csv
vendored
@@ -1,81 +1,81 @@
|
||||
center,year,input product,input amount (tonne),revenue ($),operating cost ($)
|
||||
NailFactory (Chicago),1,,0.0,0.0,0.0
|
||||
NailFactory (Chicago),2,,0.0,0.0,0.0
|
||||
NailFactory (Chicago),3,,0.0,0.0,0.0
|
||||
NailFactory (Chicago),4,,0.0,0.0,0.0
|
||||
NailFactory (Chicago),5,,0.0,0.0,0.0
|
||||
NailFactory (Phoenix),1,,0.0,0.0,0.0
|
||||
NailFactory (Phoenix),2,,0.0,0.0,0.0
|
||||
NailFactory (Phoenix),3,,0.0,0.0,0.0
|
||||
NailFactory (Phoenix),4,,0.0,0.0,0.0
|
||||
NailFactory (Phoenix),5,,0.0,0.0,0.0
|
||||
NailFactory (Dallas),1,,0.0,0.0,0.0
|
||||
NailFactory (Dallas),2,,0.0,0.0,0.0
|
||||
NailFactory (Dallas),3,,0.0,0.0,0.0
|
||||
NailFactory (Dallas),4,,0.0,0.0,0.0
|
||||
NailFactory (Dallas),5,,0.0,0.0,0.0
|
||||
Forest (Chicago),1,,0.0,0.0,0.0
|
||||
Forest (Chicago),2,,0.0,0.0,0.0
|
||||
Forest (Chicago),3,,0.0,0.0,0.0
|
||||
Forest (Chicago),4,,0.0,0.0,0.0
|
||||
Forest (Chicago),5,,0.0,0.0,0.0
|
||||
Forest (Phoenix),1,,0.0,0.0,0.0
|
||||
Forest (Phoenix),2,,0.0,0.0,0.0
|
||||
Forest (Phoenix),3,,0.0,0.0,0.0
|
||||
Forest (Phoenix),4,,0.0,0.0,0.0
|
||||
Forest (Phoenix),5,,0.0,0.0,0.0
|
||||
Forest (Dallas),1,,0.0,0.0,0.0
|
||||
Forest (Dallas),2,,0.0,0.0,0.0
|
||||
Forest (Dallas),3,,0.0,0.0,0.0
|
||||
Forest (Dallas),4,,0.0,0.0,0.0
|
||||
Forest (Dallas),5,,0.0,0.0,0.0
|
||||
Retail (Chicago),1,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Chicago),2,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Chicago),3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Chicago),4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Chicago),5,NewBoat,0.0,0.0,125000.0
|
||||
Retail (New York City),1,NewBoat,0.0,0.0,125000.0
|
||||
Retail (New York City),2,NewBoat,0.0,0.0,125000.0
|
||||
Retail (New York City),3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (New York City),4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (New York City),5,NewBoat,0.0,0.0,125000.0
|
||||
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 (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 (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),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
|
||||
Retail (Philadelphia),3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Philadelphia),4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Philadelphia),5,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Antonio),1,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Antonio),2,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Antonio),3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Antonio),4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Antonio),5,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Diego),1,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Diego),2,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Diego),3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Diego),4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Diego),5,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Dallas),1,NewBoat,63.15789,757894.73684,125000.0
|
||||
Retail (Dallas),2,NewBoat,71.46814,857617.72853,125000.0
|
||||
Retail (Dallas),3,NewBoat,75.8857,910628.37148,125000.0
|
||||
Retail (Dallas),4,NewBoat,76.90434,922852.03459,125000.0
|
||||
Retail (Dallas),5,NewBoat,77.27087,927250.44516,125000.0
|
||||
Retail (San Jose),1,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Jose),2,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Jose),3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Jose),4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Jose),5,NewBoat,0.0,0.0,125000.0
|
||||
center,latitude,longitude,year,input product,input amount (tonne),revenue ($),operating cost ($)
|
||||
NailFactory (Chicago),41.881832,-87.623177,1,,0.0,0.0,0.0
|
||||
NailFactory (Chicago),41.881832,-87.623177,2,,0.0,0.0,0.0
|
||||
NailFactory (Chicago),41.881832,-87.623177,3,,0.0,0.0,0.0
|
||||
NailFactory (Chicago),41.881832,-87.623177,4,,0.0,0.0,0.0
|
||||
NailFactory (Chicago),41.881832,-87.623177,5,,0.0,0.0,0.0
|
||||
NailFactory (Phoenix),33.448376,-112.074036,1,,0.0,0.0,0.0
|
||||
NailFactory (Phoenix),33.448376,-112.074036,2,,0.0,0.0,0.0
|
||||
NailFactory (Phoenix),33.448376,-112.074036,3,,0.0,0.0,0.0
|
||||
NailFactory (Phoenix),33.448376,-112.074036,4,,0.0,0.0,0.0
|
||||
NailFactory (Phoenix),33.448376,-112.074036,5,,0.0,0.0,0.0
|
||||
NailFactory (Dallas),32.776664,-96.796988,1,,0.0,0.0,0.0
|
||||
NailFactory (Dallas),32.776664,-96.796988,2,,0.0,0.0,0.0
|
||||
NailFactory (Dallas),32.776664,-96.796988,3,,0.0,0.0,0.0
|
||||
NailFactory (Dallas),32.776664,-96.796988,4,,0.0,0.0,0.0
|
||||
NailFactory (Dallas),32.776664,-96.796988,5,,0.0,0.0,0.0
|
||||
Forest (Chicago),41.881832,-87.623177,1,,0.0,0.0,0.0
|
||||
Forest (Chicago),41.881832,-87.623177,2,,0.0,0.0,0.0
|
||||
Forest (Chicago),41.881832,-87.623177,3,,0.0,0.0,0.0
|
||||
Forest (Chicago),41.881832,-87.623177,4,,0.0,0.0,0.0
|
||||
Forest (Chicago),41.881832,-87.623177,5,,0.0,0.0,0.0
|
||||
Forest (Phoenix),33.448376,-112.074036,1,,0.0,0.0,0.0
|
||||
Forest (Phoenix),33.448376,-112.074036,2,,0.0,0.0,0.0
|
||||
Forest (Phoenix),33.448376,-112.074036,3,,0.0,0.0,0.0
|
||||
Forest (Phoenix),33.448376,-112.074036,4,,0.0,0.0,0.0
|
||||
Forest (Phoenix),33.448376,-112.074036,5,,0.0,0.0,0.0
|
||||
Forest (Dallas),32.776664,-96.796988,1,,0.0,0.0,0.0
|
||||
Forest (Dallas),32.776664,-96.796988,2,,0.0,0.0,0.0
|
||||
Forest (Dallas),32.776664,-96.796988,3,,0.0,0.0,0.0
|
||||
Forest (Dallas),32.776664,-96.796988,4,,0.0,0.0,0.0
|
||||
Forest (Dallas),32.776664,-96.796988,5,,0.0,0.0,0.0
|
||||
Retail (Chicago),41.881832,-87.623177,1,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Chicago),41.881832,-87.623177,2,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Chicago),41.881832,-87.623177,3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Chicago),41.881832,-87.623177,4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Chicago),41.881832,-87.623177,5,NewBoat,0.0,0.0,125000.0
|
||||
Retail (New York City),40.712776,-74.005974,1,NewBoat,0.0,0.0,125000.0
|
||||
Retail (New York City),40.712776,-74.005974,2,NewBoat,0.0,0.0,125000.0
|
||||
Retail (New York City),40.712776,-74.005974,3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (New York City),40.712776,-74.005974,4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (New York City),40.712776,-74.005974,5,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Los Angeles),34.052235,-118.243683,1,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Los Angeles),34.052235,-118.243683,2,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Los Angeles),34.052235,-118.243683,3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Los Angeles),34.052235,-118.243683,4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Los Angeles),34.052235,-118.243683,5,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Houston),29.760427,-95.369804,1,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Houston),29.760427,-95.369804,2,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Houston),29.760427,-95.369804,3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Houston),29.760427,-95.369804,4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Houston),29.760427,-95.369804,5,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Phoenix),33.448376,-112.074036,1,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Phoenix),33.448376,-112.074036,2,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Phoenix),33.448376,-112.074036,3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Phoenix),33.448376,-112.074036,4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Phoenix),33.448376,-112.074036,5,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Philadelphia),39.952583,-75.165222,1,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Philadelphia),39.952583,-75.165222,2,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Philadelphia),39.952583,-75.165222,3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Philadelphia),39.952583,-75.165222,4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Philadelphia),39.952583,-75.165222,5,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Antonio),29.424122,-98.493629,1,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Antonio),29.424122,-98.493629,2,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Antonio),29.424122,-98.493629,3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Antonio),29.424122,-98.493629,4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Antonio),29.424122,-98.493629,5,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Diego),32.715736,-117.161087,1,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Diego),32.715736,-117.161087,2,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Diego),32.715736,-117.161087,3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Diego),32.715736,-117.161087,4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Diego),32.715736,-117.161087,5,NewBoat,0.0,0.0,125000.0
|
||||
Retail (Dallas),32.776664,-96.796988,1,NewBoat,63.15789,757894.73684,125000.0
|
||||
Retail (Dallas),32.776664,-96.796988,2,NewBoat,71.46814,857617.72853,125000.0
|
||||
Retail (Dallas),32.776664,-96.796988,3,NewBoat,75.8857,910628.37148,125000.0
|
||||
Retail (Dallas),32.776664,-96.796988,4,NewBoat,76.90434,922852.03459,125000.0
|
||||
Retail (Dallas),32.776664,-96.796988,5,NewBoat,77.27087,927250.44516,125000.0
|
||||
Retail (San Jose),37.338208,-121.886329,1,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Jose),37.338208,-121.886329,2,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Jose),37.338208,-121.886329,3,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Jose),37.338208,-121.886329,4,NewBoat,0.0,0.0,125000.0
|
||||
Retail (San Jose),37.338208,-121.886329,5,NewBoat,0.0,0.0,125000.0
|
||||
|
||||
|
11
test/fixtures/boat_example/plant_emissions.csv
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
plant,latitude,longitude,emission,year,processed amount (tonne),emission factor (tonne/tonne),emissions amount (tonne)
|
||||
BoatFactory (Dallas),32.776664,-96.796988,CO2,1,63.15789,5.0,315.78947
|
||||
BoatFactory (Dallas),32.776664,-96.796988,CO2,2,71.46814,5.0,357.34072
|
||||
BoatFactory (Dallas),32.776664,-96.796988,CO2,3,75.8857,5.0,379.42849
|
||||
BoatFactory (Dallas),32.776664,-96.796988,CO2,4,76.90434,5.0,384.52168
|
||||
BoatFactory (Dallas),32.776664,-96.796988,CO2,5,77.27087,5.0,386.35435
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,CO2,1,6.31579,5.0,31.57895
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,CO2,2,22.93629,5.0,114.68144
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,CO2,3,31.7714,5.0,158.85698
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,CO2,4,33.80867,5.0,169.04336
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,CO2,5,34.54174,5.0,172.7087
|
||||
|
151
test/fixtures/boat_example/plant_inputs.csv
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
plant,latitude,longitude,input product,year,amount received (tonne),current storage level (tonne),storage limit (tonne),storage cost ($)
|
||||
BoatFactory (Chicago),41.881832,-87.623177,Wood,1,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,Wood,2,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,Wood,3,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,Wood,4,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,Wood,5,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,Nail,1,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,Nail,2,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,Nail,3,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,Nail,4,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,Nail,5,0.0,0.0,1.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,Wood,1,0.0,0.0,5.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,Wood,2,0.0,0.0,5.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,Wood,3,0.0,0.0,5.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,Wood,4,0.0,0.0,5.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,Wood,5,0.0,0.0,5.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,Nail,1,0.0,0.0,1.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,Nail,2,0.0,0.0,1.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,Nail,3,0.0,0.0,1.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,Nail,4,0.0,0.0,1.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,Nail,5,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,Wood,1,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,Wood,2,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,Wood,3,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,Wood,4,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,Wood,5,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,Nail,1,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,Nail,2,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,Nail,3,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,Nail,4,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,Nail,5,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,Wood,1,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,Wood,2,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,Wood,3,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,Wood,4,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,Wood,5,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,Nail,1,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,Nail,2,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,Nail,3,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,Nail,4,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,Nail,5,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,Wood,1,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,Wood,2,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,Wood,3,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,Wood,4,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,Wood,5,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,Nail,1,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,Nail,2,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,Nail,3,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,Nail,4,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,Nail,5,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,Wood,1,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,Wood,2,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,Wood,3,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,Wood,4,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,Wood,5,0.0,0.0,5.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,Nail,1,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,Nail,2,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,Nail,3,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,Nail,4,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,Nail,5,0.0,0.0,1.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,Wood,1,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,Wood,2,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,Wood,3,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,Wood,4,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,Wood,5,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,Nail,1,0.0,0.0,1.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,Nail,2,0.0,0.0,1.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,Nail,3,0.0,0.0,1.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,Nail,4,0.0,0.0,1.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,Nail,5,0.0,0.0,1.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,Wood,1,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,Wood,2,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,Wood,3,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,Wood,4,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,Wood,5,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,Nail,1,0.0,0.0,1.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,Nail,2,0.0,0.0,1.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,Nail,3,0.0,0.0,1.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,Nail,4,0.0,0.0,1.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,Nail,5,0.0,0.0,1.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,Wood,1,60.0,0.0,5.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,Wood,2,67.89474,0.0,5.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,Wood,3,72.09141,0.0,5.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,Wood,4,73.05912,0.0,5.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,Wood,5,73.40733,0.0,5.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,Nail,1,3.15789,0.0,1.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,Nail,2,3.57341,0.0,1.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,Nail,3,3.79428,0.0,1.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,Nail,4,3.84522,0.0,1.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,Nail,5,3.86354,0.0,1.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,Wood,1,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,Wood,2,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,Wood,3,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,Wood,4,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,Wood,5,0.0,0.0,5.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,Nail,1,0.0,0.0,1.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,Nail,2,0.0,0.0,1.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,Nail,3,0.0,0.0,1.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,Nail,4,0.0,0.0,1.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,Nail,5,0.0,0.0,1.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,UsedBoat,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,UsedBoat,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,UsedBoat,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,UsedBoat,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,UsedBoat,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,UsedBoat,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,UsedBoat,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,UsedBoat,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,UsedBoat,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,UsedBoat,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,UsedBoat,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,UsedBoat,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,UsedBoat,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,UsedBoat,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,UsedBoat,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,UsedBoat,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,UsedBoat,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,UsedBoat,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,UsedBoat,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,UsedBoat,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,UsedBoat,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,UsedBoat,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,UsedBoat,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,UsedBoat,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,UsedBoat,1,6.31579,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,UsedBoat,2,22.93629,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,UsedBoat,3,31.7714,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,UsedBoat,4,33.80867,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,UsedBoat,5,34.54174,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,UsedBoat,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,UsedBoat,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,UsedBoat,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,UsedBoat,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,UsedBoat,5,0.0,0.0,0.0,0.0
|
||||
|
302
test/fixtures/boat_example/plant_outputs.csv
vendored
@@ -1,151 +1,151 @@
|
||||
plant,output product,year,amount produced (tonne),amount disposed (tonne),disposal cost ($)
|
||||
BoatFactory (Chicago),NewBoat,1,0.0,0.0,0.0
|
||||
BoatFactory (Chicago),NewBoat,2,0.0,0.0,0.0
|
||||
BoatFactory (Chicago),NewBoat,3,0.0,0.0,0.0
|
||||
BoatFactory (Chicago),NewBoat,4,0.0,0.0,0.0
|
||||
BoatFactory (Chicago),NewBoat,5,0.0,0.0,0.0
|
||||
BoatFactory (New York City),NewBoat,1,0.0,0.0,0.0
|
||||
BoatFactory (New York City),NewBoat,2,0.0,0.0,0.0
|
||||
BoatFactory (New York City),NewBoat,3,0.0,0.0,0.0
|
||||
BoatFactory (New York City),NewBoat,4,0.0,0.0,0.0
|
||||
BoatFactory (New York City),NewBoat,5,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),NewBoat,1,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),NewBoat,2,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),NewBoat,3,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),NewBoat,4,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),NewBoat,5,0.0,0.0,0.0
|
||||
BoatFactory (Houston),NewBoat,1,0.0,0.0,0.0
|
||||
BoatFactory (Houston),NewBoat,2,0.0,0.0,0.0
|
||||
BoatFactory (Houston),NewBoat,3,0.0,0.0,0.0
|
||||
BoatFactory (Houston),NewBoat,4,0.0,0.0,0.0
|
||||
BoatFactory (Houston),NewBoat,5,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),NewBoat,1,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),NewBoat,2,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),NewBoat,3,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),NewBoat,4,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),NewBoat,5,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),NewBoat,1,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),NewBoat,2,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),NewBoat,3,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),NewBoat,4,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),NewBoat,5,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),NewBoat,1,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),NewBoat,2,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),NewBoat,3,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),NewBoat,4,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),NewBoat,5,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),NewBoat,1,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),NewBoat,2,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),NewBoat,3,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),NewBoat,4,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),NewBoat,5,0.0,0.0,0.0
|
||||
BoatFactory (Dallas),NewBoat,1,63.15789,0.0,0.0
|
||||
BoatFactory (Dallas),NewBoat,2,71.46814,0.0,0.0
|
||||
BoatFactory (Dallas),NewBoat,3,75.8857,0.0,0.0
|
||||
BoatFactory (Dallas),NewBoat,4,76.90434,0.0,0.0
|
||||
BoatFactory (Dallas),NewBoat,5,77.27087,0.0,0.0
|
||||
BoatFactory (San Jose),NewBoat,1,0.0,0.0,0.0
|
||||
BoatFactory (San Jose),NewBoat,2,0.0,0.0,0.0
|
||||
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,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,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
|
||||
RecyclingPlant (New York City),Nail,1,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),Nail,2,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),Nail,3,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),Nail,4,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),Nail,5,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),Wood,1,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),Wood,2,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),Wood,3,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),Wood,4,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),Wood,5,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),Nail,1,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),Nail,2,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),Nail,3,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),Nail,4,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),Nail,5,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),Wood,1,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),Wood,2,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),Wood,3,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),Wood,4,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),Wood,5,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),Nail,1,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),Nail,2,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),Nail,3,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),Nail,4,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),Nail,5,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),Wood,1,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),Wood,2,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),Wood,3,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),Wood,4,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),Wood,5,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),Nail,1,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),Nail,2,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),Nail,3,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),Nail,4,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),Nail,5,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),Wood,1,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),Wood,2,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),Wood,3,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),Wood,4,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),Wood,5,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),Nail,1,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),Nail,2,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),Nail,3,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),Nail,4,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),Nail,5,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),Wood,1,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),Wood,2,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),Wood,3,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),Wood,4,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),Wood,5,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),Nail,1,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),Nail,2,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),Nail,3,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),Nail,4,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),Nail,5,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),Wood,1,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),Wood,2,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),Wood,3,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),Wood,4,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),Wood,5,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),Nail,1,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),Nail,2,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),Nail,3,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),Nail,4,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),Nail,5,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),Wood,1,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),Wood,2,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),Wood,3,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),Wood,4,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),Wood,5,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),Nail,1,0.15789,0.0,0.0
|
||||
RecyclingPlant (Dallas),Nail,2,0.57341,0.0,0.0
|
||||
RecyclingPlant (Dallas),Nail,3,0.79428,0.0,0.0
|
||||
RecyclingPlant (Dallas),Nail,4,0.84522,0.0,0.0
|
||||
RecyclingPlant (Dallas),Nail,5,0.86354,0.0,0.0
|
||||
RecyclingPlant (Dallas),Wood,1,3.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),Wood,2,10.89474,0.0,0.0
|
||||
RecyclingPlant (Dallas),Wood,3,15.09141,0.0,0.0
|
||||
RecyclingPlant (Dallas),Wood,4,16.05912,0.0,0.0
|
||||
RecyclingPlant (Dallas),Wood,5,16.40733,0.0,0.0
|
||||
RecyclingPlant (San Jose),Nail,1,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),Nail,2,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),Nail,3,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),Nail,4,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),Nail,5,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),Wood,1,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),Wood,2,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),Wood,3,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),Wood,4,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),Wood,5,0.0,0.0,0.0
|
||||
plant,latitude,longitude,output product,year,amount produced (tonne),amount disposed (tonne),disposal limit (tonne),disposal cost ($)
|
||||
BoatFactory (Chicago),41.881832,-87.623177,NewBoat,1,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,NewBoat,2,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,NewBoat,3,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,NewBoat,4,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,NewBoat,5,0.0,0.0,0.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,NewBoat,1,0.0,0.0,0.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,NewBoat,2,0.0,0.0,0.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,NewBoat,3,0.0,0.0,0.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,NewBoat,4,0.0,0.0,0.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,NewBoat,5,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,NewBoat,1,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,NewBoat,2,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,NewBoat,3,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,NewBoat,4,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,NewBoat,5,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,NewBoat,1,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,NewBoat,2,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,NewBoat,3,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,NewBoat,4,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,NewBoat,5,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,NewBoat,1,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,NewBoat,2,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,NewBoat,3,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,NewBoat,4,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,NewBoat,5,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,NewBoat,1,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,NewBoat,2,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,NewBoat,3,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,NewBoat,4,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,NewBoat,5,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,NewBoat,1,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,NewBoat,2,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,NewBoat,3,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,NewBoat,4,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,NewBoat,5,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,NewBoat,1,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,NewBoat,2,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,NewBoat,3,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,NewBoat,4,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,NewBoat,5,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,NewBoat,1,63.15789,0.0,0.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,NewBoat,2,71.46814,0.0,0.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,NewBoat,3,75.8857,0.0,0.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,NewBoat,4,76.90434,0.0,0.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,NewBoat,5,77.27087,0.0,0.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,NewBoat,1,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,NewBoat,2,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,NewBoat,3,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,NewBoat,4,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,NewBoat,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,Nail,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,Nail,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,Nail,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,Nail,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,Nail,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,Wood,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,Wood,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,Wood,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,Wood,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,Wood,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,Nail,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,Nail,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,Nail,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,Nail,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,Nail,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,Wood,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,Wood,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,Wood,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,Wood,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,Wood,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,Nail,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,Nail,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,Nail,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,Nail,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,Nail,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,Wood,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,Wood,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,Wood,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,Wood,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,Wood,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,Nail,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,Nail,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,Nail,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,Nail,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,Nail,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,Wood,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,Wood,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,Wood,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,Wood,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,Wood,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,Nail,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,Nail,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,Nail,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,Nail,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,Nail,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,Wood,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,Wood,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,Wood,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,Wood,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,Wood,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,Nail,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,Nail,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,Nail,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,Nail,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,Nail,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,Wood,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,Wood,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,Wood,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,Wood,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,Wood,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,Nail,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,Nail,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,Nail,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,Nail,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,Nail,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,Wood,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,Wood,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,Wood,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,Wood,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,Wood,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,Nail,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,Nail,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,Nail,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,Nail,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,Nail,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,Wood,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,Wood,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,Wood,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,Wood,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,Wood,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,Nail,1,0.15789,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,Nail,2,0.57341,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,Nail,3,0.79428,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,Nail,4,0.84522,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,Nail,5,0.86354,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,Wood,1,3.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,Wood,2,10.89474,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,Wood,3,15.09141,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,Wood,4,16.05912,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,Wood,5,16.40733,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,Nail,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,Nail,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,Nail,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,Nail,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,Nail,5,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,Wood,1,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,Wood,2,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,Wood,3,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,Wood,4,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,Wood,5,0.0,0.0,0.0,0.0
|
||||
|
||||
|
202
test/fixtures/boat_example/plants.csv
vendored
@@ -1,101 +1,101 @@
|
||||
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 (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 (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),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 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
|
||||
BoatFactory (San Diego),4,false,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),5,false,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Dallas),1,true,63.15789,100000.0,250000.0,315.78947
|
||||
BoatFactory (Dallas),2,true,71.46814,0.0,250000.0,357.34072
|
||||
BoatFactory (Dallas),3,true,75.8857,0.0,250000.0,379.42849
|
||||
BoatFactory (Dallas),4,true,76.90434,0.0,250000.0,384.52168
|
||||
BoatFactory (Dallas),5,true,77.27087,0.0,250000.0,386.35435
|
||||
BoatFactory (San Jose),1,false,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Jose),2,false,0.0,0.0,0.0,0.0
|
||||
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),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
|
||||
RecyclingPlant (New York City),1,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),2,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),3,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),4,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),5,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),1,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),2,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),3,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),4,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),5,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),1,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),2,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),3,false,0.0,0.0,0.0,0.0
|
||||
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),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
|
||||
RecyclingPlant (Philadelphia),2,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),3,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),4,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),5,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),1,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),2,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),3,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),4,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),5,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),1,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),2,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),3,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),4,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),5,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),1,true,6.31579,500000.0,125000.0,15.78947
|
||||
RecyclingPlant (Dallas),2,true,22.93629,0.0,125000.0,57.34072
|
||||
RecyclingPlant (Dallas),3,true,31.7714,0.0,125000.0,79.42849
|
||||
RecyclingPlant (Dallas),4,true,33.80867,0.0,125000.0,84.52168
|
||||
RecyclingPlant (Dallas),5,true,34.54174,0.0,125000.0,86.35435
|
||||
RecyclingPlant (San Jose),1,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),2,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),3,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),4,false,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),5,false,0.0,0.0,0.0,0.0
|
||||
plant,latitude,longitude,initial capacity,current capacity,year,operational?,input amount (tonne),stored amount (tonne),processed amount (tonne),opening cost ($),fixed operating cost ($),variable operating cost ($),expansion cost ($),storage cost ($)
|
||||
BoatFactory (Chicago),41.881832,-87.623177,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Chicago),41.881832,-87.623177,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (New York City),40.712776,-74.005974,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Los Angeles),34.052235,-118.243683,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Houston),29.760427,-95.369804,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Phoenix),33.448376,-112.074036,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Philadelphia),39.952583,-75.165222,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Antonio),29.424122,-98.493629,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Diego),32.715736,-117.161087,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,0.0,500.0,1,true,63.15789,0.0,63.15789,100000.0,250000.0,315.78947,0.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,0.0,500.0,2,true,71.46814,0.0,71.46814,0.0,250000.0,357.34072,0.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,0.0,500.0,3,true,75.8857,0.0,75.8857,0.0,250000.0,379.42849,0.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,0.0,500.0,4,true,76.90434,0.0,76.90434,0.0,250000.0,384.52168,0.0,0.0
|
||||
BoatFactory (Dallas),32.776664,-96.796988,0.0,500.0,5,true,77.27087,0.0,77.27087,0.0,250000.0,386.35435,0.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
BoatFactory (San Jose),37.338208,-121.886329,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Chicago),41.881832,-87.623177,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (New York City),40.712776,-74.005974,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Los Angeles),34.052235,-118.243683,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Houston),29.760427,-95.369804,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Phoenix),33.448376,-112.074036,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Philadelphia),39.952583,-75.165222,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Antonio),29.424122,-98.493629,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Diego),32.715736,-117.161087,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,0.0,500.0,1,true,6.31579,0.0,6.31579,500000.0,125000.0,15.78947,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,0.0,500.0,2,true,22.93629,0.0,22.93629,0.0,125000.0,57.34072,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,0.0,500.0,3,true,31.7714,0.0,31.7714,0.0,125000.0,79.42849,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,0.0,500.0,4,true,33.80867,0.0,33.80867,0.0,125000.0,84.52168,0.0,0.0
|
||||
RecyclingPlant (Dallas),32.776664,-96.796988,0.0,500.0,5,true,34.54174,0.0,34.54174,0.0,125000.0,86.35435,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,0.0,0.0,1,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,0.0,0.0,2,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,0.0,0.0,3,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,0.0,0.0,4,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
RecyclingPlant (San Jose),37.338208,-121.886329,0.0,0.0,5,false,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0
|
||||
|
||||
|
81
test/fixtures/boat_example/tr_emissions.csv
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
source,destination,product,emission,year,amount sent (tonne),distance (km),emission factor (tonne/km/tonne),emission amount (tonne)
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Nail,CO2,1,0.15789,0.0,2.68,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Nail,NH4,1,0.15789,0.0,1.02,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Nail,CO2,2,0.57341,0.0,2.68,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Nail,NH4,2,0.57341,0.0,1.02,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Nail,CO2,3,0.79428,0.0,2.68,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Nail,NH4,3,0.79428,0.0,1.02,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Nail,CO2,4,0.84522,0.0,2.68,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Nail,NH4,4,0.84522,0.0,1.02,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Nail,CO2,5,0.86354,0.0,2.68,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Nail,NH4,5,0.86354,0.0,1.02,0.0
|
||||
NailFactory (Chicago),BoatFactory (Dallas),Nail,CO2,1,1.0,1293.093,2.68,3465.48924
|
||||
NailFactory (Chicago),BoatFactory (Dallas),Nail,NH4,1,1.0,1293.093,1.02,1318.95486
|
||||
NailFactory (Chicago),BoatFactory (Dallas),Nail,CO2,2,1.0,1293.093,2.68,3465.48924
|
||||
NailFactory (Chicago),BoatFactory (Dallas),Nail,NH4,2,1.0,1293.093,1.02,1318.95486
|
||||
NailFactory (Chicago),BoatFactory (Dallas),Nail,CO2,3,1.0,1293.093,2.68,3465.48924
|
||||
NailFactory (Chicago),BoatFactory (Dallas),Nail,NH4,3,1.0,1293.093,1.02,1318.95486
|
||||
NailFactory (Chicago),BoatFactory (Dallas),Nail,CO2,4,1.0,1293.093,2.68,3465.48924
|
||||
NailFactory (Chicago),BoatFactory (Dallas),Nail,NH4,4,1.0,1293.093,1.02,1318.95486
|
||||
NailFactory (Chicago),BoatFactory (Dallas),Nail,CO2,5,1.0,1293.093,2.68,3465.48924
|
||||
NailFactory (Chicago),BoatFactory (Dallas),Nail,NH4,5,1.0,1293.093,1.02,1318.95486
|
||||
NailFactory (Phoenix),BoatFactory (Dallas),Nail,CO2,1,1.0,1423.57,2.68,3815.1676
|
||||
NailFactory (Phoenix),BoatFactory (Dallas),Nail,NH4,1,1.0,1423.57,1.02,1452.0414
|
||||
NailFactory (Phoenix),BoatFactory (Dallas),Nail,CO2,2,1.0,1423.57,2.68,3815.1676
|
||||
NailFactory (Phoenix),BoatFactory (Dallas),Nail,NH4,2,1.0,1423.57,1.02,1452.0414
|
||||
NailFactory (Phoenix),BoatFactory (Dallas),Nail,CO2,3,1.0,1423.57,2.68,3815.1676
|
||||
NailFactory (Phoenix),BoatFactory (Dallas),Nail,NH4,3,1.0,1423.57,1.02,1452.0414
|
||||
NailFactory (Phoenix),BoatFactory (Dallas),Nail,CO2,4,1.0,1423.57,2.68,3815.1676
|
||||
NailFactory (Phoenix),BoatFactory (Dallas),Nail,NH4,4,1.0,1423.57,1.02,1452.0414
|
||||
NailFactory (Phoenix),BoatFactory (Dallas),Nail,CO2,5,1.0,1423.57,2.68,3815.1676
|
||||
NailFactory (Phoenix),BoatFactory (Dallas),Nail,NH4,5,1.0,1423.57,1.02,1452.0414
|
||||
NailFactory (Dallas),BoatFactory (Dallas),Nail,CO2,1,1.0,0.0,2.68,0.0
|
||||
NailFactory (Dallas),BoatFactory (Dallas),Nail,NH4,1,1.0,0.0,1.02,0.0
|
||||
NailFactory (Dallas),BoatFactory (Dallas),Nail,CO2,2,1.0,0.0,2.68,0.0
|
||||
NailFactory (Dallas),BoatFactory (Dallas),Nail,NH4,2,1.0,0.0,1.02,0.0
|
||||
NailFactory (Dallas),BoatFactory (Dallas),Nail,CO2,3,1.0,0.0,2.68,0.0
|
||||
NailFactory (Dallas),BoatFactory (Dallas),Nail,NH4,3,1.0,0.0,1.02,0.0
|
||||
NailFactory (Dallas),BoatFactory (Dallas),Nail,CO2,4,1.0,0.0,2.68,0.0
|
||||
NailFactory (Dallas),BoatFactory (Dallas),Nail,NH4,4,1.0,0.0,1.02,0.0
|
||||
NailFactory (Dallas),BoatFactory (Dallas),Nail,CO2,5,1.0,0.0,2.68,0.0
|
||||
NailFactory (Dallas),BoatFactory (Dallas),Nail,NH4,5,1.0,0.0,1.02,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Wood,CO2,1,3.0,0.0,2.68,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Wood,NH4,1,3.0,0.0,1.02,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Wood,CO2,2,10.89474,0.0,2.68,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Wood,NH4,2,10.89474,0.0,1.02,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Wood,CO2,3,15.09141,0.0,2.68,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Wood,NH4,3,15.09141,0.0,1.02,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Wood,CO2,4,16.05912,0.0,2.68,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Wood,NH4,4,16.05912,0.0,1.02,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Wood,CO2,5,16.40733,0.0,2.68,0.0
|
||||
RecyclingPlant (Dallas),BoatFactory (Dallas),Wood,NH4,5,16.40733,0.0,1.02,0.0
|
||||
Forest (Dallas),BoatFactory (Dallas),Wood,CO2,1,57.0,0.0,2.68,0.0
|
||||
Forest (Dallas),BoatFactory (Dallas),Wood,NH4,1,57.0,0.0,1.02,0.0
|
||||
Forest (Dallas),BoatFactory (Dallas),Wood,CO2,2,57.0,0.0,2.68,0.0
|
||||
Forest (Dallas),BoatFactory (Dallas),Wood,NH4,2,57.0,0.0,1.02,0.0
|
||||
Forest (Dallas),BoatFactory (Dallas),Wood,CO2,3,57.0,0.0,2.68,0.0
|
||||
Forest (Dallas),BoatFactory (Dallas),Wood,NH4,3,57.0,0.0,1.02,0.0
|
||||
Forest (Dallas),BoatFactory (Dallas),Wood,CO2,4,57.0,0.0,2.68,0.0
|
||||
Forest (Dallas),BoatFactory (Dallas),Wood,NH4,4,57.0,0.0,1.02,0.0
|
||||
Forest (Dallas),BoatFactory (Dallas),Wood,CO2,5,57.0,0.0,2.68,0.0
|
||||
Forest (Dallas),BoatFactory (Dallas),Wood,NH4,5,57.0,0.0,1.02,0.0
|
||||
BoatFactory (Dallas),Retail (Dallas),NewBoat,CO2,1,63.15789,0.0,2.68,0.0
|
||||
BoatFactory (Dallas),Retail (Dallas),NewBoat,NH4,1,63.15789,0.0,1.02,0.0
|
||||
BoatFactory (Dallas),Retail (Dallas),NewBoat,CO2,2,71.46814,0.0,2.68,0.0
|
||||
BoatFactory (Dallas),Retail (Dallas),NewBoat,NH4,2,71.46814,0.0,1.02,0.0
|
||||
BoatFactory (Dallas),Retail (Dallas),NewBoat,CO2,3,75.8857,0.0,2.68,0.0
|
||||
BoatFactory (Dallas),Retail (Dallas),NewBoat,NH4,3,75.8857,0.0,1.02,0.0
|
||||
BoatFactory (Dallas),Retail (Dallas),NewBoat,CO2,4,76.90434,0.0,2.68,0.0
|
||||
BoatFactory (Dallas),Retail (Dallas),NewBoat,NH4,4,76.90434,0.0,1.02,0.0
|
||||
BoatFactory (Dallas),Retail (Dallas),NewBoat,CO2,5,77.27087,0.0,2.68,0.0
|
||||
BoatFactory (Dallas),Retail (Dallas),NewBoat,NH4,5,77.27087,0.0,1.02,0.0
|
||||
Retail (Dallas),RecyclingPlant (Dallas),UsedBoat,CO2,1,6.31579,0.0,2.68,0.0
|
||||
Retail (Dallas),RecyclingPlant (Dallas),UsedBoat,NH4,1,6.31579,0.0,1.02,0.0
|
||||
Retail (Dallas),RecyclingPlant (Dallas),UsedBoat,CO2,2,22.93629,0.0,2.68,0.0
|
||||
Retail (Dallas),RecyclingPlant (Dallas),UsedBoat,NH4,2,22.93629,0.0,1.02,0.0
|
||||
Retail (Dallas),RecyclingPlant (Dallas),UsedBoat,CO2,3,31.7714,0.0,2.68,0.0
|
||||
Retail (Dallas),RecyclingPlant (Dallas),UsedBoat,NH4,3,31.7714,0.0,1.02,0.0
|
||||
Retail (Dallas),RecyclingPlant (Dallas),UsedBoat,CO2,4,33.80867,0.0,2.68,0.0
|
||||
Retail (Dallas),RecyclingPlant (Dallas),UsedBoat,NH4,4,33.80867,0.0,1.02,0.0
|
||||
Retail (Dallas),RecyclingPlant (Dallas),UsedBoat,CO2,5,34.54174,0.0,2.68,0.0
|
||||
Retail (Dallas),RecyclingPlant (Dallas),UsedBoat,NH4,5,34.54174,0.0,1.02,0.0
|
||||
|
26
test/fixtures/simple.json
vendored
@@ -2,7 +2,7 @@
|
||||
"parameters": {
|
||||
"time horizon (years)": 4,
|
||||
"building period (years)": [1],
|
||||
"distance metric": "driving"
|
||||
"distance metric": "euclidean"
|
||||
},
|
||||
"products": {
|
||||
"P1": {
|
||||
@@ -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": {
|
||||
@@ -149,7 +153,17 @@
|
||||
"variable operating cost ($/tonne)": 5.0
|
||||
}
|
||||
],
|
||||
"initial capacity (tonne)": 0
|
||||
"initial capacity (tonne)": 250
|
||||
}
|
||||
},
|
||||
"emissions": {
|
||||
"CO2": {
|
||||
"limit (tonne)": [1000.0, 1100.0, 1200.0, 1300.0],
|
||||
"penalty ($/tonne)": [50.0, 55.0, 60.0, 65.0]
|
||||
},
|
||||
"CH4": {
|
||||
"limit (tonne)": null,
|
||||
"penalty ($/tonne)": 1200.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using JuliaFormatter
|
||||
include("instance/parse_test.jl")
|
||||
include("model/build_test.jl")
|
||||
include("model/dist_test.jl")
|
||||
include("model/jumpext_test.jl")
|
||||
include("reports_test.jl")
|
||||
include("../fixtures/boat_example.jl")
|
||||
|
||||
@@ -23,7 +24,9 @@ function runtests()
|
||||
model_build_test()
|
||||
model_dist_test()
|
||||
report_tests()
|
||||
jumpext_test()
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
function format()
|
||||
|
||||
@@ -8,7 +8,7 @@ function instance_parse_test_1()
|
||||
# Parameters
|
||||
@test instance.time_horizon == 4
|
||||
@test instance.building_period == [1]
|
||||
@test instance.distance_metric == "driving"
|
||||
@test instance.distance_metric isa RELOG.EuclideanDistance
|
||||
|
||||
# Products
|
||||
@test length(instance.products) == 4
|
||||
@@ -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]
|
||||
@@ -55,7 +56,7 @@ function instance_parse_test_1()
|
||||
@test l1.disposal_cost == Dict(p3 => [0, 0, 0, 0], p4 => [0.86, 0.86, 0.86, 0.86])
|
||||
@test l1.disposal_limit ==
|
||||
Dict(p3 => [Inf, Inf, Inf, Inf], p4 => [1000.0, 1000.0, 1000.0, 1000.0])
|
||||
@test l1.initial_capacity == 0
|
||||
@test l1.initial_capacity == 250
|
||||
@test length(l1.capacities) == 2
|
||||
c1 = l1.capacities[1]
|
||||
@test c1.size == 100
|
||||
@@ -67,6 +68,19 @@ function instance_parse_test_1()
|
||||
@test c2.opening_cost == [1000, 1000, 1000, 1000]
|
||||
@test c2.fix_operating_cost == [400, 400, 400, 400]
|
||||
@test c2.var_operating_cost == [5, 5, 5, 5]
|
||||
|
||||
# Emissions
|
||||
@test length(instance.emissions) == 2
|
||||
co2 = instance.emissions[1]
|
||||
@test co2.name == "CO2"
|
||||
@test co2.limit == [1000.0, 1100.0, 1200.0, 1300.0]
|
||||
@test co2.penalty == [50.0, 55.0, 60.0, 65.0]
|
||||
@test instance.emissions_by_name["CO2"] === co2
|
||||
ch4 = instance.emissions[2]
|
||||
@test ch4.name == "CH4"
|
||||
@test ch4.limit == [Inf, Inf, Inf, Inf]
|
||||
@test ch4.penalty == [1200.0, 1200.0, 1200.0, 1200.0]
|
||||
@test instance.emissions_by_name["CH4"] === ch4
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,11 @@ function model_build_test()
|
||||
y = model[:y]
|
||||
z_disp = model[:z_disp]
|
||||
z_input = model[:z_input]
|
||||
z_process = model[:z_process]
|
||||
z_storage = model[:z_storage]
|
||||
z_em_tr = model[:z_em_tr]
|
||||
z_em_plant = model[:z_em_plant]
|
||||
z_exp = model[:z_exp]
|
||||
x = model[:x]
|
||||
obj = objective_function(model)
|
||||
# print(model)
|
||||
@@ -25,6 +30,8 @@ function model_build_test()
|
||||
@test obj.terms[z_disp["C1", "P2", 1]] == 0.23
|
||||
@test obj.constant == (
|
||||
150 * 4 * 3 # center operating cost
|
||||
- 300 # initial opening cost
|
||||
- 150 * 1.75 # initial expansion
|
||||
)
|
||||
@test obj.terms[z_disp["L1", "P4", 2]] == 0.86
|
||||
@test obj.terms[x["L1", 1]] == (
|
||||
@@ -44,21 +51,58 @@ function model_build_test()
|
||||
300 # fixed operating cost
|
||||
)
|
||||
|
||||
# Test expansion variables exist and have correct initial values
|
||||
@test z_exp["L1", 0] == 150.0 # initial_capacity (250) - min_capacity (100)
|
||||
@test haskey(z_exp, ("L1", 1))
|
||||
@test haskey(z_exp, ("L1", 2))
|
||||
@test haskey(z_exp, ("L1", 3))
|
||||
@test haskey(z_exp, ("L1", 4))
|
||||
|
||||
# Test expansion costs in objective function
|
||||
# R_expand[1] = (1000 - 300) / (500 - 100) = 1.75
|
||||
# R_expand[2] = (1000 - 400) / (500 - 100) = 1.5
|
||||
# R_fix_exp[1] = (400 - 300) / (500 - 100) = 0.25
|
||||
@test obj.terms[z_exp["L1", 1]] == (
|
||||
+1.75 # expansion cost[1]
|
||||
- 1.5 # expansion cost[2]
|
||||
+ 0.25 # fixed operating cost[1]
|
||||
)
|
||||
|
||||
# Test storage cost in objective function
|
||||
@test obj.terms[z_storage["L1", "P1", 1]] == 0.1 # P1 storage cost
|
||||
@test obj.terms[z_storage["L1", "P2", 1]] == 0.1 # P2 storage cost
|
||||
|
||||
# Variables: Transportation emissions
|
||||
@test haskey(z_em_tr, ("CO2", "L1", "C3", "P4", 1))
|
||||
@test haskey(z_em_tr, ("CH4", "L1", "C3", "P4", 1))
|
||||
@test haskey(z_em_tr, ("CO2", "C2", "L1", "P1", 1))
|
||||
@test haskey(z_em_tr, ("CH4", "C2", "L1", "P1", 1))
|
||||
|
||||
# Variables: Plant emissions
|
||||
@test haskey(z_em_plant, ("CO2", "L1", 1))
|
||||
@test haskey(z_em_plant, ("CO2", "L1", 2))
|
||||
@test haskey(z_em_plant, ("CO2", "L1", 3))
|
||||
@test haskey(z_em_plant, ("CO2", "L1", 4))
|
||||
|
||||
# Plants: Definition of total plant input
|
||||
@test repr(model[:eq_z_input]["L1", 1]) ==
|
||||
"eq_z_input[L1,1] : -y[C2,L1,P1,1] - y[C1,L1,P2,1] + z_input[L1,1] = 0"
|
||||
|
||||
# Plants: Must meet input mix
|
||||
@test repr(model[:eq_input_mix]["L1", "P1", 1]) ==
|
||||
"eq_input_mix[L1,P1,1] : y[C2,L1,P1,1] - 0.953 z_input[L1,1] = 0"
|
||||
@test repr(model[:eq_input_mix]["L1", "P2", 1]) ==
|
||||
"eq_input_mix[L1,P2,1] : y[C1,L1,P2,1] - 0.047 z_input[L1,1] = 0"
|
||||
# Plants: Definition of total processing amount
|
||||
@test repr(model[:eq_z_process]["L1", 1]) ==
|
||||
"eq_z_process[L1,1] : -z_input[L1,1] + z_storage[L1,P1,1] + z_storage[L1,P2,1] + z_process[L1,1] = 0"
|
||||
|
||||
# Plants: Processing mix must have correct proportion
|
||||
@test repr(model[:eq_process_mix]["L1", "P1", 1]) ==
|
||||
"eq_process_mix[L1,P1,1] : y[C2,L1,P1,1] - z_storage[L1,P1,1] - 0.953 z_process[L1,1] = 0"
|
||||
@test repr(model[:eq_process_mix]["L1", "P2", 1]) ==
|
||||
"eq_process_mix[L1,P2,1] : y[C1,L1,P2,1] - z_storage[L1,P2,1] - 0.047 z_process[L1,1] = 0"
|
||||
|
||||
# Plants: Calculate amount produced
|
||||
@test repr(model[:eq_z_prod]["L1", "P3", 1]) ==
|
||||
"eq_z_prod[L1,P3,1] : z_prod[L1,P3,1] - 0.25 z_input[L1,1] = 0"
|
||||
"eq_z_prod[L1,P3,1] : z_prod[L1,P3,1] - 0.25 z_process[L1,1] = 0"
|
||||
@test repr(model[:eq_z_prod]["L1", "P4", 1]) ==
|
||||
"eq_z_prod[L1,P4,1] : z_prod[L1,P4,1] - 0.12 z_input[L1,1] = 0"
|
||||
"eq_z_prod[L1,P4,1] : z_prod[L1,P4,1] - 0.12 z_process[L1,1] = 0"
|
||||
|
||||
# Plants: Produced material must be sent or disposed
|
||||
@test repr(model[:eq_balance]["L1", "P3", 1]) ==
|
||||
@@ -66,9 +110,13 @@ function model_build_test()
|
||||
@test repr(model[:eq_balance]["L1", "P4", 1]) ==
|
||||
"eq_balance[L1,P4,1] : -y[L1,C3,P4,1] + z_prod[L1,P4,1] - z_disp[L1,P4,1] = 0"
|
||||
|
||||
# Plants: Capacity limit
|
||||
@test repr(model[:eq_capacity]["L1", 1]) ==
|
||||
"eq_capacity[L1,1] : -100 x[L1,1] + z_input[L1,1] ≤ 0"
|
||||
# Plants: Processing limit (capacity constraint)
|
||||
@test repr(model[:eq_process_limit]["L1", 1]) ==
|
||||
"eq_process_limit[L1,1] : -100 x[L1,1] - z_exp[L1,1] + z_process[L1,1] ≤ 0"
|
||||
|
||||
# Plants: Expansion upper bound
|
||||
@test repr(model[:eq_exp_ub]["L1", 1]) ==
|
||||
"eq_exp_ub[L1,1] : -400 x[L1,1] + z_exp[L1,1] ≤ 0"
|
||||
|
||||
# Plants: Disposal limit
|
||||
@test repr(model[:eq_disposal_limit]["L1", "P4", 1]) ==
|
||||
@@ -78,7 +126,13 @@ function model_build_test()
|
||||
# Plants: Plant remains open
|
||||
@test repr(model[:eq_keep_open]["L1", 4]) ==
|
||||
"eq_keep_open[L1,4] : -x[L1,3] + x[L1,4] ≥ 0"
|
||||
@test repr(model[:eq_keep_open]["L1", 1]) == "eq_keep_open[L1,1] : x[L1,1] ≥ 0"
|
||||
@test repr(model[:eq_keep_open]["L1", 1]) == "eq_keep_open[L1,1] : x[L1,1] ≥ 1"
|
||||
|
||||
# Plants: Capacity cannot decrease over time
|
||||
@test repr(model[:eq_capacity_nondecreasing]["L1", 4]) ==
|
||||
"eq_capacity_nondecreasing[L1,4] : -z_exp[L1,3] + z_exp[L1,4] ≥ 0"
|
||||
@test repr(model[:eq_capacity_nondecreasing]["L1", 1]) ==
|
||||
"eq_capacity_nondecreasing[L1,1] : z_exp[L1,1] ≥ 150"
|
||||
|
||||
# Plants: Building period
|
||||
@test ("L1", 1) ∉ keys(model[:eq_building_period])
|
||||
@@ -109,4 +163,60 @@ 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])
|
||||
|
||||
# Products: Transportation emissions
|
||||
@test repr(model[:eq_emission_tr]["CH4", "L1", "C3", "P4", 1]) ==
|
||||
"eq_emission_tr[CH4,L1,C3,P4,1] : -0.333354 y[L1,C3,P4,1] + z_em_tr[CH4,L1,C3,P4,1] = 0"
|
||||
|
||||
# Plants: Plant emissions (updated to use z_process)
|
||||
@test repr(model[:eq_emission_plant]["CO2", "L1", 1]) ==
|
||||
"eq_emission_plant[CO2,L1,1] : -0.1 z_process[L1,1] + z_em_plant[CO2,L1,1] = 0"
|
||||
|
||||
# Objective function: Emissions penalty costs
|
||||
@test obj.terms[z_em_plant["CO2", "L1", 1]] == 50.0 # CO2 penalty at time 1
|
||||
@test obj.terms[z_em_plant["CO2", "L1", 2]] == 55.0 # CO2 penalty at time 2
|
||||
@test obj.terms[z_em_plant["CO2", "L1", 3]] == 60.0 # CO2 penalty at time 3
|
||||
@test obj.terms[z_em_plant["CO2", "L1", 4]] == 65.0 # CO2 penalty at time 4
|
||||
@test obj.terms[z_em_tr["CO2", "L1", "C3", "P4", 1]] == 50.0 # CO2 transportation penalty at time 1
|
||||
@test obj.terms[z_em_tr["CH4", "L1", "C3", "P4", 1]] == 1200.0 # CH4 transportation penalty at time 1
|
||||
|
||||
# Global emissions limit constraints
|
||||
@test repr(model[:eq_emission_limit]["CO2", 1]) ==
|
||||
"eq_emission_limit[CO2,1] : z_em_tr[CO2,C2,L1,P1,1] + z_em_tr[CO2,C2,C1,P1,1] + z_em_tr[CO2,C1,L1,P2,1] + z_em_tr[CO2,L1,C3,P4,1] + z_em_plant[CO2,L1,1] ≤ 1000"
|
||||
@test ("CH4", 1) ∉ keys(model[:eq_emission_limit])
|
||||
|
||||
# Test storage variables exist
|
||||
@test haskey(z_storage, ("L1", "P1", 1))
|
||||
@test haskey(z_storage, ("L1", "P2", 1))
|
||||
@test haskey(z_process, ("L1", 1))
|
||||
@test haskey(z_process, ("L1", 2))
|
||||
@test haskey(z_process, ("L1", 3))
|
||||
@test haskey(z_process, ("L1", 4))
|
||||
|
||||
# Test initial storage values
|
||||
@test z_storage["L1", "P1", 0] == 0
|
||||
@test z_storage["L1", "P2", 0] == 0
|
||||
|
||||
# Test storage limit constraints (P1 has limit of 100, P2 has no limit)
|
||||
@test haskey(model[:eq_storage_limit], ("L1", "P1", 1))
|
||||
@test repr(model[:eq_storage_limit]["L1", "P1", 1]) ==
|
||||
"eq_storage_limit[L1,P1,1] : z_storage[L1,P1,1] ≤ 100"
|
||||
@test ("L1", "P2", 1) ∉ keys(model[:eq_storage_limit]) # P2 has no storage limit
|
||||
|
||||
# Test final storage constraints exist
|
||||
@test haskey(model[:eq_storage_final], ("L1", "P1"))
|
||||
@test haskey(model[:eq_storage_final], ("L1", "P2"))
|
||||
@test repr(model[:eq_storage_final]["L1", "P1"]) ==
|
||||
"eq_storage_final[L1,P1] : z_storage[L1,P1,4] = 0"
|
||||
@test repr(model[:eq_storage_final]["L1", "P2"]) ==
|
||||
"eq_storage_final[L1,P2] : z_storage[L1,P2,4] = 0"
|
||||
end
|
||||
|
||||
@@ -6,5 +6,20 @@ using RELOG
|
||||
|
||||
function model_dist_test()
|
||||
# Euclidean distance between Chicago and Indianapolis
|
||||
@test RELOG._calculate_distance(41.866, -87.656, 39.764, -86.148) == 265.818
|
||||
@test RELOG._calculate_distance(
|
||||
41.866,
|
||||
-87.656,
|
||||
39.764,
|
||||
-86.148,
|
||||
RELOG.EuclideanDistance(),
|
||||
) == 265.818
|
||||
|
||||
# Driving distance between Chicago and Indianapolis
|
||||
@test RELOG._calculate_distance(
|
||||
41.866,
|
||||
-87.656,
|
||||
39.764,
|
||||
-86.148,
|
||||
RELOG.KnnDrivingDistance(),
|
||||
) == 316.43
|
||||
end
|
||||
|
||||
144
test/src/model/jumpext_test.jl
Normal file
@@ -0,0 +1,144 @@
|
||||
# RELOG: Reverse Logistics Optimization
|
||||
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||
# Released under the modified BSD license. See COPYING.md for more details.
|
||||
|
||||
using RELOG
|
||||
using JuMP
|
||||
using HiGHS
|
||||
using Test
|
||||
|
||||
function jumpext_test()
|
||||
jumpext_pwl_single_point()
|
||||
jumpext_pwl_two_points()
|
||||
jumpext_pwl_multiple_points()
|
||||
jumpext_pwl_input_validation()
|
||||
return
|
||||
end
|
||||
|
||||
function jumpext_pwl_single_point()
|
||||
model = Model(HiGHS.Optimizer)
|
||||
set_silent(model)
|
||||
@variable(model, x)
|
||||
@variable(model, y1)
|
||||
@variable(model, y2)
|
||||
xpts = [5.0]
|
||||
ypts = [10.0 20.0]
|
||||
RELOG._add_pwl_constraints(model, x, [y1, y2], xpts, ypts)
|
||||
optimize!(model)
|
||||
@test is_solved_and_feasible(model)
|
||||
@test value(x) ≈ 5.0 atol = 1e-6
|
||||
@test value(y1) ≈ 10.0 atol = 1e-6
|
||||
@test value(y2) ≈ 20.0 atol = 1e-6
|
||||
return
|
||||
end
|
||||
|
||||
function jumpext_pwl_two_points()
|
||||
model = Model(HiGHS.Optimizer)
|
||||
set_silent(model)
|
||||
@variable(model, x)
|
||||
@variable(model, y1)
|
||||
@variable(model, y2)
|
||||
xpts = [0.0, 2.0]
|
||||
ypts = [0.0 10.0; 4.0 6.0]
|
||||
RELOG._add_pwl_constraints(model, x, [y1, y2], xpts, ypts)
|
||||
|
||||
# Test at x = 1
|
||||
JuMP.fix(x, 1.0)
|
||||
optimize!(model)
|
||||
@test is_solved_and_feasible(model)
|
||||
@test value(y1) ≈ 2.0 atol = 1e-6
|
||||
@test value(y2) ≈ 8.0 atol = 1e-6
|
||||
|
||||
# Test at x = 2
|
||||
JuMP.fix(x, 2.0)
|
||||
optimize!(model)
|
||||
@test is_solved_and_feasible(model)
|
||||
@test value(y1) ≈ 4.0 atol = 1e-6
|
||||
@test value(y2) ≈ 6.0 atol = 1e-6
|
||||
return
|
||||
end
|
||||
|
||||
function jumpext_pwl_multiple_points()
|
||||
model = Model(HiGHS.Optimizer)
|
||||
set_silent(model)
|
||||
@variable(model, x)
|
||||
@variable(model, y1)
|
||||
@variable(model, y2)
|
||||
xpts = [0.0, 1.0, 2.0]
|
||||
ypts = [0.0 5.0; 2.0 3.0; 1.0 4.0]
|
||||
RELOG._add_pwl_constraints(model, x, [y1, y2], xpts, ypts)
|
||||
|
||||
# Test at x = 0.5
|
||||
JuMP.fix(x, 0.5)
|
||||
optimize!(model)
|
||||
@test is_solved_and_feasible(model)
|
||||
@test value(y1) ≈ 1.0 atol = 1e-6
|
||||
@test value(y2) ≈ 4.0 atol = 1e-6
|
||||
|
||||
# Test at x = 1
|
||||
JuMP.fix(x, 1.0)
|
||||
optimize!(model)
|
||||
@test is_solved_and_feasible(model)
|
||||
@test value(y1) ≈ 2.0 atol = 1e-6
|
||||
@test value(y2) ≈ 3.0 atol = 1e-6
|
||||
|
||||
# Test at x = 1.5
|
||||
JuMP.fix(x, 1.5)
|
||||
optimize!(model)
|
||||
@test is_solved_and_feasible(model)
|
||||
@test value(y1) ≈ 1.5 atol = 1e-6
|
||||
@test value(y2) ≈ 3.5 atol = 1e-6
|
||||
return
|
||||
end
|
||||
|
||||
function jumpext_pwl_input_validation()
|
||||
model = Model(HiGHS.Optimizer)
|
||||
@variable(model, x)
|
||||
@variable(model, y)
|
||||
|
||||
# Test non-matrix ypts
|
||||
@test_throws ArgumentError RELOG._add_pwl_constraints(model, x, [y], [1.0], [1.0])
|
||||
|
||||
# Test mismatched dimensions
|
||||
@test_throws ArgumentError RELOG._add_pwl_constraints(
|
||||
model,
|
||||
x,
|
||||
[y],
|
||||
[1.0, 2.0],
|
||||
[1.0 2.0],
|
||||
)
|
||||
@test_throws ArgumentError RELOG._add_pwl_constraints(
|
||||
model,
|
||||
x,
|
||||
[y],
|
||||
[1.0],
|
||||
[1.0 2.0; 3.0 4.0],
|
||||
)
|
||||
|
||||
# Test empty breakpoints
|
||||
@test_throws ArgumentError RELOG._add_pwl_constraints(
|
||||
model,
|
||||
x,
|
||||
[y],
|
||||
Float64[],
|
||||
Matrix{Float64}(undef, 0, 1),
|
||||
)
|
||||
|
||||
# Test non-increasing x points
|
||||
@test_throws ArgumentError RELOG._add_pwl_constraints(
|
||||
model,
|
||||
x,
|
||||
[y],
|
||||
[2.0, 1.0],
|
||||
[1.0; 2.0],
|
||||
)
|
||||
@test_throws ArgumentError RELOG._add_pwl_constraints(
|
||||
model,
|
||||
x,
|
||||
[y],
|
||||
[1.0, 1.0],
|
||||
[1.0; 2.0],
|
||||
)
|
||||
|
||||
return
|
||||
end
|
||||
@@ -3,8 +3,10 @@ function report_tests()
|
||||
instance = RELOG.parsefile(fixture("boat_example.json"))
|
||||
model = RELOG.build_model(instance, optimizer = HiGHS.Optimizer, variable_names = true)
|
||||
optimize!(model)
|
||||
mkpath("tmp")
|
||||
write_to_file(model, "tmp/model.lp")
|
||||
RELOG.write_plants_report(model, "tmp/plants.csv")
|
||||
RELOG.write_plant_inputs_report(model, "tmp/plant_inputs.csv")
|
||||
RELOG.write_plant_outputs_report(model, "tmp/plant_outputs.csv")
|
||||
RELOG.write_centers_report(model, "tmp/centers.csv")
|
||||
RELOG.write_center_outputs_report(model, "tmp/center_outputs.csv")
|
||||
|
||||
25
web/.gitignore
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
assets
|
||||
1
web/.prettierrc.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
17746
web/package-lock.json
generated
Normal file
65
web/package.json
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "web",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.7.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^16.18.126",
|
||||
"@types/pako": "^2.0.3",
|
||||
"@types/papaparse": "^5.3.16",
|
||||
"@types/react": "^19.1.3",
|
||||
"@types/react-dom": "^19.1.3",
|
||||
"ajv": "^8.17.1",
|
||||
"eslint": "^8.57.1",
|
||||
"pako": "^2.1.0",
|
||||
"papaparse": "^5.5.2",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-scripts": "^5.0.1",
|
||||
"tabulator-tables": "^6.3.1",
|
||||
"typescript": "^4.9.5",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
],
|
||||
"rules": {
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
]
|
||||
}
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/tabulator-tables": "^6.2.6",
|
||||
"prettier": "3.5.3"
|
||||
}
|
||||
}
|
||||
BIN
web/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
49
web/public/index.html
Normal file
@@ -0,0 +1,49 @@
|
||||
<!--
|
||||
~ RELOG: Supply Chain Analysis and Optimization
|
||||
~ Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
~ Released under the modified BSD license. See COPYING.md for more details.
|
||||
-->
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="RELOG Case Builder" />
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<title>Case Builder - RELOG</title>
|
||||
<style>
|
||||
:root {
|
||||
--site-max-width: 1500px;
|
||||
--site-min-width: 900px;
|
||||
--box-border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
--box-shadow: 0px 2px 4px -3px rgba(0, 0, 0, 0.2);
|
||||
--border-radius: 4px;
|
||||
--primary: #0d6efd;
|
||||
--contrast-100: #202020;
|
||||
--contrast-80: #606060;
|
||||
--contrast-60: #909090;
|
||||
--contrast-20: #d6d6d6;
|
||||
--contrast-10: #f6f6f6;
|
||||
--contrast-0: #fefefe;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #333;
|
||||
}
|
||||
.content {
|
||||
background-color: var(--contrast-10);
|
||||
padding-bottom: 36px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
web/public/logo192.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
web/public/logo512.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
25
web/public/manifest.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
3
web/public/robots.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
27
web/src/components/CaseBuilder/CaseBuilder.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
import Header from "./Header";
|
||||
|
||||
import "tabulator-tables/dist/css/tabulator.min.css";
|
||||
import "../Common/Forms/Tables.css";
|
||||
import Footer from "./Footer";
|
||||
|
||||
const CaseBuilder = () => {
|
||||
const onClear = () => {};
|
||||
const onSave = () => {};
|
||||
const onLoad = () => {};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Header onClear={onClear} onSave={onSave} onLoad={onLoad} />
|
||||
<div className="content"></div>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CaseBuilder;
|
||||
14
web/src/components/CaseBuilder/Footer.module.css
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
.Footer {
|
||||
background-color: #333;
|
||||
text-align: center;
|
||||
color: #aaa;
|
||||
font-size: 14px;
|
||||
padding: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
18
web/src/components/CaseBuilder/Footer.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
import styles from "./Footer.module.css";
|
||||
|
||||
function Footer() {
|
||||
return (
|
||||
<div className={styles.Footer}>
|
||||
RELOG: Supply Chain Analysis and Optimization <br />
|
||||
Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Footer;
|
||||
41
web/src/components/CaseBuilder/Header.module.css
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
.HeaderBox {
|
||||
background-color: var(--contrast-0);
|
||||
border-bottom: var(--box-border);
|
||||
box-shadow: var(--box-shadow);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.HeaderContent {
|
||||
margin: 0 auto;
|
||||
max-width: var(--site-max-width);
|
||||
min-width: var(--site-min-width);
|
||||
}
|
||||
|
||||
.HeaderContent h1,
|
||||
h2 {
|
||||
color: var(--contrast-100);
|
||||
display: inline-block;
|
||||
line-height: 48px;
|
||||
font-size: 28px;
|
||||
margin: 0;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.HeaderContent h2 {
|
||||
display: inline-block;
|
||||
font-size: 22px;
|
||||
color: var(--contrast-80);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
float: right;
|
||||
padding: 16px 12px;
|
||||
}
|
||||
39
web/src/components/CaseBuilder/Header.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
import styles from "./Header.module.css";
|
||||
import SiteHeaderButton from "../Common/Buttons/SiteHeaderButton";
|
||||
import { useRef } from "react";
|
||||
import FileUploadElement from "../Common/Buttons/FileUploadElement";
|
||||
|
||||
interface HeaderProps {
|
||||
onClear: () => void;
|
||||
onSave: () => void;
|
||||
onLoad: () => void;
|
||||
}
|
||||
|
||||
function Header(props: HeaderProps) {
|
||||
const fileElem = useRef<FileUploadElement>(null);
|
||||
|
||||
function onLoad() {}
|
||||
|
||||
return (
|
||||
<div className={styles.HeaderBox}>
|
||||
<div className={styles.HeaderContent}>
|
||||
<h1>RELOG</h1>
|
||||
<h2>Case Builder</h2>
|
||||
<div className={styles.buttonContainer}>
|
||||
<SiteHeaderButton title="Clear" onClick={props.onClear} />
|
||||
<SiteHeaderButton title="Load" onClick={onLoad} />
|
||||
<SiteHeaderButton title="Save" onClick={props.onSave} />
|
||||
</div>
|
||||
<FileUploadElement ref={fileElem} accept=".json,.json.gz" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Header;
|
||||
58
web/src/components/Common/Buttons/FileUploadElement.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
import pako from "pako";
|
||||
import React, { Component } from "react";
|
||||
|
||||
class FileUploadElement extends Component<any> {
|
||||
private inputRef = React.createRef<HTMLInputElement>();
|
||||
private callback: (data: any) => void = () => {};
|
||||
|
||||
showFilePicker = (callback: (data: any) => void) => {
|
||||
this.callback = callback;
|
||||
this.inputRef.current?.click();
|
||||
};
|
||||
|
||||
onFileSelected = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files![0]!;
|
||||
let isCompressed = file.name.endsWith(".gz");
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = async (e) => {
|
||||
let content = e.target?.result;
|
||||
|
||||
if (isCompressed) {
|
||||
const compressed = new Uint8Array(content as ArrayBuffer);
|
||||
const decompressed = pako.inflate(compressed);
|
||||
content = new TextDecoder().decode(decompressed);
|
||||
}
|
||||
|
||||
this.callback(content as string);
|
||||
this.callback = () => {};
|
||||
};
|
||||
if (isCompressed) {
|
||||
reader.readAsArrayBuffer(file);
|
||||
} else {
|
||||
reader.readAsText(file);
|
||||
}
|
||||
}
|
||||
event.target.value = "";
|
||||
};
|
||||
|
||||
override render() {
|
||||
return (
|
||||
<input
|
||||
ref={this.inputRef}
|
||||
type="file"
|
||||
accept={this.props.accept}
|
||||
style={{ display: "none" }}
|
||||
onChange={this.onFileSelected}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default FileUploadElement;
|
||||
43
web/src/components/Common/Buttons/HelpButton.module.css
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
.tooltip {
|
||||
visibility: hidden;
|
||||
background-color: var(--contrast-80);
|
||||
color: var(--contrast-10);
|
||||
opacity: 0;
|
||||
width: 250px;
|
||||
margin-top: 36px;
|
||||
margin-left: -250px;
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
font-size: 14px;
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: var(--box-shadow);
|
||||
line-height: 20px;
|
||||
transition: opacity 0.5s;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: var(--contrast-60);
|
||||
font-size: 16px;
|
||||
padding: 8px 8px 8px 0;
|
||||
}
|
||||
|
||||
.HelpButton {
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.HelpButton:hover .tooltip {
|
||||
visibility: visible;
|
||||
opacity: 100%;
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
22
web/src/components/Common/Buttons/HelpButton.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
import styles from "./HelpButton.module.css";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faCircleQuestion } from "@fortawesome/free-regular-svg-icons";
|
||||
|
||||
function HelpButton({ text }: { text: String }) {
|
||||
return (
|
||||
<button className={styles.HelpButton}>
|
||||
<span className={styles.tooltip}>{text}</span>
|
||||
<span className={styles.icon}>
|
||||
<FontAwesomeIcon icon={faCircleQuestion} />
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default HelpButton;
|
||||
26
web/src/components/Common/Buttons/SectionButton.module.css
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
.SectionButton {
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
font-size: 16px;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
margin: 8px 0 8px 0px;
|
||||
cursor: pointer;
|
||||
color: var(--contrast-60);
|
||||
}
|
||||
|
||||
.SectionButton:hover {
|
||||
color: var(--contrast-100);
|
||||
background-color: var(--contrast-20);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.SectionButton:active {
|
||||
background-color: var(--contrast-60);
|
||||
}
|
||||
29
web/src/components/Common/Buttons/SectionButton.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import styles from "./SectionButton.module.css";
|
||||
|
||||
interface SectionButtonProps {
|
||||
icon: IconDefinition;
|
||||
tooltip: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
function SectionButton(props: SectionButtonProps) {
|
||||
return (
|
||||
<button
|
||||
className={styles.SectionButton}
|
||||
title={props.tooltip}
|
||||
onClick={props.onClick}
|
||||
>
|
||||
<FontAwesomeIcon icon={props.icon} />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default SectionButton;
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
.SiteHeaderButton {
|
||||
padding: 6px 36px;
|
||||
margin: 0 0 0 8px;
|
||||
line-height: 24px;
|
||||
border: var(--box-border);
|
||||
box-shadow: var(--box-shadow);
|
||||
border-radius: var(--border-radius);
|
||||
cursor: pointer;
|
||||
color: var(--contrast-80);
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
background: linear-gradient(var(--contrast-0) 25%, var(--contrast-10) 100%);
|
||||
}
|
||||
|
||||
.SiteHeaderButton:hover {
|
||||
background: rgb(245, 245, 245);
|
||||
}
|
||||
|
||||
.SiteHeaderButton:active {
|
||||
background: rgba(220, 220, 220);
|
||||
}
|
||||
23
web/src/components/Common/Buttons/SiteHeaderButton.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
import styles from "./SiteHeaderButton.module.css";
|
||||
|
||||
function SiteHeaderButton({
|
||||
title,
|
||||
onClick,
|
||||
}: {
|
||||
title: string;
|
||||
onClick?: () => void;
|
||||
}) {
|
||||
return (
|
||||
<button className={styles.SiteHeaderButton} onClick={onClick}>
|
||||
{title}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default SiteHeaderButton;
|
||||
42
web/src/components/Common/Forms/Form.module.css
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
.Form {
|
||||
background-color: var(--contrast-0);
|
||||
border: var(--box-border);
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: var(--box-shadow);
|
||||
min-height: 48px;
|
||||
margin: 0 auto;
|
||||
min-width: var(--site-min-width);
|
||||
max-width: var(--site-max-width);
|
||||
max-height: 500px;
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
.FormRow {
|
||||
display: flex;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.FormRow label {
|
||||
width: 350px;
|
||||
padding: 6px 12px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.FormRow input {
|
||||
flex: 1;
|
||||
font-family: monospace;
|
||||
border: var(--box-border);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 4px;
|
||||
margin: 2px 3px;
|
||||
}
|
||||
|
||||
.FormRow_unit {
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
14
web/src/components/Common/Forms/Form.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
import { ReactNode } from "react";
|
||||
import styles from "./Form.module.css";
|
||||
|
||||
function Form({ children }: { children: ReactNode }) {
|
||||
return <div className={styles.Form}>{children}</div>;
|
||||
}
|
||||
|
||||
export default Form;
|
||||
81
web/src/components/Common/Forms/Tables.css
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
.tabulator {
|
||||
background-color: var(--contrast-0);
|
||||
border: var(--box-border) !important;
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: var(--box-shadow);
|
||||
min-height: 48px;
|
||||
margin: 0 auto;
|
||||
min-width: var(--site-min-width);
|
||||
max-width: var(--site-max-width);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.tabulator .tabulator-header {
|
||||
border-bottom: 1px solid #ccc;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
color: var(--contrast-100);
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.tabulator .tabulator-header .subtitle {
|
||||
color: var(--contrast-80);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.tabulator .tabulator-header .tabulator-col {
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.1) !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
|
||||
.tabulator .tabulator-header .tabulator-col .tabulator-col-content {
|
||||
text-align: left;
|
||||
padding: 0 8px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.tabulator .tabulator-header .tabulator-col:last-child {
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.1) !important;
|
||||
}
|
||||
|
||||
.tabulator-row .tabulator-cell {
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
line-height: 28px;
|
||||
height: 28px;
|
||||
text-align: right;
|
||||
vertical-align: middle !important;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.1) !important;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1) !important;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.tabulator-row-even {
|
||||
background-color: rgba(0, 0, 0, 0.03) !important;
|
||||
}
|
||||
|
||||
.tabulator-row-odd {
|
||||
background-color: rgba(0, 0, 0, 0) !important;
|
||||
}
|
||||
|
||||
.tabulator-row .tabulator-cell.tabulator-editing {
|
||||
border: 0;
|
||||
padding: 0 4px;
|
||||
background-color: #cee;
|
||||
}
|
||||
|
||||
.tabulator-row .tabulator-cell.tabulator-editing input {
|
||||
font-family: monospace;
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tabulator-col-group-cols {
|
||||
font-size: 12px;
|
||||
}
|
||||
50
web/src/components/Common/Forms/TextInputRow.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
import formStyles from "./Form.module.css";
|
||||
import HelpButton from "../Buttons/HelpButton";
|
||||
import React, { useRef, useState } from "react";
|
||||
|
||||
interface TextInputRowProps {
|
||||
label: string;
|
||||
unit: string;
|
||||
tooltip: string;
|
||||
initialValue: string;
|
||||
onChange: (newValue: string) => null;
|
||||
}
|
||||
|
||||
function TextInputRow(props: TextInputRowProps) {
|
||||
const [savedValue, setSavedValue] = useState(props.initialValue);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const onBlur = (event: React.FocusEvent<HTMLInputElement>) => {
|
||||
const newValue = event.target.value;
|
||||
if (newValue === savedValue) return;
|
||||
const err = props.onChange(newValue);
|
||||
if (err) {
|
||||
inputRef.current!.value = savedValue;
|
||||
return;
|
||||
}
|
||||
setSavedValue(newValue);
|
||||
};
|
||||
return (
|
||||
<div className={formStyles.FormRow}>
|
||||
<label>
|
||||
{props.label}
|
||||
<span className={formStyles.FormRow_unit}> ({props.unit})</span>
|
||||
</label>
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
defaultValue={savedValue}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
<HelpButton text={props.tooltip} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default TextInputRow;
|
||||
23
web/src/components/Common/Forms/Toast.module.css
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
.Toast {
|
||||
width: 600px;
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: 4px 4px 16px -2px rgba(0, 0, 0, 0.5);
|
||||
margin: 0 auto;
|
||||
background-color: #424242;
|
||||
color: white;
|
||||
padding: 0 16px;
|
||||
position: fixed;
|
||||
top: 48px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
transition: opacity 0.5s ease;
|
||||
cursor: default;
|
||||
font-size: 15px;
|
||||
line-height: 48px;
|
||||
}
|
||||
35
web/src/components/Common/Forms/Toast.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
import styles from "./Toast.module.css";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
interface ToastProps {
|
||||
message: string;
|
||||
}
|
||||
|
||||
const Toast = (props: ToastProps) => {
|
||||
const [isVisible, setVisible] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.message.length === 0) return;
|
||||
setVisible(true);
|
||||
const timer = setTimeout(() => {
|
||||
setVisible(false);
|
||||
}, 5000);
|
||||
return () => clearTimeout(timer);
|
||||
}, [props.message]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.Toast} style={{ opacity: isVisible ? 1 : 0 }}>
|
||||
{props.message}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Toast;
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
.SectionHeader {
|
||||
max-width: var(--site-max-width);
|
||||
min-width: var(--site-min-width);
|
||||
margin: 0 auto;
|
||||
color: var(--contrast-100);
|
||||
}
|
||||
|
||||
.SectionHeader h1 {
|
||||
margin: 0;
|
||||
padding: 0 12px;
|
||||
font-size: 16px;
|
||||
line-height: 64px;
|
||||
}
|
||||
|
||||
.SectionButtonsContainer {
|
||||
float: right;
|
||||
height: 64px;
|
||||
}
|
||||
24
web/src/components/Common/SectionHeader/SectionHeader.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
import styles from "./SectionHeader.module.css";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
interface SectionHeaderProps {
|
||||
title: string;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
function SectionHeader({ title, children }: SectionHeaderProps) {
|
||||
return (
|
||||
<div className={styles.SectionHeader}>
|
||||
<div className={styles.SectionButtonsContainer}>{children}</div>
|
||||
<h1>{title}</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SectionHeader;
|
||||
17
web/src/components/Common/io.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
export function offerDownload(data: string, type: string, filename: string) {
|
||||
const dataBlob = new Blob([data], { type: type });
|
||||
const url = URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = filename;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
22
web/src/index.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
import CaseBuilder from "./components/CaseBuilder/CaseBuilder";
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById("root") as HTMLElement,
|
||||
);
|
||||
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<CaseBuilder />
|
||||
</React.StrictMode>,
|
||||
);
|
||||
|
||||
reportWebVitals();
|
||||
13
web/src/logo.svg
Normal file
@@ -0,0 +1,13 @@
|
||||
<!--
|
||||
- RELOG: Supply Chain Analysis and Optimization
|
||||
- Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
- Released under the modified BSD license. See COPYING.md for more details.
|
||||
-->
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
|
||||
<g fill="#61DAFB">
|
||||
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
|
||||
<circle cx="420.9" cy="296.5" r="45.7"/>
|
||||
<path d="M520.5 78.1z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
7
web/src/react-app-env.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
/// <reference types="react-scripts" />
|
||||
21
web/src/reportWebVitals.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
import { ReportHandler } from "web-vitals";
|
||||
|
||||
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
||||
7
web/src/setupTests.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* RELOG: Supply Chain Analysis and Optimization
|
||||
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
||||
* Released under the modified BSD license. See COPYING.md for more details.
|
||||
*/
|
||||
|
||||
import "@testing-library/jest-dom";
|
||||
35
web/tsconfig.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"alwaysStrict": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"noEmit": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictNullChecks": true,
|
||||
"strictPropertyInitialization": true,
|
||||
"allowUnusedLabels": false,
|
||||
"allowUnreachableCode": false,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"checkJs": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||