def in_queue(self): """Return True or False if the directory has a job in the queue.""" if self.get_db('jobid') is None: log.debug('jobid not found for calculation.') return False else: # get the jobid jobid = self.get_db('jobid') # see if jobid is in queue _, jobids_in_queue, _ = getstatusoutput('qselect', stdout=subprocess.PIPE, stderr=subprocess.PIPE) if str(jobid) in jobids_in_queue.split('\n'): # get details on specific jobid in case it is complete status, output, err = getstatusoutput(['qstat', jobid], stdout=subprocess.PIPE, stderr=subprocess.PIPE) if status == 0: lines = output.split('\n') fields = lines[2].split() job_status = fields[4] if job_status == 'C': return False else: return True else: return False
def in_queue(self): """Return True or False if the directory has a job in the queue.""" if self.get_db('jobid') is None: log.debug('jobid not found for calculation.') return False else: # get the jobid jobid = self.get_db('jobid') # see if jobid is in queue _, jobids_in_queue, _ = getstatusoutput('qselect', stdout=subprocess.PIPE, stderr=subprocess.PIPE) if str(jobid) in jobids_in_queue.split('\n'): # get details on specific jobid in case it is complete status, output, err = getstatusoutput(['qstat', jobid], stdout=subprocess.PIPE, stderr=subprocess.PIPE) if status == 0: lines = output.split('\n') fields = lines[2].split() job_status = fields[4] if job_status == 'C': return False else: return True else: return False
def read_neb_calculator(): """Read calculator from the current working directory. Static method that returns a :mod:`jasp.Jasp` calculator. """ log.debug('Entering read_neb_calculator in {0}'.format(os.getcwd())) calc = Vasp() calc.vaspdir = os.getcwd() calc.read_incar() calc.read_kpoints() if calc.in_queue(): return ([None for i in range(calc.int_params['images'] + 2)], [None for i in range(calc.int_params['images'] + 2)]) # set default functional # if both gga and xc are not specified if calc.string_params['gga'] is None: if calc.input_params['xc'] is None: calc.input_params['xc'] = 'PBE' images = [] log.debug('calc.int_params[images] = %i', calc.int_params['images']) # Add 2 to IMAGES flag from INCAR to get # first and last images for i in range(calc.int_params['images'] + 2): log.debug('reading neb calculator: 0%i', i) cwd = os.getcwd() os.chdir('{0}'.format(str(i).zfill(2))) if os.path.exists('CONTCAR'): f = open('CONTCAR') if f.read() == '': log.debug('CONTCAR was empty, vasp probably still running') fname = 'POSCAR' else: fname = 'CONTCAR' else: fname = 'POSCAR' atoms = read(fname, format='vasp') f = open('ase-sort.dat') sort, resort = [], [] for line in f: s, r = [int(x) for x in line.split()] sort.append(s) resort.append(r) images += [atoms[resort]] os.chdir(cwd) log.debug('len(images) = %i', len(images)) calc.neb_images = images calc.neb_nimages = len(images) - 2 calc.neb = True return calc
def read_neb_calculator(): """Read calculator from the current working directory. Static method that returns a :mod:`jasp.Jasp` calculator. """ log.debug('Entering read_neb_calculator in {0}'.format(os.getcwd())) calc = Vasp() calc.vaspdir = os.getcwd() calc.read_incar() calc.read_kpoints() if calc.in_queue(): return ([None for i in range(calc.int_params['images'] + 2)], [None for i in range(calc.int_params['images'] + 2)]) # set default functional # if both gga and xc are not specified if calc.string_params['gga'] is None: if calc.input_params['xc'] is None: calc.input_params['xc'] = 'PBE' images = [] log.debug('calc.int_params[images] = %i', calc.int_params['images']) # Add 2 to IMAGES flag from INCAR to get # first and last images for i in range(calc.int_params['images'] + 2): log.debug('reading neb calculator: 0%i', i) cwd = os.getcwd() os.chdir('{0}'.format(str(i).zfill(2))) if os.path.exists('CONTCAR'): f = open('CONTCAR') if f.read() == '': log.debug('CONTCAR was empty, vasp probably still running') fname = 'POSCAR' else: fname = 'CONTCAR' else: fname = 'POSCAR' atoms = read(fname, format='vasp') f = open('ase-sort.dat') sort, resort = [], [] for line in f: s, r = [int(x) for x in line.split()] sort.append(s) resort.append(r) images += [atoms[resort]] os.chdir(cwd) log.debug('len(images) = %i', len(images)) calc.neb_images = images calc.neb_nimages = len(images) - 2 calc.neb = True return calc
def get_ados(self, atom_index, orbital, spin=1, efermi=None): """Return Atom projected DOS for atom index, orbital and spin. orbital: string ['s', 'p', 'd'] If efermi is not None, use this value as 0.0. :returns: (energies, ados) """ self.update() with open(os.path.join(self.directory, 'vasprun.xml')) as f: tree = ElementTree.parse(f) path = "/".join(['calculation', 'dos', 'partial', 'array', 'set', 'set[@comment="ion {}"]', 'set[@comment="spin {}"]', "r"]) us = [k[1] for k in sorted([[j, i] for i, j in enumerate(self.resort)])] path = path.format(us.index(atom_index) + 1, spin) log.debug(path) results = [[float(x) for x in el.text.split()] for el in tree.findall(path)] if efermi is None: efermi = self.get_fermi_level() else: efermi = 0.0 energy = np.array([x[0] for x in results]) - efermi ados = np.array([x['spd'.index(orbital) + 1] for x in results]) return [energy, ados]
def set(self, **kwargs): """Set parameters with keyword=value pairs. calc.set(xc='PBE') A few special kwargs are handled separately to expand them prior to setting the parameters. This is done to enable one set to track changes. """ log.debug('Setting {}'.format(kwargs)) if 'xc' in kwargs: kwargs.update(self.set_xc_dict(kwargs['xc'])) if 'ispin' in kwargs: kwargs.update(self.set_ispin_dict(kwargs['ispin'])) if 'ldau_luj' in kwargs: kwargs.update(self.set_ldau_luj_dict(kwargs['ldau_luj'])) original_params = self.parameters changed_parameters = FileIOCalculator.set(self, **kwargs) # If we are implementing special setups, the ppp_list needs # to be updated so the POSCAR and POTCAR can be written correctly. if 'setups' in changed_parameters.keys(): self.sort_atoms(self.atoms) # we don't consider None values to be changed if the keyword was # not originally in the parameters. cp = { k: v for k, v in changed_parameters.items() if v is not None and k not in original_params } if cp != {}: log.debug('resetting because {} changed.'.format(cp)) self.reset() return changed_parameters
def calculation_required(self, atoms=None, properties=['energy']): """Returns if a calculation is needed.""" if atoms is None: atoms = self.get_atoms() system_changes = self.check_state(atoms) if system_changes: log.debug('Calculation needed for {}'.format(system_changes)) return True for name in properties: if name not in self.results: log.debug('{} not in {}. Calc required.'.format(name, self.results)) return True # if the calculation is finished we do not need to run. if os.path.exists(self.outcar): with open(self.outcar) as f: lines = f.readlines() if 'Voluntary context switches:' in lines[-1]: return False
def calculation_required(self, atoms=None, properties=['energy']): """Returns if a calculation is needed.""" if atoms is None: atoms = self.get_atoms() system_changes = self.check_state(atoms) if system_changes: log.debug('Calculation needed for {}'.format(system_changes)) return True for name in properties: if name not in self.results: log.debug('{} not in {}. Calc required.'.format( name, self.results)) return True # if the calculation is finished we do not need to run. if os.path.exists(self.outcar): with open(self.outcar) as f: lines = f.readlines() if 'Voluntary context switches:' in lines[-1]: return False
def set(self, **kwargs): """Set parameters with keyword=value pairs. calc.set(xc='PBE') A few special kwargs are handled separately to expand them prior to setting the parameters. This is done to enable one set to track changes. """ log.debug('Setting {}'.format(kwargs)) if 'xc' in kwargs: kwargs.update(self.set_xc_dict(kwargs['xc'])) if 'ispin' in kwargs: kwargs.update(self.set_ispin_dict(kwargs['ispin'])) if 'ldau_luj' in kwargs: kwargs.update(self.set_ldau_luj_dict(kwargs['ldau_luj'])) if 'nsw' in kwargs: kwargs.update(self.set_nsw_dict(kwargs['nsw'])) original_params = self.parameters changed_parameters = FileIOCalculator.set(self, **kwargs) # we don't consider None values to be changed if the keyword was # not originally in the parameters. cp = { k: v for k, v in changed_parameters.iteritems() if v is not None and k not in original_params } if cp != {}: log.debug('resetting because {} changed.'.format(cp)) self.reset() return changed_parameters
def set(self, **kwargs): """Set parameters with keyword=value pairs. calc.set(xc='PBE') A few special kwargs are handled separately to expand them prior to setting the parameters. This is done to enable one set to track changes. """ log.debug('Setting {}'.format(kwargs)) if 'xc' in kwargs: kwargs.update(self.set_xc_dict(kwargs['xc'])) if 'ispin' in kwargs: kwargs.update(self.set_ispin_dict(kwargs['ispin'])) if 'ldau_luj' in kwargs: kwargs.update(self.set_ldau_luj_dict(kwargs['ldau_luj'])) original_params = self.parameters changed_parameters = FileIOCalculator.set(self, **kwargs) # If we are implementing special setups, the ppp_list needs # to be updated so the POSCAR and POTCAR can be written correctly. if 'setups' in changed_parameters.keys(): self.sort_atoms(self.atoms) # we don't consider None values to be changed if the keyword was # not originally in the parameters. cp = {k: v for k, v in changed_parameters.iteritems() if v is not None and k not in original_params} if cp != {}: log.debug('resetting because {} changed.'.format(cp)) self.reset() return changed_parameters
def set(self, **kwargs): """Set parameters with keyword=value pairs. calc.set(xc='PBE') A few special kwargs are handled separately to expand them prior to setting the parameters. This is done to enable one set to track changes. """ log.debug('Setting {}'.format(kwargs)) if 'xc' in kwargs: kwargs.update(self.set_xc_dict(kwargs['xc'])) if 'ispin' in kwargs: kwargs.update(self.set_ispin_dict(kwargs['ispin'])) if 'ldau_luj' in kwargs: kwargs.update(self.set_ldau_luj_dict(kwargs['ldau_luj'])) if 'nsw' in kwargs: kwargs.update(self.set_nsw_dict(kwargs['nsw'])) original_params = self.parameters changed_parameters = FileIOCalculator.set(self, **kwargs) # we don't consider None values to be changed if the keyword was # not originally in the parameters. cp = {k: v for k, v in changed_parameters.iteritems() if v is not None and k not in original_params} if cp != {}: log.debug('resetting because {} changed.'.format(cp)) self.reset() return changed_parameters
def sort_atoms(self, atoms=None): """Generate resort list, and make list of POTCARs to use. Returns None. """ self.resort = None self.ppp_list = None self.symbol_count = None if atoms is None: log.debug('Atoms was none.') return self.atoms = atoms # Now we sort the atoms and generate the list of POTCARS # We end up with ppp = [(index_or_symbol, potcar_file, count)] # and resort_indices setups = self.parameters.get('setups', []) pp = self.parameters['pp'] ppp = [] # [(index_or_symbol, potcar_file, count)] # indices of original atoms needed to make sorted atoms list sort_indices = [] # First the numeric index setups for setup in [x for x in setups if isinstance(x[0], int)]: ppp += [[setup[0], 'potpaw_{}/{}{}/POTCAR'.format(pp, atoms[setup[0]].symbol, setup[1]), 1]] sort_indices += [setup[0]] # now the rest of the setups. These are atom symbols for setup in [x for x in setups if not isinstance(x[0], int)]: symbol = setup[0] count = 0 for i, atom in enumerate(atoms): if atom.symbol == symbol and i not in sort_indices: count += 1 sort_indices += [i] ppp += [[symbol, 'potpaw_{}/{}{}/POTCAR'.format(pp, symbol, setup[1]), count]] # now the remaining atoms use default potentials # First get the chemical symbols that remain symbols = [] for atom in atoms or []: if (atom.symbol not in symbols and atom.symbol not in [x[0] for x in ppp]): symbols += [atom.symbol] for symbol in symbols: count = 0 for i, atom in enumerate(atoms): if atom.symbol == symbol and i not in sort_indices: sort_indices += [i] count += 1 if count > 0: ppp += [[symbol, 'potpaw_{}/{}/POTCAR'.format(pp, symbol), count]] assert len(sort_indices) == len(atoms), \ 'Sorting error. sort_indices={}'.format(sort_indices) assert sum([x[2] for x in ppp]) == len(atoms) self.sort = sort_indices # This list is used to convert Vasp ordering back to the # user-defined order. self.resort = [k[1] for k in sorted([[j, i] for i, j in enumerate(sort_indices)])] # June 23, 2016. Jake Boes found a bug in how sorting is # done. We fixed it, but the fix is not backwards compatible # with the old resort we stored in DB.db. It appears we can # detect an old case if there is inconsistency with what is # stored and calculated here. We check here to see if we are # consistent, and if not fix the issue. This should only occur # once. if (self.resort is not None and self.get_db('resort') is not None and self.resort != list(self.get_db('resort'))): ns = [k[1] for k in sorted([[j, i] for i, j in enumerate(self.get_db('resort'))])] from ase.db import connect with connect(os.path.join(self.directory, 'DB.db')) as con: tatoms = con.get_atoms(id=1) self.write_db(atoms=tatoms, data={'resort': ns}) print('Fixed resort issue in {}. ' 'You should not see this message' ' again'.format(self.directory)) self.resort = ns sort_indices = [k[1] for k in sorted([[j, i] for i, j in enumerate(ns)])] self.ppp_list = ppp self.atoms_sorted = atoms[sort_indices] self.symbol_count = [(x[0] if isinstance(x[0], str) else atoms[x[0]].symbol, x[2]) for x in ppp]
def check_state(self, atoms=None): """Check if any changes exist that require new calculations.""" if atoms is None: atoms = self.get_atoms() log.debug('atoms IMM: {}'.format(atoms.get_initial_magnetic_moments())) system_changes = FileIOCalculator.check_state(self, atoms) # Ignore boundary conditions: if 'pbc' in system_changes: system_changes.remove('pbc') s = 'FileIOCalculator reports these changes: {}' log.debug(s.format(system_changes)) # if dir is empty, there is nothing to read here. if self.get_state() == Vasp.EMPTY: return system_changes # Check if the parameters have changed file_params = {} file_params.update(self.read_incar()) if 'rwigs' in file_params: # This gets read as a list. with open(self.potcar) as f: lines = f.readlines() # symbols are in the # FIXME: first line of each potcar symbols = [lines[0].split()[1]] for i, line in enumerate(lines): if 'End of Dataset' in line and i != len(lines) - 1: symbols += [lines[i + 1].split()[1]] file_params['rwigs'] = dict(zip(symbols, file_params['rwigs'])) file_params.update(self.read_potcar()) file_params.update(self.read_kpoints()) xc_keys = sorted(Vasp.xc_defaults, key=lambda k: len(Vasp.xc_defaults[k]), reverse=True) for ex in xc_keys: pd = {k: file_params.get(k, None) for k in Vasp.xc_defaults[ex]} if pd == Vasp.xc_defaults[ex]: file_params['xc'] = ex.lower() break # reconstruct ldau_luj if necessary if 'ldauu' in file_params: ldaul = file_params['ldaul'] ldauj = file_params['ldauj'] ldauu = file_params['ldauu'] with open(self.potcar) as f: lines = f.readlines() # symbols are in the first line of each potcar symbols = [lines[0].split()[1]] for i, line in enumerate(lines): if 'End of Dataset' in line and i != len(lines) - 1: symbols += [lines[i + 1].split()[1]] ldau_luj = {} for sym, l, j, u in zip(symbols, ldaul, ldauj, ldauu): ldau_luj[sym] = {'L': l, 'U': u, 'J': j} file_params['ldau_luj'] = ldau_luj if not {k: v for k, v in self.parameters.iteritems() if v is not None} == file_params: new_keys = set(self.parameters.keys()) - set(file_params.keys()) missing_keys = (set(file_params.keys()) - set(self.parameters.keys())) log.debug('New keys: {}'.format(new_keys)) log.debug('Missing keys: {}'.format(missing_keys)) log.debug('params_on_file do not match.') log.debug('file-params: {}'.format(file_params)) log.debug('compared to: {}'.format({ k: v for k, v in self.parameters.iteritems() if v is not None })) system_changes += ['params_on_file'] log.debug('System changes: {}'.format(system_changes)) return system_changes
def reset(self): """overwrite to avoid killing self.atoms.""" log.debug('Resetting calculator.') self.results = {}
def sort_atoms(self, atoms=None): """Generate resort list, and make list of POTCARs to use. Returns None. """ self.resort = None self.ppp_list = None self.symbol_count = None if atoms is None: log.debug('Atoms was none.') return self.atoms = atoms # Now we sort the atoms and generate the list of POTCARS # We end up with ppp = [(index_or_symbol, potcar_file, count)] # and resort_indices setups = self.parameters.get('setups', []) pp = self.parameters['pp'] ppp = [] # [(index_or_symbol, potcar_file, count)] # indices of original atoms needed to make sorted atoms list sort_indices = [] # First the numeric index setups for setup in [x for x in setups if isinstance(x[0], int)]: ppp += [[setup[1], 'potpaw_{}/{}/POTCAR'.format(pp, setup[1]), 1]] sort_indices += [setup[0]] # now the rest of the setups. These are atom symbols for setup in [x for x in setups if not isinstance(x[0], int)]: symbol = setup[0] count = 0 for i, atom in enumerate(atoms): if atom.symbol == symbol and i not in sort_indices: count += 1 sort_indices += [i] ppp += [[ symbol, 'potpaw_{}/{}{}/POTCAR'.format(pp, symbol, setup[1]), count ]] # now the remaining atoms use default potentials # First get the chemical symbols that remain symbols = [] for atom in atoms or []: if atom.symbol not in symbols: symbols += [atom.symbol] for symbol in symbols: count = 0 for i, atom in enumerate(atoms): if atom.symbol == symbol and i not in sort_indices: sort_indices += [i] count += 1 if count > 0: ppp += [[ symbol, 'potpaw_{}/{}/POTCAR'.format(pp, symbol), count ]] assert len(sort_indices) == len(atoms), \ 'Sorting error. sort_indices={}'.format(sort_indices) assert sum([x[2] for x in ppp]) == len(atoms) self.sort = sort_indices # This list is used to convert Vasp ordering back to the # user-defined order. self.resort = [ k[1] for k in sorted([[j, i] for i, j in enumerate(sort_indices)]) ] # June 23, 2016. Jake Boes found a bug in how sorting is # done. We fixed it, but the fix is not backwards compatible # with the old resort we stored in DB.db. It appears we can # detect an old case if there is inconsistency with what is # stored and calculated here. We check here to see if we are # consistent, and if not fix the issue. This should only occur # once. if (self.resort is not None and self.get_db('resort') is not None and self.resort != list(self.get_db('resort'))): ns = [ k[1] for k in sorted([[j, i] for i, j in enumerate(self.get_db('resort'))]) ] from ase.db import connect with connect(os.path.join(self.directory, 'DB.db')) as con: tatoms = con.get_atoms(id=1) self.write_db(atoms=tatoms, data={'resort': ns}) print('Fixed resort issue in {}. ' 'You should not see this message' ' again'.format(self.directory)) self.resort = ns sort_indices = [ k[1] for k in sorted([[j, i] for i, j in enumerate(ns)]) ] self.ppp_list = ppp self.atoms_sorted = atoms[sort_indices] self.symbol_count = [ (x[0] if isinstance(x[0], str) else atoms[x[0]].symbol, x[2]) for x in ppp ]
def get_neb(self, npi=1): """Returns images, energies if available or runs the job. npi = cores per image for running the calculations. Default=1 show: if True show an NEB plot """ if self.in_queue(): return self.neb, [None for a in self.neb] calc_required = False # check for OUTCAR in each image dir for i in range(1, len(self.neb) - 1): wf = '{0}/OUTCAR'.format(str(i).zfill(2)) wf = os.path.join(self.directory, wf) if not os.path.exists(wf): calc_required = True break else: # there was an OUTCAR, now we need to check for # convergence. done = False with open(wf) as f: for line in f: if ('reached required accuracy - stopping structural' ' energy minimisation') in line: done = True break if not done: calc_required = True break if calc_required: # this creates the directories and files if needed. write out # all the images, including initial and final if not os.path.isdir(self.directory): os.makedirs(self.directory) self.set(images=len(self.neb) - 2) self.write_incar() self.write_kpoints() self.write_potcar() self.write_db() for i, atoms in enumerate(self.neb): # zero-padded directory name image_dir = os.path.join(self.directory, str(i).zfill(2)) if not os.path.isdir(image_dir): # create if needed. os.makedirs(image_dir) write_vasp('{0}/POSCAR'.format(image_dir), atoms[self.resort], symbol_count=self.symbol_count) # The first and last images need to have real calculators on # them so we can write out a DB entry. We need this so we can # get the energies on the end-points. Otherwise, there doesn't # seem to be a way to do that short of cloning the whole # calculation into the end-point directories. self.write_db(os.path.join(self.directory, '00/DB.db'), self.neb[0]) # print(self.neb) # import sys # sys.exit() self.write_db( os.path.join(self.directory, '{:02}/DB.db'.format(len(self.neb) - 1)), self.neb[-1]) VASPRC['queue.ppn'] = npi * (len(self.neb) - 2) log.debug('Running on %i cores', VASPRC['queue.ppn']) self.calculate() # this will raise VaspSubmitted return self.neb, [None for a in self.neb] ############################################# # now we are just retrieving results energies = [] import ase.io atoms0 = ase.io.read(os.path.join(self.directory, '00', 'DB.db')) energies += [atoms0.get_potential_energy()] for i in range(1, len(self.neb) - 1): atoms = ase.io.read( os.path.join(self.directory, str(i).zfill(2), 'CONTCAR'))[self.resort] self.neb[i].positions = atoms.positions self.neb[i].cell = atoms.cell energy = None with open(os.path.join(self.directory, str(i).zfill(2), 'OUTCAR')) as f: for line in f: if 'free energy TOTEN =' in line: energy = float(line.split()[4]) energies += [energy] fname = os.path.join(self.directory, '0{}/DB.db'.format(len(self.neb) - 1)) atoms_end = ase.io.read(fname) energies += [atoms_end.get_potential_energy()] energies = np.array(energies) energies -= energies[0] return (self.neb, np.array(energies))
def check_state(self, atoms=None): """Check if any changes exist that require new calculations.""" if atoms is None: atoms = self.get_atoms() log.debug('atoms IMM: {}'.format(atoms.get_initial_magnetic_moments())) system_changes = FileIOCalculator.check_state(self, atoms) # Ignore boundary conditions: if 'pbc' in system_changes: system_changes.remove('pbc') s = 'FileIOCalculator reports these changes: {}' log.debug(s.format(system_changes)) # if dir is empty, there is nothing to read here. if self.get_state() == Vasp.EMPTY: return system_changes # Check if the parameters have changed file_params = {} file_params.update(self.read_incar()) file_params.update(self.read_potcar()) file_params.update(self.read_kpoints()) xc_keys = sorted(Vasp.xc_defaults, key=lambda k: len(Vasp.xc_defaults[k]), reverse=True) for ex in xc_keys: pd = {k: file_params.get(k, None) for k in Vasp.xc_defaults[ex]} if pd == Vasp.xc_defaults[ex]: file_params['xc'] = ex.lower() break # reconstruct ldau_luj if necessary if 'ldauu' in file_params: ldaul = file_params['ldaul'] ldauj = file_params['ldauj'] ldauu = file_params['ldauu'] with open(self.potcar) as f: lines = f.readlines() # symbols are in the first line of each potcar symbols = [lines[0].split()[1]] for i, line in enumerate(lines): if 'End of Dataset' in line and i != len(lines) - 1: symbols += [lines[i + 1].split()[1]] ldau_luj = {} for sym, l, j, u in zip(symbols, ldaul, ldauj, ldauu): ldau_luj[sym] = {'L': l, 'U': u, 'J': j} file_params['ldau_luj'] = ldau_luj if not {k: v for k, v in self.parameters.iteritems() if v is not None} == file_params: new_keys = set(self.parameters.keys()) - set(file_params.keys()) missing_keys = (set(file_params.keys()) - set(self.parameters.keys())) log.debug('New keys: {}'.format(new_keys)) log.debug('Missing keys: {}'.format(missing_keys)) log.debug('params_on_file do not match.') log.debug('file-params: {}'.format(file_params)) log.debug('compared to: {}'.format({k: v for k, v in self.parameters.iteritems() if v is not None})) system_changes += ['params_on_file'] log.debug('System changes: {}'.format(system_changes)) return system_changes
def reset(self): """overwrite to avoid killing self.atoms.""" log.debug('Resetting calculator.') self.results = {}
def calculate(self, atoms=None, properties=['energy'], system_changes=None): """Monkey patch to submit job through the queue. If this is called, then the calculator thinks a job should be run. If we are in the queue, we should run it, otherwise, a job should be submitted. """ log.debug('In queue: {}'.format(self.in_queue())) if self.in_queue(): raise VaspQueued('{} Queued: {}'.format(self.directory, self.get_db('jobid'))) if VASPRC['mode'] is None: log.debug('mode is None. not running') return if (not self.calculation_required(atoms, ['energy']) and not self.check_state()): print('No calculation_required.') self.read_results() return # The subclass implementation should first call this # implementation to set the atoms attribute. Calculator.calculate(self, atoms, properties, system_changes) self.write_input(atoms, properties, system_changes) if self.parameters.get('luse_vdw', False): kernel = os.path.join(self.directory, 'vdw_kernel.bindat') if not os.path.exists(kernel): os.symlink(VASPRC['vdw_kernel.bindat'], kernel) # if we are in the queue and vasp is called or if we want to use # mode='run' , we should just run the job. First, we consider how. if 'PBS_O_WORKDIR' in os.environ or VASPRC['mode'] == 'run': if 'PBS_NODEFILE' in os.environ: # we are in the queue. determine if we should run serial # or parallel NPROCS = len(open(os.environ['PBS_NODEFILE']).readlines()) log.debug('Found {0} PROCS'.format(NPROCS)) if NPROCS == 1: # no question. running in serial. vaspcmd = VASPRC['vasp.executable.serial'] log.debug('NPROCS = 1. running in serial') exitcode = os.system(vaspcmd) return exitcode else: # vanilla MPI run. multiprocessing does not work on more # than one node, and you must specify in VASPRC to use it if (VASPRC['queue.nodes'] > 1 or (VASPRC['queue.nodes'] == 1 and VASPRC['queue.ppn'] > 1 and (VASPRC['multiprocessing.cores_per_process'] == 'None'))): s = 'queue.nodes = {0}'.format(VASPRC['queue.nodes']) log.debug(s) log.debug('queue.ppn = {0}'.format(VASPRC['queue.ppn'])) mpc = VASPRC['multiprocessing.cores_per_process'] log.debug('multiprocessing.cores_per_process' '= {0}'.format(mpc)) log.debug('running vanilla MPI job') log.debug('MPI NPROCS = {}'.format(NPROCS)) vaspcmd = VASPRC['vasp.executable.parallel'] parcmd = 'mpirun -np %i %s' % (NPROCS, vaspcmd) exitcode = os.system(parcmd) return exitcode else: # we need to run an MPI job on cores_per_process if VASPRC['multiprocessing.cores_per_process'] == 1: log.debug('running single core multiprocessing job') vaspcmd = VASPRC['vasp.executable.serial'] exitcode = os.system(vaspcmd) elif VASPRC['multiprocessing.cores_per_process'] > 1: log.debug('running mpi multiprocessing job') NPROCS = VASPRC['multiprocessing.cores_per_process'] vaspcmd = VASPRC['vasp.executable.parallel'] parcmd = 'mpirun -np %i %s' % (NPROCS, vaspcmd) exitcode = os.system(parcmd) return exitcode else: # probably running at cmd line, in serial. try: cwd = os.getcwd() os.chdir(self.directory) vaspcmd = VASPRC['vasp.executable.serial'] status, output, err = getstatusoutput(vaspcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if status == 0: self.read_results() return True else: return output finally: os.chdir(cwd) # end # if you get here, a job is getting submitted CWD = os.getcwd() VASPDIR = self.directory script = """ #!/bin/bash cd {CWD} # this is the current working directory cd {VASPDIR} # this is the vasp directory runvasp.py # this is the vasp command #end""".format(**locals()) jobname = VASPDIR log.debug('{0} will be the jobname.'.format(jobname)) log.debug('-l nodes={0}:ppn={1}'.format(VASPRC['queue.nodes'], VASPRC['queue.ppn'])) cmdlist = ['{0}'.format(VASPRC['queue.command'])] cmdlist += ['-o', VASPDIR] cmdlist += [option for option in VASPRC['queue.options'].split()] cmdlist += ['-N', '{0}'.format(jobname), '-l', 'walltime={0}'.format(VASPRC['queue.walltime']), '-l', 'nodes={0}:ppn={1}'.format(VASPRC['queue.nodes'], VASPRC['queue.ppn']), '-l', 'mem={0}'.format(VASPRC['queue.mem'])] log.debug('{0}'.format(' '.join(cmdlist))) p = subprocess.Popen(cmdlist, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) log.debug(script) out, err = p.communicate(script) if out == '' or err != '': raise Exception('something went wrong in qsub:\n\n{0}'.format(err)) self.write_db(data={'jobid': out.strip()}) raise VaspSubmitted('{} submitted: {}'.format(self.directory, out.strip()))
def calculate(self, atoms=None, properties=['energy'], system_changes=None): """Monkey patch to submit job through the queue. If this is called, then the calculator thinks a job should be run. If we are in the queue, we should run it, otherwise, a job should be submitted. """ log.debug('In queue: {}'.format(self.in_queue())) if self.in_queue(): raise VaspQueued('{} Queued: {}'.format(self.directory, self.get_db('jobid'))) if VASPRC['mode'] is None: log.debug('mode is None. not running') return if (not self.calculation_required(atoms, ['energy']) and not self.check_state()): print('No calculation_required.') self.read_results() return # The subclass implementation should first call this # implementation to set the atoms attribute. Calculator.calculate(self, atoms, properties, system_changes) self.write_input(atoms, properties, system_changes) if self.parameters.get('luse_vdw', False): kernel = os.path.join(self.directory, 'vdw_kernel.bindat') if not os.path.exists(kernel): os.symlink(VASPRC['vdw_kernel.bindat'], kernel) # if we are in the queue and vasp is called or if we want to use # mode='run' , we should just run the job. First, we consider how. if 'PBS_O_WORKDIR' in os.environ or VASPRC['mode'] == 'run': if 'PBS_NODEFILE' in os.environ: # we are in the queue. determine if we should run serial # or parallel NPROCS = len(open(os.environ['PBS_NODEFILE']).readlines()) log.debug('Found {0} PROCS'.format(NPROCS)) if NPROCS == 1: # no question. running in serial. vaspcmd = VASPRC['vasp.executable.serial'] log.debug('NPROCS = 1. running in serial') exitcode = os.system(vaspcmd) return exitcode else: # vanilla MPI run. multiprocessing does not work on more # than one node, and you must specify in VASPRC to use it if (VASPRC['queue.nodes'] > 1 or (VASPRC['queue.nodes'] == 1 and VASPRC['queue.ppn'] > 1 and (VASPRC['multiprocessing.cores_per_process'] == 'None'))): s = 'queue.nodes = {0}'.format(VASPRC['queue.nodes']) log.debug(s) log.debug('queue.ppn = {0}'.format(VASPRC['queue.ppn'])) mpc = VASPRC['multiprocessing.cores_per_process'] log.debug('multiprocessing.cores_per_process' '= {0}'.format(mpc)) log.debug('running vanilla MPI job') log.debug('MPI NPROCS = {}'.format(NPROCS)) vaspcmd = VASPRC['vasp.executable.parallel'] parcmd = 'mpirun -np %i %s' % (NPROCS, vaspcmd) exitcode = os.system(parcmd) return exitcode else: # we need to run an MPI job on cores_per_process if VASPRC['multiprocessing.cores_per_process'] == 1: log.debug('running single core multiprocessing job') vaspcmd = VASPRC['vasp.executable.serial'] exitcode = os.system(vaspcmd) elif VASPRC['multiprocessing.cores_per_process'] > 1: log.debug('running mpi multiprocessing job') NPROCS = VASPRC['multiprocessing.cores_per_process'] vaspcmd = VASPRC['vasp.executable.parallel'] parcmd = 'mpirun -np %i %s' % (NPROCS, vaspcmd) exitcode = os.system(parcmd) return exitcode else: # probably running at cmd line, in serial. try: cwd = os.getcwd() os.chdir(self.directory) vaspcmd = VASPRC['vasp.executable.serial'] status, output, err = getstatusoutput(vaspcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if status == 0: self.read_results() return True else: return output finally: os.chdir(cwd) # end # if you get here, a job is getting submitted CWD = os.getcwd() VASPDIR = self.directory script = """ #!/bin/bash cd {CWD} # this is the current working directory cd {VASPDIR} # this is the vasp directory runvasp.py # this is the vasp command #end""".format(**locals()) jobname = VASPDIR log.debug('{0} will be the jobname.'.format(jobname)) log.debug('-l nodes={0}:ppn={1}'.format(VASPRC['queue.nodes'], VASPRC['queue.ppn'])) cmdlist = ['{0}'.format(VASPRC['queue.command'])] cmdlist += ['-o', VASPDIR] cmdlist += [option for option in VASPRC['queue.options'].split()] cmdlist += ['-N', '{0}'.format(jobname), '-l walltime={0}'.format(VASPRC['queue.walltime']), '-l nodes={0}:ppn={1}'.format(VASPRC['queue.nodes'], VASPRC['queue.ppn']), '-l mem={0}'.format(VASPRC['queue.mem'])] log.debug('{0}'.format(' '.join(cmdlist))) p = subprocess.Popen(cmdlist, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) log.debug(script) out, err = p.communicate(script) if out == '' or err != '': raise Exception('something went wrong in qsub:\n\n{0}'.format(err)) self.write_db(data={'jobid': out.strip()}) raise VaspSubmitted('{} submitted: {}'.format(self.directory, out.strip()))
def get_neb(self, npi=1): """Returns images, energies if available or runs the job. npi = cores per image for running the calculations. Default=1 show: if True show an NEB plot """ if self.in_queue(): return self.neb, [None for a in self.neb] calc_required = False # check for OUTCAR in each image dir for i in range(1, len(self.neb) - 1): wf = '{0}/OUTCAR'.format(str(i).zfill(2)) wf = os.path.join(self.directory, wf) if not os.path.exists(wf): calc_required = True break else: # there was an OUTCAR, now we need to check for # convergence. done = False with open(wf) as f: for line in f: if ('reached required accuracy - stopping structural' ' energy minimisation') in line: done = True break if not done: calc_required = True break if calc_required: # this creates the directories and files if needed. write out # all the images, including initial and final if not os.path.isdir(self.directory): os.makedirs(self.directory) self.set(images=len(self.neb) - 2) self.write_incar() self.write_kpoints() self.write_potcar() self.write_db() for i, atoms in enumerate(self.neb): # zero-padded directory name image_dir = os.path.join(self.directory, str(i).zfill(2)) if not os.path.isdir(image_dir): # create if needed. os.makedirs(image_dir) write_vasp('{0}/POSCAR'.format(image_dir), atoms[self.resort], symbol_count=self.symbol_count) # The first and last images need to have real calculators on # them so we can write out a DB entry. We need this so we can # get the energies on the end-points. Otherwise, there doesn't # seem to be a way to do that short of cloning the whole # calculation into the end-point directories. self.write_db(os.path.join(self.directory, '00/DB.db'), self.neb[0]) # print(self.neb) # import sys # sys.exit() self.write_db(os.path.join(self.directory, '{:02}/DB.db'.format(len(self.neb) - 1)), self.neb[-1]) VASPRC['queue.ppn'] = npi * (len(self.neb) - 2) log.debug('Running on %i cores', VASPRC['queue.ppn']) self.calculate() # this will raise VaspSubmitted return self.neb, [None for a in self.neb] ############################################# # now we are just retrieving results energies = [] import ase.io atoms0 = ase.io.read(os.path.join(self.directory, '00', 'DB.db')) energies += [atoms0.get_potential_energy()] for i in range(1, len(self.neb) - 1): atoms = ase.io.read(os.path.join(self.directory, str(i).zfill(2), 'CONTCAR'))[self.resort] self.neb[i].positions = atoms.positions self.neb[i].cell = atoms.cell energy = None with open(os.path.join(self.directory, str(i).zfill(2), 'OUTCAR')) as f: for line in f: if 'free energy TOTEN =' in line: energy = float(line.split()[4]) energies += [energy] fname = os.path.join(self.directory, '0{}/DB.db'.format(len(self.neb) - 1)) atoms_end = ase.io.read(fname) energies += [atoms_end.get_potential_energy()] energies = np.array(energies) energies -= energies[0] return (self.neb, np.array(energies))