214 """Test for making APDB schema."""
216 apdb = Apdb.from_config(config)
218 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaObject))
219 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaObjectLast))
220 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaSource))
221 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaForcedSource))
222 self.assertIsNotNone(apdb.tableDef(ApdbTables.metadata))
223 self.assertIsNotNone(apdb.tableDef(ApdbTables.SSObject))
224 self.assertIsNotNone(apdb.tableDef(ApdbTables.SSSource))
225 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaObject_To_Object_Match))
228 with tempfile.NamedTemporaryFile()
as tmpfile:
229 config.save(tmpfile.name)
230 apdb = Apdb.from_uri(tmpfile.name)
232 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaObject))
233 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaObjectLast))
234 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaSource))
235 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaForcedSource))
236 self.assertIsNotNone(apdb.tableDef(ApdbTables.metadata))
237 self.assertIsNotNone(apdb.tableDef(ApdbTables.SSObject))
238 self.assertIsNotNone(apdb.tableDef(ApdbTables.SSSource))
239 self.assertIsNotNone(apdb.tableDef(ApdbTables.DiaObject_To_Object_Match))
242 """Test for getting data from empty database.
244 All get() methods should return empty results, only useful for
245 checking that code is not broken.
249 apdb = Apdb.from_config(config)
254 res: pandas.DataFrame |
None
257 res = apdb.getDiaObjects(region)
261 res = apdb.getDiaSources(region,
None, visit_time)
264 res = apdb.getDiaSources(region, [], visit_time)
268 res = apdb.getDiaSources(region, [1, 2, 3], visit_time)
272 res = apdb.getDiaForcedSources(region, [], visit_time)
276 res = apdb.getDiaForcedSources(region, [1, 2, 3], visit_time)
280 res = apdb.containsVisitDetector(visit=1, detector=1, region=region, visit_time=visit_time)
281 self.assertFalse(res)
285 with self.assertRaises(NotImplementedError):
286 apdb.getDiaForcedSources(region,
None, visit_time)
288 res = apdb.getDiaForcedSources(region,
None, visit_time)
360 """Store and retrieve DiaObject which changes its position."""
363 apdb = Apdb.from_config(config)
366 lon_deg, lat_deg = 0.0, 0.0
367 lonlat1 = LonLat.fromDegrees(lon_deg - 1.0, lat_deg)
368 lonlat2 = LonLat.fromDegrees(lon_deg + 1.0, lat_deg)
373 self.assertNotEqual(pixelization.pixel(uv1), pixelization.pixel(uv2))
377 catalog1 = makeObjectCatalog(lonlat1, 1, visit_time1)
378 apdb.store(visit_time1, catalog1)
380 visit_time2 = visit_time1 + astropy.time.TimeDelta(120.0, format=
"sec")
381 catalog1 = makeObjectCatalog(lonlat2, 1, visit_time2)
382 apdb.store(visit_time2, catalog1)
385 region =
Circle(
UnitVector3d(LonLat.fromDegrees(lon_deg, lat_deg)), Angle.fromDegrees(1.1))
386 self.assertTrue(region.contains(uv1))
387 self.assertTrue(region.contains(uv2))
390 res = apdb.getDiaObjects(region)
394 """Store and retrieve DiaSources."""
396 apdb = Apdb.from_config(config)
402 objects = makeObjectCatalog(region, 100, visit_time)
403 oids = list(objects[
"diaObjectId"])
404 sources = makeSourceCatalog(objects, visit_time, use_mjd=self.
use_mjd)
407 apdb.store(visit_time, objects, sources)
410 res = apdb.getDiaSources(region,
None, visit_time)
414 res = apdb.getDiaSources(region, oids, visit_time)
418 res = apdb.getDiaSources(region, [], visit_time)
423 res = apdb.containsVisitDetector(visit=1, detector=1, region=region, visit_time=visit_time)
426 res = apdb.containsVisitDetector(visit=2, detector=42, region=region, visit_time=visit_time)
427 self.assertFalse(res)
430 """Store and retrieve DiaForcedSources."""
432 apdb = Apdb.from_config(config)
438 objects = makeObjectCatalog(region, 100, visit_time)
439 oids = list(objects[
"diaObjectId"])
440 catalog = makeForcedSourceCatalog(objects, visit_time, use_mjd=self.
use_mjd)
442 apdb.store(visit_time, objects, forced_sources=catalog)
445 res = apdb.getDiaForcedSources(region, oids, visit_time)
446 self.
assert_catalog(res, len(catalog), ApdbTables.DiaForcedSource)
449 res = apdb.getDiaForcedSources(region, [], visit_time)
453 res = apdb.containsVisitDetector(visit=1, detector=1, region=region, visit_time=visit_time)
456 res = apdb.containsVisitDetector(visit=2, detector=42, region=region, visit_time=visit_time)
457 self.assertFalse(res)
460 """Check that timestamp return type is as expected."""
462 apdb = Apdb.from_config(config)
469 time_before = makeTimestampNow(self.
use_mjd, -1)
470 objects = makeObjectCatalog(region, 100, visit_time)
471 oids = list(objects[
"diaObjectId"])
472 catalog = makeForcedSourceCatalog(objects, visit_time, use_mjd=self.
use_mjd)
473 time_after = makeTimestampNow(self.
use_mjd)
475 apdb.store(visit_time, objects, forced_sources=catalog)
478 res = apdb.getDiaForcedSources(region, oids, visit_time)
479 assert res
is not None
480 self.
assert_catalog(res, len(catalog), ApdbTables.DiaForcedSource)
482 time_processed_column =
"timeProcessedMjdTai" if self.
use_mjd else "time_processed"
483 self.assertIn(time_processed_column, res.dtypes)
484 dtype = res.dtypes[time_processed_column]
485 timestamp_type_name =
"float64" if self.
use_mjd else "datetime64[ns]"
486 self.assertEqual(dtype.name, timestamp_type_name)
488 self.assertTrue(all(time_before <= dt <= time_after
for dt
in res[time_processed_column]))
491 """Store and retrieve replica chunks."""
494 apdb = Apdb.from_config(config)
495 apdb_replica = ApdbReplica.from_config(config)
501 objects1 = makeObjectCatalog(region1, nobj, visit_time)
502 objects2 = makeObjectCatalog(region2, nobj, visit_time, start_id=nobj * 2)
507 (astropy.time.Time(
"2021-01-01T00:01:00", format=
"isot", scale=
"tai"), objects1),
508 (astropy.time.Time(
"2021-01-01T00:02:00", format=
"isot", scale=
"tai"), objects2),
509 (astropy.time.Time(
"2021-01-01T00:11:00", format=
"isot", scale=
"tai"), objects1),
510 (astropy.time.Time(
"2021-01-01T00:12:00", format=
"isot", scale=
"tai"), objects2),
511 (astropy.time.Time(
"2021-01-01T00:45:00", format=
"isot", scale=
"tai"), objects1),
512 (astropy.time.Time(
"2021-01-01T00:46:00", format=
"isot", scale=
"tai"), objects2),
513 (astropy.time.Time(
"2021-03-01T00:01:00", format=
"isot", scale=
"tai"), objects1),
514 (astropy.time.Time(
"2021-03-01T00:02:00", format=
"isot", scale=
"tai"), objects2),
518 for visit_time, objects
in visits:
519 sources = makeSourceCatalog(objects, visit_time, start_id=start_id, use_mjd=self.
use_mjd)
520 fsources = makeForcedSourceCatalog(objects, visit_time, visit=start_id, use_mjd=self.
use_mjd)
521 apdb.store(visit_time, objects, sources, fsources)
524 replica_chunks = apdb_replica.getReplicaChunks()
526 self.assertIsNone(replica_chunks)
528 with self.assertRaisesRegex(ValueError,
"APDB is not configured for replication"):
529 apdb_replica.getTableDataChunks(ApdbTables.DiaObject, [])
532 assert replica_chunks
is not None
533 self.assertEqual(len(replica_chunks), 4)
535 with self.assertRaisesRegex(ValueError,
"does not support replica chunks"):
536 apdb_replica.getTableDataChunks(ApdbTables.SSObject, [])
538 def _check_chunks(replica_chunks: list[ReplicaChunk], n_records: int |
None =
None) ->
None:
539 if n_records
is None:
540 n_records = len(replica_chunks) * nobj
541 res = apdb_replica.getTableDataChunks(
542 ApdbTables.DiaObject, (chunk.id
for chunk
in replica_chunks)
545 validityStartColumn =
"validityStartMjdTai" if self.
use_mjd else "validityStart"
546 validityStartType = (
547 felis.datamodel.DataType.double
if self.
use_mjd else felis.datamodel.DataType.timestamp
552 "apdb_replica_chunk": felis.datamodel.DataType.long,
553 "diaObjectId": felis.datamodel.DataType.long,
554 validityStartColumn: validityStartType,
555 "ra": felis.datamodel.DataType.double,
556 "dec": felis.datamodel.DataType.double,
557 "parallax": felis.datamodel.DataType.float,
558 "nDiaSources": felis.datamodel.DataType.int,
562 res = apdb_replica.getTableDataChunks(
563 ApdbTables.DiaSource, (chunk.id
for chunk
in replica_chunks)
569 "apdb_replica_chunk": felis.datamodel.DataType.long,
570 "diaSourceId": felis.datamodel.DataType.long,
571 "visit": felis.datamodel.DataType.long,
572 "detector": felis.datamodel.DataType.short,
576 res = apdb_replica.getTableDataChunks(
577 ApdbTables.DiaForcedSource, (chunk.id
for chunk
in replica_chunks)
583 "apdb_replica_chunk": felis.datamodel.DataType.long,
584 "diaObjectId": felis.datamodel.DataType.long,
585 "visit": felis.datamodel.DataType.long,
586 "detector": felis.datamodel.DataType.short,
591 _check_chunks(replica_chunks, 800)
592 _check_chunks(replica_chunks[1:], 600)
593 _check_chunks(replica_chunks[1:-1], 400)
594 _check_chunks(replica_chunks[2:3], 200)
598 deleted_chunks = replica_chunks[:1]
599 apdb_replica.deleteReplicaChunks(chunk.id
for chunk
in deleted_chunks)
602 _check_chunks(deleted_chunks, 0)
604 replica_chunks = apdb_replica.getReplicaChunks()
605 assert replica_chunks
is not None
606 self.assertEqual(len(replica_chunks), 3)
608 _check_chunks(replica_chunks, 600)
611 """Reassign DiaObjects."""
614 apdb = Apdb.from_config(config)
618 objects = makeObjectCatalog(region, 100, visit_time)
619 oids = list(objects[
"diaObjectId"])
620 sources = makeSourceCatalog(objects, visit_time, use_mjd=self.
use_mjd)
621 apdb.store(visit_time, objects, sources)
624 res = apdb.getDiaSources(region, oids, visit_time)
627 apdb.reassignDiaSources({1: 1, 2: 2, 5: 5})
628 res = apdb.getDiaSources(region, oids, visit_time)
631 with self.assertRaisesRegex(ValueError,
r"do not exist.*\D1000"):
632 apdb.reassignDiaSources(
641 """Test _storeUpdateRecord() method."""
643 apdb = Apdb.from_config(config)
646 update_time_ns1 = 2_000_000_000_000_000_000
647 update_time_ns2 = 2_000_000_001_000_000_000
650 update_time_ns=update_time_ns1,
655 ssObjectReassocTimeMjdTai=60000.0,
660 update_time_ns=update_time_ns1,
664 timeWithdrawnMjdTai=61000.0,
669 update_time_ns=update_time_ns1,
674 ssObjectReassocTimeMjdTai=60000.0,
679 update_time_ns=update_time_ns2,
683 timeWithdrawnMjdTai=61000.0,
689 update_time = astropy.time.Time(
"2021-01-01T00:00:00", format=
"isot", scale=
"tai")
690 chunk = ReplicaChunk.make_replica_chunk(update_time, 600)
693 with self.assertRaises(TypeError):
698 apdb_replica = ApdbReplica.from_config(config)
699 records_returned = apdb_replica.getUpdateRecordChunks([chunk.id])
702 self.assertEqual(records_returned, records)
710 """Test for time filtering of DiaSources."""
712 apdb = Apdb.from_config(config)
716 src_time1 = astropy.time.Time(
"2021-01-01T00:00:00", format=
"isot", scale=
"tai")
717 src_time2 = astropy.time.Time(
"2021-01-01T00:00:02", format=
"isot", scale=
"tai")
718 visit_time0 = astropy.time.Time(
"2021-12-26T23:59:59", format=
"isot", scale=
"tai")
719 visit_time1 = astropy.time.Time(
"2021-12-27T00:00:01", format=
"isot", scale=
"tai")
720 visit_time2 = astropy.time.Time(
"2021-12-27T00:00:03", format=
"isot", scale=
"tai")
721 one_sec = astropy.time.TimeDelta(1.0, format=
"sec")
723 objects = makeObjectCatalog(region, 100, visit_time0)
724 oids = list(objects[
"diaObjectId"])
725 sources = makeSourceCatalog(objects, src_time1, 0, use_mjd=self.
use_mjd)
726 apdb.store(src_time1, objects, sources)
728 sources = makeSourceCatalog(objects, src_time2, 100, use_mjd=self.
use_mjd)
729 apdb.store(src_time2, objects, sources)
732 res = apdb.getDiaSources(region, oids, src_time2)
736 res = apdb.getDiaSources(region, oids, visit_time0)
740 res = apdb.getDiaSources(region, oids, visit_time1)
744 res = apdb.getDiaSources(region, oids, visit_time2)
749 res = apdb.getDiaSources(region, oids, src_time1 - one_sec, src_time1 - one_sec)
752 res = apdb.getDiaSources(region, oids, src_time1 - one_sec, src_time2 - one_sec)
755 res = apdb.getDiaSources(region, oids, src_time1 - one_sec, src_time2 + one_sec)
759 """Test for time filtering of DiaForcedSources."""
761 apdb = Apdb.from_config(config)
764 src_time1 = astropy.time.Time(
"2021-01-01T00:00:00", format=
"isot", scale=
"tai")
765 src_time2 = astropy.time.Time(
"2021-01-01T00:00:02", format=
"isot", scale=
"tai")
766 visit_time0 = astropy.time.Time(
"2021-12-26T23:59:59", format=
"isot", scale=
"tai")
767 visit_time1 = astropy.time.Time(
"2021-12-27T00:00:01", format=
"isot", scale=
"tai")
768 visit_time2 = astropy.time.Time(
"2021-12-27T00:00:03", format=
"isot", scale=
"tai")
769 one_sec = astropy.time.TimeDelta(1.0, format=
"sec")
771 objects = makeObjectCatalog(region, 100, visit_time0)
772 oids = list(objects[
"diaObjectId"])
773 sources = makeForcedSourceCatalog(objects, src_time1, 1, use_mjd=self.
use_mjd)
774 apdb.store(src_time1, objects, forced_sources=sources)
776 sources = makeForcedSourceCatalog(objects, src_time2, 2, use_mjd=self.
use_mjd)
777 apdb.store(src_time2, objects, forced_sources=sources)
780 res = apdb.getDiaForcedSources(region, oids, src_time2)
784 res = apdb.getDiaForcedSources(region, oids, visit_time0)
788 res = apdb.getDiaForcedSources(region, oids, visit_time1)
792 res = apdb.getDiaForcedSources(region, oids, visit_time2)
797 res = apdb.getDiaForcedSources(region, oids, src_time1 - one_sec, src_time1 - one_sec)
800 res = apdb.getDiaForcedSources(region, oids, src_time1 - one_sec, src_time2 - one_sec)
803 res = apdb.getDiaForcedSources(region, oids, src_time1 - one_sec, src_time2 + one_sec)
807 """Simple test for writing/reading metadata table"""
809 apdb = Apdb.from_config(config)
810 metadata = apdb.metadata
814 self.assertFalse(metadata.empty())
815 self.assertEqual(len(list(metadata.items())), self.
meta_row_count)
817 metadata.set(
"meta",
"data")
818 metadata.set(
"data",
"meta")
820 self.assertFalse(metadata.empty())
821 self.assertTrue(set(metadata.items()) >= {(
"meta",
"data"), (
"data",
"meta")})
823 with self.assertRaisesRegex(KeyError,
"Metadata key 'meta' already exists"):
824 metadata.set(
"meta",
"data1")
826 metadata.set(
"meta",
"data2", force=
True)
827 self.assertTrue(set(metadata.items()) >= {(
"meta",
"data2"), (
"data",
"meta")})
829 self.assertTrue(metadata.delete(
"meta"))
830 self.assertIsNone(metadata.get(
"meta"))
831 self.assertFalse(metadata.delete(
"meta"))
833 self.assertEqual(metadata.get(
"data"),
"meta")
834 self.assertEqual(metadata.get(
"meta",
"meta"),
"meta")