mwdust 1.5__tar.gz → 1.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.
Potentially problematic release.
This version of mwdust might be problematic. Click here for more details.
- {mwdust-1.5 → mwdust-1.6}/HISTORY.txt +4 -0
- {mwdust-1.5 → mwdust-1.6}/PKG-INFO +16 -2
- {mwdust-1.5 → mwdust-1.6}/README.rst +5 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/DustMap3D.py +4 -3
- {mwdust-1.5 → mwdust-1.6}/mwdust/HierarchicalHealpixMap.py +4 -4
- {mwdust-1.5 → mwdust-1.6}/mwdust/Marshall06.py +1 -1
- mwdust-1.6/mwdust/Zucker25.py +107 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/__init__.py +5 -2
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/fortranfile.py +6 -5
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/healpix.py +39 -21
- mwdust-1.6/mwdust/util/read_SFD.py +129 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust.egg-info/PKG-INFO +16 -2
- {mwdust-1.5 → mwdust-1.6}/mwdust.egg-info/SOURCES.txt +1 -0
- {mwdust-1.5 → mwdust-1.6}/setup.py +1 -1
- mwdust-1.6/tests/test_sfd.py +64 -0
- mwdust-1.5/mwdust/util/read_SFD.py +0 -123
- mwdust-1.5/tests/test_sfd.py +0 -47
- {mwdust-1.5 → mwdust-1.6}/AUTHORS.txt +0 -0
- {mwdust-1.5 → mwdust-1.6}/LICENSE +0 -0
- {mwdust-1.5 → mwdust-1.6}/MANIFEST.in +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/Combined15.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/Combined19.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/Drimmel03.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/Green15.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/Green17.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/Green19.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/SFD.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/Sale14.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/Zero.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/SFD_CodeC/interface.h +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/SFD_CodeC/subs_asciifile.c +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/SFD_CodeC/subs_asciifile.h +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/SFD_CodeC/subs_common_math.h +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/SFD_CodeC/subs_common_string.h +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/SFD_CodeC/subs_fits.c +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/SFD_CodeC/subs_fits.h +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/SFD_CodeC/subs_inoutput.c +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/SFD_CodeC/subs_inoutput.h +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/SFD_CodeC/subs_lambert.c +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/SFD_CodeC/subs_lambert.h +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/SFD_CodeC/subs_memory.c +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/SFD_CodeC/subs_memory.h +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/__init__.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/combine_dustmaps19.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/download.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/extCurves/apj398709t6_ascii.txt +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/extCurves/extinction.tbl +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/extCurves.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/healpix_CodeC/subs_pixfunc.c +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/healpix_CodeC/subs_pixfunc.h +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/read_Drimmel.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust/util/tools.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust.egg-info/dependency_links.txt +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust.egg-info/requires.txt +0 -0
- {mwdust-1.5 → mwdust-1.6}/mwdust.egg-info/top_level.txt +0 -0
- {mwdust-1.5 → mwdust-1.6}/pyproject.toml +0 -0
- {mwdust-1.5 → mwdust-1.6}/setup.cfg +0 -0
- {mwdust-1.5 → mwdust-1.6}/tests/test_download.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/tests/test_ebv.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/tests/test_extcurve.py +0 -0
- {mwdust-1.5 → mwdust-1.6}/tests/test_green19.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: mwdust
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6
|
|
4
4
|
Summary: Dust in the Milky Way
|
|
5
5
|
Home-page: https://github.com/jobovy/mwdust
|
|
6
6
|
Author: Jo Bovy
|
|
@@ -24,6 +24,15 @@ Requires-Dist: h5py
|
|
|
24
24
|
Requires-Dist: tqdm
|
|
25
25
|
Requires-Dist: requests
|
|
26
26
|
Requires-Dist: healpy
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: author-email
|
|
29
|
+
Dynamic: classifier
|
|
30
|
+
Dynamic: description
|
|
31
|
+
Dynamic: home-page
|
|
32
|
+
Dynamic: license
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
Dynamic: requires-dist
|
|
35
|
+
Dynamic: summary
|
|
27
36
|
|
|
28
37
|
mwdust
|
|
29
38
|
======
|
|
@@ -98,6 +107,9 @@ roughly the following lay-out::
|
|
|
98
107
|
bayestar2017.h5
|
|
99
108
|
green19/
|
|
100
109
|
bayestar2019.h5
|
|
110
|
+
zucker25/
|
|
111
|
+
decaps_mean.h5
|
|
112
|
+
decaps_mean_and_samples.h5
|
|
101
113
|
maps/
|
|
102
114
|
SFD_dust_4096_ngp.fits
|
|
103
115
|
SFD_dust_4096_sgp.fits
|
|
@@ -238,6 +250,8 @@ map that you use:
|
|
|
238
250
|
|
|
239
251
|
* **mwdust.Green19**: `Green et al. (2019) <https://ui.adsabs.harvard.edu/abs/2019arXiv190502734G>`__ (added by `@jan-rybizki <https://github.com/jan-rybizki>`__)
|
|
240
252
|
|
|
253
|
+
* **mwdust.Zucker25**: `Zucker et al. (2025) <https://ui.adsabs.harvard.edu/abs/2025arXiv250302657Z>`__
|
|
254
|
+
|
|
241
255
|
* **mwdust.Combined15**: Combination of
|
|
242
256
|
|
|
243
257
|
* `Marshall et al. (2006) <http://adsabs.harvard.edu/abs/2006A%26A...453..635M>`__ (**mwdust.Marshall06**),
|
|
@@ -79,6 +79,9 @@ roughly the following lay-out::
|
|
|
79
79
|
bayestar2017.h5
|
|
80
80
|
green19/
|
|
81
81
|
bayestar2019.h5
|
|
82
|
+
zucker25/
|
|
83
|
+
decaps_mean.h5
|
|
84
|
+
decaps_mean_and_samples.h5
|
|
82
85
|
maps/
|
|
83
86
|
SFD_dust_4096_ngp.fits
|
|
84
87
|
SFD_dust_4096_sgp.fits
|
|
@@ -219,6 +222,8 @@ map that you use:
|
|
|
219
222
|
|
|
220
223
|
* **mwdust.Green19**: `Green et al. (2019) <https://ui.adsabs.harvard.edu/abs/2019arXiv190502734G>`__ (added by `@jan-rybizki <https://github.com/jan-rybizki>`__)
|
|
221
224
|
|
|
225
|
+
* **mwdust.Zucker25**: `Zucker et al. (2025) <https://ui.adsabs.harvard.edu/abs/2025arXiv250302657Z>`__
|
|
226
|
+
|
|
222
227
|
* **mwdust.Combined15**: Combination of
|
|
223
228
|
|
|
224
229
|
* `Marshall et al. (2006) <http://adsabs.harvard.edu/abs/2006A%26A...453..635M>`__ (**mwdust.Marshall06**),
|
|
@@ -11,9 +11,9 @@ try:
|
|
|
11
11
|
except ImportError:
|
|
12
12
|
_BOVY_PLOT_LOADED= False
|
|
13
13
|
|
|
14
|
-
class DustMap3D:
|
|
14
|
+
class DustMap3D(object):
|
|
15
15
|
"""top-level class for a 3D dust map; all other dust maps inherit from this"""
|
|
16
|
-
def __init__(self,filter=None):
|
|
16
|
+
def __init__(self, filter=None, **download_kwargs):
|
|
17
17
|
"""
|
|
18
18
|
NAME:
|
|
19
19
|
__init__
|
|
@@ -26,7 +26,8 @@ class DustMap3D:
|
|
|
26
26
|
2013-11-24 - Started - Bovy (IAS)
|
|
27
27
|
"""
|
|
28
28
|
self._filter= filter
|
|
29
|
-
self
|
|
29
|
+
if hasattr(self, "download"):
|
|
30
|
+
self.download(**download_kwargs) # download the map
|
|
30
31
|
|
|
31
32
|
def __call__(self,*args,**kwargs):
|
|
32
33
|
"""
|
|
@@ -14,7 +14,7 @@ _DEGTORAD= numpy.pi/180.
|
|
|
14
14
|
class HierarchicalHealpixMap(DustMap3D):
|
|
15
15
|
"""General class for extinction maps given as a hierarchical HEALPix
|
|
16
16
|
pixelation (e.g., Green et al. 2015) """
|
|
17
|
-
def __init__(self,filter=None,sf10=True):
|
|
17
|
+
def __init__(self,filter=None,sf10=True, **download_kwargs):
|
|
18
18
|
"""
|
|
19
19
|
NAME:
|
|
20
20
|
__init__
|
|
@@ -28,8 +28,8 @@ class HierarchicalHealpixMap(DustMap3D):
|
|
|
28
28
|
HISTORY:
|
|
29
29
|
2015-07-28 - Started - Bovy (UofT)
|
|
30
30
|
"""
|
|
31
|
-
|
|
32
|
-
self._sf10= sf10
|
|
31
|
+
super(HierarchicalHealpixMap, self).__init__(filter=filter, **download_kwargs)
|
|
32
|
+
self._sf10 = sf10
|
|
33
33
|
return None
|
|
34
34
|
|
|
35
35
|
|
|
@@ -221,4 +221,4 @@ class HierarchicalHealpixMap(DustMap3D):
|
|
|
221
221
|
format=r'$%g$',
|
|
222
222
|
cmap='gist_yarg',
|
|
223
223
|
**kwargs)
|
|
224
|
-
return None
|
|
224
|
+
return None
|
|
@@ -80,7 +80,7 @@ class Marshall06(DustMap3D):
|
|
|
80
80
|
2013-12-12 - Started - Bovy (IAS)
|
|
81
81
|
"""
|
|
82
82
|
if isinstance(l,numpy.ndarray) or isinstance(b,numpy.ndarray):
|
|
83
|
-
raise NotImplementedError("array input for l and b for
|
|
83
|
+
raise NotImplementedError("array input for l and b for Marshall06 dust map not implemented")
|
|
84
84
|
lbIndx= self._lbIndx(l,b)
|
|
85
85
|
if self._intps[lbIndx] != 0:
|
|
86
86
|
out= self._intps[lbIndx](d)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
#
|
|
3
|
+
# DECaPS25: extinction model from Zucker et al. (2025)
|
|
4
|
+
#
|
|
5
|
+
###############################################################################
|
|
6
|
+
import os, os.path
|
|
7
|
+
import numpy
|
|
8
|
+
import h5py
|
|
9
|
+
from mwdust.util.download import dust_dir, downloader
|
|
10
|
+
from mwdust.HierarchicalHealpixMap import HierarchicalHealpixMap
|
|
11
|
+
|
|
12
|
+
_DEGTORAD = numpy.pi/180.
|
|
13
|
+
_decapsdir = os.path.join(dust_dir, 'zucker25')
|
|
14
|
+
|
|
15
|
+
class Zucker25(HierarchicalHealpixMap):
|
|
16
|
+
"""DECaPS 3D dust-reddening map (Zucker et al. 2025)"""
|
|
17
|
+
def __init__(self, filter=None, sf10=True, load_samples=False, interpk=1):
|
|
18
|
+
"""
|
|
19
|
+
NAME:
|
|
20
|
+
__init__
|
|
21
|
+
PURPOSE:
|
|
22
|
+
Initialize the DECaPS (2025) dust map
|
|
23
|
+
INPUT:
|
|
24
|
+
filter= filter to return the extinction in
|
|
25
|
+
sf10= (True) if True, use the Schlafly & Finkbeiner calibrations
|
|
26
|
+
load_samples= (False) if True, also load the samples
|
|
27
|
+
interpk= (1) interpolation order
|
|
28
|
+
OUTPUT:
|
|
29
|
+
object
|
|
30
|
+
HISTORY:
|
|
31
|
+
2025-10-01 - Adopted
|
|
32
|
+
"""
|
|
33
|
+
HierarchicalHealpixMap.__init__(self, filter=filter, sf10=sf10, samples=load_samples)
|
|
34
|
+
if not os.path.isdir(_decapsdir):
|
|
35
|
+
os.mkdir(_decapsdir)
|
|
36
|
+
fname = 'decaps_mean_and_samples.h5' if load_samples else 'decaps_mean.h5'
|
|
37
|
+
fpath = os.path.join(_decapsdir, fname)
|
|
38
|
+
if not os.path.exists(fpath):
|
|
39
|
+
self.download(samples=load_samples)
|
|
40
|
+
self._f = h5py.File(fpath, 'r')
|
|
41
|
+
self._best_fit = self._f['/mean'][:, 0, :]
|
|
42
|
+
p = self._f['/pixel_info']
|
|
43
|
+
hpx = p['healpix_index'][:]
|
|
44
|
+
nside_attr = int(p.attrs['nside'])
|
|
45
|
+
pix_dtype = numpy.dtype([('healpix_index', hpx.dtype), ('nside', numpy.int64)])
|
|
46
|
+
self._pix_info = numpy.empty(hpx.shape[0], dtype=pix_dtype)
|
|
47
|
+
self._pix_info['healpix_index'] = hpx
|
|
48
|
+
self._pix_info['nside'] = nside_attr
|
|
49
|
+
dm = numpy.array(p.attrs['DM_bin_edges'], dtype=numpy.float64)
|
|
50
|
+
if dm.shape[0] != self._best_fit.shape[1]:
|
|
51
|
+
raise RuntimeError("DM_bin_edges length does not match radial dimension")
|
|
52
|
+
self._distmods = dm
|
|
53
|
+
if load_samples:
|
|
54
|
+
if 'samples' not in self._f:
|
|
55
|
+
raise RuntimeError("Requested load_samples=True, but 'samples' dataset not found.")
|
|
56
|
+
self._samples_dset = self._f['/samples']
|
|
57
|
+
else:
|
|
58
|
+
self._samples_dset = None
|
|
59
|
+
self._minnside = numpy.amin(self._pix_info['nside'])
|
|
60
|
+
self._maxnside = numpy.amax(self._pix_info['nside'])
|
|
61
|
+
nlevels = int(numpy.log2(self._maxnside // self._minnside)) + 1
|
|
62
|
+
self._nsides = [self._maxnside // 2**ii for ii in range(nlevels)]
|
|
63
|
+
self._indexArray = numpy.arange(len(self._pix_info['healpix_index']))
|
|
64
|
+
self._intps = numpy.zeros(len(self._pix_info['healpix_index']), dtype='object')
|
|
65
|
+
self._interpk = interpk
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
def substitute_sample(self, samplenum):
|
|
69
|
+
"""
|
|
70
|
+
NAME:
|
|
71
|
+
substitute_sample
|
|
72
|
+
PURPOSE:
|
|
73
|
+
substitute a sample for the best fit to get the extinction from a sample with the same tools; need to have setup the instance with load_samples=True
|
|
74
|
+
INPUT:
|
|
75
|
+
samplenum - sample's index to load
|
|
76
|
+
OUTPUT:
|
|
77
|
+
(none; just resets the instance to use the sample rather than the best fit)
|
|
78
|
+
HISTORY:
|
|
79
|
+
2025-10-01 - Adopted
|
|
80
|
+
"""
|
|
81
|
+
if self._samples_dset is None:
|
|
82
|
+
raise RuntimeError('No samples present in DECaPS file')
|
|
83
|
+
self._best_fit = self._samples_dset[:, samplenum, :]
|
|
84
|
+
self._intps = numpy.zeros(len(self._pix_info['healpix_index']), dtype='object')
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
def download(cls, samples=False, test=False):
|
|
89
|
+
subdir = os.path.join(dust_dir, "decaps25")
|
|
90
|
+
if not os.path.exists(subdir):
|
|
91
|
+
os.mkdir(subdir)
|
|
92
|
+
if samples:
|
|
93
|
+
target = os.path.join(subdir, "decaps_mean_and_samples.h5")
|
|
94
|
+
url = "https://dataverse.harvard.edu/api/access/datafile/11840498"
|
|
95
|
+
else:
|
|
96
|
+
target = os.path.join(subdir, "decaps_mean.h5")
|
|
97
|
+
url = "https://dataverse.harvard.edu/api/access/datafile/11838924"
|
|
98
|
+
if not os.path.exists(target):
|
|
99
|
+
downloader(url, target, cls.__name__, test=test)
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
def __del__(self):
|
|
103
|
+
try:
|
|
104
|
+
if hasattr(self, "_f") and self._f:
|
|
105
|
+
self._f.close()
|
|
106
|
+
except Exception:
|
|
107
|
+
pass
|
|
@@ -7,18 +7,21 @@ from mwdust.Green17 import Green17
|
|
|
7
7
|
from mwdust.Green19 import Green19
|
|
8
8
|
from mwdust.Combined15 import Combined15
|
|
9
9
|
from mwdust.Combined19 import Combined19
|
|
10
|
+
from mwdust.Zucker25 import Zucker25
|
|
10
11
|
from mwdust.Zero import Zero
|
|
11
12
|
|
|
12
|
-
__version__ = "1.
|
|
13
|
+
__version__ = "1.6"
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
def download_all(test=False):
|
|
16
17
|
SFD.download(test=test)
|
|
17
18
|
Marshall06.download(test=test)
|
|
18
19
|
Drimmel03.download(test=test)
|
|
19
|
-
|
|
20
|
+
if not test:
|
|
21
|
+
Sale14.download(test=test)
|
|
20
22
|
Green15.download(test=test)
|
|
21
23
|
Green17.download(test=test)
|
|
22
24
|
Green19.download(test=test)
|
|
23
25
|
Combined15.download(test=test)
|
|
24
26
|
Combined19.download(test=test)
|
|
27
|
+
Zucker25.download(test=test)
|
|
@@ -138,9 +138,10 @@ class FortranFile(file):
|
|
|
138
138
|
data += read_data
|
|
139
139
|
|
|
140
140
|
def _read_check(self):
|
|
141
|
-
return numpy.
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
return numpy.frombuffer(
|
|
142
|
+
self._read_exactly(self._header_length),
|
|
143
|
+
dtype=self.ENDIAN + self.HEADER_PREC,
|
|
144
|
+
)[0]
|
|
144
145
|
|
|
145
146
|
def _write_check(self, number_of_bytes):
|
|
146
147
|
"""Write the header for the given number of bytes"""
|
|
@@ -205,7 +206,7 @@ class FortranFile(file):
|
|
|
205
206
|
raise ValueError('Not an appropriate precision')
|
|
206
207
|
|
|
207
208
|
data_str = self.readRecord()
|
|
208
|
-
return numpy.
|
|
209
|
+
return numpy.frombuffer(data_str, dtype=self.ENDIAN + prec)
|
|
209
210
|
|
|
210
211
|
def writeReals(self, reals, prec='f'):
|
|
211
212
|
"""Write an array of floats in given precision
|
|
@@ -240,7 +241,7 @@ class FortranFile(file):
|
|
|
240
241
|
raise ValueError('Not an appropriate precision')
|
|
241
242
|
|
|
242
243
|
data_str = self.readRecord()
|
|
243
|
-
return numpy.
|
|
244
|
+
return numpy.frombuffer(data_str, dtype=self.ENDIAN + prec)
|
|
244
245
|
|
|
245
246
|
def writeInts(self, ints, prec='i'):
|
|
246
247
|
"""Write an array of integers in given precision
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import sys
|
|
2
|
-
import
|
|
2
|
+
import sysconfig
|
|
3
3
|
import ctypes
|
|
4
4
|
import ctypes.util
|
|
5
5
|
from numpy.ctypeslib import ndpointer
|
|
@@ -7,7 +7,7 @@ import numpy as np
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
9
|
# healpy number to represent bad numbers
|
|
10
|
-
UNSEEN = -1.
|
|
10
|
+
UNSEEN = -1.6375e30
|
|
11
11
|
|
|
12
12
|
# Find and load the library
|
|
13
13
|
_lib = None
|
|
@@ -37,13 +37,18 @@ if _lib is None:
|
|
|
37
37
|
def check_nside(nside, nest=False):
|
|
38
38
|
"""
|
|
39
39
|
Utility function
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
Check if healpix map with nside is valid in general
|
|
42
42
|
"""
|
|
43
43
|
# nside can only be a power of 2 for nest, but generally less than 2**29
|
|
44
44
|
nside_arr = np.array(nside).astype(np.int64)
|
|
45
45
|
is_ok = True
|
|
46
|
-
if np.all(
|
|
46
|
+
if np.all(
|
|
47
|
+
np.logical_and(
|
|
48
|
+
np.logical_and(nside == nside_arr, np.all(np.less(0, nside))),
|
|
49
|
+
nside_arr <= 2**29,
|
|
50
|
+
)
|
|
51
|
+
):
|
|
47
52
|
if nest:
|
|
48
53
|
is_ok = (nside_arr & (nside_arr - 1)) == 0
|
|
49
54
|
else:
|
|
@@ -55,7 +60,7 @@ def check_nside(nside, nest=False):
|
|
|
55
60
|
def check_npix(npix):
|
|
56
61
|
"""
|
|
57
62
|
Utility function
|
|
58
|
-
|
|
63
|
+
|
|
59
64
|
Check if total pixel number of a healpix map are valid in general
|
|
60
65
|
"""
|
|
61
66
|
# check if npix is a valid value for healpix map size
|
|
@@ -67,7 +72,7 @@ def check_npix(npix):
|
|
|
67
72
|
def check_ipix_nside(ipix, nside):
|
|
68
73
|
"""
|
|
69
74
|
Utility function
|
|
70
|
-
|
|
75
|
+
|
|
71
76
|
Check if pixel number(s) are valid in a healpix map with nside
|
|
72
77
|
"""
|
|
73
78
|
# check if all ipix are valid for a healpix map size
|
|
@@ -144,7 +149,7 @@ def ang2pix(nside, theta, phi, nest=False, lonlat=False):
|
|
|
144
149
|
else:
|
|
145
150
|
ang2pix_c = _lib.ang2pix_nest
|
|
146
151
|
ndarrayFlags = ("C_CONTIGUOUS", "WRITEABLE")
|
|
147
|
-
|
|
152
|
+
|
|
148
153
|
ang2pix_c.argtypes = [
|
|
149
154
|
ctypes.c_long,
|
|
150
155
|
ndpointer(dtype=np.float64, flags=ndarrayFlags),
|
|
@@ -182,7 +187,7 @@ def ang2vec(theta, phi, lonlat=False):
|
|
|
182
187
|
Angular coordinates to unit 3-vector direction
|
|
183
188
|
INPUT:
|
|
184
189
|
theta - colatitude
|
|
185
|
-
phi - longitude
|
|
190
|
+
phi - longitude
|
|
186
191
|
lonlat - input in longitude and latitude (deg)?
|
|
187
192
|
OUTPUT:
|
|
188
193
|
x, y, z - unit 3-vector direction
|
|
@@ -196,7 +201,7 @@ def ang2vec(theta, phi, lonlat=False):
|
|
|
196
201
|
|
|
197
202
|
ang2vec_c = _lib.ang2vec
|
|
198
203
|
ndarrayFlags = ("C_CONTIGUOUS", "WRITEABLE")
|
|
199
|
-
|
|
204
|
+
|
|
200
205
|
ang2vec_c.argtypes = [
|
|
201
206
|
ndpointer(dtype=np.float64, flags=ndarrayFlags),
|
|
202
207
|
ndpointer(dtype=np.float64, flags=ndarrayFlags),
|
|
@@ -213,7 +218,7 @@ def ang2vec(theta, phi, lonlat=False):
|
|
|
213
218
|
phi.astype(np.float64, order="C", copy=False),
|
|
214
219
|
ctypes.c_long(nstars),
|
|
215
220
|
)
|
|
216
|
-
result = np.fromiter(res, dtype=np.float64, count=nstars*3)
|
|
221
|
+
result = np.fromiter(res, dtype=np.float64, count=nstars * 3)
|
|
217
222
|
result = result.reshape(nstars, 3)
|
|
218
223
|
|
|
219
224
|
# Reset input arrays
|
|
@@ -224,6 +229,7 @@ def ang2vec(theta, phi, lonlat=False):
|
|
|
224
229
|
|
|
225
230
|
return result
|
|
226
231
|
|
|
232
|
+
|
|
227
233
|
def pix2vec(nside, ipix, nest=False):
|
|
228
234
|
"""
|
|
229
235
|
NAME:
|
|
@@ -266,7 +272,7 @@ def pix2vec(nside, ipix, nest=False):
|
|
|
266
272
|
npix,
|
|
267
273
|
ipix.astype(np.int64, order="C", copy=False),
|
|
268
274
|
)
|
|
269
|
-
result = np.fromiter(res, dtype=np.float64, count=npix*3)
|
|
275
|
+
result = np.fromiter(res, dtype=np.float64, count=npix * 3)
|
|
270
276
|
result = result.reshape(npix, 3)
|
|
271
277
|
|
|
272
278
|
# Reset input arrays
|
|
@@ -320,7 +326,7 @@ def pix2ang(nside, ipix, nest=False, lonlat=False):
|
|
|
320
326
|
npix,
|
|
321
327
|
ipix.astype(np.int64, order="C", copy=False),
|
|
322
328
|
)
|
|
323
|
-
result = np.fromiter(res, dtype=np.float64, count=npix*2)
|
|
329
|
+
result = np.fromiter(res, dtype=np.float64, count=npix * 2)
|
|
324
330
|
result = result.reshape(npix, 2)
|
|
325
331
|
|
|
326
332
|
# Reset input arrays
|
|
@@ -348,7 +354,7 @@ def nside2pixarea(nside):
|
|
|
348
354
|
HISTORY:
|
|
349
355
|
2023-03-01 - Written - Henry Leung (Toronto)
|
|
350
356
|
"""
|
|
351
|
-
return np.pi / (3 * nside
|
|
357
|
+
return np.pi / (3 * nside**2)
|
|
352
358
|
|
|
353
359
|
|
|
354
360
|
def nside2npix(nside):
|
|
@@ -367,7 +373,15 @@ def nside2npix(nside):
|
|
|
367
373
|
return 12 * nside * nside
|
|
368
374
|
|
|
369
375
|
|
|
370
|
-
def ud_grade(
|
|
376
|
+
def ud_grade(
|
|
377
|
+
map_in,
|
|
378
|
+
nside_plot,
|
|
379
|
+
pess=False,
|
|
380
|
+
order_in="RING",
|
|
381
|
+
order_out=None,
|
|
382
|
+
power=None,
|
|
383
|
+
dtype=None,
|
|
384
|
+
):
|
|
371
385
|
"""
|
|
372
386
|
NAME:
|
|
373
387
|
dust_vals_disk
|
|
@@ -383,29 +397,33 @@ def ud_grade(map_in, nside_plot, pess=False, order_in="RING", order_out=None, po
|
|
|
383
397
|
"""
|
|
384
398
|
# check if arguements are implemented
|
|
385
399
|
if order_in != "NEST" or (order_out is not None and order_out != "NEST"):
|
|
386
|
-
raise NotImplementedError(
|
|
400
|
+
raise NotImplementedError(
|
|
401
|
+
"order_in and order_out for RING scheme is not implemented for now"
|
|
402
|
+
)
|
|
387
403
|
if power is not None:
|
|
388
404
|
raise NotImplementedError("power is not implemented for now")
|
|
389
405
|
if pess is not False:
|
|
390
406
|
raise NotImplementedError("pess=True is not implemented for now")
|
|
391
407
|
if dtype is not False:
|
|
392
|
-
raise NotImplementedError(
|
|
408
|
+
raise NotImplementedError(
|
|
409
|
+
"dtype is implemented for now, output map always has the same dtype as input map"
|
|
410
|
+
)
|
|
393
411
|
check_nside(nside_plot, nest=order_in != "RING")
|
|
394
412
|
map_in = np.asarray(map_in)
|
|
395
413
|
|
|
396
414
|
num_of_map = len(np.atleast_2d(map_in))
|
|
397
415
|
if num_of_map != 1:
|
|
398
416
|
raise ValueError("This function only support one map at each time")
|
|
399
|
-
|
|
417
|
+
|
|
400
418
|
nside_in = npix2nside(len(map_in))
|
|
401
419
|
npix_in = nside2npix(nside_in)
|
|
402
420
|
npix_out = nside2npix(nside_in)
|
|
403
421
|
|
|
404
|
-
if nside_plot > nside_in:
|
|
422
|
+
if nside_plot > nside_in: # upgrade
|
|
405
423
|
rat2 = npix_out // npix_in
|
|
406
424
|
fact = np.ones(rat2, dtype=map_in.dtype)
|
|
407
425
|
map_out = np.outer(map_in, fact).reshape(npix_out)
|
|
408
|
-
elif nside_plot < nside_in:
|
|
426
|
+
elif nside_plot < nside_in: # degrade
|
|
409
427
|
rat2 = npix_in // npix_out
|
|
410
428
|
mr = map_in.reshape(npix_out, rat2)
|
|
411
429
|
goods = ~(np.isclose(mr, UNSEEN) | (~np.isfinite(mr)) | (~np.isnan(mr)))
|
|
@@ -418,5 +436,5 @@ def ud_grade(map_in, nside_plot, pess=False, order_in="RING", order_out=None, po
|
|
|
418
436
|
pass
|
|
419
437
|
else:
|
|
420
438
|
map_out = map_in
|
|
421
|
-
|
|
422
|
-
return map_out
|
|
439
|
+
|
|
440
|
+
return map_out
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import sysconfig
|
|
3
|
+
import ctypes
|
|
4
|
+
import ctypes.util
|
|
5
|
+
from numpy.ctypeslib import ndpointer
|
|
6
|
+
import os, os.path
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
import numpy
|
|
9
|
+
import platform
|
|
10
|
+
import tqdm
|
|
11
|
+
from mwdust.util.download import dust_dir
|
|
12
|
+
|
|
13
|
+
WIN32 = platform.system() == "Windows"
|
|
14
|
+
# Find and load the library
|
|
15
|
+
_lib = None
|
|
16
|
+
_libname = ctypes.util.find_library("sfd_c")
|
|
17
|
+
PY3 = sys.version > "3"
|
|
18
|
+
if PY3: # pragma: no cover
|
|
19
|
+
_ext_suffix = sysconfig.get_config_var("EXT_SUFFIX")
|
|
20
|
+
else:
|
|
21
|
+
_ext_suffix = sysconfig.get_config_var("SO")
|
|
22
|
+
if _libname:
|
|
23
|
+
_lib = ctypes.CDLL(_libname)
|
|
24
|
+
if _lib is None:
|
|
25
|
+
# Add top-level mwdust repository directory for pip install (-e) .,
|
|
26
|
+
# just becomes site-packages for regular install
|
|
27
|
+
paths = sys.path
|
|
28
|
+
paths.append(str(Path(__file__).parent.parent.parent.absolute()))
|
|
29
|
+
for path in [Path(p) for p in paths]:
|
|
30
|
+
if not path.is_dir():
|
|
31
|
+
continue
|
|
32
|
+
try:
|
|
33
|
+
_lib = ctypes.CDLL(str(path / f"sfd_c{_ext_suffix}"))
|
|
34
|
+
except OSError:
|
|
35
|
+
_lib = None
|
|
36
|
+
else:
|
|
37
|
+
break
|
|
38
|
+
if _lib is None:
|
|
39
|
+
raise IOError("SFD/C module not found")
|
|
40
|
+
|
|
41
|
+
# MAP path names
|
|
42
|
+
ebvFileN = os.path.join(dust_dir, "maps", "SFD_dust_4096_ngp.fits")
|
|
43
|
+
ebvFileS = os.path.join(dust_dir, "maps", "SFD_dust_4096_sgp.fits")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def read_SFD_EBV(glon, glat, interp=True, noloop=False, verbose=False, pbar=True):
|
|
47
|
+
"""
|
|
48
|
+
NAME:
|
|
49
|
+
read_SFD_EBV
|
|
50
|
+
PURPOSE:
|
|
51
|
+
read an E(B-V) value from the Schlegel, Finkbeiner, & Davis (1998) maps
|
|
52
|
+
INPUT:
|
|
53
|
+
glon - Galactic longitude (deg), can be an array
|
|
54
|
+
glat - Galactic latitude (deg), can be an array
|
|
55
|
+
interp= (True) if True, interpolate using the nearest pixels
|
|
56
|
+
noloop= (False) if True, don't loop through the glons
|
|
57
|
+
verbose= (False) if True, be verbose
|
|
58
|
+
pbar= (True) if True, show progress bar
|
|
59
|
+
OUTPUT:
|
|
60
|
+
array of E(B-V) from Schlegel, Finkbeiner, & Davis (1998)
|
|
61
|
+
HISTORY:
|
|
62
|
+
2013-11-23 - Written - Bovy (IAS)
|
|
63
|
+
"""
|
|
64
|
+
# Parse input
|
|
65
|
+
if isinstance(glon, (int, float, numpy.float32, numpy.float64)):
|
|
66
|
+
glon = numpy.array([glon])
|
|
67
|
+
if isinstance(glat, (int, float, numpy.float32, numpy.float64)):
|
|
68
|
+
glat = numpy.array([glat])
|
|
69
|
+
|
|
70
|
+
nstar = len(glon)
|
|
71
|
+
if nstar > 1 and pbar:
|
|
72
|
+
pbar = tqdm.tqdm(total=nstar, leave=False)
|
|
73
|
+
pbar_func_ctype = ctypes.CFUNCTYPE(None)
|
|
74
|
+
pbar_c = pbar_func_ctype(pbar.update)
|
|
75
|
+
else: # pragma: no cover
|
|
76
|
+
pbar_c = None
|
|
77
|
+
|
|
78
|
+
# Set up the C code
|
|
79
|
+
ndarrayFlags = ("C_CONTIGUOUS", "WRITEABLE")
|
|
80
|
+
evalFunc = _lib.lambert_getval
|
|
81
|
+
evalFunc.argtypes = [
|
|
82
|
+
ctypes.c_char_p,
|
|
83
|
+
ctypes.c_char_p,
|
|
84
|
+
ctypes.c_long,
|
|
85
|
+
ndpointer(dtype=numpy.float32, flags=ndarrayFlags),
|
|
86
|
+
ndpointer(dtype=numpy.float32, flags=ndarrayFlags),
|
|
87
|
+
ctypes.c_int,
|
|
88
|
+
ctypes.c_int,
|
|
89
|
+
ctypes.c_int,
|
|
90
|
+
ndpointer(dtype=numpy.int32, flags=ndarrayFlags),
|
|
91
|
+
ctypes.c_void_p,
|
|
92
|
+
]
|
|
93
|
+
evalFunc.restype = ctypes.POINTER(ctypes.c_float)
|
|
94
|
+
|
|
95
|
+
# Array requirements, first store old order
|
|
96
|
+
f_cont = [glon.flags["F_CONTIGUOUS"], glat.flags["F_CONTIGUOUS"]]
|
|
97
|
+
glon = numpy.require(glon, dtype=numpy.float64, requirements=["C", "W"])
|
|
98
|
+
glat = numpy.require(glat, dtype=numpy.float64, requirements=["C", "W"])
|
|
99
|
+
err = numpy.require(0, dtype=numpy.int32, requirements=["C", "W"])
|
|
100
|
+
|
|
101
|
+
# Check that the filename isn't too long for the SFD code
|
|
102
|
+
if len(ebvFileN.encode("ascii")) >= 120 or len(ebvFileS.encode("ascii")) >= 120:
|
|
103
|
+
raise RuntimeError(
|
|
104
|
+
f"The path of the file that contains the SFD dust maps is too long ({len(ebvFileN.encode('ascii'))}); please shorten the path of DUST_DIR"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
res = evalFunc(
|
|
108
|
+
ctypes.c_char_p(ebvFileN.encode("ascii")),
|
|
109
|
+
ctypes.c_char_p(ebvFileS.encode("ascii")),
|
|
110
|
+
ctypes.c_long(nstar),
|
|
111
|
+
glon.astype(numpy.float32, order="C", copy=False),
|
|
112
|
+
glat.astype(numpy.float32, order="C", copy=False),
|
|
113
|
+
ctypes.c_int(interp),
|
|
114
|
+
ctypes.c_int(noloop),
|
|
115
|
+
ctypes.c_int(verbose),
|
|
116
|
+
err,
|
|
117
|
+
pbar_c,
|
|
118
|
+
)
|
|
119
|
+
if numpy.any(err == -10):
|
|
120
|
+
raise KeyboardInterrupt("Interrupted by CTRL-C (SIGINT)")
|
|
121
|
+
result = numpy.fromiter(res, dtype=float, count=nstar)
|
|
122
|
+
|
|
123
|
+
# Reset input arrays
|
|
124
|
+
if f_cont[0]:
|
|
125
|
+
glon = numpy.asfortranarray(glon)
|
|
126
|
+
if f_cont[1]:
|
|
127
|
+
glat = numpy.asfortranarray(glat)
|
|
128
|
+
|
|
129
|
+
return result
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: mwdust
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6
|
|
4
4
|
Summary: Dust in the Milky Way
|
|
5
5
|
Home-page: https://github.com/jobovy/mwdust
|
|
6
6
|
Author: Jo Bovy
|
|
@@ -24,6 +24,15 @@ Requires-Dist: h5py
|
|
|
24
24
|
Requires-Dist: tqdm
|
|
25
25
|
Requires-Dist: requests
|
|
26
26
|
Requires-Dist: healpy
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: author-email
|
|
29
|
+
Dynamic: classifier
|
|
30
|
+
Dynamic: description
|
|
31
|
+
Dynamic: home-page
|
|
32
|
+
Dynamic: license
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
Dynamic: requires-dist
|
|
35
|
+
Dynamic: summary
|
|
27
36
|
|
|
28
37
|
mwdust
|
|
29
38
|
======
|
|
@@ -98,6 +107,9 @@ roughly the following lay-out::
|
|
|
98
107
|
bayestar2017.h5
|
|
99
108
|
green19/
|
|
100
109
|
bayestar2019.h5
|
|
110
|
+
zucker25/
|
|
111
|
+
decaps_mean.h5
|
|
112
|
+
decaps_mean_and_samples.h5
|
|
101
113
|
maps/
|
|
102
114
|
SFD_dust_4096_ngp.fits
|
|
103
115
|
SFD_dust_4096_sgp.fits
|
|
@@ -238,6 +250,8 @@ map that you use:
|
|
|
238
250
|
|
|
239
251
|
* **mwdust.Green19**: `Green et al. (2019) <https://ui.adsabs.harvard.edu/abs/2019arXiv190502734G>`__ (added by `@jan-rybizki <https://github.com/jan-rybizki>`__)
|
|
240
252
|
|
|
253
|
+
* **mwdust.Zucker25**: `Zucker et al. (2025) <https://ui.adsabs.harvard.edu/abs/2025arXiv250302657Z>`__
|
|
254
|
+
|
|
241
255
|
* **mwdust.Combined15**: Combination of
|
|
242
256
|
|
|
243
257
|
* `Marshall et al. (2006) <http://adsabs.harvard.edu/abs/2006A%26A...453..635M>`__ (**mwdust.Marshall06**),
|
|
@@ -48,7 +48,7 @@ install_requires= ['numpy','scipy','matplotlib','astropy','h5py','tqdm', 'reques
|
|
|
48
48
|
if not WIN32:
|
|
49
49
|
install_requires.append('healpy')
|
|
50
50
|
setup(name='mwdust',
|
|
51
|
-
version='1.
|
|
51
|
+
version='1.6',
|
|
52
52
|
description='Dust in the Milky Way',
|
|
53
53
|
author='Jo Bovy',
|
|
54
54
|
author_email='bovy@astro.utoronto.ca',
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import pathlib
|
|
2
|
+
import numpy
|
|
3
|
+
from numpy.random import default_rng
|
|
4
|
+
|
|
5
|
+
rng = default_rng()
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_distance_independent():
|
|
9
|
+
# Test that the SFD extinction is indepdendent of distance
|
|
10
|
+
# for a given line of sight.
|
|
11
|
+
from mwdust import SFD
|
|
12
|
+
|
|
13
|
+
sfd = SFD()
|
|
14
|
+
glons = rng.uniform(0.0, 360.0, size=20)
|
|
15
|
+
glats = rng.uniform(-90.0, 90.0, size=20)
|
|
16
|
+
dists = rng.uniform(0.1, 10.0, size=5)
|
|
17
|
+
ebvs = numpy.array(
|
|
18
|
+
[
|
|
19
|
+
[sfd(glons[ii], glats[ii], dists[jj]) for ii in range(len(glons))]
|
|
20
|
+
for jj in range(len(dists))
|
|
21
|
+
]
|
|
22
|
+
).T
|
|
23
|
+
assert numpy.all(
|
|
24
|
+
numpy.fabs(ebvs - ebvs[0]) < 10.0**-10.0
|
|
25
|
+
), "SFD extinction is not independent of distance for a given line of sight"
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_against_known_values():
|
|
30
|
+
# Test that the SFD extinction without interpolation agrees with a table of known values
|
|
31
|
+
# These were computed using mwdust on an M1 mac, so this test is really
|
|
32
|
+
# of consistency between other OSs and architectures
|
|
33
|
+
from mwdust import SFD
|
|
34
|
+
|
|
35
|
+
sfd = SFD(interp=False)
|
|
36
|
+
known = numpy.loadtxt(
|
|
37
|
+
pathlib.Path(__file__).parent / "sfd_benchmark.dat", delimiter=","
|
|
38
|
+
)
|
|
39
|
+
glons = known.T[0]
|
|
40
|
+
glats = known.T[1]
|
|
41
|
+
ebvs = known.T[2]
|
|
42
|
+
assert numpy.all(
|
|
43
|
+
ebvs - [sfd(glon, glat, 1.0)[0] for glon, glat in zip(glons, glats)]
|
|
44
|
+
< 10.0**-7.0
|
|
45
|
+
), f"SFD extinction without interpolation does not agree with known values, with max difference {numpy.amax(numpy.fabs(ebvs-numpy.array([sfd(glon,glat,1.)[0] for glon,glat in zip(glons,glats)])))}"
|
|
46
|
+
|
|
47
|
+
# Test that the SFD extinction with interpolation agrees with a table of known values
|
|
48
|
+
# These were computed using mwdust on a linux server, same cavert above
|
|
49
|
+
from mwdust import SFD
|
|
50
|
+
|
|
51
|
+
sfd = SFD()
|
|
52
|
+
# specifically contains lb = (30, 3), a previously known inconsistency between Linux and Windows
|
|
53
|
+
known = numpy.loadtxt(
|
|
54
|
+
pathlib.Path(__file__).parent / "sfd_mwdust12_linux_benchmark.dat",
|
|
55
|
+
delimiter=",",
|
|
56
|
+
)
|
|
57
|
+
glons = known.T[0]
|
|
58
|
+
glats = known.T[1]
|
|
59
|
+
ebvs = known.T[2]
|
|
60
|
+
assert numpy.all(
|
|
61
|
+
ebvs - [sfd(glon, glat, 1.0)[0] for glon, glat in zip(glons, glats)]
|
|
62
|
+
< 10.0**-7.0
|
|
63
|
+
), f"SFD extinction does not agree with known values, with max difference {numpy.amax(numpy.fabs(ebvs-numpy.array([sfd(glon,glat,1.)[0] for glon,glat in zip(glons,glats)])))}"
|
|
64
|
+
return None
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
import distutils.sysconfig as sysconfig
|
|
3
|
-
import ctypes
|
|
4
|
-
import ctypes.util
|
|
5
|
-
from numpy.ctypeslib import ndpointer
|
|
6
|
-
import os, os.path
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
import numpy
|
|
9
|
-
import platform
|
|
10
|
-
import tqdm
|
|
11
|
-
from mwdust.util.download import dust_dir
|
|
12
|
-
|
|
13
|
-
WIN32= platform.system() == 'Windows'
|
|
14
|
-
#Find and load the library
|
|
15
|
-
_lib = None
|
|
16
|
-
_libname = ctypes.util.find_library('sfd_c')
|
|
17
|
-
PY3= sys.version > '3'
|
|
18
|
-
if PY3: #pragma: no cover
|
|
19
|
-
_ext_suffix= sysconfig.get_config_var('EXT_SUFFIX')
|
|
20
|
-
else:
|
|
21
|
-
_ext_suffix= sysconfig.get_config_var('SO')
|
|
22
|
-
if _libname:
|
|
23
|
-
_lib = ctypes.CDLL(_libname)
|
|
24
|
-
if _lib is None:
|
|
25
|
-
# Add top-level mwdust repository directory for pip install (-e) .,
|
|
26
|
-
# just becomes site-packages for regular install
|
|
27
|
-
paths = sys.path
|
|
28
|
-
paths.append(str(Path(__file__).parent.parent.parent.absolute()))
|
|
29
|
-
for path in [Path(p) for p in paths]:
|
|
30
|
-
if not path.is_dir():
|
|
31
|
-
continue
|
|
32
|
-
try:
|
|
33
|
-
_lib = ctypes.CDLL(str(path / f"sfd_c{_ext_suffix}"))
|
|
34
|
-
except OSError:
|
|
35
|
-
_lib = None
|
|
36
|
-
else:
|
|
37
|
-
break
|
|
38
|
-
if _lib is None:
|
|
39
|
-
raise IOError('SFD/C module not found')
|
|
40
|
-
|
|
41
|
-
#MAP path names
|
|
42
|
-
ebvFileN= os.path.join(dust_dir,'maps','SFD_dust_4096_ngp.fits')
|
|
43
|
-
ebvFileS= os.path.join(dust_dir,'maps','SFD_dust_4096_sgp.fits')
|
|
44
|
-
|
|
45
|
-
def read_SFD_EBV(glon,glat,interp=True,noloop=False,verbose=False,pbar=True):
|
|
46
|
-
"""
|
|
47
|
-
NAME:
|
|
48
|
-
read_SFD_EBV
|
|
49
|
-
PURPOSE:
|
|
50
|
-
read an E(B-V) value from the Schlegel, Finkbeiner, & Davis (1998) maps
|
|
51
|
-
INPUT:
|
|
52
|
-
glon - Galactic longitude (deg), can be an array
|
|
53
|
-
glat - Galactic latitude (deg), can be an array
|
|
54
|
-
interp= (True) if True, interpolate using the nearest pixels
|
|
55
|
-
noloop= (False) if True, don't loop through the glons
|
|
56
|
-
verbose= (False) if True, be verbose
|
|
57
|
-
pbar= (True) if True, show progress bar
|
|
58
|
-
OUTPUT:
|
|
59
|
-
array of E(B-V) from Schlegel, Finkbeiner, & Davis (1998)
|
|
60
|
-
HISTORY:
|
|
61
|
-
2013-11-23 - Written - Bovy (IAS)
|
|
62
|
-
"""
|
|
63
|
-
#Parse input
|
|
64
|
-
if isinstance(glon,(int,float,numpy.float32,numpy.float64)):
|
|
65
|
-
glon= numpy.array([glon])
|
|
66
|
-
if isinstance(glat,(int,float,numpy.float32,numpy.float64)):
|
|
67
|
-
glat= numpy.array([glat])
|
|
68
|
-
|
|
69
|
-
nstar = len(glon)
|
|
70
|
-
if nstar > 1 and pbar:
|
|
71
|
-
pbar= tqdm.tqdm(total=nstar, leave=False)
|
|
72
|
-
pbar_func_ctype= ctypes.CFUNCTYPE(None)
|
|
73
|
-
pbar_c= pbar_func_ctype(pbar.update)
|
|
74
|
-
else: # pragma: no cover
|
|
75
|
-
pbar_c= None
|
|
76
|
-
|
|
77
|
-
#Set up the C code
|
|
78
|
-
ndarrayFlags= ('C_CONTIGUOUS','WRITEABLE')
|
|
79
|
-
evalFunc= _lib.lambert_getval
|
|
80
|
-
evalFunc.argtypes= [ctypes.c_char_p,
|
|
81
|
-
ctypes.c_char_p,
|
|
82
|
-
ctypes.c_long,
|
|
83
|
-
ndpointer(dtype=numpy.float32,flags=ndarrayFlags),
|
|
84
|
-
ndpointer(dtype=numpy.float32,flags=ndarrayFlags),
|
|
85
|
-
ctypes.c_int,
|
|
86
|
-
ctypes.c_int,
|
|
87
|
-
ctypes.c_int,
|
|
88
|
-
ndpointer(dtype=numpy.int32,flags=ndarrayFlags),
|
|
89
|
-
ctypes.c_void_p]
|
|
90
|
-
evalFunc.restype= ctypes.POINTER(ctypes.c_float)
|
|
91
|
-
|
|
92
|
-
#Array requirements, first store old order
|
|
93
|
-
f_cont= [glon.flags['F_CONTIGUOUS'],
|
|
94
|
-
glat.flags['F_CONTIGUOUS']]
|
|
95
|
-
glon= numpy.require(glon,dtype=numpy.float64,requirements=['C','W'])
|
|
96
|
-
glat= numpy.require(glat,dtype=numpy.float64,requirements=['C','W'])
|
|
97
|
-
err= numpy.require(0,dtype=numpy.int32,requirements=['C','W'])
|
|
98
|
-
|
|
99
|
-
# Check that the filename isn't too long for the SFD code
|
|
100
|
-
if len(ebvFileN.encode('ascii')) >= 120 \
|
|
101
|
-
or len(ebvFileS.encode('ascii')) >= 120:
|
|
102
|
-
raise RuntimeError(f"The path of the file that contains the SFD dust maps is too long ({len(ebvFileN.encode('ascii'))}); please shorten the path of DUST_DIR")
|
|
103
|
-
|
|
104
|
-
res= evalFunc(ctypes.c_char_p(ebvFileN.encode('ascii')),
|
|
105
|
-
ctypes.c_char_p(ebvFileS.encode('ascii')),
|
|
106
|
-
ctypes.c_long(nstar),
|
|
107
|
-
glon.astype(numpy.float32,order='C',copy=False),
|
|
108
|
-
glat.astype(numpy.float32,order='C',copy=False),
|
|
109
|
-
ctypes.c_int(interp),
|
|
110
|
-
ctypes.c_int(noloop),
|
|
111
|
-
ctypes.c_int(verbose),
|
|
112
|
-
err,
|
|
113
|
-
pbar_c
|
|
114
|
-
)
|
|
115
|
-
if numpy.any(err == -10):
|
|
116
|
-
raise KeyboardInterrupt("Interrupted by CTRL-C (SIGINT)")
|
|
117
|
-
result= numpy.fromiter(res,dtype=float,count=nstar)
|
|
118
|
-
|
|
119
|
-
#Reset input arrays
|
|
120
|
-
if f_cont[0]: glon= numpy.asfortranarray(glon)
|
|
121
|
-
if f_cont[1]: glat= numpy.asfortranarray(glat)
|
|
122
|
-
|
|
123
|
-
return result
|
mwdust-1.5/tests/test_sfd.py
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import pathlib
|
|
2
|
-
import numpy
|
|
3
|
-
from numpy.random import default_rng
|
|
4
|
-
rng= default_rng()
|
|
5
|
-
|
|
6
|
-
def test_distance_independent():
|
|
7
|
-
# Test that the SFD extinction is indepdendent of distance
|
|
8
|
-
# for a given line of sight.
|
|
9
|
-
from mwdust import SFD
|
|
10
|
-
sfd= SFD()
|
|
11
|
-
glons= rng.uniform(0.,360.,size=20)
|
|
12
|
-
glats= rng.uniform(-90.,90.,size=20)
|
|
13
|
-
dists= rng.uniform(0.1,10.,size=5)
|
|
14
|
-
ebvs= numpy.array([[sfd(glons[ii],glats[ii],dists[jj]) \
|
|
15
|
-
for ii in range(len(glons))]
|
|
16
|
-
for jj in range(len(dists))]).T
|
|
17
|
-
assert numpy.all(numpy.fabs(ebvs-ebvs[0]) < 10.**-10.), \
|
|
18
|
-
'SFD extinction is not independent of distance for a given line of sight'
|
|
19
|
-
return None
|
|
20
|
-
|
|
21
|
-
def test_against_known_values():
|
|
22
|
-
# Test that the SFD extinction without interpolation agrees with a table of known values
|
|
23
|
-
# These were computed using mwdust on an M1 mac, so this test is really
|
|
24
|
-
# of consistency between other OSs and architectures
|
|
25
|
-
from mwdust import SFD
|
|
26
|
-
sfd= SFD(interp=False)
|
|
27
|
-
known= numpy.loadtxt(pathlib.Path(__file__).parent / 'sfd_benchmark.dat',delimiter=',')
|
|
28
|
-
glons= known.T[0]
|
|
29
|
-
glats= known.T[1]
|
|
30
|
-
ebvs= known.T[2]
|
|
31
|
-
assert numpy.all(ebvs-[sfd(glon,glat,1.)[0]
|
|
32
|
-
for glon,glat in zip(glons,glats)] < 10.**-8.), \
|
|
33
|
-
'SFD extinction without interpolation does not agree with known values'
|
|
34
|
-
|
|
35
|
-
# Test that the SFD extinction with interpolation agrees with a table of known values
|
|
36
|
-
# These were computed using mwdust on a linux server, same cavert above
|
|
37
|
-
from mwdust import SFD
|
|
38
|
-
sfd= SFD()
|
|
39
|
-
# specifically contains lb = (30, 3), a previously known inconsistency between Linux and Windows
|
|
40
|
-
known= numpy.loadtxt(pathlib.Path(__file__).parent / 'sfd_mwdust12_linux_benchmark.dat',delimiter=',')
|
|
41
|
-
glons= known.T[0]
|
|
42
|
-
glats= known.T[1]
|
|
43
|
-
ebvs= known.T[2]
|
|
44
|
-
assert numpy.all(ebvs-[sfd(glon,glat,1.)[0]
|
|
45
|
-
for glon,glat in zip(glons,glats)] < 10.**-8.), \
|
|
46
|
-
'SFD extinction does not agree with known values'
|
|
47
|
-
return None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|