mirror of
https://github.com/ANL-CEEESA/UnitCommitment.jl.git
synced 2025-12-06 08:18:51 -06:00
web: Add createProfiledUnit
This commit is contained in:
@@ -23,6 +23,7 @@ import { ColumnDefinition } from "tabulator-tables";
|
|||||||
import { offerDownload } from "../../Common/io";
|
import { offerDownload } from "../../Common/io";
|
||||||
import FileUploadElement from "../../Common/Buttons/FileUploadElement";
|
import FileUploadElement from "../../Common/Buttons/FileUploadElement";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
|
import { createProfiledUnit } from "../../../core/Operations/profiledUnitOps";
|
||||||
|
|
||||||
interface ProfiledUnitsProps {
|
interface ProfiledUnitsProps {
|
||||||
scenario: UnitCommitmentScenario;
|
scenario: UnitCommitmentScenario;
|
||||||
@@ -98,7 +99,14 @@ const ProfiledUnitsComponent = (props: ProfiledUnitsProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onAdd = () => {};
|
const onAdd = () => {
|
||||||
|
const [newScenario, err] = createProfiledUnit(props.scenario);
|
||||||
|
if (err) {
|
||||||
|
props.onError(err.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
props.onDataChanged(newScenario);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -30,18 +30,10 @@ test("changeBusData", () => {
|
|||||||
[scenario, err] = changeBusData("b3", "Load (MW) 04:00", "99", scenario);
|
[scenario, err] = changeBusData("b3", "Load (MW) 04:00", "99", scenario);
|
||||||
assert.equal(err, null);
|
assert.equal(err, null);
|
||||||
|
|
||||||
assert.deepEqual(scenario, {
|
assert.deepEqual(scenario.Buses, {
|
||||||
Parameters: {
|
b1: { "Load (MW)": [99, 34.38835, 33.45083, 99, 33.25044] },
|
||||||
Version: "0.4",
|
b2: { "Load (MW)": [14.03739, 13.48563, 13.11797, 12.9009, 13.03939] },
|
||||||
"Power balance penalty ($/MW)": 1000.0,
|
b3: { "Load (MW)": [27.3729, 26.29698, 25.58005, 25.15675, 99] },
|
||||||
"Time horizon (h)": 5,
|
|
||||||
"Time step (min)": 60,
|
|
||||||
},
|
|
||||||
Buses: {
|
|
||||||
b1: { "Load (MW)": [99, 34.38835, 33.45083, 99, 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, 99] },
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -54,35 +46,19 @@ test("changeBusData with invalid numbers", () => {
|
|||||||
test("deleteBus", () => {
|
test("deleteBus", () => {
|
||||||
let scenario = TEST_DATA_1;
|
let scenario = TEST_DATA_1;
|
||||||
scenario = deleteBus("b2", scenario);
|
scenario = deleteBus("b2", scenario);
|
||||||
assert.deepEqual(scenario, {
|
assert.deepEqual(scenario.Buses, {
|
||||||
Parameters: {
|
b1: { "Load (MW)": [35.79534, 34.38835, 33.45083, 32.89729, 33.25044] },
|
||||||
Version: "0.4",
|
b3: { "Load (MW)": [27.3729, 26.29698, 25.58005, 25.15675, 25.4268] },
|
||||||
"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] },
|
|
||||||
b3: { "Load (MW)": [27.3729, 26.29698, 25.58005, 25.15675, 25.4268] },
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renameBus", () => {
|
test("renameBus", () => {
|
||||||
let [scenario, err] = renameBus("b2", "b99", TEST_DATA_1);
|
let [scenario, err] = renameBus("b2", "b99", TEST_DATA_1);
|
||||||
assert(err === null);
|
assert(err === null);
|
||||||
assert.deepEqual(scenario, {
|
assert.deepEqual(scenario.Buses, {
|
||||||
Parameters: {
|
b1: { "Load (MW)": [35.79534, 34.38835, 33.45083, 32.89729, 33.25044] },
|
||||||
Version: "0.4",
|
b99: { "Load (MW)": [14.03739, 13.48563, 13.11797, 12.9009, 13.03939] },
|
||||||
"Power balance penalty ($/MW)": 1000.0,
|
b3: { "Load (MW)": [27.3729, 26.29698, 25.58005, 25.15675, 25.4268] },
|
||||||
"Time horizon (h)": 5,
|
|
||||||
"Time step (min)": 60,
|
|
||||||
},
|
|
||||||
Buses: {
|
|
||||||
b1: { "Load (MW)": [35.79534, 34.38835, 33.45083, 32.89729, 33.25044] },
|
|
||||||
b99: { "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] },
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -6,34 +6,27 @@
|
|||||||
|
|
||||||
import { Buses, UnitCommitmentScenario } from "../fixtures";
|
import { Buses, UnitCommitmentScenario } from "../fixtures";
|
||||||
import { ValidationError } from "../Validation/validate";
|
import { ValidationError } from "../Validation/validate";
|
||||||
|
import { generateTimeslots } from "../../components/Common/Forms/DataTable";
|
||||||
|
|
||||||
const generateUniqueBusName = (scenario: UnitCommitmentScenario) => {
|
export const generateUniqueName = (container: any, prefix: string): string => {
|
||||||
let newBusName = "b";
|
|
||||||
let counter = 1;
|
let counter = 1;
|
||||||
let name = `${newBusName}${counter}`;
|
let name = `${prefix}${counter}`;
|
||||||
while (name in scenario.Buses) {
|
while (name in container) {
|
||||||
counter++;
|
counter++;
|
||||||
name = `${newBusName}${counter}`;
|
name = `${prefix}${counter}`;
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateDefaultBusLoad = (scenario: UnitCommitmentScenario) => {
|
|
||||||
const T =
|
|
||||||
scenario.Parameters["Time horizon (h)"] *
|
|
||||||
(60 / scenario.Parameters["Time step (min)"]);
|
|
||||||
return new Array(T).fill(0);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createBus = (scenario: UnitCommitmentScenario) => {
|
export const createBus = (scenario: UnitCommitmentScenario) => {
|
||||||
const load = generateDefaultBusLoad(scenario);
|
const name = generateUniqueName(scenario.Buses, "b");
|
||||||
let name = generateUniqueBusName(scenario);
|
const timeslots = generateTimeslots(scenario);
|
||||||
return {
|
return {
|
||||||
...scenario,
|
...scenario,
|
||||||
Buses: {
|
Buses: {
|
||||||
...scenario.Buses,
|
...scenario.Buses,
|
||||||
[name]: {
|
[name]: {
|
||||||
"Load (MW)": load,
|
"Load (MW)": Array(timeslots.length).fill(0),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,18 +15,16 @@ import { TEST_DATA_1, TEST_DATA_2 } from "../fixtures.test";
|
|||||||
test("changeTimeHorizon: Shrink 1", () => {
|
test("changeTimeHorizon: Shrink 1", () => {
|
||||||
const [newScenario, err] = changeTimeHorizon(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: {
|
Version: "0.4",
|
||||||
Version: "0.4",
|
"Power balance penalty ($/MW)": 1000.0,
|
||||||
"Power balance penalty ($/MW)": 1000.0,
|
"Time horizon (h)": 3,
|
||||||
"Time horizon (h)": 3,
|
"Time step (min)": 60,
|
||||||
"Time step (min)": 60,
|
});
|
||||||
},
|
assert.deepEqual(newScenario.Buses, {
|
||||||
Buses: {
|
b1: { "Load (MW)": [35.79534, 34.38835, 33.45083] },
|
||||||
b1: { "Load (MW)": [35.79534, 34.38835, 33.45083] },
|
b2: { "Load (MW)": [14.03739, 13.48563, 13.11797] },
|
||||||
b2: { "Load (MW)": [14.03739, 13.48563, 13.11797] },
|
b3: { "Load (MW)": [27.3729, 26.29698, 25.58005] },
|
||||||
b3: { "Load (MW)": [27.3729, 26.29698, 25.58005] },
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -51,23 +49,21 @@ test("changeTimeHorizon: Shrink 2", () => {
|
|||||||
test("changeTimeHorizon grow", () => {
|
test("changeTimeHorizon grow", () => {
|
||||||
const [newScenario, err] = changeTimeHorizon(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: {
|
Version: "0.4",
|
||||||
Version: "0.4",
|
"Power balance penalty ($/MW)": 1000.0,
|
||||||
"Power balance penalty ($/MW)": 1000.0,
|
"Time horizon (h)": 7,
|
||||||
"Time horizon (h)": 7,
|
"Time step (min)": 60,
|
||||||
"Time step (min)": 60,
|
});
|
||||||
|
assert.deepEqual(newScenario.Buses, {
|
||||||
|
b1: {
|
||||||
|
"Load (MW)": [35.79534, 34.38835, 33.45083, 32.89729, 33.25044, 0, 0],
|
||||||
},
|
},
|
||||||
Buses: {
|
b2: {
|
||||||
b1: {
|
"Load (MW)": [14.03739, 13.48563, 13.11797, 12.9009, 13.03939, 0, 0],
|
||||||
"Load (MW)": [35.79534, 34.38835, 33.45083, 32.89729, 33.25044, 0, 0],
|
},
|
||||||
},
|
b3: {
|
||||||
b2: {
|
"Load (MW)": [27.3729, 26.29698, 25.58005, 25.15675, 25.4268, 0, 0],
|
||||||
"Load (MW)": [14.03739, 13.48563, 13.11797, 12.9009, 13.03939, 0, 0],
|
|
||||||
},
|
|
||||||
b3: {
|
|
||||||
"Load (MW)": [27.3729, 26.29698, 25.58005, 25.15675, 25.4268, 0, 0],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
36
web/src/core/Operations/profiledUnitOps.test.ts
Normal file
36
web/src/core/Operations/profiledUnitOps.test.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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 { TEST_DATA_1, TEST_DATA_BLANK } from "../fixtures.test";
|
||||||
|
import assert from "node:assert";
|
||||||
|
import { createProfiledUnit } from "./profiledUnitOps";
|
||||||
|
|
||||||
|
test("createUnit", () => {
|
||||||
|
const [newScenario, err] = createProfiledUnit(TEST_DATA_1);
|
||||||
|
assert(err === null);
|
||||||
|
assert.deepEqual(newScenario.Generators, {
|
||||||
|
pu1: {
|
||||||
|
Bus: "b1",
|
||||||
|
Type: "Profiled",
|
||||||
|
"Cost ($/MW)": 12.5,
|
||||||
|
"Maximum power (MW)": [10, 12, 13, 15, 20],
|
||||||
|
"Minimum power (MW)": [0, 0, 0, 0, 0],
|
||||||
|
},
|
||||||
|
pu2: {
|
||||||
|
Bus: "b1",
|
||||||
|
Type: "Profiled",
|
||||||
|
"Cost ($/MW)": 0,
|
||||||
|
"Maximum power (MW)": [0, 0, 0, 0, 0],
|
||||||
|
"Minimum power (MW)": [0, 0, 0, 0, 0],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("createUnit with blank file", () => {
|
||||||
|
const [newScenario, err] = createProfiledUnit(TEST_DATA_BLANK);
|
||||||
|
assert(err !== null);
|
||||||
|
assert.equal(err.message, "Profiled unit requires an existing bus.");
|
||||||
|
});
|
||||||
37
web/src/core/Operations/profiledUnitOps.ts
Normal file
37
web/src/core/Operations/profiledUnitOps.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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 { UnitCommitmentScenario } from "../fixtures";
|
||||||
|
import { generateTimeslots } from "../../components/Common/Forms/DataTable";
|
||||||
|
import { generateUniqueName } from "./busOperations";
|
||||||
|
import { ValidationError } from "../Validation/validate";
|
||||||
|
|
||||||
|
export const createProfiledUnit = (
|
||||||
|
scenario: UnitCommitmentScenario,
|
||||||
|
): [UnitCommitmentScenario, ValidationError | null] => {
|
||||||
|
const busNames = Object.keys(scenario.Buses);
|
||||||
|
if (busNames.length === 0) {
|
||||||
|
return [scenario, { message: "Profiled unit requires an existing bus." }];
|
||||||
|
}
|
||||||
|
const timeslots = generateTimeslots(scenario);
|
||||||
|
const name = generateUniqueName(scenario.Generators, "pu");
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
...scenario,
|
||||||
|
Generators: {
|
||||||
|
...scenario.Generators,
|
||||||
|
[name]: {
|
||||||
|
Bus: busNames[0]!,
|
||||||
|
Type: "Profiled",
|
||||||
|
"Cost ($/MW)": 0,
|
||||||
|
"Minimum power (MW)": Array(timeslots.length).fill(0),
|
||||||
|
"Maximum power (MW)": Array(timeslots.length).fill(0),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
];
|
||||||
|
};
|
||||||
@@ -12,7 +12,17 @@ export const TEST_DATA_1: UnitCommitmentScenario = {
|
|||||||
b2: { "Load (MW)": [14.03739, 13.48563, 13.11797, 12.9009, 13.03939] },
|
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] },
|
b3: { "Load (MW)": [27.3729, 26.29698, 25.58005, 25.15675, 25.4268] },
|
||||||
},
|
},
|
||||||
|
Generators: {
|
||||||
|
pu1: {
|
||||||
|
Bus: "b1",
|
||||||
|
Type: "Profiled",
|
||||||
|
"Cost ($/MW)": 12.5,
|
||||||
|
"Maximum power (MW)": [10, 12, 13, 15, 20],
|
||||||
|
"Minimum power (MW)": [0, 0, 0, 0, 0],
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TEST_DATA_2: UnitCommitmentScenario = {
|
export const TEST_DATA_2: UnitCommitmentScenario = {
|
||||||
Parameters: {
|
Parameters: {
|
||||||
Version: "0.4",
|
Version: "0.4",
|
||||||
@@ -27,4 +37,15 @@ export const TEST_DATA_2: UnitCommitmentScenario = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const TEST_DATA_BLANK: UnitCommitmentScenario = {
|
||||||
|
Parameters: {
|
||||||
|
Version: "0.4",
|
||||||
|
"Power balance penalty ($/MW)": 1000.0,
|
||||||
|
"Time horizon (h)": 5,
|
||||||
|
"Time step (min)": 60,
|
||||||
|
},
|
||||||
|
Buses: {},
|
||||||
|
Generators: {},
|
||||||
|
};
|
||||||
|
|
||||||
test("fixtures", () => {});
|
test("fixtures", () => {});
|
||||||
|
|||||||
Reference in New Issue
Block a user