mirror of
https://github.com/ANL-CEEESA/UnitCommitment.jl.git
synced 2025-12-06 00:08:52 -06:00
web: ThermalUnits: onDataChanged
This commit is contained in:
@@ -30,6 +30,7 @@ import {
|
|||||||
import { ColumnDefinition } from "tabulator-tables";
|
import { ColumnDefinition } from "tabulator-tables";
|
||||||
import { offerDownload } from "../Common/io";
|
import { offerDownload } from "../Common/io";
|
||||||
import {
|
import {
|
||||||
|
changeThermalUnitData,
|
||||||
createThermalUnit,
|
createThermalUnit,
|
||||||
deleteGenerator,
|
deleteGenerator,
|
||||||
renameGenerator,
|
renameGenerator,
|
||||||
@@ -194,17 +195,17 @@ const ThermalUnitsComponent = (props: CaseBuilderSectionProps) => {
|
|||||||
field: string,
|
field: string,
|
||||||
newValue: string,
|
newValue: string,
|
||||||
): ValidationError | null => {
|
): ValidationError | null => {
|
||||||
// const [newScenario, err] = changeThermalUnitData(
|
const [newScenario, err] = changeThermalUnitData(
|
||||||
// name,
|
name,
|
||||||
// field,
|
field,
|
||||||
// newValue,
|
newValue,
|
||||||
// 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -350,10 +350,9 @@ const DataTable = (props: DataTableProps) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const onCellEdited = (cell: CellComponent) => {
|
const onCellEdited = (cell: CellComponent) => {
|
||||||
let newValue = cell.getValue();
|
let newValue = `${cell.getValue()}`;
|
||||||
let oldValue = cell.getOldValue();
|
let oldValue = `${cell.getOldValue()}`;
|
||||||
// eslint-disable-next-line eqeqeq
|
if (newValue === oldValue) return;
|
||||||
if (newValue == oldValue) return;
|
|
||||||
if (cell.getField() === "Name") {
|
if (cell.getField() === "Name") {
|
||||||
if (newValue === "") {
|
if (newValue === "") {
|
||||||
const err = props.onRowDeleted(oldValue);
|
const err = props.onRowDeleted(oldValue);
|
||||||
|
|||||||
@@ -108,7 +108,26 @@ export const changeNumberData = (
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const changeNumberVecData = (
|
export const changeBooleanData = (
|
||||||
|
field: string,
|
||||||
|
newValueStr: string,
|
||||||
|
container: { [key: string]: any },
|
||||||
|
): [{ [key: string]: any }, ValidationError | null] => {
|
||||||
|
// Parse value
|
||||||
|
const [newValueBool, err] = parseBool(newValueStr);
|
||||||
|
if (err) return [container, err];
|
||||||
|
|
||||||
|
// Build the new object
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
...container,
|
||||||
|
[field]: newValueBool,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const changeNumberVecTData = (
|
||||||
field: string,
|
field: string,
|
||||||
time: string,
|
time: string,
|
||||||
newValueStr: string,
|
newValueStr: string,
|
||||||
@@ -136,6 +155,43 @@ export const changeNumberVecData = (
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const changeNumberVecNData = (
|
||||||
|
field: string,
|
||||||
|
offset: string,
|
||||||
|
newValueStr: string,
|
||||||
|
container: { [key: string]: any },
|
||||||
|
): [{ [key: string]: any }, ValidationError | null] => {
|
||||||
|
const oldVec = container[field];
|
||||||
|
const newVec = [...container[field]];
|
||||||
|
const idx = parseInt(offset) - 1;
|
||||||
|
|
||||||
|
if (newValueStr === "") {
|
||||||
|
// Trim the vector
|
||||||
|
newVec.splice(idx, oldVec.length - idx);
|
||||||
|
} else {
|
||||||
|
// Parse new value
|
||||||
|
const [newValueFloat, err] = parseNumber(newValueStr);
|
||||||
|
if (err) return [container, err];
|
||||||
|
|
||||||
|
// Increase the length of the vector
|
||||||
|
if (idx >= oldVec.length) {
|
||||||
|
for (let i = oldVec.length; i < idx; i++) {
|
||||||
|
newVec[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign new value
|
||||||
|
newVec[idx] = newValueFloat;
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
...container,
|
||||||
|
[field]: newVec,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
export const changeData = (
|
export const changeData = (
|
||||||
field: string,
|
field: string,
|
||||||
newValueStr: string,
|
newValueStr: string,
|
||||||
@@ -143,9 +199,9 @@ export const changeData = (
|
|||||||
colSpecs: ColumnSpec[],
|
colSpecs: ColumnSpec[],
|
||||||
scenario: UnitCommitmentScenario,
|
scenario: UnitCommitmentScenario,
|
||||||
): [{ [key: string]: any }, ValidationError | null] => {
|
): [{ [key: string]: any }, ValidationError | null] => {
|
||||||
const match = field.match(/^([^0-9]+)(\d+:\d+)?$/);
|
const match = field.match(/^([^0-9]+)([0-9:]+)?$/);
|
||||||
const fieldName = match![1]!.trim();
|
const fieldName = match![1]!.trim();
|
||||||
const fieldTime = match![2];
|
const fieldOffset = match![2];
|
||||||
for (const spec of colSpecs) {
|
for (const spec of colSpecs) {
|
||||||
if (spec.title !== fieldName) continue;
|
if (spec.title !== fieldName) continue;
|
||||||
switch (spec.type) {
|
switch (spec.type) {
|
||||||
@@ -156,13 +212,22 @@ export const changeData = (
|
|||||||
case "number":
|
case "number":
|
||||||
return changeNumberData(fieldName, newValueStr, container);
|
return changeNumberData(fieldName, newValueStr, container);
|
||||||
case "number[T]":
|
case "number[T]":
|
||||||
return changeNumberVecData(
|
return changeNumberVecTData(
|
||||||
fieldName,
|
fieldName,
|
||||||
fieldTime!,
|
fieldOffset!,
|
||||||
newValueStr,
|
newValueStr,
|
||||||
container,
|
container,
|
||||||
scenario,
|
scenario,
|
||||||
);
|
);
|
||||||
|
case "number[N]":
|
||||||
|
return changeNumberVecNData(
|
||||||
|
fieldName,
|
||||||
|
fieldOffset!,
|
||||||
|
newValueStr,
|
||||||
|
container,
|
||||||
|
);
|
||||||
|
case "boolean":
|
||||||
|
return changeBooleanData(fieldName, newValueStr, container);
|
||||||
default:
|
default:
|
||||||
throw Error(`Unknown type: ${spec.type}`);
|
throw Error(`Unknown type: ${spec.type}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { TEST_DATA_1, TEST_DATA_BLANK } from "../fixtures.test";
|
|||||||
import assert from "node:assert";
|
import assert from "node:assert";
|
||||||
import {
|
import {
|
||||||
changeProfiledUnitData,
|
changeProfiledUnitData,
|
||||||
|
changeThermalUnitData,
|
||||||
createProfiledUnit,
|
createProfiledUnit,
|
||||||
createThermalUnit,
|
createThermalUnit,
|
||||||
deleteGenerator,
|
deleteGenerator,
|
||||||
@@ -63,6 +64,58 @@ test("changeProfiledUnitData", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("changeThermalUnitData", () => {
|
||||||
|
let scenario = TEST_DATA_1;
|
||||||
|
let err: ValidationError | null;
|
||||||
|
[scenario, err] = changeThermalUnitData(
|
||||||
|
"g1",
|
||||||
|
"Ramp up limit (MW)",
|
||||||
|
"99",
|
||||||
|
scenario,
|
||||||
|
);
|
||||||
|
assert(!err);
|
||||||
|
[scenario, err] = changeThermalUnitData(
|
||||||
|
"g1",
|
||||||
|
"Startup costs ($) 2",
|
||||||
|
"99",
|
||||||
|
scenario,
|
||||||
|
);
|
||||||
|
assert(!err);
|
||||||
|
[scenario, err] = changeThermalUnitData(
|
||||||
|
"g1",
|
||||||
|
"Production cost curve ($) 7",
|
||||||
|
"99",
|
||||||
|
scenario,
|
||||||
|
);
|
||||||
|
assert(!err);
|
||||||
|
[scenario, err] = changeThermalUnitData(
|
||||||
|
"g1",
|
||||||
|
"Production cost curve (MW) 3",
|
||||||
|
"",
|
||||||
|
scenario,
|
||||||
|
);
|
||||||
|
assert(!err);
|
||||||
|
[scenario, err] = changeThermalUnitData("g1", "Must run?", "true", scenario);
|
||||||
|
assert(!err);
|
||||||
|
assert.deepEqual(scenario.Generators["g1"], {
|
||||||
|
Bus: "b1",
|
||||||
|
Type: "Thermal",
|
||||||
|
"Production cost curve (MW)": [100.0, 110],
|
||||||
|
"Production cost curve ($)": [1400.0, 1600.0, 2200.0, 2400.0, 0, 0, 99],
|
||||||
|
"Startup costs ($)": [300.0, 99.0],
|
||||||
|
"Startup delays (h)": [1, 4],
|
||||||
|
"Ramp up limit (MW)": 99,
|
||||||
|
"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?": true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test("changeProfiledUnitData with invalid bus", () => {
|
test("changeProfiledUnitData with invalid bus", () => {
|
||||||
let scenario = TEST_DATA_1;
|
let scenario = TEST_DATA_1;
|
||||||
let err = null;
|
let err = null;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
renameItemInObject,
|
renameItemInObject,
|
||||||
} from "./commonOps";
|
} from "./commonOps";
|
||||||
import { ProfiledUnitsColumnSpec } from "../../components/CaseBuilder/ProfiledUnits";
|
import { ProfiledUnitsColumnSpec } from "../../components/CaseBuilder/ProfiledUnits";
|
||||||
|
import { ThermalUnitsColumnSpec } from "../../components/CaseBuilder/ThermalUnits";
|
||||||
|
|
||||||
const assertBusesNotEmpty = (
|
const assertBusesNotEmpty = (
|
||||||
scenario: UnitCommitmentScenario,
|
scenario: UnitCommitmentScenario,
|
||||||
@@ -109,6 +110,32 @@ export const changeProfiledUnitData = (
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const changeThermalUnitData = (
|
||||||
|
generator: string,
|
||||||
|
field: string,
|
||||||
|
newValueStr: string,
|
||||||
|
scenario: UnitCommitmentScenario,
|
||||||
|
): [UnitCommitmentScenario, ValidationError | null] => {
|
||||||
|
const [newGen, err] = changeData(
|
||||||
|
field,
|
||||||
|
newValueStr,
|
||||||
|
scenario.Generators[generator]!,
|
||||||
|
ThermalUnitsColumnSpec,
|
||||||
|
scenario,
|
||||||
|
);
|
||||||
|
if (err) return [scenario, err];
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
...scenario,
|
||||||
|
Generators: {
|
||||||
|
...scenario.Generators,
|
||||||
|
[generator]: newGen,
|
||||||
|
} as Generators,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
export const deleteGenerator = (
|
export const deleteGenerator = (
|
||||||
name: string,
|
name: string,
|
||||||
scenario: UnitCommitmentScenario,
|
scenario: UnitCommitmentScenario,
|
||||||
|
|||||||
Reference in New Issue
Block a user