web: ThermalUnits: onDataChanged

web
Alinson S. Xavier 3 months ago
parent 3bf028577e
commit eb3d39b1ab

@ -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,

Loading…
Cancel
Save