Example #1
0
    def do(self):
        cache = context.application.cache

        graph = create_molecular_graph(cache.nodes)
        parent = cache.node

        Frame = context.application.plugins.get_node("Frame")
        for group in graph.independent_nodes:
            atoms = [graph.molecule.atoms[i] for i in group]
            new_positions = self.calc_new_positions(group, atoms, graph, parent)
            frame = Frame(name=chemical_formula(atoms)[1])
            primitive.Add(frame, parent, index=0)
            for node, atom in zip(group, atoms):
                primitive.Move(atom, frame)
                new_position = new_positions[node]
                translation = Translation()
                translation.t = atom.get_parentframe_up_to(parent).vector_apply_inverse(new_position)
                primitive.SetProperty(atom, "transformation", translation)
            for atom in atoms:
                # take a copy of the references since they are going to be
                # refreshed (changed and reverted) during the loop.
                for reference in copy.copy(atom.references):
                    referent = reference.parent
                    if referent.parent != frame:
                        has_to_move = True
                        for child in referent.children:
                            if child.target.parent != frame:
                                has_to_move = False
                                break
                        if has_to_move:
                            primitive.Move(referent, frame)
Example #2
0
def coords_to_zeobuilder(org_coords, opt_coords, atoms, parent, graph=None):
    if graph == None:
        atomgroups = [numpy.arange(len(atoms))]
    else:
        atomgroups = graph.independent_nodes

    for group in atomgroups:
        group_org = org_coords[group]
        group_opt = opt_coords[group]
        # Transform the guessed geometry as to overlap with the original geometry
        transf = superpose(group_org, group_opt)
        group_opt = numpy.dot(group_opt, transf.r.transpose()) + transf.t

        # Put coordinates of guessed geometry back into Zeobuilder model
        for i,atomindex in enumerate(group):
            translation = Translation()
            atom = graph.molecule.atoms[atomindex]
            # Make sure atoms in subframes are treated properly
            transf = atom.parent.get_frame_relative_to(parent)
            org_pos = atom.transformation.t
            opt_pos = transf.vector_apply_inverse(group_opt[i])

            translation = Translation()
            translation.t = opt_pos - org_pos
            primitive.Transform(atom, translation)
Example #3
0
    def replace(self, gl_object):
        if not gl_object.get_fixed():
            state = gl_object.__getstate__()
            state.pop("name", None)
            state.pop("transformation", None)
            new = self.get_new(gl_object.transformation.t)

            if(self.current_object == "Fragment"): #fragments are inserted at frames - have no refs
                target_object = new.children[1]
            else:
                target_object = new
            for reference in gl_object.references[::-1]:
                if not reference.check_target(target_object):
                    return
            parent = gl_object.parent
            import copy
            primitive.Add(new, parent)
            if(self.current_object == "Fragment"):
                # rotation
                Bond = context.application.plugins.get_node("Bond")
                if len(gl_object.references) == 1 and isinstance(gl_object.references[0].parent, Bond):
                    bond1 = gl_object.references[0].parent
                    direction1 = bond1.shortest_vector_relative_to(parent)
                    if bond1.children[0].target != gl_object:
                        direction1 *= -1
                    bond2 = new.children[0].references[0].parent
                    direction2 = bond2.shortest_vector_relative_to(parent)
                    if bond2.children[0].target != target_object:
                        direction2 *= -1
                    axis = numpy.cross(direction2, direction1)
                    if numpy.linalg.norm(axis) < 1e-8:
                        axis = random_orthonormal(direction1)
                    angle = compute_angle(direction1, direction2)
                    rotation = Rotation()
                    rotation.set_rotation_properties(angle,axis,False)
                    primitive.Transform(new, rotation)
                else:
                    bond1 = None
                # tranlsation
                translation = Translation()
                pos_old = new.children[1].get_frame_relative_to(parent).t
                pos_new = gl_object.transformation.t
                translation.t = pos_new - pos_old
                primitive.Transform(new, translation)
                if bond1 != None:
                    # bond length
                    old_length = numpy.linalg.norm(direction1)
                    new_length = bonds.get_length(new.children[1].number, bond1.get_neighbor(gl_object).number)
                    translation = Translation()
                    translation.t = -direction1/old_length*(new_length-old_length)
                    primitive.Transform(new, translation)

            for reference in gl_object.references[::-1]:
                reference.set_target(target_object)
            primitive.Delete(gl_object)
            if(self.current_object == "Fragment"):
                primitive.Delete(new.children[0])
                # get rid of frame
                UnframeAbsolute = context.application.plugins.get_action("UnframeAbsolute")
                UnframeAbsolute([new])
Example #4
0
 def get_transformation(self, molecule):
     atom1, atom2 = self.hinge_atoms
     direction = molecule.coordinates[atom1] - molecule.coordinates[atom2]
     direction /= numpy.linalg.norm(direction)
     direction *= numpy.random.uniform(-self.max_amplitude, self.max_amplitude)
     result = Translation()
     result.t[:] = direction
     return result
Example #5
0
 def reset(self):
     config = context.application.configuration
     self.rotation_center = Translation()
     self.rotation = Rotation()
     self.eye = Translation()
     self.eye.t[2] = config.viewer_distance
     self.opening_angle = config.opening_angle
     self.window_size = config.window_size
     self.window_depth = config.window_depth
Example #6
0
 def get_transformation(self, molecule):
     atom1, atom2 = self.hinge_atoms
     direction = molecule.coordinates[atom1] - molecule.coordinates[atom2]
     direction /= numpy.linalg.norm(direction)
     direction *= numpy.random.uniform(-self.max_amplitude,
                                       self.max_amplitude)
     result = Translation()
     result.t[:] = direction
     return result
Example #7
0
 def get_transformation(self, molecule):
     atom1, atom2, atom3, atom4 = self.hinge_atoms
     a = molecule.coordinates[atom1] - molecule.coordinates[atom2]
     a /= numpy.linalg.norm(a)
     b = molecule.coordinates[atom3] - molecule.coordinates[atom4]
     b /= numpy.linalg.norm(b)
     direction = 0.5*(a+b)
     direction *= numpy.random.uniform(-self.max_amplitude, self.max_amplitude)
     result = Translation()
     result.t[:] = direction
     return result
Example #8
0
 def get_transformation(self, molecule):
     atom1, atom2, atom3, atom4 = self.hinge_atoms
     a = molecule.coordinates[atom1] - molecule.coordinates[atom2]
     a /= numpy.linalg.norm(a)
     b = molecule.coordinates[atom3] - molecule.coordinates[atom4]
     b /= numpy.linalg.norm(b)
     direction = 0.5 * (a + b)
     direction *= numpy.random.uniform(-self.max_amplitude,
                                       self.max_amplitude)
     result = Translation()
     result.t[:] = direction
     return result
Example #9
0
def coords_to_zeobuilder(org_coords, opt_coords, atoms, parent):
    # Transform the guessed geometry as to overlap with the original geometry
    transf = superpose(org_coords, opt_coords)
    opt_coords = numpy.dot(opt_coords, transf.r.transpose()) + transf.t

    # Put coordinates of guess geometry back into Zeobuilder model
    for i in xrange(len(atoms)):
        translation = Translation()
        atom = atoms[i]
        # Make sure atoms in subframes are treated properly
        transf = atom.parent.get_frame_relative_to(parent)
        org_pos = atom.transformation.t
        opt_pos = transf.vector_apply_inverse(opt_coords[i])
        translation.t = opt_pos - org_pos
        primitive.Transform(atom, translation)
Example #10
0
 def do(self):
     cache = context.application.cache
     for node in cache.nodes:
         translation = Translation()
         child_translations = []
         translated_children = []
         for child in node.children:
             if isinstance(child, GLTransformationMixin) and isinstance(child.transformation, Translation):
                 if child.get_fixed():
                     translated_children = []
                     break
                 translated_children.append(child)
                 child_translations.append(child.transformation)
         if len(translated_children) > 0:
             translation.t = calculate_center(child_translations)
             CenterAlignBase.do(self, node, translated_children, translation)
Example #11
0
 def get_transformation(self, coordinates):
     """Construct a transformation object"""
     atom1, atom2 = self.hinge_atoms
     direction = coordinates[atom1] - coordinates[atom2]
     direction /= np.linalg.norm(direction)
     direction *= np.random.uniform(-self.max_amplitude, self.max_amplitude)
     result = Translation(direction)
     return result
Example #12
0
 def get_transformation(self, coordinates):
     """Construct a transformation object"""
     atom1, atom2, atom3, atom4 = self.hinge_atoms
     a = coordinates[atom1] - coordinates[atom2]
     a /= np.linalg.norm(a)
     b = coordinates[atom3] - coordinates[atom4]
     b /= np.linalg.norm(b)
     direction = 0.5 * (a + b)
     direction *= np.random.uniform(-self.max_amplitude, self.max_amplitude)
     result = Translation(direction)
     return result
Example #13
0
    def do(self):
        cache = context.application.cache
        for node in cache.nodes:
            translation = Translation()

            translated_children = []
            for child in node.children:
                if isinstance(child, GLTransformationMixin) and isinstance(child.transformation, Translation):
                    if child.get_fixed():
                        translated_children = []
                        break
                    translated_children.append(child)
            if len(translated_children) == 0:
                continue

            mass, com = compute_center_of_mass(yield_particles(node))
            if mass == 0.0:
                continue

            translation.t = com
            CenterAlignBase.do(self, node, translated_children, translation)
Example #14
0
    def do(self):
        cache = context.application.cache

        # Translate where possible, if necessary
        translated_nodes = cache.translated_nodes
        if len(translated_nodes) > 0:
            if isinstance(cache.last, GLTransformationMixin) and \
               isinstance(cache.last.transformation, Translation):
                absolute_inversion_center = cache.last.get_absolute_frame().t
            else:
                absolute_inversion_center = numpy.zeros(3, float)
            victims_by_parent = list_by_parent(cache.transformed_nodes)
            for parent, victims in victims_by_parent.iteritems():
                local_inversion_center = parent.get_absolute_frame().vector_apply_inverse(absolute_inversion_center)
                for victim in victims:
                    translation = Translation()
                    translation.t = 2 * (local_inversion_center - victim.transformation.t)
                    primitive.Transform(victim, translation)

        # Apply an inversion rotation where possible
        r = Rotation()
        r.inversion_rotation()
        for victim in cache.rotated_nodes:
            primitive.Transform(victim, r, after=False)
Example #15
0
 def do(self):
     cache = context.application.cache
     translation = Translation()
     translation.t = copy.deepcopy(cache.node.transformation.t)
     CenterAlignBase.do(self, cache.parent, cache.translated_neighbors, translation)
Example #16
0
 def randomize(self, center):
     self.transform(Translation(-np.array(center)))
     self.transform(Rotation.random())
     self.transform(Translation(center))
Example #17
0
 def rotate(self, center, axis, angle):
     self.transform(Translation(-np.array(center)))
     self.transform(Rotation.from_properties(angle, axis, invert=False))
     self.transform(Translation(center))
Example #18
0
 def translate(self, vector):
     self.transform(Translation(vector))
Example #19
0
    def do(self):
        # the indices (n,m) that define the tube, see e.g. the wikipedia page
        # about nanotubes for the interpretation of these indices:
        # http://en.wikipedia.org/wiki/Carbon_nanotube
        n = self.parameters.n
        m = self.parameters.m

        periodic_tube = isinstance(self.parameters.tube_length, Undefined)

        universe = context.application.model.universe

        def define_flat():
            "Reads and converts the unit cell vectors from the current model."
            # some parts of the algorithm have been arranged sub functions like
            # these, to reduce the number of local variables in self.do. This
            # should also clarify the code.
            active, inactive = universe.get_active_inactive()
            lengths, angles = universe.get_parameters()
            a = lengths[active[0]]
            b = lengths[active[1]]
            theta = angles[inactive[0]]
            return (
                numpy.array([a, 0], float),
                numpy.array([b*numpy.cos(theta), b*numpy.sin(theta)], float)
            )

        flat_a, flat_b = define_flat()

        def create_pattern():
            "Read the atom positions and transform them to the flat coordinates"
            active, inactive = universe.get_active_inactive()
            tmp_cell = UnitCell()
            tmp_cell.add_cell_vector(universe.cell[:,active[0]])
            tmp_cell.add_cell_vector(universe.cell[:,active[1]])
            r = tmp_cell.calc_align_rotation_matrix()

            return [
                (atom.number, numpy.dot(r, atom.get_absolute_frame().t))
                for atom in yield_atoms([universe])
            ]

        pattern = create_pattern()

        def define_big_periodic():
            "Based on (n,m) calculate the size of the periodic sheet (that will be folded into a tube)."
            big_a = n*flat_a - m*flat_b
            norm_a = numpy.linalg.norm(big_a)
            radius = norm_a/(2*numpy.pi)
            big_x = big_a/norm_a
            big_y = numpy.array([-big_x[1], big_x[0]], float)

            big_b = None
            stack_vector = flat_b - flat_a*numpy.dot(big_x, flat_b)/numpy.dot(big_x, flat_a)
            stack_length = numpy.linalg.norm(stack_vector)
            nominator = numpy.linalg.norm(stack_vector - flat_b)
            denominator = numpy.linalg.norm(flat_a)
            fraction = nominator/denominator
            stack_size = 1
            while True:
                repeat = fraction*stack_size
                if stack_length*stack_size > self.parameters.max_length:
                    break
                if abs(repeat - round(repeat))*denominator < self.parameters.max_error:
                    big_b = stack_vector*stack_size
                    break
                stack_size += 1
            if big_b is None:
                raise UserError("Could not create a periodic tube shorter than the given maximum length.")
            rotation = numpy.array([big_x, big_y], float)
            return big_a, big_b, rotation, stack_vector, stack_size, radius

        def define_big_not_periodic():
            "Based on (n,m) calculate the size of the non-periodic sheet (that will be folded into a tube)."
            big_a = n*flat_a - m*flat_b
            norm_a = numpy.linalg.norm(big_a)
            radius = norm_a/(2*numpy.pi)
            big_x = big_a/norm_a
            big_y = numpy.array([-big_x[1], big_x[0]], float)

            stack_vector = flat_b - flat_a*numpy.dot(big_x, flat_b)/numpy.dot(big_x, flat_a)
            stack_length = numpy.linalg.norm(stack_vector)
            stack_size = int(self.parameters.tube_length/stack_length)
            big_b = stack_vector*stack_size
            rotation = numpy.array([big_x, big_y], float)
            return big_a, big_b, rotation, stack_vector, stack_size, radius


        if periodic_tube:
            big_a, big_b, rotation, stack_vector, stack_size, radius = define_big_periodic()
        else:
            big_a, big_b, rotation, stack_vector, stack_size, radius = define_big_not_periodic()

        def yield_translations():
            "Yields the indices of the periodic images that are part of the tube."
            to_fractional = numpy.linalg.inv(numpy.array([big_a, big_b]).transpose())
            col_len = int(numpy.linalg.norm(big_a + m*stack_vector)/numpy.linalg.norm(flat_a))+4
            shift = numpy.dot(stack_vector - flat_b, flat_a)/numpy.linalg.norm(flat_a)**2
            for row in xrange(-m-1, stack_size+1):
                col_start = int(numpy.floor(row*shift))-1
                for col in xrange(col_start, col_start+col_len):
                    p = col*flat_a + row*flat_b
                    i = numpy.dot(to_fractional, p)
                    if (i >= 0).all() and (i < 1-1e-15).all():
                        yield p
                    #yield p, (i >= 0).all() and (i < 1).all()

        def yield_pattern():
            for number, coordinate in pattern:
                yield number, coordinate.copy()

        # first delete everything the universe:
        for child in copy.copy(universe.children):
            primitive.Delete(child)

        # add the new atoms
        Atom = context.application.plugins.get_node("Atom")
        if self.parameters.flat:
            rot_a = numpy.dot(rotation, big_a)
            rot_b = numpy.dot(rotation, big_b)
            big_cell = numpy.array([
                [rot_a[0], rot_b[0], 0],
                [rot_a[1], rot_b[1], 0],
                [0, 0, 10*angstrom],
            ], float)
            primitive.SetProperty(universe, "cell", big_cell)
            primitive.SetProperty(universe, "cell_active", numpy.array([True, periodic_tube, False], bool))
            for p in yield_translations():
                for number, coordinate in yield_pattern():
                    coordinate[:2] += p
                    coordinate[:2] = numpy.dot(rotation, coordinate[:2])
                    translation = Translation()
                    translation.t[:] = coordinate
                    primitive.Add(Atom(number=number, transformation=translation), universe)
        else:
            tube_length = numpy.linalg.norm(big_b)
            primitive.SetProperty(universe, "cell", numpy.diag([radius*2, radius*2, tube_length]))
            primitive.SetProperty(universe, "cell_active", numpy.array([False, False, periodic_tube], bool))
            for p in yield_translations():
                for number, coordinate in yield_pattern():
                    coordinate[:2] += p
                    coordinate[:2] = numpy.dot(rotation, coordinate[:2])
                    translation = Translation()
                    translation.t[0] = (radius+coordinate[2])*numpy.cos(coordinate[0]/radius)
                    translation.t[1] = (radius+coordinate[2])*numpy.sin(coordinate[0]/radius)
                    translation.t[2] = coordinate[1]
                    primitive.Add(Atom(number=number, transformation=translation), universe)
Example #20
0
class Camera(object):
    def __init__(self):
        # register configuration settings: default camera
        from zeobuilder.gui import fields
        from zeobuilder.gui.fields_dialogs import DialogFieldInfo
        config = context.application.configuration
        config.register_setting(
            "viewer_distance",
            100.0*angstrom,
            DialogFieldInfo("Default Viewer", (1, 0), fields.faulty.Length(
                label_text="Distance from origin",
                attribute_name="viewer_distance",
                low=0.0,
                low_inclusive=True,
            )),
        )
        config.register_setting(
            "opening_angle",
            0.0,
            DialogFieldInfo("Default Viewer", (1, 1), fields.faulty.MeasureEntry(
                measure="Angle",
                label_text="Camera opening angle",
                attribute_name="opening_angle",
                low=0.0,
                low_inclusive=True,
                high=0.5*numpy.pi,
                high_inclusive=False,
                show_popup=False,
            )),
        )
        config.register_setting(
            "window_size",
            25*angstrom,
            DialogFieldInfo("Default Viewer", (1, 2), fields.faulty.Length(
                label_text="Window size",
                attribute_name="window_size",
                low=0.0,
                low_inclusive=False,
            )),
        )
        config.register_setting(
            "window_depth",
            200.0*angstrom,
            DialogFieldInfo("Default Viewer", (1, 3), fields.faulty.Length(
                label_text="Window depth",
                attribute_name="window_depth",
                low=0.0,
                low_inclusive=False,
            )),
        )

        self.reset()

    def reset(self):
        config = context.application.configuration
        self.rotation_center = Translation()
        self.rotation = Rotation()
        self.eye = Translation()
        self.eye.t[2] = config.viewer_distance
        self.opening_angle = config.opening_angle
        self.window_size = config.window_size
        self.window_depth = config.window_depth

    def get_znear(self):
        if self.opening_angle > 0.0:
            return 0.5*self.window_size/numpy.tan(0.5*self.opening_angle)
        else:
            return 0.0
    znear = property(get_znear)

    # coordinate transformations

    def eye_to_camera(self, vector_e):
        tmp = numpy.ones(2, float)
        znear = self.znear
        if znear > 0:
            return -vector_e[:2]/vector_e[2]/self.window_size*znear
        else:
            return vector_e[:2]/self.window_size

    def camera_window_to_eye(self, vector_c):
        tmp = numpy.zeros(3, float)
        tmp[:2] = vector_c*self.window_size
        znear = self.znear
        if znear > 0:
            tmp[2] = -self.znear
        else:
            tmp[2] = -self.window_size/3.0
        return tmp

    def model_to_eye(self, vector_m):
        scene = context.application.scene
        tmp = scene.model_center.vector_apply_inverse(vector_m)
        tmp = self.rotation_center.vector_apply_inverse(tmp)
        tmp = self.rotation.vector_apply_inverse(tmp)
        tmp[2] -= self.znear
        tmp = self.eye.vector_apply_inverse(tmp)
        return tmp

    def eye_to_model(self, vector_e):
        scene = context.application.scene
        tmp = self.eye.vector_apply(vector_e)
        tmp[2] += self.znear
        tmp = self.rotation.vector_apply(tmp)
        tmp = self.rotation_center.vector_apply(tmp)
        tmp = scene.model_center.vector_apply(tmp)
        return tmp

    def model_to_camera(self, vector_m):
        return self.eye_to_camera(self.model_to_eye(vector_m))

    def camera_window_to_model(self, vector_c):
        return self.eye_to_model(self.camera_window_to_eye(vector_c))

    def object_to_depth(self, gl_object):
        result = -self.model_to_eye(gl_object.get_absolute_frame().t)[2]
        return result

    def object_to_camera(self, gl_object):
        return self.eye_to_camera(self.model_to_eye(gl_object.get_absolute_frame().t))

    def object_to_eye(self, gl_object):
        return self.model_to_eye(gl_object.get_absolute_frame().t)

    def object_eye_rotation(self, gl_object):
        """
            Returns a matrix that consists of the x, y and z axes of the
            eye frame in the coordinates of the parent frame of the given
            object.
        """
        if hasattr(gl_object, "parent") and \
           isinstance(gl_object.parent, GLTransformationMixin):
            parent_matrix = gl_object.parent.get_absolute_frame().r
        else:
            parent_matrix = numpy.identity(3, float)
        result = numpy.dot(self.rotation.r.transpose(), parent_matrix).transpose()
        return result

    def depth_to_scale(self, depth):
        """ transforms a depth into a scale (au/camcoords)"""
        znear = self.znear
        if znear > 0:
            return depth/znear*self.window_size
        else:
            return self.window_size

    def vector_in_plane(self, r, p_m):
        """Returns a vector at camera position r in a plane (through p, orthogonal to viewing direction)

        Arguments
            r  --  a two-dimensional vector in camera coordinates
            p_m  --  a three-dimensional vector in model coordinates

        Returns
            rp  --  a three-dimensional vector in model coordinates that lies
                    at the intersection of a plane and a line. The plane is
                    orthogonal to the viewing direction and goes through the
                    point p. The line connects the eye (eye_m below) with the
                    point r (r_m below) in the camera window.
        """

        eye_m = self.eye_to_model(numpy.zeros(3, float))
        r_m = self.camera_window_to_model(r)
        center_m = self.camera_window_to_model(numpy.zeros(2, float))

        normal = (eye_m - center_m)
        normal /= numpy.linalg.norm(normal)

        if self.znear > 0:
            # the line is defined as r = eye_m + d*t, where t = -infinity ... infinity
            d =  eye_m - r_m

            # t at the intersection:
            t = -numpy.dot(eye_m - p_m, normal)/numpy.dot(d, normal)

            return eye_m + d*t
        else:
            # the line is defined as r = r_m + d*t, where t = -infinity ... infinity
            d = normal

            # t at the intersection:
            t = -numpy.dot(r_m - p_m, normal)/numpy.dot(d, normal)

            return r_m + d*t