CLUSTER_Python_Programme/Bachelorthesis/All_SC_3D_ORBIT.py
lisa 404049b068 All_SC_3D_ORBIT.py
This code allows you to visualize the position, trajectory of all spacecraft, and Key Science Regions of PMO in 3D. 
One .npy file is loaded per spacecraft. To plot the trajectory over a time interval, the variables start and end must correspond to the desired time interval. To plot a discrete point in time, set start=None and end=None, and only target_time receives the desired timestamp.
2026-06-04 16:01:21 +02:00

293 lines
No EOL
8.5 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Jun 1 09:00:23 2026
@author: vieweg
"""
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime
# load data
def load_data(file):
all_data = np.load(file, allow_pickle=True).item()
dates = np.array([datetime.fromisoformat(str(d)) for d in all_data['dates']])
position = all_data['position'].astype(np.float64)
x_loaded = position[:, 0]
y_loaded = position[:, 1]
z_loaded = position[:, 2]
return dates, x_loaded, y_loaded, z_loaded
# cylinder
def plot_cylinder(ax, x0, y0, z0, radius=0.2, height=0.05, color='blue'):
theta = np.linspace(0, 2*np.pi, 20)
z = np.linspace(-height/2, height/2, 2)
theta, z = np.meshgrid(theta, z)
x = x0 + radius * np.cos(theta)
y = y0 + radius * np.sin(theta)
z = z0 + z
ax.plot_surface(x, y, z, color=color)
# Deckel + Boden
theta = np.linspace(0, 2*np.pi, 20)
r = np.linspace(0, radius, 10)
theta, r = np.meshgrid(theta, r)
x_top = x0 + r * np.cos(theta)
y_top = y0 + r * np.sin(theta)
z_top = np.full_like(x_top, z0 + height/2)
x_bottom = x0 + r * np.cos(theta)
y_bottom = y0 + r * np.sin(theta)
z_bottom = np.full_like(x_bottom, z0 - height/2)
ax.plot_surface(x_top, y_top, z_top, color=color)
ax.plot_surface(x_bottom, y_bottom, z_bottom, color=color)
return
def plot_3d_multi(datasets, start=None, end=None, target_time=None):
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
# Make data
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
xe = 1 * np.outer(np.cos(u), np.sin(v))
ye = 1 * np.outer(np.sin(u), np.sin(v))
ze = 1 * np.outer(np.ones(np.size(u)), np.cos(v))
# Plot the surface
ax.plot_surface(xe, ye, ze, color = 'b', label = 'Earth')
#Plot Sun at (10, 0, 0)
r = 1.5
u = np.linspace(0, 2 * np.pi, 50)
v = np.linspace(0, np.pi, 50)
x0, y0, z0 = 20, 0 , 0
ax.quiver(x0, y0, z0, 1.0,0.0,0.0, color = 'orange', length = 5, normalize = True, linewidth = 2, zorder = 20, label = 'Direction to Sun')
#plot PMO key science region - Fore Shock
r1 = 13.5
r2 = 17
theta_max = np.deg2rad(45)
# Winkel definieren
theta = np.linspace(0, theta_max, 40)
phi = np.linspace(0, 2*np.pi, 60)
theta, phi = np.meshgrid(theta, phi)
# outer surface
x_outer = r2 * np.cos(theta)
y_outer = r2 * np.sin(theta) * np.cos(phi)
z_outer = r2 * np.sin(theta) * np.sin(phi)
# inner surface
x_inner = r1 * np.cos(theta)
y_inner = r1 * np.sin(theta) * np.cos(phi)
z_inner = r1 * np.sin(theta) * np.sin(phi)
# Plot Shell
ax.plot_surface(x_outer, y_outer, z_outer, color='yellow', alpha=0.3)
ax.plot_surface(x_inner, y_inner, z_inner, color='yellow', alpha=0.3)
r = np.linspace(r1, r2, 30)
phi = np.linspace(0, 2*np.pi, 60)
r, phi = np.meshgrid(r, phi)
x_cap = r * np.cos(theta_max)
y_cap = r * np.sin(theta_max) * np.cos(phi)
z_cap = r * np.sin(theta_max) * np.sin(phi)
ax.plot_surface(x_cap, y_cap, z_cap, color='yellow', alpha=0.3, label = r'Fore Shock ($13.5 < R_0 < 17$)')
#plot PMO key science region - Shock
r1 = 12.5
r2 = 13.5
theta_max = np.deg2rad(45)
# define angle
theta = np.linspace(0, theta_max, 40)
phi = np.linspace(0, 2*np.pi, 60)
theta, phi = np.meshgrid(theta, phi)
# outer surface
x_outer = r2 * np.cos(theta)
y_outer = r2 * np.sin(theta) * np.cos(phi)
z_outer = r2 * np.sin(theta) * np.sin(phi)
# inner surface
x_inner = r1 * np.cos(theta)
y_inner = r1 * np.sin(theta) * np.cos(phi)
z_inner = r1 * np.sin(theta) * np.sin(phi)
# plot shell
ax.plot_surface(x_outer, y_outer, z_outer, color='orange', alpha=0.3)
ax.plot_surface(x_inner, y_inner, z_inner, color='orange', alpha=0.3)
r = np.linspace(r1, r2, 30)
phi = np.linspace(0, 2*np.pi, 60)
r, phi = np.meshgrid(r, phi)
x_cap = r * np.cos(theta_max)
y_cap = r * np.sin(theta_max) * np.cos(phi)
z_cap = r * np.sin(theta_max) * np.sin(phi)
ax.plot_surface(x_cap, y_cap, z_cap, color='orange', alpha=0.3, label = r'Shock ($12.5 < R_0 < 13.5$)')
#plot PMO key science region - Magnetosheath
r1 = 10.5
r2 = 12.5
theta_max = np.deg2rad(45)
# define angle
theta = np.linspace(0, theta_max, 40)
phi = np.linspace(0, 2*np.pi, 60)
theta, phi = np.meshgrid(theta, phi)
# outer surface
x_outer = r2 * np.cos(theta)
y_outer = r2 * np.sin(theta) * np.cos(phi)
z_outer = r2 * np.sin(theta) * np.sin(phi)
# inner surface
x_inner = r1 * np.cos(theta)
y_inner = r1 * np.sin(theta) * np.cos(phi)
z_inner = r1 * np.sin(theta) * np.sin(phi)
# Plot shell
ax.plot_surface(x_outer, y_outer, z_outer, color='red', alpha=0.3)
ax.plot_surface(x_inner, y_inner, z_inner, color='red', alpha=0.3)
r = np.linspace(r1, r2, 30)
phi = np.linspace(0, 2*np.pi, 60)
r, phi = np.meshgrid(r, phi)
x_cap = r * np.cos(theta_max)
y_cap = r * np.sin(theta_max) * np.cos(phi)
z_cap = r * np.sin(theta_max) * np.sin(phi)
ax.plot_surface(x_cap, y_cap, z_cap, color='red', alpha=0.3, label = r'Magnetosheath ($10.5 < R_0 < 12.5$)')
#plot PMO key science region - Magnetopause
r1 = 10.5
r2 = 9.5
theta_max = np.deg2rad(45)
# define angle
theta = np.linspace(0, theta_max, 40)
phi = np.linspace(0, 2*np.pi, 60)
theta, phi = np.meshgrid(theta, phi)
# outer surface
x_outer = r2 * np.cos(theta)
y_outer = r2 * np.sin(theta) * np.cos(phi)
z_outer = r2 * np.sin(theta) * np.sin(phi)
# inner surface
x_inner = r1 * np.cos(theta)
y_inner = r1 * np.sin(theta) * np.cos(phi)
z_inner = r1 * np.sin(theta) * np.sin(phi)
# Plot shell
ax.plot_surface(x_outer, y_outer, z_outer, color='pink', alpha=0.3)
ax.plot_surface(x_inner, y_inner, z_inner, color='pink', alpha=0.3)
r = np.linspace(r1, r2, 30)
phi = np.linspace(0, 2*np.pi, 60)
r, phi = np.meshgrid(r, phi)
x_cap = r * np.cos(theta_max)
y_cap = r * np.sin(theta_max) * np.cos(phi)
z_cap = r * np.sin(theta_max) * np.sin(phi)
ax.plot_surface(x_cap, y_cap, z_cap, color='pink', alpha=0.3, label = r'Magnetopause ($9.5 < R_0 < 10.5$)')
#plot PMO key science regions - Transition Region (TR)
ax.bar3d(x=-12, y = -8, z=-7, dx = 7, dy = 16, dz = 14, color = 'green', alpha = 0.4, label = r'Transition Region' )
#plot PMO key science regions - Magnetotail current sheets (CS)
ax.bar3d(x=-17, y = -11, z=-10, dx = 5, dy = 22, dz = 20, color = 'purple', alpha = 0.4, label = r'Magnetotail Current Sheet' )
colors = ['red', 'green', 'blue', 'purple']
labels = ['C1', 'C2', 'C3', 'C4']
for i in range(len(labels)):
ax.plot([],[],[], color = colors[i], label = labels[i])
for i, data in enumerate(datasets):
dates, x_loaded, y_loaded, z_loaded = data
if start is not None and end is not None:
mask = (dates >= start) & (dates <= end)
ax.plot(
x_loaded[mask],
y_loaded[mask],
z_loaded[mask],
color=colors[i],
label=labels[i],
linewidth=1
)
if target_time is not None:
idx = min(range(len(dates)), key = lambda i: abs(dates[i] - target_time))
plot_cylinder(
ax,
x_loaded[idx],
y_loaded[idx],
z_loaded[idx],
radius=0.8,
height=0.3,
color=colors[i]
)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.legend(ncols = 2, fontsize = 18)
ax.set_title(f'Cluster Spacecraft at {target_time} - GSE', fontsize = 26)
ax.set_box_aspect([1,1,1])
if start is not None:
ax.legend()
ax.auto_scale_xyz([-20,20], [-20,20], [-20,20])
filename = '/home/asterix/vieweg/Desktop/All_SC_ORBIT_20020906.pdf'
plt.savefig(filename)
plt.show()
#enter file name for all SC
data1 = load_data('C1_merged_2002.npy')
data2 = load_data('C2_merged_2002.npy')
data3 = load_data('C3_merged_2002.npy')
data4 = load_data('C4_merged_2002.npy')
datasets = [data1, data2, data3, data4]
#Enter time interval or specific point in time
plot_3d_multi(
datasets,
start=None,
end=None,
target_time=datetime(2002, 9, 6, 16, 0)
)