Draft: Add Phase-Resolved Analysis Tutorial and Tools.#497
Conversation
hiyoneda
left a comment
There was a problem hiding this comment.
Thanks @KoothodilAbhijithAugustine, I am checking your codes. Let me share some comments.
| Selects events based on pulsar phase. | ||
| Highly optimized for FITS files via NumPy vectorization. | ||
| """ | ||
| def __init__(self, ephemeris_file, pstart, pstop, batch_size=10000): |
There was a problem hiding this comment.
Better to allow users to put a list of phase interval ranges.
|
|
||
| def _get_vectorized_mask(self, phases: np.ndarray) -> np.ndarray: | ||
| """Core logic applied across an entire NumPy array instantly.""" | ||
| pstop_norm = self.pstop % 1.0 if self.pstop > 1.0 else self.pstop |
There was a problem hiding this comment.
If the multiple ranges are allowered, we can constrain the pstop and pstat to be from 0 to 1.
| self.params = self._parse_par_file(par_file) | ||
|
|
||
| # Parse F0 (Frequency) or P0 (Period) | ||
| if 'F0' in self.params: |
There was a problem hiding this comment.
For future work: let's put "F1" and "F2" in the future, not this time.
| logger = logging.getLogger(__name__) | ||
|
|
||
| # --- ROBUST IMPORTS (Safety Switch) --- | ||
| try: |
There was a problem hiding this comment.
The new interface has been merged, so this part can be updated.
| for sel in mask: | ||
| yield bool(sel) | ||
|
|
||
| def filter_events(self, events, output_fits=None, template_fits=None): |
There was a problem hiding this comment.
filter_event, _save_fits_fast, and save_fits can be removed because these functionalities should be implemented as a part of DataIO and are duplicated if they are added here.
There was a problem hiding this comment.
Since we decided to make this class independent of the event selection interface, we can leave these methods.
| Generates a 3-panel figure: Pulse Profile, Phaseogram, and Significance Test. | ||
| Optimized for direct FITS table input (vectorized). | ||
| """ | ||
| def __init__(self, data, n_bins=50, n_time_bins=50): |
There was a problem hiding this comment.
I'd be happy if you could add a docstring here to explain what kind of "data" is assumed as an input of this class.
There was a problem hiding this comment.
Also, what kinds of plots will be generated
| if not batch: return | ||
| yield batch | ||
|
|
||
| class TimeSelector(EventSelectorInterface): |
There was a problem hiding this comment.
you can delete this class.
|
I checked the notebooks and found some issues. This is a draft pull request, so you may already have noticed these points and plan to resolve them in the next pull request. Let me share them anyway.
With modifications, the notebook worked well in my environment. |
|
@israelmcmc |
|
@hirokiyoneda Here's how the event selection works, but please see my point at the end that it might now be the best way to go about this for the phase. Currently the only example of an The Note that Ideally, For the case at hand, phase selection, you would need:
However, using a |
|
On a separate topic, note that we'll also need a method to update the exposure in |
|
Thanks @israelmcmc for the thorough explanation. I understand that the For Does this two-step approach sound reasonable to you @israelmcmc @KoothodilAbhijithAugustine ? |
|
@hiyoneda Yes, I'm OK with the plan for PhaseSelector/UnbinnedData. It is indeed hard to achieve a nice integration with the interfaces without refactoring DataIO first, so we can wait until then. For class PhaseEphemeris(Protocol):
def get_phase(time:Time) -> np.ndarray:
""""
Assign a phase between 0 an 1 to each timestamp.
""""
def get_duty_cycle(time_start:Time, time_stop:Time, phase_start:float, phase_stop:float) -> u.Quantity:
""""
Compute the time spend between the phase range for each time range.
""""
Then, we can add a method to class SpacecraftHistory:
def update_ephemeris(ephemeris: PhaseEphemeris, phase_start:float, phase_stop:float):
"""
Updates live time based on a phase cut.
"""
# Here you can call ephemeris.get_duty_cycle()The advantages:
|
|
@israelmcmc Thanks. Adding the new protocol and the method to SpacecraftHistory in this PR sounds good. |

Description
Resolves #395 and #413
This draft PR introduces a complete tutorial and a set of supporting Python tools for performing phase-resolved pulsar analysis within the
cosipyframework.Currently, the workflow demonstrates how to process Data Challenge 2 (DC2) FITS data for the Crab pulsar and its corresponding albedo background. The end goal of this pipeline is to prepare isolated on-pulse and off-pulse FITS files that are ready for downstream COSI Spectral Fitting.
Key Additions
example_notebook.ipynb): A step-by-step Jupyter Notebook guiding users through combining unbinned data, slicing by Mission Elapsed Time (MET), assigning phases, plotting the pulse profile, and selecting phase intervals.phase_assigner.py: A new module that reads a pulsar ephemeris file (e.g.,crab.par) and calculates/appends the exact rotational phase to individual photon events in a FITS file.plot_pulse_profile.py: A plotting utility to generate and visualize the folded light curve/pulse profile from the phase-assigned data.phase_selector.py: A filtering tool to extract specific phase windows (e.g., on-pulse and off-pulse regions) and save them as new FITS files.