web: ProfiledUnits: Rename and delete

web
Alinson S. Xavier 3 months ago
parent 8397571c11
commit 86aababf33

@ -30,7 +30,7 @@ import {
createBus, createBus,
deleteBus, deleteBus,
renameBus, renameBus,
} from "../../../core/Operations/busOperations"; } from "../../../core/Operations/busOps";
export const BusesColumnSpec: ColumnSpec[] = [ export const BusesColumnSpec: ColumnSpec[] = [
{ {

@ -12,7 +12,7 @@ import {
changeParameter, changeParameter,
changeTimeHorizon, changeTimeHorizon,
changeTimeStep, changeTimeStep,
} from "../../../core/Operations/parameterOperations"; } from "../../../core/Operations/parameterOps";
interface ParametersProps { interface ParametersProps {
scenario: UnitCommitmentScenario; scenario: UnitCommitmentScenario;

@ -23,7 +23,11 @@ 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"; import {
createProfiledUnit,
deleteGenerator,
} from "../../../core/Operations/generatorOps";
import { ValidationError } from "../../../core/Validation/validate";
interface ProfiledUnitsProps { interface ProfiledUnitsProps {
scenario: UnitCommitmentScenario; scenario: UnitCommitmentScenario;
@ -108,6 +112,12 @@ const ProfiledUnitsComponent = (props: ProfiledUnitsProps) => {
props.onDataChanged(newScenario); props.onDataChanged(newScenario);
}; };
const onDelete = (name: string): ValidationError | null => {
const newScenario = deleteGenerator(name, props.scenario);
props.onDataChanged(newScenario);
return null;
};
return ( return (
<div> <div>
<SectionHeader title="Profiled Units"> <SectionHeader title="Profiled Units">
@ -120,9 +130,7 @@ const ProfiledUnitsComponent = (props: ProfiledUnitsProps) => {
<SectionButton icon={faUpload} tooltip="Upload" onClick={onUpload} /> <SectionButton icon={faUpload} tooltip="Upload" onClick={onUpload} />
</SectionHeader> </SectionHeader>
<DataTable <DataTable
onRowDeleted={() => { onRowDeleted={onDelete}
return null;
}}
onRowRenamed={() => { onRowRenamed={() => {
return null; return null;
}} }}

@ -4,12 +4,7 @@
* 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 { import { changeBusData, createBus, deleteBus, renameBus } from "./busOps";
changeBusData,
createBus,
deleteBus,
renameBus,
} from "./busOperations";
import assert from "node:assert"; import assert from "node:assert";
import { TEST_DATA_1 } from "../fixtures.test"; import { TEST_DATA_1 } from "../fixtures.test";
@ -65,5 +60,5 @@ test("renameBus", () => {
test("renameBus with duplicated name", () => { test("renameBus with duplicated name", () => {
let [, err] = renameBus("b3", "b1", 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, `b1 already exists`);
}); });

@ -4,19 +4,10 @@
* 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 { Buses, UnitCommitmentScenario } from "../fixtures"; import { UnitCommitmentScenario } from "../fixtures";
import { ValidationError } from "../Validation/validate"; import { ValidationError } from "../Validation/validate";
import { generateTimeslots } from "../../components/Common/Forms/DataTable"; import { generateTimeslots } from "../../components/Common/Forms/DataTable";
import { generateUniqueName, renameItemInObject } from "./commonOps";
export const generateUniqueName = (container: any, prefix: string): string => {
let counter = 1;
let name = `${prefix}${counter}`;
while (name in container) {
counter++;
name = `${prefix}${counter}`;
}
return name;
};
export const createBus = (scenario: UnitCommitmentScenario) => { export const createBus = (scenario: UnitCommitmentScenario) => {
const name = generateUniqueName(scenario.Buses, "b"); const name = generateUniqueName(scenario.Buses, "b");
@ -72,10 +63,7 @@ export const changeBusData = (
export const deleteBus = (bus: string, scenario: UnitCommitmentScenario) => { export const deleteBus = (bus: string, scenario: UnitCommitmentScenario) => {
const { [bus]: _, ...newBuses } = scenario.Buses; const { [bus]: _, ...newBuses } = scenario.Buses;
return { return { ...scenario, Buses: newBuses };
...scenario,
Buses: newBuses,
};
}; };
export const renameBus = ( export const renameBus = (
@ -83,22 +71,7 @@ export const renameBus = (
newName: string, newName: string,
scenario: UnitCommitmentScenario, scenario: UnitCommitmentScenario,
): [UnitCommitmentScenario, ValidationError | null] => { ): [UnitCommitmentScenario, ValidationError | null] => {
if (newName in scenario.Buses) { const [newBuses, err] = renameItemInObject(oldName, newName, scenario.Buses);
return [scenario, { message: `Bus ${newName} already exists` }]; if (err) return [scenario, err];
} return [{ ...scenario, Buses: newBuses }, null];
const newBuses: Buses = Object.keys(scenario.Buses).reduce((acc, val) => {
if (val === oldName) {
acc[newName] = scenario.Buses[val]!;
} else {
acc[val] = scenario.Buses[val]!;
}
return acc;
}, {} as Buses);
return [
{
...scenario,
Buses: newBuses,
},
null,
];
}; };

@ -0,0 +1,39 @@
/*
* 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 { ValidationError } from "../Validation/validate";
export const renameItemInObject = <T>(
oldName: string,
newName: string,
container: { [key: string]: T },
): [{ [key: string]: T }, ValidationError | null] => {
if (newName in container) {
return [container, { message: `${newName} already exists` }];
}
const newContainer = Object.keys(container).reduce(
(acc, val) => {
if (val === oldName) {
acc[newName] = container[val]!;
} else {
acc[val] = container[val]!;
}
return acc;
},
{} as { [key: string]: T },
);
return [newContainer, null];
};
export const generateUniqueName = (container: any, prefix: string): string => {
let counter = 1;
let name = `${prefix}${counter}`;
while (name in container) {
counter++;
name = `${prefix}${counter}`;
}
return name;
};

@ -0,0 +1,81 @@
/*
* 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,
deleteGenerator,
renameGenerator,
} from "./generatorOps";
test("createProfiledUnit", () => {
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)": 120,
"Maximum power (MW)": [50, 50, 50, 50, 50],
"Minimum power (MW)": [0, 0, 0, 0, 0],
},
pu3: {
Bus: "b1",
Type: "Profiled",
"Cost ($/MW)": 0,
"Maximum power (MW)": [0, 0, 0, 0, 0],
"Minimum power (MW)": [0, 0, 0, 0, 0],
},
});
});
test("createProfiledUnit with blank file", () => {
const [_, err] = createProfiledUnit(TEST_DATA_BLANK);
assert(err !== null);
assert.equal(err.message, "Profiled unit requires an existing bus.");
});
test("deleteGenerator", () => {
const newScenario = deleteGenerator("pu1", TEST_DATA_1);
assert.deepEqual(newScenario.Generators, {
pu2: {
Bus: "b1",
Type: "Profiled",
"Cost ($/MW)": 120,
"Maximum power (MW)": [50, 50, 50, 50, 50],
"Minimum power (MW)": [0, 0, 0, 0, 0],
},
});
});
test("renameGenerator", () => {
const [newScenario, err] = renameGenerator("pu1", "pu5", TEST_DATA_1);
assert(err === null);
assert.deepEqual(newScenario.Generators, {
pu5: {
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)": 120,
"Maximum power (MW)": [50, 50, 50, 50, 50],
"Minimum power (MW)": [0, 0, 0, 0, 0],
},
});
});

@ -6,8 +6,8 @@
import { UnitCommitmentScenario } from "../fixtures"; import { UnitCommitmentScenario } from "../fixtures";
import { generateTimeslots } from "../../components/Common/Forms/DataTable"; import { generateTimeslots } from "../../components/Common/Forms/DataTable";
import { generateUniqueName } from "./busOperations";
import { ValidationError } from "../Validation/validate"; import { ValidationError } from "../Validation/validate";
import { generateUniqueName, renameItemInObject } from "./commonOps";
export const createProfiledUnit = ( export const createProfiledUnit = (
scenario: UnitCommitmentScenario, scenario: UnitCommitmentScenario,
@ -35,3 +35,25 @@ export const createProfiledUnit = (
null, null,
]; ];
}; };
export const deleteGenerator = (
name: string,
scenario: UnitCommitmentScenario,
): UnitCommitmentScenario => {
const { [name]: _, ...newGenerators } = scenario.Generators;
return { ...scenario, Generators: newGenerators };
};
export const renameGenerator = (
oldName: string,
newName: string,
scenario: UnitCommitmentScenario,
): [UnitCommitmentScenario, ValidationError | null] => {
const [newGen, err] = renameItemInObject(
oldName,
newName,
scenario.Generators,
);
if (err) return [scenario, err];
return [{ ...scenario, Generators: newGen }, null];
};

@ -8,7 +8,7 @@ import {
changeTimeHorizon, changeTimeHorizon,
changeTimeStep, changeTimeStep,
evaluatePwlFunction, evaluatePwlFunction,
} from "./parameterOperations"; } from "./parameterOps";
import assert from "node:assert"; import assert from "node:assert";
import { TEST_DATA_1, TEST_DATA_2 } from "../fixtures.test"; import { TEST_DATA_1, TEST_DATA_2 } from "../fixtures.test";
@ -31,18 +31,16 @@ test("changeTimeHorizon: Shrink 1", () => {
test("changeTimeHorizon: Shrink 2", () => { test("changeTimeHorizon: Shrink 2", () => {
const [newScenario, err] = changeTimeHorizon(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: { Version: "0.4",
Version: "0.4", "Power balance penalty ($/MW)": 1000.0,
"Power balance penalty ($/MW)": 1000.0, "Time horizon (h)": 1,
"Time horizon (h)": 1, "Time step (min)": 30,
"Time step (min)": 30, });
}, assert.deepEqual(newScenario.Buses, {
Buses: { b1: { "Load (MW)": [30, 30] },
b1: { "Load (MW)": [30, 30] }, b2: { "Load (MW)": [10, 20] },
b2: { "Load (MW)": [10, 20] }, b3: { "Load (MW)": [0, 30] },
b3: { "Load (MW)": [0, 30] },
},
}); });
}); });
@ -91,34 +89,30 @@ test("evaluatePwlFunction", () => {
test("changeTimeStep", () => { test("changeTimeStep", () => {
let [scenario, err] = changeTimeStep(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: { Version: "0.4",
Version: "0.4", "Power balance penalty ($/MW)": 1000.0,
"Power balance penalty ($/MW)": 1000.0, "Time horizon (h)": 2,
"Time horizon (h)": 2, "Time step (min)": 15,
"Time step (min)": 15, });
}, assert.deepEqual(scenario.Buses, {
Buses: { b1: { "Load (MW)": [30, 30, 30, 30, 30, 30, 30, 30] },
b1: { "Load (MW)": [30, 30, 30, 30, 30, 30, 30, 30] }, b2: { "Load (MW)": [10, 15, 20, 25, 30, 35, 40, 25] },
b2: { "Load (MW)": [10, 15, 20, 25, 30, 35, 40, 25] }, b3: { "Load (MW)": [0, 15, 30, 15, 0, 20, 40, 20] },
b3: { "Load (MW)": [0, 15, 30, 15, 0, 20, 40, 20] },
},
}); });
[scenario, err] = changeTimeStep(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: { Version: "0.4",
Version: "0.4", "Power balance penalty ($/MW)": 1000.0,
"Power balance penalty ($/MW)": 1000.0, "Time horizon (h)": 2,
"Time horizon (h)": 2, "Time step (min)": 60,
"Time step (min)": 60, });
}, assert.deepEqual(scenario.Buses, {
Buses: { b1: { "Load (MW)": [30, 30] },
b1: { "Load (MW)": [30, 30] }, b2: { "Load (MW)": [10, 30] },
b2: { "Load (MW)": [10, 30] }, b3: { "Load (MW)": [0, 0] },
b3: { "Load (MW)": [0, 0] },
},
}); });
}); });

@ -1,36 +0,0 @@
/*
* 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.");
});

@ -20,6 +20,13 @@ export const TEST_DATA_1: UnitCommitmentScenario = {
"Maximum power (MW)": [10, 12, 13, 15, 20], "Maximum power (MW)": [10, 12, 13, 15, 20],
"Minimum power (MW)": [0, 0, 0, 0, 0], "Minimum power (MW)": [0, 0, 0, 0, 0],
}, },
pu2: {
Bus: "b1",
Type: "Profiled",
"Cost ($/MW)": 120,
"Maximum power (MW)": [50, 50, 50, 50, 50],
"Minimum power (MW)": [0, 0, 0, 0, 0],
},
}, },
}; };
@ -35,6 +42,7 @@ export const TEST_DATA_2: UnitCommitmentScenario = {
b2: { "Load (MW)": [10, 20, 30, 40] }, b2: { "Load (MW)": [10, 20, 30, 40] },
b3: { "Load (MW)": [0, 30, 0, 40] }, b3: { "Load (MW)": [0, 30, 0, 40] },
}, },
Generators: {},
}; };
export const TEST_DATA_BLANK: UnitCommitmentScenario = { export const TEST_DATA_BLANK: UnitCommitmentScenario = {

@ -28,7 +28,7 @@ export interface UnitCommitmentScenario {
"Time step (min)": number; "Time step (min)": number;
}; };
Buses: Buses; Buses: Buses;
Generators?: Generators; Generators: Generators;
} }
export const BLANK_SCENARIO: UnitCommitmentScenario = { export const BLANK_SCENARIO: UnitCommitmentScenario = {

Loading…
Cancel
Save