def test_can_convert_column_to_relative_scale_with_nans(self): light_curve = LightCurve() light_curve.data_frame = pd.DataFrame({'a': [1, 2, 3, np.nan]}) light_curve.convert_column_to_relative_scale('a') light_curve_values = light_curve.data_frame['a'].values expected_values = np.array([0.5, 1, 1.5, np.nan]) assert np.allclose(light_curve_values, expected_values, equal_nan=True)
def test_setting_fluxes_sets_existing_named_flux_column_if_one_exists( self): light_curve = LightCurve() light_curve.flux_column_names = ['flux_column'] light_curve.fluxes = [0, 1] assert np.array_equal(light_curve.data_frame['flux_column'].values, [0, 1])
def inject_signal_into_light_curve(self, light_curve_fluxes: np.ndarray, light_curve_times: np.ndarray, signal_magnifications: np.ndarray, signal_times: np.ndarray, wandb_loggable_injection: Optional[WandbLoggableInjection] = None) -> np.ndarray: """ Injects a synthetic magnification signal into real light curve fluxes. :param light_curve_fluxes: The fluxes of the light curve to be injected into. :param light_curve_times: The times of the flux observations of the light curve. :param signal_magnifications: The synthetic magnifications to inject. :param signal_times: The times of the synthetic magnifications. :param wandb_loggable_injection: The object to log the injection process. :return: The fluxes with the injected signal. """ minimum_light_curve_time = np.min(light_curve_times) relative_light_curve_times = light_curve_times - minimum_light_curve_time relative_signal_times = signal_times - np.min(signal_times) signal_time_length = np.max(relative_signal_times) light_curve_time_length = np.max(relative_light_curve_times) time_length_difference = light_curve_time_length - signal_time_length signal_start_offset = (np.random.random() * time_length_difference) + minimum_light_curve_time offset_signal_times = relative_signal_times + signal_start_offset if self.baseline_flux_estimation_method == BaselineFluxEstimationMethod.MEDIAN_ABSOLUTE_DEVIATION: baseline_flux = scipy.stats.median_abs_deviation(light_curve_fluxes) baseline_to_median_absolute_deviation_ratio = 10 # Arbitrarily chosen to give a reasonable scale. baseline_flux *= baseline_to_median_absolute_deviation_ratio else: baseline_flux = np.median(light_curve_fluxes) signal_fluxes = (signal_magnifications * baseline_flux) - baseline_flux if self.out_of_bounds_injection_handling is OutOfBoundsInjectionHandlingMethod.RANDOM_INJECTION_LOCATION: signal_flux_interpolator = interp1d(offset_signal_times, signal_fluxes, bounds_error=False, fill_value=0) elif (self.out_of_bounds_injection_handling is OutOfBoundsInjectionHandlingMethod.REPEAT_SIGNAL and time_length_difference > 0): before_signal_gap = signal_start_offset - minimum_light_curve_time after_signal_gap = time_length_difference - before_signal_gap minimum_signal_time_step = np.min(np.diff(offset_signal_times)) before_repeats_needed = math.ceil(before_signal_gap / (signal_time_length + minimum_signal_time_step)) after_repeats_needed = math.ceil(after_signal_gap / (signal_time_length + minimum_signal_time_step)) repeated_signal_fluxes = np.tile(signal_fluxes, before_repeats_needed + 1 + after_repeats_needed) repeated_signal_times = None for repeat_index in range(-before_repeats_needed, after_repeats_needed + 1): repeat_signal_start_offset = (signal_time_length + minimum_signal_time_step) * repeat_index if repeated_signal_times is None: repeated_signal_times = offset_signal_times + repeat_signal_start_offset else: repeat_index_signal_times = offset_signal_times + repeat_signal_start_offset repeated_signal_times = np.concatenate([repeated_signal_times, repeat_index_signal_times]) signal_flux_interpolator = interp1d(repeated_signal_times, repeated_signal_fluxes, bounds_error=True) else: signal_flux_interpolator = interp1d(offset_signal_times, signal_fluxes, bounds_error=True) interpolated_signal_fluxes = signal_flux_interpolator(light_curve_times) fluxes_with_injected_signal = light_curve_fluxes + interpolated_signal_fluxes if wandb_loggable_injection is not None: wandb_loggable_injection.aligned_injectee_light_curve = LightCurve.from_times_and_fluxes( light_curve_times, light_curve_fluxes) wandb_loggable_injection.aligned_injectable_light_curve = LightCurve.from_times_and_fluxes( offset_signal_times, signal_fluxes) wandb_loggable_injection.aligned_injected_light_curve = LightCurve.from_times_and_fluxes( light_curve_times, fluxes_with_injected_signal) return fluxes_with_injected_signal
def test_can_convert_columns_to_relative_scale(self): light_curve = LightCurve() light_curve.data_frame = pd.DataFrame({ 'a': [1, 2, 3], 'b': [-1, -2, -3], 'c': [1, 2, 3] }) light_curve.convert_columns_to_relative_scale(['a', 'b']) assert np.array_equal(light_curve.data_frame['a'].values, [0.5, 1, 1.5]) assert np.array_equal(light_curve.data_frame['b'].values, [0.5, 1, 1.5]) assert np.array_equal(light_curve.data_frame['c'].values, [1, 2, 3])
def flat(cls, value: float = 1) -> LightCurve: """ Creates a flat light curve. """ length = 100 fluxes = np.full(shape=[length], fill_value=value, dtype=np.float32) times = np.arange(length, dtype=np.float32) return LightCurve.from_times_and_fluxes(times=times, fluxes=fluxes)
def sine_wave(cls, period=50) -> LightCurve: """ Creates a sine wave light curve. """ length = 100 periods_to_produce = length / period fluxes = (np.sin( np.linspace( 0, np.pi * periods_to_produce, num=length, endpoint=False)) / 2) + 1 times = np.arange(length) return LightCurve.from_times_and_fluxes(times=times, fluxes=fluxes)
def preprocess_standard_light_curve( self, load_times_fluxes_and_flux_errors_from_path_function: Callable[ [Path], Tuple[np.ndarray, np.ndarray, Union[np.ndarray, None]]], load_auxiliary_information_for_path_function: Callable[[Path], np.ndarray], load_label_from_path_function: Callable[[Path], Union[float, np.ndarray]], light_curve_path_tensor: tf.Tensor, evaluation_mode: bool = False, request_queue: Optional[Queue] = None, example_queue: Optional[Queue] = None ) -> (np.ndarray, np.ndarray): """ Preprocesses a individual standard light curve from a light curve path tensor, using a passed function defining how to load the values from the light curve file and the label value to use. Designed to be used with `partial` to prepare a function which will just require the light curve path tensor, and can then be mapped to a dataset. :param load_times_fluxes_and_flux_errors_from_path_function: The function to load the light curve times and fluxes from a file. :param load_label_from_path_function: The function to load the label to assign to the light curve. :param light_curve_path_tensor: The tensor containing the path to the light curve file. :param evaluation_mode: Whether or not the preprocessing should occur in evaluation mode (for repeatability). :param request_queue: The logging request queue. :param example_queue: The logging example queue. :return: The example and label arrays shaped for use as single example for the network. """ light_curve_path = Path(light_curve_path_tensor.numpy().decode('utf-8')) times, fluxes, flux_errors = load_times_fluxes_and_flux_errors_from_path_function(light_curve_path) if self.logger is not None and self.logger.should_produce_example(request_queue): light_curve = LightCurve.from_times_and_fluxes(times, fluxes) loggable_light_curve = WandbLoggableLightCurve(light_curve_name=light_curve_path.name, light_curve=light_curve) self.logger.submit_loggable(example_queue, loggable_light_curve) light_curve = self.build_light_curve_array(fluxes=fluxes, times=times, flux_errors=flux_errors) example = self.preprocess_light_curve(light_curve, evaluation_mode=evaluation_mode) label = load_label_from_path_function(light_curve_path) label = self.expand_label_to_training_dimensions(label) if self.number_of_auxiliary_values > 0: auxiliary_information = load_auxiliary_information_for_path_function(light_curve_path) return example, auxiliary_information, label else: return example, label
def test_times_are_drawn_from_light_curve_data_frame_when_column_name_is_set( self): light_curve = LightCurve() light_curve.data_frame = pd.DataFrame({'time_column': [0, 1]}) light_curve.time_column_name = 'time_column' assert np.array_equal(light_curve.times, [0, 1])
def test_can_convert_column_to_relative_scale(self): light_curve = LightCurve() light_curve.data_frame = pd.DataFrame({'a': [1, 2, 3]}) light_curve.convert_column_to_relative_scale('a') assert np.array_equal(light_curve.data_frame['a'].values, [0.5, 1, 1.5])
def test_flux_column_name_is_set_when_times_are_manually_set(self): light_curve = LightCurve() assert len(light_curve.flux_column_names) == 0 light_curve.fluxes = [0, 1] assert len(light_curve.flux_column_names) == 1
def test_time_column_name_is_set_when_times_are_manually_set(self): light_curve = LightCurve() assert light_curve.time_column_name is None light_curve.times = [0, 1] assert light_curve.time_column_name is not None
def test_fluxes_error_when_column_name_is_not_set(self): light_curve = LightCurve() light_curve.data_frame = pd.DataFrame({'flux_column': [0, 1]}) with pytest.raises(IndexError): _ = light_curve.fluxes
def test_times_error_when_column_name_is_not_set(self): light_curve = LightCurve() light_curve.data_frame = pd.DataFrame({'time_column': [0, 1]}) with pytest.raises(KeyError): _ = light_curve.times
def test_fluxes_are_drawn_from_light_curve_data_frame_when_column_names_is_set( self): light_curve = LightCurve() light_curve.data_frame = pd.DataFrame({'flux_column': [0, 1]}) light_curve.flux_column_names = ['flux_column'] assert np.array_equal(light_curve.fluxes, [0, 1])