def from_dict(cls, d): # Programmatic access to enumeration members in Enum class. structure = d["structure"] if isinstance(structure, dict): structure = Structure.from_dict(structure) return cls(structure=structure, xc=Xc.from_string(d["xc"]), task=Task.from_string(d["task"]), kpoints=d["kpoints"], potcar=Potcar.from_dict(d["potcar"]), incar_settings=d["incar_settings"], files_to_transfer=d["files_to_transfer"], **d["kwargs"])
def parse_args(args): vise_yaml_files = '\n'.join(["* " + str(f) for f in defaults.yaml_files]) parser = argparse.ArgumentParser( description=f""" Vise is a package that helps researchers to do first-principles calculations with the VASP code. Author: Yu Kumagai Version: {__version__} """, epilog=f"The parsed vise.yaml files are:\n{vise_yaml_files}", formatter_class=argparse.RawTextHelpFormatter) subparsers = parser.add_subparsers() # -- parent parser: vasprun vasprun_parser = argparse.ArgumentParser(description="", add_help=False) vasprun_parser.add_argument( "-v", "--vasprun", type=Path, default=defaults.vasprun, help="vasprun.xml file name.") # -- parent parser: outcar outcar_parser = argparse.ArgumentParser(description="", add_help=False) outcar_parser.add_argument( "-o", "--outcar", type=Path, default=defaults.outcar, help="OUTCAR file name.") # -- structure_info --------------------------------------------------- parser_structure_info = subparsers.add_parser( name="structure_info", description="Tools showing structure info or conventional cell.", formatter_class=argparse.ArgumentDefaultsHelpFormatter, aliases=['si']) parser_structure_info.add_argument( "-p", "--poscar", type=str, default="POSCAR", help="POSCAR-type file name to be read.", metavar="FILE") parser_structure_info.add_argument( "-s", "--symprec", type=float, default=defaults.symmetry_length_tolerance, help="Length tolerance for symmetry analysis.") parser_structure_info.add_argument( "-a", "--angle_tolerance", type=float, default=defaults.symmetry_angle_tolerance, help="Angle tolerance in degree for symmetry analysis.") parser_structure_info.add_argument( "-c", "--show_conventional", action="store_true", help="Set when showing the conventional cell.") parser_structure_info.set_defaults(func=structure_info) # -- get_poscar ----------------------------------------------------------- parser_get_poscar = subparsers.add_parser( name="get_poscar", description="Tools for generating a POSCAR file.", formatter_class=argparse.ArgumentDefaultsHelpFormatter, aliases=['gp']) parser_get_poscar.add_argument( "-p", "--poscar", type=str, default="POSCAR", help="POSCAR-type file name.", metavar="FILE") parser_get_poscar.add_argument( "-pi", "--prior_info", type=Path, default=Path("prior_info.yaml"), help="prior_info.yaml file name.", metavar="FILE") parser_get_poscar.add_argument( "-m", "--mpid", type=str, required=True, help="MP entry id with prefix, e.g., mp-1234.") parser_get_poscar.set_defaults(func=get_poscar_from_mp) # -- make_atom_poscars ----------------------------------------------------- parser_make_atom_poscars = subparsers.add_parser( name="make_atom_poscars", description="Tools for generating POSCAR files for atom calculations.", formatter_class=argparse.ArgumentDefaultsHelpFormatter, aliases=['map']) parser_make_atom_poscars.add_argument( "-d", "--dirname", type=Path, default=Path.cwd(), help="Directory name where atom calculation directories are created.") parser_make_atom_poscars.add_argument( "-e", "--elements", type=Element, default=None, nargs="+", help="Element names. When not set, all atom directories are created") parser_make_atom_poscars.set_defaults(func=make_atom_poscars) # -- vasp_set --------------------------------------------------------- parser_vasp_set = subparsers.add_parser( name="vasp_set", description="Tools for constructing vasp input set", parents=[vasprun_parser, outcar_parser], formatter_class=argparse.ArgumentDefaultsHelpFormatter, aliases=['vs']) parser_vasp_set.add_argument( "-p", "--poscar", default="POSCAR", type=Path, help="POSCAR-type input structure file name.") parser_vasp_set.add_argument( "-t", dest="task", default=defaults.task, type=Task, choices=Task.name_list(), help=f"Task name.") parser_vasp_set.add_argument( "-x", dest="xc", default=defaults.xc, type=Xc, choices=Xc.name_list(), help=f"Exchange-correlation (XC) interaction.") parser_vasp_set.add_argument( # Default must be None to use the insulator_kpoint_density. # defaults.kpoints_density is used at structure_kpoints_generator.py "-k", "--kpt_density", type=float, help="K-point density in Angstrom along each direction. " f"Defaults of metal and insulators are {defaults.kpoint_density}, " f"and {defaults.insulator_kpoint_density}.") parser_vasp_set.add_argument( "--potcar", dest="overridden_potcar", default=defaults.overridden_potcar, type=str, nargs="+", help="User specifying POTCAR set. E.g., Mg_pv O_h") parser_vasp_set.add_argument( "-uis", "--user_incar_settings", type=str, nargs="+", help="""Overwritten incar settings described with pairs of INCAR tag names and values. These can also be set by vise.yaml, but they are overwritten by this command line options.""") parser_vasp_set.add_argument( "-d", "--prev_dir", type=Path, help="Parse the previous calculations for better input settings.") parser_vasp_set.add_argument( "--options", type=str, nargs="+", help="Manual options used at CategorizedInputOptions class.") parser_vasp_set.add_argument( "--uniform_kpt_mode", action="store_true", help="""Kpoints with uniform k-point sampling. The k-point sampling mesh and centering are determined based on the given lattice. Note that only when the angles are 90 degrees, the centering is shifted along the perpendicular direction. This mode is useful when calculating the supercells. """) parser_vasp_set.add_argument( "--file_transfer_type", type=str, nargs="+", help="File transfer which is used with the prev_dir argument and can " "be written with pairs of file names and transfer types of " "m (move), c (copy) or l (link). An example is: " "--file_transfer_type POSCAR c WAVECAR l ") parser_vasp_set.set_defaults(func=VaspSet) # -- plot_band ------------------------------------------------------------- parser_plot_band = subparsers.add_parser( name="plot_band", description="Tools for plotting band structures", parents=[vasprun_parser], formatter_class=argparse.ArgumentDefaultsHelpFormatter, aliases=['pb']) parser_plot_band.add_argument( "-k", "--kpoints", dest="kpoints_filename", default="KPOINTS", type=str, help="KPOINTS file name.") parser_plot_band.add_argument( "-y", "--y_range", nargs="+", default=[-10, 10], type=float, help="Energy range, requiring two values.") parser_plot_band.add_argument( "-f", "--filename", type=str, default="band.pdf", help="Pdf file name.") parser_plot_band.set_defaults(func=plot_band) # -- plot_dos ----------------------------------------------------------- parser_plot_dos = subparsers.add_parser( name="plot_dos", description="Tools for plotting density of states", parents=[vasprun_parser, outcar_parser], formatter_class=argparse.ArgumentDefaultsHelpFormatter, aliases=['pd']) parser_plot_dos.add_argument( "-t", "--type", type=AtomGroupingType, default=AtomGroupingType.non_equiv_sites, choices=AtomGroupingType.name_list(), help="How to group atoms for pdos.") parser_plot_dos.add_argument( "-l", "--legend", type=str2bool, default=True, help="Whether to show the figure legend.") parser_plot_dos.add_argument( "-c", "--crop_first_value", type=str2bool, default=True, help="Whether to crop the first value in DOS.") parser_plot_dos.add_argument( "-x", "--x_range", nargs="+", type=float, help="Set minimum and maximum energies.") parser_plot_dos.add_argument( "-y", "--y_max_ranges", nargs="+", type=float, help="Set max energies for each plot. AssertionError is raised when" "the number of ranges does not fit to the number of figures.") parser_plot_dos.add_argument( "--target", type=str, nargs="+", help="""Show specific PDOS. The input depends on AtomGroupingType.\n AtomGroupingType.atoms: 1,2 3 \n AtomGroupingType.elements: Mg O""") parser_plot_dos.add_argument( "-f", "--filename", type=str, default="dos.pdf", help="Pdf file name.") parser_plot_dos.add_argument( "-b", "--base_energy", type=float, help="Set when showing the figure in the absolute energies scale.") parser_plot_dos.set_defaults(func=plot_dos) # -- plot_absorption ------------------------------------------------------- parser_plot_absorption = subparsers.add_parser( name="plot_absorption", description="Tools for plotting absorption coefficient", parents=[vasprun_parser, outcar_parser], formatter_class=argparse.ArgumentDefaultsHelpFormatter, aliases=['pa']) parser_plot_absorption.add_argument( "-f", "--filename", type=str, default="absorption.pdf", help="Pdf file name.") parser_plot_absorption.add_argument( "-y", "--y_ranges", nargs="+", default=[10**3, 10**8], type=lambda x: 10 ** float(x), help="Exponential parts of base-10 for energy range in cm-1, " "requiring two values.") parser_plot_absorption.add_argument( "-ckk", "--calc_kk", action="store_true", help="Set when real part of dielectric function is explicitly " "calculated using the Kramers-Kronig transformation.") parser_plot_absorption.add_argument( "-i", "--ita", type=float, default=0.01, help="Complex shift η in the Kramers-Kronig transformation.") parser_plot_absorption.set_defaults(func=plot_absorption) # -- effective_mass ------------------------------------------------------- parser_effective_mass = subparsers.add_parser( name="effective_mass", description="Tools for calculating effective masses", parents=[vasprun_parser, outcar_parser], formatter_class=argparse.ArgumentDefaultsHelpFormatter, aliases=['em']) parser_effective_mass.add_argument( "-t", "--temperature", type=float, default=300, help="Temperature in K.") parser_effective_mass.add_argument( "-c", "--concentrations", type=lambda x: 10 ** float(x), nargs="+", help="Exponential parts of base-10 for concentrations in cm-3") parser_effective_mass.set_defaults(func=calc_effective_mass) # -- band_edge ------------------------------------------------------------- parser_band_edge = subparsers.add_parser( name="band_edge", description="Calculate the band edge positions", parents=[vasprun_parser, outcar_parser], formatter_class=argparse.ArgumentDefaultsHelpFormatter, aliases=['be']) parser_band_edge.set_defaults(func=band_edge_properties) try: import argcomplete argcomplete.autocomplete(parser) # https://github.com/kislyuk/argcomplete#activating-global-completion # This supports bash/zsh autocompletion. To enable this, pip install # argcomplete, activate global completion, or add # eval "$(register-python-argcomplete vise)" # into your .bash_profile or .bashrc except ImportError: pass return parser.parse_args(args)
def vasp_set(args): if args.print_json: vis = ViseInputSet.load_json(args.print_json) print(vis) return flags = [str(s) for s in list(Element)] ldauu = list2dict(args.ldauu, flags) ldaul = list2dict(args.ldaul, flags) potcar_set = potcar_str2dict(args.potcar_set) task = Task.from_string(args.task) xc = Xc.from_string(args.xc) base_kwargs = {"kpt_density": args.kpt_density, "standardize_structure": args.standardize, "ldauu": ldauu, "ldaul": ldaul} flags = list(ViseInputSet.ALL_OPTIONS.keys()) base_kwargs.update(list2dict(args.vise_opts, flags)) flags = list(chain.from_iterable(incar_flags.values())) base_user_incar_settings = list2dict(args.user_incar_setting, flags) original_dir = os.getcwd() dirs = args.dirs or ["."] for d in dirs: os.chdir(os.path.join(original_dir, d)) logger.info(f"Constructing vasp set in {d}") user_incar_settings = deepcopy(base_user_incar_settings) kwargs = deepcopy(base_kwargs) if args.prior_info: if os.path.exists("prior_info.json"): prior_info = PriorInfo.load_json("prior_info.json") kwargs["band_gap"] = prior_info["band_gap"] kwargs["is_magnetization"] = \ abs(prior_info["total_magnetization"]) > 0.1 if args.prev_dir: files = {"CHGCAR": "C", "WAVECAR": "M", "WAVEDER": "M"} input_set = ViseInputSet.from_prev_calc(args.prev_dir, task=task, xc=xc, charge=args.charge, files_to_transfer=files, **kwargs) else: s = Structure.from_file(args.poscar) input_set = \ ViseInputSet.make_input(structure=s, task=task, xc=xc, charge=args.charge, user_incar_settings=user_incar_settings, override_potcar_set=potcar_set, **kwargs) input_set.write_input(".") os.chdir(original_dir)
def task(self): return Task(self._task)
def test_task_name_list(): expected = 'structure_opt, structure_opt_rough, structure_opt_tight, ' \ 'cluster_opt, phonon_force, defect, band, dos, ' \ 'dielectric_dfpt, dielectric_finite_field, dielectric_function' assert Task.names_string() == expected
def test_task_from_string_raise_error(): with pytest.raises(AttributeError): Task.from_string("not_exist_member")
def test_task_from_string(): assert Task.dos == Task.from_string("dos")
def make_input(cls, structure: Structure, task: Union[str, Task] = Task.structure_opt, xc: Union[str, Xc] = Xc.pbe, prev_set: "ViseInputSet" = None, abs_files_to_transfer: Optional[dict] = None, user_incar_settings: Optional[dict] = None, **kwargs) -> "ViseInputSet": """Construct ViseInputSet from some options including xc and task. To make a simple but practical rule for inheriting the previous calculation condition and effectively use its results, we adopt fail-safe rule. When, the prev_set is set, we compare task and xc between current input and prev_set, and inherit some options depending on whether task and/or xc are common. For instance, when we calculate the band structure with the HSE06 hybrid functional, it would be better to generate the WAVECAR file with e.g., PBE functional to reduce the computational cost. Then, the initial task was done with task=Task.band and xc=Xc.pbe with user_incar_setting={"LWAVE": True}, and next task is performed with task=Task.band, xc=Xc.hs. Then, task is common, so input set related to TaskStructureKpoints and TaskIncarSettings are inherited. Note that, CommonIncarSettings options are always inherited. Other notes are as follows. Note1: Charge set to structure is ignored when determining NELECT. For this purpose, charge option needs to be used. Note2: When the structure is changed via find_spglib_standard_primitive, all the site properties are removed. Note3: When different version of ViseInputSet with different defaults, the consistency of input set is destroyed, so the same version must be used when options are inherited. Note4: Other INCAR flags than those defined by TaskIncarSettings, XcIncarSettings, XcTaskIncarSettings, and CommonIncarSettings are not inherited. When some of them need to be inherited, they should be added to COMMON_OPTIONAL_FLAGS. Note5: user_incar_settings is not inherited from prev_set. One needs to explicitly specify it, again, if needed. Args: structure (Structure): The Structure to create inputs for. task (Task): Task defined in Task. xc (Xc): Exchange-correlation (xc) defined in Xc. prev_set (ViseInputSet): Previous ViseInputSet. abs_files_to_transfer (dict): Keys are file names with absolute paths to be transferred. Values mean the transfer modes, where there are three modes, "c": copy file, "m": move file, "l": make symbolic link e.g., {"/..../CHGCAR": "c", "/..../WAVECAR": "l", ..} user_incar_settings (dict): User INCAR settings. e.g., {"NSW": 100, "LWAVE": True, "LASPH": "A", ..} kwargs (dict): OPTION arguments. Return: ViseInputSet class object. """ abs_files_to_transfer = abs_files_to_transfer or {} user_incar_settings = user_incar_settings or {} if isinstance(task, str): task = Task.from_string(task) if isinstance(xc, str): xc = Xc.from_string(xc) # First, set default. opts = deepcopy(cls.ALL_OPTIONS) # Second, override with previous condition if prev_set: key_set = set(cls.COMMON_OPTIONS.keys()) if prev_set.task == task: key_set.update(cls.TASK_OPTIONS.keys()) if prev_set.xc == xc: key_set.update(cls.XC_OPTIONS.keys()) if prev_set.task == task and prev_set.xc == xc: key_set.update(cls.XC_TASK_OPTIONS) for k in key_set: opts[k] = prev_set.kwargs[k] # Third, override with keyword arguments for k in kwargs: if k not in opts.keys(): logger.warning( f"Keyword {k} is not adequate for ViseInputSet.") opts.update(kwargs) task_str_kpt = TaskStructureKpoints.from_options( task=task, original_structure=structure, standardize_structure=opts["standardize_structure"], sort_structure=opts["sort_structure"], is_magnetization=opts["is_magnetization"], kpt_mode=opts["kpt_mode"], kpt_density=opts["kpt_density"], kpt_shift=opts["kpt_shift"], only_even=opts["only_even"], band_ref_dist=opts["band_ref_dist"], factor=opts["factor"], symprec=opts["symprec"], angle_tolerance=opts["angle_tolerance"]) orig_matrix = structure.lattice.matrix matrix = task_str_kpt.structure.lattice.matrix structure_changed = \ not np.allclose(orig_matrix, matrix, atol=opts["symprec"]) if structure_changed and opts["charge"] != 0: raise ValueError("Structure is changed but charge is set.") if structure_changed: # The following files are useless when lattice is changed. pattern = \ re.compile("|".join([r"CHGCAR$", r"WAVECAR$", r"WAVEDER"])) for f in abs_files_to_transfer: if pattern.match(f): abs_files_to_transfer.pop(f, None) # unique_justseen https://docs.python.org/ja/3/library/itertools.html # ["H", "H", "O", "O", "H"] -> ['H', 'O', 'H'] symbol_list = get_symbol_list(task_str_kpt.structure) xc_task_potcar = XcTaskPotcar.from_options( xc=xc, symbol_list=symbol_list, potcar_set_name=opts["potcar_set_name"], override_potcar_set=opts["override_potcar_set"]) task_settings = TaskIncarSettings.from_options( task=task, structure=task_str_kpt.structure, potcar=xc_task_potcar.potcar, num_kpoints=task_str_kpt.num_kpts, max_enmax=xc_task_potcar.max_enmax, is_magnetization=opts["is_magnetization"], vbm_cbm=opts["vbm_cbm"], npar_kpar=opts["npar_kpar"], num_nodes=opts["num_nodes"], encut=opts["encut"], structure_opt_encut_factor=opts["structure_opt_encut_factor"], dos_step_size=opts["dos_step_size"]) xc_settings = XcIncarSettings.from_options( xc=xc, symbol_list=symbol_list, factor=task_str_kpt.factor, aexx=opts["aexx"], hubbard_u=opts["hubbard_u"], ldauu=opts["ldauu"], ldaul=opts["ldaul"], ldaul_set_name=opts["ldaul_set_name"]) xc_task_settings = XcTaskIncarSettings.from_options() common_settings = CommonIncarSettings.from_options( potcar=xc_task_potcar.potcar, composition=task_str_kpt.structure.composition, charge=opts["charge"]) incar_settings = \ {**task_settings.settings, **xc_settings.settings, **xc_task_settings.settings, **common_settings.settings} # user_incar_settings is the top prioritized. incar_settings.update(user_incar_settings) # TODO: tweak the unfavorable combination of the input set. # e.g., Avoiding ICHARG = 11 is a must for hybrid functional. return cls(structure=task_str_kpt.structure, task=task, xc=xc, kpoints=task_str_kpt.kpoints, potcar=xc_task_potcar.potcar, incar_settings=incar_settings, files_to_transfer=abs_files_to_transfer, **opts)