@@ -66,12 +66,11 @@ def calculate_phase_space_density(
6666 # Calculate phase space density using formula:
6767 # 2 * ((C/tau) or uncertainty data) / (G * 1.237e31 * eV^2)
6868 # See doc string for more details.
69- density = (2 * data ) / (
69+ phase_space_density = (2 * data ) / (
7070 swe_constants .GEOMETRIC_FACTORS [np .newaxis , np .newaxis , np .newaxis , :]
7171 * swe_constants .VELOCITY_CONVERSION_FACTOR
7272 * particle_energy_data [:, :, :, np .newaxis ] ** 2
7373 )
74- phase_space_density = density
7574
7675 return phase_space_density
7776
@@ -133,8 +132,72 @@ def calculate_flux(
133132 return flux
134133
135134
135+ def put_uncertainty_into_angle_bins (
136+ data : np .ndarray , angle_bin_indices : npt .NDArray [np .int_ ]
137+ ) -> npt .NDArray :
138+ """
139+ Put uncertainty data in its angle bins.
140+
141+ This function bins uncertainty data into 30 predefined angle bins
142+ while preserving the original energy step structure.
143+
144+ Since multiple data points can fall into the same angle bin,
145+ this function computes the combined uncertainty for the bin.
146+
147+ Parameters
148+ ----------
149+ data : numpy.ndarray
150+ Uncertainty data to put in bins. Shape:
151+ (full_cycle_data, N_ESA_STEPS, N_ANGLE_BINS, N_CEMS).
152+ angle_bin_indices : numpy.ndarray
153+ Indices of angle bins to put data in. Shape:
154+ (full_cycle_data, N_ESA_STEPS, N_ANGLE_BINS).
155+
156+ Returns
157+ -------
158+ numpy.ndarray
159+ Data in bins. Shape:
160+ (full_cycle_data, N_ESA_STEPS, N_ANGLE_BINS, N_CEMS).
161+ """
162+ # Initialize with zeros instead of NaN because np.add.at() does not
163+ # work with nan values. It results in nan + value = nan
164+ binned_data = np .zeros (
165+ (
166+ data .shape [0 ],
167+ swe_constants .N_ESA_STEPS ,
168+ swe_constants .N_ANGLE_BINS ,
169+ swe_constants .N_CEMS ,
170+ ),
171+ dtype = np .float64 ,
172+ )
173+
174+ time_indices = np .arange (data .shape [0 ])[:, None , None ]
175+ energy_indices = np .arange (swe_constants .N_ESA_STEPS )[None , :, None ]
176+
177+ # Calculate new uncertainty of each uncertainty data in the bins.
178+ # Per SWE instruction:
179+ # At L1B, 'data' is result from sqrt(counts). Now in L2, average
180+ # uncertainty data using this formula:
181+ # sqrt(
182+ # sum(
183+ # (unc_1) ** 2 + (unc_2) ** 2 + ... + (unc_n) ** 2
184+ # )
185+ # )
186+ # TODO: SWE want to add more defined formula based on spin data and
187+ # counts uncertainty from it in the future.
188+
189+ # Use np.add.at() to put values into bins and add values in the bins into one.
190+ # Here, we are applying power of 2 to each data point before summing them.
191+ np .add .at (
192+ binned_data ,
193+ (time_indices , energy_indices , angle_bin_indices ),
194+ data ** 2 ,
195+ )
196+ return np .sqrt (binned_data )
197+
198+
136199def put_data_into_angle_bins (
137- data : np .ndarray , angle_bin_indices : npt .NDArray [np .int_ ], is_unc : bool = False
200+ data : np .ndarray , angle_bin_indices : npt .NDArray [np .int_ ]
138201) -> npt .NDArray :
139202 """
140203 Put data in its angle bins.
@@ -145,10 +208,7 @@ def put_data_into_angle_bins(
145208 based on the provided indices.
146209
147210 Since multiple data points can fall into the same angle bin,
148- this function assigns each data point to its bin and sums
149- the values within that bin. If the data is uncertainty data,
150- it computes the combined uncertainty for the bin; otherwise,
151- it calculates the averages.
211+ this function computes the combined averages.
152212
153213 Parameters
154214 ----------
@@ -158,10 +218,6 @@ def put_data_into_angle_bins(
158218 angle_bin_indices : numpy.ndarray
159219 Indices of angle bins to put data in. Shape:
160220 (full_cycle_data, N_ESA_STEPS, N_ANGLE_BINS).
161- is_unc : bool
162- Whether data is uncertainty data or not. If yes, sqrt(sum(data)).
163- Otherwise, find mean of data.
164- Default to False.
165221
166222 Returns
167223 -------
@@ -184,28 +240,6 @@ def put_data_into_angle_bins(
184240 time_indices = np .arange (data .shape [0 ])[:, None , None ]
185241 energy_indices = np .arange (swe_constants .N_ESA_STEPS )[None , :, None ]
186242
187- if is_unc :
188- # Calculate new uncertainty of each uncertainty data in the bins.
189- # Per SWE instruction:
190- # At L1B, 'data' is result from sqrt(counts). Now in L2, average
191- # uncertainty data using this formula:
192- # sqrt(
193- # sum(
194- # (unc_1) ** 2 + (unc_2) ** 2 + ... + (unc_n) ** 2
195- # )
196- # )
197- # TODO: SWE want to add more defined formula based on spin data and
198- # counts uncertainty from it in the future.
199-
200- # Use np.add.at() to put values into bins and add values in the bins into one.
201- # Here, we are applying power of 2 to each data point before summing them.
202- np .add .at (
203- binned_data ,
204- (time_indices , energy_indices , angle_bin_indices ),
205- data ** 2 ,
206- )
207- return np .sqrt (binned_data )
208-
209243 # Use np.add.at() to put values into bins and add values in the bins into one.
210244 np .add .at (binned_data , (time_indices , energy_indices , angle_bin_indices ), data )
211245
@@ -459,8 +493,8 @@ def swe_l2(l1b_dataset: xr.Dataset) -> xr.Dataset:
459493 l1b_dataset ["counts_stat_uncert" ].data , l1b_dataset ["esa_energy" ].data
460494 )
461495 # Put uncertainty data into its spin angle bins and calculate new uncertainty
462- phase_space_density_uncert = put_data_into_angle_bins (
463- phase_space_density_uncert , spin_angle_bins_indices , is_unc = True
496+ phase_space_density_uncert = put_uncertainty_into_angle_bins (
497+ phase_space_density_uncert , spin_angle_bins_indices
464498 )
465499 dataset ["psd_stat_uncert" ] = xr .DataArray (
466500 phase_space_density_uncert ,
@@ -472,9 +506,7 @@ def swe_l2(l1b_dataset: xr.Dataset) -> xr.Dataset:
472506 flux_uncert = calculate_flux (
473507 phase_space_density_uncert , l1b_dataset ["esa_energy" ].data
474508 )
475- flux_uncert = put_data_into_angle_bins (
476- flux_uncert , spin_angle_bins_indices , is_unc = True
477- )
509+ flux_uncert = put_uncertainty_into_angle_bins (flux_uncert , spin_angle_bins_indices )
478510 dataset ["flux_stat_uncert" ] = xr .DataArray (
479511 flux_uncert ,
480512 name = "flux_stat_uncert" ,
0 commit comments