Source code for mppi.InputFiles.YamboInput
"""
Class to create and manipulate the yambo input files.
The class is partially inspired from the YamboIn class of YamboPy. In this implementation
the input object inherit from dict, so all the standard methods for python dictionaries can
be used to modify the attribute of the input.
"""
from subprocess import Popen, PIPE
import os, re
from sys import exit
[docs]class YamboInput(dict):
#Regular expressions
_variaexp = '([A-Za-z\_0-9]+(?:\_[A-Za-z]+)?)' #variables names
_numexp = '([+-]?\d+(?:\.\d+)?(?:[eE][-+]?\d+)?)' #number
_spacexp = '(?:[ \t]+)?' #space
_stringexp = '["\']([a-zA-Z0-9_ ]+?)["\']' #string
_arrayexp = '%'+_spacexp+_variaexp+'\s+(?:\#.+)?((?:(?:\s|\.|[+-]?\d)+?\|)+)\s+([a-zA-Z]+)?' #arrays
_complexexp = '\('+_spacexp+_numexp+_spacexp+','+_spacexp+_numexp+_spacexp+'\)' #complex numbers
_runexp = '([a-zA-Z0-9_]+)'
# list of available runlevels to be stored in the arguments array.
# Also the 'options' like RmTimeRev or DephCVonly were included in the _runlevels list but they have
# been removed since otherwise it seems that these values are always included in the arguments list
# after the parsing of the input file.
_runlevels = ['rim_cut','RIM_W','chi','em1s','bse','optics','bsk','bss','em1d','gw0','HF_and_locXC','setup',
'ppa','cohsex','life','collisions','negf','el_ph_scatt','el_el_scatt','excitons',
'wavefunction','fixsyms','QPDBs', 'QPDB_merge','RealTime','RT_X','RToccDos',
'RToccBnd','RToccEner','RToccTime','RTlifeBnd','amplitude','bzgrids','Random_Grid',
'gkkp','el_ph_corr','WRbsWF','Select_energy', 'RTDBs','photolum','kpts_map',
'RTtime','RToccupations','RTfitbands']
def __init__(self,args='',folder='.',filename='yambo.in'):
"""
Initalize the class
"""
dict.__init__(self,args=args,folder=folder,filename=filename)
if args != '': # if args is not empty call yambo to generate the filename input file
workdir = os.getcwd()
os.chdir(folder)
os.system('rm -f %s'%filename)
args+= ' -F %s'%filename # add -F filename so yambo generates filename with the chosen args
yambo = Popen(args, stdout=PIPE, stderr=PIPE, stdin=PIPE, shell=True)
yambo.wait()
os.chdir(workdir)
self.read_file(os.path.join(folder,filename))
else: # otherwise directly read the filename input file
self.read_file(os.path.join(folder,filename))
[docs] def read_file(self,file):
"""
Open filename and run parseInputFile to parse the input into the dictionary
"""
try:
yambofile = open(file,'r')
except IOError:
print('Could not read the file %s'%filename)
print('ERROR: yambo did not create the input file or the file you are trying to read does not exist')
print('command: %s'%self['args'])
print('folder: %s/'%self['folder'])
exit()
self.parseInputFile(yambofile.read())
yambofile.close()
[docs] def write(self,folder,filename,reformat=True):
"""
Write the yambo input on file. If the args of the object is not empty and
the reformat variable is True run yambo to recover the original format of
the yambo input.
"""
f = open(os.path.join(folder,filename),'w')
f.write(self.convert_string())
f.close()
if self['args'] != '' and reformat:
action = 'cd %s; %s -F %s'%(folder,self['args'],filename)
os.system(action)
[docs] def parseInputFile(self,file):
"""
Read the arguments and variables from the input file
"""
arguments = []
variables = {}
var_real = re.findall(self._variaexp + self._spacexp + '='+ self._spacexp +
self._numexp + self._spacexp + '([A-Za-z]+)?',file)
var_string = re.findall(self._variaexp + self._spacexp + '='+ self._spacexp + self._stringexp, file)
var_array = re.findall(self._arrayexp,file)
var_complex = re.findall(self._variaexp + self._spacexp + '='+ self._spacexp +
self._complexexp + self._spacexp + '([A-Za-z]+)?', file)
var_runlevel = re.findall(self._runexp + self._spacexp, file)
def clean(a):
"""
clean the variables according to the type of data
"""
a = a.strip()
if a.replace('.','',1).isdigit():
if "." in a: return float(a)
else: return int(a)
return a
# Determination of the arguments
for key in self._runlevels:
if key in var_runlevel:
arguments.append(key)
#float variables
for var in var_real:
name, value, unit = var
variables[name] = [float(value),unit]
#string variables
for var in var_string:
name, string = var
variables[name] = string
#complex variables
for var in var_complex:
name, real, imag, unit = var
variables[name] = [complex(float(real),float(imag)),unit]
#array variables
for var in var_array:
name, array, unit = var
array = [clean(val) for val in array.split('|')[:-1]]
variables[name] = [array,unit]
self['arguments'] = arguments
self['variables'] = variables
[docs] def convert_string(self):
"""
Convert the input object into a string
"""
s = ""
s += "\n".join(self['arguments'])+'\n'
for key,value in self['variables'].items():
if type(value)==bytes or type(value)==str:
s+= "%s = %10s\n"%(key,"'%s'"%value)
continue
if type(value[0])==float:
val, unit = value
if val > 1e-6:
s+="%s = %lf %s\n"%(key,val,unit)
else:
s+="%s = %e %s\n"%(key,val,unit)
continue
if type(value[0])==int:
val, unit = value
s+="%s = %d %s\n"%(key,val,unit)
continue
if type(value[0])==list:
array, unit = value
if type(array[0])==list:
s+='%% %s\n'%key
for l in array:
s+="%s \n"%(" | ".join(map(str,l))+' | ')
s+='%s'%unit
s+='%\n'
else:
s+="%% %s\n %s %s \n%%\n"%(key," | ".join(map(str,array))+' | ',unit)
continue
if type(value[0])==str:
array = value
s+="%% %s\n %s \n%%\n"%(key," | ".join(map(lambda x: "'%s'"%x.replace("'","").replace("\"",""),array))+' | ')
continue
if type(value[0])==complex:
value, unit = value
s+="%s = (%lf,%lf) %s\n"%(key,value.real,value.imag,unit)
continue
raise ValueError( "Unknown type %s for variable: %s" %( type(value), key) )
return s
# Set methods useful for Yambo inputs
[docs] def set_array_variables(inp,units='',**kwargs):
"""
Add to the `variables` key of the input dictionary
the elements kwargs[key] = [kwargs[value],units] for all the
elements of the kwargs provided as input.
Args:
units (:py:class:`string`) : the units associated to (all the) variables
kwargs : variable(s) added in the form name = value. All the
variables must have the same units
"""
for name,value in kwargs.items():
inp['variables'][name] = [value,units]
[docs] def set_scalar_variables(inp,**kwargs):
"""
Add to the `variables` key of the input dictionary
the elements kwargs[key] = kwargs[value] for all the
elements of the kwargs provided as input.
Args:
kwargs : variable(s) added in the form name = value
"""
for name,value in kwargs.items():
inp['variables'][name] = value
[docs] def set_extendOut(self):
"""
Activate the ExtendOut option to print all the variable in the output file.
"""
self['arguments'].append('ExtendOut')
[docs] def set_kRange(self,first_k,last_k):
"""
Set the the kpoint interval in the variable QPkpoint.
"""
bands = self['variables']['QPkrange'][0][2:4]
kpoint_bands = [first_k,last_k] + bands
self['variables']['QPkrange'] = [kpoint_bands,'']
[docs] def set_bandRange(self,first_band,last_band):
"""
Set the the band interval in the variable QPkpoint.
"""
kpoint = self['variables']['QPkrange'][0][0:2]
kpoint_bands = kpoint + [first_band,last_band]
self['variables']['QPkrange'] = [kpoint_bands,'']
[docs] def activate_RIM_W(self):
"""
Activate the RIM_W option to perform to the random integration method
on the effective potential.
"""
if 'RIM_W' not in self['arguments'] :
self['arguments'].append('RIM_W')
[docs] def deactivate_RIM_W(self):
"""
Remove the RIM_W option from the runlevel list.
"""
if 'RIM_W' in self['arguments'] :
self['arguments'].remove('RIM_W')
# Set methods useful for yambo_rt inputs
[docs] def set_rt_field(self,index=1,int=1e3,int_units='kWLm2',fwhm=100.,fwhm_units='fs',
freq=1.5,freq_units='eV',kind='QSSIN',polarization='linear',
direction=[1.,0.,0.],direction_circ=[0.,1.,0.],tstart=0.,tstart_units='fs'):
"""
Set the parameters of the field.
The index parameter is an integer that defines the name of the Field$index.
Useful to set more than one field
"""
field_name = 'Field'+str(index)
self['variables'][field_name+'_Int'] = [int,int_units]
self['variables'][field_name+'_FWHM'] = [fwhm,fwhm_units]
self['variables'][field_name+'_Freq'] = [[freq,freq],freq_units]
self['variables'][field_name+'_kind'] = kind
self['variables'][field_name+'_pol'] = polarization
self['variables'][field_name+'_Dir'] = [direction,'']
self['variables'][field_name+'_Dir_circ'] = [direction_circ,'']
self['variables'][field_name+'_Tstart'] = [tstart,tstart_units]
[docs] def set_rt_bands(self,bands=None,scissor=0.,stretch_con=1.,stretch_val=1.,damping_valence=0.05,damping_conduction=0.05):
"""
Set the bands, the scissor and the damping parameters for the RT analysis
"""
if bands is not None:
self['variables']['RTBands'] = [bands,'']
self['variables']['GfnQP_E'] = [[scissor, stretch_con, stretch_val], '']
self['variables']['GfnQP_Wv'] = [[damping_valence, 0.0, 0.0], '']
self['variables']['GfnQP_Wc'] = [[damping_conduction, 0.0, 0.0], '']
[docs] def set_rt_simulationTimes(self,time_step=10,step_units='as',sim_time=1000.,time_units='fs',
io_time = [1.,5.,1.],io_cache_time = [1.,1.],io_units='fs'):
"""
Set the time parameters of the simulation
"""
self['variables']['RTstep'] = [time_step,step_units]
self['variables']['NETime'] = [sim_time,time_units]
self['variables']['IOtime'] = [io_time,io_units]
self['variables']['IOCachetime'] = [io_cache_time,io_units]
[docs] def set_rt_cpu(self,k=1,b=1,q=1,qp=1):
"""
Set the parallelization roles of the run
"""
self['variables']['RT_CPU'] = '%s.%s.%s.%s'%(k,b,qp,q)
self['variables']['RT_ROLEs'] = 'k.b.qp.q'
# Set methods useful for Ypp inputs
[docs] def removeTimeReversal(self):
"""
Remove the time reversal symmetry
"""
self['arguments'].append('RmTimeRev')
[docs] def set_ypp_extFields(self, Efield1 = [1.,0.,0.], Efield2 = None):
"""
Set the direction of the external electric field(s). The second field (useful for the
circular polarization) is added only is the value is not `None`.
"""
self['variables']['Efield1'] = [Efield1,'']
if Efield2 is not None :
self['variables']['Efield2'] = [Efield2,'']