diff --git a/will/calculate.py b/will/calculate.py index aebc0f0..634a1d7 100644 --- a/will/calculate.py +++ b/will/calculate.py @@ -24,14 +24,14 @@ def std_min_func(sigma: float, mu: float, std: float) -> float: have standard deviation `std` Args: - sigma - lognormal sigma + sigma: lognormal sigma. - mu - lognormal mu + mu: lognormal mu. - std - The desired standard deviation + std: The desired standard deviation. Returns: - desired variance - Actual variance(sigma, mu) + Desired variance - Actual variance(sigma, mu). """ return std**2 - (np.exp(sigma**2) - 1) * np.exp(2 * mu + sigma**2) @@ -42,12 +42,12 @@ def log_normal_from_stats(median: float, std: float, size: int) -> np.ndarray: and standard deviation. Args: - median - median of resulting distribution + median: median of resulting distribution. - std - Standard deviation of returned samples + std: Standard deviation of returned samples. Returns: - `size` numbers from the sampled from lognormal distribution + `size` numbers from the sampled from lognormal distribution. """ mu = np.log(median) sigma_guess = np.sqrt(mu - 0.5 * np.log(std**2)) @@ -75,19 +75,20 @@ def quicksort( Quicksort in place. Args: - array - Array to be sorted + array: Array to be sorted. - left - Left most element of sort + left: Left most element of sort (Optional). - right - Right most element of sort + right: Right most element of sort (Optional). - sort_fraction - The fraction of the array to - stop sorting. + sort_fraction: The fraction of the array to + stop sorting, default is to sort + entire array (Optional). - sort_ascend - Sort increasing + sort_ascend: Sort increasing (Optional). Returns: - None - Sort in place + None: Sort in place (Optional). """ if left is None: left = 0 @@ -133,15 +134,16 @@ def sort_subarrays( type shape. Args: - array - array to sort + array: Array to sort. - num_subarrays - Number of subarrays to sort + num_subarrays: Number of subarrays to sort. - sort_fraction - The fraction of the subarray to - stop sorting. + sort_fraction: The fraction of the subarray to + stop sorting, default is to sort + the entire array (Optional). Returns: - Subarray sorted (also is sorted in place) + Subarray sorted (also is sorted in place). """ splits = np.array_split(array, num_subarrays) for j, split in enumerate(splits): @@ -159,14 +161,14 @@ def calculate_dm_widths( Eqn 2 in seconds. Args: - dm - The Dispersion Measure in pc/cm^3. + dm: The Dispersion Measure [pc/cm^3]. - channel_width - The channel width in MHz. + channel_width: The channel width [MHz]. - chan_freqs - The channel frequencies in MHz. + chan_freqs: The channel frequencies [MHz]. Returns: - inter-channel dm smearing in seconds + inter-channel dm smearing in seconds. """ return 8.3 / 10e6 * dm * channel_width * (1000 / chan_freqs) ** 3 @@ -177,16 +179,16 @@ def calculate_dm_boxcar_widths( chan_freqs: np.ndarray, ) -> np.ndarray: """ - This calculates the boxcar widths in samples that correspond to the + This calculates the boxcar widths in samples that correspond to the inter-channel dispersion delays in seconds. If delay is less than - than the sample time of one, return a boxcar width of one. + than the sample time of one, return a boxcar width of one. Args: - dm - Dispersion Measure in pc/cm^3. + dm: Dispersion Measure [pc/cm^3]. - sampling_time - Sampling time of data. + sampling_time: Sampling time of data [second]. - chan_freqs - The channel frequencies in MHz. + chan_freqs: The channel frequencies [MHz]. Returns: Array with boxcar lengths in samples. @@ -207,12 +209,12 @@ def generate_boxcar_array( Make a 2D array of boxcars for the given boxcar_lengths. Args: - boxcar_lengths - Array of boxcar lengths. + boxcar_lengths: Array of boxcar lengths. - normalization_func - Function to normalize the boxcar, default - is to use sqrt. + normalization_func: Function to normalize the boxcar, default + is to use sqrt (Optional). - return_max - Return max boxcar length + return_max: Return max boxcar length (Optional). Returns: Array of boxcars, with the boxcars stacked horizontally. @@ -235,13 +237,13 @@ def convolve_multi_boxcar(profile: np.ndarray, boxcar_array: np.ndarray) -> np.n Convolve an profile array with an array that contains multiple boxcars. Args: - profile - 1D or 2D array that contains the profile. For 1D array, - will be convolved with all boxcars. If 2D, time should - be on the vertical axis and number of profiles and - boxcars should match. + profile: 1D or 2D array that contains the profile. For 1D array, + will be convolved with all boxcars. If 2D, time should + be on the vertical axis and number of profiles and + boxcars should match. - boxcar_array - Array containing boxcars, boxcars should be stacked along - axis=1, see `generate_boxcar_array`. + boxcar_array: Array containing boxcars, boxcars should be stacked along + axis=1, see `generate_boxcar_array`. Returns: Profile convolved with the boxcar_array. @@ -269,12 +271,12 @@ def boxcar_convolved(time_profile: np.ndarray, boxcar_widths: np.ndarray) -> np. Calculate the pulse profile convolved with a boxcar width. Args: - time_profile - Time profile of the pulse + time_profile: Time profile of the pulse (Optional). - boxcar_widths - Array of boxcar widths + boxcar_widths: Array of boxcar widths (Optional). Returns: - Pulse profile convolved with a boxcar + Pulse profile convolved with a boxcar. """ boxcar_widths = np.array(boxcar_widths, ndmin=1) powers = np.zeros(boxcar_widths.shape, dtype=np.float64) @@ -295,12 +297,12 @@ def median_line_detrend(array: np.ndarray, num_sample: int) -> np.ndarray: to these medians, then subtracting this line. Args: - array - Array to detrend. + array: Array to detrend. - num_samples - Number of samples per median block. + num_samples: Number of samples per median block. Return: - array with trend subtracted. + Array with trend subtracted. Inspired by 'Advanced Architectures for Astrophysical Supercomputing', section 4.2.3 @@ -347,18 +349,18 @@ def calculate_noises_multi( Then use `scale_func` to calculate the noise level. Args: - time_series - The dedispersed time series. + time_series: The dedispersed time series. - box_car_length - Length of the boxcars. + box_car_length: Length of the boxcars. - sigma - Return pulses with significance above + sigma: Return pulses with significance above this - smoothing_factor - Detrend blocks are - smoothing_factor*box_car_length long. + smoothing_factor: Detrend blocks are + smoothing_factor*box_car_length long (Optional). - scale_func - The function used to calculate the measure of scale. - must accept `axis=0` argument. + scale_func: The function used to calculate the measure of scale. + must accept `axis=0` argument (Optional). Returns: Measures of scale for each boxcar in `boxcar array`. @@ -379,12 +381,13 @@ class NoiseInfoResult: """ The noise levels for a file. - noise_levels - The noise level at each location (row) and - each boxcar, column. + Args: + noise_levels: The noise level at each location (row) and + each boxcar, column. - boxcar_lengths - Length of the boxcars. + boxcar_lengths: Length of the boxcars. - num_chans - Number of channels. + num_chans: Number of channels. """ noise_levels: np.ndarray @@ -395,13 +398,25 @@ class NoiseInfoResult: def mean_noise_levels(self): """ The mean noise levels across the file. + + Args: + None. + + Returns: + Average noise level in the file. """ return self.noise_levels.mean(axis=0) @property def median_noise_levels(self): """ - The mean noise levels across the file. + The median noise levels across the file. + + Args: + None. + + Returns: + Median noise level across the file. """ return np.median(self.noise_levels, axis=0) @@ -446,18 +461,18 @@ def noise_info( convolved with boxcars of the given length. The noise is then calculated my MAD. Args: - file_path - String that is the path to a file. + file_path: String that is the path to a file. - dm - Dispersion Measure in pc/cm^3. + dm: Dispersion Measure [pc/cm^3]. - boxcar_lengths - Numpy array of boxcar lengths to consider. + boxcar_lengths: Numpy array of boxcar lengths to consider. - num_locations - Number of locations in the file to consider. + num_locations: Number of locations in the file to consider (Optional). - num_samples - Number of sample to consider, must be 4 times the - largest boxcar. + num_samples: Number of sample to consider, must be 4 times the + largest boxcar (Optional). - chan_mask - Mask these channels if given. True=value to mask + chan_mask: Mask these channels if given. True=value to mask (Optional). Returns: NoiseInfoResult diff --git a/will/create.py b/will/create.py index b24a095..ecfb1b7 100644 --- a/will/create.py +++ b/will/create.py @@ -20,17 +20,17 @@ # pylint: disable=invalid-name def gaussian(domain: np.ndarray, mu: float, sig: float) -> np.ndarray: """ - A Gaussian + A Gaussian Function. Args: - domain - Domain to calculate the Gaussian + domain: Domain to calculate the Gaussian. - mu - Center location + mu: Center location. - sig - Pulse width + sig: Pulse width. Returns: - Gaussian evaluated over x + Gaussian evaluated over x. """ return np.exp(-np.power(domain - mu, 2.0) / (2 * np.power(sig, 2.0))) @@ -48,19 +48,19 @@ def skewed_gauss( Two dimensional Gaussian with an angle theta. Args: - x - Horizontal Domain from np.meshgrid + x: Horizontal Domain from np.meshgrid. - y - Vertical Domain from np.meshgrid + y: Vertical Domain from np.meshgrid. - x_mu - Horizontal Location + x_mu: Horizontal Location. - y_mu - Vertical Distance + y_mu: Vertical Distance. - x_sig - Horizontal sigma + x_sig: Horizontal sigma. - y_sig - Vertical Sigma + y_sig: Vertical Sigma. - theta - Rotation angle increasing counterclockwise [radians] + theta: Rotation angle increasing counterclockwise [radians]. Returns: 2D gaussian with amplitude one. @@ -87,15 +87,15 @@ def skewed_gauss( def pulse_with_tail(times: np.ndarray, tau: float = 50) -> np.ndarray: """ - Create a Gaussian Pulse with a scattering tail + Create a Gaussian Pulse with a scattering tail. Args: - Times - Time array + Times: Time array. - tau - With parameter + tau: Width parameter (Optional). Returns: - pulse profile + pulse profile. Notes: Based on @@ -104,7 +104,7 @@ def pulse_with_tail(times: np.ndarray, tau: float = 50) -> np.ndarray: https://academic.oup.com/mnras/article/157/1/55/2604596 I tried moving the center to match the other Gaussian, - but this slows down the rvs sampler by a factor of ~4 + but this slows down the rvs sampler by a factor of ~4. Example: times = np.linspace(1, 256, 256) @@ -130,17 +130,17 @@ def uniform_locations( num_locations: int, ) -> np.ndarray: """ - Locations based on uniform sampling + Locations based on uniform sampling. Args: - start - Start index + start: Start index. - stop - Stop index + stop: Stop index. - num_locations - The number of locations to generate + num_locations: The number of locations to generate. - returns: - location indices for one axis + Returns: + Location indices for one axis. """ logging.debug("Creating %i uniform pulse locations", num_locations) @@ -153,15 +153,15 @@ def uniform_locations( def _normalize_pulse_with_tail(times: np.ndarray, tau: float) -> float: """ - Find the normalization constant for pulse with scatter tail + Find the normalization constant for pulse with scatter tail. Args: - times - Time sample locations + Times: Time sample locations. - tau - pulse width + tau: Pulse width. - returns: - normalization constant + Returns: + Normalization constant. Note: based on Harry45 @@ -174,6 +174,8 @@ def _normalize_pulse_with_tail(times: np.ndarray, tau: float) -> float: class pulse_with_tail_dist(stats.rv_continuous): """ + Class to create a pulse with a tail. + Args: rv_continuous class @@ -183,17 +185,17 @@ class pulse_with_tail_dist(stats.rv_continuous): def _pdf(self, times: np.ndarray, tau: float, norm_const: float): """ - The pdf is the pulse_with_tail function + The pdf is the pulse_with_tail function. Args: - times - Time index + times: Time index. - tau - Pulse width + tau: Pulse width. - norm_constant - Normalization Constant + norm_constant: Normalization Constant. Returns: - Values sampled from pulse with tail distribution + Values sampled from pulse with tail distribution. """ # center: int return (1.0 / norm_const) * pulse_with_tail(times, tau=tau) @@ -201,15 +203,15 @@ def _pdf(self, times: np.ndarray, tau: float, norm_const: float): def gauss_with_tail_cdf(times: np.ndarray, tau: float) -> np.ndarray: """ - Calculate the time locations for a Gaussian pulse with exponential tail + Calculate the time locations for a Gaussian pulse with exponential tail. Args: - times - Array with times to consider + times: Array with times to consider. - tau - Pulse width + tau: Pulse width. Returns: - Values sampled from pulse with tail distribution + Values sampled from pulse with tail distribution. Notes: based on @@ -230,16 +232,16 @@ def arbitrary_array_cdf( array: np.ndarray, locations: float, num_samples: int ) -> np.ndarray: """ - Calculate the time locations from a given array + Calculate the time locations from a given array. Args: - times - Array with times to consider + times: Array with times to consider. - tau - Pulse width + tau: Pulse width. Returns: - Values sampled from pulse with tail distribution + Values sampled from pulse with tail distribution. Notes: based on @@ -271,20 +273,20 @@ def gauss_with_tail_locations( This provides a comparison between the cdf and rvs samplers. Args: - start - Start index + start: Start index. - stop - Stop index + stop: Stop index. - sigma - Gaussian sigma + sigma: Gaussian sigma. - num_locations - The number of locations to generate + num_locations: The number of locations to generate. - back_end - How the samples are calculated [rvs] uses the rv_continuous class, - cdf creates a CDF an linearly interpolates it. The latter is - much faster. + back_end: How the samples are calculated [rvs] uses the rv_continuous class, + cdf creates a CDF an linearly interpolates it. The latter is + much faster. (Optional) Returns: - Location indices for one axis + Location indices for one axis. Example: gauss_with_tail_locations(0.1, 1024, 20, int(5e2), back_end="rvs") @@ -323,16 +325,16 @@ def build_pulse( Build the pulse from locations tuple. Args: - num_times - Length of the time samples axis + num_times: Length of the time samples axis. - num_chans - Length of channel axis + num_chans: Length of channel axis. - locations - Locations of the points to increase the energy - given as two arrays + locations: Locations of the points to increase the energy + given as two arrays. Returns: 2D float array with the pulse, time on the ventricle - axis + axis. Example: pulse = build_pulse(10, 10, [[2, 2, 2], [2, 0, 2]]) will @@ -356,17 +358,17 @@ def spectral_index( chan_freqs: np.ndarray, freq_ref: float, spectral_index_alpha: float ) -> np.ndarray: """ - Add spectral index to pulse profile + Add spectral index to pulse profile. Args: - frequencies - Frequencies of the bandpass + frequencies: Frequencies of the bandpass. - freq_ref - Reference frequency + freq_ref: Reference frequency. - spectral index - Spectral index + spectral index: Spectral index. Returns: - pulse profile modulated by spectral index + Pulse profile modulated by spectral index. """ return (chan_freqs / freq_ref) ** spectral_index_alpha @@ -375,19 +377,19 @@ def scintillation( chan_freqs: np.ndarray, freq_ref: float, nscint: int = 3, phi: float = 0 ) -> np.ndarray: """ - Adds Scintillation that is abs(cos(band)) + Adds Scintillation that is abs(cos(band)). Args: - chan_freqs - Array of channel Frequencies + chan_freqs: Array of channel Frequencies. - freq_freq - Reference Frequency + freq_freq: Reference Frequency. - nscint - number of scintills + nscint: Number of scintills (Optional). - phi - phase of of scintillation + phi: Phase of of scintillation (Optional). Returns: - scintillation intensities + Scintillation intensities. Notes: Similar to https://arxiv.org/abs/2003.14272 @@ -408,14 +410,14 @@ def scatter_profile( Create exponential scattering profile. Args: - freq - Frequencies array + freq: Frequencies array. - ref_freq - Reference Frequency + ref_freq: Reference Frequency. - tau - Scattering parameter + tau: Scattering parameter (Optional). Return: - Exponential scattering profile + Exponential scattering profile. Notes: Bases on @@ -439,16 +441,16 @@ def apply_scatter_profile( Create exponential scattering profile. Args: - freq - Frequencies array + freq: Frequencies array. - ref_freq - Reference Frequency + ref_freq: Reference Frequency. - tau - Scattering parameter + tau: Scattering parameter (Optional). - axis - Axis to perform convolution + axis: Axis to perform convolution (Optional). Return: - Exponential scattering profile + Exponential scattering profile. """ if axis is None: scatter = scatter_profile(chan_freqs, ref_freq, tau) @@ -471,12 +473,12 @@ def optimal_boxcar_width( of boxcar widths. Args: - time_profile - The time profile of the pulse + time_profile: The time profile of the pulse. - boxcar_widths - Array of boxcar widths + boxcar_widths: Array of boxcar widths. Returns: - Length of the optimal boxcar + Length of the optimal boxcar. """ powers = calculate.boxcar_convolved( time_profile=time_profile, boxcar_widths=boxcar_widths @@ -496,29 +498,28 @@ class SimpleGaussPulse: to sample the pulse. Args: + sigma_time: Time sigma in seconds. - sigma_time - time sigma in seconds - - dm - Dispersion measure + dm: Dispersion Measure [pc/cm^3]. - tau - scatter + tau: Scatter. - sigma_freq - Frequency Sigma in MHz + sigma_freq: Frequency Sigma [MHz]. - center_freq - Center Frequency in MHz + center_freq: Center Frequency [MHz]. - chan_freq - Array of channel frequencies in MHz + chan_freq: Array of channel frequencies [MHz]. - tsamp - sampling time of dynamic spectra in second + tsamp: sampling time of dynamic spectra [second]. - spectra_index_alpha - spectral index around center_freq + spectra_index_alpha: spectral index around center_freq. - nscint - number of scintills + nscint: Number of scintills. - phi - phase of of scintillation + phi: Pase of of scintillation. - bandpass - scale frequency structure with bandpass if - not None + bandpass: Scale frequency structure with bandpass if + not None (Optional). """ sigma_time: float @@ -536,21 +537,33 @@ class SimpleGaussPulse: def __post_init__(self): """ Create the pulse time and frequency profiles when - the instance is created + the instance is created. """ self.create_pulse() @property def pulse_center(self) -> np.int64: """ - The location of the pulse maximum in time samples + The location of the pulse maximum in time samples. + + Args: + None. + + Returns: + Index of pulse maximum. """ return self.pulse_time_profile.argmax() @functools.cached_property def optimal_boxcar_width(self) -> np.int64: """ - Find the optimal boxcar width + Find the optimal boxcar width. + + Args: + None. + + Returns: + Optimal Boxcar width. """ boxcar_widths = np.arange(1, self.pulse_width) return optimal_boxcar_width( @@ -559,7 +572,7 @@ def optimal_boxcar_width(self) -> np.int64: def create_pulse(self) -> None: """ - Create the pulse + Create the pulse. """ logging.debug("Creating time profile.") @@ -609,15 +622,15 @@ def create_pulse(self) -> None: def sample_pulse(self, nsamp: int, dtype: type = np.uint32) -> np.ndarray: """ - Sample the pulse with `nsamp` samples + Sample the pulse with `nsamp` samples. Args: - nsamp - Number of samples in the pulse + nsamp: Number of samples in the pulse. - dtype - Data type of the pulse + dtype: Data type of the pulse (Optional). Returns: - 2D ndarray with disperesed pulse + 2D ndarray with disperesed pulse. """ logging.debug("Calculating %i locations.", nsamp) @@ -651,15 +664,14 @@ class TwoDimensionalPulse: Create a pulse from a 2D pulse Probability Distribution Function (PDF). Args: - pulse_pdf - The 2D array containing pulse the pulse profile at + pulse_pdf: The 2D array containing pulse the pulse profile at 0 DM. - chan_freq - Array of channel frequencies in MHz + chan_freq: Array of channel frequencies [MHz]. - tsamp - sampling time of dynamic spectra in second - - dm - Dispersion Measure + tsamp: sampling time of dynamic spectra [second]. + dm: Dispersion Measure [pc/cm^3]. """ pulse_pdf: np.ndarray @@ -674,14 +686,26 @@ def __post_init__(self): @property def pulse_center(self) -> int: """ - The location of the pulse maximum in time samples + The location of the pulse maximum in time samples. + + Args: + None + + Returns: + Argument of pulse center. """ return self.pulse_pdf.mean(axis=1).argmax() @functools.cached_property def optimal_boxcar_width(self) -> np.int64: """ - Find the optimal boxcar width + Find the optimal boxcar width. + + Args: + None + + Returns: + S/N Optimizing boxcar width. """ boxcar_widths = np.arange(1, self.pulse_width) return optimal_boxcar_width( @@ -690,15 +714,15 @@ def optimal_boxcar_width(self) -> np.int64: def sample_pulse(self, nsamp: int, dtype: type = np.uint32) -> np.ndarray: """ - Sample the pulse with `nsamp` samples + Sample the pulse with `nsamp` samples. Args: - nsamp - Number of samples in the pulse + nsamp: Number of samples in the pulse. - dtype - Data type of the pulse + dtype: Data type of the pulse (Optional). Returns: - 2D ndarray with disperesed pulse + 2D ndarray with disperesed pulse. """ logging.debug("Calculating %i locations.", nsamp) @@ -726,45 +750,45 @@ def sample_pulse(self, nsamp: int, dtype: type = np.uint32) -> np.ndarray: @dataclass class GaussPulse: """ - Create a pulse from a 2D Gaussian. - This function can handle + Class to create a pulse from a 2D Gaussian. + The PDF is created ith the object. To sample use sample_pulse(nsamps). Args: - relative_intensities - The relative intensities of the + relative_intensities: The relative intensities of the pule components. - sigma_time - time sigma in seconds + sigma_time: time sigma [second]. - sigma_freq - Frequency Sigma in MHz + sigma_freq: Frequency Sigma [MHz]. - chan_freq - Array of channel frequencies in MHz + chan_freq: Array of channel frequencies [MHz]. - tsamp - sampling time of dynamic spectra in second + tsamp: Sampling time of dynamic spectra [second]. - pulse_theta - Angle of pulse components + pulse_theta: Angle of pulse components. - nsamp - Number of samples to add + nsamp: Number of samples to add. - dm - Dispersion Measure + dm: Dispersion Measure [pc/cm^3]. - tau - Scatter parameter + tau: Scatter parameter. - tsamp - Sampling time of dynamic spectra in second + tsamp: Sampling time of dynamic spectra in second. - spectra_index_alpha - Spectral index power around center_freq + spectra_index_alpha: Spectral index power around center_freq. - nscint - Number of frequency scintills + nscint: Number of frequency scintills. - phi - Phase of frequency scintillation + phi: Phase of frequency scintillation. - bandpass - Scale frequency structure with bandpass if - not None + bandpass: Scale frequency structure with bandpass if + not None (Optional). - dm_interchan_smear - Interchannel DM smearing simulated by - boxcar convolution + dm_interchan_smear: Interchannel DM smearing simulated by + boxcar convolution (Optional). """ relative_intensities: Union[Sequence, float] @@ -787,7 +811,7 @@ def __post_init__(self): """ Convert sequencies to ndarrays - Create the pulse when the object is created + Create the pulse when the object is created. """ self.relative_intensities = np.array(self.relative_intensities, ndmin=1) self.sigma_times = np.array(self.sigma_times, ndmin=1) @@ -814,14 +838,26 @@ def __post_init__(self): @property def pulse_center(self) -> int: """ - The location of the pulse maximum in time samples + The location of the pulse maximum in time samples. + + Args: + None + + Returns: + Index of pulse maximum. """ return self.pulse_pdf.mean(axis=1).argmax() @functools.cached_property def optimal_boxcar_width(self) -> np.int64: """ - Find the optimal boxcar width + Find the optimal boxcar width. + + Args: + None + + Returns: + Optimal Boxcar width in number of samples. """ boxcar_widths = np.arange(1, self.pulse_width) return optimal_boxcar_width( @@ -830,7 +866,7 @@ def optimal_boxcar_width(self) -> np.int64: def create_pulse(self) -> None: """ - Create the pulse + Create the pulse. """ logging.debug("Creating pulse profile.") @@ -917,15 +953,15 @@ def create_pulse(self) -> None: def sample_pulse(self, nsamp: int, dtype: type = np.uint32) -> np.ndarray: """ - Sample the pulse with `nsamp` samples + Sample the pulse with `nsamp` samples. Args: - nsamp - Number of samples in the pulse + nsamp: Number of samples in the pulse. - dtype - Data type of the pulse + dtype: Data type of the pulse. Returns: - 2D ndarray with disperesed pulse + 2D ndarray with disperesed pulse. """ logging.debug("Calculating %i locations.", nsamp) @@ -963,18 +999,19 @@ def filter_weights( at the end of the bandpass. Args: - dynamic_spectra - 2D dynamic spectra with time on the - vertical axis + dynamic_spectra: 2D dynamic spectra with time on the + vertical axis. - metric - The statistic to sample. + metric: The statistic to sample (Optional). - bandpass_smooth_length - length of the median filter to - smooth the bandpass + bandpass_smooth_length: length of the median filter to + smooth the bandpass (Optional). - sigma_cut - Cut values below (standard deviation)*(sigma cut) + sigma_cut: Cut values below (standard deviation)*(sigma cut) + (Optional). - smooth_sigma - Gaussian filter smoothing sigma. If =0, return - the mask where True=good channels + smooth_sigma: Gaussian filter smoothing sigma. If =0, return + the mask where True=good channels (Optional). Returns: Bandpass weights for sections of spectra with low values. @@ -1000,16 +1037,16 @@ def dynamic_from_statistics( Make a dynamic spectra from statistics. Args: - medians - Bandpass medians + medians: Bandpass medians. - stds - Standard deviation of the bandpass + stds: Standard deviation of the bandpass. - dtype - data type of fake file + dtype: data type of fake file. - nsamps - Number of time samples + nsamps: Number of time samples (Optional). Returns: - 2D random arrays + 2D array of randim numbers with the specified characteristics. """ nchans = medians.shape[0] clone = np.random.normal(size=nchans * nsamps) @@ -1026,7 +1063,10 @@ def clone_spectra( Clone a section of dynamic spectra using Gaussian random numbers. Args: - 2D array of dynamic spectra + dynamic_spectra: 2D array of dynamic spectra. + + median_filter_lenght: Run the standard devaitions and medians + through a filter with this lenght (Optional). Returns: Dynamic spectra that has simlar statstics as the given dynamic diff --git a/will/detect.py b/will/detect.py index 7c708e5..d9975a6 100644 --- a/will/detect.py +++ b/will/detect.py @@ -28,23 +28,24 @@ def find_first_pulse( box_car_length: int = 1, ) -> None: """ - Help to find the index of the first pulse by ploting the + Help to find the index of the first pulse by plotting the dedispersed dynamic spectra and time series. Args: - file - Path to the file to investigate + file: Path to the file to investigate. - dm - Dispersion measure of the pulsar + dm: Dispersion measure of the pulsar. - start - Start Index + start: Index of first sample to get from the file. - gulp - Number of samples to get + gulp: Number of samples to get from file. - box_car_length - If > 1, dynamic spectra and time series - get convolved with a boxcar of this length - - num_cands - Number of candidates to print + box_car_length: If > 1, dynamic spectra and time series + get convolved with a boxcar of this length + (optional). + Returns: + None """ start = np.around(start).astype(int) yr_obj = Your(file) @@ -115,16 +116,16 @@ def dedisped_time_series( Get the dedispered time series from a chunk of dynamic spectra. Args: - dynamic_spectra - 2D spectra with time on the vertical axis + dynamic_spectra: 2D spectra with time on the vertical axis. - dm - The dispersion measure + dm: The Dispersion Measure. - tsamp - Time sample of the data + tsamp: Time sample of the data. - chan_freqs - The channel frequencies + chan_freqs: The channel frequencies. Returns: - Time series at a the given DM + Time series at a the given DM. """ dynamic_spectra_dispered = dedisperse( dynamic_spectra, dm=dm, tsamp=tsamp, chan_freqs=chan_freqs @@ -135,13 +136,14 @@ def dedisped_time_series( @dataclass class PulseInfo: """ - Pulse info result + Pulse info result. - locations - sample location of the pulses + Args: + locations: sample location of the pulses - snrs - Signal to noise of pulses + snrs: Signal to noise of pulses - std - Standard devivation of time series + std: Standard deviation of time series """ locations: Union[np.int64, float, np.ndarray] @@ -159,20 +161,21 @@ def detect_all_pulses( Detect pulses in a dedisperesed series. Args: - time_series - The dedispersed time series + time_series: The dedispersed time series. - box_car_length - Length of the boxcar + box_car_length: Length of the boxcar. - sigma - Return pulses with significance above - this + sigma: Return pulses with significance above + this value (Optional). - smoothing_factor - Median filter is smoothing_factor*box_car_length + smoothing_factor: Median filter is smoothing_factor*box_car_length + (Optional). Returns: PulseInfo[Locations, SNRs] Deterned the time series by subtracting off the running median - Thesis described in Bardell Thesis, but Heimdall uses a different + Thesis described in Barsdell Thesis, but Heimdall uses a different method Don't scale SNR as described in https://arxiv.org/pdf/2011.10191.pdf @@ -215,20 +218,18 @@ def detect_max_pulse( standard deviation as computed by Median Absolute Deviation. Args: - time_series - The dedispersed time series + time_series: The dedispersed time series. - box_car_length - Length of the boxcar + box_car_length: Length of the boxcar - sigma - Return pulses with significance above - this - - smoothing_factor - Median filter is smoothing_factor*box_car_length + smoothing_factor: Median filter is smoothing_factor*box_car_length + (Optional). Returns: dataclass[Locations, SNRs] - Deterned the time series by subtracting off the running median - Thesis described in Bardell Thesis, but Heimdall uses a different + Detrend the time series by subtracting off the running median + Thesis described in Barsdell Thesis, but Heimdall uses a different method Don't scale SNR as described in https://arxiv.org/pdf/2011.10191.pdf @@ -240,7 +241,7 @@ def detect_max_pulse( # this follows https://arxiv.org/pdf/2011.10191.pdf # std = stats.median_abs_deviation(flattened_times_series, scale="normal") - # normatlized_time_series = flattened_times_series / std + # normalized_time_series = flattened_times_series / std if box_car_length > 1: window = signal.boxcar(box_car_length) / np.sqrt(box_car_length) @@ -281,9 +282,10 @@ class MaxPulse: """ Max pulse location - location - Sample location of max pulse + Args: + location: Sample location of max pulse - snr - Signal to noise ratio + snr: Signal to noise ratio If `None`, no pulse fitting requirements found. """ @@ -299,15 +301,15 @@ def find_max_pulse( Find the maximum pulse between two indices. Args: - pulses - The dataclass from detected pulses + pulses: The dataclass from detected pulses. - start_idx - Start index of the the range + start_idx: Start index of the the range (Optional). - end_idx - End index of range + end_idx: End index of range (Optional). Returns: dataclass(location index, SNR) - if no pulse in range, returns (None, None) + if no pulse in range, returns (None, None). """ if end_idx == -1: mask = pulses.locations >= start_idx @@ -336,27 +338,27 @@ class PulseSearchParamters: """ The parameters to use for the single pulse search. - file - Fits for Fil contaning the pulse. + file: Fits for Fil containing the pulse. - first_pulse - Location of the first pulse in seconds. + first_pulse: Location of the first pulse (in seconds). - period - Period of the pulse in seconds. + period: Period of the pulse (in seconds). - dm - Dispersion Measure of the pulse + dm: Dispersion Measure of the pulse (pc/cm^3). - box_car_length - Length of the boxcar for the matched filter. + box_car_length: Length of the boxcar for the matched filter. - samples_around_pulse - The number of samples on either side of - of the boxcar + samples_around_pulse: The number of samples on either side of + of the boxcar. - search_window_frac - The fraction, around the center, of the time - series search for a pulse. + search_window_frac: The fraction, around the center, of the time + series search for a pulse (Optional). - sigma - Pulse threshold + sigma: Pulse threshold (Optional). - start - Start sample to process (default to first sample) + start: Start sample to process (default to first sample) (Optional). - stop - Final sample to process (default is EOF) + stop: Final sample to process (default is EOF) (Optional). """ # pylint: disable=invalid-name @@ -372,7 +374,6 @@ class PulseSearchParamters: stop: int = -1 def __post_init__(self): - self.yr_obj: Your = Your(self.file) self.samples_lost: int = delay_lost( @@ -392,7 +393,7 @@ def locations_of_pulses(pulse_search_params: PulseSearchParamters) -> np.ndarray Make an array of pulse locations from the start location and period. Args: - pulse_search_params - The dataclass that has the search parameters + pulse_search_params: The dataclass that has the search parameters Returns: Location of the pulses in samples @@ -428,12 +429,13 @@ class PulseSNRs: """ Results of pulse search - snrs - Pulse Signal to Noise Ratio + Args: + snrs: Pulse Signal to Noise Ratio. - stds - Standard Deviations of pulse block - Computed via Median Abs Deviation + stds: Standard Deviations of pulse block + Computed via Median Abs Deviation. - folded - Folded dynamic spectra + folded: Folded dynamic spectra. """ snrs: np.ndarray @@ -443,18 +445,24 @@ class PulseSNRs: pulse_locations: np.ndarray @property - def percent_with_pulses(self): + def percent_with_pulses(self) -> float: """ The percent of pulse bins with a single above snr present. + + Returns: + Percent of windows with pulses above cutoff. """ mask = self.snrs >= self.pulse_search_params.sigma return 100 * mask.mean() @property - def folded_properties(self): + def folded_properties(self) -> PulseInfo: """ - Get the pulse properties of the folded profile + Get the pulse properties of the folded profile. + + Returns: + Info about pulse. """ time_series = self.folded.mean(axis=1) max_pulse = detect_max_pulse( @@ -470,8 +478,12 @@ def plot_snrs(self, cut_snrs: bool = False, title: Union[None, str] = None) -> N Args: cut_snrs: Don't plot SNRs below the cutoff specified in PulseSearchParamters + (Optional). + + title: The title of the plot, default `SNR vs. Time` (Optional) - title - The title of the plot, default `SNR vs. Time` + Returns: + None. """ # pulse locations in seconds @@ -496,7 +508,11 @@ def plot_stds(self, title: Union[None, str] = None) -> None: as a function of time. Args: - title - The tile of the plot, default `Standard Deviation vs. Time` + title: The tile of the plot, default `Standard Deviation vs. Time` + (Optional). + + Returns: + None. """ locs = self.pulse_locations * self.pulse_search_params.yr_obj.your_header.tsamp @@ -514,8 +530,11 @@ def plot_folded_dynamic(self, median_filter_length: int = 29) -> None: Plot the folded dynamic spectra. Args: - median_filter_length - The length of the median filter used to - remove the bandpass + median_filter_length: The length of the median filter used to + remove the bandpass (Optional). + + Returns: + None. """ nsamps, _ = self.folded.shape xmax = 1000 * nsamps * self.pulse_search_params.yr_obj.your_header.tsamp @@ -532,7 +551,10 @@ def plot_folded_dynamic(self, median_filter_length: int = 29) -> None: def plot_folded_profile(self) -> None: """ - Plot the folded pulse profile and print the Signal to Noise + Plot the folded pulse profile and print the Signal to Noise. + + Returns: + None. """ time_series = self.folded.mean(axis=1) times = ( @@ -556,12 +578,12 @@ def search_file( Search a Fil or Fits file for pulses. Args: - pulse_search_params - dataclass with the pulse search paramters. + pulse_search_params: dataclass with the pulse search paramters. - pulse_locations - Array with the locations of the center of the pulse. + pulse_locations: Array with the locations of the center of the pulse. Returns: - PulseSNRs - Dataclass that has the pulse snrs, standard deviations, and + PulseSNRs: Dataclass that has the pulse snrs, standard deviations, and the folded profile. """ @@ -639,14 +661,14 @@ def process_dynamic_spectra( optionally running a Gaussain filter, and zero centering. Args: - dynamic_spectra - dynamic spectra to process + dynamic_spectra: dynamic spectra to process. - sigma - Sigma for Gaussian filter, if zero filter not applied + sigma: Sigma for Gaussian filter, if zero filter not applied. - dtype - data type of output file + dtype: data type of output file. Returns: - processed to dynamic spectra, mean used to center the data + Processed to dynamic spectra, mean used to center the data. """ dynamic_spectra = dynamic_spectra - np.median(dynamic_spectra, axis=0).astype(dtype) @@ -663,13 +685,14 @@ class ExtractPulses: """ Results of extracting single pulses. - dynamic_spectra - Pulse dynamic spectra. + Args: + dynamic_spectra: Pulse dynamic spectra. - bandpass_labels - Frequency labels. + bandpass_labels: Frequency labels. - times - Time labels. + times: Time labels. - centering_means - The means used to center the pulses. + centering_means: The means used to center the pulses. """ dynamic_spectra: np.ndarray @@ -687,12 +710,14 @@ def extract_pulses( """ Search a Fil or Fits file for pulses. Args: - pulse_search_params - dataclass with the pulse search paramters. - pulse_locations - Array with the locations of the center of the pulse. - sigma - Sigma of Gauss filter, if 0 no filter is applied + pulse_search_params: dataclass with the pulse search paramters. + + pulse_locations: Array with the locations of the center of the pulse. + + sigma: Sigma of Gauss filter, if 0 no filter is applied Returns: - ExtractPulses - Dataclass that has the pulse dynamic spectra, + ExtractPulses: Dataclass that has the pulse dynamic spectra, bandpass labels, times, and means used to center """ diff --git a/will/inject.py b/will/inject.py index e9546fc..b236dcd 100644 --- a/will/inject.py +++ b/will/inject.py @@ -29,19 +29,19 @@ def inject_constant_into_file( # noqa: max-complexity:30 Inject a (the same) pulse(s) into a file. Args: - yr_input - Your object for file to inject pulse + yr_input: `Your` object for file to inject pulse. - pulse - 2D array that contains the pulse + pulse: 2D array that contains the pulse. - start - Start sample of the pulse + start: Start sample of the pulse. - period - Sample period of injected pulse + period: Sample period of injected pulse (Optional). - out_fil - Out filterbank, if None, returns array + out_fil: Out filterbank, if None, returns array (Optional). - clip_powers - Clip powers instead of wrap + clip_powers: Clip powers instead of wrap (Optional). - Returns + Returns: None if out_fil, else dynamic spectra with injected pulse """ nsamples, nchans = pulse.shape @@ -158,21 +158,21 @@ def inject_distribution_into_file( # noqa: max-complexity:30 Inject a pulse(s) into a file. From a given distributution. Args: - yr_input - Your object for file to inject pulse + yr_input: `Your` object for file to inject pulse. - pulse_obj - Object that creates the pulses + pulse_obj: Object that creates the pulses. - pulse_counts - The number of samples for each pulse + pulse_counts: The number of samples for each pulse. - start - Start sample of the pulse + start: Start sample of the pulse (Optional). - period - Sample period of injected pulse + period: Sample period of injected pulse (Optional). - out_fil - Out filterbank, if None, returns array + out_fil: Out filterbank, if None, returns array (Optional). - clip_powers - Clip powers instead of wrap + clip_powers: Clip powers instead of wrap (Optional). - Returns + Returns: None if out_fil, else dynamic spectra with injected pulse """ # create a pulse with one sample to check dims @@ -287,14 +287,14 @@ def num_pulses(period: float, nspectra: int, start: int = 0) -> int: Calculate the number of pulses needed for a chunk of data Args: - period - Period of pulse + period: Period of pulse. - nspectra - Number of spectra in chunk + nspectra: Number of spectra in chunk. - start - Start of first pulse + start: Start of first pulse (Optional). Returns: - Number of pulses within a data chunk, including partial pulses + Number of pulses within a data chunk, including partial pulses. """ window = nspectra - start npulses = np.ceil(window / period)