예제 #1
0
 def interpret_sel(s, sel):
     if sel is None:
         return AtomSelection.all(s)
     elif is_string(sel):
         return AtomSelection.from_element(s, sel)
     elif hasattr(sel, '__call__'):
         return sel(s)
예제 #2
0
    def extract(s, sel_i, sel_j, isotopes, isotope_list, self_coupling,
                block_size):

        # Selections
        if sel_i is None:
            sel_i = AtomSelection.all(s)
        elif not isinstance(sel_i, AtomSelection):
            sel_i = AtomSelection(s, sel_i)

        if sel_j is None:
            sel_j = sel_i
        elif not isinstance(sel_j, AtomSelection):
            sel_j = AtomSelection(s, sel_j)

        # Find gammas
        elems = s.get_chemical_symbols()

        gammas = _get_isotope_data(elems, 'gamma', isotopes, isotope_list)

        # Viable pairs
        pairs = [(i, j) for i in sel_i.indices for j in sel_j.indices]
        if not self_coupling:
            pairs = [p for p in pairs if p[0] != p[1]]

        pairs = np.array(pairs).T
        # Need to sort them and remove any duplicates, also take i < j as
        # convention
        pairs = np.array(
            list(zip(*set([tuple(x) for x in np.sort(pairs, axis=0).T]))))

        pos = s.get_positions()

        # Split this in blocks to make sure we don't clog the memory

        d_ij = np.zeros((0, ))
        v_ij = np.zeros((0, 3))

        npairs = pairs.shape[1]

        for b_i in range(0, npairs, block_size):
            block = pairs.T[b_i:b_i + block_size]
            r_ij = pos[block[:, 1]] - pos[block[:, 0]]
            # Reduce to NN
            r_ij, _ = minimum_periodic(r_ij, s.get_cell(), exclude_self=True)
            # Distance
            R_ij = np.linalg.norm(r_ij, axis=1)
            # Versors
            v_ij = np.concatenate([v_ij, r_ij / R_ij[:, None]], axis=0)
            # Couplings
            d_ij = np.concatenate([
                d_ij,
                _dip_constant(R_ij * 1e-10, gammas[block[:, 0]],
                              gammas[block[:, 1]])
            ])

        return {tuple(ij): [d_ij[l], v_ij[l]] for l, ij in enumerate(pairs.T)}
예제 #3
0
    def decorated_extrfunc(s, selection, **kwargs):

        # Perform basic checks on selection
        if selection is None:
            selection = AtomSelection.all(s)
        elif not selection.validate(s):
            raise ValueError('Selection passed to transform does not apply to'
                             ' system.')

        return extrfunc(s, selection, **kwargs)
예제 #4
0
    def test_iterate(self):

        a = Atoms('HCHC',
                  positions=[[i] * 3 for i in range(4)],
                  cell=[4] * 3,
                  pbc=[True] * 3)

        sAll = AtomSelection.all(a)

        # Slicing?
        self.assertTrue((sAll[:2].indices == [0, 1]).all())

        # Iterating?
        for i, s in enumerate(sAll):
            self.assertEqual(i, s.indices[0])
예제 #5
0
    def extract(s, sel_i, sel_j, tag, isotopes, isotope_list, self_coupling,
                force_recalc):

        # Compute the diagonalised eigenvectors if necessary
        iname_pairs = ISCDiagonal.default_name + '_' + tag + '_pairs'
        iname_evals = ISCDiagonal.default_name + '_' + tag + '_evals'
        iname_evecs = ISCDiagonal.default_name + '_' + tag + '_evecs'
        if iname_pairs not in s.info or force_recalc:
            iprop = ISCDiagonal(tag=tag)
            iprop(s)
        all_pairs = list(s.info[iname_pairs])
        all_evals = s.info[iname_evals]
        all_evecs = s.info[iname_evecs]

        # Selections
        if sel_i is None:
            sel_i = AtomSelection.all(s)
        elif not isinstance(sel_i, AtomSelection):
            sel_i = AtomSelection(s, sel_i)

        if sel_j is None:
            sel_j = sel_i
        elif not isinstance(sel_j, AtomSelection):
            sel_j = AtomSelection(s, sel_j)

        # Find gammas
        elems = s.get_chemical_symbols()
        _nmr_data = _get_nmr_data()

        gammas = _get_isotope_data(elems, 'gamma', isotopes, isotope_list)

        sel_pairs = [(i, j) for i in sel_i.indices
                     for j in sel_j.indices]
        if not self_coupling:
            sel_pairs = [p for p in sel_pairs if p[0] != p[1]]

        jc_dict = {}
        for sp in sel_pairs:
            try:
                i = all_pairs.index(sp)
            except ValueError:
                continue
            evals = _J_constant(all_evals[i], gammas[sp[0]], gammas[sp[1]])
            evecs = all_evecs[i]
            jc_dict[sp] = {'evals': evals, 'evecs': evecs}

        return jc_dict
예제 #6
0
def substitutionGen(struct, subst, to_replace=None, n=1, accept=None):
    """Generator function to create multiple structures with a defect of a
    given element substituted in the existing cell. The defects will be put in
    place of the atoms passed in the to_replace selection. If none is passed,
    all atoms will be replaced in turn. Multiple defects can be included, in
    which case all permutations will be generated.
    It is also possible to reject some configurations based on the output of a
    filter function.

    | Args:
    |   struct (ase.Atoms): the starting structure. All defects will be added
    |                       to it.
    |   subst (str): element symbol of the defect to add.
    |   to_replace (AtomSelection): if present, only atoms belonging to this
    |                               selection will be substituted.
    |   n (int): number of defects to include in each structure. Default is 1.
    |   accept (function): a function that determines whether a generated
    |                      structure should be accepted or rejected. Takes as
    |                      input the generated structure and a tuple of the
    |                      indices of the substituted atoms, and must return a
    |                      bool. If False, the structure will be rejected.
    | Returns:
    |   defectGenerator (generator): an iterator object that yields
    |                                structures with all possible
    |                                substitutions.
    """

    if to_replace is None:
        to_replace = AtomSelection.all(struct)

    defconfs = itertools.combinations(to_replace.indices, n)
    elems = np.array(struct.get_chemical_symbols()).astype('S2')

    print(subst)

    for dc in defconfs:
        dstruct = struct.copy()
        delems = elems.copy()
        delems[list(dc)] = subst
        dstruct.set_chemical_symbols(delems)

        if accept is not None:
            if not accept(dstruct, dc):
                continue

        yield dstruct
예제 #7
0
    def extract(s, sel_i, sel_j, isotopes, isotope_list, self_coupling):

        # Selections
        if sel_i is None:
            sel_i = AtomSelection.all(s)
        elif not isinstance(sel_i, AtomSelection):
            sel_i = AtomSelection(s, sel_i)

        if sel_j is None:
            sel_j = sel_i
        elif not isinstance(sel_j, AtomSelection):
            sel_j = AtomSelection(s, sel_j)

        # Find gammas
        elems = s.get_chemical_symbols()
        _nmr_data = _get_nmr_data()

        gammas = _get_isotope_data(elems, 'gamma', isotopes, isotope_list)

        # Viable pairs
        pairs = [(i, j) for i in sel_i.indices
                 for j in sel_j.indices]
        if not self_coupling:
            pairs = [p for p in pairs if p[0] != p[1]]

        pairs = np.array(pairs).T
        # Need to sort them and remove any duplicates, also take i < j as
        # convention
        pairs = np.array(zip(*set([tuple(x)
                                   for x in np.sort(pairs, axis=0).T])))

        pos = s.get_positions()

        r_ij = pos[pairs[1]] - pos[pairs[0]]
        # Reduce to NN
        r_ij, _ = minimum_periodic(r_ij, s.get_cell(), exclude_self=True)
        # Distance
        R_ij = np.linalg.norm(r_ij, axis=1)
        # Versors
        v_ij = r_ij/R_ij[:, None]
        # Couplings
        d_ij = _dip_constant(R_ij*1e-10, gammas[pairs[0]], gammas[pairs[1]])

        return {tuple(ij): [d_ij[l], v_ij[l]] for l, ij in enumerate(pairs.T)}
예제 #8
0
def additionGen(struct, add, to_addition=None, n=1, add_r=1.2, accept=None):
    """Generator function to create multiple structures with an atom of a
    given element added in the existing cell. The atoms will be attached to 
    the atoms passed in the to_addition selection. If none is passed,
    all atoms will be additioned in turn. Multiple defects can be included, in
    which case all permutations will be generated. The algorithm will try
    adding the atom in the direction that seems most compatible with all the
    already existing bonds. If multiple directions satisfy the condition, they
    will all be tested.
    It is also possible to reject some configurations based on the output of a
    filter function.

    | Args:
    |   struct (ase.Atoms): the starting structure. All atoms will be added
    |                       to it.
    |   add (str): element symbol of the atom to add.
    |   to_replace (AtomSelection): if present, only atoms belonging to this
    |                               selection will be substituted.
    |   n (int): number of new atoms to include in each structure. Default
    |            is 1.
    |   add_r (float): distance, in Angstroms, at which to add the atoms.
    |                  Default is 1.2 Ang
    |   accept (function): a function that determines whether a generated
    |                      structure should be accepted or rejected. Takes as
    |                      input the generated structure and a tuple of
    |                      the indices of the atoms to which the new atoms
    |                      were added, and must return a bool. The newly added
    |                      atoms will always be the last n of the structure.
    |                      If False, the structure will be rejected.
    | Returns:
    |   defectGenerator (generator): an iterator object that yields
    |                                structures with all possible additions.
    """

    if to_addition is None:
        to_addition = AtomSelection.all(struct)

    # Compute bonds
    bonds = Bonds.get(struct)

    cell = struct.get_cell()
    pos = struct.get_positions()

    # Separate bonds by atoms
    atom_bonds = [[] if i in to_addition.indices else None
                  for i in range(len(struct))]
    for b in bonds:
        v = pos[b[1]] - pos[b[0]] + np.dot(b[2], cell)
        try:
            atom_bonds[b[0]].append(v.copy())
        except AttributeError:
            pass
        try:
            atom_bonds[b[1]].append(-v.copy())
        except AttributeError:
            pass

    # Compute possible attachment points for each atom
    attach_v = [None] * len(struct)
    for i, bset in enumerate(atom_bonds):
        if bset is None:
            continue
        if len(bset) == 0:
            rndv = np.random.random((1, 3)) - 0.5
            rndv /= np.linalg.norm(rndv, axis=1)[:, None]
            attach_v[i] = rndv
        else:
            attach_v[i] = utils.rep_alg(bset)
    attach_v = np.array(attach_v)

    addconfs = itertools.combinations(to_addition.indices, n)

    for ac in addconfs:
        addpos = itertools.product(*attach_v[list(ac)])
        for ap in addpos:
            astruct = struct.copy()
            astruct += Atoms(add * n,
                             positions=pos[list(ac)] + np.array(ap) * add_r)

            if accept is not None:
                if not accept(astruct, ac):
                    continue

            yield astruct
예제 #9
0
    def dq_buildup(self,
                   sel_i,
                   sel_j=None,
                   t_max=1e-3,
                   t_steps=1000,
                   R_cut=3,
                   kdq=0.155,
                   A=1,
                   tau=np.inf):
        """
        Return a dictionary of double quantum buildup curves for given pairs
        of atoms, built according to the theory given in:

        G. Pileio et al., "Analytical theory of gamma-encoded double-quantum
        recoupling sequences in solid-state nuclear magnetic resonance"
        Journal of Magnetic Resonance 186 (2007) 65-74

        | Args:
        |   sel_i (AtomSelection or [int]): Selection or list of indices of 
        |                                   atoms for which to compute the
        |                                   curves. By default is None
        |                                   (= all of them).
        |   sel_i (AtomSelection or [int]): Selection or list of indices of 
        |                                   atoms for which to compute the
        |                                   curves with sel_i. By default is 
        |                                   None (= same as sel_i).
        |   t_max (float): maximum DQ buildup time, in seconds. Default 
        |                  is 1e-3.
        |   t_steps (int): number of DQ buildup time steps. Default is 1000.
        |   R_cut (float): cutoff radius for which periodic copies to consider
        |                  in each pair, in Angstrom. Default is 3.
        |   kdq (float): same as the k constant in eq. 35 of the reference. A
        |                parameter depending on the specific sequence used.
        |                Default is 0.155. 
        |   A (float): overall scaling factor for the curve. Default is 1.
        |   tau (float): exponential decay factor for the curve. Default
        |                is np.inf.

        | Returns:
        |   curves (dict): a dictionary of all buildup curves indexed by pair,
        |                  plus the time axis in seconds as member 't'.
        """

        tdq = np.linspace(0, t_max, t_steps)

        # Selections
        if sel_i is None:
            sel_i = AtomSelection.all(s)
        elif not isinstance(sel_i, AtomSelection):
            sel_i = AtomSelection(self._sample, sel_i)

        if sel_j is None:
            sel_j = sel_i
        elif not isinstance(sel_j, AtomSelection):
            sel_j = AtomSelection(self._sample, sel_j)

        # Find gammas
        elems = self._sample.get_chemical_symbols()
        gammas = _get_isotope_data(elems, 'gamma', {}, self._isos)

        # Need to sort them and remove any duplicates, also take i < j as
        # convention
        pairs = [
            tuple(sorted((i, j))) for i in sorted(sel_i.indices)
            for j in sorted(sel_j.indices)
        ]

        scell_shape = minimum_supcell(R_cut, latt_cart=self._sample.get_cell())
        nfg, ng = supcell_gridgen(self._sample.get_cell(), scell_shape)

        pos = self._sample.get_positions()

        curves = {'t': tdq}

        for ij in pairs:

            r = pos[ij[1]] - pos[ij[0]]

            all_r = r[None, :] + ng

            all_R = np.linalg.norm(all_r, axis=1)

            # Apply cutoff
            all_R = all_R[np.where((all_R <= R_cut) * (all_R > 0))]
            n = all_R.shape[0]

            bij = _dip_constant(all_R * 1e-10, gammas[ij[0]], gammas[ij[1]])

            th = 1.5 * kdq * abs(bij[:, None]) * tdq[None, :] * 2 * np.pi
            x = (2 * th / np.pi)**0.5

            Fs, Fc = fresnel(x * 2**0.5)

            x[:, 0] = np.inf

            bdup = 0.5-(1.0/(x*8**0.5)) * \
                (Fc*np.cos(2*th) + Fs*np.sin(2*th))
            bdup[:, 0] = 0

            curves[ij] = A * np.sum(bdup, axis=0) * np.exp(-tdq / tau)

        return curves