From 2e33077b93ec5a12c2859b2e56cd06f65378e984 Mon Sep 17 00:00:00 2001 From: nguyed99 <nguyed99@zedat.fu-berlin.de> Date: Fri, 8 Mar 2024 22:51:12 +0100 Subject: [PATCH] Add bht+jpl, etc --- .gitignore | 3 +- README.md | 4 +- build/pyproject.toml | 7 +- jobs/src/jpl_data_query.py | 6 + jobs/src/random_perturbations.py | 4 - jobs/src/visualization.py | 35 ----- jobs/tests/test_bht_algorithm_2D.py | 11 ++ jobs/tests/test_integrator.py | 11 ++ jobs/tests/test_jpl_data_query.py | 42 ++++++ pyproject.toml | 2 +- tasks/src/a_task.py | 14 -- tasks/src/direct_simulation.py | 94 ++++++++++--- tasks/src/ff_simulation.py | 189 +++++++++++++++++++++++++- tasks/src/utils.py | 33 +++++ tasks/tests/test_a_task.py | 43 ------ tasks/tests/test_direct_simulation.py | 0 tasks/tests/test_ff_simulation.py | 0 17 files changed, 375 insertions(+), 123 deletions(-) delete mode 100644 jobs/src/random_perturbations.py delete mode 100644 jobs/src/visualization.py delete mode 100644 tasks/src/a_task.py create mode 100644 tasks/src/utils.py delete mode 100644 tasks/tests/test_a_task.py delete mode 100644 tasks/tests/test_direct_simulation.py delete mode 100644 tasks/tests/test_ff_simulation.py diff --git a/.gitignore b/.gitignore index 14fdbc8..af0c7ad 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /__pycache__ -*.pyc \ No newline at end of file +*.pyc +/playground \ No newline at end of file diff --git a/README.md b/README.md index 398e8f9..109c893 100644 --- a/README.md +++ b/README.md @@ -39,11 +39,11 @@ Jobs and tasks are run inside of docker containers. There is a docker build scri The image is built now and ready to be used! The tests in the Docker container built from the image can be sanity-checked via : - docker run -it --rm git.imp.fu-berlin.de:5000/comp-sci-project/jobs-n-tasks:local python jobs/tests/test_a_job.py + docker run -it --rm git.imp.fu-berlin.de:5000/comp-sci-project/jobs-n-tasks:local pytest jobs/tests/test_a_job.py or for testing a task: - docker run -it --rm git.imp.fu-berlin.de:5000/comp-sci-project/jobs-n-tasks:local python tasks/tests/test_a_task.py + docker run -it --rm git.imp.fu-berlin.de:5000/comp-sci-project/jobs-n-tasks:local pytest tasks/tests/test_a_task.py For live experience (meaning you enter the container), run: diff --git a/build/pyproject.toml b/build/pyproject.toml index 31a7120..45a3e87 100644 --- a/build/pyproject.toml +++ b/build/pyproject.toml @@ -6,10 +6,13 @@ authors = [] readme = "README.md" [tool.poetry.dependencies] -python = ">=3.10" -numpy = "~1.24" +python = "3.11.5" +numpy = "1.24.4" matplotlib = "3.8.0" +astropy = "6.0.0" +sunpy = "5.1.1" pytest = "^7.4.4" +astroquery = "^0.4.6" [build-system] requires = ["poetry-core"] diff --git a/jobs/src/jpl_data_query.py b/jobs/src/jpl_data_query.py index 6a2713e..1924a4c 100644 --- a/jobs/src/jpl_data_query.py +++ b/jobs/src/jpl_data_query.py @@ -1,6 +1,12 @@ """ This module contains functions to query and parse JPL Horizons on-line solar system data (see https://ssd-api.jpl.nasa.gov/doc/horizons.html). + +To use, run the following command + + INPUT_PATH = "jobs/inputs/" + r_E, v_E = parse_output(query_data(INPUT_PATH + "earth_ephemeris.txt")) + r_M, v_M = parse_output(query_data(INPUT_PATH + "moon_ephemeris.txt")) """ import re diff --git a/jobs/src/random_perturbations.py b/jobs/src/random_perturbations.py deleted file mode 100644 index c950790..0000000 --- a/jobs/src/random_perturbations.py +++ /dev/null @@ -1,4 +0,0 @@ -""" -This module contains functions to add Gaussian (white) noises -as random small perturbations in the initial configuration. -""" \ No newline at end of file diff --git a/jobs/src/visualization.py b/jobs/src/visualization.py deleted file mode 100644 index 584d31a..0000000 --- a/jobs/src/visualization.py +++ /dev/null @@ -1,35 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - - -def plot_trajectory(traj: np.ndarray, mass: list, update_interval=10): - """ - Args: - - traj: trajectory with shape (no_time_steps, no_bodies * dim) - - mass: masses of bodies - """ - - n_time_step, n_bodies = traj.shape # - n_bodies //= 3 - - fig = plt.figure() - ax = fig.add_subplot(projection='3d') - - for i in range(0, n_time_step, update_interval): - ax.clear() - for j in range(n_bodies): - start_idx = j * 3 - end_idx = (j + 1) * 3 - - body_traj = traj[i, start_idx:end_idx] - ax.scatter(body_traj[0], body_traj[1], body_traj[2], s=10 * mass[j] / min(mass)) - - ax.set_xlabel("X") - ax.set_ylabel("Y") - ax.set_zlabel("Z") - ax.set_title(f"Time step: {i}") - ax.set_xticks([]) - ax.set_yticks([]) - ax.set_zticks([]) - - plt.pause(0.01) diff --git a/jobs/tests/test_bht_algorithm_2D.py b/jobs/tests/test_bht_algorithm_2D.py index 0318849..3ea2ec1 100644 --- a/jobs/tests/test_bht_algorithm_2D.py +++ b/jobs/tests/test_bht_algorithm_2D.py @@ -86,6 +86,17 @@ class IntegratorTest(unittest.TestCase): t, p, q = system.simulation() + ## plotting trajectories + plt.figure() + plt.plot(q[:, 0], q[:, 1], label="Earth") + plt.legend() + plt.show() + + plt.figure() + plt.plot(q[:, 2] - q[:, 0], q[:, 3] - q[:, 1], label="Moon seen from Earth") + plt.legend() + plt.show() + ## checking total energy conservation H = np.linalg.norm(p[:,:2], axis=1)**2 / (2 * M_E) + np.linalg.norm(p[:,2:], axis=1)**2 / (2 * M_L) + \ -G * M_S * M_E / np.linalg.norm(q[:,:2], axis=1) - G * M_S * M_L / np.linalg.norm(q[:,2:], axis=1) + \ diff --git a/jobs/tests/test_integrator.py b/jobs/tests/test_integrator.py index fbd7008..e9bb889 100644 --- a/jobs/tests/test_integrator.py +++ b/jobs/tests/test_integrator.py @@ -75,6 +75,17 @@ class IntegratorTest(unittest.TestCase): t, p, q = system.simulation() + ## plotting trajectories + plt.figure() + plt.plot(q[:, 0], q[:, 1], label="Earth") + plt.legend() + plt.show() + + plt.figure() + plt.plot(q[:, 2] - q[:, 0], q[:, 3] - q[:, 1], label="Moon seen from Earth") + plt.legend() + plt.show() + ## checking total energy conservation H = np.linalg.norm(p[:,:2], axis=1)**2 / (2 * M_E) + np.linalg.norm(p[:,2:], axis=1)**2 / (2 * M_L) + \ -G * M_S * M_E / np.linalg.norm(q[:,:2], axis=1) - G * M_S * M_L / np.linalg.norm(q[:,2:], axis=1) + \ diff --git a/jobs/tests/test_jpl_data_query.py b/jobs/tests/test_jpl_data_query.py index e69de29..5f88417 100644 --- a/jobs/tests/test_jpl_data_query.py +++ b/jobs/tests/test_jpl_data_query.py @@ -0,0 +1,42 @@ +""" +This unittest tests data query from JPL Horizons database +for the restricted three-body (sun-earth-moon) problem. +The sun is fixed at the origin (center of mass). For +simplicity, the moon is assumed to be in the eliptic plane, +so that vectors can be treated as two-dimensional. +The trajectories are plotted in Heliographic Stonyhurst coordinates. +""" + +import unittest + +import matplotlib.pyplot as plt + +import astropy.units as u +from sunpy.coordinates import (get_body_heliographic_stonyhurst, get_horizons_coord) +from sunpy.time import parse_time + +time = parse_time('2024-01-01 00:00') + + +class IntegratorTest(unittest.TestCase): + + def test_data_query(self): + moon = get_horizons_coord('301', {'start': time - 30 * u.day, 'stop': time + 30 * u.day, 'step': '1d'}) + + earth = get_horizons_coord('399', {'start': time - 30 * u.day, 'stop': time + 30 * u.day, 'step': '1d'}) + + sun = get_body_heliographic_stonyhurst('Sun', time) # (lon, lat, radius) in (deg, deg, AU) + + def coord_to_polar(coord): + return coord.lon.to_value('rad'), coord.radius.to_value('AU') + + fig = plt.figure() + ax = fig.add_subplot(projection='polar') + ax.plot(0, 0, 'o', label='Sun', color='orange', markersize=10) + ax.plot(*coord_to_polar(earth.transform_to(sun)), label='Earth', color='blue', linestyle='-.') + + ax.plot(*coord_to_polar(moon.transform_to(sun)), label='Moon', color='purple', linestyle='dashed') + ax.set_title('Stonyhurst heliographic coordinates') + ax.legend(loc='upper left', bbox_to_anchor=(1.0, 0.5)) + + plt.show() diff --git a/pyproject.toml b/pyproject.toml index abf9553..d719911 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = [] readme = "README.md" [tool.poetry.dependencies] -python = "~3.11" +python = "3.11.5" toml = "^0.10.2" [tool.poetry.group.dev.dependencies] diff --git a/tasks/src/a_task.py b/tasks/src/a_task.py deleted file mode 100644 index fa6c160..0000000 --- a/tasks/src/a_task.py +++ /dev/null @@ -1,14 +0,0 @@ -""" -This module implements the SWAP gate using the Pauli gates -""" - -import numpy as np - -from jobs.src.a_job import sigma_x, sigma_y, sigma_z - - -def swap_gate() -> np.ndarray: - - swap_matrix = 1 / 2 * (np.kron(np.identity(2), np.identity(2)) + np.kron(sigma_x(), sigma_x()) + - np.kron(sigma_y(), sigma_y()) + np.kron(sigma_z(), sigma_z())) - return swap_matrix diff --git a/tasks/src/direct_simulation.py b/tasks/src/direct_simulation.py index 2d54a92..88ff8ee 100644 --- a/tasks/src/direct_simulation.py +++ b/tasks/src/direct_simulation.py @@ -1,35 +1,48 @@ """ This module contains functions for a direct simulation -of gravitational n-body system using realistic data for various +of gravitational 2-body system using realistic data for various initial configurations """ -import logging - +import astropy.units as u +import matplotlib.pyplot as plt import numpy as np +from sunpy.coordinates import (get_body_heliographic_stonyhurst, get_horizons_coord) +from sunpy.time import parse_time from jobs.src.integrators import verlet -from jobs.src.jpl_data_query import (parse_output, query_data) from jobs.src.system import GravitationalSystem -from jobs.src.visualization import plot_trajectory - -logger = logging.getLogger(__name__) -logging.basicConfig(level=logging.INFO) - -INPUT_PATH = "jobs/inputs/" - -r_E, v_E = parse_output(query_data(INPUT_PATH + "earth_ephemeris.txt")) -r_M, v_M = parse_output(query_data(INPUT_PATH + "moon_ephemeris.txt")) +from tasks.src.utils import (coord_to_polar, xyz_to_polar) # system settings M_S = 1 # solar mass M_E = 3.00e-6 * M_S M_L = 3.69e-8 * M_S - G = 4 * np.pi**2 # AU^3 / m / yr^2 +# JPL data +time = parse_time('2024-01-01 00:00') + +moon = get_horizons_coord('301', { + 'start': time - 40 * u.day, + 'stop': time + 40 * u.day, + 'step': '1d' +}, + include_velocity=True) + +earth = get_horizons_coord('399', { + 'start': time - 40 * u.day, + 'stop': time + 40 * u.day, + 'step': '1d' +}, + include_velocity=True) + +sun = get_body_heliographic_stonyhurst('Sun', time) # (lon, lat, radius) in (deg, deg, AU) +moon = moon.transform_to(sun) +earth = earth.transform_to(sun) + # simulation settings -T = 0.3 # yr +T = 0.23 # yr n_order = 6 dt = 4**(-n_order) # yr @@ -45,8 +58,18 @@ def force(q: np.ndarray) -> np.ndarray: ]).flatten() -system = GravitationalSystem(r0=np.hstack((r_E[0], r_M[0])), - v0=np.hstack((v_E[0], v_M[0])), +# run direct simulation +moon_0_pos = moon[0].represent_as('cartesian') +earth_0_pos = earth[0].represent_as('cartesian') + +x0 = np.array([ + earth_0_pos.x.value, earth_0_pos.y.value, earth_0_pos.z.value, moon_0_pos.x.value, moon_0_pos.y.value, + moon_0_pos.z.value, earth[0].velocity.d_x.value, earth[0].velocity.d_y.value, earth[0].velocity.d_z.value, + moon[0].velocity.d_x.value, moon[0].velocity.d_y.value, moon[0].velocity.d_z.value +]) + +system = GravitationalSystem(r0=x0[:6], + v0=x0[6:], m=np.array([M_E, M_E, M_E, M_L, M_L, M_L]), t=np.linspace(0, T, int(T // dt)), force=force, @@ -54,4 +77,39 @@ system = GravitationalSystem(r0=np.hstack((r_E[0], r_M[0])), t, p, q = system.simulation() -plot_trajectory(q, mass=[M_E, M_L]) +# plot trajectory in polar coordinates +q_E_polar = np.array([xyz_to_polar(pos[0], pos[1], pos[2]) for pos in q]) +q_M_polar = np.array([xyz_to_polar(pos[3], pos[4], pos[5]) for pos in q]) + +fig = plt.figure() +ax = fig.add_subplot(projection='polar') +ax.plot(0, 0, 'o', label='Sun', color='orange', markersize=10) +ax.plot(q_E_polar[:, 0], q_E_polar[:, 1], label='Earth', color='blue', linestyle='-.') +ax.plot(q_M_polar[:, 0], q_M_polar[:, 1], label='Moon', color='purple', linestyle='dashed') +ax.plot(*coord_to_polar(earth.transform_to(sun)), label='Earth(JPL)', color='green', linestyle='-.') +ax.plot(*coord_to_polar(moon.transform_to(sun)), label='Moon(JPL)', color='red', linestyle='dashed') +ax.set_title('Stonyhurst heliographic coordinates') +ax.legend(loc='upper left', bbox_to_anchor=(1.0, 0.5)) +plt.show() + +# plot trajectory in Cartesian coordinates +moon_xyz = moon.represent_as('cartesian') +earth_xyz = earth.represent_as('cartesian') +moon_JPL = np.array([(i.x.value, i.y.value, i.z.value) for i in moon_xyz]) +earth_JPL = np.array([(i.x.value, i.y.value, i.z.value) for i in earth_xyz]) + +fig = plt.figure() +ax = fig.add_subplot(projection='3d') +ax.plot(0, 0, 0, 'o', label='Sun', color='orange', markersize=10) +ax.plot(q[:, 0], q[:, 1], q[:, 2], label="Earth") +ax.plot(q[:, 3], q[:, 4], q[:, 5], label="Moon") +ax.plot(earth_JPL[:, 0], earth_JPL[:, 1], earth_JPL[:, 2], '--', label='Earth(JPL)') +ax.plot(moon_JPL[:, 0], moon_JPL[:, 1], moon_JPL[:, 2], '-.', label='Moon(JPL)') +ax.set_xlabel("X") +ax.set_ylabel("Y") +ax.set_zlabel("Z") +ax.set_xticks([]) +ax.set_yticks([]) +ax.set_zticks([]) +ax.legend() +plt.show() diff --git a/tasks/src/ff_simulation.py b/tasks/src/ff_simulation.py index 8da049a..26fba3b 100644 --- a/tasks/src/ff_simulation.py +++ b/tasks/src/ff_simulation.py @@ -1,5 +1,188 @@ """ This module contains functions for a simulation with force field -of gravitational n-body system using realistic data for various -initial configurations -""" \ No newline at end of file +of gravitational n-body system +""" + +import matplotlib.pyplot as plt +import numpy as np + +from jobs.src.bht_algorithm_3D import MainApp, Particle + + +# Simulation class for galaxy collision using Barnes-Hut and Euler method +class GalaxyCollisionSimulation: + + def __init__(self, num_particles): + # Initialize the simulation with a given number of particles + self.num_particles = num_particles + self.particles = self.initialize_particles(initial='random') # Generate particles + self.barnes_hut = MainApp(self.particles) # Initialize Barnes-Hut algorithm instance + self.barnes_hut.BuildTree(self.particles) # Build the Barnes-Hut tree with particles + self.barnes_hut.rootNode.ComputeMassDistribution() #Compute the center of mass of the tree nodes + self.particle_positions = { + i: [(particle.x, particle.y, particle.z)] + for i, particle in enumerate(self.particles) + } # Store particle positions for each time step + self.particle_velocities = { + i: [(particle.vx, particle.vy, particle.vz)] + for i, particle in enumerate(self.particles) + } # Store particle velocities for each time step + self.particle_forces = { + i: [(particle.fx, particle.fy, particle.fz)] + for i, particle in enumerate(self.particles) + } # Store particle velocities for each time step + self.system_center_of_mass = { + 0: (self.barnes_hut.rootNode.center_of_mass[0], self.barnes_hut.rootNode.center_of_mass[1], + self.barnes_hut.rootNode.center_of_mass[2]) + } + + def initialize_particles(self, initial='random'): + + if initial == 'two': + particles = [Particle(60, 50, 40, 1000), Particle(40, 50, 60, 1000)] + particles[0].vx, particles[0].vy, particles[0].vz = 5, 3, 3 + particles[1].vx, particles[1].vy, particles[1].vz = 5, -3, 3 + #particles=particles[:2] + return particles + + elif initial == 'random': + # Generate random particles within a specified range + particles = [] + for _ in range(self.num_particles): + x = np.random.uniform(50, 150) + y = np.random.uniform(50, 150) + z = np.random.uniform(50, 150) + vx = np.random.uniform(-5, 5) + vy = np.random.uniform(-5, 5) + vz = np.random.uniform(-5, 5) + #mass = np.random.uniform(10, 100) + mass = 1000 + particle = Particle(x, y, z, mass) + particle.vx = vx + particle.vy = vy + particle.vz = vz + particles.append(particle) + + return particles + + elif initial == 'four': + particles = [ + Particle(60, 50, 40, 1000), + Particle(40, 50, 60, 1000), + Particle(50, 60, 70, 1000), + Particle(50, 40, 30, 1000) + ] + particles[0].vx, particles[0].vy, particles[0].vz = 0, 3, 3 + particles[1].vx, particles[1].vy, particles[1].vz = 0, -3, 3 + particles[2].vx, particles[2].vy, particles[2].vz = -3, 0, -3 + particles[3].vx, particles[3].vy, particles[3].vz = 3, 0, -3 + #particles=particles[:2] + return particles + + def simulate(self, num_steps, time_step): + # Simulate the galaxy collision for a certain number of steps + for step in range(num_steps): + # For each step, build the tree + self.barnes_hut.BuildTree(self.particles) + self.barnes_hut.rootNode.ComputeMassDistribution() + if step in np.arange(0, num_steps, 1000): + print(f'===Quadtree at step {step}===') + self.barnes_hut.rootNode.print_tree() + self.evaluate_forces() # Evaluate forces acting on each particle + self.integrate(time_step, 'velocity_verlet') # Integrate to update particle positions + + self.system_center_of_mass[step] = (self.barnes_hut.rootNode.center_of_mass[0], + self.barnes_hut.rootNode.center_of_mass[1], + self.barnes_hut.rootNode.center_of_mass[2]) + # Store particle positions, velocities and forces for each time step + for i, particle in enumerate(self.particles): + self.particle_positions[i].append((particle.x, particle.y, particle.z)) + self.particle_velocities[i].append((particle.vx, particle.vy, particle.vz)) + self.particle_forces[i].append((particle.fx, particle.fy, particle.fz)) + + def evaluate_forces(self): + # Evaluate forces acting on each particle using Barnes-Hut algorithm + for particle in self.particles: + force = self.barnes_hut.rootNode.CalculateForceFromTree(particle) + particle.fx, particle.fy, particle.fz = force + + def calculate_force(self, particle): + # Calculate force acting on a single particle + force = self.barnes_hut.rootNode.CalculateForceFromTree(particle) + particle.fx, particle.fy, particle.fz = force + + def integrate(self, time_step, method): + # Integrate to update particle positions based on calculated forces + if method == 'explicit_euler': + for particle in self.particles: + particle.vx += particle.fx * time_step / particle.mass # Update velocity components + particle.vy += particle.fy * time_step / particle.mass + particle.vz += particle.fz * time_step / particle.mass + particle.x += particle.vx * time_step # Update particle positions using velocity + particle.y += particle.vy * time_step + particle.z += particle.vz * time_step + + elif method == 'velocity_verlet': + for particle in self.particles: + particle.vx += particle.fx * time_step / (2 * particle.mass) # First half-step + particle.vy += particle.fy * time_step / (2 * particle.mass) + particle.vz += particle.fz * time_step / (2 * particle.mass) + particle.x += particle.vx * time_step # Full step for position + particle.y += particle.vy * time_step + particle.z += particle.vz * time_step + + self.calculate_force(particle) # Recalculate force for the particle + + particle.vx += particle.fx * time_step / (2 * particle.mass) # Second half-step + particle.vy += particle.fy * time_step / (2 * particle.mass) + particle.vz += particle.fz * time_step / (2 * particle.mass) + + def print_particle_positions(self): + # Print the positions of all particles for each time step + for i, positions in self.particle_positions.items(): + print(f"Particle {i + 1} Positions:") + for step, pos in enumerate(positions): + print(f" Time Step {step}: Position ({pos[0]}, {pos[1]}, {pos[2]})") + + def display_snapshots(self, num_shots, fix_axes=True): + # Display pictures for each time step + num_time_steps = len(next(iter(self.particle_positions.values()))) + print('===Quadtree at the end===') + self.barnes_hut.rootNode.print_tree() # print the tree + axes_type = "fixed" if fix_axes else "unfixed" + #Fixed axis limits + print(f"For {axes_type} axis limits, num_particles={self.num_particles}") + for step in np.arange(0, num_time_steps, int(num_time_steps / num_shots)): + fig = plt.figure() + ax = fig.add_subplot(111, projection='3d') + if fix_axes: + ax.set_xlim(0, 200) + ax.set_ylim(0, 200) + ax.set_zlim(0, 200) + ax.set_xlabel('X-axis') + ax.set_ylabel('Y-axis') + ax.set_zlabel('Z-axis') + ax.set_title(f'Time Step {step}') + ax.grid() + + #print(f'Step {step}') + for particle_index, positions in self.particle_positions.items(): + x, y, z = positions[step] + vx, vy, vz = self.particle_velocities[particle_index][step] + fx, fy, fz = self.particle_forces[particle_index][step] + #mass = self.particles[particle_index].mass + ax.scatter(x, y, z, c='blue', s=20, alpha=0.5) # Plot particle position for the current time step + c_x, c_y, c_z = self.system_center_of_mass[step] + ax.scatter(c_x, c_y, c_z, c='orange', s=20) + #print( + #f'i={particle_index}: x={round(x,2)}, y={round(y,2)}, z={round(z,2)}, vx={round(vx,2)}, vy={round(vy,2)}, vz={round(vz,2)}, fx={round(fx,2)}, fy={round(fy,2)}, fz={round(fz,2)}' + #) + #print(y) + + plt.show() + + +if __name__ == "__main__": + sim = GalaxyCollisionSimulation(num_particles=10) + sim.simulate(num_steps=10000, time_step=0.001) + sim.display_snapshots(200, fix_axes=True) diff --git a/tasks/src/utils.py b/tasks/src/utils.py new file mode 100644 index 0000000..6e3b611 --- /dev/null +++ b/tasks/src/utils.py @@ -0,0 +1,33 @@ +import numpy as np +from astropy.coordinates import CartesianRepresentation, SphericalRepresentation + + +def rotation_matrix(phi, theta) -> np.ndarray: + """ + Rotate a vector represented in spherical coordinates. + + Args: + phi (float): Azimuthal angle in radians. + theta (float): Polar angle in radians. + """ + # Construct the rotation matrix directly in spherical coordinates + rot_phi = np.array([[np.cos(phi), -np.sin(phi), 0], [np.sin(phi), np.cos(phi), 0], [0, 0, + 1]]) # Rotation around z-axis + + rot_theta = np.array([[np.sin(theta), 0, np.cos(theta)], [0, 1, 0], [-np.cos(theta), 0, + np.sin(theta)]]) # Rotation around y-axis + + # Combine the rotation matrices + rotation_matrix = np.dot(rot_phi, rot_theta) + + return rotation_matrix + + +def coord_to_polar(coord): + return coord.lon.to_value('rad'), coord.radius.to_value('AU') + + +def xyz_to_polar(x, y, z): + cart = CartesianRepresentation(x, y, z) + sph = cart.represent_as(SphericalRepresentation) + return sph.lon.value, sph.distance.value diff --git a/tasks/tests/test_a_task.py b/tasks/tests/test_a_task.py deleted file mode 100644 index 8ca451b..0000000 --- a/tasks/tests/test_a_task.py +++ /dev/null @@ -1,43 +0,0 @@ -import logging -import unittest - -import numpy as np - -from tasks.src.a_task import swap_gate - -logger = logging.getLogger(__name__) -logging.basicConfig(level=logging.INFO) - - -class ATaskTest(unittest.TestCase): - - def test_a_task(self): - """ - Test functionalities of swap gate on 2-qubits - """ - - qubit_0 = np.array([1, 0]) - qubit_1 = np.array([0, 1]) - - qubit_00 = np.kron(qubit_0, qubit_0) - qubit_11 = np.kron(qubit_1, qubit_1) - qubit_01 = np.kron(qubit_0, qubit_1) - qubit_10 = np.kron(qubit_1, qubit_0) - - # ensure input is a 2-qubit - self.assertTrue(qubit_00.shape[0] == 4) - self.assertTrue(qubit_01.shape[0] == 4) - self.assertTrue(qubit_10.shape[0] == 4) - self.assertTrue(qubit_11.shape[0] == 4) - - self.assertTrue(np.array_equal(np.dot(swap_gate(), qubit_00), qubit_00)) - self.assertTrue(np.array_equal(np.dot(swap_gate(), qubit_11), qubit_11)) - - self.assertTrue(np.array_equal(np.dot(swap_gate(), qubit_01), qubit_10)) - self.assertTrue(np.array_equal(np.dot(swap_gate(), qubit_10), qubit_01)) - - logger.info("Logging for fun!") - - -if __name__ == '__main__': - unittest.main() diff --git a/tasks/tests/test_direct_simulation.py b/tasks/tests/test_direct_simulation.py deleted file mode 100644 index e69de29..0000000 diff --git a/tasks/tests/test_ff_simulation.py b/tasks/tests/test_ff_simulation.py deleted file mode 100644 index e69de29..0000000 -- GitLab