def read(self, filename, format='pwinput'): """Load structure from a file, any original data become lost. l filename -- file to be loaded format -- structure formats 'pwinput' ( pw.x input, default), 'pwoutput' (pw.x output), 'bratoms', 'cif', 'discus', 'pdb', 'pdffit', 'rawxyz', 'xcfg', 'xyz' Return instance of data Parser used to process file. This can be inspected for information related to particular format. """ from qecalc.qetask.qeparser.qestructureparser import parser_index if self._qeInput == None: from qecalc.qetask.qeparser.pwinput import PWInput self._qeInput = PWInput() self._qeInput.structure = self #self._qeInput.parse() if format in parser_index: module = __import__("qestructureparser.P_" + format, globals(), \ locals(), ['P_' + format], -1) parser = module.getParser(self._qeInput) new_structure = parser.parse(filename) else: diffpyStruct = Structure() parser = diffpyStruct.read(filename, format=format) new_structure = QEStructure(qeInput=self._qeInput) new_structure._setStructureFromDiffpyStructure(diffpyStruct, \ massList = [], psList = [], ibrav = 0) new_structure.lattice._qeInput.update(forceUpdate=True) self.__Init(new_structure) return parser
def __init__(self, ibrav = 1,a = 1. ,b = 1.,c = 1., cBC = 0.,cAC = 0. ,cAB = 0., base = None, lattice = None, qeInput = None ): self.formatString = '%# .8f %# .8f %# .8f' self._qeInput = qeInput #self._qeInput = None self._type = 'celldm' # Lattice container class, used for lattice operations self.__primitiveLattice = Lattice() # Lattice vectors in bohr or angstrom: self._base = None # initialize the lattice if there is enough information if ibrav > 0 and base != None: self.setLatticeFromQEVectors(ibrav, base) else: self.setLattice(ibrav ,a ,b , c, cBC ,cAC ,cAB, base) # copy constructor: if isinstance(ibrav, QELattice) or lattice != None: if lattice.ibrav > 0: self.setLattice( ibrav = lattice.ibrav, a = lattice.a, \ b = lattice.b, c = lattice.c, cBC = lattice.cBC, cAC = lattice.cAC,\ cAB = lattice.cAB) else: self.setLattice( ibrav = lattice.ibrav, a = lattice.a, \ base = lattice.base ) # copy input: from pwinput import PWInput self._qeInput = PWInput() self._qeInput.readString( lattice._qeInput.toString() )
def __init__(self, atoms=[], lattice=None, filename=None, qeInput=None): """ atoms -- list of QEAtom atom instances or a QEStructure object lattice -- QELattice object filename -- filename QE input file qeInput -- pointer to a PWInput parsing object. If not None, its PWInput.structure and PWInput.structure.lattice will be reset to the current instance of the structure """ Structure.__init__(self) self.formatString = '%# .8f %# .8f %# .8f' self._atomicPositionsType = 'crystal' self._qeInput = qeInput self.lattice = QELattice() self.lattice._qeInput = self._qeInput if lattice != None: if self.lattice._qeInput != None: self._qeInput = self.lattice._qeInput else: self.lattice._qeInput = self._qeInput self.lattice = QELattice(lattice=lattice) # CP and PW inputs are compatible from pwinput import PWInput from cpinput import CPInput if isinstance(atoms, PWInput) or isinstance(atoms, CPInput): qeInput = atoms elif isinstance(atoms, QEStructure): stru = atoms self.__dict__.update(stru.__dict__) # deep copy of the lattice will deep copy PWInput as well self.lattice = QELattice(lattice=stru.lattice) self._qeInput = self.lattice._qeInput self[:] = stru else: if self.lattice == None: raise "Lattice must be provided" self[:] = atoms if filename != None: qeInput = PWInput(filename=filename) qeInput.parse() self.parseInput(qeInput) if qeInput != None: self.lattice._qeInput = qeInput self._qeInput = qeInput if self.lattice._qeInput != None: self.lattice._qeInput.structure = self self.lattice._qeInput.structure.lattice = self.lattice return
def save(self, filename=None): """Writes/updates structure into PW config file, if the file does not exist, new one will be created""" from os.path import exists from qecalc.qetask.qeparser.pwinput import PWInput if filename != None: if not exists(filename): f = open(filename, 'w') qeInput = PWInput() qeInput.readFile(filename) else: qeInput = self._qeInput self._qeInput.update(qeInput=qeInput, forceUpdate=True) qeInput.save()
def __init__(self, atype=None, xyz=None, mass = None, \ potential = None, lattice=None, optConstraint = None, name=None): """Create atom of a specified type at given lattice coordinates. Atom(a) creates a copy of Atom instance a. atype -- element symbol string or Atom instance xyz -- fractional(crystal) coordinates name -- atom label mass -- atom mass potential -- pseudopotential file name lattice -- QE coordinate system for fractional coordinates optConstraint -- list of up to three constraints for each coordinate for QE geometry optimization (0 or 1) """ # declare data members self.element = None self._xyz = numpy.zeros(3, dtype=float) self.name = '' self._mass = 0 self._potential = '' self.lattice = QELattice() from pwinput import PWInput self.lattice._qeInput = PWInput() self._optConstraint = numpy.array([], dtype = int) # assign them as needed if isinstance(atype, QEAtom): atype_dup = atype.__copy__() self.__dict__.update(atype_dup.__dict__) else: self.element = atype # take care of remaining arguments if xyz is not None: self._xyz[:] = xyz if name is not None: self.name = name if mass is not None: self._mass = mass if potential is not None: self._potential = potential if lattice is not None: self.lattice = lattice if optConstraint is not None: self._optConstraint = \ numpy.array(optConstraint, dtype = int) return
def make_fd_supercell(pw: PWInput, q_cry, ucart, skip_minkowski=False): import copy from math import floor, ceil from itertools import product """ Generate nondiagonal supercell with finite displacements qe_input: a Pwscf() instance of an input file q_cry: perturbation crystal momentum, (m1/n1, m2/n2, m3/n3). ucart: displacement of atoms in the unit cell in cartesian alat units """ # find fractional representation of q tol = 1E-10 mlist = [] nlist = [] for i in range(3): found = False for n in range(1, 101): m = round(abs(q_cry[i]) * n) if abs(abs(q_cry[i]) - m / n) < tol: mlist.append(m) nlist.append(n) found = True break if not found: print(f"Unable to find fractional representation of q = {q[i]}") return None s_new = find_nondiagonal(mlist, nlist) multiplier = s_new[0, 0] * s_new[1, 1] * s_new[2, 2] cell_new = np.einsum('ij,xj->xi', s_new, pw.cell) nat_new = pw.nat * multiplier # Minkowski reduction of lattice vector: linear combination to make them # as short as possible if skip_minkowski: cell_red = np.copy(cell_new) else: cell_red = minkowski_reduce(cell_new) cell_cell = np.einsum('xi,xj->ij', pw.cell, pw.cell) redcell_cell = np.einsum('xi,xj->ij', cell_red, pw.cell) s_red = redcell_cell @ np.linalg.inv(cell_cell) s_red = np.rint(s_red) atoms_name_new, atoms_cart_new = atom_supercell(pw, s_new) # move atoms to [0, 1)^3 unit cell of cell_red atoms_cry_new = np.linalg.inv(cell_red) @ atoms_cart_new for iat in range(nat_new): for idir in range(3): atoms_cart_new[:, iat] -= floor( atoms_cry_new[idir, iat]) * cell_red[:, idir] # apply displacements s_diag = np.diag(s_new) for nz, ny, nx in product(range(s_diag[2]), range(s_diag[1]), range(s_diag[0])): icell = nx + ny * s_diag[0] + nz * s_diag[0] * s_diag[1] phase = np.exp(2j * np.pi * sum([x * y for x, y in zip(q_cry, (nx, ny, nz))])) for iat in range(pw.nat): atoms_cart_new[:, icell * pw.nat + iat] += (ucart[:, iat] * phase).real pw_super = PWInput(nat=nat_new, cell=cell_red, atoms_name=atoms_name_new, atoms_cart=atoms_cart_new, input_cards=copy.deepcopy(pw.input_cards), input_namelists=copy.deepcopy(pw.input_namelists)) if 'ATOMIC_POSITIONS' in pw_super.input_cards.keys(): input_atmpos = ['ATOMIC_POSITIONS alat \n'] for iat in range(pw_super.nat): line = ( f" {atoms_name_new[iat]:4s} {atoms_cart_new[0, iat]:18.12f}" f" {atoms_cart_new[1, iat]:18.12f} {atoms_cart_new[2, iat]:18.12f}\n" ) input_atmpos.append(line) pw_super.input_cards['ATOMIC_POSITIONS'] = input_atmpos if 'CELL_PARAMETERS' in pw_super.input_cards.keys(): input_cell = ['CELL_PARAMETERS alat\n'] for i in range(3): line = (f" {pw_super.cell[0,i]:18.12f} {pw_super.cell[1,i]:18.12f}" f" {pw_super.cell[2,i]:18.12f}\n") input_cell.append(line) pw_super.input_cards['CELL_PARAMETERS'] = input_cell if 'K_POINTS' in pw_super.input_cards.keys(): nks = np.array( [int(x) for x in pw.input_cards['K_POINTS'][1].split()[:3]]) dks = np.linalg.norm(lat_to_reclat(pw.cell), axis=0) / nks nks_new = np.linalg.norm(lat_to_reclat(pw_super.cell), axis=0) / min(dks) nks_new = [ceil(x - 1E-4) for x in nks_new] # minus 1E-3 to avoid floating point truncation error (of the input file) # If original nk is 8, nks_new can become 8.00001 due to small digits in # the input file. If we ceil this, it becomes 9. We want it to be 8, so # we subtract a small value, 1E-4, from nks_new. input_kpt = ['K_POINTS automatic\n'] input_kpt.append( f" {nks_new[0]:3d}{nks_new[1]:3d}{nks_new[2]:3d} 0 0 0") pw_super.input_cards['K_POINTS'] = input_kpt # update namelists try: pw_super.input_namelists['SYSTEM']['ibrav'] = "0" pw_super.input_namelists['SYSTEM']['nat'] = f"{pw_super.nat}" except KeyError as e: print("KeyError in pw_super.input_namelists, keyword {e.args[0]}") return pw_super