aiida_pythonjob_ins.operations¶
Atomic Euphonic operations, written as plain Python functions.
These functions use only the public Euphonic API and know nothing about
AiiDA, so they can be unit-tested directly and reused elsewhere. Crucially, this
module’s import chain is AiiDA-free (the package __init__ is empty), so
by-reference cloudpickling can target a lean remote environment (euphonic +
seekpath + numpy, no aiida). They are turned into AiiDA PythonJobs by the
helpers in aiida_pythonjob_ins.pythonjobs.
The dispersion workflow is built from composable pieces, mirroring
euphonic.cli.dispersion (https://euphonic.readthedocs.io/en/stable/cli.html)
without relying on Euphonic’s private _bands_from_force_constants helper:
band_path_qpoints()– build a high-symmetry q-point path (seekpath).interpolate_phonon_modes()– Fourier-interpolate modes at those points.
calculate_dispersion is a convenience that chains the two. The band path is
turned into a native KpointsData by a parent-side calcfunction (see
aiida_pythonjob_ins.workflows.dispersion.generate_band_path()), so these
functions stay AiiDA-free and unit-testable.
Attributes¶
Classes¶
A high-symmetry q-point path: positions + labels + cell (no energies). |
Functions¶
|
Read a CASTEP |
Read force constants from Phonopy output into |
|
|
Return a |
|
Fourier-interpolate phonon modes at the given fractional q-points. |
|
Convenience: build a band path and interpolate modes along it. |
|
Compute default bin edges with asymmetric padding and fixed physical spacing. |
|
Compute a phonon density of states by sampling a Monkhorst-Pack grid. |
Compute thermal mode/atomic displacements at a sample temperature. |
|
|
Indirect-geometry Q² for a scattering angle and analyser final energy. |
|
Build the TOSCA energy axis: data-sized, then clipped to the instrument. |
Apply TOSCA's energy-dependent resolution broadening to a spectrum. |
|
Interpolate phonon modes on a Monkhorst-Pack grid (a powder average). |
|
|
Compute the full, ungrouped TOSCA intensity line set from phonon modes. |
Module Contents¶
- aiida_pythonjob_ins.operations.LOGGER¶
- class aiida_pythonjob_ins.operations.QpointPath[source]¶
Bases:
NamedTupleA high-symmetry q-point path: positions + labels + cell (no energies).
A well-defined return type for
band_path_qpoints(). It is a plainNamedTupleused purely on the Python side; the parent-sidegenerate_band_pathcalcfunction turns it into a nativeKpointsData.(Note: aiida-pythonjob would treat a
NamedTuplereturn annotation as a structured multi-output spec, splitting it into one output port per field. That does not apply here becauseband_path_qpointsis not used as a PythonJobfunction– if it were, the split into qpoints/labels/cell could even be desirable.)- qpoints: numpy.ndarray¶
- labels: list[tuple[int, str]]¶
- cell: numpy.ndarray¶
- aiida_pythonjob_ins.operations.read_force_constants_from_castep(filename: str | pathlib.Path) euphonic.ForceConstants[source]¶
Read a CASTEP
.castep_bin/.checkfile intoForceConstants.A thin wrapper over
ForceConstants.from_castep. It exists because a PythonJob’sfunctionmust be a plain module-level function: a bound classmethod (ForceConstants.from_castep) is amethod, not aFunctionType, so aiida-pythonjob’sbuild_function_datarejects it. The wrapper is also where we attach logging.filenameis resolved relative to the working directory. When run as a PythonJob the CASTEP file is staged there viaupload_files(seeaiida_pythonjob_ins.pythonjobs.prepare_read_force_constants_inputs()).
- aiida_pythonjob_ins.operations.read_force_constants_from_phonopy(summary_name: str = 'phonopy.yaml', fc_name: str = 'FORCE_CONSTANTS', born_name: str | None = None) euphonic.ForceConstants[source]¶
Read force constants from Phonopy output into
ForceConstants.Thin wrapper over
ForceConstants.from_phonopy(requires euphonic’sphonopy-readerextra, which this package installs by default). All names are resolved in the working directory; when run as a PythonJob the files are staged there viaupload_files(seeaiida_pythonjob_ins.pythonjobs.prepare_read_phonopy_inputs()).born_nameis optional (Born charges for LO-TO splitting); passNoneto skip it.
- aiida_pythonjob_ins.operations.band_path_qpoints(cell: tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray], q_spacing: float = 0.025, *, insert_gamma: bool = True) QpointPath[source]¶
Return a
QpointPath(q-points + labels + cell) for a band path.cellis a spglib-style(lattice, scaled_positions, numbers)tuple – e.g. fromeuphonic.Crystal.to_spglib_cell()or an ASEAtoms. Only the structure is needed; force constants are not. Pure/AiiDA-free: the parent-sidegenerate_band_pathcalcfunction wraps this into a nativeKpointsData.
- aiida_pythonjob_ins.operations.interpolate_phonon_modes(force_constants: euphonic.ForceConstants, qpoints: numpy.ndarray, *, asr: str | None = 'reciprocal') euphonic.QpointPhononModes[source]¶
Fourier-interpolate phonon modes at the given fractional q-points.
qpointsis an(N, 3)array in the crystal’s reciprocal basis (as provided by an AiiDAKpointsData). This is the coreForceConstants -> QpointPhononModesstep.
- aiida_pythonjob_ins.operations.calculate_dispersion(force_constants: euphonic.ForceConstants, q_spacing: float = 0.025, *, insert_gamma: bool = True, asr: str | None = 'reciprocal') euphonic.QpointPhononModes[source]¶
Convenience: build a band path and interpolate modes along it.
- aiida_pythonjob_ins.operations.default_energy_bins(frequencies: pint.Quantity, energy_spacing: pint.Quantity, *, padding_fraction: float = 0.05) pint.Quantity[source]¶
Compute default bin edges with asymmetric padding and fixed physical spacing.
Parameters¶
- frequencies
Phonon frequencies as a dimensional Quantity.
- energy_spacing
Width of each energy bin as a dimensional Quantity (e.g.
1.0 * ureg('meV')).- padding_fraction
Fractional padding based on the occupied frequency span (default: 0.05). Always added above the maximum frequency; added below the minimum frequency only if negative (imaginary modes present).
Returns¶
- pint.Quantity
Bin edges with uniform spacing in the units of
energy_spacing.
- aiida_pythonjob_ins.operations.calculate_dos(force_constants: euphonic.ForceConstants, q_spacing: float = 0.1, energy_spacing: float = 1.0, *, energy_unit: str = 'meV', adaptive: bool = True, asr: str | None = 'reciprocal') euphonic.Spectrum1D[source]¶
Compute a phonon density of states by sampling a Monkhorst-Pack grid.
Parameters¶
- force_constants
Interatomic force constants to interpolate from.
- q_spacing
Target spacing of the sampling grid, in 1/Angstrom (finer -> denser grid).
- energy_spacing
Width of the DOS energy bins, in
energy_unit.- energy_unit
Unit for the energy axis (e.g.
"meV","1/cm").- adaptive
Use adaptive broadening (per-mode widths from mode gradients) rather than fixed bins. Recommended; requires computing mode gradients.
- asr
Acoustic sum rule applied during interpolation (
Noneto disable).
Returns¶
- Spectrum1D
Density of states vs energy (bin edges in
x_data, values iny_data; useget_bin_centres()for matching x/y lengths).
- aiida_pythonjob_ins.operations.calculate_thermal_displacements(modes: euphonic.QpointPhononModes, temperature: float) tuple[abinslib.displacements.Displacements, pint.Quantity][source]¶
Compute thermal mode/atomic displacements at a sample temperature.
Thin wrapper over
Displacements.from_modesand.to_atomic_displacements(). The atomic displacements determine the Debye-Waller attenuation applied by the intensity calculations below.Parameters¶
- modes
Phonon frequencies and eigenvectors.
- temperature
Sample temperature in kelvin.
Returns¶
- tuple[Displacements, pint.Quantity]
The per-mode displacement dataset and the derived per-atom displacement tensor (
Quantity, shape(n_atoms, 3, 3)).
- aiida_pythonjob_ins.operations.calculate_scattering_q2(energy_transfer: pint.Quantity, detector_angle: float, final_energy: float, *, energy_unit: str = '1/cm') pint.Quantity[source]¶
Indirect-geometry Q² for a scattering angle and analyser final energy.
Thin wrapper over
abinslib.util.calculate_indirect_q2that takes the detector angle in degrees (the natural unit for describing a bank) rather than radians, and the final energy as a plain float inenergy_unit(matching the other TOSCA operations’ unit convention) rather than a pre-builtQuantity.Called once per detector bank, with
energy_transferset to the mode frequencies for the fundamental calculation and to the output bin centres for the combination-mode calculation – the two kinematic evaluations the reference pipeline performs.
- aiida_pythonjob_ins.operations.tosca_energy_bins(frequencies: pint.Quantity, energy_spacing: pint.Quantity, energy_max: pint.Quantity, *, max_quantum_order: int = 2) pint.Quantity[source]¶
Build the TOSCA energy axis: data-sized, then clipped to the instrument.
Reuses
default_energy_bins()’ padding and bin-alignment rule, sized from the fundamental frequencies scaled by the highest quantum order to be computed (combination modes extend to roughly that multiple of the fundamental range), then clips to whichever of the data range orenergy_maxis tighter.The lower end is additionally clipped at zero. Unlike a density of states, where a negative energy indicates a real, physically meaningful soft mode, TOSCA measures only energy loss from the neutron to the sample: an energy transfer below zero (let alone below
-final_energy) is kinematically inaccessible, and evaluating the Q² relation there produces nonsense (calculate_scattering_q2takes a square root that goes complex). A q-point mesh’s small numerical noise around an acoustic mode at the zone centre is enough to trigger asymmetric padding on the negative side, so this clip is not merely a corner case.
- aiida_pythonjob_ins.operations.broaden_tosca_spectrum(spectrum: euphonic.Spectrum1D | euphonic.Spectrum1DCollection, resolution_model: str = 'AbINS_v1') euphonic.Spectrum1D | euphonic.Spectrum1DCollection[source]¶
Apply TOSCA’s energy-dependent resolution broadening to a spectrum.
Broadens on the spectrum’s own bin centres (
points == mesh), so no rebinning takes place – only the resolution-smeared intensity changes. Becauseresins’ broadening operator is linear, this gives the same result whether applied before or after summing lines (seegroup_spectra/broaden_spectrainaiida_pythonjob_ins.workflows.tosca, which rely on this).A collection is broadened line by line: the underlying
resinsmodel only accepts a single 1-D intensity array per call (seeInstrumentModel.broaden), not a 2-D stack of lines.
- aiida_pythonjob_ins.operations.interpolate_phonon_modes_on_grid(force_constants: euphonic.ForceConstants, q_spacing: float = 0.1, *, asr: str | None = 'reciprocal') euphonic.QpointPhononModes[source]¶
Interpolate phonon modes on a Monkhorst-Pack grid (a powder average).
Unlike
interpolate_phonon_modes(), which evaluates a caller-supplied set of q-points (e.g. a high-symmetry band path), this samples the whole Brillouin zone the waycalculate_dos()does – the samplingToscaFromForceConstantsWorkChainneeds. The almost-isotropic incoherent approximation disregards actual q-point positions (see the reference pipeline’s kinematic treatment incalculate_tosca_spectrum()), but still needs a representative density of modes across the zone, exactly as a DOS does.Parameters¶
- force_constants
Interatomic force constants to interpolate from.
- q_spacing
Target spacing of the sampling grid, in 1/Angstrom (finer -> denser grid).
- asr
Acoustic sum rule applied during interpolation (
Noneto disable).
- aiida_pythonjob_ins.operations.calculate_tosca_spectrum(modes: euphonic.QpointPhononModes, temperature: float = 10.0, energy_spacing: float = 10.0, energy_max: float = 4000.0, detector_angles: list[float] | None = None, final_energy: float = 32.0, energy_unit: str = '1/cm') euphonic.Spectrum1DCollection[source]¶
Compute the full, ungrouped TOSCA intensity line set from phonon modes.
Combines fundamental (one-phonon) and combination (two-phonon) intensities in the almost-isotropic incoherent approximation, for every requested detector bank, into a single collection with one line per atom, quantum order and detector angle – mirroring the reference pipeline’s
fundamentals + second_ordersum, repeated per bank.Parameters¶
- modes
Phonon frequencies and eigenvectors (e.g. from a molecular-crystal calculation; the almost-isotropic approximation assumes hydrogenous, largely incoherent scattering).
- temperature
Sample temperature in kelvin, governing the Debye-Waller attenuation.
- energy_spacing, energy_max
Energy axis bin width and instrument-range cutoff, in
energy_unit. Seetosca_energy_bins().- detector_angles
Scattering angles in degrees, one per detector bank to evaluate. Defaults to TOSCA’s backward (135°) and forward (45°) banks.
- final_energy
Analyser-fixed final neutron energy, in
energy_unit.- energy_unit
Unit for
energy_spacing,energy_maxandfinal_energy. TOSCA results are conventionally reported in wavenumbers.
Returns¶
- Spectrum1DCollection
One line per (atom, quantum order, detector angle), each carrying that triple in its
line_datametadata underatom_symbol,quantum_orderanddetector_angle. Not yet grouped or broadened.