Skip to content

Commit

Permalink
[feat]: Add support to inplace calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
hentt30 committed Jul 13, 2021
1 parent e227a43 commit 7da3fc4
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 60 deletions.
2 changes: 1 addition & 1 deletion minushalf/commands/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ def execute(quiet: bool):
"correction_indexes"] = get_fractionary_correction_indexes(
cbm_projection,
treshold=minushalf_yaml.
correction["fractional_conduction_treshold"])
correction[" "])

valence_fractionary_correction = correction(**valence_options)
valence_cuts, _ = valence_fractionary_correction.execute()
Expand Down
53 changes: 32 additions & 21 deletions minushalf/corrections/vasp_correction.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
import os
import shutil
from subprocess import Popen, PIPE
from pandas.core import base
from scipy.optimize import minimize
from loguru import logger
import pandas as pd
from minushalf.data import (CorrectionDefaultParams,
AtomicProgramDefaultParams, OrbitalType,
CutInitialGuessMethods)
from minushalf.utils import (InputFile, Vtotal, MinushalfYaml, AtomicPotential,
BandStructure, find_reverse_band_gap,
BandStructure, find_negative_band_gap,
CutInitialGuess)
from minushalf.interfaces import (Correction, Runner, SoftwaresAbstractFactory)

Expand All @@ -33,6 +34,7 @@ def __init__(
is_conduction: bool,
correction_indexes: dict,
only_conduction: bool = False,
inplace: bool = True,
):
"""
init method for the vasp correction class
Expand All @@ -49,6 +51,8 @@ def __init__(
runner (Runner): class to execute the program that makes ab initio calculations
only_conduction (bool): Conduction correction without previous valence correction
inplace (bool): Realize calculations inplace, do not create find_cut folders
"""
self.root_folder = root_folder

Expand Down Expand Up @@ -115,7 +119,9 @@ def __init__(

self.correction_indexes = correction_indexes

self.software_files = ["INCAR", "POSCAR", "KPOINTS"]
self.input_files = ["INCAR", "POSCAR", "KPOINTS"]

self.inplace = inplace

@property
def potential_folder(self) -> str:
Expand Down Expand Up @@ -177,7 +183,7 @@ def _get_result_gap(self) -> float:
shutil.rmtree(calculation_folder)
os.mkdir(calculation_folder)

for file in self.software_files:
for file in self.input_files:
shutil.copyfile(file, os.path.join(calculation_folder, file))

potfile_path = os.path.join(calculation_folder,
Expand Down Expand Up @@ -276,7 +282,7 @@ def _find_best_correction(self, symbol: str, orbitals: list) -> float:
if os.path.exists(path):
shutil.rmtree(path)
os.mkdir(path)
self._generate_atom_pseudopotential(path, symbol)
self._generate_atom_potential(path, symbol)

percentuals = {}
## Check for bonds with equal atoms
Expand All @@ -290,7 +296,7 @@ def _find_best_correction(self, symbol: str, orbitals: list) -> float:
percentuals[orbital] = round(value)
self._generate_occupation_potential(path, percentuals)

self.atom_potential = self._get_atom_potential(path, symbol)
self.atom_potential = self._get_atom_potential_class(path, symbol)

cut = self._find_cut(symbol, path)
self._write_result_in_potfile(symbol, cut, self.amplitude)
Expand Down Expand Up @@ -326,7 +332,7 @@ def _write_result_in_potfile(
with open(new_potential_path, "w") as file:
file.writelines(lines)

def _generate_atom_pseudopotential(
def _generate_atom_potential(
self,
base_path: str,
symbol: str,
Expand Down Expand Up @@ -367,7 +373,7 @@ def _generate_occupation_potential(
percentuals: dict,
) -> None:
"""
Generate the pseudo potential for the occupation
Generate the potential for the occupation
of a fraction of half electron.
Args:
Expand Down Expand Up @@ -398,8 +404,8 @@ def _generate_occupation_potential(
if stderr:
raise Exception("Call to occupation command failed")

def _get_atom_potential(self, base_path: str,
symbol: str) -> AtomicPotential:
def _get_atom_potential_class(self, base_path: str,
symbol: str) -> AtomicPotential:
"""
Creates atom_potential class
Expand Down Expand Up @@ -429,10 +435,14 @@ def _find_cut(self, symbol: str, base_path: str) -> tuple:
symbol (str): Atom symbol
base_path (str): Path to mkpotcar{symbol}
"""
folder = os.path.join(base_path, "find_cut")
if os.path.exists(folder):
shutil.rmtree(folder)
os.mkdir(folder)
if not self.inplace:
folder = os.path.join(base_path, "find_cut")
if os.path.exists(folder):
shutil.rmtree(folder)
os.mkdir(folder)
else:
base_path = '.' # Local Path

function_args = {
"base_path": base_path,
"software_factory": self.software_factory,
Expand All @@ -443,8 +453,9 @@ def _find_cut(self, symbol: str, base_path: str) -> tuple:
"potfiles_folder": self.potential_folder,
"amplitude": self.amplitude,
"atoms": self.atoms,
"software_files": self.software_files,
"software_files": self.input_files,
"is_conduction": self.is_conduction,
"inplace": self.inplace
}
if self.automatic_cut_guess:
atoms_map = self.software_factory.get_atoms_map()
Expand All @@ -460,15 +471,15 @@ def _find_cut(self, symbol: str, base_path: str) -> tuple:
nearest_distance,
CutInitialGuessMethods.three_dimensions.value)

res = minimize(find_reverse_band_gap,
x0=self.cut_initial_guess,
args=(function_args),
method="Nelder-Mead",
options={'xatol': self.tolerance})
cut = res.x[0]
result = minimize(find_negative_band_gap,
x0=self.cut_initial_guess,
args=(function_args),
method="Nelder-Mead",
options={'xatol': self.tolerance})

if not res.success:
if not result.success:
logger.error("Optimization failed")
raise Exception("Optimization failed.")

cut = result.x[0]
return cut
2 changes: 1 addition & 1 deletion minushalf/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from .parse_cut import parse_cut
from .minushalf_yaml import MinushalfYaml
from .make_minushalf_results import make_minushalf_results
from .reverse_band_gap import find_reverse_band_gap
from .reverse_band_gap import find_negative_band_gap
from .fractionary_correction_indexes import get_fractionary_correction_indexes
from .simple_correction_indexes import get_simple_correction_indexes
from .cut_initial_guess import CutInitialGuess
139 changes: 102 additions & 37 deletions minushalf/utils/reverse_band_gap.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import shutil
import math
from loguru import logger
from minushalf.interfaces import SoftwaresAbstractFactory
from .atomic_potential import AtomicPotential
from .band_structure import BandStructure

Expand All @@ -22,7 +23,7 @@ def _get_corrected_potfile_lines(
Args:
cut (float): Cut radius to the algorithm
cut (float): Distance to trimm the potential
atom_potential(AtomicPotential): Class that represents the
potential of the atom
amplitude (float): Scale factor to trimming function
Expand All @@ -41,7 +42,7 @@ def _join_potfiles(
potfiles_folder: str,
symbol: str,
corrected_potfile_lines: list,
):
) -> None:
"""
Join valence potfiles in one
Expand Down Expand Up @@ -77,9 +78,87 @@ def _join_potfiles(
potential_file.close()


def find_reverse_band_gap(cuts: list, *args: tuple) -> float:
def _set_up_cut_folder(base_path: str, input_files: list, cut: float) -> str:
"""
Run vasp and find the eigenvalue for a value of cut
Creates and populates the folder where the first principles calculations will be done
Args:
base_path (str): Path where the folder will be created
cut (float): Distance to trimm the potential
input_files (List[str]): List of input files
Returns:
cut_folder (str): Path to folder where the first principles calculations will be done
"""
cut_folder = _create_cut_folder(base_path, cut)
_copy_input_files(input_files, cut_folder)
return cut_folder


def _create_cut_folder(base_path: str, cut: float) -> str:
"""
Creates the folder where the first principles calculations will be done
Args:
base_path (str): Path where the folder will be created
cut (float): Distance to trimm the potential
Returns:
cut_folder (str): Path to folder where the first principles calculations will be done
"""
find_cut_path = os.path.join(base_path, "find_cut")
cut_folder = os.path.join(find_cut_path, "cut_{:.2f}".format(cut))

if os.path.exists(cut_folder):
shutil.rmtree(cut_folder)
os.mkdir(cut_folder)

return cut_folder


def _copy_input_files(input_files: list, destination_folder: str) -> None:
"""
Copy the input files for the first principles calculations
Args:
input_files (List[str]): List of input files
destination_folder (str): Path to which files will be copied
"""

for file in input_files:
shutil.copyfile(file, os.path.join(destination_folder, file))


def _get_gap(software_factory: SoftwaresAbstractFactory,
cut_folder: str) -> float:
"""
Returns the gap value
Args:
software_factory (SoftwaresAbstractFactory) : Get informations for output files of the first principle calculations
cut_folder (str): Folder where first principles calculations were made
Returns:
gap (float): Gap of the semiconductor material
"""
eigenvalues = software_factory.get_eigenvalues(base_path=cut_folder)
fermi_energy = software_factory.get_fermi_energy(base_path=cut_folder)
atoms_map = software_factory.get_atoms_map(base_path=cut_folder)
num_bands = software_factory.get_number_of_bands(base_path=cut_folder)
band_projection_file = software_factory.get_band_projection_class(
base_path=cut_folder)

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

gap_report = band_structure.band_gap()
return gap_report["gap"]


def find_negative_band_gap(cuts: list, *args: tuple) -> float:
"""
Run vasp and return the gap value multiplied by -1
Args:
cuts (float): List of cuts
Expand All @@ -97,27 +176,24 @@ def find_reverse_band_gap(cuts: list, *args: tuple) -> float:
Returns:
reverse_gap (float): band gap multiplied for -1
"""
negative_gap (float): band gap multiplied for -1
"""
extra_args = args[0]
cut = cuts[0]

if cut <= extra_args["atom_potential"].vtotal.radius[1]:
return math.inf
runner = extra_args["runner"]
software_factory = extra_args["software_factory"]
inplace = extra_args["inplace"]
is_conduction = extra_args["is_conduction"]

find_cut_path = os.path.join(extra_args["base_path"], "find_cut")
cut_folder = os.path.join(find_cut_path, "cut_{:.2f}".format(cut))

if os.path.exists(cut_folder):
shutil.rmtree(cut_folder)
os.mkdir(cut_folder)
if cut <= extra_args["atom_potential"].vtotal.radius[1]:
return math.inf

software_files = extra_args["software_files"]
for file in software_files:
shutil.copyfile(file, os.path.join(cut_folder, file))
## Add condition to include inplace calculations
if not inplace:
cut_folder = _set_up_cut_folder(extra_args["base_path"],
extra_args["software_files"], cut)
else:
cut_folder = '.'

potfile_lines = _get_corrected_potfile_lines(
cut,
Expand All @@ -136,34 +212,23 @@ def find_reverse_band_gap(cuts: list, *args: tuple) -> float:

runner.run(cut_folder)

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

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

gap_report = band_structure.band_gap()
gap = _get_gap(software_factory, cut_folder)

## Cut and Gap logger
if extra_args["is_conduction"]:
## Logger
if is_conduction:
logger.info(
"CONDUCTION CORRECTION: Current CUT value is {:.2f}A".format(cut))
logger.info(
"CONDUCTION CORRECTION: Current Gap value is {:.2f}eV".format(
gap_report["gap"]))
"CONDUCTION CORRECTION: Current Gap value is {:.2f}eV".format(gap))
else:
logger.info(
"VALENCE CORRECTION: Current CUT value is {:.2f}A".format(cut))
logger.info("VALENCE CORRECTION: Current Gap value is {:.2f}eV".format(
gap_report["gap"]))
logger.info(
"VALENCE CORRECTION: Current Gap value is {:.2f}eV".format(gap))

if cut < 0.5:
logger.warning(
"Pay attention, CUT values less than 0.5 might have no physical meaning."
)

return (-1) * gap_report["gap"]
return (-1) * gap

0 comments on commit 7da3fc4

Please sign in to comment.