mirror of
https://github.com/ANL-CEEESA/UnitCommitment.jl.git
synced 2025-12-06 08:18:51 -06:00
web: ThermalUnits: Add, delete, and rename
This commit is contained in:
@@ -27,6 +27,11 @@ import {
|
|||||||
} from "../../core/fixtures";
|
} from "../../core/fixtures";
|
||||||
import { ColumnDefinition } from "tabulator-tables";
|
import { ColumnDefinition } from "tabulator-tables";
|
||||||
import { offerDownload } from "../Common/io";
|
import { offerDownload } from "../Common/io";
|
||||||
|
import {
|
||||||
|
createThermalUnit,
|
||||||
|
deleteGenerator,
|
||||||
|
renameGenerator,
|
||||||
|
} from "../../core/Operations/generatorOps";
|
||||||
|
|
||||||
export const ThermalUnitsColumnSpec: ColumnSpec[] = [
|
export const ThermalUnitsColumnSpec: ColumnSpec[] = [
|
||||||
{
|
{
|
||||||
@@ -155,17 +160,17 @@ const ThermalUnitsComponent = (props: CaseBuilderSectionProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onAdd = () => {
|
const onAdd = () => {
|
||||||
// const [newScenario, err] = createThermalUnit(props.scenario);
|
const [newScenario, err] = createThermalUnit(props.scenario);
|
||||||
// if (err) {
|
if (err) {
|
||||||
// props.onError(err.message);
|
props.onError(err.message);
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
// props.onDataChanged(newScenario);
|
props.onDataChanged(newScenario);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDelete = (name: string): ValidationError | null => {
|
const onDelete = (name: string): ValidationError | null => {
|
||||||
// const newScenario = deleteGenerator(name, props.scenario);
|
const newScenario = deleteGenerator(name, props.scenario);
|
||||||
// props.onDataChanged(newScenario);
|
props.onDataChanged(newScenario);
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -192,16 +197,16 @@ const ThermalUnitsComponent = (props: CaseBuilderSectionProps) => {
|
|||||||
oldName: string,
|
oldName: string,
|
||||||
newName: string,
|
newName: string,
|
||||||
): ValidationError | null => {
|
): ValidationError | null => {
|
||||||
// const [newScenario, err] = renameGenerator(
|
const [newScenario, err] = renameGenerator(
|
||||||
// oldName,
|
oldName,
|
||||||
// newName,
|
newName,
|
||||||
// props.scenario,
|
props.scenario,
|
||||||
// );
|
);
|
||||||
// if (err) {
|
if (err) {
|
||||||
// props.onError(err.message);
|
props.onError(err.message);
|
||||||
// return err;
|
return err;
|
||||||
// }
|
}
|
||||||
// props.onDataChanged(newScenario);
|
props.onDataChanged(newScenario);
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,9 @@ export const generateTableData = (
|
|||||||
break;
|
break;
|
||||||
case "number[N]":
|
case "number[N]":
|
||||||
for (let i = 0; i < spec.length!; i++) {
|
for (let i = 0; i < spec.length!; i++) {
|
||||||
entry[`${spec.title} ${i + 1}`] = entryData[spec.title][i] || "";
|
let v = entryData[spec.title][i];
|
||||||
|
if (v === undefined || v === null) v = "";
|
||||||
|
entry[`${spec.title} ${i + 1}`] = v;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -9,21 +9,24 @@ import assert from "node:assert";
|
|||||||
import {
|
import {
|
||||||
changeProfiledUnitData,
|
changeProfiledUnitData,
|
||||||
createProfiledUnit,
|
createProfiledUnit,
|
||||||
|
createThermalUnit,
|
||||||
deleteGenerator,
|
deleteGenerator,
|
||||||
renameGenerator,
|
renameGenerator,
|
||||||
} from "./generatorOps";
|
} from "./generatorOps";
|
||||||
|
import { ValidationError } from "../Validation/validate";
|
||||||
|
|
||||||
test("createProfiledUnit", () => {
|
test("createProfiledUnit", () => {
|
||||||
const [newScenario, err] = createProfiledUnit(TEST_DATA_1);
|
const [newScenario, err] = createProfiledUnit(TEST_DATA_1);
|
||||||
assert(err === null);
|
assert(err === null);
|
||||||
assert.equal(Object.keys(newScenario.Generators).length, 4);
|
assert.equal(Object.keys(newScenario.Generators).length, 4);
|
||||||
assert.deepEqual(newScenario.Generators["pu3"], {
|
assert("pu3" in newScenario.Generators);
|
||||||
Bus: "b1",
|
});
|
||||||
Type: "Profiled",
|
|
||||||
"Cost ($/MW)": 0,
|
test("createThermalUnit", () => {
|
||||||
"Maximum power (MW)": [0, 0, 0, 0, 0],
|
const [newScenario, err] = createThermalUnit(TEST_DATA_1);
|
||||||
"Minimum power (MW)": [0, 0, 0, 0, 0],
|
assert(err === null);
|
||||||
});
|
assert.equal(Object.keys(newScenario.Generators).length, 4);
|
||||||
|
assert("g2" in newScenario.Generators);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("createProfiledUnit with blank file", () => {
|
test("createProfiledUnit with blank file", () => {
|
||||||
@@ -34,7 +37,7 @@ test("createProfiledUnit with blank file", () => {
|
|||||||
|
|
||||||
test("changeProfiledUnitData", () => {
|
test("changeProfiledUnitData", () => {
|
||||||
let scenario = TEST_DATA_1;
|
let scenario = TEST_DATA_1;
|
||||||
let err = null;
|
let err: ValidationError | null;
|
||||||
[scenario, err] = changeProfiledUnitData(
|
[scenario, err] = changeProfiledUnitData(
|
||||||
"pu1",
|
"pu1",
|
||||||
"Cost ($/MW)",
|
"Cost ($/MW)",
|
||||||
@@ -71,7 +74,7 @@ test("changeProfiledUnitData with invalid bus", () => {
|
|||||||
test("deleteGenerator", () => {
|
test("deleteGenerator", () => {
|
||||||
const newScenario = deleteGenerator("pu1", TEST_DATA_1);
|
const newScenario = deleteGenerator("pu1", TEST_DATA_1);
|
||||||
assert.equal(Object.keys(newScenario.Generators).length, 2);
|
assert.equal(Object.keys(newScenario.Generators).length, 2);
|
||||||
assert("gen1" in newScenario.Generators);
|
assert("g1" in newScenario.Generators);
|
||||||
assert("pu2" in newScenario.Generators);
|
assert("pu2" in newScenario.Generators);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,20 @@ import {
|
|||||||
} from "./commonOps";
|
} from "./commonOps";
|
||||||
import { ProfiledUnitsColumnSpec } from "../../components/CaseBuilder/ProfiledUnits";
|
import { ProfiledUnitsColumnSpec } from "../../components/CaseBuilder/ProfiledUnits";
|
||||||
|
|
||||||
|
const assertBusesNotEmpty = (
|
||||||
|
scenario: UnitCommitmentScenario,
|
||||||
|
): ValidationError | null => {
|
||||||
|
if (Object.keys(scenario.Buses).length === 0)
|
||||||
|
return { message: "Profiled unit requires an existing bus." };
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
export const createProfiledUnit = (
|
export const createProfiledUnit = (
|
||||||
scenario: UnitCommitmentScenario,
|
scenario: UnitCommitmentScenario,
|
||||||
): [UnitCommitmentScenario, ValidationError | null] => {
|
): [UnitCommitmentScenario, ValidationError | null] => {
|
||||||
const busNames = Object.keys(scenario.Buses);
|
const err = assertBusesNotEmpty(scenario);
|
||||||
if (busNames.length === 0) {
|
if (err) return [scenario, err];
|
||||||
return [scenario, { message: "Profiled unit requires an existing bus." }];
|
const busName = Object.keys(scenario.Buses)[0]!;
|
||||||
}
|
|
||||||
const timeslots = generateTimeslots(scenario);
|
const timeslots = generateTimeslots(scenario);
|
||||||
const name = generateUniqueName(scenario.Generators, "pu");
|
const name = generateUniqueName(scenario.Generators, "pu");
|
||||||
return [
|
return [
|
||||||
@@ -29,7 +36,7 @@ export const createProfiledUnit = (
|
|||||||
Generators: {
|
Generators: {
|
||||||
...scenario.Generators,
|
...scenario.Generators,
|
||||||
[name]: {
|
[name]: {
|
||||||
Bus: busNames[0]!,
|
Bus: busName,
|
||||||
Type: "Profiled",
|
Type: "Profiled",
|
||||||
"Cost ($/MW)": 0,
|
"Cost ($/MW)": 0,
|
||||||
"Minimum power (MW)": Array(timeslots.length).fill(0),
|
"Minimum power (MW)": Array(timeslots.length).fill(0),
|
||||||
@@ -41,6 +48,41 @@ export const createProfiledUnit = (
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const createThermalUnit = (
|
||||||
|
scenario: UnitCommitmentScenario,
|
||||||
|
): [UnitCommitmentScenario, ValidationError | null] => {
|
||||||
|
const err = assertBusesNotEmpty(scenario);
|
||||||
|
if (err) return [scenario, err];
|
||||||
|
const busName = Object.keys(scenario.Buses)[0]!;
|
||||||
|
const name = generateUniqueName(scenario.Generators, "g");
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
...scenario,
|
||||||
|
Generators: {
|
||||||
|
...scenario.Generators,
|
||||||
|
[name]: {
|
||||||
|
Bus: busName,
|
||||||
|
Type: "Thermal",
|
||||||
|
"Production cost curve (MW)": [0],
|
||||||
|
"Production cost curve ($)": [0],
|
||||||
|
"Startup costs ($)": [0],
|
||||||
|
"Startup delays (h)": [1],
|
||||||
|
"Ramp up limit (MW)": "",
|
||||||
|
"Ramp down limit (MW)": "",
|
||||||
|
"Startup limit (MW)": "",
|
||||||
|
"Shutdown limit (MW)": "",
|
||||||
|
"Minimum downtime (h)": 1,
|
||||||
|
"Minimum uptime (h)": 1,
|
||||||
|
"Initial status (h)": -24,
|
||||||
|
"Initial power (MW)": 0,
|
||||||
|
"Must run?": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
export const changeProfiledUnitData = (
|
export const changeProfiledUnitData = (
|
||||||
generator: string,
|
generator: string,
|
||||||
field: string,
|
field: string,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const TEST_DATA_1: UnitCommitmentScenario = {
|
|||||||
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: {
|
Generators: {
|
||||||
gen1: {
|
g1: {
|
||||||
Bus: "b1",
|
Bus: "b1",
|
||||||
Type: "Thermal",
|
Type: "Thermal",
|
||||||
"Production cost curve (MW)": [100.0, 110.0, 130.0, 135.0],
|
"Production cost curve (MW)": [100.0, 110.0, 130.0, 135.0],
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ export interface ThermalUnit {
|
|||||||
"Production cost curve ($)": number[];
|
"Production cost curve ($)": number[];
|
||||||
"Startup costs ($)": number[];
|
"Startup costs ($)": number[];
|
||||||
"Startup delays (h)": number[];
|
"Startup delays (h)": number[];
|
||||||
"Ramp up limit (MW)": number;
|
"Ramp up limit (MW)": number | "";
|
||||||
"Ramp down limit (MW)": number;
|
"Ramp down limit (MW)": number | "";
|
||||||
"Startup limit (MW)": number;
|
"Startup limit (MW)": number | "";
|
||||||
"Shutdown limit (MW)": number;
|
"Shutdown limit (MW)": number | "";
|
||||||
"Minimum downtime (h)": number;
|
"Minimum downtime (h)": number;
|
||||||
"Minimum uptime (h)": number;
|
"Minimum uptime (h)": number;
|
||||||
"Initial status (h)": number;
|
"Initial status (h)": number;
|
||||||
@@ -158,7 +158,7 @@ export const TEST_SCENARIO: UnitCommitmentScenario = {
|
|||||||
],
|
],
|
||||||
"Cost ($/MW)": 50.0,
|
"Cost ($/MW)": 50.0,
|
||||||
},
|
},
|
||||||
gen1: {
|
g1: {
|
||||||
Bus: "b1",
|
Bus: "b1",
|
||||||
Type: "Thermal",
|
Type: "Thermal",
|
||||||
"Production cost curve (MW)": [100.0, 110.0, 130.0, 135.0],
|
"Production cost curve (MW)": [100.0, 110.0, 130.0, 135.0],
|
||||||
|
|||||||
Reference in New Issue
Block a user