mirror of https://github.com/QMCPACK/qmcpack.git
375 lines
14 KiB
Python
375 lines
14 KiB
Python
##################################################################
|
|
## (c) Copyright 2015- by Jaron T. Krogel ##
|
|
##################################################################
|
|
|
|
|
|
#====================================================================#
|
|
# pwscf.py #
|
|
# Nexus interface to the PWSCF simulation code. #
|
|
# #
|
|
# Content summary: #
|
|
# Pwscf #
|
|
# Simulation class for PWSCF. #
|
|
# #
|
|
# generate_pwscf #
|
|
# User-facing function to create Pwscf simulation objects. #
|
|
# #
|
|
#====================================================================#
|
|
|
|
|
|
import os
|
|
from numpy import array
|
|
from generic import obj
|
|
from physical_system import PhysicalSystem
|
|
from simulation import Simulation
|
|
from pwscf_input import PwscfInput,generate_pwscf_input
|
|
from pwscf_analyzer import PwscfAnalyzer
|
|
from execute import execute
|
|
from debug import ci
|
|
|
|
|
|
unique_vdw_functionals = [
|
|
'optb86b-vdw',
|
|
'vdw-df3', # optB88+vdW
|
|
'vdw-df',
|
|
'vdw-df2',
|
|
'rev-vdw-df2',
|
|
'vdw-df-c09',
|
|
'vdw-df2-c09',
|
|
'rvv10',
|
|
]
|
|
repeat_vdw_functionals = [
|
|
'vdw-df4', # 'optB86b-vdW'
|
|
]
|
|
unique_functionals = [
|
|
'revpbe',
|
|
'pw86pbe',
|
|
'b86bpbe',
|
|
'pbe0',
|
|
'hse',
|
|
'gaup',
|
|
'pbesol',
|
|
'pbeq2d',
|
|
'optbk88',
|
|
'optb86b',
|
|
'pbe',
|
|
'wc',
|
|
'b3lyp',
|
|
'pbc',
|
|
'bp',
|
|
'pw91',
|
|
'hcth',
|
|
'olyp',
|
|
'tpss',
|
|
'oep',
|
|
'hf',
|
|
'blyp',
|
|
'lda',
|
|
'sogga',
|
|
'm06l',
|
|
'ev93',
|
|
]+unique_vdw_functionals
|
|
repeat_functionals = [
|
|
'q2d', # pbeq2d
|
|
'pz', # lda
|
|
]+repeat_vdw_functionals
|
|
|
|
vdw_functionals = set(unique_vdw_functionals+repeat_vdw_functionals)
|
|
allowed_functionals = set(unique_functionals+repeat_functionals)
|
|
|
|
|
|
|
|
class Pwscf(Simulation):
|
|
input_type = PwscfInput
|
|
analyzer_type = PwscfAnalyzer
|
|
generic_identifier = 'pwscf'
|
|
application = 'pw.x'
|
|
application_properties = set(['serial','mpi'])
|
|
application_results = set(['charge_density','orbitals','structure','restart'])
|
|
|
|
supports_restarts = True # supports restartable, but not force restart yet
|
|
|
|
vdw_table = None
|
|
|
|
@staticmethod
|
|
def settings(vdw_table=None):
|
|
# van der Waals family of functional require the vdW table generated by
|
|
# generate_vdW_kernel_table.x: specify 'vdw_table' in settings
|
|
Pwscf.vdw_table = vdw_table
|
|
#end def settings
|
|
|
|
@staticmethod
|
|
def restore_default_settings():
|
|
Pwscf.vdw_table = None
|
|
#end def restore_default_settings
|
|
|
|
|
|
#def propagate_identifier(self):
|
|
# self.input.control.prefix = self.identifier
|
|
##end def propagate_identifier
|
|
|
|
|
|
def __init__(self,**sim_args):
|
|
group_atoms = sim_args.pop('group_atoms',False)
|
|
sync_from_scf = sim_args.pop('sync_from_scf',True)
|
|
Simulation.__init__(self,**sim_args)
|
|
self.sync_from_scf = False
|
|
calc = self.input.control.get('calculation',None)
|
|
if calc=='nscf':
|
|
self.sync_from_scf = sync_from_scf
|
|
#end if
|
|
if group_atoms and isinstance(self.system,PhysicalSystem):
|
|
self.warn('requested grouping by atomic species, but pwscf does not group atoms anymore!')
|
|
#self.system.structure.group_atoms()
|
|
#end if
|
|
#end def __init__
|
|
|
|
|
|
def write_prep(self):
|
|
#make sure the output directory exists
|
|
outdir = os.path.join(self.locdir,self.input.control.outdir)
|
|
if not os.path.exists(outdir):
|
|
os.makedirs(outdir)
|
|
#end if
|
|
#copy over vdw_table for vdW-DF functional
|
|
if self.path_exists('input/system/input_dft'):
|
|
functional = self.input.system.input_dft.lower()
|
|
if '+' not in functional and functional not in allowed_functionals:
|
|
self.warn('functional "{0}" is unknown to pwscf'.format(functional))
|
|
#end if
|
|
if functional in vdw_functionals:
|
|
if self.vdw_table is None:
|
|
self.error('attempting to run vdW functional "{0}", but vdw_table is missing\nplease provide path to table file via "vdw_table" parameter in settings'.format(functional))
|
|
#end if
|
|
cd_rel = os.path.relpath(self.vdw_table,self.locdir)
|
|
# copy instead of link to vdw_table to avoid file-lock from multiple pw.x instances
|
|
cp_cmd = 'cd '+self.locdir+';cp '+cd_rel+' .'
|
|
os.system(cp_cmd)
|
|
#end if
|
|
#end if
|
|
#end def write_prep
|
|
|
|
|
|
def check_result(self,result_name,sim):
|
|
input = self.input
|
|
control = input.control
|
|
if result_name=='charge_density' or result_name=='restart':
|
|
calculating_result = True
|
|
elif result_name=='orbitals':
|
|
calculating_result = 'calculation' not in control or 'scf' in control.calculation.lower()
|
|
elif result_name=='structure':
|
|
calculating_result = 'calculation' in control and 'relax' in control.calculation.lower()
|
|
else:
|
|
calculating_result = False
|
|
#end if
|
|
return calculating_result
|
|
#end def check_result
|
|
|
|
|
|
def get_result(self,result_name,sim):
|
|
result = obj()
|
|
input = self.input
|
|
control = input.control
|
|
prefix = 'pwscf'
|
|
outdir = './'
|
|
if 'prefix' in control:
|
|
prefix = control.prefix
|
|
#end if
|
|
if 'outdir' in control:
|
|
outdir = control.outdir
|
|
#end if
|
|
if outdir.startswith('./'):
|
|
outdir = outdir[2:]
|
|
#end if
|
|
if result_name=='charge_density' or result_name=='restart':
|
|
result.locdir = self.locdir
|
|
result.outdir = os.path.join(self.locdir,outdir)
|
|
result_save_outdir = os.path.join(self.locdir,outdir,prefix+'.save')
|
|
if os.path.exists(os.path.join(result_save_outdir,'charge-density.hdf5')):
|
|
result.location = os.path.join(result_save_outdir,'charge-density.hdf5')
|
|
chg_dens_format = 'hdf5'
|
|
else:
|
|
result.location = os.path.join(result_save_outdir,'charge-density.dat')
|
|
chg_dens_format = 'dat'
|
|
|
|
if chg_dens_format == 'dat':
|
|
result.spin_location = os.path.join(result_save_outdir,'spin-polarization.dat')
|
|
elif chg_dens_format == 'hdf5':
|
|
result.spin_location = None
|
|
elif result_name=='orbitals':
|
|
result.location = os.path.join(self.locdir,outdir,prefix+'.wfc1')
|
|
elif result_name=='structure':
|
|
pa = self.load_analyzer_image()
|
|
structs = pa.structures
|
|
struct = structs[len(structs)-1]
|
|
pos = struct.positions
|
|
atoms = struct.atoms
|
|
if 'celldm(1)' in self.input.system:
|
|
scale = self.input.system['celldm(1)']
|
|
else:
|
|
scale = 1.0
|
|
#end if
|
|
pos = scale*array(pos)
|
|
|
|
structure = self.system.structure.copy()
|
|
structure.change_units('B')
|
|
structure.pos = pos
|
|
structure.set_elem(atoms)
|
|
if 'axes' in struct:
|
|
structure.axes = struct.axes.copy()
|
|
#end if
|
|
result.structure = structure
|
|
else:
|
|
self.error('ability to get result '+result_name+' has not been implemented')
|
|
#end if
|
|
return result
|
|
#end def get_result
|
|
|
|
|
|
def incorporate_result(self,result_name,result,sim):
|
|
if result_name=='charge_density':
|
|
c = self.input.control
|
|
res_path = os.path.abspath(result.locdir)
|
|
loc_path = os.path.abspath(self.locdir)
|
|
if res_path==loc_path:
|
|
None # don't need to do anything if in same directory
|
|
elif self.sync_from_scf: # rsync output into nscf dir
|
|
outdir = os.path.join(self.locdir,c.outdir)
|
|
command = 'rsync -av {0}/* {1}/'.format(result.outdir,outdir)
|
|
if not os.path.exists(outdir):
|
|
os.makedirs(outdir)
|
|
#end if
|
|
sync_record = os.path.join(outdir,'nexus_sync_record')
|
|
if not os.path.exists(sync_record):
|
|
print(' Running rsync for the {} directory. This might take a while.'.format(outdir))
|
|
execute(command)
|
|
print(' Completed rsync for the {} directory.'.format(outdir))
|
|
f = open(sync_record,'w')
|
|
f.write('\n')
|
|
f.close()
|
|
#end if
|
|
else: # attempt to use symbolic links instead
|
|
link_loc = os.path.join(self.locdir,c.outdir,c.prefix+'.save')
|
|
cd_loc = result.location
|
|
cd_rel = os.path.relpath(cd_loc,link_loc)
|
|
sp_loc = result.spin_location
|
|
|
|
cwd = os.getcwd()
|
|
if not os.path.exists(link_loc):
|
|
os.makedirs(link_loc)
|
|
#end if
|
|
|
|
os.chdir(link_loc)
|
|
if cd_rel.endswith('charge-density.hdf5'):
|
|
os.system('ln -s '+cd_rel+' charge-density.hdf5')
|
|
elif cd_rel.endswith('charge-density.dat'):
|
|
sp_rel = os.path.relpath(sp_loc,link_loc)
|
|
os.system('ln -s '+cd_rel+' charge-density.dat')
|
|
os.system('ln -s '+sp_rel+' spin-polarization.dat')
|
|
else:
|
|
raise FileNotFoundError('charge-density.dat or charge-density.hdf5 not found in {0}'.format(result_save_outdir))
|
|
os.chdir(cwd)
|
|
|
|
#end if
|
|
elif result_name=='structure':
|
|
relstruct = result.structure.copy()
|
|
relstruct.change_units('B')
|
|
self.system.structure = relstruct
|
|
self.system.remove_folded()
|
|
|
|
input = self.input
|
|
preserve_kp = 'k_points' in input and 'specifier' in input.k_points and (input.k_points.specifier=='automatic' or input.k_points.specifier=='gamma')
|
|
if preserve_kp:
|
|
kp = input.k_points.copy()
|
|
#end if
|
|
input.incorporate_system(self.system)
|
|
if preserve_kp:
|
|
input.k_points = kp
|
|
#end if
|
|
elif result_name=='restart':
|
|
c = self.input.control
|
|
if('startingwfc' in self.input.electrons and self.input.electrons.startingwfc != 'file'):
|
|
self.error('Exiting. User has specified startingwfc=\''+self.input.electrons.startingwfc+'\'.\nThis value will be overwritten when incorporating result \'restart\'.\nPlease fix conflict.')
|
|
#end if
|
|
if('startingpot' in self.input.electrons and self.input.electrons.startingpot != 'file'):
|
|
self.error('Exiting. User has specified startingpot=\''+self.input.electrons.startingpot+'\'.\nThis value will be overwritten when incorporating result \'restart\'.\nPlease fix conflict.')
|
|
#end if
|
|
c.restart_mode='restart'
|
|
res_path = os.path.abspath(result.locdir)
|
|
loc_path = os.path.abspath(self.locdir)
|
|
if res_path==loc_path:
|
|
None # don't need to do anything if in same directory
|
|
else: # rsync output into new scf dir
|
|
outdir = os.path.join(self.locdir,c.outdir)
|
|
command = 'rsync -av {0}/* {1}/'.format(result.outdir,outdir)
|
|
if not os.path.exists(outdir):
|
|
os.makedirs(outdir)
|
|
#end if
|
|
sync_record = os.path.join(outdir,'nexus_sync_record')
|
|
if not os.path.exists(sync_record):
|
|
print(' Running rsync for the {} directory. This might take a while.'.format(outdir))
|
|
execute(command)
|
|
print(' Completed rsync for the {} directory.'.format(outdir))
|
|
f = open(sync_record,'w')
|
|
f.write('\n')
|
|
f.close()
|
|
#end if
|
|
#end if
|
|
elif result_name == 'hubbard_parameters':
|
|
self.input.incorporate_hubbard(result)
|
|
else:
|
|
self.error('ability to incorporate result '+result_name+' has not been implemented')
|
|
#end if
|
|
#end def incorporate_result
|
|
|
|
|
|
def check_sim_status(self):
|
|
outfile = os.path.join(self.locdir,self.outfile)
|
|
fobj = open(outfile,'r')
|
|
output = fobj.read()
|
|
fobj.close()
|
|
not_converged = 'convergence NOT achieved' in output
|
|
time_exceeded = 'Maximum CPU time exceeded' in output
|
|
user_stop = 'Program stopped by user request' in output
|
|
run_finished = 'JOB DONE' in output
|
|
restartable = not_converged or time_exceeded or user_stop
|
|
restart = run_finished and self.restartable and restartable
|
|
if restart:
|
|
self.save_attempt()
|
|
self.input.control.restart_mode = 'restart'
|
|
self.reset_indicators()
|
|
else:
|
|
error_in_routine = 'Error in routine' in output
|
|
failed = not_converged or time_exceeded or user_stop
|
|
failed |= error_in_routine
|
|
self.finished = run_finished
|
|
self.failed = failed
|
|
#end if
|
|
#end def check_sim_status
|
|
|
|
|
|
def get_output_files(self):
|
|
output_files = []
|
|
return output_files
|
|
#end def get_output_files
|
|
|
|
|
|
def app_command(self):
|
|
return self.app_name+' -input '+self.infile
|
|
#end def app_command
|
|
#end class Pwscf
|
|
|
|
|
|
|
|
def generate_pwscf(**kwargs):
|
|
sim_args,inp_args = Pwscf.separate_inputs(kwargs)
|
|
|
|
if not 'input' in sim_args:
|
|
input_type = inp_args.delete_optional('input_type','generic')
|
|
sim_args.input = generate_pwscf_input(input_type,**inp_args)
|
|
#end if
|
|
pwscf = Pwscf(**sim_args)
|
|
|
|
return pwscf
|
|
#end def generate_pwscf
|