Skip to content

Commit da7b9e3

Browse files
Merge pull request #1316 from LenaMacke/feature/cluster-psd
Feature/Cluster cis-codif psd
2 parents 22d9660 + c62e342 commit da7b9e3

3 files changed

Lines changed: 163 additions & 3 deletions

File tree

pyspedas/projects/cluster/cis.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
def cis(trange:List[str]=['2018-11-5', '2018-11-6'],
99
probe:Union[str,List[str]]='1',
10+
option:str='mom',
1011
datatype:str='pp',
1112
prefix:str='',
1213
suffix:str='',
@@ -33,6 +34,10 @@ def cis(trange:List[str]=['2018-11-5', '2018-11-6'],
3334
List of probes to load. Valid options: '1','2','3','4'
3435
Default: '1'
3536
37+
option: str
38+
The data option to load. Valid options: 'mom' (moments), 'psd_h1' (H+ PSD), 'psd_he1' (He+ PSD), 'psd_o1' (O+ PSD)
39+
Default: 'mom'
40+
3641
datatype: str
3742
Data type; Valid options:
3843
Default: 'pp'
@@ -94,6 +99,14 @@ def cis(trange:List[str]=['2018-11-5', '2018-11-6'],
9499
>>> tplot(['N_p__C1_PP_CIS','N_O1__C1_PP_CIS','N_He1__C1_PP_CIS','N_He2__C1_PP_CIS','N_HIA__C1_PP_CIS'])
95100
96101
"""
97-
return load(instrument='cis', trange=trange, probe=probe, datatype=datatype, prefix=prefix, suffix=suffix, get_support_data=get_support_data, varformat=varformat, varnames=varnames, downloadonly=downloadonly, notplot=notplot, no_update=no_update, time_clip=time_clip, force_download=force_download)
102+
103+
if option == 'mom':
104+
species = None
105+
elif option.startswith('psd'):
106+
species = option.split('_')[1]
107+
else:
108+
raise ValueError("Invalid option: " + option + ". Valid options are 'mom', 'psd_h1' 'psd_he1', 'psd_o1'.")
109+
110+
return load(instrument='cis', trange=trange, probe=probe, datatype=datatype, prefix=prefix, suffix=suffix, get_support_data=get_support_data, varformat=varformat, varnames=varnames, downloadonly=downloadonly, notplot=notplot, no_update=no_update, time_clip=time_clip, force_download=force_download, species=species)
98111

99112

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import logging
2+
import re
3+
import numpy as np
4+
from pyspedas.tplot_tools import get_data
5+
6+
logging.captureWarnings(True)
7+
logging.basicConfig(format='%(asctime)s: %(message)s', datefmt='%d-%b-%y %H:%M:%S', level=logging.INFO)
8+
9+
def cluster_get_codif_dist(tname, probe=None):
10+
"""
11+
Returns 3D particle data structures containing Cluster CODIF
12+
data for use with pySPEDAS particle routines.
13+
14+
Input
15+
----------
16+
tname: str
17+
tplot variable name containing the CODIF distribution data
18+
Example: 'ions_3d__C1_CP_CIS_CODIF_HS_H1_PSD'
19+
20+
Parameters
21+
----------
22+
probe: str
23+
Spacecraft probe #
24+
25+
Returns
26+
----------
27+
3D particle data structure(s) containing Cluster CODIF distribution functions
28+
"""
29+
data = get_data(tname)
30+
31+
if data is None:
32+
logging.error('Problem extracting the CODIF distribution data.')
33+
return
34+
35+
if any(data[i].ndim == 2 for i in (2, 3, 4)):
36+
raise ValueError(
37+
"data[2], data[3], and data[4] must all be 1-D arrays"
38+
)
39+
40+
# check which species by looking at second last part of input string
41+
# this could be a function
42+
parts = tname.split("_")
43+
if re.fullmatch(r"[A-Z][a-z]?\d", parts[-2]):
44+
species = parts[-2].lower()
45+
else:
46+
raise ValueError(f"No valid species found in: {tname}")
47+
48+
# possible masses in amu
49+
if species == 'h1':
50+
mass = 1.04535e-2
51+
charge = 1.0
52+
elif species == 'he1':
53+
mass = 4.18138e-2
54+
charge = 1.0
55+
elif species == 'o1':
56+
mass = 0.167255
57+
charge = 1.0
58+
else:
59+
logging.error('Invalid species: ' + species)
60+
#return
61+
62+
out = {'project_name': 'Cluster',
63+
'spacecraft': probe,
64+
'species': species,
65+
'data_name': 'CODIF ' + species,
66+
'charge': charge,
67+
'units_name': 'df_km',
68+
'mass': mass}
69+
70+
# --- Reformat data
71+
# Shuffle the output to be [time, energy, phi, theta]
72+
# (data[1] is currently [time, theta, phi, energy])
73+
out_data = data[1].transpose([0, 3, 2, 1]) #* 1.0E-18 * 1.0E-12 # convert from s^3 km^-6 to s^3 cm^-6
74+
out_bins = np.zeros(out_data.shape) + 1
75+
out_dphi = np.zeros(out_data.shape) + 22.5 # 16 pixels in 360 degree window
76+
out_dtheta = np.zeros(out_data.shape) + 22.5 # 8 pixels in 180 degree window
77+
out_denergy = np.zeros(out_data.shape)
78+
79+
# theta
80+
# elevations are constant across time
81+
theta_reform = np.asarray(data[2]) # shape: (theta,)
82+
theta_reform = theta_reform[None, None, :] # shape: (1, 1, theta)
83+
theta_rebinned = np.broadcast_to(
84+
theta_reform,
85+
(len(data[4]), len(data[3]), theta_reform.shape[2])
86+
) # shape: (energy, phi, theta)
87+
out_theta = np.broadcast_to(
88+
theta_rebinned,
89+
(len(data[0]),) + theta_rebinned.shape
90+
) # shape: (time, energy, phi, theta)
91+
92+
# energy
93+
energy_len = len(data[4])
94+
energy_reform = np.asarray(data[4])[:, None, None] # shape: (energy, 1, 1)
95+
energy_table = np.broadcast_to(
96+
energy_reform,
97+
(len(data[4]), len(data[3]), len(data[2]))
98+
) # shape: (energy, phi, theta)
99+
out_energy = np.broadcast_to(
100+
energy_table,
101+
(len(data[0]),) + energy_table.shape
102+
) # shape: (time, energy, phi, theta)
103+
104+
# phi
105+
phi_reform = np.asarray(data[3])[None, :, None] # shape: (1, phi, 1)
106+
phi_rebinned = np.broadcast_to(
107+
phi_reform,
108+
(len(data[4]), len(data[3]), len(data[2]))
109+
) # shape: (energy, phi, theta)
110+
out_phi = np.broadcast_to(
111+
phi_rebinned,
112+
(len(data[0]),) + phi_rebinned.shape
113+
) # shape: (time, energy, phi, theta)
114+
115+
out_list = []
116+
for time_idx, time in enumerate(data[0]):
117+
out_table = {**out}
118+
out_table['data'] = out_data[time_idx, :]
119+
out_table['bins'] = out_bins[time_idx, :]
120+
out_table['theta'] = out_theta[time_idx, :]
121+
out_table['phi'] = out_phi[time_idx, :]
122+
out_table['energy'] = out_energy[time_idx, :]
123+
out_table['dtheta'] = out_dtheta[time_idx, :]
124+
out_table['dphi'] = out_dphi[time_idx, :]
125+
out_table['denergy'] = out_denergy[time_idx, :]
126+
out_table['n_energy'] = energy_len
127+
out_table['n_theta'] = len(data[3])
128+
out_table['n_phi'] = len(data[2])
129+
out_table['start_time'] = time # note: assumes the data weren't centered
130+
out_table['end_time'] = time + 4 # one spin = 4 seconds
131+
out_list.append(out_table)
132+
133+
return out_list

pyspedas/projects/cluster/load.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ def load(trange:List[str]=['2018-11-5', '2018-11-6'],
1818
notplot:bool=False,
1919
no_update:bool=False,
2020
time_clip:bool=False,
21-
force_download=False) -> List[str]:
21+
force_download=False,
22+
species=None
23+
) -> List[str]:
2224
"""
2325
Load data from Cluster instruments
2426
@@ -85,6 +87,9 @@ def load(trange:List[str]=['2018-11-5', '2018-11-6'],
8587
Download file even if local version is more recent than server version
8688
Default: False
8789
90+
species: str
91+
Species to load psd data for. Valid options are: 'h1', 'he1', 'o1'.
92+
Default: None
8893
8994
Returns
9095
-------
@@ -137,7 +142,16 @@ def load(trange:List[str]=['2018-11-5', '2018-11-6'],
137142
elif instrument == 'aspoc':
138143
pathformat = 'c'+prb+'/'+datatype+'/asp/%Y/c'+prb+'_'+datatype+'_asp_%Y%m%d_v??.cdf'
139144
elif instrument == 'cis':
140-
pathformat = 'c'+prb+'/'+datatype+'/'+instrument+'/%Y/c'+prb+'_'+datatype+'_'+instrument+'_%Y%m%d_v??.cdf'
145+
if species == None:
146+
pathformat = 'c'+prb+'/'+datatype+'/'+instrument+'/%Y/c'+prb+'_'+datatype+'_'+instrument+'_%Y%m%d_v??.cdf'
147+
else:
148+
if species == 'h1':
149+
scd = 'proton' # second name for H+
150+
if species == 'he1':
151+
scd = 'heplus' # second name for He+
152+
if species == 'o1':
153+
scd = 'oplus' # second name for O+
154+
pathformat = 'c'+prb+'/'+instrument+'-codif/'+scd+'_3ddist_highsens_phasespacedens'+'/%Y/c'+prb+'_cp_'+instrument+'-codif_hs_'+species+'_psd'+'_%Y%m%d_v????????.cdf'
141155
elif instrument == 'dwp':
142156
pathformat = 'c'+prb+'/'+datatype+'/'+instrument+'/%Y/c'+prb+'_'+datatype+'_'+instrument+'_%Y%m%d_v??.cdf'
143157
elif instrument == 'edi':

0 commit comments

Comments
 (0)