/ proof-of-concept / plate-dynamics-lab-2
Sign in
proof-of-concept / plate-dynamics-lab-2
plate-dynamics-lab-2 / packages / components / src / status / RunStatus.tsx
156 lines · 5.6 KBBlameHistoryRaw
1import type { BackendInfo, MethodDefinition, PlateResult } from "@plate-dyn/core";
3export type StagedStatus =
4 | { status: "idle" }
5 | { status: "running"; stage: "modes" | "strike" | "script"; startedAt: number; output: string[] }
6 | {
7 status: "done";
8 output: string[];
9 wallMs: number;
10 /** Wall time of the modes stage in this run, or null when the modes were reused */
11 modesMs: number | null;
12 strikeMs: number;
13 backend: BackendInfo;
14 }
15 | {
16 status: "error";
17 error: string;
18 output: string[];
19 wallMs: number;
20 backend: BackendInfo;
21 cancelled?: boolean;
22 };
24export interface RunStatusProps {
25 state: StagedStatus;
26 result?: PlateResult | null;
27 method?: MethodDefinition;
28 backend?: BackendInfo | null;
29 /** Predicted wall times for the next run [ms], shown while idle */
30 estimate?: { modesMs: number | null; strikeMs: number };
31 onCancel?: () => void;
34/** Makes the execution visible: what ran, where, how big it was and how long it took. */
35export function RunStatus({ state, result, method, backend, estimate, onCancel }: RunStatusProps) {
36 const be = state.status === "done" || state.status === "error" ? state.backend : backend;
37 return (
38 <div className="pl-status">
39 <div className="pl-row">
40 {state.status === "idle" && <span className="pl-badge pl-badge-info">ready</span>}
41 {state.status === "running" && (
42 <>
43 <span className="pl-badge pl-badge-info">
44 {state.stage === "modes"
45 ? "solving the modes"
46 : state.stage === "strike"
47 ? "striking"
48 : "running the script"}
49 </span>
50 {onCancel && (
51 <button className="pl-btn pl-btn-danger" onClick={onCancel}>
52 Cancel
53 </button>
54 )}
55 </>
56 )}
57 {state.status === "done" && <span className="pl-badge pl-badge-ok">finished</span>}
58 {state.status === "error" && (
59 <span className="pl-badge pl-badge-error">{state.cancelled ? "cancelled" : "error"}</span>
60 )}
61 {method && <span className="pl-muted">{method.name}</span>}
62 </div>
63 {state.status === "running" && (
64 <div className="pl-progress">
65 <div />
66 </div>
67 )}
68 {state.status === "error" && <div className="pl-error">{state.error}</div>}
69 <table>
70 <tbody>
71 <tr>
72 <td>Backend</td>
73 <td>
74 {be
75 ? `${be.engine} ${be.version}, ${be.optimization === "1" ? "JS JIT (opt 1)" : "interpreter (opt 0)"}, ${be.host === "web-worker" ? "Web Worker in this browser" : "Node.js"}, double precision`
76 : "numbl (not yet started)"}
77 </td>
78 </tr>
79 <tr>
80 <td>Wall time</td>
81 <td>
82 {state.status === "done" ? (
83 <>
84 {fmtMs(state.wallMs)} in total:{" "}
85 {state.modesMs === null
86 ? "the modes were kept from an earlier run"
87 : `${fmtMs(state.modesMs)} for the modes`}
88 , {fmtMs(state.strikeMs)} for the strike and the synthesis
89 </>
90 ) : state.status === "running" ? (
91 "…"
92 ) : estimate ? (
93 `about ${estimate.modesMs === null ? "" : `${fmtMs(estimate.modesMs)} for the modes and `}${fmtMs(estimate.strikeMs)} for the strike expected`
94 ) : (
95 "–"
96 )}
97 </td>
98 </tr>
99 {result && (
100 <tr>
101 <td>Problem size</td>
102 <td>
103 {result.info.size_note}; {result.info.nmodes} modes kept ({result.info.n_audible}{" "}
104 audible below {(result.info.f_max / 1000).toFixed(1)} kHz
105 {result.info.n_rigid > 0 ? `, ${result.info.n_rigid} rigid-body` : ""}),{" "}
106 {result.info.nsamples.toLocaleString()} samples at {result.info.fs} Hz,{" "}
107 {result.frames.t.length} frames
108 </td>
109 </tr>
110 )}
111 {result && (
112 <tr>
113 <td>Inside the solver</td>
114 <td>
115 {fmtMs(result.info.modes_wall_s * 1000)} for the modes (by tic/toc, when they were
116 computed), {fmtMs(result.info.strike_wall_s * 1000)} for the strike
117 {result.info.extra.eig_iterations !== undefined
118 ? `; eigensolver ${result.info.extra.eig_iterations} iterations`
119 : ""}
120 </td>
121 </tr>
122 )}
123 </tbody>
124 </table>
125 {result && result.info.notes.length > 0 && (
126 <div>
127 {result.info.notes.map((n, i) => (
128 <div className="pl-note" key={i}>
129 {n}
130 </div>
131 ))}
132 </div>
133 )}
134 {(state.status === "running" || state.status === "done" || state.status === "error") &&
135 state.output.length > 0 && (
136 <details>
137 <summary className="pl-small pl-muted">
138 Script output ({state.output.length} lines)
139 </summary>
140 <div className="pl-log">{state.output.join("")}</div>
141 </details>
142 )}
143 </div>
144 );
147export function fmtMs(ms: number): string {
148 if (ms < 1000) return `${ms.toFixed(0)} ms`;
149 return `${(ms / 1000).toFixed(2)} s`;
152export function fmtTime(s: number): string {
153 if (s >= 1) return `${s.toPrecision(3)} s`;
154 if (s >= 1e-3) return `${(s * 1e3).toPrecision(3)} ms`;
155 return `${(s * 1e6).toPrecision(3)} µs`;
↑↓ move↵openescclose