Source code for ase2sprkkr.tools.commands.uppasd

#!/usr/bin/env python3
"""Convert SPRKKR output to UppASD input files and Jij plots."""

import sys
from pathlib import Path
from ...common.tools import main  # NOQA

if not __package__:
    __package__ = "ase2sprkkr.tools.commands"
sys.path.append(str(Path(__file__).resolve().parents[3]))

help = "Convert SPRKKR output to UppASD input files and plots the computed Jij (experimental)"
description = "Given .pot, .jxc and .dmi file, plot the Jij values."


[docs] def parser(parser): group = parser.add_argument_group("Input files") group.add_argument( "outfile", type=str, default=None, help="Output file name of a JXC computation (if it is given, other files can be found automatically)", ) group.add_argument("-p", "--pot-file", type=str, default=None, help="Input potential file (.pot or .pot_new)") group.add_argument( "-j", "--jxc-file", type=str, default=None, help="Input exchange interaction file (_XCPLTEN_Jij.dat)" ) group.add_argument("-d", "--dmi-file", type=str, default=None, help="Input DMI file (_DMIVEC_Dij.dat)") group = parser.add_argument_group("Geerating uppasd files") group.add_argument("-o", "--output-dir", type=str, default=".", help="Output directory for files") group.add_argument("-u", "--inpsd", action="store_true", default=None, help="Write inpsd input file stub") group.add_argument("-n", "--no-write", action="store_true", help="Skip writing output files") group = parser.add_argument_group("Plotting") group.add_argument("--plot", action="store_true", help="Generate exchange interaction plots") group.add_argument("--no-plot", action="store_true", help="Skip generating plots") group.add_argument("--separate-plots", action="store_true", help="Generate one plot file per site type") group.add_argument( "--axis", type=str, choices=("all", "x", "y", "z"), default="all", help="DMI component to plot: all, x, y, or z" ) group.add_argument( "-r", "--exchange-radius", type=float, default=4.0, help="Maximum distance for exchange interaction plots" ) group.add_argument( "-c", "--cartesian", action="store_const", dest="coordinates", default="lattice", const="cartesian", help="Use cartesian coordinates for interaction instead of lattice ones", ) group.add_argument("-f", "--font-size", type=int, default=14, help="Font size for plots") group = parser.add_argument_group("Filtering") group.add_argument( "-e", "--exclude", type=str, nargs="*", default=None, help="Comma-separated site selectors to exclude" ) group.add_argument( "-i", "--include", type=str, nargs="*", default=None, help="Comma-separated site selectors to include" ) group.add_argument( "--include-vacuum", action="store_true", help="Include vacuum sites in selector matching and exported outputs" )
[docs] def run(args, global_args): import glob from ...bindings.uppasd import Coordinates, write_mom_file, write_pos_file, write_inpsd_file # NOQA from ...output_files.output_files import OutputFile # NOQA from ...output_files.definitions.jxc import JXCOutputFile # NOQA from ...potentials.potentials import Potential # NOQA def _load_jxc_output(filename, potential): output = OutputFile.from_file(filename, try_only="jxc", unknown=False) output.potential = potential return output def _plot_exchange_interactions( output, output_dir, selector, exchange_radius, font_size, separate_plots=False, axis="all" ): if output.is_Jij(): plot_name = "Jij" elif axis == "all": plot_name = "Dij" else: plot_name = f"Dij_{axis}" filename = output_dir / ("{name}.pdf" if separate_plots else f"{plot_name}.pdf") out = output.plot( layout=2, filename=str(filename), show=False, selector=selector, exchange_radius=exchange_radius, font_size=font_size, axis=axis, separate_plots=separate_plots, ) if out: print(f"Created plot files in: {output_dir}") else: print("No interaction data to plot") return True def find_files_by_pattern(args): if args.pot_file is None: if result is not None and result.potential_filename: pot_files = [result.potential_filename] else: pot_files = glob.glob("*.pot_new") if pot_files: args.pot_file = pot_files[0] else: pot_files = glob.glob("*.pot") if pot_files: args.pot_file = pot_files[0] if args.jxc_file is None: if result is not None: try: jxc_files = [result.jxc_filename] except AttributeError: jxc_files = None else: jxc_files = glob.glob("*_XCPLTEN_Jij.dat") if jxc_files: args.jxc_file = jxc_files[0] if args.dmi_file is None: if result is not None: try: dmi_files = [result.dmi_filename] except AttributeError: dmi_files = None else: dmi_files = glob.glob("*_DMIVEC_Dij.dat") if dmi_files: args.dmi_file = dmi_files[0] return args if args.outfile: from ase2sprkkr import TaskResult result = TaskResult.from_file(args.outfile) if result.__class__.__name__ != "JxcResult": raise ValueError("Given output file is not an output of a JXC calculation") else: result = None args = find_files_by_pattern(args) output_dir = Path(args.output_dir) output_dir.mkdir(parents=True, exist_ok=True) if args.pot_file is None: print("Error: No potential file found!") sys.exit(1) try: potential = Potential.from_file(args.pot_file) atoms = potential.atoms if args.jxc_file: jxc_output = _load_jxc_output(args.jxc_file, potential) else: jxc_output = None print("No JXC file found - skipping exchange processing") if args.dmi_file: dmi_output = _load_jxc_output(args.dmi_file, potential) elif args.jxc_file: print("No DMI file found - skipping DMI export") dmi_output = None selector_obj = jxc_output or dmi_output or JXCOutputFile.from_atoms(atoms) selector = selector_obj.create_selector( iq=args.include, it=args.include, exclude_it=args.exclude, exclude_vc=not args.include_vacuum ) coordinates = getattr(Coordinates, args.coordinates) print(f"Potential: {args.pot_file}") print(f"Number of atoms: {len(atoms.sites)}") if selector.it is not ...: print(f"Selected IQs: {', '.join(map(lambda i: selector_obj.it_labels[i], selector.it))}") if not args.no_write and dmi_output is not None: dmi_output.write_uppasd_file( output_dir / "dmfile.dat", selector=selector, exchange_radius=args.exchange_radius, coordinates=coordinates, ) if not args.no_write and jxc_output is not None: jxc_output.write_uppasd_file( output_dir / "jfile.dat", selector=selector, exchange_radius=args.exchange_radius, coordinates=coordinates, ) if not args.no_write: write_pos_file(atoms, output_dir / "posfile.dat", selector=selector) if not write_mom_file(atoms, output_dir / "momfile.dat", selector=selector): print("Warning: no selected site type has moments. Skipping momfile.dat.") if args.inpsd: write_inpsd_file(atoms, directory=output_dir) if args.plot and not args.no_plot and jxc_output is not None: _plot_exchange_interactions( jxc_output, output_dir, selector=selector, exchange_radius=args.exchange_radius, font_size=args.font_size, separate_plots=args.separate_plots, axis=args.axis, ) if args.plot and not args.no_plot and args.dmi_file: _plot_exchange_interactions( dmi_output, output_dir, selector=selector, exchange_radius=args.exchange_radius, font_size=args.font_size, separate_plots=args.separate_plots, axis=args.axis, ) except FileNotFoundError as exc: print(f"Error: {exc}") sys.exit(1) except Exception as exc: if global_args["debug"]: raise print(f"Unexpected error: {exc}") sys.exit(1)
if __name__ == "__main__": main(globals())