1import type { MethodDefinition } from "./types";
2import { ALL_GROUPS } from "./common";
4export const FD_METHOD: MethodDefinition = {
5 id: "fd",
6 name: "Explicit finite differences",
7 shortName: "Explicit FD",
8 summary:
9 "Explicit second-order time stepping on the energy-method operators, rigid-body coordinates plus flexural field, gravity through the self-weight prestress.",
10 solverFunction: "plate_fd",
11 planFunction: "plate_fd_plan",
12 supports: {
13 shape: ["rectangle", "ellipse"],
14 mount: ["thread", "threads", "pads", "cymbal", "vise", "pinched"],
15 excitation: ["impulse", "release"],
16 },
17 readingOrder: [
18 "plate_fd.m",
19 "plate_fd_setup.m",
20 "plate_fd_loop.m",
21 "plate_fd_output.m",
22 "plate_fd_plan.m",
23 "plate_model.m",
24 "plate_setup.m",
25 "plate_domain.m",
26 "plate_mount.m",
27 "plate_bending.m",
28 "plate_prestress.m",
29 "plate_static.m",
30 "plate_rigid_basis.m",
31 "plate_force_time.m",
32 "plate_force_footprint.m",
33 "plate_stress.m",
34 "plate_listener.m",
35 "plate_spectrum.m",
36 "plate_curvature_free.m",
37 "plate_curvature_domain.m",
38 "plate_result_schema.m",
39 ],
40 equationGroups: ALL_GROUPS,
41 validity: [
42 "Kirchhoff-Love thin-plate theory: no shear deformation or rotary inertia, so thick plates and very high modes are wrong.",
43 "Small-angle theory throughout: the threads are linear springs, the pendulum motion is linearized, and the plate's in-plane motion (a swing in its own plane, a rotation about the normal) is not part of the model. A pull beyond a few degrees of swing or a hard strike on a light plate leaves this regime.",
44 "Second-order truncation error in dx, dy and dt; the top modes on the grid are dispersive and their frequencies are too low. Free edges and curved edges are first order at the boundary.",
45 "Mounts are idealizations: a thread has one tension, a pad or felt is a spring and dashpot per unit area with order-of-magnitude constants, a vise is perfectly rigid, a hand is a guess. The rod and the hole of a cymbal stand are not modelled, nor is the cymbal's curvature.",
46 "The self-weight prestress is exact for the discrete model, but the stress at a hole or a jaw is the stress of a point or a line constraint on the grid, and depends on the spacing.",
47 "Damping is a two-parameter model plus the mount's dashpots, chosen, not measured. The sigma1 loss acts on the flexural part only.",
48 "The probe is snapped to the nearest grid node with a full stencil, and the series are averaged over each output sample.",
49 "Stress fields are evaluated only at the saved frames, so the envelope samples the true peak; near a strike the stress depends on the load footprint.",
50 "Radiated sound is an estimate of the waveform, not a calibrated level: Rayleigh's integral in a baffle, or a rough front-back cancellation for an unbaffled plate.",
51 "With the GPU option the time loop runs in single precision (a WebGPU port of plate_fd_loop.m); setup, statics, stresses, sound and spectra stay in double precision in numbl. Rigid-body coordinates and flexural field are carried separately, which is what keeps the swing and the vibration both accurate in single precision.",
52 ],
53 durationOf: (spec) => spec.fd.duration,
54 gridOf: (spec) => [spec.fd.nx, spec.fd.ny],
55 usPerCellStep: 0.8,
56 gpu: {
57 loopFile: "plate_fd_loop.m",
58 setupFunction: "plate_fd_setup",
59 outputFunction: "plate_fd_output",
60 usPerCellStep: 0.03,
61 },
62};