def output_mpqc(self, specname=None, indent=0, basisname=None): """Outputs the basis definition in mpqc input format. The argument indent can be an integer (how many whitespaces added for indentation or a string.""" from pyqmc.physics.atoms import get as get_atom_rec full_species_name = get_atom_rec(self.species).name() specname = specname or full_species_name basisname = basisname or self.basisname if isinstance(indent, int) and indent >= 0: indent = " " * indent FMT = "%s %s" % (self.fmt_exp, self.fmt_coeff) return \ "\n".join([ '%s%s: "%s": [' % (indent, specname, basisname), ] + list_join(*[[ '%s (type: [(am=%s%s)]\n' % (indent, typ.lower(), ifelse(self.ispher and self.nfuncs_spher_map[typ] >= 5, " puream=1", "")) + \ '%s {exp coef:0} = {' % (indent,) + \ ("\n%s " % indent).join([""] + [ FMT % (Exp, Coeff) for (Exp,Coeff) in desc ]) + \ '\n%s })' % (indent,) ] for (typ, desc) in self.funcs ]) + \ [ '%s]' % (indent,), ] )
def read0(self, infile, nbasis, debug=None): """Reads in the matrix elements from a Fortran binary file. This is a reference implementation, very slow. """ assert nbasis > 0 dbg = text_output(ifelse(debug, sys.stdout, None), flush=True) H2 = numpy.zeros((nbasis, nbasis, nbasis, nbasis), dtype=float) self.H2 = H2 F = fortran_bin_file(infile) S = os.stat(infile) fsize = S.st_size rec_desc = (('i', numpy.int32, 4), ('v', numpy.float64)) rec_bytesize = F.byte_length(*rec_desc) + F.default_int(0).itemsize * 2 rec_count = fsize // rec_bytesize dbg("File %s: %d integral records to be read\n" % (infile, rec_count)) for cc in xrange(rec_count): rec = F.read(*rec_desc) rec['i'] -= 1 # convert to py index (i, l, j, k) = rec['i'] v = rec['v'] # Use: V2b_inspect.permute_V2b('i','j','l','k',chem=1) # to generate this: H2[i, l, j, k] = v H2[j, k, i, l] = v H2[l, i, k, j] = v H2[k, j, l, i] = v H2[i, l, k, j] = v H2[k, j, i, l] = v H2[j, k, l, i] = v H2[l, i, j, k] = v F.close()
def parse_measurement0(self, info_file, rslt): """Internal routine to parse only the measurement results of the file. info_file is an open file-like object. The last line read must have been 'Measurement phase...' TODO: - add stand-alone parse_measurement routine? """ from pyqmc import PyqmcParseError L1 = info_file.next().strip() L2 = info_file.next().strip() if not L1.startswith("psi*psi_T") or not L2.startswith("-----"): raise PyqmcParseError, \ "Error detecting the beginning of measurement phase output stream." for_D2E = lambda s: s.replace("D", "E").replace("d", "e") EOS = re.compile(r"^\s*\*+\s*$") # end-of-stream marker RS = re.compile(r"^\s*-+\s*$") # record separator meas = [] for L in info_file: Ls = for_D2E(L.strip()) flds = Ls.split() if EOS.search(Ls): break # end-of-stream detected elif len(flds) == 3: # special case to handle wrapped Fortran output Ls2 = for_D2E(info_file.next().strip()) flds2 = Ls2.split() if len(flds2) == 0: raise PyqmcParseError, \ "Invalid format in PWQMC measurement text (INFO)" flds.append(flds2[0]) elif len(flds) < 4: raise PyqmcParseError, \ "Invalid format in PWQMC measurement text (INFO)" try: rec = tuple(map(lambda x: float(x.rstrip(",")), flds[:4])) except: raise PyqmcParseError, \ "Error parsing PWQMC measurement text (INFO)" meas.append(rec) Ls = info_file.next().strip() if not RS.search(Ls): raise PyqmcParseError, \ "Invalid record separator in PWQMC measurement text (INFO)" dtype = ifelse(rslt["has_pseudo"], self.meas_dtype, self.meas_jell_dtype) rslt["meas_energy"] = numpy.array(meas, dtype=dtype)
def str(self): rslt = [" $VEC\n"] for spin in ifelse(self.udet, ('alpha', 'beta'), ('alpha', )): vecs = getattr(self, spin) for (i, v) in enumerate(vecs.T): for j1 in xrange(0, self.nbasis, 5): j2 = min(j1 + 5, self.nbasis) rslt.append(("%2d%3d" % ((i + 1) % 100, j1//5 + 1)) \ + "".join([ "%15.8E" % v[j] for j in xrange(j1,j2)]) \ + "\n") rslt.append(" $END\n") return "".join(rslt)
def check_qmc(fname=None, archive=False, xflags=(), eqlb=(1, ), reblk=(2, 20, 2), eqlb_flags=(), reblk_flags=(), quiet_stdout=0, force_raw=0): """Checks the QMC results (INFO file) using my stand-alone QMC inspect tools. x is the extra flags to be passed on to check_* tools.""" if fname == None: if os.path.isfile("INFO"): fname = ("INFO", ) else: fname = tuple(sh.sorted_glob("part[0-9]*/INFO")) elif not hasattr(fname, "__iter__"): fname = (fname, ) else: fname = tuple(fname) fname_format = {} for f in fname: if not is_qmc_output(f): if not force_raw: raise ValueError, "Not a QMC output file: " + f else: print >> sys.stderr, "Warning: assuming raw output: " + f fname_format[f] = "raw" else: fname_format[f] = "qmc" if archive: fnarch = ifelse(isinstance(archive, basestring), archive, "analysis.txt") farch = open(fnarch, "a") if quiet_stdout: def prn(x): farch.write(str(x) + "\n") else: def prn(x): sys.stdout.write(str(x) + "\n") farch.write(str(x) + "\n") else: def prn(x): sys.stdout.write(str(x) + "\n") prn("") prn("Date: " + time.strftime("%Y%m%d")) prn("Checking QMC result: " + "\n + ".join( ifelse(len(fname) > 0, [""],[]) + \ [ os.path.abspath(f) for f in fname ] )) for f in fname: if fname_format[f] == "qmc" and not is_qmc_output_finished(f): prn("Warning: calculation unfinished yet: %s" % f) prn("") # Use the formal tool names here: #sh.run("check_eqlb", (fname, "1")) if eqlb: prn("EQUILIBRATION/QMC RAW ENERGIES:") eqlb_info = tuple(map(str, eqlb)) x = tuple(xflags) + tuple(eqlb_flags) if True or len(x) > 0: prn("Flags: " + " ".join(eqlb_info + x)) prn( sh.pipe_out(("check_eqlb", ) + fname + eqlb_info + x).replace( '\x0c', '')) if reblk: prn("REBLOCKING:") reblk_info = tuple(map(str, reblk)) x = tuple(xflags) + tuple(reblk_flags) if True or len(x) > 0: prn("Flags: " + " ".join(reblk_info + x)) prn( sh.pipe_out(("check_reblocking", ) + fname + reblk_info + ("plt", "txt") + x).replace('\x0c', '')) if archive: farch.close()
def read(self, infile, vec_select=1, verbose=0, nbasis=None, out=sys.stdout): """Reads off molecular orbital vectors. Usage: movecs = pyqmc.gamess.datfile.movecs(fname, [options]) Valid options: vec_select = <integer> (default: 1; 1-based choice) verbose = 0|1 (default: 0) nbasis = <integer> (default: autodetected) This routine was translated from Gamess::ReadGamessMOVecs routine in my Gamess.pm perl module. The latter routine was derived from C2_UHF_gamess.pl dated ~20070813. CAUTION: The resulting orbital (orbitals_alpha, orbitals_beta) arrays are 1-based, both in the orbital index and the basis index. Strict vector ordering (1, 2, 3, ..., N) is required in the $VEC data. We will check orbital indices strictly. This requires the orbitals be strictly ordered, with no skipping, etc. Strict checking is necessary for proper reading when we have more than 99 basis functions. In anticipating for large basis size, the rule for deducing UHF-type movecs is more complicated. For nbasis >= 100, the tag number rolls back to zero, unfortunately, which makes thing a bit difficult: when we see a tag of " 1" again, is it UHF beta sector, or movec #101? One way we can be assured that it IS an UHF movecs is prohibiting the size of movecs to be greater than the deduced nbasis, which is a reasonable restriction. Then, when we apparently encounter movec "101" when nbasis==100, we can be sure that the 101st vector is actually beta movec #1. Thus UHF movecs can be detected by the following rule: - ( old $VecTag != 0, or old $VecIndex == $nbasis already ) AND new $VecTag == 1 . FIXME: The solution above is still not foolproof in two cases: 1) suppose we have an UHF-type movecs with nbasis=220, but each spin sector only has 100 orbitals listed. Then this will be interpreted as an RHF-type movecs with nbasis=220 and norbitals=200. 2) in spherical basis, maximum norbitals is <= nbasis. When this happens, then the deduced nbasis is not the right number of spherical basis functions (thus the nbasis deduced above is not right). But I haven't seen this case yet, so forget about them temporarily. """ from wpylib.regexps import regex # MOVECS comments (always 3 lines preceding the $VEC block) rx_comment = regex(r'^--- ') rx_vec = regex(r'^(?i) \$vec') rx_endvec = regex(r'^(?i) ?\$end') F = text_input(infile) comments = None found = False vec_blk_count = 0 n_comment_lines = 0 O = text_output(out, flush=True) spin = "alpha" udet = False AllVecs = {} for txt in F: if rx_comment % txt: comments = [] n_comment_lines = 3 if n_comment_lines > 0: comments.append(txt) n_comment_lines -= 1 if rx_vec % txt: vec_blk_count += 1 if vec_blk_count < vec_select: # the comments we just read (if any) are irrelevant, so # remove them. comments = None continue found = True # This is the actual movecs reading loop --- # The $END marker for initial orbital guess (PUNMO=.TRUE.) is # buggy--we must tolerate that txt = F.next() # VecIndex = MO index to identify the whole vector # VecTag = MO "tag" number # In general VecTag is equal to VecIndex except when we have >= 100 # basis funcs (where VecTag has only the last two digits). # NOTE: VecTag is *always* a 2-character string! VecIndex = 1 VecTag = " 1" AmplIndex = 0 Ampl = [] Vecs = [Ampl] while not (rx_endvec % txt): NewVecTag = txt[0:2] #print "H: $txt\n"; #print "V: $NewVecTag\n"; # We should safely assume that VecTag > 1 at the end # of alpha orbitals; if that's not the case, that's # YOUR fault (why doing 1-basis quantum chemistry?) if NewVecTag != VecTag: # Just in case, we are very pedantic in checking for errors here: if nbasis != None: # (1) nbasis must be consistent if AmplIndex != nbasis: raise PyqmcDataError, \ ("%s:%d: Inconsistent nbasis " + \ "(original guess was = %d, most recently deduced value = %d) " + \ "for %s vector #%d") \ % (infile, F.lineno, nbasis, AmplIndex, spin, VecIndex) else: # Deduce nbasis nbasis = AmplIndex if nbasis == 0: raise PyqmcDataError, \ ("%s:%d: nbasis detected as zero! " + \ "Maybe there is corruption in the input file?") \ % (infile, F.lineno) if verbose > 0: O("pyqmc.gamess.movecs.read:%s: Deduced nbasis = %d\n" \ % (infile, nbasis)) # UHF-type vector detection scheme: see the notes above if (VecTag != " 0" or VecIndex == nbasis) and NewVecTag == " 1": if verbose > 0: O("pyqmc.gamess.movecs.read:%s: Found UHF-type movecs\n" \ % (infile,)) if udet: raise PyqmcDataError, \ ("%s:%d: alpha and beta orbitals were already defined?! " + \ "Maybe there is a mistake with your $VEC data?") \ % (infile, F.lineno) AllVecs[spin] = numpy.array(Vecs, dtype=float).T # start all over with a new MO block Ampl = [] Vecs = [Ampl] spin = "beta" udet = True VecIndex = 0 # end UHF-type detection scheme else: # Some additional error checking(s) if VecIndex >= nbasis: # and nbasis != 100: # NOTE: We disallow norbitals > nbasis in our reader. raise PyqmcDataError, \ ("%s:%d: The $VEC block has more than %d orbitals, " + \ "which is prohibited by this routine") \ % (infile, F.lineno, nbasis) Ampl = [] Vecs.append(Ampl) AmplIndex = 0 # Start off a new vector VecIndex += 1 VecTag = NewVecTag # end new vector/new spin sector detection # Strict index vs. tag checking: TagChk = "%2d" % (VecIndex % 100) if TagChk != VecTag: raise PyqmcDataError, \ ("%s:%d: Mismatch vector tag number in vector #%d " + \ "(wanted '%s', got '%s')") \ % (infile, F.lineno, VecIndex, TagChk, VecTag) # the amplitudes are always stored in -n.nnnnnnnnE+nn fixed format # (15 characters wide) txtdata = txt[5:].rstrip() lendata = len(txtdata) // 15 Ampl += [ float(txtdata[i * 15:i * 15 + 15]) for i in xrange(0, lendata) ] AmplIndex += lendata # TODO: $i < 5 is allowed ONLY on the last line; # Make sure we catch that. #print $VecIndex, " ", $AmplIndex, "\n"; try: txt = F.next() except StopIteration: raise PyqmcDataError, \ ("%s:%d: Unexpected EOF while reading in $VEC data") \ % (infile, F.lineno) # end loop for reading in $VEC data # Finalization: do final checks, etc. AllVecs[spin] = numpy.array(Vecs, dtype=float).T if AmplIndex != nbasis: raise PyqmcDataError, \ ("%s:%d: Inconsistent nbasis " + \ "(original guess was = %d, most recently deduced value = %d) " + \ "for %s vector #%d") \ % (infile, F.lineno, nbasis, AmplIndex, spin, VecIndex) if udet: if AllVecs['alpha'].shape != AllVecs['beta'].shape: raise PyqmcDataError, \ ("%s:%d: Inconsistent shape of MO matrix: " + \ "(alpha = %s, beta = %s)") \ % (infile, F.lineno, \ AllVecs['alpha'].shape, \ AllVecs['beta'].shape, \ ) if verbose > 0: O("pyqmc.gamess.movecs.read:%s: Total MO vectors read = %s%s\n" \ % (infile, VecIndex, ifelse(udet, " (UHF-type)", ""))) # stop reading if the desired vectors have been loaded break # end main text reading loop if not found: raise PyqmcDataError, \ ("%s: Cannot find $VEC block number %s") \ % (infile, vec_select) # Save the reading results to the "self" record: self.filename = infile self.vec_select = vec_select self.comments = comments self.udet = udet self.nbasis = nbasis for (spin, mo) in AllVecs.iteritems(): setattr(self, spin, mo) return self
def get_header_structs(self, kind): """Obtains various ABINIT header structures; one at a time. Caveat: Sizes in some header structures depend on the preceding structure.""" Int = self.int_ Dbl = self.double hdr = self.header """From ABINIT manuals: 4.2: read(fdWFK) bantot,date,intxc,ixc,natom,ngfft(1:3), & & nkpt,nspden,nspinor,nsppol,nsym,npsp,ntypat,occopt,pertcase, & & ecut,ecutsm,ecut_eff,qptn(1:3),rprimd(1:3,1:3),stmbias,tphysel,tsmear 4.4, 5.3, 5.6: read(fdWFK) bantot,date,intxc,ixc,natom,ngfft(1:3), & & nkpt,nspden,nspinor,nsppol,nsym,npsp,ntypat,occopt,pertcase, & & usepaw, & & ecut,ecutdg,ecutsm,ecut_eff,qptn(1:3), & & rprimd(1:3,1:3),stmbias,tphysel,tsmear 5.7: read(fdWFK) bantot,date,intxc,ixc,natom,ngfft(1:3), & & nkpt,nspden,nspinor,nsppol,nsym,npsp,ntypat,occopt,pertcase, & & usepaw, & & ecut,ecutdg,ecutsm,ecut_eff,qptn(1:3), & & rprimd(1:3,1:3),stmbias,tphysel,tsmear,usewvl """ if kind == 1: return [ ('bantot', Int), ('date', Int), ('intxc', Int), ('ixc', Int), ('natom', Int), ('ngfft', Int, 3), ('nkpt', Int), ('nspden', Int), ('nspinor', Int), ('nsppol', Int), ('nsym', Int), ('npsp', Int), ('ntypat', Int), ('occopt', Int), ('pertcase', Int), ] \ + ifelse(self.headform >= 44, [('usepaw', Int)], []) \ + [ ('ecut', Dbl), ] \ + ifelse(self.headform >= 44, [('ecutdg', Dbl)], []) \ + [ ('ecutsm', Dbl), ('ecut_eff', Dbl), ('qptn', Dbl, 3), ('rprimd', Dbl, (3,3)), ('stmbias', Dbl), ('tphysel', Dbl), ('tsmear', Dbl), ] \ + ifelse(self.headform >= 57, [('usewvl', Int)], []) \ + [ ] """ <= 4.4: read(fdWFK) istwfk(1:nkpt), nband(1:nkpt*nsppol), & & npwarr(1:nkpt), so_typat(1:ntypat), & & symafm(1:nsym), & & symrel(1:3,1:3,1:nsym), & & typat(1:natom), kpt(1:3,1:nkpt), & & occ(1:bantot), tnons(1:3,1:nsym), & & znucltypat(1:ntypat) >= 5.3: read(fdWFK) istwfk(1:nkpt), nband(1:nkpt*nsppol), & & npwarr(1:nkpt), so_psp(1:npsp), & & symafm(1:nsym), & & symrel(1:3,1:3,1:nsym), & & typat(1:natom), kpt(1:3,1:nkpt), & & occ(1:bantot), tnons(1:3,1:nsym), & & znucltypat(1:ntypat), & & wtk(1:nkpt) """ if kind == 2: return [ ('istwfk', Int, hdr.nkpt), ('nband', Int, (hdr.nkpt,hdr.nsppol)), ('npwarr', Int, (hdr.nkpt)), ] \ + ifelse(self.headform <= 44, [('so_typat', Int, (hdr.ntypat))], []) \ + ifelse(self.headform >= 53, [('so_psp', Int, (hdr.npsp))], []) \ + [ ('symafm', Int, (hdr.nsym)), ('symrel', Int, (3,3,hdr.nsym)), ('typat', Int, (hdr.natom)), ('kpt', Dbl, (3,hdr.nkpt)), ('occ', Dbl, (hdr.bantot)), ('tnons', Dbl, (3,hdr.nsym)), ('znucltypat', Dbl, (hdr.ntypat)), ] \ + ifelse(self.headform >= 53, [('wtk', Dbl, (hdr.nkpt))], []) \ + [ ] """ do ipsp=1,npsp ! (npsp lines, 1 for each pseudopotential; npsp=ntypat, except if ! alchemical pseudo-atoms) <= 4.2: read (fdWFK) title,znuclpsp,zionpsp,pspso,pspdat,pspcod,pspxc >= 4.4: read (fdWFK) title,znuclpsp,zionpsp,pspso,pspdat,pspcod,pspxc,lmn_size """ if kind == 3: return [ # psp header ('title', 'S132'), ('znuclpsp', Dbl), ('zionpsp', Dbl), ('pspso', Int), ('pspdat', Int), ('pspcod', Int), ('pspxc', Int), ] \ + ifelse(self.headform >= 44, [('lmn_size', Int)], []) \ + [ ] """ (in case of usepaw==0, final record: residm, coordinates, total energy, Fermi energy) write(unit=unit) residm,xred(1:3,1:natom),etotal,fermie """ if kind == 4: return [ ('residm', Dbl), ('xred', Dbl, (3, hdr.natom)), ('etotal', Dbl), ('fermie', Dbl), ] """ (in case of usepaw==1, there are some additional records) """ raise ValueError, "Invalid header structure kind = %d" % kind
def read(self, infile, nbasis, debug=None, blksize=16384, perm='default'): """Reads in the matrix elements from a Fortran binary file. This is supposed to be an accelerated implementation. We *bypass* the fortran binary format and slurp the file into memory before doing further processing. Permutation flags (`perm`) honored: * 0, False, None = No permutation (generally you don't want this except for debugging) * 1, 'standard' = standard fourfold permutation for a Hermitian two-body Hamiltonian * 2, 'real' = eightfold permutation for a Hermitian two-body Hamiltonian with real basis functions in real space """ from numpy import conj from os.path import abspath assert nbasis > 0 try: perm = self.V2b_permutation_options[perm] except KeyError: raise ValueError, "Invalid permutation options: `%s'" % perm self.nbasis = nbasis dbg = text_output(ifelse(debug, sys.stdout, None), flush=True) H2 = numpy.zeros((nbasis, nbasis, nbasis, nbasis), dtype=float) self.H2 = H2 nn = nbasis * (nbasis + 1) // 2 S = os.stat(infile) fsize = S.st_size # net bytesize excluding marker rec_count = fsize // self.rectype.itemsize dbg("File %s: %d integral records to be read\n" % (infile, rec_count)) dbg("Matrix element permutation flag = %s\n" % (perm)) F = open(infile, "rb") self.filename = infile self.filename_abs = abspath(infile) # We use blocked read and assignment to minimize the python overhead for iblk in xrange(0, rec_count, blksize): read_blksize = min(blksize, rec_count - iblk) blob = numpy.fromfile(F, dtype=self.rectype, count=read_blksize) # The following provides a minimal consistency check if the file just read # is indeed a valid two_body_gms_ufmt file: if not numpy.all(blob['m1'] == self.recsize_net): raise PyqmcDataError, \ "Invalid record marker (m1) detected: file %s may be corrupt or of incorrect format." \ % (infile,) if not numpy.all(blob['m2'] == self.recsize_net): raise PyqmcDataError, \ "Invalid record marker (m2) detected: file %s may be corrupt or of incorrect format." \ % (infile,) # convert to py index (0-based) blob['i'] -= 1 blob['l'] -= 1 blob['j'] -= 1 blob['k'] -= 1 get_flat_perm_index = lambda iljk: \ self.make_flat_index(blob[iljk[0]], blob[iljk[1]], blob[iljk[2]], blob[iljk[3]]) # Use: V2b_inspect.permute_V2b('i','j','l','k',chem=1) # to generate this: v = blob['v'] H2.put(get_flat_perm_index('iljk'), v) if (perm == 1 or perm == 2): H2.put(get_flat_perm_index('jkil'), v) H2.put(get_flat_perm_index('likj'), conj(v)) H2.put(get_flat_perm_index('kjli'), conj(v)) if (perm == 2): # Only usable if the basis orbitals are real in real-space. H2.put(get_flat_perm_index('ilkj'), v) H2.put(get_flat_perm_index('kjil'), v) H2.put(get_flat_perm_index('jkli'), v) H2.put(get_flat_perm_index('lijk'), v) F.close()