def parse_cmdline_args(cmdlineargs=None): '''Parses command line arguments. Args: cmdlineargs: List of command line arguments. When None, arguments in sys.argv are parsed (Default: None). ''' parser = optparse.OptionParser(usage=USAGE) msg = 'file containing lattice vectors (overrides lattice vectors'\ ' in the geometry file)' parser.add_option( '-l', '--lattice-file', action='store', help=msg, dest='latticefile') msg = 'output file to store the resulting geometry' parser.add_option('-o', '--output', action='store', default='-', help=msg) options, args = parser.parse_args(cmdlineargs) if len(args) != 4: raise ScriptError('Incorrect number of arguments') infile = args[0] reps = [] for repstr in args[1:4]: try: reps.append(int(repstr)) except ValueError: msg = "Invalid repetition number '" + repstr + "'." raise ScriptError(msg) if not (reps[0] > 0 and reps[1] > 0 and reps[2] > 0): raise ScriptError('Repetition numbers must be greater than zero') return infile, (reps[0], reps[1], reps[2]), options
def repeatgen(infile, repeats, options): '''Repeats geometry from gen files. Args: infile: File containing the gen-formatted geometry. repeats: (n1, n2, n3) integer tuple containing the repetitions along each lattice vector. options: Options (e.g. as returned by the command line parser). ''' gen = Gen.fromfile(infile) geo = gen.geometry latvecs = geo.latvecs if options.latticefile: latvecs = np.fromfile(options.latticefile, sep=' ') if len(latvecs) != 9: msg = ('Invalid number of lattice vector components in ' + options.latticefile) raise ScriptError(msg) latvecs.shape = (3, 3) if latvecs is None: msg = 'No lattice vectors found (neither in gen nor in external file)' raise ScriptError(msg) newgeo = _repeatgeo(geo, latvecs, repeats) newgen = Gen(newgeo, gen.fractional) outfile = options.output if outfile == '-': outfile = sys.stdout newgen.tofile(outfile)
def parse_cmdline_args(cmdlineargs=None): '''Parses command line arguments. Args: cmdlineargs: List of command line arguments. When None, arguments in sys.argv are parsed. (Default: None) ''' parser = optparse.OptionParser(usage=USAGE) parser.add_option("-o", "--output", action="store", dest="output", default='-', help="override the name of the output file " "(use '-' for standard out") parser.add_option("-c", "--component", action="store", dest="component", type=str, default='I', help="strain type to apply " "posible values being xx, yy, zz, xz, xz, yz or I for " "isotropic (default value: I)") options, args = parser.parse_args(cmdlineargs) if options.component.lower() not in LABELS: msg = "Invalid strain component '" + options.component + "'" raise ScriptError(msg) if len(args) != 2: raise ScriptError("You must specify exactly two arguments " "(input file, strain).") infile = args[0] try: strain = float(args[1]) except ValueError: raise ScriptError("Invalid strain value '" + args[1] + "'") if options.component.lower() in ('xx', 'yy', 'zz', 'i') and strain <= -100: raise ScriptError("Compressive strain cannot exceed 100%") return infile, strain, options
def parse_cmdline_args(cmdlineargs=None): '''Parses command line arguments. Args: cmdlineargs: List of command line arguments. When None, arguments in sys.argv are parsed. (Default: None) ''' parser = argparse.ArgumentParser(description=USAGE) msg = "override the name of the output file (use '-' for standard out)" parser.add_argument("-o", "--output", action="store", dest="output", default='-', help=msg) msg = "strain type to apply posible values being xx, yy, zz, xz, xz, yz or"\ " I for isotropic (default value: I)" parser.add_argument("-c", "--component", action="store", dest="component", type=str, default='I', help=msg) msg = "input file name" parser.add_argument("infile", metavar="INPUT", help=msg) msg = "strain to apply as positive or negative percentage" parser.add_argument("strain", type=float, metavar="STRAIN", help=msg) args = parser.parse_args(cmdlineargs) if args.component.lower() not in LABELS: msg = "Invalid strain component '" + args.component + "'" raise ScriptError(msg) strain = args.strain if args.component.lower() in ('xx', 'yy', 'zz', 'i') and strain <= -100: raise ScriptError("Compressive strain cannot exceed 100%") return args, strain
def gen2cif(args): '''Converts the given INPUT file in DFTB+ GEN format to CIF format. Args: args: Namespace of command line arguments ''' infile = args.infile try: gen = Gen.fromfile(infile) except OSError: raise ScriptError('You must enter a valid path to the input file.') geometry = gen.geometry if not geometry.periodic: geometry.setlattice(args.cellsize * np.eye(3)) cif = Cif(gen.geometry) if args.output: if args.output == "-": outfile = sys.stdout else: outfile = args.output else: if infile.endswith(".gen"): outfile = infile[:-4] + ".cif" else: outfile = infile + ".cif" cif.tofile(outfile)
def xyz2gen(args): '''Converts the given INPUT file in XYZ format to DFTB+ GEN format. Args: args: Namespace of command line arguments ''' infile = args.infile try: xyz = Xyz.fromfile(infile) except OSError: raise ScriptError('You must enter a valid path to the input file.') geo = xyz.geometry if args.lattfile: fp = open(args.lattfile, "r") tmp = np.fromfile(fp, count=9, dtype=float, sep=" ") latvecs = tmp.reshape((3, 3)) fp.close() geo.setlattice(latvecs) gen = Gen(geo, fractional=args.fractional) if args.output: if args.output == "-": outfile = sys.stdout else: outfile = args.output else: if infile.endswith(".xyz"): outfile = infile[:-4] + ".gen" else: outfile = infile + ".gen" gen.tofile(outfile)
def gen2xyz(args): '''Converts the given INPUT file in DFTB+ GEN format to XYZ format. Args: args: Namespace of command line arguments ''' infile = args.infile try: gen = Gen.fromfile(infile) except OSError: raise ScriptError('You must enter a valid path to the input file.') xyz = Xyz(gen.geometry, args.comment) if args.output: if args.output == "-": outfile = sys.stdout else: outfile = args.output else: if infile.endswith(".gen"): outfile = infile[:-4] + ".xyz" else: outfile = infile + ".xyz" xyz.tofile(outfile) if gen.geometry.periodic and args.lattfile: fp = open(args.lattfile, "w") for vec in gen.geometry.latvecs: fp.write("{0:18.10E} {1:18.10E} {2:18.10E}\n".format(*vec)) fp.close()
def parse_cmdline_args(cmdlineargs=None): '''Parses command line arguments. Args: cmdlineargs: List of command line arguments. When None, arguments in sys.argv are parsed (Default: None). ''' parser = argparse.ArgumentParser(description=USAGE) msg = 'file containing lattice vectors (overrides lattice vectors'\ ' in the geometry file)' parser.add_argument('-l', '--lattice-file', action='store', help=msg, dest='latticefile') msg = 'output file to store the resulting geometry' parser.add_argument('-o', '--output', action='store', default='-', help=msg) msg = 'create a repeat geometry for phonon bandstructure' parser.add_argument('-p', '--phonons', action='store_true', default=False, help=msg) msg = 'input file name' parser.add_argument("infile", metavar="INPUT", help=msg) msg = 'repetition along the first lattice vector' parser.add_argument('n1', type=int, metavar="N1", help=msg) msg = 'repetition along the second lattice vector' parser.add_argument('n2', type=int, metavar="N2", help=msg) msg = 'repetition along the third lattice vector' parser.add_argument('n3', type=int, metavar="N3", help=msg) args = parser.parse_args(cmdlineargs) if not (args.n1 > 0 and args.n2 > 0 and args.n3 > 0): raise ScriptError('Repetition numbers must be greater than zero') if args.phonons: if (args.n1 % 2 == 0 or args.n2 % 2 == 0 or args.n3 % 2 == 0): raise ScriptError('Repetition numbers must be odd numbers') return args
def dp_bands(args): '''Converts band structure information of DFTB+ output to NXY-format. Args: args: Namespace of command line arguments ''' infile = args.infile outprefix = args.outprefix try: bandout = BandOut.fromfile(infile) except OSError: raise ScriptError('You must enter a valid path to the input file.') if args.spinsep: # Create filename for each spin-channel fnames = [ "{0}_s{1:d}.dat".format(outprefix, ispin) for ispin in range(1, bandout.nspin + 1) ] plotvals = bandout.eigvalarray[:, :, :, 0] else: # Put all eigenvalues in one channel, if no spin separation required eigvals = bandout.eigvalarray[:, :, :, 0] plotvals = np.empty( (1, eigvals.shape[1], eigvals.shape[2] * eigvals.shape[0]), dtype=float) for ispin in range(bandout.nspin): istart = ispin * bandout.nstate iend = (ispin + 1) * bandout.nstate plotvals[0, :, istart:iend] = eigvals[ispin, :, :] fnames = [ outprefix + "_tot.dat", ] if args.enum: formstr0 = "{0:d} " tmp = [ "{" + str(ii) + ":18.10E}" for ii in range(1, plotvals.shape[2] + 1) ] formstr = formstr0 + " ".join(tmp) + "\n" else: tmp = ["{" + str(ii) + ":18.10E}" for ii in range(plotvals.shape[2])] formstr = " ".join(tmp) + "\n" for iout, data in enumerate(plotvals): fp = open(fnames[iout], "w") for ik, kdata in enumerate(data): if args.enum: fp.write(formstr.format(ik + 1, *kdata)) else: fp.write(formstr.format(*kdata)) fp.close()
def repeatgen(args): '''Repeats geometry from gen files. Args: args: Namespace of command line arguments ''' infile = args.infile repeats = [args.n1, args.n2, args.n3] try: gen = Gen.fromfile(infile) except OSError: raise ScriptError('You must enter a valid path to the input file.') geo = gen.geometry latvecs = geo.latvecs if args.latticefile: latvecs = np.fromfile(args.latticefile, sep=' ') if len(latvecs) != 9: msg = ('Invalid number of lattice vector components in ' + args.latticefile) raise ScriptError(msg) latvecs.shape = (3, 3) if latvecs is None: msg = 'No lattice vectors found (neither in gen nor in external file)' raise ScriptError(msg) if args.phonons: newgeo = _repeatgeo2(geo, latvecs, repeats) else: newgeo = _repeatgeo(geo, latvecs, repeats) newgen = Gen(newgeo, gen.fractional) outfile = args.output if outfile == '-': outfile = sys.stdout newgen.tofile(outfile)
def straingen(args, strain): '''Strains a geometry from a gen file. Args: args: Namespace of command line arguments strain: Strain to apply ''' infile = args.infile try: gen = Gen.fromfile(infile) except OSError: raise ScriptError('You must enter a valid path to the input file.') geometry = gen.geometry strainmtx = np.zeros((3, 3), dtype=float) for jj in range(3): strainmtx[jj][jj] = 1.0 components = LABELS[args.component.lower()] for ii in components: strainmtx[VOIGHT[ii][0]][VOIGHT[ii][1]] += 0.005 * strain strainmtx[VOIGHT[ii][1]][VOIGHT[ii][0]] += 0.005 * strain if geometry.latvecs is not None: geometry.latvecs = np.dot(geometry.latvecs, strainmtx) geometry.coords = np.dot(geometry.coords, strainmtx) if args.output: if args.output == "-": outfile = sys.stdout else: outfile = args.output else: if infile.endswith(".gen"): outfile = infile else: outfile = infile + ".gen" gen = Gen(geometry, fractional=gen.fractional) gen.tofile(outfile)
def parse_arguments(cmdlineargs=None): '''Parses command line arguments. Args: cmdlineargs: List of command line arguments. When None, arguments in sys.argv are parsed (Default: None). ''' parser = argparse.ArgumentParser(description=USAGE) msg = "grid separation (default: {0:.2f})".format(DEFAULT_GRID_SEPARATION) parser.add_argument("-g", "--gridres", type=float, dest="gridres", default=DEFAULT_GRID_SEPARATION, help=msg) msg = "create pdos or occupation weighted dos" parser.add_argument("-w", "--weight-occ", action="store_true", dest="occweight", default=False, help=msg) msg = "broadening function (default: gauss)" parser.add_argument("-f", "--broadening-function", dest="broadening", choices=BROADENING_FUNCTIONS, default=GAUSS_BROADENING, help=msg) msg = "order of mp function" parser.add_argument("-o", "--mporder", type=int, dest="mporder", help=msg) msg = "broadening width sigma (default: gauss {:.2f}, fermi {:.2f}, "\ "mp {:.2f})".format(DEFAULT_WIDTHS[GAUSS_BROADENING], DEFAULT_WIDTHS[FERMI_BROADENING], DEFAULT_WIDTHS[MP_BROADENING]) parser.add_argument("-b", "--broadening-width", type=float, metavar="WIDTH", dest="broadwidth", help=msg, default=-1.0) msg = "number of sigmas after which the broadening function is considered "\ "to be zero (default: gauss {0:.2f}, fermi {1:.2f}, mp {1:.2f})"\ .format(DEFAULT_RANGES[GAUSS_BROADENING], DEFAULT_RANGES[FERMI_BROADENING], DEFAULT_RANGES[MP_BROADENING]) parser.add_argument("-s", "--sigma-range", type=float, metavar="RANGE", dest="broadrange", default=-1.0, help=msg) msg = "turn on verbose operation" parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False, help=msg) msg = "input file name" parser.add_argument("infile", metavar="INPUT", help=msg) msg = "output file name" parser.add_argument("outfile", metavar="OUTPUT", help=msg) args = parser.parse_args(cmdlineargs) if args.mporder: if args.broadening != 'mp': msg = '--mporder can only be set when --broadening-function=mp.' raise ScriptError(msg) if args.mporder < 1: raise ScriptError(msg) infile = args.infile outfile = args.outfile broadening = args.broadening if args.broadwidth < 0.0: sigma = DEFAULT_WIDTHS[broadening] else: sigma = args.broadwidth if args.broadrange < 0.0: sigmarange = DEFAULT_RANGES[broadening] else: sigmarange = args.broadrange return args, broadening, sigma, sigmarange, infile, outfile
def dp_dos(args, broadening, sigma, sigmarange, infile, outfile): '''convolves the eigenlevels with a broadening function to produce nice DOS/PDOS curves. Args: args: Containing the obtained parsed arguments. broadening: Specified broadening width sigma. sigma: Broadening width sigmarange: number of sigmas after which the broadening function is considered to be zero infile: File containing the DFTB+ band structure information. outfile: Output file name ''' try: bandout = BandOut.fromfile(infile) except OSError: raise ScriptError('You must enter a valid path to the input file.') eigvals = bandout.eigvalarray if not args.occweight: eigvals[:, :, :, 1] = 1.0 if broadening == FERMI_BROADENING: aa = 0.5 / sigma bb = 1.0 / sigma broadening_function = lambda x: 1.0 / (1.0 + np.cosh(bb * x)) elif broadening == GAUSS_BROADENING: aa = 1.0 / (sigma * np.sqrt(np.pi)) bb = -1.0 / sigma**2 broadening_function = lambda x: np.exp(bb * x * x) else: # Methfessel-Paxton aa = 1.0 / sigma bb = 1.0 / sigma order = args.mporder + 1 # order = 0 => Gaussian coefs = np.zeros(2 * order, dtype=float) for ii in range(order): coefs[2*ii] = ((-1)**ii) / (math.factorial(ii) * (4**ii) \ * math.sqrt(math.pi)) broadening_function = lambda x: H.hermval(bb * x, coefs) \ * np.exp(-x * x * bb * bb) dsigma = sigmarange * sigma gridres = args.gridres minval = np.min(eigvals[:, :, :, 0]) - dsigma maxval = np.max(eigvals[:, :, :, 0]) + dsigma if args.verbose: if broadening == GAUSS_BROADENING: print("Gaussian broadening") elif broadening == FERMI_BROADENING: print("Fermi-function compatible broadening") else: print("Methfessel-Paxton compatible broadening") print("Broadening by {0:.2f} eV".format(sigma)) if args.occweight: print("Weighting DOS by second column of data") print("Plotting from {0:.2f} eV to {1:.2f} eV".format(minval, maxval)) print("Sigma window is : {0:.2f} eV with a grid resolution of {1:.2f}". format(dsigma, gridres)) # First and last grid points, x-grid xmin = np.floor((minval) / gridres) * gridres xmax = np.ceil((maxval) / gridres) * gridres xvals = np.arange(xmin, xmax + gridres, gridres, dtype=float) nval = len(xvals) # Empty container for y-values yvals = np.zeros((bandout.nspin, nval), dtype=float) # Calculate broadened values around each state on the grid. for ispin in range(bandout.nspin): for ik in range(bandout.nkpt): prefac = aa * bandout.kweights[ispin, ik] for eigval, occ in eigvals[ispin, ik]: # Grid points for the current curve (first, last) ilower = int(np.floor((eigval - dsigma - xmin) / gridres)) iupper = int(np.ceil((eigval + dsigma - xmin) / gridres)) dx = eigval - xvals[ilower:iupper + 1] yvals[ispin, ilower:iupper + 1] += ((prefac * occ) * broadening_function(dx)) # Write resulting DOS fp = open(outfile, "w") if bandout.nspin == 1: for xx, yy in zip(xvals, yvals[0]): fp.write("{0:18.10E} {1:18.10E}\n".format(xx, yy)) else: ytotal = np.sum(yvals, axis=0) formstr0 = "{0:18.10E} " tmp = [ "{" + "{0:d}".format(ii) + ":18.10E}" for ii in range(1, bandout.nspin + 2) ] formstr = formstr0 + " ".join(tmp) + "\n" nvals = len(xvals) for ii in range(nvals): fp.write(formstr.format(xvals[ii], ytotal[ii], *yvals[:, ii])) fp.close()