Exemple #1
0
 def test_center_and_dimensions(self):
     e = Ellipse(UnitVector3d.X(), UnitVector3d.Y(), Angle(2 * math.pi / 3))
     self.assertAlmostEqual(e.getF1().dot(UnitVector3d.X()), 1.0)
     self.assertAlmostEqual(e.getF2().dot(UnitVector3d.Y()), 1.0)
     self.assertAlmostEqual(e.getAlpha(), Angle(2 * math.pi / 3))
     f = Ellipse(UnitVector3d.X(), Angle(math.pi / 3), Angle(math.pi / 6),
                 Angle(0))
     self.assertEqual(f.getCenter(), UnitVector3d.X())
Exemple #2
0
 def test_relationships(self):
     e = Ellipse(UnitVector3d.X(), Angle(math.pi / 3), Angle(math.pi / 6),
                 Angle(0))
     self.assertTrue(e.contains(UnitVector3d.X()))
     self.assertTrue(UnitVector3d.X() in e)
     c = Circle(UnitVector3d.X(), Angle(math.pi / 2))
     self.assertEqual(c.relate(e), CONTAINS)
     self.assertEqual(e.relate(c), WITHIN)
 def testComparisonOperators(self):
     a1 = Angle(1)
     a2 = Angle(2)
     self.assertNotEqual(a1, a2)
     self.assertLess(a1, a2)
     self.assertLessEqual(a1, a2)
     self.assertGreater(a2, a1)
     self.assertGreaterEqual(a2, a1)
 def testArithmeticOperators(self):
     a = Angle(1)
     b = -a
     self.assertEqual(a + b, Angle(0))
     self.assertEqual(a - b, 2.0 * a)
     self.assertEqual(a - b, a * 2.0)
     self.assertEqual(a / 1.0, a)
     self.assertEqual(a / a, 1.0)
     a += a
     a *= 2
     a -= b
     a /= 5
     self.assertEqual(a.asRadians(), 1)
 def test_construction(self):
     self.assertTrue(Circle.empty().isEmpty())
     self.assertTrue(Circle().isEmpty())
     self.assertTrue(Circle.full().isFull())
     c = Circle(UnitVector3d.X())
     self.assertEqual(c.getOpeningAngle(), Angle(0))
     self.assertEqual(c.getSquaredChordLength(), 0)
     c = Circle(UnitVector3d.Z(), 2.0)
     self.assertTrue(c.contains(UnitVector3d.Z()))
     c = Circle(UnitVector3d.Z(), Angle(math.pi))
     self.assertTrue(c.isFull())
     d = c.clone()
     self.assertEqual(c, d)
     self.assertNotEqual(id(c), id(d))
     e = Circle(d)
     self.assertEqual(d, e)
Exemple #6
0
 def test_construction(self):
     self.assertTrue(Ellipse.empty().isEmpty())
     self.assertTrue(Ellipse().isEmpty())
     self.assertTrue(Ellipse.full().isFull())
     e = Ellipse(Circle(UnitVector3d.X(), Angle(math.pi / 2)))
     f = Ellipse(UnitVector3d.X(), Angle(math.pi / 2))
     self.assertEqual(e, f)
     self.assertEqual(e.getAlpha(), e.getBeta())
     self.assertTrue(e.isCircle())
     self.assertTrue(e.isGreatCircle())
     g = Ellipse(e)
     h = e.clone()
     self.assertEqual(e, g)
     self.assertEqual(g, h)
     self.assertNotEqual(id(e), id(g))
     self.assertNotEqual(id(g), id(h))
 def test_dilation_and_erosion(self):
     a = Angle(math.pi / 2)
     c = Circle(UnitVector3d.X())
     d = c.dilatedBy(a).erodedBy(a)
     c.dilateBy(a).erodeBy(a)
     self.assertEqual(c, d)
     self.assertEqual(c, Circle(UnitVector3d.X()))
Exemple #8
0
def _makePixelRanges():
    """Generate pixel ID ranges for some envelope region"""
    pointing_v = UnitVector3d(1., 1., -1.)
    fov = 0.05  # radians
    region = Circle(pointing_v, Angle(fov / 2))
    pixelator = HtmPixelization(HTM_LEVEL)
    indices = pixelator.envelope(region, 128)
    return indices.ranges()
 def testConstruction(self):
     a1 = Angle(1.0)
     a2 = Angle.fromRadians(1.0)
     a3 = Angle.fromDegrees(57.29577951308232)
     self.assertEqual(a1, a2)
     self.assertEqual(a1.asRadians(), 1.0)
     self.assertEqual(a1, a3)
     self.assertEqual(a1.asDegrees(), 57.29577951308232)
Exemple #10
0
 def testArithmeticOperators(self):
     a = NormalizedAngle(1)
     b = -a
     self.assertEqual(a + b, Angle(0))
     self.assertEqual(a - b, 2.0 * a)
     self.assertEqual(a - b, a * 2.0)
     self.assertEqual(a / 1.0, a)
     self.assertEqual(a / a, 1.0)
 def test_string(self):
     c = Circle(UnitVector3d.Z(), Angle(1.0))
     self.assertEqual(str(c), 'Circle([0.0, 0.0, 1.0], 1.0)')
     self.assertEqual(repr(c),
                      'Circle(UnitVector3d(0.0, 0.0, 1.0), Angle(1.0))')
     self.assertEqual(
         c,
         eval(repr(c),
              dict(Angle=Angle, Circle=Circle, UnitVector3d=UnitVector3d)))
Exemple #12
0
 def test_construction(self):
     b = Box(Box.allLongitudes(), Box.allLatitudes())
     self.assertTrue(b.isFull())
     b = Box.fromDegrees(-90, -45, 90, 45)
     self.assertEqual(b, Box(b.getLon(), b.getLat()))
     a = Box.fromRadians(-0.5 * math.pi, -0.25 * math.pi, 0.5 * math.pi,
                         0.25 * math.pi)
     b = Box(LonLat.fromRadians(-0.5 * math.pi, -0.25 * math.pi),
             LonLat.fromRadians(0.5 * math.pi, 0.25 * math.pi))
     c = Box(LonLat.fromRadians(0, 0), Angle(0.5 * math.pi),
             Angle(0.25 * math.pi))
     d = c.clone()
     self.assertEqual(a, b)
     self.assertEqual(b, c)
     self.assertEqual(c, d)
     self.assertNotEqual(id(c), id(d))
     b = Box()
     self.assertTrue(b.isEmpty())
     self.assertTrue(Box.empty().isEmpty())
     self.assertTrue(Box.full().isFull())
Exemple #13
0
 def test_string(self):
     c = Ellipse(UnitVector3d.Z(), Angle(1.0))
     self.assertEqual(str(c),
                      'Ellipse([0.0, 0.0, 1.0], [0.0, 0.0, 1.0], 1.0)')
     self.assertEqual(
         repr(c), 'Ellipse(UnitVector3d(0.0, 0.0, 1.0), '
         'UnitVector3d(0.0, 0.0, 1.0), Angle(1.0))')
     self.assertEqual(
         c,
         eval(repr(c),
              dict(Angle=Angle, Ellipse=Ellipse,
                   UnitVector3d=UnitVector3d)))
 def test_relationships(self):
     c = Circle(UnitVector3d.X(), Angle.fromDegrees(0.1))
     d = Circle(UnitVector3d(1, 1, 1), Angle(math.pi / 2))
     e = Circle(-UnitVector3d.X())
     self.assertTrue(c.contains(UnitVector3d.X()))
     self.assertTrue(UnitVector3d.X() in c)
     self.assertTrue(d.contains(c))
     self.assertTrue(c.isWithin(d))
     self.assertTrue(c.intersects(d))
     self.assertTrue(c.intersects(UnitVector3d.X()))
     self.assertTrue(e.isDisjointFrom(d))
     self.assertEqual(d.relate(c), CONTAINS)
     self.assertEqual(e.relate(d), DISJOINT)
Exemple #15
0
    def run(self) -> Optional[int]:
        """Run whole shebang.
        """

        # load configurations
        if self.args.app_config:
            self.config.load(self.args.app_config)

        if self.args.backend == "sql":
            self.dbconfig = ApdbSqlConfig()
            if self.args.config:
                self.dbconfig.load(self.args.config)
        elif self.args.backend == "cassandra":
            self.dbconfig = ApdbCassandraConfig()
            if self.args.config:
                self.dbconfig.load(self.args.config)

        if self.args.dump_config:
            self.config.saveToStream(sys.stdout)
            self.dbconfig.saveToStream(sys.stdout)
            return 0

        # instantiate db interface
        db: Apdb
        if self.args.backend == "sql":
            db = ApdbSql(config=self.dbconfig)
        elif self.args.backend == "cassandra":
            db = ApdbCassandra(config=self.dbconfig)

        visitInfoStore = VisitInfoStore(self.args.visits_file)

        num_tiles = 1
        if self.config.divide != 1:

            tiles = geom.make_tiles(self.config.FOV_rad, self.config.divide)
            num_tiles = len(tiles)

            # check that we have reasonable MPI setup
            if self.config.mp_mode == "mpi":
                comm = MPI.COMM_WORLD
                num_proc = comm.Get_size()
                rank = comm.Get_rank()
                node = MPI.Get_processor_name()
                _LOG.info(
                    COLOR_YELLOW + "MPI job rank=%d size=%d, node %s" +
                    COLOR_RESET, rank, num_proc, node)
                if num_proc != num_tiles:
                    raise ValueError(
                        f"Number of MPI processes ({num_proc}) "
                        f"does not match number of tiles ({num_tiles})")
                if rank != 0:
                    # run simple loop for all non-master processes
                    self.run_mpi_tile_loop(db, comm)
                    return None

        # Initialize starting values from database visits table
        last_visit = visitInfoStore.lastVisit()
        if last_visit is not None:
            start_visit_id = last_visit.visitId + 1
            nsec = last_visit.visitTime.nsecs(
                DateTime.TAI) + self.config.interval * 1_000_000_000
            start_time = DateTime(nsec, DateTime.TAI)
        else:
            start_visit_id = self.config.start_visit_id
            start_time = self.config.start_time_dt

        if self.config.divide > 1:
            _LOG.info("Will divide FOV into %d regions", num_tiles)

        src_read_period = self.config.src_read_period
        src_read_visits = round(self.config.src_read_period *
                                self.config.src_read_duty_cycle)
        _LOG.info("Will read sources for %d visits out of %d", src_read_visits,
                  src_read_period)

        # read sources file
        _LOG.info("Start loading variable sources from %r",
                  self.config.sources_file)
        var_sources = numpy.load(self.config.sources_file)
        _LOG.info("Finished loading variable sources, count = %s",
                  len(var_sources))

        # diaObjectId for last new DIA object, for variable sources we use their
        # index as objectId, for transients we want to use ID outside that range
        if last_visit is not None and last_visit.lastObjectId is not None:
            self.lastObjectId = max(self.lastObjectId, last_visit.lastObjectId)
        if self.lastObjectId < len(var_sources):
            _LOG.error('next object id is too low: %s', self.lastObjectId)
            return 1
        _LOG.debug("lastObjectId: %s", self.lastObjectId)

        # diaSourceId for last DIA source stored in database
        if last_visit is not None and last_visit.lastSourceId is not None:
            self.lastSourceId = max(self.lastSourceId, last_visit.lastSourceId)
        _LOG.info("lastSourceId: %s", self.lastSourceId)

        # loop over visits
        visitTimes = _visitTimes(start_time, self.config.interval,
                                 self.args.num_visits)
        for visit_id, dt in enumerate(visitTimes, start_visit_id):

            if visit_id % 1000 == 0:
                _LOG.info(COLOR_YELLOW + "+++ Start daily activities" +
                          COLOR_RESET)
                db.dailyJob()
                _LOG.info(COLOR_YELLOW + "+++ Done with daily activities" +
                          COLOR_RESET)

            _LOG.info(
                COLOR_GREEN + "+++ Start processing visit %s at %s" +
                COLOR_RESET, visit_id, dt)
            loop_timer = timer.Timer().start()

            with timer.Timer("DIA"):
                # point telescope in random southern direction
                pointing_xyz = generators.rand_sphere_xyz(1, -1)[0]
                pointing_v = UnitVector3d(pointing_xyz[0], pointing_xyz[1],
                                          pointing_xyz[2])
                ra = LonLat.longitudeOf(pointing_v).asDegrees()
                decl = LonLat.latitudeOf(pointing_v).asDegrees()

                # sphgeom.Circle opening angle is actually a half of opening angle
                region = Circle(pointing_v, Angle(self.config.FOV_rad / 2))

                _LOG.info("Pointing ra, decl = %s, %s; xyz = %s", ra, decl,
                          pointing_xyz)

                # Simulating difference image analysis
                dia = DIA.DIA(
                    pointing_xyz, self.config.FOV_rad, var_sources,
                    self.config.false_per_visit +
                    self.config.transient_per_visit)
                sources, indices = dia.makeSources()
                _LOG.info("DIA generated %s sources", len(sources))

                # assign IDs to transients
                for i in range(len(sources)):
                    if indices[i] < 0:
                        self.lastObjectId += 1
                        indices[i] = self.lastObjectId

            # print current database row counts, this takes long time
            # so only do it once in a while
            modu = 200 if visit_id <= 10000 else 1000
            if visit_id % modu == 0:
                if hasattr(db, "tableRowCount"):
                    counts = db.tableRowCount()  # type: ignore
                    for tbl, count in sorted(counts.items()):
                        _LOG.info('%s row count: %s', tbl, count)

            # numpy seems to do some multi-threaded stuff which "leaks" CPU cycles to the code below
            # and it gets counted as resource usage in timers, add a short delay here so that threads
            # finish and don't influence our timers below.
            time.sleep(0.1)

            if self.config.divide == 1:

                # do it in-process
                with timer.Timer("VisitProcessing"):
                    self.visit(db, visit_id, dt, region, sources, indices)

            else:

                if self.config.mp_mode == "fork":

                    tiles = geom.make_tiles(self.config.FOV_rad,
                                            self.config.divide, pointing_v)

                    with timer.Timer("VisitProcessing"):
                        # spawn subprocesses to handle individual tiles
                        children = []
                        for ix, iy, region in tiles:

                            # make sure lastSourceId is unique in in each process
                            self.lastSourceId += len(sources)
                            tile = (ix, iy)

                            pid = os.fork()
                            if pid == 0:
                                # child

                                self.visit(db, visit_id, dt, region, sources,
                                           indices, tile)
                                # stop here
                                sys.exit(0)

                            else:
                                _LOG.debug("Forked process %d for tile %s",
                                           pid, tile)
                                children.append(pid)

                        # wait until all children finish
                        for pid in children:
                            try:
                                pid, status = os.waitpid(pid, 0)
                                if status != 0:
                                    _LOG.warning(
                                        COLOR_RED +
                                        "Child process PID=%s failed: %s" +
                                        COLOR_RESET, pid, status)
                            except OSError as exc:
                                _LOG.warning(
                                    COLOR_RED + "wait failed for PID=%s: %s" +
                                    COLOR_RESET, pid, exc)

                elif self.config.mp_mode == "mpi":

                    tiles = geom.make_tiles(self.config.FOV_rad,
                                            self.config.divide, pointing_v)
                    _LOG.info("Split FOV into %d tiles for MPI", len(tiles))

                    # spawn subprocesses to handle individual tiles, special
                    # care needed for self.lastSourceId because it's
                    # propagated back from (0, 0)
                    lastSourceId = self.lastSourceId
                    tile_data = []
                    for ix, iy, region in tiles:
                        lastSourceId += len(sources)
                        tile = (ix, iy)
                        tile_data += [(visit_id, dt, region, sources, indices,
                                       tile, lastSourceId)]
                        # make sure lastSourceId is unique in in each process

                    with timer.Timer("VisitProcessing"):
                        _LOG.info("Scatter sources to %d tile processes",
                                  len(tile_data))
                        self.run_mpi_tile(db, MPI.COMM_WORLD, tile_data)
                    self.lastSourceId = lastSourceId

            if not self.args.no_update:
                # store last visit info
                visitInfoStore.saveVisit(visit_id, dt, self.lastObjectId,
                                         self.lastSourceId)

            _LOG.info(
                COLOR_BLUE + "--- Finished processing visit %s, time: %s" +
                COLOR_RESET, visit_id, loop_timer)

        # stop MPI slaves
        if num_tiles > 1 and self.config.mp_mode == "mpi":
            _LOG.info("Stopping MPI tile processes")
            tile_data_stop = [None] * self.config.divide**2
            self.run_mpi_tile(db, MPI.COMM_WORLD, tile_data_stop)

        return 0
Exemple #16
0
 def test_comparison_operators(self):
     e = Ellipse(UnitVector3d.X(), UnitVector3d.Y(), Angle(2 * math.pi / 3))
     f = Ellipse(UnitVector3d.X(), Angle(math.pi / 3), Angle(math.pi / 6),
                 Angle(0))
     self.assertEqual(e, e)
     self.assertNotEqual(e, f)
Exemple #17
0
 def test_dilation_and_erosion(self):
     a = Box.fromRadians(0.5, -0.5, 1.5, 0.5)
     b = a.dilatedBy(Angle(0.5), Angle(0.5)).erodedBy(Angle(1), Angle(1))
     a.dilateBy(Angle(0.5), Angle(0.5)).erodeBy(Angle(1), Angle(1))
     self.assertEqual(a, b)
     self.assertEqual(a, LonLat.fromRadians(1, 0))
Exemple #18
0
 def test_yaml(self):
     a = Ellipse(UnitVector3d.X(), UnitVector3d.Y(), Angle(2 * math.pi / 3))
     b = yaml.safe_load(yaml.dump(a))
     self.assertEqual(a, b)
Exemple #19
0
 def test_pickle(self):
     a = Ellipse(UnitVector3d.X(), UnitVector3d.Y(), Angle(2 * math.pi / 3))
     b = pickle.loads(pickle.dumps(a, pickle.HIGHEST_PROTOCOL))
     self.assertEqual(a, b)
 def testPickle(self):
     a = Angle(1.5)
     b = pickle.loads(pickle.dumps(a))
     self.assertEqual(a, b)
Exemple #21
0
 def test_complement(self):
     e = Ellipse(UnitVector3d.X(), Angle(math.pi / 3), Angle(math.pi / 6),
                 Angle(0))
     f = e.complemented().complement()
     self.assertEqual(e, f)
Exemple #22
0
 def test_codec(self):
     e = Ellipse(UnitVector3d.X(), UnitVector3d.Y(), Angle(2 * math.pi / 3))
     s = e.encode()
     self.assertEqual(Ellipse.decode(s), e)
     self.assertEqual(Region.decode(s), e)
 def testString(self):
     self.assertEqual(str(Angle(1)), '1.0')
     self.assertEqual(repr(Angle(1)), 'Angle(1.0)')
     a = Angle(2.5)
     self.assertEqual(a, eval(repr(a), dict(Angle=Angle)))
Exemple #24
0
 def testRotation(self):
     v = UnitVector3d.Y().rotatedAround(UnitVector3d.X(),
                                        Angle(0.5 * math.pi))
     self.assertAlmostEqual(v.x(), 0.0, places=15)
     self.assertAlmostEqual(v.y(), 0.0, places=15)
     self.assertAlmostEqual(v.z(), 1.0, places=15)
Exemple #25
0
    def testSkyMapDimensions(self):
        """Test involving only skymap dimensions, no joins to instrument"""
        registry = self.registry

        # need a bunch of dimensions and datasets for test, we want
        # "abstract_filter" in the test so also have to add physical_filter
        # dimensions
        registry.addDimensionEntry("instrument", dict(instrument="DummyCam"))
        registry.addDimensionEntry("physical_filter", dict(instrument="DummyCam",
                                                           physical_filter="dummy_r",
                                                           abstract_filter="r"))
        registry.addDimensionEntry("physical_filter", dict(instrument="DummyCam",
                                                           physical_filter="dummy_i",
                                                           abstract_filter="i"))
        registry.addDimensionEntry("skymap", dict(skymap="DummyMap", hash="sha!".encode("utf8")))
        for tract in range(10):
            registry.addDimensionEntry("tract", dict(skymap="DummyMap", tract=tract))
            for patch in range(10):
                registry.addDimensionEntry("patch", dict(skymap="DummyMap", tract=tract, patch=patch,
                                                         cell_x=0, cell_y=0,
                                                         region=Box(LonLat(NormalizedAngle(0.), Angle(0.)))))

        # dataset types
        collection = "test"
        run = registry.makeRun(collection=collection)
        storageClass = StorageClass("testDataset")
        registry.storageClasses.registerStorageClass(storageClass)
        calexpType = DatasetType(name="deepCoadd_calexp",
                                 dimensions=registry.dimensions.extract(("skymap", "tract", "patch",
                                                                         "abstract_filter")),
                                 storageClass=storageClass)
        registry.registerDatasetType(calexpType)
        mergeType = DatasetType(name="deepCoadd_mergeDet",
                                dimensions=registry.dimensions.extract(("skymap", "tract", "patch")),
                                storageClass=storageClass)
        registry.registerDatasetType(mergeType)
        measType = DatasetType(name="deepCoadd_meas",
                               dimensions=registry.dimensions.extract(("skymap", "tract", "patch",
                                                                       "abstract_filter")),
                               storageClass=storageClass)
        registry.registerDatasetType(measType)

        dimensions = registry.dimensions.empty.union(calexpType.dimensions, mergeType.dimensions,
                                                     measType.dimensions, implied=True)

        # add pre-existing datasets
        for tract in (1, 3, 5):
            for patch in (2, 4, 6, 7):
                dataId = dict(skymap="DummyMap", tract=tract, patch=patch)
                registry.addDataset(mergeType, dataId=dataId, run=run)
                for aFilter in ("i", "r"):
                    dataId = dict(skymap="DummyMap", tract=tract, patch=patch, abstract_filter=aFilter)
                    registry.addDataset(calexpType, dataId=dataId, run=run)

        # with empty expression
        builder = DataIdQueryBuilder.fromDimensions(registry, dimensions)
        builder.requireDataset(calexpType, collections=[collection])
        builder.requireDataset(mergeType, collections=[collection])
        rows = list(builder.execute())
        self.assertEqual(len(rows), 3*4*2)   # 4 tracts x 4 patches x 2 filters
        for dataId in rows:
            self.assertCountEqual(dataId.keys(), ("skymap", "tract", "patch", "abstract_filter"))
        self.assertCountEqual(set(dataId["tract"] for dataId in rows), (1, 3, 5))
        self.assertCountEqual(set(dataId["patch"] for dataId in rows), (2, 4, 6, 7))
        self.assertCountEqual(set(dataId["abstract_filter"] for dataId in rows), ("i", "r"))

        # limit to 2 tracts and 2 patches
        builder = DataIdQueryBuilder.fromDimensions(registry, dimensions)
        builder.requireDataset(calexpType, collections=[collection])
        builder.requireDataset(mergeType, collections=[collection])
        builder.whereParsedExpression("tract IN (1, 5) AND patch.patch IN (2, 7)")
        rows = list(builder.execute())
        self.assertEqual(len(rows), 2*2*2)   # 4 tracts x 4 patches x 2 filters
        self.assertCountEqual(set(dataId["tract"] for dataId in rows), (1, 5))
        self.assertCountEqual(set(dataId["patch"] for dataId in rows), (2, 7))
        self.assertCountEqual(set(dataId["abstract_filter"] for dataId in rows), ("i", "r"))

        # limit to single filter
        builder = DataIdQueryBuilder.fromDimensions(registry, dimensions)
        builder.requireDataset(calexpType, collections=[collection])
        builder.requireDataset(mergeType, collections=[collection])
        builder.whereParsedExpression("abstract_filter = 'i'")
        rows = list(builder.execute())
        self.assertEqual(len(rows), 3*4*1)   # 4 tracts x 4 patches x 2 filters
        self.assertCountEqual(set(dataId["tract"] for dataId in rows), (1, 3, 5))
        self.assertCountEqual(set(dataId["patch"] for dataId in rows), (2, 4, 6, 7))
        self.assertCountEqual(set(dataId["abstract_filter"] for dataId in rows), ("i",))

        # expression excludes everything, specifying non-existing skymap is
        # not a fatal error, it's operator error
        builder = DataIdQueryBuilder.fromDimensions(registry, dimensions)
        builder.requireDataset(calexpType, collections=[collection])
        builder.requireDataset(mergeType, collections=[collection])
        builder.whereParsedExpression("skymap = 'Mars'")
        rows = list(builder.execute())
        self.assertEqual(len(rows), 0)