Beispiel #1
0
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)
Beispiel #2
0
    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)
Beispiel #3
0
    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)
Beispiel #5
0
    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()
Beispiel #6
0
    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)