mirror of https://github.com/ANL-CEEESA/RELOG.git
parent
56b673fb9e
commit
01452441dc
@ -1,7 +0,0 @@
|
|||||||
import styles from './ButtonRow.module.css';
|
|
||||||
|
|
||||||
const ButtonRow = (props) => {
|
|
||||||
return <div className={styles.ButtonRow}>{props.children}</div>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ButtonRow;
|
|
@ -1,3 +0,0 @@
|
|||||||
.ButtonRow {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
import styles from './Card.module.css';
|
import styles from "./Card.module.css";
|
||||||
|
|
||||||
const Card = (props) => {
|
const Card = (props) => {
|
||||||
return (<div className={styles.Card}>{props.children}</div>);
|
return <div className={styles.Card}>{props.children}</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Card;
|
export default Card;
|
@ -1,10 +1,15 @@
|
|||||||
import styles from './Footer.module.css';
|
import styles from "./Footer.module.css";
|
||||||
|
|
||||||
const Footer = () => {
|
const Footer = () => {
|
||||||
return <div className={styles.Footer}>
|
return (
|
||||||
|
<div className={styles.Footer}>
|
||||||
<p>RELOG: Reverse Logistics Optimization</p>
|
<p>RELOG: Reverse Logistics Optimization</p>
|
||||||
<p>Copyright © 2020—2022, UChicago Argonne, LLC. All Rights Reserved.</p>
|
<p>
|
||||||
</div>;
|
Copyright © 2020—2022, UChicago Argonne, LLC. All Rights
|
||||||
|
Reserved.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Footer;
|
export default Footer;
|
@ -1,24 +1,25 @@
|
|||||||
.PipelineBlock {
|
.PipelineBlock {
|
||||||
height: 600px;
|
height: 600px !important;
|
||||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
border: 1px solid rgba(0, 0, 0, 0.1) !important;
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius) !important;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.PlantNode, .ProductNode {
|
.PlantNode,
|
||||||
border-color: rgba(0, 0, 0, 0.8);
|
.ProductNode {
|
||||||
color: black;
|
border-color: rgba(0, 0, 0, 0.8) !important;
|
||||||
font-size: 13px;
|
color: black !important;
|
||||||
border-width: 1px;
|
font-size: 13px !important;
|
||||||
border-radius: 6px;
|
border-width: 1px !important;
|
||||||
box-shadow: 0px 2px 4px -3px black;
|
border-radius: 6px !important;
|
||||||
width: 100px;
|
box-shadow: 0px 2px 4px -3px black !important;
|
||||||
|
width: 100px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.PlantNode {
|
.PlantNode {
|
||||||
background-color: #0df;
|
background-color: #8d8 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ProductNode {
|
.ProductNode {
|
||||||
background-color: #f6f6f6;
|
background-color: #e6e6e6 !important;
|
||||||
}
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
import * as d3 from "d3";
|
||||||
|
|
||||||
|
export const csvParse = ({ contents, requiredCols }) => {
|
||||||
|
const data = d3.csvParse(contents, d3.autoType);
|
||||||
|
requiredCols.forEach((col) => {
|
||||||
|
if (!(col in data[0])) {
|
||||||
|
throw Error(`Column "${col}" not found in CSV file.`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const parseCsv = (contents, requiredCols = []) => {
|
||||||
|
const data = d3.csvParse(contents);
|
||||||
|
const T = data.columns.length - requiredCols.length;
|
||||||
|
let isValid = true;
|
||||||
|
for (let t = 0; t < T; t++) {
|
||||||
|
requiredCols.push(t + 1);
|
||||||
|
}
|
||||||
|
requiredCols.forEach((col) => {
|
||||||
|
if (!(col in data[0])) {
|
||||||
|
console.log(`Column "${col}" not found in CSV file.`);
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!isValid) return [undefined, undefined];
|
||||||
|
return [data, T];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const extractNumericColumns = (obj, prefix) => {
|
||||||
|
const result = [];
|
||||||
|
for (let i = 1; `${prefix} ${i}` in obj; i++) {
|
||||||
|
result.push(obj[`${prefix} ${i}`]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const csvFormat = (data) => {
|
||||||
|
return d3.csvFormat(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const generateFile = (filename, contents) => {
|
||||||
|
var link = document.createElement("a");
|
||||||
|
link.setAttribute("href", URL.createObjectURL(new Blob([contents])));
|
||||||
|
link.setAttribute("download", filename);
|
||||||
|
link.style.visibility = "hidden";
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
};
|
@ -0,0 +1,53 @@
|
|||||||
|
import { csvParse, extractNumericColumns, csvFormat } from "./csv";
|
||||||
|
import { exportValue } from "./export";
|
||||||
|
|
||||||
|
test("parse CSV", () => {
|
||||||
|
const contents = "name,location,1,2,3\ntest,illinois,100,200,300";
|
||||||
|
const actual = csvParse({
|
||||||
|
contents: contents,
|
||||||
|
requiredCols: ["name", "location"],
|
||||||
|
});
|
||||||
|
expect(actual.length).toEqual(1);
|
||||||
|
expect(actual[0]).toEqual({
|
||||||
|
name: "test",
|
||||||
|
location: "illinois",
|
||||||
|
1: 100,
|
||||||
|
2: 200,
|
||||||
|
3: 300,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("parse CSV with missing columns", () => {
|
||||||
|
const contents = "name,location,1,2,3\ntest,illinois,100,200,300";
|
||||||
|
expect(() =>
|
||||||
|
csvParse({
|
||||||
|
contents: contents,
|
||||||
|
requiredCols: ["name", "location", "latitude"],
|
||||||
|
})
|
||||||
|
).toThrow('Column "latitude" not found in CSV file.');
|
||||||
|
});
|
||||||
|
|
||||||
|
test("extract numeric columns from object", () => {
|
||||||
|
const obj1 = {
|
||||||
|
"amount 1": "hello",
|
||||||
|
"amount 2": "world",
|
||||||
|
"amount 4": "ignored",
|
||||||
|
};
|
||||||
|
const obj2 = { hello: "world" };
|
||||||
|
expect(extractNumericColumns(obj1, "amount")).toEqual(["hello", "world"]);
|
||||||
|
expect(extractNumericColumns(obj2, "amount")).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("generate CSV", () => {
|
||||||
|
const data = [
|
||||||
|
{ name: "alice", age: 20 },
|
||||||
|
{ name: "bob", age: null },
|
||||||
|
];
|
||||||
|
expect(csvFormat(data)).toEqual("name,age\nalice,20\nbob,");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("export value", () => {
|
||||||
|
expect(exportValue("1")).toEqual(1);
|
||||||
|
expect(exportValue("[1,2,3]")).toEqual([1, 2, 3]);
|
||||||
|
expect(exportValue("qwe")).toEqual("qwe");
|
||||||
|
});
|
@ -0,0 +1,49 @@
|
|||||||
|
export const defaultProduct = {
|
||||||
|
"initial amounts": {},
|
||||||
|
"disposal cost ($/tonne)": "0",
|
||||||
|
"disposal limit (tonne)": "0",
|
||||||
|
"disposal limit (%)": "",
|
||||||
|
"transportation cost ($/km/tonne)": "0",
|
||||||
|
"transportation energy (J/km/tonne)": "0",
|
||||||
|
"transportation emissions (tonne/km/tonne)": {},
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const defaultPlantLocation = {
|
||||||
|
"area cost factor": 1.0,
|
||||||
|
"latitude (deg)": 0,
|
||||||
|
"longitude (deg)": 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const defaultPlant = {
|
||||||
|
locations: {},
|
||||||
|
"outputs (tonne/tonne)": {},
|
||||||
|
"disposal cost ($/tonne)": {},
|
||||||
|
"disposal limit (tonne)": {},
|
||||||
|
"emissions (tonne/tonne)": {},
|
||||||
|
storage: {
|
||||||
|
"cost ($/tonne)": 0,
|
||||||
|
"limit (tonne)": 0,
|
||||||
|
},
|
||||||
|
"maximum capacity (tonne)": 0,
|
||||||
|
"minimum capacity (tonne)": 0,
|
||||||
|
"opening cost (max capacity) ($)": 0,
|
||||||
|
"opening cost (min capacity) ($)": 0,
|
||||||
|
"fixed operating cost (max capacity) ($)": 0,
|
||||||
|
"fixed operating cost (min capacity) ($)": 0,
|
||||||
|
"variable operating cost ($/tonne)": 0,
|
||||||
|
"energy (GJ/tonne)": 0,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const defaultData = {
|
||||||
|
parameters: {
|
||||||
|
"time horizon (years)": "1",
|
||||||
|
"building period (years)": "[1]",
|
||||||
|
// "annual inflation rate (%)": "0",
|
||||||
|
},
|
||||||
|
products: {},
|
||||||
|
plants: {},
|
||||||
|
};
|
@ -0,0 +1,464 @@
|
|||||||
|
const isNumeric = (val) => {
|
||||||
|
return String(val).length > 0 && !isNaN(val);
|
||||||
|
};
|
||||||
|
|
||||||
|
const keysToList = (obj) => {
|
||||||
|
const result = [];
|
||||||
|
for (const key of Object.keys(obj)) {
|
||||||
|
result.push(key);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const exportValue = (original, T) => {
|
||||||
|
if (isNumeric(original)) {
|
||||||
|
if (T) {
|
||||||
|
const v = parseFloat(original);
|
||||||
|
const result = [];
|
||||||
|
for (let i = 0; i < T; i++) result.push(v);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return parseFloat(original);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(original);
|
||||||
|
return parsed;
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
return original;
|
||||||
|
};
|
||||||
|
|
||||||
|
const exportValueDict = (original, T) => {
|
||||||
|
const result = {};
|
||||||
|
for (const [key, val] of Object.entries(original)) {
|
||||||
|
if (key.length === 0) continue;
|
||||||
|
result[key] = exportValue(val, T);
|
||||||
|
}
|
||||||
|
if (Object.keys(result).length > 0) {
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const computeTotalInitialAmount = (prod) => {
|
||||||
|
let total = null;
|
||||||
|
for (const locDict of Object.values(prod["initial amounts"])) {
|
||||||
|
const locAmount = locDict["amount (tonne)"];
|
||||||
|
if (!total) total = [...locAmount];
|
||||||
|
else {
|
||||||
|
for (let i = 0; i < locAmount.length; i++) {
|
||||||
|
total[i] += locAmount[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const importList = (args) => {
|
||||||
|
if (!args) return "";
|
||||||
|
if (Array.isArray(args) && args.length > 0) {
|
||||||
|
let isConstant = true;
|
||||||
|
for (let i = 1; i < args.length; i++) {
|
||||||
|
if (args[i - 1] !== args[i]) {
|
||||||
|
isConstant = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isConstant) {
|
||||||
|
return String(args[0]);
|
||||||
|
} else {
|
||||||
|
return JSON.stringify(args);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const importDict = (args) => {
|
||||||
|
if (!args) return {};
|
||||||
|
const result = {};
|
||||||
|
for (const [key, val] of Object.entries(args)) {
|
||||||
|
result[key] = importList(val);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const computeAbsDisposal = (prod) => {
|
||||||
|
const disposalPerc = prod["disposal limit (%)"];
|
||||||
|
const total = computeTotalInitialAmount(prod);
|
||||||
|
const disposalAbs = [];
|
||||||
|
for (let i = 0; i < total.length; i++) {
|
||||||
|
disposalAbs[i] = (total[i] * disposalPerc) / 100;
|
||||||
|
}
|
||||||
|
return disposalAbs;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const exportProduct = (original, T) => {
|
||||||
|
const result = {};
|
||||||
|
|
||||||
|
// Copy time series values
|
||||||
|
result["initial amounts"] = original["initial amounts"];
|
||||||
|
[
|
||||||
|
"disposal cost ($/tonne)",
|
||||||
|
"disposal limit (tonne)",
|
||||||
|
"transportation cost ($/km/tonne)",
|
||||||
|
"transportation energy (J/km/tonne)",
|
||||||
|
].forEach((key) => {
|
||||||
|
const v = exportValue(original[key], T);
|
||||||
|
if (v.length > 0) result[key] = v;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Copy dictionaries
|
||||||
|
["transportation emissions (tonne/km/tonne)"].forEach((key) => {
|
||||||
|
const v = exportValueDict(original[key], T);
|
||||||
|
if (v) result[key] = v;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Transform percentage disposal limits into absolute
|
||||||
|
if (isNumeric(original["disposal limit (%)"])) {
|
||||||
|
result["disposal limit (tonne)"] = computeAbsDisposal(original);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const exportPlant = (original, T) => {
|
||||||
|
const result = {};
|
||||||
|
|
||||||
|
// Copy scalar values
|
||||||
|
["input"].forEach((key) => {
|
||||||
|
result[key] = original[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Copy time series values
|
||||||
|
["energy (GJ/tonne)"].forEach((key) => {
|
||||||
|
result[key] = exportValue(original[key], T);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Copy scalar dicts
|
||||||
|
["outputs (tonne/tonne)"].forEach((key) => {
|
||||||
|
const v = exportValueDict(original[key]);
|
||||||
|
if (v) result[key] = v;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Copy time series dicts
|
||||||
|
["emissions (tonne/tonne)"].forEach((key) => {
|
||||||
|
const v = exportValueDict(original[key], T);
|
||||||
|
if (v) result[key] = v;
|
||||||
|
});
|
||||||
|
|
||||||
|
const minCap = original["minimum capacity (tonne)"];
|
||||||
|
const maxCap = original["maximum capacity (tonne)"];
|
||||||
|
|
||||||
|
result.locations = {};
|
||||||
|
for (const [locName, origDict] of Object.entries(original["locations"])) {
|
||||||
|
const resDict = (result.locations[locName] = {});
|
||||||
|
const capDict = (resDict["capacities (tonne)"] = {});
|
||||||
|
|
||||||
|
const acf = origDict["area cost factor"];
|
||||||
|
|
||||||
|
const exportValueAcf = (obj, T) => {
|
||||||
|
const v = exportValue(obj, T);
|
||||||
|
if (Array.isArray(v)) {
|
||||||
|
return v.map((v) => v * acf);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
|
// Copy scalar values
|
||||||
|
["latitude (deg)", "longitude (deg)"].forEach((key) => {
|
||||||
|
resDict[key] = origDict[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Copy minimum capacity dict
|
||||||
|
capDict[minCap] = {};
|
||||||
|
for (const [resKeyName, origKeyName] of Object.entries({
|
||||||
|
"opening cost ($)": "opening cost (min capacity) ($)",
|
||||||
|
"fixed operating cost ($)": "fixed operating cost (min capacity) ($)",
|
||||||
|
"variable operating cost ($/tonne)": "variable operating cost ($/tonne)",
|
||||||
|
})) {
|
||||||
|
capDict[minCap][resKeyName] = exportValueAcf(original[origKeyName], T);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxCap !== minCap) {
|
||||||
|
// Copy maximum capacity dict
|
||||||
|
capDict[maxCap] = {};
|
||||||
|
for (const [resKeyName, origKeyName] of Object.entries({
|
||||||
|
"opening cost ($)": "opening cost (max capacity) ($)",
|
||||||
|
"fixed operating cost ($)": "fixed operating cost (max capacity) ($)",
|
||||||
|
"variable operating cost ($/tonne)":
|
||||||
|
"variable operating cost ($/tonne)",
|
||||||
|
})) {
|
||||||
|
capDict[maxCap][resKeyName] = exportValueAcf(original[origKeyName], T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy disposal
|
||||||
|
resDict.disposal = {};
|
||||||
|
for (const [dispName, dispCost] of Object.entries(
|
||||||
|
original["disposal cost ($/tonne)"]
|
||||||
|
)) {
|
||||||
|
if (dispName.length === 0) continue;
|
||||||
|
const v = exportValueAcf(dispCost, T);
|
||||||
|
if (v) {
|
||||||
|
resDict.disposal[dispName] = { "cost ($/tonne)": v };
|
||||||
|
const limit = original["disposal limit (tonne)"][dispName];
|
||||||
|
if (isNumeric(limit)) {
|
||||||
|
resDict.disposal[dispName]["limit (tonne)"] = exportValue(limit, T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy storage
|
||||||
|
resDict.storage = {
|
||||||
|
"cost ($/tonne)": exportValueAcf(
|
||||||
|
original["storage"]["cost ($/tonne)"],
|
||||||
|
T
|
||||||
|
),
|
||||||
|
};
|
||||||
|
const storLimit = original["storage"]["limit (tonne)"];
|
||||||
|
if (isNumeric(storLimit)) {
|
||||||
|
resDict.storage["limit (tonne)"] = exportValue(storLimit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const exportData = (original) => {
|
||||||
|
const result = {
|
||||||
|
parameters: {},
|
||||||
|
products: {},
|
||||||
|
plants: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Export parameters
|
||||||
|
["time horizon (years)", "building period (years)"].forEach((key) => {
|
||||||
|
result.parameters[key] = exportValue(original.parameters[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Read time horizon
|
||||||
|
let T = result.parameters["time horizon (years)"];
|
||||||
|
if (!isNumeric(T)) T = 1;
|
||||||
|
|
||||||
|
// Export products
|
||||||
|
for (const [prodName, prodDict] of Object.entries(original.products)) {
|
||||||
|
result.products[prodName] = exportProduct(prodDict, T);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export plants
|
||||||
|
for (const [plantName, plantDict] of Object.entries(original.plants)) {
|
||||||
|
result.plants[plantName] = exportPlant(plantDict, T);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const compressDisposalLimits = (original, result) => {
|
||||||
|
if (!("disposal limit (tonne)" in original)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const total = computeTotalInitialAmount(original);
|
||||||
|
const limit = original["disposal limit (tonne)"];
|
||||||
|
let perc = Math.round((limit[0] / total[0]) * 1e6) / 1e6;
|
||||||
|
for (let i = 1; i < limit.length; i++) {
|
||||||
|
if (Math.abs(limit[i] / total[i] - perc) > 1e-5) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result["disposal limit (tonne)"] = "";
|
||||||
|
result["disposal limit (%)"] = String(perc * 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const importProduct = (original) => {
|
||||||
|
const result = {};
|
||||||
|
|
||||||
|
result["initial amounts"] = { ...original["initial amounts"] };
|
||||||
|
|
||||||
|
// Initialize null values
|
||||||
|
["x", "y"].forEach((key) => {
|
||||||
|
result[key] = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize empty values
|
||||||
|
["disposal limit (%)"].forEach((key) => {
|
||||||
|
result[key] = "";
|
||||||
|
});
|
||||||
|
|
||||||
|
// Import lists
|
||||||
|
[
|
||||||
|
"transportation energy (J/km/tonne)",
|
||||||
|
"transportation cost ($/km/tonne)",
|
||||||
|
"disposal cost ($/tonne)",
|
||||||
|
"disposal limit (tonne)",
|
||||||
|
].forEach((key) => {
|
||||||
|
result[key] = importList(original[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Import dicts
|
||||||
|
["transportation emissions (tonne/km/tonne)"].forEach((key) => {
|
||||||
|
result[key] = importDict(original[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Attempt to convert absolute disposal limits to relative
|
||||||
|
compressDisposalLimits(original, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const importPlant = (original) => {
|
||||||
|
const result = {};
|
||||||
|
|
||||||
|
// Initialize null values
|
||||||
|
["x", "y"].forEach((key) => {
|
||||||
|
result[key] = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Import scalar values
|
||||||
|
["input"].forEach((key) => {
|
||||||
|
result[key] = original[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Import timeseries values
|
||||||
|
["energy (GJ/tonne)"].forEach((key) => {
|
||||||
|
result[key] = importList(original[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Import dicts
|
||||||
|
["outputs (tonne/tonne)", "emissions (tonne/tonne)"].forEach((key) => {
|
||||||
|
result[key] = importDict(original[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Read locations
|
||||||
|
let costsInitialized = false;
|
||||||
|
const resLocDict = (result.locations = {});
|
||||||
|
for (const [locName, origLocDict] of Object.entries(original["locations"])) {
|
||||||
|
resLocDict[locName] = {};
|
||||||
|
|
||||||
|
// Import latitude and longitude
|
||||||
|
["latitude (deg)", "longitude (deg)"].forEach((key) => {
|
||||||
|
resLocDict[locName][key] = origLocDict[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
const capacities = keysToList(origLocDict["capacities (tonne)"]);
|
||||||
|
const last = capacities.length - 1;
|
||||||
|
const minCap = capacities[0];
|
||||||
|
const maxCap = capacities[last];
|
||||||
|
const minCapDict = origLocDict["capacities (tonne)"][minCap];
|
||||||
|
const maxCapDict = origLocDict["capacities (tonne)"][maxCap];
|
||||||
|
|
||||||
|
// Import min/max capacity
|
||||||
|
if ("minimum capacity (tonne)" in result) {
|
||||||
|
if (
|
||||||
|
result["minimum capacity (tonne)"] !== minCap ||
|
||||||
|
result["maximum capacity (tonne)"] !== maxCap
|
||||||
|
) {
|
||||||
|
throw "Data loss";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result["minimum capacity (tonne)"] = minCap;
|
||||||
|
result["maximum capacity (tonne)"] = maxCap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute area cost factor
|
||||||
|
let acf = 1;
|
||||||
|
if (costsInitialized) {
|
||||||
|
acf = result["opening cost (min capacity) ($)"];
|
||||||
|
if (Array.isArray(acf)) acf = acf[0];
|
||||||
|
acf = minCapDict["opening cost ($)"][0] / acf;
|
||||||
|
}
|
||||||
|
resLocDict[locName]["area cost factor"] = acf;
|
||||||
|
|
||||||
|
// Read adjusted costs
|
||||||
|
const importListAcf = (obj) => importList(obj.map((v) => v / acf));
|
||||||
|
const openCostMax = importListAcf(maxCapDict["opening cost ($)"]);
|
||||||
|
const openCostMin = importListAcf(minCapDict["opening cost ($)"]);
|
||||||
|
const fixCostMax = importListAcf(maxCapDict["fixed operating cost ($)"]);
|
||||||
|
const fixCostMin = importListAcf(minCapDict["fixed operating cost ($)"]);
|
||||||
|
const storCost = importListAcf(origLocDict.storage["cost ($/tonne)"]);
|
||||||
|
const storLimit = String(origLocDict.storage["limit (tonne)"]);
|
||||||
|
const varCost = importListAcf(
|
||||||
|
minCapDict["variable operating cost ($/tonne)"]
|
||||||
|
);
|
||||||
|
|
||||||
|
const dispCost = {};
|
||||||
|
const dispLimit = {};
|
||||||
|
for (const prodName of Object.keys(original["outputs (tonne/tonne)"])) {
|
||||||
|
dispCost[prodName] = "";
|
||||||
|
dispLimit[prodName] = "";
|
||||||
|
|
||||||
|
if (prodName in origLocDict["disposal"]) {
|
||||||
|
const prodDict = origLocDict["disposal"][prodName];
|
||||||
|
dispCost[prodName] = importListAcf(prodDict["cost ($/tonne)"]);
|
||||||
|
if ("limit (tonne)" in prodDict)
|
||||||
|
dispLimit[prodName] = importList(prodDict["limit (tonne)"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const check = (left, right) => {
|
||||||
|
let valid = true;
|
||||||
|
if (isNumeric(left) && isNumeric(right)) {
|
||||||
|
valid = Math.abs(left - right) < 1.0;
|
||||||
|
} else {
|
||||||
|
valid = left === right;
|
||||||
|
}
|
||||||
|
if (!valid)
|
||||||
|
console.warn(`Data loss detected: ${locName}, ${left} != ${right}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (costsInitialized) {
|
||||||
|
// Verify that location costs match the previously initialized ones
|
||||||
|
check(result["opening cost (max capacity) ($)"], openCostMax);
|
||||||
|
check(result["opening cost (min capacity) ($)"], openCostMin);
|
||||||
|
check(result["fixed operating cost (max capacity) ($)"], fixCostMax);
|
||||||
|
check(result["fixed operating cost (min capacity) ($)"], fixCostMin);
|
||||||
|
check(result["variable operating cost ($/tonne)"], varCost);
|
||||||
|
check(result["storage"]["cost ($/tonne)"], storCost);
|
||||||
|
check(result["storage"]["limit (tonne)"], storLimit);
|
||||||
|
check(String(result["disposal cost ($/tonne)"]), String(dispCost));
|
||||||
|
check(String(result["disposal limit (tonne)"]), String(dispLimit));
|
||||||
|
} else {
|
||||||
|
// Initialize plant costs
|
||||||
|
costsInitialized = true;
|
||||||
|
result["opening cost (max capacity) ($)"] = openCostMax;
|
||||||
|
result["opening cost (min capacity) ($)"] = openCostMin;
|
||||||
|
result["fixed operating cost (max capacity) ($)"] = fixCostMax;
|
||||||
|
result["fixed operating cost (min capacity) ($)"] = fixCostMin;
|
||||||
|
result["variable operating cost ($/tonne)"] = varCost;
|
||||||
|
result["storage"] = {};
|
||||||
|
result["storage"]["cost ($/tonne)"] = storCost;
|
||||||
|
result["storage"]["limit (tonne)"] = storLimit;
|
||||||
|
result["disposal cost ($/tonne)"] = dispCost;
|
||||||
|
result["disposal limit (tonne)"] = dispLimit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const importData = (original) => {
|
||||||
|
["parameters", "plants", "products"].forEach((key) => {
|
||||||
|
if (!(key in original)) {
|
||||||
|
throw "File not recognized.";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = {};
|
||||||
|
result.parameters = importDict(original.parameters);
|
||||||
|
|
||||||
|
// Import products
|
||||||
|
result.products = {};
|
||||||
|
for (const [prodName, origProdDict] of Object.entries(original.products)) {
|
||||||
|
result.products[prodName] = importProduct(origProdDict);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import plants
|
||||||
|
result.plants = {};
|
||||||
|
for (const [plantName, origPlantDict] of Object.entries(original.plants)) {
|
||||||
|
result.plants[plantName] = importPlant(origPlantDict);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
@ -0,0 +1,564 @@
|
|||||||
|
import {
|
||||||
|
exportProduct,
|
||||||
|
exportPlant,
|
||||||
|
importProduct,
|
||||||
|
importList,
|
||||||
|
importDict,
|
||||||
|
importPlant,
|
||||||
|
} from "./export";
|
||||||
|
|
||||||
|
const sampleProductsOriginal = [
|
||||||
|
// basic product
|
||||||
|
{
|
||||||
|
"initial amounts": {
|
||||||
|
"Washakie County": {
|
||||||
|
"latitude (deg)": 43.8356,
|
||||||
|
"longitude (deg)": -107.6602,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
"Platte County": {
|
||||||
|
"latitude (deg)": 42.1314,
|
||||||
|
"longitude (deg)": -104.9676,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
"Park County": {
|
||||||
|
"latitude (deg)": 44.4063,
|
||||||
|
"longitude (deg)": -109.4153,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"disposal cost ($/tonne)": "50",
|
||||||
|
"disposal limit (tonne)": "30",
|
||||||
|
"disposal limit (%)": "",
|
||||||
|
"transportation cost ($/km/tonne)": "5",
|
||||||
|
"transportation energy (J/km/tonne)": "10",
|
||||||
|
"transportation emissions (tonne/km/tonne)": {
|
||||||
|
CO2: "0.5",
|
||||||
|
},
|
||||||
|
x: null,
|
||||||
|
y: null,
|
||||||
|
},
|
||||||
|
// product with percentage disposal limit
|
||||||
|
{
|
||||||
|
"initial amounts": {
|
||||||
|
"Washakie County": {
|
||||||
|
"latitude (deg)": 43.8356,
|
||||||
|
"longitude (deg)": -107.6602,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
"Platte County": {
|
||||||
|
"latitude (deg)": 42.1314,
|
||||||
|
"longitude (deg)": -104.9676,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
"Park County": {
|
||||||
|
"latitude (deg)": 44.4063,
|
||||||
|
"longitude (deg)": -109.4153,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"disposal cost ($/tonne)": "50",
|
||||||
|
"disposal limit (tonne)": "",
|
||||||
|
"disposal limit (%)": "10",
|
||||||
|
"transportation cost ($/km/tonne)": "5",
|
||||||
|
"transportation energy (J/km/tonne)": "10",
|
||||||
|
"transportation emissions (tonne/km/tonne)": {
|
||||||
|
CO2: "0.5",
|
||||||
|
},
|
||||||
|
x: null,
|
||||||
|
y: null,
|
||||||
|
},
|
||||||
|
// product using defaults
|
||||||
|
{
|
||||||
|
"initial amounts": {
|
||||||
|
"Washakie County": {
|
||||||
|
"latitude (deg)": 43.8356,
|
||||||
|
"longitude (deg)": -107.6602,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
"Platte County": {
|
||||||
|
"latitude (deg)": 42.1314,
|
||||||
|
"longitude (deg)": -104.9676,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
"Park County": {
|
||||||
|
"latitude (deg)": 44.4063,
|
||||||
|
"longitude (deg)": -109.4153,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"disposal cost ($/tonne)": "50",
|
||||||
|
"disposal limit (tonne)": "",
|
||||||
|
"disposal limit (%)": "",
|
||||||
|
"transportation cost ($/km/tonne)": "5",
|
||||||
|
"transportation energy (J/km/tonne)": "",
|
||||||
|
"transportation emissions (tonne/km/tonne)": {},
|
||||||
|
x: null,
|
||||||
|
y: null,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const sampleProductsExported = [
|
||||||
|
// basic product
|
||||||
|
{
|
||||||
|
"initial amounts": {
|
||||||
|
"Washakie County": {
|
||||||
|
"latitude (deg)": 43.8356,
|
||||||
|
"longitude (deg)": -107.6602,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
"Platte County": {
|
||||||
|
"latitude (deg)": 42.1314,
|
||||||
|
"longitude (deg)": -104.9676,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
"Park County": {
|
||||||
|
"latitude (deg)": 44.4063,
|
||||||
|
"longitude (deg)": -109.4153,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"disposal cost ($/tonne)": [50, 50, 50],
|
||||||
|
"disposal limit (tonne)": [30, 30, 30],
|
||||||
|
"transportation cost ($/km/tonne)": [5, 5, 5],
|
||||||
|
"transportation energy (J/km/tonne)": [10, 10, 10],
|
||||||
|
"transportation emissions (tonne/km/tonne)": {
|
||||||
|
CO2: [0.5, 0.5, 0.5],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// product with percentage disposal limit
|
||||||
|
{
|
||||||
|
"initial amounts": {
|
||||||
|
"Washakie County": {
|
||||||
|
"latitude (deg)": 43.8356,
|
||||||
|
"longitude (deg)": -107.6602,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
"Platte County": {
|
||||||
|
"latitude (deg)": 42.1314,
|
||||||
|
"longitude (deg)": -104.9676,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
"Park County": {
|
||||||
|
"latitude (deg)": 44.4063,
|
||||||
|
"longitude (deg)": -109.4153,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"disposal cost ($/tonne)": [50, 50, 50],
|
||||||
|
"disposal limit (tonne)": [30, 60, 90],
|
||||||
|
"transportation cost ($/km/tonne)": [5, 5, 5],
|
||||||
|
"transportation energy (J/km/tonne)": [10, 10, 10],
|
||||||
|
"transportation emissions (tonne/km/tonne)": {
|
||||||
|
CO2: [0.5, 0.5, 0.5],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// product using defaults
|
||||||
|
{
|
||||||
|
"initial amounts": {
|
||||||
|
"Washakie County": {
|
||||||
|
"latitude (deg)": 43.8356,
|
||||||
|
"longitude (deg)": -107.6602,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
"Platte County": {
|
||||||
|
"latitude (deg)": 42.1314,
|
||||||
|
"longitude (deg)": -104.9676,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
"Park County": {
|
||||||
|
"latitude (deg)": 44.4063,
|
||||||
|
"longitude (deg)": -109.4153,
|
||||||
|
"amount (tonne)": [100, 200, 300],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"disposal cost ($/tonne)": [50, 50, 50],
|
||||||
|
"transportation cost ($/km/tonne)": [5, 5, 5],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const samplePlantsOriginal = [
|
||||||
|
// basic plant
|
||||||
|
{
|
||||||
|
input: "Baled agricultural biomass",
|
||||||
|
"outputs (tonne/tonne)": {
|
||||||
|
"Hydrogen gas": 0.095,
|
||||||
|
"Carbon dioxide": 1.164,
|
||||||
|
Tar: 0.06,
|
||||||
|
},
|
||||||
|
"energy (GJ/tonne)": "50",
|
||||||
|
locations: {
|
||||||
|
"Washakie County": {
|
||||||
|
"latitude (deg)": 43.8356,
|
||||||
|
"longitude (deg)": -107.6602,
|
||||||
|
"area cost factor": 1.0,
|
||||||
|
},
|
||||||
|
"Platte County": {
|
||||||
|
"latitude (deg)": 42.1314,
|
||||||
|
"longitude (deg)": -104.9676,
|
||||||
|
"area cost factor": 0.5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"disposal cost ($/tonne)": {
|
||||||
|
"Hydrogen gas": "0",
|
||||||
|
"Carbon dioxide": "0",
|
||||||
|
Tar: "200",
|
||||||
|
},
|
||||||
|
"disposal limit (tonne)": {
|
||||||
|
"Hydrogen gas": "10",
|
||||||
|
"Carbon dioxide": "",
|
||||||
|
Tar: "",
|
||||||
|
},
|
||||||
|
"emissions (tonne/tonne)": {
|
||||||
|
CO2: "100",
|
||||||
|
},
|
||||||
|
storage: {
|
||||||
|
"cost ($/tonne)": "5",
|
||||||
|
"limit (tonne)": "10000",
|
||||||
|
},
|
||||||
|
"maximum capacity (tonne)": "730000",
|
||||||
|
"minimum capacity (tonne)": "182500",
|
||||||
|
"opening cost (max capacity) ($)": "300000",
|
||||||
|
"opening cost (min capacity) ($)": "200000",
|
||||||
|
"fixed operating cost (max capacity) ($)": "7000",
|
||||||
|
"fixed operating cost (min capacity) ($)": "5000",
|
||||||
|
"variable operating cost ($/tonne)": "10",
|
||||||
|
x: null,
|
||||||
|
y: null,
|
||||||
|
},
|
||||||
|
// plant with fixed capacity
|
||||||
|
{
|
||||||
|
input: "Baled agricultural biomass",
|
||||||
|
"outputs (tonne/tonne)": {
|
||||||
|
"Hydrogen gas": 0.095,
|
||||||
|
"Carbon dioxide": 1.164,
|
||||||
|
Tar: 0.06,
|
||||||
|
},
|
||||||
|
"energy (GJ/tonne)": "50",
|
||||||
|
locations: {
|
||||||
|
"Washakie County": {
|
||||||
|
"latitude (deg)": 43.8356,
|
||||||
|
"longitude (deg)": -107.6602,
|
||||||
|
"area cost factor": 1.0,
|
||||||
|
},
|
||||||
|
"Platte County": {
|
||||||
|
"latitude (deg)": 42.1314,
|
||||||
|
"longitude (deg)": -104.9676,
|
||||||
|
"area cost factor": 0.5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"disposal cost ($/tonne)": {
|
||||||
|
"Hydrogen gas": "0",
|
||||||
|
"Carbon dioxide": "0",
|
||||||
|
Tar: "200",
|
||||||
|
},
|
||||||
|
"disposal limit (tonne)": {
|
||||||
|
"Hydrogen gas": "10",
|
||||||
|
"Carbon dioxide": "",
|
||||||
|
Tar: "",
|
||||||
|
},
|
||||||
|
"emissions (tonne/tonne)": {
|
||||||
|
CO2: "100",
|
||||||
|
},
|
||||||
|
storage: {
|
||||||
|
"cost ($/tonne)": "5",
|
||||||
|
"limit (tonne)": "10000",
|
||||||
|
},
|
||||||
|
"maximum capacity (tonne)": "182500",
|
||||||
|
"minimum capacity (tonne)": "182500",
|
||||||
|
"opening cost (max capacity) ($)": "200000",
|
||||||
|
"opening cost (min capacity) ($)": "200000",
|
||||||
|
"fixed operating cost (max capacity) ($)": "5000",
|
||||||
|
"fixed operating cost (min capacity) ($)": "5000",
|
||||||
|
"variable operating cost ($/tonne)": "10",
|
||||||
|
x: null,
|
||||||
|
y: null,
|
||||||
|
},
|
||||||
|
// plant with defaults
|
||||||
|
{
|
||||||
|
input: "Baled agricultural biomass",
|
||||||
|
"outputs (tonne/tonne)": {
|
||||||
|
"Hydrogen gas": 0.095,
|
||||||
|
"Carbon dioxide": 1.164,
|
||||||
|
Tar: 0.06,
|
||||||
|
},
|
||||||
|
"energy (GJ/tonne)": "50",
|
||||||
|
locations: {
|
||||||
|
"Washakie County": {
|
||||||
|
"latitude (deg)": 43.8356,
|
||||||
|
"longitude (deg)": -107.6602,
|
||||||
|
"area cost factor": 1.0,
|
||||||
|
},
|
||||||
|
"Platte County": {
|
||||||
|
"latitude (deg)": 42.1314,
|
||||||
|
"longitude (deg)": -104.9676,
|
||||||
|
"area cost factor": 0.5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"disposal cost ($/tonne)": {
|
||||||
|
"Hydrogen gas": "",
|
||||||
|
"Carbon dioxide": "",
|
||||||
|
Tar: "",
|
||||||
|
},
|
||||||
|
"disposal limit (tonne)": {
|
||||||
|
"Hydrogen gas": "",
|
||||||
|
"Carbon dioxide": "",
|
||||||
|
Tar: "",
|
||||||
|
},
|
||||||
|
"emissions (tonne/tonne)": {
|
||||||
|
CO2: "100",
|
||||||
|
},
|
||||||
|
storage: {
|
||||||
|
"cost ($/tonne)": "5",
|
||||||
|
"limit (tonne)": "10000",
|
||||||
|
},
|
||||||
|
"maximum capacity (tonne)": "730000",
|
||||||
|
"minimum capacity (tonne)": "182500",
|
||||||
|
"opening cost (max capacity) ($)": "300000",
|
||||||
|
"opening cost (min capacity) ($)": "200000",
|
||||||
|
"fixed operating cost (max capacity) ($)": "7000",
|
||||||
|
"fixed operating cost (min capacity) ($)": "5000",
|
||||||
|
"variable operating cost ($/tonne)": "10",
|
||||||
|
x: null,
|
||||||
|
y: null,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const samplePlantsExported = [
|
||||||
|
//basic plant
|
||||||
|
{
|
||||||
|
input: "Baled agricultural biomass",
|
||||||
|
"outputs (tonne/tonne)": {
|
||||||
|
"Hydrogen gas": 0.095,
|
||||||
|
"Carbon dioxide": 1.164,
|
||||||
|
Tar: 0.06,
|
||||||
|
},
|
||||||
|
"energy (GJ/tonne)": [50, 50, 50],
|
||||||
|
locations: {
|
||||||
|
"Washakie County": {
|
||||||
|
"latitude (deg)": 43.8356,
|
||||||
|
"longitude (deg)": -107.6602,
|
||||||
|
disposal: {
|
||||||
|
"Hydrogen gas": {
|
||||||
|
"cost ($/tonne)": [0, 0, 0],
|
||||||
|
"limit (tonne)": [10, 10, 10],
|
||||||
|
},
|
||||||
|
"Carbon dioxide": {
|
||||||
|
"cost ($/tonne)": [0, 0, 0],
|
||||||
|
},
|
||||||
|
Tar: {
|
||||||
|
"cost ($/tonne)": [200.0, 200.0, 200.0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
storage: {
|
||||||
|
"cost ($/tonne)": [5, 5, 5],
|
||||||
|
"limit (tonne)": 10000,
|
||||||
|
},
|
||||||
|
"capacities (tonne)": {
|
||||||
|
182500: {
|
||||||
|
"opening cost ($)": [200000, 200000, 200000],
|
||||||
|
"fixed operating cost ($)": [5000, 5000, 5000],
|
||||||
|
"variable operating cost ($/tonne)": [10, 10, 10],
|
||||||
|
},
|
||||||
|
730000: {
|
||||||
|
"opening cost ($)": [300000, 300000, 300000],
|
||||||
|
"fixed operating cost ($)": [7000, 7000, 7000],
|
||||||
|
"variable operating cost ($/tonne)": [10, 10, 10],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Platte County": {
|
||||||
|
"latitude (deg)": 42.1314,
|
||||||
|
"longitude (deg)": -104.9676,
|
||||||
|
disposal: {
|
||||||
|
"Hydrogen gas": {
|
||||||
|
"cost ($/tonne)": [0, 0, 0],
|
||||||
|
"limit (tonne)": [10, 10, 10],
|
||||||
|
},
|
||||||
|
"Carbon dioxide": {
|
||||||
|
"cost ($/tonne)": [0, 0, 0],
|
||||||
|
},
|
||||||
|
Tar: {
|
||||||
|
"cost ($/tonne)": [100.0, 100.0, 100.0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
storage: {
|
||||||
|
"cost ($/tonne)": [2.5, 2.5, 2.5],
|
||||||
|
"limit (tonne)": 10000,
|
||||||
|
},
|
||||||
|
"capacities (tonne)": {
|
||||||
|
182500: {
|
||||||
|
"opening cost ($)": [100000, 100000, 100000],
|
||||||
|
"fixed operating cost ($)": [2500, 2500, 2500],
|
||||||
|
"variable operating cost ($/tonne)": [5, 5, 5],
|
||||||
|
},
|
||||||
|
730000: {
|
||||||
|
"opening cost ($)": [150000, 150000, 150000],
|
||||||
|
"fixed operating cost ($)": [3500, 3500, 3500],
|
||||||
|
"variable operating cost ($/tonne)": [5, 5, 5],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"emissions (tonne/tonne)": {
|
||||||
|
CO2: [100, 100, 100],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// plant with fixed capacity
|
||||||
|
{
|
||||||
|
input: "Baled agricultural biomass",
|
||||||
|
"outputs (tonne/tonne)": {
|
||||||
|
"Hydrogen gas": 0.095,
|
||||||
|
"Carbon dioxide": 1.164,
|
||||||
|
Tar: 0.06,
|
||||||
|
},
|
||||||
|
"energy (GJ/tonne)": [50, 50, 50],
|
||||||
|
locations: {
|
||||||
|
"Washakie County": {
|
||||||
|
"latitude (deg)": 43.8356,
|
||||||
|
"longitude (deg)": -107.6602,
|
||||||
|
disposal: {
|
||||||
|
"Hydrogen gas": {
|
||||||
|
"cost ($/tonne)": [0, 0, 0],
|
||||||
|
"limit (tonne)": [10, 10, 10],
|
||||||
|
},
|
||||||
|
"Carbon dioxide": {
|
||||||
|
"cost ($/tonne)": [0, 0, 0],
|
||||||
|
},
|
||||||
|
Tar: {
|
||||||
|
"cost ($/tonne)": [200.0, 200.0, 200.0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
storage: {
|
||||||
|
"cost ($/tonne)": [5, 5, 5],
|
||||||
|
"limit (tonne)": 10000,
|
||||||
|
},
|
||||||
|
"capacities (tonne)": {
|
||||||
|
182500: {
|
||||||
|
"opening cost ($)": [200000, 200000, 200000],
|
||||||
|
"fixed operating cost ($)": [5000, 5000, 5000],
|
||||||
|
"variable operating cost ($/tonne)": [10, 10, 10],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Platte County": {
|
||||||
|
"latitude (deg)": 42.1314,
|
||||||
|
"longitude (deg)": -104.9676,
|
||||||
|
disposal: {
|
||||||
|
"Hydrogen gas": {
|
||||||
|
"cost ($/tonne)": [0, 0, 0],
|
||||||
|
"limit (tonne)": [10, 10, 10],
|
||||||
|
},
|
||||||
|
"Carbon dioxide": {
|
||||||
|
"cost ($/tonne)": [0, 0, 0],
|
||||||
|
},
|
||||||
|
Tar: {
|
||||||
|
"cost ($/tonne)": [100.0, 100.0, 100.0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
storage: {
|
||||||
|
"cost ($/tonne)": [2.5, 2.5, 2.5],
|
||||||
|
"limit (tonne)": 10000,
|
||||||
|
},
|
||||||
|
"capacities (tonne)": {
|
||||||
|
182500: {
|
||||||
|
"opening cost ($)": [100000, 100000, 100000],
|
||||||
|
"fixed operating cost ($)": [2500, 2500, 2500],
|
||||||
|
"variable operating cost ($/tonne)": [5, 5, 5],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"emissions (tonne/tonne)": {
|
||||||
|
CO2: [100, 100, 100],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// plant with defaults
|
||||||
|
{
|
||||||
|
input: "Baled agricultural biomass",
|
||||||
|
"outputs (tonne/tonne)": {
|
||||||
|
"Hydrogen gas": 0.095,
|
||||||
|
"Carbon dioxide": 1.164,
|
||||||
|
Tar: 0.06,
|
||||||
|
},
|
||||||
|
"energy (GJ/tonne)": [50, 50, 50],
|
||||||
|
locations: {
|
||||||
|
"Washakie County": {
|
||||||
|
"latitude (deg)": 43.8356,
|
||||||
|
"longitude (deg)": -107.6602,
|
||||||
|
disposal: {},
|
||||||
|
storage: {
|
||||||
|
"cost ($/tonne)": [5, 5, 5],
|
||||||
|
"limit (tonne)": 10000,
|
||||||
|
},
|
||||||
|
"capacities (tonne)": {
|
||||||
|
182500: {
|
||||||
|
"opening cost ($)": [200000, 200000, 200000],
|
||||||
|
"fixed operating cost ($)": [5000, 5000, 5000],
|
||||||
|
"variable operating cost ($/tonne)": [10, 10, 10],
|
||||||
|
},
|
||||||
|
730000: {
|
||||||
|
"opening cost ($)": [300000, 300000, 300000],
|
||||||
|
"fixed operating cost ($)": [7000, 7000, 7000],
|
||||||
|
"variable operating cost ($/tonne)": [10, 10, 10],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Platte County": {
|
||||||
|
"latitude (deg)": 42.1314,
|
||||||
|
"longitude (deg)": -104.9676,
|
||||||
|
disposal: {},
|
||||||
|
storage: {
|
||||||
|
"cost ($/tonne)": [2.5, 2.5, 2.5],
|
||||||
|
"limit (tonne)": 10000,
|
||||||
|
},
|
||||||
|
"capacities (tonne)": {
|
||||||
|
182500: {
|
||||||
|
"opening cost ($)": [100000, 100000, 100000],
|
||||||
|
"fixed operating cost ($)": [2500, 2500, 2500],
|
||||||
|
"variable operating cost ($/tonne)": [5, 5, 5],
|
||||||
|
},
|
||||||
|
730000: {
|
||||||
|
"opening cost ($)": [150000, 150000, 150000],
|
||||||
|
"fixed operating cost ($)": [3500, 3500, 3500],
|
||||||
|
"variable operating cost ($/tonne)": [5, 5, 5],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"emissions (tonne/tonne)": {
|
||||||
|
CO2: [100, 100, 100],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
test("export products", () => {
|
||||||
|
for (let i = 0; i < sampleProductsOriginal.length; i++) {
|
||||||
|
const original = sampleProductsOriginal[i];
|
||||||
|
const exported = sampleProductsExported[i];
|
||||||
|
expect(exportProduct(original, 3)).toEqual(exported);
|
||||||
|
expect(importProduct(exported)).toEqual(original);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("export plants", () => {
|
||||||
|
for (let i = 0; i < samplePlantsOriginal.length; i++) {
|
||||||
|
const original = samplePlantsOriginal[i];
|
||||||
|
const exported = samplePlantsExported[i];
|
||||||
|
expect(exportPlant(original, 3)).toEqual(exported);
|
||||||
|
expect(importPlant(exported)).toEqual(original);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("importList", () => {
|
||||||
|
expect(importList("invalid")).toEqual("invalid");
|
||||||
|
expect(importList([1, 1, 1])).toEqual("1");
|
||||||
|
expect(importList([1, 2, 3])).toEqual("[1,2,3]");
|
||||||
|
expect(importList(["A", "A", "A"])).toEqual("A");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("importDict", () => {
|
||||||
|
expect(importDict({ a: [5, 5, 5] })).toEqual({ a: "5" });
|
||||||
|
expect(importDict({ a: [1, 2, 3] })).toEqual({ a: "[1,2,3]" });
|
||||||
|
expect(importDict({ a: "invalid" })).toEqual({ a: "invalid" });
|
||||||
|
});
|
@ -1,17 +1,11 @@
|
|||||||
import React from 'react';
|
import React from "react";
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from "react-dom";
|
||||||
import './index.css';
|
import "./index.css";
|
||||||
import Header from './Header';
|
import InputPage from "./InputPage";
|
||||||
import InputPage from './InputPage';
|
|
||||||
import Footer from './Footer';
|
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<Header />
|
|
||||||
<div id="content">
|
|
||||||
<InputPage />
|
<InputPage />
|
||||||
</div>
|
|
||||||
<Footer />
|
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
document.getElementById('root')
|
document.getElementById("root")
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in new issue