Ejemplo n.º 1
0
    def set_surfaces_layers(self, surfaces, layers):
        if len(surfaces) != len(layers):
            raise ValueError("Improper size of surface and layer arrays: %i != %i"
                             % (len(surfaces), len(layers)))

        sg = Spacegroup(self.spacegroup)
        surfaces = np.array(surfaces)
        layers = np.array(layers)

        for i, s in enumerate(surfaces):
            s = reduce_miller(s)
            surfaces[i] = s

        surfaces_full = surfaces.copy()
        layers_full = layers.copy()

        for s, l in zip(surfaces, layers):
            equivalent_surfaces = sg.equivalent_reflections(s.reshape(-1, 3))

            for es in equivalent_surfaces:
                # If the equivalent surface (es) is not in the surface list,
                # then append it.
                if not np.equal(es, surfaces_full).all(axis=1).any():
                    surfaces_full = np.append(surfaces_full, es.reshape(1, 3), axis=0)
                    layers_full = np.append(layers_full, l)

        self.surfaces = surfaces_full.copy()
        self.layers = layers_full.copy()
Ejemplo n.º 2
0
def fit_elastic():
    from ase.db import connect
    atoms = bulk("Al") * (2, 2, 2)
    elastic = ElasticConstants(atoms, DB_NAME)
    db = connect(DB_NAME)

    stresses = []
    strains = []
    for row in db.select('id>=25'):
        stress = np.array(row["stress"])
        stresses.append(stress)
        strain = np.array(db.get(id=row.init_struct).data["strain"])
        strains.append(strain)

    from ase.spacegroup import Spacegroup
    spg = Spacegroup(123)
    print(spg.get_rotations())
    C = elastic.get(stresses=stresses, strains=strains, spg=225, perm="zxy")
    print("Bulk:")
    print("Voigt: {}".format(elastic.bulk_modulus(mode="V") / GPa))
    print("Reuss: {}".format(elastic.bulk_modulus(mode="R") / GPa))
    print("VRH: {}".format(elastic.bulk_modulus(mode="VRH") / GPa))
    print("Shear:")
    print("Voigt: {}".format(elastic.shear_modulus(mode="V") / GPa))
    print("Reuss: {}".format(elastic.shear_modulus(mode="R") / GPa))
    print("VRH: {}".format(elastic.shear_modulus(mode="VRH") / GPa))
    print("Shear: {}".format(elastic.shear_modulus(mode="VRH")))
    print("Poisson: {}".format(elastic.poisson_ratio))
    #np.set_printoptions(precision=2)
    print(C)
    np.savetxt("data/C_MgSi100_225.csv", C, delimiter=",")
Ejemplo n.º 3
0
def _spacegroup_reciprocal_cell(no, setting):
    try:
        sg = Spacegroup(no, setting)
    except SpacegroupNotFoundError:
        return
    reciprocal_check = np.linalg.inv(sg.scaled_primitive_cell).T
    assert_allclose(sg.reciprocal_cell, reciprocal_check, atol=TOL)
Ejemplo n.º 4
0
    def __init__(self, atoms, tolerance=1e-3):

        self.spglibdata = get_symmetry_dataset((atoms.get_cell(),
                                                atoms.get_scaled_positions(),
                                                atoms.get_atomic_numbers()),
                                               symprec=tolerance)

        self.tolerance = tolerance

        self.spacegroup = self.spglibdata['number']
        self.Spacegroup = Spacegroup(self.spacegroup)
        self.atoms = self.get_conventional_atoms(atoms)

        super().__init__(spacegroup=self.spacegroup)

        self.set_wyckoff_species()
        WyckoffSymmetries.wyckoffs = self.wyckoffs
        WyckoffSymmetries.species = self.species
Ejemplo n.º 5
0
 def writeFile(self, filename):
     ''' Write molecule to P1 cell to check things '''
     from ase import Atoms
     from ase.spacegroup import Spacegroup
     dummyAtoms = Atoms(symbols=[x['symbol'] for x in self.atomList],
                        positions=[x['position'] for x in self.atomList],
                        cell=50. * np.eye(3),
                        info={'spacegroup': Spacegroup(1)})
     dummyAtoms.write(filename)
Ejemplo n.º 6
0
 def writeFile(self, filename):
     ''' Write molecule to P1 cell to check things -note that ase cif writer might wrap atoms '''
     from ase import Atoms
     from ase.spacegroup import Spacegroup
     dummyAtoms = Atoms(symbols=self.aseAtoms.get_chemical_symbols(),
                        positions=self.aseAtoms.get_positions(),
                        cell=50. * np.eye(3),
                        info={'spacegroup': Spacegroup(1)})
     dummyAtoms.write(filename)
 def _symmetrize_elastic_tensor(self, spg=1, perm="xyz"):
     if spg == 1:
         return
     permut_lut = {"xyz": 0, "zxy": -1, "yzx": -2}
     from ase.spacegroup import Spacegroup
     spg = Spacegroup(spg)
     sym_op = spg.get_rotations()
     full = self._to_full_rank4(self.elastic_tensor)
     new_tensor = np.zeros((3, 3, 3, 3))
     for op in sym_op:
         op = np.roll(op, permut_lut[perm], (0, 1))
         avg_tensor = np.zeros((3, 3, 3, 3))
         avg_tensor = np.einsum("pl,ijkl->ijkp", op, full)
         avg_tensor = np.einsum("ok,ijkp->ijop", op, avg_tensor)
         avg_tensor = np.einsum("nj,ijop->inop", op, avg_tensor)
         avg_tensor = np.einsum("mi,inop->mnop", op, avg_tensor)
         new_tensor += avg_tensor
     new_tensor /= len(sym_op)
     self.elastic_tensor = self._to_mandel_rank4(new_tensor)
Ejemplo n.º 8
0
def _get_spacegroup(atoms, symprec=1e-5, center=None):
    """ASE implementation of get_spacegroup.
    """

    # we try all available spacegroups from 1 to 230, backwards
    # a Space group is the collection of all symmetry operations which lets the
    # unit cell invariant.
    found = None
    positions = atoms.get_scaled_positions(wrap=True)  # in the lattice frame

    # make sure we are insensitive to translation. this choice is arbitrary and
    # could lead to a 'slightly' wrong guess for the Space group, e.g. do not
    # guess centro-symmetry.
    if center:
        try:
            positions -= positions[center]
        except IndexError:
            pass

    # search space groups from the highest symmetry to the lowest
    # retain the first match
    for nb in range(230, 0, -1):
        sg = Spacegroup(nb)
        #
        # now we scan all atoms in the cell and look for equivalent sites
        try:
            sites, kinds = sg.equivalent_sites(positions,
                                               onduplicates='keep',
                                               symprec=symprec)
        except TypeError:
            # ASE <= 3.9
            sites, kinds = sg.equivalent_sites(positions,
                                               ondublicates='keep',
                                               symprec=symprec)
        #
        # the equivalent sites should match all other atom locations in the cell
        # as the spacegroup transforms the unit cell in itself
        if len(sites) == len(positions):
            # store the space group into the list
            found = sg
            break

    return found
Ejemplo n.º 9
0
 def aseAtoms(self):
     ''' Take symbols and positions from atomList
         Function as atomList may be updated 
         Cell is just large P1 box '''
     from ase import Atoms
     from ase.spacegroup import Spacegroup
     return Atoms(symbols=[x['symbol'] for x in self.atomList],
                  positions=[x['position'] for x in self.atomList],
                  cell=50. * np.eye(3),
                  info={'spacegroup': Spacegroup(1)})
Ejemplo n.º 10
0
def test_spacegroup_miscellaneous():
    no = 225
    sg = Spacegroup(no)
    assert int(sg) == no == sg.no
    assert sg.centrosymmetric
    assert sg.symbol == 'F m -3 m'
    assert sg.symbol in str(sg)
    assert sg.lattice == 'F'  # face-centered
    assert sg.setting == 1
    assert sg.scaled_primitive_cell == pytest.approx(FCC(1.0).tocell()[:])
    assert sg.reciprocal_cell @ sg.scaled_primitive_cell == pytest.approx(
        np.identity(3))
Ejemplo n.º 11
0
    def __init__(self, interface: "CppInterfaceClass" = None, weight=0.5) -> None:
        bottom = cpp_atoms_to_ase_atoms(interface.bottom)
        top = cpp_atoms_to_ase_atoms(interface.top)
        stack = cpp_atoms_to_ase_atoms(interface.stack)

        self.bottom = recenter(bottom)
        self.top = recenter(top)
        self.stack = recenter(stack)
        self.stack = stack
        self.M = [[j for j in k] for k in interface.M]
        self.N = [[j for j in k] for k in interface.N]
        self.spacegroup = Spacegroup(interface.spacegroup)
        self.angle = interface.angle
        self._weight = weight
        self._stress = None
Ejemplo n.º 12
0
def get_sg(lattice):

    """
    Get the space-group of the system.

    Args:
        lattice: the ASE crystal class
    Returns:
        sg (int): integer number of the spacegroup
    """
    spacegroup = spglib.get_spacegroup(lattice, symprec=1e-5)
    space_split=spacegroup.split()
    spg_num = space_split[1].replace('(','').replace(')','')
    sg = Spacegroup(int(spg_num))
    return sg
Ejemplo n.º 13
0
def write_jsv(f, atoms):
    """Writes JSV file."""
    f.write('asymmetric_unit_cell\n')

    f.write('[cell]')
    for v in cell_to_cellpar(atoms.cell):
        f.write('  %g' % v)
    f.write('\n')

    f.write('[natom]  %d\n' % len(atoms))
    f.write('[nbond]  0\n')  # FIXME
    f.write('[npoly]  0\n')  # FIXME

    if 'spacegroup' in atoms.info:
        sg = Spacegroup(atoms.info['spacegroup'])
        f.write('[space_group]  %d %d\n' % (sg.no, sg.setting))
    else:
        f.write('[space_group]  1  1\n')

    f.write('[title] %s\n' % atoms.info.get('title', 'untitled'))

    f.write('\n')
    f.write('[atoms]\n')
    if 'labels' in atoms.info:
        labels = atoms.info['labels']
    else:
        labels = [
            '%s%d' % (s, i + 1)
            for i, s in enumerate(atoms.get_chemical_symbols())
        ]
    numbers = atoms.get_atomic_numbers()
    scaled = atoms.get_scaled_positions()
    for l, n, p in zip(labels, numbers, scaled):
        f.write('%-4s  %2d  %9.6f  %9.6f  %9.6f\n' % (l, n, p[0], p[1], p[2]))

    f.write('Label  AtomicNumber  x y z (repeat natom times)\n')

    f.write('\n')
    f.write('[bonds]\n')

    f.write('\n')
    f.write('[poly]\n')

    f.write('\n')
Ejemplo n.º 14
0
def get_spacegroup(atoms, symprec=1e-5, method='phonopy'):
    """Determine the spacegroup to which belongs the Atoms object.
    
    Parameters:
    atoms:    an Atoms object
    symprec:  Symmetry tolerance, i.e. distance tolerance in Cartesian 
              coordinates to find crystal symmetry.
    method:   'phonopy' when available, or 'ase'
              
    The Spacegroup object is returned, and stored in atoms.info['spacegroup'] 
    when this key does not exist (avoids overwrite). To force overwrite of the 
    spacegroup first use:
        del atoms.info["spacegroup"]
                  
    Examples:
    
    >>> from ase.lattice import bulk
    >>> atoms = bulk("Cu", "fcc", a=3.6, cubic=True)
    >>> sg = ifit.get_spacegroup(atoms)
    """

    # use spglib when it is available (and return)
    if has_spglib and method in ('phonopy', 'spglib'):
        sg = spglib.get_spacegroup(atoms)
        sg_no = int(sg[sg.find("(") + 1:sg.find(")")])
        atoms.info["spacegroup"] = Spacegroup(sg_no)
        return atoms.info["spacegroup"]

    # no spglib, we use our own spacegroup finder. Not as robust as spglib.
    # we center the Atoms positions on each atom in the cell, and find the
    # spacegroup of highest symmetry
    found = None
    for kind, pos in enumerate(atoms.get_scaled_positions()):
        sg = _get_spacegroup(atoms, symprec=1e-5, center=kind)
        if found is None or sg.no > found.no:
            found = sg

    # return None when no space group is found (would be surprising)
    if found is not None and 'spacegroup' not in atoms.info:
        atoms.info["spacegroup"] = found

    return found
Ejemplo n.º 15
0
    def writeASEAtoms(self, filename, pbc=True, wrapAtoms=False):
        ''' Combine aseAtoms objects and then write to filename 
            N.B. Atoms.write puts things into P1 for some reason '''
        from ase import Atoms

        if filename.lower()[-4:] == '.xyz':
            from ase.spacegroup import Spacegroup
            dummyAtoms = Atoms(symbols=np.concatenate([
                x.aseAtoms.get_chemical_symbols()
                for x in self.asymmetricMolecules
            ]),
                               positions=np.concatenate([
                                   x.aseAtoms.get_positions()
                                   for x in self.asymmetricMolecules
                               ]),
                               cell=50. * np.eye(3),
                               info={'spacegroup': Spacegroup(1)})
            dummyAtoms.write(filename)
            return True

        _writingAtoms = Atoms(
            symbols=[
                x for m in self.asymmetricMolecules
                for x in m.aseAtoms.get_chemical_symbols()
            ],
            scaled_positions=np.array([
                x for m in self.asymmetricMolecules
                for x in m.aseAtoms.get_scaled_positions(wrap=False)
            ]),
            cell=self.aseCell,
            pbc=pbc,
            info=self.aseInfo)
        #                              cell    = self.asymmetricMolecules[0].aseAtoms.cell,
        #                              pbc     = True,
        #                              info    = self.asymmetricMolecules[0].aseAtoms.info)
        if wrapAtoms == False:
            from ioAndInterfaces import aseWriteCifNoWrap
            aseWriteCifNoWrap(filename, [_writingAtoms])
        else:
            _writingAtoms.write(filename)
Ejemplo n.º 16
0
    def interface_energy_poly_expansion(self,
                                        order=2,
                                        show=False,
                                        spg=1,
                                        penalty=0.0,
                                        average_cutoff=10.0):
        """Fit a multidimensional polynomial of a certain order."""
        from itertools import combinations_with_replacement
        interf = self.interface_energy(average_cutoff=average_cutoff)
        self.spg = spg
        if spg > 1:
            from ase.spacegroup import Spacegroup
            self.spg_group = Spacegroup(spg)
        num_terms = int((3**(order + 1) - 1) / 2)

        print("Number of terms in polynomial expansion: {}".format(num_terms))
        # A = np.zeros((len(interf), num_terms))
        A = []
        num_data_points = len(interf)
        A.append(np.ones(num_data_points))
        col = 1
        mult_order = [()]
        now = time.time()
        output_every = 10
        self.spg_num = spg

        # Try to load already computed orders
        try:
            import json
            with open(self.symmetry_fname, 'r') as infile:
                precomputed_order = json.load(infile)
            print("Valid terms are read from {}. "
                  "Delete the file if you want a "
                  "new calculation from scratch."
                  "".format(self.symmetry_fname))
        except IOError:
            precomputed_order = {}

        pre_computed_sizes = [int(key) for key in precomputed_order.keys()]
        for p in range(1, order + 1):
            if p in pre_computed_sizes:
                # Use only the ones that already have been
                # calculated
                combs = precomputed_order[str(p)]
            else:
                # No precalculations was made
                # Check all combinations
                combs = combinations_with_replacement(range(3), p)
            for comb in combs:
                if not self.is_valid(comb):
                    continue
                if time.time() - now > output_every:
                    print("Calculating order {} permutation {}"
                          "".format(p, comb))
                    now = time.time()
                vec = np.zeros(len(interf))
                row = 0
                for n, value in interf:
                    x = self._get_x_value(n, comb)
                    vec[row] = x
                    row += 1
                A.append(vec)
                mult_order.append(comb)
                col += 1
        A = np.array(A).T
        print(A.shape)

        rhs = np.zeros(len(interf))
        row = 0
        for n, value in interf:
            rhs[row] = value
            row += 1

        print("Filtering duplicates...")
        # unique_cols = self._unique_columns(A)
        # A = A[:, unique_cols]
        num_rows = A.shape[0]
        # A, unique_cols = np.unique(A, axis=1, return_index=True)
        unique_cols = self._unique_columns(A)
        A = A[:, unique_cols]
        assert A.shape[0] == num_rows
        mult_order = [mult_order[indx] for indx in unique_cols]

        # Filter constant columns
        constant_columns = []
        for i in range(1, A.shape[1]):
            if np.allclose(A[:, i], A[0, i]):
                constant_columns.append(i)
        A = np.delete(A, constant_columns, axis=1)
        assert A.shape[0] == num_rows

        mult_order = [
            mult_order[indx] for indx in range(len(mult_order))
            if indx not in constant_columns
        ]
        self._save_valid_order(mult_order)
        print(
            "Number of terms after applying spacegroup symmetries: {}".format(
                A.shape[1]))
        print("Solving linear system...")
        if A.shape[1] == 1:
            # TODO: Trivial solution, calculate this directly
            coeff, residual, rank, s = np.linalg.lstsq(A, rhs)
        else:
            N = A.shape[1]
            matrix = np.linalg.inv(A.T.dot(A) + penalty * np.identity(N))
            coeff = matrix.dot(A.T.dot(rhs))

        # Perform one consistency check
        mean_val = np.mean(rhs)
        if coeff[0] > 2.0 * mean_val or coeff[0] < 0.5 * mean_val:
            print("Warning! This fit looks suspicious. Constant term {}"
                  "Mean of dataset: {}."
                  "Consider to increase the penalty!"
                  "".format(coeff[0], mean_val))

        self.linear_fit["coeff"] = coeff
        self.linear_fit["order"] = mult_order
        pred = A.dot(coeff)
        rmse = np.sqrt(np.mean((pred - rhs)**2))
        print("RMSE of surface parametrization: {}".format(rmse))
        if show:
            from matplotlib import pyplot as plt
            fig = plt.figure()
            ax = fig.add_subplot(1, 1, 1)
            ax.plot(pred, rhs, 'o', mfc="none")
            min_val = np.min(pred) - 1
            max_val = np.max(pred) + 1
            ax.plot([min_val, max_val], [min_val, max_val])
            ax.plot([min_val, max_val], [min_val + rmse, max_val + rmse], "--")
            ax.plot([min_val, max_val], [min_val - rmse, max_val - rmse], "--")
            self.plot_fitting_coefficients()
            plt.show()
Ejemplo n.º 17
0
class PrototypeClassification(WyckoffSymmetries):
    """Prototype classification of atomic structure in ASE Atoms format"""

    def __init__(self, atoms, tolerance=1e-3):

        self.spglibdata = get_symmetry_dataset((atoms.get_cell(),
                                                atoms.get_scaled_positions(),
                                                atoms.get_atomic_numbers()),
                                               symprec=tolerance)

        self.tolerance = tolerance

        self.spacegroup = self.spglibdata['number']
        self.Spacegroup = Spacegroup(self.spacegroup)
        self.atoms = self.get_conventional_atoms(atoms)

        super().__init__(spacegroup=self.spacegroup)

        self.set_wyckoff_species()
        WyckoffSymmetries.wyckoffs = self.wyckoffs
        WyckoffSymmetries.species = self.species


    def get_conventional_atoms(self, atoms):
        """Transform from primitive to conventional cell"""


        std_cell = self.spglibdata['std_lattice']

        positions = self.spglibdata['std_positions']
        numbers = self.spglibdata['std_types']

        atoms = Atoms(numbers=numbers,
                      cell=std_cell,
                      pbc=True)

        atoms.set_scaled_positions(positions)
        atoms.wrap()

        return atoms

    def get_primitive_atoms(self, atoms):
        """Transform from primitive to conventional cell"""

        lattice, scaled_positions, numbers = standardize_cell(atoms,
                                                              to_primitive=True,
                                                              no_idealize=False,
                                                              symprec=1e-5)

        atoms = Atoms(numbers=numbers,
                      cell=lattice,
                      pbc=True)

        atoms.set_scaled_positions(scaled_positions)

        atoms.wrap()

        return atoms

    def set_wyckoff_species(self):
        self.wyckoffs = []
        self.species = []

        relative_positions = np.dot(np.linalg.inv(
            self.atoms.cell.T), self.atoms.positions.T).T

        relative_positions = np.round(relative_positions, 10)

        normalized_sites = \
            self.Spacegroup.symmetry_normalised_sites(
                np.array(relative_positions,
                         ndmin=2))

        equivalent_sites = []
        for i, site in enumerate(normalized_sites):
            indices = np.all(np.isclose(site, normalized_sites[:i+1],
                                        rtol=self.tolerance), axis=1)
            index = np.min(np.where(indices)[0])
            equivalent_sites += [index]

        unique_site_indices = list(set(equivalent_sites))

        unique_sites = normalized_sites[unique_site_indices]
        count_sites = [list(equivalent_sites).count(i)
                       for i in unique_site_indices]

        symbols = self.atoms[unique_site_indices].get_chemical_symbols()

        for i, position in enumerate(unique_sites):
            found = False
            for w in sorted(self.wyckoff_symmetries.keys()):
                m = self.wyckoff_multiplicities[w]
                if not count_sites[i] == m:
                    continue
                for w_sym in self.wyckoff_symmetries[w]:
                    if found:
                        break
                    if self.is_position_wyckoff(position, w_sym):
                        found = True
                        self.wyckoffs += [w]
                        self.species += [symbols[i]]
                        break
            if not found:
                print('Error: position: ', position, ' not identified')

        indices = np.argsort(self.species)

        w_sorted = []
        # for s in set(self.species):
        #    indices = [i for i, s0 in enumerate(self.species) if s0==s]
        #    w_sorted += sorted([self.wyckoffs[i] for i in indices])
        #self.wyckoffs = w_sorted

        free_wyckoffs = self.get_free_wyckoffs()
        self.atoms_wyckoffs = []
        self.free_atoms = []
        for site in equivalent_sites:
            index = unique_site_indices.index(site)
            w_position = self.wyckoffs[index]
            self.atoms_wyckoffs += [w_position + str(index)]
            self.free_atoms += [w_position in free_wyckoffs]

    def get_spacegroup(self):
        return self.spacegroup

    def get_wyckoff_species(self):
        return self.wyckoffs, self.species

    def get_classification(self, include_parameters=True):

        p_name = self.get_prototype_name(self.species)

        structure_name = str(self.spacegroup)
        for spec, wy_spec in zip(self.species, self.wyckoffs):
            structure_name += '_{}_{}'.format(spec, wy_spec)

        prototype = {'p_name': p_name,
                     'structure_name': structure_name,
                     'spacegroup': self.spacegroup,
                     'wyckoffs': self.wyckoffs,
                     'species': self.species}

        if include_parameters:
            cell_parameters = self.get_cell_parameters(self.atoms)

            return prototype, cell_parameters

        else:
            return prototype
def main():

    args = parse_args()
    print("args", args)

    if args.implementation == TORCHANI:
        from torchani_calculator import torchani_calculator
        calculator = torchani_calculator(args.network_type)
    elif args.implementation == AES_ANI:
        from ani_ase import ani_ase_calculator
        calculator = ani_ase_calculator(args.network_type)
    elif args.implementation == KHAN:
        from khan_calculator import khan_calculator
        calculator = khan_calculator(args.network_type, args.khan_network,
                                     args.numb_networks)

    assert args.cif_file.endswith('.cif')

    print('debug? ', args.debug)
    atoms = ase_io.read(args.cif_file)
    numb_molecules = len(molecule_lists(atoms))
    print('number of molecules: ', numb_molecules)
    MC_stpes = args.MC
    space_group = Spacegroup(args.space_group)
    # step size in MC
    f1, f2, f3, f4, f5, f6, f7, f8 = args.MC_f1_f2_f3_f4_f5_f6_f7_f8
    perturbation_type = args.perturbation_type
    molecule1_in_cell = []
    for i in range(1, atoms.get_number_of_atoms()):
        if atom_belong_to_mol1(i, atoms):
            molecule1_in_cell.append(i)
    print("initial unit cell")
    print(atoms.cell)
    print("To do Monte Carlo for %d step." % MC_stpes)
    print("Molecule index in ASU are: ", molecule1_in_cell)

    counter = 0
    atoms.set_calculator(calculator)
    while (counter <= MC_stpes):
        if isinstance(perturbation_type, list):
            # random_number = random.choice([1,2,3,4,5,6,7,8])
            random_choices = get_random_choices(
                [f1, f2, f3, f4, f5, f6, f7, f8])
            random_number = random.choice(random_choices)
        else:
            random_number = perturbation_dict[perturbation_type]
        if random_number == 1:
            # translation
            Monte_Carlo(atoms, calculator, space_group, f1, 'translate',
                        counter, numb_molecules, molecule1_in_cell, MC_stpes,
                        args.debug)
            counter += 1
        elif random_number == 2:
            # rotation
            Monte_Carlo(atoms, calculator, space_group, f2, 'rotation',
                        counter, numb_molecules, molecule1_in_cell, MC_stpes,
                        args.debug)
            counter += 1
        elif random_number == 3:
            # cell_length a
            Monte_Carlo(atoms, calculator, space_group, f3, 'cell_length_a',
                        counter, numb_molecules, molecule1_in_cell, MC_stpes,
                        args.debug)
            counter += 1
        elif random_number == 4:
            # cell_length b
            Monte_Carlo(atoms, calculator, space_group, f4, 'cell_length_b',
                        counter, numb_molecules, molecule1_in_cell, MC_stpes,
                        args.debug)
            counter += 1
        elif random_number == 5:
            # cell_length c
            Monte_Carlo(atoms, calculator, space_group, f5, 'cell_length_c',
                        counter, numb_molecules, molecule1_in_cell, MC_stpes,
                        args.debug)
            counter += 1
        elif random_number == 6:
            # cell_angle alpha
            Monte_Carlo(atoms, calculator, space_group, f6, 'cell_angle_alpha',
                        counter, numb_molecules, molecule1_in_cell, MC_stpes,
                        args.debug)
            counter += 1
        elif random_number == 7:
            # cell_angle beta
            Monte_Carlo(atoms, calculator, space_group, f7, 'cell_angle_beta',
                        counter, numb_molecules, molecule1_in_cell, MC_stpes,
                        args.debug)
            counter += 1
        elif random_number == 8:
            # cell_angle gamma
            Monte_Carlo(atoms, calculator, space_group, f8, 'cell_angle_gamma',
                        counter, numb_molecules, molecule1_in_cell, MC_stpes,
                        args.debug)
            counter += 1
Ejemplo n.º 19
0
def read_castep_cell(fd,
                     index=None,
                     calculator_args={},
                     find_spg=False,
                     units=units_CODATA2002):
    """Read a .cell file and return an atoms object.
    Any value found that does not fit the atoms API
    will be stored in the atoms.calc attribute.

    By default, the Castep calculator will be tolerant and in the absence of a
    castep_keywords.json file it will just accept all keywords that aren't 
    automatically parsed.
    """

    from ase.calculators.castep import Castep

    cell_units = {  # Units specifiers for CASTEP
        'bohr': units_CODATA2002['a0'],
        'ang': 1.0,
        'm': 1e10,
        'cm': 1e8,
        'nm': 10,
        'pm': 1e-2
    }

    calc = Castep(**calculator_args)

    if calc.cell.castep_version == 0:
        # No valid castep_keywords.json was found
        print('read_cell: Warning - Was not able to validate CASTEP input.')
        print('           This may be due to a non-existing '
              '"castep_keywords.json"')
        print('           file or a non-existing CASTEP installation.')
        print('           Parsing will go on but keywords will not be '
              'validated and may cause problems if incorrect during a CASTEP '
              'run.')

    celldict = read_freeform(fd)

    def parse_blockunit(line_tokens, blockname):
        u = 1.0
        if len(line_tokens[0]) == 1:
            usymb = line_tokens[0][0].lower()
            u = cell_units.get(usymb, 1)
            if usymb not in cell_units:
                warnings.warn(
                    ('read_cell: Warning - ignoring invalid '
                     'unit specifier in %BLOCK {0} '
                     '(assuming Angstrom instead)').format(blockname))
            line_tokens = line_tokens[1:]
        return u, line_tokens

    # Arguments to pass to the Atoms object at the end
    aargs = {'pbc': True}

    # Start by looking for the lattice
    lat_keywords = [w in celldict for w in ('lattice_cart', 'lattice_abc')]
    if all(lat_keywords):
        warnings.warn('read_cell: Warning - two lattice blocks present in the'
                      ' same file. LATTICE_ABC will be ignored')
    elif not any(lat_keywords):
        raise ValueError('Cell file must contain at least one between '
                         'LATTICE_ABC and LATTICE_CART')

    if 'lattice_abc' in celldict:

        lines = celldict.pop('lattice_abc').split('\n')
        line_tokens = [l.split() for l in lines]

        u, line_tokens = parse_blockunit(line_tokens, 'lattice_abc')

        if len(line_tokens) != 2:
            warnings.warn('read_cell: Warning - ignoring additional '
                          'lines in invalid %BLOCK LATTICE_ABC')

        abc = [float(p) * u for p in line_tokens[0][:3]]
        angles = [float(phi) for phi in line_tokens[1][:3]]

        aargs['cell'] = cellpar_to_cell(abc + angles)

    if 'lattice_cart' in celldict:

        lines = celldict.pop('lattice_cart').split('\n')
        line_tokens = [l.split() for l in lines]

        u, line_tokens = parse_blockunit(line_tokens, 'lattice_cart')

        if len(line_tokens) != 3:
            warnings.warn('read_cell: Warning - ignoring more than '
                          'three lattice vectors in invalid %BLOCK '
                          'LATTICE_CART')

        aargs['cell'] = [[float(x) * u for x in lt[:3]] for lt in line_tokens]

    # Now move on to the positions
    pos_keywords = [w in celldict for w in ('positions_abs', 'positions_frac')]

    if all(pos_keywords):
        warnings.warn('read_cell: Warning - two lattice blocks present in the'
                      ' same file. POSITIONS_FRAC will be ignored')
        del celldict['positions_frac']
    elif not any(pos_keywords):
        raise ValueError('Cell file must contain at least one between '
                         'POSITIONS_FRAC and POSITIONS_ABS')

    aargs['symbols'] = []
    pos_type = 'positions'
    pos_block = celldict.pop('positions_abs', None)
    if pos_block is None:
        pos_type = 'scaled_positions'
        pos_block = celldict.pop('positions_frac', None)
    aargs[pos_type] = []

    lines = pos_block.split('\n')
    line_tokens = [l.split() for l in lines]

    if not 'scaled' in pos_type:
        u, line_tokens = parse_blockunit(line_tokens, 'positions_abs')
    else:
        u = 1.0

    # Here we extract all the possible additional info
    # These are marked by their type

    add_info = {
        'SPIN': (float, 0.0),  # (type, default)
        'MAGMOM': (float, 0.0),
        'LABEL': (str, 'NULL')
    }
    add_info_arrays = dict((k, []) for k in add_info)

    def parse_info(raw_info):

        re_keys = (r'({0})\s*[=:\s]{{1}}\s'
                   r'*([^\s]*)').format('|'.join(add_info.keys()))
        # Capture all info groups
        info = re.findall(re_keys, raw_info)
        info = {g[0]: add_info[g[0]][0](g[1]) for g in info}
        return info

    # Array for custom species (a CASTEP special thing)
    # Usually left unused
    custom_species = None

    for tokens in line_tokens:
        # Now, process the whole 'species' thing
        spec_custom = tokens[0].split(':', 1)
        elem = spec_custom[0]
        if len(spec_custom) > 1 and custom_species is None:
            # Add it to the custom info!
            custom_species = list(aargs['symbols'])
        if custom_species is not None:
            custom_species.append(tokens[0])
        aargs['symbols'].append(elem)
        aargs[pos_type].append([float(p) * u for p in tokens[1:4]])
        # Now for the additional information
        info = ' '.join(tokens[4:])
        info = parse_info(info)
        for k in add_info:
            add_info_arrays[k] += [info.get(k, add_info[k][1])]

    # Now on to the species potentials...
    if 'species_pot' in celldict:
        lines = celldict.pop('species_pot').split('\n')
        line_tokens = [l.split() for l in lines]

        for tokens in line_tokens:
            if len(tokens) == 1:
                # It's a library
                all_spec = (set(custom_species) if custom_species is not None
                            else set(aargs['symbols']))
                for s in all_spec:
                    calc.cell.species_pot = (s, tokens[0])
            else:
                calc.cell.species_pot = tuple(tokens[:2])

    # Ionic constraints
    raw_constraints = {}

    if 'ionic_constraints' in celldict:
        lines = celldict.pop('ionic_constraints').split('\n')
        line_tokens = [l.split() for l in lines]

        for tokens in line_tokens:
            if not len(tokens) == 6:
                continue
            _, species, nic, x, y, z = tokens
            # convert xyz to floats
            x = float(x)
            y = float(y)
            z = float(z)

            nic = int(nic)
            if (species, nic) not in raw_constraints:
                raw_constraints[(species, nic)] = []
            raw_constraints[(species, nic)].append(np.array([x, y, z]))

    # Symmetry operations
    if 'symmetry_ops' in celldict:
        lines = celldict.pop('symmetry_ops').split('\n')
        line_tokens = [l.split() for l in lines]

        # Read them in blocks of four
        blocks = np.array(line_tokens).astype(float)
        if (len(blocks.shape) != 2 or blocks.shape[1] != 3
                or blocks.shape[0] % 4 != 0):
            warnings.warn('Warning: could not parse SYMMETRY_OPS'
                          ' block properly, skipping')
        else:
            blocks = blocks.reshape((-1, 4, 3))
            rotations = blocks[:, :3]
            translations = blocks[:, 3]

            # Regardless of whether we recognize them, store these
            calc.cell.symmetry_ops = (rotations, translations)

    # Anything else that remains, just add it to the cell object:
    for k, val in celldict.items():
        try:
            calc.cell.__setattr__(k, val)
        except Exception:
            raise RuntimeError('Problem setting calc.cell.%s = %s' % (k, val))

    # Get the relevant additional info
    aargs['magmoms'] = np.array(add_info_arrays['SPIN'])
    # SPIN or MAGMOM are alternative keywords
    aargs['magmoms'] = np.where(aargs['magmoms'] != 0, aargs['magmoms'],
                                add_info_arrays['MAGMOM'])
    labels = np.array(add_info_arrays['LABEL'])

    aargs['calculator'] = calc

    atoms = ase.Atoms(**aargs)

    # Spacegroup...
    if find_spg:
        # Try importing spglib
        try:
            import spglib
        except ImportError:
            try:
                from pyspglib import spglib
            except ImportError:
                # spglib is not present
                warnings.warn('spglib not found installed on this system - '
                              'automatic spacegroup detection is not possible')
                spglib = None

        if spglib is not None:
            symmd = spglib.get_symmetry_dataset(atoms)
            atoms_spg = Spacegroup(int(symmd['number']))
            atoms.info['spacegroup'] = atoms_spg

    atoms.new_array('castep_labels', labels)
    if custom_species is not None:
        atoms.new_array('castep_custom_species', np.array(custom_species))

    fixed_atoms = []
    constraints = []
    for (species, nic), value in raw_constraints.items():
        absolute_nr = atoms.calc._get_absolute_number(species, nic)
        if len(value) == 3:
            # Check if they are linearly independent
            if np.linalg.det(value) == 0:
                print('Error: Found linearly dependent constraints attached '
                      'to atoms %s' % (absolute_nr))
                continue
            fixed_atoms.append(absolute_nr)
        elif len(value) == 2:
            direction = np.cross(value[0], value[1])
            # Check if they are linearly independent
            if np.linalg.norm(direction) == 0:
                print('Error: Found linearly dependent constraints attached '
                      'to atoms %s' % (absolute_nr))
                continue
            constraint = ase.constraints.FixedLine(a=absolute_nr,
                                                   direction=direction)
            constraints.append(constraint)
        elif len(value) == 1:
            constraint = ase.constraints.FixedPlane(a=absolute_nr,
                                                    direction=np.array(
                                                        value[0],
                                                        dtype=np.float32))
            constraints.append(constraint)
        else:
            print('Error: Found %s statements attached to atoms %s' %
                  (len(value), absolute_nr))

    # we need to sort the fixed atoms list in order not to raise an assertion
    # error in FixAtoms
    if fixed_atoms:
        constraints.append(
            ase.constraints.FixAtoms(indices=sorted(fixed_atoms)))
    if constraints:
        atoms.set_constraint(constraints)

    atoms.calc.atoms = atoms
    atoms.calc.push_oldstate()

    return atoms
Ejemplo n.º 20
0
 def _analyze(self):
     """Analyze the topology to cut the fragments out."""
     # separate the dummies from the rest
     logger.debug("Analyzing fragments of topology {0}.".format(self.name))
     numbers = numpy.asarray(self.atoms.get_atomic_numbers())
     Xis = numpy.where(numbers == 0)[0]
     Ais = numpy.where(numbers > 0)[0]
     # setup the tags
     tags = numpy.zeros(len(self.atoms))
     tags[Xis] = Xis + 1
     self.atoms.set_tags(tags)
     tags = self.atoms.get_tags()
     # analyze
     # first build the neighborlist
     cutoffs = self._get_cutoffs(Xis=Xis, Ais=Ais)
     neighborlist = NeighborList(cutoffs=cutoffs,
                                 bothways=True,
                                 self_interaction=False,
                                 skin=0.0)
     neighborlist.update(self.atoms)
     # iterate over non-dummies to find dummy neighbors
     for ai in Ais:
         # get indices and offsets of dummies only!
         ni, no = neighborlist.get_neighbors(ai)
         ni, no = zip(*[(idx, off) for idx, off in list(zip(ni, no))
                        if idx in Xis])
         ni = numpy.asarray(ni)
         no = numpy.asarray(no)
         # get absolute positions, no offsets
         positions = self.atoms.positions[ni] + no.dot(self.atoms.cell)
         # create the Atoms object
         fragment = Atoms("X" * len(ni), positions, tags=tags[ni])
         # calculate the point group properties
         max_order = min(8, len(ni))
         shape = symmetry.get_symmetry_elements(mol=fragment.copy(),
                                                max_order=max_order)
         pg = symmetry.PointGroup(mol=fragment.copy(), tol=0.1)
         # save that info
         self.fragments[ai] = fragment
         self.shapes[ai] = shape
         self.pointgroups[ai] = pg.schoenflies
     # now getting the equivalent sites using the Spacegroup object
     sg = self.atoms.info["spacegroup"]
     if not isinstance(sg, Spacegroup):
         sg = Spacegroup(sg)
     scaled_positions = self.atoms.get_scaled_positions()
     seen_indices = []
     symbols = numpy.array(self.atoms.get_chemical_symbols())
     for ai in Ais:
         if ai in seen_indices:
             continue
         sites, _ = sg.equivalent_sites(scaled_positions[ai])
         these_indices = []
         for site in sites:
             norms = numpy.linalg.norm(scaled_positions - site, axis=1)
             if norms.min() < 1e-6:
                 these_indices.append(norms.argmin())
             # take pbc into account
             norms = numpy.abs(norms - 1.0)
             if norms.min() < 1e-6:
                 these_indices.append(norms.argmin())
         these_indices = [idx for idx in these_indices if idx in Ais]
         seen_indices += these_indices
         self.equivalent_sites.append(these_indices)
     logger.info("{es} equivalent sites kinds.".format(
         es=len(self.equivalent_sites)))
     return None
Ejemplo n.º 21
0
 def _dlite_set_info(value):
     self.info.update(value)
     self.info['spacegroup'] = Spacegroup(self.info['spacegroup'])
Ejemplo n.º 22
0
def read_magres(fd, include_unrecognised=False):
    """
        Reader function for magres files.
    """

    blocks_re = re.compile(r'[\[<](?P<block_name>.*?)[>\]](.*?)[<\[]/' +
                           r'(?P=block_name)[\]>]', re.M | re.S)

    """
    Here are defined the various functions required to parse
    different blocks.
    """

    def tensor33(x):
        return np.squeeze(np.reshape(x, (3, 3))).tolist()

    def tensor31(x):
        return np.squeeze(np.reshape(x, (3, 1))).tolist()

    def get_version(file_contents):
        """
            Look for and parse the magres file format version line
        """

        lines = file_contents.split('\n')
        match = re.match(r'\#\$magres-abinitio-v([0-9]+).([0-9]+)', lines[0])

        if match:
            version = match.groups()
            version = tuple(vnum for vnum in version)
        else:
            version = None

        return version

    def parse_blocks(file_contents):
        """
            Parse series of XML-like deliminated blocks into a list of
            (block_name, contents) tuples
        """

        blocks = blocks_re.findall(file_contents)

        return blocks

    def parse_block(block):
        """
            Parse block contents into a series of (tag, data) records
        """

        def clean_line(line):
            # Remove comments and whitespace at start and ends of line
            line = re.sub('#(.*?)\n', '', line)
            line = line.strip()

            return line

        name, data = block

        lines = [clean_line(line) for line in data.split('\n')]

        records = []

        for line in lines:
            xs = line.split()

            if len(xs) > 0:
                tag = xs[0]
                data = xs[1:]

                records.append((tag, data))

        return (name, records)

    def check_units(d):
        """
            Verify that given units for a particular tag are correct.
        """

        allowed_units = {'lattice': 'Angstrom',
                         'atom': 'Angstrom',
                         'ms': 'ppm',
                         'efg': 'au',
                         'efg_local': 'au',
                         'efg_nonlocal': 'au',
                         'isc': '10^19.T^2.J^-1',
                         'isc_fc': '10^19.T^2.J^-1',
                         'isc_orbital_p': '10^19.T^2.J^-1',
                         'isc_orbital_d': '10^19.T^2.J^-1',
                         'isc_spin': '10^19.T^2.J^-1',
                         'isc': '10^19.T^2.J^-1',
                         'sus': '10^-6.cm^3.mol^-1',
                         'calc_cutoffenergy': 'Hartree', }

        if d[0] in d and d[1] == allowed_units[d[0]]:
            pass
        else:
            raise RuntimeError('Unrecognized units: %s %s' % (d[0], d[1]))

        return d

    def parse_magres_block(block):
        """
            Parse magres block into data dictionary given list of record
            tuples.
        """

        name, records = block

        # 3x3 tensor
        def ntensor33(name):
            return lambda d: {name: tensor33([float(x) for x in data])}

        # Atom label, atom index and 3x3 tensor
        def sitensor33(name):
            return lambda d: {'atom': {'label': data[0],
                                       'index': int(data[1])},
                              name: tensor33([float(x) for x in data[2:]])}

        # 2x(Atom label, atom index) and 3x3 tensor
        def sisitensor33(name):
            return lambda d: {'atom1': {'label': data[0],
                                        'index': int(data[1])},
                              'atom2': {'label': data[2],
                                        'index': int(data[3])},
                              name: tensor33([float(x) for x in data[4:]])}

        tags = {'ms': sitensor33('sigma'),
                'sus': ntensor33('S'),
                'efg': sitensor33('V'),
                'efg_local': sitensor33('V'),
                'efg_nonlocal': sitensor33('V'),
                'isc': sisitensor33('K'),
                'isc_fc': sisitensor33('K'),
                'isc_spin': sisitensor33('K'),
                'isc_orbital_p': sisitensor33('K'),
                'isc_orbital_d': sisitensor33('K'),
                'units': check_units}

        data_dict = {}

        for record in records:
            tag, data = record

            if tag not in data_dict:
                data_dict[tag] = []

            data_dict[tag].append(tags[tag](data))

        return data_dict

    def parse_atoms_block(block):
        """
            Parse atoms block into data dictionary given list of record tuples.
        """

        name, records = block

        # Lattice record: a1, a2 a3, b1, b2, b3, c1, c2 c3
        def lattice(d):
            return tensor33([float(x) for x in data])

        # Atom record: label, index, x, y, z
        def atom(d):
            return {'species': data[0],
                    'label': data[1],
                    'index': int(data[2]),
                    'position': tensor31([float(x) for x in data[3:]])}

        def symmetry(d):
            return ' '.join(data)

        tags = {'lattice': lattice,
                'atom': atom,
                'units': check_units,
                'symmetry': symmetry}

        data_dict = {}

        for record in records:
            tag, data = record
            if tag not in data_dict:
                data_dict[tag] = []
            data_dict[tag].append(tags[tag](data))

        return data_dict

    def parse_generic_block(block):
        """
            Parse any other block into data dictionary given list of record
            tuples.
        """

        name, records = block

        data_dict = {}

        for record in records:
            tag, data = record

            if tag not in data_dict:
                data_dict[tag] = []

            data_dict[tag].append(data)

        return data_dict

    """
        Actual parser code.
    """

    block_parsers = {'magres': parse_magres_block,
                     'atoms': parse_atoms_block,
                     'calculation': parse_generic_block, }

    file_contents = fd.read()

    # This works as a validity check
    version = get_version(file_contents)
    if version is None:
        # This isn't even a .magres file!
        raise RuntimeError('File is not in standard Magres format')
    blocks = parse_blocks(file_contents)

    data_dict = {}

    for block_data in blocks:
        block = parse_block(block_data)

        if block[0] in block_parsers:
            block_dict = block_parsers[block[0]](block)
            data_dict[block[0]] = block_dict
        else:
            # Throw in the text content of blocks we don't recognise
            if include_unrecognised:
                data_dict[block[0]] = block_data[1]

    # Now the loaded data must be turned into an ASE Atoms object

    # First check if the file is even viable
    if 'atoms' not in data_dict:
        raise RuntimeError('Magres file does not contain structure data')

    # Allowed units handling. This is redundant for now but
    # could turn out useful in the future

    magres_units = {'Angstrom': ase.units.Ang}

    # Lattice parameters?
    if 'lattice' in data_dict['atoms']:
        try:
            u = dict(data_dict['atoms']['units'])['lattice']
        except KeyError:
            raise RuntimeError('No units detected in file for lattice')
        u = magres_units[u]
        cell = np.array(data_dict['atoms']['lattice'][0]) * u
        pbc = True
    else:
        cell = None
        pbc = False

    # Now the atoms
    symbols = []
    positions = []
    indices = []
    labels = []

    if 'atom' in data_dict['atoms']:
        try:
            u = dict(data_dict['atoms']['units'])['atom']
        except KeyError:
            raise RuntimeError('No units detected in file for atom positions')
        u = magres_units[u]
        # Now we have to account for the possibility of there being CASTEP
        # 'custom' species amongst the symbols
        custom_species = None
        for a in data_dict['atoms']['atom']:
            spec_custom = a['species'].split(':', 1)
            if len(spec_custom) > 1 and custom_species is None:
                # Add it to the custom info!
                custom_species = list(symbols)
            symbols.append(spec_custom[0])
            positions.append(a['position'])
            indices.append(a['index'])
            labels.append(a['label'])
            if custom_species is not None:
                custom_species.append(a['species'])

    atoms = Atoms(cell=cell,
                  pbc=pbc,
                  symbols=symbols,
                  positions=positions)

    # Add custom species if present
    if custom_species is not None:
        atoms.new_array('castep_custom_species', np.array(custom_species))

    # Add the spacegroup, if present and recognizable
    if 'symmetry' in data_dict['atoms']:
        try:
            spg = Spacegroup(data_dict['atoms']['symmetry'][0])
        except:
            # Not found
            spg = Spacegroup(1)  # Most generic one
        atoms.info['spacegroup'] = spg

    # Set up the rest of the properties as arrays
    atoms.new_array('indices', np.array(indices))
    atoms.new_array('labels', np.array(labels))

    # Now for the magres specific stuff
    li_list = list(zip(labels, indices))

    def create_magres_array(name, order, block):

        if order == 1:
            u_arr = [None] * len(li_list)
        elif order == 2:
            u_arr = [[None] * (i + 1) for i in range(len(li_list))]
        else:
            raise ValueError(
                'Invalid order value passed to create_magres_array')

        for s in block:
            # Find the atom index/indices
            if order == 1:
                # First find out which atom this is
                at = (s['atom']['label'], s['atom']['index'])
                try:
                    ai = li_list.index(at)
                except ValueError:
                    raise RuntimeError('Invalid data in magres block')
                # Then add the relevant quantity
                u_arr[ai] = s[mn]
            else:
                at1 = (s['atom1']['label'], s['atom1']['index'])
                at2 = (s['atom2']['label'], s['atom2']['index'])
                ai1 = li_list.index(at1)
                ai2 = li_list.index(at2)
                # Sort them
                ai1, ai2 = sorted((ai1, ai2), reverse=True)
                u_arr[ai1][ai2] = s[mn]

        return np.array(u_arr)

    if 'magres' in data_dict:
        if 'units' in data_dict['magres']:
            atoms.info['magres_units'] = dict(data_dict['magres']['units'])
            for u in atoms.info['magres_units']:
                # This bit to keep track of tags
                u0 = u.split('_')[0]

                if u0 not in _mprops:
                    raise RuntimeError('Invalid data in magres block')

                mn, order = _mprops[u0]

                if order > 0:
                    u_arr = create_magres_array(mn, order,
                                                data_dict['magres'][u])
                    atoms.new_array(u, u_arr)
                else:
                    # atoms.info['magres_data'] = atoms.info.get('magres_data',
                    #                                            {})
                    # # We only take element 0 because for this sort of data
                    # # there should be only that
                    # atoms.info['magres_data'][u] = data_dict['magres'][u][0][mn]
                    if atoms.calc is None:
                        calc = SinglePointDFTCalculator(atoms)
                        atoms.set_calculator(calc)
                        atoms.calc.results[u] = data_dict['magres'][u][0][mn]

    if 'calculation' in data_dict:
        atoms.info['magresblock_calculation'] = data_dict['calculation']

    if include_unrecognised:
        for b in data_dict:
            if b not in block_parsers:
                atoms.info['magresblock_' + b] = data_dict[b]

    return atoms
def main():

    args = parse_args()
    print("args", args)

    if args.implementation == TORCHANI:
        from torchani_calculator import torchani_calculator
        calculator = torchani_calculator(args.network_type)
    elif args.implementation == AES_ANI:
        from ani_ase import ani_ase_calculator
        calculator = ani_ase_calculator(args.network_type)
    elif args.implementation == KHAN:
        from khan_calculator import khan_calculator
        calculator = khan_calculator(args.network_type, args.khan_network,
                                     args.numb_networks)

    assert args.cif_file.endswith('.cif')

    print('debug? ', args.debug)
    atoms = ase_io.read(args.cif_file)
    numb_molecules = len(molecule_lists(atoms))
    print('number of molecules: ', numb_molecules)
    MC_stpes = args.MC
    space_group = Spacegroup(args.space_group)
    # step size in MC
    f1, f2, f3, f4, f5, f6, f7, f8 = args.MC_f1_f2_f3_f4_f5_f6_f7_f8
    perturbation_type = args.perturbation_type
    molecule1_in_cell = []
    for i in range(1, atoms.get_number_of_atoms()):
        if atom_belong_to_mol1(i, atoms):
            molecule1_in_cell.append(i)
    print("initial unit cell")
    print(atoms.cell)
    print("To do Monte Carlo for %d step." % MC_stpes)
    print("Molecule index in ASU are: ", molecule1_in_cell)

    translation_stats = []
    rotation_stats = []
    cell_length_a_stats = []
    cell_length_b_stats = []
    cell_length_c_stats = []
    cell_angle_alpha_stats = []
    cell_angle_beta_stats = []
    cell_angle_gamma_stats = []
    counter = 0
    atoms_input = atoms.copy()
    while (counter <= MC_stpes):
        if isinstance(perturbation_type, list):
            # random_number = random.choice([1,2,3,4,5,6,7,8])
            random_choices = get_random_choices(
                [f1, f2, f3, f4, f5, f6, f7, f8])
            random_number = random.choice(random_choices)
        else:
            random_number = perturbation_dict[perturbation_type]
        if random_number == 1:
            # translation
            atoms_input.set_calculator(calculator)
            ret_atoms, message = Monte_Carlo(atoms_input, calculator,
                                             space_group, f1, 'translate',
                                             counter, molecule1_in_cell,
                                             MC_stpes, args.debug)
            translation_stats.append(message)
            counter += 1
            atoms_input = ret_atoms.copy()
        elif random_number == 2:
            # rotation
            atoms_input.set_calculator(calculator)
            ret_atoms, message = Monte_Carlo(atoms_input, calculator,
                                             space_group, f2, 'rotation',
                                             counter, molecule1_in_cell,
                                             MC_stpes, args.debug)
            rotation_stats.append(message)
            counter += 1
            atoms_input = ret_atoms.copy()
        elif random_number == 3:
            # cell_length a
            atoms_input.set_calculator(calculator)
            ret_atoms, message = Monte_Carlo(atoms_input, calculator,
                                             space_group, f3, 'cell_length_a',
                                             counter, molecule1_in_cell,
                                             MC_stpes, args.debug)
            cell_length_a_stats.append(message)
            counter += 1
            atoms_input = ret_atoms.copy()
        elif random_number == 4:
            # cell_length b
            atoms_input.set_calculator(calculator)
            ret_atoms, message = Monte_Carlo(atoms_input, calculator,
                                             space_group, f4, 'cell_length_b',
                                             counter, molecule1_in_cell,
                                             MC_stpes, args.debug)
            cell_length_b_stats.append(message)
            counter += 1
            atoms_input = ret_atoms.copy()
        elif random_number == 5:
            # cell_length c
            atoms_input.set_calculator(calculator)
            ret_atoms, message = Monte_Carlo(atoms_input, calculator,
                                             space_group, f5, 'cell_length_c',
                                             counter, molecule1_in_cell,
                                             MC_stpes, args.debug)
            cell_length_c_stats.append(message)
            counter += 1
            atoms_input = ret_atoms.copy()
        elif random_number == 6:
            # cell_angle alpha
            atoms_input.set_calculator(calculator)
            ret_atoms, message = Monte_Carlo(atoms_input, calculator,
                                             space_group, f6,
                                             'cell_angle_alpha', counter,
                                             molecule1_in_cell, MC_stpes,
                                             args.debug)
            cell_angle_alpha_stats.append(message)
            counter += 1
            atoms_input = ret_atoms.copy()
        elif random_number == 7:
            # cell_angle beta
            atoms_input.set_calculator(calculator)
            ret_atoms, message = Monte_Carlo(atoms_input, calculator,
                                             space_group, f7,
                                             'cell_angle_beta', counter,
                                             molecule1_in_cell, MC_stpes,
                                             args.debug)
            cell_angle_beta_stats.append(message)
            counter += 1
            atoms_input = ret_atoms.copy()
        elif random_number == 8:
            # cell_angle gamma
            atoms_input.set_calculator(calculator)
            ret_atoms, message = Monte_Carlo(atoms_input, calculator,
                                             space_group, f8,
                                             'cell_angle_gamma', counter,
                                             molecule1_in_cell, MC_stpes,
                                             args.debug)
            cell_angle_gamma_stats.append(message)
            counter += 1
            atoms_input = ret_atoms.copy()
        #if counter % 1000 == 0:
        #    with open("MC_trace_%d.json"%counter, "w") as fh:
        #        json.dump(MC_trace, fh, indent=4)

    #with open("MC_trace.json", "w") as fh:
    #    json.dump(MC_trace, fh, indent=4)
    #print("MC trace are recorded in: MC_trace.json")

    if len(translation_stats):
        print("Acceptance ratio of translation move is %f" %
              (countX("Accepted", translation_stats) / len(translation_stats)))
    if len(rotation_stats):
        print("Acceptance ratio of rotation move is %f" %
              (countX("Accepted", rotation_stats) / len(rotation_stats)))
    if len(cell_length_a_stats):
        print("Acceptance ratio of cell length a move is %f" %
              (countX("Accepted", cell_length_a_stats) /
               len(cell_length_a_stats)))
    if len(cell_length_b_stats):
        print("Acceptance ratio of cell length b move is %f" %
              (countX("Accepted", cell_length_b_stats) /
               len(cell_length_b_stats)))
    if len(cell_length_c_stats):
        print("Acceptance ratio of cell length c move is %f" %
              (countX("Accepted", cell_length_c_stats) /
               len(cell_length_c_stats)))
    if len(cell_angle_alpha_stats):
        print("Acceptance ratio of cell angle alpha move is %f" %
              (countX("Accepted", cell_angle_alpha_stats) /
               len(cell_angle_alpha_stats)))
    if len(cell_angle_beta_stats):
        print("Acceptance ratio of cell angle beta move is %f" %
              (countX("Accepted", cell_angle_beta_stats) /
               len(cell_angle_beta_stats)))
    if len(cell_angle_gamma_stats):
        print("Acceptance ratio of cell angle gamma move is %f" %
              (countX("Accepted", cell_angle_gamma_stats) /
               len(cell_angle_gamma_stats)))
Ejemplo n.º 24
0
    def update(self, *args):
        """ all changes of physical constants are handled here, atoms are set up"""
        if self.clearing_in_process:
            return True
        self.update_element()
        a_equals = self.lattice_lequals[0].get_active()
        b_equals = self.lattice_lequals[1].get_active()
        c_equals = self.lattice_lequals[2].get_active()
        alpha_equals = self.lattice_aequals[0].get_active()
        beta_equals = self.lattice_aequals[1].get_active()
        gamma_equals = self.lattice_aequals[2].get_active()
        sym = self.spacegroup.get_text()
        valid = True
        try:
            no = int(sym)
            spg = Spacegroup(no).symbol
            self.spacegroupinfo.set_label(_('Symbol: %s') % str(spg))
            spg = no
        except:
            try:
                no = Spacegroup(sym).no
                self.spacegroupinfo.set_label(_('Number: %s') % str(no))
                spg = no
            except:
                self.spacegroupinfo.set_label(_('Invalid Spacegroup!'))
                valid = False

        if a_equals == 0:
            self.lattice_lbuts[0].set_sensitive(True)
        elif a_equals == 1:
            self.lattice_lbuts[0].set_sensitive(False)
            self.lattice_lbuts[0].set_value(self.lattice_lbuts[1].get_value())
        elif a_equals == 2:
            self.lattice_lbuts[0].set_sensitive(False)
            self.lattice_lbuts[0].set_value(self.lattice_lbuts[2].get_value())
        else:
            self.lattice_lbuts[0].set_sensitive(False)
        if b_equals == 0:
            self.lattice_lbuts[1].set_sensitive(True)
        elif b_equals == 1:
            self.lattice_lbuts[1].set_sensitive(False)
            self.lattice_lbuts[1].set_value(self.lattice_lbuts[0].get_value())
        elif b_equals == 2:
            self.lattice_lbuts[1].set_sensitive(False)
            self.lattice_lbuts[1].set_value(self.lattice_lbuts[2].get_value())
        else:
            self.lattice_lbuts[1].set_sensitive(False)
        if c_equals == 0:
            self.lattice_lbuts[2].set_sensitive(True)
        elif c_equals == 1:
            self.lattice_lbuts[2].set_sensitive(False)
            self.lattice_lbuts[2].set_value(self.lattice_lbuts[0].get_value())
        elif c_equals == 2:
            self.lattice_lbuts[2].set_sensitive(False)
            self.lattice_lbuts[2].set_value(self.lattice_lbuts[1].get_value())
        else:
            self.lattice_lbuts[2].set_sensitive(False)
        if alpha_equals == 0:
            self.lattice_abuts[0].set_sensitive(True)
        elif alpha_equals == 1:
            self.lattice_abuts[0].set_sensitive(False)
            self.lattice_abuts[0].set_value(self.lattice_abuts[1].get_value())
        elif alpha_equals == 2:
            self.lattice_abuts[0].set_sensitive(False)
            self.lattice_abuts[0].set_value(self.lattice_abuts[2].get_value())
        else:
            self.lattice_abuts[0].set_sensitive(False)
        if beta_equals == 0:
            self.lattice_abuts[1].set_sensitive(True)
        elif beta_equals == 1:
            self.lattice_abuts[1].set_sensitive(False)
            self.lattice_abuts[1].set_value(self.lattice_abuts[0].get_value())
        elif beta_equals == 2:
            self.lattice_abuts[1].set_sensitive(False)
            self.lattice_abuts[1].set_value(self.lattice_abuts[2].get_value())
        else:
            self.lattice_abuts[1].set_sensitive(False)
        if gamma_equals == 0:
            self.lattice_abuts[2].set_sensitive(True)
        elif gamma_equals == 1:
            self.lattice_abuts[2].set_sensitive(False)
            self.lattice_abuts[2].set_value(self.lattice_abuts[0].get_value())
        elif gamma_equals == 2:
            self.lattice_abuts[2].set_sensitive(False)
            self.lattice_abuts[2].set_value(self.lattice_abuts[1].get_value())
        else:
            self.lattice_abuts[2].set_sensitive(False)

        valid = len(self.elements[0][0].get_text()) and valid
        self.get_data.set_sensitive(valid and self.get_n_elements() == 1
                                    and self.update_element())
        self.atoms = None
        if valid:
            basis_count = -1
            for el in self.elements:
                if el[-1]:
                    basis_count += 1
            if basis_count:
                symbol_str = '['
                basis_str = "["
                symbol = []
                basis = []
            else:
                symbol_str = ''
                basis_str = ''
                basis = None
            for el in self.elements:
                if el[-1]:
                    symbol_str += "'" + el[0].get_text() + "'"
                    if basis_count:
                        symbol_str += ','
                        symbol += [el[0].get_text()]
                        exec('basis += [[float(' + el[1].get_text() +
                             '),float(' + el[2].get_text() + '),float(' +
                             el[3].get_text() + ')]]')
                    else:
                        symbol = el[0].get_text()
                        exec('basis = [[float(' + el[1].get_text() +
                             '),float(' + el[2].get_text() + '),float(' +
                             el[3].get_text() + ')]]')
                    basis_str += '[' + el[1].get_text() + ',' + el[2].get_text(
                    ) + ',' + el[3].get_text() + '],'
            basis_str = basis_str[:-1]
            if basis_count:
                symbol_str = symbol_str[:-1] + ']'
                basis_str += ']'
            size_str = '(' + str(int(self.size[0].get_value())) + ',' + str(
                int(self.size[1].get_value())) + ',' + str(
                    int(self.size[2].get_value())) + ')'
            size = (int(self.size[0].get_value()),
                    int(self.size[1].get_value()),
                    int(self.size[2].get_value()))
            cellpar_str = ''
            cellpar = []
            for i in self.lattice_lbuts:
                cellpar_str += str(i.get_value()) + ','
                cellpar += [i.get_value()]
            for i in self.lattice_abuts:
                cellpar_str += str(i.get_value()) + ','
                cellpar += [i.get_value()]
            cellpar_str = '[' + cellpar_str[:-1] + ']'
            args = {
                'symbols': symbol,
                'basis': basis,
                'size': size,
                'spacegroup': spg,
                'cellpar': cellpar
            }
            args_str = {
                'symbols': symbol_str,
                'basis': basis_str,
                'size': size_str,
                'spacegroup': spg,
                'cellpar': cellpar_str
            }
            self.pybut.python = py_template % args_str
            try:
                self.atoms = crystal(**args)
                label = label_template % {
                    'natoms': len(self.atoms),
                    'symbols': formula(self.atoms.get_atomic_numbers()),
                    'volume': self.atoms.get_volume()
                }
                self.status.set_label(label)
            except:
                self.atoms = None
                self.status.set_markup(
                    _("Please specify a consistent set of atoms."))
        else:
            self.atoms = None
            self.status.set_markup(
                _("Please specify a consistent set of atoms."))
Ejemplo n.º 25
0
    def read(self):
        """
        Read data from the CIF file
        """
        with open(self.filename, 'r') as f:
            ciffile = ReadCif(f)
            for block in ciffile:
                spacegroup = Spacegroup(int(block['_space_group_IT_number']))

                cellpar = np.array([
                    block['_cell_length_a'],
                    block['_cell_length_b'],
                    block['_cell_length_c'],
                    block['_cell_angle_alpha'],
                    block['_cell_angle_beta'],
                    block['_cell_angle_gamma'],
                ],
                                   dtype=float)

                try:
                    site_labels = block['_atom_site_label']
                except KeyError:
                    print('Could not get site labels from cif file')
                try:
                    occupancies = np.array(block['_atom_site_occupancy'],
                                           dtype=float)
                except KeyError:
                    print('Could not get occupancies from cif file')
                try:
                    fract_x = np.array(block['_atom_site_fract_x'],
                                       dtype=float)
                    fract_y = np.array(block['_atom_site_fract_y'],
                                       dtype=float)
                    fract_z = np.array(block['_atom_site_fract_z'],
                                       dtype=float)
                except KeyError:
                    warn(
                        'Could not get fractional coordinates from cif file, getting absolute coordinates instead.'
                    )
                    try:
                        x = np.array(block['_atom_site_cartn_x'], dtype=float)
                        y = np.array(block['_atom_site_cartn_y'], dtype=float)
                        z = np.array(block['_atom_site_cartn_z'], dtype=float)
                    except KeyError:
                        warn(
                            'Could not get absolute coordinates from cif file')
                        x = [np.nan] * len(block)
                        y = [np.nan] * len(block)
                        z = [np.nan] * len(block)
                    finally:
                        fract_x = x / cellpar[0]
                        fract_y = y / cellpar[1]
                        fract_z = z / cellpar[2]
                else:
                    x = fract_x * cellpar[0]
                    y = fract_y * cellpar[1]
                    z = fract_y * cellpar[2]
                finally:
                    x = x.T
                    y = y.T
                    z = z.T
                    fract_x = fract_x.T
                    fract_y = fract_y.T
                    fract_z = fract_z.T

                    positions = np.array([x, y, z])
                    fractional_positions = np.array(
                        [fract_x, fract_y, fract_z])
                try:
                    symbols = block['_atom_site_type_symbol']
                except KeyError:
                    print(
                        'Could not get atom site chemical symbols from cif file'
                    )
                try:
                    dwf = block['_atom_site_B_iso_or_equiv']
                except KeyError:
                    print('Could not get Debye-Waller factors from cif file')

                basis_atoms = []
                for label, occ, fx, fy, fz, symbol, B in zip(
                        site_labels, occupancies, fractional_positions[0],
                        fractional_positions[1], fractional_positions[2],
                        symbols, dwf):
                    atom = CIFAtom(cellpar,
                                   symbol=symbol,
                                   occupancy=occ,
                                   fractional_position=(fx, fy, fz),
                                   dwf=B,
                                   site_label=label)
                    basis_atoms.append(atom)

                atoms = []
                for atom in basis_atoms:
                    equivalent_sites, kinds = spacegroup.equivalent_sites(
                        atom.fractional_position,
                        onduplicates='warn',
                        occupancies=atom.occupancy)
                    for site in equivalent_sites:
                        position = site * cellpar[:3]
                        equivalent_atom = CIFAtom(cellpar,
                                                  fractional_position=site,
                                                  site_label=atom.site_label,
                                                  symbol=atom.symbol,
                                                  dwf=atom.dwf,
                                                  occupancy=atom.occupancy)
                        atoms.append(equivalent_atom)
                self.atoms = atoms
                self.crystal = Crystal(atoms, cellpar)
Ejemplo n.º 26
0
def tag_sites(atoms):
    name = spglib.get_spacegroup(get_cell(atoms))
    number = int(re.search(r'\((.*?)\)', name).group(1))
    spg = Spacegroup(number)
    sites = spg.tag_sites(atoms.get_scaled_positions())
    return sites
Ejemplo n.º 27
0
def crystal(symbols=None,
            basis=None,
            occupancies=None,
            spacegroup=1,
            setting=1,
            cell=None,
            cellpar=None,
            ab_normal=(0, 0, 1),
            a_direction=None,
            size=(1, 1, 1),
            onduplicates='warn',
            symprec=0.001,
            pbc=True,
            primitive_cell=False,
            **kwargs):
    """Create an Atoms instance for a conventional unit cell of a
    space group.

    Parameters:

    symbols : str | sequence of str | sequence of Atom | Atoms
        Element symbols of the unique sites.  Can either be a string
        formula or a sequence of element symbols. E.g. ('Na', 'Cl')
        and 'NaCl' are equivalent.  Can also be given as a sequence of
        Atom objects or an Atoms object.
    basis : list of scaled coordinates
        Positions of the unique sites corresponding to symbols given
        either as scaled positions or through an atoms instance.  Not
        needed if *symbols* is a sequence of Atom objects or an Atoms
        object.
    occupancies : list of site occupancies
        Occupancies of the unique sites. Defaults to 1.0 and thus no mixed
        occupancies are considered if not explicitly asked for. If occupancies
        are given, the most dominant species will yield the atomic number.
    spacegroup : int | string | Spacegroup instance
        Space group given either as its number in International Tables
        or as its Hermann-Mauguin symbol.
    setting : 1 | 2
        Space group setting.
    cell : 3x3 matrix
        Unit cell vectors.
    cellpar : [a, b, c, alpha, beta, gamma]
        Cell parameters with angles in degree. Is not used when `cell`
        is given.
    ab_normal : vector
        Is used to define the orientation of the unit cell relative
        to the Cartesian system when `cell` is not given. It is the
        normal vector of the plane spanned by a and b.
    a_direction : vector
        Defines the orientation of the unit cell a vector. a will be
        parallel to the projection of `a_direction` onto the a-b plane.
    size : 3 positive integers
        How many times the conventional unit cell should be repeated
        in each direction.
    onduplicates : 'keep' | 'replace' | 'warn' | 'error'
        Action if `basis` contain symmetry-equivalent positions:
            'keep'    - ignore additional symmetry-equivalent positions
            'replace' - replace
            'warn'    - like 'keep', but issue an UserWarning
            'error'   - raises a SpacegroupValueError
    symprec : float
        Minimum "distance" betweed two sites in scaled coordinates
        before they are counted as the same site.
    pbc : one or three bools
        Periodic boundary conditions flags.  Examples: True,
        False, 0, 1, (1, 1, 0), (True, False, False).  Default
        is True.
    primitive_cell : bool
        Wheter to return the primitive instead of the conventional
        unit cell.

    Keyword arguments:

    All additional keyword arguments are passed on to the Atoms
    constructor.  Currently, probably the most useful additional
    keyword arguments are `info`, `constraint` and `calculator`.

    Examples:

    Two diamond unit cells (space group number 227)

    >>> diamond = crystal('C', [(0,0,0)], spacegroup=227,
    ...     cellpar=[3.57, 3.57, 3.57, 90, 90, 90], size=(2,1,1))
    >>> ase.view(diamond)  # doctest: +SKIP

    A CoSb3 skutterudite unit cell containing 32 atoms

    >>> skutterudite = crystal(('Co', 'Sb'),
    ...     basis=[(0.25,0.25,0.25), (0.0, 0.335, 0.158)],
    ...     spacegroup=204, cellpar=[9.04, 9.04, 9.04, 90, 90, 90])
    >>> len(skutterudite)
    32
    """
    sg = Spacegroup(spacegroup, setting)
    if (not isinstance(symbols, basestring)
            and hasattr(symbols, '__getitem__') and len(symbols) > 0
            and isinstance(symbols[0], ase.Atom)):
        symbols = ase.Atoms(symbols)
    if isinstance(symbols, ase.Atoms):
        basis = symbols
        symbols = basis.get_chemical_symbols()
    if isinstance(basis, ase.Atoms):
        basis_coords = basis.get_scaled_positions()
        if cell is None and cellpar is None:
            cell = basis.cell
        if symbols is None:
            symbols = basis.get_chemical_symbols()
    else:
        basis_coords = np.array(basis, dtype=float, copy=False, ndmin=2)

    if occupancies is not None:
        occupancies_dict = {}

        for index, coord in enumerate(basis_coords):
            # Compute all distances and get indices of nearest atoms
            dist = spatial.distance.cdist(coord.reshape(1, 3), basis_coords)
            indices_dist = np.flatnonzero(dist < symprec)

            occ = {symbols[index]: occupancies[index]}

            # Check nearest and update occupancy
            for index_dist in indices_dist:
                if index == index_dist:
                    continue
                else:
                    occ.update({symbols[index_dist]: occupancies[index_dist]})

            occupancies_dict[index] = occ.copy()

    sites, kinds = sg.equivalent_sites(basis_coords,
                                       onduplicates=onduplicates,
                                       symprec=symprec)

    # this is needed to handle deuterium masses
    masses = None
    if 'masses' in kwargs:
        masses = kwargs['masses'][kinds]
        del kwargs['masses']

    symbols = parse_symbols(symbols)

    if occupancies is None:
        symbols = [symbols[i] for i in kinds]
    else:
        # make sure that we put the dominant species there
        symbols = [
            sorted(occupancies_dict[i].items(), key=lambda x: x[1])[-1][0]
            for i in kinds
        ]

    if cell is None:
        cell = cellpar_to_cell(cellpar, ab_normal, a_direction)

    info = dict(spacegroup=sg)
    if primitive_cell:
        info['unit_cell'] = 'primitive'
    else:
        info['unit_cell'] = 'conventional'

    if 'info' in kwargs:
        info.update(kwargs['info'])

    if occupancies is not None:
        info['occupancy'] = occupancies_dict

    kwargs['info'] = info

    atoms = ase.Atoms(symbols,
                      scaled_positions=sites,
                      cell=cell,
                      pbc=pbc,
                      masses=masses,
                      **kwargs)

    #  if all occupancies are 1, no partial occupancy present
    if occupancies:
        if not all([occ == 1 for occ in occupancies]):
            # use tags to identify sites, and in particular the occupancy
            atoms.set_tags(kinds)

    if isinstance(basis, ase.Atoms):
        for name in basis.arrays:
            if not atoms.has(name):
                array = basis.get_array(name)
                atoms.new_array(name, [array[i] for i in kinds],
                                dtype=array.dtype,
                                shape=array.shape[1:])

    if primitive_cell:
        from ase.build import cut
        prim_cell = sg.scaled_primitive_cell

        # Preserve calculator if present:
        calc = atoms.calc
        atoms = cut(atoms, a=prim_cell[0], b=prim_cell[1], c=prim_cell[2])
        atoms.calc = calc

    if size != (1, 1, 1):
        atoms = atoms.repeat(size)
    return atoms
Ejemplo n.º 28
0
    print("after translation ", molecule_lists(ret_atoms_translate))
    ret_atoms = ret_atoms_translate.copy()

    return ret_atoms


if __name__ == "__main__":

    print("runing main function for debugging...")
    atoms = ase_io.read(sys.argv[1])
    spacegroup_number = sys.argv[2]
    molecule1_atoms_index = molecule_lists(atoms)[0]
    print(molecule_lists(atoms))
    print("molecule1_atoms_index: ", molecule1_atoms_index)
    if spacegroup_number:
        space_group = Spacegroup(int(spacegroup_number))
    else:
        space_group = spacegroup.get_spacegroup(atoms)
    print("before perturbation: ", space_group)
    # first enlarge cell and then change the anlge.
    #ret_atoms = ret_atoms_translate.copy()
    # atoms_input = atoms.copy()
    # ret_atoms = generate_perturb(atoms_input)
    # dummy input
    ret_atoms = Atoms('Au',
                      positions=[[0, 10 / 2, 10 / 2]],
                      cell=[10, 10, 10],
                      pbc=[1, 0, 0])

    counter = 1
    while (len(molecule_lists(atoms)) != len(molecule_lists(ret_atoms))):
Ejemplo n.º 29
0
def crystal(symbols=None, basis=None, spacegroup=1, setting=1,
            cell=None, cellpar=None,
            ab_normal=(0, 0, 1), a_direction=None, size=(1, 1, 1),
            onduplicates='warn', symprec=0.001,
            pbc=True, primitive_cell=False, **kwargs):
    """Create an Atoms instance for a conventional unit cell of a
    space group.

    Parameters:

    symbols : str | sequence of str | sequence of Atom | Atoms
        Element symbols of the unique sites.  Can either be a string
        formula or a sequence of element symbols. E.g. ('Na', 'Cl')
        and 'NaCl' are equivalent.  Can also be given as a sequence of
        Atom objects or an Atoms object.
    basis : list of scaled coordinates
        Positions of the unique sites corresponding to symbols given
        either as scaled positions or through an atoms instance.  Not
        needed if *symbols* is a sequence of Atom objects or an Atoms
        object.
    spacegroup : int | string | Spacegroup instance
        Space group given either as its number in International Tables
        or as its Hermann-Mauguin symbol.
    setting : 1 | 2
        Space group setting.
    cell : 3x3 matrix
        Unit cell vectors.
    cellpar : [a, b, c, alpha, beta, gamma]
        Cell parameters with angles in degree. Is not used when `cell`
        is given.
    ab_normal : vector
        Is used to define the orientation of the unit cell relative
        to the Cartesian system when `cell` is not given. It is the
        normal vector of the plane spanned by a and b.
    a_direction : vector
        Defines the orientation of the unit cell a vector. a will be
        parallel to the projection of `a_direction` onto the a-b plane.
    size : 3 positive integers
        How many times the conventional unit cell should be repeated
        in each direction.
    onduplicates : 'keep' | 'replace' | 'warn' | 'error'
        Action if `basis` contain symmetry-equivalent positions:
            'keep'    - ignore additional symmetry-equivalent positions
            'replace' - replace
            'warn'    - like 'keep', but issue an UserWarning
            'error'   - raises a SpacegroupValueError
    symprec : float
        Minimum "distance" betweed two sites in scaled coordinates
        before they are counted as the same site.
    pbc : one or three bools
        Periodic boundary conditions flags.  Examples: True,
        False, 0, 1, (1, 1, 0), (True, False, False).  Default
        is True.
    primitive_cell : bool
        Wheter to return the primitive instead of the conventional
        unit cell.

    Keyword arguments:

    All additional keyword arguments are passed on to the Atoms
    constructor.  Currently, probably the most useful additional
    keyword arguments are `info`, `constraint` and `calculator`.

    Examples:

    Two diamond unit cells (space group number 227)

    >>> diamond = crystal('C', [(0,0,0)], spacegroup=227,
    ...     cellpar=[3.57, 3.57, 3.57, 90, 90, 90], size=(2,1,1))
    >>> ase.view(diamond)  # doctest: +SKIP

    A CoSb3 skutterudite unit cell containing 32 atoms

    >>> skutterudite = crystal(('Co', 'Sb'),
    ...     basis=[(0.25,0.25,0.25), (0.0, 0.335, 0.158)],
    ...     spacegroup=204, cellpar=[9.04, 9.04, 9.04, 90, 90, 90])
    >>> len(skutterudite)
    32
    """
    sg = Spacegroup(spacegroup, setting)
    if (not isinstance(symbols, str) and
        hasattr(symbols, '__getitem__') and
        len(symbols) > 0 and
        isinstance(symbols[0], ase.Atom)):
        symbols = ase.Atoms(symbols)
    if isinstance(symbols, ase.Atoms):
        basis = symbols
        symbols = basis.get_chemical_symbols()
    if isinstance(basis, ase.Atoms):
        basis_coords = basis.get_scaled_positions()
        if cell is None and cellpar is None:
            cell = basis.cell
        if symbols is None:
            symbols = basis.get_chemical_symbols()
    else:
        basis_coords = np.array(basis, dtype=float, copy=False, ndmin=2)
    sites, kinds = sg.equivalent_sites(basis_coords,
                                       onduplicates=onduplicates,
                                       symprec=symprec)
    symbols = parse_symbols(symbols)
    symbols = [symbols[i] for i in kinds]
    if cell is None:
        cell = cellpar_to_cell(cellpar, ab_normal, a_direction)

    info = dict(spacegroup=sg)
    if primitive_cell:
        info['unit_cell'] = 'primitive'
    else:
        info['unit_cell'] = 'conventional'

    if 'info' in kwargs:
        info.update(kwargs['info'])
    kwargs['info'] = info

    atoms = ase.Atoms(symbols,
                      scaled_positions=sites,
                      cell=cell,
                      pbc=pbc,
                      **kwargs)

    if isinstance(basis, ase.Atoms):
        for name in basis.arrays:
            if not atoms.has(name):
                array = basis.get_array(name)
                atoms.new_array(name, [array[i] for i in kinds],
                                dtype=array.dtype, shape=array.shape[1:])

    if primitive_cell:
        from ase.build import cut
        prim_cell = sg.scaled_primitive_cell
        atoms = cut(atoms, a=prim_cell[0], b=prim_cell[1], c=prim_cell[2])

    if size != (1, 1, 1):
        atoms = atoms.repeat(size)
    return atoms
Ejemplo n.º 30
0
import numpy as np
import ase
from ase.visualize import view
from ase.spacegroup import crystal, Spacegroup

a = b = 4.9134
c = 5.4052
alpha = beta = 90
gamma = 120
Si = ase.Atom("Si", [0.4699, 0, 2 / 3])
O = ase.Atom("O", [0.4141, 0.2681, 0.1188 + 2 / 3])
spacegroup = Spacegroup(154)
cell = crystal([Si, O],
               spacegroup=spacegroup,
               cellpar=[a, b, c, alpha, beta, gamma])

ase.io.write("alpha-quartz.eps", cell, rotation="10x,-10y", show_unit_cell=2)

cell = cell.repeat([2, 2, 1])
cell.set_cell([[a, 0, 0], [0, b * np.sqrt(3), 0], [0, 0, c]])
cell.wrap()

positions = cell.get_positions()
atomic_numbers = cell.get_atomic_numbers()
basis_vectors = cell.get_cell()
ase.geometry.get_duplicate_atoms(cell, delete=True)

with open("orthogonal_alpha_quartz.data", "w") as outfile:
    outfile.write("# Orthogonal alpha quartz supercell\n\n")
    outfile.write(f"{len(positions)} atoms\n"
                  "2 atom types\n"
Ejemplo n.º 31
0
 def _dlite_get_info(self):
     d = self.info.copy()
     sg = Spacegroup(d.get('spacegroup', 'P 1'))
     d['spacegroup'] = sg.symbol
     return [(k, str(v)) for k, v in d.items()]