spectral_galerkin_heat.physics.spectral_ops =========================================== .. py:module:: spectral_galerkin_heat.physics.spectral_ops .. autoapi-nested-parse:: Backend-agnostic spectral free functions (shared by CPU and GPU kernels). These operate on a :class:`~spectral_galerkin_heat.physics.spectral_state.SpectralSolverState` and are pure ``einsum`` / array-copy logic: they take the array module from ``SsState.xp``, so both kernel modules import them from here. Operations that differ between backends stay in the per-backend kernel modules: the FFT (``DCT_II`` / ``IDCT_II``), the ``scipy``/``cupyx`` ndimage shifts, and the ``@njit`` vs ``@cuda.jit`` source-term kernel. Functions --------- .. autoapisummary:: spectral_galerkin_heat.physics.spectral_ops.project_box_to_modes spectral_galerkin_heat.physics.spectral_ops.reconstruct_volume spectral_galerkin_heat.physics.spectral_ops.project_volume spectral_galerkin_heat.physics.spectral_ops.assemble_property_correction spectral_galerkin_heat.physics.spectral_ops.reconstruct_temperature_box spectral_galerkin_heat.physics.spectral_ops.initialize_latent_heat_if_needed spectral_galerkin_heat.physics.spectral_ops.update_latent_heat_history spectral_galerkin_heat.physics.spectral_ops.reconstruct_surface_temperature spectral_galerkin_heat.physics.spectral_ops.reconstruct_bottom_temperature spectral_galerkin_heat.physics.spectral_ops.compute_latent_heat_source spectral_galerkin_heat.physics.spectral_ops.shift_latent_heat_history Module Contents --------------- .. py:function:: project_box_to_modes(field_box, SsState) Project fine box field to global spectral modes. The two branches give bit-identical results. einsum returns an F-contiguous view, which makes the ``* dV_fine`` scaling read uncoalesced on GPU, so the GPU path spells the same contraction out as tensordots to keep every intermediate C-contiguous. Strided access is cheap on CPU, where einsum is the faster of the two. .. py:function:: reconstruct_volume(a, SsState) Reconstruct the full cell-centred temperature field over Ω from modes *a*. Inverse of :func:`project_volume`: ``T = IDCT_II(a) / sqrt(dV)``. Returns a ``(nz, ny, nx)`` array on the same grid the modes live on. .. py:function:: project_volume(field, SsState) Project a full cell-centred volume field onto the modal basis. Forward of :func:`reconstruct_volume`: ``modes = sqrt(dV) * DCT_II(field)``. Scaled in place, for the reason given in :func:`reconstruct_volume`. .. py:function:: assemble_property_correction(SsState, a_trial, T_prev_full, dt, model, k_bar, a_bar) Assemble the temperature-dependent property correction modes ``C_mnp``. Forcing-assembly recipe: reconstruct ``T`` over Ω from the current trial modes, read the property fluctuations ``k'(T)=k(T)-k̄`` and ``a'(T)=a(T)-ā`` from the tabulated model, form ``g = k' ∇T`` (finite-difference gradient) and ``s_a = -a' ∂_t T``, then project. The projection returns only the **volume** modes; the boundary contribution of the conductivity correction is handled by the solver as a rescaling of the prescribed surface flux (see below and ``SpectralSolver.step``). :param a_trial: Current Picard trial modes. :type a_trial: ndarray (nz, ny, nx) :param T_prev_full: Previous converged full-volume temperature field (for ∂_t T). :type T_prev_full: ndarray (nz, ny, nx) :param dt: Time step. :type dt: float :param model: Temperature-dependent property model. :type model: MaterialModel :param k_bar: The ETD1 propagators' reference constants (k̄, ā). :type k_bar: float :param a_bar: The ETD1 propagators' reference constants (k̄, ā). :type a_bar: float :returns: **C** -- Correction forcing modes, to be injected as ``a += KK · C``. :rtype: ndarray (nz, ny, nx) .. py:function:: reconstruct_temperature_box(a, SsState) Reconstructs temperature in the refined, laser-following sub-box of the domain. .. py:function:: initialize_latent_heat_if_needed(SsState) Initialize fine-mesh T_prev from current trial modes on the first time step. Must be called after ``buffers.a_temp`` has been set to a reasonable estimate (e.g. the decayed modes). .. py:function:: update_latent_heat_history(SsState) Store the converged fine-mesh temperature as T_prev for the next step. Call once per time step, after the fixed-point iteration has converged and ``buffers.a_temp`` holds the final spectral modes. .. py:function:: reconstruct_surface_temperature(a, SsState) Reconstruct the 2D temperature field at the top surface (z = Lz). Sums the z-modes weighted by the top-surface Cp coefficients, then applies the inverse DCT (via the backend ``idct`` hook). .. py:function:: reconstruct_bottom_temperature(a, SsState) Reconstruct the 2D temperature field at the bottom surface (z = 0). At z=0, ``cos(p*pi*0/Lz) = 1`` so the weighting is plain Cp (no sign alternation). .. py:function:: compute_latent_heat_source(Q_buffer, phys, num, SsState) Compute volumetric latent heat source Q (W/m^3) on the fine mesh. Uses the current trial modes (``buffers.a_temp``) and the stored ``T_prev``. Does not update ``T_prev``; call :func:`update_latent_heat_history` after the iteration has converged. The latent source is ``Q = -rho(T) * L_f * (f_l(T) - f_l(T_prev)) / dt`` with ``f_l`` clamped to ``[0, 1]``. For a temperature-dependent material the density is the **blended** ``rho(T) = (1-f_l)rho_s(T)+f_l rho_l(T)`` evaluated per cell. .. py:function:: shift_latent_heat_history(SsState, laser_state, num) Shift T_prev and Q_prev to align with the current laser position. Call once per time step, before the fixed-point iteration begins.