diff --git a/app/server/src/controllers/appsController.ts b/app/server/src/controllers/appsController.ts index 7d15c58c4..c34d1a426 100644 --- a/app/server/src/controllers/appsController.ts +++ b/app/server/src/controllers/appsController.ts @@ -42,7 +42,7 @@ export class AppsController { loadSessionId: sessionId || "", shareNotFound: shareNotFound || "", mathjaxSrc: "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js", - enableI18n: wodinConfig.enableI18n ?? true, // if option not set then true by default + enableI18n: wodinConfig.enableI18n ?? false, // if option not set then false by default defaultLanguage: wodinConfig?.defaultLanguage || "en" }; res.render("app", viewOptions); diff --git a/app/server/tests/controllers/appsController.test.ts b/app/server/tests/controllers/appsController.test.ts index 3b85f9af2..0c27d2012 100644 --- a/app/server/tests/controllers/appsController.test.ts +++ b/app/server/tests/controllers/appsController.test.ts @@ -82,7 +82,7 @@ describe("appsController", () => { shareNotFound: "", mathjaxSrc, defaultLanguage: "en", - enableI18n: true + enableI18n: false }); expect(mockStatus).not.toBeCalled(); }); @@ -104,7 +104,7 @@ describe("appsController", () => { shareNotFound: "", mathjaxSrc, defaultLanguage: "en", - enableI18n: true + enableI18n: false }); }); @@ -130,7 +130,7 @@ describe("appsController", () => { shareNotFound: "", mathjaxSrc, defaultLanguage: "en", - enableI18n: true + enableI18n: false }); }); @@ -154,7 +154,7 @@ describe("appsController", () => { shareNotFound: "tiny-mouse", mathjaxSrc, defaultLanguage: "en", - enableI18n: true + enableI18n: false }); }); diff --git a/app/static/src/app/components/options/EditParamSettings.vue b/app/static/src/app/components/options/EditParamSettings.vue index 2890f276f..3c5818423 100644 --- a/app/static/src/app/components/options/EditParamSettings.vue +++ b/app/static/src/app/components/options/EditParamSettings.vue @@ -101,7 +101,9 @@ - + diff --git a/app/static/src/app/components/options/SensitivityParamValues.vue b/app/static/src/app/components/options/SensitivityParamValues.vue index 77cae371c..cd7e2e58c 100644 --- a/app/static/src/app/components/options/SensitivityParamValues.vue +++ b/app/static/src/app/components/options/SensitivityParamValues.vue @@ -17,13 +17,21 @@ export default defineComponent({ batchPars: { type: Object as PropType, required: false + }, + paramName: { + type: String, + required: false } }, components: { VueFeather }, setup(props) { - const paramValues = computed(() => props.batchPars?.values || []); + const paramValues = computed(() => { + const varyingPar = props.batchPars?.varying.filter((v) => v.name === props.paramName); + return varyingPar?.length ? varyingPar[0].values : []; + }); + const valuesText = computed(() => { const formatValue = format(".3f"); const { length } = paramValues.value; diff --git a/app/static/src/app/components/sensitivity/SensitivitySummaryPlot.vue b/app/static/src/app/components/sensitivity/SensitivitySummaryPlot.vue index 7330f6663..b61744ba8 100644 --- a/app/static/src/app/components/sensitivity/SensitivitySummaryPlot.vue +++ b/app/static/src/app/components/sensitivity/SensitivitySummaryPlot.vue @@ -18,11 +18,11 @@ import { import { AxisType, newPlot, Plots } from "plotly.js-basic-dist-min"; import { useStore } from "vuex"; import { - config, fadePlotStyle, filterSeriesSet, margin, odinToPlotly, updatePlotTraceName + config, fadePlotStyle, filterUserTypeSeriesSet, margin, odinToPlotly, updatePlotTraceName } from "../../plot"; import { SensitivityPlotExtremePrefix, SensitivityPlotType, SensitivityScaleType } from "../../store/sensitivity/state"; import { SensitivityMutation } from "../../store/sensitivity/mutations"; -import { Batch, OdinSeriesSet } from "../../types/responseTypes"; +import { Batch, OdinUserTypeSeriesSet } from "../../types/responseTypes"; import { runPlaceholderMessage } from "../../utils"; import { RunGetter } from "../../store/run/getters"; import { Dict } from "../../types/utilTypes"; @@ -91,8 +91,9 @@ export default defineComponent({ const plotData = computed(() => { if (batch.value) { - let data: null | OdinSeriesSet; - const paramSetData: Dict = {}; + const paramName = store.state.sensitivity.paramSettings.parameterToVary; + let data: null | OdinUserTypeSeriesSet; + const paramSetData: Dict = {}; if (plotSettings.value.plotType === SensitivityPlotType.ValueAtTime) { verifyValidPlotSettingsTime(store.state, store.commit); data = batch.value.valueAtTime(plotSettings.value.time); @@ -110,7 +111,7 @@ export default defineComponent({ }); } - const filtered = filterSeriesSet(data!, selectedVariables.value); + const filtered = filterUserTypeSeriesSet(data!, paramName, selectedVariables.value); const result = [...odinToPlotly(filtered, palette.value, { includeLegendGroup: true })]; Object.keys(paramSetData).forEach((name: string) => { const dash = lineStylesForParamSets.value[name]; @@ -121,7 +122,7 @@ export default defineComponent({ dash }; const psData = paramSetData[name]; - const psFiltered = filterSeriesSet(psData, selectedVariables.value); + const psFiltered = filterUserTypeSeriesSet(psData, paramName, selectedVariables.value); const psPlotData = odinToPlotly(psFiltered, palette.value, options); const currentParamSet = parameterSets.value.find((paramSet) => paramSet.name === name); psPlotData.forEach((plotTrace) => { diff --git a/app/static/src/app/components/sensitivity/SensitivityTracesPlot.vue b/app/static/src/app/components/sensitivity/SensitivityTracesPlot.vue index 4d290ff42..97af3a13d 100644 --- a/app/static/src/app/components/sensitivity/SensitivityTracesPlot.vue +++ b/app/static/src/app/components/sensitivity/SensitivityTracesPlot.vue @@ -25,7 +25,7 @@ import { } from "../../plot"; import { Batch, - DiscreteSeriesValues, OdinSeriesSet, OdinSolution + DiscreteSeriesValues, OdinSeriesSet, OdinSolution, VaryingPar } from "../../types/responseTypes"; import { AppType } from "../../store/appState/state"; import { runPlaceholderMessage } from "../../utils"; @@ -52,6 +52,7 @@ export default defineComponent({ const parameterSetDisplayNames = computed(() => { return parameterSets.value.map((paramSet) => paramSet.displayName); }); + const paramSettings = computed(() => store.state.sensitivity.paramSettings); const parameterSetBatches = computed(() => { const result = {} as Dict; @@ -88,6 +89,9 @@ export default defineComponent({ const time = { mode: "grid" as const, tStart: start, tEnd: end, nPoints: points }; + const varyingParamName = paramSettings.value.parameterToVary; + const varyingPar = pars.varying.filter((v: VaryingPar) => v.name === varyingParamName); + const parValues = varyingPar.length ? varyingPar[0].values : []; const addSolutionOutputToResult = ( solution: OdinSolution, @@ -120,7 +124,7 @@ export default defineComponent({ showLegend: false }; addSolutionOutputToResult(sln, plotlyOptions, - (plotTrace) => updatePlotTraceName(plotTrace, pars.name, pars.values[slnIdx])); + (plotTrace) => updatePlotTraceName(plotTrace, varyingParamName, parValues[slnIdx])); }); if (centralSolution.value) { @@ -151,8 +155,8 @@ export default defineComponent({ addSolutionOutputToResult(sln, plotlyOptions, (plotTrace) => updatePlotTraceName( plotTrace, - pars.name, - pars.values[slnIdx], + varyingParamName, + parValues[slnIdx], currentParamSet!.displayName )); }); diff --git a/app/static/src/app/excel/wodinSensitivitySummaryDownload.ts b/app/static/src/app/excel/wodinSensitivitySummaryDownload.ts index 138f9c473..53c9fd366 100644 --- a/app/static/src/app/excel/wodinSensitivitySummaryDownload.ts +++ b/app/static/src/app/excel/wodinSensitivitySummaryDownload.ts @@ -1,7 +1,7 @@ import * as XLSX from "xlsx"; import { WodinExcelDownload } from "./wodinExcelDownload"; import { SensitivityPlotExtreme, SensitivityPlotExtremePrefix } from "../store/sensitivity/state"; -import { OdinSeriesSet } from "../types/responseTypes"; +import { OdinUserType, OdinUserTypeSeriesSet } from "../types/responseTypes"; interface ExtremeSummarySheetSettings { name: string, @@ -16,10 +16,12 @@ const extremeSummarySheets: ExtremeSummarySheetSettings[] = [ { name: "TimeAtMax", extremePrefix: SensitivityPlotExtremePrefix.time, extreme: SensitivityPlotExtreme.Max } ]; export class WodinSensitivitySummaryDownload extends WodinExcelDownload { - private _addSummarySheetFromOdinSeriesSet = (data: OdinSeriesSet, varyingParameter: string, sheetName: string) => { - const sheetData = data.x.map((x: number, index: number) => { + private _addSummarySheetFromOdinSeriesSet = (data: OdinUserTypeSeriesSet, varyingParameter: string, + sheetName: string) => { + const sheetData = data.x.map((x: OdinUserType, index: number) => { + const xValue = x[varyingParameter]; return Object.fromEntries([ - [varyingParameter, x], + [varyingParameter, xValue], ...data.values.map((v) => [v.name, v.y[index]]) ]); }); diff --git a/app/static/src/app/plot.ts b/app/static/src/app/plot.ts index 3a3256497..1da0bf249 100644 --- a/app/static/src/app/plot.ts +++ b/app/static/src/app/plot.ts @@ -3,7 +3,7 @@ import { format } from "d3-format"; import { Palette, paletteData } from "./palette"; import type { AllFitData, FitData, FitDataLink } from "./store/fitData/state"; import { - DiscreteSeriesSet, OdinSeriesSet, OdinSeriesSetValues + DiscreteSeriesSet, OdinSeriesSet, OdinSeriesSetValues, OdinUserTypeSeriesSet } from "./types/responseTypes"; import { Dict } from "./types/utilTypes"; @@ -22,6 +22,15 @@ export const config = { responsive: true }; +export function filterUserTypeSeriesSet(s: OdinUserTypeSeriesSet, param: string, names: string[]): OdinSeriesSet { + const values = s.values.filter((v) => names.includes(v.name)); + const xValues = s.x.map((x) => x[param]); + return { + x: xValues, + values + }; +} + export function filterSeriesSet(s: OdinSeriesSet, names: string[]): OdinSeriesSet { const values = s.values.filter((v) => names.includes(v.name)); return { diff --git a/app/static/src/app/types/responseTypes.ts b/app/static/src/app/types/responseTypes.ts index b906c57c8..767973f15 100644 --- a/app/static/src/app/types/responseTypes.ts +++ b/app/static/src/app/types/responseTypes.ts @@ -83,6 +83,13 @@ export interface OdinModelResponse{ error?: OdinModelResponseError } +// This is strictly a little more restrictive than what odin supports, +// but wodin does not support fancy user variables yet and we can sort +// that out later (odin allows the union of number, number[], and a +// tensor type - the latter two will be a challenge to expose nicely +// in the interface). +export type OdinUserType = Dict; + // This is Odin's SeriesSetValues and SeriesSet export interface OdinSeriesSetValues { description?: string; @@ -95,6 +102,11 @@ export type OdinSeriesSet = { values: OdinSeriesSetValues[]; } +export type OdinUserTypeSeriesSet = { + x: OdinUserType[], + values: OdinSeriesSetValues[] +} + export interface TimeGrid { mode: "grid"; tStart: number; @@ -117,13 +129,6 @@ export interface OdinFitData { value: number[] } -// This is strictly a little more restrictive than what odin supports, -// but wodin does not support fancy user variables yet and we can sort -// that out later (odin allows the union of number, number[], and a -// tensor type - the latter two will be a challenge to expose nicely -// in the interface). -export type OdinUserType = Dict; - export interface OdinFitParameters { base: OdinUserType, vary: string[] @@ -147,23 +152,29 @@ export interface Simplex { result: () => SimplexResult; } +export interface VaryingPar { + name: string, + values: number[] +} + export interface BatchPars { base: OdinUserType; - name: string; - values: number[]; + varying: VaryingPar[]; } -export interface BatchError { - value: number, - error: string +export interface OdinRunStatus { + pars: OdinUserType, + success: boolean, + error: string | null } export interface Batch { pars: BatchPars, solutions: OdinSolution[], - errors: BatchError[], - valueAtTime: (time: number) => OdinSeriesSet, - extreme: (type: string) => OdinSeriesSet, + errors: OdinRunStatus[], + successfulVaryingParams: OdinUserType[], + valueAtTime: (time: number) => OdinUserTypeSeriesSet, + extreme: (type: string) => OdinUserTypeSeriesSet, compute: () => boolean } @@ -207,13 +218,13 @@ export interface OdinRunnerOde { count: number, logarithmic: boolean, min: number, - max: number) => BatchPars; + max: number) => VaryingPar; batchParsDisplace: (base: OdinUserType, name: string, count: number, logarithmic: boolean, - displace: number) => BatchPars; + displace: number) => VaryingPar; batchRun: (odin: Odin, pars: BatchPars, tStart: number, diff --git a/app/static/src/app/utils.ts b/app/static/src/app/utils.ts index f1714fd36..7a8f5de1c 100644 --- a/app/static/src/app/utils.ts +++ b/app/static/src/app/utils.ts @@ -136,7 +136,7 @@ function generateBatchParsFromOdin( paramSettings: SensitivityParameterSettings, paramValues: OdinUserType ): GenerateBatchParsResult { - let batchPars = null; + let varyingParam = null; let errorDetail = null; // TODO: NB For now we use ode runner to generate batch pars for all app types, but expect this to change const runner = rootState.model.odinRunnerOde; @@ -147,7 +147,7 @@ function generateBatchParsFromOdin( if (variationType === SensitivityVariationType.Percentage) { try { - batchPars = runner!.batchParsDisplace( + varyingParam = runner!.batchParsDisplace( paramValues, parameterToVary!, numberOfRuns, logarithmic, variationPercentage @@ -157,7 +157,7 @@ function generateBatchParsFromOdin( } } else { try { - batchPars = runner!.batchParsRange( + varyingParam = runner!.batchParsRange( paramValues, parameterToVary!, numberOfRuns, @@ -171,6 +171,7 @@ function generateBatchParsFromOdin( } const error = errorDetail ? { error: userMessages.sensitivity.invalidSettings, detail: errorDetail } : null; + const batchPars = errorDetail ? null : { base: paramValues!, varying: [varyingParam!] }; return { batchPars, error @@ -198,8 +199,10 @@ export function generateBatchPars( if (paramSettings.variationType === SensitivityVariationType.Custom) { const batchPars: BatchPars = { base: paramValues!, - name: paramSettings.parameterToVary!, - values: paramSettings.customValues + varying: [{ + name: paramSettings.parameterToVary!, + values: paramSettings.customValues + }] }; return { batchPars, diff --git a/app/static/tests/e2e/tabs.etest.ts b/app/static/tests/e2e/tabs.etest.ts index c067e1611..446345342 100644 --- a/app/static/tests/e2e/tabs.etest.ts +++ b/app/static/tests/e2e/tabs.etest.ts @@ -9,8 +9,7 @@ test.describe("Wodin App tabs tests", () => { expect(await page.innerText("nav a.navbar-brand")).toBe("WODIN Example"); expect(await page.getAttribute("nav a.navbar-brand", "href")).toBe("http://localhost:3000"); expect(await page.innerText("nav .navbar-app")).toBe("Day 1 - Basic Model"); - expect(await page.innerText("nav .navbar-version >> nth=1")).toMatch(/^WODIN v[0-9].[0-9].[0-9]$/); - expect(await page.innerText("nav span .navbar-text >> nth=0")).toBe("English"); + expect(await page.innerText("nav .navbar-version >> nth=0")).toMatch(/^WODIN v[0-9].[0-9].[0-9]$/); }); test("link in header navigates to index page", async ({ page }) => { @@ -59,12 +58,4 @@ test.describe("Wodin App tabs tests", () => { await expect(await page.innerText(".wodin-right .wodin-content div.mt-4 button")) .toBe("Run sensitivity"); }); - - test("can change language to French", async ({ page }) => { - const languageSwitcher = await page.locator("nav span .navbar-text >> nth=0"); - await languageSwitcher.click(); - const frenchMenuItem = await languageSwitcher.locator(".dropdown-item >> nth=1"); - await frenchMenuItem.click(); - expect(await page.innerText("nav span .navbar-text >> nth=0")).toBe("Français"); - }); }); diff --git a/app/static/tests/mocks.ts b/app/static/tests/mocks.ts index e835db58d..87e593add 100644 --- a/app/static/tests/mocks.ts +++ b/app/static/tests/mocks.ts @@ -5,7 +5,7 @@ import { FitState } from "../src/app/store/fit/state"; import { StochasticState } from "../src/app/store/stochastic/state"; import { AdvancedOptions, - BatchPars, OdinUserType, ResponseFailure, ResponseSuccess, WodinError + BatchPars, OdinUserType, ResponseFailure, ResponseSuccess, VaryingPar, WodinError } from "../src/app/types/responseTypes"; import { ModelState } from "../src/app/store/model/state"; import { AdvancedComponentType, RunState } from "../src/app/store/run/state"; @@ -298,7 +298,7 @@ export const mockStochasticState = (state: Partial = {}): Stoch export const mockBatchParsRange = (base: OdinUserType, name: string, count: number, logarithmic: boolean, - min: number, max: number): BatchPars => { + min: number, max: number): VaryingPar => { if (count < 2) { throw new Error("Mock error: count must be 2 or more"); } @@ -317,12 +317,12 @@ export const mockBatchParsRange = (base: OdinUserType, name: string, count: numb current += d; i += 1; } - return { base, name, values }; + return { name, values }; }; export const mockBatchParsDisplace = (base: OdinUserType, name: string, count: number, logarithmic: boolean, - displace: number): BatchPars => { + displace: number): VaryingPar => { const paramValue = base[name]!; const max = paramValue * (1 + (displace / 100)); const min = paramValue * (1 - (displace / 100)); diff --git a/app/static/tests/unit/components/options/editParamSettings.test.ts b/app/static/tests/unit/components/options/editParamSettings.test.ts index 306cb1d82..2a3046816 100644 --- a/app/static/tests/unit/components/options/editParamSettings.test.ts +++ b/app/static/tests/unit/components/options/editParamSettings.test.ts @@ -256,8 +256,9 @@ describe("EditParamSettings", () => { const rangeSpy = jest.spyOn(mockRunner, "batchParsRange"); const wrapper = await getWrapper(percentSettings); const sensitivityValues = wrapper.findComponent(SensitivityParamValues); - expectCloseNumericArray(sensitivityValues.props("batchPars").values, [1.8, 1.9, 2, 2.1, 2.2]); - expect(sensitivityValues.props("batchPars").name).toBe("B"); + const { values, name } = sensitivityValues.props("batchPars").varying[0]; + expectCloseNumericArray(values, [1.8, 1.9, 2, 2.1, 2.2]); + expect(name).toBe("B"); expect(percentSpy).toHaveBeenCalledTimes(1); expect(percentSpy.mock.calls[0][0]).toStrictEqual(parameterValues); expect(percentSpy.mock.calls[0][1]).toBe("B"); @@ -268,7 +269,8 @@ describe("EditParamSettings", () => { await updateSelect(wrapper, "edit-variation-type", SensitivityVariationType.Range); await wrapper.find("#edit-from").findComponent(NumericInput).vm.$emit("update", 1); await wrapper.find("#edit-to").findComponent(NumericInput).vm.$emit("update", 3); - expectCloseNumericArray(sensitivityValues.props("batchPars").values, [1, 1.5, 2, 2.5, 3]); + const updatedValues = sensitivityValues.props("batchPars").varying[0].values; + expectCloseNumericArray(updatedValues, [1, 1.5, 2, 2.5, 3]); expect(rangeSpy).toHaveBeenCalledTimes(3); // called on each update expect(rangeSpy.mock.calls[2][0]).toStrictEqual(parameterValues); expect(rangeSpy.mock.calls[2][1]).toBe("B"); diff --git a/app/static/tests/unit/components/options/sensitivityOptions.test.ts b/app/static/tests/unit/components/options/sensitivityOptions.test.ts index 1e9a1ded7..0e42bc724 100644 --- a/app/static/tests/unit/components/options/sensitivityOptions.test.ts +++ b/app/static/tests/unit/components/options/sensitivityOptions.test.ts @@ -22,8 +22,10 @@ const mockTooltipDirective = jest.fn(); describe("SensitivityOptions", () => { const mockBatchPars = { - values: [1, 2, 3], - name: "A" + varying: [{ + name: "B", + values: [1, 2, 3] + }] } as any; const mockMultiBatchPars = [ diff --git a/app/static/tests/unit/components/options/sensitivityParamValues.test.ts b/app/static/tests/unit/components/options/sensitivityParamValues.test.ts index 6480502b9..2b5482e8e 100644 --- a/app/static/tests/unit/components/options/sensitivityParamValues.test.ts +++ b/app/static/tests/unit/components/options/sensitivityParamValues.test.ts @@ -4,8 +4,14 @@ import SensitivityParamValues from "../../../../src/app/components/options/Sensi describe("SensitivityParamValues", () => { const getWrapper = (values: number[]) => { - const batchPars = { values }; - return mount(SensitivityParamValues, { props: { batchPars } }); + const paramName = "beta"; + const batchPars = { + varying: [{ + name: paramName, + values + }] + }; + return mount(SensitivityParamValues, { props: { batchPars, paramName } }); }; it("renders up to three values as expected", () => { diff --git a/app/static/tests/unit/components/sensitivity/sensitivitySummaryPlot.test.ts b/app/static/tests/unit/components/sensitivity/sensitivitySummaryPlot.test.ts index d676091ca..58468e006 100644 --- a/app/static/tests/unit/components/sensitivity/sensitivitySummaryPlot.test.ts +++ b/app/static/tests/unit/components/sensitivity/sensitivitySummaryPlot.test.ts @@ -39,7 +39,7 @@ describe("SensitivitySummaryPlot", () => { const mockSetLoading = jest.fn(); const mockData = { - x: [1, 1.1], + x: [{ beta: 1 }, { beta: 1.1 }], values: [ { name: "S", y: [10, 10.1] }, { name: "I", y: [20, 19.9] }, @@ -48,7 +48,7 @@ describe("SensitivitySummaryPlot", () => { }; const mockDataSet1 = { - x: [10, 10.1], + x: [{ beta: 10 }, { beta: 10.1 }], values: [ { name: "S", y: [100, 100.1] }, { name: "I", y: [200, 190.9] }, @@ -57,7 +57,7 @@ describe("SensitivitySummaryPlot", () => { }; const mockDataSet2 = { - x: [20, 20.1], + x: [{ beta: 20 }, { beta: 20.1 }], values: [ { name: "S", y: [101, 101.1] }, { name: "I", y: [201, 191.9] }, @@ -66,7 +66,7 @@ describe("SensitivitySummaryPlot", () => { }; const mockDataSet3 = { - x: [30, 30.1], + x: [{ beta: 30 }, { beta: 30.1 }], values: [ { name: "S", y: [102, 102.1] }, { name: "I", y: [202, 192.9] }, diff --git a/app/static/tests/unit/components/sensitivity/sensitivityTracesPlot.test.ts b/app/static/tests/unit/components/sensitivity/sensitivityTracesPlot.test.ts index 9c34c1bd8..f1901ef7c 100644 --- a/app/static/tests/unit/components/sensitivity/sensitivityTracesPlot.test.ts +++ b/app/static/tests/unit/components/sensitivity/sensitivityTracesPlot.test.ts @@ -431,13 +431,18 @@ describe("SensitivityTracesPlot", () => { sensitivity: { namespaced: true, state: { + paramSettings: { + parameterToVary: "alpha" + }, result: { batch: { solutions: sensitivityHasSolutions ? mockSolutions : null, allFitData: sensitivityHasData ? mockAllFitData : undefined, pars: { - name: "alpha", - values: [1.11111, 2.22222] + varying: [{ + name: "alpha", + values: [1.11111, 2.22222] + }] } } }, diff --git a/app/static/tests/unit/excel/wodinSensitivitySummaryDownload.test.ts b/app/static/tests/unit/excel/wodinSensitivitySummaryDownload.test.ts index 3e2fb44c1..b8e779e93 100644 --- a/app/static/tests/unit/excel/wodinSensitivitySummaryDownload.test.ts +++ b/app/static/tests/unit/excel/wodinSensitivitySummaryDownload.test.ts @@ -2,7 +2,11 @@ import { mockBookNew, mockBookAppendSheet, mockWriteFile } from "./mocks"; import { mockBasicState, mockRunState, mockSensitivityState } from "../../mocks"; import { WodinSensitivitySummaryDownload } from "../../../src/app/excel/wodinSensitivitySummaryDownload"; -const xValues = [1, 1.1, 1.2]; +const xValues = [ + { beta: 1 }, + { beta: 1.1 }, + { beta: 1.2 } +]; const mockBatch = { valueAtTime: jest.fn().mockImplementation(() => { return { diff --git a/app/static/tests/unit/serialiser.test.ts b/app/static/tests/unit/serialiser.test.ts index 806bbd5d5..c5203e92e 100644 --- a/app/static/tests/unit/serialiser.test.ts +++ b/app/static/tests/unit/serialiser.test.ts @@ -135,14 +135,18 @@ describe("serialise", () => { const sensitivityBatchPars = { base: { alpha: 1, beta: 1.1 }, - name: "alpha", - values: [0.5, 0.75, 1, 1.25, 1.5] + varying: [{ + name: "alpha", + values: [0.5, 0.75, 1, 1.25, 1.5] + }] }; const sensitivityParamSetBatchPars = { base: { alpha: 2, beta: 3.3 }, - name: "alpha", - values: [1.5, 1.75, 2, 2.25, 2.5] + varying: [{ + name: "alpha", + values: [1.5, 1.75, 2, 2.25, 2.5] + }] }; const sensitivityState = { running: true, @@ -180,6 +184,7 @@ describe("serialise", () => { pars: sensitivityBatchPars, solutions: [jest.fn(), jest.fn()], errors: [], + successfulVaryingParams: [], valueAtTime: jest.fn(), extreme: jest.fn(), compute: jest.fn() @@ -196,6 +201,7 @@ describe("serialise", () => { pars: sensitivityParamSetBatchPars, solutions: [jest.fn(), jest.fn()], errors: [], + successfulVaryingParams: [], valueAtTime: jest.fn(), extreme: jest.fn(), compute: jest.fn() diff --git a/app/static/tests/unit/store/sensitivity/getters.test.ts b/app/static/tests/unit/store/sensitivity/getters.test.ts index 6edc0af48..f462bfe7d 100644 --- a/app/static/tests/unit/store/sensitivity/getters.test.ts +++ b/app/static/tests/unit/store/sensitivity/getters.test.ts @@ -34,8 +34,9 @@ describe("Sensitivity getters", () => { const mockSpy = jest.spyOn(odinRunnerOde, "batchParsDisplace"); const result = getters[SensitivityGetter.batchPars](state, getters, rootState, {} as any); - expect(result.values).toStrictEqual([1, 2, 3]); - expect(result.name).toBe("A"); + expect(result.varying).toStrictEqual([ + { name: "A", values: [1, 2, 3] } + ]); expect(result.base).toBe(parameterValues); expect(mockSpy).toHaveBeenCalledTimes(1); }); @@ -66,12 +67,16 @@ describe("Sensitivity getters", () => { const result = getters[SensitivityGetter.parameterSetBatchPars](state, getters, rootState, {} as any); expect(Object.keys(result)).toStrictEqual(["Set 1", "Set 2"]); const pars1 = result["Set 1"]; - expect(pars1.values).toStrictEqual([0.5, 1, 1.5]); - expect(pars1.name).toBe("A"); + expect(pars1.varying).toStrictEqual([{ + name: "A", + values: [0.5, 1, 1.5] + }]); expect(pars1.base).toStrictEqual({ A: 1 }); const pars2 = result["Set 2"]; - expect(pars2.values).toStrictEqual([2, 4, 6]); - expect(pars2.name).toBe("A"); + expect(pars2.varying).toStrictEqual([{ + name: "A", + values: [2, 4, 6] + }]); expect(pars2.base).toStrictEqual({ A: 4 }); expect(mockSpy).toHaveBeenCalledTimes(2); }); diff --git a/app/static/tests/unit/utils.test.ts b/app/static/tests/unit/utils.test.ts index edec27d85..727731a35 100644 --- a/app/static/tests/unit/utils.test.ts +++ b/app/static/tests/unit/utils.test.ts @@ -359,9 +359,11 @@ describe("generateBatchPars", () => { it("generates BatchPars for Percentage variation type", () => { const result = generateBatchPars(rootState, percentSettings, parameterValues)!; expect(result.error).toBe(null); - expect(result.batchPars!.name).toBe("A"); expect(result.batchPars!.base).toBe(parameterValues); - expect(result.batchPars!.values).toStrictEqual([0.5, 0.75, 1, 1.25, 1.5]); + expect(result.batchPars!.varying).toStrictEqual([{ + name: "A", + values: [0.5, 0.75, 1, 1.25, 1.5] + }]); expect(spyBatchParsDisplace).toHaveBeenCalledTimes(1); expect(spyBatchParsDisplace.mock.calls[0][0]).toStrictEqual(parameterValues); @@ -374,9 +376,11 @@ describe("generateBatchPars", () => { it("generates BatchPars for Range variation type", () => { const result = generateBatchPars(rootState, rangeSettings, parameterValues)!; expect(result.error).toBe(null); - expect(result.batchPars!.name).toBe("B"); expect(result.batchPars!.base).toBe(parameterValues); - expect(result.batchPars!.values).toStrictEqual([2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6]); + expect(result.batchPars!.varying).toStrictEqual([{ + name: "B", + values: [2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6] + }]); expect(spyBatchParsRange).toHaveBeenCalledTimes(1); expect(spyBatchParsRange.mock.calls[0][0]).toStrictEqual(parameterValues); expect(spyBatchParsRange.mock.calls[0][1]).toStrictEqual("B"); @@ -389,9 +393,11 @@ describe("generateBatchPars", () => { it("generates BatchPars for Custom variation type", () => { const result = generateBatchPars(rootState, customSettings, parameterValues)!; expect(result.error).toBe(null); - expect(result.batchPars!.name).toBe("C"); expect(result.batchPars!.base).toBe(parameterValues); - expect(result.batchPars!.values).toStrictEqual([1, 2, 3]); + expect(result.batchPars!.varying).toStrictEqual([{ + name: "C", + values: [1, 2, 3] + }]); expect(spyBatchParsDisplace).not.toHaveBeenCalled(); expect(spyBatchParsRange).not.toHaveBeenCalled(); }); diff --git a/config/wodin.config.json b/config/wodin.config.json index 320255026..35c22f9a7 100644 --- a/config/wodin.config.json +++ b/config/wodin.config.json @@ -6,6 +6,6 @@ "baseUrl": "http://localhost:3000", "odinApi": "http://localhost:8001", "redisUrl": "redis://localhost:6379", - "enableI18n": true, + "enableI18n": false, "defaultLanguage": "en" }