def test_set_one_pass(self): """Test _tc_from_track function.""" intensity_idx = [0, 1, 2, 3, 80, 100, 120, 200, 220, 250, 260, 295] intensity_values = { "geosphere": [25.60794285, 26.90906280, 28.26649026, 25.54076797, 31.21986961, 36.17171808, 21.11408573, 28.01457948, 32.65349378, 31.34027741, 0, 40.27362679], "equirect": [25.60778909, 26.90887264, 28.26624642, 25.54092386, 31.21941738, 36.16596567, 21.11399856, 28.01452136, 32.65076804, 31.33884098, 0, 40.27002104] } # the values for the two metrics should agree up to first digit at least for i, val in enumerate(intensity_values["geosphere"]): self.assertAlmostEqual(intensity_values["equirect"][i], val, 1) tc_track = TCTracks() tc_track.read_processed_ibtracs_csv(TEST_TRACK) tc_track.equal_timestep() tc_track.data = tc_track.data[:1] for metric in ["equirect", "geosphere"]: tc_haz = TropCyclone() tc_haz.set_from_tracks(tc_track, centroids=CENTR_TEST_BRB, model='H08', store_windfields=True, metric=metric) self.assertEqual(tc_haz.tag.haz_type, 'TC') self.assertEqual(tc_haz.tag.description, '') self.assertEqual(tc_haz.tag.file_name, 'Name: 1951239N12334') self.assertEqual(tc_haz.units, 'm/s') self.assertEqual(tc_haz.centroids.size, 296) self.assertEqual(tc_haz.event_id.size, 1) self.assertEqual(tc_haz.date.size, 1) self.assertEqual(dt.datetime.fromordinal(tc_haz.date[0]).year, 1951) self.assertEqual(dt.datetime.fromordinal(tc_haz.date[0]).month, 8) self.assertEqual(dt.datetime.fromordinal(tc_haz.date[0]).day, 27) self.assertEqual(tc_haz.event_id[0], 1) self.assertEqual(tc_haz.event_name, ['1951239N12334']) self.assertTrue(np.array_equal(tc_haz.frequency, np.array([1]))) self.assertTrue(isinstance(tc_haz.fraction, sparse.csr.csr_matrix)) self.assertEqual(tc_haz.fraction.shape, (1, 296)) self.assertEqual(tc_haz.fraction[0, 100], 1) self.assertEqual(tc_haz.fraction[0, 260], 0) self.assertEqual(tc_haz.fraction.nonzero()[0].size, 280) self.assertTrue(isinstance(tc_haz.intensity, sparse.csr.csr_matrix)) self.assertEqual(tc_haz.intensity.shape, (1, 296)) self.assertEqual(np.nonzero(tc_haz.intensity)[0].size, 280) for idx, val in zip(intensity_idx, intensity_values[metric]): if val == 0: self.assertEqual(tc_haz.intensity[0, idx], 0) else: self.assertAlmostEqual(tc_haz.intensity[0, idx], val) windfields = tc_haz.windfields[0].toarray() windfields = windfields.reshape(windfields.shape[0], -1, 2) windfield_norms = np.linalg.norm(windfields, axis=-1).max(axis=0) intensity = tc_haz.intensity.toarray()[0, :] msk = (intensity > 0) np.testing.assert_array_equal(windfield_norms[msk], intensity[msk])
def test_set_one_pass(self): """Test _tc_from_track function.""" tc_track = TCTracks() tc_track.read_processed_ibtracs_csv(TEST_TRACK) tc_track.equal_timestep() tc_track.data = tc_track.data[:1] tc_haz = TropCyclone() tc_haz.set_from_tracks(tc_track, centroids=CENTR_TEST_BRB, model='H08', store_windfields=True) self.assertEqual(tc_haz.tag.haz_type, 'TC') self.assertEqual(tc_haz.tag.description, '') self.assertEqual(tc_haz.tag.file_name, 'Name: 1951239N12334') self.assertEqual(tc_haz.units, 'm/s') self.assertEqual(tc_haz.centroids.size, 296) self.assertEqual(tc_haz.event_id.size, 1) self.assertEqual(tc_haz.date.size, 1) self.assertEqual(dt.datetime.fromordinal(tc_haz.date[0]).year, 1951) self.assertEqual(dt.datetime.fromordinal(tc_haz.date[0]).month, 8) self.assertEqual(dt.datetime.fromordinal(tc_haz.date[0]).day, 27) self.assertEqual(tc_haz.event_id[0], 1) self.assertEqual(tc_haz.event_name, ['1951239N12334']) self.assertTrue(np.array_equal(tc_haz.frequency, np.array([1]))) self.assertTrue(isinstance(tc_haz.fraction, sparse.csr.csr_matrix)) self.assertEqual(tc_haz.fraction.shape, (1, 296)) self.assertEqual(tc_haz.fraction[0, 100], 1) self.assertEqual(tc_haz.fraction[0, 260], 0) self.assertEqual(tc_haz.fraction.nonzero()[0].size, 280) self.assertTrue(isinstance(tc_haz.intensity, sparse.csr.csr_matrix)) self.assertEqual(tc_haz.intensity.shape, (1, 296)) self.assertEqual(np.nonzero(tc_haz.intensity)[0].size, 280) self.assertEqual(tc_haz.intensity[0, 260], 0) self.assertAlmostEqual(tc_haz.intensity[0, 1], 27.08333002) self.assertAlmostEqual(tc_haz.intensity[0, 2], 28.46008202) self.assertAlmostEqual(tc_haz.intensity[0, 3], 25.70445069) self.assertAlmostEqual(tc_haz.intensity[0, 100], 36.45564037) self.assertAlmostEqual(tc_haz.intensity[0, 250], 31.60115745) self.assertAlmostEqual(tc_haz.intensity[0, 295], 40.62433745) to_kn = (1.0 * ureg.meter / ureg.second).to(ureg.knot).magnitude wind = tc_haz.intensity.toarray()[0, :] self.assertAlmostEqual(wind[0] * to_kn, 50.08492156) self.assertAlmostEqual(wind[80] * to_kn, 61.13812028) self.assertAlmostEqual(wind[120] * to_kn, 41.26159439) self.assertAlmostEqual(wind[200] * to_kn, 54.85572160) self.assertAlmostEqual(wind[220] * to_kn, 63.99749424) windfields = tc_haz.windfields[0].toarray() windfields = windfields.reshape(windfields.shape[0], -1, 2) windfield_norms = np.linalg.norm(windfields, axis=-1).max(axis=0) intensity = tc_haz.intensity.toarray()[0, :] msk = (intensity > 0) self.assertTrue(np.allclose(windfield_norms[msk], intensity[msk]))
def test_two_files_pass(self): """Test set function set_from_tracks with two ibtracs.""" tc_track = TCTracks() tc_track.read_processed_ibtracs_csv([TEST_TRACK_SHORT, TEST_TRACK_SHORT]) tc_haz = TropCyclone() tc_haz.set_from_tracks(tc_track, CENTR_TEST_BRB) tc_haz.remove_duplicates() tc_haz.check() self.assertEqual(tc_haz.tag.haz_type, 'TC') self.assertEqual(tc_haz.tag.description, '') self.assertEqual(tc_haz.tag.file_name, ['Name: 1951239N12334', 'Name: 1951239N12334']) self.assertEqual(tc_haz.units, 'm/s') self.assertEqual(tc_haz.centroids.size, 296) self.assertEqual(tc_haz.event_id.size, 1) self.assertEqual(tc_haz.event_id[0], 1) self.assertEqual(tc_haz.event_name, ['1951239N12334']) self.assertTrue(np.array_equal(tc_haz.frequency, np.array([1]))) self.assertTrue(np.array_equal(tc_haz.orig, np.array([True]))) self.assertTrue(isinstance(tc_haz.intensity, sparse.csr.csr_matrix)) self.assertTrue(isinstance(tc_haz.fraction, sparse.csr.csr_matrix)) self.assertEqual(tc_haz.intensity.shape, (1, 296)) self.assertEqual(tc_haz.fraction.shape, (1, 296)) self.assertEqual(tc_haz.fraction.nonzero()[0].size, 0) self.assertEqual(tc_haz.intensity.nonzero()[0].size, 0)
def test_set_one_file_pass(self): """Test from_tracks with one input.""" tc_track = TCTracks.from_processed_ibtracs_csv(TEST_TRACK_SHORT) tc_haz = TropCyclone.from_tracks(tc_track, centroids=CENTR_TEST_BRB) tc_haz.check() self.assertEqual(tc_haz.tag.haz_type, 'TC') self.assertEqual(tc_haz.tag.description, '') self.assertEqual(tc_haz.tag.file_name, 'Name: 1951239N12334') self.assertEqual(tc_haz.units, 'm/s') self.assertEqual(tc_haz.centroids.size, 296) self.assertEqual(tc_haz.event_id.size, 1) self.assertEqual(tc_haz.event_id[0], 1) self.assertEqual(tc_haz.event_name, ['1951239N12334']) self.assertEqual(tc_haz.category, tc_track.data[0].category) self.assertEqual(tc_haz.basin[0], 'NA') self.assertIsInstance(tc_haz.basin, list) self.assertIsInstance(tc_haz.category, np.ndarray) self.assertTrue(np.array_equal(tc_haz.frequency, np.array([1]))) self.assertTrue(isinstance(tc_haz.intensity, sparse.csr.csr_matrix)) self.assertTrue(isinstance(tc_haz.fraction, sparse.csr.csr_matrix)) self.assertEqual(tc_haz.intensity.shape, (1, 296)) self.assertEqual(tc_haz.fraction.shape, (1, 296)) self.assertEqual(tc_haz.fraction.nonzero()[0].size, 0) self.assertEqual(tc_haz.intensity.nonzero()[0].size, 0)
def test_set_one_pass(self): """Test _hazard_from_track function.""" tc_track = TCTracks() tc_track.read_processed_ibtracs_csv(TEST_TRACK_SHORT) tc_track.equal_timestep() coastal_centr = tc.coastal_centr_idx(CENT_CLB) tc_haz = TropCyclone._tc_from_track(tc_track.data[0], CENT_CLB, coastal_centr) self.assertEqual(tc_haz.tag.haz_type, 'TC') self.assertEqual(tc_haz.tag.description, '') self.assertEqual(tc_haz.tag.file_name, 'IBTrACS: 1951239N12334') self.assertEqual(tc_haz.units, 'm/s') self.assertEqual(tc_haz.centroids.size, 1656093) self.assertEqual(tc_haz.event_id.size, 1) self.assertEqual(tc_haz.date.size, 1) self.assertEqual(dt.datetime.fromordinal(tc_haz.date[0]).year, 1951) self.assertEqual(dt.datetime.fromordinal(tc_haz.date[0]).month, 8) self.assertEqual(dt.datetime.fromordinal(tc_haz.date[0]).day, 27) self.assertEqual(tc_haz.event_id[0], 1) self.assertEqual(tc_haz.event_name, ['1951239N12334']) self.assertTrue(np.array_equal(tc_haz.frequency, np.array([1]))) self.assertTrue(isinstance(tc_haz.intensity, sparse.csr.csr_matrix)) self.assertTrue(isinstance(tc_haz.fraction, sparse.csr.csr_matrix)) self.assertEqual(tc_haz.intensity.shape, (1, 1656093)) self.assertEqual(tc_haz.fraction.shape, (1, 1656093)) self.assertAlmostEqual(tc_haz.intensity[0, 1630393], 18.511077471450232, 6) self.assertEqual(tc_haz.intensity[0, 1630394], 0) self.assertEqual(tc_haz.fraction[0, 1630393], 1) self.assertEqual(tc_haz.fraction[0, 1630394], 0) self.assertEqual(tc_haz.fraction.nonzero()[0].size, 7) self.assertEqual(tc_haz.intensity.nonzero()[0].size, 7)
def set_from_tracks(self, tracks, centroids=None, dist_degree=3, description=''): """Computes rainfield from tracks based on the RCLIPER model. Parallel process. Parameters: tracks (TCTracks): tracks of events centroids (Centroids, optional): Centroids where to model TC. Default: global centroids. disr_degree (int): distance (in degrees) from node within which the rainfield is processed (default 3 deg,~300km) description (str, optional): description of the events """ num_tracks = tracks.size if centroids is None: centroids = Centroids.from_base_grid(res_as=360, land=True) if not centroids.coord.size: centroids.set_meta_to_lat_lon() LOGGER.info('Mapping %s tracks to %s centroids.', str(tracks.size), str(centroids.size)) if self.pool: chunksize = min(num_tracks // self.pool.ncpus, 1000) tc_haz = self.pool.map(self._set_from_track, tracks.data, itertools.repeat(centroids, num_tracks), itertools.repeat(dist_degree, num_tracks), itertools.repeat(self.intensity_thres, num_tracks), chunksize=chunksize) else: tc_haz = list() for track in tracks.data: tc_haz.append( self._set_from_track(track, centroids, dist_degree=dist_degree, intensity=self.intensity_thres)) LOGGER.debug('Append events.') self.concatenate(tc_haz) LOGGER.debug('Compute frequency.') TropCyclone.frequency_from_tracks(self, tracks.data) self.tag.description = description
def test_set_one_file_pass(self): """ Test set function set_from_tracks with one input.""" pool = Pool() tc_track = TCTracks(pool) tc_track.read_processed_ibtracs_csv(TEST_TRACK) tc_track.calc_random_walk() tc_track.equal_timestep() tc_haz = TropCyclone(pool) tc_haz.set_from_tracks(tc_track, CENTR_TEST_BRB) tc_haz.check() pool.close() pool.join() self.assertEqual(tc_haz.tag.haz_type, 'TC') self.assertEqual(tc_haz.tag.description, '') self.assertEqual(tc_haz.units, 'm/s') self.assertEqual(tc_haz.centroids.size, 296) self.assertEqual(tc_haz.event_id.size, 10) self.assertTrue(isinstance(tc_haz.intensity, sparse.csr.csr_matrix)) self.assertTrue(isinstance(tc_haz.fraction, sparse.csr.csr_matrix)) self.assertEqual(tc_haz.intensity.shape, (10, 296)) self.assertEqual(tc_haz.fraction.shape, (10, 296))
def test_windfield_models(self): """Test _tc_from_track function with different wind field models.""" intensity_idx = [0, 1, 2, 3, 80, 100, 120, 200, 220, 250, 260, 295] intensity_values = { "H08": [ 25.60778909, 26.90887264, 28.26624642, 25.54092386, 31.21941738, 36.16596567, 21.11399856, 28.01452136, 32.65076804, 31.33884098, 0, 40.27002104 ], "H10": [ 27.477252, 28.626236, 29.829914, 27.393616, 32.495186, 37.113324, 23.573216, 29.552127, 33.767067, 32.530964, 19.656737, 41.014578 ], # Holland 1980 is the only model that uses recorded wind speeds, while the above use # pressure values only. That's why the results for Holland 1980 are so different: "H1980": [ 20.291397, 22.678914, 25.428598, 20.44718, 31.868592, 41.920317, 0, 25.715983, 38.351686, 35.591153, 0, 46.873912 ], } tc_track = TCTracks() tc_track.read_processed_ibtracs_csv(TEST_TRACK) tc_track.equal_timestep() tc_track.data = tc_track.data[:1] for model in ["H08", "H10", "H1980"]: tc_haz = TropCyclone() tc_haz.set_from_tracks(tc_track, centroids=CENTR_TEST_BRB, model=model) np.testing.assert_array_almost_equal( tc_haz.intensity[0, intensity_idx].toarray()[0], intensity_values[model]) for idx, val in zip(intensity_idx, intensity_values[model]): if val == 0: self.assertEqual(tc_haz.intensity[0, idx], 0)
def test_negative_freq_error(self): """Test _apply_knutson_criterion with infeasible input.""" criterion = [{'basin': 'SP', 'category': [0, 1], 'year': 2100, 'change': 0.5, 'variable': 'frequency'} ] tc = TropCyclone() tc.frequency = np.ones(2) tc.basin = ['SP', 'SP'] tc.category = np.array([0, 1]) with self.assertRaises(ValueError): tc._apply_knutson_criterion(criterion, 3)
def test_two_criterion_track(self): """Test _apply_criterion function with two criteria""" criterion = [ {'basin': 'NA', 'category': [1, 2, 3, 4, 5], 'year': 2100, 'change': 1.045, 'variable': 'intensity'}, {'basin': 'WP', 'category': [1, 2, 3, 4, 5], 'year': 2100, 'change': 1.025, 'variable': 'intensity'}, {'basin': 'WP', 'category': [1, 2, 3, 4, 5], 'year': 2100, 'change': 1.025, 'variable': 'frequency'}, {'basin': 'NA', 'category': [0, 1, 2, 3, 4, 5], 'year': 2100, 'change': 0.7, 'variable': 'frequency'}, {'basin': 'NA', 'category': [1, 2, 3, 4, 5], 'year': 2100, 'change': 1, 'variable': 'frequency'}, {'basin': 'NA', 'category': [3, 4, 5], 'year': 2100, 'change': 1, 'variable': 'frequency'}, {'basin': 'NA', 'category': [4, 5], 'year': 2100, 'change': 2, 'variable': 'frequency'} ] scale = 0.75 tc = TropCyclone() tc.intensity = np.zeros((4, 10)) tc.intensity[0, :] = np.arange(10) tc.intensity[1, 5] = 10 tc.intensity[2, :] = np.arange(10, 20) tc.intensity[3, 3] = 3 tc.intensity = sparse.csr_matrix(tc.intensity) tc.frequency = np.ones(4) * 0.5 tc.basin = ['NA'] * 4 tc.basin[3] = 'WP' tc.category = np.array([2, 0, 4, 1]) tc.event_id = np.arange(4) tc_cc = tc._apply_knutson_criterion(criterion, scale) self.assertTrue(np.allclose(tc.intensity[1, :].toarray(), tc_cc.intensity[1, :].toarray())) self.assertFalse( np.allclose(tc.intensity[3, :].toarray(), tc_cc.intensity[3, :].toarray())) self.assertFalse( np.allclose(tc.intensity[0, :].toarray(), tc_cc.intensity[0, :].toarray())) self.assertFalse( np.allclose(tc.intensity[2, :].toarray(), tc_cc.intensity[2, :].toarray())) self.assertTrue( np.allclose(tc.intensity[0, :].toarray() * 1.03375, tc_cc.intensity[0, :].toarray())) self.assertTrue( np.allclose(tc.intensity[2, :].toarray() * 1.03375, tc_cc.intensity[2, :].toarray())) self.assertTrue( np.allclose(tc.intensity[3, :].toarray() * 1.01875, tc_cc.intensity[3, :].toarray())) res_frequency = np.ones(4) * 0.5 res_frequency[1] = 0.5 * (1 + (0.7 - 1) * scale) res_frequency[2] = 0.5 * (1 + (2 - 1) * scale) res_frequency[3] = 0.5 * (1 + (1.025 - 1) * scale) self.assertTrue(np.allclose(tc_cc.frequency, res_frequency))
def test_apply_criterion_track(self): """Test _apply_criterion function.""" criterion = [{'basin': 'NA', 'category': [1, 2, 3, 4, 5], 'year': 2100, 'change': 1.045, 'variable': 'intensity'} ] scale = 0.75 # artificially increase the size of the hazard by repeating (tiling) the data: ntiles = 8 tc = TropCyclone() tc.intensity = np.zeros((4, 10)) tc.intensity[0, :] = np.arange(10) tc.intensity[1, 5] = 10 tc.intensity[2, :] = np.arange(10, 20) tc.intensity[3, 3] = 3 tc.intensity = np.tile(tc.intensity, (ntiles, 1)) tc.intensity = sparse.csr_matrix(tc.intensity) tc.basin = ['NA'] * 4 tc.basin[3] = 'WP' tc.basin = ntiles * tc.basin tc.category = np.array(ntiles * [2, 0, 4, 1]) tc.event_id = np.arange(tc.intensity.shape[0]) tc_cc = tc._apply_knutson_criterion(criterion, scale) for i_tile in range(ntiles): offset = i_tile * 4 # no factor applied because of category 0 np.testing.assert_array_equal( tc.intensity[offset + 1, :].toarray(), tc_cc.intensity[offset + 1, :].toarray()) # no factor applied because of basin "WP" np.testing.assert_array_equal( tc.intensity[offset + 3, :].toarray(), tc_cc.intensity[offset + 3, :].toarray()) # factor is applied to the remaining events np.testing.assert_array_almost_equal( tc.intensity[offset + 0, :].toarray() * 1.03375, tc_cc.intensity[offset + 0, :].toarray()) np.testing.assert_array_almost_equal( tc.intensity[offset + 2, :].toarray() * 1.03375, tc_cc.intensity[offset + 2, :].toarray())
def test_apply_criterion_track(self): """Test _apply_criterion function.""" tc = TropCyclone() tc.intensity = np.zeros((4, 10)) tc.intensity[0, :] = np.arange(10) tc.intensity[1, 5] = 10 tc.intensity[2, :] = np.arange(10, 20) tc.intensity[3, 3] = 3 tc.intensity = sparse.csr_matrix(tc.intensity) tc.basin = ['NA'] * 4 tc.basin[3] = 'NO' tc.category = np.array([2, 0, 4, 1]) tc.event_id = np.arange(4) tc.frequency = np.ones(4) * 0.5 tc_cc = tc.set_climate_scenario_knu(ref_year=2050, rcp_scenario=45) self.assertTrue(np.allclose(tc.intensity[1, :].toarray(), tc_cc.intensity[1, :].toarray())) self.assertTrue(np.allclose(tc.intensity[3, :].toarray(), tc_cc.intensity[3, :].toarray())) self.assertFalse( np.allclose(tc.intensity[0, :].toarray(), tc_cc.intensity[0, :].toarray())) self.assertFalse( np.allclose(tc.intensity[2, :].toarray(), tc_cc.intensity[2, :].toarray())) self.assertTrue(np.allclose(tc.frequency, tc_cc.frequency)) self.assertEqual( tc_cc.tag.description, 'climate change scenario for year 2050 and RCP 45 from Knutson et al 2015.')
def test_two_criterion_track(self): """Test _apply_criterion function with two criteria""" criterion = list() tmp_chg = { 'criteria': { 'basin': ['NA'], 'category': [1, 2, 3, 4, 5] }, 'year': 2100, 'change': 1.045, 'variable': 'intensity', 'function': np.multiply } criterion.append(tmp_chg) tmp_chg = { 'criteria': { 'basin': ['WP'], 'category': [1, 2, 3, 4, 5] }, 'year': 2100, 'change': 1.025, 'variable': 'intensity', 'function': np.multiply } criterion.append(tmp_chg) tmp_chg = { 'criteria': { 'basin': ['WP'], 'category': [1, 2, 3, 4, 5] }, 'year': 2100, 'change': 1.025, 'variable': 'frequency', 'function': np.multiply } criterion.append(tmp_chg) scale = 0.75 tc = TropCyclone() tc.intensity = np.zeros((4, 10)) tc.intensity[0, :] = np.arange(10) tc.intensity[1, 5] = 10 tc.intensity[2, :] = np.arange(10, 20) tc.intensity[3, 3] = 3 tc.intensity = sparse.csr_matrix(tc.intensity) tc.frequency = np.ones(4) * 0.5 tc.basin = ['NA'] * 4 tc.basin[3] = 'WP' tc.category = np.array([2, 0, 4, 1]) tc.event_id = np.arange(4) tc_cc = tc._apply_criterion(criterion, scale) self.assertTrue( np.allclose(tc.intensity[1, :].toarray(), tc_cc.intensity[1, :].toarray())) self.assertFalse( np.allclose(tc.intensity[3, :].toarray(), tc_cc.intensity[3, :].toarray())) self.assertFalse( np.allclose(tc.intensity[0, :].toarray(), tc_cc.intensity[0, :].toarray())) self.assertFalse( np.allclose(tc.intensity[2, :].toarray(), tc_cc.intensity[2, :].toarray())) self.assertTrue( np.allclose(tc.intensity[0, :].toarray() * 1.03375, tc_cc.intensity[0, :].toarray())) self.assertTrue( np.allclose(tc.intensity[2, :].toarray() * 1.03375, tc_cc.intensity[2, :].toarray())) self.assertTrue( np.allclose(tc.intensity[3, :].toarray() * 1.01875, tc_cc.intensity[3, :].toarray())) res_frequency = np.ones(4) * 0.5 res_frequency[3] = 0.5 * 1.01875 self.assertTrue(np.allclose(tc_cc.frequency, res_frequency))
def test_read_and_tc_fail(self): """ Append Hazard and Tropical Cyclone. Fail because of missing category in hazard. """ tc_track = TCTracks() tc_track.read_processed_ibtracs_csv(TEST_TRACK_SHORT) tc_haz1 = TropCyclone() tc_haz1.read_mat(HAZ_TEST_MAT) tc_haz2 = TropCyclone() tc_haz2.set_from_tracks(tc_track, CENTR_TEST_BRB) tc_haz2.append(tc_haz1) self.assertEqual(tc_haz2.intensity.shape, (14451, 396)) with self.assertRaises(ValueError): tc_haz2.check()