Пример #1
0
def test_bounding_circle_radius_random_hull_rotation(points, rotation):
    """Test that rotating vertices does not change the bounding radius."""
    assume(not np.all(rotation == 0))

    hull = ConvexHull(points)
    poly = Polygon(points[hull.vertices])

    rotation = rowan.normalize(rotation)
    rotated_vertices = rowan.rotate(rotation, poly.vertices)
    poly_rotated = Polygon(rotated_vertices)

    circle = poly.minimal_bounding_circle
    rotated_circle = poly_rotated.minimal_bounding_circle
    assert np.isclose(circle.radius, rotated_circle.radius)
Пример #2
0
    def test_ap(self):
        """Test finding quaternion to rotate antiparallel vectors onto each
        other"""
        # For this test, there are multiple quaternions that would effect the
        # correct rotation, so rather than checking for a specific one we check
        # that the appropriate rotation results from applying the quaternion
        vec1 = np.array([1, 0, 0])
        vec2 = np.array([0, 1, 0])
        quat = rowan.vector_vector_rotation(vec1, vec2)
        self.assertTrue(
                np.allclose(
                    rowan.rotate(quat, vec1),
                    vec2/np.linalg.norm(vec2, axis=-1)
                    ))

        vec1 = np.array([1, 0, 0])
        vec2 = np.array([[0, 1, 0],
                         [2, 0, 0],
                         [-2, 0, 0]])
        quat = rowan.vector_vector_rotation(vec1, vec2)
        self.assertTrue(
                np.allclose(
                    rowan.rotate(quat, vec1),
                    vec2/np.linalg.norm(vec2, axis=-1)[:, np.newaxis]
                    ))

        vec1 = np.array([0, 1, 0])
        vec2 = np.array([[0, 0, 1],
                         [0, 2, 0],
                         [0, -2, 0]])
        quat = rowan.vector_vector_rotation(vec1, vec2)
        self.assertTrue(
                np.allclose(
                    rowan.rotate(quat, vec1),
                    vec2/np.linalg.norm(vec2, axis=-1)[:, np.newaxis]
                    ))
Пример #3
0
    def testfun(random_quat):
        assume(not np.all(random_quat == 0))
        random_quat = rowan.normalize(random_quat)
        rotated_points = rowan.rotate(random_quat, square_points)
        r = 1
        poly = ConvexSpheropolygon(rotated_points, radius=r)

        hull = ConvexHull(square_points[:, :2])

        cap_area = np.pi * r * r
        edge_area = np.sum(
            np.linalg.norm(square_points - np.roll(square_points, 1, 0), axis=1), axis=0
        )
        sphero_area = cap_area + edge_area
        assert np.isclose(poly.signed_area, hull.volume + sphero_area)
Пример #4
0
def _calc_shift(orientations: np.ndarray, molecule: Molecule) -> np.ndarray:
    """A function to calculate the shift of large particle positions to COM positions.

    The positions defined in the Trimer classes are for the center of the 'large' particle since
    this was the output from the packing algorithm. This offsets these values to be on the center of
    mass, taking into account the orientation of the molecule.

    Args:
        orientations: Orientation of particles in degrees
        molecule: The molecule for which the shift is occurring.

    """
    pos_shift = molecule.get_relative_positions()[0]
    orient_quat = rowan.from_euler(np.deg2rad(orientations), 0, 0)
    return rowan.rotate(orient_quat, pos_shift)
Пример #5
0
    def get_bin(self, query_point, point, query_point_orientation,
                point_orientation):
        r_ij = point - query_point
        rot_r_ij = rowan.rotate(rowan.conjugate(query_point_orientation), r_ij)

        limits = np.asarray(self.limits)
        xy_bins = tuple(
            np.floor((rot_r_ij[:2] + limits) * np.asarray(self.bins[:2]) /
                     (2 * limits)).astype(np.int32))

        point_angle = rowan.geometry.angle(point_orientation)
        angle_bin = np.floor(
            ((point_angle - np.arctan2(-r_ij[1], -r_ij[0])) % TWO_PI) *
            self.bins[2] / TWO_PI).astype(np.int32)
        return xy_bins + (angle_bin, )
    def test_rotational_invariance(self):
        classes = [[(-1., 0, 0), (1., 0, 0)], [(0, 1, 0), (0, -1, 0)]]
        num_classes = len(classes)
        num_data = 128

        train_ins = np.tile(classes, (num_data, 1, 1))
        train_ins += np.random.normal(scale=.1, size=train_ins.shape)

        # sort by R to learn permutation invariance
        rsqs = np.linalg.norm(train_ins, axis=-1)
        for (neighborhood, rsq) in zip(train_ins, rsqs):
            neighborhood[:] = neighborhood[np.argsort(rsq)]

        train_ins, test_ins = train_ins[:num_data], train_ins[num_data:]
        train_outs = np.tile(np.arange(num_classes), num_data // 2)

        quats = rowan.random.rand(test_ins.shape[0])
        test_ins = rowan.rotate(quats[:, np.newaxis], test_ins)

        model = keras.models.Sequential()
        model.add(
            pythia.learned.bonds.InertiaRotation(
                4, input_shape=train_ins.shape[1:]))
        model.add(pythia.learned.spherical_harmonics.SphericalHarmonics(2))
        model.add(pythia.learned.spherical_harmonics.NeighborAverage())
        model.add(
            pythia.learned.spherical_harmonics.ComplexProjection(4, 'abs'))
        model.add(keras.layers.Activation('relu'))
        model.add(keras.layers.Flatten())
        model.add(keras.layers.BatchNormalization())
        model.add(keras.layers.Dense(num_classes, activation='softmax'))
        model.compile('sgd', 'categorical_crossentropy', metrics=['accuracy'])

        net_train_outs = keras.utils.to_categorical(train_outs, num_classes)

        train_history = model.fit(train_ins,
                                  net_train_outs,
                                  validation_data=(test_ins, net_train_outs),
                                  epochs=100,
                                  verbose=0,
                                  shuffle=True)

        self.assertLess(np.mean(train_history.history['val_accuracy']), .55)
Пример #7
0
def to_view(bod, view_orientation, image_size):
    lin_grid = np.linspace(-1, 1, image_size)
    x, y = np.meshgrid(lin_grid, lin_grid)
    y = -y
    r2 = x**2 + y**2
    z = np.sqrt(np.clip(1 - r2, 0, None))
    xyz = np.dstack((x, y, z))
    xyz = rowan.rotate(rowan.inverse(view_orientation), xyz)
    x, y, z = xyz[:, :, 0], xyz[:, :, 1], xyz[:, :, 2]
    view = np.zeros((image_size, image_size))
    phi = np.arccos(z)
    theta = np.arctan2(y, x) % (2 * np.pi)
    num_theta_bins, num_phi_bins = bod.nbins
    theta_bin_edges, phi_bin_edges = bod.bin_edges
    theta_bins = np.trunc(theta / (2 * np.pi) * num_theta_bins).astype(int)
    phi_bins = np.trunc(phi / np.pi * num_phi_bins).astype(int)
    view = bod.bond_order[theta_bins, phi_bins]
    view[r2 > 1] = np.nan
    return view
Пример #8
0
    def test_rotational_invariance(self):
        box = freud.box.Box.cube(10)
        positions = np.array([[0, 0, 0], [-1, -1, 0], [-1, 1, 0], [1, -1, 0],
                              [1, 1, 0], [-1, 0, -1], [-1, 0, 1], [1, 0, -1],
                              [1, 0, 1], [0, -1, -1], [0, -1, 1], [0, 1, -1],
                              [0, 1, 1]])
        query_point_indices = np.zeros(len(positions) - 1)
        point_indices = np.arange(1, len(positions))
        nlist = freud.locality.NeighborList.from_arrays(
            len(positions), len(positions), query_point_indices, point_indices,
            np.full(len(query_point_indices), np.sqrt(2)))

        q6 = freud.order.Steinhardt(6)
        w6 = freud.order.Steinhardt(6, wl=True)

        q6.compute((box, positions), neighbors=nlist)
        q6_unrotated_order = q6.particle_order[0]
        w6.compute((box, positions), neighbors=nlist)
        w6_unrotated_order = w6.particle_order[0]

        for i in range(10):
            np.random.seed(i)
            quat = rowan.random.rand()
            positions_rotated = rowan.rotate(quat, positions)

            # Ensure Q6 is rotationally invariant
            q6.compute((box, positions_rotated), neighbors=nlist)
            npt.assert_allclose(q6.particle_order[0],
                                q6_unrotated_order,
                                rtol=1e-5)
            npt.assert_allclose(q6.particle_order[0],
                                PERFECT_FCC_Q6,
                                rtol=1e-5)

            # Ensure W6 is rotationally invariant
            w6.compute((box, positions_rotated), neighbors=nlist)
            npt.assert_allclose(w6.particle_order[0],
                                w6_unrotated_order,
                                rtol=1e-5)
            npt.assert_allclose(w6.particle_order[0],
                                PERFECT_FCC_W6,
                                rtol=1e-5)
Пример #9
0
 def transform(self, coords, sensor_labels):
     sensor_order = {s: idx for idx, s in enumerate(sensor_labels)}
     ref_cols = [
         sensor_order[self._nasion],
         sensor_order[self._right],
         sensor_order[self._left]
     ]
     if len(coords.shape) == 2:
         coords = np.expand_dims(coords, axis=0)
     for n in np.arange(coords.shape[0]):
         try:
             q, t = rowan.mapping.davenport(
                 coords[n, ref_cols, :],
                 self.fixed_ref
             )
             coords[n,:,:] = rowan.rotate(q, coords[n,:,:]) + t
         except Exception as e:
             warnings.warn(
                 'Caught an error and emitting NaNs.\nError message:\n' + \
                 str(e)
             )
             coords[n,:,:] = np.nan
     return coords
Пример #10
0
def test_init_crystal_position(crystal_params):
    if isinstance(crystal_params.crystal, (TrimerP2)):
        return
    with crystal_params.temp_context(cell_dimensions=1):
        snap = init_from_crystal(crystal_params,
                                 equilibration=False,
                                 minimize=False)

        crys = crystal_params.crystal

        num_mols = get_num_mols(snap)
        mol_positions = crystal_params.molecule.get_relative_positions()
        positions = np.concatenate([
            pos + rowan.rotate(orient, mol_positions)
            for pos, orient in zip(crys.positions, crys.get_orientations())
        ])
        box = np.array([snap.box.Lx, snap.box.Ly, snap.box.Lz])
        if crys.molecule.rigid:
            sim_pos = snap.particles.position[num_mols:] % box
        else:
            sim_pos = snap.particles.position % box
        init_pos = positions % box
        assert_allclose(sim_pos, init_pos)
Пример #11
0
    def f(self, s, a):
        # input:
        # 	s, nd array, (n,)
        # 	a, nd array, (m,1)
        # output
        # 	dsdt, nd array, (n,1)

        dsdt = np.zeros(self.n)
        q = s[6:10]
        omega = s[10:]

        # get input
        a = np.reshape(a, (self.m, ))
        eta = np.dot(self.B0, a)
        f_u = np.array([0, 0, eta[0]])
        tau_u = np.array([eta[1], eta[2], eta[3]])

        # dynamics
        # dot{p} = v
        dsdt[0:3] = s[3:6]
        # mv = mg + R f_u
        dsdt[3:6] = self.g + rowan.rotate(q, f_u) / self.mass

        # dot{R} = R S(w)
        # to integrate the dynamics, see
        # https://www.ashwinnarayan.com/post/how-to-integrate-quaternions/, and
        # https://arxiv.org/pdf/1604.08139.pdf
        qnew = rowan.calculus.integrate(q, omega, self.ave_dt)
        qnew = rowan.normalize(qnew)
        if qnew[0] < 0:
            qnew = -qnew
        # transform qnew to a "delta q" that works with the usual euler integration
        dsdt[6:10] = (qnew - q) / self.ave_dt

        # mJ = Jw x w + tau_u
        dsdt[10:] = self.inv_J * (np.cross(self.J * omega, omega) + tau_u)
        return dsdt.reshape((len(dsdt), 1))
Пример #12
0
    def render(self, rotation=(1, 0, 0, 0), **kwargs):
        positions = rowan.rotate(rotation, self.positions)
        orientations = rowan.multiply(rotation,
                                      rowan.normalize(self.orientations))
        rotations = np.degrees(rowan.to_euler(orientations))

        lines = []
        for (pos, rot, col, alpha) in zip(positions, rotations,
                                          self.colors[:, :3],
                                          1 - self.colors[:, 3]):
            lines.append(
                'sphere {{ '
                '0, 1 scale<{a}, {b}, {c}> '
                'rotate <{rot[2]}, {rot[1]}, {rot[0]}> '
                'translate <{pos[0]}, {pos[1]}, {pos[2]}> '
                'pigment {{ color <{col[0]}, {col[1]}, {col[2]}> transmit {alpha} }} '
                '}}'.format(a=self.a,
                            b=self.b,
                            c=self.c,
                            pos=pos,
                            rot=rot,
                            col=col,
                            alpha=alpha))
        return lines
Пример #13
0
 def test_single_quaternion(self):
     """Testing trivial rotations"""
     self.assertTrue(np.all(rowan.rotate(one, one_vector) == one_vector))
Пример #14
0
def initialize(job):
    import hoomd
    import hoomd.hpmc
    import scipy.spatial
    """Sets up the system and sets default values for writers and stuf

    """
    # get sp params
    f = job.sp.patch_offset
    n_e = job.sp.n_edges
    n_ge = job.sp.n_guest_edges
    gar = job.sp.guest_aspect_ratio
    host_guest_area_ratio = job.sp.host_guest_area_ratio
    n_repeats = job.sp.n_repeats
    seed = job.sp.replica

    # initialize the hoomd context
    msg_fn = job.fn('init-hoomd.log')
    hoomd.context.initialize('--mode=cpu --msg-file={}'.format(msg_fn))

    # figure out shape vertices and patch locations
    xs = np.array([np.cos(n * 2 * np.pi / n_e) for n in range(n_e)])
    ys = np.array([np.sin(n * 2 * np.pi / n_e) for n in range(n_e)])
    zs = np.zeros_like(ys)
    vertices = np.vstack((xs, ys, zs)).T
    A_particle = scipy.spatial.ConvexHull(vertices[:, :2]).volume
    vertices = vertices - np.mean(vertices, axis=0)
    vertex_vertex_vectors = np.roll(vertices, -1, axis=0) - vertices
    half_edge_locations = vertices + 0.5 * vertex_vertex_vectors
    patch_locations = half_edge_locations + f * (vertices -
                                                 half_edge_locations)

    # make the guest particles
    xs = np.array([np.cos(n * 2 * np.pi / n_ge) for n in range(n_ge)])
    ys = np.array([np.sin(n * 2 * np.pi / n_ge) for n in range(n_ge)])
    zs = np.zeros_like(ys)
    guest_vertices = np.vstack((xs, ys, zs)).T
    rot_quat = rowan.from_axis_angle([0, 0, 1], 2 * np.pi / n_ge / 2)
    guest_vertices = rowan.rotate(rot_quat, guest_vertices)
    guest_vertices[:, 0] *= gar
    target_guest_area = A_particle * host_guest_area_ratio
    current_guest_area = scipy.spatial.ConvexHull(guest_vertices[:, :2]).volume
    guest_vertices *= np.sqrt(target_guest_area / current_guest_area)

    # save everything into the job doc that we need to
    if hoomd.comm.get_rank() == 0:
        job.doc.vertices = vertices
        job.doc.patch_locations = patch_locations
        job.doc.A_particle = A_particle
        job.doc.guest_vertices = guest_vertices
    hoomd.comm.barrier()

    # build the system
    if job.sp.initial_config in ('open', 's3'):
        uc = job._project.s3_unitcell(job.sp.patch_offset)
        system = hoomd.init.create_lattice(uc, n_repeats)
    else:
        raise NotImplementedError('Initialization not implemented.')

    # restart writer; period=None since we'll just call write_restart() at end
    restart_writer = hoomd.dump.gsd(filename=job.fn('restart.gsd'),
                                    group=hoomd.group.all(),
                                    truncate=True,
                                    period=None,
                                    phase=0)

    # set up the integrator with the shape info
    mc = hoomd.hpmc.integrate.convex_polygon(seed=seed, d=0, a=0)
    mc.shape_param.set('A', vertices=vertices[:, :2])
    total_particle_area = len(system.particles) * A_particle
    phi = total_particle_area / system.box.get_volume()
    sf = np.sqrt(phi / job.sp.phi)
    hoomd.update.box_resize(
        Lx=system.box.Lx * sf,
        Ly=system.box.Ly * sf,
        period=None,
    )
    restart_writer.dump_shape(mc)
    restart_writer.dump_state(mc)
    mc.set_params(d=0.1, a=0.5)

    # save everything into the job doc that we need to
    if hoomd.comm.get_rank() == 0:
        job.doc.mc_d = {x: 0.05 for x in system.particles.types}
        job.doc.mc_a = {x: 0.1 for x in system.particles.types}
        job.doc.vertices = vertices
        job.doc.patch_locations = patch_locations
        job.doc.A_particle = A_particle
        for k, v in job._project.required_defaults:
            job.doc.setdefault(k, v)
        os.system('cp {} {}'.format(job.fn('restart.gsd'), job.fn('init.gsd')))
    hoomd.comm.barrier()
    restart_writer.write_restart()
    if hoomd.comm.get_rank() == 0:
        os.system('cp {} {}'.format(job.fn('restart.gsd'), job.fn('init.gsd')))
    hoomd.comm.barrier()
    return
Пример #15
0
    (3, [0, 0, 1]),
    (-3, [0, 0, 1]),
    (2, [1, 0, 0]),
    (2, [np.cos(np.pi / 3), np.sin(np.pi / 3), 0]),
    (2, [-np.cos(np.pi / 3), np.sin(np.pi / 3), 0]),
]

# http://www-history.mcs.st-and.ac.uk/~john/geometry/Lectures/L10.html
# Generated by hand
# Some variables to clean up the icosohedral group
icodi = np.pi - np.arctan(2)  # the dihedral angle
picodi = -np.pi / 2 + np.arctan(2)  # pi/2 - the dihedral angle
# a face vector that will be used a lot
face1 = [np.cos(picodi), 0, -np.sin(picodi)]
# the vector to the crown edges
lat_edge = rowan.rotate(
    rowan.from_axis_angle(axes=[0, 1, 0], angles=icodi / 2), [0, 0, 1])
# the vector to the mid-latitude edges
crown_edge = rowan.rotate(
    rowan.from_axis_angle(axes=face1, angles=2 * 2 * np.pi / 5), lat_edge)
crown_vert = [-0.850651, 0.0, 1.11352]  # A vertex in the top pentagon
equi_vert = rowan.rotate(
    rowan.from_axis_angle(axes=face1, angles=1 * 2 * np.pi / 5), crown_vert)

icosohedral = [
    (1, [1, 0, 0]),
    # first face pair
    (5, [0, 0, 1]),
    (5 / 2, [0, 0, 1]),
    (5 / 3, [0, 0, 1]),
    (5 / 4, [0, 0, 1]),
    # second face pair
Пример #16
0
    def update_arrays(self):
        if not self._dirty_attributes:
            return

        # TODO make number of facets a configurable attribute
        thetas = np.linspace(0, 2 * np.pi, 10, endpoint=False)

        # to begin, pretend we are constructing a unit circle in the
        # xy plane; multiply xy by each line radius and z by each line
        # length before rotating and translating appropriately
        image = np.array(
            [np.cos(thetas),
             np.sin(thetas),
             np.zeros_like(thetas)]).T
        image = np.concatenate([image, image + (0, 0, 1)], axis=0)

        # indices to make all triangles for a given Line object
        image_indices = np.tile(
            np.arange(2 * len(thetas))[:, np.newaxis], (1, 3))
        image_indices[:len(thetas), 1] += 1
        image_indices[:len(thetas), 2] += len(thetas)
        image_indices[len(thetas):, 1] += 1 - len(thetas)
        image_indices[len(thetas):, 2] += 1
        image_indices[len(thetas) - 1, 1] -= len(thetas)
        image_indices[-1, 1:] -= len(thetas)

        cap_indices = np.array(
            list(
                geometry.fanTriangleIndices(
                    np.arange(len(thetas))[np.newaxis])))
        image_indices = np.concatenate(
            [image_indices, cap_indices[:, ::-1],
             len(thetas) + cap_indices],
            axis=0)

        # normal vectors for each Line segment
        normals = self.end_points - self.start_points
        lengths = np.linalg.norm(normals, axis=-1, keepdims=True)
        normals /= lengths

        # find quaternion to rotate (0, 0, 1) into the direction each
        # Line is pointing
        quats = rowan.vector_vector_rotation(
            np.array([0, 0, 1.])[np.newaxis, :], normals)

        # Nlines*Nvertices*3
        vertices = np.tile(image[np.newaxis], (len(quats), 1, 1))
        # set xy according to line width
        vertices[:, :, :2] *= self.widths[:, np.newaxis, np.newaxis] * 0.5
        # set z according to line length
        vertices[:, :, 2] *= lengths[:, np.newaxis, 0]
        # rotate appropriately
        vertices = rowan.rotate(quats[:, np.newaxis], vertices)
        # translation by start_points will happen in _finalize_primitive_arrays

        # these are incorrect normals, but this looks to be the most
        # straightforward way to have the normals get serialized
        normals = vertices - self.start_points[:, np.newaxis]

        colors = np.tile(self.colors[:, np.newaxis], (1, len(image), 1))

        positions = np.tile(self.start_points[:, np.newaxis],
                            (1, len(image), 1))

        self._finalize_primitive_arrays(positions, None, colors, vertices,
                                        normals, image_indices)
Пример #17
0
    def write(self, trajectory, file=sys.stdout):
        """Serialize a trajectory into pos-format and write it to file.

        :param trajectory: The trajectory to serialize
        :type trajectory: :class:`~garnett.trajectory.Trajectory`
        :param file: A file-like object."""
        def _write(msg, end='\n'):
            file.write(msg + end)

        for i, frame in enumerate(trajectory):
            # data section
            if frame.data is not None:
                header_keys = frame.data_keys
                _write('#[data] ', end='')
                _write(' '.join(header_keys))
                columns = list()
                for key in header_keys:
                    columns.append(frame.data[key])
                rows = np.array(columns).transpose()
                for row in rows:
                    _write(' '.join(row))
                _write('#[done]')

            # boxMatrix and rotation
            box_matrix = np.array(frame.box.get_box_matrix())
            if self._rotate and frame.view_rotation is not None:
                for i in range(3):
                    box_matrix[:, i] = rowan.rotate(frame.view_rotation,
                                                    box_matrix[:, i])

            if frame.view_rotation is not None and not self._rotate:
                angles = rowan.to_euler(frame.view_rotation,
                                        axis_type='extrinsic',
                                        convention='xyz') * 180 / math.pi
                _write('rotation ' + ' '.join((str(_num(_)) for _ in angles)))

            _write('boxMatrix ', end='')
            _write(' '.join((str(_num(v)) for v in box_matrix.flatten())))

            # shape defs
            try:
                if len(frame.types) != len(frame.type_shapes):
                    raise ValueError(
                        "Unequal number of types and type_shapes.")
                for name, type_shape in zip(frame.types, frame.type_shapes):
                    _write('def {} "{}"'.format(name, type_shape.pos_string))
            except AttributeError:
                # If AttributeError is raised because the frame does not contain
                # shape information, fill them all with the default shape
                for name in frame.types:
                    logger.info("No shape defined for '{}'. "
                                "Using fallback definition.".format(name))
                    _write('def {} "{}"'.format(
                        name, DEFAULT_SHAPE_DEFINITION.pos_string))

            # Orientations must be provided for all particles
            # If the frame does not have orientations, identity quaternions are used
            orientation = getattr(frame, 'orientation',
                                  np.array([[1, 0, 0, 0]] * frame.N))

            for typeid, pos, rot in zip(frame.typeid, frame.position,
                                        orientation):
                name = frame.types[typeid]
                _write(name, end=' ')
                try:
                    shapedef = frame.shapedef.get(name)
                except AttributeError:
                    shapedef = DEFAULT_SHAPE_DEFINITION

                if self._rotate and frame.view_rotation is not None:
                    pos = rowan.rotate(frame.view_rotation, pos)
                    rot = rowan.multiply(frame.view_rotation, rot)

                if isinstance(shapedef, SphereShape):
                    _write(' '.join((str(_num(v)) for v in pos)))
                elif isinstance(shapedef, ArrowShape):
                    # The arrow shape actually has two position vectors of
                    # three elements since it has start.{x,y,z} and end.{x,y,z}.
                    # That is, "rot" is not an accurate variable name, since it
                    # does not represent a quaternion.
                    _write(' '.join(
                        (str(_num(v)) for v in chain(pos, rot[:3]))))
                else:
                    _write(' '.join((str(_num(v)) for v in chain(pos, rot))))
            _write('eof')
            logger.debug("Wrote frame {}.".format(i + 1))
        logger.info("Wrote {} frames.".format(i + 1))
Пример #18
0
 def translation(self, value):
     controls = self._backend_objects['controls']
     value = np.asarray(value) - (0, 0, self.z_offset)
     value = rowan.rotate(rowan.conjugate(self.rotation), value)
     controls.target = (-value).tolist()
     controls.exec_three_obj_method('update')
Пример #19
0
 def check_rotation_invariance(quat):
     rotated_poly = ConvexPolyhedron(rowan.rotate(quat, poly.vertices))
     assert sphere_isclose(poly_insphere, rotated_poly.insphere, atol=1e-4)
Пример #20
0
def quatrot(q, v):
    """Rotates the given vector array v by the quaternions in the array
    q"""
    return rowan.rotate(q, v)
Пример #21
0
    def test_orientation_with_query_points(self):
        """The orientations should be associated with the query points if they
        are provided."""
        L = 8
        box = freud.box.Box.cube(L)
        # Don't place the points at exactly distances of 0/1 apart to avoid any
        # ambiguity when the distances fall on the bin boundaries.
        points = np.array([[0.1, 0.1, 0]], dtype=np.float32)
        points2 = np.array([[1, 0, 0]], dtype=np.float32)
        angles = np.array([np.deg2rad(0)] * points2.shape[0], dtype=np.float32)
        quats = rowan.from_axis_angle([0, 0, 1], angles)

        max_width = 3
        cells_per_unit_length = 4
        nbins = max_width * cells_per_unit_length
        pmft = freud.pmft.PMFTXYZ(max_width, max_width, max_width, nbins)

        # In this case, the only nonzero bin should be in the bin corresponding
        # to dx=-0.9, dy=0.1, which is (4, 6).
        pmft.compute(
            (box, points),
            quats,
            points2,
            neighbors={
                "mode": "nearest",
                "num_neighbors": 1
            },
        )
        npt.assert_array_equal(
            np.asarray(np.where(pmft.bin_counts)).squeeze(), (4, 6, 6))

        # Now the sets of points are swapped, so dx=0.9, dy=-0.1, which is
        # (7, 5).
        pmft.compute(
            (box, points2),
            quats,
            points,
            neighbors={
                "mode": "nearest",
                "num_neighbors": 1
            },
        )
        npt.assert_array_equal(
            np.asarray(np.where(pmft.bin_counts)).squeeze(), (7, 5, 6))

        # Apply a rotation to whichever point is provided as a query_point by
        # 45 degrees (easiest to picture if you think of each point as a
        # square).
        angles = np.array([np.deg2rad(45)] * points2.shape[0],
                          dtype=np.float32)
        quats = rowan.from_axis_angle([0, 0, 1], angles)

        # Determine the relative position of the point when points2 is rotated
        # by 45 degrees. Since we're undoing the orientation of the orientation
        # of the particle, we have to conjugate the quaternion.
        bond_vector = rowan.rotate(rowan.conjugate(quats), points - points2)
        bins = ((bond_vector + max_width) * cells_per_unit_length /
                2).astype(int)

        pmft.compute(
            (box, points),
            quats,
            points2,
            neighbors={
                "mode": "nearest",
                "num_neighbors": 1
            },
        )
        npt.assert_array_equal(
            np.asarray(np.where(pmft.bin_counts)).squeeze(), bins.squeeze())

        # If we swap the order of the points, the angle should no longer
        # matter.
        bond_vector = rowan.rotate(rowan.conjugate(quats), points2 - points)
        bins = ((bond_vector + max_width) * cells_per_unit_length /
                2).astype(int)

        pmft.compute(
            (box, points2),
            quats,
            points,
            neighbors={
                "mode": "nearest",
                "num_neighbors": 1
            },
        )
        npt.assert_array_equal(
            np.asarray(np.where(pmft.bin_counts)).squeeze(), bins.squeeze())
Пример #22
0
def calculateNematicAndPlot(orientations,points,clusterOrient,latent, name):
	# To show orientations, we use arrows rotated by the quaternions.
	arrowheads = rowan.rotate(orientations, [1, 0, 0])

	(a,b,c)=(np.min(points[:,0]), np.min(points[:,1]), np.min(points[:,2]))
	(x,y,z)=(np.max(points[:,0]), np.max(points[:,1]), np.max(points[:,2]))

	boxSize=(x-a)*(y-b)*(z-c)
	ls=boxSize**(1/3.0)
	
	fig = plt.figure(figsize=(8,4))

	ax = fig.add_subplot(121, projection='3d')

	ax.plot(centroids[:,0],centroids[:,1],centroids[:,2],'k.',ms=0.5)
	ax.plot(points[:,0],points[:,1],points[:,2],'b.')
	ax.set_xlabel('X')
	ax.set_ylabel('Y')
	ax.set_zlabel('Z')
	ax.view_init(elev=105., azim=165)

	ax = fig.add_subplot(122, projection='3d')
	factor=1
	ax.quiver3D(points[:, 0], points[:, 1], points[:, 2],
		    factor*arrowheads[:, 0], factor*arrowheads[:, 1], factor*arrowheads[:, 2],length=ls/5.0, arrow_length_ratio=0.4, color='b', lw=1)
	

	nop = freud.order.Nematic([1, 0, 0])
	nop.compute(orientations)
	#print("The value of the order parameter is {}.".format(nop.order))

	center=np.mean(points,axis=0)

	'''
	eig = np.linalg.eig(nop.nematic_tensor)
	rotation=R.from_dcm(eig[1])
	arrowheads = rowan.rotate(rotation.as_quat(), [1, 0, 0])
	
	#ax.quiver3D(center[0], center[1], center[2],arrowheads[0], arrowheads[1], arrowheads[2],length=20, color='k', lw=2)
	print(name,  np.max(eig[0]),eig[1], rotation.as_dcm())
	'''

	'''
	arrowheads = rowan.rotate(clusterOrient[[0,1,2,3]], [1, 0, 0])
	factor=ls/50.0
	latent=[12,6,3]
	ax.quiver3D(center[0], center[1], center[2],arrowheads[0], arrowheads[1], arrowheads[2],length=latent[0]*factor, color='b', lw=1)
	ax.quiver3D(center[0], center[1], center[2],-arrowheads[0], -arrowheads[1], -arrowheads[2],length=latent[0]*factor, color='b', lw=1)

	arrowheads = rowan.rotate(clusterOrient[[4,5,6,7]], [1, 0, 0])
	ax.quiver3D(center[0], center[1], center[2],arrowheads[0], arrowheads[1], arrowheads[2],length=latent[1]*factor, color='m', lw=1)
	ax.quiver3D(center[0], center[1], center[2],-arrowheads[0], -arrowheads[1], -arrowheads[2],length=latent[1], color='m', lw=1)

	arrowheads = rowan.rotate(clusterOrient[[8,9,10,11]], [1, 0, 0])
	ax.quiver3D(center[0], center[1], center[2],arrowheads[0], arrowheads[1], arrowheads[2],length=latent[2]*factor, color='k', lw=1)
	ax.quiver3D(center[0], center[1], center[2],-arrowheads[0], -arrowheads[1], -arrowheads[2],length=latent[2]*factor, color='k', lw=1)
	'''

	t=' ['
	t1=[]
	axes = [[1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 0], [1, 0, 1], [0, 1, 1], [1, 1, 1]]
	for ax1 in axes:
	    nop = freud.order.Nematic(ax1)
	    nop.compute(orientations)
	    #print("For axis {}, the value of the order parameter is {:0.3f}.".format(ax1, nop.order))
	    t=t+' %0.2f,'%nop.order	
	    t1.append(nop.order)	 	    	
	t=t[0:-1]+']'	
	fig.suptitle("Cluster "+str(name)+''+'', fontsize=16);
	ax.set_xlabel('X')
	ax.set_ylabel('Y')
	ax.set_zlabel('Z')

	ax.view_init(elev=105., azim=165)
	plt.savefig('Nematic/cluster'+str(name)+'.png')
	#plt.show()
	plt.close()
	return t1
    def f(self, X, Z, A, t, logentry=None):
        # x = X[0]
        # y = X[1]
        # z = X[2]
        # xdot = X[3]
        # ydot = X[4]
        # zdot = X[5]
        # qw = X[6]
        # qx = X[7]
        # qy = X[8]
        # qz = X[9]
        # wx = X[10]
        # wy = X[11]
        # wz = X[12]
        a = Z**2
        # a = A
        J = self.J
        dxdt = np.zeros(13)
        q = X[6:10]
        q = rowan.normalize(q)
        omega = X[10:]
        B0 = self.B0 * self.params['C_T']
        # B0 = self.B0
        eta = np.dot(B0, a)
        f_u = np.array([0, 0, eta[0]])
        tau_u = np.array([eta[1], eta[2], eta[3]])

        dxdt[0:3] = X[3:6]
        # dxdt[3:6] = -9.81 + rowan.rotate(q, f_u) / self.params['m']
        dxdt[3:6] = np.array([0., 0., -9.81
                              ]) + rowan.rotate(q, f_u) / self.params['m']
        Vinf = self.params['Vwind_mean'] - np.linalg.norm(X[3:6])
        Vinf_B = rowan.rotate(rowan.inverse(q), Vinf)
        Vz_B = np.array([0.0, 0.0, Vinf_B[2]])
        Vs_B = Vinf_B - Vz_B
        alpha = np.arcsin(np.linalg.norm(Vz_B) / np.linalg.norm(Vinf_B))
        n = np.sqrt(
            np.multiply(a, self.B0[0, :]) /
            (self.params['C_T'] * self.params['rho'] * self.params['D']**4))
        Fs_B = (Vs_B / np.linalg.norm(Vs_B)
                ) * self.params['C_s'] * self.params['rho'] * sum(
                    n**self.params['k1']) * (np.linalg.norm(Vinf)**(
                        2 - self.params['k1'])) * (self.params['D']**(
                            2 + self.params['k1'])) * (
                                (np.pi / 2)**2 -
                                alpha**2) * (alpha + self.params['k2'])
        # Fs_B = [0,0,0]
        dxdt[3:6] += rowan.rotate(q, Fs_B) / self.mass
        qnew = rowan.calculus.integrate(q, omega, self.ave_dt)
        if qnew[0] < 0:
            qnew = -qnew

        dxdt[6:10] = (qnew - q) / self.ave_dt
        dxdt[10:] = 1 / J * (np.cross(J * omega, omega) + tau_u)
        dxdt[10:] += 1 / J * np.cross(
            np.array([0.0, 0.0, self.params['D'] / 4]), Fs_B)
        euler_o = rowan.to_euler(q, 'xyz')
        if logentry is not None:
            logentry['f_u'] = f_u
            logentry['tau'] = tau_u
            logentry['euler_o'] = euler_o

        return dxdt.reshape((len(dxdt), 1))
Пример #24
0
    def render(self):
        """Render this Scene object."""
        # Remove existing fresnel geometries from the scene
        for geometry in self._geometries:
            geometry.remove()

        # Clear the list of fresnel geometries
        self._geometries = []

        # Add fresnel scene geometries from plato scene primitives
        for prim in self._primitives:
            geometry = prim.render(self._fresnel_scene)
            self._geometries.append(geometry)

        # Set up the camera
        camera_up = rowan.rotate(rowan.conjugate(self.rotation), [0, 1, 0])
        camera_position = rowan.rotate(rowan.conjugate(self.rotation), -self.translation)
        camera_look_at = camera_position + rowan.rotate(rowan.conjugate(self.rotation), [0, 0, -1])
        camera_height = self.size[1]/self.zoom
        try:
            orthographic_camera = fresnel.camera.Orthographic
        except AttributeError:
            # Support fresnel < 0.13.0
            orthographic_camera = fresnel.camera.orthographic
        self._fresnel_scene.camera = orthographic_camera(
            position=camera_position,
            look_at=camera_look_at,
            up=camera_up,
            height=camera_height)

        # Set up lights
        lights = []
        if 'ambient_light' in self.enabled_features:
            config = self.get_feature_config('ambient_light')
            magnitude = config.get('value', 0.25)
            if magnitude > 0:
                lights.append(fresnel.light.Light(direction=(0, 0, 1),
                                                  color=(magnitude, magnitude, magnitude),
                                                  theta=np.pi))
        if 'directional_light' in self.enabled_features:
            config = self.get_feature_config('directional_light')
            directions = config.get('value', (.25, .5, -1))
            directions = np.atleast_2d(directions).astype(np.float32)
            for direction in directions:
                magnitude = np.linalg.norm(direction)
                if magnitude > 0:
                    lights.append(fresnel.light.Light(direction=-direction,
                                                      color=(magnitude, magnitude, magnitude),
                                                      theta=0.7))
        if len(lights) > 0:
            self._fresnel_scene.lights = lights

        # Set up tracer
        if 'pathtracer' in self.enabled_features:
            # Use path tracer if enabled
            config = self.get_feature_config('pathtracer')
            tracer = self._path_tracer
            samples = config.get('samples', 64)
            def render_function(scene, **kwargs):
                return tracer.sample(scene, samples, **kwargs)
        else:
            # Use preview tracer by default
            tracer = self._preview_tracer
            tracer.anti_alias = 'antialiasing' in self.enabled_features
            render_function = tracer.render

        self._output = render_function(self._fresnel_scene)
Пример #25
0
 def translation(self):
     controls = self._backend_objects['controls']
     translation = -np.array(controls.target)
     translation = rowan.rotate(self.rotation, translation)
     translation[2] += self.z_offset
     return translation
Пример #26
0
 def check_position(central_position, central_orientation,
                    constituent_position, local_position):
     d_pos = rowan.rotate(central_orientation, local_position)
     assert np.allclose(central_position + d_pos, constituent_position)
Пример #27
0
    def test_zero_beta(self):
        """Check cases where beta is 0."""
        # Since the Euler calculations are all done using matrices, it's easier
        # to construct the test cases by directly using matrices as well. We
        # assume gamma is 0 since, due to gimbal lock, only either alpha+gamma
        # or alpha-gamma is a relevant parameter, and we just scan the other
        # possible values. The actual function is defined such that gamma will
        # always be zero in those cases. We define the matrices using lambda
        # functions to support sweeping a range of values for alpha and beta,
        # specifically to test cases where signs flip e.g. cos(0) vs cos(pi).
        # These sign flips lead to changes in the rotation angles that must be
        # tested.
        mats_euler_intrinsic = [
            ('xzx', 'intrinsic', lambda alpha, beta:
             [[np.cos(beta), 0, 0],
              [0, np.cos(beta) * np.cos(alpha), -np.sin(alpha)],
              [0, np.cos(beta) * np.sin(alpha),
               np.cos(alpha)]]),
            ('xyx', 'intrinsic', lambda alpha, beta:
             [[np.cos(beta), 0, 0],
              [0, np.cos(alpha), -np.cos(beta) * np.sin(alpha)],
              [0, np.sin(alpha),
               np.cos(beta) * np.cos(alpha)]]),
            ('yxy', 'intrinsic', lambda alpha, beta:
             [[np.cos(alpha), 0,
               np.cos(beta) * np.sin(alpha)], [0, np.cos(beta), 0],
              [-np.sin(alpha), 0,
               np.cos(beta) * np.cos(alpha)]]),
            ('yzy', 'intrinsic', lambda alpha, beta:
             [[np.cos(beta) * np.cos(alpha), 0,
               np.sin(alpha)], [0, np.cos(beta), 0],
              [-np.cos(beta) * np.sin(alpha), 0,
               np.cos(alpha)]]),
            ('zyz', 'intrinsic', lambda alpha, beta: [[
                np.cos(beta) * np.cos(alpha), -np.sin(alpha), 0
            ], [np.cos(beta) * np.sin(alpha),
                np.cos(beta), 0], [0, 0, np.cos(beta)]]),
            ('zxz', 'intrinsic', lambda alpha, beta:
             [[np.cos(alpha), -np.cos(beta) * np.sin(alpha), 0],
              [np.sin(alpha), np.cos(beta) * np.cos(beta), 0],
              [0, 0, np.cos(beta)]]),
        ]

        mats_tb_intrinsic = [
            ('xzy', 'intrinsic', lambda alpha, beta: [[0, -np.sin(
                beta), 0], [np.sin(beta) * np.cos(alpha), 0, -np.sin(
                    alpha)], [np.sin(beta) * np.sin(alpha), 0,
                              np.cos(alpha)]]),
            ('xyz', 'intrinsic',
             lambda alpha, beta: [[0, 0, np.sin(
                 beta)], [np.sin(beta) * np.sin(alpha),
                          np.cos(alpha), 0
                          ], [-np.sin(beta) * np.cos(alpha),
                              np.sin(alpha), 0]]),
            ('yxz', 'intrinsic', lambda alpha, beta:
             [[np.cos(alpha), np.sin(beta) * np.sin(alpha), 0],
              [0, 0, -np.sin(beta)],
              [-np.sin(alpha), np.sin(beta) * np.cos(alpha), 0]]),
            ('yzx', 'intrinsic', lambda alpha, beta:
             [[0, -np.sin(beta) * np.cos(alpha),
               np.sin(alpha)], [np.sin(beta), 0, 0],
              [0, np.sin(beta) * np.sin(alpha),
               np.cos(alpha)]]),
            ('zyx', 'intrinsic', lambda alpha, beta: [[
                0, -np.sin(alpha),
                np.sin(beta) * np.cos(alpha)
            ], [0, np.cos(alpha),
                np.sin(beta) * np.sin(alpha)], [-np.sin(beta), 0, 0]]),
            ('zxy', 'intrinsic', lambda alpha, beta: [[
                np.cos(alpha), 0,
                np.sin(beta) * np.sin(alpha)
            ], [np.sin(alpha), 0, -np.sin(beta) * np.cos(alpha)], [0, -1, 0]]),
        ]

        # Extrinsic rotations can be tested identically to intrinsic rotations
        # in the case of proper Euler angles.
        mats_euler_extrinsic = [(m[0], 'extrinsic', m[2])
                                for m in mats_euler_intrinsic]

        # For Tait-Bryan angles, extrinsic rotations axis order must be
        # reversed (since axes 1 and 3 are not identical), but more
        # importantly, due to the sum/difference of alpha and gamma that
        # arises, we need to test the negative of alpha to catch the dangerous
        # cases. In practice we get the same results since we're sweeping alpha
        # values in the tests below, but it's useful to set this up precisely.
        mats_tb_extrinsic = [(m[0][::-1], 'extrinsic', lambda alpha, beta: m[2]
                              (-alpha, beta)) for m in mats_tb_intrinsic]

        # Since angle representations may not be unique, checking that
        # quaternions are equal may not work. Instead we perform rotations and
        # check that they are identical.  For simplicity, we rotate the
        # simplest vector with all 3 components (otherwise tests won't catch
        # the problem because there's no component to rotate).
        test_vector = [1, 1, 1]

        mats_intrinsic = (mats_euler_intrinsic, mats_tb_intrinsic)
        mats_extrinsic = (mats_euler_extrinsic, mats_tb_extrinsic)

        # The beta angles are different for proper Euler angles and Tait-Bryan
        # angles because the relevant beta terms will be sines and cosines,
        # respectively.
        all_betas = ((0, np.pi), (np.pi / 2, -np.pi / 2))
        alphas = (0, np.pi / 2, np.pi, 3 * np.pi / 2)

        for mats in (mats_intrinsic, mats_extrinsic):
            for betas, mat_set in zip(all_betas, mats):
                for convention, axis_type, mat_func in mat_set:
                    quaternions = []
                    for beta in betas:
                        for alpha in alphas:
                            mat = mat_func(alpha, beta)
                            if np.linalg.det(mat) == -1:
                                # Some of these will be improper rotations.
                                continue
                            quat = rowan.from_matrix(mat)
                            quaternions.append(quat)
                            euler = rowan.to_euler(quat, convention, axis_type)
                            converted = rowan.from_euler(*euler,
                                                         convention=convention,
                                                         axis_type=axis_type)
                            correct_rotation = rowan.rotate(quat, test_vector)
                            test_rotation = rowan.rotate(
                                converted, test_vector)
                            self.assertTrue(np.allclose(correct_rotation,
                                                        test_rotation,
                                                        atol=1e-6),
                                            msg="""
                                       Failed for convention {},
                                       axis type {},
                                       alpha = {},
                                       beta = {}.
                                       Expected quaternion: {}.
                                       Calculated: {}.
                                       Expected vector: {}.
                                       Calculated vector: {}.""".format(
                                                convention, axis_type, alpha,
                                                beta, quat, converted,
                                                correct_rotation,
                                                test_rotation))

                    # For completeness, also test with broadcasting.
                    quaternions = np.asarray(quaternions).reshape(-1, 4)
                    all_euler = rowan.to_euler(quaternions, convention,
                                               axis_type)
                    converted = rowan.from_euler(all_euler[...,
                                                           0], all_euler[...,
                                                                         1],
                                                 all_euler[..., 2], convention,
                                                 axis_type)
                    self.assertTrue(
                        np.allclose(rowan.rotate(quaternions, test_vector),
                                    rowan.rotate(converted, test_vector),
                                    atol=1e-6))
Пример #28
0
def rotate_vectors(quaternion, vector):
    return rowan.rotate(quaternion, vector)
Пример #29
0
    def test_orientation_with_fewer_query_points(self):
        """The orientations should be associated with the query points if they
        are provided. Ensure that this works when the number of points and
        query points differ."""
        L = 8
        box = freud.box.Box.cube(L)
        # Don't place the points at exactly distances of 0/1 apart to avoid any
        # ambiguity when the distances fall on the bin boundaries.
        points = np.array([[0.1, 0.1, 0], [0.89, 0.89, 0]], dtype=np.float32)
        points2 = np.array([[1, 0, 0]], dtype=np.float32)
        angles = np.array([np.deg2rad(0)] * points.shape[0], dtype=np.float32)
        quats = rowan.from_axis_angle([0, 0, 1], angles)
        angles2 = np.array([np.deg2rad(0)] * points2.shape[0],
                           dtype=np.float32)
        quats2 = rowan.from_axis_angle([0, 0, 1], angles2)

        def points_to_set(bin_counts):
            """Extract set of unique occupied bins from pmft bin counts."""
            return set(zip(*np.asarray(np.where(bin_counts)).tolist()))

        max_width = 3
        cells_per_unit_length = 4
        nbins = max_width * cells_per_unit_length
        pmft = freud.pmft.PMFTXYZ(max_width, max_width, max_width, nbins)

        # There should be two nonzero bins:
        #     dx=-0.9, dy=0.1: bin (4, 6).
        #     dx=-0.11, dy=0.89: bin (5, 7).
        pmft.compute(
            (box, points),
            quats2,
            points2,
            neighbors={
                "mode": "nearest",
                "num_neighbors": 2
            },
        )
        npt.assert_array_equal(points_to_set(pmft.bin_counts), {(4, 6, 6),
                                                                (5, 7, 6)})

        # Now the sets of points are swapped, so:
        #     dx=0.9, dy=-0.1: bin (7, 5).
        #     dx=0.11, dy=-0.89: bin (6, 4).
        pmft.compute(
            (box, points2),
            quats,
            points,
            neighbors={
                "mode": "nearest",
                "num_neighbors": 2
            },
        )
        npt.assert_array_equal(points_to_set(pmft.bin_counts), {(7, 5, 6),
                                                                (6, 4, 6)})

        # Apply a rotation to whichever point is provided as a query_point by
        # 45 degrees (easiest to picture if you think of each point as a
        # square).
        angles2 = np.array([np.deg2rad(45)] * points2.shape[0],
                           dtype=np.float32)
        quats2 = rowan.from_axis_angle([0, 0, 1], angles2)

        # Determine the relative position of the point when points2 is rotated
        # by 45 degrees. Since we're undoing the orientation of the orientation
        # of the particle, we have to conjugate the quaternion.
        bond_vector = rowan.rotate(rowan.conjugate(quats2), points - points2)
        bins = ((bond_vector + max_width) * cells_per_unit_length /
                2).astype(int)
        bins = {tuple(x) for x in bins}

        pmft.compute(
            (box, points),
            quats2,
            points2,
            neighbors={
                "mode": "nearest",
                "num_neighbors": 2
            },
        )
        npt.assert_array_equal(points_to_set(pmft.bin_counts), bins)
Пример #30
0
    def read(self):
        "Read the frame data from the stream."
        self.stream.seek(self.start)
        i = line = None

        def _assert(assertion):
            assert i is not None
            assert line is not None
            if not assertion:
                raise ParserError("Failed to read line #{}: {}.".format(
                    i, line))

        monotype = False
        raw_frame = _RawFrameData()
        raw_frame.view_rotation = None
        for i, line in enumerate(self.stream):
            if _is_comment(line):
                continue
            if line.startswith('#'):
                if line.startswith('#[data]'):
                    _assert(raw_frame.data is None)
                    raw_frame.data_keys, raw_frame.data, j = \
                        self._read_data_section(line, self.stream)
                    i += j
                else:
                    raise ParserError(line)
            else:
                tokens = line.rstrip().split()
                if not tokens:
                    continue  # empty line
                elif tokens[0] in TOKENS_SKIP:
                    continue  # skip these lines
                if tokens[0] == 'eof':
                    logger.debug("Reached end of frame.")
                    break
                elif tokens[0] == 'def':
                    definition, data, end = line.strip().split('"')
                    _assert(len(end) == 0)
                    name = definition.split()[1]
                    type_shape = self._parse_shape_definition(data)
                    if name not in raw_frame.types:
                        raw_frame.types.append(name)
                        raw_frame.type_shapes.append(type_shape)
                    else:
                        typeid = raw_frame.type_shapes.index(name)
                        raw_frame.type_shapes[typeid] = type_shape
                        warnings.warn(
                            "Redefinition of type '{}'.".format(name))
                elif tokens[0] == 'shape':  # monotype
                    data = line.strip().split('"')[1]
                    raw_frame.types.append(self.default_type)
                    type_shape = self._parse_shape_definition(data)
                    raw_frame.type_shapes.append(type_shape)
                    _assert(len(raw_frame.type_shapes) == 1)
                    monotype = True
                elif tokens[0] in ('boxMatrix', 'box'):
                    if len(tokens) == 10:
                        raw_frame.box = np.array(
                            [self._num(v) for v in tokens[1:]]).reshape((3, 3))
                    elif len(tokens) == 4:
                        raw_frame.box = np.array([[self._num(tokens[1]), 0, 0],
                                                  [0,
                                                   self._num(tokens[2]), 0],
                                                  [0, 0,
                                                   self._num(tokens[3])]
                                                  ]).reshape((3, 3))
                elif tokens[0] == 'rotation':
                    euler_angles = np.array([float(t) for t in tokens[1:]])
                    euler_angles *= np.pi / 180
                    raw_frame.view_rotation = rowan.from_euler(
                        *euler_angles, axis_type='extrinsic', convention='xyz')
                else:
                    # assume we are reading positions now
                    if not monotype:
                        name = tokens[0]
                        if name not in raw_frame.types:
                            raw_frame.types.append(name)
                            type_shape = self._parse_shape_definition(' '.join(
                                tokens[:3]))
                            raw_frame.type_shapes.append(type_shape)
                    else:
                        name = self.default_type
                    typeid = raw_frame.types.index(name)
                    type_shape = raw_frame.type_shapes[typeid]
                    if len(tokens) == 7 and isinstance(type_shape, ArrowShape):
                        xyz = tokens[-6:-3]
                        quat = tokens[-3:] + [0]
                    elif len(tokens) >= 7:
                        xyz = tokens[-7:-4]
                        quat = tokens[-4:]
                    elif len(tokens) >= 3:
                        xyz = tokens[-3:]
                        quat = None
                    else:
                        raise ParserError(line)
                    raw_frame.typeid.append(typeid)
                    raw_frame.position.append([self._num(v) for v in xyz])
                    if quat is None:
                        raw_frame.orientation.append(quat)
                    else:
                        raw_frame.orientation.append(
                            [self._num(v) for v in quat])

        # Perform inverse rotation to recover original coordinates
        if raw_frame.view_rotation is not None:
            pos = rowan.rotate(rowan.inverse(raw_frame.view_rotation),
                               raw_frame.position)
        else:
            pos = np.asarray(raw_frame.position)
        # If all the z coordinates are close to zero, set box dimension to 2
        if np.allclose(pos[:, 2], 0.0, atol=1e-7):
            raw_frame.box_dimensions = 2

        # If no valid orientations have been added, the array should be empty
        if all([quat is None for quat in raw_frame.orientation]):
            raw_frame.orientation = []
        else:
            # Replace values of None with an identity quaternion
            for i in range(len(raw_frame.orientation)):
                if raw_frame.orientation[i] is None:
                    raw_frame.orientation[i] = [1, 0, 0, 0]
        return raw_frame