Skip to content
Open
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
25 changes: 14 additions & 11 deletions packages/frontend/src/stdlib/analyses.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { DiagramAnalysisMeta, ModelAnalysisMeta } from "../theory";
import * as GraphLayoutConfig from "../visualization/graph_layout_config";
import type * as Checkers from "./analyses/checker_types";
import { defaultSchemaERDConfig, type SchemaERDConfig } from "./analyses/schema_erd_config";
import type { AnalysisId } from "./analyses/simulation_config";
import type {
DecapodesAnalysisContent,
KuramotoProblemData,
Expand All @@ -28,6 +29,8 @@ type AnalysisOptions = {
help?: string;
};

type SimulationAnalysisOptions = Omit<Partial<AnalysisOptions>, "id"> & { id: AnalysisId };

export const decapodes = (
options: AnalysisOptions,
): DiagramAnalysisMeta<DecapodesAnalysisContent> => ({
Expand Down Expand Up @@ -66,7 +69,7 @@ export const tabularView = (
const TabularView = lazy(() => import("./analyses/tabular_view"));

export function kuramoto(
options: Partial<AnalysisOptions> & {
options: SimulationAnalysisOptions & {
parameterLabels?: {
coupling?: string;
damping?: string;
Expand All @@ -75,7 +78,7 @@ export function kuramoto(
},
): ModelAnalysisMeta<KuramotoProblemData> {
const {
id = "kuramoto",
id,
name = "Kuramoto dynamics",
description = "Simulate the system using the Kuramoto dynamical model",
help = "kuramoto",
Expand Down Expand Up @@ -110,10 +113,10 @@ export function kuramoto(
const Kuramoto = lazy(() => import("./analyses/kuramoto"));

export function linearODE(
options: Partial<AnalysisOptions> = {},
options: SimulationAnalysisOptions,
): ModelAnalysisMeta<LinearODEProblemData> {
const {
id = "linear-ode",
id,
name = "Linear ODE dynamics",
description = "Simulate the system using a constant-coefficient linear first-order ODE",
help = "linear-ode",
Expand All @@ -135,10 +138,10 @@ export function linearODE(
const LinearODE = lazy(() => import("./analyses/linear_ode"));

export function lotkaVolterra(
options: Partial<AnalysisOptions> = {},
options: SimulationAnalysisOptions,
): ModelAnalysisMeta<LotkaVolterraProblemData> {
const {
id = "lotka-volterra",
id,
name = "Lotka-Volterra dynamics",
description = "Simulate the system using a Lotka-Volterra ODE",
help = "lotka-volterra",
Expand All @@ -161,14 +164,14 @@ export function lotkaVolterra(
const LotkaVolterra = lazy(() => import("./analyses/lotka_volterra"));

export function massAction(
options: Partial<AnalysisOptions> & {
options: SimulationAnalysisOptions & {
ratesHaveGranularity: boolean;
stateType?: ObType;
transitionType?: MorType;
},
): ModelAnalysisMeta<MassActionProblemData> {
const {
id = "mass-action",
id,
name = "Mass-action dynamics",
description = "Simulate the system using the law of mass action",
help = "mass-action",
Expand Down Expand Up @@ -226,13 +229,13 @@ export function massActionEquations(
const MassActionEquationsDisplay = lazy(() => import("./analyses/mass_action_equations"));

export function stochasticMassAction(
options: Partial<AnalysisOptions> & {
options: SimulationAnalysisOptions & {
stateType?: ObType;
transitionType?: MorType;
} = {},
},
): ModelAnalysisMeta<StochasticMassActionProblemData> {
const {
id = "stochastic-mass-action",
id,
name = "Stochastic mass-action dynamics",
description = "Simulate the system using stochastic mass-action dynamics",
help = "stochastic-mass-action",
Expand Down
3 changes: 2 additions & 1 deletion packages/frontend/src/stdlib/analyses/kuramoto.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ import type { ModelAnalysisProps } from "../../analysis";
import { morLabelOrDefault } from "../../model";
import { ODEResultPlot } from "../../visualization";
import { createModelODEPlot } from "./model_ode_plot";
import type { AnalysisId } from "./simulation_config";

import "./simulation.css";

/** Analyse a model using first- or second-order Kuramoto dynamics. */
export default function Kuramoto(
props: ModelAnalysisProps<KuramotoProblemData> & {
analysisId: string;
analysisId: AnalysisId;
title?: string;
couplingLabel?: string;
dampingLabel?: string;
Expand Down
3 changes: 2 additions & 1 deletion packages/frontend/src/stdlib/analyses/linear_ode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import type { ModelAnalysisProps } from "../../analysis";
import { morLabelOrDefault } from "../../model";
import { ODEResultPlot } from "../../visualization";
import { createModelODEPlot } from "./model_ode_plot";
import type { AnalysisId } from "./simulation_config";

import "./simulation.css";

/** Analyze a model using LinearODE dynamics. */
export default function LinearODE(
props: ModelAnalysisProps<LinearODEProblemData> & {
analysisId: string;
analysisId: AnalysisId;
title?: string;
},
) {
Expand Down
3 changes: 2 additions & 1 deletion packages/frontend/src/stdlib/analyses/lotka_volterra.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import type { ModelAnalysisProps } from "../../analysis";
import { morLabelOrDefault } from "../../model";
import { ODEResultPlot } from "../../visualization";
import { createModelODEPlot } from "./model_ode_plot";
import type { AnalysisId } from "./simulation_config";

import "./simulation.css";

/** Analyze a model using Lotka-Volterra dynamics. */
export default function LotkaVolterra(
props: ModelAnalysisProps<LotkaVolterraProblemData> & {
analysisId: string;
analysisId: AnalysisId;
title?: string;
},
) {
Expand Down
3 changes: 2 additions & 1 deletion packages/frontend/src/stdlib/analyses/mass_action.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ import { morLabelOrDefault } from "../../model";
import { ODEResultPlot } from "../../visualization";
import { MassActionConfigForm } from "./mass_action_config_form";
import { createModelODEPlotWithEquations } from "./model_ode_plot";
import type { AnalysisId } from "./simulation_config";

import "./simulation.css";

/** Analyze a model using mass-action dynamics. */
export default function MassAction(
props: ModelAnalysisProps<MassActionProblemData> & {
analysisId: string;
analysisId: AnalysisId;
ratesHaveGranularity: boolean;
stateType?: ObType;
title?: string;
Expand Down
7 changes: 4 additions & 3 deletions packages/frontend/src/stdlib/analyses/model_ode_plot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { DblModel, JsResult, LatexEquation, ModelNotebook, ODELatex } from
import type { LiveModelDoc, ValidatedModel } from "../../model";
import { debounce } from "../../util/debounce";
import type { ODEPlotData, StateVarData } from "../../visualization";
import type { AnalysisId } from "./simulation_config";
import type {
SerializedODESolution,
SimulationRequest,
Expand Down Expand Up @@ -115,7 +116,7 @@ function serializedSolutionToPlotData(
/** Internal helper that both `createModelODEPlot` and `createModelODEPlotWithEquations` delegate to. */
function createWorkerSimulation<T>(
liveModel: LiveModelDoc,
analysisId: string,
analysisId: AnalysisId,
params: Accessor<unknown>,
mapOk: (response: SimulationResponse & { tag: "Ok" }, model: DblModel) => T,
mapErr: (error: string) => T,
Expand Down Expand Up @@ -206,7 +207,7 @@ rapid parameter changes.
*/
export function createModelODEPlot(
liveModel: LiveModelDoc,
analysisId: string,
analysisId: AnalysisId,
params: Accessor<unknown>,
): ODEPlotResult {
return createWorkerSimulation<JsResult<ODEPlotData, string>>(
Expand All @@ -227,7 +228,7 @@ Returns both plot data and LaTeX equations.
*/
export function createModelODEPlotWithEquations(
liveModel: LiveModelDoc,
analysisId: string,
analysisId: AnalysisId,
params: Accessor<unknown>,
): ODEPlotResultWithEquations {
return createWorkerSimulation<ODEPlotDataWithEquations>(
Expand Down
7 changes: 5 additions & 2 deletions packages/frontend/src/stdlib/analyses/simulation_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const theoryClassCtors: Record<string, () => object> = {
};

/** Analysis ID -> dispatch function. Independent of theory. */
export const analysisDispatches: Record<string, AnalysisDispatch> = {
export const analysisDispatches = {
"mass-action": (th, model, params) => ({
hasEquations: true,
result: th.massAction(model, params),
Expand All @@ -49,4 +49,7 @@ export const analysisDispatches: Record<string, AnalysisDispatch> = {
hasEquations: false,
result: th.kuramoto(model, params),
}),
};
} satisfies Record<string, AnalysisDispatch>;

/** Union type of all valid simulation analysis IDs. */
export type AnalysisId = keyof typeof analysisDispatches;
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { LatexEquation, ModelNotebook } from "catlog-wasm";
import type { AnalysisId } from "./simulation_config";

/** Request sent from the main thread to the simulation worker. */
export type SimulationRequest = {
requestId: number;
theoryId: string;
analysisId: string;
analysisId: AnalysisId;
notebook: ModelNotebook;
refId: string;
params: unknown;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ import type { ModelAnalysisProps } from "../../analysis";
import { morLabelOrDefault } from "../../model";
import { ODEResultPlot } from "../../visualization";
import { createModelODEPlot } from "./model_ode_plot";
import type { AnalysisId } from "./simulation_config";

import "./simulation.css";

/** Analyze a model using stochastic mass-action dynamics. */
export default function StochasticMassAction(
props: ModelAnalysisProps<StochasticMassActionProblemData> & {
analysisId: string;
analysisId: AnalysisId;
stateType?: ObType;
transitionType?: MorType;
title?: string;
Expand Down
4 changes: 2 additions & 2 deletions packages/frontend/src/stdlib/theories/causal-loop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ export default function createCausalLoopTheory(theoryMeta: TheoryMeta): Theory {
return thSignedCategory.positiveLoops(model, options);
},
}),
analyses.linearODE(),
analyses.lotkaVolterra(),
analyses.linearODE({ id: "linear-ode" }),
analyses.lotkaVolterra({ id: "lotka-volterra" }),
],
});
}
1 change: 1 addition & 0 deletions packages/frontend/src/stdlib/theories/petri-net.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default function createPetriNetTheory(theoryMeta: TheoryMeta): Theory {
help: "visualization",
}),
analyses.massAction({
id: "mass-action",
ratesHaveGranularity: true,
}),
analyses.massActionEquations({
Expand Down
1 change: 1 addition & 0 deletions packages/frontend/src/stdlib/theories/power-system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export default function createPowerSystemsTheory(theoryMeta: TheoryMeta): Theory
help: "visualization",
}),
analyses.kuramoto({
id: "kuramoto",
parameterLabels: {
coupling: "Capacity",
forcing: "Input power",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export default function createPrimitiveSignedStockFlowTheory(theoryMeta: TheoryM
help: "visualization",
}),
analyses.massAction({
id: "mass-action",
ratesHaveGranularity: false,
transitionType: {
tag: "Hom",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export default function createPrimitiveStockFlowTheory(theoryMeta: TheoryMeta):
help: "visualization",
}),
analyses.massAction({
id: "mass-action",
ratesHaveGranularity: false,
transitionType: {
tag: "Hom",
Expand Down
4 changes: 2 additions & 2 deletions packages/frontend/src/stdlib/theories/reg-net.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ export default function createRegulatoryNetworkTheory(theoryMeta: TheoryMeta): T
return thSignedCategory.negativeLoops(model, options);
},
}),
analyses.linearODE(),
analyses.lotkaVolterra(),
analyses.linearODE({ id: "linear-ode" }),
analyses.lotkaVolterra({ id: "lotka-volterra" }),
],
});
}
Loading