Ejemplo n.º 1
0
    def crystalAtoms(self,
                     start_layer=0,
                     end_layer=1,
                     coordinates='orth_surface',
                     sub_layers=False,
                     minimal=True,
                     ):
        atoms = self.crystal().atoms()

        if sub_layers:
            in_equal_layers = self.inequivalentLayers()
            repeats = int(np.ceil(end_layer/float(in_equal_layers)))
            atoms = atoms.repeat((1, 1, repeats + 1))
            atoms.positions -= self.crystal().unitCell()*(repeats)
            start_layer += in_equal_layers -1
            end_layer += in_equal_layers -1
            atoms = orderAtoms(atoms, (2, 1, 0))
            sl = slice(start_layer, end_layer)

            groups = groupAtoms(atoms)[::-1][sl]
            if len(groups) == 0:
                atoms = Atoms([], cell=atoms.get_cell(), pbc=atoms.get_pbc())
            else:
                atoms, indices = groups[0]
                for group, indices in groups[1:]:
                    atoms += group
        else:
            cell = atoms.unitCell()
            atoms = atoms.repeat((1, 1, end_layer-start_layer))
            atoms.positions += cell*start_layer

        return atoms
Ejemplo n.º 2
0
def test_negativeindex():
    from ase.atoms import Atoms
    from ase.constraints import FixScaled

    a1 = Atoms(
        symbols='X2',
        positions=[
            [0., 0., 0.],
            [2., 0., 0.],
        ],
        cell=[
            [4., 0., 0.],
            [0., 4., 0.],
            [0., 0., 4.],
        ],
    )

    fs1 = FixScaled(a1.get_cell(), -1, mask=(True, False, False))
    fs2 = FixScaled(a1.get_cell(), 1, mask=(False, True, False))

    a1.set_constraint([fs1, fs2])

    # reassigning using atoms.__getitem__
    a2 = a1[0:2]

    assert len(a1._constraints) == len(a2._constraints)
def unf(phonon, sc_mat, qpoints, knames=None, x=None, xpts=None):
    prim = phonon.get_primitive()
    prim = Atoms(symbols=prim.get_chemical_symbols(),
                 cell=prim.get_cell(),
                 positions=prim.get_positions())
    #vesta_view(prim)
    sc_qpoints = np.array([np.dot(q, sc_mat) for q in qpoints])
    phonon.set_qpoints_phonon(sc_qpoints, is_eigenvectors=True)
    freqs, eigvecs = phonon.get_qpoints_phonon()
    uf = phonon_unfolder(atoms=prim,
                         supercell_matrix=sc_mat,
                         eigenvectors=eigvecs,
                         qpoints=sc_qpoints,
                         phase=False)
    weights = uf.get_weights()

    #ax=plot_band_weight([list(x)]*freqs.shape[1],freqs.T*8065.6,weights[:,:].T*0.98+0.01,xticks=[knames,xpts],style='alpha')
    ax = plot_band_weight([list(x)] * freqs.shape[1],
                          freqs.T * 33.356,
                          weights[:, :].T * 0.99 + 0.001,
                          xticks=[knames, xpts],
                          style='alpha')
    return ax
Ejemplo n.º 4
0
from __future__ import print_function
from ase.atoms import Atoms
from ase.constraints import FixScaled

a1 = Atoms(symbols = 'X2',
           positions = [[0.,0.,0.], [2.,0.,0.], ],
           cell = [[4.,0.,0.], [0.,4.,0.], [0.,0.,4.], ],
           )

fs1 = FixScaled(a1.get_cell(), -1, mask=(True, False, False))
fs2 = FixScaled(a1.get_cell(), 1, mask=(False, True, False))

a1.set_constraint([fs1,fs2])

# reassigning using atoms.__getitem__
a2 = a1[0:2]

assert len(a1._constraints) == len(a2._constraints)
Ejemplo n.º 5
0
def HEA(f_file, verbose=3):
    """ Helium approach
          Calculate porosity using celllist
          f_file  ... file name
          verbose ... verbosity
      """
    #print('----------------')
    #print('HEA: calculation')
    #print('----------------')
    print('f_file : {}'.format(f_file))
    t1 = time.time()
    # read the structure
    struct = read(f_file)
    p_framework = struct.get_positions()
    s_framework = struct.get_chemical_symbols()
    cell = struct.get_cell()
    Lx = numpy.linalg.norm(cell[:][0, :])
    Ly = numpy.linalg.norm(cell[:][1, :])
    Lz = numpy.linalg.norm(cell[:][2, :])
    # Guess for M
    M0 = get_M(Lx=Lx, Ly=Ly, Lz=Lz, m='high')
    # Optimize d for M0
    dopt = get_opt_r(Lx=Lx, Ly=Ly, Lz=Lz, Mx=M0[0], My=M0[1], Mz=M0[2])
    # Optimize M for dopt
    M = get_M(Lx=Lx, Ly=Ly, Lz=Lz, m='high', d=dopt)
    Mx, My, Mz = M
    # Celllist = get_subcells(cell, M, p_framework)
    # Get COMs of Celllist
    p_insert = get_COMs_celllist(cell, M)
    # Species we are inserting
    s_insert = ['He'] * len(p_insert)
    # Remove atoms an the insertion grid overlapping with the framework
    ropt = dopt / 2.
    print('r_opt:            {:10.5f} A'.format(ropt))
    p_insert_red, s_insert_red = prune_points(p_framework=p_framework,
                                              p_insert=p_insert,
                                              s_framework=s_framework,
                                              s_insert=s_insert,
                                              r_i=ropt)
    # Calculate number of atoms
    N_insert = len(p_insert)
    N_insert_red = len(p_insert_red)
    P_points = N_insert_red / N_insert
    print('N_insert:         {:10d}'.format(N_insert))
    print('N_insert_reduced: {:10d}'.format(N_insert_red))
    # Calculate volumes
    struct_subcell = Atoms(cell=cell)
    cell_subcell = struct_subcell.get_cell()
    cell_subcell[:][0, :] = cell_subcell[:][0, :] / Mx
    cell_subcell[:][1, :] = cell_subcell[:][1, :] / My
    cell_subcell[:][2, :] = cell_subcell[:][2, :] / Mz
    struct_subcell.set_cell(cell_subcell)
    V_subcell = struct_subcell.get_volume() * N_insert_red
    V_insert = 4 / 3. * numpy.pi * ropt**3. * N_insert_red
    V_framework = struct.get_volume()
    P_subcell = V_subcell / V_framework
    print('optimal M:        {:10d} {:10d} {:10d}'.format(Mx, My, Mz))
    # simple cubic packing
    f_sc = 0.52
    f_calc = V_insert / V_subcell
    print('------------------')
    print('packing fraction f')
    print('------------------')
    print('f_sc:             {:15.5f}'.format(f_sc))
    print('f_calc:           {:15.5f}'.format(f_calc))
    P_volume = V_insert / (V_framework * f_calc)
    print('----------------------')
    print('HEA porosity P [%]')
    print('----------------------')
    print('P_subcell:        {:15.5f}'.format(P_subcell * 100.0))
    print('P_points:         {:15.5f}'.format(P_points * 100.0))
    print('P_volume:         {:15.5f}'.format(P_volume * 100.0))
    print('---------------')
    print(' Volume V [A^3]')
    print('---------------')
    print('V_framework:      {:15.5f}'.format(V_framework))
    print('V_subcell:        {:15.5f}'.format(V_subcell))
    print('V_He:             {:15.5f}'.format(V_insert))
    t2 = time.time()
    print('Total CPU time:   {:15.5f} s'.format(t2 - t1))
    print('\n')

    if verbose > 3:
        get_ase(f_file, p_insert_red, s_insert_red)
    return [
        P_points * 100.0, P_subcell * 100.0, P_volume * 100.0, V_framework,
        V_subcell, V_insert, N_insert, N_insert_red, f_calc, ropt
    ]
Ejemplo n.º 6
0
class execution(object):
    def __init__(self, executionInput, xyz=None, stateFile='state.json'):
        '''
  Setup a new execution

  Name:  input file
  xyz:   xyz coordinates (for future automated execution)
  stateFile: state file to use for tracking of executions

  TODO: 

  - only ground state in non-periodic cell supported NOW, more to add!
  - inputs from a dict to better handle automated executions
  '''
        if isinstance(executionInput, str):
            self.inp = self.json(executionInput)
            self.inputFileName = executionInput

        if isinstance(executionInput, dict):
            self.inp = executionInput
            self.inputFileName = 'dict'  # TODO: generate meaningful name here (how?)

        self.setup()

    def setup(self):
        '''setup'''

        self.functional = self.inp.get('functional') or 'LDA'
        self.runtype = self.inp.get('runtype') or 'calc'

        # this actually can't be none!
        _xyz = self.inp.get('xyz')

        if isinstance(_xyz, str):
            self.inputXYZ = _xyz
            self.atoms = read(self.inputXYZ)
        else:
            # support reading frm a dict (TODO: other type of objects - ?)
            from ase.atoms import Atoms
            from ase.atom import Atom

            self.atoms = \
             Atoms([Atom(a[0],(a[1],a[2],a[3])) for a in _xyz])

        # TODO: support multiple cell types
        self.atoms.cell = (self.inp['cell']['x'], self.inp['cell']['y'],
                           self.inp['cell']['z'])

        # Mixer setup - only "broyden" supported
        self.mixer = self.inp.get('mixer')

        if self.mixer is None:
            self.mixer = Mixer
        else:
            self.mixer = BroydenMixer

        # Custom ID: allow to trace parameter set using a custom id
        self.custom_id = self.inp.get('custom_id')

        # Periodic Boundary Conditions
        self.atoms.pbc = False

        # This should not be done always
        self.atoms.center()

        self.nbands = self.inp.get('nbands')

        self.gpts = None
        self.setup_gpts()

        self.max_iterations = self.inp.get('maxiter') or 333

        # Name: to be set by __str__ first time it is run
        self.name = None

        #
        self.logExtension = 'txt'
        self.dataExtension = 'gpw'

        # Timing / statistics
        self.lastElapsed = None

    #
    def get_optimizer(self, name='QuasiNewton'):

        from importlib import import_module

        name = name.lower()
        _optimMap = \
         {
          'mdmin':       'MDMin',
          'hesslbfgs':   'HessLBFGS',
          'linelbfgs':   'LineLBFGS',
          'fire':        'FIRE',
          'lbfgs':       'LBFGS',
          'lbfgsls':     'LBFGSLineSearch',
          'bfgsls':      'BFGSLineSearch',
          'bfgs':        'BFGS',
          'quasinewton': 'QuasiNewton'
         }
        _class = _optimMap[name]
        _m = import_module('ase.optimize')
        return getattr(_m, _class)

    #
    def setup_gpts(self):
        self.gpts = h2gpts(self.inp.get('spacing') or 0.20,
                           self.atoms.get_cell(),
                           idiv=self.inp.get('idiv') or 8)

    def filename(self, force_id=None, extension='txt'):
        '''to correctly support this:
     stateFile support must be completed
     as it isn't just add "_0" to __str__() for now
  '''
        base = self.__str__()

        if self.custom_id is not None:
            base = base + '_' + self.custom_id

        if force_id is None:
            _fn = base + '_0.' + extension
        else:
            _fn = '{}_{}.{}'.format(base, force_id, extension)

        return _fn

    #
    @property
    def xyz(self):
        return self.inp['xyz']

    #
    @property
    def spacegroup(self):
        '''international ID of determined spacegroup'''
        sg = spglib.get_symmetry_dataset(spglib.refine_cell(
            self.atoms))['international']

        return sg.replace('/', ':')

    #
    def __str__(self):
        '''get execution name - to be used for log filename

  Components:

  - Number atoms
  - Volume
  - Spacegroup number
  - Functional name

  '''

        if self.name is None:
            self.name = '{}_{}_{}_{}'.format(
                len(self.atoms), int(self.atoms.get_volume() * 100),
                self.spacegroup, self.functional)

        _gpaw = os.environ['GPAW']
        _pwd = os.environ['PWD']

        self.procname = '{} ({})'.format(self.name,
                                         _pwd.replace(_gpaw + '/', ''))
        setproctitle(self.procname)

        return self.name

    ##
    def print(self, *args, **kwargs):
        '''print wrapper - initial step before logger'''
        r = print(*args, *kwargs)
        return r

    #
    def pretty(self):
        '''pretty print original parameters'''
        _p = pformat(self.inp)
        self.print(_p)

    #
    def json(self, filename):
        '''load parameters from json'''

        with open(filename, 'rb') as f:
            s = f.read()
            j = json.loads(s)

        return j

    #
    def run(self, force_id=None, runtype=None):
        '''
    perform execution - only calc or optim supported now
  '''

        _lastStart = time.time()

        if runtype is None and self.runtype is 'calc':
            _f = self.calc
        else:
            _f = self.optim

        # calculate
        try:
            result = _f(force_id)
        finally:
            _lastEnd = time.time()
            self.lastElapsed = _lastEnd - _lastStart

        return result

    #
    def calc(self, force_id=None, functional=None):
        '''prepare and launch execution
     force_id: use this id for filename generation
  '''

        # Allow to override the funtional
        _fnl = functional or self.functional

        # generate filenames
        _fn = self.filename(force_id)
        _dn = self.filename(force_id, extension=self.dataExtension)

        self.print('Calculation with {} log and Input: {}.'.format(
            _fn, self.inputFileName))

        if self.nbands is None:
            _calc = GPAW(xc=_fnl,
                         txt=self.filename(force_id),
                         mixer=self.mixer(),
                         maxiter=self.max_iterations,
                         gpts=self.gpts)
        else:
            _calc = GPAW(xc=_fnl,
                         txt=self.filename(force_id),
                         nbands=self.nbands,
                         mixer=self.mixer(),
                         maxiter=self.max_iterations,
                         gpts=self.gpts)

        self.atoms.set_calculator(_calc)
        self.atoms.get_potential_energy()

        # write out wavefunctions
        _calc.write(_dn, 'all')
        return _calc

    #####
    def optim(self, force_id=None, functional=None):
        '''prepare and launch execution
     force_id: use this id for filename generation
  '''

        _optim_name = self.inp.get('optimizer') or 'QuasiNewton'
        optimizer = self.get_optimizer(_optim_name)

        # Allow to override the funtional
        _fnl = functional or self.functional

        # generate filenames
        _fn = self.filename(force_id)
        _dn = self.filename(force_id, extension=self.dataExtension)

        self.print('Optimization with {} log and Input: {}.'.format(
            _fn, self.inputFileName))

        if self.nbands is None:
            _calc = GPAW(xc=_fnl,
                         txt=self.filename(force_id),
                         mixer=self.mixer(),
                         maxiter=self.max_iterations,
                         gpts=self.gpts)
        else:
            _calc = GPAW(xc=_fnl,
                         txt=self.filename(force_id),
                         nbands=self.nbands,
                         mixer=self.mixer(),
                         maxiter=self.max_iterations,
                         gpts=self.gpts)

        self.atoms.set_calculator(_calc)

        self.opt = optimizer(self.atoms,
                             trajectory=self.__str__() + '_emt.traj')
        self.opt.run(fmax=0.05)

        # write out wavefunctions
        _calc.write(_dn, 'all')
        return _calc
Ejemplo n.º 7
0
    def __init__(self, geometry=None, **kwargs) -> None:
        if geometry == None:
            atoms = Atoms(**kwargs)
        elif type(geometry) == ase.atoms.Atoms:
            atoms = geometry.copy()
        elif Path(geometry).is_file():
            if str(Path(geometry).parts[-1]) == "geometry.in.next_step":
                atoms = ase.io.read(geometry, format="aims")
            else:
                try:
                    atoms = ase.io.read(geometry)
                except Exception as excpt:
                    logger.error(str(excpt))
                    raise Exception(
                        "ASE was not able to recognize the file format, e.g., a non-standard cif-format."
                    )
        elif Path(geometry).is_dir():
            raise Exception(
                "You specified a directory as input. The geometry must be a file."
            )
        else:
            atoms = None

        assert type(atoms) == ase.atoms.Atoms, "Atoms not read correctly."
        # Get data from another Atoms object:
        numbers = atoms.get_atomic_numbers()
        positions = atoms.get_positions()
        cell = atoms.get_cell()
        celldisp = atoms.get_celldisp()
        pbc = atoms.get_pbc()
        constraint = [c.copy() for c in atoms.constraints]
        masses = atoms.get_masses()
        magmoms = None
        charges = None
        momenta = None
        if atoms.has("initial_magmoms"):
            magmoms = atoms.get_initial_magnetic_moments()
        if atoms.has("initial_charges"):
            charges = atoms.get_initial_charges()
        if atoms.has("momenta"):
            momenta = atoms.get_momenta()
        self.arrays = {}
        super().__init__(
            numbers=numbers,
            positions=positions,
            cell=cell,
            celldisp=celldisp,
            pbc=pbc,
            constraint=constraint,
            masses=masses,
            magmoms=magmoms,
            charges=charges,
            momenta=momenta,
        )
        self._is_1d = None
        self._is_2d = None
        self._is_3d = None
        self._periodic_axes = None
        self._check_lattice_vectors()

        try:
            self.sg = ase.spacegroup.get_spacegroup(self, symprec=1e-2)
        except:
            self.sg = ase.spacegroup.Spacegroup(1)
        self.lattice = self.cell.get_bravais_lattice().crystal_family
Ejemplo n.º 8
0
def read_pw_out(fileobj, index=-1, results_required=True):
    """Reads Quantum ESPRESSO output files.

    The atomistic configurations as well as results (energy, force, stress,
    magnetic moments) of the calculation are read for all configurations
    within the output file.

    Will probably raise errors for broken or incomplete files.

    Parameters
    ----------
    fileobj : file|str
        A file like object or filename
    index : slice
        The index of configurations to extract.
    results_required : bool
        If True, atomistic configurations that do not have any
        associated results will not be included. This prevents double
        printed configurations and incomplete calculations from being
        returned as the final configuration with no results data.

    Yields
    ------
    structure : Atoms
        The next structure from the index slice. The Atoms has a
        SinglePointCalculator attached with any results parsed from
        the file.


    """
    if isinstance(fileobj, str):
        fileobj = open(fileobj, 'rU')

    # work with a copy in memory for faster random access
    pwo_lines = fileobj.readlines()

    # TODO: index -1 special case?
    # Index all the interesting points
    indexes = {
        _PW_START: [],
        _PW_END: [],
        _PW_CELL: [],
        _PW_POS: [],
        _PW_MAGMOM: [],
        _PW_FORCE: [],
        _PW_TOTEN: [],
        _PW_STRESS: [],
        _PW_FERMI: [],
        _PW_HIGHEST_OCCUPIED: [],
        _PW_HIGHEST_OCCUPIED_LOWEST_FREE: [],
        _PW_KPTS: [],
        _PW_BANDS: [],
        _PW_BANDSTRUCTURE: [],
        _PW_ELECTROSTATIC_EMBEDDING: [],
        _PW_NITER: [],
        _PW_DONE: [],
        _PW_WALLTIME: []
    }

    for idx, line in enumerate(pwo_lines):
        for identifier in indexes:
            if identifier in line:
                indexes[identifier].append(idx)

    # Configurations are either at the start, or defined in ATOMIC_POSITIONS
    # in a subsequent step. Can deal with concatenated output files.
    all_config_indexes = sorted(indexes[_PW_START] + indexes[_PW_POS])

    # Slice only requested indexes
    # setting results_required argument stops configuration-only
    # structures from being returned. This ensures the [-1] structure
    # is one that has results. Two cases:
    # - SCF of last configuration is not converged, job terminated
    #   abnormally.
    # - 'relax' and 'vc-relax' re-prints the final configuration but
    #   only 'vc-relax' recalculates.
    if results_required:
        results_indexes = sorted(indexes[_PW_TOTEN] + indexes[_PW_FORCE] +
                                 indexes[_PW_STRESS] + indexes[_PW_MAGMOM] +
                                 indexes[_PW_BANDS] +
                                 indexes[_PW_ELECTROSTATIC_EMBEDDING] +
                                 indexes[_PW_BANDSTRUCTURE])

        # Prune to only configurations with results data before the next
        # configuration
        results_config_indexes = []
        for config_index, config_index_next in zip(
                all_config_indexes, all_config_indexes[1:] + [len(pwo_lines)]):
            if any([
                    config_index < results_index < config_index_next
                    for results_index in results_indexes
            ]):
                results_config_indexes.append(config_index)

        # slice from the subset
        image_indexes = results_config_indexes[index]
    else:
        image_indexes = all_config_indexes[index]

    # Extract initialisation information each time PWSCF starts
    # to add to subsequent configurations. Use None so slices know
    # when to fill in the blanks.
    pwscf_start_info = dict((idx, None) for idx in indexes[_PW_START])

    if isinstance(image_indexes, int):
        image_indexes = [image_indexes]

    for image_index in image_indexes:
        # Find the nearest calculation start to parse info. Needed in,
        # for example, relaxation where cell is only printed at the
        # start.
        if image_index in indexes[_PW_START]:
            prev_start_index = image_index
        else:
            # The greatest start index before this structure
            prev_start_index = [
                idx for idx in indexes[_PW_START] if idx < image_index
            ][-1]

        # add structure to reference if not there
        if pwscf_start_info[prev_start_index] is None:
            pwscf_start_info[prev_start_index] = parse_pwo_start(
                pwo_lines, prev_start_index)

        # Get the bounds for information for this structure. Any associated
        # values will be between the image_index and the following one,
        # EXCEPT for cell, which will be 4 lines before if it exists.
        for next_index in all_config_indexes:
            if next_index > image_index:
                break
        else:
            # right to the end of the file
            next_index = len(pwo_lines)

        # Get the structure
        # Use this for any missing data
        prev_structure = pwscf_start_info[prev_start_index]['atoms']
        if image_index in indexes[_PW_START]:
            structure = prev_structure.copy()  # parsed from start info
        else:
            if _PW_CELL in pwo_lines[image_index - 5]:
                # CELL_PARAMETERS would be just before positions if present
                cell, cell_alat = get_cell_parameters(pwo_lines[image_index -
                                                                5:image_index])
            else:
                cell = prev_structure.cell
                cell_alat = pwscf_start_info[prev_start_index]['alat']

            # give at least enough lines to parse the positions
            # should be same format as input card
            n_atoms = len(prev_structure)
            positions_card = get_atomic_positions(
                pwo_lines[image_index:image_index + n_atoms + 1],
                n_atoms=n_atoms,
                cell=cell,
                alat=cell_alat)

            # convert to Atoms object
            symbols = [
                label_to_symbol(position[0]) for position in positions_card
            ]
            tags = [label_to_tag(position[0]) for position in positions_card]
            positions = [position[1] for position in positions_card]

            constraint_idx = [position[2] for position in positions_card]
            constraint = get_constraint(constraint_idx)

            structure = Atoms(symbols=symbols,
                              positions=positions,
                              cell=cell,
                              constraint=constraint,
                              pbc=True,
                              tags=tags)

        # Extract calculation results
        # Energy
        energy = None
        for energy_index in indexes[_PW_TOTEN]:
            if image_index < energy_index < next_index:
                energy = float(
                    pwo_lines[energy_index].split()[-2]) * units['Ry']

        # Electrostatic enbedding energy
        elec_embedding_energy = None
        for eee_index in indexes[_PW_ELECTROSTATIC_EMBEDDING]:
            if image_index < eee_index < next_index:
                elec_embedding_energy = float(
                    pwo_lines[eee_index].split()[-2]) * units['Ry']

        # Number of iterations
        n_iterations = None
        for niter_index in indexes[_PW_NITER]:
            if image_index < niter_index < next_index:
                n_iterations = int(
                    pwo_lines[niter_index].split('#')[1].split()[0])

        # Forces
        forces = None
        for force_index in indexes[_PW_FORCE]:
            if image_index < force_index < next_index:
                # Before QE 5.3 'negative rho' added 2 lines before forces
                # Use exact lines to stop before 'non-local' forces
                # in high verbosity
                if not pwo_lines[force_index + 2].strip():
                    force_index += 4
                else:
                    force_index += 2
                # assume contiguous
                forces = [[float(x) for x in force_line.split()[-3:]]
                          for force_line in pwo_lines[force_index:force_index +
                                                      len(structure)]]
                forces = np.array(forces) * units['Ry'] / units['Bohr']

        # Stress
        stress = None
        for stress_index in indexes[_PW_STRESS]:
            if image_index < stress_index < next_index:
                sxx, sxy, sxz = pwo_lines[stress_index + 1].split()[:3]
                _, syy, syz = pwo_lines[stress_index + 2].split()[:3]
                _, _, szz = pwo_lines[stress_index + 3].split()[:3]
                stress = np.array([sxx, syy, szz, syz, sxz, sxy], dtype=float)
                # sign convention is opposite of ase
                stress *= -1 * units['Ry'] / (units['Bohr']**3)

        # Magmoms
        magmoms = None
        for magmoms_index in indexes[_PW_MAGMOM]:
            if image_index < magmoms_index < next_index:
                magmoms = [
                    float(mag_line.split('=')[-1])
                    for mag_line in pwo_lines[magmoms_index + 1:magmoms_index +
                                              1 + len(structure)]
                ]

        # Fermi level / highest occupied level and lowest unoccupied level
        efermi = None
        lumo_ene = None
        for fermi_index in indexes[_PW_FERMI]:
            if image_index < fermi_index < next_index:
                efermi = float(pwo_lines[fermi_index].split()[-2])

        if efermi is None:
            for ho_index in indexes[_PW_HIGHEST_OCCUPIED]:
                if image_index < ho_index < next_index:
                    efermi = float(pwo_lines[ho_index].split()[-1])

        if efermi is None:
            for holf_index in indexes[_PW_HIGHEST_OCCUPIED_LOWEST_FREE]:
                if image_index < holf_index < next_index:
                    efermi = float(pwo_lines[holf_index].split()[-2])
                    lumo_ene = float(pwo_lines[holf_index].split()[-1])

        # K-points
        ibzkpts = None
        weights = None
        kpoints_warning = "Number of k-points >= 100: " + \
                          "set verbosity='high' to print them."

        for kpts_index in indexes[_PW_KPTS]:
            nkpts = int(pwo_lines[kpts_index].split()[4])
            kpts_index += 2

            if pwo_lines[kpts_index].strip() == kpoints_warning:
                continue

            # QE prints the k-points in units of 2*pi/alat
            # with alat defined as the length of the first
            # cell vector
            cell = structure.get_cell()
            alat = np.linalg.norm(cell[0])
            ibzkpts = []
            weights = []
            for i in range(nkpts):
                L = pwo_lines[kpts_index + i].split()
                weights.append(float(L[-1]))
                coord = np.array([L[-6], L[-5], L[-4].strip('),')],
                                 dtype=float)
                coord *= 2 * np.pi / alat
                coord = kpoint_convert(cell, ckpts_kv=coord)
                ibzkpts.append(coord)
            ibzkpts = np.array(ibzkpts)
            weights = np.array(weights)

        # Bands
        kpts = None
        kpoints_warning = "Number of k-points >= 100: " + \
                          "set verbosity='high' to print the bands."

        for bands_index in indexes[_PW_BANDS] + indexes[_PW_BANDSTRUCTURE]:
            if image_index < bands_index < next_index:
                bands_index += 2

                if pwo_lines[bands_index].strip() == kpoints_warning:
                    continue

                assert ibzkpts is not None
                spin, bands, eigenvalues = 0, [], [[], []]

                while True:
                    L = pwo_lines[bands_index].replace('-', ' -').split()
                    if len(L) == 0:
                        if len(bands) > 0:
                            eigenvalues[spin].append(bands)
                            bands = []
                    elif L == ['occupation', 'numbers']:
                        # Skip the lines with the occupation numbers
                        bands_index += len(eigenvalues[spin][0]) // 8 + 1
                    elif L[0] == 'k' and L[1].startswith('='):
                        pass
                    elif 'SPIN' in L:
                        if 'DOWN' in L:
                            spin += 1
                    else:
                        try:
                            bands.extend(map(float, L))
                        except ValueError:
                            break
                    bands_index += 1

                if spin == 1:
                    assert len(eigenvalues[0]) == len(eigenvalues[1])
                # assert len(eigenvalues[0]) == len(ibzkpts), \
                #     (np.shape(eigenvalues), len(ibzkpts))

                kpts = []
                for s in range(spin + 1):
                    for w, k, e in zip(weights, ibzkpts, eigenvalues[s]):
                        kpt = SinglePointKPoint(w, s, k, eps_n=e)
                        kpts.append(kpt)

        # Convergence
        job_done = False
        for done_index in indexes[_PW_DONE]:
            if image_index < done_index < next_index:
                job_done = True

        # Walltime
        walltime = None
        for wt_index in indexes[_PW_WALLTIME]:
            if image_index < wt_index < next_index:
                walltime = time_to_float(pwo_lines[wt_index].split()[-2])

        # Put everything together
        calc = SinglePointDFTCalculator(structure,
                                        energy=energy,
                                        forces=forces,
                                        stress=stress,
                                        magmoms=magmoms,
                                        efermi=efermi,
                                        ibzkpts=ibzkpts)
        calc.results['homo_energy'] = efermi
        calc.results['lumo_energy'] = lumo_ene
        calc.results['electrostatic embedding'] = elec_embedding_energy
        calc.results['iterations'] = n_iterations
        calc.results['job done'] = job_done
        calc.results['walltime'] = walltime

        calc.kpts = kpts
        structure.calc = calc

        yield structure
Ejemplo n.º 9
0
from ase.atoms import Atoms
from ase.constraints import FixScaled

a1 = Atoms(
    symbols='X2',
    positions=[
        [0., 0., 0.],
        [2., 0., 0.],
    ],
    cell=[
        [4., 0., 0.],
        [0., 4., 0.],
        [0., 0., 4.],
    ],
)

fs1 = FixScaled(a1.get_cell(), -1, mask=(True, False, False))
fs2 = FixScaled(a1.get_cell(), 1, mask=(False, True, False))

a1.set_constraint([fs1, fs2])

# reassigning using atoms.__getitem__
a2 = a1[0:2]

assert len(a1._constraints) == len(a2._constraints)