예제 #1
0
 def __init__(self, runfdf):
     self.fdf = runfdf
     self.directory, self.tail = os.path.split(runfdf)
     self.systemlabel = SIO.GetFDFlineWithDefault(runfdf, 'SystemLabel',
                                                  str, 'siesta', 'Phonons')
     # Read geometry
     self.geom = MG.Geom(runfdf)
     # Compare with XV file corrected for last displacement
     XV = self.directory + '/%s.XV' % self.systemlabel
     # Determine TSHS files
     files = glob.glob(self.directory + '/%s*.TSHS' % self.systemlabel)
     # Build dictionary over TSHS files and corresponding displacement amplitudes
     self.TSHS = {}
     try:
         self.TSHS[0] = files[0]  # Equilibrium TSHS
     except:
         warnings.warn('Phonons.GetFileLists: No TSHS file found in %s' %
                       self.directory)
예제 #2
0
def GetOptions(argv):
    """
    Returns an instance of ``options`` for the ``Phonons`` module

    Parameters
    ----------
    argv : string
        For example `-c test_dir`, which gives instructions to compute not only
        vibrational modes and frequencies, but also the corresponding electron-vibration
        couplings and to place the results in the output directory `test_dir`.
    """
    # if text string is specified, convert to list
    if isinstance(argv, VC.string_types):
        argv = argv.split()

    import argparse

    p = argparse.ArgumentParser(
        description=
        'Methods to calculate vibrations and e-ph couplings from SIESTA output'
    )
    p.add_argument('DestDir', help='Destination directory')
    p.add_argument(
        '-f',
        '--fdf',
        dest='fdf',
        default='./RUN.fdf',
        type=str,
        help='Input fdf-file for SIESTA/TranSIESTA calculation [%(default)s]')
    p.add_argument('-c',
                   '--CalcCoupl',
                   dest='CalcCoupl',
                   action='store_true',
                   default=False,
                   help='Calculate e-ph couplings [default=%(default)s]')
    p.add_argument('-r',
                   '--Restart',
                   dest='Restart',
                   action='store_true',
                   default=False,
                   help='Restart from a previous run [default=%(default)s]')
    p.add_argument(
        '--CheckPointNetCDF',
        dest='CheckPointNetCDF',
        type=str,
        default='None',
        help='Old NetCDF file used for restart [default=%(default)s]')
    p.add_argument(
        '-s',
        '--SinglePrec',
        dest='SinglePrec',
        action='store_true',
        default=False,
        help=
        'Calculate e-ph couplings using single precision arrays [default=%(default)s]'
    )
    p.add_argument(
        '-F',
        '--DeviceFirst',
        dest='DeviceFirst',
        type=int,
        default=1,
        help=
        'First device atom index (in the electronic basis) [default=%(default)s]'
    )
    p.add_argument(
        '-L',
        '--DeviceLast',
        dest='DeviceLast',
        type=int,
        default=0,
        help=
        'Last device atom index (in the electronic basis) [default=NumberOfAtoms]'
    )
    p.add_argument('--FCfirst',
                   dest='FCfirst',
                   type=int,
                   default=1,
                   help='First FC atom index [default=%(default)s]')
    p.add_argument('--FClast',
                   dest='FClast',
                   type=int,
                   default=0,
                   help='Last FC atom index [default=NumberOfAtoms]')
    p.add_argument(
        '--EPHfirst',
        dest='EPHfirst',
        type=int,
        default=1,
        help=
        'First atom index for which the e-ph. couplings are evaluated [default=FCfirst]'
    )
    p.add_argument(
        '--EPHlast',
        dest='EPHlast',
        type=int,
        default=0,
        help=
        'Last atom index for which the e-ph. couplings are evaluated [default=FClast]'
    )
    p.add_argument(
        '--PBCFirst',
        dest='PBCFirst',
        type=int,
        default=1,
        help=
        'For eliminating interactions through periodic boundary conditions in z-direction [default=%(default)s]'
    )
    p.add_argument(
        '--PBCLast',
        dest='PBCLast',
        type=int,
        default=0,
        help=
        'For eliminating interactions through periodic boundary conditions in z-direction [default=NumberOfAtoms]'
    )
    p.add_argument('--FCwildcard',
                   dest='FCwildcard',
                   type=str,
                   default='./FC*',
                   help='Wildcard for FC directories [default=%(default)s]')
    p.add_argument('--OSdir',
                   dest='onlySdir',
                   type=str,
                   default='./OSrun',
                   help='Location of OnlyS directory [default=%(default)s]')
    p.add_argument(
        '-a',
        '--AbsoluteEnergyReference',
        dest='AbsEref',
        action='store_true',
        default=False,
        help=
        'Use an absolute energy reference (Fermi energy of equilibrium structure) for displaced Hamiltonians (e.g., when eF is not well-defined) instead of the instantaneous Fermi energy for the displaced geometries, cf. Eq.(17) in PRB 75, 205413 (2007) [default=%(default)s]'
    )
    p.add_argument(
        '-i',
        '--Isotopes',
        dest='Isotopes',
        default='[]',
        help=
        'String, formatted as a list [[i1,m1],...], where the mass of atom index i1 (SIESTA numbering) will be set to m1. Alternatively, the argument can be a file with the string [default=%(default)s]'
    )
    p.add_argument(
        '-x',
        '--k1',
        dest='k1',
        default=0.0,
        type=float,
        help='k-point along a1 where e-ph couplings are evaluated [%(default)s]'
    )
    p.add_argument(
        '-y',
        '--k2',
        dest='k2',
        default=0.0,
        type=float,
        help='k-point along a2 where e-ph couplings are evaluated [%(default)s]'
    )
    p.add_argument(
        '-z',
        '--k3',
        dest='k3',
        default=0.0,
        type=float,
        help='k-point along a3 where e-ph couplings are evaluated [%(default)s]'
    )
    p.add_argument(
        '-g',
        '--WriteGradients',
        dest='WriteGradients',
        action='store_true',
        default=False,
        help='Write real-space gradients dH/dR to NetCDF [default=%(default)s]'
    )

    options = p.parse_args(argv)

    # Set module name
    options.module = 'Phonons'

    # k-point
    options.kpoint = N.array([options.k1, options.k2, options.k3], N.float)
    del options.k1, options.k2, options.k3

    # Determine array type for H,S,dH,...
    options.GammaPoint = N.dot(options.kpoint, options.kpoint) < 1e-7
    if options.GammaPoint:
        if options.SinglePrec:
            options.atype = N.float32
        else:
            options.atype = N.float64
    else:
        if options.SinglePrec:
            options.atype = N.complex64
        else:
            options.atype = N.complex128

    # Check if we need to set the last atom(s)
    if options.FClast * options.DeviceLast * options.EPHlast * options.PBCLast == 0:
        # We need NumberOfAtoms
        fdf = glob.glob(options.FCwildcard + '/' + options.fdf)
        natoms = SIO.GetFDFlineWithDefault(fdf[0], 'NumberOfAtoms', int, 1000,
                                           'Phonons')
    if options.FClast == 0:
        options.FClast = natoms
    if options.DeviceLast == 0:
        options.DeviceLast = natoms
    if options.EPHlast == 0:
        options.EPHlast = natoms
    if options.PBCLast == 0:
        options.PBCLast = natoms

    # Dynamic atoms
    options.DynamicAtoms = list(range(options.FCfirst, options.FClast + 1))

    # EPH atoms - set only different from options.DynamicAtoms if a subset is specified
    if options.EPHfirst >= options.FCfirst and options.EPHlast <= options.FClast:
        options.EPHAtoms = list(range(options.EPHfirst, options.EPHlast + 1))
    else:
        options.EPHAtoms = options.DynamicAtoms
    del options.EPHfirst, options.EPHlast
    del options.FCfirst, options.FClast

    # PBCFirst/PBCLast
    if options.PBCFirst < options.DeviceFirst:
        options.PBCFirst = options.DeviceFirst
    if options.PBCLast > options.DeviceLast:
        options.PBCLast = options.DeviceLast

    # Isotopes specified in separate file?
    if os.path.isfile(options.Isotopes):
        f = open(options.Isotopes)
        s = ''
        for line in f.readlines():
            s += line.replace('\n', '')
        options.Isotopes = s
    options.Isotopes = ast.literal_eval(options.Isotopes)

    return options
예제 #3
0
    def __init__(self, runfdf):
        self.fdf = runfdf
        self.directory, self.tail = os.path.split(runfdf)
        self.systemlabel = SIO.GetFDFlineWithDefault(runfdf, 'SystemLabel',
                                                     str, 'siesta', 'Phonons')
        FCfirst = SIO.GetFDFlineWithDefault(runfdf, 'MD.FCfirst', int, 0,
                                            'Phonons')
        FClast = SIO.GetFDFlineWithDefault(runfdf, 'MD.FClast', int, 0,
                                           'Phonons')
        # Finite-displacement amplitude
        ampl, unit = SIO.GetFDFline(runfdf, KeyWord='MD.FCDispl')
        if unit.upper() == 'ANG':
            self.Displ = float(ampl)
        elif unit.upper() == 'BOHR':
            self.Displ = float(ampl) * PC.Bohr2Ang
        print('Displacement = %.6f Ang' % self.Displ)
        # Read geometry
        self.geom = MG.Geom(runfdf)
        # Compare with XV file corrected for last displacement
        XV = self.directory + '/%s.XV' % self.systemlabel
        geomXV = MG.Geom(XV)
        geomXV.xyz[FClast - 1, 2] -= self.Displ
        if not N.allclose(geomXV.xyz, self.geom.xyz):
            sys.exit('Error: Geometries %s and %s should differ ONLY by displacement of atom %s in z'\
                     %(runfdf, XV, FClast))
        # Set up FC[i,a,j,b]: Force constant (eV/A^2) from moved atom i, axis a to atom j, axis b
        natoms = self.geom.natoms
        self.m = N.zeros((FClast - FCfirst + 1, 3, natoms, 3), N.float)
        self.p = N.zeros((FClast - FCfirst + 1, 3, natoms, 3), N.float)
        fc = N.array(
            SIO.ReadFCFile(self.directory + '/%s.FC' % self.systemlabel))
        for i in range(FClast - FCfirst + 1):
            for j in range(3):
                self.m[i, j] = fc[2 * (3 * i + j) *
                                  natoms:(2 * (3 * i + j) + 1) * natoms]
                self.p[i, j] = fc[(2 * (3 * i + j) + 1) *
                                  natoms:(2 * (3 * i + j) + 2) * natoms]
        # Correct force constants for the moved atom
        # Cf. Eq. (13) in Frederiksen et al. PRB 75, 205413 (2007)
        for i in range(FClast - FCfirst + 1):
            for j in range(3):
                self.m[i, j, FCfirst - 1 + i, :] = 0.0
                self.m[i, j, FCfirst - 1 + i, :] = -N.sum(self.m[i, j], axis=0)
                self.p[i, j, FCfirst - 1 + i, :] = 0.0
                self.p[i, j, FCfirst - 1 + i, :] = -N.sum(self.p[i, j], axis=0)
        self.DynamicAtoms = list(range(FCfirst, FClast + 1))

        # Determine TSHS files
        files = glob.glob(self.directory + '/%s*.TSHS' % self.systemlabel)
        files.sort()
        if self.directory + '/%s.TSHS' % self.systemlabel in files:
            # If present, ignore this file which does not origninate from the FCrun
            files.remove(self.directory + '/%s.TSHS' % self.systemlabel)
        if (FClast - FCfirst + 1) * 6 + 1 != len(files):
            warnings.warn(
                'Phonons.GetFileLists: WARNING - Inconsistent number of *.TSHS files in %s'
                % self.directory)
            return

        # Build dictionary over TSHS files and corresponding displacement amplitudes
        self.TSHS = {}
        self.TSHS[0] = files[0]  # Equilibrium TSHS
        for i, v in enumerate(self.DynamicAtoms):
            for j in range(3):
                # Shifted TSHS files (atom,axis,direction)
                self.TSHS[v, j, -1] = files[1 + 6 * i + 2 * j]
                self.TSHS[v, j, 1] = files[1 + 6 * i + 2 * j + 1]
예제 #4
0
    def get_elec_vars(lr):

        # Look up old format first
        TSHS = SIO.GetFDFlineWithDefault(opts.fn, 'TS.HSFile' + lr, str, '',
                                         exe)
        NA1 = SIO.GetFDFlineWithDefault(opts.fn, 'TS.ReplicateA1' + lr, int, 1,
                                        exe)
        NA2 = SIO.GetFDFlineWithDefault(opts.fn, 'TS.ReplicateA2' + lr, int, 1,
                                        exe)

        # default semi-inf direction
        semiinf = 2

        # Proceed looking up new format, which precedes
        belec = 'TS.Elec.' + lr
        print('Looking for new electrode format in: %%block {}'.format(belec))

        # Default replication stuff
        TSHS = SIO.GetFDFlineWithDefault(opts.fn, belec + '.TSHS', str, TSHS,
                                         exe)
        NA1 = SIO.GetFDFlineWithDefault(opts.fn, belec + '.Bloch.A1', int, NA1,
                                        exe)
        NA2 = SIO.GetFDFlineWithDefault(opts.fn, belec + '.Bloch.A2', int, NA2,
                                        exe)
        NA3 = SIO.GetFDFlineWithDefault(opts.fn, belec + '.Bloch.A3', int, 1,
                                        exe)

        # Overwrite block
        block = SIO.GetFDFblock(opts.fn, KeyWord=belec)

        for line in block:
            print(line)
            # Lower-case, FDF is case-insensitive
            key = line[0].lower()
            if key in ['tshs', 'tshs-file', 'hs', 'hs-file']:
                TSHS = line[1]
            elif key in [
                    'replicate-a', 'rep-a', 'replicate-a1', 'rep-a1',
                    'bloch-a1'
            ]:
                NA1 = int(line[1])
            elif key in [
                    'replicate-b', 'rep-b', 'replicate-a2', 'rep-a2',
                    'bloch-a2'
            ]:
                NA2 = int(line[1])
            elif key in [
                    'replicate-c', 'rep-c', 'replicate-a3', 'rep-a3',
                    'bloch-a3'
            ]:
                NA3 = int(line[1])
            elif key in ['replicate', 'rep', 'bloch']:
                # We have *at least* 2 integers
                NA1 = int(line[1])
                NA2 = int(line[2])
                NA3 = int(line[3])

            elif key in ['semi-inf-direction', 'semi-inf-dir', 'semi-inf']:
                # This is lower-case checked
                axis = line[1][1:].lower()
                if 'a' == axis or 'a1' == axis:
                    semiinf = 0
                elif 'b' == axis or 'a2' == axis:
                    semiinf = 1
                elif 'c' == axis or 'a3' == axis:
                    semiinf = 2

                # Simple check of input, this may be overwritten later
                if semiinf != 2 and NA1 * NA2 * NA3 > 1:
                    raise ValueError(
                        ("Cannot provide semi-infinite directions "
                         "other than A3-direction with repetition."))
        if TSHS[0] != '/':
            # path is relative
            TSHS = opts.head + '/' + TSHS
        return TSHS, NA1, NA2, semiinf
예제 #5
0
def OptionsCheck(opts):
    """
    Generic routine for adjusting most used options for routines.
    I.e. Inelastica/EigenChannels/pyTBT.
    """
    import Inelastica.io.siesta as SIO
    import os
    import os.path as osp

    # Module name
    exe = opts.module

    # Destination directory
    if not osp.isdir(opts.DestDir):
        print('\n' + exe + ': Creating folder {0}'.format(opts.DestDir))
        os.mkdir(opts.DestDir)

    if not osp.isfile(opts.fn):
        raise IOError("FDF-file not found: " + opts.fn)

    # Read SIESTA files
    opts.head = osp.split(opts.fn)[0]
    if opts.head == '':  # set filepath if missing
        opts.head = '.'
    print(exe + ": Reading keywords from {0} \n".format(opts.fn))

    opts.systemlabel = SIO.GetFDFlineWithDefault(opts.fn, 'SystemLabel', str,
                                                 'siesta', exe)
    opts.TSHS = '%s/%s.TSHS' % (opts.head, opts.systemlabel)

    # These first keys can be used, but they are superseeded by keys in the TS.Elec.<> block
    # Hence if they are read in first it will do it in correct order.

    if opts.UseBulk < 0:
        # Note NRP:
        #  in principle this is now a per-electrode setting which
        #  may be useful for certain systems...
        opts.UseBulk = SIO.GetFDFlineWithDefault(opts.fn,
                                                 'TS.UseBulkInElectrodes',
                                                 bool, True, exe)
        opts.UseBulk = SIO.GetFDFlineWithDefault(opts.fn, 'TS.Elecs.Bulk',
                                                 bool, opts.UseBulk, exe)

    def get_elec_vars(lr):

        # Look up old format first
        TSHS = SIO.GetFDFlineWithDefault(opts.fn, 'TS.HSFile' + lr, str, '',
                                         exe)
        NA1 = SIO.GetFDFlineWithDefault(opts.fn, 'TS.ReplicateA1' + lr, int, 1,
                                        exe)
        NA2 = SIO.GetFDFlineWithDefault(opts.fn, 'TS.ReplicateA2' + lr, int, 1,
                                        exe)

        # default semi-inf direction
        semiinf = 2

        # Proceed looking up new format, which precedes
        belec = 'TS.Elec.' + lr
        print('Looking for new electrode format in: %%block {}'.format(belec))

        # Default replication stuff
        TSHS = SIO.GetFDFlineWithDefault(opts.fn, belec + '.TSHS', str, TSHS,
                                         exe)
        NA1 = SIO.GetFDFlineWithDefault(opts.fn, belec + '.Bloch.A1', int, NA1,
                                        exe)
        NA2 = SIO.GetFDFlineWithDefault(opts.fn, belec + '.Bloch.A2', int, NA2,
                                        exe)
        NA3 = SIO.GetFDFlineWithDefault(opts.fn, belec + '.Bloch.A3', int, 1,
                                        exe)

        # Overwrite block
        block = SIO.GetFDFblock(opts.fn, KeyWord=belec)

        for line in block:
            print(line)
            # Lower-case, FDF is case-insensitive
            key = line[0].lower()
            if key in ['tshs', 'tshs-file', 'hs', 'hs-file']:
                TSHS = line[1]
            elif key in [
                    'replicate-a', 'rep-a', 'replicate-a1', 'rep-a1',
                    'bloch-a1'
            ]:
                NA1 = int(line[1])
            elif key in [
                    'replicate-b', 'rep-b', 'replicate-a2', 'rep-a2',
                    'bloch-a2'
            ]:
                NA2 = int(line[1])
            elif key in [
                    'replicate-c', 'rep-c', 'replicate-a3', 'rep-a3',
                    'bloch-a3'
            ]:
                NA3 = int(line[1])
            elif key in ['replicate', 'rep', 'bloch']:
                # We have *at least* 2 integers
                NA1 = int(line[1])
                NA2 = int(line[2])
                NA3 = int(line[3])

            elif key in ['semi-inf-direction', 'semi-inf-dir', 'semi-inf']:
                # This is lower-case checked
                axis = line[1][1:].lower()
                if 'a' == axis or 'a1' == axis:
                    semiinf = 0
                elif 'b' == axis or 'a2' == axis:
                    semiinf = 1
                elif 'c' == axis or 'a3' == axis:
                    semiinf = 2

                # Simple check of input, this may be overwritten later
                if semiinf != 2 and NA1 * NA2 * NA3 > 1:
                    raise ValueError(
                        ("Cannot provide semi-infinite directions "
                         "other than A3-direction with repetition."))
        if TSHS[0] != '/':
            # path is relative
            TSHS = opts.head + '/' + TSHS
        return TSHS, NA1, NA2, semiinf

    # Look up electrode block
    block = SIO.GetFDFblock(opts.fn, KeyWord='TS.Elecs')
    if len(block) == 0:
        # Did not find the electrode block, defaults to old naming scheme
        opts.fnL, opts.NA1L, opts.NA2L, opts.semiinfL = get_elec_vars('Left')
        opts.fnR, opts.NA1R, opts.NA2R, opts.semiinfR = get_elec_vars('Right')
    elif len(block) == 2:
        # NB: The following assumes that the left electrode is the first in the block!
        opts.fnL, opts.NA1L, opts.NA2L, opts.semiinfL = get_elec_vars(
            block[0][0])
        opts.fnR, opts.NA1R, opts.NA2R, opts.semiinfR = get_elec_vars(
            block[1][0])
    else:
        print(block)
        raise IOError('Currently only two electrodes are supported')

    # Read in number of buffer atoms
    opts.buffer, L, R = SIO.GetBufferAtomsList(opts.TSHS, opts.fn)
    opts.bufferL = L
    opts.bufferR = R

    if 'maxBias' in opts.__dict__:
        # Bias range
        opts.maxBias = abs(opts.maxBias)
        opts.minBias = -abs(opts.maxBias)

    # Device region
    if opts.DeviceFirst <= 0:
        opts.DeviceFirst = SIO.GetFDFlineWithDefault(opts.fn,
                                                     'TS.TBT.PDOSFrom', int, 1,
                                                     exe)
    opts.DeviceFirst -= L
    if opts.DeviceLast <= 0:
        opts.DeviceLast = SIO.GetFDFlineWithDefault(opts.fn, 'TS.TBT.PDOSTo',
                                                    int, 1e10, exe)
    opts.DeviceLast -= L
    opts.NumberOfAtoms = SIO.GetFDFlineWithDefault(opts.fn, 'NumberOfAtoms',
                                                   int, 1e10, exe)
    opts.NumberOfAtoms -= L + R
    if opts.DeviceLast < opts.DeviceFirst:
        print(
            exe +
            ' error: DeviceLast<DeviceFirst not allowed. Setting DeviceLast=DeviceFirst'
        )
        opts.DeviceLast = opts.DeviceFirst
    opts.DeviceAtoms = [
        max(opts.DeviceFirst, 1),
        min(opts.DeviceLast, opts.NumberOfAtoms)
    ]

    # Voltage
    opts.voltage = SIO.GetFDFlineWithDefault(opts.fn, 'TS.Voltage', float, 0.0,
                                             exe)

    #############
    # Here comes some specifics related to different executables:
    #############

    if "VfracL" in opts.__dict__:
        if opts.VfracL < 0.0 or opts.VfracL > 1.0:
            raise RuntimeError(
                'Option VfracL must be a value in the range [0,1].')

    if "PhononNetCDF" in opts.__dict__:
        if not osp.isfile(opts.PhononNetCDF):
            raise IOError("Electron-phonon coupling NetCDF file not found: " +
                          opts.PhononNetCDF)
    if "eta" in opts.__dict__:
        if opts.eta < 0:
            raise RuntimeError("eta must be a posivite number")
    if "etaLead" in opts.__dict__:
        if opts.etaLead < 0:
            raise RuntimeError("etaLead must be a posivite number")
    if "PhExtDamp" in opts.__dict__:
        if opts.PhExtDamp < 0:
            raise RuntimeError("PhExtDamp must be a posivite number")
    if "biasPoints" in opts.__dict__:
        if opts.biasPoints < 6:
            raise AssertionError("BiasPoints must be larger than 5")
    if "iSpin" in opts.__dict__:
        if not opts.iSpin in [0, 1]:
            raise AssertionError("Spin must be either 0 or 1")

    if "Emin" in opts.__dict__:
        if opts.Emin == 1e10:
            opts.Emin = SIO.GetFDFlineWithDefault(opts.fn, 'TS.TBT.Emin',
                                                  float, 0.0, 'pyTBT')
    if "Emax" in opts.__dict__:
        if opts.Emax == 1e10:
            opts.Emax = SIO.GetFDFlineWithDefault(opts.fn, 'TS.TBT.Emax',
                                                  float, 1.0, 'pyTBT')
    if "NPoints" in opts.__dict__:
        if opts.NPoints <= 0:
            opts.NPoints = SIO.GetFDFlineWithDefault(opts.fn, 'TS.TBT.NPoints',
                                                     int, 1, 'pyTBT')

        # Create list of energies
        try:
            opts.Elist
            # Do not overwrite if some Elist is already specified
        except:
            if opts.NPoints == 1:
                opts.Elist = _np.array((opts.Emin, ), _np.float)
            else:
                # Linspace is just what we need
                opts.Elist = _np.linspace(opts.Emin, opts.Emax, opts.NPoints)
예제 #6
0
def main(options):
    Log.CreatePipeOutput(options)
    #VC.OptionsCheck(options)
    Log.PrintMainHeader(options)

    try:
        fdf = glob.glob(options.onlyTSdir + '/RUN.fdf')
        TSrun = True
    except:
        fdf = glob.glob(options.FCwildcard +
                        '/RUN.fdf')  # This should be made an input flag
        TSrun = False
    SCDM = Supercell_DynamicalMatrix(fdf, TSrun)

    # Write high-symmetry path
    WritePath(options.DestDir + '/symmetry-path', SCDM.Sym.path, options.steps)

    # Write mesh
    k1, k2, k3 = ast.literal_eval(options.mesh)
    rvec = 2 * N.pi * N.array([SCDM.Sym.b1, SCDM.Sym.b2, SCDM.Sym.b3])
    import Inelastica.physics.mesh as Kmesh
    # Full mesh
    kmesh = Kmesh.kmesh(2**k1,
                        2**k2,
                        2**k3,
                        meshtype=['LIN', 'LIN', 'LIN'],
                        invsymmetry=False)
    WriteKpoints(options.DestDir + '/mesh_%ix%ix%i' % tuple(kmesh.Nk),
                 N.dot(kmesh.k, rvec))
    # Mesh reduced by inversion symmetry
    kmesh = Kmesh.kmesh(2**k1,
                        2**k2,
                        2**k3,
                        meshtype=['LIN', 'LIN', 'LIN'],
                        invsymmetry=True)
    WriteKpoints(options.DestDir + '/mesh_%ix%ix%i_invsym' % tuple(kmesh.Nk),
                 N.dot(kmesh.k, rvec))

    # Evaluate electron k-points
    if options.kfile:
        # Prepare Hamiltonian etc in Gamma for whole supercell
        natoms = SIO.GetFDFlineWithDefault(fdf[0], 'NumberOfAtoms', int, -1,
                                           'Error')
        SCDM.PrepareGradients(options.onlySdir,
                              N.array([0., 0., 0.]),
                              1,
                              natoms,
                              AbsEref=False,
                              atype=N.complex,
                              TSrun=TSrun)
        SCDM.nao = SCDM.h0.shape[-1]
        SCDM.FirstOrb = SCDM.OrbIndx[0][0]  # First atom = 1
        SCDM.LastOrb = SCDM.OrbIndx[SCDM.Sym.basis.NN -
                                    1][1]  # Last atom = Sym.NN
        SCDM.rednao = SCDM.LastOrb + 1 - SCDM.FirstOrb
        # Read kpoints
        kpts, dk, klabels, kticks = ReadKpoints(options.kfile)
        if klabels:
            # Only write ascii if labels exist
            WriteKpoints(options.DestDir + '/kpoints', kpts, klabels)
        # Prepare netcdf
        ncfn = options.DestDir + '/Electrons.nc'
        ncf = NC4.Dataset(ncfn, 'w')
        # Grid
        ncf.createDimension('gridpts', len(kpts))
        ncf.createDimension('vector', 3)
        grid = ncf.createVariable('grid', 'd', ('gridpts', 'vector'))
        grid[:] = kpts
        grid.units = '1/Angstrom'
        # Geometry
        ncf.createDimension('atoms', SCDM.Sym.basis.NN)
        xyz = ncf.createVariable('xyz', 'd', ('atoms', 'vector'))
        xyz[:] = SCDM.Sym.basis.xyz
        xyz.units = 'Angstrom'
        pbc = ncf.createVariable('pbc', 'd', ('vector', 'vector'))
        pbc.units = 'Angstrom'
        pbc[:] = [SCDM.Sym.a1, SCDM.Sym.a2, SCDM.Sym.a3]
        rvec1 = ncf.createVariable('rvec', 'd', ('vector', 'vector'))
        rvec1.units = '1/Angstrom (incl. factor 2pi)'
        rvec1[:] = rvec
        ncf.sync()
        # Loop over kpoints
        for i, k in enumerate(kpts):
            if i < 100:  # Print only for the first 100 points
                ev, evec = SCDM.ComputeElectronStates(k,
                                                      verbose=True,
                                                      TSrun=TSrun)
            else:
                ev, evec = SCDM.ComputeElectronStates(k,
                                                      verbose=False,
                                                      TSrun=TSrun)
                # otherwise something simple
                if i % 100 == 0:
                    print('%i out of %i k-points computed' % (i, len(kpts)))
            if i == 0:
                ncf.createDimension('nspin', SCDM.nspin)
                ncf.createDimension('orbs', SCDM.rednao)
                if options.nbands and options.nbands < SCDM.rednao:
                    nbands = options.nbands
                else:
                    nbands = SCDM.rednao
                ncf.createDimension('bands', nbands)
                evals = ncf.createVariable('eigenvalues', 'd',
                                           ('gridpts', 'nspin', 'bands'))
                evals.units = 'eV'
                evecsRe = ncf.createVariable(
                    'eigenvectors.re', 'd',
                    ('gridpts', 'nspin', 'orbs', 'bands'))
                evecsIm = ncf.createVariable(
                    'eigenvectors.im', 'd',
                    ('gridpts', 'nspin', 'orbs', 'bands'))
                # Check eigenvectors
                print('SupercellPhonons: Checking eigenvectors at', k)
                for j in range(SCDM.nspin):
                    ev2 = N.diagonal(
                        MM.mm(MM.dagger(evec[j]), SCDM.h0_k[j], evec[j]))
                    print(' ... spin %i: Allclose=' % j,
                          N.allclose(ev[j], ev2, atol=1e-5, rtol=1e-3))
                ncf.sync()
            # Write to NetCDF
            evals[i, :] = ev[:, :nbands]
            evecsRe[i, :] = evec[:, :, :nbands].real
            evecsIm[i, :] = evec[:, :, :nbands].imag
        ncf.sync()
        # Include basis orbitals in netcdf file
        if SCDM.Sym.basis.NN == len(SCDM.OrbIndx):
            lasto = N.zeros(SCDM.Sym.basis.NN + 1, N.float)
            lasto[:SCDM.Sym.basis.NN] = SCDM.OrbIndx[:SCDM.Sym.basis.NN, 0]
            lasto[SCDM.Sym.basis.NN] = SCDM.OrbIndx[SCDM.Sym.basis.NN - 1,
                                                    1] + 1
        else:
            lasto = SCDM.OrbIndx[:SCDM.Sym.basis.NN + 1, 0]
        orbbasis = SIO.BuildBasis(fdf[0], 1, SCDM.Sym.basis.NN, lasto)
        # Note that the above basis is for the geometry with an atom FC-moved in z.
        #print dir(orbbasis)
        #print orbbasis.xyz # Hence, this is not the correct geometry of the basis atoms!
        center = ncf.createVariable('orbcenter', 'i', ('orbs', ))
        center[:] = N.array(orbbasis.ii - 1, dtype='int32')
        center.description = 'Atom index (counting from 0) of the orbital center'
        nn = ncf.createVariable('N', 'i', ('orbs', ))
        nn[:] = N.array(orbbasis.N, dtype='int32')
        ll = ncf.createVariable('L', 'i', ('orbs', ))
        ll[:] = N.array(orbbasis.L, dtype='int32')
        mm = ncf.createVariable('M', 'i', ('orbs', ))
        mm[:] = N.array(orbbasis.M, dtype='int32')
        # Cutoff radius and delta
        Rc = ncf.createVariable('Rc', 'd', ('orbs', ))
        Rc[:] = orbbasis.coff
        Rc.units = 'Angstrom'
        delta = ncf.createVariable('delta', 'd', ('orbs', ))
        delta[:] = orbbasis.delta
        delta.units = 'Angstrom'
        # Radial components of the orbitals
        ntb = len(orbbasis.orb[0])
        ncf.createDimension('ntb', ntb)
        rii = ncf.createVariable('rii', 'd', ('orbs', 'ntb'))
        rii[:] = N.outer(orbbasis.delta, N.arange(ntb))
        rii.units = 'Angstrom'
        radialfct = ncf.createVariable('radialfct', 'd', ('orbs', 'ntb'))
        radialfct[:] = orbbasis.orb
        # Sort eigenvalues to connect crossing bands?
        if options.sorting:
            for i in range(SCDM.nspin):
                evals[:, i, :] = SortBands(evals[:, i, :])
        # Produce nice plots if labels exist
        if klabels:
            if SCDM.nspin == 1:
                PlotElectronBands(options.DestDir + '/Electrons.agr', dk,
                                  evals[:, 0, :], kticks)
            elif SCDM.nspin == 2:
                PlotElectronBands(options.DestDir + '/Electrons.UP.agr', dk,
                                  evals[:, 0, :], kticks)
                PlotElectronBands(options.DestDir + '/Electrons.DOWN.agr', dk,
                                  evals[:, 1, :], kticks)
        ncf.close()

    if TSrun:  # only electronic calculation
        # Ugly hack to get my old code to work again. -Magnus
        if options.FermiSurface == True:
            from . import BandStruct as BS
            options.fdfFile = 'RUN.fdf'
            options.eMin, options.eMax = -10, 10
            options.NNk = 101
            BS.general = options
            BS.main()

        return SCDM.Sym.path

    # Compute phonon eigenvalues
    if options.qfile:
        SCDM.SymmetrizeFC(options.radius)
        SCDM.SetMasses()
        qpts, dq, qlabels, qticks = ReadKpoints(options.qfile)
        if qlabels:
            # Only write ascii if labels exist
            WriteKpoints(options.DestDir + '/qpoints', qpts, qlabels)
        # Prepare netcdf
        ncfn = options.DestDir + '/Phonons.nc'
        ncf = NC4.Dataset(ncfn, 'w')
        # Grid
        ncf.createDimension('gridpts', len(qpts))
        ncf.createDimension('vector', 3)
        grid = ncf.createVariable('grid', 'd', ('gridpts', 'vector'))
        grid[:] = qpts
        grid.units = '1/Angstrom'
        # Geometry
        ncf.createDimension('atoms', SCDM.Sym.basis.NN)
        xyz = ncf.createVariable('xyz', 'd', ('atoms', 'vector'))
        xyz[:] = SCDM.Sym.basis.xyz
        xyz.units = 'Angstrom'
        pbc = ncf.createVariable('pbc', 'd', ('vector', 'vector'))
        pbc.units = 'Angstrom'
        pbc[:] = [SCDM.Sym.a1, SCDM.Sym.a2, SCDM.Sym.a3]
        rvec1 = ncf.createVariable('rvec', 'd', ('vector', 'vector'))
        rvec1.units = '1/Angstrom (incl. factor 2pi)'
        rvec1[:] = rvec
        ncf.sync()
        # Loop over q
        for i, q in enumerate(qpts):
            if i < 100:  # Print only for the first 100 points
                hw, U = SCDM.ComputePhononModes_q(q, verbose=True)
            else:
                hw, U = SCDM.ComputePhononModes_q(q, verbose=False)
                # otherwise something simple
                if i % 100 == 0:
                    print('%i out of %i q-points computed' % (i, len(qpts)))
            if i == 0:
                ncf.createDimension('bands', len(hw))
                ncf.createDimension('displ', len(hw))
                evals = ncf.createVariable('eigenvalues', 'd',
                                           ('gridpts', 'bands'))
                evals.units = 'eV'
                evecsRe = ncf.createVariable('eigenvectors.re', 'd',
                                             ('gridpts', 'bands', 'displ'))
                evecsIm = ncf.createVariable('eigenvectors.im', 'd',
                                             ('gridpts', 'bands', 'displ'))
                # Check eigenvectors
                print('SupercellPhonons.Checking eigenvectors at', q)
                tmp = MM.mm(N.conjugate(U), SCDM.FCtilde, N.transpose(U))
                const = PC.hbar2SI * (1e20 / (PC.eV2Joule * PC.amu2kg))**0.5
                hw2 = const * N.diagonal(tmp)**0.5  # Units in eV
                print(' ... Allclose=',
                      N.allclose(hw, N.absolute(hw2), atol=1e-5, rtol=1e-3))
                ncf.sync()
                # Write only AXSF files for the first q-point
                PH.WriteAXSFFiles(options.DestDir + '/q%i_re.axsf' % i,
                                  SCDM.Sym.basis.xyz, SCDM.Sym.basis.anr, hw,
                                  U.real, 1, SCDM.Sym.basis.NN)
                PH.WriteAXSFFiles(options.DestDir + '/q%i_im.axsf' % i,
                                  SCDM.Sym.basis.xyz, SCDM.Sym.basis.anr, hw,
                                  U.imag, 1, SCDM.Sym.basis.NN)
                PH.WriteFreqFile(options.DestDir + '/q%i.freq' % i, hw)
            evals[i] = hw
            evecsRe[i] = U.real
            evecsIm[i] = U.imag
        ncf.sync()
        # Sort eigenvalues to connect crossing bands?
        if options.sorting:
            evals = SortBands(evals)
        # Produce nice plots if labels exist
        if qlabels:
            PlotPhononBands(options.DestDir + '/Phonons.agr', dq,
                            N.array(evals[:]), qticks)
        ncf.close()

    # Compute e-ph couplings
    if options.kfile and options.qfile:
        SCDM.ReadGradients()
        ncf = NC4.Dataset(options.DestDir + '/EPH.nc', 'w')
        ncf.createDimension('kpts', len(kpts))
        ncf.createDimension('qpts', len(qpts))
        ncf.createDimension('modes', len(hw))
        ncf.createDimension('nspin', SCDM.nspin)
        ncf.createDimension('bands', SCDM.rednao)
        ncf.createDimension('vector', 3)
        kgrid = ncf.createVariable('kpts', 'd', ('kpts', 'vector'))
        kgrid[:] = kpts
        qgrid = ncf.createVariable('qpts', 'd', ('qpts', 'vector'))
        qgrid[:] = qpts
        evalfkq = ncf.createVariable('evalfkq', 'd',
                                     ('kpts', 'qpts', 'nspin', 'bands'))
        # First (second) band index n (n') is the initial (final) state, i.e.,
        # Mkq(k,q,mode,spin,n,n') := < n',k+q | dV_q(mode) | n,k >
        MkqAbs = ncf.createVariable(
            'Mkqabs', 'd',
            ('kpts', 'qpts', 'modes', 'nspin', 'bands', 'bands'))
        GkqAbs = ncf.createVariable(
            'Gkqabs', 'd',
            ('kpts', 'qpts', 'modes', 'nspin', 'bands', 'bands'))
        ncf.sync()
        # Loop over k-points
        for i, k in enumerate(kpts):
            kpts[i] = k
            # Compute initial electronic states
            evi, eveci = SCDM.ComputeElectronStates(k, verbose=True)
            # Loop over q-points
            for j, q in enumerate(qpts):
                # Compute phonon modes
                hw, U = SCDM.ComputePhononModes_q(q, verbose=True)
                # Compute final electronic states
                evf, evecf = SCDM.ComputeElectronStates(k + q, verbose=True)
                evalfkq[i, j, :] = evf
                # Compute electron-phonon couplings
                m, g = SCDM.ComputeEPHcouplings_kq(
                    k, q)  # (modes,nspin,bands,bands)
                # Data to file
                # M (modes,spin,i,l) = m(modes,k,j) init(i,j) final(k,l)
                #                            0 1 2       0,1        0 1
                #                                ^-------^
                #                              ^----------------------^
                for ispin in range(SCDM.nspin):
                    evecfd = MM.dagger(evecf[ispin])  # (bands,bands)
                    M = N.tensordot(N.tensordot(m[:, ispin],
                                                eveci[ispin],
                                                axes=[2, 0]),
                                    evecfd,
                                    axes=[1, 1])
                    G = N.tensordot(N.tensordot(g[:, ispin],
                                                eveci[ispin],
                                                axes=[2, 0]),
                                    evecfd,
                                    axes=[1, 1])
                    MkqAbs[i, j, :, ispin] = N.absolute(M)
                    GkqAbs[i, j, :, ispin] = N.absolute(G)
                ncf.sync()
        ncf.close()
    return SCDM.Sym.path