You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
210 lines
6.7 KiB
210 lines
6.7 KiB
/*
|
|
* UnitCommitment.jl: Optimization Package for Security-Constrained Unit Commitment
|
|
* Copyright (C) 2020-2025, UChicago Argonne, LLC. All rights reserved.
|
|
* Released under the modified BSD license. See COPYING.md for more details.
|
|
*/
|
|
|
|
import {
|
|
floatFormatter,
|
|
generateCsv,
|
|
generateTableColumns,
|
|
generateTableData,
|
|
} from "../Common/Forms/DataTable";
|
|
import { TEST_DATA_1 } from "../../core/Data/fixtures.test";
|
|
import {
|
|
generateThermalUnitsData,
|
|
parseThermalUnitsCsv,
|
|
ThermalUnitsColumnSpec,
|
|
} from "./ThermalUnits";
|
|
import assert from "node:assert";
|
|
import {
|
|
getProfiledGenerators,
|
|
getThermalGenerators,
|
|
} from "../../core/Data/types";
|
|
|
|
test("generateTableColumns", () => {
|
|
const columns = generateTableColumns(TEST_DATA_1, ThermalUnitsColumnSpec);
|
|
assert.equal(columns[2]!["columns"]!.length, 10);
|
|
assert.deepEqual(columns[2]!["columns"]![0], {
|
|
editor: "input",
|
|
editorParams: {
|
|
selectContents: true,
|
|
},
|
|
field: "Production cost curve (MW) 1",
|
|
formatter: floatFormatter,
|
|
headerHozAlign: "left",
|
|
headerSort: false,
|
|
headerWordWrap: true,
|
|
hozAlign: "left",
|
|
minWidth: 75,
|
|
resizable: false,
|
|
title: "1",
|
|
});
|
|
});
|
|
|
|
test("generateTableData", () => {
|
|
const data = generateTableData(
|
|
getThermalGenerators(TEST_DATA_1),
|
|
ThermalUnitsColumnSpec,
|
|
TEST_DATA_1,
|
|
);
|
|
assert.deepEqual(data[0], {
|
|
Name: "g1",
|
|
Bus: "b1",
|
|
"Initial power (MW)": 115,
|
|
"Initial status (h)": 12,
|
|
"Minimum downtime (h)": 4,
|
|
"Minimum uptime (h)": 4,
|
|
"Ramp down limit (MW)": 232.68,
|
|
"Ramp up limit (MW)": 232.68,
|
|
"Shutdown limit (MW)": 232.68,
|
|
"Startup limit (MW)": 232.68,
|
|
"Production cost curve ($) 1": 1400,
|
|
"Production cost curve ($) 2": 1600,
|
|
"Production cost curve ($) 3": 2200,
|
|
"Production cost curve ($) 4": 2400,
|
|
"Production cost curve ($) 5": "",
|
|
"Production cost curve ($) 6": "",
|
|
"Production cost curve ($) 7": "",
|
|
"Production cost curve ($) 8": "",
|
|
"Production cost curve ($) 9": "",
|
|
"Production cost curve ($) 10": "",
|
|
"Production cost curve (MW) 1": 100,
|
|
"Production cost curve (MW) 2": 110,
|
|
"Production cost curve (MW) 3": 130,
|
|
"Production cost curve (MW) 4": 135,
|
|
"Production cost curve (MW) 5": "",
|
|
"Production cost curve (MW) 6": "",
|
|
"Production cost curve (MW) 7": "",
|
|
"Production cost curve (MW) 8": "",
|
|
"Production cost curve (MW) 9": "",
|
|
"Production cost curve (MW) 10": "",
|
|
"Startup costs ($) 1": 300,
|
|
"Startup costs ($) 2": 400,
|
|
"Startup costs ($) 3": "",
|
|
"Startup costs ($) 4": "",
|
|
"Startup costs ($) 5": "",
|
|
"Startup delays (h) 1": 1,
|
|
"Startup delays (h) 2": 4,
|
|
"Startup delays (h) 3": "",
|
|
"Startup delays (h) 4": "",
|
|
"Startup delays (h) 5": "",
|
|
"Must run?": false,
|
|
});
|
|
});
|
|
|
|
const expectedCsvContents =
|
|
"Name,Bus," +
|
|
"Production cost curve (MW) 1," +
|
|
"Production cost curve (MW) 2," +
|
|
"Production cost curve (MW) 3," +
|
|
"Production cost curve (MW) 4," +
|
|
"Production cost curve (MW) 5," +
|
|
"Production cost curve (MW) 6," +
|
|
"Production cost curve (MW) 7," +
|
|
"Production cost curve (MW) 8," +
|
|
"Production cost curve (MW) 9," +
|
|
"Production cost curve (MW) 10," +
|
|
"Production cost curve ($) 1," +
|
|
"Production cost curve ($) 2," +
|
|
"Production cost curve ($) 3," +
|
|
"Production cost curve ($) 4," +
|
|
"Production cost curve ($) 5," +
|
|
"Production cost curve ($) 6," +
|
|
"Production cost curve ($) 7," +
|
|
"Production cost curve ($) 8," +
|
|
"Production cost curve ($) 9," +
|
|
"Production cost curve ($) 10," +
|
|
"Startup costs ($) 1," +
|
|
"Startup costs ($) 2," +
|
|
"Startup costs ($) 3," +
|
|
"Startup costs ($) 4," +
|
|
"Startup costs ($) 5," +
|
|
"Startup delays (h) 1," +
|
|
"Startup delays (h) 2," +
|
|
"Startup delays (h) 3," +
|
|
"Startup delays (h) 4," +
|
|
"Startup delays (h) 5," +
|
|
"Minimum uptime (h),Minimum downtime (h),Ramp up limit (MW)," +
|
|
"Ramp down limit (MW),Startup limit (MW),Shutdown limit (MW)," +
|
|
"Initial status (h),Initial power (MW),Must run?\n" +
|
|
"g1,b1,100,110,130,135,,,,,,,1400,1600,2200,2400,,,,,,,300,400,,,,1,4,,,,4,4,232.68,232.68,232.68,232.68,12,115,false";
|
|
|
|
const invalidCsv =
|
|
"Name,Bus," +
|
|
"Production cost curve (MW) 1," +
|
|
"Production cost curve (MW) 2," +
|
|
"Production cost curve (MW) 3," +
|
|
"Production cost curve (MW) 4," +
|
|
"Production cost curve (MW) 5," +
|
|
"Production cost curve (MW) 6," +
|
|
"Production cost curve (MW) 7," +
|
|
"Production cost curve (MW) 8," +
|
|
"Production cost curve (MW) 9," +
|
|
"Production cost curve (MW) 10," +
|
|
"Production cost curve ($) 1," +
|
|
"Production cost curve ($) 2," +
|
|
"Production cost curve ($) 3," +
|
|
"Production cost curve ($) 4," +
|
|
"Production cost curve ($) 5," +
|
|
"Production cost curve ($) 6," +
|
|
"Production cost curve ($) 7," +
|
|
"Production cost curve ($) 8," +
|
|
"Production cost curve ($) 9," +
|
|
"Production cost curve ($) 10," +
|
|
"Startup costs ($) 1," +
|
|
"Startup costs ($) 2," +
|
|
"Startup costs ($) 3," +
|
|
"Startup costs ($) 4," +
|
|
"Startup costs ($) 5," +
|
|
"Startup delays (h) 1," +
|
|
"Startup delays (h) 2," +
|
|
"Startup delays (h) 3," +
|
|
"Startup delays (h) 4," +
|
|
"Startup delays (h) 5," +
|
|
"Minimum uptime (h),Minimum downtime (h),Ramp up limit (MW)," +
|
|
"Ramp down limit (MW),Startup limit (MW),Shutdown limit (MW)," +
|
|
"Initial status (h),Initial power (MW),Must run?\n" +
|
|
"g1,b1,100,110,130,x,,,,,,,1400,1600,2200,2400,,,,,,,300,400,,,,1,4,,,,4,4,232.68,232.68,232.68,232.68,12,115,false";
|
|
|
|
test("generateCSV", () => {
|
|
const [data, columns] = generateThermalUnitsData(TEST_DATA_1);
|
|
const actualCsvContents = generateCsv(data, columns);
|
|
assert.equal(actualCsvContents, expectedCsvContents);
|
|
});
|
|
|
|
test("parseCSV", () => {
|
|
const [scenario, err] = parseThermalUnitsCsv(
|
|
expectedCsvContents,
|
|
TEST_DATA_1,
|
|
);
|
|
assert(!err);
|
|
const thermalGens = getThermalGenerators(scenario);
|
|
const profGens = getProfiledGenerators(scenario);
|
|
assert.equal(Object.keys(thermalGens).length, 1);
|
|
assert.equal(Object.keys(profGens).length, 2);
|
|
assert.deepEqual(thermalGens["g1"], {
|
|
Bus: "b1",
|
|
Type: "Thermal",
|
|
"Production cost curve (MW)": [100.0, 110.0, 130.0, 135.0],
|
|
"Production cost curve ($)": [1400.0, 1600.0, 2200.0, 2400.0],
|
|
"Startup costs ($)": [300.0, 400.0],
|
|
"Startup delays (h)": [1, 4],
|
|
"Ramp up limit (MW)": 232.68,
|
|
"Ramp down limit (MW)": 232.68,
|
|
"Startup limit (MW)": 232.68,
|
|
"Shutdown limit (MW)": 232.68,
|
|
"Minimum downtime (h)": 4,
|
|
"Minimum uptime (h)": 4,
|
|
"Initial status (h)": 12,
|
|
"Initial power (MW)": 115,
|
|
"Must run?": false,
|
|
});
|
|
});
|
|
|
|
test("parseCSV with invalid number[T]", () => {
|
|
const [, err] = parseThermalUnitsCsv(invalidCsv, TEST_DATA_1);
|
|
assert(err);
|
|
assert.equal(err.message, '"x" is not a valid number (row 1)');
|
|
});
|