mirror of
https://github.com/ANL-CEEESA/UnitCommitment.jl.git
synced 2025-12-06 08:18:51 -06:00
web: Update busOperations to support time-indexed loads
This commit is contained in:
@@ -5,13 +5,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import assert from "node:assert";
|
import assert from "node:assert";
|
||||||
import { BUS_TEST_DATA_1 } from "../../../core/Operations/busOperations.test";
|
|
||||||
import { parseBusesCsv } from "../../CaseBuilder/Buses/BusesCsv";
|
import { parseBusesCsv } from "../../CaseBuilder/Buses/BusesCsv";
|
||||||
import { generateBusesData } from "../../CaseBuilder/Buses/Buses";
|
import { generateBusesData } from "../../CaseBuilder/Buses/Buses";
|
||||||
import { generateCsv } from "./DataTable";
|
import { generateCsv } from "./DataTable";
|
||||||
|
import { TEST_DATA_1 } from "../../../core/fixtures.test";
|
||||||
|
|
||||||
test("generate CSV", () => {
|
test("generate CSV", () => {
|
||||||
const [data, columns] = generateBusesData(BUS_TEST_DATA_1);
|
const [data, columns] = generateBusesData(TEST_DATA_1);
|
||||||
const actualCsv = generateCsv(data, columns);
|
const actualCsv = generateCsv(data, columns);
|
||||||
const expectedCsv =
|
const expectedCsv =
|
||||||
"Name,Load (MW) 00:00,Load (MW) 01:00,Load (MW) 02:00,Load (MW) 03:00,Load (MW) 04:00\n" +
|
"Name,Load (MW) 00:00,Load (MW) 01:00,Load (MW) 02:00,Load (MW) 03:00,Load (MW) 04:00\n" +
|
||||||
@@ -26,7 +26,7 @@ test("parse valid CSV", () => {
|
|||||||
// "Name,Load 0,Load 1,Load 2,Load 3,Load 4\n" +
|
// "Name,Load 0,Load 1,Load 2,Load 3,Load 4\n" +
|
||||||
// "b1,0,1,2,3,4\n" +
|
// "b1,0,1,2,3,4\n" +
|
||||||
// "b3,27.3729,26.29698,25.58005,25.15675,25.4268";
|
// "b3,27.3729,26.29698,25.58005,25.15675,25.4268";
|
||||||
// const newScenario = parseBusesCsv(BUS_TEST_DATA_1, csvContents);
|
// const newScenario = parseBusesCsv(FixturesTest, csvContents);
|
||||||
// assert.deepEqual(newScenario.Buses, {
|
// assert.deepEqual(newScenario.Buses, {
|
||||||
// b1: {
|
// b1: {
|
||||||
// "Load (MW)": [0, 1, 2, 3, 4],
|
// "Load (MW)": [0, 1, 2, 3, 4],
|
||||||
@@ -43,7 +43,7 @@ test("parse invalid CSV (wrong headers)", () => {
|
|||||||
"b1,0,1,2,3,4\n" +
|
"b1,0,1,2,3,4\n" +
|
||||||
"b3,27.3729,26.29698,25.58005,25.15675,25.4268";
|
"b3,27.3729,26.29698,25.58005,25.15675,25.4268";
|
||||||
expect(() => {
|
expect(() => {
|
||||||
parseBusesCsv(BUS_TEST_DATA_1, csvContents);
|
parseBusesCsv(TEST_DATA_1, csvContents);
|
||||||
}).toThrow(Error);
|
}).toThrow(Error);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -53,6 +53,6 @@ test("parse invalid CSV (wrong data length)", () => {
|
|||||||
"b1,0,1,2,3\n" +
|
"b1,0,1,2,3\n" +
|
||||||
"b3,27.3729,26.29698,25.58005,25.15675,25.4268";
|
"b3,27.3729,26.29698,25.58005,25.15675,25.4268";
|
||||||
expect(() => {
|
expect(() => {
|
||||||
parseBusesCsv(BUS_TEST_DATA_1, csvContents);
|
parseBusesCsv(TEST_DATA_1, csvContents);
|
||||||
}).toThrow(Error);
|
}).toThrow(Error);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* Released under the modified BSD license. See COPYING.md for more details.
|
* Released under the modified BSD license. See COPYING.md for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { UnitCommitmentScenario } from "../fixtures";
|
|
||||||
import {
|
import {
|
||||||
changeBusData,
|
changeBusData,
|
||||||
createBus,
|
createBus,
|
||||||
@@ -12,51 +11,23 @@ import {
|
|||||||
renameBus,
|
renameBus,
|
||||||
} from "./busOperations";
|
} from "./busOperations";
|
||||||
import assert from "node:assert";
|
import assert from "node:assert";
|
||||||
|
import { TEST_DATA_1 } from "../fixtures.test";
|
||||||
export const BUS_TEST_DATA_1: UnitCommitmentScenario = {
|
|
||||||
Parameters: {
|
|
||||||
Version: "0.4",
|
|
||||||
"Power balance penalty ($/MW)": 1000.0,
|
|
||||||
"Time horizon (h)": 5,
|
|
||||||
"Time step (min)": 60,
|
|
||||||
},
|
|
||||||
Buses: {
|
|
||||||
b1: { "Load (MW)": [35.79534, 34.38835, 33.45083, 32.89729, 33.25044] },
|
|
||||||
b2: { "Load (MW)": [14.03739, 13.48563, 13.11797, 12.9009, 13.03939] },
|
|
||||||
b3: { "Load (MW)": [27.3729, 26.29698, 25.58005, 25.15675, 25.4268] },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const BUS_TEST_DATA_2: UnitCommitmentScenario = {
|
|
||||||
Parameters: {
|
|
||||||
Version: "0.4",
|
|
||||||
"Power balance penalty ($/MW)": 1000.0,
|
|
||||||
"Time horizon (h)": 2,
|
|
||||||
"Time step (min)": 30,
|
|
||||||
},
|
|
||||||
Buses: {
|
|
||||||
b1: { "Load (MW)": [30, 30, 30, 30] },
|
|
||||||
b2: { "Load (MW)": [10, 20, 30, 40] },
|
|
||||||
b3: { "Load (MW)": [0, 30, 0, 40] },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
test("createBus", () => {
|
test("createBus", () => {
|
||||||
const newScenario = createBus(BUS_TEST_DATA_1);
|
const newScenario = createBus(TEST_DATA_1);
|
||||||
assert.deepEqual(Object.keys(newScenario.Buses), ["b1", "b2", "b3", "b4"]);
|
assert.deepEqual(Object.keys(newScenario.Buses), ["b1", "b2", "b3", "b4"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("changeBusData", () => {
|
test("changeBusData", () => {
|
||||||
let scenario = BUS_TEST_DATA_1;
|
let scenario = TEST_DATA_1;
|
||||||
let err = null;
|
let err = null;
|
||||||
|
|
||||||
[scenario, err] = changeBusData("b1", "Load 0", "99", scenario);
|
[scenario, err] = changeBusData("b1", "Load (MW) 00:00", "99", scenario);
|
||||||
|
assert.equal(err, null);
|
||||||
|
[scenario, err] = changeBusData("b1", "Load (MW) 03:00", "99", scenario);
|
||||||
assert.equal(err, null);
|
assert.equal(err, null);
|
||||||
|
|
||||||
[scenario, err] = changeBusData("b1", "Load 3", "99", scenario);
|
[scenario, err] = changeBusData("b3", "Load (MW) 04:00", "99", scenario);
|
||||||
assert.equal(err, null);
|
|
||||||
|
|
||||||
[scenario, err] = changeBusData("b3", "Load 4", "99", scenario);
|
|
||||||
assert.equal(err, null);
|
assert.equal(err, null);
|
||||||
|
|
||||||
assert.deepEqual(scenario, {
|
assert.deepEqual(scenario, {
|
||||||
@@ -75,13 +46,13 @@ test("changeBusData", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("changeBusData with invalid numbers", () => {
|
test("changeBusData with invalid numbers", () => {
|
||||||
let [, err] = changeBusData("b1", "Load 0", "xx", BUS_TEST_DATA_1);
|
let [, err] = changeBusData("b1", "Load (MW) 00:00", "xx", TEST_DATA_1);
|
||||||
assert(err !== null);
|
assert(err !== null);
|
||||||
assert.equal(err.message, "Invalid value: xx");
|
assert.equal(err.message, "Invalid value: xx");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("deleteBus", () => {
|
test("deleteBus", () => {
|
||||||
let scenario = BUS_TEST_DATA_1;
|
let scenario = TEST_DATA_1;
|
||||||
scenario = deleteBus("b2", scenario);
|
scenario = deleteBus("b2", scenario);
|
||||||
assert.deepEqual(scenario, {
|
assert.deepEqual(scenario, {
|
||||||
Parameters: {
|
Parameters: {
|
||||||
@@ -98,7 +69,7 @@ test("deleteBus", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("renameBus", () => {
|
test("renameBus", () => {
|
||||||
let [scenario, err] = renameBus("b2", "b99", BUS_TEST_DATA_1);
|
let [scenario, err] = renameBus("b2", "b99", TEST_DATA_1);
|
||||||
assert(err === null);
|
assert(err === null);
|
||||||
assert.deepEqual(scenario, {
|
assert.deepEqual(scenario, {
|
||||||
Parameters: {
|
Parameters: {
|
||||||
@@ -116,7 +87,7 @@ test("renameBus", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("renameBus with duplicated name", () => {
|
test("renameBus with duplicated name", () => {
|
||||||
let [, err] = renameBus("b3", "b1", BUS_TEST_DATA_1);
|
let [, err] = renameBus("b3", "b1", TEST_DATA_1);
|
||||||
assert(err != null);
|
assert(err != null);
|
||||||
assert.equal(err.message, `Bus b1 already exists`);
|
assert.equal(err.message, `Bus b1 already exists`);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,13 +46,18 @@ export const changeBusData = (
|
|||||||
scenario: UnitCommitmentScenario,
|
scenario: UnitCommitmentScenario,
|
||||||
): [UnitCommitmentScenario, ValidationError | null] => {
|
): [UnitCommitmentScenario, ValidationError | null] => {
|
||||||
// Load (MW)
|
// Load (MW)
|
||||||
const match = field.match(/Load (\d+)/);
|
const match = field.match(/Load \(MW\) (\d+):(\d+)/);
|
||||||
if (match) {
|
if (match) {
|
||||||
const newValueFloat = parseFloat(newValueStr);
|
const newValueFloat = parseFloat(newValueStr);
|
||||||
if (isNaN(newValueFloat)) {
|
if (isNaN(newValueFloat)) {
|
||||||
return [scenario, { message: `Invalid value: ${newValueStr}` }];
|
return [scenario, { message: `Invalid value: ${newValueStr}` }];
|
||||||
}
|
}
|
||||||
const idx = parseInt(match[1]!, 10);
|
|
||||||
|
// Convert HH:MM to offset
|
||||||
|
const hours = parseInt(match[1]!, 10);
|
||||||
|
const min = parseInt(match[2]!, 10);
|
||||||
|
const idx = (hours * 60 + min) / scenario.Parameters["Time step (min)"];
|
||||||
|
|
||||||
const newLoad = [...scenario.Buses[bus]!["Load (MW)"]];
|
const newLoad = [...scenario.Buses[bus]!["Load (MW)"]];
|
||||||
newLoad[idx] = newValueFloat;
|
newLoad[idx] = newValueFloat;
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ import {
|
|||||||
changeTimeStep,
|
changeTimeStep,
|
||||||
evaluatePwlFunction,
|
evaluatePwlFunction,
|
||||||
} from "./parameterOperations";
|
} from "./parameterOperations";
|
||||||
import { BUS_TEST_DATA_1, BUS_TEST_DATA_2 } from "./busOperations.test";
|
|
||||||
import assert from "node:assert";
|
import assert from "node:assert";
|
||||||
|
import { TEST_DATA_1, TEST_DATA_2 } from "../fixtures.test";
|
||||||
|
|
||||||
test("changeTimeHorizon: Shrink 1", () => {
|
test("changeTimeHorizon: Shrink 1", () => {
|
||||||
const [newScenario, err] = changeTimeHorizon(BUS_TEST_DATA_1, "3");
|
const [newScenario, err] = changeTimeHorizon(TEST_DATA_1, "3");
|
||||||
assert(err === null);
|
assert(err === null);
|
||||||
assert.deepEqual(newScenario, {
|
assert.deepEqual(newScenario, {
|
||||||
Parameters: {
|
Parameters: {
|
||||||
@@ -31,7 +31,7 @@ test("changeTimeHorizon: Shrink 1", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("changeTimeHorizon: Shrink 2", () => {
|
test("changeTimeHorizon: Shrink 2", () => {
|
||||||
const [newScenario, err] = changeTimeHorizon(BUS_TEST_DATA_2, "1");
|
const [newScenario, err] = changeTimeHorizon(TEST_DATA_2, "1");
|
||||||
assert(err === null);
|
assert(err === null);
|
||||||
assert.deepEqual(newScenario, {
|
assert.deepEqual(newScenario, {
|
||||||
Parameters: {
|
Parameters: {
|
||||||
@@ -49,7 +49,7 @@ test("changeTimeHorizon: Shrink 2", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("changeTimeHorizon grow", () => {
|
test("changeTimeHorizon grow", () => {
|
||||||
const [newScenario, err] = changeTimeHorizon(BUS_TEST_DATA_1, "7");
|
const [newScenario, err] = changeTimeHorizon(TEST_DATA_1, "7");
|
||||||
assert(err === null);
|
assert(err === null);
|
||||||
assert.deepEqual(newScenario, {
|
assert.deepEqual(newScenario, {
|
||||||
Parameters: {
|
Parameters: {
|
||||||
@@ -73,11 +73,11 @@ test("changeTimeHorizon grow", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("changeTimeHorizon invalid", () => {
|
test("changeTimeHorizon invalid", () => {
|
||||||
let [, err] = changeTimeHorizon(BUS_TEST_DATA_1, "x");
|
let [, err] = changeTimeHorizon(TEST_DATA_1, "x");
|
||||||
assert(err !== null);
|
assert(err !== null);
|
||||||
assert.equal(err.message, "Invalid value: x");
|
assert.equal(err.message, "Invalid value: x");
|
||||||
|
|
||||||
[, err] = changeTimeHorizon(BUS_TEST_DATA_1, "-3");
|
[, err] = changeTimeHorizon(TEST_DATA_1, "-3");
|
||||||
assert(err !== null);
|
assert(err !== null);
|
||||||
assert.equal(err.message, "Invalid value: -3");
|
assert.equal(err.message, "Invalid value: -3");
|
||||||
});
|
});
|
||||||
@@ -93,7 +93,7 @@ test("evaluatePwlFunction", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("changeTimeStep", () => {
|
test("changeTimeStep", () => {
|
||||||
let [scenario, err] = changeTimeStep(BUS_TEST_DATA_2, "15");
|
let [scenario, err] = changeTimeStep(TEST_DATA_2, "15");
|
||||||
assert(err === null);
|
assert(err === null);
|
||||||
assert.deepEqual(scenario, {
|
assert.deepEqual(scenario, {
|
||||||
Parameters: {
|
Parameters: {
|
||||||
@@ -109,7 +109,7 @@ test("changeTimeStep", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
[scenario, err] = changeTimeStep(BUS_TEST_DATA_2, "60");
|
[scenario, err] = changeTimeStep(TEST_DATA_2, "60");
|
||||||
assert(err === null);
|
assert(err === null);
|
||||||
assert.deepEqual(scenario, {
|
assert.deepEqual(scenario, {
|
||||||
Parameters: {
|
Parameters: {
|
||||||
@@ -127,19 +127,19 @@ test("changeTimeStep", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("changeTimeStep invalid", () => {
|
test("changeTimeStep invalid", () => {
|
||||||
let [, err] = changeTimeStep(BUS_TEST_DATA_2, "x");
|
let [, err] = changeTimeStep(TEST_DATA_2, "x");
|
||||||
assert(err !== null);
|
assert(err !== null);
|
||||||
assert.equal(err.message, "Invalid value: x");
|
assert.equal(err.message, "Invalid value: x");
|
||||||
|
|
||||||
[, err] = changeTimeStep(BUS_TEST_DATA_2, "-10");
|
[, err] = changeTimeStep(TEST_DATA_2, "-10");
|
||||||
assert(err !== null);
|
assert(err !== null);
|
||||||
assert.equal(err.message, "Invalid value: -10");
|
assert.equal(err.message, "Invalid value: -10");
|
||||||
|
|
||||||
[, err] = changeTimeStep(BUS_TEST_DATA_2, "120");
|
[, err] = changeTimeStep(TEST_DATA_2, "120");
|
||||||
assert(err !== null);
|
assert(err !== null);
|
||||||
assert.equal(err.message, "Invalid value: 120");
|
assert.equal(err.message, "Invalid value: 120");
|
||||||
|
|
||||||
[, err] = changeTimeStep(BUS_TEST_DATA_2, "7");
|
[, err] = changeTimeStep(TEST_DATA_2, "7");
|
||||||
assert(err !== null);
|
assert(err !== null);
|
||||||
assert.equal(err.message, "Time step must be a divisor of 60: 7");
|
assert.equal(err.message, "Time step must be a divisor of 60: 7");
|
||||||
});
|
});
|
||||||
|
|||||||
30
web/src/core/fixtures.test.ts
Normal file
30
web/src/core/fixtures.test.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { UnitCommitmentScenario } from "./fixtures";
|
||||||
|
|
||||||
|
export const TEST_DATA_1: UnitCommitmentScenario = {
|
||||||
|
Parameters: {
|
||||||
|
Version: "0.4",
|
||||||
|
"Power balance penalty ($/MW)": 1000.0,
|
||||||
|
"Time horizon (h)": 5,
|
||||||
|
"Time step (min)": 60,
|
||||||
|
},
|
||||||
|
Buses: {
|
||||||
|
b1: { "Load (MW)": [35.79534, 34.38835, 33.45083, 32.89729, 33.25044] },
|
||||||
|
b2: { "Load (MW)": [14.03739, 13.48563, 13.11797, 12.9009, 13.03939] },
|
||||||
|
b3: { "Load (MW)": [27.3729, 26.29698, 25.58005, 25.15675, 25.4268] },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export const TEST_DATA_2: UnitCommitmentScenario = {
|
||||||
|
Parameters: {
|
||||||
|
Version: "0.4",
|
||||||
|
"Power balance penalty ($/MW)": 1000.0,
|
||||||
|
"Time horizon (h)": 2,
|
||||||
|
"Time step (min)": 30,
|
||||||
|
},
|
||||||
|
Buses: {
|
||||||
|
b1: { "Load (MW)": [30, 30, 30, 30] },
|
||||||
|
b2: { "Load (MW)": [10, 20, 30, 40] },
|
||||||
|
b3: { "Load (MW)": [0, 30, 0, 40] },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
test("fixtures", () => {});
|
||||||
Reference in New Issue
Block a user