From b20a9f5b5d4601a8fb85eb9225dc0edef0b52f54 Mon Sep 17 00:00:00 2001 From: lassejsc Date: Thu, 12 Mar 2026 10:02:40 +0200 Subject: [PATCH 1/7] Moving themis obs to plot --- .../themis_observation.py => plot/plot_themis_observation.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename analysator/{calculations/themis_observation.py => plot/plot_themis_observation.py} (100%) diff --git a/analysator/calculations/themis_observation.py b/analysator/plot/plot_themis_observation.py similarity index 100% rename from analysator/calculations/themis_observation.py rename to analysator/plot/plot_themis_observation.py From 18acbc3cce0f697e08f009c8ee6d97114347f932 Mon Sep 17 00:00:00 2001 From: lassejsc Date: Thu, 12 Mar 2026 10:03:36 +0200 Subject: [PATCH 2/7] removed get_dv in favor of already defined get_velocity_mesh_dv --- analysator/plot/plot_themis_observation.py | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/analysator/plot/plot_themis_observation.py b/analysator/plot/plot_themis_observation.py index f93bb4e5..c9fccbac 100644 --- a/analysator/plot/plot_themis_observation.py +++ b/analysator/plot/plot_themis_observation.py @@ -48,26 +48,6 @@ themis_colors=[(0,0,0),(.5,0,.5),(0,0,1),(0,1,1),(0,1,0),(1,1,0),(1,0,0)] themis_colormap = matplotlib.colors.LinearSegmentedColormap.from_list("themis",themis_colors) -def get_dv(vlsvReader,pop="proton"): - # Get velocity grid sizes: - vel_mesh_size = vlsvReader.get_velocity_mesh_size(pop=pop) - vel_block_size = vlsvReader.get_velocity_block_size(pop=pop) - vxcells = vel_mesh_size[0]*vel_block_size[0] - vycells = vel_mesh_size[1]*vel_block_size[1] - vzcells = vel_mesh_size[2]*vel_block_size[2] - - vel_mesh_limits = vlsvReader.get_velocity_mesh_extent(pop=pop) - vxmin = vel_mesh_limits[0] - vymin = vel_mesh_limits[1] - vzmin = vel_mesh_limits[2] - vxmax = vel_mesh_limits[3] - vymax = vel_mesh_limits[4] - vzmax = vel_mesh_limits[5] - - dvx = (vxmax - vxmin) / (float)(vxcells) - dvy = (vymax - vymin) / (float)(vycells) - dvz = (vzmax - vzmin) / (float)(vzcells) - return [dvx,dvy,dvz] def simulation_to_spacecraft_frame(spinvector, detector_axis, phi=0): ''' Builds a matrix to transform coordinates from simulation frame into spaceraft frame @@ -248,7 +228,7 @@ def themis_observation_from_file( vlsvReader, cellid, matrix=np.array([[1,0,0],[ pl.show() ''' # Get velocity space resolution - dvx,dvy,dvz = get_dv(vlsvReader,pop=pop) + dvx,dvy,dvz = vlsvReader.get_velocity_mesh_dv(pop=pop) # Read the velocity cells: velocity_cell_data = vlsvReader.read_velocity_cells(cellid,pop=pop) From 05f31f2ef1b7d5a664d05633d2e1bc8f4e9d00cf Mon Sep 17 00:00:00 2001 From: lassejsc Date: Thu, 12 Mar 2026 10:05:38 +0200 Subject: [PATCH 3/7] removed unsused imports from plot_themis_observation --- analysator/plot/plot_themis_observation.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/analysator/plot/plot_themis_observation.py b/analysator/plot/plot_themis_observation.py index c9fccbac..6130ce6c 100644 --- a/analysator/plot/plot_themis_observation.py +++ b/analysator/plot/plot_themis_observation.py @@ -25,10 +25,8 @@ import analysator as pt import matplotlib.pyplot as plt import matplotlib -from .rotation import rotateVectorToVector from scipy.interpolate import griddata from scipy.signal import sepfir2d -from packaging.version import Version import logging # Detector data obtained from the Themis ESA instrument paper From a95026707c484845e2686105747ec42504319022 Mon Sep 17 00:00:00 2001 From: lassejsc Date: Thu, 12 Mar 2026 13:01:08 +0200 Subject: [PATCH 4/7] Init file setups for the themis plot and new virtual_observations in calculations --- analysator/calculations/__init__.py | 8 +++----- analysator/plot/__init__.py | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/analysator/calculations/__init__.py b/analysator/calculations/__init__.py index 3257cef4..57c70f80 100644 --- a/analysator/calculations/__init__.py +++ b/analysator/calculations/__init__.py @@ -37,7 +37,7 @@ ''' #for usage with "from (package) import *" -__all__=["ids3d","intpol_file","intpol_points","cutthrough","fourier","spectra","variable","timeevolution","pitchangle","gyrophaseangle","themis_observation","cut3d","lineout","fit","fieldtracer","non_maxwellianity","null_lines","interpolator_amr"] +__all__=["ids3d","intpol_file","intpol_points","cutthrough","fourier","spectra","variable","timeevolution","pitchangle","gyrophaseangle","virtual_observations","cut3d","lineout","fit","fieldtracer","non_maxwellianity","null_lines","interpolator_amr"] # List of functions and classes that should be imported into the interface @@ -53,10 +53,7 @@ from .pitchangle import pitch_angles #from .backstream import extract_velocity_cells_sphere, extract_velocity_cells_non_sphere from .gyrophaseangle import gyrophase_angles_from_file -from .themis_observation import themis_observation_from_file -from .themis_observation import themis_plot_detector -from .themis_observation import themis_plot_phasespace_contour -from .themis_observation import themis_plot_phasespace_helistyle + #from .themis_observation import simulation_to_spacecraft_frame from .cut3d import cut3d from .lineout import lineout @@ -66,3 +63,4 @@ from .non_maxwellianity import epsilon_M from .null_lines import LMN_null_lines_FOTE from .interpolator_amr import AMRInterpolator, supported_amr_interpolators +from .virtual_observations import spacecraft_to_simulation_frame,simulation_to_spacecraft_frame,simulation_to_observation_frame diff --git a/analysator/plot/__init__.py b/analysator/plot/__init__.py index 0e71900d..c74d87ed 100644 --- a/analysator/plot/__init__.py +++ b/analysator/plot/__init__.py @@ -36,7 +36,7 @@ #for usage with "from (package) import *" __all__ = ['plot_colormap', 'plot_vdf', 'plot_vdfdiff', 'plot_vdf_profiles', 'plot_colormap3dslice', 'plot_threeslice', 'plot_ionosphere', 'plot_isosurface', 'plot_neutral_sheet', - 'plot_variables','colormaps', 'plot_helpers'] + 'plot_variables','colormaps', 'plot_helpers','plot_themis_observation'] from .plot_variables import plot_variables, plot_multiple_variables @@ -46,7 +46,7 @@ import matplotlib.pyplot as plt import matplotlib from . import colormaps - +from . import plot_themis_observation from . import plot_helpers from .plot_colormap import plot_colormap from .plot_vdf import plot_vdf From 0941fd23be307d3d790c2032213232a2304ef4a9 Mon Sep 17 00:00:00 2001 From: lassejsc Date: Thu, 12 Mar 2026 13:01:45 +0200 Subject: [PATCH 5/7] Moved some functions from former themis_observations to virtual_observations --- .../calculations/virtual_observations.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 analysator/calculations/virtual_observations.py diff --git a/analysator/calculations/virtual_observations.py b/analysator/calculations/virtual_observations.py new file mode 100644 index 00000000..9660881a --- /dev/null +++ b/analysator/calculations/virtual_observations.py @@ -0,0 +1,40 @@ + +import numpy as np +def simulation_to_spacecraft_frame(spinvector, detector_axis, phi=0): + ''' Builds a matrix to transform coordinates from simulation frame into spaceraft frame + :param spinvector Spacecraft spin axis, in simulation coordinates + :param detector_axis Detector plane normal axis + :param phi Rotate spacecraft around spin axis after setting up coordinate system + ''' + # TODO: Normalize vectors? + y = np.cross(detector_axis,spinvector) + z = np.cross(spinvector, y) + yr = np.cos(phi)*y - np.sin(phi)*z + zr = np.sin(phi)*y + np.cos(phi)*z + m = np.array([spinvector, yr, zr]) + + return m + +def spacecraft_to_simulation_frame(spinvector, detector_axis, phi=0): + ''' Builds a matrix to transform coordinates from spaceraft frame back to simulation frame + :param spinvector Spacecraft spin axis, in simulation coordinates + :param detector_axis Detector plane normal axis + :param phi Rotate spacecraft around spin axis after setting up coordinate system + ''' + return simulation_to_spacecraft_frame(spinvector,detector_axis,phi).T + +def simulation_to_observation_frame(x_axis,y_axis): + ''' Builds a 3x3 matrix to transform velocities into an observation plane + :param x_axis: x-axis of the observation plane (in simulation coordinates) + :param y_axis: y-axis of the observation plane (gets orthonormalized) + ''' + xn = np.linalg.norm(x_axis) + x_axis /= xn + p = x_axis.dot(y_axis) + y_axis -= p*x_axis + yn = np.linalg.norm(y_axis) + y_axis /= yn + z_axis = np.cross(x_axis,y_axis) + return np.array([x_axis,y_axis,z_axis]) + + From 9fb80701a6c4750e7b1f5ddf13393f5b19a74245 Mon Sep 17 00:00:00 2001 From: lassejsc Date: Thu, 12 Mar 2026 13:29:19 +0200 Subject: [PATCH 6/7] Fixed imports and function calls --- analysator/calculations/__init__.py | 4 +- analysator/plot/__init__.py | 7 +++- analysator/plot/plot_themis_observation.py | 45 ++-------------------- 3 files changed, 11 insertions(+), 45 deletions(-) diff --git a/analysator/calculations/__init__.py b/analysator/calculations/__init__.py index 57c70f80..1aea6eaa 100644 --- a/analysator/calculations/__init__.py +++ b/analysator/calculations/__init__.py @@ -37,7 +37,8 @@ ''' #for usage with "from (package) import *" -__all__=["ids3d","intpol_file","intpol_points","cutthrough","fourier","spectra","variable","timeevolution","pitchangle","gyrophaseangle","virtual_observations","cut3d","lineout","fit","fieldtracer","non_maxwellianity","null_lines","interpolator_amr"] +__all__=["ids3d","intpol_file","intpol_points","cutthrough","fourier","spectra","variable","timeevolution","pitchangle","gyrophaseangle","cut3d","lineout","fit","fieldtracer","non_maxwellianity","null_lines","interpolator_amr" + "spacecraft_to_simulation_frame","simulation_to_spacecraft_frame","simulation_to_observation_frame"] # List of functions and classes that should be imported into the interface @@ -53,7 +54,6 @@ from .pitchangle import pitch_angles #from .backstream import extract_velocity_cells_sphere, extract_velocity_cells_non_sphere from .gyrophaseangle import gyrophase_angles_from_file - #from .themis_observation import simulation_to_spacecraft_frame from .cut3d import cut3d from .lineout import lineout diff --git a/analysator/plot/__init__.py b/analysator/plot/__init__.py index c74d87ed..e591a6e8 100644 --- a/analysator/plot/__init__.py +++ b/analysator/plot/__init__.py @@ -36,7 +36,10 @@ #for usage with "from (package) import *" __all__ = ['plot_colormap', 'plot_vdf', 'plot_vdfdiff', 'plot_vdf_profiles', 'plot_colormap3dslice', 'plot_threeslice', 'plot_ionosphere', 'plot_isosurface', 'plot_neutral_sheet', - 'plot_variables','colormaps', 'plot_helpers','plot_themis_observation'] + 'plot_variables','colormaps', 'plot_helpers' + 'themis_plot_phasespace_contour','themis_plot_detector','themis_observation_from_file' + 'themis_plot_phasespace_helistyle',"themis_observation" + ] from .plot_variables import plot_variables, plot_multiple_variables @@ -46,7 +49,7 @@ import matplotlib.pyplot as plt import matplotlib from . import colormaps -from . import plot_themis_observation +from .plot_themis_observation import themis_plot_detector,themis_plot_phasespace_contour,themis_plot_phasespace_helistyle,themis_observation,themis_observation_from_file from . import plot_helpers from .plot_colormap import plot_colormap from .plot_vdf import plot_vdf diff --git a/analysator/plot/plot_themis_observation.py b/analysator/plot/plot_themis_observation.py index 6130ce6c..10875ef7 100644 --- a/analysator/plot/plot_themis_observation.py +++ b/analysator/plot/plot_themis_observation.py @@ -28,6 +28,7 @@ from scipy.interpolate import griddata from scipy.signal import sepfir2d import logging +from analysator.calculations import virtual_observations as vsc # Detector data obtained from the Themis ESA instrument paper # http://dx.doi.org/10.1007/s11214-008-9440-2 @@ -46,44 +47,6 @@ themis_colors=[(0,0,0),(.5,0,.5),(0,0,1),(0,1,1),(0,1,0),(1,1,0),(1,0,0)] themis_colormap = matplotlib.colors.LinearSegmentedColormap.from_list("themis",themis_colors) - -def simulation_to_spacecraft_frame(spinvector, detector_axis, phi=0): - ''' Builds a matrix to transform coordinates from simulation frame into spaceraft frame - :param spinvector Spacecraft spin axis, in simulation coordinates - :param detector_axis Detector plane normal axis - :param phi Rotate spacecraft around spin axis after setting up coordinate system - ''' - # TODO: Normalize vectors? - y = np.cross(detector_axis,spinvector) - z = np.cross(spinvector, y) - yr = np.cos(phi)*y - np.sin(phi)*z - zr = np.sin(phi)*y + np.cos(phi)*z - m = np.array([spinvector, yr, zr]) - - return m - -def spacecraft_to_simulation_frame(spinvector, detector_axis, phi=0): - ''' Builds a matrix to transform coordinates from spaceraft frame back to simulation frame - :param spinvector Spacecraft spin axis, in simulation coordinates - :param detector_axis Detector plane normal axis - :param phi Rotate spacecraft around spin axis after setting up coordinate system - ''' - return simulation_to_spacecraft_frame(spinvector,detector_axis,phi).T - -def simulation_to_observation_frame(x_axis,y_axis): - ''' Builds a 3x3 matrix to transform velocities into an observation plane - :param x_axis: x-axis of the observation plane (in simulation coordinates) - :param y_axis: y-axis of the observation plane (gets orthonormalized) - ''' - xn = np.linalg.norm(x_axis) - x_axis /= xn - p = x_axis.dot(y_axis) - y_axis -= p*x_axis - yn = np.linalg.norm(y_axis) - y_axis /= yn - z_axis = np.cross(x_axis,y_axis) - return np.array([x_axis,y_axis,z_axis]) - def themis_plot_detector(vlsvReader, cellID, detector_axis=np.array([0,1,0]), pop="proton"): ''' Plots a view of the detector countrates using matplotlib :param vlsvReader: Some VlsvReader class with a file open @@ -92,7 +55,7 @@ def themis_plot_detector(vlsvReader, cellID, detector_axis=np.array([0,1,0]), po :param detector_axis: detector axis direction (note: this is not spacecraft spin axis!) ''' - matrix = spacecraft_to_simulation_frame(np.cross(np.array([1.,0,0]),detector_axis),detector_axis) + matrix = vsc.spacecraft_to_simulation_frame(np.cross(np.array([1.,0,0]),detector_axis),detector_axis) logging.info("Getting phasespace data...") angles, energies, vmin, vmax, values = themis_observation_from_file( vlsvReader=vlsvReader, @@ -121,7 +84,7 @@ def themis_plot_phasespace_contour(vlsvReader, cellID, plane_x=np.array([1.,0,0] :param plane_x and plane_y: x and y direction of the resulting plot plane ''' - matrix = simulation_to_observation_frame(plane_x,plane_y) + matrix = vsc.simulation_to_observation_frame(plane_x,plane_y) angles, energies, vmin, vmax, values = themis_observation_from_file( vlsvReader=vlsvReader, cellid=cellID, matrix=matrix,pop=pop) @@ -165,7 +128,7 @@ def themis_plot_phasespace_helistyle(vlsvReader, cellID, plane_x=np.array([1.,0, :param plane_x and plane_y: x and y direction of the resulting plot plane ''' - matrix = simulation_to_observation_frame(plane_x,plane_y) + matrix = vsc.simulation_to_observation_frame(plane_x,plane_y) angles, energies, vmin, vmax, values = themis_observation_from_file( vlsvReader=vlsvReader, cellid=cellID, matrix=matrix, countrates=False) if vmin == 0: From e00e46683df1c60b5896c57255ff9394bdc46697 Mon Sep 17 00:00:00 2001 From: lassjsc Date: Mon, 23 Mar 2026 16:57:46 +0200 Subject: [PATCH 7/7] Added output to file for the plots --- analysator/plot/plot_themis_observation.py | 36 +++++++++++++++++----- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/analysator/plot/plot_themis_observation.py b/analysator/plot/plot_themis_observation.py index 10875ef7..b6e0259b 100644 --- a/analysator/plot/plot_themis_observation.py +++ b/analysator/plot/plot_themis_observation.py @@ -47,12 +47,16 @@ themis_colors=[(0,0,0),(.5,0,.5),(0,0,1),(0,1,1),(0,1,0),(1,1,0),(1,0,0)] themis_colormap = matplotlib.colors.LinearSegmentedColormap.from_list("themis",themis_colors) -def themis_plot_detector(vlsvReader, cellID, detector_axis=np.array([0,1,0]), pop="proton"): +def themis_plot_detector(vlsvReader, cellID,outputfile="./themis_plot_detector.png",nooverwrite=False,draw=True, detector_axis=np.array([0,1,0]), pop="proton"): ''' Plots a view of the detector countrates using matplotlib :param vlsvReader: Some VlsvReader class with a file open :type vlsvReader: :class:`vlsvfile.VlsvReader` :param cellid: The cell id where the distribution is supposet to be sampled NOTE: The cell id must have a velocity distribution! :param detector_axis: detector axis direction (note: this is not spacecraft spin axis!) + :param draw: Set to false to save to file instead of drawing on screen + :kward outputfile: File to output the image to if Draw=False + :kward nooverwrite: Whether to allow overwriting of files when saving, Default False + ''' matrix = vsc.spacecraft_to_simulation_frame(np.cross(np.array([1.,0,0]),detector_axis),detector_axis) @@ -74,13 +78,20 @@ def themis_plot_detector(vlsvReader, cellID, detector_axis=np.array([0,1,0]), po cax = ax.pcolormesh(grid_theta,grid_r,values, norm=matplotlib.colors.LogNorm(vmin=vmin,vmax=vmax), cmap=themis_colormap) ax.grid(True) fig.colorbar(cax) - plt.show() + if not draw: + outputpath=pt.plot.output_path(outputfile,None,None,nooverwrite) + plt.savefig(outputpath) + else: + plt.show() -def themis_plot_phasespace_contour(vlsvReader, cellID, plane_x=np.array([1.,0,0]), plane_y=np.array([0,0,1.]), smooth=False, xlabel="Vx", ylabel="Vy", pop="proton"): +def themis_plot_phasespace_contour(vlsvReader, cellID,outputfile='./themis_plot_phasespace_contour.png', nooverwrite=False, draw=True, plane_x=np.array([1.,0,0]), plane_y=np.array([0,0,1.]), smooth=False, xlabel="Vx", ylabel="Vy", pop="proton"): ''' Plots a contour view of phasespace, as seen by a themis detector, at the given cellID :param vlsvReader: Some VlsvReader class with a file open :type vlsvReader: :class:`vlsvfile.VlsvReader` :param cellid: The cell id where the distribution is supposet to be sampled NOTE: The cell id must have a velocity distribution! + :param draw: Set to false to save to file instead of drawing on screen + :kward outputfile: File to output the image to if Draw=False + :kward nooverwrite: Whether to allow overwriting of files when saving, Default False :param plane_x and plane_y: x and y direction of the resulting plot plane ''' @@ -117,14 +128,21 @@ def themis_plot_phasespace_contour(vlsvReader, cellID, plane_x=np.array([1.,0,0] cax = ax.contour(xi,yi,vi.T, levels=np.logspace(np.log10(vmin),np.log10(vmax),20), norm=matplotlib.colors.LogNorm(vmin=vmin,vmax=vmax)) ax.grid(True) fig.colorbar(cax) - plt.show() + if not draw: + outputpath=pt.plot.output_path(outputfile,None,None,nooverwrite) + plt.savefig(outputpath) + else: + plt.show() -def themis_plot_phasespace_helistyle(vlsvReader, cellID, plane_x=np.array([1.,0,0]), plane_y=np.array([0,0,1.]), smooth=True, xlabel="Vx", ylabel="Vy"): +def themis_plot_phasespace_helistyle(vlsvReader, cellID,outputfile='./themis_plot_phasespace_helistyle',plane_x=np.array([1.,0,0]), plane_y=np.array([0,0,1.]), smooth=True, xlabel="Vx", ylabel="Vy",draw=True,nooverwrite=False): ''' Plots a view of phasespace, as seen by a themis detector, at the given cellID, in the style that heli likes. :param vlsvReader: Some VlsvReader class with a file open :type vlsvReader: :class:`vlsvfile.VlsvReader` :param cellid: The cell id where the distribution is supposet to be sampled NOTE: The cell id must have a velocity distribution! :param smooth: Smooth re-gridded phasespace before plotting + :param draw: Set to false to save to file instead of drawing on screen + :kward outputfile: File to output the image to if Draw=False + :kward nooverwrite: Whether to allow overwriting of files when saving, Default False :param plane_x and plane_y: x and y direction of the resulting plot plane ''' @@ -159,12 +177,16 @@ def themis_plot_phasespace_helistyle(vlsvReader, cellID, plane_x=np.array([1.,0, ax.set_ylabel(ylabel+" (km/s)") cmapuse=pt.plot.get_cmap("Blues") - cax = ax.pcolormesh(xi,yi,vi.T, norm=matplotlib.colors.LogNorm(vmin=vmin,vmax=vmax), vmin=vmin, vmax=vmax, cmap=cmapuse, shading='flat') + cax = ax.pcolormesh(xi,yi,vi.T, norm=matplotlib.colors.LogNorm(vmin=vmin,vmax=vmax), cmap=cmapuse) cax2 = ax.contourf(xi,yi,vi.T, levels=np.logspace(np.log10(vmin),np.log10(vmax),20), norm=matplotlib.colors.LogNorm(vmin=vmin,vmax=vmax), vmin=vmin, vmax=vmax, cmap=cmapuse) #cax3 = ax.contour(xi,yi,vi.T, levels=np.logspace(np.log10(vmin),np.log10(vmax),20), norm=matplotlib.colors.LogNorm(vmin=vmin,vmax=vmax), cmap=pl.get_cmap("binary")) ax.grid(True) fig.colorbar(cax) - plt.show() + if not draw: + outputpath=pt.plot.output_path(outputfile,None,None,nooverwrite) + fig.savefig(outputpath) + else: + plt.show() def themis_observation_from_file( vlsvReader, cellid, matrix=np.array([[1,0,0],[0,1,0],[0,0,1]]), countrates=True, interpolate=True,binOffset=[0.,0.],pop='proton'): ''' Calculates artificial THEMIS EMS observation from the given cell :param vlsvReader: Some VlsvReader class with a file open