Skip to content

Commit fac0f15

Browse files
committed
Merge branch 'develop'
2 parents 1659e6a + bb953a2 commit fac0f15

7 files changed

Lines changed: 250 additions & 7 deletions

File tree

docs/installation.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ Start up a python interpreter and type:
5656
import dustmaps.leike2020
5757
dustmaps.leike2020.fetch()
5858
59+
import dustmaps.gaia_tge
60+
dustmaps.gaia_tge.fetch()
61+
5962
All the dust maps should now be in the path you gave to
6063
:code:`config['data_dir']`. Note that these dust maps can be very large - some
6164
are several Gigabytes! Only download those you think you'll need.
@@ -113,6 +116,7 @@ to only download those you think you'll need:
113116
python setup.py fetch --map-name=lenz2017
114117
python setup.py fetch --map-name=leikeensslin2019
115118
python setup.py fetch --map-name=leike2020
119+
python setup.py fetch --map-name=gaia_tge
116120
117121
That's it!
118122

docs/maps.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@ conversions provided in
2323
* **Reference**: `Schlegel, Finkbeiner & Davis (1998) <http://adsabs.harvard.edu/abs/1998ApJ...500..525S>`_
2424
* **Recalibration**: `Schlafly & Finkbeiner (2011) <http://adsabs.harvard.edu/abs/2011ApJ...737..103S>`_
2525

26+
Gaia Total Galactic Extinction (2022)
27+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28+
29+
A two-dimensional map of A0, the monochromatic extinction at 541.4 nm. The map
30+
is based on extinction estimates for giants beyond 300 pc. The individual
31+
exitnction estimates estimates were obtained by fitting Gaia BP/RP spectra,
32+
parallaxes and G-band apparent magnitudes.
33+
34+
The map comes in multiple HEALPix levels (6 to 9). By default, an "optimum"
35+
map is loaded, with an adaptive HEALPix level, based on the local number
36+
of stars (at least 3 stars are required per pixel).
37+
38+
* **Reference**: Delchambre et al. (2022).
39+
2640

2741
Lenz, Hensley & Doré (2017)
2842
~~~~~~~~~~~~~~~~~~~~~~~~~~~

docs/modules.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ chen2014 (Chen et al. 2014)
2626
:special-members:
2727
:show-inheritance:
2828

29+
gaia_tge (Delchambre et al. 2022)
30+
---------------------------
31+
.. automodule:: dustmaps.gaia_tge
32+
:members:
33+
:special-members:
34+
:show-inheritance:
35+
2936
iphas (Sale et al. 2014)
3037
------------------------
3138
.. automodule:: dustmaps.iphas

dustmaps/gaia_tge.py

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
#!/usr/bin/env python
2+
#
3+
# gaia_tge.py
4+
# Reads the Gaia TGE dust reddening maps.
5+
#
6+
# Copyright (C) 2022 Gregory M. Green
7+
#
8+
# This program is free software; you can redistribute it and/or modify
9+
# it under the terms of the GNU General Public License as published by
10+
# the Free Software Foundation; either version 2 of the License, or
11+
# (at your option) any later version.
12+
#
13+
# This program is distributed in the hope that it will be useful,
14+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
# GNU General Public License for more details.
17+
#
18+
# You should have received a copy of the GNU General Public License along
19+
# with this program; if not, write to the Free Software Foundation, Inc.,
20+
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21+
#
22+
23+
from __future__ import print_function, division
24+
25+
import os
26+
import numpy as np
27+
import healpy as hp
28+
from astropy.table import Table
29+
import astropy.units as units
30+
31+
from .std_paths import *
32+
from .healpix_map import HEALPixQuery
33+
from . import fetch_utils
34+
from . import dustexceptions
35+
36+
37+
class GaiaTGEQuery(HEALPixQuery):
38+
"""
39+
Queries the Gaia Total Galactic Extinction (Delchambre 2022) dust map,
40+
which contains estimates of monochromatic extinction, A0, in mags.
41+
"""
42+
43+
def __init__(self, map_fname=None, healpix_level='optimum'):
44+
"""
45+
Args:
46+
map_fname (Optional[`str`]): Filename of the Gaia TGE map.
47+
Defaults to ``None``, meaning that the default location is
48+
used.
49+
healpix_level (Optional[`int` or `str`]): Which HEALPix
50+
level to load into the map. If "optimum" (the default), loads
51+
the optimum HEALPix level available at each location. If an
52+
`int`, instead loads the specified HEALPix level.
53+
"""
54+
55+
if map_fname is None:
56+
map_fname = os.path.join(
57+
data_dir(),
58+
'gaia_tge',
59+
'TotalGalacticExtinctionMap_001.csv.gz'
60+
)
61+
62+
try:
63+
# Cannot use astropy ECSV reader, due to bug in processing
64+
# null values
65+
dtype = [
66+
('solution_id', 'i8'),
67+
('healpix_id', 'i8'),
68+
('healpix_level', 'i1'),
69+
('a0', 'f4'),
70+
('a0_uncertainty', 'f4'),
71+
('a0_min', 'f4'),
72+
('a0_max', 'f4'),
73+
('num_tracers_used', 'i4'),
74+
('optimum_hpx_flag', '?'),
75+
('status', 'i2')
76+
]
77+
converters = {8: lambda x: x == '"True"'}
78+
d = np.genfromtxt(
79+
map_fname, comments='#', delimiter=',',
80+
encoding='utf-8', converters=converters,
81+
dtype=dtype
82+
)[1:]
83+
except IOError as error:
84+
print(dustexceptions.data_missing_message('gaia_tge',
85+
'Gaia TGE'))
86+
raise error
87+
88+
if isinstance(healpix_level, int):
89+
idx = (d['healpix_level'] == healpix_level)
90+
n_pix = np.count_nonzero(idx)
91+
if n_pix == 0:
92+
levels_avail = np.unique(d['healpix_level']).tolist()
93+
raise ValueError(
94+
'Requested HEALPix level not stored in map. Available '
95+
'levels: {}'.format(levels_avail)
96+
)
97+
hpx_sort_idx = np.argsort(d['healpix_id'][idx])
98+
idx = np.where(idx)[0]
99+
idx = idx[hpx_sort_idx]
100+
elif healpix_level == 'optimum':
101+
idx_opt = d['optimum_hpx_flag']
102+
# Upscale to highest HEALPix level
103+
hpx_level = d['healpix_level'][idx_opt]
104+
hpx_level_max = np.max(hpx_level)
105+
n_pix = 12 * 4**hpx_level_max
106+
# Index from original array to use in each pixel of final map
107+
idx = np.full(n_pix, -1, dtype='i8') # Empty pixel -> index=-1
108+
# Get the ring-ordered index of the optimal pixels
109+
idx_opt = np.where(idx_opt)[0]
110+
hpx_idx = d['healpix_id'][idx_opt]
111+
# Add pixels of each level to the map
112+
for level in np.unique(hpx_level):
113+
nside = 2**level
114+
idx_lvl = (hpx_level == level)
115+
# Get the nest-ordered index of optimal pixels at this level
116+
hpx_idx_nest = hpx_idx[idx_lvl]
117+
# Fill in index (in orig arr) of these pixels
118+
mult_factor = 4**(hpx_level_max-level)
119+
hpx_idx_base = hpx_idx_nest*mult_factor
120+
for offset in range(mult_factor):
121+
idx[hpx_idx_base+offset] = idx_opt[idx_lvl]
122+
else:
123+
raise ValueError(
124+
'`healpix_level` must be either an integer or "optimum"'
125+
)
126+
127+
bad_mask = (idx == -1)
128+
129+
pix_val = d['a0'][idx]
130+
pix_val[bad_mask] = np.nan
131+
132+
dtype = [
133+
('a0_uncertainty', 'f4'),
134+
('num_tracers_used', 'i4'),
135+
('optimum_hpx_flag', 'bool')
136+
]
137+
flags = np.empty(n_pix, dtype=dtype)
138+
for key,dt in dtype:
139+
flags[key] = d[key][idx]
140+
flags[key][bad_mask] = {'f4':np.nan, 'i4':-1, 'bool':False}[dt]
141+
142+
super(GaiaTGEQuery, self).__init__(
143+
pix_val, True, 'icrs', flags=flags
144+
)
145+
146+
def query(self, coords, **kwargs):
147+
"""
148+
Returns a numpy array containing A0 at the specified
149+
location(s) on the sky. Optionally, returns a 2nd array containing
150+
flags at the same location(s).
151+
152+
Args:
153+
coords (`astropy.coordinates.SkyCoord`): The coordinates to
154+
query.
155+
return_flags (Optional[`bool`]): If `True`, returns a 2nd array
156+
containing flags at each coordinate. Defaults to `False`.
157+
158+
Returns:
159+
A numpy array containing A0 at the specified
160+
coordinates. The shape of the output is the same as the shape of
161+
the input coordinate array, ``coords``. If `return_flags` is
162+
`True`, a 2nd record array containing flags at each coordinate
163+
is also returned.
164+
"""
165+
return super(GaiaTGEQuery, self).query(coords, **kwargs)
166+
167+
168+
def fetch():
169+
"""
170+
Downloads the Gaia Total Galactic Extinction (TGE) dust maps, placing
171+
it in the default ``dustmaps`` directory.
172+
"""
173+
props = {
174+
'url': (
175+
'http://cdn.gea.esac.esa.int/Gaia/gdr3/Astrophysical_parameters/'
176+
'total_galactic_extinction_map/TotalGalacticExtinctionMap_001.csv.gz'
177+
),
178+
'md5': '5f6271869b7e60960a955f08ca11dc37',
179+
'fname': 'TotalGalacticExtinctionMap_001.csv.gz'
180+
}
181+
fname = os.path.join(data_dir(), 'gaia_tge', props['fname'])
182+
fetch_utils.download_and_verify(props['url'], props['md5'], fname=fname)
183+
184+
185+
def main():
186+
from astropy.coordinates import SkyCoord
187+
q = GaiaTGEQuery()
188+
c = SkyCoord([0., 180., 0.], [0., 0., 90.], frame='galactic', unit='deg')
189+
print(q(c))
190+
191+
192+
if __name__ == '__main__':
193+
main()

dustmaps/healpix_map.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class HEALPixQuery(DustMap):
3535
A class for querying HEALPix maps.
3636
"""
3737

38-
def __init__(self, pix_val, nest, coord_frame):
38+
def __init__(self, pix_val, nest, coord_frame, flags=None):
3939
"""
4040
Args:
4141
pix_val (array): Value of the map in every pixel. The length of the
@@ -50,20 +50,40 @@ def __init__(self, pix_val, nest, coord_frame):
5050
self._pix_val = pix_val
5151
self._nest = nest
5252
self._frame = coord_frame
53+
self._flags = flags
54+
if (flags is not None) and (flags.shape[0] != pix_val.shape[0]):
55+
raise ValueError((
56+
'The shape of `flags` ({}) must match the shape '
57+
'of `pix_val` ({}) along the first axis.'
58+
).format(flags.shape, pix_val.shape))
5359
super(HEALPixQuery, self).__init__()
5460

55-
def query(self, coords):
61+
def query(self, coords, return_flags=False):
5662
"""
5763
Args:
5864
coords (`astropy.coordinates.SkyCoord`): The coordinates to query.
65+
return_flags ([Optional[:obj:`bool`]): If `True`, return flags at
66+
each pixel. Only possible if flags were provided during
67+
initialization.
5968
6069
Returns:
6170
A float array of the value of the map at the given coordinates. The
6271
shape of the output is the same as the shape of the coordinates
63-
stored by `coords`.
72+
stored by `coords`. If `return_flags` is `True`, then a second
73+
array, containing flags at each pixel, is also returned.
6474
"""
6575
pix_idx = coord2healpix(coords, self._frame,
6676
self._nside, nest=self._nest)
77+
sel_pix = self._pix_val[pix_idx]
78+
79+
if return_flags:
80+
if self._flags is None:
81+
raise ValueError(
82+
'`return_flags` is True, but the class was initialized '
83+
'without flags.'
84+
)
85+
return sel_pix, self._flags[pix_idx]
86+
6787
return self._pix_val[pix_idx]
6888

6989

dustmaps/json_serializers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ def deserialize_ndarray(d):
212212
An :obj:`ndarray` object.
213213
"""
214214
if 'data' in d:
215-
x = np.fromstring(
215+
x = np.frombuffer(
216216
base64.b64decode(d['data']),
217217
dtype=d['dtype'])
218218
x.shape = d['shape']

setup.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ def fetch_pg2010():
101101
import dustmaps.pg2010
102102
dustmaps.pg2010.fetch()
103103

104+
def fetch_gaia_tge():
105+
import dustmaps.gaia_tge
106+
dustmaps.gaia_tge.fetch()
107+
104108
def fetch_bh():
105109
print('Burstein & Heiles (1982) is already installed by default.')
106110

@@ -126,7 +130,8 @@ class FetchCommand(distutils.cmd.Command):
126130
'lenz2017': fetch_lenz2017,
127131
'pg2010': fetch_pg2010,
128132
'leikeensslin2019': fetch_leikeensslin2019,
129-
'leike2020': fetch_leike2020
133+
'leike2020': fetch_leike2020,
134+
'gaia_tge': fetch_gaia_tge
130135
}
131136

132137
def initialize_options(self):
@@ -153,12 +158,12 @@ def readme():
153158

154159
setup(
155160
name='dustmaps',
156-
version='1.0.9',
161+
version='1.0.10',
157162
description='Uniform interface for multiple dust reddening maps.',
158163
long_description=readme(),
159164
long_description_content_type='text/markdown',
160165
url='https://github.com/gregreen/dustmaps',
161-
download_url='https://github.com/gregreen/dustmaps/archive/v1.0.9.tar.gz',
166+
download_url='https://github.com/gregreen/dustmaps/archive/v1.0.10.tar.gz',
162167
author='Gregory M. Green',
163168
author_email='gregorymgreen@gmail.com',
164169
license='GPLv2',

0 commit comments

Comments
 (0)