lineshape_tools.cli =================== .. py:module:: lineshape_tools.cli .. autoapi-nested-parse:: Contains functionality for the command line interface. Functions --------- .. autoapisummary:: lineshape_tools.cli.collect lineshape_tools.cli.get_force_opt_modes lineshape_tools.cli.get_random_phonons lineshape_tools.cli.gen_confs lineshape_tools.cli.reestimate_e0s_linear_system lineshape_tools.cli.gen_ft_config lineshape_tools.cli.parse_force_constants_file lineshape_tools.cli.convert_from_phonopy lineshape_tools.cli.compute_dynmat lineshape_tools.cli.compute_lineshape lineshape_tools.cli.analyze_dynmat Module Contents --------------- .. py:function:: collect(files: Annotated[list[pathlib.Path], Parameter(negative='')], output_file: pathlib.Path = Path('./database.extxyz'), strategy: str = 'none', read_index: str = ':', max_force: float = 2.0, min_force: float = -np.inf, dx_tol: float = 0.1, rtol: float = 1e-05, config_weight: float = 1.0, force_weighting: bool = False, allow_constraint: bool = False) -> None Collect and process data for fine-tuning. Collect files into an extxyz database that can be used for fine-tuning. An optional filtering strategy can be applied. This is potentially useful if relaxation data is being included in the dataset, as it can be noisey from having multiple closely spaced geometries close to the equilibrium geomtry. By default, configurations with too large forces will be thrown away to avoid potential anharmonic contributions to the PES. :param files: list of paths to files that are parseable by ase.io. The files should contain atomic geometries, total energies, and forces at a minimum (for example, vasprun.xml). :type files: list :param output_file: optional path where data is written (output to stdout by default) :type output_file: Path :param strategy: optional specification of strategy to be used for filtering. Available options are 'none', 'qr', or 'dx'. :type strategy: str :param read_index: pythonic index passed to ase.io.read to determine which structures are read from the input files (the same value is used for each file). The default ":" reads all of the structures, while ":3" would read the first three for example. :type read_index: str :param max_force: remove structures where the maximum force acting on any atom is above the specified value (in eV/Å) :type max_force: float :param min_force: remove structures where the maximum force acting on any atom is below the specified value (in eV/Å) :type min_force: float :param dx_tol: tolerance (in Å) for how far atoms must move to accept configuration in 'dx' filtering strategy :type dx_tol: float :param rtol: tolerance ratio for determining rank of displacement vectors in 'qr' strategy :type rtol: float :param config_weight: set the configuration weight for training :type config_weight: float :param force_weighting: store a config_weight that's inversely proportional to the max force that any atom feels in the configuration [min(0.02 / max_fpa, 1)]. Overwrites the value specified by config_weight. :type force_weighting: bool :param allow_constraint: allow constraints on atoms (e.g. selective dynamics) to modify the forces. This is typically not desirable. :type allow_constraint: bool .. py:function:: get_force_opt_modes(n: int, omega2: numpy.ndarray, U: numpy.ndarray, sqrt_mass: numpy.ndarray, F: float = 0.5, tol: float = 1e-06, seed: int = 897689932, start_with_min_spread: bool = False, save_plot: bool = False) -> tuple[numpy.ndarray, numpy.ndarray] Bin phonons by energy and find a vector in the subspace that minimizes the spread in forces. :param n: number of modes to select :type n: int :param omega2: frequencies squared of the modes (directly from np.linalg.eigh) :type omega2: np.ndarray :param U: matrix where eigenvectors of modes are cols (directly from np.linalg.eigh) :type U: np.ndarray :param sqrt_mass: sqrt of the vector of atomic masses :type sqrt_mass: np.ndarray :param F: target forces to optimize amplitudes for :type F: float :param tol: convergence tolerance for scipy minimize call :type tol: float :param seed: seed value for random number generator :type seed: int :param start_with_min_spread: determines if mode with smallest force spread is used as the starting point for optimization. Uses a random vector otherwise. :type start_with_min_spread: bool :param save_plot: save a plot for analyzing resulting modes :type save_plot: bool :returns: generated modes as columns of the matrix mode_dqs (np.ndarray): optimized displacement amplitudes following above criteria :rtype: modes (np.ndarray) .. py:function:: get_random_phonons(n: int, omega2: numpy.ndarray, U: numpy.ndarray, sqrt_mass: numpy.ndarray, F: float = 0.5, seed: int = 897689932) -> tuple[numpy.ndarray, numpy.ndarray] Bin phonons by energy and select one randomly from each bin. The amplitude of each phonon is chosen to produce a max force per atom as close to F as possible. The max displacement on a given atom is kept within a reasonable range (0.005, 0.05). :param n: number of modes to select :type n: int :param omega2: frequencies squared of the modes (directly from np.linalg.eigh) :type omega2: np.ndarray :param U: matrix where eigenvectors of modes are cols (directly from np.linalg.eigh) :type U: np.ndarray :param sqrt_mass: sqrt of the vector of atomic masses :type sqrt_mass: np.ndarray :param F: target forces to optimize amplitudes for :type F: float :param seed: seed value for random number generator :type seed: int :returns: generated modes as columns of the matrix mode_dqs (np.ndarray): optimized displacement amplitudes following above criteria :rtype: modes (np.ndarray) .. py:function:: gen_confs(struct_path: pathlib.Path, num_conf: int, strategy: str = 'rand', output_dir: pathlib.Path = Path('./confs'), accepting_mode: pathlib.Path | None = None, dynmat_file: pathlib.Path | None = None, orthogonalize: bool = False, default_max_dx: float = 0.015, start_with_min_spread: bool = False, opt_tol: float = 1e-06, seed: int = 897689932) -> None Generate additional configurations to enhance fine-tuning dataset. :param struct_path: path to file containing structure that will be displaced :type struct_path: Path :param num_conf: total number of additional configurations to generate :type num_conf: int :param strategy: strategy used to generate the additional configurations. Available options are 'rand', 'phon_rand', and 'phon_opt'. :type strategy: str :param output_dir: output directory where the new configurations will be written to :type output_dir: Path :param accepting_mode: path to file containing the structure that defines the accepting mode. For example, if struct_path refers to the ground-state equilibrium geometry, then accepting_mode should refer to the excited-state equilibrium geometry and vice versa. :type accepting_mode: Path :param dynmat_file: path to the .npz file containing the dynamical matrix presumably calculated using the "compute-dynmat" function. :type dynmat_file: Path :param orthogonalize: perform Gram-Schmidt orthogonalization at the last step :type orthogonalize: bool :param default_max_dx: default value for max displacement of a given atom :type default_max_dx: float :param start_with_min_spread: determines if mode with smallest force spread is used as the starting point for optimization in phon_opt strategy. Uses a random vector otherwise. :type start_with_min_spread: bool :param opt_tol: convergence tolerance for the call to scipy minimize in the phon_opt strat :type opt_tol: float :param seed: seed value for random number generator :type seed: int .. py:function:: reestimate_e0s_linear_system(calculator: mace.calculators.MACECalculator, database_atoms: list[ase.atoms.Atoms], elements: list | None = None, initial_e0s: dict | None = None) -> dict Estimate atomic reference energies (E0s) by solving a linear system. .. rubric:: Notes Slightly adapted from code by Noam Bernstein based on private communications with Ilyes Batatia and Joe Hart. This functionality will eventually be removed once merged into MACE. :param calculator: Calculator object for the MACE model. :type calculator: MACECalculator :param database_atoms: List of ase Atoms objects with energy and atomic_numbers. :type database_atoms: list :param elements: List of element atomic numbers to consider, default to set present in database_atoms. :type elements: list :param initial_e0s: Dictionary mapping element atomic numbers to E0 values, default to values returned by foundation_model for isolated atom configs> :type initial_e0s: dict :returns: Dictionary with re-estimated E0 values for each element .. py:function:: gen_ft_config(out: pathlib.Path | str = './config.default', estimate_e0s: bool = False, device: str = 'cuda', name: str = 'fine-tuned', mace_model: str = 'medium-omat-0', database: pathlib.Path | str = './database.extxyz', head: str = 'default') -> None Generate a configuration file for mace_run_train. :param out: path where the mace_run_train configuration file is written to. :type out: Path :param estimate_e0s: estimate the E0s for training of the foundation model. :type estimate_e0s: bool :param device: device string passed to MACE to determine where calculation is performed. :type device: str :param name: name of the model. :type name: str :param mace_model: pre-trained MACE model that is used, can be a local path :type mace_model: str :param database: path to the training dataset file (likely generated with :func:`collect`) :type database: Path :param head: which head from the model to use for prediction :type head: str .. py:function:: parse_force_constants_file(fname: pathlib.Path | str) -> numpy.ndarray Parse a force constants file from phonopy. .. py:function:: convert_from_phonopy(fname: pathlib.Path | str, atoms_file: pathlib.Path | str, save_file: pathlib.Path | str = 'dynmat.npz') -> None Convert phonopy FORCE_CONSTANTS to dynmat.npz. FORCE_CONSTANTS is written by phonopy when specifying the "--writefc" tag. :param fname: path to FORCE_CONSTANTS file. :type fname: Path :param atoms_file: path to file containing the equilibrium structure that was used to evaluate the force constants. (Only needed to extract sqrt masses.) :type atoms_file: Path :param save_file: path where dynamical matrix is saved to (should end in .npz) :type save_file: Path .. py:function:: compute_dynmat(input_struct: pathlib.Path, save_file: pathlib.Path = Path('./dynmat.npz'), mace_model: str = 'medium-omat-0', device: str = 'cuda', head: str = 'default', relax_struct: bool = True, analytical_hessian: bool = True, relax_algo: str = 'LBFGSLineSearch', fmax: float = 0.001) -> None Calculate the dynamical matrix using MACE. :param input_struct: structure about which to compute the dynamical matrix :type input_struct: Path :param save_file: path where dynamical matrix is saved to (should end in .npz) :type save_file: Path :param mace_model: pre-trained MACE model that is used, can be a local path :type mace_model: str :param device: device string passed to MACE to determine where calculation is performed :type device: str :param head: which head from the model to use for prediction :type head: str :param relax_struct: determines if an atomic relaxation is performed prior to computing the Hessian matrix. This is recommended if the model does not predict the same equilibrium structure as your explicit DFT calculation, which is generally the case unless good fine tuning has been performed. :type relax_struct: bool :param analytical_hessian: determines if the Hessian is computed analytically or numerically using finite differences :type analytical_hessian: bool :param relax_algo: name of algorithm from ase.optimize that is used for atomic relaxation. :type relax_algo: str :param fmax: force convergence criteria for atomic relaxation in eV/Ä :type fmax: float .. py:function:: compute_lineshape(ground: pathlib.Path, excited: pathlib.Path, dynmat_file: pathlib.Path, emission: Annotated[bool, Parameter(name='--luminescence', negative='--absorption')] = True, dE: float | None = None, gamma_zpl: float = 0.001, sigma_zpl: float = 0.0, sigma_psb: tuple[float, float] = (0.005, 0.001), gamma_psb: tuple[float, float] | None = None, omega_mult: float = 5.0, norm: str = 'area', T: Annotated[float, Parameter(name=['--T', '-T'])] = 0.0, plot: str | None = None) -> None Calculate the spectral density/function and lineshape for a given dynamical matrix. :param ground: path to structure containing the ground state equilibrium geometry. :type ground: Path :param excited: path to structure containing the excited state equilibrium geometry. :type excited: Path :param dynmat_file: path to dynamical matrix file produced by :func:`compute_dynmat` or by phonopy and converted with :func:`convert_from_phonopy`. :type dynmat_file: Path :param emission: write luminescence (True) or absorption (False) spectrum. :type emission: bool :param dE: zero-phonon line energy in eV, inferred from ground/excited if not provided. :type dE: float :param gamma_zpl: Lorentzian broadening in the ZPL to capture homogeneous broadening. :type gamma_zpl: float :param sigma_zpl: Gaussian broadening in the ZPL to capture inhomogeneous broadening. :type sigma_zpl: float :param sigma_psb: Gaussian broadening used to broaden the partial Huang-Rhys factors. The broadening factor is linearly interpolated from sigma_psb[0] at zero frequency to sigma_psb[1] at the highest (non-LVM) frequency. :type sigma_psb: float, float :param gamma_psb: Turns on Lorentzian broadening of local vibrational modes identified by their inverse participation ratio. gamma_psb[0] is ipr_cut and gamma_psb[1] is gamma_lvm. See :class:`Broadening`. :type gamma_psb: float, float :param omega_mult: number of factors of maximum phonon frequency from ZPL to plot. :type omega_mult: float :param norm: normalization of luminescence (area or max). :type norm: str :param T: Temperature in kelvin. :type T: float :param plot: if provide, specifies the type of plot to be generated and save in the current working directory. Can be "subplot", "inset", "dos", "S", or "L". See :func:`plot_spec_funcs` for more info. :type plot: str .. py:function:: analyze_dynmat(dynmat: pathlib.Path, structure: pathlib.Path) -> None Produce analysis plots of the dynamical matrix.