function plan = plate_fd_plan(params) % PLATE_FD_PLAN Grid, time step and cost of the explicit finite-difference scheme. % % plan = plate_fd_plan(params) returns % plan.nx, plan.ny, plan.dx, plan.dy grid (nodes include the edges of the bounding box) % plan.dt_max largest stable time step [s] % plan.dt step actually used, params.fd.cfl * dt_max % plan.nsteps, plan.ncells, plan.cell_steps problem size (ncells counts every grid node) % plan.nunknowns nodes the scheme actually updates % % Stability. Von Neumann analysis of the scheme in plate_fd for a Fourier % mode on which the discrete Laplacian has eigenvalue -lambda gives the % amplification polynomial % (1 + sigma0 dt) z^2 - (2 - dt^2 kappa^2 lambda^2 - 2 sigma1 dt lambda) z % + (1 - sigma0 dt - 2 sigma1 dt lambda) = 0. % Both roots stay inside the unit circle for every lambda up to the largest % eigenvalue of the five-point Laplacian, lambda_max = 4/dx^2 + 4/dy^2, iff % dt <= 2 / ( lambda_max (sigma1 + sqrt(kappa^2 + sigma1^2)) ), % which for a square grid without sigma1 is the familiar dt <= dx^2 / (4 kappa). % Because dt scales with dx^2, halving the grid spacing costs eight times % as many cell updates for the same simulated time. % % The same bound serves the free and centre-pinned plates and the ellipse: % the Dirichlet Laplacian of any sub-domain has its spectrum inside that of % the full grid, the clamped correction of plate_matrices does not raise the % row sums above the interior stencil's, and the largest eigenvalue of the % energy-method operator M \ K lies just below lambda_max^2 (about 0.97 to % 0.99 of it on the grids used here), so the step is safe and slightly % conservative there. P = plate_setup(params); plan.nx = P.fd.nx; plan.ny = P.fd.ny; if plan.nx < 5 || plan.ny < 5 error('plate_fd_plan: the grid needs at least 5 nodes in each direction'); end plan.dx = P.plate.Lx / (plan.nx - 1); plan.dy = P.plate.Ly / (plan.ny - 1); lambda_max = 4 / plan.dx^2 + 4 / plan.dy^2; s1 = P.damping.sigma1; plan.dt_max = 2 / (lambda_max * (s1 + sqrt(P.kappa^2 + s1^2))); plan.dt = P.fd.cfl * plan.dt_max; plan.nsteps = ceil(P.fd.duration / plan.dt); plan.ncells = plan.nx * plan.ny; dom = plate_domain(P.plate, plan.nx, plan.ny); if any(strcmp(P.bc, {'free', 'pinned-center'})) plan.nunknowns = dom.nunknowns_free; else plan.nunknowns = dom.nunknowns_dirichlet; end plan.cell_steps = plan.ncells * plan.nsteps; end