Getting the band structure of graphene

To get the band structure for graphene (or h-BN), only a few changes are required compared to the previous example for calculating the PDOS:

graphene_kp_dos.inp
&GLOBAL
  PROJECT graphene_kp_dos
  RUN_TYPE ENERGY 
  PRINT_LEVEL MEDIUM
&END GLOBAL

&FORCE_EVAL
  METHOD Quickstep
  &DFT
    BASIS_SET_FILE_NAME  BASIS_MOLOPT
    POTENTIAL_FILE_NAME  POTENTIAL

    &POISSON
      PERIODIC XYZ
    &END POISSON
    &QS
      EXTRAPOLATION USE_GUESS ! required for K-Point sampling
    &END QS
    &SCF
      SCF_GUESS ATOMIC
      EPS_SCF 1.0E-6
      MAX_SCF 300

      ADDED_MOS 2
      &SMEAR ON
        METHOD FERMI_DIRAC
        ELECTRONIC_TEMPERATURE [K] 300
      &END SMEAR
      &DIAGONALIZATION
        ALGORITHM STANDARD
        EPS_ADAPT 0.01
      &END DIAGONALIZATION
      &MIXING
        METHOD BROYDEN_MIXING
        ALPHA 0.2
        BETA 1.5
        NBROYDEN 8
      &END MIXING
    &END SCF
    &XC
      &XC_FUNCTIONAL PBE
      &END XC_FUNCTIONAL
    &END XC
    &KPOINTS
      SCHEME MONKHORST-PACK 3 3 1
      SYMMETRY OFF 
      WAVEFUNCTIONS REAL
      FULL_GRID .TRUE.
      PARALLEL_GROUP_SIZE  0
      &BAND_STRUCTURE
        ADDED_MOS 2
        FILE_NAME graphene.bs
        &KPOINT_SET
          UNITS CART_BOHR ! work around a bug in CP2K, should be B_VECTOR
          SPECIAL_POINT 0.0   0.0   0.0
          SPECIAL_POINT 1./2. 0.0   0.0
          NPOINTS 5
        &END
      &END BAND_STRUCTURE
    &END KPOINTS
  &END DFT

  &SUBSYS
    &CELL
      ABC [angstrom] 2.4612 2.4612 8
      ALPHA_BETA_GAMMA 90. 90. 60.
      SYMMETRY HEXAGONAL
      PERIODIC XYZ
      MULTIPLE_UNIT_CELL 1 1 1
    &END CELL
    &TOPOLOGY
      MULTIPLE_UNIT_CELL 1 1 1
    &END TOPOLOGY
    &COORD
      SCALED
      C  1./3.  1./3.  0.
      C  2./3.  2./3.  0.
    &END
    &KIND C
      ELEMENT C
      BASIS_SET TZVP-MOLOPT-GTH
      POTENTIAL GTH-PBE
    &END KIND
  &END SUBSYS

&END FORCE_EVAL
At present (CP2K 4.1) it is not possible to get the projected density of states when doing a K-Point calculation. Plus there is currently an issue with the UNITS specification for the special point coordinates: even though the unit is set to Cartesian coordinates (in Bohr), the special points are multiplied by the reciprocal vectors and must therefore be given in terms of the b-vectors.

Some notes on the input file:

Now, when you run this input file you will get in addition the the output file, a file named graphene.bs which will look similar to the following:

 SET:       1                 TOTAL POINTS:      6
   POINT   1                     0.000000    0.000000    0.000000
   POINT   2                     0.500000    0.000000    0.000000
       Nr.    1    Spin 1        K-Point  0.00000000  0.00000000  0.00000000
                8
           -15.30752034     -3.31285773      0.93143545      1.03651421
             8.71874068     12.74920179     12.83785311     15.50144316
       Nr.    2    Spin 1        K-Point  0.02500000  0.00000000  0.00000000
                8
           -15.29453364     -3.29547462      0.87472486      1.00321991
             8.31998068     12.81500348     12.93001933     15.45108207
       Nr.    3    Spin 1        K-Point  0.05000000  0.00000000  0.00000000
[...]

For each set there is a block named SET with the special points listed as POINT, followed by sub-blocks for each K-Point containing the energies for each MO.

Your tasks:

To convert the band structure file to a file which can be loaded directly into MATLAB for example, you can use the script cp2k_bs2csv.py from below, which when passed a band structure file graphene.bs as an argument will write files graphene.bs-setN.csv for each set containing the K-Point coordinates and the energies in one line.

cp2k_bs2csv.py
#!/usr/bin/env python
"""
Convert the CP2K band structure output to CSV files
"""
 
import re
import argparse
 
SET_MATCH = re.compile(r'''
[ ]*
  SET: [ ]* (?P<setnr>\d+) [ ]*
  TOTAL [ ] POINTS: [ ]* (?P<totalpoints>\d+) [ ]*
  \n
(?P<content>
  [\s\S]*?(?=\n.*?[ ] SET|$)  # match everything until next 'SET' or EOL
)
''', re.VERBOSE)
 
SPOINTS_MATCH = re.compile(r'''
[ ]*
  POINT [ ]+ (?P<pointnr>\d+) [ ]+ (?P<a>\S+) [ ]+ (?P<b>\S+) [ ]+ (?P<c>\S+)
''', re.VERBOSE)
 
POINTS_MATCH = re.compile(r'''
[ ]*
  Nr\. [ ]+ (?P<nr>\d+) [ ]+
  Spin [ ]+ (?P<spin>\d+) [ ]+
  K-Point [ ]+ (?P<a>\S+) [ ]+ (?P<b>\S+) [ ]+ (?P<c>\S+) [ ]*
  \n
[ ]* (?P<npoints>\d+) [ ]* \n
(?P<values>
  [\s\S]*?(?=\n.*?[ ] Nr|$)  # match everything until next 'Nr.' or EOL
)
''', re.VERBOSE)
 
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('bsfilename', metavar='bandstructure-file', type=str,
                        help="the band structure file generated by CP2K")
 
    args = parser.parse_args()
 
    with open(args.bsfilename, 'r') as fhandle:
        for kpoint_set in SET_MATCH.finditer(fhandle.read()):
            filename = "{}.set-{}.csv".format(args.bsfilename,
                                              kpoint_set.group('setnr'))
            set_content = kpoint_set.group('content')
 
            with open(filename, 'w') as csvout:
                print(("writing point set {}"
                       " (total number of k-points: {totalpoints})"
                       .format(filename, **kpoint_set.groupdict())))
 
                print("  with the following special points:")
                for point in SPOINTS_MATCH.finditer(set_content):
                    print("  {pointnr}: {a}/{b}/{c}".format(
                        **point.groupdict()))
 
                for point in POINTS_MATCH.finditer(set_content):
                    results = point.groupdict()
                    results['values'] = " ".join(results['values'].split())
                    csvout.write("{a} {b} {c} {values}\n".format(**results))