From 0cf93e7aa06f9fb7403241f89b1daf3e6e0bbd47 Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Tue, 20 May 2025 10:27:24 -0500 Subject: [PATCH] web: use defaults; calculate table height --- web/src/components/CaseBuilder/BusesTable.tsx | 8 +++- .../components/CaseBuilder/CaseBuilder.tsx | 10 ++++- web/src/core/Operations/preprocessing.test.ts | 39 +++++++++++++++++++ web/src/core/Operations/preprocessing.ts | 34 ++++++++++++++++ web/src/core/Validation/validate.ts | 1 + 5 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 web/src/core/Operations/preprocessing.test.ts create mode 100644 web/src/core/Operations/preprocessing.ts diff --git a/web/src/components/CaseBuilder/BusesTable.tsx b/web/src/components/CaseBuilder/BusesTable.tsx index c137dad..25cdc0e 100644 --- a/web/src/components/CaseBuilder/BusesTable.tsx +++ b/web/src/components/CaseBuilder/BusesTable.tsx @@ -152,6 +152,12 @@ interface BusesTableProps { onBusRenamed: (oldName: string, newName: string) => ValidationError | null; } +function computeBusesTableHeight(scenario: UnitCommitmentScenario): string { + const numBuses = Object.keys(scenario.Buses).length; + const height = 65 + Math.min(numBuses, 15) * 28; + return `${height}px`; +} + function BusesTable(props: BusesTableProps) { const tableContainerRef = useRef(null); @@ -188,7 +194,7 @@ function BusesTable(props: BusesTableProps) { layout: "fitColumns", data: generateBusesTableData(scenario), columns: generateBusesTableColumns(scenario), - maxHeight: "500px", + height: computeBusesTableHeight(scenario), }); table.on("cellEdited", (cell) => { onCellEdited(cell); diff --git a/web/src/components/CaseBuilder/CaseBuilder.tsx b/web/src/components/CaseBuilder/CaseBuilder.tsx index d7a48e4..dfdaa05 100644 --- a/web/src/components/CaseBuilder/CaseBuilder.tsx +++ b/web/src/components/CaseBuilder/CaseBuilder.tsx @@ -29,6 +29,7 @@ import { changeTimeHorizon, changeTimeStep, } from "../../core/Operations/parameterOperations"; +import { preprocess } from "../../core/Operations/preprocessing"; const CaseBuilder = () => { const [scenario, setScenario] = useState(TEST_SCENARIO); @@ -87,11 +88,16 @@ const CaseBuilder = () => { }; const onLoad = (scenario: UnitCommitmentScenario) => { - if (!validate(scenario)) { + const preprocessed = preprocess( + scenario, + ) as unknown as UnitCommitmentScenario; + + // Validate and assign default values + if (!validate(preprocessed)) { console.error(validate.errors); return; } - setScenario(scenario); + setScenario(preprocessed); }; const onParameterChanged = (key: string, value: string) => { diff --git a/web/src/core/Operations/preprocessing.test.ts b/web/src/core/Operations/preprocessing.test.ts new file mode 100644 index 0000000..0398491 --- /dev/null +++ b/web/src/core/Operations/preprocessing.test.ts @@ -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 assert from "node:assert"; +import { preprocess } from "./preprocessing"; + +export const PREPROCESSING_TEST_DATA_1: any = { + Parameters: { + Version: "0.4", + "Time horizon (h)": 5, + }, + Buses: { + b1: { "Load (MW)": [35.79534, 34.38835, 33.45083, 32.89729, 33.25044] }, + b2: { "Load (MW)": 10 }, + b3: { "Load (MW)": [27.3729, 26.29698, 25.58005, 25.15675, 25.4268] }, + }, +}; + +test("preprocess", () => { + const newScenario = preprocess(PREPROCESSING_TEST_DATA_1); + assert.deepEqual(newScenario, { + Parameters: { + Version: "0.4", + "Time horizon (h)": 5, + "Power balance penalty ($/MW)": 1000, + "Scenario name": "s1", + "Scenario weight": 1, + "Time step (min)": 60, + }, + Buses: { + b1: { "Load (MW)": [35.79534, 34.38835, 33.45083, 32.89729, 33.25044] }, + b2: { "Load (MW)": [10, 10, 10, 10, 10] }, + b3: { "Load (MW)": [27.3729, 26.29698, 25.58005, 25.15675, 25.4268] }, + }, + }); +}); diff --git a/web/src/core/Operations/preprocessing.ts b/web/src/core/Operations/preprocessing.ts new file mode 100644 index 0000000..ccc0a0e --- /dev/null +++ b/web/src/core/Operations/preprocessing.ts @@ -0,0 +1,34 @@ +// @ts-nocheck + +/* + * 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 { validate } from "../Validation/validate"; + +export const preprocess = (data) => { + // Make a copy of the original data + let result = JSON.parse(JSON.stringify(data)); + + // Run JSON validation and assign default values + if (!validate(result)) { + console.error(validate.errors); + throw Error("Invalid JSON"); + } + + // Expand scalars into arrays + const timeHorizon = result["Parameters"]["Time horizon (h)"]; + const timeStep = result["Parameters"]["Time step (min)"]; + const T = (timeHorizon * 60) / timeStep; + for (const busName in result["Buses"]) { + // @ts-ignore + const busData = result["Buses"][busName]; + const busLoad = busData["Load (MW)"]; + if (typeof busLoad === "number") { + busData["Load (MW)"] = Array(T).fill(busLoad); + } + } + return result; +}; diff --git a/web/src/core/Validation/validate.ts b/web/src/core/Validation/validate.ts index 89e5f69..80df10d 100644 --- a/web/src/core/Validation/validate.ts +++ b/web/src/core/Validation/validate.ts @@ -9,6 +9,7 @@ import Ajv from "ajv"; // Create Ajv instance with detailed debug options const ajv = new Ajv({ + useDefaults: true, verbose: true, allErrors: true, $data: true,