def worker(db_settings, entry_id, workdir, target_forces, relaxator_params): pcdb = get_database(db_settings) pcm_log.info('[%s]: Starting relaxation. Target forces: %7.3e' % (str(entry_id), target_forces)) if pcdb.is_locked(entry_id): return else: pcdb.lock(entry_id) structure = pcdb.get_structure(entry_id) structure = structure.scale() print('relaxator_params', relaxator_params) relaxer = IonRelaxation(structure, workdir=workdir, target_forces=target_forces, waiting=False, binary=relaxator_params['binary'], encut=1.3, kp_grid=None, kp_density=1E4, relax_cell=True, max_calls=10) print('relaxing on:', relaxer.workdir) relaxer.run(relaxator_params['nmpiparal']) pcm_log.info('[%s]: Finished relaxation. Target forces: %7.3e' % (str(entry_id), target_forces)) filename = workdir + os.sep + 'OUTCAR' if os.path.isfile(filename): forces, stress, total_energy = relaxer.get_forces_stress_energy() if forces is not None: magnitude_forces = np.apply_along_axis(np.linalg.norm, 1, forces) print('Forces: Max: %9.3e Avg: %9.3e' % (np.max(magnitude_forces), np.average(magnitude_forces))) print('Stress: ', np.max(np.abs(stress.flatten()))) if forces is None: pcm_log.error('No forces found on %s' % filename) if stress is None: pcm_log.error('No stress found on %s' % filename) if total_energy is None: pcm_log.error('No total_energy found on %s' % filename) new_structure = relaxer.get_final_geometry() if forces is not None and stress is not None and total_energy is not None and new_structure is not None: pcm_log.info('[%s]: Updating properties' % str(entry_id)) pcdb.update(entry_id, structure=new_structure) te = total_energy pcdb.entries.update({'_id': entry_id}, { '$set': { 'status.relaxation': 'succeed', 'status.target_forces': target_forces, 'properties.forces': generic_serializer(forces), 'properties.stress': generic_serializer(stress), 'properties.energy': te, 'properties.energy_pa': te / new_structure.natom, 'properties.energy_pf': te / new_structure.get_composition().gcd } }) # Fingerprint # Update the fingerprints only if the two structures are really different diffnatom = structure.natom != new_structure.natom diffcell = np.max( np.abs((structure.cell - new_structure.cell).flatten())) diffreduced = np.max( np.abs((structure.reduced - new_structure.reduced).flatten())) if diffnatom != 0 or diffcell > 1E-7 or diffreduced > 1E-7: analysis = StructureAnalysis(new_structure, radius=50) x, ys = analysis.fp_oganov(delta=0.01, sigma=0.01) fingerprint = {'_id': entry_id} for k in ys: atomic_number1 = atomic_number(new_structure.species[k[0]]) atomic_number2 = atomic_number(new_structure.species[k[1]]) pair = '%06d' % min(atomic_number1 * 1000 + atomic_number2, atomic_number2 * 1000 + atomic_number1) fingerprint[pair] = list(ys[k]) if pcdb.db.fingerprints.find_one({'_id': entry_id}) is None: pcdb.db.fingerprints.insert(fingerprint) else: pcdb.db.fingerprints.update({'_id': entry_id}, fingerprint) else: pcm_log.debug('Original and new structures are very similar.') pcm_log.debug('Max diff cell: %10.3e' % np.max( np.absolute( (structure.cell - new_structure.cell).flatten()))) if structure.natom == new_structure.natom: pcm_log.debug( 'Max diff reduced coordinates: %10.3e' % np.max( np.absolute((structure.reduced - new_structure.reduced).flatten()))) else: pcdb.entries.update({'_id': entry_id}, {'$set': { 'status.relaxation': 'failed' }}) pcm_log.error( 'Bad data after relaxation. Tagging relaxation as failed') else: pcm_log.error('ERROR: File not found %s' % filename) pcm_log.info('[%s]: Unlocking the entry' % str(entry_id)) pcdb.unlock(entry_id)
def run(self): irun = 0 score = INITIAL_SCORE dftb = DFTBplus() dftb.initialize(workdir=self.workdir, structure=self.structure, kpoints=self.kpoints) dftb.set_slater_koster(search_paths=self.slater_path) dftb.basic_input() dftb.driver['LatticeOpt'] = False # Decreasing the target_forces to avoid the final static # calculation of raising too much the forces after symmetrization dftb.driver['MaxForceComponent'] = self.target_forces dftb.driver['ConvergentForcesOnly'] = True dftb.driver['MaxSteps'] = 100 dftb.hamiltonian['MaxSCCIterations'] = 20 dftb.set_inputs() print(('Launching DFTB+ with target force of %9.2E ' % dftb.driver['MaxForceComponent'])) dftb.run() if self.waiting: dftb.runner.wait() while True: if dftb.runner is not None and dftb.runner.poll() is not None: pcm_log.info('Execution completed. Return code %d' % dftb.runner.returncode) stdo = read_dftb_stdout(filename=self.workdir + os.sep + 'dftb_stdout.log') good_forces, good_stress = self.relaxation_status() if 'max_force' in stdo: print(( 'Converged: %s\t Max Force: %9.3e\t MaxForceComponent: %9.3e' % (stdo['ion_convergence'], stdo['max_force'], self.target_forces))) filename = dftb.workdir + os.sep + 'detailed.out' if not os.path.exists(filename): pcm_log.error('Could not find ' + filename) break if not good_forces and not good_stress: # This happens when all the SCC are completed without convergence dftb.driver['ConvergentForcesOnly'] = False else: dftb.driver['ConvergentForcesOnly'] = True score = self.quality(score) pcm_log.debug('Score : %d Good Forces: %s Good Stress: %s' % (score, good_forces, good_stress)) if score < 0: if good_forces and good_stress: pcm_log.debug('Convergence: Internals + Cell') dftb.driver['MovedAtoms'] = '1:-1' dftb.driver['LatticeOpt'] = True elif not good_forces and good_stress: pcm_log.debug('Convergence: Internals') dftb.driver['LatticeOpt'] = False dftb.driver['MovedAtoms'] = '1:-1' elif good_forces and not good_stress: pcm_log.debug('Convergence: Internals + Cell') dftb.driver['LatticeOpt'] = True dftb.driver['MovedAtoms'] = '1:-1' dftb.structure = read_geometry_gen(dftb.workdir + os.sep + 'geo_end.gen') # lets change the positions if the score have lowered to -10 if score == -10 and self.forced: dftb.structure.positions += 0.2 * np.random.rand( dftb.structure.natom, 3) - 0.1 dftb.structure.positions2reduced() dftb.structure.set_cell(1.1 * dftb.structure.cell) if score == -1 and self.forced: dftb.structure = dftb.structure.random_cell( dftb.structure.composition) print('RANDOM STRUCTURE') print((dftb.structure)) score = INITIAL_SCORE dftb.structure.save_json(dftb.workdir + os.sep + 'structure_current.json') if self.symmetrize: dftb.structure = symmetrize(dftb.structure) self.structure = dftb.structure dftb.get_geometry() dftb.roll_outputs(irun) dftb.set_inputs() irun += 1 print(('Launching DFTB+ with target force of %9.2E ' % dftb.driver['MaxForceComponent'])) dftb.run() if self.waiting: dftb.runner.wait() else: pcm_log.debug('Final static calculation') dftb.structure = self.get_final_geometry() dftb.structure.save_json(dftb.workdir + os.sep + 'structure_final.json') if self.symmetrize: dftb.structure = symmetrize(dftb.structure) self.structure = dftb.structure dftb.get_geometry() dftb.roll_outputs(irun) dftb.options['CalculateForces'] = True dftb.driver = {} dftb.set_inputs() print('Launching DFTB+ with static evaluation of forces ') dftb.run() if self.waiting: dftb.runner.wait() while dftb.runner.poll() is None: dftb.run_status() time.sleep(10) print('Completed Static run') forces, stress, total_energy = self.get_forces_stress_energy( ) if stress is None or forces is None or total_energy is None: pcm_log.debug( 'Null Forces, Stress or Energy, relaxing and exiting' ) dftb.basic_input() dftb.driver['LatticeOpt'] = False # Decreasing the target_forces to avoid the final static # calculation of raising too much the forces after symmetrization dftb.driver[ 'MaxForceComponent'] = 0.9 * self.target_forces dftb.driver['ConvergentForcesOnly'] = False dftb.driver['MaxSteps'] = 10 dftb.hamiltonian['MaxSCCIterations'] = 50 print((dftb.driver)) dftb.set_inputs() dftb.run() if self.waiting: dftb.runner.wait() while dftb.runner.poll() is None: time.sleep(10) print(('FINAL:', read_detailed_out(filename=filename))) forces, stress, total_energy = self.get_forces_stress_energy( ) if stress is None or forces is None or total_energy is None: pcm_log.debug( 'Again Null Forces, Stress or Energy, Randomizing Structure' ) dftb.structure = dftb.structure.random_cell( dftb.structure.composition) print('RANDOM STRUCTURE') print((dftb.structure)) score = INITIAL_SCORE else: break else: break else: pcm_log.debug('ID: %s' % os.path.basename(self.workdir)) filename = dftb.workdir + os.sep + 'dftb_stdout.log' if os.path.exists(filename): stdo = read_dftb_stdout(filename=filename) print(('Number of steps:', len(stdo['Geometry_Steps']))) if len(stdo['Geometry_Steps']) > 1: line = 'Energy behavior: ' prev_energy = stdo['Geometry_Steps'][0][ 'Total Energy']['value'] line += ' %7.3f ' % prev_energy for step in stdo['Geometry_Steps'][1:]: new_energy = step['Total Energy']['value'] if prev_energy > new_energy: line += '>' else: line += '<' prev_energy = new_energy finene = stdo['Geometry_Steps'][-1]['Total Energy'][ 'value'] line += ' %7.3f' % finene print(line) time.sleep(10)
def outcar_parser(self): for istr in ['NKPTS', 'NBANDS', 'NEDOS', 'NIONS', 'NGX', 'NGY', 'NGZ', 'NGXF', 'NGYF', 'NGZF', 'ISPIN']: redata = re.findall(istr + r'\s*=\s*(\d+)', self.data) if len(redata) > 0: self.array_sizes[istr] = int(redata[0]) # pcm_log.info('Array sizes : ' + str(self.array_sizes)) self.species = re.findall(r'POTCAR\s*:\s*[\w_]+\s*(\w+)', self.data) self.species = self.species[:int(len(self.species) / 2)] # pcm_log.info('Number of species (= number of POTCARs):' + str(self.species)) pos_forces = re.findall(r'TOTAL-FORCE \(eV/Angst\)\s*-*\s*([-.\d\s]+)\s+-{2}', self.data) pos_forces = np.array([x.split() for x in pos_forces], dtype=float) if len(pos_forces) > 0 and len(pos_forces[-1]) % 6 == 0: pos_forces.shape = (len(pos_forces), -1, 6) forces = pos_forces[:, :, 3:] positions = pos_forces[:, :, :3] pcm_log.debug('Positions from OUTCAR: %d iterations' % len(positions)) pcm_log.debug('Forces from OUTCAR: %d iterations' % len(forces)) self.forces = forces self.positions = positions self.array_sizes['NIONSTEPS'] = len(self.forces) pcm_log.debug('Number of Ionic steps: ' + str(self.array_sizes['NIONSTEPS'])) else: print('Forces and Positions could not be parsed : ', pos_forces.shape) print('pos_forces =\n%s ' % pos_forces) fermi = re.findall(r'E-fermi\s+:\s+([-.\d]+)', self.data) fermi = np.array(fermi, dtype=float) # pcm_log.debug('Fermi Level(eV): ' + str(fermi)) self.fermi = fermi # This regex covers the entire information for each electronic iteration. # The expression in the middle, catch everything but ('>' greater than) # The final part catch the value of the energy # It returns a list of tuples in the form [(ionic iter, Energy (elect. Iter), ...] energy = re.findall(r'Iteration\s*(\d+)\s*\(\s*(\d+)\)[-+*/=():.\s\d\w]+>0\)\s*=\s*([-.\d]+)', self.data) # pcm_log.debug('Energy(eV) [(ionic iter, Energy (elect. Iter)),...]: ' + str(energy)) self.energies = [] index = None for ienergy in energy: self.energies.append([int(ienergy[0]), int(ienergy[1]), float(ienergy[2])]) level0 = 0 level1 = 0 for i in self.energies: if i[0] > level0: self.last_energy = i[2] level0 = i[0] elif i[0] == level0 and i[1] > level1: self.last_energy = i[2] level1 = i[1] pattern = r"k-point([\s\d]+):([\d\s.+-]+)\s*band No.\s*band energies\s*occupation\s*\n([\d\w\s.+-]+)\n\n" bands = re.findall(pattern, self.data) bands_dict = {} for iband in bands: try: ikpt = int(iband[0]) kpt_pos = [float(x) for x in iband[1].split()] kpt_eigenvals = np.array([float(x) for x in iband[2].split()[:3 * self.array_sizes['NBANDS']]]) kpt_eigenvals.reshape((-1, 3)) bands_dict[ikpt] = {'position': kpt_pos, 'eigenvalues': kpt_eigenvals} except ValueError: print('Error parsing bands') self.bands = bands_dict if False and 'NIONSTEPS' in self.array_sizes: if len(bands) != self.array_sizes['NBANDS'] * self.array_sizes['ISPIN'] * self.array_sizes['NKPTS'] \ * self.array_sizes['NIONSTEPS']: pcm_log.debug('NBANDS: %s != ISPIN: %s x NKPTS: %s x NIONSTEPS: %s' % (self.array_sizes['NBANDS'], self.array_sizes['ISPIN'], self.array_sizes['NKPTS'], self.array_sizes['NIONSTEPS'])) # pcm_log.info('Bands : ' + str(bands)) stress = re.findall(r'in\s+kB ([-*.\s\d]+)external', self.data) # Converted from kBar to GPa if stress: stress = 0.1 * np.array([x.split() if '*' not in x else 6 * [float('nan')] for x in stress], dtype=float) stress.reshape((-1, 6)) nionsteps = len(stress) self.stress = np.zeros((nionsteps, 3, 3)) self.stress[:, 0, 0] = stress[:, 0] self.stress[:, 1, 1] = stress[:, 1] self.stress[:, 2, 2] = stress[:, 2] self.stress[:, 0, 1] = stress[:, 3] self.stress[:, 1, 2] = stress[:, 4] self.stress[:, 0, 2] = stress[:, 5] self.stress[:, 1, 0] = stress[:, 3] self.stress[:, 2, 1] = stress[:, 4] self.stress[:, 2, 0] = stress[:, 5] # pcm_log.info('Stress (GPa):\n ' + str(self.stress)) charge = re.findall(r'total\s*charge\s*#\s*of\s*ion\s*s\s*p\s*d\s*tot\s*-+([-.\s\d]+)\s--', self.data) if charge: charge = np.array([x.split() for x in charge], dtype=float) charge.shape = (len(charge), -1, 5) if len(charge) == 2: if np.all(charge[0] != charge[1]): pcm_log.error('Bad Charge') charge = charge[0, :, 1:] self.charge['s'] = list(charge[:, 0]) self.charge['p'] = list(charge[:, 1]) self.charge['d'] = list(charge[:, 2]) self.charge['total'] = list(charge[:, 3]) # pcm_log.debug('Charge :' + str(self.charge)) # Processing Final self.free_energy() self.iterations()
def worker(db_settings, entry_id, workdir, target_forces, relaxator_params): pcdb = get_database(db_settings) pcm_log.info('[%s]: Starting relaxation. Target forces: %7.3e' % (str(entry_id), target_forces)) if pcdb.is_locked(entry_id): return else: pcdb.lock(entry_id) structure = pcdb.get_structure(entry_id) structure = structure.scale() print('relaxator_params', relaxator_params) relaxer = IonRelaxation2(structure, workdir=workdir, target_forces=target_forces, waiting=False, binary=relaxator_params['binary'], encut=1.3, kp_grid=None, kp_density=1E4, relax_cell=True) print('relaxing on:', relaxer.workdir) relaxer.run(relaxator_params['nmpiparal']) pcm_log.info('[%s]: Finished relaxation. Target forces: %7.3e' % (str(entry_id), target_forces)) filename = workdir + os.sep + 'OUTCAR' if os.path.isfile(filename): forces, stress, total_energy = relaxer.get_forces_stress_energy() if forces is not None: magnitude_forces = np.apply_along_axis(np.linalg.norm, 1, forces) print('Forces: Max: %9.3e Avg: %9.3e' % (np.max(magnitude_forces), np.average(magnitude_forces))) print('Stress: ', np.max(np.abs(stress.flatten()))) if forces is None: pcm_log.error('No forces found on %s' % filename) if stress is None: pcm_log.error('No stress found on %s' % filename) if total_energy is None: pcm_log.error('No total_energy found on %s' % filename) new_structure = relaxer.get_final_geometry() if forces is not None and stress is not None and total_energy is not None and new_structure is not None: pcm_log.info('[%s]: Updating properties' % str(entry_id)) pcdb.update(entry_id, structure=new_structure) te = total_energy pcdb.entries.update({'_id': entry_id}, {'$set': {'status.relaxation': 'succeed', 'status.target_forces': target_forces, 'properties.forces': generic_serializer(forces), 'properties.stress': generic_serializer(stress), 'properties.energy': te, 'properties.energy_pa': te / new_structure.natom, 'properties.energy_pf': te / new_structure.get_composition().gcd}}) # Fingerprint # Update the fingerprints only if the two structures are really different diffnatom = structure.natom != new_structure.natom diffcell = np.max(np.abs((structure.cell - new_structure.cell).flatten())) diffreduced = np.max(np.abs((structure.reduced - new_structure.reduced).flatten())) if diffnatom != 0 or diffcell > 1E-7 or diffreduced > 1E-7: analysis = StructureAnalysis(new_structure, radius=50) x, ys = analysis.fp_oganov(delta=0.01, sigma=0.01) fingerprint = {'_id': entry_id} for k in ys: atomic_number1 = atomic_number(new_structure.species[k[0]]) atomic_number2 = atomic_number(new_structure.species[k[1]]) pair = '%06d' % min(atomic_number1 * 1000 + atomic_number2, atomic_number2 * 1000 + atomic_number1) fingerprint[pair] = list(ys[k]) if pcdb.db.fingerprints.find_one({'_id': entry_id}) is None: pcdb.db.fingerprints.insert(fingerprint) else: pcdb.db.fingerprints.update({'_id': entry_id}, fingerprint) else: pcm_log.debug('Original and new structures are very similar.') pcm_log.debug('Max diff cell: %10.3e' % np.max(np.absolute((structure.cell - new_structure.cell).flatten()))) if structure.natom == new_structure.natom: pcm_log.debug('Max diff reduced coordinates: %10.3e' % np.max(np.absolute((structure.reduced - new_structure.reduced).flatten()))) else: pcdb.entries.update({'_id': entry_id}, {'$set': {'status.relaxation': 'failed'}}) pcm_log.error('Bad data after relaxation. Tagging relaxation as failed') else: pcm_log.error('ERROR: File not found %s' % filename) pcm_log.info('[%s]: Unlocking the entry' % str(entry_id)) pcdb.unlock(entry_id)
def outcar_parser(self): for istr in ['NKPTS', 'NBANDS', 'NEDOS', 'NIONS', 'NGX', 'NGY', 'NGZ', 'NGXF', 'NGYF', 'NGZF', 'ISPIN']: redata = re.findall(istr + r'\s*=\s*(\d+)', self.data) if len(redata) > 0: self.array_sizes[istr] = int(redata[0]) # pcm_log.info('Array sizes : ' + str(self.array_sizes)) self.species = re.findall(r'POTCAR\s*:\s*[\w_]+\s*(\w+)', self.data) self.species = self.species[:int(len(self.species) / 2)] # pcm_log.info('Number of species (= number of POTCARs):' + str(self.species)) pos_forces = re.findall(r'TOTAL-FORCE \(eV/Angst\)\s*-*\s*([-.\d\s]+)\s+-{2}', self.data) pos_forces = np.array([x.split() for x in pos_forces], dtype=float) if len(pos_forces) > 0 and len(pos_forces[-1]) % 6 == 0: pos_forces.shape = (len(pos_forces), -1, 6) forces = pos_forces[:, :, 3:] positions = pos_forces[:, :, :3] pcm_log.debug('Positions from OUTCAR: %d iterations' % len(positions)) pcm_log.debug('Forces from OUTCAR: %d iterations' % len(forces)) self.forces = forces self.positions = positions self.array_sizes['NIONSTEPS'] = len(self.forces) pcm_log.debug('Number of Ionic steps: ' + str(self.array_sizes['NIONSTEPS'])) else: print(('Forces and Positions could not be parsed : ', pos_forces.shape)) print(('pos_forces =\n%s ' % pos_forces)) fermi = re.findall(r'E-fermi\s+:\s+([-.\d]+)', self.data) fermi = np.array(fermi, dtype=float) # pcm_log.debug('Fermi Level(eV): ' + str(fermi)) self.fermi = fermi # This regex covers the entire information for each electronic iteration. # The expression in the middle, catch everything but ('>' greater than) # The final part catch the value of the energy # It returns a list of tuples in the form [(ionic iter, Energy (elect. Iter), ...] energy = re.findall(r'Iteration\s*(\d+)\s*\(\s*(\d+)\)[-+*/=():.\s\d\w]+>0\)\s*=\s*([-.\d]+)', self.data) # pcm_log.debug('Energy(eV) [(ionic iter, Energy (elect. Iter)),...]: ' + str(energy)) self.energies = [] index = None for ienergy in energy: self.energies.append([int(ienergy[0]), int(ienergy[1]), float(ienergy[2])]) level0 = 0 level1 = 0 for i in self.energies: if i[0] > level0: self.last_energy = i[2] level0 = i[0] elif i[0] == level0 and i[1] > level1: self.last_energy = i[2] level1 = i[1] pattern = r"k-point([\s\d]+):([\d\s.+-]+)\s*band No.\s*band energies\s*occupation\s*\n([\d\w\s.+-]+)\n\n" bands = re.findall(pattern, self.data) bands_dict = {} for iband in bands: try: ikpt = int(iband[0]) kpt_pos = [float(x) for x in iband[1].split()] kpt_eigenvals = np.array([float(x) for x in iband[2].split()[:3 * self.array_sizes['NBANDS']]]) kpt_eigenvals.reshape((-1, 3)) bands_dict[ikpt] = {'position': kpt_pos, 'eigenvalues': kpt_eigenvals} except ValueError: print('Error parsing bands') self.bands = bands_dict if False and 'NIONSTEPS' in self.array_sizes: if len(bands) != self.array_sizes['NBANDS'] * self.array_sizes['ISPIN'] * self.array_sizes['NKPTS'] \ * self.array_sizes['NIONSTEPS']: pcm_log.debug('NBANDS: %s != ISPIN: %s x NKPTS: %s x NIONSTEPS: %s' % (self.array_sizes['NBANDS'], self.array_sizes['ISPIN'], self.array_sizes['NKPTS'], self.array_sizes['NIONSTEPS'])) # pcm_log.info('Bands : ' + str(bands)) stress = re.findall(r'in\s+kB ([-*.\s\d]+)external', self.data) # Converted from kBar to GPa if stress: stress = 0.1 * np.array([x.split() if '*' not in x else 6 * [float('nan')] for x in stress], dtype=float) stress.reshape((-1, 6)) nionsteps = len(stress) self.stress = np.zeros((nionsteps, 3, 3)) self.stress[:, 0, 0] = stress[:, 0] self.stress[:, 1, 1] = stress[:, 1] self.stress[:, 2, 2] = stress[:, 2] self.stress[:, 0, 1] = stress[:, 3] self.stress[:, 1, 2] = stress[:, 4] self.stress[:, 0, 2] = stress[:, 5] self.stress[:, 1, 0] = stress[:, 3] self.stress[:, 2, 1] = stress[:, 4] self.stress[:, 2, 0] = stress[:, 5] # pcm_log.info('Stress (GPa):\n ' + str(self.stress)) charge = re.findall(r'total\s*charge\s*#\s*of\s*ion\s*s\s*p\s*d\s*tot\s*-+([-.\s\d]+)\s--', self.data) if charge: charge = np.array([x.split() for x in charge], dtype=float) charge.shape = (len(charge), -1, 5) if len(charge) == 2: if np.all(charge[0] != charge[1]): pcm_log.error('Bad Charge') charge = charge[0, :, 1:] self.charge['s'] = list(charge[:, 0]) self.charge['p'] = list(charge[:, 1]) self.charge['d'] = list(charge[:, 2]) self.charge['total'] = list(charge[:, 3]) # pcm_log.debug('Charge :' + str(self.charge)) # Processing Final self.free_energy() self.iterations()
def run(self): irun = 0 score = INITIAL_SCORE dftb = DFTBplus() dftb.initialize(workdir=self.workdir, structure=self.structure, kpoints=self.kpoints) dftb.set_slater_koster(search_paths=self.slater_path) dftb.basic_input() dftb.driver['LatticeOpt'] = False # Decreasing the target_forces to avoid the final static # calculation of raising too much the forces after symmetrization dftb.driver['MaxForceComponent'] = self.target_forces dftb.driver['ConvergentForcesOnly'] = True dftb.driver['MaxSteps'] = 100 dftb.hamiltonian['MaxSCCIterations'] = 20 dftb.set_inputs() print('Launching DFTB+ with target force of %9.2E ' % dftb.driver['MaxForceComponent']) dftb.run() if self.waiting: dftb.runner.wait() while True: if dftb.runner is not None and dftb.runner.poll() is not None: pcm_log.info('Execution completed. Return code %d' % dftb.runner.returncode) stdo = read_dftb_stdout(filename=self.workdir + os.sep + 'dftb_stdout.log') good_forces, good_stress = self.relaxation_status() if 'max_force' in stdo: print('Converged: %s\t Max Force: %9.3e\t MaxForceComponent: %9.3e' % (stdo['ion_convergence'], stdo['max_force'], self.target_forces)) filename = dftb.workdir + os.sep + 'detailed.out' if not os.path.exists(filename): pcm_log.error('Could not find ' + filename) break if not good_forces and not good_stress: # This happens when all the SCC are completed without convergence dftb.driver['ConvergentForcesOnly'] = False else: dftb.driver['ConvergentForcesOnly'] = True score = self.quality(score) pcm_log.debug('Score : %d Good Forces: %s Good Stress: %s' % (score, good_forces, good_stress)) if score < 0: if good_forces and good_stress: pcm_log.debug('Convergence: Internals + Cell') dftb.driver['MovedAtoms'] = '1:-1' dftb.driver['LatticeOpt'] = True elif not good_forces and good_stress: pcm_log.debug('Convergence: Internals') dftb.driver['LatticeOpt'] = False dftb.driver['MovedAtoms'] = '1:-1' elif good_forces and not good_stress: pcm_log.debug('Convergence: Internals + Cell') dftb.driver['LatticeOpt'] = True dftb.driver['MovedAtoms'] = '1:-1' dftb.structure = read_geometry_gen(dftb.workdir + os.sep + 'geo_end.gen') # lets change the positions if the score have lowered to -10 if score == -10 and self.forced: dftb.structure.positions += 0.2 * np.random.rand(dftb.structure.natom, 3) - 0.1 dftb.structure.positions2reduced() dftb.structure.set_cell(1.1 * dftb.structure.cell) if score == -1 and self.forced: dftb.structure = dftb.structure.random_cell(dftb.structure.composition) print('RANDOM STRUCTURE') print(dftb.structure) score = INITIAL_SCORE dftb.structure.save_json(dftb.workdir + os.sep + 'structure_current.json') if self.symmetrize: dftb.structure = symmetrize(dftb.structure) self.structure = dftb.structure dftb.get_geometry() dftb.roll_outputs(irun) dftb.set_inputs() irun += 1 print('Launching DFTB+ with target force of %9.2E ' % dftb.driver['MaxForceComponent']) dftb.run() if self.waiting: dftb.runner.wait() else: pcm_log.debug('Final static calculation') dftb.structure = self.get_final_geometry() dftb.structure.save_json(dftb.workdir + os.sep + 'structure_final.json') if self.symmetrize: dftb.structure = symmetrize(dftb.structure) self.structure = dftb.structure dftb.get_geometry() dftb.roll_outputs(irun) dftb.options['CalculateForces'] = True dftb.driver = {} dftb.set_inputs() print('Launching DFTB+ with static evaluation of forces ') dftb.run() if self.waiting: dftb.runner.wait() while dftb.runner.poll() is None: dftb.run_status() time.sleep(10) print('Completed Static run') forces, stress, total_energy = self.get_forces_stress_energy() if stress is None or forces is None or total_energy is None: pcm_log.debug('Null Forces, Stress or Energy, relaxing and exiting') dftb.basic_input() dftb.driver['LatticeOpt'] = False # Decreasing the target_forces to avoid the final static # calculation of raising too much the forces after symmetrization dftb.driver['MaxForceComponent'] = 0.9 * self.target_forces dftb.driver['ConvergentForcesOnly'] = False dftb.driver['MaxSteps'] = 10 dftb.hamiltonian['MaxSCCIterations'] = 50 print(dftb.driver) dftb.set_inputs() dftb.run() if self.waiting: dftb.runner.wait() while dftb.runner.poll() is None: time.sleep(10) print('FINAL:', read_detailed_out(filename=filename)) forces, stress, total_energy = self.get_forces_stress_energy() if stress is None or forces is None or total_energy is None: pcm_log.debug('Again Null Forces, Stress or Energy, Randomizing Structure') dftb.structure = dftb.structure.random_cell(dftb.structure.composition) print('RANDOM STRUCTURE') print(dftb.structure) score = INITIAL_SCORE else: break else: break else: pcm_log.debug('ID: %s' % os.path.basename(self.workdir)) filename = dftb.workdir + os.sep + 'dftb_stdout.log' if os.path.exists(filename): stdo = read_dftb_stdout(filename=filename) print('Number of steps:', len(stdo['Geometry_Steps'])) if len(stdo['Geometry_Steps']) > 1: line = 'Energy behavior: ' prev_energy = stdo['Geometry_Steps'][0]['Total Energy']['value'] line += ' %7.3f ' % prev_energy for step in stdo['Geometry_Steps'][1:]: new_energy = step['Total Energy']['value'] if prev_energy > new_energy: line += '>' else: line += '<' prev_energy = new_energy finene = stdo['Geometry_Steps'][-1]['Total Energy']['value'] line += ' %7.3f' % finene print(line) time.sleep(10)