Scattering API
This page lists the pySED-native scattering extension APIs. See Scattering Extensions for the theory, q-point rules, and implementation rationale.
Shared Kernel
Shared low-level kernels for pySED scattering calculations.
The functions here are deliberately small CPU/NumPy kernels. They centralize the operations that will later be natural targets for optional CuPy or Numba-CUDA implementations: phase construction, density amplitudes, time FFT power spectra, and block statistics.
- class pySED.scattering_kernel.FrequencyGrid(frequencies_thz: numpy.ndarray, freq_slice: slice)
Bases:
object- freq_slice: slice
- frequencies_thz: ndarray
- class pySED.scattering_kernel.KernelBackend(name: str, xp: object, fft: object, fftfreq: object, asnumpy: object)
Bases:
object- asnumpy: object
- fft: object
- fftfreq: object
- name: str
- xp: object
- pySED.scattering_kernel.as_blocks(n_frames, num_blocks)
Split a trajectory length into equally sized contiguous blocks.
- pySED.scattering_kernel.circular_autocorrelation(signal, backend='cpu')
Return circular autocorrelation used for finite-block reference DSF.
- pySED.scattering_kernel.density_amplitude(positions_block, q_vec, weights=None, backend='cpu')
Return weighted density amplitude
rho(Q,t)for one block.
- pySED.scattering_kernel.density_amplitude_from_phase(phase, weights=None, backend='cpu')
Return weighted density amplitude from precomputed phase factors.
- pySED.scattering_kernel.fft_power(signal, axis=0, norm='forward', backend='cpu')
Return
abs(FFT(signal))**2with the configured FFT normalization.
- pySED.scattering_kernel.frequency_grid(block_size, dt, positive_only=True, backend='cpu')
Return THz frequencies and the slice used for spectral outputs.
- pySED.scattering_kernel.phase_factors(positions_block, q_vec, backend='cpu')
Return
exp(i Q dot r_i(t))for one trajectory block and Q vector.
- pySED.scattering_kernel.positive_frequency_slice(num_frames)
Return the positive-frequency half used by pySED spectra.
- pySED.scattering_kernel.resolve_backend(backend='cpu')
Resolve a scattering kernel backend.
"cpu"and"numpy"use NumPy/SciPy and are always available."cupy"and"gpu"request CuPy/CuPyX. CuPy is optional and must be installed by the user with the wheel that matches their CUDA runtime.
- pySED.scattering_kernel.standard_error(samples, backend='cpu')
Return the standard error over the first axis.
- pySED.scattering_kernel.to_numpy(array, backend='cpu')
Move a backend array to a NumPy array.
Probe Weights
Probe-specific scattering weights.
This module keeps scattering constants separate from the DSF estimators. The X-ray path uses the Cromer-Mann analytic approximation for the neutral-atom form factor,
f0(s) = sum_i a_i exp(-b_i s**2) + c, s = abs(Q) / (4*pi).
Q is expected in inverse Angstrom.
- class pySED.probe_weights.CromerMannCoefficients(a: tuple, b: tuple, c: float, source: str = 'Cromer and Mann neutral-atom analytic form')
Bases:
objectFour-Gaussian Cromer-Mann coefficients for an atomic form factor.
- a: tuple
- b: tuple
- c: float
- source: str = 'Cromer and Mann neutral-atom analytic form'
- pySED.probe_weights.atomic_number_weights(atom_types, qpoints_cartesian=None, missing='raise')
Return atomic-number X-ray weights.
This is a fallback for elements without form-factor coefficients. It is useful for exploratory calculations but should not be treated as an experiment-quality X-ray model.
- pySED.probe_weights.coerce_cromer_mann_coefficients(value)
Return
valueasCromerMannCoefficients.valuecan be aCromerMannCoefficientsinstance, a mapping witha,b, andckeys, or a flat nine-value iterable ordered asa1, b1, a2, b2, a3, b3, a4, b4, c.
- pySED.probe_weights.cromer_mann_form_factor(q_magnitude, coefficients)
Evaluate the Cromer-Mann form factor for
|Q|in inverse Angstrom.
- pySED.probe_weights.electron_form_factor_weights(atom_types, qpoints_cartesian, coefficients_table=None, missing='raise')
Return relative electron form-factor weights using Mott-Bethe.
This is a neutral-atom, first-Born approximation suitable for kinematic EELS visibility estimates. For quantitative electron diffraction or multislice calculations, users should pass a dedicated electron-scattering table through the higher-level EELS API.
- pySED.probe_weights.mott_bethe_electron_form_factor(q_magnitude, atomic_number, coefficients, small_q=1e-08)
Return a relative electron scattering factor from Mott-Bethe.
The returned value is proportional to
(Z - f_x(Q)) / |Q|**2withQin inverse Angstrom. The dimensional constant is omitted because pySED’s kinematic EELS visibility uses relative intensities by default. TheQ -> 0limit is evaluated analytically from the Cromer-Mann derivative.
- pySED.probe_weights.xray_form_factor_weights(atom_types, qpoints_cartesian=None, coefficients_table=None, missing='atomic_number')
Return q-dependent X-ray form-factor weights.
Parameters
- atom_types
Element symbols for each atom.
- qpoints_cartesian
Qpoints in inverse Angstrom. If omitted,Q=0weights are returned as a one-dimensional atom array.- coefficients_table
Optional mapping from atom symbol to Cromer-Mann coefficients. Entries override the built-in neutral-atom table.
- missing
"atomic_number"falls back toatomic_number_weights(),"zero"inserts zero weights, and"raise"raisesKeyError.
Quantum Correction
Quantum detailed-balance corrections for classical scattering spectra.
- pySED.quantum_correction.BOLTZMANN_MEV_PER_K = 0.08617333262145
Boltzmann constant expressed as meV/K.
- pySED.quantum_correction.PLANCK_MEV_THZ = 4.135667696
Planck constant expressed as meV per THz.
- pySED.quantum_correction.WAVENUMBER_MEV = 0.1239841984332003
Energy of one inverse centimeter expressed in meV.
- pySED.quantum_correction.apply_quantum_correction(intensity, axis, temperature, unit='thz', axis_index=-1)
Multiply a spectrum or map by the harmonic quantum correction factor.
- pySED.quantum_correction.bose_population(axis, temperature, unit='thz')
Return the Bose-Einstein population for positive energy magnitudes.
- pySED.quantum_correction.classical_to_quantum_factor(axis, temperature, unit='thz')
Return the harmonic classical-to-quantum correction factor.
The factor is
x / (1 - exp(-x)), wherex = E / (k_B T).For negative energy transfers the same signed expression obeys detailed balance. The zero-energy limit is evaluated with the Taylor expansion.
- pySED.quantum_correction.convert_energy_axis(axis, source_unit='thz', target_unit='meV')
Convert an axis between supported frequency/energy units.
- pySED.quantum_correction.energy_axis_from_mev(energy_mev, unit='thz')
Convert signed meV values to the requested unit.
- pySED.quantum_correction.energy_axis_to_mev(axis, unit='thz')
Convert an energy/frequency axis to signed meV values.
Q-Point Advisor
Q-point utilities for finite periodic MD trajectories.
The routines in this module make the supercell commensurability condition
explicit. For a primitive cell p and a simulation supercell S with
S = P @ p, a reduced q point is compatible with the trajectory if
q_red @ P.T is an integer vector.
This is the same condition used by the existing Brillouin-zone path builder, but exposed as reusable API for SED, DSF, EELS, and experiment comparison.
- class pySED.q_advisor.ExtendedZoneQPathPlan(report: QAdvisorReport, Q_reduced: ndarray, Q_cartesian: ndarray, qpoints_reduced: ndarray, qpoints_cartesian: ndarray, g_vectors_reduced: ndarray, g_vectors_cartesian: ndarray)
Bases:
objectPairwise
Q = q + Gplan for extended-zone scattering paths.- Q_cartesian: ndarray
- Q_reduced: ndarray
- g_vectors_cartesian: ndarray
- g_vectors_reduced: ndarray
- property num_points
- qpoints_cartesian: ndarray
- qpoints_reduced: ndarray
- report: QAdvisorReport
- to_dict()
- to_records(flat=False)
- write_csv(path)
Write the extended-zone path plan to
pathas CSV.
- write_phonopy_qpoints(path)
Write folded commensurate q points for phonopy eigenvectors.
- class pySED.q_advisor.QAdvisor(primitive_cell, supercell_cell, atol=1e-08)
Bases:
objectConstruct, validate, and map q points for a finite MD supercell.
- advise_cartesian_qpoints(qpoints_cartesian, preserve_image=False)
Map Cartesian experimental Q points to nearest commensurate q points.
- advise_experimental_path(qpoints, coordinates='reduced', preserve_image=True, suggest_supercell=True)
Return a full commensurability report for an experimental q path.
Parameters
- qpoints
Requested q or Q points, either reduced coordinates in the primitive reciprocal basis or Cartesian vectors in inverse Angstrom.
- coordinates
"reduced"/"fractional"/"crystal"or"cartesian"/"angstrom^-1".- preserve_image
Preserve the extended-zone reciprocal-lattice image when mapping to the nearest commensurate point. This should normally stay
Truefor EELS, INS, and IXS comparison because form factors and basis interference depend on the fullQ = q + G.- suggest_supercell
If
True, recommend diagonal primitive-cell repeats that would make all requested reduced coordinates commensurate.
- advise_map_q_axis(scattering_map, start_qpoint, end_qpoint, coordinates='cartesian', preserve_image=True, suggest_supercell=True)
Advise Q points implied by a calibrated experimental map q axis.
scattering_mapmay be any object with a one-dimensionalq_axisattribute, includingpySED.compare_experiment.ScatteringMap. The vector endpoints define the reciprocal-space path corresponding to the first and last q-axis values.
- advise_qpoints(qpoints_reduced, preserve_image=False)
- build_commensurate_path(start_reduced, end_reduced)
- cartesian_to_reduced(qpoints_cartesian)
- commensurate_grid(centered=False, max_bound=256)
Return all distinct commensurate q points modulo primitive G vectors.
For diagonal supercells this is the usual
i/Nx, j/Ny, k/Nzgrid. For non-diagonal integer repetition matrices, a bounded integer enumeration is used and stopped onceabs(det(P))unique q points are found.
- estimate_selected_q_efficiency(qpoints_reduced=None, num_selected_qpoints=None, num_frames=None, num_atoms=None)
Estimate selected-Q savings against this supercell’s full q grid.
- is_commensurate(qpoint_reduced, atol=None)
- nearest_commensurate(qpoint_reduced, grid=None, preserve_image=False)
- nearest_commensurate_cartesian(qpoint_cartesian, grid=None, preserve_image=False)
Map one Cartesian experimental Q point to the nearest allowed q point.
- plan_extended_zone_q_path(qpoints, coordinates='reduced', q_policy='strict', max_error_reduced=None, max_error_cartesian=None)
Plan a pairwise extended-zone path for EELS, INS, or IXS.
The returned
ExtendedZoneQPathPlancontains the nearest allowed extended-zone \(Q_i\), the folded commensurate \(q_i\), and the integer reciprocal vector \(G_i\) for each experimental point:Q_i = q_i + G_i.
- plan_map_q_axis(scattering_map, start_qpoint, end_qpoint, coordinates='cartesian', q_policy='strict', max_error_reduced=None, max_error_cartesian=None)
Plan
Q=q+Gpoints from an experimental map’s calibrated q axis.
- reduced_to_cartesian(qpoints_reduced)
- supercell_indices(qpoints_reduced)
- validate_qpoints(qpoints_reduced, atol=None)
- write_phonopy_qpoints(qpoints_reduced, path)
- class pySED.q_advisor.QAdvisorReport(coordinate_system: str, preserve_image: bool, requested_reduced: ndarray, nearest_reduced: ndarray, requested_cartesian: ndarray, nearest_cartesian: ndarray, is_commensurate: ndarray, error_reduced: ndarray, error_cartesian: ndarray, integer_supercell_indices: ndarray, suggested_diagonal_supercell: ndarray)
Bases:
objectVectorized report for an experimental q or Q path.
The report keeps the requested points, the nearest commensurate points, the finite-supercell integer indices, and a diagonal-supercell recommendation in one object so scripts can print, export, or archive the q-selection decision before running SED, DSF, or EELS calculations.
- property all_commensurate
- coordinate_system: str
- error_cartesian: ndarray
- error_reduced: ndarray
- integer_supercell_indices: ndarray
- is_commensurate: ndarray
- property max_error_cartesian
- property max_error_reduced
- nearest_cartesian: ndarray
- nearest_reduced: ndarray
- property num_commensurate
- property num_points
- preserve_image: bool
- requested_cartesian: ndarray
- requested_reduced: ndarray
- suggested_diagonal_supercell: ndarray
- summary()
Return scalar report metadata useful for logs or JSON exports.
- to_dict()
Return a JSON-serializable report dictionary.
- to_records(flat=False)
Return one serializable record per requested point.
- to_table(precision=6)
Return a compact plain-text table for terminal logs.
- write_csv(path)
Write the q-advisor point table to
pathas CSV.
- class pySED.q_advisor.QPathSegments(qpoints_reduced: ndarray, path_axis: ndarray, segment_start_indices: ndarray, segment_end_indices: ndarray)
Bases:
objectSelected-Q path assembled from one or more linear segments.
- path_axis: ndarray
- qpoints_reduced: ndarray
- segment_end_indices: ndarray
- segment_start_indices: ndarray
- class pySED.q_advisor.QPointAdvice(requested_reduced: ndarray, nearest_reduced: ndarray, requested_cartesian: ndarray, nearest_cartesian: ndarray, is_commensurate: bool, error_reduced: float, error_cartesian: float, integer_supercell_index: ndarray)
Bases:
objectResult of mapping one requested q point to the commensurate grid.
- error_cartesian: float
- error_reduced: float
- integer_supercell_index: ndarray
- is_commensurate: bool
- nearest_cartesian: ndarray
- nearest_reduced: ndarray
- requested_cartesian: ndarray
- requested_reduced: ndarray
- class pySED.q_advisor.QPointMesh(qpoints_reduced: ndarray, axes: tuple, mesh_shape: tuple)
Bases:
objectSelected-Q mesh in reduced reciprocal coordinates.
- axes: tuple
- mesh_shape: tuple
- qpoints_reduced: ndarray
- reshape_values(values)
Reshape per-Q values back onto the selected-Q mesh.
- class pySED.q_advisor.SelectedQEfficiencyReport(num_selected_qpoints: int, num_full_qpoints: int, selected_fraction: float, qpoint_reduction_factor: float, num_frames: int = None, num_atoms: int = None, selected_phase_evaluations: float = None, full_phase_evaluations: float = None, selected_fft_work_units: float = None, full_fft_work_units: float = None)
Bases:
objectCost estimate for selected-Q evaluation relative to a full q grid.
- full_fft_work_units: float = None
- full_phase_evaluations: float = None
- num_atoms: int = None
- num_frames: int = None
- num_full_qpoints: int
- num_selected_qpoints: int
- qpoint_reduction_factor: float
- selected_fft_work_units: float = None
- selected_fraction: float
- selected_phase_evaluations: float = None
- summary()
Return a JSON-serializable cost summary.
- to_table(precision=6)
Return a compact plain-text table for logs or methods notes.
- pySED.q_advisor.compute_repetition_matrix(primitive_cell, supercell_cell, atol=0.0001)
Return integer
Psuch thatsupercell_cell = P @ primitive_cell.
- pySED.q_advisor.estimate_selected_q_efficiency(num_selected_qpoints, num_full_qpoints, num_frames=None, num_atoms=None)
Estimate selected-Q savings relative to evaluating a full q grid.
The estimate follows the direct DSF cost model
O(N_Q * N_t * N) + O(N_Q * N_t * log(N_t)). The phase-evaluation counts are exact under this model whennum_framesandnum_atomsare supplied; FFT work units are proportional estimates.
- pySED.q_advisor.qpoints_from_mesh(h_axis, k_axis, l_axis)
Generate a pynamic-style selected-Q mesh in reduced coordinates.
Each axis may be a scalar or
[start, stop, num]. The function does not enforce commensurability; pass the returnedqpoints_reducedtoQAdvisorbefore using the points with finite periodic trajectories.
- pySED.q_advisor.qpoints_from_path_axis(q_axis, start_qpoint, end_qpoint)
Interpolate vector Q points along a calibrated scalar q-path axis.
Experimental maps often store only a scalar horizontal axis, for example a path distance or detector coordinate after calibration. This helper maps each scalar axis value linearly between two vector endpoints. The returned vectors use the same coordinate system as
start_qpointandend_qpoint.
- pySED.q_advisor.qpoints_from_path_segments(starts, ends, steps, endpoint=False)
Generate selected Q points along one or more reduced-coordinate paths.
This follows the selected-path convention used by pynamic-structure-factor: each segment is sampled with
stepspoints; by default the segment end point is omitted to avoid duplicate vertices when consecutive segments share endpoints. Useendpoint=Truewhen every segment should include its final point.
- pySED.q_advisor.reciprocal_lattice(cell)
Return reciprocal lattice vectors as rows, including the 2*pi factor.
- pySED.q_advisor.reduced_delta(q1, q2)
Shortest periodic difference between reduced reciprocal coordinates.
- pySED.q_advisor.split_extended_zone_qpoints(qpoints_reduced)
Split reduced extended-zone
Qpoints into foldedqandG.The folded q points use the centered first Brillouin-zone image. The returned G vectors are integer reduced reciprocal-lattice vectors satisfying
Q = q + Gwithin floating-point tolerance.
- pySED.q_advisor.suggest_diagonal_supercell(qpoints_reduced, max_denominator=96)
Suggest diagonal repeats so every supplied reduced q point is allowed.
- pySED.q_advisor.wrap_reduced(q_red, centered=False)
Wrap reduced coordinates into [0, 1) or [-0.5, 0.5).
Dynamic Structure Factor
Dynamic structure factor calculations from MD trajectories.
This module implements the density-correlation route used for neutron and X-ray inelastic scattering. The computation is organized in terms of
rho(Q, t) = sum_i w_i(Q) exp(i Q dot r_i(t))
and estimates the coherent spectrum from the time Fourier transform of rho. This is equivalent to evaluating the intermediate scattering function and then Fourier transforming it, but avoids storing F(Q, t) explicitly.
- class pySED.dsf.CurrentCorrelationResult(qpoints_cartesian: numpy.ndarray, frequencies_thz: numpy.ndarray, longitudinal: numpy.ndarray, transverse: numpy.ndarray, num_blocks: int, longitudinal_sem: numpy.ndarray = None, transverse_sem: numpy.ndarray = None, metadata: dict = None)
Bases:
object- frequencies_thz: ndarray
- longitudinal: ndarray
- longitudinal_sem: ndarray = None
- metadata: dict = None
- num_blocks: int
- qpoints_cartesian: ndarray
- transverse: ndarray
- transverse_sem: ndarray = None
- class pySED.dsf.DSFResult(qpoints_cartesian: numpy.ndarray, frequencies_thz: numpy.ndarray, coherent: numpy.ndarray, incoherent: numpy.ndarray, total: numpy.ndarray, elastic_coherent: numpy.ndarray, elastic_incoherent: numpy.ndarray, num_blocks: int, metadata: dict, coherent_sem: numpy.ndarray = None, incoherent_sem: numpy.ndarray = None, total_sem: numpy.ndarray = None, elastic_coherent_sem: numpy.ndarray = None, elastic_incoherent_sem: numpy.ndarray = None)
Bases:
object- coherent: ndarray
- coherent_sem: ndarray = None
- elastic_coherent: ndarray
- elastic_coherent_sem: ndarray = None
- elastic_incoherent: ndarray
- elastic_incoherent_sem: ndarray = None
- frequencies_thz: ndarray
- incoherent: ndarray
- incoherent_sem: ndarray = None
- metadata: dict
- num_blocks: int
- qpoints_cartesian: ndarray
- total: ndarray
- total_sem: ndarray = None
- class pySED.dsf.PartialDSFResult(qpoints_cartesian: numpy.ndarray, frequencies_thz: numpy.ndarray, species: tuple, partial: numpy.ndarray, partial_sem: numpy.ndarray, weighted_total: numpy.ndarray, weighted_total_sem: numpy.ndarray, num_blocks: int, metadata: dict)
Bases:
object- frequencies_thz: ndarray
- metadata: dict
- num_blocks: int
- partial: ndarray
- partial_sem: ndarray
- qpoints_cartesian: ndarray
- species: tuple
- weighted_total: ndarray
- weighted_total_sem: ndarray
- pySED.dsf.compute_coherent_dsf_via_correlation(positions, qpoints_cartesian, dt, coherent_weights=None, num_blocks=1, positive_only=True, backend='cpu')
Reference coherent DSF from the density autocorrelation function.
This routine is intentionally more explicit and slower than
compute_dsf(). It first constructs the finite-block circular intermediate scattering functionF(Q, lag) = mean_t rho(Q, t + lag) rho(Q, t).conjugate()and then Fourier transforms
Fin time. It is mainly useful for validating that the production estimator based onabs(FFT_t[rho(Q, t)])**2is consistent with the correlation-function formulation.
- pySED.dsf.compute_current_correlations(positions, velocities, qpoints_cartesian, dt, weights=None, num_blocks=1, positive_only=True, backend='cpu')
Compute longitudinal and transverse current spectra.
Spectra are evaluated independently for each time block, normalized by
block_size * num_atoms, then averaged. Whennum_blocks > 1, the result includes standard errors of the block-averaged spectra.
- pySED.dsf.compute_dsf(positions, qpoints_cartesian, dt, atom_types=None, experiment='neutron', coherent_weights=None, incoherent_cross_sections=None, xray_form_factor_table=None, xray_missing='atomic_number', num_blocks=1, positive_only=True, backend='cpu')
Compute coherent/incoherent dynamic structure factors.
Parameters
- positions
Array with shape
(num_frames, num_atoms, 3)in Angstrom.- qpoints_cartesian
Q points in inverse Angstrom, including the
2*piconvention.- dt
Sampling interval in seconds.
- backend
"cpu"/"numpy"by default. Use"cupy"or"gpu"only when CuPy is installed for the local CUDA runtime.
- pySED.dsf.compute_partial_dsf(positions, qpoints_cartesian, dt, atom_types, species_weights=None, num_blocks=1, positive_only=True, backend='cpu')
Compute species-pair coherent partial DSF matrices.
The returned
partialarray has shape(num_qpoints, num_species, num_species, num_frequencies)and contains the block-averaged cross spectraFFT[rho_A(Q,t)] * conj(FFT[rho_B(Q,t))).weighted_totalis the coherent spectrum reconstructed from the partials using the supplied species weights.
- pySED.dsf.neutron_weights(atom_types, include_incoherent=True)
- pySED.dsf.resolve_scattering_weights(atom_types=None, qpoints_cartesian=None, experiment='neutron', coherent_weights=None, incoherent_cross_sections=None, xray_form_factor_table=None, xray_missing='atomic_number')
- pySED.dsf.xray_atomic_number_weights(atom_types, qpoints_cartesian=None)
Return an approximate X-ray weight using atomic number.
This is a safe default when no tabulated form-factor data are supplied. For publication-quality X-ray comparison, pass q-dependent form factors through
coherent_weights.
- pySED.dsf.xray_form_factor_weights(atom_types, qpoints_cartesian=None, coefficients_table=None, missing='atomic_number')
Return q-dependent X-ray form-factor weights.
This thin wrapper exposes
pySED.probe_weightsthrough the historical DSF namespace.
Mode Visibility
Mode-resolved one-phonon visibility for neutron and X-ray scattering.
- class pySED.mode_visibility.OnePhononDecompositionMap(Q_reduced: ndarray, Q_cartesian: ndarray, energy_axis: ndarray, intensity: ndarray, atom_intensity: ndarray, direction_intensity: ndarray, atom_interference_intensity: ndarray, visibility: ndarray, atom_visibility: ndarray, direction_visibility: ndarray, atom_interference: ndarray, metadata: dict)
Bases:
objectEnergy-resolved atom/direction/interference one-phonon diagnostics.
- Q_cartesian: ndarray
- Q_reduced: ndarray
- atom_intensity: ndarray
- atom_interference: ndarray
- atom_interference_intensity: ndarray
- atom_visibility: ndarray
- direction_intensity: ndarray
- direction_visibility: ndarray
- energy_axis: ndarray
- intensity: ndarray
- metadata: dict
- visibility: ndarray
- class pySED.mode_visibility.OnePhononMap(Q_reduced: ndarray, Q_cartesian: ndarray, energy_axis: ndarray, intensity: ndarray, visibility: ndarray, metadata: dict)
Bases:
objectEnergy-resolved coherent one-phonon visibility map.
- Q_cartesian: ndarray
- Q_reduced: ndarray
- energy_axis: ndarray
- intensity: ndarray
- metadata: dict
- visibility: ndarray
- class pySED.mode_visibility.OnePhononVisibility(qpoints_reduced: ndarray, g_vectors_reduced: ndarray, Q_reduced: ndarray, Q_cartesian: ndarray, amplitude: ndarray, visibility: ndarray, atom_amplitude: ndarray, atom_visibility: ndarray, direction_amplitude: ndarray, direction_visibility: ndarray, atom_interference: ndarray, scattering_weights: ndarray, metadata: dict)
Bases:
objectCoherent one-phonon mode visibility and diagnostic amplitudes.
- Q_cartesian: ndarray
- Q_reduced: ndarray
- amplitude: ndarray
- atom_amplitude: ndarray
- atom_interference: ndarray
- atom_visibility: ndarray
- direction_amplitude: ndarray
- direction_visibility: ndarray
- g_vectors_reduced: ndarray
- metadata: dict
- qpoints_reduced: ndarray
- scattering_weights: ndarray
- visibility: ndarray
- pySED.mode_visibility.build_one_phonon_decomposition_map_from_mode_spectra(visibility, mode_spectra, energy_axis)
Build energy-resolved atom/direction/interference INS/IXS maps.
- pySED.mode_visibility.build_one_phonon_map(visibility, mode_frequencies, energy_axis, broadening, broadening_kind='lorentzian')
Convert one-phonon visibility into a broadened harmonic map.
- pySED.mode_visibility.build_one_phonon_map_from_mode_spectra(visibility, mode_spectra, energy_axis)
Weight branch-resolved spectra into coherent INS/IXS intensity maps.
mode_spectramust have shape(num_energy, num_q, num_modes)and can be taken directly frompySED.eigen_sed.EigenSEDResult.sed.
- pySED.mode_visibility.compute_one_phonon_visibility(qpoints_reduced, g_vectors_reduced, primitive_cell, basis_positions_reduced, masses, eigenvectors, atom_types=None, experiment='neutron', scattering_weights=None, mode_frequencies=None, frequency_power=0, xray_form_factor_table=None, xray_missing='atomic_number', pairwise_g_vectors=False)
Compute coherent one-phonon INS/IXS visibility for each mode.
The elementary complex contribution is
A[b, alpha] = w_b(Q) Q_alpha e_balpha(q, nu) exp(i 2*pi Q_red dot tau_b) / sqrt(m_b).frequency_power=-1adds the common harmonic one-phonon1/omegaintensity prefactor. The default0reports the pure polarization, probe-weight, mass, and interference visibility.
- pySED.mode_visibility.compute_one_phonon_visibility_for_q_path(qpoints_reduced, g_vectors_reduced, primitive_cell, basis_positions_reduced, masses, eigenvectors, atom_types=None, experiment='neutron', scattering_weights=None, mode_frequencies=None, frequency_power=0, xray_form_factor_table=None, xray_missing='atomic_number')
Compute coherent INS/IXS one-phonon visibility for a pairwise Q path.
- pySED.mode_visibility.gaussian(axis, center, sigma)
- pySED.mode_visibility.lorentzian(axis, center, hwhm)
Visibility Diagnostics
Mode-level visibility diagnostics for experiment-facing scattering maps.
- class pySED.visibility_diagnostics.ModeVisibilityDiagnostics(visibility: ndarray, relative_visibility: ndarray, atom_sum: ndarray, direction_sum: ndarray, basis_interference: ndarray, direction_interference: ndarray, basis_interference_fraction: ndarray, direction_interference_fraction: ndarray, dominant_atom_index: ndarray, dominant_direction_index: ndarray, dominant_reason: ndarray, q_error_reduced: ndarray, q_error_cartesian: ndarray, atom_labels: list, direction_labels: list, mode_labels: list, metadata: dict)
Bases:
objectBranch-level explanation of EELS/INS/IXS mode visibility.
The arrays have shape
(num_q, num_g, num_modes)unless noted otherwise. The diagnostic quantities are derived from the complex visibility decompositionI = |sum_{b,alpha} A_{b,alpha}|^2.- atom_labels: list
- atom_sum: ndarray
- basis_interference: ndarray
- basis_interference_fraction: ndarray
- direction_interference: ndarray
- direction_interference_fraction: ndarray
- direction_labels: list
- direction_sum: ndarray
- dominant_atom_index: ndarray
- dominant_direction_index: ndarray
- dominant_reason: ndarray
- metadata: dict
- mode_labels: list
- q_error_cartesian: ndarray
- q_error_reduced: ndarray
- reason_counts()
Return a dictionary counting the dominant reason labels.
- relative_visibility: ndarray
- to_records(include_all=True, relative_threshold=None)
Return a list of row dictionaries suitable for tables or CSV.
Parameters
- include_allbool
If
False, only rows with relative visibility less thanrelative_thresholdare emitted.- relative_thresholdfloat or None
Relative-visibility cutoff for weak-branch rows. When
None, the value stored inmetadata["relative_floor"]is used.
- visibility: ndarray
- weak_records(relative_threshold=None)
Return only branches classified as weak by relative visibility.
- write_csv(path, include_all=True, relative_threshold=None)
Write diagnostic records to a CSV table.
- pySED.visibility_diagnostics.diagnose_mode_visibility(visibility_decomposition, q_advice=None, atom_labels=None, mode_labels=None, visibility_floor=1e-14, relative_floor=0.001, interference_floor=0.8, q_error_floor=1e-10)
Diagnose why each branch is visible or weak in EELS/INS/IXS.
visibility_decompositioncan be anpySED.eels.EELSVisibilityDecompositionor apySED.mode_visibility.OnePhononVisibility. It must exposevisibility,atom_visibilityanddirection_visibility. The returned object quantifies atom/basis interference and Cartesian-direction selection without changing the underlying scattering intensity.
Eigenvector SED
Eigenvector-resolved spectral energy density.
- class pySED.eigen_sed.EigenSEDResult(frequencies_thz: numpy.ndarray, qpoints_reduced: numpy.ndarray, sed: numpy.ndarray, mode_frequencies: numpy.ndarray, metadata: dict)
Bases:
object- frequencies_thz: ndarray
- metadata: dict
- mode_frequencies: ndarray
- qpoints_reduced: ndarray
- sed: ndarray
- class pySED.eigen_sed.EigenvectorSet(qpoints_reduced: numpy.ndarray, frequencies: numpy.ndarray, eigenvectors: numpy.ndarray, source: str = 'unknown')
Bases:
object- eigenvectors: ndarray
- frequencies: ndarray
- qpoints_reduced: ndarray
- source: str = 'unknown'
- pySED.eigen_sed.compute_eigen_sed(velocities, unitcell_vectors, basis_index, masses, primitive_cell, supercell_cell, eigenvectors, dt, num_blocks=1, target_qpoints=None, validate_q=True, backend='cpu')
Project velocities onto phonon eigenvectors and compute branch SED.
velocitiesmust have shape(num_frames, num_atoms, 3). Thebasis_indexarray maps each atom to a one-based primitive basis label.unitcell_vectorsmust contain the equilibrium cell-vector position of each repeated primitive cell in Angstrom.
- pySED.eigen_sed.read_phonopy_band_yaml(path)
Read q points, frequencies, and eigenvectors from a phonopy band.yaml.
- pySED.eigen_sed.validate_eigenvector_qpoints(eigenvectors, advisor, target_qpoints=None, atol=1e-06)
Electron Kinematics
Electron-beam kinematics for calibrating q-EELS momentum axes.
- pySED.electron_kinematics.angular_resolution_to_q_sigma(sigma_angle, beam_energy_ev, angle_unit='mrad')
Convert an angular resolution width to transverse
sigma_q.The returned value is in inverse Angstrom and can be passed to
pySED.compare_experiment.prepare_map_comparison()assigma_qwhen the scattering-map q axis is a Cartesian path distance in inverse Angstrom.
- pySED.electron_kinematics.eels_qpoints_from_angle_axis(angle_axis, beam_energy_ev, direction=(1.0, 0.0), energy_loss_ev=0.0, angle_unit='mrad', include_longitudinal=False)
Return a q-EELS line-scan Q path from a scalar scattering-angle axis.
- pySED.electron_kinematics.electron_beta(beam_energy_ev)
Return relativistic electron speed as
v/c.
- pySED.electron_kinematics.electron_momentum_pc_ev(beam_energy_ev)
Return relativistic electron momentum times c in eV.
- pySED.electron_kinematics.electron_wavelength_angstrom(beam_energy_ev)
Return relativistic de Broglie wavelength in Angstrom.
- pySED.electron_kinematics.electron_wavenumber_per_angstrom(beam_energy_ev)
Return electron wave number
2*pi/lambdain inverse Angstrom.
- pySED.electron_kinematics.longitudinal_momentum_transfer(energy_loss_ev, beam_energy_ev)
Return the small-loss longitudinal momentum transfer in inverse Angstrom.
The approximation is
q_parallel = DeltaE / (hbar v)withv = beta c. For vibrational losses this term is usually much smaller than the transverse detector momentum but it is useful for documenting the experiment geometry.
- pySED.electron_kinematics.scattering_angles_to_qpoints(theta_x, theta_y=None, beam_energy_ev=200000.0, energy_loss_ev=0.0, angle_unit='rad', include_longitudinal=True)
Convert small electron scattering angles to Cartesian Q points.
theta_xandtheta_yare detector scattering angles. The transverse momentum transfer is reported with the experimental sign conventionQ_perp = k0 * thetawherek0 = 2*pi/lambda. Ifinclude_longitudinalis true, the third component isDeltaE / (hbar v); otherwise it is zero.
Kinematic q-EELS
Kinematic q-EELS visibility and map construction.
- class pySED.eels.EELSDecompositionMap(Q_reduced: numpy.ndarray, Q_cartesian: numpy.ndarray, energy_axis: numpy.ndarray, intensity: numpy.ndarray, atom_intensity: numpy.ndarray, direction_intensity: numpy.ndarray, atom_interference_intensity: numpy.ndarray, visibility: numpy.ndarray, atom_visibility: numpy.ndarray, direction_visibility: numpy.ndarray, atom_interference: numpy.ndarray, metadata: dict)
Bases:
object- Q_cartesian: ndarray
- Q_reduced: ndarray
- atom_intensity: ndarray
- atom_interference: ndarray
- atom_interference_intensity: ndarray
- atom_visibility: ndarray
- direction_intensity: ndarray
- direction_visibility: ndarray
- energy_axis: ndarray
- intensity: ndarray
- metadata: dict
- visibility: ndarray
- class pySED.eels.EELSMap(Q_reduced: numpy.ndarray, Q_cartesian: numpy.ndarray, energy_axis: numpy.ndarray, intensity: numpy.ndarray, visibility: numpy.ndarray)
Bases:
object- Q_cartesian: ndarray
- Q_reduced: ndarray
- energy_axis: ndarray
- intensity: ndarray
- visibility: ndarray
- class pySED.eels.EELSVisibility(qpoints_reduced: numpy.ndarray, g_vectors_reduced: numpy.ndarray, Q_reduced: numpy.ndarray, Q_cartesian: numpy.ndarray, visibility: numpy.ndarray, metadata: dict)
Bases:
object- Q_cartesian: ndarray
- Q_reduced: ndarray
- g_vectors_reduced: ndarray
- metadata: dict
- qpoints_reduced: ndarray
- visibility: ndarray
- class pySED.eels.EELSVisibilityDecomposition(qpoints_reduced: numpy.ndarray, g_vectors_reduced: numpy.ndarray, Q_reduced: numpy.ndarray, Q_cartesian: numpy.ndarray, amplitude: numpy.ndarray, visibility: numpy.ndarray, atom_amplitude: numpy.ndarray, atom_visibility: numpy.ndarray, direction_amplitude: numpy.ndarray, direction_visibility: numpy.ndarray, atom_interference: numpy.ndarray, metadata: dict)
Bases:
object- Q_cartesian: ndarray
- Q_reduced: ndarray
- amplitude: ndarray
- atom_amplitude: ndarray
- atom_interference: ndarray
- atom_visibility: ndarray
- direction_amplitude: ndarray
- direction_visibility: ndarray
- g_vectors_reduced: ndarray
- metadata: dict
- qpoints_reduced: ndarray
- visibility: ndarray
- pySED.eels.build_eels_decomposition_map_from_mode_spectra(decomposition, mode_spectra, energy_axis)
Convert mode-resolved EELS diagnostics into energy-resolved maps.
decompositionshould come fromcompute_mode_visibility_decomposition(). The returned maps preserve the non-additive diagnostics:total = sum_atom(atom_intensity) + atom_interference_intensity.
- pySED.eels.build_eels_map(visibility, mode_frequencies, energy_axis, broadening, broadening_kind='lorentzian')
Convert mode visibility into an energy-resolved q-EELS map.
- pySED.eels.build_eels_map_from_mode_spectra(visibility, mode_spectra, energy_axis)
Weight branch-resolved spectral functions into an EELS intensity map.
mode_spectramust have shape(num_energy, num_q, num_modes). This matchespySED.eigen_sed.EigenSEDResult.sed, allowing branch-resolved MD spectra to be converted directly into extended-zone q-EELS maps:I(Q, energy) = sum_mode visibility(Q, mode) * A(q, mode, energy).
- pySED.eels.compute_mode_visibility(qpoints_reduced, g_vectors_reduced, primitive_cell, basis_positions_reduced, masses, eigenvectors, electron_form_factors=None, atom_types=None, electron_form_factor_model='unit', electron_form_factor_table=None, electron_missing='raise', pairwise_g_vectors=False)
Compute branch visibility for extended-zone kinematic q-EELS.
The implemented factor is
abs(sum_b f_b(Q) (Q dot e_bv(q)) exp(i 2*pi Q_red dot tau_b) / sqrt(m_b))**2.
- pySED.eels.compute_mode_visibility_decomposition(qpoints_reduced, g_vectors_reduced, primitive_cell, basis_positions_reduced, masses, eigenvectors, electron_form_factors=None, atom_types=None, electron_form_factor_model='unit', electron_form_factor_table=None, electron_missing='raise', pairwise_g_vectors=False)
Compute complex q-EELS visibility contributions.
The primitive contribution is
A[b, alpha] = f_b(Q) Q_alpha e_balpha(q, nu) exp(i 2*pi Q_red dot tau_b) / sqrt(m_b).Atom and direction amplitudes are coherent sums of
A[b, alpha]. Their squared magnitudes are diagnostic quantities; they do not add up to the total visibility when there is destructive or constructive interference.
- pySED.eels.compute_mode_visibility_for_q_path(qpoints_reduced, g_vectors_reduced, primitive_cell, basis_positions_reduced, masses, eigenvectors, electron_form_factors=None, atom_types=None, electron_form_factor_model='unit', electron_form_factor_table=None, electron_missing='raise')
Compute EELS visibility for a pairwise experimental path.
Unlike
compute_mode_visibility(), this function interpretsqpoints_reduced[i]andg_vectors_reduced[i]as one experimental pointQ_i = q_i + G_i. The returned visibility has shape(num_points, 1, num_modes)so it remains compatible withbuild_eels_map_from_mode_spectra()without creating the full q-by-G Cartesian product.
- pySED.eels.fold_to_first_bz(qpoints_reduced)
- pySED.eels.gaussian(axis, center, sigma)
- pySED.eels.lorentzian(axis, center, hwhm)
Experiment Comparison
Utilities for comparing simulated scattering maps with experiments.
- class pySED.compare_experiment.MapComparison(simulated: numpy.ndarray, experimental: numpy.ndarray, residual: numpy.ndarray, rmse: float, mae: float, correlation: float, simulated_map: object = None, experimental_map: object = None)
Bases:
object- correlation: float
- experimental: ndarray
- experimental_map: object = None
- mae: float
- residual: ndarray
- rmse: float
- simulated: ndarray
- simulated_map: object = None
- class pySED.compare_experiment.ScatteringMap(q_axis: numpy.ndarray, energy_axis: numpy.ndarray, intensity: numpy.ndarray, metadata: dict = None)
Bases:
object- energy_axis: ndarray
- intensity: ndarray
- metadata: dict = None
- q_axis: ndarray
- pySED.compare_experiment.align_intensity_map(intensity, source_q, source_energy, target_q, target_energy)
Interpolate a 2D q-energy map onto target experimental axes.
- pySED.compare_experiment.align_to_experiment(simulated_map, experimental_map)
Return the simulated map interpolated onto the experimental axes.
- pySED.compare_experiment.apply_quantum_correction_to_map(scattering_map, temperature, energy_unit='thz')
Apply the harmonic classical-to-quantum correction to a map.
- pySED.compare_experiment.broaden_energy(intensity, sigma_points, axis=-1)
- pySED.compare_experiment.compare_maps(simulated, experimental, normalization='max')
- pySED.compare_experiment.comparison_linecut_records(comparison, q_indices=None, energy_indices=None)
Return fixed-q and fixed-energy line-cut records.
The records use the normalized arrays stored in
pySED.compare_experiment.MapComparison, so they match the residual and scalar metrics used in the paper-ready comparison.
- pySED.compare_experiment.comparison_peak_records(comparison)
Return peak-tracking rows along the energy axis for every q point.
- pySED.compare_experiment.comparison_residual_map(comparison)
Return the residual as a calibrated
ScatteringMap.
- pySED.compare_experiment.comparison_summary(comparison)
Return JSON-ready scalar metrics for a map comparison.
- pySED.compare_experiment.convolve_q_resolution(intensity, sigma_q_points, sigma_energy_points=0.0)
- pySED.compare_experiment.convolve_resolution_units(scattering_map, sigma_q=None, sigma_energy=None)
Apply Gaussian q/energy resolution using physical axis units.
- pySED.compare_experiment.crop_image(image, crop=None)
Crop an image with
(row_start, row_stop, col_start, col_stop).
- pySED.compare_experiment.image_to_grayscale(image, channel_weights=(0.299, 0.587, 0.114))
Convert a grayscale/RGB/RGBA image array to a 2D intensity array.
- pySED.compare_experiment.interpolate_energy_axis(intensity, source_energy, target_energy, axis=-1)
- pySED.compare_experiment.linecut(intensity, index, axis=0)
- pySED.compare_experiment.load_intensity_map(path, delimiter=None)
Load an experimental intensity map from .npy or text/CSV.
- pySED.compare_experiment.load_scattering_map_image(path, q_range, energy_range, crop=None, invert=False, origin='upper', normalization=None, channel_weights=(0.299, 0.587, 0.114), metadata=None)
Load an image file and calibrate it into a
ScatteringMap.
- pySED.compare_experiment.map_value_records(scattering_map, value_name='intensity')
Return flattened q-energy map records for CSV export.
- pySED.compare_experiment.normalize_intensity(intensity, method='max', eps=1e-30)
- pySED.compare_experiment.prepare_map_comparison(simulated_map, experimental_map, sigma_q=None, sigma_energy=None, normalization='max', quantum_temperature=None, energy_unit='thz')
Align, optionally quantum-correct, broaden, normalize, and compare maps.
- pySED.compare_experiment.scattering_map_from_image(image, q_range, energy_range, crop=None, invert=False, origin='upper', normalization=None, channel_weights=(0.299, 0.587, 0.114), metadata=None)
Calibrate an image array into a
ScatteringMap.q_rangeis mapped left-to-right across image columns.energy_rangeis mapped bottom-to-top fororigin="upper"images, matching ordinary image files where row zero is the top of the image.
- pySED.compare_experiment.track_peak_positions(intensity, energy_axis, axis=-1)
- pySED.compare_experiment.write_map_comparison_report(comparison, output_dir, prefix='comparison', write_residual=True, write_peaks=True, linecut_q_indices=None, linecut_energy_indices=None)
Write paper-ready comparison metrics and tables.
The report consists of a JSON summary plus optional flattened CSV tables for the residual map, q-resolved peak tracking, and fixed-q/fixed-energy line cuts.
Scattering Plots
Plotting helpers for paper-ready scattering-map comparisons.
- pySED.scattering_plot.plot_linecuts(simulated_map, experimental_map=None, q_indices=None, ax=None, labels=None, energy_label='Energy', intensity_label='Intensity', save_path=None, dpi=300)
Plot energy line cuts at selected q indices.
- pySED.scattering_plot.plot_map_comparison(comparison, q_label='Q path', energy_label='Energy', cmap='magma', residual_cmap='coolwarm', q_indices=None, figsize=(10.0, 6.2), save_path=None, dpi=300)
Create a simulated/experimental/residual map and line-cut figure.
- pySED.scattering_plot.plot_scattering_map(scattering_map, ax=None, title=None, cmap='magma', vmin=None, vmax=None, q_label='Q path', energy_label='Energy', colorbar=True, save_path=None, dpi=300)
Plot a single q-energy scattering map.
Returns
(fig, ax, image)so callers can further tune labels, ticks, or panel annotations before saving.
Scattering Workflows
High-level workflows for experiment-facing scattering maps.
- class pySED.scattering_workflow.CurrentCorrelationWorkflowResult(advisor: QAdvisor, q_advice: list, qpoints_reduced: ndarray, qpoints_cartesian: ndarray, current: object, scattering_map: ScatteringMap = None, comparison: object = None)
Bases:
objectOutputs from q-advised longitudinal/transverse current spectra.
- comparison: object = None
- current: object
- q_advice: list
- qpoints_cartesian: ndarray
- qpoints_reduced: ndarray
- scattering_map: ScatteringMap = None
- class pySED.scattering_workflow.DSFWorkflowResult(advisor: QAdvisor, q_advice: list, qpoints_reduced: ndarray, qpoints_cartesian: ndarray, dsf: object, scattering_map: ScatteringMap = None, comparison: object = None)
Bases:
objectOutputs from q-advised DSF calculation.
- comparison: object = None
- dsf: object
- q_advice: list
- qpoints_cartesian: ndarray
- qpoints_reduced: ndarray
- scattering_map: ScatteringMap = None
- class pySED.scattering_workflow.EELSWorkflowResult(advisor: QAdvisor, q_advice: list, eigen_sed: object, visibility: object, eels_map: object, scattering_map: ScatteringMap, comparison: object = None, q_plan: object = None)
Bases:
objectOutputs from the MD-to-extended-zone-EELS workflow.
- comparison: object = None
- eels_map: object
- eigen_sed: object
- q_advice: list
- q_plan: object = None
- scattering_map: ScatteringMap
- visibility: object
- class pySED.scattering_workflow.OnePhononWorkflowResult(advisor: QAdvisor, q_advice: list, eigen_sed: object, visibility: object, one_phonon_map: object, scattering_map: ScatteringMap, comparison: object = None, q_plan: object = None)
Bases:
objectOutputs from eigen-SED-to-INS/IXS one-phonon workflow.
- comparison: object = None
- eigen_sed: object
- one_phonon_map: object
- q_advice: list
- q_plan: object = None
- scattering_map: ScatteringMap
- visibility: object
- class pySED.scattering_workflow.PartialDSFWorkflowResult(advisor: QAdvisor, q_advice: list, qpoints_reduced: ndarray, qpoints_cartesian: ndarray, partial_dsf: object, scattering_map: ScatteringMap = None, comparison: object = None)
Bases:
objectOutputs from q-advised species-partial DSF calculation.
- comparison: object = None
- partial_dsf: object
- q_advice: list
- qpoints_cartesian: ndarray
- qpoints_reduced: ndarray
- scattering_map: ScatteringMap = None
- pySED.scattering_workflow.compute_current_correlation_workflow(positions, velocities, qpoints, primitive_cell, supercell_cell, dt, qpoint_coordinates='reduced', q_policy='strict', max_error_reduced=None, max_error_cartesian=None, map_component='longitudinal', q_axis=None, experimental_map=None, sigma_q=None, sigma_energy=None, normalization='max', quantum_temperature=None, output_energy_unit='thz', **current_kwargs)
Validate/map requested Q points before computing current spectra.
- pySED.scattering_workflow.compute_dsf_workflow(positions, qpoints, primitive_cell, supercell_cell, dt, qpoint_coordinates='reduced', q_policy='strict', max_error_reduced=None, max_error_cartesian=None, map_component='total', q_axis=None, experimental_map=None, sigma_q=None, sigma_energy=None, normalization='max', quantum_temperature=None, output_energy_unit='thz', **dsf_kwargs)
Validate or map requested Q points before computing DSF.
q_policy="strict"rejects non-commensurate points."nearest"maps each requested point to the nearest commensurate point while preserving the extended-zone reciprocal-lattice image, soQ = q + Gis not folded back to the first Brillouin zone.
- pySED.scattering_workflow.compute_eels_workflow(velocities, unitcell_vectors, basis_index, masses, primitive_cell, supercell_cell, eigenvectors, basis_positions_reduced, g_vectors_reduced, dt, num_blocks=1, sed_backend='cpu', target_qpoints_reduced=None, electron_form_factors=None, atom_types=None, electron_form_factor_model='unit', electron_form_factor_table=None, electron_missing='raise', pairwise_g_vectors=False, g_index=0, q_axis=None, experimental_map=None, sigma_q=None, sigma_energy=None, normalization='max', quantum_temperature=None, output_energy_unit='thz')
Run the commensurate-q, eigen-SED, and kinematic EELS workflow.
This function is intentionally a workflow wrapper around the lower-level modules. It keeps the paper-facing sequence explicit:
q_advisor -> eigen_sed -> EELS visibility -> extended-zone map.
- pySED.scattering_workflow.compute_eels_workflow_from_angle_axis(velocities, unitcell_vectors, basis_index, masses, primitive_cell, supercell_cell, eigenvectors, basis_positions_reduced, angle_axis, beam_energy_ev, dt, direction=(1.0, 0.0), energy_loss_ev=0.0, angle_unit='mrad', include_longitudinal=False, q_policy='strict', max_error_reduced=None, max_error_cartesian=None, num_blocks=1, sed_backend='cpu', electron_form_factors=None, atom_types=None, electron_form_factor_model='unit', electron_form_factor_table=None, electron_missing='raise', q_axis=None, experimental_map=None, sigma_q=None, sigma_energy=None, normalization='max', quantum_temperature=None, output_energy_unit='thz')
Run q-EELS workflow from a calibrated detector scattering-angle axis.
The angle axis is converted to Cartesian momentum transfer with
pySED.electron_kinematics.eels_qpoints_from_angle_axis(), then the standard extended-zone q-path workflow is used.
- pySED.scattering_workflow.compute_eels_workflow_from_q_path(velocities, unitcell_vectors, basis_index, masses, primitive_cell, supercell_cell, eigenvectors, basis_positions_reduced, experimental_qpoints, dt, qpoint_coordinates='cartesian', q_policy='strict', max_error_reduced=None, max_error_cartesian=None, num_blocks=1, sed_backend='cpu', electron_form_factors=None, atom_types=None, electron_form_factor_model='unit', electron_form_factor_table=None, electron_missing='raise', q_axis=None, experimental_map=None, sigma_q=None, sigma_energy=None, normalization='max', quantum_temperature=None, output_energy_unit='thz')
Run the EELS workflow directly from an experimental extended-zone Q path.
This wrapper performs the full experiment-facing sequence:
experimental Q -> q_plan(Q=q+G) -> eigen-SED at folded q -> pairwise EELS map.
- pySED.scattering_workflow.compute_one_phonon_workflow(velocities, unitcell_vectors, basis_index, masses, primitive_cell, supercell_cell, eigenvectors, basis_positions_reduced, g_vectors_reduced, dt, atom_types=None, experiment='neutron', scattering_weights=None, frequency_power=0, num_blocks=1, sed_backend='cpu', target_qpoints_reduced=None, pairwise_g_vectors=False, g_index=0, q_axis=None, experimental_map=None, sigma_q=None, sigma_energy=None, normalization='max', quantum_temperature=None, output_energy_unit='thz')
Run commensurate-q, eigen-SED, and one-phonon INS/IXS workflow.
- pySED.scattering_workflow.compute_one_phonon_workflow_from_q_path(velocities, unitcell_vectors, basis_index, masses, primitive_cell, supercell_cell, eigenvectors, basis_positions_reduced, experimental_qpoints, dt, qpoint_coordinates='cartesian', q_policy='strict', max_error_reduced=None, max_error_cartesian=None, atom_types=None, experiment='neutron', scattering_weights=None, frequency_power=0, num_blocks=1, sed_backend='cpu', q_axis=None, experimental_map=None, sigma_q=None, sigma_energy=None, normalization='max', quantum_temperature=None, output_energy_unit='thz')
Run coherent INS/IXS one-phonon workflow from an experimental Q path.
- pySED.scattering_workflow.compute_partial_dsf_workflow(positions, qpoints, primitive_cell, supercell_cell, dt, atom_types, qpoint_coordinates='reduced', q_policy='strict', max_error_reduced=None, max_error_cartesian=None, map_component='weighted_total', species_pair=None, complex_part='real', q_axis=None, experimental_map=None, sigma_q=None, sigma_energy=None, normalization='max', quantum_temperature=None, output_energy_unit='thz', **partial_kwargs)
Validate/map requested Q points before computing species-partial DSF.
- pySED.scattering_workflow.current_correlation_to_scattering_map(current_result, component='longitudinal', q_axis=None, source_energy_unit='thz', output_energy_unit='thz')
Convert a longitudinal/transverse current spectrum to a q-energy map.
- pySED.scattering_workflow.dsf_to_scattering_map(dsf_result, component='total', q_axis=None, source_energy_unit='thz', output_energy_unit='thz')
Convert a DSF result component into a q-energy scattering map.
- pySED.scattering_workflow.eels_map_to_scattering_map(eels_map, g_index=0, q_axis=None, source_energy_unit='thz', output_energy_unit='thz')
Select one extended-zone G branch as a 2D q-energy map.
The returned q axis is the cumulative Cartesian path distance unless a user-supplied
q_axisis provided.
- pySED.scattering_workflow.one_phonon_map_to_scattering_map(one_phonon_map, g_index=0, q_axis=None, source_energy_unit='thz', output_energy_unit='thz')
Select one extended-zone G branch from an INS/IXS one-phonon map.
- pySED.scattering_workflow.partial_dsf_to_scattering_map(partial_result, component='weighted_total', species_pair=None, complex_part='real', q_axis=None, source_energy_unit='thz', output_energy_unit='thz')
Convert a partial DSF component into a q-energy scattering map.
component="weighted_total"returns the probe-weighted coherent total.component="partial"selects one species pair from the complex partial matrix and returns its real part, imaginary part, or magnitude.
- pySED.scattering_workflow.q_path_axis(qpoints_cartesian)
Return cumulative path distance for ordered Cartesian Q points.
Scattering Export
Export helpers for paper-ready scattering workflow bundles.
- pySED.scattering_export.workflow_export_summary(result, diagnostics=None)
Return a JSON-ready summary for a scattering workflow result.
- pySED.scattering_export.write_scattering_workflow_bundle(result, output_dir, prefix='workflow', atom_labels=None, mode_labels=None, include_all_visibility=True, visibility_relative_threshold=None, linecut_q_indices=None, linecut_energy_indices=None, write_scattering_map=True)
Write a reproducible bundle for a DSF/EELS/INS/IXS workflow result.
The bundle gathers q-advisor decisions, folded phonopy q points, simulated maps, visibility diagnostics, and experimental comparison tables when those objects are present on
result.
Validation
Validation helpers for scattering implementations.
- class pySED.validation.DSFValidationCase(positions: ndarray, qpoints_cartesian: ndarray, coherent_weights: ndarray, dt: float, num_blocks: int = 4, description: str = 'synthetic deterministic trajectory')
Bases:
objectSmall deterministic DSF validation problem.
- coherent_weights: ndarray
- description: str = 'synthetic deterministic trajectory'
- dt: float
- num_blocks: int = 4
- positions: ndarray
- qpoints_cartesian: ndarray
- class pySED.validation.SpectrumComparison(passed: bool, candidate_shape: tuple, reference_shape: tuple, normalization: str, scale_factor: float, rmse: float, mae: float, max_abs: float, normalized_rmse: float, correlation: float, peak_frequency_mae: float = None, reason: str = None)
Bases:
objectMetrics for comparing a pySED spectrum with an external reference.
- candidate_shape: tuple
- correlation: float
- mae: float
- max_abs: float
- normalization: str
- normalized_rmse: float
- passed: bool
- peak_frequency_mae: float = None
- reason: str = None
- reference_shape: tuple
- rmse: float
- scale_factor: float
- to_dict()
- pySED.validation.build_dsf_validation_report(case=None, tolerance=1e-12)
Build a structured DSF validation report.
- pySED.validation.compare_arrays(candidate, reference, atol=1e-12, rtol=1e-12)
Return scalar comparison metrics between two arrays.
- pySED.validation.compare_external_dsf_reference(reference_path, reference_key='coherent', reference_frequency_key=None, case=None, component='coherent', normalization='least_squares', rmse_tolerance=None)
Compare pySED DSF with an external dynasor/pynamic-style
.npzoutput.
- pySED.validation.compare_reference_spectrum(candidate, reference, candidate_frequencies=None, reference_frequencies=None, normalization='least_squares', rmse_tolerance=None)
Compare a spectrum against an external reference spectrum.
The last axis is treated as frequency. If both frequency grids are supplied and differ, the reference is interpolated onto the candidate grid before scalar metrics are computed.
- pySED.validation.compute_pysed_validation_pair(case=None)
Compute pySED direct and explicit-correlation DSF for one case.
- pySED.validation.export_dsf_validation_case(path, case=None, include_pysed_reference=True)
Export a deterministic validation case as an
.npzfile.
- pySED.validation.load_dsf_validation_case(path)
Load a validation case exported by
export_dsf_validation_case().
- pySED.validation.optional_scattering_package_report()
Report optional package availability for external DSF validation.
- pySED.validation.package_status(module_name)
Return installation metadata for an optional validation dependency.
- pySED.validation.run_internal_dsf_reference_validation(case=None, tolerance=1e-12)
Validate pySED’s direct estimator against its explicit correlation path.
- pySED.validation.synthetic_dsf_validation_case(num_frames=64)
Return a deterministic trajectory and weighted Q points.
- pySED.validation.validation_environment()
Return reproducibility metadata for a validation report.
- pySED.validation.write_validation_report(report, path)
Write a JSON validation report.