Implement inflation

feature/gui
Alinson S. Xavier 4 years ago
parent 01452441dc
commit 096d95a1aa
No known key found for this signature in database
GPG Key ID: DCA0DAD4D2F58624

@ -29,14 +29,14 @@ const ParametersBlock = (props) => {
onChange={(v) => onChangeField("building period (years)", v)} onChange={(v) => onChangeField("building period (years)", v)}
validate="intList" validate="intList"
/> />
{/* <TextInputRow <TextInputRow
label="Annual inflation rate" label="Inflation rate"
unit="%" unit="%"
tooltip="Rate of inflation applied to all costs." tooltip="Rate at which costs change from one time period to the next. This is applied uniformly to all costs."
value={props.value["annual inflation rate (%)"]} value={props.value["inflation rate (%)"]}
onChange={(v) => onChangeField("annual inflation rate (%)", v)} onChange={(v) => onChangeField("inflation rate (%)", v)}
validate="float" validate="float"
/> */} />
</Form> </Form>
</Card> </Card>
</> </>

@ -1,4 +1,4 @@
import React from "react"; import React, { useEffect } from "react";
import ReactFlow, { Background, isNode } from "react-flow-renderer"; import ReactFlow, { Background, isNode } from "react-flow-renderer";
import Section from "./Section"; import Section from "./Section";
import Card from "./Card"; import Card from "./Card";
@ -47,7 +47,10 @@ const getLayoutedElements = (elements) => {
const PipelineBlock = (props) => { const PipelineBlock = (props) => {
let elements = []; let elements = [];
let mapNameToType = {}; let mapNameToType = {};
let hasNullPositions = false;
for (const [productName, product] of Object.entries(props.products)) { for (const [productName, product] of Object.entries(props.products)) {
if (!product.x || !product.y) hasNullPositions = true;
mapNameToType[productName] = "product"; mapNameToType[productName] = "product";
elements.push({ elements.push({
id: productName, id: productName,
@ -60,6 +63,7 @@ const PipelineBlock = (props) => {
} }
for (const [plantName, plant] of Object.entries(props.plants)) { for (const [plantName, plant] of Object.entries(props.plants)) {
if (!plant.x || !plant.y) hasNullPositions = true;
mapNameToType[plantName] = "plant"; mapNameToType[plantName] = "plant";
elements.push({ elements.push({
id: plantName, id: plantName,
@ -149,6 +153,10 @@ const PipelineBlock = (props) => {
}); });
}; };
useEffect(() => {
if (hasNullPositions) onLayout();
}, [hasNullPositions]);
return ( return (
<> <>
<Section title="Pipeline" /> <Section title="Pipeline" />

@ -42,7 +42,7 @@ export const defaultData = {
parameters: { parameters: {
"time horizon (years)": "1", "time horizon (years)": "1",
"building period (years)": "[1]", "building period (years)": "[1]",
// "annual inflation rate (%)": "0", "inflation rate (%)": "0",
}, },
products: {}, products: {},
plants: {}, plants: {},

@ -10,12 +10,15 @@ const keysToList = (obj) => {
return result; return result;
}; };
export const exportValue = (original, T) => { export const exportValue = (original, T, R = 1) => {
if (isNumeric(original)) { if (isNumeric(original)) {
if (T) { if (T) {
const v = parseFloat(original); let v = parseFloat(original);
const result = []; const result = [];
for (let i = 0; i < T; i++) result.push(v); for (let i = 0; i < T; i++) {
result.push(v);
v *= R;
}
return result; return result;
} else { } else {
return parseFloat(original); return parseFloat(original);
@ -58,12 +61,12 @@ const computeTotalInitialAmount = (prod) => {
return total; return total;
}; };
export const importList = (args) => { export const importList = (args, R = 1) => {
if (!args) return ""; if (!args) return "";
if (Array.isArray(args) && args.length > 0) { if (Array.isArray(args) && args.length > 0) {
let isConstant = true; let isConstant = true;
for (let i = 1; i < args.length; i++) { for (let i = 1; i < args.length; i++) {
if (args[i - 1] !== args[i]) { if (Math.abs(args[i - 1] - args[i] / R) > 1e-3) {
isConstant = false; isConstant = false;
break; break;
} }
@ -97,20 +100,51 @@ const computeAbsDisposal = (prod) => {
return disposalAbs; return disposalAbs;
}; };
export const exportProduct = (original, T) => { const computeInflationAndTimeHorizon = (obj, keys) => {
for (let i = 0; i < keys.length; i++) {
const list = obj[keys[i]];
if (
Array.isArray(list) &&
list.length > 1 &&
isNumeric(list[0]) &&
isNumeric(list[1]) &&
Math.abs(list[0]) > 0
) {
return [list[1] / list[0], list.length];
}
}
return [1, 1];
};
export const exportProduct = (original, parameters) => {
const result = {}; const result = {};
// Copy time series values // Read time horizon
let T = parameters["time horizon (years)"];
if (isNumeric(T)) T = parseInt(T);
else T = 1;
// Read inflation
let R = parameters["inflation rate (%)"];
if (isNumeric(R)) R = parseFloat(R) / 100 + 1;
else R = 1;
// Copy constant time series
result["initial amounts"] = original["initial amounts"]; result["initial amounts"] = original["initial amounts"];
[ ["disposal limit (tonne)", "transportation energy (J/km/tonne)"].forEach(
"disposal cost ($/tonne)", (key) => {
"disposal limit (tonne)",
"transportation cost ($/km/tonne)",
"transportation energy (J/km/tonne)",
].forEach((key) => {
const v = exportValue(original[key], T); const v = exportValue(original[key], T);
if (v.length > 0) result[key] = v; if (v.length > 0) result[key] = v;
}); }
);
// Copy cost time series (with inflation)
["disposal cost ($/tonne)", "transportation cost ($/km/tonne)"].forEach(
(key) => {
const v = exportValue(original[key], T, R);
if (v.length > 0) result[key] = v;
}
);
// Copy dictionaries // Copy dictionaries
["transportation emissions (tonne/km/tonne)"].forEach((key) => { ["transportation emissions (tonne/km/tonne)"].forEach((key) => {
@ -125,9 +159,19 @@ export const exportProduct = (original, T) => {
return result; return result;
}; };
export const exportPlant = (original, T) => { export const exportPlant = (original, parameters) => {
const result = {}; const result = {};
// Read time horizon
let T = parameters["time horizon (years)"];
if (isNumeric(T)) T = parseInt(T);
else T = 1;
// Read inflation
let R = parameters["inflation rate (%)"];
if (isNumeric(R)) R = parseFloat(R) / 100 + 1;
else R = 1;
// Copy scalar values // Copy scalar values
["input"].forEach((key) => { ["input"].forEach((key) => {
result[key] = original[key]; result[key] = original[key];
@ -160,8 +204,8 @@ export const exportPlant = (original, T) => {
const acf = origDict["area cost factor"]; const acf = origDict["area cost factor"];
const exportValueAcf = (obj, T) => { const exportValueAcf = (obj) => {
const v = exportValue(obj, T); const v = exportValue(obj, T, R);
if (Array.isArray(v)) { if (Array.isArray(v)) {
return v.map((v) => v * acf); return v.map((v) => v * acf);
} }
@ -180,7 +224,7 @@ export const exportPlant = (original, T) => {
"fixed operating cost ($)": "fixed operating cost (min capacity) ($)", "fixed operating cost ($)": "fixed operating cost (min capacity) ($)",
"variable operating cost ($/tonne)": "variable operating cost ($/tonne)", "variable operating cost ($/tonne)": "variable operating cost ($/tonne)",
})) { })) {
capDict[minCap][resKeyName] = exportValueAcf(original[origKeyName], T); capDict[minCap][resKeyName] = exportValueAcf(original[origKeyName]);
} }
if (maxCap !== minCap) { if (maxCap !== minCap) {
@ -192,7 +236,7 @@ export const exportPlant = (original, T) => {
"variable operating cost ($/tonne)": "variable operating cost ($/tonne)":
"variable operating cost ($/tonne)", "variable operating cost ($/tonne)",
})) { })) {
capDict[maxCap][resKeyName] = exportValueAcf(original[origKeyName], T); capDict[maxCap][resKeyName] = exportValueAcf(original[origKeyName]);
} }
} }
@ -214,10 +258,7 @@ export const exportPlant = (original, T) => {
// Copy storage // Copy storage
resDict.storage = { resDict.storage = {
"cost ($/tonne)": exportValueAcf( "cost ($/tonne)": exportValueAcf(original["storage"]["cost ($/tonne)"]),
original["storage"]["cost ($/tonne)"],
T
),
}; };
const storLimit = original["storage"]["limit (tonne)"]; const storLimit = original["storage"]["limit (tonne)"];
if (isNumeric(storLimit)) { if (isNumeric(storLimit)) {
@ -246,12 +287,12 @@ export const exportData = (original) => {
// Export products // Export products
for (const [prodName, prodDict] of Object.entries(original.products)) { for (const [prodName, prodDict] of Object.entries(original.products)) {
result.products[prodName] = exportProduct(prodDict, T); result.products[prodName] = exportProduct(prodDict, original.parameters);
} }
// Export plants // Export plants
for (const [plantName, plantDict] of Object.entries(original.plants)) { for (const [plantName, plantDict] of Object.entries(original.plants)) {
result.plants[plantName] = exportPlant(plantDict, T); result.plants[plantName] = exportPlant(plantDict, original.parameters);
} }
return result; return result;
}; };
@ -273,67 +314,83 @@ const compressDisposalLimits = (original, result) => {
}; };
export const importProduct = (original) => { export const importProduct = (original) => {
const result = {}; const prod = {};
const parameters = {};
result["initial amounts"] = { ...original["initial amounts"] }; prod["initial amounts"] = { ...original["initial amounts"] };
// Initialize null values // Initialize null values
["x", "y"].forEach((key) => { ["x", "y"].forEach((key) => {
result[key] = null; prod[key] = null;
}); });
// Initialize empty values // Initialize empty values
["disposal limit (%)"].forEach((key) => { ["disposal limit (%)"].forEach((key) => {
result[key] = ""; prod[key] = "";
}); });
// Import lists // Import constant lists
[ ["transportation energy (J/km/tonne)", "disposal limit (tonne)"].forEach(
"transportation energy (J/km/tonne)", (key) => {
prod[key] = importList(original[key]);
}
);
// Compute inflation and time horizon
const [R, T] = computeInflationAndTimeHorizon(original, [
"transportation cost ($/km/tonne)", "transportation cost ($/km/tonne)",
"disposal cost ($/tonne)", "disposal cost ($/tonne)",
"disposal limit (tonne)", ]);
].forEach((key) => { parameters["inflation rate (%)"] = String((R - 1) * 100);
result[key] = importList(original[key]); parameters["time horizon (years)"] = String(T);
});
// Import cost lists
["transportation cost ($/km/tonne)", "disposal cost ($/tonne)"].forEach(
(key) => {
prod[key] = importList(original[key], R);
}
);
// Import dicts // Import dicts
["transportation emissions (tonne/km/tonne)"].forEach((key) => { ["transportation emissions (tonne/km/tonne)"].forEach((key) => {
result[key] = importDict(original[key]); prod[key] = importDict(original[key]);
}); });
// Attempt to convert absolute disposal limits to relative // Attempt to convert absolute disposal limits to relative
compressDisposalLimits(original, result); compressDisposalLimits(original, prod);
return result; return [prod, parameters];
}; };
export const importPlant = (original) => { export const importPlant = (original) => {
const result = {}; const plant = {};
const parameters = {};
// Initialize null values // Initialize null values
["x", "y"].forEach((key) => { ["x", "y"].forEach((key) => {
result[key] = null; plant[key] = null;
}); });
// Import scalar values // Import scalar values
["input"].forEach((key) => { ["input"].forEach((key) => {
result[key] = original[key]; plant[key] = original[key];
}); });
// Import timeseries values // Import timeseries values
["energy (GJ/tonne)"].forEach((key) => { ["energy (GJ/tonne)"].forEach((key) => {
result[key] = importList(original[key]); plant[key] = importList(original[key]);
}); });
// Import dicts // Import dicts
["outputs (tonne/tonne)", "emissions (tonne/tonne)"].forEach((key) => { ["outputs (tonne/tonne)", "emissions (tonne/tonne)"].forEach((key) => {
result[key] = importDict(original[key]); plant[key] = importDict(original[key]);
}); });
// Read locations
let costsInitialized = false; let costsInitialized = false;
const resLocDict = (result.locations = {}); let R = null;
// Read locations
const resLocDict = (plant.locations = {});
for (const [locName, origLocDict] of Object.entries(original["locations"])) { for (const [locName, origLocDict] of Object.entries(original["locations"])) {
resLocDict[locName] = {}; resLocDict[locName] = {};
@ -350,29 +407,41 @@ export const importPlant = (original) => {
const maxCapDict = origLocDict["capacities (tonne)"][maxCap]; const maxCapDict = origLocDict["capacities (tonne)"][maxCap];
// Import min/max capacity // Import min/max capacity
if ("minimum capacity (tonne)" in result) { if ("minimum capacity (tonne)" in plant) {
if ( if (
result["minimum capacity (tonne)"] !== minCap || plant["minimum capacity (tonne)"] !== minCap ||
result["maximum capacity (tonne)"] !== maxCap plant["maximum capacity (tonne)"] !== maxCap
) { ) {
throw "Data loss"; throw "Data loss";
} }
} else { } else {
result["minimum capacity (tonne)"] = minCap; plant["minimum capacity (tonne)"] = minCap;
result["maximum capacity (tonne)"] = maxCap; plant["maximum capacity (tonne)"] = maxCap;
} }
// Compute area cost factor // Compute area cost factor
let acf = 1; let acf = 1;
if (costsInitialized) { if (costsInitialized) {
acf = result["opening cost (min capacity) ($)"]; acf = plant["opening cost (min capacity) ($)"];
if (Array.isArray(acf)) acf = acf[0]; if (Array.isArray(acf)) acf = acf[0];
acf = minCapDict["opening cost ($)"][0] / acf; acf = minCapDict["opening cost ($)"][0] / acf;
} }
resLocDict[locName]["area cost factor"] = acf; resLocDict[locName]["area cost factor"] = acf;
const [R, T] = computeInflationAndTimeHorizon(maxCapDict, [
"opening cost ($)",
"fixed operating cost ($)",
"variable operating cost ($/tonne)",
]);
parameters["inflation rate (%)"] = String((R - 1) * 100);
parameters["time horizon (years)"] = String(T);
// Read adjusted costs // Read adjusted costs
const importListAcf = (obj) => importList(obj.map((v) => v / acf)); const importListAcf = (obj) =>
importList(
obj.map((v) => v / acf),
R
);
const openCostMax = importListAcf(maxCapDict["opening cost ($)"]); const openCostMax = importListAcf(maxCapDict["opening cost ($)"]);
const openCostMin = importListAcf(minCapDict["opening cost ($)"]); const openCostMin = importListAcf(minCapDict["opening cost ($)"]);
const fixCostMax = importListAcf(maxCapDict["fixed operating cost ($)"]); const fixCostMax = importListAcf(maxCapDict["fixed operating cost ($)"]);
@ -410,32 +479,33 @@ export const importPlant = (original) => {
if (costsInitialized) { if (costsInitialized) {
// Verify that location costs match the previously initialized ones // Verify that location costs match the previously initialized ones
check(result["opening cost (max capacity) ($)"], openCostMax); check(plant["opening cost (max capacity) ($)"], openCostMax);
check(result["opening cost (min capacity) ($)"], openCostMin); check(plant["opening cost (min capacity) ($)"], openCostMin);
check(result["fixed operating cost (max capacity) ($)"], fixCostMax); check(plant["fixed operating cost (max capacity) ($)"], fixCostMax);
check(result["fixed operating cost (min capacity) ($)"], fixCostMin); check(plant["fixed operating cost (min capacity) ($)"], fixCostMin);
check(result["variable operating cost ($/tonne)"], varCost); check(plant["variable operating cost ($/tonne)"], varCost);
check(result["storage"]["cost ($/tonne)"], storCost); check(plant["storage"]["cost ($/tonne)"], storCost);
check(result["storage"]["limit (tonne)"], storLimit); check(plant["storage"]["limit (tonne)"], storLimit);
check(String(result["disposal cost ($/tonne)"]), String(dispCost)); check(String(plant["disposal cost ($/tonne)"]), String(dispCost));
check(String(result["disposal limit (tonne)"]), String(dispLimit)); check(String(plant["disposal limit (tonne)"]), String(dispLimit));
} else { } else {
// Initialize plant costs // Initialize plant costs
costsInitialized = true; costsInitialized = true;
result["opening cost (max capacity) ($)"] = openCostMax; plant["opening cost (max capacity) ($)"] = openCostMax;
result["opening cost (min capacity) ($)"] = openCostMin; plant["opening cost (min capacity) ($)"] = openCostMin;
result["fixed operating cost (max capacity) ($)"] = fixCostMax; plant["fixed operating cost (max capacity) ($)"] = fixCostMax;
result["fixed operating cost (min capacity) ($)"] = fixCostMin; plant["fixed operating cost (min capacity) ($)"] = fixCostMin;
result["variable operating cost ($/tonne)"] = varCost; plant["variable operating cost ($/tonne)"] = varCost;
result["storage"] = {}; plant["storage"] = {};
result["storage"]["cost ($/tonne)"] = storCost; plant["storage"]["cost ($/tonne)"] = storCost;
result["storage"]["limit (tonne)"] = storLimit; plant["storage"]["limit (tonne)"] = storLimit;
result["disposal cost ($/tonne)"] = dispCost; plant["disposal cost ($/tonne)"] = dispCost;
result["disposal limit (tonne)"] = dispLimit; plant["disposal limit (tonne)"] = dispLimit;
parameters["inflation rate (%)"] = String((R - 1) * 100);
} }
} }
return result; return [plant, parameters];
}; };
export const importData = (original) => { export const importData = (original) => {
@ -447,17 +517,25 @@ export const importData = (original) => {
const result = {}; const result = {};
result.parameters = importDict(original.parameters); result.parameters = importDict(original.parameters);
["building period (years)"].forEach((k) => {
result.parameters[k] = JSON.stringify(original.parameters[k]);
});
result.parameters["inflation rate (%)"] = "0";
// Import products // Import products
result.products = {}; result.products = {};
for (const [prodName, origProdDict] of Object.entries(original.products)) { for (const [prodName, origProdDict] of Object.entries(original.products)) {
result.products[prodName] = importProduct(origProdDict); const [recoveredProd, recoveredParams] = importProduct(origProdDict);
result.products[prodName] = recoveredProd;
result.parameters = { ...result.parameters, ...recoveredParams };
} }
// Import plants // Import plants
result.plants = {}; result.plants = {};
for (const [plantName, origPlantDict] of Object.entries(original.plants)) { for (const [plantName, origPlantDict] of Object.entries(original.plants)) {
result.plants[plantName] = importPlant(origPlantDict); const [recoveredPlant, recoveredParams] = importPlant(origPlantDict);
result.plants[plantName] = recoveredPlant;
result.parameters = { ...result.parameters, ...recoveredParams };
} }
return result; return result;

@ -30,7 +30,7 @@ const sampleProductsOriginal = [
"disposal cost ($/tonne)": "50", "disposal cost ($/tonne)": "50",
"disposal limit (tonne)": "30", "disposal limit (tonne)": "30",
"disposal limit (%)": "", "disposal limit (%)": "",
"transportation cost ($/km/tonne)": "5", "transportation cost ($/km/tonne)": "0",
"transportation energy (J/km/tonne)": "10", "transportation energy (J/km/tonne)": "10",
"transportation emissions (tonne/km/tonne)": { "transportation emissions (tonne/km/tonne)": {
CO2: "0.5", CO2: "0.5",
@ -118,9 +118,9 @@ const sampleProductsExported = [
"amount (tonne)": [100, 200, 300], "amount (tonne)": [100, 200, 300],
}, },
}, },
"disposal cost ($/tonne)": [50, 50, 50], "disposal cost ($/tonne)": [50, 100, 200],
"disposal limit (tonne)": [30, 30, 30], "disposal limit (tonne)": [30, 30, 30],
"transportation cost ($/km/tonne)": [5, 5, 5], "transportation cost ($/km/tonne)": [0, 0, 0],
"transportation energy (J/km/tonne)": [10, 10, 10], "transportation energy (J/km/tonne)": [10, 10, 10],
"transportation emissions (tonne/km/tonne)": { "transportation emissions (tonne/km/tonne)": {
CO2: [0.5, 0.5, 0.5], CO2: [0.5, 0.5, 0.5],
@ -347,23 +347,23 @@ const samplePlantsExported = [
"cost ($/tonne)": [0, 0, 0], "cost ($/tonne)": [0, 0, 0],
}, },
Tar: { Tar: {
"cost ($/tonne)": [200.0, 200.0, 200.0], "cost ($/tonne)": [200, 400, 800],
}, },
}, },
storage: { storage: {
"cost ($/tonne)": [5, 5, 5], "cost ($/tonne)": [5, 10, 20],
"limit (tonne)": 10000, "limit (tonne)": 10000,
}, },
"capacities (tonne)": { "capacities (tonne)": {
182500: { 182500: {
"opening cost ($)": [200000, 200000, 200000], "opening cost ($)": [200000, 400000, 800000],
"fixed operating cost ($)": [5000, 5000, 5000], "fixed operating cost ($)": [5000, 10000, 20000],
"variable operating cost ($/tonne)": [10, 10, 10], "variable operating cost ($/tonne)": [10, 20, 40],
}, },
730000: { 730000: {
"opening cost ($)": [300000, 300000, 300000], "opening cost ($)": [300000, 600000, 1200000],
"fixed operating cost ($)": [7000, 7000, 7000], "fixed operating cost ($)": [7000, 14000, 28000],
"variable operating cost ($/tonne)": [10, 10, 10], "variable operating cost ($/tonne)": [10, 20, 40],
}, },
}, },
}, },
@ -379,23 +379,23 @@ const samplePlantsExported = [
"cost ($/tonne)": [0, 0, 0], "cost ($/tonne)": [0, 0, 0],
}, },
Tar: { Tar: {
"cost ($/tonne)": [100.0, 100.0, 100.0], "cost ($/tonne)": [100, 200.0, 400],
}, },
}, },
storage: { storage: {
"cost ($/tonne)": [2.5, 2.5, 2.5], "cost ($/tonne)": [2.5, 5, 10],
"limit (tonne)": 10000, "limit (tonne)": 10000,
}, },
"capacities (tonne)": { "capacities (tonne)": {
182500: { 182500: {
"opening cost ($)": [100000, 100000, 100000], "opening cost ($)": [100000, 200000, 400000],
"fixed operating cost ($)": [2500, 2500, 2500], "fixed operating cost ($)": [2500, 5000, 10000],
"variable operating cost ($/tonne)": [5, 5, 5], "variable operating cost ($/tonne)": [5, 10, 20],
}, },
730000: { 730000: {
"opening cost ($)": [150000, 150000, 150000], "opening cost ($)": [150000, 300000, 600000],
"fixed operating cost ($)": [3500, 3500, 3500], "fixed operating cost ($)": [3500, 7000, 14000],
"variable operating cost ($/tonne)": [5, 5, 5], "variable operating cost ($/tonne)": [5, 10, 20],
}, },
}, },
}, },
@ -532,12 +532,30 @@ const samplePlantsExported = [
}, },
]; ];
const sampleParameters = [
{
"time horizon (years)": "3",
"inflation rate (%)": "100",
},
{
"time horizon (years)": "3",
"inflation rate (%)": "0",
},
{
"time horizon (years)": "3",
"inflation rate (%)": "0",
},
];
test("export products", () => { test("export products", () => {
for (let i = 0; i < sampleProductsOriginal.length; i++) { for (let i = 0; i < sampleProductsOriginal.length; i++) {
const original = sampleProductsOriginal[i]; const original = sampleProductsOriginal[i];
const exported = sampleProductsExported[i]; const exported = sampleProductsExported[i];
expect(exportProduct(original, 3)).toEqual(exported); expect(exportProduct(original, sampleParameters[i])).toEqual(exported);
expect(importProduct(exported)).toEqual(original);
const [recoveredProd, recoveredParams] = importProduct(exported);
expect(recoveredProd).toEqual(original);
expect(recoveredParams).toEqual(sampleParameters[i]);
} }
}); });
@ -545,8 +563,11 @@ test("export plants", () => {
for (let i = 0; i < samplePlantsOriginal.length; i++) { for (let i = 0; i < samplePlantsOriginal.length; i++) {
const original = samplePlantsOriginal[i]; const original = samplePlantsOriginal[i];
const exported = samplePlantsExported[i]; const exported = samplePlantsExported[i];
expect(exportPlant(original, 3)).toEqual(exported); expect(exportPlant(original, sampleParameters[i])).toEqual(exported);
expect(importPlant(exported)).toEqual(original);
const [recoveredPlant, recoveredParams] = importPlant(exported);
expect(recoveredPlant).toEqual(original);
expect(recoveredParams).toEqual(sampleParameters[i]);
} }
}); });

Loading…
Cancel
Save