xdust 1.0__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.
- xdust-1.0/LICENSE +25 -0
- xdust-1.0/PKG-INFO +68 -0
- xdust-1.0/README.md +43 -0
- xdust-1.0/pyproject.toml +43 -0
- xdust-1.0/setup.cfg +4 -0
- xdust-1.0/setup.py +5 -0
- xdust-1.0/src/xdust/__init__.py +5 -0
- xdust-1.0/src/xdust/graindist/__init__.py +6 -0
- xdust-1.0/src/xdust/graindist/composition/__init__.py +165 -0
- xdust-1.0/src/xdust/graindist/composition/cmdrude.py +72 -0
- xdust-1.0/src/xdust/graindist/composition/cmgraphite.py +61 -0
- xdust-1.0/src/xdust/graindist/composition/cmsilicate.py +32 -0
- xdust-1.0/src/xdust/graindist/composition/minerals.py +91 -0
- xdust-1.0/src/xdust/graindist/graindist.py +190 -0
- xdust-1.0/src/xdust/graindist/shape/__init__.py +42 -0
- xdust-1.0/src/xdust/graindist/shape/sphere.py +54 -0
- xdust-1.0/src/xdust/graindist/sizedist/__init__.py +85 -0
- xdust-1.0/src/xdust/graindist/sizedist/astrodust.py +137 -0
- xdust-1.0/src/xdust/graindist/sizedist/exp_cutoff.py +130 -0
- xdust-1.0/src/xdust/graindist/sizedist/grain.py +74 -0
- xdust-1.0/src/xdust/graindist/sizedist/powerlaw.py +126 -0
- xdust-1.0/src/xdust/graindist/sizedist/weingartner.py +366 -0
- xdust-1.0/src/xdust/graindist/tables/PAHion_30 +36129 -0
- xdust-1.0/src/xdust/graindist/tables/PAHneu_30 +36129 -0
- xdust-1.0/src/xdust/graindist/tables/Table1.WD.dat +22 -0
- xdust-1.0/src/xdust/graindist/tables/Table3_LMC2.WD.dat +10 -0
- xdust-1.0/src/xdust/graindist/tables/Table3_LMCavg.WD.dat +9 -0
- xdust-1.0/src/xdust/graindist/tables/Table3_SMC.WD.dat +7 -0
- xdust-1.0/src/xdust/graindist/tables/callindex.out_CpaD03_0.01 +391 -0
- xdust-1.0/src/xdust/graindist/tables/callindex.out_CpaD03_0.10 +391 -0
- xdust-1.0/src/xdust/graindist/tables/callindex.out_CpeD03_0.01 +388 -0
- xdust-1.0/src/xdust/graindist/tables/callindex.out_CpeD03_0.10 +388 -0
- xdust-1.0/src/xdust/graindist/tables/callindex.out_sil.D03 +842 -0
- xdust-1.0/src/xdust/grainpop.py +587 -0
- xdust-1.0/src/xdust/halos/__init__.py +2 -0
- xdust-1.0/src/xdust/halos/galhalo.py +605 -0
- xdust-1.0/src/xdust/halos/halo.py +449 -0
- xdust-1.0/src/xdust/helpers.py +103 -0
- xdust-1.0/src/xdust/scatteringmodel/__init__.py +247 -0
- xdust-1.0/src/xdust/scatteringmodel/ggadt.py +21 -0
- xdust-1.0/src/xdust/scatteringmodel/make_ggadt.py +243 -0
- xdust-1.0/src/xdust/scatteringmodel/make_ggadt_astrodust.py +157 -0
- xdust-1.0/src/xdust/scatteringmodel/miescat.py +340 -0
- xdust-1.0/src/xdust/scatteringmodel/pah.py +182 -0
- xdust-1.0/src/xdust/scatteringmodel/rgscat.py +131 -0
- xdust-1.0/src/xdust.egg-info/PKG-INFO +68 -0
- xdust-1.0/src/xdust.egg-info/SOURCES.txt +57 -0
- xdust-1.0/src/xdust.egg-info/dependency_links.txt +1 -0
- xdust-1.0/src/xdust.egg-info/requires.txt +14 -0
- xdust-1.0/src/xdust.egg-info/top_level.txt +1 -0
- xdust-1.0/tests/test_cmindex.py +58 -0
- xdust-1.0/tests/test_galhalo.py +169 -0
- xdust-1.0/tests/test_ggadt_file.py +149 -0
- xdust-1.0/tests/test_graindist.py +73 -0
- xdust-1.0/tests/test_grainpop.py +168 -0
- xdust-1.0/tests/test_inits.py +36 -0
- xdust-1.0/tests/test_scatmodels.py +162 -0
- xdust-1.0/tests/test_shape.py +18 -0
- xdust-1.0/tests/test_sizedist.py +66 -0
xdust-1.0/LICENSE
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
BSD 2-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017, Lia Corrales
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
17
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
18
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
19
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
20
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
21
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
22
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
23
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
24
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
25
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
xdust-1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xdust
|
|
3
|
+
Version: 1.0
|
|
4
|
+
Summary: Library of dust scattering codes
|
|
5
|
+
Author-email: Lia Corrales <liac@umich.edu>
|
|
6
|
+
License: BSD 2-clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/eblur/xdust
|
|
8
|
+
Project-URL: Documentation, https://eblur.github.io/xdust
|
|
9
|
+
Requires-Python: >=3.7
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: numpy
|
|
13
|
+
Requires-Dist: astropy
|
|
14
|
+
Requires-Dist: scipy
|
|
15
|
+
Requires-Dist: matplotlib
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
18
|
+
Provides-Extra: docs
|
|
19
|
+
Requires-Dist: sphinx>=7.0; extra == "docs"
|
|
20
|
+
Requires-Dist: furo; extra == "docs"
|
|
21
|
+
Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
|
|
22
|
+
Requires-Dist: sphinx-autobuild; extra == "docs"
|
|
23
|
+
Requires-Dist: myst-nb; extra == "docs"
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# Xdust
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
*Previously eblur/newdust*
|
|
30
|
+
|
|
31
|
+
[](https://doi.org/10.5281/zenodo.7500048)
|
|
32
|
+
|
|
33
|
+
This package calculates extinction curves and small-angle scattering halos from a user-defined dust grain size distribution. It calculates scattering and absorption from first principles (optical constants of the material, Mie or Rayleigh-Gans scattering).
|
|
34
|
+
|
|
35
|
+
**Updated 2026.06** to by installable via PyPI and documented with Sphinx
|
|
36
|
+
|
|
37
|
+
**Documentation:** https://eblur.github.io/xdust
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
### Typical installation
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
pip install xdust
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### For developers
|
|
48
|
+
|
|
49
|
+
If you need to stay up to date with development versions of xdust, use:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
git clone https://github.com/eblur/xdust.git
|
|
53
|
+
|
|
54
|
+
cd xdust
|
|
55
|
+
|
|
56
|
+
pip install -e .
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## To invoke:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
import xdust
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## How to use:
|
|
66
|
+
|
|
67
|
+
See the jupyter notebooks in **examples/**
|
|
68
|
+
for examples of setting up grain populations and modeling scattering halos from Galactic dust.
|
xdust-1.0/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Xdust
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
*Previously eblur/newdust*
|
|
5
|
+
|
|
6
|
+
[](https://doi.org/10.5281/zenodo.7500048)
|
|
7
|
+
|
|
8
|
+
This package calculates extinction curves and small-angle scattering halos from a user-defined dust grain size distribution. It calculates scattering and absorption from first principles (optical constants of the material, Mie or Rayleigh-Gans scattering).
|
|
9
|
+
|
|
10
|
+
**Updated 2026.06** to by installable via PyPI and documented with Sphinx
|
|
11
|
+
|
|
12
|
+
**Documentation:** https://eblur.github.io/xdust
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### Typical installation
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
pip install xdust
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### For developers
|
|
23
|
+
|
|
24
|
+
If you need to stay up to date with development versions of xdust, use:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
git clone https://github.com/eblur/xdust.git
|
|
28
|
+
|
|
29
|
+
cd xdust
|
|
30
|
+
|
|
31
|
+
pip install -e .
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## To invoke:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
import xdust
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## How to use:
|
|
41
|
+
|
|
42
|
+
See the jupyter notebooks in **examples/**
|
|
43
|
+
for examples of setting up grain populations and modeling scattering halos from Galactic dust.
|
xdust-1.0/pyproject.toml
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "xdust"
|
|
7
|
+
version = "1.0"
|
|
8
|
+
description = "Library of dust scattering codes"
|
|
9
|
+
authors = [
|
|
10
|
+
{ name = "Lia Corrales", email = "liac@umich.edu" }
|
|
11
|
+
]
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
license = { text = "BSD 2-clause" }
|
|
14
|
+
requires-python = ">=3.7"
|
|
15
|
+
dependencies = [
|
|
16
|
+
"numpy",
|
|
17
|
+
"astropy",
|
|
18
|
+
"scipy",
|
|
19
|
+
"matplotlib"
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
dev = ["pytest>=7.0"]
|
|
24
|
+
docs = [
|
|
25
|
+
"sphinx>=7.0",
|
|
26
|
+
"furo",
|
|
27
|
+
"sphinx-autodoc-typehints",
|
|
28
|
+
"sphinx-autobuild",
|
|
29
|
+
"myst-nb"
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Homepage = "https://github.com/eblur/xdust"
|
|
34
|
+
Documentation = "https://eblur.github.io/xdust"
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.packages.find]
|
|
37
|
+
where = ["src"]
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.package-data]
|
|
40
|
+
xdust = [
|
|
41
|
+
"graindist/tables/*",
|
|
42
|
+
"scatteringmodel/tables/*",
|
|
43
|
+
]
|
xdust-1.0/setup.cfg
ADDED
xdust-1.0/setup.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import numpy as np
|
|
3
|
+
import astropy.units as u
|
|
4
|
+
|
|
5
|
+
GTYPES = ['Graphite', 'Silicate', 'Drude']
|
|
6
|
+
|
|
7
|
+
def _find_cmfile(name):
|
|
8
|
+
root_path = os.path.dirname(__file__).rstrip('composition')
|
|
9
|
+
data_path = root_path + 'tables/'
|
|
10
|
+
return data_path + name
|
|
11
|
+
|
|
12
|
+
class Composition(object):
|
|
13
|
+
"""
|
|
14
|
+
Composition class for storing information about grain material
|
|
15
|
+
|
|
16
|
+
Attributes
|
|
17
|
+
----------
|
|
18
|
+
cmtype : str
|
|
19
|
+
Label for the compound.
|
|
20
|
+
|
|
21
|
+
rho : float
|
|
22
|
+
Density of the material [g cm^-3].
|
|
23
|
+
|
|
24
|
+
citation : str
|
|
25
|
+
Citation for the optical constants loaded.
|
|
26
|
+
|
|
27
|
+
wavel : astropy.units.Quantity
|
|
28
|
+
Wavelength grid for optical constants.
|
|
29
|
+
|
|
30
|
+
revals : numpy.ndarray
|
|
31
|
+
Real part of the complex index of refraction.
|
|
32
|
+
|
|
33
|
+
imvals : numpy.ndarray
|
|
34
|
+
Imaginary part of the complex index of refraction.
|
|
35
|
+
"""
|
|
36
|
+
def __init__(self):
|
|
37
|
+
self.cmtype = None
|
|
38
|
+
self.rho = None
|
|
39
|
+
self.citation = None
|
|
40
|
+
self.wavel = None
|
|
41
|
+
self.revals = 1.0
|
|
42
|
+
self.imvals = 0.0
|
|
43
|
+
|
|
44
|
+
def rp(self, x):
|
|
45
|
+
"""
|
|
46
|
+
Interpolate over the input wavelength grid to get the real part of the
|
|
47
|
+
complex index of refraction.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
x : astropy.units.Quantity or numpy.ndarray
|
|
52
|
+
Wavelength or energy; if an ``astropy.units.Quantity``, converted to
|
|
53
|
+
the same units as ``self.wavel``; if a plain array, keV units are assumed.
|
|
54
|
+
|
|
55
|
+
Returns
|
|
56
|
+
-------
|
|
57
|
+
numpy.ndarray
|
|
58
|
+
``np.interp(x, self.wavel, self.revals, left=1.0, right=1.0)``
|
|
59
|
+
"""
|
|
60
|
+
# If the input is an astropy quantity, convert it to the same unit as wavel
|
|
61
|
+
if isinstance(x, u.Quantity):
|
|
62
|
+
new_x = x.to(self.wavel.unit, equivalencies=u.spectral()).value
|
|
63
|
+
# Otherwise, assume the unit is keV
|
|
64
|
+
else:
|
|
65
|
+
new_x = (x * u.keV).to(self.wavel.unit, equivalencies=u.spectral()).value
|
|
66
|
+
return np.interp(new_x, self.wavel.value, self.revals, left=1.0, right=1.0)
|
|
67
|
+
|
|
68
|
+
def ip(self, x):
|
|
69
|
+
"""
|
|
70
|
+
Interpolate over the input wavelength grid to get the imaginary part of the
|
|
71
|
+
complex index of refraction.
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
x : astropy.units.Quantity or numpy.ndarray
|
|
76
|
+
Wavelength or energy; if an ``astropy.units.Quantity``, converted to
|
|
77
|
+
the same units as ``self.wavel``; if a plain array, keV units are assumed.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
numpy.ndarray
|
|
82
|
+
``np.interp(x, self.wavel, self.imvals, left=0.0, right=0.0)``
|
|
83
|
+
"""
|
|
84
|
+
# If the input is an astropy quantity, convert it to the same unit as wavel
|
|
85
|
+
if isinstance(x, u.Quantity):
|
|
86
|
+
new_x = x.to(self.wavel.unit, equivalencies=u.spectral()).value
|
|
87
|
+
# Otherwise, assume the unit is keV
|
|
88
|
+
else:
|
|
89
|
+
new_x = (x * u.keV).to(self.wavel.unit, equivalencies=u.spectral()).value
|
|
90
|
+
return np.interp(new_x, self.wavel.value, self.imvals, left=0.0, right=0.0)
|
|
91
|
+
|
|
92
|
+
def cm(self, x):
|
|
93
|
+
"""
|
|
94
|
+
Returns the complex index of refraction using Python complex numbers
|
|
95
|
+
|
|
96
|
+
Parameters
|
|
97
|
+
----------
|
|
98
|
+
x : astropy.units.Quantity or numpy.ndarray
|
|
99
|
+
Wavelength or energy; if an ``astropy.units.Quantity``, converted to
|
|
100
|
+
the same units as ``self.wavel``; if a plain array, keV units are assumed.
|
|
101
|
+
|
|
102
|
+
Returns
|
|
103
|
+
-------
|
|
104
|
+
complex or numpy.ndarray of complex
|
|
105
|
+
Complex index of refraction :math:`n = n_r + i n_i`.
|
|
106
|
+
"""
|
|
107
|
+
return self.rp(x) + 1j * self.ip(x)
|
|
108
|
+
|
|
109
|
+
def plot(self, ax, lam=None, rppart=True, impart=True, xunit=None, label=''):
|
|
110
|
+
"""
|
|
111
|
+
Plots the different parts of the complex index of refraction on a matplotlib axis
|
|
112
|
+
|
|
113
|
+
Parameters
|
|
114
|
+
----------
|
|
115
|
+
ax : matplotlib.pyplot.Axes
|
|
116
|
+
The axes on which to plot.
|
|
117
|
+
|
|
118
|
+
lam : astropy.units.Quantity or numpy.ndarray, optional
|
|
119
|
+
If ``None``, plots using the default ``self.wavel`` grid; otherwise
|
|
120
|
+
interpolates onto the provided grid. Plain arrays are assumed to be
|
|
121
|
+
in keV.
|
|
122
|
+
|
|
123
|
+
rppart : bool
|
|
124
|
+
If ``True`` (default), plot the real part :math:`|Re(m)-1|`.
|
|
125
|
+
|
|
126
|
+
impart : bool
|
|
127
|
+
If ``True`` (default), plot the imaginary part :math:`Im(m)`.
|
|
128
|
+
|
|
129
|
+
xunit : str, optional
|
|
130
|
+
Unit string for the x-axis. Defaults to ``self.wavel.unit``.
|
|
131
|
+
|
|
132
|
+
label : str
|
|
133
|
+
Prefix string appended to legend labels.
|
|
134
|
+
"""
|
|
135
|
+
if xunit is None:
|
|
136
|
+
xunit = self.wavel.unit
|
|
137
|
+
# If no grid specified, plot the default one
|
|
138
|
+
if lam is None:
|
|
139
|
+
rp_m1 = np.abs(self.revals - 1.0)
|
|
140
|
+
ip = self.imvals
|
|
141
|
+
x = self.wavel.to(xunit, equivalencies=u.spectral()).value
|
|
142
|
+
# Else, plot the interpolated values
|
|
143
|
+
else:
|
|
144
|
+
rp_m1 = np.abs(self.rp(lam)-1.0)
|
|
145
|
+
ip = self.ip(lam)
|
|
146
|
+
# Check if the input value had units
|
|
147
|
+
if isinstance(lam, u.Quantity):
|
|
148
|
+
x = lam.to(xunit, equivalencies=u.spectral()).value
|
|
149
|
+
# If not, assume keV units
|
|
150
|
+
else:
|
|
151
|
+
x = (lam * u.keV).to(xunit, equivalencies=u.spectral()).value
|
|
152
|
+
# If the user wants to plot Real Part
|
|
153
|
+
if rppart:
|
|
154
|
+
ax.plot(x, rp_m1, ls='-', label='{} |Re(m-1)|'.format(label))
|
|
155
|
+
# If the user wants to plot Imaginary Part
|
|
156
|
+
if impart:
|
|
157
|
+
ax.plot(x, ip, ls='--', label='{} Im(m)'.format(label))
|
|
158
|
+
ax.set_xlabel(xunit)
|
|
159
|
+
ax.legend()
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
from .cmdrude import CmDrude
|
|
164
|
+
from .cmsilicate import CmSilicate
|
|
165
|
+
from .cmgraphite import CmGraphite
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import astropy.units as u
|
|
3
|
+
import astropy.constants as c
|
|
4
|
+
|
|
5
|
+
from . import Composition
|
|
6
|
+
|
|
7
|
+
__all__ = ['CmDrude']
|
|
8
|
+
|
|
9
|
+
RHO_DRUDE = 3.0 # g cm^-3
|
|
10
|
+
|
|
11
|
+
## -- Some constants to use for the calculation
|
|
12
|
+
# Classical electron radius
|
|
13
|
+
RE_CM = 2.8179403227e-15 * u.m.to('cm')
|
|
14
|
+
# Mass of proton
|
|
15
|
+
MP_G = c.m_p.to('g').value
|
|
16
|
+
|
|
17
|
+
class CmDrude(Composition):
|
|
18
|
+
"""
|
|
19
|
+
Optical constants under the Drude approximation.
|
|
20
|
+
"""
|
|
21
|
+
def __init__(self, rho=RHO_DRUDE): # Returns a CM using the Drude approximation
|
|
22
|
+
Composition.__init__(self)
|
|
23
|
+
self.cmtype = 'Drude'
|
|
24
|
+
self.rho = rho
|
|
25
|
+
self.citation = "Using the Drude approximation.\nBohren, C. F. & Huffman, D. R., 1983, Absorption and Scattering of Light by Small Particles (New York: Wiley)"
|
|
26
|
+
|
|
27
|
+
# Set up default values so that inherited plotting method from Composition will work
|
|
28
|
+
self.wavel = np.linspace(1.0, 10.0, 50) * u.keV
|
|
29
|
+
self.revals = self.rp(self.wavel)
|
|
30
|
+
self.imvals = self.ip(self.wavel)
|
|
31
|
+
|
|
32
|
+
def rp(self, x):
|
|
33
|
+
"""
|
|
34
|
+
Calculate the real part of the complex index of refraction under the Drude approximation.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
x : astropy.units.Quantity or numpy.ndarray
|
|
39
|
+
Wavelength or energy; plain arrays are assumed to be in keV.
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
numpy.ndarray
|
|
44
|
+
:math:`1 + (\\rho / 2 m_p)(r_e / 2\\pi)\\lambda^2`
|
|
45
|
+
"""
|
|
46
|
+
if isinstance(x, u.Quantity):
|
|
47
|
+
lam_cm = x.to('cm', equivalencies=u.spectral()).value
|
|
48
|
+
else:
|
|
49
|
+
lam_cm = (x * u.keV).to('cm', equivalencies=u.spectral()).value
|
|
50
|
+
|
|
51
|
+
mm1 = self.rho / (2.0*MP_G) * RE_CM/(2.0*np.pi) * np.power(lam_cm, 2)
|
|
52
|
+
return mm1 + 1.0
|
|
53
|
+
|
|
54
|
+
def ip(self, x):
|
|
55
|
+
"""
|
|
56
|
+
Gives the imaginary part of the complex index of refraction under the Drude approximation.
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
x : astropy.units.Quantity or numpy.ndarray
|
|
61
|
+
Wavelength or energy; plain arrays are assumed to be in keV.
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
-------
|
|
65
|
+
float or numpy.ndarray
|
|
66
|
+
``0.0`` for scalar input; array of zeros matching the length of ``x``
|
|
67
|
+
for array input.
|
|
68
|
+
"""
|
|
69
|
+
if np.size(x) > 1:
|
|
70
|
+
return np.zeros(np.size(x))
|
|
71
|
+
else:
|
|
72
|
+
return 0.0
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from astropy.io import ascii
|
|
3
|
+
from astropy import units as u
|
|
4
|
+
|
|
5
|
+
from . import _find_cmfile
|
|
6
|
+
from . import Composition
|
|
7
|
+
|
|
8
|
+
__all__ = ['CmGraphite']
|
|
9
|
+
|
|
10
|
+
RHO_GRA = 2.2 # g cm^-3
|
|
11
|
+
|
|
12
|
+
class CmGraphite(Composition):
|
|
13
|
+
"""
|
|
14
|
+
Optical constants for Graphite from
|
|
15
|
+
`Draine (2003), ApJ 598, 1026 <http://adsabs.harvard.edu/abs/2003ApJ...598.1026D>`_
|
|
16
|
+
|
|
17
|
+
Attributes
|
|
18
|
+
----------
|
|
19
|
+
size : str
|
|
20
|
+
``'big'`` gives results for 0.1 um sized graphite grains at 20 K;
|
|
21
|
+
``'small'`` gives results for 0.01 um sized grains at 20 K.
|
|
22
|
+
|
|
23
|
+
orient : str
|
|
24
|
+
``'perp'`` gives results for E-field perpendicular to the c-axis;
|
|
25
|
+
``'para'`` gives results for E-field parallel to the c-axis.
|
|
26
|
+
"""
|
|
27
|
+
def __init__(self, rho=RHO_GRA, size='big', orient='perp'):
|
|
28
|
+
Composition.__init__(self)
|
|
29
|
+
self.cmtype = 'Graphite'
|
|
30
|
+
self.rho = rho
|
|
31
|
+
self.citation = "Using optical constants for graphite,\nDraine, B. T. 2003, ApJ, 598, 1026\nhttp://adsabs.harvard.edu/abs/2003ApJ...598.1026D"
|
|
32
|
+
# Additional info not in default class
|
|
33
|
+
self.size = size
|
|
34
|
+
self.orient = orient
|
|
35
|
+
|
|
36
|
+
# Populate the wavelength and optical constants info
|
|
37
|
+
if size == 'big':
|
|
38
|
+
D03file_para = _find_cmfile('callindex.out_CpaD03_0.10')
|
|
39
|
+
D03file_perp = _find_cmfile('callindex.out_CpeD03_0.10')
|
|
40
|
+
if size == 'small':
|
|
41
|
+
D03file_para = _find_cmfile('callindex.out_CpaD03_0.01')
|
|
42
|
+
D03file_perp = _find_cmfile('callindex.out_CpeD03_0.01')
|
|
43
|
+
|
|
44
|
+
D03dat_para = ascii.read(D03file_para, header_start=4, data_start=5)
|
|
45
|
+
D03dat_perp = ascii.read(D03file_perp, header_start=4, data_start=5)
|
|
46
|
+
|
|
47
|
+
# The wavelength grid needs to be in ascending order
|
|
48
|
+
# for np.interp to run correctly
|
|
49
|
+
if orient == 'perp':
|
|
50
|
+
wavel = D03dat_perp['wave(um)'] * u.micron
|
|
51
|
+
wsort = np.argsort(wavel.value)
|
|
52
|
+
self.wavel = wavel[wsort]
|
|
53
|
+
self.revals = 1.0 + D03dat_perp['Re(n)-1'][wsort]
|
|
54
|
+
self.imvals = D03dat_perp['Im(n)'][wsort]
|
|
55
|
+
|
|
56
|
+
if orient == 'para':
|
|
57
|
+
wavel = D03dat_para['wave(um)'] * u.micron
|
|
58
|
+
wsort = np.argsort(wavel)
|
|
59
|
+
self.wavel = wavel[wsort]
|
|
60
|
+
self.revals = 1.0 + D03dat_para['Re(n)-1'][wsort]
|
|
61
|
+
self.imvals = D03dat_para['Im(n)'][wsort]
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from astropy.io import ascii
|
|
3
|
+
from astropy import units as u
|
|
4
|
+
|
|
5
|
+
from . import _find_cmfile
|
|
6
|
+
from . import Composition
|
|
7
|
+
|
|
8
|
+
__all__ = ['CmSilicate']
|
|
9
|
+
|
|
10
|
+
RHO_SIL = 3.8 # g cm^-3
|
|
11
|
+
|
|
12
|
+
class CmSilicate(Composition):
|
|
13
|
+
"""
|
|
14
|
+
Optical constants for Silicate from
|
|
15
|
+
`Draine (2003), ApJ 598, 1026 <http://adsabs.harvard.edu/abs/2003ApJ...598.1026D>`_
|
|
16
|
+
"""
|
|
17
|
+
def __init__(self, rho=RHO_SIL):
|
|
18
|
+
Composition.__init__(self)
|
|
19
|
+
self.cmtype = 'Silicate'
|
|
20
|
+
self.rho = rho
|
|
21
|
+
self.citation = "Using optical constants for astrosilicate,\nDraine, B. T. 2003, ApJ, 598, 1026\nhttp://adsabs.harvard.edu/abs/2003ApJ...598.1026D"
|
|
22
|
+
|
|
23
|
+
D03file = _find_cmfile('callindex.out_sil.D03')
|
|
24
|
+
D03dat = ascii.read(D03file, header_start=4, data_start=5)
|
|
25
|
+
|
|
26
|
+
# The wavelength grid needs to be in ascending order for np.interp to run correctly
|
|
27
|
+
wavel = D03dat['wave(um)'] * u.micron
|
|
28
|
+
wsort = np.argsort(wavel.value)
|
|
29
|
+
|
|
30
|
+
self.wavel = wavel[wsort]
|
|
31
|
+
self.revals = 1.0 + D03dat['Re(n)-1'][wsort]
|
|
32
|
+
self.imvals = D03dat['Im(n)'][wsort]
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#
|
|
2
|
+
# minerals.py -- Some tables for ISM abundances and depletion factors
|
|
3
|
+
# that are useful for calculating dust mass and dust-to-gas ratios
|
|
4
|
+
#
|
|
5
|
+
# 2016.01.22 - lia@space.mit.edu
|
|
6
|
+
##----------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
amu = {'H':1.008,'He':4.0026,'C':12.011,'N':14.007,'O':15.999,'Ne':20.1797,
|
|
11
|
+
'Na':22.989,'Mg':24.305,'Al':26.981,'Si':28.085,'P':30.973,'S':32.06,
|
|
12
|
+
'Cl':35.45,'Ar':39.948,'Ca':40.078,'Ti':47.867,'Cr':51.9961,'Mn':54.938,
|
|
13
|
+
'Fe':55.845,'Co':58.933,'Ni':58.6934}
|
|
14
|
+
amu_g = 1.661e-24 # g
|
|
15
|
+
mp = 1.673e-24 # g (proton mass)
|
|
16
|
+
|
|
17
|
+
wilms = {'H':12.0, 'He':10.99, 'C':8.38, 'N':7.88, 'O':8.69, 'Ne':7.94,
|
|
18
|
+
'Na':6.16, 'Mg':7.40, 'Al':6.33, 'Si':7.27, 'P':5.42, 'S':7.09,
|
|
19
|
+
'Cl':5.12, 'Ar':6.41, 'Ca':6.20, 'Ti':4.81, 'Cr':5.51, 'Mn':5.34,
|
|
20
|
+
'Fe':7.43, 'Co':4.92, 'Ni':6.05} # 12 + log A_z
|
|
21
|
+
|
|
22
|
+
# Fraction of elements still in gas form
|
|
23
|
+
wilms_1mbeta = {'H':1.0, 'He':1.0, 'C':0.5, 'N':1.0, 'O':0.6, 'Ne':1.0, 'Na':0.25,
|
|
24
|
+
'Mg':0.2, 'Al':0.02, 'Si':0.1, 'P':0.6, 'S':0.6, 'Cl':0.5, 'Ar':1.0,
|
|
25
|
+
'Ca':0.003, 'Ti':0.002, 'Cr':0.03, 'Mn':0.07, 'Fe':0.3, 'Co':0.05,
|
|
26
|
+
'Ni':0.04}
|
|
27
|
+
|
|
28
|
+
class Mineral(object):
|
|
29
|
+
"""
|
|
30
|
+
| Use a dictionary to define the composition.
|
|
31
|
+
| e.g. Olivines of pure MgFe^{2+}SiO_4 composition would be
|
|
32
|
+
| olivine_halfMg = Mineral( {'Mg':1.0, 'Fe':1.0, 'Si':1.0, 'O':4.0} )
|
|
33
|
+
| self.composition : dictionary containing elements and their weights
|
|
34
|
+
|
|
|
35
|
+
| @property
|
|
36
|
+
| self._weight_amu : amu weight of unit crystal
|
|
37
|
+
| self.weight_g : g weight of unit crystal
|
|
38
|
+
"""
|
|
39
|
+
def __init__(self, comp):
|
|
40
|
+
self.composition = comp
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def weight_amu(self):
|
|
44
|
+
result = 0.0
|
|
45
|
+
for atom in self.composition.keys():
|
|
46
|
+
result += self.composition[atom] * amu[atom]
|
|
47
|
+
return result
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def weight_g(self):
|
|
51
|
+
return self.weight_amu * amu_g
|
|
52
|
+
|
|
53
|
+
def calc_mass_conversion(elem, mineral):
|
|
54
|
+
"""
|
|
55
|
+
| Returns the number of atoms per gram of a particular mineral object
|
|
56
|
+
| Useful for converting mass column to a number density column for an element
|
|
57
|
+
"""
|
|
58
|
+
assert type(mineral) == Mineral
|
|
59
|
+
assert type(elem) == str
|
|
60
|
+
return mineral.composition[elem] / mineral.weight_g # g^{-1}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def calc_element_column(NH, fmineral, atom, mineral, d2g=0.009):
|
|
64
|
+
"""
|
|
65
|
+
Calculate the column density of an element for a particular NH value,
|
|
66
|
+
assuming a dust-to-gas ratio (d2g) and the fraction of dust in that
|
|
67
|
+
particular mineral species (fmineral)
|
|
68
|
+
"""
|
|
69
|
+
dust_mass = NH * mp * d2g * fmineral # g cm^{-2}
|
|
70
|
+
print('Dust mass = %.3e g cm^-2' % (dust_mass))
|
|
71
|
+
return calc_mass_conversion(atom, mineral) * dust_mass # cm^{-2}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def get_ISM_abund(elem, abund_table=wilms):
|
|
75
|
+
"""
|
|
76
|
+
Given an abundance table, calculate the number per H atom of a
|
|
77
|
+
given element in any ISM form
|
|
78
|
+
"""
|
|
79
|
+
assert type(elem) == str
|
|
80
|
+
assert type(abund_table) == dict
|
|
81
|
+
return np.power(10.0, abund_table[elem] - 12.0) # number per H atom
|
|
82
|
+
|
|
83
|
+
def get_dust_abund(elem, abund_table=wilms, gas_ratio=wilms_1mbeta):
|
|
84
|
+
"""
|
|
85
|
+
Given an abundance table (dict) and a table of gas ratios (dict),
|
|
86
|
+
calculate the number per H atom of a given ISM element in *solid* form
|
|
87
|
+
"""
|
|
88
|
+
assert type(elem) == str
|
|
89
|
+
assert type(abund_table) == dict
|
|
90
|
+
assert type(gas_ratio) == dict
|
|
91
|
+
return get_ISM_abund(elem, abund_table) * (1.0 - gas_ratio[elem]) # number per H atom
|