示例#1
0
def create_input(chemical_symbol: str, exchange_correlation_code: str,
                 calculation_code: str, maximum_iterations: int, filename: str,
                 quiet: bool):
    """
    Create the input file for the run-atomic command.


    Requires:

        CHEMICAL_SYMBOL: Chemical symbol of the atom (H, He, Na, Li...). Check the list
                         of available atoms in the docs


    Returns:

        INP: The input file for run-atomic command
    """

    welcome_message("minushalf")

    if quiet:
        logger.remove()
        logger.add(sys.stdout, level="ERROR")

    input_file = InputFile.minimum_setup(chemical_symbol.capitalize(),
                                         exchange_correlation_code,
                                         maximum_iterations, calculation_code)
    logger.info("Creating INP file")

    input_file.to_file(filename)

    end_message()
示例#2
0
def band_gap(software: str, base_path: str) -> None:
    """Uses output files from softwares that perform ab initio calculations to
      provide the locations of VBM, CBM and the Gap value in electronvolts.The
      names of the files required for each software are listed below, it is
      worth mentioning that their names cannot be modified.

    VASP: PROCAR, EIGENVAL, vasprun.xml
    """

    welcome_message("minushalf")

    softwares = {"VASP": Vasp()}

    factory = softwares[software.upper()]

    eigenvalues = factory.get_eigenvalues(base_path=base_path)
    fermi_energy = factory.get_fermi_energy(base_path=base_path)
    atoms_map = factory.get_atoms_map(base_path=base_path)
    num_bands = factory.get_number_of_bands(base_path=base_path)
    band_projection_file = factory.get_band_projection_class(
        base_path=base_path)

    band_structure = BandStructure(eigenvalues, fermi_energy, atoms_map,
                                   num_bands, band_projection_file)

    gap_report = band_structure.band_gap()
    click.echo(gap_report["vbm"])
    click.echo(gap_report["cbm"])
    click.echo("Gap: {:.3f}eV".format(gap_report["gap"]))
    end_message()
示例#3
0
def cbm_character(software: str, base_path: str) -> None:
    """Uses output files from softwares that perform ab initio calculations to
      discover the first conduction band (CBM) and extract, in percentage, its
      character corresponding to each orbital type (s, p, d, ... ). The
      names of the files required for each software are listed below, it is
      worth mentioning that their names cannot be modified.

    VASP: PROCAR, EIGENVAL, vasprun.xml
    """

    welcome_message("minushalf")

    softwares = {"VASP": Vasp()}

    factory = softwares[software.upper()]

    eigenvalues = factory.get_eigenvalues(base_path=base_path)
    fermi_energy = factory.get_fermi_energy(base_path=base_path)
    atoms_map = factory.get_atoms_map(base_path=base_path)
    num_bands = factory.get_number_of_bands(base_path=base_path)
    band_projection_file = factory.get_band_projection_class(
        base_path=base_path)

    band_structure = BandStructure(eigenvalues, fermi_energy, atoms_map,
                                   num_bands, band_projection_file)
    cbm_projection = band_structure.cbm_projection()
    normalized_df = projection_to_df(cbm_projection)
    click.echo(normalized_df.to_markdown())

    end_message()
示例#4
0
def run_atomic(quiet: bool):
    """
    Run the atomic program. The atomic program used is a version of the
    ATOM modified by the professor Luiz Guimarães Ferreira to be used in
    the DFT -1/2 method.

    Requires:

        INP: The input file for the calculation.

    Returns:

        VTOTAL.ae: Contains the atom potential.


        OUT: Contains detailed information about the run.


        AECHARGE: Contains in four columns values of r, the “up” and “down” parts of the total
                  charge density, and the total core charge density (the charges multiplied by 4πr 2 ).

        CHARGE: is exactly identical to AECHARGE and is generated for backwards compatibility.


        RHO: Like CHARGE, but without the 4πr 2 factor


        AEWFNR0...AEWFNR3: All-electron valence wavefunctions as function of radius, for s, p, d,
                           and f valence orbitals (0, 1, 2, 3, respectively — some channels might not be available).
                           They include a factor of r, the s orbitals also going to zero at the origin.
    """
    welcome_message("minushalf")

    if quiet:
        logger.remove()
        logger.add(sys.stdout, level="ERROR")

    logger.info("Run atomic program")

    try:
        atomic_program.run()
    except:
        raise Exception('Problems in atomic program execution')

    logger.info("Atomic program finished execution.")

    if not os.path.exists('./VTOTAL1'):
        logger.warning(
            "VTOTAL1 not found, thus VTOTAL.ae will not be generated")
    else:
        logger.info("Changing VTOTAL1 to VTOTAL.ae")
        os.rename("VTOTAL1", "VTOTAL.ae")

    end_message()
示例#5
0
def occupation(orbital_quantum_number: str, occupation_percentage: str,
               quiet: bool):
    """
    Perform fractional occupation on the atom and generate the potential for this occupation.
    The occupation can subtract any fraction of the electron between 0 and 0.5, half occupation is the default.

    Requires:

        ORBITAL_QUANTUM_NUMBER: A string that defines the orbital(s) in which the occupation will be made,
        it can assume four values: (0: s | 1: p | 2: d | 3: f). if going to modify multiple orbitals,
        pass a string with numbers separated by commas : ("0,1,2,3").


        OCCUPATION_PERCENTAGE: A string that defines percentual of half an electron to be used in the occupation.
        The default is 100%, which states for 0.5e. For multiple occupations in different orbitals, pass a string
        separated by commas ("100,50,40,100"). For simplicity, to avoid the excessive repetition of the number
        100, just replace the number with * ("*,30,*"). If this argument is not used, the occupation of
        half an electron will be made for all orbitals assed as arguments.


        INP: Input file of the run-atomic command.

    Returns:

        INP_OCC : Input file modified for fractional occupation.


        INP.ae: A copy of the input file for the calculation.


        VTOTAL_OCC: Contains the atom potential for fractional occupation.


        OUT: Contains detailed information about the run.


        AECHARGE: Contains in four columns values of r, the “up” and “down” parts of the total
        charge density, and the total core charge density (the charges multiplied by 4πr 2 ).


        CHARGE: is exactly identical to AECHARGE and is generated for backwards compatibility.


        RHO: Like CHARGE, but without the 4πr 2 factor


        AEWFNR0...AEWFNR3: All-electron valence wavefunctions as function of radius, for s, p, d,
        and f valence orbitals (0, 1, 2, 3, respectively — some channels might not be available).
        They include a factor of r, the s orbitals also going to zero at the origin.
    """

    welcome_message("minushalf")

    if quiet:
        logger.remove()
        logger.add(sys.stdout, level="ERROR")

    input_file = InputFile.from_file()
    logger.info("Adding minus one half electron correction on INP")

    try:
        quantum_numbers = np.array(orbital_quantum_number.split(","),
                                   dtype=int)
    except ValueError as wrong_input:
        raise ValueError(
            "Invalid value for secondary quantum number") from wrong_input

    for quantum_number in quantum_numbers:
        if quantum_number < 0 or quantum_number > 3:
            raise ValueError("Invalid value for secondary quantum number")

    percentuals = np.ones(len(quantum_numbers)) * 100

    for index, percentual in enumerate(occupation_percentage.split(",")):
        if percentual != "*":
            if float(percentual) < 0 or float(percentual) > 100:
                raise ValueError("Invalid value for occupation percentual")
            percentuals[index] = float(percentual)

    for quantum_number, percentual in zip(quantum_numbers, percentuals):
        input_file.electron_occupation(0.5 * (percentual / 100),
                                       quantum_number)

    os.rename('INP', 'INP.ae')
    input_file.to_file()

    logger.info("Run atomic program")
    try:
        atomic_program.run()
    except Exception as program_fail:
        raise Exception('Problems in atomic program') from program_fail

    logger.info("Atomic program finished execution.")

    if not os.path.exists('./VTOTAL1'):
        raise FileNotFoundError("Problems in INP file generation")
    logger.info("Changing VTOTAL1 to VTOTAL_OCC")
    os.rename("VTOTAL1", "VTOTAL_OCC")

    logger.info("Changing INP to INP_OCC")
    os.rename('INP', 'INP_OCC')

    end_message()
示例#6
0
def correct_potfile(
    quiet: bool,
    base_potfile_path: str,
    vtotal_path: str,
    vtotal_occupied_path: str,
    software: str,
    correction: str,
    cut: str,
    amplitude: float,
) -> None:
    """Generate the occupied atomic potential file used for ab initio calculations.

    Requires:

        VTOTAL.ae: potential of the atom with all electrons

        VTOTAL_OCC: potential of the occupied atom

        INP_OCC: Input file for the run-atomic command of the occupied atom

        The command also needs the potential files used by the chosen software:

            VASP: POTCAR (This name can't be changed)


    Generates:

        POTFILEcut${CUT_VALUE} (If amplitude is equal to 1.0)

        POTFILEcut${CUT_VALUE}A${AMPLITUDE_VALUE} (If amplitude is different from 1.0)

    """
    welcome_message("minushalf")

    if quiet:
        logger.remove()
        logger.add(sys.stdout, level="ERROR")

    softwares = {"VASP": Vasp()}
    factory = softwares[software.upper()]

    vtotal = Vtotal.from_file(vtotal_path)
    vtotal_occ = Vtotal.from_file(vtotal_occupied_path)
    potential_file = factory.get_potential_class(base_path=base_potfile_path)

    atomic_potential = AtomicPotential(vtotal, vtotal_occ, potential_file)

    cut_numbers = parse_cut(cut)

    is_conduction = False
    if correction.upper() == "CONDUCTION":
        is_conduction = True

    for new_cut in cut_numbers:
        logger.info("Correcting POTFILE for cut = {:.2f} a.u".format(new_cut))
        new_potential = atomic_potential.correct_potential(
            new_cut, amplitude, is_conduction)
        atomic_potential.correct_file(new_potential, new_cut, amplitude,
                                      is_conduction)

    end_message()
示例#7
0
def execute(quiet: bool):
    """
    Uses the Nelder-Mead method to find
    the optimal values for the CUT(S) and,
    finally, find the corrected Gap value.
    This command uses external software to
    perform ab initio calculations, so it must
    be installed in order to perform the command.
    Check the docs for an list of the softwares supported
    by the CLI.


        Requires:


            minushalf.yaml : Parameters file. Check the docs
                            for a more detailed description.

            ab_initio_files: Files needed to perform the ab initio calculations.
                            They must be in the same directory as the input
                            file minushalf.yaml

            potential_folder: Folder with the potential files for each atom in
                            the crystal. The files must be named in the following pattern
                            ${POTENTIAL_FILE_NAME}.${LOWERCASE_CHEMICAL_SYMBOL}

        Returns:

            minushalf_results.dat : File that contains the optimal
                                values of the cuts and the final
                                value of the Gap.

            corrected_valence_potfiles: Potential files corrected with opti-mum valence cuts.

            corrected_conduction_potfiles: Potential files corrected with optimum conduction cuts.
    """
    welcome_message("minushalf")

    if quiet:
        logger.remove()
        logger.add(sys.stdout, level="ERROR")
    ## Read yaml file
    logger.info("Reading minushalf.yaml file")
    minushalf_yaml = MinushalfYaml.from_file()
    correction_factory_chooser = {Softwares.vasp.value: DFTCorrection}
    software_factory_chooser = {Softwares.vasp.value: Vasp()}

    software_name = minushalf_yaml.get_software_name()
    correction = correction_factory_chooser[software_name]
    software_factory = software_factory_chooser[software_name]

    ## Makes abinition calculation
    logger.info("Running ab initio calculations")
    software_configurations = minushalf_yaml.get_software_configurations_params(
    )
    runner = software_factory.get_runner(**software_configurations)
    runner.run()

    ## Makes root folder
    logger.info("Make potfiles folder")
    root_folder = "mkpotfiles"
    if os.path.exists(root_folder):
        shutil.rmtree(root_folder)
    os.mkdir(root_folder)

    ## get atoms list
    logger.info("Get atoms list")
    atoms = get_atoms_list(software_factory)

    ## amplitude logger
    if not np.isclose(minushalf_yaml.get_amplitude(),
                      CorrectionDefaultParams.amplitude.value):
        logger.warning(
            "Amplitude value is different from 1.0. This is not recommended unless you know exactly what you are doing."
        )

    valence_options = get_valence_correction_params(minushalf_yaml,
                                                    software_factory,
                                                    atoms=atoms,
                                                    runner=runner,
                                                    root_folder=root_folder)

    conduction_options = get_conduction_correction_params(
        minushalf_yaml,
        software_factory,
        atoms=atoms,
        runner=runner,
        root_folder=root_folder)

    correction_code = minushalf_yaml.get_correction_code()

    logger.info("Doing corrections")
    gap = None
    valence_cuts = None
    conduction_cuts = None

    if "v" in correction_code:
        valence_correction = correction(**valence_options)
        valence_cuts, valence_gap = valence_correction.execute()
        gap = valence_gap
        make_minushalf_results(valence_cuts=valence_cuts, gap=valence_gap)

    if "c" in correction_code:
        conduction_correction = correction(**conduction_options)
        conduction_cuts, conduction_gap = conduction_correction.execute()
        gap = conduction_gap

    make_minushalf_results(valence_cuts=valence_cuts,
                           gap=gap,
                           conduction_cuts=conduction_cuts)

    end_message()