import numpy as np
from datetime import datetime
from EPWpy.default import default
from EPWpy.utilities.printing import *
from EPWpy.utilities.write_job import *
[docs]
class SetDefaultVals:
"""
Internal helper class that defines and manages default parameter values
used throughout the **EPWpy** framework.
This class is not intended to be instantiated directly by users.
It is primarily used internally to initialize consistent default
paths, code settings, and runtime parameters across different EPWpy modules.
Parameters
----------
code : str or None, optional
Name or path of the simulation code for which default values
are being set. Typically `'qe'`, `'epw'`, or `'bgw'`.
Default is `None`.
Attributes
----------
code : str or None
Identifier or path of the code for which defaults apply.
home : str
Current working directory when the object is initialized.
Used as the default base path for relative directories.
Notes
-----
- This class is invoked internally by EPWpy setup and configuration modules.
- Modifying defaults manually is discouraged; use higher-level
configuration interfaces instead.
- The defaults defined here ensure that all components of EPWpy
share a consistent runtime environment.
Examples
--------
>>> from EPWpy.default.set_default import SetDefaultVals
>>> defaults = SetDefaultVals(code="<path to qe bin>")
>>> print(defaults.home)
'/home/user/current_project'
"""
def __init__(self, code=None):
"""
Initialize the default value manager for EPWpy.
Parameters
----------
code : str or None, optional
Name or path of the code for which default values
are being initialized. Default is `None`.
"""
import os
self.code = code
self.home = os.getcwd()
self.home_real = os.getcwd()
[docs]
def default_values(self):
"""
Putting default values in respective dictionaries
--------------------
"""
self.run_serial = False
self.pw_control = {'calculation': '\'scf\'','verbosity':'\'low\'',
'restart_mode':'\'from_scratch\'','outdir': '\'./\'',
'pseudo_dir':'\'./\'','prefix':'\'si\''}
self.pw_system = {'ibrav':2,'celldm(1)':10.8,'celldm(2)':None,'celldm(3)':None, 'nat':2,'ntyp': 1,
'ecutwfc':None,'ecutrho':None,'lspinorb':None,'noncolin':None,'assume_isolated':None,
'vdw_corr':None,
'occupations':None, 'smearing':None, 'degauss':None}
self.pw_electrons = {'conv_thr':'1E-12','diagonalization':'\'david\'' }
self.pw_ions = {'ion_dynamics':'\'bfgs\''}
self.pw_cell = {'cell_dynamics':'\'bfgs\'','press':0.0}
self.iondynamics = False
self.celldynamics = False
self.pw_atomic_species = {'pseudo':[],'mass':[],'atomic_species':[]}
shift=np.array([[0 ,0 ,0]])
atomic_pos = np.zeros((2,3),dtype=float)
atoms=np.array(['si','si'])
self.pw_atomic_positions={'num':self.pw_system['nat'],
'atomic_pos':atomic_pos,'atoms':atoms,'atomic_position_type':'alat'}
kpoints=np.array([[6.0,6.0,6.0]])
shift=np.array([[0 ,0 ,0]])
self.pw_kpoints = {'kpoints_type':'automatic','shift':shift,'kpoints':kpoints}
self.pw_cell_parameters = {'cell_type': 'alat', 'lattice_vector':np.array([['0.000 0.000 0.000'],
['0.000 0.000 0.00'],['0.000 0.000 0.000']])}
self.pw_system['nat'] = len(self.pw_atomic_positions['atomic_pos'][:,0])
self.pw_system['ntyp'] = len(self.pw_atomic_species['atomic_species'])
self.pw_atomic_species['atoms'] = self.pw_system['nat']
self.ph_params = {'prefix':self.pw_control['prefix'],'fildyn': str(self.pw_control['prefix'])+'.dyn\'',
'ldisp': '.true.','fildvscf':'\'dvscf\'','nq1':2,'nq2':2,'nq3':2,'tr2_ph':'1.0d-14'}
self.ph_qpoints = {}
self.q2r_params = {'fildyn': '\'si.dyn\'','flfrc': '\'si.fc\'','zasr':'\'crystal\''}
self.dvscf_q2r_params = {}
self.postahc_params = {}
nk1=self.ph_params['nq1']
nk2=self.ph_params['nq2']
nk3=self.ph_params['nq3']
nq1=self.ph_params['nq3']
nq2=self.ph_params['nq3']
nq3=self.ph_params['nq3']
self.epw_params = {'prefix':self.pw_control['prefix'],'mass':self.pw_atomic_species['mass'],
'outdir':self.pw_control['outdir'],'elph':'.true.','epbwrite':'.false.','epbread':'.false.',
'epwwrite':'.true.','epwread':'.false.','etf_mem':1,'nbndsub':8,
'use_ws':'.true.','wannierize':'.true.','num_iter':5000,'iprint': 2,'dis_win_max':None,'dis_froz_max':None,
'fsthick':1.2, 'temps':300,'degaussw':0.005,'dvscf_dir':'\'./save\'','band_plot':'.false.','nk1': nk1,
'nk2':nk2,'nk3':nk3,'nq1':nq1,'nq2':nq2,'nq3':nq3}
self.zg_inputzg = {'flfrc':'\'SPECIFY\'','asr':self.q2r_params['zasr'],
'flscf':'\'scf.in\'','T':0.00,'dim1':3,'dim2':3,'dim3':3,'compute_error':'.true.','synch':'.true.','error_thresh':0.4,
'niters':3000,'incl_qA':'.true.','ASDM':'.false.'}
self.zg_inputazg = {}
self.eps_inputpp = {'prefix':self.pw_control['prefix'],'outdir':self.pw_control['outdir'],'calculation':'\'eps\''}
self.eps_energy_grid = {'smeartype':'\'gauss\'','intersmear':'0.03','wmin':'0.2','wmax':'4.5','nw':'600','shift':'0.0'}
self.pw_bands = {'prefix':'\'si\'',
'outdir':self.pw_control['outdir'],
'filband': '\'bands.dat\'',
'lsym': '.false.'}
self.nscf_supercond = {'prefix':'\'si\'',
'outdir':self.pw_control['outdir'],
'filband': '\'bands.dat\''}
self.matdyn_input={'asr': '\'crystal\'',
'q_in_band_form': '.true.',
'q_in_cryst_coord': '.true.',
'dos': '.false.'}
self.matdyn_kpoints={}
self.dynmat_input = {'asr':'\'crystal\''}
self.phdos_input={'asr': '\'crystal\'',
'mass':self.pw_atomic_species['mass'],
'flfrc':self.q2r_params['flfrc'],
'flfrq':str(self.pw_control['prefix'][:-1])+'.freq\'',
'dos': '.true.'}
self.dos_input={'prefix':self.pw_control['prefix']}
self.pdos_input={'prefix':self.pw_control['prefix']}
self.wannier_params = {'num_iter':100}
self.pw2wann_params = {'outdir':'\'./\'','write_amn':'.true.','write_mmn':'.true.','write_unk':'.false.'}
self.card_params = {}
self.cards = {}
[docs]
def default_checks(self, type_input):
#if (self.verbosity > 2):
# print('Mass length: ', len(self.pw_atomic_species['mass']))
if (len(self.pw_atomic_species['pseudo']) == 0):
type_input.update({'pseudo_auto': True})
if self.pw_system['ecutwfc'] is None:
self.pw_system['ecutwfc'] = self.get_ecutwfc()
if (len(self.pw_atomic_species['mass']) == 0):
self.pw_atomic_species['mass'] = self.get_mass()
return(type_input)
[docs]
@decorated_structure
def set_values(self,type_input):
"""
Fills default keys with values provided by user
"""
self.home=os.getcwd()
self.home_real = os.getcwd()
for key in type_input.keys():
if (key == 'home_dir'):
self.home = type_input[key]
if key in self.pw_control:
self.pw_control[key] = type_input[key]
if key in self.pw_system:
self.pw_system[key] = type_input[key]
if key in self.pw_electrons:
self.pw_electrons[key] = type_input[key]
if key in self.pw_ions:
self.pw_ions[key] = type_input[key]
if key in self.pw_cell:
self.pw_cell[key] = type_input[key]
if key in self.pw_atomic_species:
self.pw_atomic_species[key] = type_input[key]
if key in self.pw_atomic_positions:
self.pw_atomic_positions[key] = type_input[key]
if key in self.pw_kpoints:
self.pw_kpoints[key] = type_input[key]
if key in self.pw_cell_parameters:
self.pw_system['ibrav']=0
self.pw_cell_parameters[key] = type_input[key]
if (self.pw_system['ibrav'] == 0):
self.pw_system['celldm(1)'] = None
# del self.pw_system['celldm(1)']
for key in type_input.keys():
if key in self.ph_params:
self.ph_params[key] = type_input[key]
for key in type_input.keys():
if key in self.epw_params:
self.epw_params[key] = type_input[key]
for key in type_input.keys():
if key in self.q2r_params:
self.q2r_params[key] = type_input[key]
for key in type_input.keys():
if key in self.dvscf_q2r_params:
self.dvscf_q2r_params[key] = type_input[key]
for key in type_input.keys():
if key in self.postahc_params:
self.postahc_params[key] = type_input[key]
for key in type_input.keys():
if key in self.zg_inputzg:
self.zg_inputzg[key] = type_input[key]
for key in type_input.keys():
if key in self.zg_inputazg:
self.zg_inputazg[key] = type_input[key]
for key in type_input.keys():
if key in self.eps_inputpp:
self.eps_inputpp[key] = type_input[key]
for key in type_input.keys():
if key in self.eps_energy_grid:
self.eps_energy_grid[key] = type_input[key]
for key in type_input.keys():
if key in self.pw_bands:
self.pw_bands[key] = type_input[key]
for key in type_input.keys():
if key in self.nscf_supercond:
self.nscf_supercond[key] = type_input[key]
for key in type_input.keys():
if key in self.dynmat_input:
self.dynmat_input[key]=type_input[key]
for key in type_input.keys():
if key in self.matdyn_input:
self.matdyn_input[key]=type_input[key]
for key in type_input.keys():
if key in self.phdos_input:
self.phdos_input[key]=type_input[key]
for key in type_input.keys():
if key in self.dos_input:
self.dos_input[key]=type_input[key]
for key in type_input.keys():
if key in self.pdos_input:
self.pdos_input[key]=type_input[key]
self.prefix=self.pw_control['prefix']
self.prefix=self.prefix.replace('\'','')
self.structure = None
if ('structure' in type_input.keys()):
self.structure = type_input['structure']
self.import_struct(type_input)
if ('structure_mp' in type_input.keys()):
self.matid = type_input['structure_mp']
self.import_struct(type_input)
if ('read_config' in type_input.keys()):
self.read_config(type_input)
type_input = self.default_checks(type_input)
self.pseudo_typs = ['PBE-FR-PDv0.4','PBE-SR','LDA-FR-PDv0.4','LDA-SR','PBE-SR-noCCv0.4']
self.pseudo_orbitals = ['','_r','-sp_r','-d_r','-s_r','-sp','-d','-s','_std','_str']
self.pseudo_end = 'upf'
if ('pseudo_auto' not in type_input.keys()):
resp = [True]
else:
resp = [False]
for i in range(len(self.pseudo_typs)):
if ('pseudo_auto' in type_input.keys()):
if (type_input['pseudo_auto'] == True):
if ('pseudo_type' in type_input.keys()):
print('setting pseudo type to:', type_input['pseudo_type'])
self.pseudo_typ = type_input['pseudo_type']
else:
print('setting pseudo type to:', self.pseudo_typs[i])
self.pseudo_typ = self.pseudo_typs[i]
if ('pseudo_orbitals' in type_input.keys()):
self.pseudo_orbitals = type_input['pseudo_orbitals']
self.atomic_species = self.pw_atomic_species['atomic_species']
pseudo, pseudo_dir, resp = self.get_pseudo()
if ('pseudo_dir' in type_input.keys()):
if (type_input['pseudo_dir'] == pseudo_dir):
pass
else:
print("WARNING: pseudo_auto=True and pseudo_dir both specified, likely resulting in a crash")
self.pw_control['pseudo_dir']='\''+pseudo_dir+'\''
self.pw_atomic_species['pseudo'] = pseudo
if (all(resp) == True):
break
if ('pseudo_orbitals' in type_input.keys()):
self.pseudo_orbitals = type_input['pseudo_orbitals']
self.atomic_species = self.pw_atomic_species['atomic_species']
pseudo, pseudo_dir, resp = self.get_pseudo()
self.pw_control['pseudo_dir']='\''+pseudo_dir+'\''
self.pw_atomic_species['pseudo'] = pseudo
if (all(resp) == True):
break
self.pseudo = self.pw_atomic_species['pseudo']
if ('pseudo_dir' in type_input.keys()):
self.pseudo_dir = type_input['pseudo_dir']
self.pw_control['pseudo_dir'] = type_input['pseudo_dir']
[docs]
def read_config(self, type_input):
"""
Reads a configure file to build EPWpy calculation
"""
pass
# @decorated_structure
[docs]
def import_struct(self,type_input):
self.pw_system['ibrav'] = 0
if ('structure_mp' in type_input.keys()):
self.get_poscar()
self.structure = f'POSCAR_{self.matid}'
atomic_pos,_,lattice_vec,atoms,atomic_species,natoms, lattice_constant = self.get_atom()
self.pw_system['celldm(1)'] = 1.0 # lattice_constant
self.pw_system['nat'] = sum(natoms)
self.pw_system['ntyp'] = len(natoms)
self.pw_atomic_species['atomic_species'] = atomic_species
self.pw_atomic_species['nat_species'] = natoms
self.pw_atomic_positions={'num':self.pw_system['nat'], ### This was using the default nat by mistake
'atomic_pos':atomic_pos,'atoms':atoms,'atomic_position_type':'crystal'}
self.pw_cell_parameters['lattice_vector'] = lattice_vec[:,:]*lattice_constant
del self.pw_system['celldm(1)']
self.pw_cell_parameters['cell_type'] = 'angstrom'
if(len(self.pw_atomic_species['mass']) < len(atomic_species)) :
self.pw_atomic_species['mass']= self.get_mass()
self.print_struct()
[docs]
def print_struct(self):
for key in self.pw_cell_parameters.keys():
if(key == 'lattice_vector'):
for i,lattice_vector in enumerate(self.pw_cell_parameters[key]):
print(f'lattice vector({i+1}): ',end=" ")
print(lattice_vector)
for key in self.pw_atomic_positions.keys():
if(key == 'atomic_pos'):
for i,atomic_pos in enumerate(self.pw_atomic_positions[key]):
atom=self.pw_atomic_positions['atoms'][i]
print(f'atom({i+1}): {atom}',end=" ")
print(atomic_pos)
[docs]
def create_writer(self, type_input = None):
"""
Creates a writer to write jobs
"""
if type_input is None:
type_input = {}
self.writer = write_job()
self.writer.write_script = False
self.writer.rewrite_script = False
self.writer.script_params = default.script_params
self.writer.dir_to_QE = self.code
for key1 in type_input.keys():
if (key1 == 'write_script'):
self.writer.write_script = type_input[key1]
self.writer.script_params[key1] = type_input[key1]
if (key1 == 'rewrite_script'):
self.writer.script_params[key1] = type_input[key1]
self.writer.rewrite_script = type_input[key1]
if (key1 == 'script_params'):
for key2 in type_input[key1].keys():
self.writer.script_params[key2] = type_input[key1][key2]
job_name = self.writer.script_params['job_name']
self.writer.script_params['job_name'] = f'{self.home_real}/{job_name}'
return(self.writer)
[docs]
def update_script_date(self):
"""
Gives a unique name to script
"""
name = self.writer.script_params['job_name']
date_is_found = False
for index, char in enumerate(name):
if char.isdigit():
if name[index:index+6].isdigit() and name[index+6:index+7]=='_' and name[index+7:index+15].isdigit(): # find timestamp substring
name = name[:index] + name[index+15:]
date_is_found = True
break
if (date_is_found) == False:
index = name.find('.')
self.writer.script_params['job_name'] = name[:index] + datetime.today().strftime('%H%M%S_%Y%m%d') + name[index:]
if (self.writer.write_script == True):
self.write_sbatch_statements()
[docs]
def write_sbatch_statements(self):
"""
Writes the sbatch statements
"""
self.writer.write_precondition()
[docs]
def get_default_writer(self):
"""
Gets the writer
"""
# self.writer = self.create_writer()
self.writer.script_params['dir_to_QE'] = self.code
self.writer.home = self.home
if (self.writer.script_params['rewrite_script'] == False):
self.update_script_date()
return(self.writer)