Exemplo n.º 1
0
def parse_symmetry(session, group, center=None, axis=None, molecule=None):

    # Handle products of symmetry groups.
    groups = group.split('*')
    from chimerax.geometry import Places
    ops = Places()
    for g in groups:
        ops = ops * group_symmetries(session, g, molecule)

    # Apply center and axis transformation.
    if center is not None or axis is not None:
        from chimerax.geometry import Place, vector_rotation, translation
        tf = Place()
        if center is not None and tuple(center) != (0, 0, 0):
            tf = translation([-c for c in center])
        if axis is not None and tuple(axis) != (0, 0, 1):
            tf = vector_rotation(axis, (0, 0, 1)) * tf
        if not tf.is_identity():
            ops = ops.transform_coordinates(tf)
    return ops
Exemplo n.º 2
0
def group_symmetries(session, group, molecule):

    from chimerax import geometry
    from chimerax.core.errors import UserError

    g0 = group[:1].lower()
    gfields = group.split(',')
    nf = len(gfields)
    recenter = True
    if g0 in ('c', 'd'):
        # Cyclic or dihedral symmetry: C<n>, D<n>
        try:
            n = int(group[1:])
        except ValueError:
            raise UserError('Invalid symmetry group syntax "%s"' % group)
        if n < 1:
            raise UserError('Cn or Dn with n = %d < 1' % (n, ))
        if g0 == 'c':
            tflist = geometry.cyclic_symmetry_matrices(n)
        else:
            tflist = geometry.dihedral_symmetry_matrices(n)
    elif g0 == 'i':
        # Icosahedral symmetry: i[,<orientation>]
        if nf == 1:
            orientation = '222'
        elif nf == 2:
            orientation = gfields[1]
            if not orientation in geometry.icosahedral_orientations:
                raise UserError('Unknown icosahedron orientation "%s"' %
                                orientation)
        else:
            raise UserError('Invalid symmetry group syntax "%s"' % group)
        tflist = geometry.icosahedral_symmetry_matrices(orientation)
    elif g0 == 't' and nf <= 2:
        # Tetrahedral symmetry t[,<orientation]
        if nf == 1:
            orientation = '222'
        elif nf == 2:
            orientation = gfields[1]
            if not orientation in geometry.tetrahedral_orientations:
                tos = ', '.join(geometry.tetrahedral_orientations)
                raise UserError('Unknown tetrahedral symmetry orientation %s'
                                ', must be one of %s' % (gfields[1], tos))
        else:
            raise UserError('Invalid symmetry group syntax "%s"' % group)
        tflist = geometry.tetrahedral_symmetry_matrices(orientation)
    elif g0 == 'o':
        # Octahedral symmetry
        if nf == 1:
            tflist = geometry.octahedral_symmetry_matrices()
        else:
            raise UserError('Invalid symmetry group syntax "%s"' % group)
    elif g0 == 'h':
        # Helical symmetry: h,<rise>,<angle>,<n>[,<offset>]
        if nf < 4 or nf > 5:
            raise UserError('Invalid symmetry group syntax "%s"' % group)
        try:
            param = [float(f) for f in gfields[1:]]
        except ValueError:
            raise UserError('Invalid symmetry group syntax "%s"' % group)
        if len(param) == 3:
            param.append(0.0)
        rise, angle, n, offset = param
        n = int(n)
        from chimerax.geometry import Places
        tflist = Places([
            geometry.helical_symmetry_matrix(rise, angle, n=i + offset)
            for i in range(n)
        ])
    elif gfields[0].lower() == 'shift' or (g0 == 't' and nf >= 3):
        # Translation symmetry: t,<n>,<distance> or t,<n>,<dx>,<dy>,<dz>
        if nf != 3 and nf != 5:
            raise UserError('Invalid symmetry group syntax "%s"' % group)
        try:
            param = [float(f) for f in gfields[1:]]
        except ValueError:
            raise UserError('Invalid symmetry group syntax "%s"' % group)
        n = param[0]
        if n != int(n):
            raise UserError('Invalid symmetry group syntax "%s"' % group)
        n = int(n)
        if nf == 3:
            delta = (0, 0, param[1])
        else:
            delta = param[1:]
        tflist = geometry.translation_symmetry_matrices(n, delta)
    elif group.lower() == 'biomt':
        # Biological unit
        from . import biological_unit_matrices
        tflist = biological_unit_matrices(molecule)
        if len(tflist) == 0:
            raise UserError('Molecule %s has no biological unit info' %
                            molecule.name)
        if len(tflist) == 1 and tflist[0].is_identity():
            log = session.logger
            log.status('Molecule %s is the biological unit' % molecule.name)
        tflist = tflist.transform_coordinates(molecule.position.inverse())
        recenter = False
    elif g0 == '#':
        from chimerax.core.commands import ModelsArg
        if nf == 1:
            models = ModelsArg.parse(group, session)[0]
            mslist = [model_symmetry(m) for m in models]
            mslist = [ms for ms in mslist if ms is not None]
            if len(mslist) == 0:
                raise UserError('No symmetry for "%s"' % group)
            elif len(mslist) > 1:
                raise UserError('Multiple models "%s"' % group)
            tflist = mslist[0]
            recenter = False
        elif nf == 2:
            gf0, gf1 = gfields
            models = ModelsArg.parse(gf0, session)[0]
            mlist = [
                m for m in models
                if hasattr(m, 'placements') and callable(m.placements)
            ]
            if len(mlist) == 0:
                raise UserError('No placements for "%s"' % gf0)
            elif len(mlist) > 1:
                raise UserError('Multiple models with placements "%s"' % gf0)
            m = mlist[0]
            tflist = m.placements(gf1)
            if len(tflist) == 0:
                raise UserError('No placements "%s" for "%s"' % (gf1, gf0))
            c = molecule.atoms.coords.mean(axis=0)
            cg = molecule.position * c
            cm = m.position.inverse() * cg
            tflist = make_closest_placement_identity(tflist, cm)
            recenter = False
    else:
        raise UserError('Unknown symmetry group "%s"' % group)

    return tflist