예제 #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 _generate_atom_potential(
        self,
        base_path: str,
        symbol: str,
    ) -> None:
        """
        Make a dir with the atoms name,generate
        the input file and run the atomic program

            Args:
                symbol (str): Atom symbol
                base_path (str): Path to mkpotcar{symbol}
        """

        folder_path = os.path.join(base_path, "pseudopotential")
        if os.path.exists(folder_path):
            shutil.rmtree(folder_path)
        os.mkdir(folder_path)
        input_file = InputFile.minimum_setup(
            symbol,
            self.exchange_correlation_type,
            self.max_iterations,
            self.calculation_code,
        )
        input_file.to_file(os.path.join(folder_path, "INP"))
        process = Popen(['minushalf', 'run-atomic', "--quiet"],
                        stdout=PIPE,
                        stderr=PIPE,
                        cwd=folder_path)

        _, stderr = process.communicate()
        if stderr:

            raise Exception("Call to atomic program failed")
예제 #3
0
def test_chemical_symbol():
    """
        Test if the chemical symbol of the predetermined
        will raises exception in the class construction.
        """
    for element in PeriodicTable:
        InputFile("pb", "ae", element.value, "", 1, 1, [])
예제 #4
0
def test_from_file(file_path):
    """
    Test from_file path to generate instances
    of the InputFile class with an INP text file
    """
    for element in ElectronicDistribution:
        symbol = str(element)
        path = file_path(f"{symbol}/INP_COMMENTED")

        inp_from_file = InputFile.from_file(path)
        inp_minimum_setup = InputFile.minimum_setup(symbol, 'pb')

        from_file_string = "".join(inp_from_file.to_stringlist())
        minimum_setup_string = "".join(inp_minimum_setup.to_stringlist())

        assert from_file_string == minimum_setup_string
예제 #5
0
def test_occupation_with_default_params_Yb():
    """
    Test occupation command in the p orbital of ytterbium
    """
    inp_oxygen = InputFile.minimum_setup("Yb", "pb")
    lines = inp_oxygen.to_stringlist()
    runner = CliRunner()
    with runner.isolated_filesystem():
        with open("INP", "w") as file:
            file.writelines(lines)

        result = runner.invoke(occupation, ["0", "50"])
        assert result.exit_code == 0
        occupied_file = InputFile.from_file("INP_OCC")
        for orbital in occupied_file.valence_orbitals:
            if orbital["l"] == 0:
                assert np.isclose(orbital["occupation"][0], 1.75) == True
예제 #6
0
def test_exchange_and_correlation_functional_spin():
    """
        Test if the factor of correlation and exchange with
        spin factor will raises exception in the class construction.
        """
    exchange_correlation_types = [
        "cas", "wis", "hls", "gls", "bhs", "pbs", "rps", "rvs", "bls"
    ]
    for type_correlation in exchange_correlation_types:
        InputFile(type_correlation, "ae", "Ge", "", 1, 1, [])
예제 #7
0
def test_exchange_and_correlation_functional_relativistic():
    """
        Test if the factor of correlation and exchange with
        relativistic factor will raises exception in the class construction.
        """
    exchange_correlation_types = [
        "car", "wir", "hlr", "glr", "bhr", "pbr", "rpr", "rvr", "blr"
    ]
    for type_correlation in exchange_correlation_types:
        InputFile(type_correlation, "ae", "Ge", "", 1, 1, [])
예제 #8
0
def test_electron_occupation_na():
    """
        Test occupation in INP file for Na
        """
    inp = InputFile.minimum_setup('Na', 'pb')
    inp.electron_occupation(0.5, 0)

    for orbital in inp.valence_orbitals:
        if orbital["l"] == 0:
            assert np.isclose(orbital["occupation"][0], 0.5)
예제 #9
0
def test_exchange_and_correlation_functional():
    """
        Test if the factor of correlation and exchange
        will raises exception in the class construction.
        """
    exchange_correlation_types = [
        "ca", "wi", "hl", "gl", "bh", "pb", "rp", "rv", "bl"
    ]
    for type_correlation in exchange_correlation_types:
        InputFile(type_correlation, "ae", "Ge", "", 1, 1, [])
예제 #10
0
def test_electron_occupation_au():
    """
        Test occupation in INP file for Au
        """
    inp = InputFile.minimum_setup('Au', 'pb')
    inp.electron_occupation(0.1, 0)
    inp.electron_occupation(0.4, 2)

    for orbital in inp.valence_orbitals:
        if orbital["l"] == 0:
            assert np.isclose(orbital["occupation"][0], 0.9)
        elif orbital["l"] == 2:
            assert np.isclose(orbital["occupation"][0], 9.6)
예제 #11
0
def test_failing_occupation_with_default_params_O():
    """
    Test passing invalid secondary quantum number
    """
    inp_oxygen = InputFile.minimum_setup("O", "pb")
    lines = inp_oxygen.to_stringlist()
    runner = CliRunner()
    with runner.isolated_filesystem():
        with open("INP", "w") as file:
            file.writelines(lines)

        result = runner.invoke(occupation, ["0,-1", "*,*"])
        assert result.exit_code == 1
예제 #12
0
def test_failing_occupation_with_default_params_Au():
    """
    Test wrong occuparion percentual passed to command
    """
    inp_oxygen = InputFile.minimum_setup("Au", "pb")
    lines = inp_oxygen.to_stringlist()
    runner = CliRunner()
    with runner.isolated_filesystem():
        with open("INP", "w") as file:
            file.writelines(lines)

        result = runner.invoke(occupation, ["2", "-1"])
        assert result.exit_code == 2
예제 #13
0
def test_failing_occupation_with_default_params_Yb():
    """
    Test invalid occupation number for Yb
    """
    inp_oxygen = InputFile.minimum_setup("Yb", "pb")
    lines = inp_oxygen.to_stringlist()
    runner = CliRunner()
    with runner.isolated_filesystem():
        with open("INP", "w") as file:
            file.writelines(lines)

        result = runner.invoke(occupation, ["0,3", "50,101"])
        assert result.exit_code == 1
예제 #14
0
def test_electron_occupation_yb():
    """
        Test occupation in INP file for Yb
        """
    inp = InputFile.minimum_setup('Yb', 'pb')
    inp.electron_occupation(0.5, 0)
    inp.electron_occupation(0.5, 3)

    for orbital in inp.valence_orbitals:
        if orbital["l"] == 0:
            assert np.isclose(orbital["occupation"][0], 1.5)
        elif orbital["l"] == 3:
            assert np.isclose(orbital["occupation"][0], 13.5)
예제 #15
0
def test_electron_occupation_si():
    """
        Test occupation in INP file for Si
        """
    inp = InputFile.minimum_setup('Si', 'pb')
    inp.electron_occupation(0.4, 0)
    inp.electron_occupation(0.3, 1)

    for orbital in inp.valence_orbitals:
        if orbital["l"] == 0:
            assert np.isclose(orbital["occupation"][0], 1.6)
        elif orbital["l"] == 1:
            assert np.isclose(orbital["occupation"][0], 1.7)
예제 #16
0
def test_electron_occupation_ag():
    """
        Test occupation in INP file for Ag
        """
    inp = InputFile.minimum_setup('Ag', 'pb')
    inp.electron_occupation(0.5, 2)
    inp.electron_occupation(0.2, 0)

    for orbital in inp.valence_orbitals:
        if orbital["l"] == 2:
            assert np.isclose(orbital["occupation"][0], 9.5)
        elif orbital["l"] == 0:
            assert np.isclose(orbital["occupation"][0], 0.8)
예제 #17
0
def test_minimum_setup(file_path):
    """
    Test minimum setup function to
    generate INP files with the elements
    symbol and the functional of exchange and exchange
    correlation
    """

    for element in ElectronicDistribution:
        symbol = str(element)
        path = file_path(f"{symbol}/INP")
        inp = InputFile.minimum_setup(symbol, 'pb')
        with open(path, "r") as file:
            assert file.read() == "".join(inp.to_stringlist())
예제 #18
0
def test_atomic_with_all_elements():
    """
    Test if the atomic run produce the correct output for
    elements in the periodic table
    """
    runner = CliRunner()

    for element in ElectronicDistribution:
        inp = InputFile.minimum_setup(str(element), "pb")
        lines = inp.to_stringlist()
        with runner.isolated_filesystem():
            with open("INP", "w") as file:
                file.writelines(lines)
            result = runner.invoke(run_atomic, [])
            assert result.exit_code == 0
            assert os.path.exists("VTOTAL0") == True
            assert os.path.exists("VTOTAL.ae") == True
            assert os.path.exists("VTOTAL2") == True
            assert os.path.exists("VTOTAL3") == True
예제 #19
0
def test_pass_wrong_exchange_functional():
    """
        Pass wrong correlation and exchange functional and
        expect to fail
        """
    InputFile('sd', 'ae', 'Ge', "", 1, 1, [])
예제 #20
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()
예제 #21
0
def test_pass_wrong_calculation_code():
    """
        Pass wrong calculation code and
        expect to fail
        """
    InputFile('pb', 'ee', 'Ge', "", 1, 1, [])
예제 #22
0
def test_pass_wrong_chemical_symbol():
    """
        Pass wrong chemical symbol and
        expect to fail
        """
    InputFile('pb', 'ae', 'Ss', "", 1, 1, [])