• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nikhil-sarin / redback / 14430354752

13 Apr 2025 02:23PM UTC coverage: 86.635% (+6.0%) from 80.663%
14430354752

Pull #266

github

web-flow
Merge 8147dba2c into e087188ab
Pull Request #266: A big overhaul

1621 of 1828 new or added lines in 14 files covered. (88.68%)

4 existing lines in 2 files now uncovered.

12673 of 14628 relevant lines covered (86.64%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.75
/test/transient_test.py
1
import os
1✔
2
import unittest
1✔
3
from unittest import mock
1✔
4
from unittest.mock import MagicMock, patch
1✔
5
import numpy as np
1✔
6
import pandas as pd
1✔
7

8
import redback
1✔
9

10
dirname = os.path.dirname(__file__)
1✔
11

12
import redback.get_data.directory as directory
1✔
13

14
_original_spec_dir_struct = directory.spectrum_directory_structure
1✔
15
directory.spectrum_directory_structure = lambda transient: "dummy_directory_structure"
1✔
16

17
class TestSpectrum(unittest.TestCase):
1✔
18

19
    def setUp(self):
1✔
20
        # Create dummy spectral data
21
        # Use three wavelengths (in Angstroms) that might cover the optical
22
        self.angstroms = np.array([4000, 5000, 6000])
1✔
23
        # Fake flux density in erg / s / cm^2 / Angstrom (typical values are small)
24
        self.flux_density = np.array([1e-17, 2e-17, 3e-17])
1✔
25
        # Assume small errors
26
        self.flux_density_err = np.array([1e-18, 1e-18, 1e-18])
1✔
27
        # A dummy observation time and a name for the spectrum
28
        self.time_str = "10d"  # could be a phase string
1✔
29
        self.name = "TestSpec"
1✔
30

31
    def tearDown(self):
1✔
32
        # Restore the patched directory function if needed.
33
        directory.spectrum_directory_structure = _original_spec_dir_struct
1✔
34

35
    def test_initialization_with_time(self):
1✔
36
        spec = redback.transient.Spectrum(self.angstroms, self.flux_density, self.flux_density_err,
1✔
37
                        time=self.time_str, name=self.name)
38
        self.assertTrue(spec.plot_with_time_label,
1✔
39
                        "When a time is provided, plot_with_time_label should be True.")
40

41
    def test_initialization_without_time(self):
1✔
42
        spec = redback.transient.Spectrum(self.angstroms, self.flux_density, self.flux_density_err,
1✔
43
                        name=self.name)  # time defaults to None
44
        self.assertFalse(spec.plot_with_time_label,
1✔
45
                         "When no time is provided, plot_with_time_label should be False.")
46

47
    def test_directory_structure(self):
1✔
48
        spec = redback.transient.Spectrum(self.angstroms, self.flux_density, self.flux_density_err, name=self.name)
1✔
49
        # The __init__ should call redback.get_data.directory.spectrum_directory_structure(name)
50
        self.assertEqual(spec.directory_structure, "dummy_directory_structure",
1✔
51
                         "Directory structure should be patched to a dummy value.")
52

53
    def test_xlabel_property(self):
1✔
54
        spec = redback.transient.Spectrum(self.angstroms, self.flux_density, self.flux_density_err)
1✔
55
        expected_xlabel = r'Wavelength [$\mathrm{\AA}$]'
1✔
56
        self.assertEqual(spec.xlabel, expected_xlabel,
1✔
57
                         "The xlabel property did not match the expected value.")
58

59
    def test_ylabel_property(self):
1✔
60
        spec = redback.transient.Spectrum(self.angstroms, self.flux_density, self.flux_density_err)
1✔
61
        expected_ylabel = r'Flux ($10^{-17}$ erg s$^{-1}$ cm$^{-2}$ $\mathrm{\AA}$)'
1✔
62
        self.assertEqual(spec.ylabel, expected_ylabel,
1✔
63
                         "The ylabel property did not match the expected value.")
64

65
class TestTransient(unittest.TestCase):
1✔
66

67
    def setUp(self) -> None:
1✔
68
        self.time = np.array([1, 2, 3])
1✔
69
        self.time_err = np.array([0.2, 0.3, 0.4])
1✔
70
        self.y = np.array([3, 4, 2])
1✔
71
        self.y_err = np.sqrt(self.y)
1✔
72
        self.redshift = 0.75
1✔
73
        self.data_mode = 'counts'
1✔
74
        self.name = "GRB123456"
1✔
75
        self.photon_index = 2
1✔
76
        self.use_phase_model = False
1✔
77
        self.transient = redback.transient.transient.Transient(
1✔
78
            time=self.time, time_err=self.time_err, counts=self.y,
79
            redshift=self.redshift, data_mode=self.data_mode, name=self.name,
80
            photon_index=self.photon_index, use_phase_model=self.use_phase_model)
81

82
    def tearDown(self) -> None:
1✔
83
        del self.time
1✔
84
        del self.time_err
1✔
85
        del self.y
1✔
86
        del self.y_err
1✔
87
        del self.redshift
1✔
88
        del self.data_mode
1✔
89
        del self.name
1✔
90
        del self.photon_index
1✔
91
        del self.use_phase_model
1✔
92
        del self.transient
1✔
93

94
    def test_ttes_data_mode_setting(self):
1✔
95
        bin_ttes = MagicMock(return_value=(self.time, self.y))
1✔
96
        ttes = np.arange(0, 1, 1000)
1✔
97
        self.data_mode = 'ttes'
1✔
98
        self.bin_size = 0.1
1✔
99
        self.transient = redback.transient.transient.Transient(
1✔
100
            ttes=ttes, redshift=self.redshift, data_mode=self.data_mode, name=self.name,
101
            photon_index=self.photon_index, bin_ttes=bin_ttes)
102
        bin_ttes.assert_called_once()
1✔
103

104
    def test_data_mode_switches(self):
1✔
105
        self.assertTrue(self.transient.counts_data)
1✔
106
        self.assertFalse(self.transient.luminosity_data)
1✔
107
        self.assertFalse(self.transient.flux_data)
1✔
108
        self.assertFalse(self.transient.flux_density_data)
1✔
109
        self.assertFalse(self.transient.magnitude_data)
1✔
110
        self.assertFalse(self.transient.tte_data)
1✔
111

112
    def test_set_data_mode_switch(self):
1✔
113
        self.transient.flux_data = True
1✔
114
        self.assertTrue(self.transient.flux_data)
1✔
115
        self.assertFalse(self.transient.counts_data)
1✔
116

117
    def test_get_time_via_x(self):
1✔
118
        self.assertTrue(np.array_equal(self.time, self.transient.x))
1✔
119
        self.assertTrue(np.array_equal(self.time_err, self.transient.x_err))
1✔
120

121
    def test_get_time_via_x_luminosity_data(self):
1✔
122
        new_times = np.array([1, 2, 3])
1✔
123
        new_time_errs = np.array([0.1, 0.2, 0.3])
1✔
124
        self.transient.time_rest_frame = new_times
1✔
125
        self.transient.time_rest_frame_err = new_time_errs
1✔
126
        self.transient.data_mode = "luminosity"
1✔
127
        self.assertTrue(np.array_equal(new_times, self.transient.x))
1✔
128
        self.assertTrue(np.array_equal(new_time_errs, self.transient.x_err))
1✔
129

130
    def test_x_same_as_time(self):
1✔
131
        self.assertTrue(np.array_equal(self.transient.x, self.transient.time))
1✔
132

133
    def test_xerr_same_as_time_err(self):
1✔
134
        self.assertTrue(np.array_equal(self.transient.x_err, self.transient.time_err))
1✔
135

136
    def test_set_use_phase_model(self):
1✔
137
        self.assertFalse(self.transient.use_phase_model)
1✔
138

139
    def test_xlabel(self):
1✔
140
        self.assertEqual(r"Time since explosion [days]", self.transient.xlabel)
1✔
141
        self.transient.use_phase_model = True
1✔
142
        self.assertEqual(r"Time [MJD]", self.transient.xlabel)
1✔
143

144
    def test_ylabel(self):
1✔
145
        self.assertEqual(r'Counts', self.transient.ylabel)
1✔
146
        self.transient.luminosity_data = True
1✔
147
        self.assertEqual(r'Luminosity [$10^{50}$ erg s$^{-1}$]', self.transient.ylabel)
1✔
148
        self.transient.magnitude_data = True
1✔
149
        self.assertEqual(r'Magnitude', self.transient.ylabel)
1✔
150
        self.transient.flux_data = True
1✔
151
        self.assertEqual(r'Flux [erg cm$^{-2}$ s$^{-1}$]', self.transient.ylabel)
1✔
152
        self.transient.flux_density_data = True
1✔
153
        self.assertEqual(r'Flux density [mJy]', self.transient.ylabel)
1✔
154
        self.transient.flux_density_data = False
1✔
155
        with self.assertRaises(ValueError):
1✔
156
            _ = self.transient.ylabel
1✔
157

158
    def test_use_phase_model_time_attribute(self):
1✔
159
        self.transient = redback.transient.transient.Transient(
1✔
160
            time_mjd=self.time, time_mjd_err=self.time_err, counts=self.y, redshift=self.redshift,
161
            data_mode=self.data_mode, name=self.name, photon_index=self.photon_index,
162
            use_phase_model=True)
163
        self.assertTrue(np.array_equal(self.transient.time_mjd, self.transient.x))
1✔
164
        self.assertTrue(np.array_equal(self.transient.time_mjd_err, self.transient.x_err))
1✔
165

166
    def test_set_x(self):
1✔
167
        new_x = np.array([2, 3, 4])
1✔
168
        self.transient.x = new_x
1✔
169
        self.assertTrue(np.array_equal(new_x, self.transient.x))
1✔
170
        self.assertTrue(np.array_equal(new_x, self.transient.time))
1✔
171

172
    def test_set_x_err(self):
1✔
173
        new_x_err = np.array([3, 4, 5])
1✔
174
        self.transient.x_err = new_x_err
1✔
175
        self.assertTrue(np.array_equal(new_x_err, self.transient.x_err))
1✔
176
        self.assertTrue(np.array_equal(new_x_err, self.transient.time_err))
1✔
177

178
    def test_set_y(self):
1✔
179
        new_y = np.array([7, 8, 9])
1✔
180
        self.transient.y = new_y
1✔
181
        self.assertTrue(np.array_equal(new_y, self.transient.y))
1✔
182
        self.assertTrue(np.array_equal(new_y, self.transient.counts))
1✔
183

184
    def test_set_y_err(self):
1✔
185
        new_y_err = np.array([7, 8, 9])
1✔
186
        self.transient.y_err = new_y_err
1✔
187
        self.assertTrue(np.array_equal(new_y_err, self.transient.y_err))
1✔
188
        self.assertTrue(np.array_equal(new_y_err, self.transient.counts_err))
1✔
189

190
    def test_y_same_as_counts(self):
1✔
191
        self.assertTrue(np.array_equal(self.transient.y, self.transient.counts))
1✔
192

193
    def test_yerr_same_as_counts(self):
1✔
194
        self.assertTrue(np.array_equal(self.transient.y_err, self.transient.counts_err))
1✔
195

196
    def test_redshift(self):
1✔
197
        self.assertEqual(self.redshift, self.transient.redshift)
1✔
198

199
    def test_get_data_mode(self):
1✔
200
        self.assertEqual(self.data_mode, self.transient.data_mode)
1✔
201

202
    def test_set_data_mode(self):
1✔
203
        new_data_mode = "luminosity"
1✔
204
        self.transient.data_mode = new_data_mode
1✔
205
        self.assertEqual(new_data_mode, self.transient.data_mode)
1✔
206

207
    def test_set_illegal_data_mode(self):
1✔
208
        with self.assertRaises(ValueError):
1✔
209
            self.transient.data_mode = "abc"
1✔
210

211
    def test_plot_lightcurve(self):
1✔
212
        pass
1✔
213
        # self.transient.plot_lightcurve(model=None)
214

215
    def test_plot_data(self):
1✔
216
        pass
1✔
217
        # self.transient.plot_data()
218

219

220
class TestOpticalTransient(unittest.TestCase):
1✔
221

222
    def setUp(self) -> None:
1✔
223
        self.time = np.array([1, 2, 3])
1✔
224
        self.time_err = np.array([0.2, 0.3, 0.4])
1✔
225
        self.y = np.array([3, 4, 2])
1✔
226
        self.y_err = np.sqrt(self.y)
1✔
227
        self.redshift = 0.75
1✔
228
        self.data_mode = 'flux_density'
1✔
229
        self.name = "SN2000A"
1✔
230
        self.photon_index = 2
1✔
231
        self.use_phase_model = False
1✔
232
        self.bands = np.array(['i', 'g', 'g'])
1✔
233
        self.active_bands = np.array(['g'])
1✔
234
        self.transient = redback.transient.transient.OpticalTransient(
1✔
235
            time=self.time, time_err=self.time_err, flux_density=self.y, flux_density_err=self.y_err,
236
            redshift=self.redshift, data_mode=self.data_mode, name=self.name,
237
            photon_index=self.photon_index, use_phase_model=self.use_phase_model, bands=self.bands,
238
            active_bands=self.active_bands)
239

240
    def tearDown(self) -> None:
1✔
241
        del self.time
1✔
242
        del self.time_err
1✔
243
        del self.y
1✔
244
        del self.y_err
1✔
245
        del self.redshift
1✔
246
        del self.data_mode
1✔
247
        del self.name
1✔
248
        del self.photon_index
1✔
249
        del self.use_phase_model
1✔
250
        del self.bands
1✔
251
        del self.active_bands
1✔
252
        del self.transient
1✔
253

254
    def test_load_data_magnitude(self):
1✔
255
        name = "optical_transient_test_data"
1✔
256
        transient_dir = f"{dirname}/data"
1✔
257
        processed_file_path = f"{transient_dir}/{name}.csv"
1✔
258
        data_mode = "magnitude"
1✔
259
        time_days, time_mjd, magnitude, magnitude_err, bands, system = \
1✔
260
            self.transient.load_data(processed_file_path=processed_file_path, data_mode=data_mode)
261
        expected_time_days = np.array([0.4813999999969383, 0.49020000000018626])
1✔
262
        expected_time_mjd = np.array([57982.9814, 57982.9902])
1✔
263
        expected_magnitude = np.array([17.48, 18.26])
1✔
264
        expected_magnitude_err = np.array([0.02, 0.15])
1✔
265
        expected_bands = np.array(["i", "H"])
1✔
266
        expected_system = np.array(["AB", "AB"])
1✔
267
        self.assertTrue(np.allclose(expected_time_days, time_days))
1✔
268
        self.assertTrue(np.allclose(expected_time_mjd, time_mjd))
1✔
269
        self.assertTrue(np.allclose(expected_magnitude, magnitude))
1✔
270
        self.assertTrue(np.allclose(expected_magnitude_err, magnitude_err))
1✔
271
        self.assertTrue(np.array_equal(expected_bands, bands))
1✔
272
        self.assertTrue(np.array_equal(expected_system, system))
1✔
273

274
    def test_load_data_flux_density(self):
1✔
275
        name = "optical_transient_test_data"
1✔
276
        transient_dir = f"{dirname}/data"
1✔
277
        data_mode = "flux_density"
1✔
278
        processed_file_path = f"{transient_dir}/{name}.csv"
1✔
279

280
        time_days, time_mjd, flux_density, flux_density_err, bands, system = \
1✔
281
            self.transient.load_data(processed_file_path=processed_file_path, data_mode=data_mode)
282
        expected_time_days = np.array([0.4813999999969383, 0.49020000000018626])
1✔
283
        expected_time_mjd = np.array([57982.9814, 57982.9902])
1✔
284
        expected_flux_density = np.array([0.36982817978026444, 0.1803017740859559])
1✔
285
        expected_flux_density_err = np.array([0.006812898591418732, 0.024911116226263914])
1✔
286
        expected_bands = np.array(["i", "H"])
1✔
287
        expected_system = np.array(["AB", "AB"])
1✔
288
        self.assertTrue(np.allclose(expected_time_days, time_days))
1✔
289
        self.assertTrue(np.allclose(expected_time_mjd, time_mjd))
1✔
290
        self.assertTrue(np.allclose(expected_flux_density, flux_density))
1✔
291
        self.assertTrue(np.allclose(expected_flux_density_err, flux_density_err))
1✔
292
        self.assertTrue(np.array_equal(expected_bands, bands))
1✔
293
        self.assertTrue(np.array_equal(expected_system, system))
1✔
294

295
    def test_load_data_all(self):
1✔
296
        name = "optical_transient_test_data"
1✔
297
        transient_dir = f"{dirname}/data"
1✔
298
        processed_file_path = f"{transient_dir}/{name}.csv"
1✔
299
        data_mode = "all"
1✔
300
        time_days, time_mjd, flux_density, flux_density_err, magnitude, magnitude_err, flux, flux_err, bands, system = \
1✔
301
            self.transient.load_data(processed_file_path=processed_file_path, data_mode=data_mode)
302
        expected_time_days = np.array([0.4813999999969383, 0.49020000000018626])
1✔
303
        expected_time_mjd = np.array([57982.9814, 57982.9902])
1✔
304
        expected_flux_density = np.array([0.36982817978026444, 0.1803017740859559])
1✔
305
        expected_flux_density_err = np.array([0.006812898591418732, 0.024911116226263914])
1✔
306
        expected_flux = np.array([0.36982817978026444, 0.1803017740859559])
1✔
307
        expected_flux_err = np.array([0.006812898591418732, 0.024911116226263914])
1✔
308
        expected_magnitude = np.array([17.48, 18.26])
1✔
309
        expected_magnitude_err = np.array([0.02, 0.15])
1✔
310
        expected_bands = np.array(["i", "H"])
1✔
311
        expected_system = np.array(["AB", "AB"])
1✔
312
        self.assertTrue(np.allclose(expected_time_days, time_days))
1✔
313
        self.assertTrue(np.allclose(expected_time_mjd, time_mjd))
1✔
314
        self.assertTrue(np.allclose(expected_flux_density, flux_density))
1✔
315
        self.assertTrue(np.allclose(expected_flux_density_err, flux_density_err))
1✔
316
        self.assertTrue(np.allclose(expected_magnitude, magnitude))
1✔
317
        self.assertTrue(np.allclose(expected_magnitude_err, magnitude_err))
1✔
318
        self.assertTrue(np.allclose(expected_flux, flux))
1✔
319
        self.assertTrue(np.allclose(expected_flux_err, flux_err))
1✔
320
        self.assertTrue(np.array_equal(expected_bands, bands))
1✔
321
        self.assertTrue(np.array_equal(expected_system, system))
1✔
322

323
    def test_get_from_open_access_catalogue(self):
1✔
324
        with mock.patch("redback.transient.transient.OpticalTransient.load_data") as m:
1✔
325
            expected_time_days = np.array([0.4813999999969383, 0.49020000000018626])
1✔
326
            expected_time_mjd = np.array([57982.9814, 57982.9902])
1✔
327
            expected_flux_density = np.array([0.36982817978026444, 0.1803017740859559])
1✔
328
            expected_flux_density_err = np.array([0.006812898591418732, 0.024911116226263914])
1✔
329
            expected_flux = np.array([0.36982817978026444, 0.1803017740859559])
1✔
330
            expected_flux_err = np.array([0.006812898591418732, 0.024911116226263914])
1✔
331
            expected_magnitude = np.array([17.48, 18.26])
1✔
332
            expected_magnitude_err = np.array([0.02, 0.15])
1✔
333
            expected_bands = np.array(["i", "H"])
1✔
334
            expected_system = np.array(["AB", "AB"])
1✔
335
            m.return_value = \
1✔
336
                expected_time_days, expected_time_mjd, expected_flux_density, expected_flux_density_err, \
337
                expected_magnitude, expected_magnitude_err, expected_flux, expected_flux_err, \
338
                expected_bands, expected_system
339
            name = "test"
1✔
340
            transient = redback.transient.transient.OpticalTransient.from_open_access_catalogue(name=name)
1✔
341
            self.assertTrue(transient.magnitude_data)
1✔
342
            self.assertEqual(name, transient.name)
1✔
343
            self.assertTrue(np.allclose(expected_time_days, transient.time))
1✔
344
            self.assertTrue(np.allclose(expected_time_mjd, transient.time_mjd))
1✔
345
            self.assertTrue(np.allclose(expected_flux_density, transient.flux_density))
1✔
346
            self.assertTrue(np.allclose(expected_flux_density_err, transient.flux_density_err))
1✔
347
            self.assertTrue(np.allclose(expected_flux, transient.flux))
1✔
348
            self.assertTrue(np.allclose(expected_flux_err, transient.flux_err))
1✔
349
            self.assertTrue(np.allclose(expected_magnitude, transient.magnitude))
1✔
350
            self.assertTrue(np.allclose(expected_magnitude_err, transient.magnitude_err))
1✔
351
            self.assertTrue(np.array_equal(expected_bands, transient.bands))
1✔
352
            self.assertTrue(np.array_equal(expected_system, transient.system))
1✔
353

354
    def test_set_active_bands(self):
1✔
355
        self.assertTrue(np.array_equal(np.array(self.active_bands), self.transient.active_bands))
1✔
356

357
    def test_set_active_bands_all(self):
1✔
358
        self.transient = redback.transient.transient.OpticalTransient(
1✔
359
            time=self.time, time_err=self.time_err, flux_density=self.y, flux_density_err=self.y_err,
360
            redshift=self.redshift, data_mode=self.data_mode, name=self.name,
361
            photon_index=self.photon_index, use_phase_model=self.use_phase_model, bands=self.bands,
362
            active_bands='all')
363
        self.assertTrue(np.array_equal(np.array(['g', 'i']), self.transient.active_bands))
1✔
364

365
    def test_set_frequencies_from_bands(self):
1✔
366
        expected = [1, 2, 2]
1✔
367
        bands_to_frequency = MagicMock(return_value=expected)
1✔
368
        self.transient = redback.transient.transient.OpticalTransient(
1✔
369
            time=self.time, time_err=self.time_err, flux_density=self.y, flux_density_err=self.y_err,
370
            redshift=self.redshift, data_mode=self.data_mode, name=self.name,
371
            photon_index=self.photon_index, use_phase_model=self.use_phase_model, bands=self.bands,
372
            active_bands=self.active_bands, bands_to_frequency=bands_to_frequency)
373
        self.assertTrue(np.array_equal(expected, self.transient.frequency))
1✔
374
        bands_to_frequency.assert_called_once()
1✔
375

376
    def test_set_frequencies_default(self):
1✔
377
        frequency = np.array([1, 2, 2])
1✔
378
        self.transient = redback.transient.transient.OpticalTransient(
1✔
379
            time=self.time, time_err=self.time_err, flux_density=self.y, flux_density_err=self.y_err,
380
            redshift=self.redshift, data_mode=self.data_mode, name=self.name,
381
            photon_index=self.photon_index, use_phase_model=self.use_phase_model, bands=self.bands,
382
            frequency=frequency, active_bands=self.active_bands)
383
        self.assertTrue(np.array_equal(frequency, self.transient.frequency))
1✔
384

385
    def test_get_filtered_data(self):
1✔
386
        filtered_x, filtered_x_err, filtered_y, filtered_y_err = self.transient.get_filtered_data()
1✔
387
        expected_x = self.time[1:]
1✔
388
        expected_x_err = self.time_err[1:]
1✔
389
        expected_y = self.y[1:]
1✔
390
        expected_y_err = self.y_err[1:]
1✔
391
        self.assertTrue(np.array_equal(expected_x, filtered_x))
1✔
392
        self.assertTrue(np.array_equal(expected_x_err, filtered_x_err))
1✔
393
        self.assertTrue(np.array_equal(expected_y, filtered_y))
1✔
394
        self.assertTrue(np.array_equal(expected_y_err, filtered_y_err))
1✔
395

396
    def test_get_filtered_data_no_x_err(self):
1✔
397
        self.transient.x_err = None
1✔
398
        _, filtered_x_err, _, _ = self.transient.get_filtered_data()
1✔
399
        self.assertIsNone(filtered_x_err)
1✔
400

401
    def test_get_filtered_data_illegal_data_mode(self):
1✔
402
        with self.assertRaises(ValueError):
1✔
403
            self.transient.luminosity_data = True
1✔
404
            self.transient.get_filtered_data()
1✔
405

406
    def test_meta_data_not_available(self):
1✔
407
        self.assertIsNone(self.transient.meta_data)
1✔
408

409
    @mock.patch("pandas.read_csv")
1✔
410
    def test_meta_data_from_csv(self, read_csv):
1✔
411
        self.transient.directory_structure = redback.get_data.directory.DirectoryStructure(
1✔
412
            directory_path='data', raw_file_path=None, processed_file_path=None)
413
        expected = dict(a=1)
1✔
414
        read_csv.return_value = expected
1✔
415
        self.transient._set_data()
1✔
416
        self.assertDictEqual(expected, self.transient.meta_data)
1✔
417

418
    def test_transient_dir(self):
1✔
419
        with mock.patch('redback.get_data.directory.open_access_directory_structure') as m:
1✔
420
            expected = 'expected'
1✔
421
            m.return_value = expected, '_', '_'
1✔
422
            self.assertEqual(expected, self.transient.transient_dir)
1✔
423

424
    def test_unique_bands(self):
1✔
425
        expected = np.array(['g', 'i'])
1✔
426
        self.assertTrue(np.array_equal(expected, self.transient.unique_bands))
1✔
427

428
    def test_list_of_band_indices(self):
1✔
429
        expected = [np.array([1, 2]), np.array([0])]
1✔
430
        self.assertTrue(np.array_equal(expected[0], self.transient.list_of_band_indices[0]))
1✔
431
        self.assertTrue(np.array_equal(expected[1], self.transient.list_of_band_indices[1]))
1✔
432

433
    def test_default_colors(self):
1✔
434
        expected = ["g", "r", "i", "z", "y", "J", "H", "K"]
1✔
435
        self.assertListEqual(expected, self.transient.default_filters)
1✔
436

437
    def test_get_colors(self):
1✔
438
        with mock.patch('matplotlib.cm.rainbow') as m:
1✔
439
            expected = 'rainbow'
1✔
440
            m.return_value = expected
1✔
441
            self.assertEqual(expected, self.transient.get_colors(filters=['a', 'b']))
1✔
442

443
    def test_estimate_bb_params_effective(self):
1✔
444
        """Test that estimate_bb_params returns a DataFrame with expected columns and positive values
445
        in effective flux density mode."""
446
        # Create a transient instance with flux_density data.
447
        new_time = np.array([10, 10.1, 10.2, 10.3, 10.4])
1✔
448
        new_flux = np.array([1e4, 1.05e4, 1.1e4, 1.05e4, 1e4])
1✔
449
        new_flux_err = np.array([100, 100, 100, 100, 100])
1✔
450
        new_freq = np.array([5e14, 6e14, 7e14, 8e14, 9e14])
1✔
451
        transient_bb = redback.transient.OpticalTransient(
1✔
452
            time=new_time, flux_density=new_flux,
453
            redshift=0.1, data_mode="flux_density", name="TestBB",
454
            frequency=new_freq, use_phase_model=False)
455
        # Monkey-patch get_filtered_data to return our simulated data.
456
        transient_bb.get_filtered_data = lambda: (new_time, np.zeros(5), new_flux, new_flux_err)
1✔
457
        df_bb = transient_bb.estimate_bb_params(distance=1e27, bin_width=1.0, min_filters=3)
1✔
458
        self.assertIsNotNone(df_bb, "Expected a DataFrame when sufficient data are provided.")
1✔
459
        self.assertIsInstance(df_bb, pd.DataFrame, "The output must be a DataFrame.")
1✔
460
        for col in ['epoch_times', 'temperature', 'radius', 'temp_err', 'radius_err']:
1✔
461
            self.assertIn(col, df_bb.columns, f"Column '{col}' is missing in the DataFrame.")
1✔
462
        # Check that the fitted temperature and radius are positive.
463
        self.assertGreater(df_bb['temperature'].iloc[0], 0, "Temperature should be positive.")
1✔
464
        self.assertGreater(df_bb['radius'].iloc[0], 0, "Radius should be positive.")
1✔
465

466
    def test_estimate_bolometric_luminosity_no_corrections(self):
1✔
467
        """Test that a bolometric luminosity is computed from the BB parameters (without boost or extinction)."""
468
        # Create a fake DataFrame of blackbody parameters.
469
        fake_df = pd.DataFrame({
1✔
470
            "epoch_times": [10.5],
471
            "temperature": [1e4],  # Kelvin
472
            "radius": [1e15],  # cm
473
            "temp_err": [500],
474
            "radius_err": [1e14]
475
        })
476
        transient_bb = redback.transient.OpticalTransient(
1✔
477
            time=np.array([10, 10.1, 10.2, 10.3, 10.4]),
478
            time_err=np.array([0.1] * 5),
479
            flux_density=np.array([1e4, 1.05e4, 1.1e4, 1.05e4, 1e4]),
480
            redshift=0.1, data_mode="flux_density", name="TestBB",
481
            photon_index=2, use_phase_model=False)
482
        # Monkey-patch estimate_bb_params to return our fake blackbody parameters.
483
        transient_bb.estimate_bb_params = lambda **kwargs: fake_df
1✔
484
        df_bol = transient_bb.estimate_bolometric_luminosity(distance=1e27, bin_width=1.0, min_filters=3)
1✔
485
        self.assertIsNotNone(df_bol, "A valid bolometric luminosity DataFrame is expected.")
1✔
486
        for col in ['lum_bol', 'lum_bol_err', 'lum_bol_bb', 'time_rest_frame']:
1✔
487
            self.assertIn(col, df_bol.columns, f"Column '{col}' is missing in the bolometric DataFrame.")
1✔
488
        self.assertGreater(df_bol['lum_bol'].iloc[0], 0, "Bolometric luminosity should be positive.")
1✔
489

490
    def test_estimate_bolometric_luminosity_with_boost_extinction(self):
1✔
491
        """Test that providing lambda_cut and A_ext yields a DataFrame with the boost/extinction corrections applied."""
492
        fake_df = pd.DataFrame({
1✔
493
            "epoch_times": [10.5],
494
            "temperature": [1e4],
495
            "radius": [1e15],
496
            "temp_err": [500],
497
            "radius_err": [1e14]
498
        })
499
        transient_bb = redback.transient.OpticalTransient(
1✔
500
            time=np.array([10, 10.1, 10.2, 10.3, 10.4]),
501
            time_err=np.array([0.1] * 5),
502
            flux_density=np.array([1e4, 1.05e4, 1.1e4, 1.05e4, 1e4]),
503
            redshift=0.1, data_mode="flux_density", name="TestBB",
504
            photon_index=2, use_phase_model=False)
505
        transient_bb.estimate_bb_params = lambda **kwargs: fake_df
1✔
506
        # Set lambda_cut (in angstroms) and an extinction A_ext in magnitudes.
507
        df_bol = transient_bb.estimate_bolometric_luminosity(
1✔
508
            distance=1e27, bin_width=1.0, min_filters=3, lambda_cut=3000, A_ext=0.5)
509
        self.assertIsNotNone(df_bol, "A DataFrame with boost and extinction corrections should be returned.")
1✔
510
        self.assertIn('lum_bol', df_bol.columns)
1✔
511
        # Check that luminosity is positive.
512
        self.assertGreater(df_bol['lum_bol'].iloc[0], 0, "Corrected bolometric luminosity should be positive.")
1✔
513

514

515
class TestAfterglow(unittest.TestCase):
1✔
516

517
    def setUp(self) -> None:
1✔
518
        self.time = np.array([1, 2, 3])
1✔
519
        self.time_err = np.array([0.2, 0.3, 0.4])
1✔
520
        self.y = np.array([3, 4, 2])
1✔
521
        self.y_err = np.sqrt(self.y)
1✔
522
        self.data_mode = 'flux'
1✔
523
        self.name = "GRB070809"
1✔
524
        self.use_phase_model = False
1✔
525
        self.bands = np.array(['i', 'g', 'g'])
1✔
526
        self.active_bands = np.array(['g'])
1✔
527
        self.FluxToLuminosityConverter = MagicMock()
1✔
528
        self.Truncator = MagicMock()
1✔
529
        self.sgrb = redback.transient.afterglow.SGRB(
1✔
530
            time=self.time, time_err=self.time_err, flux_density=self.y, flux_density_err=self.y_err,
531
            data_mode=self.data_mode, name=self.name,
532
            use_phase_model=self.use_phase_model, bands=self.bands,
533
            active_bands=self.active_bands, FluxToLuminosityConverter=self.FluxToLuminosityConverter,
534
            Truncator=self.Truncator)
535
        self.sgrb_luminosity = redback.transient.afterglow.SGRB(
1✔
536
            time=self.time, time_err=self.time_err, flux_density=self.y, flux_density_err=self.y_err,
537
            data_mode="luminosity", name=self.name,
538
            use_phase_model=self.use_phase_model, bands=self.bands,
539
            active_bands=self.active_bands, FluxToLuminosityConverter=self.FluxToLuminosityConverter,
540
            Truncator=self.Truncator)
541
        self.sgrb_flux_density = redback.transient.afterglow.SGRB(
1✔
542
            time=self.time, time_err=self.time_err, flux_density=self.y, flux_density_err=self.y_err,
543
            data_mode="flux_density", name=self.name,
544
            use_phase_model=self.use_phase_model, bands=self.bands,
545
            active_bands=self.active_bands, FluxToLuminosityConverter=self.FluxToLuminosityConverter,
546
            Truncator=self.Truncator)
547
        self.sgrb_not_existing = redback.transient.afterglow.SGRB(
1✔
548
            time=self.time, time_err=self.time_err, flux_density=self.y, flux_density_err=self.y_err,
549
            data_mode=self.data_mode, name="123456",
550
            use_phase_model=self.use_phase_model, bands=self.bands,
551
            active_bands=self.active_bands, FluxToLuminosityConverter=self.FluxToLuminosityConverter,
552
            Truncator=self.Truncator)
553
        self.sgrb_magnitude = redback.transient.afterglow.SGRB(
1✔
554
            time=self.time, time_err=self.time_err, magnitude=self.y, magnitude_err=self.y_err,
555
            data_mode="magnitude", name=self.name,
556
            use_phase_model=self.use_phase_model, bands=self.bands,
557
            active_bands=self.active_bands, FluxToLuminosityConverter=self.FluxToLuminosityConverter,
558
            Truncator=self.Truncator)
559
        self.sgrb_all_active_bands = redback.transient.afterglow.SGRB(
1✔
560
            time=self.time, time_err=self.time_err, flux_density=self.y, flux_density_err=self.y_err,
561
            data_mode=self.data_mode, name=self.name,
562
            use_phase_model=self.use_phase_model, bands=self.bands,
563
            active_bands='all', FluxToLuminosityConverter=self.FluxToLuminosityConverter, Truncator=self.Truncator)
564

565
    def tearDown(self) -> None:
1✔
566
        del self.time
1✔
567
        del self.time_err
1✔
568
        del self.y
1✔
569
        del self.y_err
1✔
570
        del self.data_mode
1✔
571
        del self.name
1✔
572
        del self.use_phase_model
1✔
573
        del self.bands
1✔
574
        del self.active_bands
1✔
575
        del self.sgrb
1✔
576
        del self.sgrb_not_existing
1✔
577
        del self.sgrb_magnitude
1✔
578
        del self.sgrb_all_active_bands
1✔
579
        del self.FluxToLuminosityConverter
1✔
580

581
    def test_stripped_name(self):
1✔
582
        expected = "070809"
1✔
583
        self.assertEqual(expected, self.sgrb._stripped_name)
1✔
584

585
    def test_truncate(self):
1✔
586
        expected_x = 0
1✔
587
        expected_x_err = 1
1✔
588
        expected_y = 2
1✔
589
        expected_yerr = 3
1✔
590
        return_value = expected_x, expected_x_err, expected_y, expected_yerr
1✔
591
        truncator = MagicMock(return_value=MagicMock(truncate=MagicMock(return_value=return_value)))
1✔
592
        self.sgrb.Truncator = truncator
1✔
593
        self.sgrb.truncate()
1✔
594
        self.assertListEqual(
1✔
595
            [expected_x, expected_x_err, expected_y, expected_yerr],
596
            [self.sgrb.x, self.sgrb.x_err, self.sgrb.y, self.sgrb.y_err])
597

598
    def test_set_active_bands(self):
1✔
599
        self.assertTrue(np.array_equal(np.array(self.active_bands), self.sgrb.active_bands))
1✔
600

601
    def test_set_active_bands_all(self):
1✔
602
        self.assertTrue(np.array_equal(np.array(['g', 'i']), self.sgrb_all_active_bands.active_bands))
1✔
603

604
    def test_set_frequencies_from_bands(self):
1✔
605
        expected = [1, 2, 2]
1✔
606
        bands_to_frequency = MagicMock(return_value=expected)
1✔
607
        self.sgrb = redback.transient.afterglow.SGRB(
1✔
608
            time=self.time, time_err=self.time_err, flux_density=self.y, flux_density_err=self.y_err,
609
            data_mode=self.data_mode, name=self.name,
610
            use_phase_model=self.use_phase_model, bands=self.bands,
611
            active_bands=self.active_bands, bands_to_frequency=bands_to_frequency)
612
        self.assertTrue(np.array_equal(expected, self.sgrb.frequency))
1✔
613
        bands_to_frequency.assert_called_once()
1✔
614

615
    def test_set_frequencies_default(self):
1✔
616
        frequency = np.array([1, 2, 2])
1✔
617
        self.sgrb = redback.transient.afterglow.SGRB(
1✔
618
            time=self.time, time_err=self.time_err, flux_density=self.y, flux_density_err=self.y_err,
619
            data_mode=self.data_mode, name=self.name,
620
            use_phase_model=self.use_phase_model, bands=self.bands,
621
            frequency=frequency, active_bands=self.active_bands)
622
        self.assertTrue(np.array_equal(frequency, self.sgrb.frequency))
1✔
623

624
    def test_get_filtered_data(self):
1✔
625
        filtered_x, filtered_x_err, filtered_y, filtered_y_err = self.sgrb_magnitude.get_filtered_data()
1✔
626
        expected_x = self.time[1:]
1✔
627
        expected_x_err = self.time_err[1:]
1✔
628
        expected_y = self.y[1:]
1✔
629
        expected_y_err = self.y_err[1:]
1✔
630
        self.assertTrue(np.array_equal(expected_x, filtered_x))
1✔
631
        self.assertTrue(np.array_equal(expected_x_err, filtered_x_err))
1✔
632
        self.assertTrue(np.array_equal(expected_y, filtered_y))
1✔
633
        self.assertTrue(np.array_equal(expected_y_err, filtered_y_err))
1✔
634

635
    def test_get_filtered_data_no_x_err(self):
1✔
636
        self.sgrb_magnitude.x_err = None
1✔
637
        _, filtered_x_err, _, _ = self.sgrb_magnitude.get_filtered_data()
1✔
638
        self.assertIsNone(filtered_x_err)
1✔
639

640
    def test_get_filtered_data_illegal_data_mode(self):
1✔
641
        self.sgrb.data_mode = "luminosity"
1✔
642
        with self.assertRaises(ValueError):
1✔
643
            self.sgrb.get_filtered_data()
1✔
644

645
    def test_event_table(self):
1✔
646
        expected = "/tables/SGRB_table.txt"
1✔
647
        self.assertIn(expected, self.sgrb.event_table)
1✔
648

649
    def test_meta_data_from_csv(self):
1✔
650
        with mock.patch("pandas.read_csv") as m:
1✔
651
            field_name = 'BAT Photon Index (15-150 keV) (PL = simple power-law, CPL = cutoff power-law)'
1✔
652
            data_frame = pd.DataFrame.from_dict({field_name: [0, 1, np.nan]})
1✔
653
            m.return_value = data_frame
1✔
654
            expected = np.array([0, 1, 0])
1✔
655
            self.sgrb._set_data()
1✔
656
            self.assertTrue(np.array_equal(expected, np.array(self.sgrb.meta_data[field_name])))
1✔
657

658
    def test_photon_index(self):
1✔
659
        self.assertEqual(1.69, self.sgrb.photon_index)
1✔
660

661
    def test_photon_index_missing(self):
1✔
662
        self.assertTrue(np.isnan(self.sgrb_not_existing.photon_index))
1✔
663

664
    def test_redshift(self):
1✔
665
        self.assertTrue(np.isnan(self.sgrb.redshift))
1✔
666

667
    def test_redshift_missing(self):
1✔
668
        self.assertTrue(np.isnan(self.sgrb_not_existing.redshift))
1✔
669

670
    def test_t90(self):
1✔
671
        lgrb = redback.transient.afterglow.LGRB(
1✔
672
            time=self.time, time_err=self.time_err, flux_density=self.y, flux_density_err=self.y_err,
673
            data_mode=self.data_mode, name="210318B",
674
            use_phase_model=self.use_phase_model, bands=self.bands,
675
            active_bands=self.active_bands)
676
        self.assertEqual(14.95, lgrb.t90)
1✔
677

678
    def test_t90_missing(self):
1✔
679
        self.assertTrue(np.isnan(self.sgrb_not_existing.t90))
1✔
680

681
    def test_flux_to_luminosity_luminosity(self):
1✔
682
        self.sgrb_luminosity.FluxToLuminosityConverter.convert_flux_to_luminosity = MagicMock()
1✔
683
        self.sgrb_luminosity.analytical_flux_to_luminosity()
1✔
684
        self.sgrb_luminosity.FluxToLuminosityConverter.convert_flux_to_luminosity.assert_not_called()
1✔
685

686
    def test_flux_to_luminosity_flux_density(self):
1✔
687
        self.sgrb_flux_density.FluxToLuminosityConverter.convert_flux_to_luminosity = MagicMock()
1✔
688
        self.sgrb_flux_density.analytical_flux_to_luminosity()
1✔
689
        self.sgrb_flux_density.FluxToLuminosityConverter.convert_flux_to_luminosity.assert_not_called()
1✔
690
        self.assertTrue(self.sgrb_flux_density.flux_density_data)
1✔
691

692
    def test_flux_to_luminosity_nan_redshift(self):
1✔
693
        return_value = np.array([0, 1, 2, 3]), np.array([[1, 2, 3, 4], [1, 2, 3, 4]]), \
1✔
694
                       np.array([2, 3, 4, 5]), np.array([[3, 4, 5, 6], [3, 4, 5, 6]])
695
        converter = MagicMock(return_value=MagicMock(convert_flux_to_luminosity=MagicMock(return_value=return_value)))
1✔
696
        self.sgrb.FluxToLuminosityConverter = converter
1✔
697
        self.sgrb.redshift = np.nan
1✔
698
        self.sgrb.analytical_flux_to_luminosity()
1✔
699
        converter.assert_called_once()
1✔
700
        self.assertTrue(self.sgrb.luminosity_data)
1✔
701
        self.assertTrue(np.array_equal(return_value[0], self.sgrb.x))
1✔
702
        self.assertTrue(np.array_equal(return_value[1], self.sgrb.x_err))
1✔
703
        self.assertTrue(np.array_equal(return_value[2], self.sgrb.y))
1✔
704
        self.assertTrue(np.array_equal(return_value[3], self.sgrb.y_err))
1✔
705

706
    def test_flux_to_luminosity_none_redshift(self):
1✔
707
        return_value = np.array([0, 1, 2, 3]), np.array([[1, 2, 3, 4], [1, 2, 3, 4]]), \
1✔
708
                       np.array([2, 3, 4, 5]), np.array([[3, 4, 5, 6], [3, 4, 5, 6]])
709
        converter = MagicMock(return_value=MagicMock(convert_flux_to_luminosity=MagicMock(return_value=return_value)))
1✔
710
        self.sgrb.FluxToLuminosityConverter = converter
1✔
711
        self.sgrb.redshift = None
1✔
712
        self.sgrb.analytical_flux_to_luminosity()
1✔
713

714
    def test_flux_to_luminosity_real_redshift(self):
1✔
715
        return_value = np.array([0, 1, 2, 3]), np.array([[1, 2, 3, 4], [1, 2, 3, 4]]), \
1✔
716
                       np.array([2, 3, 4, 5]), np.array([[3, 4, 5, 6], [3, 4, 5, 6]])
717
        converter = MagicMock(return_value=MagicMock(convert_flux_to_luminosity=MagicMock(return_value=return_value)))
1✔
718
        self.sgrb.FluxToLuminosityConverter = converter
1✔
719
        self.sgrb.redshift = 0.5
1✔
720
        self.sgrb.analytical_flux_to_luminosity()
1✔
721
        self.assertTrue(self.sgrb.luminosity_data)
1✔
722
        self.assertTrue(np.array_equal(return_value[0], self.sgrb.x))
1✔
723
        self.assertTrue(np.array_equal(return_value[1], self.sgrb.x_err))
1✔
724
        self.assertTrue(np.array_equal(return_value[2], self.sgrb.y))
1✔
725
        self.assertTrue(np.array_equal(return_value[3], self.sgrb.y_err))
1✔
726
        self.assertEqual(0.5, self.sgrb.redshift)
1✔
727

728
    def test_numerical_flux_to_luminosity(self):
1✔
729
        return_value = np.array([0, 1, 2, 3]), np.array([[1, 2, 3, 4], [1, 2, 3, 4]]), \
1✔
730
                       np.array([2, 3, 4, 5]), np.array([[3, 4, 5, 6], [3, 4, 5, 6]])
731
        converter = MagicMock(return_value=MagicMock(convert_flux_to_luminosity=MagicMock(return_value=return_value)))
1✔
732
        self.sgrb.FluxToLuminosityConverter = converter
1✔
733
        self.sgrb.redshift = 0.5
1✔
734
        self.sgrb.numerical_flux_to_luminosity(counts_to_flux_absorbed=1, counts_to_flux_unabsorbed=1)
1✔
735
        self.assertTrue(self.sgrb.luminosity_data)
1✔
736
        self.assertTrue(np.array_equal(return_value[0], self.sgrb.x))
1✔
737
        self.assertTrue(np.array_equal(return_value[1], self.sgrb.x_err))
1✔
738
        self.assertTrue(np.array_equal(return_value[2], self.sgrb.y))
1✔
739
        self.assertTrue(np.array_equal(return_value[3], self.sgrb.y_err))
1✔
740
        self.assertEqual(0.5, self.sgrb.redshift)
1✔
741

742

743
    def test_analytical_flux_to_luminosity(self):
1✔
744
        pass
1✔
745

746

747
class TestTrunctator(unittest.TestCase):
1✔
748

749
    def setUp(self):
1✔
750
        self.x = np.array([-1, 0., 0.2, 0.5, 0.8, 1.2, 1.5, 2.0, 2.5])
1✔
751
        self.x_err = np.array([[0.1, 0.1], [0.2, 0.2], [0.3, 0.3], [0.4, 0.4],
1✔
752
                               [0.5, 0.5], [0.6, 0.6], [0.7, 0.7], [0.8, 0.8], [0.9, 0.9]]).T
753
        self.y = np.array([0, 1, 2, 3, 4, 3, 2, 1, 0])
1✔
754
        self.y_err = np.array([[0.1, 0.1], [0.2, 0.2], [0.3, 0.3], [0.4, 0.4],
1✔
755
                               [0.5, 0.5], [0.6, 0.6], [0.7, 0.7], [0.8, 0.8], [0.9, 0.9]]).T
756
        self.truncate_method = 'default'
1✔
757
        self.truncator = redback.transient.afterglow.Truncator(
1✔
758
            x=self.x, x_err=self.x_err, y=self.y, y_err=self.y_err,
759
            time=self.x, time_err=self.x_err, truncate_method=self.truncate_method)
760

761
    def tearDown(self):
1✔
762
        del self.x
1✔
763
        del self.x_err
1✔
764
        del self.y
1✔
765
        del self.y_err
1✔
766
        del self.truncate_method
1✔
767
        del self.truncator
1✔
768

769
    def test_truncate_left_of_max(self):
1✔
770
        x, x_err, y, y_err = self.truncator.truncate_left_of_max()
1✔
771
        expected_x = np.array([0.8, 1.2, 1.5, 2.0, 2.5])
1✔
772
        expected_x_err = np.array([[0.5, 0.5], [0.6, 0.6], [0.7, 0.7], [0.8, 0.8], [0.9, 0.9]]).T
1✔
773
        expected_y = np.array([4, 3, 2, 1, 0])
1✔
774
        expected_y_err = np.array([[0.5, 0.5], [0.6, 0.6], [0.7, 0.7], [0.8, 0.8], [0.9, 0.9]]).T
1✔
775
        self.assertTrue(np.array_equal(expected_x, x))
1✔
776
        self.assertTrue(np.array_equal(expected_x_err, x_err))
1✔
777
        self.assertTrue(np.array_equal(expected_y, y))
1✔
778
        self.assertTrue(np.array_equal(expected_y_err, y_err))
1✔
779

780
    def test_truncate_default(self):
1✔
781
        x, x_err, y, y_err = self.truncator.truncate_default()
1✔
782
        expected_x = np.array([2.5])
1✔
783
        expected_x_err = np.array([[0.9, 0.9]]).T
1✔
784
        expected_y = np.array([0])
1✔
785
        expected_y_err = np.array([[0.9, 0.9]]).T
1✔
786
        self.assertTrue(np.array_equal(expected_x, x))
1✔
787
        self.assertTrue(np.array_equal(expected_x_err, x_err))
1✔
788
        self.assertTrue(np.array_equal(expected_y, y))
1✔
789
        self.assertTrue(np.array_equal(expected_y_err, y_err))
1✔
790

791
    def test_truncate_prompt_time_error(self):
1✔
792
        x, x_err, y, y_err = self.truncator.truncate_prompt_time_error()
1✔
793
        expected_x = np.array([2.0, 2.5])
1✔
794
        expected_x_err = np.array([[0.8, 0.8], [0.9, 0.9]]).T
1✔
795
        expected_y = np.array([1, 0])
1✔
796
        expected_y_err = np.array([[0.8, 0.8], [0.9, 0.9]]).T
1✔
797
        self.assertTrue(np.array_equal(expected_x, x))
1✔
798
        self.assertTrue(np.array_equal(expected_x_err, x_err))
1✔
799
        self.assertTrue(np.array_equal(expected_y, y))
1✔
800
        self.assertTrue(np.array_equal(expected_y_err, y_err))
1✔
801

802
    def test_truncate_with_prompt_time_error(self):
1✔
803
        with mock.patch.object(redback.transient.afterglow.Truncator, 'truncate_prompt_time_error') as m:
1✔
804
            self.truncator.truncate_method = 'prompt_time_error'
1✔
805
            self.truncator.truncate()
1✔
806
            m.assert_called_once()
1✔
807

808
    def test_truncate_with_left_of_max(self):
1✔
809
        with mock.patch.object(redback.transient.afterglow.Truncator, 'truncate_left_of_max') as m:
1✔
810
            self.truncator.truncate_method = 'left_of_max'
1✔
811
            self.truncator.truncate()
1✔
812
            m.assert_called_once()
1✔
813

814
    def test_truncate_with_default(self):
1✔
815
        with mock.patch.object(redback.transient.afterglow.Truncator, 'truncate_default') as m:
1✔
816
            self.truncator.truncate_method = 'default'
1✔
817
            self.truncator.truncate()
1✔
818
            m.assert_called_once()
1✔
819

820
    def test_truncate_with_default_with_other_string(self):
1✔
821
        with mock.patch.object(redback.transient.afterglow.Truncator, 'truncate_default') as m:
1✔
822
            self.truncator.truncate_method = 'other_string'
1✔
823
            self.truncator.truncate()
1✔
824
            m.assert_called_once()
1✔
825

826

827
class TestFluxToLuminosityConversion(unittest.TestCase):
1✔
828

829
    def setUp(self):
1✔
830
        self.redshift = 0.5
1✔
831
        self.photon_index = 2
1✔
832
        self.time = np.array([1, 2, 3])
1✔
833
        self.time_err = np.array([[0.1, 0.1], [0.2, 0.2], [0.1, 0.1]]).T
1✔
834
        self.flux = np.array([3.3, 4.4, 5.5])
1✔
835
        self.flux_err = np.array([0.33, 0.44, 0.55])
1✔
836
        self.counts_to_flux_absorbed = 2
1✔
837
        self.counts_to_flux_unabsorbed = 0.5
1✔
838
        self.conversion_method = "analytical"
1✔
839
        self.converter = redback.transient.afterglow.FluxToLuminosityConverter(
1✔
840
            redshift=self.redshift, photon_index=self.photon_index, time=self.time, time_err=self.time_err,
841
            flux=self.flux, flux_err=self.flux_err, counts_to_flux_absorbed=self.counts_to_flux_absorbed,
842
            counts_to_flux_unabsorbed=self.counts_to_flux_unabsorbed, conversion_method=self.conversion_method)
843

844
    def tearDown(self):
1✔
845
        del self.redshift
1✔
846
        del self.photon_index
1✔
847
        del self.time
1✔
848
        del self.time_err
1✔
849
        del self.flux
1✔
850
        del self.flux_err
1✔
851
        del self.counts_to_flux_absorbed
1✔
852
        del self.counts_to_flux_unabsorbed
1✔
853
        del self.conversion_method
1✔
854
        del self.converter
1✔
855

856
    def test_counts_to_flux_fraction(self):
1✔
857
        expected = 0.25
1✔
858
        self.assertEqual(expected, self.converter.counts_to_flux_fraction)
1✔
859

860
    def test_luminosity_distance(self):
1✔
861
        with mock.patch('astropy.cosmology.Planck18') as m:
1✔
862
            planck18_return_object = MagicMock()
1✔
863
            m.luminosity_distance.return_value = planck18_return_object
1✔
864
            # Assuming self.converter has a method that gets the luminosity distance
865
            result = self.converter.luminosity_distance  # Call the method
1✔
866
            self.assertEqual(result, 9.009021261306723e+27)  # Check the value
1✔
867

868
    def test_get_isotropic_bolometric_flux(self):
1✔
869
        expected = self.converter.luminosity_distance ** 2 * 4 * np.pi
1✔
870
        isotropic_bolometric_flux = self.converter.get_isotropic_bolometric_flux(k_corr=1)
1✔
871
        self.assertEqual(expected, isotropic_bolometric_flux)
1✔
872

873
    def test_get_analytical_k_correction(self):
1✔
874
        expected = (1 + self.redshift) ** (self.photon_index - 2)
1✔
875
        actual = self.converter.get_k_correction()
1✔
876
        self.assertEqual(expected, actual)
1✔
877

878
    def test_convert_flux_to_luminosity(self):
1✔
879
        x, x_err, y, y_err = self.converter.convert_flux_to_luminosity()
1✔
880
        self.assertEqual(len(self.time), len(x))
1✔
881
        self.assertEqual(len(self.time_err), len(x_err))
1✔
882
        self.assertEqual(len(self.flux), len(y))
1✔
883
        self.assertEqual(len(self.flux_err), len(y_err))
1✔
884
        self.assertTrue(np.array_equal(self.converter.time_rest_frame, x))
1✔
885
        self.assertTrue(np.array_equal(self.converter.time_rest_frame_err, x_err))
1✔
886
        self.assertTrue(np.array_equal(self.converter.Lum50, y))
1✔
887
        self.assertTrue(np.array_equal(self.converter.Lum50_err, y_err))
1✔
888

889
class TestLoadTransient(unittest.TestCase):
1✔
890

891
    def setUp(self) -> None:
1✔
892
        self.mock_file_path = "test_data.csv"
1✔
893
        self.mock_data = {
1✔
894
            "time (days)": [1.0, 2.0, 3.0],
895
            "time": [2450000.5, 2450001.5, 2450002.5],
896
            "magnitude": [21.0, 22.0, 23.0],
897
            "e_magnitude": [0.1, 0.1, 0.2],
898
            "band": ["g", "r", "i"],
899
            "flux_density(mjy)": [1.0, 2.0, 3.0],
900
            "flux_density_error": [0.1, 0.2, 0.3],
901
        }
902
        self.mock_df = pd.DataFrame(self.mock_data)
1✔
903

904
    def tearDown(self) -> None:
1✔
905
        if os.path.exists(self.mock_file_path):
1✔
NEW
906
            os.remove(self.mock_file_path)
×
907

908
    @patch("redback.transient.transient.pd.read_csv")
1✔
909
    def test_load_data_generic_with_magnitude_mode(self, mock_read_csv):
1✔
910
        mock_read_csv.return_value = self.mock_df
1✔
911
        result = redback.transient.Transient.load_data_generic(self.mock_file_path, data_mode="magnitude")
1✔
912
        expected_result = (
1✔
913
            np.array(self.mock_data["time (days)"]),
914
            np.array(self.mock_data["time"]),
915
            np.array(self.mock_data["magnitude"]),
916
            np.array(self.mock_data["e_magnitude"]),
917
            np.array(self.mock_data["band"]),
918
        )
919
        for res, exp in zip(result, expected_result):
1✔
920
            np.testing.assert_array_equal(res, exp)
1✔
921

922
    @patch("redback.transient.transient.pd.read_csv")
1✔
923
    def test_load_data_generic_with_flux_density_mode(self, mock_read_csv):
1✔
924
        mock_read_csv.return_value = self.mock_df
1✔
925
        result = redback.transient.Transient.load_data_generic(self.mock_file_path, data_mode="flux_density")
1✔
926
        expected_result = (
1✔
927
            np.array(self.mock_data["time (days)"]),
928
            np.array(self.mock_data["time"]),
929
            np.array(self.mock_data["flux_density(mjy)"]),
930
            np.array(self.mock_data["flux_density_error"]),
931
            np.array(self.mock_data["band"]),
932
        )
933
        for res, exp in zip(result, expected_result):
1✔
934
            np.testing.assert_array_equal(res, exp)
1✔
935

936
    @patch("redback.transient.transient.pd.read_csv")
1✔
937
    def test_load_data_generic_with_all_mode(self, mock_read_csv):
1✔
938
        mock_read_csv.return_value = self.mock_df
1✔
939
        result = redback.transient.Transient.load_data_generic(self.mock_file_path, data_mode="all")
1✔
940
        expected_result = (
1✔
941
            np.array(self.mock_data["time (days)"]),
942
            np.array(self.mock_data["time"]),
943
            np.array(self.mock_data["flux_density(mjy)"]),
944
            np.array(self.mock_data["flux_density_error"]),
945
            np.array(self.mock_data["magnitude"]),
946
            np.array(self.mock_data["e_magnitude"]),
947
            np.array(self.mock_data["band"]),
948
        )
949
        for res, exp in zip(result, expected_result):
1✔
950
            np.testing.assert_array_equal(res, exp)
1✔
951

952
    def test_load_data_generic_invalid_file_path(self):
1✔
953
        invalid_file_path = "invalid_path.csv"
1✔
954
        with self.assertRaises(FileNotFoundError):
1✔
955
            redback.transient.Transient.load_data_generic(invalid_file_path, data_mode="magnitude")
1✔
956

957
    @patch("redback.transient.transient.pd.read_csv")
1✔
958
    def test_load_data_generic_invalid_data_mode(self, mock_read_csv):
1✔
959
        with self.assertRaises(ValueError):
1✔
960
            redback.transient.Transient.load_data_generic(self.mock_file_path, data_mode="invalid_mode")
1✔
961

962
class TestFitGP(unittest.TestCase):
1✔
963
    def setUp(self) -> None:
1✔
964
        self.transient = redback.transient.Transient()
1✔
965
        self.transient.data_mode = "luminosity"
1✔
966
        self.transient.time_rest_frame = np.array([0.0, 1.0, 2.0, 3.0])
1✔
967
        self.transient.y = np.array([1.0, 2.0, 1.5, 3.0])
1✔
968
        self.transient.y_err = np.array([0.1, 0.2, 0.15, 0.3])
1✔
969
        self.transient.frequency = np.array([100.0, 200.0, 300.0, 400.0])
1✔
970
        self.transient._filtered_indices = np.array([0, 1, 2, 3])
1✔
971
        self.transient.active_bands = 'all'
1✔
972

973
    def tearDown(self) -> None:
1✔
974
        del self.transient
1✔
975

976
    def test_fit_gp_without_mean_model(self):
1✔
977
        """Test fitting a GP without a mean model."""
978
        kernel = MagicMock()
1✔
979

980
        with patch("george.GP") as mock_gp, \
1✔
981
                patch("scipy.optimize.minimize") as mock_minimize:
982
            mock_gp_instance = mock_gp.return_value
1✔
983
            mock_minimize.return_value.x = [1.0]
1✔
984

985
            result = self.transient.fit_gp(mean_model=None, kernel=kernel, prior=None, use_frequency=False)
1✔
986

987
            self.assertIsNotNone(result.gp)
1✔
988
            self.assertTrue(mock_gp_instance.compute.called)
1✔
989
            self.assertTrue(mock_minimize.called)
1✔
990
            self.assertEqual(result.mean_model, None)
1✔
991
            self.assertFalse(result.use_frequency)
1✔
992

993
    def test_fit_gp_with_mean_model(self):
1✔
994
        """Test fitting a GP with a specified mean model."""
995
        kernel = MagicMock()
1✔
996
        mean_model = MagicMock()
1✔
997
        prior = MagicMock()
1✔
998
        prior.sample.return_value = {"param1": 1.0, "param2": 2.0}
1✔
999

1000
        with patch("george.GP") as mock_gp, \
1✔
1001
                patch("bilby.core.likelihood.function_to_george_mean_model") as mock_mean_model, \
1002
                patch("scipy.optimize.minimize") as mock_minimize:
1003
            mock_gp_instance = mock_gp.return_value
1✔
1004
            mock_minimize.return_value.x = [2.0]
1✔
1005
            mock_mean_model.return_value = MagicMock()
1✔
1006

1007
            result = self.transient.fit_gp(mean_model=mean_model, kernel=kernel, prior=prior, use_frequency=False)
1✔
1008

1009
            self.assertIsNotNone(result.gp)
1✔
1010
            self.assertEqual(result.mean_model, mean_model)
1✔
1011
            self.assertTrue(mock_mean_model.called)
1✔
1012
            self.assertTrue(mock_gp_instance.compute.called)
1✔
1013
            self.assertTrue(mock_minimize.called)
1✔
1014

1015
    def test_fit_gp_without_prior_for_mean_model(self):
1✔
1016
        """Test fitting a GP with a mean model but without providing priors."""
1017
        kernel = MagicMock()
1✔
1018
        mean_model = MagicMock()
1✔
1019

1020
        with self.assertRaises(ValueError):
1✔
1021
            self.transient.fit_gp(mean_model=mean_model, kernel=kernel, prior=None, use_frequency=False)
1✔
1022

1023
    def test_fit_gp_with_invalid_data_mode(self):
1✔
1024
        """Test fitting a GP when an invalid/unsupported data mode is set."""
1025
        kernel = MagicMock()
1✔
1026

1027
        with self.assertRaises(ValueError) as context:
1✔
1028
            self.transient.data_mode = "invalid_mode"  # Invalid data mode
1✔
1029

1030
        self.assertEqual(str(context.exception), "Unknown data mode.")
1✔
1031

1032
    def test_fit_gp_with_use_frequency(self):
1✔
1033
        """Test fitting GP while using frequency as an input (2D GP)."""
1034
        kernel = MagicMock()
1✔
1035

1036
        with patch("george.GP") as mock_gp, \
1✔
1037
                patch("scipy.optimize.minimize") as mock_minimize:
1038
            mock_gp_instance = mock_gp.return_value
1✔
1039
            mock_minimize.return_value.x = [3.0]
1✔
1040

1041
            result = self.transient.fit_gp(mean_model=None, kernel=kernel, prior=None, use_frequency=True)
1✔
1042

1043
            self.assertIsNotNone(result.gp)
1✔
1044
            self.assertTrue(mock_gp_instance.compute.called)
1✔
1045
            self.assertTrue(mock_minimize.called)
1✔
1046
            self.assertTrue(result.use_frequency)
1✔
1047

1048
    def test_fit_gp_scaling_behavior(self):
1✔
1049
        """Test that GP fitting scales the y values correctly."""
1050
        kernel = MagicMock()
1✔
1051

1052
        with patch("george.GP") as mock_gp, \
1✔
1053
                patch("scipy.optimize.minimize") as mock_minimize:
1054
            mock_gp_instance = mock_gp.return_value
1✔
1055
            mock_minimize.return_value.x = [1.0]
1✔
1056

1057
            result = self.transient.fit_gp(mean_model=None, kernel=kernel, prior=None, use_frequency=False)
1✔
1058

1059
            self.assertTrue(mock_gp_instance.compute.called)
1✔
1060
            self.assertTrue(mock_minimize.called)
1✔
1061
            self.assertAlmostEqual(result.y_scaler, np.max(self.transient.y))
1✔
1062
            self.assertTrue(np.allclose(result.scaled_y, self.transient.y / np.max(self.transient.y)))
1✔
1063

1064
class TestFromSimulatedOpticalData(unittest.TestCase):
1✔
1065
    @mock.patch("pandas.read_csv")
1✔
1066
    def test_from_simulated_optical_data_success(self, mock_read_csv):
1✔
1067
        mock_data = {
1✔
1068
            "time (days)": [1.0, 2.0, 3.0],
1069
            "time": [10.0, 20.0, 30.0],
1070
            "magnitude": [22.1, 23.2, 24.3],
1071
            "e_magnitude": [0.1, 0.2, 0.3],
1072
            "band": ["g", "r", "i"],
1073
            "bands": ["g", "r", "i"],
1074
            "wavelength [Hz]": [1e14, 2e14, 3e14],
1075
            "sncosmo_name": ["ztfg", "ztfr", "ztfi"],
1076
            "flux(erg/cm2/s)": [1e-15, 2e-15, 3e-15],
1077
            "flux_error": [1e-16, 2e-16, 3e-16],
1078
            "flux_density(mjy)": [1.1, 1.2, 1.3],
1079
            "flux_density_error": [0.1, 0.2, 0.3],
1080
            "detected": [1, 1, 1],
1081
        }
1082
        mock_df = pd.DataFrame(mock_data)
1✔
1083
        mock_read_csv.return_value = mock_df
1✔
1084

1085
        instance = redback.transient.Transient.from_simulated_optical_data(
1✔
1086
            name="test_transient",
1087
            data_mode="magnitude",
1088
            active_bands="all",
1089
            plotting_order=None,
1090
            use_phase_model=False,
1091
        )
1092

1093
        self.assertEqual(instance.name, "test_transient")
1✔
1094
        np.testing.assert_array_equal(instance.time, np.array(mock_data["time (days)"]))
1✔
1095
        np.testing.assert_array_equal(instance.time_mjd, np.array(mock_data["time"]))
1✔
1096
        np.testing.assert_array_equal(instance.magnitude, np.array(mock_data["magnitude"]))
1✔
1097
        np.testing.assert_array_equal(instance.magnitude_err, np.array(mock_data["e_magnitude"]))
1✔
1098
        np.testing.assert_array_equal(instance.bands, np.array(mock_data["band"]))
1✔
1099
        np.testing.assert_array_equal(instance.flux, np.array(mock_data["flux(erg/cm2/s)"]))
1✔
1100
        np.testing.assert_array_equal(instance.flux_err, np.array(mock_data["flux_error"]))
1✔
1101
        np.testing.assert_array_equal(instance.flux_density, np.array(mock_data["flux_density(mjy)"]))
1✔
1102
        np.testing.assert_array_equal(instance.flux_density_err, np.array(mock_data["flux_density_error"]))
1✔
1103

1104
    @mock.patch("pandas.read_csv")
1✔
1105
    def test_from_simulated_optical_data_no_detected_entries(self, mock_read_csv):
1✔
1106
        mock_data = {
1✔
1107
            "time (days)": [1.0, 2.0, 3.0],
1108
            "time": [10.0, 20.0, 30.0],
1109
            "magnitude": [22.1, 23.2, 24.3],
1110
            "e_magnitude": [0.1, 0.2, 0.3],
1111
            "band": ["g", "r", "i"],
1112
            "bands": ["g", "r", "i"],
1113
            "wavelength [Hz]": [1e14, 2e14, 3e14],
1114
            "sncosmo_name": ["ztfg", "ztfr", "ztfi"],
1115
            "flux(erg/cm2/s)": [1e-15, 2e-15, 3e-15],
1116
            "flux_error": [1e-16, 2e-16, 3e-16],
1117
            "flux_density(mjy)": [1.1, 1.2, 1.3],
1118
            "flux_density_error": [0.1, 0.2, 0.3],
1119
            "detected": [0, 0, 0],
1120
        }
1121
        mock_df = pd.DataFrame(mock_data)
1✔
1122
        mock_read_csv.return_value = mock_df
1✔
1123

1124
        instance = redback.transient.Transient.from_simulated_optical_data(
1✔
1125
            name="test_transient",
1126
            data_mode="magnitude",
1127
            active_bands="all",
1128
            plotting_order=None,
1129
            use_phase_model=False,
1130
        )
1131

1132
        # safer assertions for either empty arrays or None to ensure test robustness
1133
        attributes = [
1✔
1134
            instance.time,
1135
            instance.time_mjd,
1136
            instance.magnitude,
1137
            instance.magnitude_err,
1138
            instance.bands,
1139
            instance.flux,
1140
            instance.flux_err,
1141
            instance.flux_density,
1142
            instance.flux_density_err
1143
        ]
1144

1145
        for attr in attributes:
1✔
1146
            if attr is not None:
1✔
1147
                self.assertEqual(len(attr), 0)
1✔
1148
            else:
NEW
1149
                self.assertIsNone(attr)
×
1150

1151
    @mock.patch("pandas.read_csv")
1✔
1152
    def test_from_simulated_optical_data_file_not_found(self, mock_read_csv):
1✔
1153
        mock_read_csv.side_effect = FileNotFoundError
1✔
1154

1155
        with self.assertRaises(FileNotFoundError):
1✔
1156
            redback.transient.Transient.from_simulated_optical_data(
1✔
1157
                name="non_existent_transient",
1158
                data_mode="magnitude",
1159
                active_bands="all",
1160
                plotting_order=None,
1161
                use_phase_model=False,
1162
            )
1163

1164
class TestFromLasairTransient(unittest.TestCase):
1✔
1165
    def setUp(self) -> None:
1✔
1166
        self.mock_data = {
1✔
1167
            "time (days)": [0.1, 0.2, 0.3],
1168
            "time": [59000.1, 59000.2, 59000.3],
1169
            "magnitude": [20.5, 20.6, 20.7],
1170
            "e_magnitude": [0.1, 0.1, 0.1],
1171
            "band": ["g", "r", "i"],
1172
            "bands": ["g", "r", "i"],
1173
            "wavelength [Hz]": [1e14, 2e14, 3e14],
1174
            "sncosmo_name": ["ztfg", "ztfr", "ztfi"],
1175
            "flux(erg/cm2/s)": [1e-15, 1.1e-15, 1.2e-15],
1176
            "flux_error": [1e-16, 1.1e-16, 1.2e-16],
1177
            "flux_density(mjy)": [0.35, 0.36, 0.37],
1178
            "flux_density_error": [0.05, 0.05, 0.05]
1179
        }
1180
        self.mock_df = pd.DataFrame(self.mock_data)
1✔
1181

1182
        self.mock_directory = mock.MagicMock()
1✔
1183
        self.mock_directory.processed_file_path = "mock/path/to/file.csv"
1✔
1184

1185
    def tearDown(self) -> None:
1✔
1186
        pass
1✔
1187

1188
    @mock.patch("redback.get_data.directory.lasair_directory_structure")
1✔
1189
    @mock.patch("pandas.read_csv")
1✔
1190
    def test_from_lasair_data_basic_functionality(self, mock_read_csv, mock_directory_structure):
1✔
1191
        mock_directory_structure.return_value = self.mock_directory
1✔
1192
        mock_read_csv.return_value = self.mock_df
1✔
1193

1194
        transient = redback.transient.Transient.from_lasair_data(
1✔
1195
            name="test_transient",
1196
            data_mode="magnitude",
1197
            active_bands="all",
1198
            use_phase_model=False
1199
        )
1200

1201
        self.assertEqual(transient.name, "test_transient")
1✔
1202
        self.assertEqual(transient.data_mode, "magnitude")
1✔
1203
        np.testing.assert_array_equal(transient.time, self.mock_data["time (days)"])
1✔
1204
        np.testing.assert_array_equal(transient.time_mjd, self.mock_data["time"])
1✔
1205
        np.testing.assert_array_equal(transient.magnitude, self.mock_data["magnitude"])
1✔
1206
        np.testing.assert_array_equal(transient.magnitude_err, self.mock_data["e_magnitude"])
1✔
1207
        np.testing.assert_array_equal(transient.bands, self.mock_data["band"])
1✔
1208
        np.testing.assert_array_equal(transient.flux, self.mock_data["flux(erg/cm2/s)"])
1✔
1209
        np.testing.assert_array_equal(transient.flux_err, self.mock_data["flux_error"])
1✔
1210
        np.testing.assert_array_equal(transient.flux_density, self.mock_data["flux_density(mjy)"])
1✔
1211
        np.testing.assert_array_equal(transient.flux_density_err, self.mock_data["flux_density_error"])
1✔
1212

1213
    @mock.patch("redback.get_data.directory.lasair_directory_structure")
1✔
1214
    @mock.patch("pandas.read_csv")
1✔
1215
    def test_from_lasair_data_with_plotting_order(self, mock_read_csv, mock_directory_structure):
1✔
1216
        mock_directory_structure.return_value = self.mock_directory
1✔
1217
        mock_read_csv.return_value = self.mock_df
1✔
1218

1219
        plotting_order = np.array(["r", "g", "i"])
1✔
1220
        transient = redback.transient.Transient.from_lasair_data(
1✔
1221
            name="test_transient",
1222
            data_mode="magnitude",
1223
            active_bands="all",
1224
            use_phase_model=False,
1225
            plotting_order=plotting_order
1226
        )
1227

1228
        self.assertEqual(transient.plotting_order.tolist(), plotting_order.tolist())
1✔
1229

1230
    @mock.patch("redback.get_data.directory.lasair_directory_structure")
1✔
1231
    @mock.patch("pandas.read_csv")
1✔
1232
    def test_from_lasair_data_invalid_data_mode(self, mock_read_csv, mock_directory_structure):
1✔
1233
        mock_directory_structure.return_value = self.mock_directory
1✔
1234
        mock_read_csv.return_value = self.mock_df
1✔
1235

1236
        with self.assertRaises(ValueError):
1✔
1237
            redback.transient.Transient.from_lasair_data(
1✔
1238
                name="test_transient",
1239
                data_mode="invalid_mode",
1240
                active_bands="all",
1241
                use_phase_model=False
1242
            )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc