2016-02-01 14:06:41 +01:00
|
|
|
|
|
|
|
################################################################################
|
|
|
|
#
|
|
|
|
# TRIQS: a Toolbox for Research in Interacting Quantum Systems
|
|
|
|
#
|
|
|
|
# Copyright (C) 2011 by M. Ferrero, O. Parcollet
|
|
|
|
#
|
|
|
|
# DFT tools: Copyright (C) 2011 by M. Aichhorn, L. Pourovskii, V. Vildosola
|
|
|
|
#
|
|
|
|
# PLOVasp: Copyright (C) 2015 by O. E. Peil
|
|
|
|
#
|
|
|
|
# TRIQS is free software: you can redistribute it and/or modify it under the
|
|
|
|
# terms of the GNU General Public License as published by the Free Software
|
|
|
|
# Foundation, either version 3 of the License, or (at your option) any later
|
|
|
|
# version.
|
|
|
|
#
|
|
|
|
# TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
# details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License along with
|
|
|
|
# TRIQS. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
################################################################################
|
2016-02-01 13:44:08 +01:00
|
|
|
|
|
|
|
import errno
|
2016-05-10 11:43:29 +02:00
|
|
|
import os
|
|
|
|
import re
|
|
|
|
import time
|
2016-02-01 13:44:08 +01:00
|
|
|
import signal
|
|
|
|
import sys
|
2020-05-27 17:30:24 +02:00
|
|
|
import triqs.utility.mpi as mpi
|
2023-06-15 21:09:14 +02:00
|
|
|
from h5 import HDFArchive
|
2020-04-08 21:35:59 +02:00
|
|
|
from . import converter
|
2019-09-16 10:59:46 +02:00
|
|
|
from shutil import copyfile
|
2016-02-01 13:44:08 +01:00
|
|
|
|
2016-12-31 14:42:43 +01:00
|
|
|
xch = sys.excepthook
|
|
|
|
def excepthook(typ, value, traceback):
|
|
|
|
xch(typ, value, traceback)
|
|
|
|
if mpi.MPI.COMM_WORLD.size > 1:
|
|
|
|
mpi.MPI.COMM_WORLD.Abort(1)
|
|
|
|
sys.excepthook = excepthook
|
|
|
|
|
2019-09-16 10:59:46 +02:00
|
|
|
debug = False
|
2016-02-01 13:44:08 +01:00
|
|
|
#
|
|
|
|
# Helper functions
|
|
|
|
#
|
|
|
|
def sigint_handler(signal, frame):
|
|
|
|
raise SystemExit(1)
|
|
|
|
|
|
|
|
def is_vasp_lock_present():
|
2016-12-31 14:42:43 +01:00
|
|
|
res_bool = False
|
|
|
|
if mpi.is_master_node():
|
|
|
|
res_bool = os.path.isfile('./vasp.lock')
|
|
|
|
res_bool = mpi.bcast(res_bool)
|
|
|
|
return res_bool
|
2016-02-01 13:44:08 +01:00
|
|
|
|
|
|
|
def is_vasp_running(vasp_pid):
|
|
|
|
"""
|
|
|
|
Tests if VASP initial process is still alive.
|
|
|
|
"""
|
|
|
|
pid_exists = False
|
|
|
|
if mpi.is_master_node():
|
|
|
|
try:
|
|
|
|
os.kill(vasp_pid, 0)
|
2020-04-08 21:35:59 +02:00
|
|
|
except OSError as e:
|
2016-02-01 13:44:08 +01:00
|
|
|
pid_exists = e.errno == errno.EPERM
|
|
|
|
else:
|
|
|
|
pid_exists = True
|
|
|
|
|
|
|
|
pid_exists = mpi.bcast(pid_exists)
|
|
|
|
return pid_exists
|
|
|
|
|
|
|
|
def get_dft_energy():
|
|
|
|
"""
|
|
|
|
Reads energy from the last line of OSZICAR.
|
|
|
|
"""
|
|
|
|
with open('OSZICAR', 'r') as f:
|
|
|
|
nextline = f.readline()
|
|
|
|
while nextline.strip():
|
|
|
|
line = nextline
|
|
|
|
nextline = f.readline()
|
|
|
|
# print "OSZICAR: ", line[:-1]
|
|
|
|
|
|
|
|
try:
|
|
|
|
dft_energy = float(line.split()[2])
|
|
|
|
except ValueError:
|
2020-04-08 21:35:59 +02:00
|
|
|
print("Cannot read energy from OSZICAR, setting it to zero")
|
2016-02-01 13:44:08 +01:00
|
|
|
dft_energy = 0.0
|
|
|
|
|
|
|
|
return dft_energy
|
|
|
|
|
|
|
|
class bcolors:
|
|
|
|
MAGENTA = '\033[95m'
|
|
|
|
BLUE = '\033[94m'
|
|
|
|
GREEN = '\033[92m'
|
|
|
|
YELLOW = '\033[93m'
|
|
|
|
RED = '\033[91m'
|
|
|
|
ENDC = '\033[0m'
|
|
|
|
#
|
|
|
|
# Main self-consistent cycle
|
|
|
|
#
|
2019-09-16 10:59:46 +02:00
|
|
|
def run_all(vasp_pid, dmft_cycle, cfg_file, n_iter, n_iter_dft, vasp_version):
|
2016-02-01 13:44:08 +01:00
|
|
|
"""
|
|
|
|
"""
|
|
|
|
mpi.report(" Waiting for VASP lock to appear...")
|
|
|
|
while not is_vasp_lock_present():
|
|
|
|
time.sleep(1)
|
|
|
|
|
|
|
|
vasp_running = True
|
|
|
|
|
2016-05-10 11:43:29 +02:00
|
|
|
iter = 0
|
2016-02-01 13:44:08 +01:00
|
|
|
while vasp_running:
|
2020-04-08 21:35:59 +02:00
|
|
|
if debug: print(bcolors.RED + "rank %s"%(mpi.rank) + bcolors.ENDC)
|
2016-02-01 13:44:08 +01:00
|
|
|
mpi.report(" Waiting for VASP lock to disappear...")
|
|
|
|
mpi.barrier()
|
|
|
|
while is_vasp_lock_present():
|
|
|
|
time.sleep(1)
|
|
|
|
# if debug: print bcolors.YELLOW + " waiting: rank %s"%(mpi.rank) + bcolors.ENDC
|
|
|
|
if not is_vasp_running(vasp_pid):
|
|
|
|
mpi.report(" VASP stopped")
|
|
|
|
vasp_running = False
|
|
|
|
break
|
2019-09-16 10:59:46 +02:00
|
|
|
|
2016-05-10 11:43:29 +02:00
|
|
|
# Tell VASP to stop if the maximum number of iterations is reached
|
2019-11-21 21:34:37 +01:00
|
|
|
|
2016-05-10 11:43:29 +02:00
|
|
|
|
2020-04-08 21:35:59 +02:00
|
|
|
if debug: print(bcolors.MAGENTA + "rank %s"%(mpi.rank) + bcolors.ENDC)
|
2016-02-01 13:44:08 +01:00
|
|
|
err = 0
|
|
|
|
exc = None
|
2020-04-08 21:35:59 +02:00
|
|
|
if debug: print(bcolors.BLUE + "plovasp: rank %s"%(mpi.rank) + bcolors.ENDC)
|
2016-12-31 14:42:43 +01:00
|
|
|
if mpi.is_master_node():
|
|
|
|
converter.generate_and_output_as_text(cfg_file, vasp_dir='./')
|
|
|
|
# Read energy from OSZICAR
|
|
|
|
dft_energy = get_dft_energy()
|
2016-02-01 13:44:08 +01:00
|
|
|
mpi.barrier()
|
|
|
|
|
2020-04-08 21:35:59 +02:00
|
|
|
if debug: print(bcolors.GREEN + "rank %s"%(mpi.rank) + bcolors.ENDC)
|
2023-06-15 21:09:14 +02:00
|
|
|
corr_energy, sum_k = dmft_cycle()
|
2016-02-01 13:44:08 +01:00
|
|
|
mpi.barrier()
|
|
|
|
|
|
|
|
if mpi.is_master_node():
|
2023-06-15 21:09:14 +02:00
|
|
|
total_energy = dft_energy + corr_energy - sum_k.dc_energ[0]
|
2020-04-08 21:35:59 +02:00
|
|
|
print()
|
|
|
|
print("="*80)
|
|
|
|
print(" Total energy: ", total_energy)
|
|
|
|
print(" DFT energy: ", dft_energy)
|
|
|
|
print(" Corr. energy: ", corr_energy)
|
2023-06-15 21:09:14 +02:00
|
|
|
print(" DFT DC: ", sum_k.dc_energ[0])
|
2020-04-08 21:35:59 +02:00
|
|
|
print("="*80)
|
|
|
|
print()
|
2019-09-16 10:59:46 +02:00
|
|
|
|
|
|
|
# check if we should do additional VASP calculations
|
|
|
|
# in the standard VASP version, VASP writes out GAMMA itself
|
|
|
|
# so that if we want to keep GAMMA fixed we have to copy it to
|
|
|
|
# GAMMA_recent and copy it back after VASP has completed an iteration
|
|
|
|
# if we are using a hacked Version of VASP where the write out is
|
|
|
|
# disabled we can skip this step.
|
|
|
|
# the hack consists of removing the call of LPRJ_LDApU in VASP src file
|
|
|
|
# electron.F around line 644
|
|
|
|
iter_dft = 0
|
2019-11-21 21:34:37 +01:00
|
|
|
|
2019-09-16 10:59:46 +02:00
|
|
|
if vasp_version == 'standard':
|
|
|
|
copyfile(src='GAMMA',dst='GAMMA_recent')
|
|
|
|
while iter_dft < n_iter_dft:
|
2023-06-15 21:09:14 +02:00
|
|
|
# insert recalculation of GAMMA here
|
|
|
|
# Recalculates the density correction
|
|
|
|
# Reads in new projectors and hopping and updates chemical potential
|
|
|
|
# rot_mat is not updated since it's more closely related to the local problem than DFT
|
|
|
|
# New fermi weights are directly read in calc_density_correction
|
|
|
|
if iter > 0 and not iter == n_iter and mpi.is_master_node():
|
|
|
|
with HDFArchive('vasp.h5', 'r') as archive:
|
|
|
|
sum_k.proj_mat = archive['dft_input/proj_mat']
|
|
|
|
sum_k.hopping = archive['dft_input/hopping']
|
|
|
|
sum_k.proj_mat = mpi.bcast(sum_k.proj_mat)
|
|
|
|
sum_k.hopping = mpi.bcast(sum_k.hopping)
|
|
|
|
sum_k.calc_mu(precision=0.001)
|
|
|
|
|
|
|
|
# Writes out GAMMA file
|
|
|
|
sum_k.calc_density_correction(dm_type='vasp')
|
|
|
|
|
|
|
|
mpi.barrier()
|
2019-09-16 10:59:46 +02:00
|
|
|
if mpi.is_master_node():
|
|
|
|
open('./vasp.lock', 'a').close()
|
|
|
|
while is_vasp_lock_present():
|
|
|
|
time.sleep(1)
|
|
|
|
if not is_vasp_running(vasp_pid):
|
|
|
|
mpi.report(" VASP stopped")
|
|
|
|
vasp_running = False
|
|
|
|
break
|
|
|
|
iter_dft += 1
|
|
|
|
if vasp_version == 'standard':
|
|
|
|
copyfile(src='GAMMA_recent',dst='GAMMA')
|
2019-11-21 21:34:37 +01:00
|
|
|
iter += 1
|
|
|
|
if iter == n_iter:
|
2020-04-08 21:35:59 +02:00
|
|
|
print("\n Maximum number of iterations reached.")
|
|
|
|
print(" Aborting VASP iterations...\n")
|
2019-11-21 21:34:37 +01:00
|
|
|
f_stop = open('STOPCAR', 'wt')
|
|
|
|
f_stop.write("LABORT = .TRUE.\n")
|
|
|
|
f_stop.close()
|
2016-02-01 13:44:08 +01:00
|
|
|
if mpi.is_master_node():
|
2023-06-15 21:09:14 +02:00
|
|
|
total_energy = dft_energy + corr_energy - sum_k.dc_energ[0]
|
2016-02-01 13:44:08 +01:00
|
|
|
with open('TOTENERGY', 'w') as f:
|
|
|
|
f.write(" Total energy: %s\n"%(total_energy))
|
|
|
|
f.write(" DFT energy: %s\n"%(dft_energy))
|
|
|
|
f.write(" Corr. energy: %s\n"%(corr_energy))
|
2023-06-15 21:09:14 +02:00
|
|
|
f.write(" DFT DC: %s\n"%(sum_k.dc_energ[0]))
|
|
|
|
f.write(" Energy correction: %s\n"%(corr_energy - sum_k.dc_energ[0]))
|
2016-02-01 13:44:08 +01:00
|
|
|
|
|
|
|
mpi.report("***Done")
|
|
|
|
|
2016-03-11 18:49:29 +01:00
|
|
|
def main():
|
2019-09-16 10:59:46 +02:00
|
|
|
|
2016-05-10 11:43:29 +02:00
|
|
|
import importlib
|
2019-09-16 10:59:46 +02:00
|
|
|
|
2016-02-01 13:44:08 +01:00
|
|
|
try:
|
|
|
|
vasp_pid = int(sys.argv[1])
|
|
|
|
except (ValueError, KeyError):
|
|
|
|
if mpi.is_master_node():
|
2020-04-08 21:35:59 +02:00
|
|
|
print("ERROR: VASP process pid must be provided as the first argument")
|
2016-05-10 11:43:29 +02:00
|
|
|
raise
|
|
|
|
|
|
|
|
try:
|
|
|
|
n_iter = int(sys.argv[2])
|
|
|
|
except (ValueError, KeyError):
|
|
|
|
if mpi.is_master_node():
|
2020-04-08 21:35:59 +02:00
|
|
|
print("ERROR: Number of iterations must be provided as the second argument")
|
2016-02-01 13:44:08 +01:00
|
|
|
raise
|
2019-09-16 10:59:46 +02:00
|
|
|
|
|
|
|
try:
|
|
|
|
n_iter_dft = int(sys.argv[3])
|
|
|
|
except (ValueError, KeyError):
|
|
|
|
if mpi.is_master_node():
|
2020-04-08 21:35:59 +02:00
|
|
|
print("ERROR: Number of VASP iterations with fixed charge density must be provided as the third argument")
|
2019-09-16 10:59:46 +02:00
|
|
|
raise
|
2016-03-11 18:49:29 +01:00
|
|
|
|
|
|
|
try:
|
2019-09-16 10:59:46 +02:00
|
|
|
dmft_script = re.sub("\.py$", "", sys.argv[4])
|
2016-03-11 18:49:29 +01:00
|
|
|
except:
|
|
|
|
if mpi.is_master_node():
|
2020-04-08 21:35:59 +02:00
|
|
|
print("ERROR: User-defined DMFT script must be provided as the fourth argument")
|
2016-03-11 18:49:29 +01:00
|
|
|
raise
|
2016-05-10 11:43:29 +02:00
|
|
|
|
|
|
|
# Optional parameter: config-file name
|
|
|
|
try:
|
2019-09-16 10:59:46 +02:00
|
|
|
cfg_file = sys.argv[5]
|
2016-05-10 11:43:29 +02:00
|
|
|
except KeyError:
|
|
|
|
cfg_file = 'plo.cfg'
|
2019-09-16 10:59:46 +02:00
|
|
|
|
|
|
|
try:
|
|
|
|
vasp_version = sys.argv[6]
|
|
|
|
except KeyError:
|
|
|
|
vasp_version = 'standard'
|
|
|
|
|
|
|
|
if vasp_version != 'standard' and vasp_version != 'no_gamma_write':
|
|
|
|
raise Exception('vasp_version has to be standard or no_gamma_write')
|
2016-05-10 11:43:29 +02:00
|
|
|
|
2016-02-01 13:44:08 +01:00
|
|
|
# if len(sys.argv) > 1:
|
|
|
|
# vasp_path = sys.argv[1]
|
|
|
|
# else:
|
|
|
|
# try:
|
|
|
|
# vasp_path = os.environ['VASP_DIR']
|
|
|
|
# except KeyError:
|
|
|
|
# if mpi.is_master_node():
|
|
|
|
# print "Path to VASP must be specified either as an argument of in VASP_DIR"
|
|
|
|
# raise
|
|
|
|
signal.signal(signal.SIGINT, sigint_handler)
|
|
|
|
|
2016-05-10 11:43:29 +02:00
|
|
|
dmft_mod = importlib.import_module(dmft_script)
|
2016-03-11 18:49:29 +01:00
|
|
|
|
2019-09-16 10:59:46 +02:00
|
|
|
run_all(vasp_pid, dmft_mod.dmft_cycle, cfg_file, n_iter, n_iter_dft, vasp_version)
|
2016-03-11 18:49:29 +01:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|