Example #1
0
    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,), ]
          )
Example #2
0
 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()
Example #3
0
    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)
Example #4
0
 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)
Example #5
0
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()
Example #6
0
    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
Example #7
0
    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
Example #8
0
    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()