Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions apps/class-solid/src/components/Analysis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,18 @@ import {
createUniqueId,
} from "solid-js";
import { createStore } from "solid-js/store";
import type {
Analysis,
ProfilesAnalysis,
SkewTAnalysis,
TimeseriesAnalysis,
} from "~/lib/analysis_type";
import type { Observation } from "~/lib/experiment_config";
import {
observationsForProfile,
observationsForSounding,
} from "~/lib/profiles";
import {
type Analysis,
type ProfilesAnalysis,
type SkewTAnalysis,
type TimeseriesAnalysis,
deleteAnalysis,
experiments,
updateAnalysis,
} from "~/lib/store";
import { deleteAnalysis, experiments, updateAnalysis } from "~/lib/store";
import { MdiCamera, MdiDelete, MdiImageFilterCenterFocus } from "./icons";
import { AxisBottom, AxisLeft, getNiceAxisLimits } from "./plots/Axes";
import { Chart, ChartContainer, type ChartData } from "./plots/ChartContainer";
Expand Down
87 changes: 87 additions & 0 deletions apps/class-solid/src/lib/analysis_type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { ajv } from "@classmodel/class/validate";
import { type DefinedError, type JSONSchemaType, ValidationError } from "ajv";

export interface BaseAnalysis {
id: string;
description: string;
type: string;
name: string;
}

export type TimeseriesAnalysis = BaseAnalysis & {
xVariable: string;
yVariable: string;
};

export type ProfilesAnalysis = BaseAnalysis & {
variable: string;
time: number;
};

export type SkewTAnalysis = BaseAnalysis & {
time: number;
};

export type Analysis = TimeseriesAnalysis | ProfilesAnalysis | SkewTAnalysis;
export const analysisNames = [
"Vertical profiles",
"Timeseries",
"Thermodynamic diagram",
];

export function parseAnalysis(raw: unknown): Analysis {
const schema = {
oneOf: [
{
type: "object",
required: [
"id",
"description",
"type",
"name",
"xVariable",
"yVariable",
],
properties: {
id: { type: "string" },
description: { type: "string" },
type: { const: "timeseries" },
name: { type: "string" },
xVariable: { type: "string" },
yVariable: { type: "string" },
},
additionalProperties: false,
},
{
type: "object",
required: ["id", "description", "type", "name", "variable", "time"],
properties: {
id: { type: "string" },
description: { type: "string" },
type: { const: "profiles" },
name: { type: "string" },
variable: { type: "string" },
time: { type: "number" },
},
additionalProperties: false,
},
{
type: "object",
required: ["id", "description", "type", "name", "time"],
properties: {
id: { type: "string" },
description: { type: "string" },
type: { const: "skewT" },
name: { type: "string" },
time: { type: "number" },
},
additionalProperties: false,
},
],
} as unknown as JSONSchemaType<Analysis>;
const validate = ajv.compile(schema);
if (!validate(raw)) {
throw new ValidationError(validate.errors as DefinedError[]);
}
return raw;
}
14 changes: 12 additions & 2 deletions apps/class-solid/src/lib/encode.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { pruneConfig } from "@classmodel/class/config_utils";
import { unwrap } from "solid-js/store";
import { parseAnalysis } from "./analysis_type";
import type { Analysis } from "./analysis_type";
import {
type ExperimentConfig,
type PartialExperimentConfig,
parseExperimentConfig,
} from "./experiment_config";
import { findPresetByName } from "./presets";
import type { Analysis, Experiment } from "./store";
import type { Experiment } from "./store";

export function decodeAppState(encoded: string): [Experiment[], Analysis[]] {
const decoded = decodeURI(encoded);
Expand All @@ -28,8 +30,14 @@ export function decodeAppState(encoded: string): [Experiment[], Analysis[]] {
} else {
console.error("No experiments found in ", encoded);
}

const analyses: Analysis[] = [];
if (typeof parsed === "object" && Array.isArray(parsed.analyses)) {
for (const analysisRaw of parsed.analyses) {
const analysis = parseAnalysis(analysisRaw);
analyses.push(analysis);
}
}

return [experiments, analyses];
}

Expand All @@ -38,8 +46,10 @@ export function encodeAppState(
analyses: Analysis[],
) {
const rawExperiments = unwrap(experiments);
const rawAnalyses = unwrap(analyses);
const minimizedState = {
experiments: rawExperiments.map((exp) => toPartial(exp.config)),
analyses: rawAnalyses,
};
return encodeURI(JSON.stringify(minimizedState, undefined, 0));
}
Expand Down
8 changes: 7 additions & 1 deletion apps/class-solid/src/lib/profiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,15 @@ export function observationsForProfile(obs: Observation, variable = "theta") {
return { y: h, x: u };
case "v":
return { y: h, x: v };
case "rh":
return { y: h, x: rh };
case "T":
return { y: h, x: T };
case "p":
return { y: h, x: p };
default:
console.warn(
"Unknown variable '${variable}' for observation profile.",
`Unknown variable '${variable}' for observation profile.`,
);
return { y: Number.NaN, x: Number.NaN };
}
Expand Down
38 changes: 7 additions & 31 deletions apps/class-solid/src/lib/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import {
mergeConfigurations,
pruneConfig,
} from "@classmodel/class/config_utils";
import type {
Analysis,
ProfilesAnalysis,
SkewTAnalysis,
TimeseriesAnalysis,
} from "./analysis_type";
import { decodeAppState } from "./encode";
import { parseExperimentConfig } from "./experiment_config";
import type { ExperimentConfig } from "./experiment_config";
Expand Down Expand Up @@ -233,41 +239,11 @@ export function swapPermutationAndReferenceConfiguration(

export async function loadStateFromString(rawState: string): Promise<void> {
const [loadedExperiments, loadedAnalyses] = decodeAppState(rawState);
setAnalyses(loadedAnalyses);
setExperiments(loadedExperiments);
await Promise.all(loadedExperiments.map((_, i) => runExperiment(i)));
}

export interface Analysis {
id: string;
description: string;
type: string;
name: string;
}

export type TimeseriesAnalysis = Analysis & {
xVariable: string;
yVariable: string;
};

export type ProfilesAnalysis = Analysis & {
variable: string;
time: number;
};

export type SkewTAnalysis = Analysis & {
time: number;
};

export type AnalysisType =
| TimeseriesAnalysis
| ProfilesAnalysis
| SkewTAnalysis;
export const analysisNames = [
"Vertical profiles",
"Timeseries",
"Thermodynamic diagram",
];

export function addAnalysis(name: string) {
let newAnalysis: Analysis;

Expand Down
3 changes: 2 additions & 1 deletion apps/class-solid/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import { Flex } from "~/components/ui/flex";
import { Toaster } from "~/components/ui/toast";
import { onPageLoad } from "~/lib/state";

import { addAnalysis, analysisNames, experiments } from "~/lib/store";
import { analysisNames } from "~/lib/analysis_type";
import { addAnalysis, experiments } from "~/lib/store";
import { analyses } from "~/lib/store";

export default function Home() {
Expand Down