def __init__(self, structure): """ Creates a new StructureSymmetry object for a given structure This class allows interaction with spglib for several operations related to symmetry :param structure: Example: >>> import pychemia >>> a = 4.05 >>> b = a/2 >>> fcc = pychemia.Structure(symbols=['Au'], cell=[[0, b, b], [b, 0, b], [b, b, 0]], periodicity=True) >>> symm = pychemia.crystal.CrystalSymmetry(fcc) >>> symm.number() 225 >>> symm.symbol() == u'Fm-3m' True """ assert structure.is_crystal assert structure.is_perfect self.structure = structure # Spglib"s convention for the lattice definition is the transpose of cell # self._transposed_cell = structure.cell.transpose().copy() self.spglib_lattice = generic_serializer(structure.cell.copy()) # Spglib requires numpy floats. # self._transposed_cell = np.array(self._transposed_cell, dtype='double', order='C') # self._reduced = np.array(structure.reduced, dtype='double', order='C') self.spglib_positions = generic_serializer(structure.reduced) # Get a list of indices for each atom in structure # Indices starting in 1 # self._numbers = np.array([structure.species.index(x) + 1 for x in structure.symbols], dtype='intc') self.spglib_numbers = [structure.species.index(x) + 1 for x in structure.symbols]
def evaluate(self, imember): entry = self.population.get_entry(imember) pcm_structure = pychemia.Structure.from_dict(entry['structure']) ase_structure = pychemia.external.ase.pychemia2ase(pcm_structure) ase_structure.set_calculator(LennardJones()) dyn = QuasiNewton(ase_structure) dyn.run() ase_structure.set_constraint( FixAtoms(mask=[True for atom in ase_structure])) ucf = UnitCellFilter(ase_structure) qn = QuasiNewton(ucf) qn.run() new_structure = pychemia.external.ase.ase2pychemia(ase_structure) energy = ase_structure.get_potential_energy() forces = ase_structure.get_forces() stress = ase_structure.get_stress() new_properties = { 'energy': float(energy), 'forces': generic_serializer(forces), 'stress': generic_serializer(stress) } self.population.db.update(imember, structure=new_structure, properties=new_properties)
def run(self, nparal=4): vj = VaspJob() vj.initialize(self.structure, self.workdir, self.kpoints, binary=self.binary) vj.clean() vj.job_static() vj.input_variables.set_density_for_restart() vj.input_variables.set_encut(ENCUT=self.encut, POTCAR=self.workdir + os.sep + 'POTCAR') vj.input_variables.variables['NBANDS'] = nparal * ((int(self.structure.valence_electrons()) + self.structure.natom) / nparal + 1) vj.input_variables.set_ismear(self.kpoints) vj.input_variables.variables['SIGMA'] = 0.2 vj.input_variables.variables['ISPIN'] = 2 if self.task_params['extra_incar'] is not None: for i in self.task_params['extra_incar']: vj.input_variables.variables[i] = self.task_params['extra_incar'][i] vj.set_inputs() self.encut = vj.input_variables.variables['ENCUT'] vj.run(use_mpi=True, mpi_num_procs=nparal) pcm_log.debug('Starting VASP') while True: energy_str = '' filename = self.workdir + os.sep + 'vasp_stdout.log' if os.path.exists(filename): vasp_stdout = read_vasp_stdout(filename=filename) if len(vasp_stdout['data']) > 2: scf_energies = [i[2] for i in vasp_stdout['data']] energy_str = ' %7.3f' % scf_energies[1] for i in range(1, len(scf_energies)): if scf_energies[i] < scf_energies[i - 1]: energy_str += ' >' else: energy_str += ' <' pcm_log.debug(energy_str) if vj.runner is not None and vj.runner.poll() is not None: filename = self.workdir + os.sep + 'vasp_stdout.log' if os.path.exists(filename): vasp_stdout = read_vasp_stdout(filename=filename) if len(vasp_stdout['data']) > 2: scf_energies = [i[2] for i in vasp_stdout['data']] energy_str += ' %7.3f' % scf_energies[-1] pcm_log.debug(energy_str) pcm_log.debug('Execution complete') break time.sleep(5) vj.get_outputs() self.output = {'forces': generic_serializer(vj.outcar.forces), 'stress': generic_serializer(vj.outcar.stress), 'energy': vj.outcar.energy, 'energies': generic_serializer(vj.outcar.energies), 'INCAR': vj.input_variables.variables} if vj.outcar.is_finished: self.finished = True
def test_serializer(self): """ Test (pychemia.utils.serializer) : """ a = np.array([1, 2, 3]) assert generic_serializer(a) == [1, 2, 3] b = np.array([[1, 2, 3], [4, 5, 6]]) assert generic_serializer(b) == [[1, 2, 3], [4, 5, 6]] c = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [0, 1, 2]]]) assert generic_serializer(c) == [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [0, 1, 2]]] mydict = {'a': a, 'b': b, 'c': c} assert generic_serializer(mydict) == {u'a': [1, 2, 3], u'b': [[1, 2, 3], [4, 5, 6]], u'c': [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [0, 1, 2]]]}
def test_serializer(self): """ Tests (pychemia.utils.serializer) : """ a = np.array([1, 2, 3]) assert generic_serializer(a) == [1, 2, 3] b = np.array([[1, 2, 3], [4, 5, 6]]) assert generic_serializer(b) == [[1, 2, 3], [4, 5, 6]] c = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [0, 1, 2]]]) assert generic_serializer(c) == [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [0, 1, 2]]] mydict = {'a': a, 'b': b, 'c': c} generic_serializer(mydict) == {u'a': [1, 2, 3], u'b': [[1, 2, 3], [4, 5, 6]], u'c': [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [0, 1, 2]]]}
def set_kpoints_list(self, kpoints_list, weights=None): """ Set an explicit list of kpoints with a proper check of correct arguments :param kpoints_list: Explicit list of k-points (Only for 'cartesian' and 'reduced') :param weights: List of weights associated to each k-point (Only for 'cartesian' and 'reduced') """ assert (self.kmode in ['cartesian', 'reduced']) if kpoints_list is None: self.kpoints_list = [[0, 0, 0]] else: if np.array(kpoints_list).shape == (3, ): self.kpoints_list = np.array(kpoints_list).reshape((-1, 3)) elif np.array(kpoints_list).shape[1] == 3: self.kpoints_list = np.array(kpoints_list) else: raise ValueError( "Wrong value for kpoints_list, should be an array with shape (nkpt,3)" ) self.kpoints_list = generic_serializer(self.kpoints_list) nkpt = len(self.kpoints_list) if weights is None: self.weights = np.ones(nkpt) elif len(np.array(weights)) == nkpt: self.weights = np.array(weights) else: raise ValueError( "Wrong value for weights, should be an array with shape (nkpt,)" ) self.weights = list(self.weights)
def cluster_fb_worker(db_settings): while True: pcdb = pychemia.db.get_database(db_settings) population = pychemia.population.LJCluster(pcdb) entry = population.pcdb.db.pychemia_entries.find_one({'status.' + population.tag: True, 'status.lock': {'$exists': False}, 'properties': {}}, {'_id': 1}) if entry is not None: population.pcdb.lock(entry['_id']) structure = population.pcdb.get_structure(entry['_id']) fb = pychemia.code.fireball.FireBall(fdata_path='../Fdata') fb.initialize(structure, workdir=str(entry['_id'])) fb.cluster_relaxation() fb.set_inputs() sp = fb.run() sp.wait() so = pychemia.code.fireball.read_fireball_stdout(fb.workdir + os.sep + 'fireball.log') forces = generic_serializer(so['forces'][-1]) energy = so['energy'][-1]['ETOT'] properties = {'forces': forces, 'energy': energy} structure = pychemia.code.fireball.read_geometry_bas(fb.workdir + os.sep + 'answer.bas') population.pcdb.update(entry['_id'], structure=structure, properties=properties) population.pcdb.unlock(entry['_id']) else: break
def move_random(self, entry_id, factor=0.2, in_place=False, kind='move'): entry = self.get_entry(entry_id) pos = np.array(entry['structure']['positions']).reshape((-1, 3)) # Unit Vectors uv = pychemia.utils.mathematics.unit_vectors( 2 * np.random.rand(*pos.shape) - 1) new_pos = generic_serializer(pos + factor * uv) structure = pychemia.Structure(positions=new_pos, symbols=entry['structure']['symbols'], periodicity=False) if in_place: return self.pcdb.db.pychemia_entries.update_one( {'_id': entry_id}, {'$set': { 'structure': structure.to_dict, 'properties': {} }}) else: structure = pychemia.Structure( positions=new_pos, symbols=entry['structure']['symbols'], periodicity=False) return self.new_entry(structure, active=False)
def set_kpoints_list(self, kpoints_list, weights=None): """ Set an explicit list of kpoints with a proper check of correct arguments :param kpoints_list: Explicit list of k-points (Only for 'cartesian' and 'reduced') :param weights: List of weights associated to each k-point (Only for 'cartesian' and 'reduced') """ assert (self.kmode in ['cartesian', 'reduced']) if kpoints_list is None: self.kpoints_list = [[0, 0, 0]] else: if np.array(kpoints_list).shape == (3,): self.kpoints_list = np.array(kpoints_list).reshape((-1, 3)) elif np.array(kpoints_list).shape[1] == 3: self.kpoints_list = np.array(kpoints_list) else: raise ValueError("Wrong value for kpoints_list, should be an array with shape (nkpt,3)") self.kpoints_list = generic_serializer(self.kpoints_list) nkpt = len(self.kpoints_list) if weights is None: self.weights = np.ones(nkpt) elif len(np.array(weights)) == nkpt: self.weights = np.array(weights) else: raise ValueError("Wrong value for weights, should be an array with shape (nkpt,)") self.weights = list(self.weights)
def read_fireball_stdout(filename): rf = open(filename, 'r') data = rf.read() atom_data = re.findall(r'Atom Coordinates from Basis File:([\d\w\s=\-\.#]+)===\n', data)[0] symbols = [] positions = [] for iline in atom_data.split('\n'): # print iline tmp = iline.split() if len(tmp) == 6 and tmp[0].isdigit(): symbols.append(tmp[1]) positions.append([float(x) for x in tmp[2:5]]) natom = len(symbols) initial_positions = np.array(positions) # print symbols # print initial_positions forces_data = re.findall(r'The grand total force \(eV/A\):([\w\d\s\.\-=\+]*)Cartesian', data) # print len(forces_data) forces = np.zeros((len(forces_data), natom, 3)) # print forces.shape iteration = 0 for idata in forces_data: for iline in idata.split('\n'): if 'iatom' in iline: fields = iline.split() forces[iteration, int(fields[2]) - 1] = np.array(fields[-3:], dtype=float) iteration += 1 ret = re.findall('Cartesian Forces:\s*Max = ([=\w\s\d.]*)RMS = ([\s\d.]*)\n', data) ret = [[float(x) for x in y] for y in ret] max_force = [x[0] for x in ret] rms = [x[1] for x in ret] energy_data = re.findall(r'---------- T H E T O T A L E N E R G Y -----------([\s\w\d\.\-=/]+)--- \n', data) energy = [] for idata in energy_data: for iline in idata.split('\n'): if 'Time step' in iline: tmp = iline.split() ienergy = {'Time_step': int(tmp[3]), 'SCF_step': int(tmp[7]), 'etot/atom': float(tmp[10])} elif len(iline.split('=')) == 2: tmp = iline.split('=') ienergy[tmp[0].strip()] = float(tmp[1]) energy.append(ienergy) ret = {'symbols': symbols, 'initial_positions': initial_positions, 'forces': generic_serializer(forces), 'energetics': energy, 'max_force': max_force, 'rms_force': rms} return ret
def to_dict(self): ret = {} for i in ['charge', 'energy', 'forces', 'stress']: ret[i] = eval('self.' + i) for i in ret: if isinstance(ret[i], np.ndarray): ret[i] = generic_serializer(ret[i]) return ret
def elastic_moduli(filename='OUTCAR'): ret = {} rf = open(filename) data = rf.read() subblock = re.findall('ELASTIC MODULI CONTR FROM IONIC RELAXATION \(kBar\)[\s\d\w]*-*([\s\d\w.-]*)\n\n\n', data) ret['elastic_moduli_contr'] = np.array(np.array(subblock[0].split()[:42]).reshape(6, -1)[:, 1:], dtype=float) subblock = re.findall('TOTAL ELASTIC MODULI \(kBar\)[\s\d\w]*-*([\s\d\w.-]*)\n\n\n', data) ret['total_elastic_moduli'] = np.array(np.array(subblock[0].split()[:42]).reshape(6, -1)[:, 1:], dtype=float) return generic_serializer(ret)
def evaluate(self, imember): entry = self.population.get_entry(imember) pcm_structure = pychemia.Structure.from_dict(entry['structure']) ase_structure = pychemia.external.ase.pychemia2ase(pcm_structure) ase_structure.set_calculator(LennardJones()) dyn = QuasiNewton(ase_structure) dyn.run() ase_structure.set_constraint(FixAtoms(mask=[True for atom in ase_structure])) ucf = UnitCellFilter(ase_structure) qn = QuasiNewton(ucf) qn.run() new_structure = pychemia.external.ase.ase2pychemia(ase_structure) energy = ase_structure.get_potential_energy() forces = ase_structure.get_forces() stress = ase_structure.get_stress() new_properties = {'energy': float(energy), 'forces': generic_serializer(forces), 'stress': generic_serializer(stress)} self.population.db.update(imember, structure=new_structure, properties=new_properties)
def move_random(self, entry_id, factor=0.2, in_place=False, kind='move'): entry = self.get_entry(entry_id) pos = np.array(entry['structure']['positions']).reshape((-1, 3)) # Unit Vectors uv = unit_vectors(2 * np.random.rand(*pos.shape) - 1) new_pos = generic_serializer(pos + factor * uv) structure = Structure(positions=new_pos, symbols=entry['structure']['symbols'], periodicity=False) if in_place: self.update_properties(entry_id=entry_id, new_properties={}) return self.set_structure(entry_id, structure) else: structure = Structure(positions=new_pos, symbols=entry['structure']['symbols'], periodicity=False) return self.new_entry(structure, active=False)
def evaluate(self, structure, gtol=None): if gtol is None: gtol = self.target_forces positions, forces, energy = lj_compact_evaluate(structure, gtol, self.minimal_density) structure.set_positions(positions) structure.relocate_to_cm() if structure.natom > 2: structure.align_inertia_momenta() sorted_indices = structure.sort_sites() forces = forces[sorted_indices] pg = get_point_group(structure, executable='symmol') properties = {'forces': generic_serializer(forces), 'energy': energy, 'point_group': pg} return structure, properties
def evaluate(self, entry_id, gtol=None): if gtol is None: gtol = self.target_forces print('Evaluating %s target density= %7.3F' % (entry_id, self.minimal_density)) structure = self.get_structure(entry_id) positions, forces, energy = lj_compact_evaluate(structure, gtol, self.minimal_density) structure.set_positions(positions) structure.relocate_to_cm() if structure.natom > 2: structure.align_inertia_momenta() sorted_indices = structure.sort_sites() forces = forces[sorted_indices] properties = {'forces': generic_serializer(forces), 'energy': energy} return structure, properties, energy
def set_grid(self, grid, shifts=None): """ Set a grid of kpoints with a proper check of correct arguments :param grid: Number of kpoints on each direction (Only for 'gamma' and 'monkhorst-pack') :param shifts: Shift applied to the grid (Only for 'gamma' and 'monkhorst-pack') """ assert (self.kmode in ['gamma', 'monkhorst-pack']) if grid is None: self.grid = [1, 1, 1] elif len(grid) == 3: self.grid = [int(x) for x in grid] else: raise ValueError("Wrong value for grid, should be an array with shape (-1,3)") if shifts is None: self.shifts = [0, 0, 0] else: self.shifts = generic_serializer(np.array(shifts).reshape(3))
def set_grid(self, grid, shifts=None): """ Set a grid of kpoints with a proper check of correct arguments :param grid: Number of kpoints on each direction (Only for 'gamma' and 'monkhorst-pack') :param shifts: Shift applied to the grid (Only for 'gamma' and 'monkhorst-pack') """ assert (self.kmode in ['gamma', 'monkhorst-pack']) if grid is None: self.grid = [1, 1, 1] elif len(grid) == 3: self.grid = [int(x) for x in grid] else: raise ValueError( "Wrong value for grid, should be an array with shape (-1,3)") if shifts is None: self.shifts = [0, 0, 0] else: self.shifts = generic_serializer(np.array(shifts).reshape((-1, 3)))
def evaluate(self, entry_id, gtol=None): if gtol is None: gtol = self.target_forces print('Evaluating %s target density= %7.3F' % (entry_id, self.minimal_density)) structure = self.get_structure(entry_id) positions, forces, energy = lj_compact_evaluate( structure, gtol, self.minimal_density) structure.set_positions(positions) structure.relocate_to_cm() if structure.natom > 2: structure.align_inertia_momenta() sorted_indices = structure.sort_sites() forces = forces[sorted_indices] properties = {'forces': generic_serializer(forces), 'energy': energy} return structure, properties, energy
def move_random(self, entry_id, factor=0.2, in_place=False, kind='move'): entry = self.get_entry(entry_id) pos = np.array(entry['structure']['positions']).reshape((-1, 3)) # Unit Vectors uv = pychemia.utils.mathematics.unit_vectors(2 * np.random.rand(*pos.shape) - 1) new_pos = generic_serializer(pos + factor * uv) structure = pychemia.Structure(positions=new_pos, symbols=entry['structure']['symbols'], periodicity=False) if in_place: return self.pcdb.db.pychemia_entries.update_one({'_id': entry_id}, {'$set': {'structure': structure.to_dict, 'properties': {}}}) else: structure = pychemia.Structure(positions=new_pos, symbols=entry['structure']['symbols'], periodicity=False) return self.new_entry(structure, active=False)
def evaluate(self, structure, gtol=None): if gtol is None: gtol = self.target_forces positions, forces, energy = lj_compact_evaluate( structure, gtol, self.minimal_density) structure.set_positions(positions) structure.relocate_to_cm() if structure.natom > 2: structure.align_inertia_momenta() sorted_indices = structure.sort_sites() forces = forces[sorted_indices] pg = get_point_group(structure, executable='symmol') properties = { 'forces': generic_serializer(forces), 'energy': energy, 'point_group': pg } return structure, properties
def cluster_fb_worker(db_settings): while True: pcdb = pychemia.db.get_database(db_settings) population = pychemia.population.LJCluster(pcdb) entry = population.pcdb.db.pychemia_entries.find_one( { 'status.' + population.tag: True, 'status.lock': { '$exists': False }, 'properties': {} }, {'_id': 1}) if entry is not None: population.pcdb.lock(entry['_id']) structure = population.pcdb.get_structure(entry['_id']) fb = pychemia.code.fireball.FireBall(fdata_path='../Fdata') fb.initialize(structure, workdir=str(entry['_id'])) fb.cluster_relaxation() fb.set_inputs() sp = fb.run() sp.wait() so = pychemia.code.fireball.read_fireball_stdout(fb.workdir + os.sep + 'fireball.log') forces = generic_serializer(so['forces'][-1]) energy = so['energy'][-1]['ETOT'] properties = {'forces': forces, 'energy': energy} structure = pychemia.code.fireball.read_geometry_bas(fb.workdir + os.sep + 'answer.bas') population.pcdb.update(entry['_id'], structure=structure, properties=properties) population.pcdb.unlock(entry['_id']) else: break
def test_orbital(self): """ Test (pychemia.population.OrbitalDFTU) : """ if not pychemia.db.has_connection(): return pychemia_path = pychemia.__path__[0] abiinput = pychemia.code.abinit.AbinitInput('tests/data/abinit_dmatpawu/abinit.in') dmatpawu = np.array(abiinput['dmatpawu']).reshape(-1, 5, 5) params = pychemia.population.orbitaldftu.dmatpawu2params(dmatpawu, 5) dmatpawu_new = pychemia.population.orbitaldftu.params2dmatpawu(params) self.assertLess(np.min(dmatpawu-dmatpawu_new), 0.01) with self.assertRaises(ValueError) as context: pychemia.population.orbitaldftu.OrbitalDFTU('test', '/tmp/no_abinit.in') with self.assertRaises(ValueError) as context: pychemia.population.orbitaldftu.OrbitalDFTU('test', input_path='tests/data/abinit_01/abinit.in') popu = pychemia.population.orbitaldftu.OrbitalDFTU('test', input_path='tests/data/abinit_dmatpawu/abinit.in') popu.pcdb.clean() ea = [[-0.1, -0.2, -0.3, -0.4, -0.5, -0.6, -0.7, -0.8, -0.9, -1.0], [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] params['euler_angles'] = ea params = generic_serializer(params) entry_id = popu.new_entry(params) ea = [[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0], [-0.1, -0.2, -0.3, -0.4, -0.5, -0.6, -0.7, -0.8, -0.9, -1.0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] params['euler_angles'] = ea params = generic_serializer(params) entry_jd = popu.new_entry(params) popu.add_random() popu.random_population(16) print(popu) self.assertFalse(popu.is_evaluated(entry_id)) for entry_id in popu.members: params = popu.get_correlation_params(entry_id, final=False) popu.set_final_results(entry_id, params, 0.0, 1E-13) self.assertTrue(popu.is_evaluated(entry_id)) popu.get_duplicates(popu.members, tolerance=0.1) popu.cross([entry_id, entry_jd]) entry_idm = popu.move_random(entry_id) popu.get_entry(entry_idm, {'properties': 1}) entry_imj = popu.move(entry_id, entry_jd) popu.get_entry(entry_imj, {'properties': 1}) # pd = popu.to_dict # popu.from_dict(pd) tmpdir = tempfile.mkdtemp() for i in popu.members: popu.prepare_folder(i, workdir=tmpdir, source_dir=pychemia_path + 'tests/data/abinit_dmatpawu') popu.pcdb.clean() shutil.rmtree(tmpdir)
def worker_maise(db_settings, entry_id, workdir, target_forces, relaxator_params): max_ncalls = 6 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) status = pcdb.get_dicts(entry_id)[2] if 'ncalls' in status: ncalls = status['ncalls'] + 1 else: ncalls = 1 #print('Current directory: '+os.getcwd() ) #print('Working directory: '+workdir) write_poscar(structure,workdir+os.sep+'POSCAR') if not os.path.exists(workdir+os.sep+'setup'): shutil.copy2('setup', workdir) if not os.path.exists(workdir+os.sep+'INI'): os.symlink(os.getcwd()+os.sep+'INI', workdir+os.sep+'INI') if not os.path.exists(workdir+os.sep+'maise'): os.symlink(os.getcwd()+os.sep+'maise', workdir+os.sep+'maise') cwd=os.getcwd() os.chdir(workdir) wf=open('maise.stdout','w') subprocess.call(['./maise'], stdout=wf) wf.close() if os.path.isfile('OSZICAR'): energies=np.loadtxt('OSZICAR') else: energies=None if os.path.isfile('OUTCAR'): rf = open('OUTCAR', 'r') data = rf.read() pos_forces = re.findall(r'TOTAL-FORCE \(eV/Angst\)\s*-*\s*([-.\d\s]+)\s+-{2}', data) pos_forces = np.array([x.split() for x in pos_forces], dtype=float) if len(pos_forces) > 0 and len(pos_forces[-1]) % 7 == 0: pos_forces.shape = (len(pos_forces), -1, 7) forces = pos_forces[:, :, 3:6] positions = pos_forces[:, :, :3] else: print('Forces and Positions could not be parsed : ', pos_forces.shape) print('pos_forces =\n%s ' % pos_forces) str_stress=re.findall('Total([\.\d\s-]*)in',data) if len(str_stress)==2: stress = np.array([[float(y) for y in x.split()] for x in str_stress]) str_stress=re.findall('in kB([\.\d\s-]*)energy',data) if len(str_stress)==2: stress_kB = np.array([[float(y) for y in x.split()] for x in str_stress]) else: forces=None stress=None stress_kB=None new_structure=read_poscar('CONTCAR') if np.min(new_structure.distance_matrix()+np.eye(new_structure.natom))<0.23: print('WARNING: Structure collapse 2 atoms, creating a new random structure') new_structure=Structure.random_cell(new_structure.composition) if ncalls > max_ncalls: print('WARNING: Too many calls to MAISE and no relaxation succeeded, replacing structure') new_structure=Structure.random_cell(new_structure.composition) pcdb.entries.update({'_id': entry_id}, {'$set': {'status.ncalls': 0}}) else: pcdb.entries.update({'_id': entry_id}, {'$set': {'status.ncalls': ncalls}}) pcdb.update(entry_id, structure=new_structure) if energies is not None and forces is not None and stress is not None: te = energies[1] pcdb.entries.update({'_id': entry_id}, {'$set': {'status.relaxation': 'succeed', 'status.target_forces': target_forces, 'properties.initial_forces': generic_serializer(forces[0]), 'properties.initial_stress': generic_serializer(stress[0]), 'properties.initial_stress_kB': generic_serializer(stress_kB[0]), 'properties.forces': generic_serializer(forces[1]), 'properties.stress': generic_serializer(stress[1]), 'properties.stress_kB': generic_serializer(stress_kB[1]), 'properties.energy': te, 'properties.energy_pa': te / new_structure.natom, 'properties.energy_pf': te / new_structure.get_composition().gcd}}) for ifile in ['POSCAR', 'CONTCAR', 'setup', 'OUTCAR', 'maise.stdout', 'list.dat']: if not os.path.exists(ifile): wf = open(ifile, 'w') wf.write('') wf.close() n=1 while True: if os.path.exists(ifile+ ('_%03d' % n)): n+=1 else: break os.rename(ifile,ifile+('_%03d' % n)) pcm_log.info('[%s]: Unlocking the entry' % str(entry_id)) pcdb.unlock(entry_id)
def run(self, nparal=1): self.started = True self.cleaner() vj = self.vaspjob ncalls = 1 self.first_run(nparal) while True: if vj.runner is not None and vj.runner.poll() is not None: pcm_log.info('Execution completed. Return code %d' % vj.runner.returncode) filename = self.workdir + os.sep + 'vasp_stdout.log' if os.path.exists(filename): read_vasp_stdout(filename=filename) ncalls += 1 va = VaspAnalyser(self.workdir) va.run() max_force, max_stress = self.get_max_force_stress() print('Max Force: %9.3E Stress: %9.3E (target forces= %E)' % (max_force, max_stress, self.target_forces)) if max_force is not None and max_force < self.target_forces: # Conditions to finish the run if max_stress < self.target_forces: self.success = True break elif not self.relax_cell: self.success = True break elif ncalls >= self.max_calls: self.success = False break self.update() vj.run(use_mpi=True, mpi_num_procs=nparal) if self.waiting: vj.runner.wait() else: filename = self.workdir + os.sep + 'vasp_stdout.log' if os.path.exists(filename): vasp_stdout = read_vasp_stdout(filename=filename) if len(vasp_stdout['iterations']) > 0: pcm_log.debug('[%s] SCF: %s' % (os.path.basename(self.workdir), str(vasp_stdout['iterations']))) # if len(vasp_stdout['energies']) > 2: # energy_str = ' %9.3E' % vasp_stdout['energies'][0] # for i in range(1, len(vasp_stdout['energies'])): # if vasp_stdout['energies'][i] < vasp_stdout['energies'][i-1]: # energy_str += ' >' # else: # energy_str += ' <' # pcm_log.debug(energy_str) time.sleep(30) outcars = sorted([x for x in os.listdir(self.workdir) if x.startswith('OUTCAR')])[::-1] vo = VaspOutput(self.workdir + os.sep + outcars[0]) forces = vo.forces stress = vo.stress if len(outcars) > 1: for i in outcars[1:]: vo = VaspOutput(self.workdir + os.sep + i) forces = np.concatenate((forces, vo.forces)) stress = np.concatenate((stress, vo.stress)) vj.get_outputs() self.output = {'forces': generic_serializer(forces), 'stress': generic_serializer(stress), 'energy': vj.outcar.energy, 'energies': generic_serializer(vj.outcar.energies)} if vj.outcar.is_finished: self.finished = True
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 worker_maise(db_settings, entry_id, workdir, relaxator_params): """ Relax and return evaluate the energy of the structure stored with identifier 'entry_id' using the MAISE code :param db_settings: (dict) Dictionary of DB parameters needed to create a PyChemiaDB object :param entry_id: MongoDB identifier of one entry of the database created from db_settings :param workdir: (str) Working directory where input and output from MAISE is written :param relaxator_params: (dict) Arguments needed to control the relaxation using MAISE Arguments are store as keys and they include: 'target_forces' : Used to defined the tolerance to consider one candidate as relaxed. 'source_dir': Directory with executable maise and directory INI :return: """ max_ncalls = 6 pcdb = get_database(db_settings) target_forces = relaxator_params['target_forces'] source_dir = relaxator_params['source_dir'] 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) status = pcdb.get_dicts(entry_id)[2] if 'ncalls' in status and status['ncalls'] > 0: ncalls = status['ncalls'] + 1 print('ncalls = ', status['ncalls']) else: ncalls = 1 print('Verifing initial structure...') while np.min(structure.distance_matrix()+(np.eye(structure.natom)*5)) < 1.9: print('ERROR: Bad initial guess, two atoms are to close. Creating new random structure for id: %s' % str(entry_id)) write_poscar(structure, workdir + os.sep + 'Fail_initial_POSCAR') # WIH structure = Structure.random_cell(structure.composition) write_poscar(structure, workdir + os.sep + 'POSCAR') if not os.path.exists(workdir + os.sep + 'setup') and ncalls == 1: # WIH print('First run.') # WIH # print('Verifying that everything runs smoothly') # WIH print(workdir + os.sep + 'setup') shutil.copy2(source_dir + os.sep + 'setup_1', workdir + os.sep + 'setup') # WIH elif ncalls > 1: # WIH shutil.copy2(source_dir + os.sep + 'setup_2', workdir + os.sep + 'setup') # WIH if not os.path.exists(workdir + os.sep + 'INI'): os.symlink(source_dir + os.sep + 'INI', workdir + os.sep + 'INI') if not os.path.exists(workdir + os.sep + 'maise'): os.symlink(source_dir + os.sep + 'maise', workdir + os.sep + 'maise') # Get the Current Working Directory # cwd = os.getcwd() # Move to the actual directory where maise will run os.chdir(workdir) wf = open('maise.stdout', 'w') subprocess.call(['./maise'], stdout=wf) wf.close() if os.path.isfile('OSZICAR'): energies = np.loadtxt('OSZICAR') else: energies = None forces = None stress = None stress_kb = None if os.path.isfile('OUTCAR'): rf = open('OUTCAR', 'r') data = rf.read() pos_forces = re.findall(r'TOTAL-FORCE \(eV/Angst\)\s*-*\s*([-.\d\s]+)\s+-{2}', data) pos_forces = np.array([x.split() for x in pos_forces], dtype=float) if len(pos_forces) > 0 and len(pos_forces[-1]) % 7 == 0: pos_forces.shape = (len(pos_forces), -1, 7) forces = pos_forces[:, :, 3:6] # positions = pos_forces[:, :, :3] else: print('Forces and Positions could not be parsed : ', pos_forces.shape) print('pos_forces =\n%s ' % pos_forces) str_stress = re.findall('Total([.\d\s-]*)in', data) if len(str_stress) == 2: stress = np.array([[float(y) for y in x.split()] for x in str_stress]) str_stress = re.findall('in kB([.\d\s-]*)energy', data) if len(str_stress) == 2: stress_kb = np.array([[float(y) for y in x.split()] for x in str_stress]) create_new = False if not os.path.isfile('CONTCAR') or os.path.getsize("CONTCAR") == 0: create_new = True print('CONTCAR not found in entry: %s' % str(entry_id)) i = 1 while True: if not os.path.isfile('POSCAR-failed-%03s' % str(i)): os.rename('POSCAR', 'POSCAR-failed-%03s' % str(i)) break else: i += 1 else: new_structure = read_poscar('CONTCAR') # min_dist = np.min(new_structure.distance_matrix+np.ones((new_structure.natom,new_structure.natom))) min_dist = np.min(new_structure.distance_matrix()+(np.eye(new_structure.natom)*5)) # WIH print('Minimal distance= %8.7f' % min_dist) # WIH if min_dist < 2.0: print('ERROR: MAISE finished with and structure with distances too close:', entry_id) # WIH write_poscar(new_structure, workdir + os.sep + 'Collapsed_CONTCAR') # WIH create_new = True # WIH if create_new: new_structure = Structure.random_cell(structure.composition) ncalls = 0 # WIH if ncalls > max_ncalls: print('WARNING: Too many calls to MAISE and no relaxation succeeded, replacing structure: ', entry_id) # WIH new_structure = Structure.random_cell(structure.composition) pcdb.entries.update({'_id': entry_id}, {'$set': {'status.ncalls': 0}}) create_new = True else: pcdb.entries.update({'_id': entry_id}, {'$set': {'status.ncalls': ncalls}}) pcdb.update(entry_id, structure=new_structure, properties={}) # if not create_new and energies is not None and forces is not None and stress is not None: if energies is not None and forces is not None and stress is not None: te = energies[1] pcdb.entries.update({'_id': entry_id}, {'$set': {'status.relaxation': 'succeed', 'status.target_forces': target_forces, 'properties.initial_forces': generic_serializer(forces[0]), 'properties.initial_stress': generic_serializer(stress[0]), 'properties.initial_stress_kB': generic_serializer(stress_kb[0]), 'properties.forces': generic_serializer(forces[1]), 'properties.stress': generic_serializer(stress[1]), 'properties.stress_kB': generic_serializer(stress_kb[1]), 'properties.energy': te, 'properties.energy_pa': te / new_structure.natom, 'properties.energy_pf': te / new_structure.get_composition().gcd}}) for ifile in ['POSCAR', 'CONTCAR', 'setup', 'OUTCAR', 'maise.stdout', 'list.dat']: if not os.path.exists(ifile): wf = open(ifile, 'w') wf.write('') wf.close() n = 1 while True: if os.path.exists(ifile + ('_%03d' % n)): n += 1 else: break os.rename(ifile, ifile+('_%03d' % n)) pcm_log.info('[%s]: Unlocking the entry' % str(entry_id)) pcdb.unlock(entry_id)
def worker_maise(db_settings, entry_id, workdir, relaxator_params): """ Relax and return evaluate the energy of the structure stored with identifier 'entry_id' using the MAISE code :param db_settings: (dict) Dictionary of DB parameters needed to create a PyChemiaDB object :param entry_id: MongoDB identifier of one entry of the database created from db_settings :param workdir: (str) Working directory where input and output from MAISE is written :param relaxator_params: (dict) Arguments needed to control the relaxation using MAISE Arguments are store as keys and they include: 'target_forces' : Used to defined the tolerance to consider one candidate as relaxed. 'source_dir': Directory with executable maise and directory INI :return: """ max_ncalls = 6 pcdb = get_database(db_settings) target_forces = relaxator_params['target_forces'] source_dir = relaxator_params['source_dir'] 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) status = pcdb.get_dicts(entry_id)[2] if 'ncalls' in status and status['ncalls'] > 0: ncalls = status['ncalls'] + 1 print('ncalls = ', status['ncalls']) else: ncalls = 1 print('Verifing initial structure...') while np.min(structure.distance_matrix() + (np.eye(structure.natom) * 5)) < 1.9: print( 'ERROR: Bad initial guess, two atoms are to close. Creating new random structure for id: %s' % str(entry_id)) write_poscar(structure, workdir + os.sep + 'Fail_initial_POSCAR') # WIH structure = Structure.random_cell(structure.composition) write_poscar(structure, workdir + os.sep + 'POSCAR') if not os.path.exists(workdir + os.sep + 'setup') and ncalls == 1: # WIH print('First run.') # WIH # print('Verifying that everything runs smoothly') # WIH print(workdir + os.sep + 'setup') shutil.copy2(source_dir + os.sep + 'setup_1', workdir + os.sep + 'setup') # WIH elif ncalls > 1: # WIH shutil.copy2(source_dir + os.sep + 'setup_2', workdir + os.sep + 'setup') # WIH if not os.path.exists(workdir + os.sep + 'INI'): os.symlink(source_dir + os.sep + 'INI', workdir + os.sep + 'INI') if not os.path.exists(workdir + os.sep + 'maise'): os.symlink(source_dir + os.sep + 'maise', workdir + os.sep + 'maise') # Get the Current Working Directory # cwd = os.getcwd() # Move to the actual directory where maise will run os.chdir(workdir) wf = open('maise.stdout', 'w') subprocess.call(['./maise'], stdout=wf) wf.close() if os.path.isfile('OSZICAR'): energies = np.loadtxt('OSZICAR') else: energies = None forces = None stress = None stress_kb = None if os.path.isfile('OUTCAR'): rf = open('OUTCAR', 'r') data = rf.read() pos_forces = re.findall( r'TOTAL-FORCE \(eV/Angst\)\s*-*\s*([-.\d\s]+)\s+-{2}', data) pos_forces = np.array([x.split() for x in pos_forces], dtype=float) if len(pos_forces) > 0 and len(pos_forces[-1]) % 7 == 0: pos_forces.shape = (len(pos_forces), -1, 7) forces = pos_forces[:, :, 3:6] # positions = pos_forces[:, :, :3] else: print('Forces and Positions could not be parsed : ', pos_forces.shape) print('pos_forces =\n%s ' % pos_forces) str_stress = re.findall('Total([.\d\s-]*)in', data) if len(str_stress) == 2: stress = np.array([[float(y) for y in x.split()] for x in str_stress]) str_stress = re.findall('in kB([.\d\s-]*)energy', data) if len(str_stress) == 2: stress_kb = np.array([[float(y) for y in x.split()] for x in str_stress]) create_new = False if not os.path.isfile('CONTCAR') or os.path.getsize("CONTCAR") == 0: create_new = True print('CONTCAR not found in entry: %s' % str(entry_id)) i = 1 while True: if not os.path.isfile('POSCAR-failed-%03s' % str(i)): os.rename('POSCAR', 'POSCAR-failed-%03s' % str(i)) break else: i += 1 else: new_structure = read_poscar('CONTCAR') # min_dist = np.min(new_structure.distance_matrix+np.ones((new_structure.natom,new_structure.natom))) min_dist = np.min(new_structure.distance_matrix() + (np.eye(new_structure.natom) * 5)) # WIH print('Minimal distance= %8.7f' % min_dist) # WIH if min_dist < 2.0: print( 'ERROR: MAISE finished with and structure with distances too close:', entry_id) # WIH write_poscar(new_structure, workdir + os.sep + 'Collapsed_CONTCAR') # WIH create_new = True # WIH if create_new: new_structure = Structure.random_cell(structure.composition) ncalls = 0 # WIH if ncalls > max_ncalls: print( 'WARNING: Too many calls to MAISE and no relaxation succeeded, replacing structure: ', entry_id) # WIH new_structure = Structure.random_cell(structure.composition) pcdb.entries.update({'_id': entry_id}, {'$set': {'status.ncalls': 0}}) create_new = True else: pcdb.entries.update({'_id': entry_id}, {'$set': { 'status.ncalls': ncalls }}) pcdb.update(entry_id, structure=new_structure, properties={}) # if not create_new and energies is not None and forces is not None and stress is not None: if energies is not None and forces is not None and stress is not None: te = energies[1] pcdb.entries.update({'_id': entry_id}, { '$set': { 'status.relaxation': 'succeed', 'status.target_forces': target_forces, 'properties.initial_forces': generic_serializer(forces[0]), 'properties.initial_stress': generic_serializer(stress[0]), 'properties.initial_stress_kB': generic_serializer( stress_kb[0]), 'properties.forces': generic_serializer(forces[1]), 'properties.stress': generic_serializer(stress[1]), 'properties.stress_kB': generic_serializer(stress_kb[1]), 'properties.energy': te, 'properties.energy_pa': te / new_structure.natom, 'properties.energy_pf': te / new_structure.get_composition().gcd } }) for ifile in [ 'POSCAR', 'CONTCAR', 'setup', 'OUTCAR', 'maise.stdout', 'list.dat' ]: if not os.path.exists(ifile): wf = open(ifile, 'w') wf.write('') wf.close() n = 1 while True: if os.path.exists(ifile + ('_%03d' % n)): n += 1 else: break os.rename(ifile, ifile + ('_%03d' % n)) pcm_log.info('[%s]: Unlocking the entry' % str(entry_id)) pcdb.unlock(entry_id)
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 read_dftb_stdout(filename='dftb_stdout.log'): """ Read the standard output stored in a file (by default 'dftb_stdout.log') and extract relevant information useful for a relaxation procedure :param filename: The standard output stored in a file :return: """ rf = open(filename, 'r') data = rf.read() ret = {} start_ini = re.findall(r'Starting initialization...[\s-]+([.\s\d\w\-:\(\),+]+)---', data) if len(start_ini) == 1: start_ini = start_ini[0].replace('\n ', ' ').split('\n') ret['Starting_Initialization'] = {} for line in start_ini: if len(line.split(':')) == 2: left, right = line.split(':') elif line[:3] != '---': left = line[:29].replace(':', '') right = line[29:] ret['Starting_Initialization'][left.strip()] = parse_value(right.strip()) if left.strip() == 'K-points and weights': right = right.replace(':', '') right = np.array(right.split(), dtype=float).reshape((-1, 5)) ret['Starting_Initialization'][left.strip()] = {'kpoints': generic_serializer(right[:, 1:-1]), 'weights': generic_serializer(right[:, -1])} geom_blocks = re.findall(r'Geometry step:([\^*.\s\d\w\-:\(\),+]+)Pa', data) ret['Geometry_Steps'] = [] for iblock in geom_blocks: ib = iblock.split('\n') if 'Lattice' in ib[0]: tmp = {'iter': int(ib[0].split(',')[0]), 'scc': {}} else: tmp = {'iter': int(ib[0]), 'scc': {}} tmp['scc']['tot_electronic'] = [] tmp['scc']['diff_electronic'] = [] tmp['scc']['scc_error'] = [] for iline in ib[4:]: fields = iline.split() if len(fields) > 0 and fields[0].strip().isdigit(): tmp['scc']['tot_electronic'].append(float(fields[1])) tmp['scc']['diff_electronic'].append(float(fields[2])) tmp['scc']['scc_error'].append(float(fields[3])) elif len(iline.split(':')) == 2: left, right = iline.split(':') tmp[left.strip()] = {'value': float(right.split()[0]), 'units': right.split()[1]} ret['Geometry_Steps'].append(tmp) max_force = re.findall(r'Maximal force component:\s*([\s\dE+-.]+)\s*\n', data) if len(max_force) > 0: ret['max_force'] = float(max_force[-1]) if re.findall('Geometry did NOT converge', data): pcm_log.debug('Convergence not achieved!') ret['ion_convergence'] = False else: ret['ion_convergence'] = True if re.findall('Geometry converged', data): pcm_log.debug('Convergence achieved!') ret['ion_convergence'] = True else: ret['ion_convergence'] = False return ret
def run(self, nparal=1): self.started = True self.cleaner() vj = self.vaspjob ncalls = 1 self.first_run(nparal) while True: if vj.runner is not None and vj.runner.poll() is not None: pcm_log.info('Execution completed. Return code %d' % vj.runner.returncode) filename = self.workdir + os.sep + 'vasp_stdout.log' if os.path.exists(filename): read_vasp_stdout(filename=filename) ncalls += 1 va = VaspAnalyser(self.workdir) va.run() max_force, max_stress = self.get_max_force_stress() print('Max Force: %9.3E Stress: %9.3E (target forces= %E)' % (max_force, max_stress, self.target_forces)) if max_force is not None and max_force < self.target_forces: # Conditions to finish the run if max_stress < self.target_forces: self.success = True break elif not self.relax_cell: self.success = True break elif ncalls >= self.max_calls: self.success = False break self.update() vj.run(use_mpi=True, mpi_num_procs=nparal) if self.waiting: vj.runner.wait() else: filename = self.workdir + os.sep + 'vasp_stdout.log' if os.path.exists(filename): vasp_stdout = read_vasp_stdout(filename=filename) if len(vasp_stdout['iterations']) > 0: pcm_log.debug('[%s] SCF: %s' % (os.path.basename( self.workdir), str(vasp_stdout['iterations']))) # if len(vasp_stdout['energies']) > 2: # energy_str = ' %9.3E' % vasp_stdout['energies'][0] # for i in range(1, len(vasp_stdout['energies'])): # if vasp_stdout['energies'][i] < vasp_stdout['energies'][i-1]: # energy_str += ' >' # else: # energy_str += ' <' # pcm_log.debug(energy_str) time.sleep(30) outcars = sorted([ x for x in os.listdir(self.workdir) if x.startswith('OUTCAR') ])[::-1] vo = VaspOutput(self.workdir + os.sep + outcars[0]) forces = vo.forces stress = vo.stress if len(outcars) > 1: for i in outcars[1:]: vo = VaspOutput(self.workdir + os.sep + i) forces = np.concatenate((forces, vo.forces)) stress = np.concatenate((stress, vo.stress)) vj.get_outputs() self.output = { 'forces': generic_serializer(forces), 'stress': generic_serializer(stress), 'energy': vj.outcar.energy, 'energies': generic_serializer(vj.outcar.energies) } if vj.outcar.is_finished: self.finished = True
def test_orbital(self): """ Tests (pychemia.population.OrbitalDFTU) : """ if not pychemia.db.has_connection(): return pychemia_path = pychemia.__path__[0] abiinput = pychemia.code.abinit.AbinitInput('tests/data/abinit_dmatpawu/abinit.in') dmatpawu = np.array(abiinput['dmatpawu']).reshape(-1, 5, 5) params = pychemia.population.orbitaldftu.dmatpawu2params(dmatpawu, 5) dmatpawu_new = pychemia.population.orbitaldftu.params2dmatpawu(params) self.assertLess(np.min(dmatpawu-dmatpawu_new), 0.01) with self.assertRaises(ValueError) as context: pychemia.population.orbitaldftu.OrbitalDFTU('test', '/tmp/no_abinit.in') with self.assertRaises(ValueError) as context: pychemia.population.orbitaldftu.OrbitalDFTU('test', input_path='tests/data/abinit_01/abinit.in') popu = pychemia.population.orbitaldftu.OrbitalDFTU('test', input_path='tests/data/abinit_dmatpawu/abinit.in') popu.pcdb.clean() ea = [[-0.1, -0.2, -0.3, -0.4, -0.5, -0.6, -0.7, -0.8, -0.9, -1.0], [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] params['euler_angles'] = ea params = generic_serializer(params) entry_id = popu.new_entry(params) ea = [[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0], [-0.1, -0.2, -0.3, -0.4, -0.5, -0.6, -0.7, -0.8, -0.9, -1.0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] params['euler_angles'] = ea params = generic_serializer(params) entry_jd = popu.new_entry(params) popu.add_random() popu.random_population(16) print(popu) self.assertFalse(popu.is_evaluated(entry_id)) for entry_id in popu.members: params = popu.get_correlation_params(entry_id, final=False) popu.set_final_results(entry_id, params, 0.0, 1E-13) self.assertTrue(popu.is_evaluated(entry_id)) popu.get_duplicates(popu.members, tolerance=0.1) popu.cross([entry_id, entry_jd]) entry_idm = popu.move_random(entry_id) popu.get_entry(entry_idm, {'properties': 1}) entry_imj = popu.move(entry_id, entry_jd) popu.get_entry(entry_imj, {'properties': 1}) # pd = popu.to_dict # popu.from_dict(pd) tmpdir = tempfile.mkdtemp() for i in popu.members: popu.prepare_folder(i, workdir=tmpdir, source_dir=pychemia_path + 'tests/data/abinit_dmatpawu') popu.pcdb.clean() shutil.rmtree(tmpdir)