aiida_pythonjob_ins.pythonjobs ============================== .. py:module:: aiida_pythonjob_ins.pythonjobs .. autoapi-nested-parse:: AiiDA process wrappers around the atomic Euphonic operations. We use ``aiida-pythonjob`` to run the plain functions in :mod:`aiida_pythonjob_ins.operations` as AiiDA ``PythonJob`` processes. ``PythonJob`` runs through a ``Code`` on a ``Computer`` (localhost in tests, but any configured machine in production), so the standard AiiDA Computer/Code hooks apply. See https://github.com/aiidateam/aiida-pythonjob . Code-environment note: aiida-pythonjob cloudpickles these module-level functions *by reference* -- a tiny module+name string per job -- so the remote unpickles via ``from aiida_pythonjob_ins.operations import ...``. That module's import chain is deliberately AiiDA-free, so loading the function on the remote does not import or initialise aiida (no profile/config needed there). By-reference pickling is the required execution strategy: scientific dependencies like Euphonic, NumPy, and seekpath contain compiled C-extensions that cannot be pickled by value. See "Remote Execution, Pickling, and register_pickle_by_value" in docs/source/design_notes.rst. Functions --------- .. autoapisummary:: aiida_pythonjob_ins.pythonjobs.band_path_qpoints aiida_pythonjob_ins.pythonjobs.calculate_dispersion aiida_pythonjob_ins.pythonjobs.calculate_dos aiida_pythonjob_ins.pythonjobs.calculate_tosca_spectrum aiida_pythonjob_ins.pythonjobs.interpolate_phonon_modes aiida_pythonjob_ins.pythonjobs.interpolate_phonon_modes_on_grid aiida_pythonjob_ins.pythonjobs.read_force_constants_from_castep aiida_pythonjob_ins.pythonjobs.read_force_constants_from_phonopy aiida_pythonjob_ins.pythonjobs.prepare_interpolation_inputs aiida_pythonjob_ins.pythonjobs.prepare_read_force_constants_inputs aiida_pythonjob_ins.pythonjobs.prepare_read_phonopy_inputs aiida_pythonjob_ins.pythonjobs.prepare_dispersion_inputs aiida_pythonjob_ins.pythonjobs.prepare_dos_inputs aiida_pythonjob_ins.pythonjobs.prepare_grid_interpolation_inputs aiida_pythonjob_ins.pythonjobs.prepare_tosca_spectrum_inputs Module Contents --------------- .. py:function:: band_path_qpoints(cell: tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray], q_spacing: float = 0.025, *, insert_gamma: bool = True) -> QpointPath Return a :class:`QpointPath` (q-points + labels + cell) for a band path. ``cell`` is a spglib-style ``(lattice, scaled_positions, numbers)`` tuple -- e.g. from ``euphonic.Crystal.to_spglib_cell()`` or an ASE ``Atoms``. Only the structure is needed; force constants are not. Pure/AiiDA-free: the parent-side ``generate_band_path`` calcfunction wraps this into a native ``KpointsData``. .. py:function:: calculate_dispersion(force_constants: euphonic.ForceConstants, q_spacing: float = 0.025, *, insert_gamma: bool = True, asr: str | None = 'reciprocal') -> euphonic.QpointPhononModes Convenience: build a band path and interpolate modes along it. .. py:function:: 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 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 (``None`` to disable). Returns ------- Spectrum1D Density of states vs energy (bin edges in ``x_data``, values in ``y_data``; use ``get_bin_centres()`` for matching x/y lengths). .. py:function:: 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 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_order`` sum, 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``. See :func:`tosca_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_max`` and ``final_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_data`` metadata under ``atom_symbol``, ``quantum_order`` and ``detector_angle``. Not yet grouped or broadened. .. py:function:: interpolate_phonon_modes(force_constants: euphonic.ForceConstants, qpoints: numpy.ndarray, *, asr: str | None = 'reciprocal') -> euphonic.QpointPhononModes Fourier-interpolate phonon modes at the given fractional q-points. ``qpoints`` is an ``(N, 3)`` array in the crystal's reciprocal basis (as provided by an AiiDA ``KpointsData``). This is the core ``ForceConstants -> QpointPhononModes`` step. .. py:function:: interpolate_phonon_modes_on_grid(force_constants: euphonic.ForceConstants, q_spacing: float = 0.1, *, asr: str | None = 'reciprocal') -> euphonic.QpointPhononModes Interpolate phonon modes on a Monkhorst-Pack grid (a powder average). Unlike :func:`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 way :func:`calculate_dos` does -- the sampling :class:`ToscaFromForceConstantsWorkChain ` needs. The almost-isotropic incoherent approximation disregards actual q-point *positions* (see the reference pipeline's kinematic treatment in :func:`calculate_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 (``None`` to disable). .. py:function:: read_force_constants_from_castep(filename: str | pathlib.Path) -> euphonic.ForceConstants Read a CASTEP ``.castep_bin``/``.check`` file into ``ForceConstants``. A thin wrapper over ``ForceConstants.from_castep``. It exists because a PythonJob's ``function`` must be a plain module-level function: a bound classmethod (``ForceConstants.from_castep``) is a ``method``, not a ``FunctionType``, so aiida-pythonjob's ``build_function_data`` rejects it. The wrapper is also where we attach logging. ``filename`` is resolved relative to the working directory. When run as a PythonJob the CASTEP file is staged there via ``upload_files`` (see :func:`aiida_pythonjob_ins.pythonjobs.prepare_read_force_constants_inputs`). .. py:function:: read_force_constants_from_phonopy(summary_name: str = 'phonopy.yaml', fc_name: str = 'FORCE_CONSTANTS', born_name: str | None = None) -> euphonic.ForceConstants Read force constants from Phonopy output into ``ForceConstants``. Thin wrapper over ``ForceConstants.from_phonopy`` (requires euphonic's ``phonopy-reader`` extra, which this package installs by default). All names are resolved in the working directory; when run as a PythonJob the files are staged there via ``upload_files`` (see :func:`aiida_pythonjob_ins.pythonjobs.prepare_read_phonopy_inputs`). ``born_name`` is optional (Born charges for LO-TO splitting); pass ``None`` to skip it. .. py:function:: prepare_interpolation_inputs(force_constants: aiida.orm.Data, qpoints: aiida.orm.KpointsData, *, computer: str | aiida.orm.Computer = 'localhost', code: aiida.orm.AbstractCode | None = None, **kwargs: Any) -> dict[str, Any] Build inputs to run :func:`interpolate_phonon_modes` as a PythonJob. ``qpoints`` is a native ``KpointsData`` q-point specification, deserialized to a fractional-coordinate array before interpolation. The returned modes are serialized to a :class:`~aiida_pythonjob_ins.data.QpointPhononModesData`. .. py:function:: prepare_read_force_constants_inputs(castep_file: str | aiida.orm.SinglefileData, *, computer: str | aiida.orm.Computer = 'localhost', code: aiida.orm.AbstractCode | None = None, **kwargs: Any) -> dict[str, Any] Build inputs to run :func:`read_force_constants_from_castep` as a PythonJob. The CASTEP file is staged into the job's working directory via ``upload_files`` (mirroring how a real remote calculation stages its inputs); the function then reads it by basename and returns a ``ForceConstants`` serialized to a :class:`~aiida_pythonjob_ins.data.ForceConstantsData` node. .. py:function:: prepare_read_phonopy_inputs(summary: str | aiida.orm.SinglefileData, force_constants: str | aiida.orm.SinglefileData, born: str | aiida.orm.SinglefileData | None = None, *, computer: str | aiida.orm.Computer = 'localhost', code: aiida.orm.AbstractCode | None = None, **kwargs: Any) -> dict[str, Any] Build inputs to run :func:`read_force_constants_from_phonopy` as a PythonJob. The Phonopy ``summary`` (``phonopy.yaml``), ``force_constants`` (e.g. ``FORCE_CONSTANTS``) and optional ``born`` (``BORN``) files are staged into the working directory via ``upload_files``; the function reads them by basename and returns a ``ForceConstants`` serialized to a ``ForceConstantsData`` node. .. py:function:: prepare_dispersion_inputs(force_constants: aiida.orm.Data, q_spacing: float = 0.025, *, computer: str | aiida.orm.Computer = 'localhost', code: aiida.orm.AbstractCode | None = None, **kwargs: Any) -> dict[str, Any] Build the input dict to run :func:`calculate_dispersion` as a PythonJob. Parameters ---------- force_constants A :class:`~aiida_pythonjob_ins.data.ForceConstantsData` node. It is deserialized to a Euphonic ``ForceConstants`` before the function runs. q_spacing Target q-point spacing in 1/Angstrom. computer, code Standard AiiDA execution targets. If ``code`` is ``None``, aiida-pythonjob resolves/creates a Python code on ``computer``. kwargs Extra keyword arguments forwarded to ``prepare_pythonjob_inputs``. Returns ------- dict Inputs to launch with ``aiida.engine.run``/``submit`` and ``aiida_pythonjob.PythonJob``. .. py:function:: prepare_dos_inputs(force_constants: aiida.orm.Data, q_spacing: float = 0.1, energy_spacing: float = 1.0, *, computer: str | aiida.orm.Computer = 'localhost', code: aiida.orm.AbstractCode | None = None, **kwargs: Any) -> dict[str, Any] Build inputs to run :func:`calculate_dos` as a PythonJob. ``q_spacing`` is the target Monkhorst-Pack grid spacing (1/Angstrom) and ``energy_spacing`` the DOS bin width (meV). The returned euphonic ``Spectrum1D`` is serialized to a native ``XyData``. .. py:function:: prepare_grid_interpolation_inputs(force_constants: aiida.orm.Data, q_spacing: float = 0.1, *, computer: str | aiida.orm.Computer = 'localhost', code: aiida.orm.AbstractCode | None = None, **kwargs: Any) -> dict[str, Any] Build inputs to run :func:`interpolate_phonon_modes_on_grid` as a PythonJob. ``q_spacing`` is the target Monkhorst-Pack grid spacing (1/Angstrom), matching :func:`prepare_dos_inputs`'s convention. Used by ``ToscaFromForceConstantsWorkChain`` to obtain a powder-average q-point sampling for the TOSCA intensity calculation, as distinct from :func:`prepare_interpolation_inputs`'s caller-supplied path (used for a band structure). .. py:function:: prepare_tosca_spectrum_inputs(modes: aiida.orm.Data, 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', *, computer: str | aiida.orm.Computer = 'localhost', code: aiida.orm.AbstractCode | None = None, **kwargs: Any) -> dict[str, Any] Build inputs to run :func:`calculate_tosca_spectrum` as a PythonJob. ``modes`` is a :class:`~aiida_pythonjob_ins.data.QpointPhononModesData` node, deserialized to a Euphonic ``QpointPhononModes`` before the function runs. The returned ``Spectrum1DCollection`` -- the full, ungrouped line set -- is serialized to a single native ``XyData`` with one y array per line (see :func:`aiida_pythonjob_ins.conversions.spectrum_collection_to_xydata`). ``detector_angles`` defaults to ``None`` here (rather than a mutable literal default) and is passed through unchanged; :func:`calculate_tosca_spectrum` supplies the actual default (TOSCA's two banks) so it is documented in one place.