Skip to content

Commit eee403d

Browse files
committed
Update class output structure
1 parent 7da9999 commit eee403d

File tree

9 files changed

+63
-38
lines changed

9 files changed

+63
-38
lines changed

apps/class-solid/src/components/Analysis.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Config } from "@classmodel/class/config";
22
import { calculatePlume, transposePlumeData } from "@classmodel/class/fire";
33
import {
4-
type ClassOutput,
4+
type ClassTimeSeries,
55
type OutputVariableKey,
66
getOutputAtTime,
77
outputVariables,
@@ -78,7 +78,7 @@ interface FlatExperiment {
7878
color: string;
7979
linestyle: string;
8080
config: Config;
81-
output?: ClassOutput;
81+
output?: ClassTimeSeries;
8282
}
8383

8484
// Create a derived store for looping over all outputs:
@@ -322,8 +322,7 @@ export function VerticalProfilePlot({
322322
...observations().flatMap((obs) => obs.data.map((d) => d.y)),
323323
];
324324

325-
// TODO: better to include jump at top in extent calculation rather than adding random margin.
326-
const xLim = () => getNiceAxisLimits(allX(), 1);
325+
const xLim = () => getNiceAxisLimits(allX(), 0);
327326
const yLim = () => [0, getNiceAxisLimits(allY(), 0)[1]] as [number, number];
328327

329328
function chartData() {

apps/class-solid/src/lib/download.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import type { ClassOutput, OutputVariableKey } from "@classmodel/class/output";
1+
import type {
2+
ClassTimeSeries,
3+
OutputVariableKey,
4+
} from "@classmodel/class/output";
25
import { BlobReader, BlobWriter, ZipWriter } from "@zip.js/zip.js";
36
import { toPartial } from "./encode";
47
import type { ExperimentConfig } from "./experiment_config";
@@ -11,7 +14,7 @@ export function toConfigBlob(experiment: ExperimentConfig) {
1114
});
1215
}
1316

14-
function outputToCsv(output: ClassOutput) {
17+
function outputToCsv(output: ClassTimeSeries) {
1518
const headers = Object.keys(output) as OutputVariableKey[];
1619
const lines = [headers.join(",")];
1720
for (let i = 0; i < output[headers[0]].length; i++) {

apps/class-solid/src/lib/runner.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { Config } from "@classmodel/class/config";
2-
import type { ClassOutput } from "@classmodel/class/output";
3-
import type { runClass } from "@classmodel/class/runner";
2+
import type { ClassData, runClass } from "@classmodel/class/runner";
43
import { wrap } from "comlink";
54

65
const worker = new Worker(new URL("./worker.ts", import.meta.url), {
@@ -9,7 +8,7 @@ const worker = new Worker(new URL("./worker.ts", import.meta.url), {
98

109
const asyncRunner = wrap<typeof runClass>(worker);
1110

12-
export async function runClassAsync(config: Config): Promise<ClassOutput> {
11+
export async function runClassAsync(config: Config): Promise<ClassData> {
1312
try {
1413
const output = asyncRunner(config);
1514
return output;

apps/class-solid/src/lib/store.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,22 @@ import { createUniqueId } from "solid-js";
22
import { createStore, produce, unwrap } from "solid-js/store";
33

44
import type { Config } from "@classmodel/class/config";
5-
import type { ClassOutput } from "@classmodel/class/output";
65

76
import {
87
mergeConfigurations,
98
pruneConfig,
109
} from "@classmodel/class/config_utils";
10+
11+
import type { ClassData } from "@classmodel/class/runner";
1112
import { decodeAppState } from "./encode";
1213
import { parseExperimentConfig } from "./experiment_config";
1314
import type { ExperimentConfig } from "./experiment_config";
1415
import { findPresetByName } from "./presets";
1516
import { runClassAsync } from "./runner";
1617

1718
interface ExperimentOutput {
18-
reference?: ClassOutput;
19-
permutations: Array<ClassOutput | undefined>;
19+
reference?: ClassData;
20+
permutations: Array<ClassData | undefined>;
2021
running: number | false;
2122
}
2223

packages/class/src/cli.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { readFile, writeFile } from "node:fs/promises";
77
import { EOL } from "node:os";
88
import { Command, Option } from "@commander-js/extra-typings";
99
import { jsonSchemaOfConfig } from "./config.js";
10-
import type { ClassOutput, OutputVariableKey } from "./output.js";
10+
import type { ClassTimeSeries, OutputVariableKey } from "./output.js";
1111
import { runClass } from "./runner.js";
1212
import { parse } from "./validate.js";
1313

@@ -51,7 +51,7 @@ async function writeTextFile(body: string, fn: string): Promise<void> {
5151
/**
5252
* Create a DSV (delimiter-separated values) string from an object of arrays.
5353
*/
54-
function dsv(output: ClassOutput, delimiter: string): string {
54+
function dsv(output: ClassTimeSeries, delimiter: string): string {
5555
const keys = Object.keys(output) as OutputVariableKey[];
5656
// order of headers is now in which they were added to the object
5757
// TODO make configurable: which columns and in which order
@@ -67,7 +67,7 @@ function dsv(output: ClassOutput, delimiter: string): string {
6767
/**
6868
* Format the output.
6969
*/
70-
function formatOutput(output: ClassOutput, format: string): string {
70+
function formatOutput(output: ClassTimeSeries, format: string): string {
7171
switch (format) {
7272
case "json":
7373
return JSON.stringify(output, null, 2);

packages/class/src/fire.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ export interface Parcel {
6262
rh: number; // Relative humidity [%]
6363
}
6464

65+
export type FirePlume = Parcel[];
66+
6567
/**
6668
* Initialize fire parcel with ambient conditions and fire properties
6769
*/
@@ -144,7 +146,7 @@ export function calculatePlume(
144146
fire: FireConfig,
145147
bg: ClassProfile,
146148
plumeConfig: PlumeConfig = defaultPlumeConfig,
147-
): Parcel[] {
149+
): FirePlume {
148150
const { dz } = plumeConfig;
149151
let parcel = initializeFireParcel(bg, fire);
150152
const plume: Parcel[] = [parcel];

packages/class/src/output.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,4 @@ export const outputVariables = {
118118
} as const satisfies Record<string, VariableInfo>;
119119

120120
export type OutputVariableKey = keyof typeof outputVariables;
121-
export type ClassOutput = Record<OutputVariableKey, number[]>;
122-
export type ClassOutputAtSingleTime = Record<OutputVariableKey, number>;
123-
124-
export function getOutputAtTime(
125-
output: ClassOutput,
126-
timeIndex: number,
127-
): ClassOutputAtSingleTime {
128-
return Object.fromEntries(
129-
Object.entries(output).map(([key, values]) => [key, values[timeIndex]]),
130-
) as ClassOutputAtSingleTime;
131-
}
121+
export type ClassOutput = Record<OutputVariableKey, number>;

packages/class/src/profiles.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// profiles.ts
22

33
import type { MixedLayerConfig, NoWindConfig, WindConfig } from "./config.js";
4-
import type { ClassOutputAtSingleTime } from "./output.js";
4+
import type { ClassOutput } from "./output.js";
55
import {
66
dewpoint,
77
qsatLiq,
@@ -55,7 +55,7 @@ export const NoProfile: ClassProfile = {
5555
*/
5656
export function generateProfiles(
5757
config: MixedLayerConfig & (WindConfig | NoWindConfig),
58-
output: ClassOutputAtSingleTime,
58+
output: ClassOutput,
5959
dz = 1,
6060
): ClassProfile {
6161
const { Rd, cp, g } = CONSTANTS;

packages/class/src/runner.ts

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,38 +5,62 @@
55
*/
66
import { CLASS } from "./class.js";
77
import type { Config } from "./config.js";
8+
import { type FirePlume, calculatePlume } from "./fire.js";
89
import {
910
type ClassOutput,
1011
type OutputVariableKey,
1112
outputVariables,
1213
} from "./output.js";
14+
import { type ClassProfile, generateProfiles } from "./profiles.js";
1315
import { parse } from "./validate.js";
1416

17+
type ClassTimeSeries = Record<OutputVariableKey, number[]>;
18+
type ClassProfiles = ClassProfile[];
19+
type ClassFirePlumes = FirePlume[];
20+
export type ClassData = [ClassTimeSeries, ClassProfiles?, ClassFirePlumes?];
21+
1522
/**
1623
* Runs the CLASS model with the given configuration and frequency.
1724
*
1825
* @param config - The configuration object for the CLASS model.
1926
* @param freq - The frequency in seconds at which to write output, defaults to 600.
2027
* @returns An object containing the output variables collected during the simulation.
2128
*/
22-
export function runClass(config: Config, freq = 600): ClassOutput {
29+
export function runClass(config: Config, freq = 600): ClassData {
2330
const validatedConfig = parse(config);
2431
const model = new CLASS(validatedConfig);
2532

26-
const output_keys = Object.keys(outputVariables) as OutputVariableKey[];
33+
const outputKeys = Object.keys(outputVariables) as OutputVariableKey[];
2734

2835
const writeOutput = () => {
29-
for (const key of output_keys) {
36+
const output: Partial<ClassOutput> = {};
37+
for (const key of outputKeys) {
3038
const value = model.getValue(key);
3139
if (value !== undefined) {
32-
(output[key] as number[]).push(value as number);
40+
output[key] = model.getValue(key);
41+
timeSeries[key].push(value as number);
42+
}
43+
44+
// Include profiles
45+
if (config.sw_ml) {
46+
const profile = generateProfiles(config, output as ClassOutput);
47+
profiles.push(profile);
48+
49+
// Include fireplumes
50+
if (config.sw_fire) {
51+
const plume = calculatePlume(config, profile);
52+
firePlumes.push(plume);
53+
}
3354
}
3455
}
3556
};
3657

37-
const output = Object.fromEntries(
38-
output_keys.map((key) => [key, []]),
39-
) as unknown as ClassOutput;
58+
// Initialize output arrays
59+
const timeSeries = Object.fromEntries(
60+
outputKeys.map((key) => [key, []]),
61+
) as unknown as ClassTimeSeries;
62+
const profiles: ClassProfiles = [];
63+
const firePlumes: ClassFirePlumes = [];
4064

4165
// Initial time
4266
writeOutput();
@@ -50,5 +74,12 @@ export function runClass(config: Config, freq = 600): ClassOutput {
5074
}
5175
}
5276

53-
return output;
54-
}
77+
// Construct ClassData
78+
if (config.sw_ml) {
79+
if (config.sw_fire) {
80+
return [timeSeries, profiles, firePlumes];
81+
}
82+
return [timeSeries, profiles];
83+
}
84+
return [timeSeries];
85+
}

0 commit comments

Comments
 (0)