cabaret 0.0.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
@@ -0,0 +1,52 @@
1
+ name: cabaret/build-publish
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ tags:
8
+ - "*"
9
+ pull_request:
10
+ merge_group:
11
+
12
+ jobs:
13
+ build:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ with:
18
+ fetch-depth: 0
19
+ - uses: actions/setup-python@v5
20
+ name: Install Python
21
+ with:
22
+ python-version: "3.10"
23
+ - name: Install dependencies
24
+ run: |
25
+ python -m pip install -U pip
26
+ python -m pip install -U build twine
27
+ - name: Build the distribution
28
+ run: python -m build .
29
+ - name: Check the distribution
30
+ run: python -m twine check --strict dist/*
31
+ - uses: actions/upload-artifact@v4
32
+ with:
33
+ name: dist
34
+ path: dist/*
35
+
36
+ publish:
37
+ environment:
38
+ name: pypi
39
+ url: https://pypi.org/p/cabaret
40
+ permissions:
41
+ contents: read
42
+ id-token: write
43
+ needs: [build]
44
+ runs-on: ubuntu-latest
45
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
46
+ steps:
47
+ - uses: actions/download-artifact@v4
48
+ with:
49
+ name: dist
50
+ path: dist
51
+ - uses: pypa/gh-action-pypi-publish@v1.8.11
52
+
@@ -0,0 +1,160 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/#use-with-ide
110
+ .pdm.toml
111
+
112
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113
+ __pypackages__/
114
+
115
+ # Celery stuff
116
+ celerybeat-schedule
117
+ celerybeat.pid
118
+
119
+ # SageMath parsed files
120
+ *.sage.py
121
+
122
+ # Environments
123
+ .env
124
+ .venv
125
+ env/
126
+ venv/
127
+ ENV/
128
+ env.bak/
129
+ venv.bak/
130
+
131
+ # Spyder project settings
132
+ .spyderproject
133
+ .spyproject
134
+
135
+ # Rope project settings
136
+ .ropeproject
137
+
138
+ # mkdocs documentation
139
+ /site
140
+
141
+ # mypy
142
+ .mypy_cache/
143
+ .dmypy.json
144
+ dmypy.json
145
+
146
+ # Pyre type checker
147
+ .pyre/
148
+
149
+ # pytype static type analyzer
150
+ .pytype/
151
+
152
+ # Cython debug symbols
153
+ cython_debug/
154
+
155
+ # PyCharm
156
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
159
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160
+ #.idea/
@@ -0,0 +1,15 @@
1
+ {
2
+ "editor.formatOnSave": true,
3
+ "[python]": {
4
+ "editor.codeActionsOnSave": {
5
+ "source.organizeImports": "explicit"
6
+ },
7
+ "editor.formatOnPaste": false,
8
+ "editor.defaultFormatter": "ms-python.black-formatter"
9
+ },
10
+ "python.testing.pytestArgs": [
11
+ "tests"
12
+ ],
13
+ "python.testing.unittestEnabled": false,
14
+ "python.testing.pytestEnabled": true
15
+ }
cabaret-0.0.6/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Peter Pihlmann Pedersen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
cabaret-0.0.6/PKG-INFO ADDED
@@ -0,0 +1,77 @@
1
+ Metadata-Version: 2.3
2
+ Name: cabaret
3
+ Version: 0.0.6
4
+ Author: Peter Pedersen, Lionel Garcia
5
+ License: MIT License
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.9
8
+ Requires-Dist: astropy
9
+ Requires-Dist: astroquery
10
+ Requires-Dist: numpy
11
+ Provides-Extra: dev
12
+ Requires-Dist: black; extra == 'dev'
13
+ Requires-Dist: pytest; extra == 'dev'
14
+ Description-Content-Type: text/markdown
15
+
16
+ # cabaret
17
+ ![](example.jpg)
18
+ *cabaret* is a Python package to simulate astronomical images using the [GAIA catalog](https://en.wikipedia.org/wiki/Gaia_catalogues) of stars.
19
+ ## Installation
20
+
21
+ You can install *cabaret* in a Python (`>=3.9`) environment with
22
+
23
+ ```bash
24
+ pip install cabaret
25
+ ```
26
+
27
+ or from a local clone
28
+
29
+ ```bash
30
+ git clone https://github.com/ppp-one/cabaret
31
+ pip install -e cabaret
32
+ ```
33
+
34
+ You can test the package has been properly installed with
35
+
36
+ ```bash
37
+ python -c "import cabaret"
38
+ ```
39
+
40
+ ## Example
41
+
42
+ ### Basic image
43
+
44
+ To generate an image from RA/DEC coordinates and a field of vue specified in degrees:
45
+
46
+ ```python
47
+ import cabaret
48
+
49
+ ra, dec = 12.3323, 30.4343 # in degrees
50
+ exposure_time = 10 # in seconds
51
+
52
+ image = cabaret.generate_image(ra, dec, exposure_time)
53
+ ```
54
+
55
+ and to display the image (`matplotlib` required here):
56
+
57
+ ```python
58
+ import matplotlib.pyplot as plt
59
+
60
+ plt.imshow(image)
61
+ ```
62
+
63
+ ### Using the camera characteristics
64
+
65
+ To adjust the physical characteristics of the camera, you can define and pass a `Camera` object
66
+
67
+ ```python
68
+ import cabaret
69
+ from cabaret import Camera
70
+
71
+ camera = Camera(read_noise=10, gain=1)
72
+
73
+ ra, dec = 12.3323, 30.4343 # in degrees
74
+ exposure_time = 10 # in seconds
75
+
76
+ image = cabaret.generate_image(ra, dec, exposure_time, camera=camera)
77
+ ```
@@ -0,0 +1,62 @@
1
+ # cabaret
2
+ ![](example.jpg)
3
+ *cabaret* is a Python package to simulate astronomical images using the [GAIA catalog](https://en.wikipedia.org/wiki/Gaia_catalogues) of stars.
4
+ ## Installation
5
+
6
+ You can install *cabaret* in a Python (`>=3.9`) environment with
7
+
8
+ ```bash
9
+ pip install cabaret
10
+ ```
11
+
12
+ or from a local clone
13
+
14
+ ```bash
15
+ git clone https://github.com/ppp-one/cabaret
16
+ pip install -e cabaret
17
+ ```
18
+
19
+ You can test the package has been properly installed with
20
+
21
+ ```bash
22
+ python -c "import cabaret"
23
+ ```
24
+
25
+ ## Example
26
+
27
+ ### Basic image
28
+
29
+ To generate an image from RA/DEC coordinates and a field of vue specified in degrees:
30
+
31
+ ```python
32
+ import cabaret
33
+
34
+ ra, dec = 12.3323, 30.4343 # in degrees
35
+ exposure_time = 10 # in seconds
36
+
37
+ image = cabaret.generate_image(ra, dec, exposure_time)
38
+ ```
39
+
40
+ and to display the image (`matplotlib` required here):
41
+
42
+ ```python
43
+ import matplotlib.pyplot as plt
44
+
45
+ plt.imshow(image)
46
+ ```
47
+
48
+ ### Using the camera characteristics
49
+
50
+ To adjust the physical characteristics of the camera, you can define and pass a `Camera` object
51
+
52
+ ```python
53
+ import cabaret
54
+ from cabaret import Camera
55
+
56
+ camera = Camera(read_noise=10, gain=1)
57
+
58
+ ra, dec = 12.3323, 30.4343 # in degrees
59
+ exposure_time = 10 # in seconds
60
+
61
+ image = cabaret.generate_image(ra, dec, exposure_time, camera=camera)
62
+ ```
Binary file
@@ -0,0 +1,22 @@
1
+ [project]
2
+ name = "cabaret"
3
+ version = "0.0.6"
4
+ authors = [
5
+ {name = "Peter Pedersen"},
6
+ {name = "Lionel Garcia"},
7
+ ]
8
+ repository = "https://github.com/ppp-one/cabaret"
9
+ readme = "README.md"
10
+ license = { text = "MIT License" }
11
+ requires-python = ">=3.9"
12
+ dependencies = ["numpy", "astropy", "astroquery"]
13
+
14
+ [build-system]
15
+ requires = ["hatchling", "hatch-vcs"]
16
+ build-backend = "hatchling.build"
17
+
18
+ [tool.hatch.version]
19
+ source = "vcs"
20
+
21
+ [project.optional-dependencies]
22
+ dev = ["black", "pytest"]
@@ -0,0 +1,2 @@
1
+ from cabaret.image import generate_image
2
+ from cabaret.camera import Camera
@@ -0,0 +1,24 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class Camera:
6
+ device_number: int = 0
7
+ width: int = 1000
8
+ height: int = 1000
9
+ max_adu: int = 2**16
10
+ bin_x: int = 1
11
+ bin_y: int = 1
12
+ gain: float = 1.0
13
+ pitch: float = 12.0
14
+ plate_scale: float = 0.35
15
+ well_depth: int = 2**16
16
+ bias: int = 200
17
+ read_noise: float = 4.0
18
+ dark_current: float = 10.0
19
+ sky_background: float = 10.0
20
+ quantum_efficiency: float = 1.0
21
+ collecting_area: float = 10.0
22
+ temperature: float = -10
23
+ sensor_name: str = "gaia-camera-simulated"
24
+ seeing: float = 1.0
@@ -0,0 +1,150 @@
1
+ import numpy as np
2
+
3
+ from astropy.coordinates import SkyCoord
4
+ from astropy.wcs import WCS
5
+
6
+ from datetime import datetime
7
+
8
+ from cabaret.camera import Camera
9
+ from cabaret.queries import gaia_radecs
10
+
11
+
12
+ def moffat_profile(x, y, x0, y0, FWHM, beta=2.5):
13
+ # https://nbviewer.org/github/ysbach/AO_2017/blob/master/04_Ground_Based_Concept.ipynb#1.2.-Moffat
14
+ # FWHM = 2 * R * (2**(1/beta) - 1)**0.5
15
+
16
+ R = (FWHM / 2) * (1 / (2 ** (1 / beta) - 1) ** 0.5)
17
+ A = (beta - 1) / (np.pi * R**2)
18
+
19
+ r_squared = (x - x0) ** 2 + (y - y0) ** 2
20
+
21
+ mp = A * (1 + (r_squared / R**2)) ** (-beta)
22
+
23
+ mp_sum = np.sum(mp)
24
+
25
+ return mp / mp_sum
26
+
27
+
28
+ def generate_star_image(pos, fluxes, FWHM, frame_size):
29
+ x = np.linspace(0, frame_size[0] - 1, frame_size[0])
30
+ y = np.linspace(0, frame_size[1] - 1, frame_size[1])
31
+ xx, yy = np.meshgrid(x, y)
32
+
33
+ image = np.zeros(frame_size).T
34
+ for i, flux in enumerate(fluxes):
35
+ x0 = pos[0][i]
36
+ y0 = pos[1][i]
37
+ star = np.random.poisson(flux) * moffat_profile(xx, yy, x0, y0, FWHM)
38
+ image += star
39
+
40
+ return image
41
+
42
+
43
+ def generate_image(
44
+ ra, dec, exp_time, dateobs=datetime.utcnow(), light=1, camera=Camera, tmass=True
45
+ ):
46
+
47
+ base = np.ones((camera.height, camera.width)).astype(np.float64)
48
+ base += camera.bias + np.random.poisson(
49
+ base * camera.dark_current * exp_time
50
+ ).astype(np.float64)
51
+ base += np.random.normal(
52
+ 0, camera.read_noise, (camera.height, camera.width)
53
+ ).astype(np.float64)
54
+
55
+ if light == 1:
56
+
57
+ # call gaia
58
+ center = SkyCoord(ra=ra, dec=dec, unit="deg")
59
+
60
+ fovx = (
61
+ (1 / np.abs(np.cos(center.dec.rad)))
62
+ * camera.width
63
+ * camera.plate_scale
64
+ / 3600
65
+ )
66
+ fovy = (
67
+ np.sqrt(2) * camera.height * camera.plate_scale / 3600
68
+ ) # to account for poles, maybe should scale instead
69
+
70
+ gaias, mags = gaia_radecs(
71
+ center, (fovx * 1.5, fovy * 1.5), tmass=tmass, dateobs=dateobs
72
+ )
73
+
74
+ wcs = WCS(naxis=2)
75
+ wcs.wcs.cdelt = [-camera.plate_scale / 3600, -camera.plate_scale / 3600]
76
+ wcs.wcs.cunit = ["deg", "deg"]
77
+ wcs.wcs.crpix = [int(camera.width / 2), int(camera.height / 2)]
78
+ wcs.wcs.crval = [center.ra.deg, center.dec.deg]
79
+ wcs.wcs.ctype = ["RA---TAN", "DEC--TAN"]
80
+
81
+ if len(gaias) > 0:
82
+ if tmass:
83
+ # convert mags to fluxes. Reference: https://lweb.cfa.harvard.edu/~dfabricant/huchra/ay145/mags.html
84
+ Jy = 1.51e7 # [photons sec^-1 m^-2 (dlambda/lambda)^-1]
85
+ photons = 0.16 * 1600 * Jy # [photons sec^-1 m^-2] at mag 0
86
+ fluxes = (
87
+ photons
88
+ * 10 ** (-0.4 * mags)
89
+ * camera.quantum_efficiency
90
+ * camera.collecting_area
91
+ * exp_time
92
+ ) # [electrons]
93
+ else:
94
+ fluxes = (
95
+ fluxes
96
+ * camera.quantum_efficiency
97
+ * camera.collecting_area
98
+ * exp_time
99
+ ) # [electrons]
100
+
101
+ # convert gaia stars to pixel coordinates
102
+ gaias_pixel = np.array(SkyCoord(gaias, unit="deg").to_pixel(wcs))
103
+
104
+ # stars within frame and moffat profile
105
+ stars = generate_star_image(
106
+ gaias_pixel,
107
+ fluxes,
108
+ camera.seeing / camera.plate_scale,
109
+ (camera.width, camera.height),
110
+ ).astype(
111
+ np.float64
112
+ ) # * flat
113
+
114
+ # make base image with sky background
115
+ image = base + np.random.poisson(
116
+ base * camera.sky_background * exp_time
117
+ ).astype(
118
+ np.float64
119
+ ) # * flat
120
+
121
+ image += stars
122
+
123
+ else:
124
+ # dark exposure
125
+ image = base
126
+
127
+ # convert to adu and add camera's bias
128
+ image = image / camera.gain + camera.bias # [adu]
129
+
130
+ # clip to max adu
131
+ image = np.clip(image, 0, camera.max_adu)
132
+
133
+ # make image 16 bit
134
+ image = image.astype(np.uint16)
135
+
136
+ return image
137
+
138
+
139
+ if __name__ == "__main__":
140
+ import matplotlib.pyplot as plt
141
+
142
+ # example usage
143
+ image = generate_image(323.36152, -0.82325, 1)
144
+
145
+ fig = plt.figure(figsize=(10, 10))
146
+
147
+ med = np.median(image)
148
+ std = np.std(image)
149
+ plt.imshow(image, cmap="Greys_r", vmax=3 * std + med, vmin=med - 1 * std)
150
+ plt.show()
@@ -0,0 +1,140 @@
1
+ from typing import Optional, Tuple, Union
2
+ from astropy.units import Quantity
3
+ from astropy.coordinates import SkyCoord
4
+ from datetime import datetime
5
+ import numpy as np
6
+ from astropy import units as u
7
+
8
+
9
+ def gaia_radecs(
10
+ center: Union[Tuple[float, float], SkyCoord],
11
+ fov: Union[float, Quantity],
12
+ limit: int = 100000,
13
+ circular: bool = True,
14
+ tmass: bool = False,
15
+ dateobs: Optional[datetime] = None,
16
+ ) -> np.ndarray:
17
+ """
18
+ Query the Gaia archive to retrieve the RA-DEC coordinates of stars within a given field-of-view (FOV) centered on a given sky position.
19
+
20
+ Parameters
21
+ ----------
22
+ center : tuple or astropy.coordinates.SkyCoord
23
+ The sky coordinates of the center of the FOV. If a tuple is given, it should contain the RA and DEC in degrees.
24
+ fov : float or astropy.units.Quantity
25
+ The field-of-view of the FOV in degrees. If a float is given, it is assumed to be in degrees.
26
+ limit : int, optional
27
+ The maximum number of sources to retrieve from the Gaia archive. By default, it is set to 10000.
28
+ circular : bool, optional
29
+ Whether to perform a circular or a rectangular query. By default, it is set to True.
30
+ tmass : bool, optional
31
+ Whether to retrieve the 2MASS J magnitudes catelog. By default, it is set to False.
32
+ dateobs : datetime.datetime, optional
33
+ The date of the observation. If given, the proper motions of the sources will be taken into account. By default, it is set to None.
34
+
35
+ Returns
36
+ -------
37
+ np.ndarray
38
+ An array of shape (n, 2) containing the RA-DEC coordinates of the retrieved sources in degrees.
39
+
40
+ Raises
41
+ ------
42
+ ImportError
43
+ If the astroquery package is not installed.
44
+
45
+ Examples
46
+ --------
47
+ >>> from astropy.coordinates import SkyCoord
48
+ >>> from twirl import gaia_radecs
49
+ >>> center = SkyCoord(ra=10.68458, dec=41.26917, unit='deg')
50
+ >>> fov = 0.1
51
+ >>> radecs = gaia_radecs(center, fov)
52
+ """
53
+ from astroquery.gaia import Gaia
54
+
55
+ if isinstance(center, SkyCoord):
56
+ ra = center.ra.deg
57
+ dec = center.dec.deg
58
+ else:
59
+ ra, dec = center
60
+
61
+ if not isinstance(fov, u.Quantity):
62
+ fov = fov * u.deg
63
+
64
+ if fov.ndim == 1:
65
+ ra_fov, dec_fov = fov.to(u.deg).value
66
+ else:
67
+ ra_fov = dec_fov = fov.to(u.deg).value
68
+
69
+ radius = np.max([ra_fov, dec_fov]) / 2
70
+
71
+ if circular and not tmass:
72
+ job = Gaia.launch_job(
73
+ f"""
74
+ SELECT top {limit} gaia.ra, gaia.dec, gaia.pmra, gaia.pmdec, gaia.phot_rp_mean_flux
75
+ FROM gaiadr2.gaia_source AS gaia
76
+ WHERE 1=CONTAINS(
77
+ POINT('ICRS', {ra}, {dec}),
78
+ CIRCLE('ICRS', gaia.ra, gaia.dec, {radius}))
79
+ ORDER BY gaia.phot_rp_mean_flux DESC
80
+ """
81
+ )
82
+ elif circular and tmass:
83
+ job = Gaia.launch_job(
84
+ f"""
85
+ SELECT top {limit} gaia.ra, gaia.dec, gaia.pmra, gaia.pmdec, gaia.phot_rp_mean_flux, tmass.j_m
86
+ FROM gaiadr2.gaia_source AS gaia
87
+ INNER JOIN gaiadr2.tmass_best_neighbour AS tmass_match ON tmass_match.source_id = gaia.source_id
88
+ INNER JOIN gaiadr1.tmass_original_valid AS tmass ON tmass.tmass_oid = tmass_match.tmass_oid
89
+ WHERE 1=CONTAINS(
90
+ POINT('ICRS', {ra}, {dec}),
91
+ CIRCLE('ICRS', gaia.ra, gaia.dec, {radius}))
92
+ ORDER BY tmass.j_m
93
+ """
94
+ )
95
+ elif not circular and tmass:
96
+ job = Gaia.launch_job(
97
+ f"""
98
+ SELECT top {limit} gaia.ra, gaia.dec, gaia.pmra, gaia.pmdec, gaia.phot_rp_mean_flux, tmass.j_m
99
+ FROM gaiadr2.gaia_source AS gaia
100
+ INNER JOIN gaiadr2.tmass_best_neighbour AS tmass_match ON tmass_match.source_id = gaia.source_id
101
+ INNER JOIN gaiadr1.tmass_original_valid AS tmass ON tmass.tmass_oid = tmass_match.tmass_oid
102
+ WHERE gaia.ra BETWEEN {ra-ra_fov/2} AND {ra+ra_fov/2} AND
103
+ gaia.dec BETWEEN {dec-dec_fov/2} AND {dec+dec_fov/2}
104
+ ORDER BY tmass.j_m
105
+ """
106
+ )
107
+ else:
108
+ job = Gaia.launch_job(
109
+ f"""
110
+ SELECT top {limit} gaia.ra, gaia.dec, gaia.pmra, gaia.pmdec, gaia.phot_rp_mean_flux
111
+ FROM gaiadr2.gaia_source AS gaia
112
+ WHERE gaia.ra BETWEEN {ra-ra_fov/2} AND {ra+ra_fov/2} AND
113
+ gaia.dec BETWEEN {dec-dec_fov/2} AND {dec+dec_fov/2}
114
+ ORDER BY gaia.phot_rp_mean_flux DESC
115
+ """
116
+ )
117
+
118
+ table = job.get_results()
119
+
120
+ # add proper motion to ra and dec
121
+ if dateobs is not None:
122
+ # calculate fractional year
123
+ dateobs = dateobs.year + (dateobs.timetuple().tm_yday - 1) / 365.25 # type: ignore
124
+
125
+ years = dateobs - 2015.5 # type: ignore
126
+ table["ra"] += years * table["pmra"] / 1000 / 3600
127
+ table["dec"] += years * table["pmdec"] / 1000 / 3600
128
+
129
+ if tmass:
130
+ table.remove_rows(np.isnan(table["j_m"]))
131
+ return (
132
+ np.array([table["ra"].value.data, table["dec"].value.data]).T,
133
+ table["j_m"].value.data,
134
+ )
135
+ else:
136
+ table.remove_rows(np.isnan(table["phot_rp_mean_flux"]))
137
+ return (
138
+ np.array([table["ra"].value.data, table["dec"].value.data]).T,
139
+ table["phot_rp_mean_flux"].value.data,
140
+ )
@@ -0,0 +1,19 @@
1
+ def test_readme_1():
2
+ import cabaret
3
+
4
+ ra, dec = 12.3323, 30.4343 # in degrees
5
+ exposure_time = 10 # in seconds
6
+
7
+ image = cabaret.generate_image(ra, dec, exposure_time)
8
+
9
+
10
+ def test_readme_2():
11
+ import cabaret
12
+ from cabaret import Camera
13
+
14
+ camera = Camera(read_noise=10, gain=1, width=100, height=100)
15
+
16
+ ra, dec = 12.3323, 30.4343 # in degrees
17
+ exposure_time = 10 # in seconds
18
+
19
+ image = cabaret.generate_image(ra, dec, exposure_time, camera=camera)
@@ -0,0 +1,9 @@
1
+ import pytest
2
+ from cabaret import generate_image
3
+ from cabaret import Camera
4
+
5
+
6
+ def test_simple():
7
+ camera = Camera(width=100, height=100)
8
+ ra, dec = 323.36152, -0.82325
9
+ image = generate_image(ra, dec, 1, camera=camera)