215 """Test for making APDB schema."""
217 apdb = Apdb.from_config(config)
219 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaObject))
220 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaObjectLast))
221 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaSource))
222 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaForcedSource))
223 self.assertIsNotNone(apdb.tableDef(ApdbTables.metadata))
224 self.assertIsNotNone(apdb.tableDef(ApdbTables.SSObject))
225 self.assertIsNotNone(apdb.tableDef(ApdbTables.SSSource))
226 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaObject_To_Object_Match))
229 with tempfile.NamedTemporaryFile()
as tmpfile:
230 config.save(tmpfile.name)
231 apdb = Apdb.from_uri(tmpfile.name)
233 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaObject))
234 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaObjectLast))
235 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaSource))
236 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaForcedSource))
237 self.assertIsNotNone(apdb.tableDef(ApdbTables.metadata))
238 self.assertIsNotNone(apdb.tableDef(ApdbTables.SSObject))
239 self.assertIsNotNone(apdb.tableDef(ApdbTables.SSSource))
240 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaObject_To_Object_Match))
243 """Test for getting data from empty database.
245 All get() methods should return empty results, only useful for
246 checking that code is not broken.
250 apdb = Apdb.from_config(config)
255 res: pandas.DataFrame |
None
258 res = apdb.getDiaObjects(region)
262 res = apdb.getDiaSources(region,
None, visit_time)
265 res = apdb.getDiaSources(region, [], visit_time)
269 res = apdb.getDiaSources(region, [1, 2, 3], visit_time)
273 res = apdb.getDiaForcedSources(region, [], visit_time)
277 res = apdb.getDiaForcedSources(region, [1, 2, 3], visit_time)
281 res = apdb.containsVisitDetector(visit=1, detector=1, region=region, visit_time=visit_time)
282 self.assertFalse(res)
286 with self.assertRaises(NotImplementedError):
287 apdb.getDiaForcedSources(region,
None, visit_time)
289 res = apdb.getDiaForcedSources(region,
None, visit_time)
361 """Store and retrieve DiaObject which changes its position."""
364 apdb = Apdb.from_config(config)
367 lon_deg, lat_deg = 0.0, 0.0
368 lonlat1 = LonLat.fromDegrees(lon_deg - 1.0, lat_deg)
369 lonlat2 = LonLat.fromDegrees(lon_deg + 1.0, lat_deg)
374 self.assertNotEqual(pixelization.pixel(uv1), pixelization.pixel(uv2))
378 catalog1 = makeObjectCatalog(lonlat1, 1, visit_time1)
379 apdb.store(visit_time1, catalog1)
381 visit_time2 = visit_time1 + astropy.time.TimeDelta(120.0, format=
"sec")
382 catalog1 = makeObjectCatalog(lonlat2, 1, visit_time2)
383 apdb.store(visit_time2, catalog1)
386 region =
Circle(
UnitVector3d(LonLat.fromDegrees(lon_deg, lat_deg)), Angle.fromDegrees(1.1))
387 self.assertTrue(region.contains(uv1))
388 self.assertTrue(region.contains(uv2))
391 res = apdb.getDiaObjects(region)
395 """Store and retrieve DiaSources."""
397 apdb = Apdb.from_config(config)
403 objects = makeObjectCatalog(region, 100, visit_time)
404 oids = list(objects[
"diaObjectId"])
405 sources = makeSourceCatalog(objects, visit_time, use_mjd=self.
use_mjd)
408 apdb.store(visit_time, objects, sources)
411 res = apdb.getDiaSources(region,
None, visit_time)
415 res = apdb.getDiaSources(region, oids, visit_time)
419 res = apdb.getDiaSources(region, [], visit_time)
424 res = apdb.containsVisitDetector(visit=1, detector=1, region=region, visit_time=visit_time)
427 res = apdb.containsVisitDetector(visit=2, detector=42, region=region, visit_time=visit_time)
428 self.assertFalse(res)
431 """Store and retrieve DiaForcedSources."""
433 apdb = Apdb.from_config(config)
439 objects = makeObjectCatalog(region, 100, visit_time)
440 oids = list(objects[
"diaObjectId"])
441 catalog = makeForcedSourceCatalog(objects, visit_time, use_mjd=self.
use_mjd)
443 apdb.store(visit_time, objects, forced_sources=catalog)
446 res = apdb.getDiaForcedSources(region, oids, visit_time)
447 self.
assert_catalog(res, len(catalog), ApdbTables.DiaForcedSource)
450 res = apdb.getDiaForcedSources(region, [], visit_time)
454 res = apdb.containsVisitDetector(visit=1, detector=1, region=region, visit_time=visit_time)
457 res = apdb.containsVisitDetector(visit=2, detector=42, region=region, visit_time=visit_time)
458 self.assertFalse(res)
461 """Check that timestamp return type is as expected."""
463 apdb = Apdb.from_config(config)
470 time_before = makeTimestampNow(self.
use_mjd, -1)
471 objects = makeObjectCatalog(region, 100, visit_time)
472 oids = list(objects[
"diaObjectId"])
473 catalog = makeForcedSourceCatalog(objects, visit_time, use_mjd=self.
use_mjd)
474 time_after = makeTimestampNow(self.
use_mjd)
476 apdb.store(visit_time, objects, forced_sources=catalog)
479 res = apdb.getDiaForcedSources(region, oids, visit_time)
480 assert res
is not None
481 self.
assert_catalog(res, len(catalog), ApdbTables.DiaForcedSource)
483 time_processed_column =
"timeProcessedMjdTai" if self.
use_mjd else "time_processed"
484 self.assertIn(time_processed_column, res.dtypes)
485 dtype = res.dtypes[time_processed_column]
486 timestamp_type_name =
"float64" if self.
use_mjd else "datetime64[ns]"
487 self.assertEqual(dtype.name, timestamp_type_name)
489 self.assertTrue(all(time_before <= dt <= time_after
for dt
in res[time_processed_column]))
492 """Store and retrieve replica chunks."""
495 apdb = Apdb.from_config(config)
496 apdb_replica = ApdbReplica.from_config(config)
502 objects1 = makeObjectCatalog(region1, nobj, visit_time)
503 objects2 = makeObjectCatalog(region2, nobj, visit_time, start_id=nobj * 2)
508 (astropy.time.Time(
"2021-01-01T00:01:00", format=
"isot", scale=
"tai"), objects1),
509 (astropy.time.Time(
"2021-01-01T00:02:00", format=
"isot", scale=
"tai"), objects2),
510 (astropy.time.Time(
"2021-01-01T00:11:00", format=
"isot", scale=
"tai"), objects1),
511 (astropy.time.Time(
"2021-01-01T00:12:00", format=
"isot", scale=
"tai"), objects2),
512 (astropy.time.Time(
"2021-01-01T00:45:00", format=
"isot", scale=
"tai"), objects1),
513 (astropy.time.Time(
"2021-01-01T00:46:00", format=
"isot", scale=
"tai"), objects2),
514 (astropy.time.Time(
"2021-03-01T00:01:00", format=
"isot", scale=
"tai"), objects1),
515 (astropy.time.Time(
"2021-03-01T00:02:00", format=
"isot", scale=
"tai"), objects2),
519 for visit_time, objects
in visits:
520 sources = makeSourceCatalog(objects, visit_time, start_id=start_id, use_mjd=self.
use_mjd)
521 fsources = makeForcedSourceCatalog(objects, visit_time, visit=start_id, use_mjd=self.
use_mjd)
522 apdb.store(visit_time, objects, sources, fsources)
525 replica_chunks = apdb_replica.getReplicaChunks()
527 self.assertIsNone(replica_chunks)
529 with self.assertRaisesRegex(ValueError,
"APDB is not configured for replication"):
530 apdb_replica.getTableDataChunks(ApdbTables.DiaObject, [])
533 assert replica_chunks
is not None
534 self.assertEqual(len(replica_chunks), 4)
536 with self.assertRaisesRegex(ValueError,
"does not support replica chunks"):
537 apdb_replica.getTableDataChunks(ApdbTables.SSObject, [])
539 def _check_chunks(replica_chunks: list[ReplicaChunk], n_records: int |
None =
None) ->
None:
540 if n_records
is None:
541 n_records = len(replica_chunks) * nobj
542 res = apdb_replica.getTableDataChunks(
543 ApdbTables.DiaObject, (chunk.id
for chunk
in replica_chunks)
546 validityStartColumn =
"validityStartMjdTai" if self.
use_mjd else "validityStart"
547 validityStartType = (
548 felis.datamodel.DataType.double
if self.
use_mjd else felis.datamodel.DataType.timestamp
553 "apdb_replica_chunk": felis.datamodel.DataType.long,
554 "diaObjectId": felis.datamodel.DataType.long,
555 validityStartColumn: validityStartType,
556 "ra": felis.datamodel.DataType.double,
557 "dec": felis.datamodel.DataType.double,
558 "parallax": felis.datamodel.DataType.float,
559 "nDiaSources": felis.datamodel.DataType.int,
563 res = apdb_replica.getTableDataChunks(
564 ApdbTables.DiaSource, (chunk.id
for chunk
in replica_chunks)
570 "apdb_replica_chunk": felis.datamodel.DataType.long,
571 "diaSourceId": felis.datamodel.DataType.long,
572 "visit": felis.datamodel.DataType.long,
573 "detector": felis.datamodel.DataType.short,
577 res = apdb_replica.getTableDataChunks(
578 ApdbTables.DiaForcedSource, (chunk.id
for chunk
in replica_chunks)
584 "apdb_replica_chunk": felis.datamodel.DataType.long,
585 "diaObjectId": felis.datamodel.DataType.long,
586 "visit": felis.datamodel.DataType.long,
587 "detector": felis.datamodel.DataType.short,
592 _check_chunks(replica_chunks, 800)
593 _check_chunks(replica_chunks[1:], 600)
594 _check_chunks(replica_chunks[1:-1], 400)
595 _check_chunks(replica_chunks[2:3], 200)
599 deleted_chunks = replica_chunks[:1]
600 apdb_replica.deleteReplicaChunks(chunk.id
for chunk
in deleted_chunks)
603 _check_chunks(deleted_chunks, 0)
605 replica_chunks = apdb_replica.getReplicaChunks()
606 assert replica_chunks
is not None
607 self.assertEqual(len(replica_chunks), 3)
609 _check_chunks(replica_chunks, 600)
612 """Store and retrieve SSObjects."""
615 apdb = Apdb.from_config(config)
618 catalog = makeSSObjectCatalog(100, flags=1)
621 apdb.storeSSObjects(catalog)
624 res = apdb.getSSObjects()
628 catalog = makeSSObjectCatalog(100, 51, flags=2)
629 apdb.storeSSObjects(catalog)
630 res = apdb.getSSObjects()
632 self.assertEqual(len(res[res[
"flags"] == 1]), 50)
633 self.assertEqual(len(res[res[
"flags"] == 2]), 100)
636 """Reassign DiaObjects."""
639 apdb = Apdb.from_config(config)
643 objects = makeObjectCatalog(region, 100, visit_time)
644 oids = list(objects[
"diaObjectId"])
645 sources = makeSourceCatalog(objects, visit_time, use_mjd=self.
use_mjd)
646 apdb.store(visit_time, objects, sources)
648 catalog = makeSSObjectCatalog(100)
649 apdb.storeSSObjects(catalog)
652 res = apdb.getDiaSources(region, oids, visit_time)
655 apdb.reassignDiaSources({1: 1, 2: 2, 5: 5})
656 res = apdb.getDiaSources(region, oids, visit_time)
659 with self.assertRaisesRegex(ValueError,
r"do not exist.*\D1000"):
660 apdb.reassignDiaSources(
669 """Test _storeUpdateRecord() method."""
671 apdb = Apdb.from_config(config)
674 update_time_ns1 = 2_000_000_000_000_000_000
675 update_time_ns2 = 2_000_000_001_000_000_000
678 update_time_ns=update_time_ns1,
683 ssObjectReassocTimeMjdTai=60000.0,
688 update_time_ns=update_time_ns1,
692 timeWithdrawnMjdTai=61000.0,
697 update_time_ns=update_time_ns1,
702 ssObjectReassocTimeMjdTai=60000.0,
707 update_time_ns=update_time_ns2,
711 timeWithdrawnMjdTai=61000.0,
717 update_time = astropy.time.Time(
"2021-01-01T00:00:00", format=
"isot", scale=
"tai")
718 chunk = ReplicaChunk.make_replica_chunk(update_time, 600)
721 with self.assertRaises(TypeError):
726 apdb_replica = ApdbReplica.from_config(config)
727 records_returned = apdb_replica.getUpdateRecordChunks([chunk.id])
730 self.assertEqual(records_returned, records)
738 """Test for time filtering of DiaSources."""
740 apdb = Apdb.from_config(config)
744 src_time1 = astropy.time.Time(
"2021-01-01T00:00:00", format=
"isot", scale=
"tai")
745 src_time2 = astropy.time.Time(
"2021-01-01T00:00:02", format=
"isot", scale=
"tai")
746 visit_time0 = astropy.time.Time(
"2021-12-26T23:59:59", format=
"isot", scale=
"tai")
747 visit_time1 = astropy.time.Time(
"2021-12-27T00:00:01", format=
"isot", scale=
"tai")
748 visit_time2 = astropy.time.Time(
"2021-12-27T00:00:03", format=
"isot", scale=
"tai")
749 one_sec = astropy.time.TimeDelta(1.0, format=
"sec")
751 objects = makeObjectCatalog(region, 100, visit_time0)
752 oids = list(objects[
"diaObjectId"])
753 sources = makeSourceCatalog(objects, src_time1, 0, use_mjd=self.
use_mjd)
754 apdb.store(src_time1, objects, sources)
756 sources = makeSourceCatalog(objects, src_time2, 100, use_mjd=self.
use_mjd)
757 apdb.store(src_time2, objects, sources)
760 res = apdb.getDiaSources(region, oids, src_time2)
764 res = apdb.getDiaSources(region, oids, visit_time0)
768 res = apdb.getDiaSources(region, oids, visit_time1)
772 res = apdb.getDiaSources(region, oids, visit_time2)
777 res = apdb.getDiaSources(region, oids, src_time1 - one_sec, src_time1 - one_sec)
780 res = apdb.getDiaSources(region, oids, src_time1 - one_sec, src_time2 - one_sec)
783 res = apdb.getDiaSources(region, oids, src_time1 - one_sec, src_time2 + one_sec)
787 """Test for time filtering of DiaForcedSources."""
789 apdb = Apdb.from_config(config)
792 src_time1 = astropy.time.Time(
"2021-01-01T00:00:00", format=
"isot", scale=
"tai")
793 src_time2 = astropy.time.Time(
"2021-01-01T00:00:02", format=
"isot", scale=
"tai")
794 visit_time0 = astropy.time.Time(
"2021-12-26T23:59:59", format=
"isot", scale=
"tai")
795 visit_time1 = astropy.time.Time(
"2021-12-27T00:00:01", format=
"isot", scale=
"tai")
796 visit_time2 = astropy.time.Time(
"2021-12-27T00:00:03", format=
"isot", scale=
"tai")
797 one_sec = astropy.time.TimeDelta(1.0, format=
"sec")
799 objects = makeObjectCatalog(region, 100, visit_time0)
800 oids = list(objects[
"diaObjectId"])
801 sources = makeForcedSourceCatalog(objects, src_time1, 1, use_mjd=self.
use_mjd)
802 apdb.store(src_time1, objects, forced_sources=sources)
804 sources = makeForcedSourceCatalog(objects, src_time2, 2, use_mjd=self.
use_mjd)
805 apdb.store(src_time2, objects, forced_sources=sources)
808 res = apdb.getDiaForcedSources(region, oids, src_time2)
812 res = apdb.getDiaForcedSources(region, oids, visit_time0)
816 res = apdb.getDiaForcedSources(region, oids, visit_time1)
820 res = apdb.getDiaForcedSources(region, oids, visit_time2)
825 res = apdb.getDiaForcedSources(region, oids, src_time1 - one_sec, src_time1 - one_sec)
828 res = apdb.getDiaForcedSources(region, oids, src_time1 - one_sec, src_time2 - one_sec)
831 res = apdb.getDiaForcedSources(region, oids, src_time1 - one_sec, src_time2 + one_sec)
835 """Simple test for writing/reading metadata table"""
837 apdb = Apdb.from_config(config)
838 metadata = apdb.metadata
842 self.assertFalse(metadata.empty())
843 self.assertEqual(len(list(metadata.items())), self.
meta_row_count)
845 metadata.set(
"meta",
"data")
846 metadata.set(
"data",
"meta")
848 self.assertFalse(metadata.empty())
849 self.assertTrue(set(metadata.items()) >= {(
"meta",
"data"), (
"data",
"meta")})
851 with self.assertRaisesRegex(KeyError,
"Metadata key 'meta' already exists"):
852 metadata.set(
"meta",
"data1")
854 metadata.set(
"meta",
"data2", force=
True)
855 self.assertTrue(set(metadata.items()) >= {(
"meta",
"data2"), (
"data",
"meta")})
857 self.assertTrue(metadata.delete(
"meta"))
858 self.assertIsNone(metadata.get(
"meta"))
859 self.assertFalse(metadata.delete(
"meta"))
861 self.assertEqual(metadata.get(
"data"),
"meta")
862 self.assertEqual(metadata.get(
"meta",
"meta"),
"meta")