-
Notifications
You must be signed in to change notification settings - Fork 29
Adds livetime correction to get data #192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5fc327e
d739718
4645db0
677220e
bb73b37
f8a8890
10e8dd3
e11a2c4
8fb1a27
81c8544
dbb9edd
79ff5f7
150e10d
9d2f182
e3ea8dd
826c56f
18493f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| from pathlib import Path | ||
|
|
||
| import numpy as np | ||
|
|
||
| from stixpy.calibration.detector import get_sci_channels | ||
| from stixpy.io.readers import read_elut, read_elut_index | ||
| import datetime | ||
|
|
||
| __all__ = ["get_elut", "get_elut_correction"] | ||
|
|
||
| def get_elut(date): | ||
| r""" | ||
| Get the energy lookup table (ELUT) for the given date | ||
|
|
||
| Combines the ELUT with the science energy channels for the same date. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| date `astropy.time.Time` | ||
| Date to look up the ELUT. | ||
|
|
||
| Returns | ||
| ------- | ||
|
|
||
| """ | ||
|
|
||
| # date = datetime.datetime(2023,11,15,0,0,0) | ||
|
|
||
| root = Path(__file__).parent.parent | ||
| elut_index_file = Path(root, *["config", "data", "elut", "elut_index.csv"]) | ||
|
|
||
| elut_index = read_elut_index(elut_index_file) | ||
| elut_info = elut_index.at(date) | ||
| if len(elut_info) == 0: | ||
| raise ValueError(f"No ELUT for for date {date}") | ||
| elif len(elut_info) > 1: | ||
| raise ValueError(f"Multiple ELUTs for for date {date}") | ||
| start_date, end_date, elut_file = list(elut_info)[0] | ||
| sci_channels = get_sci_channels(date) | ||
|
|
||
| # print('ELUT_FILENAME = ' , elut_file) | ||
|
|
||
| elut_table = read_elut(elut_file, sci_channels) | ||
|
|
||
| return elut_table | ||
|
|
||
| def get_elut_correction(e_ind, pixel_data): | ||
| r""" | ||
| Get ELUT correction factors | ||
|
|
||
| Only correct the low and high energy edges as internal bins are contiguous. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| e_ind : `np.ndarray` | ||
| Energy channel indices | ||
| pixel_data : `~stixpy.products.sources.CompressedPixelData` | ||
| Pixel data | ||
|
|
||
| Returns | ||
| ------- | ||
|
|
||
| """ | ||
|
|
||
| energy_mask = pixel_data.energy_masks.energy_mask.astype(bool) | ||
| elut = get_elut(pixel_data.time_range.center) | ||
| ebin_edges_low = np.zeros((32, 12, 32), dtype=float) | ||
| ebin_edges_low[..., 1:] = elut.e_actual | ||
| ebin_edges_low = ebin_edges_low[..., energy_mask] | ||
| ebin_edges_high = np.zeros((32, 12, 32), dtype=float) | ||
| ebin_edges_high[..., 0:-1] = elut.e_actual | ||
| ebin_edges_high[..., -1] = np.nan | ||
| ebin_edges_high = ebin_edges_high[..., energy_mask] | ||
| ebin_widths = ebin_edges_high - ebin_edges_low | ||
| ebin_sci_edges_low = elut.e[..., 0:-1].value | ||
| ebin_sci_edges_low = ebin_sci_edges_low[..., energy_mask] | ||
| ebin_sci_edges_high = elut.e[..., 1:].value | ||
| ebin_sci_edges_high = ebin_sci_edges_high[..., energy_mask] | ||
| e_cor_low = (ebin_edges_high[..., e_ind[0]] - ebin_sci_edges_low[..., e_ind[0]]) / ebin_widths[..., e_ind[0]] | ||
| e_cor_high = (ebin_sci_edges_high[..., e_ind[-1]] - ebin_edges_low[..., e_ind[-1]]) / ebin_widths[..., e_ind[-1]] | ||
|
|
||
| numbers = np.array([ | ||
| 0, 1, 2, 3, 4, 5, 6, 7, 13, 14, 15, 19, 20, 21, 22, 23, 24, 25, | ||
| 26, 27, 28, 29, 30, 31 | ||
| ]) | ||
|
|
||
| bins = ebin_sci_edges_high - ebin_sci_edges_low | ||
|
|
||
| det_indices_top24 = np.array([0, 1, 2, 3, 4, 5, 6, 7, 13, 14, 15, 19, | ||
| 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]) | ||
|
|
||
| det_indices_full = np.where(pixel_data.detector_masks.__dict__['masks'] == 1 )[1] | ||
|
|
||
| det_indices = [d for i,d in enumerate(det_indices_top24) if d in det_indices_full] | ||
|
|
||
| # det_indices = np.where(self.detector_masks.__dict__['masks'] == 1 )[1] | ||
|
|
||
| pix_indices = np.where(pixel_data.pixel_masks.__dict__['masks'] == 1 )[1] | ||
|
|
||
| bins_actual_1 = ebin_widths[det_indices, :, :] | ||
| bins_actual = bins_actual_1[:, pix_indices, :].mean(axis=1).mean(axis=0) | ||
|
|
||
|
|
||
| cor = bins / bins_actual | ||
| # print('ELUT_COR = ',cor) | ||
|
|
||
| return e_cor_high, e_cor_low, cor |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
|
|
||
| import logging | ||
|
|
||
| import astropy.units as u | ||
| import matplotlib.pyplot as plt | ||
| import numpy as np | ||
| from astropy.coordinates import SkyCoord | ||
| from sunpy.coordinates import HeliographicStonyhurst, Helioprojective, frames | ||
| from sunpy.map import Map, make_fitswcs_header | ||
| from sunpy.time import TimeRange | ||
| from xrayvision.clean import vis_clean | ||
| from xrayvision.imaging import vis_to_image, vis_to_map | ||
| from xrayvision.mem import mem, resistant_mean | ||
|
|
||
| from stixpy.calibration.visibility import calibrate_visibility, create_meta_pixels, create_visibility | ||
| from stixpy.coordinates.frames import STIXImaging | ||
| from stixpy.coordinates.transforms import get_hpc_info | ||
| from stixpy.imaging.em import em | ||
| from stixpy.map.stix import STIXMap # noqa | ||
| from stixpy.product import Product | ||
|
|
||
|
|
||
|
|
||
| __all__ = [ | ||
| "estimate_flare_location", | ||
| ] | ||
|
|
||
| def estimate_flare_location(sci_file,time_range_sci): | ||
|
|
||
| energy_range = [6.,10.] * u.keV | ||
| imsize = [512,512] * u.pixel | ||
| pixel = [10, 10] * u.arcsec / u.pixel | ||
|
|
||
| cpd_sci = Product(sci_file) | ||
|
|
||
| meta_pixels_sci = create_meta_pixels( | ||
| cpd_sci, time_range=time_range_sci, energy_range=energy_range, flare_location=[0, 0] * u.arcsec, no_shadowing=True | ||
| ) | ||
|
|
||
| vis = create_visibility(meta_pixels_sci) | ||
|
|
||
| vis_tr = TimeRange(vis.meta["time_range"]) | ||
| roll, solo_xyz, pointing = get_hpc_info(vis_tr.start, vis_tr.end) | ||
| solo = HeliographicStonyhurst(*solo_xyz, obstime=vis_tr.center, representation_type="cartesian") | ||
| center_hpc = SkyCoord(0 * u.deg, 0 * u.deg, frame=Helioprojective(obstime=vis_tr.center, observer=solo)) | ||
|
|
||
| cal_vis = calibrate_visibility(vis, flare_location=center_hpc) | ||
|
|
||
| # order by sub-collimator e.g. 10a, 10b, 10c, 9a, 9b, 9c .... | ||
| isc_10_7 = [3, 20, 22, 16, 14, 32, 21, 26, 4, 24, 8, 28] | ||
| idx = np.argwhere(np.isin(cal_vis.meta["isc"], isc_10_7)).ravel() | ||
|
|
||
| vis10_7 = cal_vis[idx] | ||
|
|
||
| bp_image = vis_to_image(vis10_7, imsize, pixel_size=pixel) | ||
|
|
||
| vis_tr = TimeRange(vis.meta["time_range"]) | ||
| roll, solo_xyz, pointing = get_hpc_info(vis_tr.start, vis_tr.end) | ||
| solo = HeliographicStonyhurst(*solo_xyz, obstime=vis_tr.center, representation_type="cartesian") | ||
| coord_stix = center_hpc.transform_to(STIXImaging(obstime=vis_tr.start, obstime_end=vis_tr.end, observer=solo)) | ||
| header = make_fitswcs_header( | ||
| bp_image, coord_stix, telescope="STIX", observatory="Solar Orbiter", scale=[10, 10] * u.arcsec / u.pix | ||
| ) | ||
| fd_bp_map = Map((bp_image, header)) | ||
|
|
||
| max_pixel = np.argwhere(fd_bp_map.data == fd_bp_map.data.max()).ravel() * u.pixel | ||
| # because WCS axes and array are reversed | ||
| max_stix = fd_bp_map.pixel_to_world(max_pixel[1], max_pixel[0]) | ||
|
|
||
| hpc_x = max_stix.transform_to(frames.Helioprojective).Tx.value | ||
| hpc_y = max_stix.transform_to(frames.Helioprojective).Ty.value | ||
|
|
||
| stx_x = max_stix.Tx.value | ||
| stx_y = max_stix.Ty.value | ||
|
|
||
| dictionary = {'stx':np.array([stx_x,stx_y]), | ||
| 'hpc':np.array([hpc_x,hpc_y])} | ||
|
|
||
| return dictionary |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,13 +7,14 @@ | |
| import astropy.units as u | ||
| import numpy as np | ||
| from astropy.table import Table | ||
| import xraydb | ||
|
|
||
| __all__ = ["get_grid_transmission", "_calculate_grid_transmission"] | ||
|
|
||
| from stixpy.coordinates.frames import STIXImaging | ||
|
|
||
|
|
||
| def get_grid_transmission(flare_location: STIXImaging): | ||
| def get_grid_transmission(ph_energy, flare_location: STIXImaging): | ||
| r""" | ||
| Return the grid transmission for the 32 sub-collimators corrected for internal shadowing. | ||
|
|
||
|
|
@@ -32,18 +33,141 @@ def get_grid_transmission(flare_location: STIXImaging): | |
| front = Table.read(grid_info / "grid_param_front.txt", format="ascii", names=column_names) | ||
| rear = Table.read(grid_info / "grid_param_rear.txt", format="ascii", names=column_names) | ||
|
|
||
| transmission_front = _calculate_grid_transmission(front, flare_location) | ||
| transmission_rear = _calculate_grid_transmission(rear, flare_location) | ||
| total_transmission = transmission_front * transmission_rear | ||
| # ;; Orientation of the slits of the grid as seen from the detector side | ||
| grid_orient_front_all = front['o'] | ||
| grid_orient_rear_all = rear['o'] | ||
|
|
||
| pitch_front_all = front['p'] | ||
| pitch_rear_all = rear['p'] | ||
|
|
||
| thickness_front_all = front['thick'] | ||
| thickness_rear_all = rear['thick'] | ||
|
|
||
| sc = front['sc'] | ||
|
|
||
|
|
||
| # fpath = loc_file( 'CFL_subcoll_transmission.txt', path = getenv('STX_GRID') ) | ||
| column_names_cfl = ["subc_n", "subc_label", "intercept", "slope[1/deg]"] | ||
|
|
||
| subcol_transmission = Table.read(grid_info / "CFL_subcoll_transmission.txt", format="ascii", names=column_names_cfl) | ||
|
|
||
| subc_n_all = subcol_transmission['subc_n'] | ||
| subc_label = subcol_transmission['subc_label'] | ||
| intercept_all = subcol_transmission['intercept'] | ||
| slope_all = subcol_transmission['slope[1/deg]'] | ||
|
|
||
|
|
||
| muvals = xraydb.material_mu('W', ph_energy * 1e3, density=19.30, kind='total') / 10 # in units of mm^-1 | ||
| L = 1 / muvals | ||
| # print('L = ', L) | ||
| # trans = np.exp(-0.4 / L) | ||
| subc_transm=L | ||
|
|
||
| det_indices_top24 = np.array([0, 1, 2, 3, 4, 5, 6, 7, 13, 14, 15, 19, | ||
| 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]) | ||
| # det_all = np.arange(0,32,1) | ||
|
|
||
| # det_indices_top24 = [0, 1, 2, 3, 4, 5, 6, 7, 13, 14, 15, 19, | ||
| # 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31] | ||
| idx_full = det_indices_top24 | ||
| idx = [i for i,x in enumerate(sc-1) if x in det_indices_top24] | ||
| # print('idx = ', idx) | ||
| # print('lenidx = ',len(idx)) | ||
| # idx = det_all | ||
|
|
||
| # # for i,idx in enumerate(idx_full): | ||
| # print(grid_orient_front_all) | ||
|
|
||
| grid_orient_front = grid_orient_front_all[idx] | ||
| pitch_front = pitch_front_all[idx] | ||
| thickness_front = thickness_front_all[idx] | ||
|
|
||
| # ;;------ Rear grid | ||
| grid_orient_rear = grid_orient_rear_all[idx] | ||
| pitch_rear = pitch_rear_all[idx] | ||
| thickness_rear = thickness_rear_all[idx] | ||
|
|
||
| grid_orient_avg = (grid_orient_front + grid_orient_rear) / 2 | ||
|
|
||
| flare_loc_deg = flare_location / 3600 #. ;; Convert coordinates to deg | ||
| theta = flare_loc_deg[0] * np.cos(np.deg2rad(grid_orient_avg)) + flare_loc_deg[1] * np.sin(np.deg2rad(grid_orient_avg)) | ||
| # print('THETA = ', theta) | ||
|
|
||
| # ;;------ Subcollimator tranmsission at low energies | ||
| # idx = np.where(subc_n_all eq (subc_n+1)) | ||
|
|
||
| intercept = intercept_all[det_indices_top24] | ||
| slope = slope_all[det_indices_top24] | ||
| subc_transm_low_e = intercept + slope * theta | ||
|
|
||
| # ;;------ Transmission of front and rear grid | ||
| slit_to_pitch = np.sqrt(subc_transm_low_e) | ||
|
|
||
| slit_front = slit_to_pitch*pitch_front | ||
| slit_rear = slit_to_pitch*pitch_rear | ||
|
|
||
| transm_front = stx_grid_transmission(pitch_front, slit_front, thickness_front, L) | ||
| transm_rear = stx_grid_transmission(pitch_rear, slit_rear, thickness_rear, L) | ||
|
|
||
| # subc_transm.append(transm_front * transm_rear) | ||
|
|
||
| subc_transm = transm_front * transm_rear | ||
|
|
||
| # transmission_front = _calculate_grid_transmission(front, flare_location) | ||
| # transmission_rear = _calculate_grid_transmission(rear, flare_location) | ||
| # total_transmission = transmission_front * transmission_rear | ||
|
|
||
| # The finest grids are made from multiple layers for the moment remove these and set 1 | ||
| final_transmission = np.ones(32) | ||
| sc = front["sc"] | ||
| finest_scs = [11, 12, 13, 17, 18, 19] # 1a, 2a, 1b, 2c, 1c, 2b | ||
| idx = np.argwhere(np.isin(sc, finest_scs, invert=True)).ravel() | ||
| final_transmission[sc[idx] - 1] = total_transmission[idx] | ||
|
|
||
| return final_transmission | ||
| # final_transmission = np.ones(32) | ||
| # sc = front["sc"] | ||
| # finest_scs = [11, 12, 13, 17, 18, 19] # 1a, 2a, 1b, 2c, 1c, 2b | ||
| # idx = np.argwhere(np.isin(sc, finest_scs, invert=True)).ravel() | ||
| # final_transmission[sc[idx] - 1] = total_transmission[idx] | ||
|
|
||
| # print('subc = ',subc_transm) | ||
| return subc_transm | ||
|
|
||
|
|
||
| def stx_grid_transmission(pitch, slit, thickness, L): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needs a docstring and test |
||
|
|
||
| ds = 5e-3 | ||
| dh = 5e-2 | ||
|
Comment on lines
+133
to
+134
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Magic numbers need at least comment and ideally units |
||
|
|
||
| # n_energies = np.shape(L)[0] | ||
| # n_subc = np.shape(pitch) | ||
|
|
||
| slit_rep = slit.reshape(1, len(slit)) | ||
| pitch_rep = pitch.reshape(1, len(pitch)) | ||
| H_rep = thickness.reshape(1, len(thickness)) | ||
| L_rep = L.reshape(len(L), 1) | ||
|
|
||
| # print('slit = ',slit[0]) | ||
| # print('pitch = ',pitch[0]) | ||
| # print('h_rep = ',thickness[0]) | ||
|
|
||
| # slit_rep = np.tile(slit, (n_energies, 1)) | ||
| # pitch_rep = np.tile(pitch, (n_energies, 1)) | ||
| # H_rep = np.tile(thickness, (n_energies, 1)) | ||
| # L_rep = np.tile(L, (n_subc, 1)).T | ||
|
|
||
| # print(np.shape(slit_rep)) | ||
| # print(np.shape(pitch_rep)) | ||
| # print(np.shape(H_rep)) | ||
| # print(np.shape(L_rep)) | ||
|
|
||
| # ;; Transmission for a wedge shape model for grid imperfections | ||
| g0 = slit_rep / pitch_rep + (pitch_rep - slit_rep) / pitch_rep * np.exp( - H_rep / L_rep ) | ||
| ttt = L_rep / dh * ( 1. - np.exp(- dh / L_rep ) ) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. naming
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ask paolo |
||
| g1 = 2. * ds / pitch_rep * (ttt - np.exp( - H_rep / L_rep )) | ||
|
|
||
| # print('g0 = ',g0[:,0]) | ||
| # print('g1 = ',g1[:,0]) | ||
|
|
||
| g_transmission = g0 + g1 | ||
|
|
||
| # print('transmission = ',g_transmission) | ||
|
|
||
| return g_transmission | ||
|
|
||
|
|
||
| def _calculate_grid_transmission(grid_params, flare_location): | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we already use
roentgenshould either migrate toxraydbor keep using