def __init__(self, atoms, restart, logfile, trajectory, master=None): """Structure optimizer object. Parameters: atoms: Atoms object The Atoms object to relax. restart: str Filename for restart file. Default value is *None*. logfile: file object or str If *logfile* is a string, a file with that name will be opened. Use '-' for stdout. trajectory: Trajectory object or str Attach trajectory object. If *trajectory* is a string a Trajectory will be constructed. Use *None* for no trajectory. master: boolean Defaults to None, which causes only rank 0 to save files. If set to true, this rank will save files. """ Dynamics.__init__(self, atoms, logfile, trajectory, master) self.restart = restart if restart is None or not isfile(restart): self.initialize() else: self.read() barrier()
def _open_append(self, atoms): if not os.path.exists(self.filename): # OK, no old bundle. Open as for write instead. barrier() self._open_write(atoms, False) return if not self.is_bundle(self.filename): raise IOError('Not a BundleTrajectory: ' + self.filename) self.state = 'read' metadata = self._read_metadata() self.metadata = metadata if metadata['version'] != self.version: raise NotImplementedError( 'Cannot append to a BundleTrajectory version ' '%s (supported version is %s)' % (str(metadata['version']), str(self.version))) if metadata['subtype'] not in ('normal', 'split'): raise NotImplementedError( 'This version of ASE cannot append to BundleTrajectory ' 'subtype ' + metadata['subtype']) self.subtype = metadata['subtype'] if metadata['backend'] == 'ulm': self.singleprecision = metadata['ulm.singleprecision'] self._set_backend(metadata['backend']) self.nframes = self._read_nframes() self._open_log() self.log('Opening "%s" in append mode (nframes=%i)' % (self.filename, self.nframes)) self.state = 'write' self.atoms = atoms
def open(self, filename, mode): """Opens the file. For internal use only. """ self.fd = filename if mode == 'r': if isinstance(filename, str): self.fd = open(filename, 'rb') self.read_header() elif mode == 'a': exists = True if isinstance(filename, str): exists = os.path.isfile(filename) if exists: self.fd = open(filename, 'rb') self.read_header() self.fd.close() barrier() if self.master: self.fd = open(filename, 'ab+') else: self.fd = devnull elif mode == 'w': if self.master: if isinstance(filename, str): if self.backup and os.path.isfile(filename): os.rename(filename, filename + '.bak') self.fd = open(filename, 'wb') else: self.fd = devnull else: raise ValueError('mode must be "r", "w" or "a".')
def do_calculations(self, formulas): """Perform calculation on molecules, write results to .gpw files.""" atoms = {} for formula in formulas: for symbol in string2symbols(formula.split('_')[0]): atoms[symbol] = None formulas = formulas + atoms.keys() for formula in formulas: if path.isfile(formula + '.gpw'): continue barrier() open(formula + '.gpw', 'w') s = molecule(formula) s.center(vacuum=self.vacuum) cell = s.get_cell() h = self.h s.set_cell((cell / (4 * h)).round() * 4 * h) s.center() calc = GPAW(h=h, xc=self.xc, eigensolver=self.eigensolver, setups=self.setups, basis=self.basis, fixmom=True, txt=formula + '.txt') if len(s) == 1: calc.set(hund=True) s.set_calculator(calc) if formula == 'BeH': calc.initialize(s) calc.nuclei[0].f_si = [(1, 0, 0.5, 0, 0), (0.5, 0, 0, 0, 0)] if formula in ['NO', 'ClO', 'CH']: s.positions[:, 1] += h * 1.5 try: energy = s.get_potential_energy() except (RuntimeError, ConvergenceError): if rank == 0: print >> sys.stderr, 'Error in', formula traceback.print_exc(file=sys.stderr) else: print >> self.txt, formula, repr(energy) self.txt.flush() calc.write(formula) if formula in diatomic and self.calculate_dimer_bond_lengths: traj = PickleTrajectory(formula + '.traj', 'w') d = diatomic[formula][1] for x in range(-2, 3): s.set_distance(0, 1, d * (1.0 + x * 0.02)) traj.write(s)
def _rename_bundle(self, oldname, newname): "Rename a bundle. Used to create the .bak" if self.master: os.rename(oldname, newname) else: while os.path.exists(oldname): time.sleep(1) # The master may not proceed before all tasks have seen the # directory go away. barrier()
def is_empty_bundle(filename): """Check if a filename is an empty bundle. Assumes that it is a bundle.""" if not os.listdir(filename): return True # Empty folders are empty bundles. with open(os.path.join(filename, 'frames'), 'rb') as fd: nframes = int(fd.read()) # File may be removed by the master immediately after this. barrier() return nframes == 0
def __init__(self, atoms, restart, logfile, trajectory, master=None, force_consistent=False): """Structure optimizer object. Parameters: atoms: Atoms object The Atoms object to relax. restart: str Filename for restart file. Default value is *None*. logfile: file object or str If *logfile* is a string, a file with that name will be opened. Use '-' for stdout. trajectory: Trajectory object or str Attach trajectory object. If *trajectory* is a string a Trajectory will be constructed. Use *None* for no trajectory. master: boolean Defaults to None, which causes only rank 0 to save files. If set to true, this rank will save files. force_consistent: boolean or None Use force-consistent energy calls (as opposed to the energy extrapolated to 0 K). If force_consistent=None, uses force-consistent energies if available in the calculator, but falls back to force_consistent=False if not. """ Dynamics.__init__(self, atoms, logfile, trajectory, master) self.force_consistent = force_consistent if self.force_consistent is None: self.set_force_consistent() self.restart = restart # initialize attribute self.fmax = None if restart is None or not isfile(restart): self.initialize() else: self.read() barrier()
def run(self): """Run the vibration calculations. This will calculate the forces for 6 displacements per atom ±x, ±y, ±z. Only those calculations that are not already done will be started. Be aware that an interrupted calculation may produce an empty file (ending with .pckl), which must be deleted before restarting the job. Otherwise the forces will not be calculated for that displacement.""" if not isfile(self.name + '.eq.pckl'): barrier() if rank == 0: fd = open(self.name + '.eq.pckl', 'w') forces = self.atoms.get_forces() if self.ir: dipole = self.calc.get_dipole_moment(self.atoms) if rank == 0: if self.ir: pickle.dump([forces, dipole], fd) else: pickle.dump(forces, fd) fd.close() p = self.atoms.positions.copy() for a in self.indices: for i in range(3): for sign in [-1, 1]: for ndis in range(1, self.nfree/2+1): filename = '%s.%d%s%s.pckl' % (self.name, a, 'xyz'[i], ndis*' +-'[sign]) if isfile(filename): continue barrier() if rank == 0: fd = open(filename, 'w') self.atoms.positions[a, i] = p[a, i] + ndis * sign * self.delta forces = self.atoms.get_forces() if self.ir: dipole = self.calc.get_dipole_moment(self.atoms) if rank == 0: if self.ir: pickle.dump([forces, dipole], fd) else: pickle.dump(forces, fd) fd.close() self.atoms.positions[a, i] = p[a, i] self.atoms.set_positions(p)
def run(self): """Run the vibration calculations. This will calculate the forces for 6 displacements per atom ±x, ±y, ±z. Only those calculations that are not already done will be started. Be aware that an interrupted calculation may produce an empty file (ending with .pckl), which must be deleted before restarting the job. Otherwise the forces will not be calculated for that displacement.""" p = self.atoms.positions.copy() # Get forces and dipole moment at zero displacement filename = '%s.static.pckl' % self.name if not isfile(filename): if rank == 0: fd = open(filename, 'w') print '%s started.' % filename forces = self.atoms.get_forces() dipole = self.calc.get_dipole_moment(self.atoms) barrier() if rank == 0: pickle.dump([forces, dipole], fd) fd.close() print '%s done.' % filename # Get forces and dipole moments for the finite displacements for a in self.indices: for i in range(3): for sign in [-1, 1]: for n in range(1, self.nfree + 1): filename = '%s.%d%s%s.pckl' % (self.name, a, 'xyz'[i], n * ' +-'[sign]) if isfile(filename): continue if rank == 0: fd = open(filename, 'w') self.atoms.positions[a, i] = p[a, i] + sign * n * self.delta forces = self.atoms.get_forces() dipole = self.calc.get_dipole_moment(self.atoms) barrier() if rank == 0: pickle.dump([forces, dipole], fd) fd.close() self.atoms.positions[a, i] = p[a, i] self.atoms.set_positions(p)
def test(): # Generate setup symbol = 'He' if rank == 0: g = Generator(symbol, 'revPBE', scalarrel=True, nofiles=True) g.run(exx=True, **parameters[symbol]) barrier() setup_paths.insert(0, '.') a = 7.5 * Bohr n = 16 atoms = Atoms([Atom('He', (0.0, 0.0, 0.0))], cell=(a, a, a), pbc=True) calc = Calculator(gpts=(n, n, n), nbands=1, xc='revPBE') atoms.set_calculator(calc) e1 = atoms.get_potential_energy() calc.write('He') e2 = e1 + calc.get_xc_difference('vdWDF') print e1, e2
def run(self): """Run the vibration calculations. This will calculate the forces for 6 displacements per atom ±x, ±y, ±z. Only those calculations that are not already done will be started. Be aware that an interrupted calculation may produce an empty file (ending with .pckl), which must be deleted before restarting the job. Otherwise the forces will not be calculated for that displacement.""" p = self.atoms.positions.copy() # Get forces and dipole moment at zero displacement filename = '%s.static.pckl' % self.name if not isfile(filename): if rank == 0: fd = open(filename, 'w') print '%s started.' % filename forces = self.atoms.get_forces() dipole = self.calc.get_dipole_moment(self.atoms) barrier() if rank == 0: pickle.dump([forces, dipole], fd) fd.close() print '%s done.' % filename # Get forces and dipole moments for the finite displacements for a in self.indices: for i in range(3): for sign in [-1, 1]: for n in range(1, self.nfree+1): filename = '%s.%d%s%s.pckl' % (self.name, a, 'xyz'[i], n*' +-'[sign]) if isfile(filename): continue if rank == 0: fd = open(filename, 'w') self.atoms.positions[a, i] = p[a, i]+sign*n*self.delta forces = self.atoms.get_forces() dipole = self.calc.get_dipole_moment(self.atoms) barrier() if rank == 0: pickle.dump([forces, dipole], fd) fd.close() self.atoms.positions[a, i] = p[a, i] self.atoms.set_positions(p)
def _make_bundledir(self, filename): """Make the main bundle directory. Since all MPI tasks might write to it, all tasks must wait for the directory to appear. """ self.log('Making directory ' + filename) assert not os.path.isdir(filename) barrier() if self.master: os.mkdir(filename) else: i = 0 while not os.path.isdir(filename): time.sleep(1) i += 1 if i > 10: self.log('Waiting %d seconds for %s to appear!' % (i, filename))
def open(self, filename, mode): """Opens the file. For internal use only. """ self.fd = filename if mode == 'r': if isinstance(filename, basestring): self.fd = open(filename, 'rb') self.read_header() elif mode == 'a': exists = True if isinstance(filename, basestring): exists = os.path.isfile(filename) if exists: exists = os.path.getsize(filename) > 0 if exists: self.fd = open(filename, 'rb') self.read_header() self.fd.close() barrier() if self.master: self.fd = open(filename, 'ab+') else: self.fd = devnull elif mode == 'w': if self.master: if isinstance(filename, basestring): if self.backup and os.path.isfile(filename): try: os.rename(filename, filename + '.bak') except WindowsError as e: # this must run on Win only! Not atomic! if e.errno != errno.EEXIST: raise os.unlink(filename + '.bak') os.rename(filename, filename + '.bak') self.fd = open(filename, 'wb') else: self.fd = devnull else: raise ValueError('mode must be "r", "w" or "a".')
def __init__(self, atoms, restart, logfile, trajectory, master=None, force_consistent=False): """Structure optimizer object. Parameters: atoms: Atoms object The Atoms object to relax. restart: str Filename for restart file. Default value is *None*. logfile: file object or str If *logfile* is a string, a file with that name will be opened. Use '-' for stdout. trajectory: Trajectory object or str Attach trajectory object. If *trajectory* is a string a Trajectory will be constructed. Use *None* for no trajectory. master: boolean Defaults to None, which causes only rank 0 to save files. If set to true, this rank will save files. force_consistent: boolean or None Use force-consistent energy calls (as opposed to the energy extrapolated to 0 K). If force_consistent=None, uses force-consistent energies if available in the calculator, but falls back to force_consistent=False if not. """ Dynamics.__init__(self, atoms, logfile, trajectory, master) self.force_consistent = force_consistent self.restart = restart if restart is None or not isfile(restart): self.initialize() else: self.read() barrier()
def open(self, filename, mode): """Opens the file. For internal use only. """ self.fd = filename if mode == "r": if isinstance(filename, str): self.fd = open(filename, "rb") self.read_header() elif mode == "a": exists = True if isinstance(filename, str): exists = os.path.isfile(filename) if exists: exists = os.path.getsize(filename) > 0 if exists: self.fd = open(filename, "rb") self.read_header() self.fd.close() barrier() if self.master: self.fd = open(filename, "ab+") else: self.fd = devnull elif mode == "w": if self.master: if isinstance(filename, str): if self.backup and os.path.isfile(filename): try: os.rename(filename, filename + ".bak") except WindowsError, e: # this must run on Win only! Not atomic! if e.errno != errno.EEXIST: raise os.unlink(filename + ".bak") os.rename(filename, filename + ".bak") self.fd = open(filename, "wb") else: self.fd = devnull
def delete_bundle(cls, filename): "Deletes a bundle." if world.rank == 0: # Only the master deletes if not cls.is_bundle(filename, allowempty=True): raise IOError( 'Cannot remove "%s" as it is not a bundle trajectory.' % (filename, )) if os.path.islink(filename): # A symbolic link to a bundle. Only remove the link. os.remove(filename) else: # A real bundle shutil.rmtree(filename) else: # All other tasks wait for the directory to go away. while os.path.exists(filename): time.sleep(1) # The master may not proceed before all tasks have seen the # directory go away, as it might otherwise create a new bundle # with the same name, fooling the wait loop in _make_bundledir. barrier()
def __init__(self, atoms, restart, logfile, trajectory): """Structure optimizer object. atoms: Atoms object The Atoms object to relax. restart: str Filename for restart file. Default value is *None*. logfile: file object or str If *logfile* is a string, a file with that name will be opened. Use '-' for stdout. trajectory: Trajectory object or str Attach trajectory object. If *trajectory* is a string a PickleTrajectory will be constructed. Use *None* for no trajectory. """ Dynamics.__init__(self, atoms, logfile, trajectory) self.restart = restart if restart is None or not isfile(restart): self.initialize() else: self.read() barrier()
def run(self): """Run the total energy calculations for the required displacements. This will calculate the forces for 6 displacements per atom, +-x, +-y, and +-z. Only those calculations that are not already done will be started. Be aware that an interrupted calculation may produce an empty file (ending with .pckl), which must be deleted before restarting the job. Otherwise the forces will not be calculated for that displacement. """ # Atoms in the supercell -- repeated in the lattice vector directions # beginning with the last atoms_lmn = self.atoms * self.N_c # Set calculator if provided assert self.calc is not None, "Provide calculator in __init__ method" atoms_lmn.set_calculator(self.calc) # Calculate forces in equilibrium structure filename = self.name + '.eq.pckl' if not isfile(filename): # Wait for all ranks to enter barrier() # Create file if rank == 0: fd = open(filename, 'w') fd.close() # Call derived class implementation of __call__ output = self.__call__(atoms_lmn) # Write output to file if rank == 0: fd = open(filename, 'w') pickle.dump(output, fd) sys.stdout.write('Writing %s\n' % filename) fd.close() sys.stdout.flush() # Positions of atoms to be displaced in the small unit cell pos = self.atoms.positions.copy() # Loop over all displacements and calculate forces for a in self.indices: for i in range(3): for sign in [-1, 1]: # Filename for atomic displacement filename = '%s.%d%s%s.pckl' % \ (self.name, a, 'xyz'[i], ' +-'[sign]) # Wait for ranks before checking for file # barrier() if isfile(filename): # Skip if already done continue # Wait for ranks barrier() if rank == 0: fd = open(filename, 'w') fd.close() # Update atomic positions and calculate forces atoms_lmn.positions[a, i] = \ pos[a, i] + sign * self.delta # Call derived class implementation of __call__ output = self.__call__(atoms_lmn) # Write output to file if rank == 0: fd = open(filename, 'w') pickle.dump(output, fd) sys.stdout.write('Writing %s\n' % filename) fd.close() sys.stdout.flush() # Return to initial positions atoms_lmn.positions[a, i] = pos[a, i]
def run(self): """Run the calculations for the required displacements. This will do a calculation for 6 displacements per atom, +-x, +-y, and +-z. Only those calculations that are not already done will be started. Be aware that an interrupted calculation may produce an empty file (ending with .pckl), which must be deleted before restarting the job. Otherwise the calculation for that displacement will not be done. """ # Atoms in the supercell -- repeated in the lattice vector directions # beginning with the last atoms_N = self.atoms * self.N_c # Set calculator if provided assert self.calc is not None, "Provide calculator in __init__ method" atoms_N.set_calculator(self.calc) # Do calculation on equilibrium structure filename = self.name + '.eq.pckl' if not isfile(filename): # Wait for all ranks to enter barrier() # Create file if rank == 0: fd = open(filename, 'w') fd.close() # Call derived class implementation of __call__ output = self.__call__(atoms_N) # Write output to file if rank == 0: fd = open(filename, 'w') pickle.dump(output, fd) sys.stdout.write('Writing %s\n' % filename) fd.close() sys.stdout.flush() # Positions of atoms to be displaced in the reference cell natoms = len(self.atoms) offset = natoms * self.offset pos = atoms_N.positions[offset: offset + natoms].copy() # Loop over all displacements for a in self.indices: for i in range(3): for sign in [-1, 1]: # Filename for atomic displacement filename = '%s.%d%s%s.pckl' % \ (self.name, a, 'xyz'[i], ' +-'[sign]) # Wait for ranks before checking for file # barrier() if isfile(filename): # Skip if already done continue # Wait for ranks barrier() if rank == 0: fd = open(filename, 'w') fd.close() # Update atomic positions atoms_N.positions[offset + a, i] = \ pos[a, i] + sign * self.delta # Call derived class implementation of __call__ output = self.__call__(atoms_N) # Write output to file if rank == 0: fd = open(filename, 'w') pickle.dump(output, fd) sys.stdout.write('Writing %s\n' % filename) fd.close() sys.stdout.flush() # Return to initial positions atoms_N.positions[offset + a, i] = pos[a, i]
def _open_write(self, atoms, backup, backend): "Open a bundle trajectory for writing." self._set_backend(backend) self.logfile = None # enable delayed logging self.atoms = atoms if os.path.exists(self.filename): # The output directory already exists. barrier() # all must have time to see it exists if not self.is_bundle(self.filename, allowempty=True): raise IOError( 'Filename "' + self.filename + '" already exists, but is not a BundleTrajectory.' + 'Cowardly refusing to remove it.') if self.is_empty_bundle(self.filename): barrier() self.log('Deleting old "%s" as it is empty' % (self.filename, )) self.delete_bundle(self.filename) elif not backup: barrier() self.log('Deleting old "%s" as backup is turned off.' % (self.filename, )) self.delete_bundle(self.filename) else: barrier() # Make a backup file bakname = self.filename + '.bak' if os.path.exists(bakname): barrier() # All must see it exists self.log('Deleting old backup file "%s"' % (bakname, )) self.delete_bundle(bakname) self.log('Renaming "%s" to "%s"' % (self.filename, bakname)) self._rename_bundle(self.filename, bakname) # Ready to create a new bundle. barrier() self.log('Creating new "%s"' % (self.filename, )) self._make_bundledir(self.filename) self.state = 'prewrite' self._write_metadata({}) self._write_nframes(0) # Mark new bundle as empty self._open_log() self.nframes = 0
def main(): atoms = build.bulk("Al") atoms = atoms * (2, 2, 2) print(len(atoms)) nRuns = 10 optimizerFname = "optimizer.pck" for i in range(nRuns): nMgAtoms = np.random.randint(0, len(atoms) / 2) # Insert Mg atoms system = cp.copy(atoms) if (parallel.rank == 0): for j in range(nMgAtoms): system[i].symbol = "Mg" # Shuffle the list for j in range(10 * len(system)): first = np.random.randint(0, len(system)) second = np.random.randint(0, len(system)) symb1 = system[first].symbol system[first].symbol = system[second].symbol system[second].symbol = symb1 system = parallel.broadcast(system) # Initialize the calculator calc = gp.GPAW(mode=gp.PW(400), xc="PBE", kpts=(4, 4, 4), nbands=-10) system.set_calculator(calc) traj = Trajectory("trajectoryResuse.traj", 'w', atoms) if (i == 0): relaxer = PreconLBFGS(UnitCellFilter(system), logfile="resuse.log") else: relaxer = None relaxParams = None if (parallel.rank == 0): with open(optimizerFname, 'rb') as infile: relaxParams = pck.load(infile) relaxParams = parallel.broadcast(relaxParams) precon = Exp(r_cut=relaxParams["r_cut"], r_NN=relaxParams["r_NN"], mu=relaxParams["mu"], mu_c=relaxParams["mu_c"]) relaxer = PreconLBFGS(UnitCellFilter(system), logfile="resuse.log", precon=precon) relaxer.attach(traj) relaxer.run(fmax=0.05) print(relaxer.iteration) if (parallel.rank == 0): with open(optimizerFname, 'wb') as outfile: relaxParams = { "r_cut": relaxer.precon.r_cut, "r_NN": relaxer.precon.r_NN, "mu": relaxer.precon.mu, "mu_c": relaxer.precon.mu_c } pck.dump(relaxParams, outfile, pck.HIGHEST_PROTOCOL) parallel.barrier()
for ending in endings: restart = 'gpaw-restart.' + ending restart_wf = 'gpaw-restart-wf.' + ending # H2 H = Atoms([Atom('H', (0, 0, 0)), Atom('H', (0, 0, 1))]) H.center(vacuum=2.0) wfdir = 'wfs_tmp' mode = ending + ':' + wfdir + '/psit_s%dk%dn%d' if 1: calc = GPAW(nbands=2, convergence={'eigenstates': 1e-3}) H.set_calculator(calc) H.get_potential_energy() barrier() calc.write(restart_wf, 'all') calc.write(restart, mode) barrier() # refine the restart file containing the wfs E1 = GPAW(restart_wf, convergence={ 'eigenstates': 1.e-5 }).get_atoms().get_potential_energy() # refine the restart file and separate wfs calc = GPAW(restart, convergence={'eigenstates': 1.e-5}) calc.read_wave_functions(mode) E2 = calc.get_atoms().get_potential_energy() print E1, E2
def read_atat_input(filename='str.out', pbc=(1, 1, 1), verbosity=0, minimize_tilt=False, niggli_reduce=False): """ Reads an ATAT structure file (str.out) and returns the corresponding ASE Atoms object """ if verbosity > 1: parprint("read_atat_input called with options:\n\t filename: {}\n" "\t pbc: {} \n\t verbosity: {} \n\t minimize_tilt: {}\n" "\t niggli_reduce: {}".format(filename, pbc, verbosity, minimize_tilt, niggli_reduce)) ifile = open(filename, 'rb') # Read coordinate system cs = np.zeros((3, 3), dtype=float) l1 = ifile.readline() items = [float(i) for i in l1.split()] if len(items) == 3: cs[0, :] = np.array(items) cs[1, :] = np.array(ifile.readline().split()) cs[2, :] = np.array(ifile.readline().split()) else: # print("WARNING: [a, b, c, alpha, beta, gamma] format" + # " not well tested") a, b, c, alpha, beta, gamma = items alpha, beta, gamma = [ angle * np.pi / 180. for angle in [alpha, beta, gamma] ] (ca, sa) = (math.cos(alpha), math.sin(alpha)) (cb, sb) = (math.cos(beta), math.sin(beta)) (cg, sg) = (math.cos(gamma), math.sin(gamma)) # v_unit is a volume of unit cell with a=b=c=1 v_unit = math.sqrt(1.0 + 2.0 * ca * cb * cg - ca * ca - cb * cb - cg * cg) # from the reciprocal lattice ar = sa / (a * v_unit) cgr = (ca * cb - cg) / (sa * sb) sgr = math.sqrt(1.0 - cgr**2) cs[0, :] = np.array([1.0 / ar, -cgr / sgr / ar, cb * a]) cs[1, :] = np.array([0.0, b * sa, b * ca]) cs[2, :] = np.array([0.0, 0.0, c]) if verbosity > 0: parprint("Coordinate system:\n {}".format(cs)) # Read unit cell cell = np.zeros((3, 3), dtype=float) for i in range(3): cell[i, :] = np.array(ifile.readline().split()) if verbosity > 1: parprint("Initial cell:\n {}".format(cell)) cell = np.dot(cell, cs) if verbosity > 0: parprint("Cell:\n {}".format(cell)) parprint("Cell volume: {}".format(np.linalg.det(cell))) # Read atoms positions rest = ifile.readlines() ifile.close() positions = [] atom_symbols = [] for line in rest: split = line.split() positions.append(np.dot(np.array(split[:3], dtype=float), cs)) atom_symbols.append(split[3]) if verbosity > 0: parprint("Positions:\n {}".format(positions)) # Create atoms object atoms = Atoms(symbols=atom_symbols, positions=positions, cell=cell, pbc=pbc) # Modify cell to the maximally-reduced Niggli unit cell or minimize tilt # angle between cell axes. Niggli takes precedence. if niggli_reduce: ase.build.niggli_reduce(atoms) if verbosity > 0: parprint("Niggli cell:\n {}".format(atoms.get_cell())) parprint("N. cell volume: {}".format( np.linalg.det(atoms.get_cell()))) write_atat_input(atoms, filename='str_niggli.out') barrier() if rank == 0: if not os.path.isfile('str_atat.out'): copyfile('str.out', 'str_atat.out') copyfile('str_niggli.out', 'str.out') barrier() elif minimize_tilt: ase.build.minimize_tilt(atoms) if verbosity > 0: parprint("Minimum tilt cell:\n {}".format(atoms.cell)) parprint("M. T. cell volume: {}".format(np.linalg.det(atoms.cell))) write_atat_input(atoms, filename='str_mintilt.out') barrier() if rank == 0: if not os.path.isfile('str_atat.out'): copyfile('str.out', 'str_atat.out') copyfile('str_mintilt.out', 'str.out') barrier() return atoms
def run(self): if not isfile(self.name + '.eq.pckl'): self.calc.calculate(self.atoms) Vt_G = self.calc.get_effective_potential(pad=False) Vt_G = self.calc.wfs.gd.collect(Vt_G, broadcast=True) / Hartree dH_asp = self.calc.hamiltonian.dH_asp setups = self.calc.wfs.setups nspins = self.calc.wfs.nspins gd_comm = self.calc.wfs.gd.comm alldH_asp = {} for a, setup in enumerate(setups): ni = setup.ni nii = ni * (ni + 1) // 2 tmpdH_sp = np.zeros((nspins, nii)) if a in dH_asp: tmpdH_sp[:] = dH_asp[a] gd_comm.sum(tmpdH_sp) alldH_asp[a] = tmpdH_sp forces = self.atoms.get_forces() self.calc.write('eq.gpw') barrier() if rank == 0: vd = open(self.name + '.eq.pckl', 'wb') fd = open('vib.eq.pckl', 'wb') pickle.dump((Vt_G, alldH_asp), vd, 2) pickle.dump(forces, fd) vd.close() fd.close() barrier() p = self.atoms.positions.copy() for a in self.indices: for j in range(3): for sign in [-1, 1]: for ndis in range(1, self.nfree / 2 + 1): name = '.%d%s%s.pckl' % (a, 'xyz'[j], ndis * ' +-'[sign]) if isfile(self.name + name): continue self.atoms.positions[ a, j] = p[a, j] + sign * ndis * self.delta self.calc.calculate(self.atoms) Vt_G = self.calc.get_effective_potential(pad=False) Vt_G = self.calc.wfs.gd.collect( Vt_G, broadcast=True) / Hartree dH_asp = self.calc.hamiltonian.dH_asp alldH_asp = {} for a2, setup in enumerate(setups): ni = setup.ni nii = ni * (ni + 1) // 2 tmpdH_sp = np.zeros((nspins, nii)) if a2 in dH_asp: tmpdH_sp[:] = dH_asp[a2] gd_comm.sum(tmpdH_sp) alldH_asp[a2] = tmpdH_sp forces = self.atoms.get_forces() barrier() if rank == 0: vd = open(self.name + name, 'wb') fd = open('vib' + name, 'wb') pickle.dump((Vt_G, alldH_asp), vd) pickle.dump(forces, fd) vd.close() fd.close() barrier() self.atoms.positions[a, j] = p[a, j] self.atoms.set_positions(p)
def get_bader_charges(atoms, calc, charge_source="all-electron", gridrefinement=4): """This function uses an external Bader charge calculator from http://theory.cm.utexas.edu/henkelman/code/bader/. This tool is provided also in pysic/tools. Before using this function the bader executable directory has to be added to PATH. Parameters: atoms: ASE Atoms The structure from which we want to calculate the charges from. calc: ASE calculator charge_source: string Indicates the electron density that is used in charge calculation. Can be "pseudo" or "all-electron". gridrefinement: int The factor by which the calculation grid is densified in charge calculation. Returns: numpy array of the atomic charges """ # First check that the bader executable is in PATH if spawn.find_executable("bader") is None: error(( "Cannot find the \"bader\" executable in PATH. The bader " "executable is provided in the pysic/tools folder, or it can be " "downloaded from http://theory.cm.utexas.edu/henkelman/code/bader/. " "Ensure that the executable is named \"bader\", place it in any " "directory you want and then add that directory to your system" "PATH.")) atoms_copy = atoms.copy() calc.set_atoms(atoms_copy) if charge_source == "pseudo": try: density = np.array(calc.get_pseudo_density()) except AttributeError: error("The calculator doesn't provide pseudo density.") if charge_source == "all-electron": try: density = np.array( calc.get_all_electron_density(gridrefinement=gridrefinement)) except AttributeError: error("The calculator doesn't provide all electron density.") wrk_dir = os.getcwd() + "/.BADERTEMP" dir_created = False # Write the density in bader supported units and format if rank == 0: # Create temporary folder for calculations if not os.path.exists(wrk_dir): os.makedirs(wrk_dir) dir_created = True else: error( "Tried to create a temporary folder in " + wrk_dir + ", but the folder already existed. Please remove it manually first." ) rho = density * Bohr**3 write(wrk_dir + '/electron_density.cube', atoms, data=rho) # Run the bader executable in terminal. The bader executable included # int pysic/tools has to be in the PATH/PYTHONPATH command = "cd " + wrk_dir + "; bader electron_density.cube" subprocess.check_output(command, shell=True) #os.system("gnome-terminal --disable-factory -e '"+command+"'") # Wait for the main process to write the file barrier() # ASE provides an existing function for attaching the charges to the # atoms (safe because using a copy). Although we don't want to actually # attach the charges to anything, we use this function and extract the # charges later. bader.attach_charges(atoms_copy, wrk_dir + "/ACF.dat") # The call for charges was changed between # ASE 3.6 and 3.7 try: bader_charges = np.array(atoms_copy.get_initial_charges()) except: bader_charges = np.array(atoms_copy.get_charges()) # Remove the temporary files if rank == 0: if dir_created: shutil.rmtree(wrk_dir) return bader_charges
def run(self): """Run the vibration calculations. This will calculate the forces for 6 displacements per atom ±x, ±y, ±z. Only those calculations that are not already done will be started. Be aware that an interrupted calculation may produce an empty file (ending with .pckl), which must be deleted before restarting the job. Otherwise the forces will not be calculated for that displacement. Note that the calculations for the different displacements can be done simultaneously by several independent processes. This feature relies on the existence of files and the subsequent creation of the file in case it is not found. """ filename = self.name + '.eq.pckl' if not isfile(filename): barrier() if rank == 0: fd = open(filename, 'w') forces = self.atoms.get_forces() if self.ir: dipole = self.calc.get_dipole_moment(self.atoms) if rank == 0: if self.ir: pickle.dump([forces, dipole], fd) sys.stdout.write( 'Writing %s, dipole moment = (%.6f %.6f %.6f)\n' % (filename, dipole[0], dipole[1], dipole[2])) else: pickle.dump(forces, fd) sys.stdout.write('Writing %s\n' % filename) fd.close() sys.stdout.flush() p = self.atoms.positions.copy() for a in self.indices: for i in range(3): for sign in [-1, 1]: for ndis in range(1, self.nfree//2+1): filename = ('%s.%d%s%s.pckl' % (self.name, a, 'xyz'[i], ndis*' +-'[sign])) if isfile(filename): continue barrier() if rank == 0: fd = open(filename, 'w') self.atoms.positions[a, i] = (p[a, i] + ndis * sign * self.delta) forces = self.atoms.get_forces() if self.ir: dipole = self.calc.get_dipole_moment(self.atoms) if rank == 0: if self.ir: pickle.dump([forces, dipole], fd) sys.stdout.write( 'Writing %s, ' % filename + 'dipole moment = (%.6f %.6f %.6f)\n' % (dipole[0], dipole[1], dipole[2])) else: pickle.dump(forces, fd) sys.stdout.write('Writing %s\n' % filename) fd.close() sys.stdout.flush() self.atoms.positions[a, i] = p[a, i] self.atoms.set_positions(p)
def run_vdw(self, nonsc_calculation=None): """Starts the vdW calculation. The method runs only if the pickle corresponding pickle file does not exist. The vdw_nonsc program is executed in the directory set by the environmental variable VDW_PATH where the kernel and other data files must exist.""" if os.path.isfile('%s.pckl' % self.name): return self.prepare(nonsc_calculation) sys.stdout.write('Running non self-consistent vdW-DF calculation... ') sys.stdout.flush() barrier() path = os.path.abspath('.') fd = open(path + '/%s.pckl' % self.name, 'w') data = pickle.load(open('%s_no-vdw.pckl' % self.name, 'r'))[0] E_dft = data['E_dft'] # Change path to where the vdw data files are os.chdir(self.vdw_path) # Execute vdw vdw_nonsc program tmp_name = path + '/%s' % self.name exitcode = os.system('%s %s.atoms.inp %s.chargeden > %s.vdw.out' % (self.vdw_nonsc, tmp_name, tmp_name, tmp_name)) os.chdir(path) if exitcode != 0: raise RuntimeError('vdw_nonsc exited with exit code: %d. ' % exitcode) barrier() sys.stdout.flush() # Extract and pickle the output if rank == 0: [E_LDAc, E_LDAx, E_PBEc, E_PBEx, E_revPBEx, E_nl] = self.extract() pickle.dump([{ 'E_dft': E_dft, 'E_2': data['E_2'], 'E_LDA-c': E_LDAc, 'E_LDA-x': E_LDAx, 'E_PBE-c': E_PBEc, 'E_PBE-x': E_PBEx, 'E_revPBE-x': E_revPBEx, 'E_nl': E_nl, 'E_vdW': E_dft - E_PBEc + E_LDAc + E_nl, 'atoms': data['atoms'], }], fd) fd.close() # Delete input files self.clean() sys.stdout.write('Done!\n\n') self.tf = int(time.time()) print '================================================================================' print 'Finished vdW-DF calculation \'%s\' on %s.\n' % (self.name, time.ctime()) print 'Timings:\n' print 'Self-consistent DFT calculation: %3d hours %2d minutes %2d seconds' % \ ((self.t2-self.t1)/3600, ((self.t2-self.t1)/60)%60, (self.t2-self.t1)%60) if self.nonsc_calculation: print 'Non self-consistent DFT calculation: %3d hours %2d minutes %2d seconds' % \ ((self.t_nonsc-self.t2)/3600, ((self.t_nonsc-self.t2)/60)%60, (self.t_nonsc-self.t2)%60) self.t2 = self.t_nonsc print 'Converting charge density: %3d hours %2d minutes %2d seconds' % \ ((self.t3-self.t2)/3600, ((self.t3-self.t2)/60)%60, (self.t3-self.t2)%60) print 'Non-self-consistent vdW-DF calculation: %3d hours %2d minutes %2d seconds' % \ ((self.tf-self.t3)/3600, ((self.tf-self.t2)/60)%60, (self.tf-self.t3)%60) print '---------------------------------------------------------------------------' print 'Total time: %3d hours %2d minutes %2d seconds' % ( (self.tf - self.t1) / 3600, ((self.tf - self.t1) / 60) % 60, (self.tf - self.t1) % 60) print '================================================================================\n' return
txt=None print '--- Comparing LB94 with', ref1 print 'and', ref2 print '**** all electron calculations' print 'atom [refs] -e_homo diff all in mHa' if rank == 0: for atom in e_HOMO_cs.keys(): ae = AllElectron(atom, 'LB94', txt=txt) ae.run() e_homo = int( ae.e_j[-1] * 10000 + .5 ) / 10. diff = e_HOMO_cs[atom] + e_homo print '%2s %8g %6.1f %4.1g' % (atom, e_HOMO_cs[atom], -e_homo, diff) assert abs(diff) < 6 barrier() setup_paths.insert(0, '.') setups = {} print '**** 3D calculations' print 'atom [refs] -e_homo diff all in mHa' for atom in e_HOMO_cs.keys(): e_ref = e_HOMO_cs[atom] # generate setup for the atom if rank == 0 and not setups.has_key(atom): g = Generator(atom, 'LB94', nofiles=True, txt=txt) g.run(**parameters[atom]) setups[atom] = 1 barrier()
def get_bader_charges(atoms, calc, charge_source="all-electron", gridrefinement=4): """This function uses an external Bader charge calculator from http://theory.cm.utexas.edu/henkelman/code/bader/. This tool is provided also in pysic/tools. Before using this function the bader executable directory has to be added to PATH. Parameters: atoms: ASE Atoms The structure from which we want to calculate the charges from. calc: ASE calculator charge_source: string Indicates the electron density that is used in charge calculation. Can be "pseudo" or "all-electron". gridrefinement: int The factor by which the calculation grid is densified in charge calculation. Returns: numpy array of the atomic charges """ # First check that the bader executable is in PATH if spawn.find_executable("bader") is None: error(( "Cannot find the \"bader\" executable in PATH. The bader " "executable is provided in the pysic/tools folder, or it can be " "downloaded from http://theory.cm.utexas.edu/henkelman/code/bader/. " "Ensure that the executable is named \"bader\", place it in any " "directory you want and then add that directory to your system" "PATH.")) atoms_copy = atoms.copy() calc.set_atoms(atoms_copy) if charge_source == "pseudo": try: density = np.array(calc.get_pseudo_density()) except AttributeError: error("The calculator doesn't provide pseudo density.") if charge_source == "all-electron": try: density = np.array(calc.get_all_electron_density(gridrefinement=gridrefinement)) except AttributeError: error("The calculator doesn't provide all electron density.") wrk_dir = os.getcwd()+"/.BADERTEMP" dir_created = False # Write the density in bader supported units and format if rank == 0: # Create temporary folder for calculations if not os.path.exists(wrk_dir): os.makedirs(wrk_dir) dir_created = True else: error("Tried to create a temporary folder in " + wrk_dir + ", but the folder already existed. Please remove it manually first.") rho = density * Bohr**3 write(wrk_dir + '/electron_density.cube', atoms, data=rho) # Run the bader executable in terminal. The bader executable included # int pysic/tools has to be in the PATH/PYTHONPATH command = "cd " + wrk_dir + "; bader electron_density.cube" subprocess.check_output(command, shell=True) #os.system("gnome-terminal --disable-factory -e '"+command+"'") # Wait for the main process to write the file barrier() # ASE provides an existing function for attaching the charges to the # atoms (safe because using a copy). Although we don't want to actually # attach the charges to anything, we use this function and extract the # charges later. bader.attach_charges(atoms_copy, wrk_dir + "/ACF.dat") # The call for charges was changed between # ASE 3.6 and 3.7 try: bader_charges = np.array(atoms_copy.get_initial_charges()) except: bader_charges = np.array(atoms_copy.get_charges()) # Remove the temporary files if rank == 0: if dir_created: shutil.rmtree(wrk_dir) return bader_charges
def run(self): if not isfile(self.name + '.eq.pckl'): self.calc.calculate(self.atoms) Vt_G = self.calc.get_effective_potential(pad=False) Vt_G = self.calc.wfs.gd.collect(Vt_G, broadcast=True) / Hartree dH_asp = self.calc.hamiltonian.dH_asp setups = self.calc.wfs.setups nspins = self.calc.wfs.nspins gd_comm = self.calc.wfs.gd.comm alldH_asp = {} for a, setup in enumerate(setups): ni = setup.ni nii = ni * (ni + 1) // 2 tmpdH_sp = np.zeros((nspins, nii)) if a in dH_asp: tmpdH_sp[:] = dH_asp[a] gd_comm.sum(tmpdH_sp) alldH_asp[a] = tmpdH_sp forces = self.atoms.get_forces() self.calc.write('eq.gpw') barrier() if rank == 0: vd = open(self.name + '.eq.pckl', 'wb') fd = open('vib.eq.pckl','wb') pickle.dump((Vt_G, alldH_asp), vd,2) pickle.dump(forces,fd) vd.close() fd.close() barrier() p = self.atoms.positions.copy() for a in self.indices: for j in range(3): for sign in [-1,1]: for ndis in range(1,self.nfree/2+1): name = '.%d%s%s.pckl' % (a, 'xyz'[j], ndis * ' +-'[sign]) if isfile(self.name + name): continue self.atoms.positions[a, j] = p[a, j] + sign * ndis * self.delta self.calc.calculate(self.atoms) Vt_G = self.calc.get_effective_potential(pad=False) Vt_G =self.calc.wfs.gd.collect(Vt_G, broadcast=True) / Hartree dH_asp = self.calc.hamiltonian.dH_asp alldH_asp = {} for a2, setup in enumerate(setups): ni = setup.ni nii = ni * (ni + 1) // 2 tmpdH_sp = np.zeros((nspins, nii)) if a2 in dH_asp: tmpdH_sp[:] = dH_asp[a2] gd_comm.sum(tmpdH_sp) alldH_asp[a2] = tmpdH_sp forces = self.atoms.get_forces() barrier() if rank == 0: vd = open(self.name + name , 'w') fd = open('vib' + name, 'w') pickle.dump((Vt_G, alldH_asp), vd) pickle.dump(forces, fd) vd.close() fd.close() barrier() self.atoms.positions[a, j] = p[a, j] self.atoms.set_positions(p)
def run_vdw(self, nonsc_calculation=None): """Starts the vdW calculation. The method runs only if the pickle corresponding pickle file does not exist. The vdw_nonsc program is executed in the directory set by the environmental variable VDW_PATH where the kernel and other data files must exist.""" if os.path.isfile('%s.pckl' % self.name): return self.prepare(nonsc_calculation) sys.stdout.write('Running non self-consistent vdW-DF calculation... ') sys.stdout.flush() barrier() path = os.path.abspath('.') fd = open(path + '/%s.pckl' % self.name, 'w') data = pickle.load(open('%s_no-vdw.pckl' % self.name, 'r'))[0] E_dft = data['E_dft'] # Change path to where the vdw data files are os.chdir(self.vdw_path) # Execute vdw vdw_nonsc program tmp_name = path + '/%s' % self.name exitcode = os.system('%s %s.atoms.inp %s.chargeden > %s.vdw.out' % (self.vdw_nonsc, tmp_name, tmp_name, tmp_name)) os.chdir(path) if exitcode != 0: raise RuntimeError('vdw_nonsc exited with exit code: %d. ' % exitcode) barrier() sys.stdout.flush() # Extract and pickle the output if rank == 0: [E_LDAc, E_LDAx, E_PBEc, E_PBEx, E_revPBEx, E_nl] = self.extract() pickle.dump([{'E_dft': E_dft, 'E_2': data['E_2'], 'E_LDA-c': E_LDAc, 'E_LDA-x': E_LDAx, 'E_PBE-c': E_PBEc, 'E_PBE-x': E_PBEx, 'E_revPBE-x': E_revPBEx, 'E_nl': E_nl, 'E_vdW': E_dft-E_PBEc+E_LDAc+E_nl, 'atoms': data['atoms'], }], fd) fd.close() # Delete input files self.clean() sys.stdout.write('Done!\n\n') self.tf = int(time.time()) print '================================================================================' print 'Finished vdW-DF calculation \'%s\' on %s.\n' % (self.name, time.ctime()) print 'Timings:\n' print 'Self-consistent DFT calculation: %3d hours %2d minutes %2d seconds' % \ ((self.t2-self.t1)/3600, ((self.t2-self.t1)/60)%60, (self.t2-self.t1)%60) if self.nonsc_calculation: print 'Non self-consistent DFT calculation: %3d hours %2d minutes %2d seconds' % \ ((self.t_nonsc-self.t2)/3600, ((self.t_nonsc-self.t2)/60)%60, (self.t_nonsc-self.t2)%60) self.t2 = self.t_nonsc print 'Converting charge density: %3d hours %2d minutes %2d seconds' % \ ((self.t3-self.t2)/3600, ((self.t3-self.t2)/60)%60, (self.t3-self.t2)%60) print 'Non-self-consistent vdW-DF calculation: %3d hours %2d minutes %2d seconds' % \ ((self.tf-self.t3)/3600, ((self.tf-self.t2)/60)%60, (self.tf-self.t3)%60) print '---------------------------------------------------------------------------' print 'Total time: %3d hours %2d minutes %2d seconds' % ((self.tf-self.t1)/3600, ((self.tf-self.t1)/60)%60, (self.tf-self.t1)%60) print '================================================================================\n' return