exoatlas 0.3.7__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.
- exoatlas-0.3.7/LICENSE +21 -0
- exoatlas-0.3.7/PKG-INFO +40 -0
- exoatlas-0.3.7/README.md +42 -0
- exoatlas-0.3.7/exoatlas/__init__.py +6 -0
- exoatlas-0.3.7/exoatlas/imports.py +192 -0
- exoatlas-0.3.7/exoatlas/models/__init__.py +4 -0
- exoatlas-0.3.7/exoatlas/models/chen.py +81 -0
- exoatlas-0.3.7/exoatlas/models/kopparapu.py +63 -0
- exoatlas-0.3.7/exoatlas/models/seager.py +39 -0
- exoatlas-0.3.7/exoatlas/models/zeng.py +35 -0
- exoatlas-0.3.7/exoatlas/populations/Exoplanets.py +341 -0
- exoatlas-0.3.7/exoatlas/populations/Population.py +1648 -0
- exoatlas-0.3.7/exoatlas/populations/SolarSystem.py +112 -0
- exoatlas-0.3.7/exoatlas/populations/TESS.py +1 -0
- exoatlas-0.3.7/exoatlas/populations/TOI.py +228 -0
- exoatlas-0.3.7/exoatlas/populations/TOISubsets.py +99 -0
- exoatlas-0.3.7/exoatlas/populations/TransitingExoplanets.py +106 -0
- exoatlas-0.3.7/exoatlas/populations/TransitingExoplanetsSubsets.py +195 -0
- exoatlas-0.3.7/exoatlas/populations/__init__.py +17 -0
- exoatlas-0.3.7/exoatlas/populations/collections.py +34 -0
- exoatlas-0.3.7/exoatlas/populations/column_descriptions.py +48 -0
- exoatlas-0.3.7/exoatlas/populations/curation/Confirmed.py +260 -0
- exoatlas-0.3.7/exoatlas/populations/curation/TransitingExoplanets.py +2 -0
- exoatlas-0.3.7/exoatlas/populations/curation/__init__.py +0 -0
- exoatlas-0.3.7/exoatlas/populations/downloaders.py +283 -0
- exoatlas-0.3.7/exoatlas/populations/summary.py +74 -0
- exoatlas-0.3.7/exoatlas/talker.py +73 -0
- exoatlas-0.3.7/exoatlas/telescopes/__init__.py +1 -0
- exoatlas-0.3.7/exoatlas/telescopes/buckets.py +223 -0
- exoatlas-0.3.7/exoatlas/tests/__init__.py +9 -0
- exoatlas-0.3.7/exoatlas/tests/setup_tests.py +2 -0
- exoatlas-0.3.7/exoatlas/tests/test_buckets.py +34 -0
- exoatlas-0.3.7/exoatlas/tests/test_downloaders.py +25 -0
- exoatlas-0.3.7/exoatlas/tests/test_imports.py +17 -0
- exoatlas-0.3.7/exoatlas/tests/test_models.py +37 -0
- exoatlas-0.3.7/exoatlas/tests/test_populations.py +134 -0
- exoatlas-0.3.7/exoatlas/tests/test_snr.py +68 -0
- exoatlas-0.3.7/exoatlas/tests/test_uncertainties.py +26 -0
- exoatlas-0.3.7/exoatlas/tests/test_visualizations.py +62 -0
- exoatlas-0.3.7/exoatlas/tests/test_whatsup.py +22 -0
- exoatlas-0.3.7/exoatlas/version.py +10 -0
- exoatlas-0.3.7/exoatlas/visualizations/MultiPanel.py +136 -0
- exoatlas-0.3.7/exoatlas/visualizations/ThumbtackMovie.py +26 -0
- exoatlas-0.3.7/exoatlas/visualizations/ThumbtackPlot.py +428 -0
- exoatlas-0.3.7/exoatlas/visualizations/__init__.py +4 -0
- exoatlas-0.3.7/exoatlas/visualizations/axes/__init__.py +2 -0
- exoatlas-0.3.7/exoatlas/visualizations/axes/plottable.py +143 -0
- exoatlas-0.3.7/exoatlas/visualizations/axes/preset_plottables.py +486 -0
- exoatlas-0.3.7/exoatlas/visualizations/buildable.py +273 -0
- exoatlas-0.3.7/exoatlas/visualizations/ink_errorbar.py +106 -0
- exoatlas-0.3.7/exoatlas/visualizations/panels/BubblePanel.py +280 -0
- exoatlas-0.3.7/exoatlas/visualizations/panels/ErrorPanel.py +225 -0
- exoatlas-0.3.7/exoatlas/visualizations/panels/Panel.py +392 -0
- exoatlas-0.3.7/exoatlas/visualizations/panels/__init__.py +4 -0
- exoatlas-0.3.7/exoatlas/visualizations/panels/preset_panels.py +390 -0
- exoatlas-0.3.7/exoatlas/visualizations/tweaks.py +37 -0
- exoatlas-0.3.7/exoatlas/whatsup/__init__.py +7 -0
- exoatlas-0.3.7/exoatlas/whatsup/block.py +69 -0
- exoatlas-0.3.7/exoatlas/whatsup/night.py +6 -0
- exoatlas-0.3.7/exoatlas/whatsup/observatory.py +215 -0
- exoatlas-0.3.7/exoatlas/whatsup/plan.py +312 -0
- exoatlas-0.3.7/exoatlas/whatsup/transit.py +180 -0
- exoatlas-0.3.7/exoatlas.egg-info/PKG-INFO +40 -0
- exoatlas-0.3.7/exoatlas.egg-info/SOURCES.txt +68 -0
- exoatlas-0.3.7/exoatlas.egg-info/dependency_links.txt +1 -0
- exoatlas-0.3.7/exoatlas.egg-info/not-zip-safe +1 -0
- exoatlas-0.3.7/exoatlas.egg-info/requires.txt +25 -0
- exoatlas-0.3.7/exoatlas.egg-info/top_level.txt +1 -0
- exoatlas-0.3.7/setup.cfg +4 -0
- exoatlas-0.3.7/setup.py +117 -0
exoatlas-0.3.7/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015-2024 Zach Berta-Thompson
|
|
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.
|
exoatlas-0.3.7/PKG-INFO
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: exoatlas
|
|
3
|
+
Version: 0.3.7
|
|
4
|
+
Summary: Tools for working with transiting exoplanet populations.
|
|
5
|
+
Home-page: https://github.com/zkbt/exoatlas
|
|
6
|
+
Author: Zach Berta-Thompson
|
|
7
|
+
Author-email: zach.bertathompson@colorado.edu
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Intended Audience :: Education
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: Programming Language :: Python
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
13
|
+
Requires-Python: >=3.9
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: numpy>=1.13
|
|
16
|
+
Requires-Dist: matplotlib>=2.0
|
|
17
|
+
Requires-Dist: astropy>=3.2.3
|
|
18
|
+
Requires-Dist: astroquery>=0.3.9
|
|
19
|
+
Requires-Dist: astroplan>=0.10
|
|
20
|
+
Requires-Dist: rainbow-connection>=0.0.1
|
|
21
|
+
Requires-Dist: PyYAML
|
|
22
|
+
Requires-Dist: tqdm
|
|
23
|
+
Requires-Dist: pytz
|
|
24
|
+
Provides-Extra: develop
|
|
25
|
+
Requires-Dist: pytest; extra == "develop"
|
|
26
|
+
Requires-Dist: black; extra == "develop"
|
|
27
|
+
Requires-Dist: black[jupyter]; extra == "develop"
|
|
28
|
+
Requires-Dist: jupyter; extra == "develop"
|
|
29
|
+
Requires-Dist: ipython; extra == "develop"
|
|
30
|
+
Requires-Dist: mkdocs; extra == "develop"
|
|
31
|
+
Requires-Dist: mkdocs-material; extra == "develop"
|
|
32
|
+
Requires-Dist: mkdocstrings; extra == "develop"
|
|
33
|
+
Requires-Dist: mkdocstrings-python; extra == "develop"
|
|
34
|
+
Requires-Dist: pytkdocs[numpy-style]; extra == "develop"
|
|
35
|
+
Requires-Dist: mkdocs-jupyter; extra == "develop"
|
|
36
|
+
Requires-Dist: mkdocs-exclude; extra == "develop"
|
|
37
|
+
Requires-Dist: twine; extra == "develop"
|
|
38
|
+
Requires-Dist: pre-commit; extra == "develop"
|
|
39
|
+
|
|
40
|
+
For detailed usage, please read the documentation at https://zkbt.github.io/exoatlas/
|
exoatlas-0.3.7/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# exoatlas
|
|
2
|
+
Tools for compiling and plotting populations of transiting exoplanets. This package still a bit of a work in progress, but can be generally useful for downloading and working with exoplanet populations. For draft documentation explaing how to use `exoatlas`, please [read the documentation](https://zkbt.github.io/exoatlas/build/html/index.html).
|
|
3
|
+
|
|
4
|
+
### Installation
|
|
5
|
+
If you want the most recent stable version, the simplest way is to install it from PyPI directly via `pip` from any UNIX prompt:
|
|
6
|
+
```bash
|
|
7
|
+
pip install exoatlas
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Or, if you want the very-most-up-to-date version, you can install directly from this repository via:
|
|
11
|
+
```bash
|
|
12
|
+
pip install git+https://github.com/zkbt/exoatlas
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or, if you want to be able to modify the code yourself, please also feel free to fork/clone this repository onto your own computer and install directly from that editable package. For example, this might look like:
|
|
16
|
+
```bash
|
|
17
|
+
git clone https://github.com/zkbt/exoatlas.git
|
|
18
|
+
cd exoatlas
|
|
19
|
+
pip install -e .
|
|
20
|
+
```
|
|
21
|
+
The `pip install -e .` command will link the installed version of the package to the directory of your local repository. Changes you make to the code in that directory should be reflected in the version Python sees when it tries to `import exoatlas`.
|
|
22
|
+
|
|
23
|
+
### Usage
|
|
24
|
+
Here's a quick preview:
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
# import some population definitions and plotting tool
|
|
29
|
+
from exoatlas import *
|
|
30
|
+
|
|
31
|
+
# create a dictionary of populations
|
|
32
|
+
exo = TransitingExoplanets()
|
|
33
|
+
solar = SolarSystem()
|
|
34
|
+
pops = {'solar':solar,
|
|
35
|
+
'exo':exo}
|
|
36
|
+
|
|
37
|
+
# use a default visualization to summarize these populations
|
|
38
|
+
physical_summary(pops)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Authors
|
|
42
|
+
This toolkit was made by [Zach Berta-Thompson](http://casa.colorado.edu/~bertathompson/). It relies heavily on the incredible work done by the folks over at the [NASA Exoplanet Archive](https://exoplanetarchive.ipac.caltech.edu), and their generously designed API.
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
from .version import *
|
|
2
|
+
|
|
3
|
+
# imports that are need by many exoatlas subsections
|
|
4
|
+
from ast import Import
|
|
5
|
+
import os, sys, time, shutil, warnings, copy
|
|
6
|
+
from tqdm import tqdm
|
|
7
|
+
|
|
8
|
+
# (possibly different on Mac, Linux, Windows, even for Python versions 3.8-3.12)
|
|
9
|
+
try:
|
|
10
|
+
from importlib.resources import files
|
|
11
|
+
except (ModuleNotFoundError, AttributeError, ImportError):
|
|
12
|
+
from importlib_resources import files
|
|
13
|
+
|
|
14
|
+
code_directory = files(import_name)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
import numpy as np, matplotlib.pyplot as plt, matplotlib.animation as animation
|
|
18
|
+
from matplotlib.ticker import ScalarFormatter, FormatStrFormatter, LogLocator
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
from astropy.utils.exceptions import AstropyDeprecationWarning
|
|
22
|
+
|
|
23
|
+
warnings.simplefilter("ignore", category=AstropyDeprecationWarning)
|
|
24
|
+
|
|
25
|
+
# this function downloads a file and returns its filepath
|
|
26
|
+
from astropy.utils.data import download_file
|
|
27
|
+
from astropy.io import ascii
|
|
28
|
+
from astropy.table import Table, vstack, join, setdiff
|
|
29
|
+
from astropy.visualization import quantity_support
|
|
30
|
+
from astropy.coordinates import SkyCoord
|
|
31
|
+
|
|
32
|
+
quantity_support()
|
|
33
|
+
|
|
34
|
+
# some general custom utilities from Zach
|
|
35
|
+
from .talker import Talker
|
|
36
|
+
|
|
37
|
+
# units and constants from astropy
|
|
38
|
+
import astropy.units as u, astropy.constants as con
|
|
39
|
+
from astropy.time import Time
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def mkdir(path):
|
|
43
|
+
"""A mkdir that doesn't complain if it fails."""
|
|
44
|
+
try:
|
|
45
|
+
os.mkdir(path)
|
|
46
|
+
except:
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
import matplotlib.colors as co
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def name2color(name):
|
|
54
|
+
"""
|
|
55
|
+
Return the 3-element RGB array of a given color name.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
name : str
|
|
60
|
+
The name ('black') or hex ('#000000')
|
|
61
|
+
for a particular color.
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
-------
|
|
65
|
+
rgb : tuple
|
|
66
|
+
Three-elements array of floats,
|
|
67
|
+
expressing brightness in RGB.
|
|
68
|
+
"""
|
|
69
|
+
if "#" in name:
|
|
70
|
+
h = name
|
|
71
|
+
else:
|
|
72
|
+
h = co.cnames[name].lower()
|
|
73
|
+
return co.hex2color(h)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# create a directory structure ()
|
|
77
|
+
try:
|
|
78
|
+
# search for an environment variable
|
|
79
|
+
base = os.getenv("exoatlas_DATA")
|
|
80
|
+
assert base is not None
|
|
81
|
+
except AssertionError:
|
|
82
|
+
# otherwise put it in the local directory
|
|
83
|
+
cwd = os.getcwd()
|
|
84
|
+
base = os.path.join(cwd, "downloads-for-exoatlas")
|
|
85
|
+
mkdir(base)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def locate_local_data():
|
|
89
|
+
print("💾 `exoatlas` archive data will be stored in:")
|
|
90
|
+
print(base)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
directories = dict(data=os.path.join(base, "data/"))
|
|
94
|
+
for k in directories.keys():
|
|
95
|
+
mkdir(directories[k])
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def reset_local_data():
|
|
99
|
+
if "y" in input(
|
|
100
|
+
"Are you sure you want to wipe all " "local exoatlas data files? [y/N]"
|
|
101
|
+
):
|
|
102
|
+
shutil.rmtree(directories["data"])
|
|
103
|
+
mkdir(directories["data"])
|
|
104
|
+
print(f"Removed all local data from {directories['data']}")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# some kludge for dealing with Python 3 vs 2?
|
|
108
|
+
try:
|
|
109
|
+
FileNotFoundError
|
|
110
|
+
except NameError:
|
|
111
|
+
FileNotFoundError = IOError
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def clean(s):
|
|
115
|
+
"""
|
|
116
|
+
A wrapper function to clean up complicated strings.
|
|
117
|
+
"""
|
|
118
|
+
bad = """ !@#$%^&*()+-_'",./<>?"""
|
|
119
|
+
cleaned = str(s) + ""
|
|
120
|
+
for c in bad:
|
|
121
|
+
cleaned = cleaned.replace(c, "")
|
|
122
|
+
return cleaned
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def time_from_modified(filename):
|
|
126
|
+
"""
|
|
127
|
+
How long ago was this file last modified?
|
|
128
|
+
"""
|
|
129
|
+
try:
|
|
130
|
+
dt = Time.now().unix - os.path.getmtime(filename)
|
|
131
|
+
return dt / 60 / 60 / 24
|
|
132
|
+
except FileNotFoundError:
|
|
133
|
+
return np.inf
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def check_if_needs_updating(filename, maximum_age=1.0):
|
|
137
|
+
"""
|
|
138
|
+
Do a (possibly interactive) check to see if this file
|
|
139
|
+
is so old that it needs to be updated.
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
old : bool
|
|
144
|
+
True if the file is so old it needs updating
|
|
145
|
+
False if the file doesn't need updating
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
# how long ago was the data updated?
|
|
149
|
+
dt = time_from_modified(filename)
|
|
150
|
+
|
|
151
|
+
old = False
|
|
152
|
+
if dt == np.inf:
|
|
153
|
+
old = True
|
|
154
|
+
elif dt > maximum_age:
|
|
155
|
+
print(f"{filename} is {dt:.3f} days old.")
|
|
156
|
+
old = "y" in input("Should it be updated? [y/N]").lower()
|
|
157
|
+
|
|
158
|
+
return old
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def one2another(bottom="white", top="red", alphabottom=1.0, alphatop=1.0, N=256):
|
|
162
|
+
"""
|
|
163
|
+
Create a cmap that goes smoothly (linearly in RGBA) from "bottom" to "top".
|
|
164
|
+
"""
|
|
165
|
+
try:
|
|
166
|
+
rgb_bottom = bottom[0:3] + 0
|
|
167
|
+
except:
|
|
168
|
+
rgb_bottom = name2color(bottom or "white")
|
|
169
|
+
try:
|
|
170
|
+
rgb_top = top[0:3] + 0
|
|
171
|
+
except:
|
|
172
|
+
rgb_top = name2color(top or "black")
|
|
173
|
+
|
|
174
|
+
r = np.linspace(rgb_bottom[0], rgb_top[0], N)
|
|
175
|
+
g = np.linspace(rgb_bottom[1], rgb_top[1], N)
|
|
176
|
+
b = np.linspace(rgb_bottom[2], rgb_top[2], N)
|
|
177
|
+
a = np.linspace(alphabottom, alphatop, N)
|
|
178
|
+
colors = np.transpose(np.vstack([r, g, b, a]))
|
|
179
|
+
cmap = co.ListedColormap(colors, name="{bottom}2{top}".format(**locals()))
|
|
180
|
+
return cmap
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class AtlasError(ValueError):
|
|
184
|
+
pass
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
# KLUDGE
|
|
188
|
+
|
|
189
|
+
import warnings
|
|
190
|
+
|
|
191
|
+
warnings.catch_warnings()
|
|
192
|
+
warnings.simplefilter("ignore")
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A simple cartoon of the Chen & Kipping (2017) forecaster model,
|
|
3
|
+
using the values quoted in their Table 2.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
__all__ = ["estimate_radius", "plot_chen"]
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import matplotlib.pyplot as plt
|
|
10
|
+
from astropy.units import Rearth, Mearth, Rjupiter, Mjupiter, Rsun, Msun
|
|
11
|
+
|
|
12
|
+
T_min, T_max, C, S = {}, {}, {}, {}
|
|
13
|
+
|
|
14
|
+
# define the terran range
|
|
15
|
+
T_min["terran"] = 1.0 * Mearth
|
|
16
|
+
T_max["terran"] = 2.04 * Mearth
|
|
17
|
+
S["terran"] = 0.2790
|
|
18
|
+
C["terran"] = 1.008 * Rearth
|
|
19
|
+
|
|
20
|
+
# define the neptunian range
|
|
21
|
+
T_min["neptunian"] = T_max["terran"]
|
|
22
|
+
T_max["neptunian"] = 0.414 * Mjupiter
|
|
23
|
+
S["neptunian"] = 0.589
|
|
24
|
+
C["neptunian"] = (
|
|
25
|
+
C["terran"] * (T_min["neptunian"] / T_min["terran"]).decompose() ** S["terran"]
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# define the jovian range
|
|
29
|
+
T_min["jovian"] = T_max["neptunian"]
|
|
30
|
+
T_max["jovian"] = 0.0800 * Msun
|
|
31
|
+
S["jovian"] = -0.044
|
|
32
|
+
C["jovian"] = (
|
|
33
|
+
C["neptunian"]
|
|
34
|
+
* (T_min["jovian"] / T_min["neptunian"]).decompose() ** S["neptunian"]
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# define the jovian range
|
|
38
|
+
T_min["stellar"] = T_max["jovian"]
|
|
39
|
+
T_max["stellar"] = 1 * Msun
|
|
40
|
+
S["stellar"] = 0.881
|
|
41
|
+
C["stellar"] = (
|
|
42
|
+
C["jovian"] * (T_min["stellar"] / T_min["jovian"]).decompose() ** S["jovian"]
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def estimate_radius(M):
|
|
47
|
+
"""
|
|
48
|
+
Estimate the radii, given an array of masses.
|
|
49
|
+
|
|
50
|
+
Parameters
|
|
51
|
+
----------
|
|
52
|
+
M : astropy.units.quantity.quantity
|
|
53
|
+
The masses of the planets.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
# create an empty array of radii
|
|
57
|
+
original_shape = np.shape(M)
|
|
58
|
+
M = np.atleast_1d(M)
|
|
59
|
+
R = np.zeros(np.shape(M)) * Rearth
|
|
60
|
+
|
|
61
|
+
# work our way down in mass, updating radii as we go
|
|
62
|
+
for this in ["stellar", "jovian", "neptunian", "terran"]:
|
|
63
|
+
# which planets are below this maximum?
|
|
64
|
+
x = M < T_max[this]
|
|
65
|
+
|
|
66
|
+
# calculate the radius
|
|
67
|
+
R[x] = C[this] * (M[x] / T_min[this]).decompose() ** S[this]
|
|
68
|
+
|
|
69
|
+
# return the same shape
|
|
70
|
+
return R.reshape(original_shape)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def plot_chen(**kw):
|
|
74
|
+
"""
|
|
75
|
+
Plot the MAP mass-radius curve from Chen and Kipping (2017).
|
|
76
|
+
This is mostly a wrapper to make testing easier.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
M = np.logspace(-1, 5, 1000) * Mearth
|
|
80
|
+
R = estimate_radius(M)
|
|
81
|
+
plt.loglog(M, R, **kw)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tools for working with the habitable zone definitions
|
|
3
|
+
in Kopparapu et al. (2013).
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
coefficients = {}
|
|
7
|
+
coefficients["recent-venus"] = [1.7753, 1.4316e-4, 2.9875e-9, -7.5702e-12, -1.1635e-15]
|
|
8
|
+
coefficients["runaway-greenhouse"] = [
|
|
9
|
+
1.0512,
|
|
10
|
+
1.3242e-4,
|
|
11
|
+
1.5418e-8,
|
|
12
|
+
-7.9895e-12,
|
|
13
|
+
-1.8328e-15,
|
|
14
|
+
]
|
|
15
|
+
coefficients["moist-greenhouse"] = [
|
|
16
|
+
1.0140,
|
|
17
|
+
8.1774e-5,
|
|
18
|
+
1.7063e-9,
|
|
19
|
+
-4.3241e-12,
|
|
20
|
+
-6.6462e-16,
|
|
21
|
+
]
|
|
22
|
+
coefficients["maximum-greenhouse"] = [
|
|
23
|
+
0.348,
|
|
24
|
+
5.8924e-5,
|
|
25
|
+
1.6558e-9,
|
|
26
|
+
-3.0045e-12,
|
|
27
|
+
-5.2983e-16,
|
|
28
|
+
]
|
|
29
|
+
coefficients["early-mars"] = [0.3179, 5.4513e-5, 1.5313e-9, -2.7786e-12, -4.8997e-16]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def make_hz(which="runaway-greenhouse"):
|
|
33
|
+
"""
|
|
34
|
+
Create a function f(Teff) describing one of
|
|
35
|
+
the habitable zone boundaries presented in
|
|
36
|
+
Table 3 of Kopparapu et al. (2013).
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
# pull out the coefficients
|
|
40
|
+
try:
|
|
41
|
+
S_o, a, b, c, d = coefficients[which]
|
|
42
|
+
except KeyError:
|
|
43
|
+
error_message = f"""
|
|
44
|
+
Alas! There seems to be no way to determine
|
|
45
|
+
coefficients for your choice of `{which}`.
|
|
46
|
+
The available options are:
|
|
47
|
+
"""
|
|
48
|
+
for k in which:
|
|
49
|
+
error_message += k + "\n"
|
|
50
|
+
raise ValueError(error_message)
|
|
51
|
+
|
|
52
|
+
# define the function
|
|
53
|
+
def f(Teff):
|
|
54
|
+
f"""
|
|
55
|
+
The `{which}` HZ boundary from Kopparapu et al. (2013),
|
|
56
|
+
as a function of stellar effective temperature.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
T = Teff - 5780
|
|
60
|
+
return S_o + a * T + b * T**2 + c * T**3 + d * T**4
|
|
61
|
+
|
|
62
|
+
# return that function definition
|
|
63
|
+
return f
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from ..imports import *
|
|
2
|
+
|
|
3
|
+
__all__ = ["plot_seager", "plot_both_seager"]
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# plot the mass radius models
|
|
7
|
+
def plot_seager(which="rock", **kw):
|
|
8
|
+
"""
|
|
9
|
+
Plot a single model from Seager et al. (2007). These were
|
|
10
|
+
originally point-clicked out of the GJ1214b discovery paper.
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
which : str
|
|
15
|
+
Options are 'rock' or 'HHe'
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
assert (which.lower() == "rock") or (which.lower() == "hhe")
|
|
19
|
+
|
|
20
|
+
# load the values
|
|
21
|
+
file = os.path.join(code_directory, f"models/data/seager/gj1214mr_{which}.txt")
|
|
22
|
+
m, r = np.transpose(np.loadtxt(file))
|
|
23
|
+
|
|
24
|
+
# fit a simply polynomial to smooth out the messiness
|
|
25
|
+
fit = np.poly1d(np.polyfit(np.log(m), np.log(r), 5))
|
|
26
|
+
|
|
27
|
+
# plot over a grid of masses
|
|
28
|
+
mm = np.logspace(np.log10(min(m)), np.log10(max(m)), 1000)
|
|
29
|
+
return plt.plot(mm, np.exp(fit(np.log(mm))), **kw)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def plot_both_seager(**kw):
|
|
33
|
+
"""
|
|
34
|
+
Plot both the rock and the cold H/He models from Seager et al. (2007)
|
|
35
|
+
"""
|
|
36
|
+
zkw = dict(linewidth=4, alpha=0.25, zorder=1.0)
|
|
37
|
+
zkw.update(**kw)
|
|
38
|
+
plot_seager("hhe", label="cold H/He", color="darkorange", **zkw)
|
|
39
|
+
plot_seager("rock", label="rock", color="black", **zkw)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from ..imports import *
|
|
2
|
+
|
|
3
|
+
__all__ = ["plot_zeng", "plot_three_zeng"]
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# plot the mass radius models
|
|
7
|
+
def plot_zeng(which="75pSi_25pFe", **kw):
|
|
8
|
+
"""
|
|
9
|
+
Plot a single mass-radius model from Zeng & Sasselov (2013).
|
|
10
|
+
|
|
11
|
+
Parameters
|
|
12
|
+
----------
|
|
13
|
+
which : str
|
|
14
|
+
A string to indicate which model to plot.
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
file = os.path.join(code_directory, f"models/data/zengandsasselov/MR_{which}.csv")
|
|
19
|
+
|
|
20
|
+
# load the values
|
|
21
|
+
m, r = np.transpose(np.loadtxt(file, delimiter=","))
|
|
22
|
+
|
|
23
|
+
# plot the values
|
|
24
|
+
return plt.plot(m, r, **kw)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def plot_three_zeng(**kw):
|
|
28
|
+
"""
|
|
29
|
+
Plot both the rock and the cold H/He models from Seager et al. (2007)
|
|
30
|
+
"""
|
|
31
|
+
zkw = dict(linewidth=4, alpha=0.25, zorder=1.0)
|
|
32
|
+
zkw.update(**kw)
|
|
33
|
+
plot_zeng("75pSi_25pFe", label="75% Si, 25% Fe", color="sienna", **zkw)
|
|
34
|
+
plot_zeng("50pSi_50pFe", label="50% Si, 25% 50", color="brown", **zkw)
|
|
35
|
+
plot_zeng("25pSi_75pFe", label="25% Si, 75% Fe", color="maroon", **zkw)
|