Beispiel #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)
Beispiel #2
0
    def extract(s, l_channels, center_atoms, environment_atoms, cutoff_radius,
                cutoff_width, compute_W):

        # Check that l_channels are valid
        l_channels = np.array(l_channels)
        if ((l_channels < 1) | ((l_channels % 1) != 0)).any():
            raise ValueError('Invalid angular momentum channels')

        # Turn center_atoms and environment_atoms into AtomSelections
        if not isinstance(center_atoms, AtomSelection):
            if center_atoms is None:
                center_atoms = range(len(s))
            elif not isinstance(center_atoms, list):
                center_atoms = [center_atoms]
            center_atoms = AtomSelection(s, center_atoms)

        if not isinstance(environment_atoms, AtomSelection):
            if environment_atoms is None:
                environment_atoms = range(len(s))
            elif not isinstance(environment_atoms, list):
                environment_atoms = [environment_atoms]
            environment_atoms = AtomSelection(s, environment_atoms)

        xyz = s.get_positions()

        # Now to build the total list of vectors and weights
        all_vecs = np.zeros((0, 3))
        all_weights = np.zeros((0, ))

        for ci in center_atoms.indices:
            # What would the environment be?
            env_inds = list(set(environment_atoms.indices) - set([ci]))
            # So what are the 'bonds'?
            bonds = minimum_periodic(xyz[env_inds] - xyz[ci], s.get_cell())[0]
            bnorms = np.linalg.norm(bonds, axis=1)

            # Compute sigmoid weights
            bweights = 0.5 * (((cutoff_radius - bnorms) / cutoff_width) / ((
                (cutoff_radius - bnorms) / cutoff_width)**2 + 1)**0.5 + 1)
            bweights /= np.sum(bweights)  # Norm to 1

            all_vecs = np.concatenate((all_vecs, bonds))
            all_weights = np.concatenate((all_weights, bweights))

        # Norm to 1 all weights:
        all_weights /= len(center_atoms.indices)

        # Now compute the order parameters!
        stp = _steinhardt_pars(all_vecs,
                               l_channels,
                               weights=all_weights,
                               compute_W=compute_W)

        if compute_W:
            return {'Q': stp[0], 'W': stp[1]}
        else:
            return {'Q': stp}
Beispiel #3
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)}
    def test_arrays(self):

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

        s = AtomSelection.from_element(a, 'C')
        s.set_array('testarr', [1, 2])

        self.assertTrue(all(s.subset(a).get_array('testarr') == [1, 2]))

        # Test that arrays are reordered
        a.set_array('testarr', np.array([1, 2, 3, 4]))

        s = AtomSelection(a, [2, 0])
        a2 = s.subset(a)

        self.assertTrue((a2.get_array('testarr') == np.array([3, 1])).all())

        # Cell indices test!
        s = AtomSelection(a, [0, 3])
        s.set_array('cell_indices', [[0, 0, 0], [-1, 0, 0]])
        a2 = s.subset(a, True)

        self.assertTrue(np.allclose(a2.get_positions()[-1], [-1, 3, 3]))
    def test_operators(self):

        # Create an Atoms object
        a1 = Atoms('HHH')
        a2 = Atoms('CC')

        s1 = AtomSelection(a1, [0, 2])
        s2 = AtomSelection(a1, [0, 1])

        self.assertTrue(set((s1 + s2).indices) == set([0, 1, 2]))
        self.assertTrue(set((s1 - s2).indices) == set([2]))
        self.assertTrue(set((s1 * s2).indices) == set([0]))
    def test_transformprops(self):

        from ase.quaternions import Quaternion
        from soprano.selection import AtomSelection
        from soprano.properties.transform import (Translate, Rotate, Mirror)

        a = Atoms('CH', positions=[[0, 0, 0], [0.5, 0, 0]])

        sel = AtomSelection.from_element(a, 'C')
        transl = Translate(selection=sel, vector=[0.5, 0, 0])
        rot = Rotate(selection=sel, center=[0.25, 0.0, 0.25],
                     quaternion=Quaternion([np.cos(np.pi/4.0),
                                            0,
                                            np.sin(np.pi/4.0),
                                            0]))
        mirr = Mirror(selection=sel, plane=[1, 0, 0, -0.25])

        aT = transl(a)
        aR = rot(a)
        aM = mirr(a)

        self.assertAlmostEqual(np.linalg.norm(aT.get_positions()[0]),
                               np.linalg.norm(aT.get_positions()[1]))
        self.assertAlmostEqual(np.linalg.norm(aR.get_positions()[0]),
                               np.linalg.norm(aR.get_positions()[1]))
        self.assertAlmostEqual(np.linalg.norm(aM.get_positions()[0]),
                               np.linalg.norm(aM.get_positions()[1]))
Beispiel #7
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
    def test_basic(self):

        # Create an Atoms object
        a = Atoms('HHH')

        # Try a valid selection
        s1 = AtomSelection(a, [0, 2])

        # Try an invalid one
        self.assertRaises(ValueError, AtomSelection, a, [0, 3])

        # Check validation
        self.assertTrue(s1.validate(a))

        # Now make a subset
        a_s = s1.subset(a)
        self.assertTrue(len(a_s) == 2)
Beispiel #9
0
    def test_arrays(self):

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

        s = AtomSelection.from_element(a, 'C')
        s.set_array('testarr', [1, 2])

        self.assertTrue(all(s.subset(a).get_array('testarr') == [1, 2]))
Beispiel #10
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)}
Beispiel #11
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)
    def test_selectors(self):

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

        # Element test
        s1 = AtomSelection.from_element(a, 'C')

        self.assertTrue(set(s1.indices) == set([1, 3]))

        # Box test
        s1 = AtomSelection.from_box(a, [1.5] * 3, [4.5] * 3, periodic=True)
        s2 = AtomSelection.from_box(a, [1.5] * 3, [4.5] * 3, periodic=False)
        s3 = AtomSelection.from_box(a, [0.375] * 3, [1.125] * 3,
                                    periodic=True,
                                    scaled=True)

        self.assertTrue(set(s1.indices) == set([0, 2, 3]))
        self.assertTrue(set(s2.indices) == set([2, 3]))
        self.assertTrue(set(s3.indices) == set([0, 2, 3]))

        # Sphere test

        s1 = AtomSelection.from_sphere(a, [0.5] * 3, 3, periodic=True)
        s2 = AtomSelection.from_sphere(a, [0.5] * 3, 3, periodic=False)

        self.assertTrue(set(s1.indices) == set([0, 1, 2, 3]))
        self.assertTrue(set(s2.indices) == set([0, 1, 2]))
    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])
Beispiel #14
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
Beispiel #15
0
Besides allowing to manipulate information about multiple structures, Soprano provides tools to edit them as well.
This is accomplished by combining selection of atoms and transformation operations that change their positions.
As an example we will use again the ammonia molecule.
Selections can be carried with multiple criteria. The basic ones are selection by element, selection of all atoms
in a box, and selection of all atoms in a sphere.
"""
from soprano.selection import AtomSelection

nh3coords = np.array([[2.5, 2.5, 2.5], [3.4373, 2.5, 2.1193],
                      [2.0314, 3.3117, 2.1193], [2.0314, 1.6883, 2.1193]])
nh3l = Atoms('NHHH', nh3coords, cell=[5, 5,
                                      5])  # The cell is just an empty box

# Now instead of switching the coordinates by hand let's do this with selections.
nh3Hsel = AtomSelection.from_element(nh3l, 'H')  # All H atoms in nh3l

# Selections can be manipulated in interesting ways. To begin with, we can create an Atoms object containing
# only the selected atoms

h3 = nh3Hsel.subset(nh3l)

print "---- Selected atoms contained in nh3Hsel ----\n"
print h3.get_chemical_symbols(), "\n\n"

# Also, selections can be summed, subtracted, or multiplied (representing intersection)
sel1 = AtomSelection(nh3l, [1])  # A custom generated selection
sel2 = AtomSelection(nh3l, [0, 2])  # A custom generated selection

print "---- Indices of selected atoms for various combinations ----\n"
print "sel1:\t", sel1.indices
Beispiel #16
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
Beispiel #17
0
    def extract(s, vdw_set, vdw_scale, default_vdw, save_info):

        # Sanity check
        if len(s) < 2:
            # WTF?
            print('WARNING: impossible to calculate molecules on single-atom '
                  'system')
            return None

        # Get the bonds
        bond_calc = Bonds(vdw_set=vdw_set,
                          vdw_scale=vdw_scale,
                          default_vdw=default_vdw)
        bonds = bond_calc(s)

        # First, we need the biggest Van der Waals radius
        # So that we know how big the supercell needs to be
        vdw_vals = _vdw_radii[vdw_set][s.get_atomic_numbers()]
        vdw_vals = np.where(np.isnan(vdw_vals), default_vdw, vdw_vals)
        vdw_vals *= vdw_scale
        vdw_max = max(vdw_vals)

        # Get the interatomic pair distances
        atomn = s.get_number_of_atoms()
        triui = np.triu_indices(atomn, k=1)
        v = s.get_positions()
        v = (v[:, None, :] - v[None, :, :])[triui]
        # Reduce them
        v, v_cells = minimum_periodic(v, s.get_cell())
        v = np.linalg.norm(v, axis=-1)

        # Now distance and VdW matrices
        vdw_M = ((vdw_vals[None, :] + vdw_vals[:, None]) / 2.0)[triui]
        link_M = v <= vdw_M

        mol_sets = []
        unsorted_atoms = list(range(atomn))

        def get_linked(i):
            i_bonds = filter(lambda b: i in b[:2], bonds)
            links = map(lambda b: (b[1], b[2])
                        if b[0] == i else (b[0], -b[2]), i_bonds)
            return links

        while len(unsorted_atoms) > 0:
            mol_queue = [(unsorted_atoms.pop(0), np.zeros(3))]
            current_mol = []
            current_mol_cells = []
            current_mol_bonds = []
            while len(mol_queue) > 0:
                a1, cell1 = mol_queue.pop(0)
                current_mol.append(a1)
                current_mol_cells.append(cell1)
                current_mol_bonds.append([])
                # Find linked atoms
                links = get_linked(a1)
                for l, cl in links:
                    if l in unsorted_atoms:
                        mol_queue.append((l, cell1 + cl))
                        unsorted_atoms.remove(l)
                    current_mol_bonds[-1].append(l)

            mol_sets.append(
                (current_mol, current_mol_cells, current_mol_bonds))

        mols = []
        for m_i, m_cells, m_bonds in mol_sets:
            mols.append(AtomSelection(s, m_i))
            mols[-1].set_array('cell_indices', m_cells)
            mols[-1].set_array('bonds', m_bonds)

        if save_info:
            s.info[Molecules.default_name] = mols

        return mols
Beispiel #18
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
Beispiel #19
0
    def extract(s, vdw_set, vdw_scale, default_vdw, vdw_custom, save_info):

        N = len(s)
        # Sanity check
        if N < 2:
            # WTF?
            print('WARNING: impossible to calculate molecules on single-atom '
                  'system')
            return None

        # Get the bonds
        bond_calc = Bonds(vdw_set=vdw_set,
                          vdw_scale=vdw_scale,
                          default_vdw=default_vdw,
                          vdw_custom=vdw_custom)
        bonds = bond_calc(s)

        mol_sets = []
        unsorted_atoms = list(range(N))

        def get_linked(i):
            i_bonds = filter(lambda b: i in b[:2], bonds)
            links = map(lambda b: (b[1], b[2])
                        if b[0] == i else (b[0], -b[2]), i_bonds)
            return links

        while len(unsorted_atoms) > 0:
            mol_queue = [(unsorted_atoms.pop(0), np.zeros(3))]
            current_mol = []
            current_mol_cells = []
            current_mol_bonds = []
            while len(mol_queue) > 0:
                a1, cell1 = mol_queue.pop(0)
                current_mol.append(a1)
                current_mol_cells.append(cell1)
                current_mol_bonds.append([])
                # Find linked atoms
                links = get_linked(a1)
                for l, cl in links:
                    if l in unsorted_atoms:
                        mol_queue.append((l, cell1 + cl))
                        unsorted_atoms.remove(l)
                    current_mol_bonds[-1].append(l)

            mol_sets.append(
                (current_mol, current_mol_cells, current_mol_bonds))

        mols = []
        for m_i, m_cells, m_bonds in mol_sets:
            mols.append(AtomSelection(s, m_i))
            mols[-1].set_array('cell_indices', m_cells)
            # This is necessary to guarantee shape consistency
            m_barr = np.empty((len(m_bonds), ), dtype=list)
            for i, m_b in enumerate(m_bonds):
                m_barr[i] = m_b
            mols[-1].set_array('bonds', m_barr)

        if save_info:
            s.info[Molecules.default_name] = mols

        return mols