def read(self, mos): state_list = [] for lfile in sorted(os.listdir('WORK')): # Find the suitable files. This could also be done with regexps ... if not '.iwfmt' in lfile: continue #if (not 'mcsd1fl' in lfile) and (not 'mcad1fl' in lfile): continue if not 'mcsd1fl' in lfile: continue if self.ioptions['s_or_t'] == 't': if not '-' in lfile: continue print "Reading %s ..." % lfile state_list.append({}) self.read_mc_tden(state_list[-1], mos, lfile) elif self.ioptions['s_or_t'] == 's': if '-' in lfile: continue print "Reading %s ..." % lfile state_list.append({}) self.read_mc_sden(state_list[-1], mos, lfile) if len(state_list) == 0: raise error_handler.MsgError( 'No density file found! Did you run write_den.bash?') return state_list
def read_dens(self): """ Read the (transition) density matrices and some supplementary information. """ rtype = self.ioptions.get('rtype') if self.ioptions['read_libwfa']: self.mos = None if rtype == 'ricc2': self.state_list = file_parser.file_parser_ricc2( self.ioptions).read(self.mos) elif rtype in ['tddft', 'escf', 'tmtddft']: self.state_list = file_parser.file_parser_escf(self.ioptions).read( self.mos) elif rtype == 'libwfa': self.state_list = file_parser.file_parser_libwfa( self.ioptions).read() elif rtype == 'qcadc': self.state_list = file_parser.file_parser_qcadc( self.ioptions).read() elif rtype == 'qctddft': self.state_list = file_parser.file_parser_qctddft( self.ioptions).read(self.mos) elif rtype in ['mcscf', 'colmcscf']: self.state_list = file_parser.file_parser_col_mcscf( self.ioptions).read(self.mos) elif rtype in ['mrci', 'colmrci']: self.state_list = file_parser.file_parser_col_mrci( self.ioptions).read(self.mos) elif rtype in ['rassi', 'molcas']: self.state_list = file_parser.file_parser_rassi( self.ioptions).read(self.mos) elif rtype.lower() == 'nos': self.state_list = file_parser.file_parser_nos(self.ioptions).read( self.mos) elif rtype.lower() in ['cclib', 'gamess', 'orca']: # these are parsed with the external cclib library ccli = cclib_interface.file_parser_cclib(self.ioptions) errcode = ccli.check() if errcode >= 2: raise error_handler.MsgError( "The file cannot be parsed by cclib") print self.mos = ccli.read_mos() self.read2_mos() self.state_list = ccli.read(self.mos) # Write a Molden file if possible if errcode == 0: self.mos.write_molden_file(fname='MOs.mld') self.ioptions['mo_file'] = 'MOs.mld' else: self.ioptions['molden_orbitals'] = False else: raise error_handler.ElseError(rtype, 'rtype') self.extra_info()
def ret_Om_OmAt(self, state): """ Construction of the Omega matrix with respect to atoms. formula=0: Om_mn = (DS)_mn (SD)_mn [JCTC (2012) 8, 2777] formula=1: Om_mn = 1/2 (DS)_mn (SD)_mn + 1/2 D_mn (SDS)_mn [JCP (2014), 141, 024106] formula=2: TODO - Loewdin partitioning """ if 'Om' in state and 'OmAt' in state: return state['Om'], state['OmAt'] formula = self.ioptions.get('Om_formula') try: D = state['tden'] except KeyError: return None, None print("Computation of Omega matrix ...") # construction of intermediate matrices # S implicitly computed from C temp = self.mos.CdotD(D, trnsp=False, inv=False) # C.DAO DS = self.mos.MdotC(temp, trnsp=False, inv=True) # DAO.S = C.D.C^(-1) if formula == 1: DAO = self.mos.MdotC(temp, trnsp=True, inv=False) # DAO = C.D.C^T temp = self.mos.CdotD(D, trnsp=True, inv=True) # C^(-1,T).DAO SD = self.mos.MdotC(temp, trnsp=True, inv=False) # S.DAO = C^(-1,T).DAO.C^T if formula == 1: # S.DAO.S = C^(-1,T).D.C^(-1) SDS = self.mos.MdotC(temp, trnsp=False, inv=True) # add up the contributions for the different atoms state['Om'] = 0. state['OmAt'] = numpy.zeros([self.mos.num_at, self.mos.num_at]) if formula == 0: OmBas = DS * SD elif formula == 1: OmBas = 0.5 * (DS * SD + DAO * SDS) else: raise error_handler.MsgError( "Om_formula=%i for CT numbers not implemented!" % formula) for i in range(self.num_bas): iat = self.mos.basis_fcts[i].at_ind - 1 for j in range(self.num_bas): jat = self.mos.basis_fcts[j].at_ind - 1 state['Om'] += OmBas[i, j] state['OmAt'][iat, jat] += OmBas[i, j] return state['Om'], state['OmAt']
def ret_MAeh(self, Om, OmAt): """ Return the mean absolute electron-hole distance (Ang). """ if self.distmat == None: raise error_handler.MsgError("Compute the distance matrix first!") MA_dist = numpy.dot(OmAt.flatten(), self.distmat.flatten()) / Om return MA_dist
def get(self, option, strict=True): """ Return the value of an option. """ self.chk_option(option) if strict and self.opt_dict[option] == None: raise error_handler.MsgError('Option "%s" not defined in file %s!'%(option, self.ifile)) else: return self.opt_dict[option]
def read_ifile(self): """ Read the input file self.ifile. Key and value are separated by '='. Leading and trailing whitespace is removed. """ try: fileh = open(self.ifile, 'r') except: return 1 for line in fileh: # take out possible comments if '#' in line: continue words = line.strip().split('=') if len(line.strip()) == 0: continue if len(words) != 2: print(" ERROR: in file %s\n line cannot be parsed:" % self.ifile) print(len(line)) print(line) exit(6) key = words[0].strip() if words[1] == '': raise error_handler.MsgError( 'Please specify a value for "%s=" in %s!' % (key, self.ifile)) val = eval(words[1]) # every possible option has to be initiliazed in set_defaults to avoid confusion if not key in self.opt_dict: raise error_handler.MsgError('Unknown option in %s: %s' % (self.ifile, key)) self.opt_dict[key] = val return 0
def __init__(self, occmin=0.01, occmax=2.0, mldfile=""): if mldfile == "": raise error_handler.MsgError("mldfile has to be specified for occupation screening!") self.mldfile = mldfile self.moset = lib_mo.MO_set_molden(mldfile) self.moset.read(lvprt=0) self.molist = [] for imo, occ in enumerate(self.moset.occs): if occmin <= occ <= occmax: self.molist.append(imo)
def ret_RMSeh(self, Om, OmAt): """ Return the root mean square electron-hole distance (Ang). """ if self.distmat == None: raise error_handler.MsgError("Compute the distance matrix first!") MS_dist = numpy.dot(OmAt.flatten(), self.distmat.flatten()**2.) / Om RMS_dist = numpy.sqrt(MS_dist) return RMS_dist
def read(self, mos): state_list = [] (energies, oscs) = self.read_rassi_output(self.ioptions['rfile']) if not os.path.exists('TRD'): errmsg = """Did not find the TRD directory! To run the job you have to: 1. Run RASSI specifying the TRD1 keyword 2. call 'mkdir TRD && cp $WorkDir/TRD2* TRD'""" raise error_handler.MsgError(errmsg) for lfile in self.ioptions['ana_files']: words = lfile.split('_') (st1, st2) = (int(words[1]), int(words[2])) if self.ioptions['s_or_t'] == 't': if st1 == st2: continue print "Reading %s ..." % lfile state_list.append({}) state_list[-1]['name'] = 'R%i.%i' % (st1, st2) state_list[-1]['exc_en'] = ( energies[st1 - 1] - energies[st2 - 1]) * units.energy['eV'] try: state_list[-1]['osc_str'] = oscs[(st2, st1)] except: print "No osc. strength found for transition %i -> %i" % ( st2, st1) state_list[-1]['tden'] = self.init_den(mos) self.read_rassi_den(state_list[-1]['tden'], mos, lfile) elif self.ioptions['s_or_t'] == 's': if st1 != st2: continue print "Reading %s ..." % lfile state_list.append({}) state_list[-1]['name'] = 'RASSI_%i' % st1 state_list[-1]['exc_en'] = (energies[st1 - 1] - energies[0]) * units.energy['eV'] state_list[-1]['sden'] = self.init_den(mos) self.read_rassi_den(state_list[-1]['sden'], mos, lfile, sden=True) return state_list
def sym_split(self, sym): """ Split an MO "sym" label into the index and irrep. "51b1u" -> [51, "b1u"] """ st = 1000 if sym.find('a') != -1: st = min(st, sym.find('a')) if sym.find('b') != -1: st = min(st, sym.find('b')) if sym.find('e') != -1: st = min(st, sym.find('e')) if sym.find('t') != -1: st = min(st, sym.find('t')) if (st == 1000): raise error_handler.MsgError("sym_split: %s" % sym) return (int(sym[:st]), sym[st:])
def ret_Eb(self, Om, OmAt, Eb_diag=1.0): """ Return an approximate exciton binding energy (eV). """ if self.distmat == None: raise error_handler.MsgError("Compute the distance matrix first!") Eb_dist = self.distmat.flatten() / units.length['A'] for i in xrange(len(self.distmat)): Eb_dist[i + i * len(self.distmat)] = Eb_diag Eb_au = numpy.dot(OmAt.flatten(), Eb_dist**-1.) / Om return Eb_au * units.energy['eV']
def read(self, mos): if self.ioptions['s_or_t'] == 's': raise error_handler.MsgError( 'analyze_sden.py not implemented for col_mrci! Use "nos" instead.' ) state_list = [] for lfile in sorted(os.listdir('LISTINGS')): if not 'trncils' in lfile: continue print "Reading %s ..." % lfile state_list.append({}) self.read_trncils(state_list[-1], mos, 'LISTINGS/%s' % lfile) return state_list
def ret_general_pop(self, state, ana_type='mullpop', dens_type=''): """ Return the result of a general population analysis. """ if dens_type == '' or dens_type == 'state': dens_name = 'sden' mp_name = ana_type else: dens_name = '%s_den'%dens_type mp_name = '%s_%s'%(ana_type, dens_type) if mp_name in state: return state[mp_name] if not dens_name in state: return None if ana_type == 'mullpop': pana = pop_ana.mullpop_ana() else: raise error_handler.MsgError('Population analyis type not implmented: %s'%ana_type) state[mp_name] = pana.ret_pop(state[dens_name], self.mos) return state[mp_name]
def read(self, lvprt=1): """ Read in MO coefficients from a molden File. """ MO = False GTO = False mo_vecs = [] mo_ind = 0 self.syms = [ ] # list with the orbital descriptions. they are entered after Sym in the molden file. self.occs = [] # occupations self.ens = [ ] # orbital energies (or whatever is written in that field) num_bas = {'s': 1, 'p': 3, 'sp': 4, 'd': 6, 'f': 10, 'g': 15} orient = { 's': ['1'], 'p': ['x', 'y', 'z'], 'sp': ['1', 'x', 'y', 'z'], 'd': ['x2', 'y2', 'z2', 'xy', 'xz', 'yz'], 'f': [ 'xxx', 'yyy', 'zzz', 'xyy', 'xxy', 'xxz', 'xzz', 'yzz', 'yyz', 'xyz' ], 'g': 15 * ['?'] } num_orb = 0 curr_at = -1 self.header = '' fileh = open(self.file, 'r') fstr = fileh.read() if ('[D5' in fstr) or ('[5D' in fstr): num_bas['d'] = 5 orient['d'] = ['D0', 'D+1', 'D-1', 'D+2', 'D-2'] if ('F7]' in fstr) or ('7F]' in fstr): num_bas['f'] = 7 orient['f'] = ['F0', 'F+1', 'F-1', 'F+2', 'F-2', 'F+3', 'F-3'] if ('9G]' in fstr) or ('9G]' in fstr): num_bas['g'] = 9 orient['g'] = 9 * ['?'] fileh.seek(0) # rewind the file for line in fileh: words = line.replace('=', ' ').split() if 'molden format' in line.lower(): if not '[Molden Format]' in line: print " WARNING: the header may not be understood by Jmol:" print line, print " This has to be changed to:" print " [Molden Format]" # what section are we in if '[' in line: MO = False GTO = False if '[MO]' in line: if lvprt >= 2: print "Found [MO] tag" MO = True GTO = False # extract the information in that section elif MO: if not '=' in line: try: mo_vecs[-1].append(float(words[1])) except: if words == []: break # stop parsing the file if an empty line is found print " ERROR in lib_mo, parsing the following line:" print line raise elif 'ene' in line.lower(): mo_ind += 1 mo_vecs.append([]) self.ens.append(float(words[-1])) elif 'sym' in line.lower(): self.syms.append(words[-1]) elif 'occ' in line.lower(): self.occs.append(float(words[-1])) elif ('[GTO]' in line): GTO = True # extract the information in that section elif GTO: if len(words) == 0: # empty line: atom is finished curr_at = -1 elif curr_at == -1: curr_at = int(words[0]) self.num_at = max(curr_at, self.num_at) elif (len(words) >= 2) and (words[0].lower() in num_bas): orbsymb = words[0].lower() for i in xrange(num_bas[orbsymb]): self.basis_fcts.append( basis_fct(curr_at, orbsymb, orient[orbsymb][i])) num_orb += 1 if not MO: self.header += line fileh.close() ### file parsing finished ### if lvprt >= 1 or len(mo_vecs[0]) != num_orb: print '\nMO file %s parsed.' % self.file print 'Number of atoms: %i' % self.num_at print 'Number of MOs read in: %i' % len(mo_vecs) print 'Dimension: %i,%i,...,%i' % (len(mo_vecs[0]), len( mo_vecs[1]), len(mo_vecs[-1])) print 'Number of basis functions parsed: ', num_orb if len(mo_vecs[0]) != num_orb: raise error_handler.MsgError( 'Inconsistent number of basis functions!') try: self.mo_mat = numpy.array(mo_vecs).transpose() except ValueError: print "\n *** Unable to construct MO matrix! ***" print "Is there a mismatch between spherical/cartesian functions?\n ---" raise
def chk_option(self, option): if not option in self.opt_dict: raise error_handler.MsgError("Option %s not known!"%option)
""" Check if a file can be read by cclib and if all the required information is available. """ import theo_header, cclib_interface, input_options, error_handler import sys theo_header.print_header('Check cclib') print("cc_check.py <logfile>") print("Check if a logfile can be parsed with cclib") try: logfile = sys.argv[1] except IndexError: raise error_handler.MsgError("Please enter the name of the logfile!") ioptions = input_options.dens_ana_options(ifile=None, check_init=False) ioptions['rtype'] = 'cclib' ioptions['rfile'] = logfile ccparser = cclib_interface.file_parser_cclib(ioptions) errcode = ccparser.check() if errcode <= 1: print("\n %s can be parsed by using rtype='cclib' in dens_ana.in." % logfile) if errcode == 0: print(" Conversion to Molden format also possible") else: print(" But conversion to Molden format is not possible")
def read(self, mos): """ Read the X vector from standard output. Y is discarded. """ state_list = [] exc_diff = False exc_1TDM = False tdread = False libwfa = False istate = 1 if self.ioptions.get('TDA'): ststr = 'TDDFT/TDA Excitation Energies' else: ststr = 'TDDFT Excitation Energies' print "Parsing %s for %s ..." % (self.ioptions.get('rfile'), ststr) # for line in open(self.ioptions.get('rfile'), 'r'): rfileh = open(self.ioptions.get('rfile'), 'r') while True: # loop over all lines try: line = rfileh.next() except StopIteration: print "Finished parsing file %s" % self.ioptions.get('rfile') break if ststr in line: tdread = True elif 'TDDFT calculation will be performed' in line: tdread = False elif 'Timing summary' in line: tdread = False elif 'Excited State Analysis' in line: libwfa = True if len(state_list) == 0: errstr = "No excitation energy parsed!" errstr += "\n Please, set 'TDA=True' if this was a TDA calculation." raise (error_handler.MsgError(errstr)) elif 'SA-NTO Decomposition' in line: libwfa = False if tdread: words = line.replace(':', '').split() if 'Excited state' in line: state_list.append({}) state_list[-1]['state_num'] = int(words[2]) state_list[-1]['exc_en'] = float(words[-1]) line = rfileh.next() line = rfileh.next() words = line.split() if words[0] == 'Multiplicity:': state_list[-1]['mult'] = '(%s)' % words[1][0] else: state_list[-1]['mult'] = '(-)' state_list[-1]['name'] = 'es_%i%s' % ( state_list[-1]['state_num'], state_list[-1]['mult']) if self.ioptions['read_libwfa']: om_filen = 'es_%i_ctnum_atomic.om' % state_list[-1][ 'state_num'] (typ, exctmp, osc, num_at, num_at1, om_at) = self.rmatfile(om_filen) if not typ == None: state_list[-1]['Om'] = om_at.sum() state_list[-1]['OmAt'] = om_at else: state_list[-1]['tden'] = self.init_den(mos, rect=True) elif 'Strength' in line: state_list[-1]['osc_str'] = float(words[-1]) elif 'amplitude' in line and not self.ioptions['read_libwfa']: # ignore the Y vector. # Otherwise the Y would go into the virt-occ block! if 'Y:' in line: continue awords = self.delete_chars( line, ['X:', 'Y:', 'D', 'V', '(', ')', '-->']).split() iocc = int(awords[0]) - 1 ivirt = int(awords[1]) + mos.ret_ihomo() coeff = float(awords[4]) state_list[-1]['tden'][iocc, ivirt] += coeff if libwfa: if 'Excited state' in line: istate = int(line.split()[-1].replace(':', '')) elif 'Exciton analysis of the difference density matrix' in line: exc_1TDM = False exc_diff = True elif 'Exciton analysis of the transition density matrix' in line: exc_diff = False exc_1TDM = True self.parse_keys(state_list[istate - 1], exc_diff, exc_1TDM, line) rfileh.close() return state_list
def read(self): state_list = [] basedir = '.' exc_diff = False exc_1TDM = False self.irrep_labels = None for line in open(self.ioptions.get('rfile')): words = line.split() if 'Irreducible representations in point group:' in line: self.irrep_labels = line.lstrip( 'Irreducible representations in point group:').split() elif ' Term symbol' in line: if self.irrep_labels == None: print "\n WARNING: irrep labels not found in %s" % self.ioptions.get( 'rfile') print " Use 'adc_print 2' or enter them into %s" % self.ioptions.ifile print " Using info from %s: irrep_labels=" % self.ioptions.ifile, self.ioptions.get( 'irrep_labels') print self.irrep_labels = self.ioptions.get('irrep_labels') state_list.append({}) state_list[-1]['state_ind'] = int(words[2]) state_list[-1]['mult'] = words[3] state_list[-1]['irrep'] = words[4] state_list[-1]['name'] = '%s%s%s' % (words[2], words[3], words[4]) om_filen = self.om_file_name(state_list[-1]) (typ, exctmp, osc, num_at, num_at1, om_at) = self.rmatfile(os.path.join(basedir, om_filen)) if typ == None: continue state_list[-1]['exc_en'] = exctmp * units.energy['eV'] state_list[-1]['osc_str'] = osc state_list[-1]['Om'] = om_at.sum() state_list[-1]['OmAt'] = om_at elif ' Excitation energy:' in line: exc_chk = float(words[2]) if not 'exc_en' in state_list[-1]: state_list[-1]['exc_en'] = exc_chk if abs(exc_chk - state_list[-1]['exc_en']) > 1.e-4: print exc_chk, state_list[-1]['exc_en'] raise error_handler.MsgError( "Excitation energies do not match") elif 'Exciton analysis of the difference density matrix' in line: exc_1TDM = False if len(state_list) > 0: exc_diff = True elif 'Exciton analysis of the transition density matrix' in line: exc_diff = False if len(state_list) > 0: exc_1TDM = True elif 'Transition Summary' in line: break if len(state_list) > 0: self.parse_keys(state_list[-1], exc_diff, exc_1TDM, line) return state_list
def read_rassi_den(self, dens, mos, filen, sden=False): """ Read the output of RASSI generated with TRD1. No support for symmetry (yet). """ trd1 = False imo = -1 jmo = -1 rfile = open(filen, 'r') TRD_string = 'Active TRD1' while True: try: line = rfile.next() except StopIteration: break if 'Multiplicities' in line: words = rfile.next().split() mult1 = int(words[0]) mult2 = int(words[1]) print 'Multiplicities: %i, %i' % (mult1, mult2) # Read the spin-traced TDM if the multiplicities are the same # and the spin-difference TDM otherwise if mult1 == mult2: TRD_string = 'Active TRD1' else: TRD_string = 'Active Spin TRD1' elif 'Basis functions' in line: nbas = int(rfile.next().split()[0]) assert (nbas == mos.ret_num_mo()) elif 'Inactive orbitals' in line: ninact = int(rfile.next().split()[0]) if sden: for imo in xrange(ninact): dens[imo, imo] = 2.0 imo = ninact jmo = ninact elif 'Active orbitals' in line: nact = int(rfile.next().split()[0]) elif TRD_string in line: line = rfile.next() trd1 = True elif trd1: #print imo, line[:-1] for i in xrange(5): val = float(line[i * 18:(i + 1) * 18].replace('D', 'E')) dens[jmo, imo] = val if 0.2 < abs(val) < 1.9999: print "(i,j)=(%2i,%2i), val=%6.3f" % (imo, jmo, val) jmo += 1 if jmo == ninact + nact: jmo = ninact imo += 1 if imo == ninact + nact: #print "Finished parsing" trd1 = False break rfile.close() if trd1: raise error_handler.MsgError('Parsing of RASSI output') if not sden: dens *= 2**(-.5)