├── pdspy
├── constants
│ ├── math.py
│ ├── __init__.py
│ ├── time.py
│ ├── astronomy.py
│ ├── NumberUnit.py
│ └── physics.py
├── gas
│ ├── __init__.py
│ └── data
│ │ ├── test.hdf5
│ │ └── test.py
├── mcmc
│ ├── __init__.py
│ ├── change_params.py
│ ├── ml2d.py
│ ├── ml.py
│ ├── mcmc.py
│ └── mcmc2d.py
├── table
│ ├── __init__.py
│ ├── column.py
│ └── table.py
├── dust
│ ├── data
│ │ ├── c2d.hdf5
│ │ ├── diana.hdf5
│ │ ├── test.hdf5
│ │ ├── PAH_MRN.hdf5
│ │ ├── draine.hdf5
│ │ ├── pollack.hdf5
│ │ ├── diana_10cm.hdf5
│ │ ├── diana_10um.hdf5
│ │ ├── diana_1cm.hdf5
│ │ ├── diana_1mm.hdf5
│ │ ├── diana_1um.hdf5
│ │ ├── diana_wice.hdf5
│ │ ├── draine_1cm.hdf5
│ │ ├── draine_1mm.hdf5
│ │ ├── draine_1um.hdf5
│ │ ├── draine_2mm.hdf5
│ │ ├── draine_3mm.hdf5
│ │ ├── ricci_1um.hdf5
│ │ ├── diana_100um.hdf5
│ │ ├── draine_100um.hdf5
│ │ ├── draine_10um.hdf5
│ │ ├── pollack_100um.hdf5
│ │ ├── pollack_10cm.hdf5
│ │ ├── pollack_10um.hdf5
│ │ ├── pollack_1cm.hdf5
│ │ ├── pollack_1mm.hdf5
│ │ ├── pollack_1um.hdf5
│ │ ├── pollack_new.hdf5
│ │ ├── diana_wice_10cm.hdf5
│ │ ├── diana_wice_10um.hdf5
│ │ ├── diana_wice_1cm.hdf5
│ │ ├── diana_wice_1mm.hdf5
│ │ ├── diana_wice_1um.hdf5
│ │ ├── diana_wice_100um.hdf5
│ │ ├── diana_wice_singlesize.hdf5
│ │ ├── make_PAH_MRN.py
│ │ ├── make_dsharp.py
│ │ ├── make_diana.py
│ │ ├── make_diana_wice.py
│ │ ├── make_diana_wice_singlesize.py
│ │ ├── make_diana_10cm.py
│ │ ├── make_diana_10um.py
│ │ ├── make_diana_1cm.py
│ │ ├── make_diana_1mm.py
│ │ ├── make_diana_1um.py
│ │ ├── make_diana_wice_1cm.py
│ │ ├── make_diana_wice_1mm.py
│ │ ├── make_diana_wice_1um.py
│ │ ├── make_ricci_1um.py
│ │ ├── make_diana_100um.py
│ │ ├── make_diana_wice_100um.py
│ │ ├── make_diana_wice_10cm.py
│ │ ├── make_diana_wice_10um.py
│ │ ├── make_pollack_new.py
│ │ ├── optical_constants
│ │ │ ├── extrapolate_as.py
│ │ │ ├── extrapolate_acz96.py
│ │ │ ├── PAH_qion.txt
│ │ │ └── graphite.txt
│ │ ├── make_draine.py
│ │ ├── make_draine_1cm.py
│ │ ├── make_draine_100um.py
│ │ ├── make_draine_10um.py
│ │ ├── make_draine_1mm.py
│ │ ├── make_draine_1um.py
│ │ ├── make_draine_2mm.py
│ │ ├── make_draine_3mm.py
│ │ ├── plot_kabs.py
│ │ ├── test.py
│ │ ├── make_pollack_1um.py
│ │ ├── make_pollack.py
│ │ ├── plot_beta.py
│ │ ├── make_pollack_1cm.py
│ │ ├── make_pollack_1mm.py
│ │ ├── make_pollack_100um.py
│ │ ├── make_pollack_10cm.py
│ │ ├── make_pollack_10um.py
│ │ ├── plot_draine.py
│ │ ├── compare_c2d.py
│ │ ├── plot_diana.py
│ │ ├── plot_diana_wice.py
│ │ └── plot_pollack.py
│ ├── __init__.py
│ ├── reddening
│ │ └── steenman_the.dat
│ ├── run_opacity_tool.py
│ ├── mix_dust.py
│ └── redden.py
├── radmc3d
│ └── __init__.py
├── misc
│ ├── gaussian.py
│ ├── __init__.py
│ ├── B_nu.py
│ ├── dB_nu.py
│ └── gaussian2d.py
├── statistics
│ ├── binomial.py
│ ├── __init__.py
│ ├── fisher_exact.py
│ ├── linear_regression.py
│ ├── Ftest.py
│ ├── ttest.py
│ └── leastsq.py
├── modeling
│ ├── DartoisPringleDisk.py
│ ├── __init__.py
│ ├── Star.py
│ ├── check_parameters.py
│ ├── get_surrogate_model.py
│ ├── PringleDisk.py
│ └── SettledPringleDisk.py
├── utils
│ ├── __init__.py
│ └── propose_point_emcee.py
├── spectroscopy
│ ├── __init__.py
│ ├── read_spectrum.py
│ ├── freefree.py
│ ├── spectroscopy.py
│ ├── btsettl_photometry.py
│ └── find_lines.py
├── plotting
│ ├── Transform.py
│ ├── __init__.py
│ ├── colormaps.py
│ ├── cubeshow.py
│ ├── plot_scattered_light.py
│ ├── plot_2D_visibilities.py
│ └── plot_SED.py
├── stars
│ ├── __init__.py
│ └── Teff_from_SpT.py
├── imaging
│ ├── __init__.py
│ ├── imtovis.py
│ ├── update_catalog.py
│ ├── extract_pv_diagram.py
│ ├── readpvfits.py
│ ├── match_source_lists.py
│ ├── readimfits.py
│ └── imaging.py
├── interferometry
│ ├── rotate.py
│ ├── __init__.py
│ ├── center.py
│ ├── rmlimage.py
│ ├── readvis.py
│ ├── concatenate.py
│ ├── interpolate_model.py
│ ├── invert.py
│ └── readuvfits.py
└── __init__.py
├── tests
├── testdata.hdf5
├── test.py
└── test_dartois_disk.py
├── pyproject.toml
├── MANIFEST.in
├── docs
├── interferometry.rst
├── requirements.txt
├── modeling.rst
├── utils.rst
├── Makefile
├── plotting.rst
├── make.bat
├── installation.rst
├── upgrading.rst
└── conf.py
├── .gitignore
├── .readthedocs.yaml
├── compile
├── meta.yaml
├── README.md
├── .github
└── workflows
│ └── python-build-test-publish.yml
├── setup.py
└── examples
└── run_radiative_transfer_model.py
/pdspy/constants/math.py:
--------------------------------------------------------------------------------
1 | pi = 3.14159265
2 |
--------------------------------------------------------------------------------
/pdspy/gas/__init__.py:
--------------------------------------------------------------------------------
1 | from .Gas import Gas
2 |
--------------------------------------------------------------------------------
/pdspy/mcmc/__init__.py:
--------------------------------------------------------------------------------
1 | from .mcmc import mcmc
2 | from .mcmc2d import mcmc2d
3 |
--------------------------------------------------------------------------------
/tests/testdata.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/tests/testdata.hdf5
--------------------------------------------------------------------------------
/pdspy/table/__init__.py:
--------------------------------------------------------------------------------
1 | from .column import MaskedColumn
2 | from .table import Table
3 |
--------------------------------------------------------------------------------
/pdspy/dust/data/c2d.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/c2d.hdf5
--------------------------------------------------------------------------------
/pdspy/gas/data/test.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/gas/data/test.hdf5
--------------------------------------------------------------------------------
/pdspy/radmc3d/__init__.py:
--------------------------------------------------------------------------------
1 | from . import read
2 | from . import write
3 | from . import run
4 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["setuptools","wheel","Cython", "numpy<2.0.0"]
3 |
--------------------------------------------------------------------------------
/pdspy/dust/data/diana.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/test.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/test.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/PAH_MRN.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/PAH_MRN.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/draine.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/draine.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/pollack.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/pollack.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/diana_10cm.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana_10cm.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/diana_10um.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana_10um.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/diana_1cm.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana_1cm.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/diana_1mm.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana_1mm.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/diana_1um.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana_1um.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/diana_wice.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana_wice.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/draine_1cm.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/draine_1cm.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/draine_1mm.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/draine_1mm.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/draine_1um.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/draine_1um.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/draine_2mm.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/draine_2mm.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/draine_3mm.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/draine_3mm.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/ricci_1um.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/ricci_1um.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/diana_100um.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana_100um.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/draine_100um.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/draine_100um.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/draine_10um.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/draine_10um.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/pollack_100um.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/pollack_100um.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/pollack_10cm.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/pollack_10cm.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/pollack_10um.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/pollack_10um.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/pollack_1cm.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/pollack_1cm.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/pollack_1mm.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/pollack_1mm.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/pollack_1um.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/pollack_1um.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/pollack_new.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/pollack_new.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/diana_wice_10cm.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana_wice_10cm.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/diana_wice_10um.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana_wice_10um.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/diana_wice_1cm.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana_wice_1cm.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/diana_wice_1mm.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana_wice_1mm.hdf5
--------------------------------------------------------------------------------
/pdspy/dust/data/diana_wice_1um.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana_wice_1um.hdf5
--------------------------------------------------------------------------------
/pdspy/constants/__init__.py:
--------------------------------------------------------------------------------
1 | from . import astronomy
2 | from . import math
3 | from . import physics
4 | from . import time
5 |
--------------------------------------------------------------------------------
/pdspy/dust/data/diana_wice_100um.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana_wice_100um.hdf5
--------------------------------------------------------------------------------
/pdspy/constants/time.py:
--------------------------------------------------------------------------------
1 | hour = 3.6e3 # s
2 | day = 8.64e4 # s
3 | year = 3.1557600e7 # s
4 |
--------------------------------------------------------------------------------
/pdspy/dust/data/diana_wice_singlesize.hdf5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psheehan/pdspy/HEAD/pdspy/dust/data/diana_wice_singlesize.hdf5
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include pyproject.toml
2 |
3 | # Include the README
4 | include *.md
5 |
6 | # Include the license file
7 | include LICENSE
8 |
--------------------------------------------------------------------------------
/docs/interferometry.rst:
--------------------------------------------------------------------------------
1 | pdspy.interferometry
2 | ===============================
3 |
4 | .. autofunction:: pdspy.interferometry.readms
5 |
--------------------------------------------------------------------------------
/pdspy/misc/gaussian.py:
--------------------------------------------------------------------------------
1 | from numpy import exp
2 |
3 | def gaussian(x,x0,sigma,f0):
4 |
5 | return f0*exp(-1*(x-x0)**2/(2*sigma**2))
--------------------------------------------------------------------------------
/pdspy/misc/__init__.py:
--------------------------------------------------------------------------------
1 | from .B_nu import B_nu
2 | from .dB_nu import dB_nu
3 | from .gaussian import gaussian
4 | from .gaussian2d import gaussian2d
5 |
--------------------------------------------------------------------------------
/pdspy/statistics/binomial.py:
--------------------------------------------------------------------------------
1 | from math import factorial
2 |
3 | def binomial(N, m, p):
4 |
5 | return factorial(N)/(factorial(m)*factorial(N-m))*p**m*(1-p)**(N-m)
6 |
--------------------------------------------------------------------------------
/pdspy/misc/B_nu.py:
--------------------------------------------------------------------------------
1 | from numpy import exp
2 | from ..constants.physics import h, c, k
3 |
4 | def B_nu(nu,T):
5 |
6 | return (2*h*nu**3/c**2)/(exp(h*nu/(k*T))-1.0)
7 |
--------------------------------------------------------------------------------
/pdspy/modeling/DartoisPringleDisk.py:
--------------------------------------------------------------------------------
1 | from .DartoisDisk import DartoisDisk
2 | from .PringleDisk import PringleDisk
3 |
4 | class DartoisPringleDisk(DartoisDisk,PringleDisk):
5 | pass
6 |
--------------------------------------------------------------------------------
/pdspy/misc/dB_nu.py:
--------------------------------------------------------------------------------
1 | from numpy import exp
2 | from ..constants.physics import h, c, k
3 |
4 | def dB_nu(nu,T):
5 |
6 | return (-2*h**2*nu**4/(c**2*k*T**2))/(exp(h*nu/(k*T))-1)/ \
7 | (1.-exp(-h*nu/(k*T)))
8 |
--------------------------------------------------------------------------------
/pdspy/dust/__init__.py:
--------------------------------------------------------------------------------
1 | from .Dust import Dust
2 | from .DustGenerator import DustGenerator
3 | from .PAH import PAH
4 | from .mix_dust import mix_dust
5 | from .redden import redden
6 | from .run_opacity_tool import run_opacity_tool
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.so
2 | *.pyc
3 | __pycache__
4 | *.swp
5 | *.pdf
6 | *.dSYM
7 | pdspy/dust/reddening/*.py
8 | pdspy/dust/reddening/*.pdf
9 | test
10 | *.c
11 | *.cover
12 | _build
13 | _static
14 | _templates
15 | build
16 | pdspy.egg-info
17 |
--------------------------------------------------------------------------------
/pdspy/statistics/__init__.py:
--------------------------------------------------------------------------------
1 | from .binomial import binomial
2 | from .fisher_exact import fisher_exact
3 | from .leastsq import leastsq
4 | from .linear_regression import linear_regression
5 | from .ttest import ttest
6 | from .Ftest import Ftest
7 |
--------------------------------------------------------------------------------
/pdspy/utils/__init__.py:
--------------------------------------------------------------------------------
1 | from .load_config import load_config
2 | from .load_data import load_data
3 | from .load_results import load_results
4 | from .propose_point_emcee import propose_point_emcee
5 |
6 | from . import emcee
7 | from . import dynesty
8 |
--------------------------------------------------------------------------------
/pdspy/misc/gaussian2d.py:
--------------------------------------------------------------------------------
1 | from numpy import exp,cos,sin
2 |
3 | def gaussian2d(x,y,x0,y0,sigmax,sigmay,pa,f0):
4 |
5 | xp=(x-x0)*cos(pa)-(y-y0)*sin(pa)
6 | yp=(x-x0)*sin(pa)+(y-y0)*cos(pa)
7 |
8 | return f0*exp(-1*xp**2/(2*sigmax**2))*exp(-1*yp**2/(2*sigmay**2))
--------------------------------------------------------------------------------
/pdspy/spectroscopy/__init__.py:
--------------------------------------------------------------------------------
1 | from .spectroscopy import Spectrum
2 | from .find_lines import find_lines
3 | from .line_flux import line_flux
4 | from .read_spectrum import read_spectrum
5 | from .btsettl_photometry import btsettl_photometry
6 | from .freefree import freefree
7 |
--------------------------------------------------------------------------------
/pdspy/plotting/Transform.py:
--------------------------------------------------------------------------------
1 | class Transform:
2 | def __init__(self, xmin, xmax, dx, fmt):
3 | self.xmin = xmin
4 | self.xmax = xmax
5 | self.dx = dx
6 | self.fmt = fmt
7 |
8 | def __call__(self, x, p):
9 | return self.fmt% ((x-(self.xmax-self.xmin+1)/2)*self.dx)
10 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | # File: .readthedocs.yaml
2 |
3 | version: 2
4 |
5 | # Build from the docs/ directory with Sphinx
6 | sphinx:
7 | configuration: docs/conf.py
8 |
9 | # Explicitly set the version of Python and its requirements
10 | python:
11 | version: 3.7
12 | install:
13 | - requirements: docs/requirements.txt
14 |
--------------------------------------------------------------------------------
/pdspy/stars/__init__.py:
--------------------------------------------------------------------------------
1 | from .pms_evolutionary_tracks import pms_get_mstar
2 | from .pms_evolutionary_tracks import pms_get_age
3 | from .pms_evolutionary_tracks import pms_get_teff
4 | from .pms_evolutionary_tracks import pms_get_luminosity
5 | from .pms_evolutionary_tracks import pms_get_radius
6 | from .Teff_from_SpT import Teff_from_SpT
7 |
--------------------------------------------------------------------------------
/pdspy/table/column.py:
--------------------------------------------------------------------------------
1 | import astropy.table
2 |
3 | class MaskedColumn(astropy.table.MaskedColumn):
4 |
5 | def __getitem__(self, item):
6 | x = super(MaskedColumn, self).__getitem__(item)
7 |
8 | try:
9 | if x.mask:
10 | return '--'
11 | except:
12 | return x
13 |
--------------------------------------------------------------------------------
/pdspy/statistics/fisher_exact.py:
--------------------------------------------------------------------------------
1 | from math import factorial
2 |
3 | def fisher_exact(a,b,c,d):
4 |
5 | return float(factorial(a+b))*float(factorial(c+d))*float(factorial(a+c))* \
6 | float(factorial(b+d))/(float(factorial(a))*float(factorial(b))* \
7 | float(factorial(c))*float(factorial(d))*float(factorial(a+b+c+d)))
8 |
--------------------------------------------------------------------------------
/pdspy/spectroscopy/read_spectrum.py:
--------------------------------------------------------------------------------
1 | from numpy import loadtxt
2 | from .spectroscopy import Spectrum
3 |
4 | def read_spectrum(file):
5 |
6 | spectrum = loadtxt(file)
7 | wave = spectrum[:,0]
8 | flux = spectrum[:,1]
9 | unc = spectrum[:,2]
10 |
11 | data = Spectrum(wave,flux,unc)
12 |
13 | return data
14 |
--------------------------------------------------------------------------------
/compile:
--------------------------------------------------------------------------------
1 | command=python
2 |
3 | while [[ $# -gt 0 ]]; do
4 | case "$1" in
5 | -v|--version)
6 | command="${2#*=}"
7 | shift 2
8 | ;;
9 | esac
10 | done
11 |
12 | $command setup.py build_ext --inplace
13 |
14 | rm -r build pdspy/interferometry/libinterferometry.c
15 | rm -r build pdspy/imaging/libimaging.c
16 | rm -r build pdspy/radmc3d/read.c
17 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | # File: docs/requirements.txt
2 |
3 | # Defining the exact version will make sure things don't break
4 | sphinx==4.1.2
5 | sphinx_rtd_theme==0.5.2
6 | readthedocs-sphinx-search==0.3.2
7 | docutils==0.16
8 | numpy
9 | scipy
10 | matplotlib
11 | emcee
12 | corner
13 | hyperion
14 | h5py
15 | Cython
16 | astropy
17 | schwimmbad
18 | dynesty
19 | scikit-learn
20 |
--------------------------------------------------------------------------------
/tests/test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import pdspy.interferometry as uv
4 | import matplotlib.pyplot as plt
5 |
6 | data = uv.Visibilities()
7 | data.read("testdata.hdf5")
8 |
9 | image = uv.invert(data, imsize=512, pixel_size=0.5, convolution="expsinc")
10 |
11 | plt.imshow(image.image[:,:,0], origin="lower", interpolation="none")
12 | plt.colorbar()
13 | plt.savefig("test.pdf")
14 |
--------------------------------------------------------------------------------
/docs/modeling.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | pdspy.modeling
5 | ===============================
6 |
7 | .. automodule:: pdspy.modeling
8 | .. currentmodule:: pdspy.modeling
9 |
10 | Model
11 | ----------------------
12 |
13 | .. autoclass:: Model
14 | :members:
15 |
16 | YSOModel
17 | ----------------------
18 |
19 | .. autoclass:: YSOModel
20 | :members:
21 |
--------------------------------------------------------------------------------
/pdspy/imaging/__init__.py:
--------------------------------------------------------------------------------
1 | from .libimaging import Image
2 | from .libimaging import UnstructuredImage
3 | from .imtovis import imtovis
4 | from .readimfits import readimfits
5 | from .readpvfits import readpvfits
6 | from .find import find
7 | from .match_source_lists import match_source_lists
8 | from .update_catalog import update_catalog
9 | from .extract_pv_diagram import extract_pv_diagram
10 |
--------------------------------------------------------------------------------
/pdspy/interferometry/rotate.py:
--------------------------------------------------------------------------------
1 | from .libinterferometry import Visibilities
2 | import numpy
3 |
4 | def rotate(data, pa=0):
5 |
6 | newu = data.u * numpy.cos(pa) + data.v * numpy.sin(pa)
7 | newv = -data.u * numpy.sin(pa) + data.v * numpy.cos(pa)
8 |
9 | return Visibilities(newu, newv, data.freq.copy(), data.real.copy(), \
10 | data.imag.copy(), data.weights.copy())
11 |
--------------------------------------------------------------------------------
/pdspy/constants/astronomy.py:
--------------------------------------------------------------------------------
1 | AU = 1.495978707e13 # cm
2 | pc = 3.085677581e18 # cm
3 | ly = 9.463e17 # cm
4 | M_sun = 1.99e33 # g
5 | R_sun = 6.96e10 # cm
6 | L_sun = 3.9e33 # erg s^-1
7 | T_sun = 5.78e3 # K
8 | Jy = 1.0e-23 # erg s^-1 cm^-2 Hz^-1
9 | arcsec = 4.84813681e-6 # radians
10 | kms = 1e5
11 | M_jupiter = 1.89813e30
12 | M_earth = 5.97219e27
13 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_PAH_MRN.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | dust = PAH()
7 | dust.set_properties_from_draine("optical_constants/PAHneu_30.txt", \
8 | "optical_constants/PAHneu_30.txt","optical_constants/PAH_qion.txt")
9 | dust.set_density(3.0)
10 |
11 | amin = dust.a.min()
12 | amax = dust.a.max()
13 | pl = 3.5
14 |
15 | dust.calculate_size_distribution_opacity(amin, amax, pl)
16 |
17 | dust.write('PAH_MRN.hdf5')
18 |
--------------------------------------------------------------------------------
/pdspy/plotting/__init__.py:
--------------------------------------------------------------------------------
1 | from .plot_SED import plot_SED
2 | from .plot_continuum_image import plot_continuum_image
3 | from .plot_1D_visibilities import plot_1D_visibilities
4 | from .plot_2D_visibilities import plot_2D_visibilities
5 | from .plot_scattered_light import plot_scattered_light
6 | from .plot_channel_maps import plot_channel_maps
7 | from .plot_pvdiagram import plot_pvdiagram
8 | from . import colormaps
9 | from .Transform import Transform
10 | from .cubeshow import cubeshow
11 |
--------------------------------------------------------------------------------
/pdspy/dust/reddening/steenman_the.dat:
--------------------------------------------------------------------------------
1 | # steenman_the.dat
2 | #
3 | # Josh Eisner
4 | # April 2, 2003
5 | #
6 | # Hold Extinction Coefficients from Steenman & The 1991, Ap&SS,184,9S
7 | #
8 | # Filter Wvlngth(um) A_lambda/A_v
9 | JohnU 0.36 1.65
10 | JohnB 0.44 1.33
11 | JohnV 0.55 1.00
12 | CousR 0.64 0.82
13 | JohnR 0.70 0.72
14 | CousI 0.79 0.60
15 | JohnI 0.90 0.48
16 | J 1.25 0.26
17 | H 1.65 0.15
18 | K 2.20 0.08
19 | L 3.60 0.03
20 | M 4.80 0.02
21 |
--------------------------------------------------------------------------------
/docs/utils.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | pdspy.utils
5 | ===============================
6 |
7 | .. automodule:: pdspy.utils
8 | .. currentmodule:: pdspy.utils
9 |
10 | utils.load_config
11 | ---------------------------------
12 |
13 | .. autofunction:: load_config
14 |
15 | utils.load_data
16 | ---------------------------------
17 |
18 | .. autofunction:: load_data
19 |
20 | utils.load_results
21 | ---------------------------------
22 |
23 | .. autofunction:: load_results
24 |
25 |
--------------------------------------------------------------------------------
/pdspy/mcmc/change_params.py:
--------------------------------------------------------------------------------
1 | from numpy import zeros
2 | from numpy.random import randint, normal
3 |
4 | def change_params(params, sigma_params, change_param=None):
5 |
6 | new_params = zeros(params.size)
7 |
8 | if change_param == None:
9 | change_param = randint(low=0, high=params.size, size=1)[0]
10 |
11 | new_params = params.copy()
12 | new_params[change_param] = params[change_param] + \
13 | normal(loc=0., scale=sigma_params[change_param], size=1)[0]
14 |
15 | return new_params
16 |
--------------------------------------------------------------------------------
/pdspy/interferometry/__init__.py:
--------------------------------------------------------------------------------
1 | from .libinterferometry import Visibilities, average, grid, freqcorrect, chisq
2 | from .readuvfits import readuvfits
3 | from .readvis import readvis
4 | from .center import center
5 | from .clean import clean
6 | from .concatenate import concatenate
7 | from .fit_model import fit_model
8 | from .invert import invert
9 | from .model import model
10 | from .rotate import rotate
11 | from .interpolate_model import interpolate_model
12 |
13 | try:
14 | from .readms import readms
15 | except:
16 | pass
17 |
18 | from .rmlimage import rmlimage
19 |
--------------------------------------------------------------------------------
/pdspy/spectroscopy/freefree.py:
--------------------------------------------------------------------------------
1 | import numpy
2 |
3 | def freefree(nu, F_nu_ff, nu_turn, pl_turn):
4 | if type(nu) == numpy.ndarray:
5 | flux = numpy.where(nu < nu_turn, F_nu_ff * (nu / nu_turn)**pl_turn, \
6 | F_nu_ff * (nu / nu_turn)**-0.1)
7 |
8 | flux = numpy.where(nu > 1.0e13, 0., flux)
9 |
10 | return flux
11 | else:
12 | if nu < nu_turn:
13 | return F_nu_ff * (nu / nu_turn)**pl_turn
14 | elif nu > 1.0e13:
15 | return 0.
16 | else:
17 | return F_nu_ff * (nu / nu_turn)**-0.1
18 |
--------------------------------------------------------------------------------
/pdspy/statistics/linear_regression.py:
--------------------------------------------------------------------------------
1 | import numpy
2 |
3 | def linear_regression(_x, _y, sigma_y=None):
4 |
5 | x = numpy.mat(_x).T
6 | y = numpy.mat(_y).T
7 |
8 | A = numpy.concatenate((x, numpy.ones(x.shape)), axis=1)
9 |
10 | if type(sigma_y) != type(None):
11 | C = numpy.diag(sigma_y**2)
12 | else:
13 | C = numpy.diag(numpy.ones(_y.shape))
14 |
15 | Xa = numpy.linalg.inv(A.T * numpy.linalg.inv(C) * A) * \
16 | (A.T * numpy.linalg.inv(C) * y)
17 |
18 | Cov = numpy.linalg.inv(A.T * numpy.linalg.inv(C) * A)
19 |
20 | return Xa[0,0], Xa[1,0], Cov[0,0]**0.5, Cov[1,1]**0.5
21 |
--------------------------------------------------------------------------------
/pdspy/constants/NumberUnit.py:
--------------------------------------------------------------------------------
1 | class NumberUnit:
2 |
3 | def __init__(self,cgs):
4 | self.cgs = cgs
5 |
6 | def __add__(self,a):
7 | return self.cgs + a
8 |
9 | def __radd__(self,a):
10 | return self.cgs + a
11 |
12 | def __sub__(self,a):
13 | return self.cgs - a
14 |
15 | def __rsub__(self,a):
16 | return a - self.cgs
17 |
18 | def __mul__(self,a):
19 | return self.cgs * a
20 |
21 | def __rmul__(self,a):
22 | return self.cgs * a
23 |
24 | def __div__(self,a):
25 | return self.cgs / a
26 |
27 | def __rdiv__(self,a):
28 | return a / self.cgs
29 |
--------------------------------------------------------------------------------
/pdspy/gas/data/test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.constants.math import pi
4 | from pdspy.modeling import YSOModel
5 | from pdspy.gas import Gas
6 | import numpy
7 | import matplotlib.pyplot as plt
8 | import matplotlib
9 |
10 | # Change a few of the plotting parameters.
11 |
12 | matplotlib.rcParams['font.family'] = 'serif'
13 |
14 | # Read in the gas.
15 |
16 | g = Gas()
17 | g.set_properties_from_lambda('co.dat')
18 |
19 | # Make the model.
20 |
21 | model = YSOModel()
22 | model.set_spherical_grid(0.1,20.,100,2,2)
23 | model.add_star()
24 | model.add_disk(rmax=20., gas=g, abundance=1.0e-5)
25 |
26 | # Save the model.
27 |
28 | model.write_yso("test.hdf5")
29 |
30 |
--------------------------------------------------------------------------------
/pdspy/constants/physics.py:
--------------------------------------------------------------------------------
1 | c = 2.99792458e10 # cm s^-1
2 | h = 6.6260755e-27 # erg s
3 | hbar = 1.05457266e-27 # erg s
4 | G = 6.67259e-8 # cm^3 g^-1 s^-2
5 | e = 4.8032068e-10 # esu
6 | m_e = 9.1093897e-28 # g
7 | m_p = 1.6726231e-24 # g
8 | m_n = 1.6749286e-24 # g
9 | m_H = 1.6733e-24 # g
10 | amu = 1.6605402e-24 # g
11 | N_A = 6.0221367e23 #
12 | k = 1.380658e-16 # erg K^-1
13 | eV = 1.6021772e-12 # erg
14 | a = 7.5646e-15 # erg cm^-3 K^-4
15 | sigma = 5.67051e-5 # erg cm^-2 K^-4 s^-1
16 | alpha = 7.29735308e-3 #
17 | R = 2.1798741e-11 # erg
18 |
--------------------------------------------------------------------------------
/pdspy/__init__.py:
--------------------------------------------------------------------------------
1 | import warnings
2 |
3 | text = warnings.warn("pdspy v2.0.0 represents a major update to the pdspy code, and is not backwards compatible with the results of versions < 2.0.0. *Do not use v2.0.0 to work with results from earlier versions.* For more information, see pdspy.readthedocs.io.", stacklevel=2)
4 |
5 | from . import constants
6 | from . import dust
7 | from . import gas
8 | from . import imaging
9 | from . import interferometry
10 | from . import mcmc
11 | from . import misc
12 | from . import modeling
13 | from . import plotting
14 | from . import radmc3d
15 | from . import spectroscopy
16 | from . import stars
17 | from . import statistics
18 | from . import table
19 | from . import utils
20 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/pdspy/statistics/Ftest.py:
--------------------------------------------------------------------------------
1 | import numpy
2 |
3 | def Ftest(data1, data2, tailed=2):
4 |
5 | N = len(data1)
6 | M = len(data2)
7 |
8 | mean1 = numpy.mean(data1)
9 | mean2 = numpy.mean(data2)
10 |
11 | S1 = numpy.sum((data1 - mean1)**2) / (N - 1)
12 | S2 = numpy.sum((data2 - mean2)**2) / (M - 1)
13 |
14 | F = S1 / S2
15 | f = numpy.random.f(N-1, M-1, 100000)
16 |
17 | if tailed == 1:
18 | if F > 1:
19 | p = len(f[f > F]) / len(f)
20 | elif F < 1:
21 | p = len(f[f < F]) / len(f)
22 | elif tailed == 2:
23 | if F > 1:
24 | p = len(f[(f > F) | (f < 1./F)]) / len(f)
25 | elif F < 1:
26 | p = len(f[(f > 1./F) | (f < F)]) / len(f)
27 |
28 | return F, p
29 |
--------------------------------------------------------------------------------
/docs/plotting.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | pdspy.plotting
5 | ===============================
6 |
7 | .. automodule:: pdspy.plotting
8 | .. currentmodule:: pdspy.plotting
9 |
10 | plotting.plot_1D_visibilities
11 | ---------------------------------
12 |
13 | .. autofunction:: plot_1D_visibilities
14 |
15 | plotting.plot_continuum_image
16 | ---------------------------------
17 |
18 | .. autofunction:: plot_continuum_image
19 |
20 | plotting.plot_channel_maps
21 | ---------------------------------
22 |
23 | .. autofunction:: plot_channel_maps
24 |
25 | plotting.plot_SED
26 | ---------------------------------
27 |
28 | .. autofunction:: plot_SED
29 |
30 | plotting.plot_pvdiagram
31 | ---------------------------------
32 |
33 | .. autofunction:: plot_pvdiagram
34 |
--------------------------------------------------------------------------------
/pdspy/modeling/__init__.py:
--------------------------------------------------------------------------------
1 | from .Disk import Disk
2 | from .DartoisDisk import DartoisDisk
3 | from .SettledDisk import SettledDisk
4 |
5 | from .PringleDisk import PringleDisk
6 | from .DartoisPringleDisk import DartoisPringleDisk
7 | from .SettledPringleDisk import SettledPringleDisk
8 |
9 | from .Grid import Grid
10 | from .Model import Model
11 | from .Star import Star
12 | from .UlrichEnvelope import UlrichEnvelope
13 | from .UlrichEnvelopeExtended import UlrichEnvelopeExtended
14 | from .TaperedUlrichEnvelope import TaperedUlrichEnvelope
15 | from .TaperedUlrichEnvelopeExtended import TaperedUlrichEnvelopeExtended
16 | from .YSOModel import YSOModel
17 |
18 | from .run_disk_model import run_disk_model
19 | from .run_flared_model import run_flared_model
20 | from .check_parameters import check_parameters
21 | from .get_surrogate_model import get_surrogate_model
22 |
--------------------------------------------------------------------------------
/pdspy/statistics/ttest.py:
--------------------------------------------------------------------------------
1 | import numpy
2 |
3 | def ttest(data1, data2, tailed=2):
4 |
5 | n = len(data1)
6 | m = len(data2)
7 | nu = n + m - 2
8 |
9 | mean1 = numpy.mean(data1)
10 | mean2 = numpy.mean(data2)
11 |
12 | S1 = numpy.sum((data1 - mean1)**2) / n
13 | S2 = numpy.sum((data2 - mean2)**2) / m
14 |
15 | s = (n*S1 + m*S2) / nu
16 |
17 | t = (mean1 - mean2) / (numpy.sqrt(s) * numpy.sqrt(m**-1 + n**-1))
18 |
19 | T = numpy.random.standard_t(nu, size=100000)
20 |
21 | if tailed == 1:
22 | if t < 0:
23 | p = len(T[T < t]) / len(T)
24 | elif t > 0:
25 | p = len(T[T > t]) / len(T)
26 | elif tailed == 2:
27 | if t < 0:
28 | p = len(T[(T < t) | (T > -t)]) / len(T)
29 | elif t > 0:
30 | p = len(T[(T > t) | (T < -t)]) / len(T)
31 |
32 | return t, p
33 |
--------------------------------------------------------------------------------
/pdspy/mcmc/ml2d.py:
--------------------------------------------------------------------------------
1 | from numpy import sqrt, exp, pi
2 |
3 | def ml2d(x, y, z, sigma_z, params, model, args=None, limits=None):
4 |
5 | if (type(limits) != type(None)):
6 | for i in range(params.size):
7 | if ((limits[i]["limited"][0] == True) and \
8 | (params[i] < limits[i]["limits"][0])):
9 | ml = 0.0
10 | chisq = 1.0e300
11 | return ml, chisq
12 | elif ((limits[i]["limited"][1] == True) and \
13 | (params[i] > limits[i]["limits"][1])):
14 | ml = 0.0
15 | chisq = 1.0e300
16 | return ml, chisq
17 |
18 | m = model(x, y, params, **args)
19 |
20 | mlarr = 1./sqrt(2*pi*sigma_z**2)*\
21 | exp(-(z-m)**2/(2*sigma_z**2))
22 |
23 | ml = (mlarr**(1./(z.size-params.size))).prod()
24 | chisq = ((z-m)**2/sigma_z**2).sum()
25 |
26 | return ml, chisq
27 |
--------------------------------------------------------------------------------
/pdspy/mcmc/ml.py:
--------------------------------------------------------------------------------
1 | from numpy import sqrt, exp, pi
2 |
3 | def ml(x, y, sigma_y, params, model, args=None, limits=None):
4 |
5 | if (type(limits) != type(None)):
6 | for i in range(params.size):
7 | if ((limits[i]["limited"][0] == True) and \
8 | (params[i] < limits[i]["limits"][0])):
9 | ml = 0.0
10 | chisq = 1.0e300
11 | return ml, chisq
12 | elif ((limits[i]["limited"][1] == True) and \
13 | (params[i] > limits[i]["limits"][1])):
14 | ml = 0.0
15 | chisq = 1.0e300
16 | return ml, chisq
17 |
18 | m = model(x, params, **args)
19 |
20 | mlarr = 1./sqrt(2*pi*sigma_y**2)*\
21 | exp(-(y-m)**2/(2*sigma_y**2))
22 |
23 | #ml = (mlarr**(1./(y.size-params.size))).prod()
24 | ml = 1.
25 | chisq = ((y-m)**2/sigma_y**2).sum()
26 |
27 | return ml, chisq
28 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/pdspy/interferometry/center.py:
--------------------------------------------------------------------------------
1 | from .model import model
2 | from .libinterferometry import Visibilities
3 | import numpy
4 |
5 | def center(data, params):
6 |
7 | if type(params) == list:
8 | params = numpy.array(params)
9 | elif type(params) == numpy.ndarray:
10 | pass
11 |
12 | centering_params = [params[0], params[1], 1.]
13 |
14 | data_complex = data.real+1j*data.imag
15 |
16 | model_complex = numpy.empty(data.real.shape, dtype=complex)
17 | for i in range(len(data.freq)):
18 | model_complex[:,i] = model(data.u*data.freq[i]/data.freq.mean(), \
19 | data.v*data.freq[i]/data.freq.mean(), centering_params, \
20 | funct="point", return_type="complex")[:,0]
21 |
22 | centered_data = data_complex * model_complex.conj()
23 |
24 | return Visibilities(data.u.copy(), data.v.copy(), data.freq.copy(), \
25 | centered_data.real, centered_data.imag, data.weights.copy())
26 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_dsharp.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | troilite = Dust()
7 | troilite.set_optical_constants_from_henn("optical_constants/troilite.txt")
8 | troilite.set_density(4.83)
9 |
10 | water_ice = Dust()
11 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
12 | water_ice.set_density(0.92)
13 |
14 | silicates = Dust()
15 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
16 | silicates.set_density(3.3)
17 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
18 |
19 | organics = Dust()
20 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
21 | organics.set_density(1.5)
22 |
23 | species = [silicates,troilite,organics,water_ice]
24 | abundances = [0.1670,0.0258,0.4430,0.3642]
25 |
26 | dust = mix_dust(species, abundances)
27 |
28 | # Create the dust generator class.
29 |
30 | dust_gen = DustGenerator(dust)
31 |
32 | dust_gen.write("dsharp.hdf5")
33 |
--------------------------------------------------------------------------------
/pdspy/interferometry/rmlimage.py:
--------------------------------------------------------------------------------
1 | from scipy.optimize import minimize
2 | from ..imaging import Image
3 | from . import interpolate_model
4 | import numpy
5 |
6 | def rmlimage(data, imsize=512, pixelsize=0.01):
7 |
8 | def neg_ln_like(p):
9 | if numpy.any(p <= 0):
10 | return numpy.inf
11 | else:
12 | model = Image(numpy.array(p).reshape((imsize,imsize,1,1)), \
13 | x=numpy.arange(imsize)*pixelsize, y=numpy.arange(imsize)*\
14 | pixelsize, freq=data.freq)
15 |
16 | model_vis = interpolate_model(data.u, data.v, data.freq, model)
17 |
18 | return ((data.real - model_vis.real)**2 * data.weights + \
19 | (data.imag - model_vis.imag)**2 * data.weights).sum() + \
20 | (model.image * numpy.log(model.image)).sum()
21 |
22 | result = minimize(neg_ln_like, numpy.ones(imsize**2))
23 |
24 | return Image(numpy.array(result.x).reshape((imsize,imsize,1,1)), \
25 | x=numpy.arange(imsize)*pixelsize, y=numpy.arange(imsize)*\
26 | pixelsize, freq=data.freq)
27 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | amorphous_carbon = Dust()
11 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
12 | #amorphous_carbon.set_density(2.24)
13 | amorphous_carbon.set_density(1.0)
14 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | silicates = Dust()
17 | silicates.set_optical_constants_from_henn("optical_constants/amorphous_silicates_extrapolated.txt")
18 | silicates.set_density(3.3)
19 | silicates.calculate_optical_constants_on_wavelength_grid(amorphous_carbon.lam)
20 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
21 |
22 | species = [silicates,amorphous_carbon]
23 | abundances = numpy.array([0.8,0.2])
24 |
25 | dust = mix_dust(species, abundances, filling=0.75)
26 |
27 | dust_gen = DustGenerator(dust, with_dhs=True)
28 |
29 | dust_gen.write('diana.hdf5')
30 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana_wice.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | silicates = Dust()
11 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
12 | silicates.set_density(3.3)
13 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
14 |
15 | amorphous_carbon = Dust()
16 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
17 | #amorphous_carbon.set_density(2.24)
18 | amorphous_carbon.set_density(1.0)
19 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
20 |
21 | species = [silicates,amorphous_carbon,water_ice]
22 | abundances = numpy.array([0.8,0.2,0.5])
23 | abundances = abundances / abundances.sum()
24 | print(abundances)
25 |
26 | dust = mix_dust(species, abundances, filling=0.75)
27 |
28 | dust_gen = DustGenerator(dust, with_dhs=True)
29 |
30 | dust_gen.write('diana_wice.hdf5')
31 |
--------------------------------------------------------------------------------
/pdspy/imaging/imtovis.py:
--------------------------------------------------------------------------------
1 | import numpy
2 | from ..interferometry import Visibilities
3 | from ..constants.astronomy import pc, arcsec
4 | from scipy.fftpack import fft2, fftshift, fftfreq, ifftshift
5 |
6 | def imtovis(image):
7 |
8 | ##### Some natural constants
9 |
10 | real = numpy.empty((image.x.size*image.y.size,image.freq.size))
11 | imag = numpy.empty((image.x.size*image.y.size,image.freq.size))
12 | weights = numpy.ones(real.shape)
13 | for i in range(image.freq.size):
14 | vis = fftshift(fft2(ifftshift(image.image[:,:,i,0])))
15 | real[:,i] = vis.real.reshape((image.x.size*image.y.size,))
16 | imag[:,i] = vis.imag.reshape((image.x.size*image.y.size,))
17 |
18 | uu = fftshift(fftfreq(image.x.size, (image.x[1] - image.x[0]) * arcsec))
19 | vv = fftshift(fftfreq(image.y.size, (image.y[1] - image.y[0]) * arcsec))
20 |
21 | u, v = numpy.meshgrid(uu, vv)
22 | u = u.reshape((image.x.size*image.y.size,))
23 | v = v.reshape((image.y.size*image.y.size,))
24 |
25 | freq = image.freq
26 |
27 | return Visibilities(u, v, freq, real, imag, weights)
28 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana_wice_singlesize.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | silicates = Dust()
11 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
12 | silicates.set_density(3.3)
13 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
14 |
15 | amorphous_carbon = Dust()
16 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
17 | #amorphous_carbon.set_density(2.24)
18 | amorphous_carbon.set_density(1.0)
19 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
20 |
21 | species = [silicates,amorphous_carbon,water_ice]
22 | abundances = numpy.array([0.8,0.2,0.5])
23 | abundances = abundances / abundances.sum()
24 | print(abundances)
25 |
26 | dust = mix_dust(species, abundances, filling=0.75)
27 |
28 | dust_gen = DustGenerator(dust, with_dhs=True, singlesize=True)
29 |
30 | dust_gen.write('diana_wice_singlesize.hdf5')
31 |
--------------------------------------------------------------------------------
/pdspy/mcmc/mcmc.py:
--------------------------------------------------------------------------------
1 | from numpy import array, arange, exp
2 | from numpy.random import uniform
3 | from .change_params import change_params
4 | from .ml import ml
5 |
6 | def mcmc(x, y, sigma_y, params, sigma_params, model, args={}, \
7 | nsteps=1e5, change_param=None, limits=None):
8 |
9 | MLold, chisq_old = ml(x, y, sigma_y, params, model, args=args, \
10 | limits=limits)
11 |
12 | accepted_params = []
13 |
14 | for i in arange(nsteps):
15 | new_params = change_params(params, sigma_params, \
16 | change_param=change_param)
17 |
18 | MLnew, chisq_new = ml(x, y, sigma_y, new_params, model, \
19 | args=args, limits=limits)
20 |
21 | if chisq_new < chisq_old:
22 | accepted_params.append(params)
23 | params = new_params
24 | MLold = MLnew
25 | chisq_old = chisq_new
26 | else:
27 | if uniform(low=0., high=1., size=1)[0] <= \
28 | exp(0.5*(chisq_old-chisq_new)):
29 | accepted_params.append(params)
30 | params = new_params
31 | MLold = MLnew
32 | chisq_old = chisq_new
33 |
34 | return array(accepted_params)
35 |
--------------------------------------------------------------------------------
/pdspy/statistics/leastsq.py:
--------------------------------------------------------------------------------
1 | import scipy.optimize
2 | import numpy
3 |
4 | def leastsq(func, x0, args=(), limits=None, Dfun=None, full_output=0, \
5 | col_deriv=0, ftol=1.49012e-08, xtol=1.49012e-08, gtol=0.0, maxfev=0, \
6 | epsfcn=None, factor=100, diag=None):
7 |
8 | def within_bounds(p):
9 | if (type(limits) != type(None)):
10 | for i in range(len(p)):
11 | if ((limits[i]["limited"][0] == True) and \
12 | (p[i] < limits[i]["limits"][0])):
13 | return False
14 | elif ((limits[i]["limited"][1] == True) and \
15 | (p[i] > limits[i]["limits"][1])):
16 | return False
17 |
18 | return True
19 | else:
20 | return True
21 |
22 | def residuals(p):
23 | if within_bounds(p):
24 | return func(p, *args)
25 | else:
26 | return numpy.repeat(1e20, len(func(p, *args)))
27 |
28 | return scipy.optimize.leastsq(residuals, x0, args=(), \
29 | full_output=full_output, col_deriv=col_deriv, ftol=ftol, \
30 | xtol=xtol, gtol=gtol, maxfev=maxfev, epsfcn=epsfcn, factor=factor, \
31 | diag=diag)
32 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana_10cm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | amorphous_carbon = Dust()
11 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
12 | #amorphous_carbon.set_density(2.24)
13 | amorphous_carbon.set_density(1.0)
14 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | silicates = Dust()
17 | silicates.set_optical_constants_from_henn("optical_constants/amorphous_silicates_extrapolated.txt")
18 | silicates.set_density(3.3)
19 | silicates.calculate_optical_constants_on_wavelength_grid(amorphous_carbon.lam)
20 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
21 |
22 | species = [silicates,amorphous_carbon]
23 | abundances = numpy.array([0.8,0.2])
24 |
25 | dust = mix_dust(species, abundances, filling=0.75)
26 |
27 | amin = 0.05e-4
28 | amax = 1.000e1
29 | pl = 3.5
30 |
31 | dust.calculate_size_distribution_opacity(amin, amax, pl, with_dhs=True, \
32 | coat_volume_fraction=0.0, nang=1)
33 |
34 | dust.write('diana_10cm.hdf5')
35 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana_10um.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | amorphous_carbon = Dust()
11 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
12 | #amorphous_carbon.set_density(2.24)
13 | amorphous_carbon.set_density(1.0)
14 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | silicates = Dust()
17 | silicates.set_optical_constants_from_henn("optical_constants/amorphous_silicates_extrapolated.txt")
18 | silicates.set_density(3.3)
19 | silicates.calculate_optical_constants_on_wavelength_grid(amorphous_carbon.lam)
20 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
21 |
22 | species = [silicates,amorphous_carbon]
23 | abundances = numpy.array([0.8,0.2])
24 |
25 | dust = mix_dust(species, abundances, filling=0.75)
26 |
27 | amin = 0.05e-4
28 | amax = 1.000e-3
29 | pl = 3.5
30 |
31 | dust.calculate_size_distribution_opacity(amin, amax, pl, with_dhs=True, \
32 | coat_volume_fraction=0.0, nang=1)
33 |
34 | dust.write('diana_10um.hdf5')
35 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana_1cm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | amorphous_carbon = Dust()
11 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
12 | #amorphous_carbon.set_density(2.24)
13 | amorphous_carbon.set_density(1.0)
14 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | silicates = Dust()
17 | silicates.set_optical_constants_from_henn("optical_constants/amorphous_silicates_extrapolated.txt")
18 | silicates.set_density(3.3)
19 | silicates.calculate_optical_constants_on_wavelength_grid(amorphous_carbon.lam)
20 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
21 |
22 | species = [silicates,amorphous_carbon]
23 | abundances = numpy.array([0.8,0.2])
24 |
25 | dust = mix_dust(species, abundances, filling=0.75)
26 |
27 | amin = 0.05e-4
28 | amax = 1.000e0
29 | pl = 3.5
30 |
31 | dust.calculate_size_distribution_opacity(amin, amax, pl, with_dhs=True, \
32 | coat_volume_fraction=0.0, nang=1)
33 |
34 | dust.write('diana_1cm.hdf5')
35 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana_1mm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | amorphous_carbon = Dust()
11 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
12 | #amorphous_carbon.set_density(2.24)
13 | amorphous_carbon.set_density(1.0)
14 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | silicates = Dust()
17 | silicates.set_optical_constants_from_henn("optical_constants/amorphous_silicates_extrapolated.txt")
18 | silicates.set_density(3.3)
19 | silicates.calculate_optical_constants_on_wavelength_grid(amorphous_carbon.lam)
20 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
21 |
22 | species = [silicates,amorphous_carbon]
23 | abundances = numpy.array([0.8,0.2])
24 |
25 | dust = mix_dust(species, abundances, filling=0.75)
26 |
27 | amin = 0.05e-4
28 | amax = 1.000e-1
29 | pl = 3.5
30 |
31 | dust.calculate_size_distribution_opacity(amin, amax, pl, with_dhs=True, \
32 | coat_volume_fraction=0.0, nang=1)
33 |
34 | dust.write('diana_1mm.hdf5')
35 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana_1um.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | amorphous_carbon = Dust()
11 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
12 | #amorphous_carbon.set_density(2.24)
13 | amorphous_carbon.set_density(1.0)
14 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | silicates = Dust()
17 | silicates.set_optical_constants_from_henn("optical_constants/amorphous_silicates_extrapolated.txt")
18 | silicates.set_density(3.3)
19 | silicates.calculate_optical_constants_on_wavelength_grid(amorphous_carbon.lam)
20 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
21 |
22 | species = [silicates,amorphous_carbon]
23 | abundances = numpy.array([0.8,0.2])
24 |
25 | dust = mix_dust(species, abundances, filling=0.75)
26 |
27 | amin = 0.05e-4
28 | amax = 1.000e-4
29 | pl = 3.5
30 |
31 | dust.calculate_size_distribution_opacity(amin, amax, pl, with_dhs=True, \
32 | coat_volume_fraction=0.0, nang=1)
33 |
34 | dust.write('diana_1um.hdf5')
35 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana_wice_1cm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | silicates = Dust()
11 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
12 | silicates.set_density(3.3)
13 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
14 |
15 | amorphous_carbon = Dust()
16 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
17 | #amorphous_carbon.set_density(2.24)
18 | amorphous_carbon.set_density(1.0)
19 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
20 |
21 | species = [silicates,amorphous_carbon,water_ice]
22 | abundances = numpy.array([0.8,0.2,0.5])
23 | abundances = abundances / abundances.sum()
24 | print(abundances)
25 |
26 | dust = mix_dust(species, abundances, filling=0.75)
27 |
28 | amin = 0.05e-4
29 | amax = 1.000e0
30 | pl = 3.5
31 |
32 | dust.calculate_size_distribution_opacity(amin, amax, pl, with_dhs=True, \
33 | coat_volume_fraction=0.0, nang=1)
34 |
35 | dust.write('diana_wice_1cm.hdf5')
36 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana_wice_1mm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | silicates = Dust()
11 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
12 | silicates.set_density(3.3)
13 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
14 |
15 | amorphous_carbon = Dust()
16 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
17 | #amorphous_carbon.set_density(2.24)
18 | amorphous_carbon.set_density(1.0)
19 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
20 |
21 | species = [silicates,amorphous_carbon,water_ice]
22 | abundances = numpy.array([0.8,0.2,0.5])
23 | abundances = abundances / abundances.sum()
24 | print(abundances)
25 |
26 | dust = mix_dust(species, abundances, filling=0.75)
27 |
28 | amin = 0.05e-4
29 | amax = 1.000e-1
30 | pl = 3.5
31 |
32 | dust.calculate_size_distribution_opacity(amin, amax, pl, with_dhs=True, \
33 | coat_volume_fraction=0.0, nang=1)
34 |
35 | dust.write('diana_wice_1mm.hdf5')
36 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana_wice_1um.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | silicates = Dust()
11 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
12 | silicates.set_density(3.3)
13 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
14 |
15 | amorphous_carbon = Dust()
16 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
17 | #amorphous_carbon.set_density(2.24)
18 | amorphous_carbon.set_density(1.0)
19 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
20 |
21 | species = [silicates,amorphous_carbon,water_ice]
22 | abundances = numpy.array([0.8,0.2,0.5])
23 | abundances = abundances / abundances.sum()
24 | print(abundances)
25 |
26 | dust = mix_dust(species, abundances, filling=0.75)
27 |
28 | amin = 0.05e-4
29 | amax = 1.000e-4
30 | pl = 3.5
31 |
32 | dust.calculate_size_distribution_opacity(amin, amax, pl, with_dhs=True, \
33 | coat_volume_fraction=0.0, nang=1)
34 |
35 | dust.write('diana_wice_1um.hdf5')
36 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_ricci_1um.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | organics = Dust()
11 | organics.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
12 | organics.set_density(2.24)
13 | organics.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
14 |
15 | silicates = Dust()
16 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
17 | silicates.set_density(3.3)
18 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
19 |
20 | species = [silicates,organics,water_ice]
21 | mass_fraction = numpy.array([2.64e-3,3.53e-3,5.55e-3])
22 | rho = numpy.array([silicates.rho,organics.rho,water_ice.rho])
23 | abundances = (mass_fraction/rho)/(mass_fraction/rho).sum()
24 | print(abundances)
25 |
26 | dust = mix_dust(species, abundances, filling=0.6)
27 |
28 | amin = 0.1e-4
29 | amax = 1.000e-4
30 | pl = 3.5
31 |
32 | dust.calculate_size_distribution_opacity(amin, amax, pl, with_dhs=True, \
33 | coat_volume_fraction=0.0)
34 |
35 | dust.write('ricci_1um.hdf5')
36 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana_100um.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | amorphous_carbon = Dust()
11 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
12 | #amorphous_carbon.set_density(2.24)
13 | amorphous_carbon.set_density(1.0)
14 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | silicates = Dust()
17 | silicates.set_optical_constants_from_henn("optical_constants/amorphous_silicates_extrapolated.txt")
18 | silicates.set_density(3.3)
19 | silicates.calculate_optical_constants_on_wavelength_grid(amorphous_carbon.lam)
20 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
21 |
22 | species = [silicates,amorphous_carbon]
23 | abundances = numpy.array([0.8,0.2])
24 |
25 | dust = mix_dust(species, abundances, filling=0.75)
26 |
27 | amin = 0.05e-4
28 | amax = 1.000e-2
29 | pl = 3.5
30 |
31 | dust.calculate_size_distribution_opacity(amin, amax, pl, with_dhs=True, \
32 | coat_volume_fraction=0.0, nang=1)
33 |
34 | dust.write('diana_100um.hdf5')
35 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana_wice_100um.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | silicates = Dust()
11 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
12 | silicates.set_density(3.3)
13 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
14 |
15 | amorphous_carbon = Dust()
16 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
17 | #amorphous_carbon.set_density(2.24)
18 | amorphous_carbon.set_density(1.0)
19 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
20 |
21 | species = [silicates,amorphous_carbon,water_ice]
22 | abundances = numpy.array([0.8,0.2,0.5])
23 | abundances = abundances / abundances.sum()
24 | print(abundances)
25 |
26 | dust = mix_dust(species, abundances, filling=0.75)
27 |
28 | amin = 0.05e-4
29 | amax = 1.000e-2
30 | pl = 3.5
31 |
32 | dust.calculate_size_distribution_opacity(amin, amax, pl, with_dhs=True, \
33 | coat_volume_fraction=0.0, nang=1)
34 |
35 | dust.write('diana_wice_100um.hdf5')
36 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana_wice_10cm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | silicates = Dust()
11 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
12 | silicates.set_density(3.3)
13 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
14 |
15 | amorphous_carbon = Dust()
16 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
17 | #amorphous_carbon.set_density(2.24)
18 | amorphous_carbon.set_density(1.0)
19 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
20 |
21 | species = [silicates,amorphous_carbon,water_ice]
22 | abundances = numpy.array([0.8,0.2,0.5])
23 | abundances = abundances / abundances.sum()
24 | print(abundances)
25 |
26 | dust = mix_dust(species, abundances, filling=0.75)
27 |
28 | amin = 0.05e-4
29 | amax = 1.000e1
30 | pl = 3.5
31 |
32 | dust.calculate_size_distribution_opacity(amin, amax, pl, with_dhs=True, \
33 | coat_volume_fraction=0.0, nang=1)
34 |
35 | dust.write('diana_wice_10cm.hdf5')
36 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_diana_wice_10um.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | silicates = Dust()
11 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
12 | silicates.set_density(3.3)
13 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
14 |
15 | amorphous_carbon = Dust()
16 | amorphous_carbon.set_optical_constants_from_henn("optical_constants/amorphous_carbon_zubko1996_extrapolated.txt")
17 | #amorphous_carbon.set_density(2.24)
18 | amorphous_carbon.set_density(1.0)
19 | amorphous_carbon.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
20 |
21 | species = [silicates,amorphous_carbon,water_ice]
22 | abundances = numpy.array([0.8,0.2,0.5])
23 | abundances = abundances / abundances.sum()
24 | print(abundances)
25 |
26 | dust = mix_dust(species, abundances, filling=0.75)
27 |
28 | amin = 0.05e-4
29 | amax = 1.000e-3
30 | pl = 3.5
31 |
32 | dust.calculate_size_distribution_opacity(amin, amax, pl, with_dhs=True, \
33 | coat_volume_fraction=0.0, nang=1)
34 |
35 | dust.write('diana_wice_10um.hdf5')
36 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_pollack_new.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | troilite = Dust()
7 | troilite.set_optical_constants_from_henn("optical_constants/troilite.txt")
8 | troilite.set_density(4.83)
9 |
10 | organics = Dust()
11 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
12 | organics.set_density(1.5)
13 |
14 | water_ice = Dust()
15 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
16 | water_ice.set_density(0.92)
17 |
18 | silicates = Dust()
19 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
20 | silicates.set_density(3.3)
21 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
22 |
23 | species = [silicates,troilite,organics,water_ice]
24 | #mass_fraction = numpy.array([6.4e-3,7.68e-4,2.13e-3,1.4e-3])
25 | mass_fraction = numpy.array([3.41e-3,7.68e-4,4.13e-3,5.55e-3])
26 | rho = numpy.array([silicates.rho,troilite.rho,organics.rho,water_ice.rho])
27 | abundances = (mass_fraction/rho)/(mass_fraction/rho).sum()
28 |
29 | dust = mix_dust(species, abundances)
30 |
31 | # Create the dust generator class.
32 |
33 | dust_gen = DustGenerator(dust)
34 |
35 | dust_gen.write("pollack_new.hdf5")
36 |
--------------------------------------------------------------------------------
/pdspy/mcmc/mcmc2d.py:
--------------------------------------------------------------------------------
1 | from numpy import array, arange, exp
2 | from numpy.random import uniform
3 | from .change_params import change_params
4 | from .ml2d import ml2d
5 |
6 | def mcmc2d(x, y, z, sigma_z, params, sigma_params, model, args={}, \
7 | nsteps=1e5, change_param=None, limits=None):
8 |
9 | MLold, chisq_old = ml2d(x, y, z, sigma_z, params, model, args=args, \
10 | limits=limits)
11 |
12 | accepted_params = []
13 |
14 | for i in arange(nsteps):
15 | new_params = change_params(params, sigma_params, \
16 | change_param=change_param)
17 |
18 | MLnew, chisq_new = ml2d(x, y, z, sigma_z, new_params, model, \
19 | args=args, limits=limits)
20 |
21 | if chisq_new < chisq_old:
22 | accepted_params.append(params)
23 | params = new_params
24 | MLold = MLnew
25 | chisq_old = chisq_new
26 | else:
27 | if uniform(low=0., high=1., size=1)[0] <= \
28 | exp(0.5*(chisq_old-chisq_new)):
29 | accepted_params.append(params)
30 | params = new_params
31 | MLold = MLnew
32 | chisq_old = chisq_new
33 |
34 | return array(accepted_params)
35 |
--------------------------------------------------------------------------------
/pdspy/dust/data/optical_constants/extrapolate_as.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import matplotlib.pyplot as plt
4 | import pdspy.dust as dust
5 | import numpy
6 |
7 | d = dust.Dust()
8 | d.set_optical_constants_from_henn("amorphous_silicates.txt")
9 |
10 | new_lam = numpy.logspace(numpy.log10(d.lam[-1]),numpy.log10(d.lam[-1]*10),50)
11 |
12 | lognpoly = numpy.polyfit(numpy.log10(d.lam[d.lam > 1.0e-1]), \
13 | numpy.log10(d.n[d.lam > 1.0e-1]), deg=1)
14 |
15 | logkpoly = numpy.polyfit(numpy.log10(d.lam[d.lam > 1.0e-1]), \
16 | numpy.log10(d.k[d.lam > 1.0e-1]), deg=1)
17 |
18 | new_n = 10.**numpy.polyval(lognpoly, numpy.log10(new_lam))
19 | new_k = 10.**numpy.polyval(logkpoly, numpy.log10(new_lam))
20 |
21 | new_lam = numpy.concatenate((d.lam, new_lam[1:]))
22 | new_n = numpy.concatenate((d.n, new_n[1:]))
23 | new_k = numpy.concatenate((d.k, new_k[1:]))
24 |
25 | plt.loglog(d.lam, d.n, "b-")
26 | plt.loglog(new_lam, new_n, "b--")
27 |
28 | plt.loglog(d.lam, d.k, "r-")
29 | plt.loglog(new_lam, new_k, "r--")
30 |
31 | plt.show()
32 |
33 | f = open("amorphous_silicates_extrapolated.txt", "w")
34 |
35 | for i in range(len(new_lam)):
36 | f.write("{0:f} {1:f} {2:f}\n".format(new_lam[i]/1.0e-4, new_n[i], \
37 | new_k[i]))
38 |
39 | f.close()
40 |
--------------------------------------------------------------------------------
/pdspy/stars/Teff_from_SpT.py:
--------------------------------------------------------------------------------
1 | import numpy
2 |
3 | def Teff_from_SpT(SpT, relation="HH14"):
4 |
5 | # Set up the data.
6 |
7 | SpT_list = ['F5','F8','G0',"G2", "G5", "G8", "K0", "K2", "K5", "K7", "M0", \
8 | "M1", "M2", "M3", "M4", "M5", "M6", "M7"]
9 | SpT_numbers = [float(test[0].replace("F","4").replace("G","3").\
10 | replace("K","2").replace("M","1") + str(9-float(test[1:]))) \
11 | for test in SpT_list]
12 |
13 | if relation == 'HH14':
14 | Teff_list = [6600, 6130, 5930, 5690, 5430, 5180, 4870, 4710, 4210, \
15 | 4020, 3900, 3720, 3560, 3410, 3190, 2980, 2860, 2770]
16 | elif relation == 'PM13':
17 | Teff_list = [6420, 6100, 6050, 5870, 5500, 5210, 5030, 4760, 4140, \
18 | 3970, 3770, 3630, 3490, 3360, 3160, 2880]
19 |
20 | SpT_list = SpT_list[0:-2]
21 | SpT_numbers = SpT_numbers[0:-2]
22 |
23 | # Now turn the provided spectral type into a number.
24 |
25 | SpT_number = float(SpT[0].replace("F","4").replace("G","3").\
26 | replace("K","2").replace("M","1") + str(9-float(SpT[1:])))
27 |
28 | # Finally, interpolate to a temperature.
29 |
30 | Teff = numpy.interp(SpT_number, SpT_numbers[::-1], Teff_list[::-1])
31 |
32 | return Teff
33 |
--------------------------------------------------------------------------------
/pdspy/dust/data/optical_constants/extrapolate_acz96.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import matplotlib.pyplot as plt
4 | import pdspy.dust as dust
5 | import numpy
6 |
7 | d = dust.Dust()
8 | d.set_optical_constants_from_henn("amorphous_carbon_zubko1996.txt")
9 |
10 | new_lam = numpy.logspace(numpy.log10(d.lam[-1]),numpy.log10(d.lam[-1]*10),50)
11 |
12 | lognpoly = numpy.polyfit(numpy.log10(d.lam[d.lam > 1.0e-1]), \
13 | numpy.log10(d.n[d.lam > 1.0e-1]), deg=1)
14 |
15 | logkpoly = numpy.polyfit(numpy.log10(d.lam[d.lam > 1.0e-1]), \
16 | numpy.log10(d.k[d.lam > 1.0e-1]), deg=1)
17 |
18 | new_n = 10.**numpy.polyval(lognpoly, numpy.log10(new_lam))
19 | new_k = 10.**numpy.polyval(logkpoly, numpy.log10(new_lam))
20 |
21 | new_lam = numpy.concatenate((d.lam, new_lam[1:]))
22 | new_n = numpy.concatenate((d.n, new_n[1:]))
23 | new_k = numpy.concatenate((d.k, new_k[1:]))
24 |
25 | plt.loglog(d.lam, d.n, "b-")
26 | plt.loglog(new_lam, new_n, "b--")
27 |
28 | plt.loglog(d.lam, d.k, "r-")
29 | plt.loglog(new_lam, new_k, "r--")
30 |
31 | plt.show()
32 |
33 | f = open("amorphous_carbon_zubko1996_extrapolated.txt", "w")
34 |
35 | for i in range(len(new_lam)):
36 | f.write("{0:f} {1:f} {2:f}\n".format(new_lam[i]/1.0e-4, new_n[i], \
37 | new_k[i]))
38 |
39 | f.close()
40 |
--------------------------------------------------------------------------------
/meta.yaml:
--------------------------------------------------------------------------------
1 | {% set name = "pdspy" %}
2 | {% set version = "2.0.8" %}
3 |
4 | package:
5 | name: {{ name|lower }}
6 | version: {{ version }}
7 |
8 | source:
9 | path: ../pdspy
10 |
11 | build:
12 | number: 0
13 | script: "{{ PYTHON }} -m pip install . -vv --no-deps"
14 | skip: True # [win]
15 |
16 | requirements:
17 | build:
18 | - {{ compiler('c') }}
19 | - {{ compiler('fortran') }}
20 | host:
21 | - python
22 | - numpy >=1.16
23 | - cython
24 | - pip
25 | run:
26 | - python
27 | - {{ pin_compatible('numpy>=1.16') }}
28 | - scipy
29 | - matplotlib-base
30 | - astropy
31 | - h5py
32 | - mpi4py
33 | - emcee
34 | - dynesty
35 | - corner
36 | - galario
37 | - schwimmbad
38 | - scikit-learn
39 |
40 | test:
41 | imports:
42 | - pdspy
43 | commands:
44 | - test -d ${PREFIX}
45 | - test -f ${PREFIX}/bin/disk_model.py
46 |
47 | about:
48 | home: https://github.com/psheehan/pdspy
49 | license: GPL-3.0-only
50 | license_family: GPL
51 | license_file: LICENSE
52 | summary: 'Radiative transfer modeling of protoplanetary disks'
53 |
54 | extra:
55 | recipe-maintainers:
56 | - psheehan
57 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_draine.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | #1/3
11 | graphite_parallel = Dust()
12 | graphite_parallel.set_optical_constants_from_draine("optical_constants/graphite_parallel_0.01.txt")
13 | graphite_parallel.set_density(2.24)
14 | graphite_parallel.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | #2/3
17 | graphite_perpendicular = Dust()
18 | graphite_perpendicular.set_optical_constants_from_draine("optical_constants/graphite_perpendicular_0.01.txt")
19 | graphite_perpendicular.set_density(2.24)
20 | graphite_perpendicular.calculate_optical_constants_on_wavelength_grid(\
21 | water_ice.lam)
22 |
23 | silicates = Dust()
24 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
25 | silicates.set_density(3.3)
26 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
27 |
28 | species = [silicates,graphite_parallel,graphite_perpendicular]
29 | abundances = numpy.array([0.65,0.35*1./3,0.35*2./3])
30 | print(abundances)
31 |
32 | dust = mix_dust(species, abundances)
33 |
34 | # Create the dust generator class.
35 |
36 | dust_gen = DustGenerator(dust)
37 |
38 | dust_gen.write("draine.hdf5")
39 |
--------------------------------------------------------------------------------
/pdspy/dust/data/optical_constants/PAH_qion.txt:
--------------------------------------------------------------------------------
1 | 3.5443603241341353, 0.19099992790714426
2 | 3.948168451911216, 0.2679335784490422
3 | 4.485109834840719, 0.3091207074712229
4 | 5.045342937893085, 0.3393151178718189
5 | 5.9608377769061995, 0.3777377261913345
6 | 6.973713698650947, 0.41066589767620687
7 | 8.118784695255469, 0.4449705620839641
8 | 9.35961822288943, 0.47515536010381365
9 | 10.42595729839427, 0.49710619277629586
10 | 11.332461379712768, 0.5163174969360537
11 | 12.936939791522699, 0.5451315694614663
12 | 15.061161573520614, 0.5780616634224882
13 | 17.109443206462625, 0.6068776584240503
14 | 19.3411986305669, 0.6384447167952323
15 | 22.40682877100203, 0.6727513036791388
16 | 25.70499980895651, 0.7084363059620793
17 | 31.123162362342114, 0.7537221541345254
18 | 36.4116642382865, 0.7935231778530748
19 | 40.5600364749332, 0.8195977218657632
20 | 45.6263728481819, 0.8470429913728883
21 | 50.08227535091069, 0.8717487323672891
22 | 54.17045171926874, 0.8675942614086944
23 | 57.73659415947844, 0.8661946987720184
24 | 62.14406622756642, 0.8661658616297792
25 | 66.23512666637937, 0.8702645807800448
26 | 70.94257957284145, 0.8757359479008964
27 | 77.48991458126022, 0.8853233364573572
28 | 82.5912210002754, 0.8949203373945642
29 | 88.8960352160657, 0.9058880638262082
30 | 92.00081914295062, 0.9347405858746066
31 | 96.15254798160309, 0.9677129743109125
32 | 99.51077295504223, 0.9979400668060463
33 |
--------------------------------------------------------------------------------
/pdspy/imaging/update_catalog.py:
--------------------------------------------------------------------------------
1 | import numpy
2 | import astropy
3 | import astropy.coordinates
4 |
5 | #def update_catalog(catalog, *lists, tol=0.3, column_names=['1']):
6 | def update_catalog(catalog, tol=0.3, column_names=['1'], *lists):
7 |
8 | coord_catalog = astropy.coordinates.SkyCoord(catalog["ra"].tolist(), \
9 | catalog["dec"].tolist(), frame='icrs')
10 | catalog["id"] = numpy.arange(len(catalog))
11 |
12 | for i, list1 in enumerate(lists):
13 | coord1 = astropy.coordinates.SkyCoord(list1["ra"].tolist(), \
14 | list1['dec'].tolist(), frame='icrs')
15 |
16 | idx, d2d, d3d = astropy.coordinates.match_coordinates_sky(coord1, \
17 | coord_catalog)
18 |
19 | ids, counts = numpy.unique(idx[d2d.arcsec < tol], return_counts=True)
20 | for j in range(len(ids)):
21 | if counts[j] > 1:
22 | min_d2d = min(d2d[idx == ids[j]].arcsec)
23 | d2d[(d2d.arcsec != min_d2d) & (idx == ids[j])] = \
24 | astropy.coordinates.Angle("0d00m{0:f}s".format(2*tol))
25 |
26 | for j, k in enumerate(idx):
27 | if d2d.arcsec[j] < tol:
28 | for key in list1.colnames:
29 | catalog[key+"_{0}".format(column_names[i])][k] = \
30 | list1[key][j]
31 |
32 | del catalog["id"]
33 |
34 | return catalog
35 |
--------------------------------------------------------------------------------
/pdspy/interferometry/readvis.py:
--------------------------------------------------------------------------------
1 | from .readuvfits import readuvfits
2 | from .libinterferometry import Visibilities
3 | from glob import glob
4 | import numpy
5 |
6 | def readvis(filename, fmt="casa"):
7 |
8 | filenames = numpy.array(glob(filename+"/*.uv.fits"))
9 |
10 | for i in range(filenames.size):
11 | if i == 0:
12 | vis = readuvfits(filenames[i],fmt=fmt)
13 |
14 | vis.u /= vis.freq.mean()
15 | vis.v /= vis.freq.mean()
16 | else:
17 | new = readuvfits(filenames[i],fmt=fmt)
18 |
19 | vis.freq = numpy.concatenate((vis.freq,new.freq))
20 | vis.real = numpy.concatenate((vis.real,new.real),axis=1)
21 | vis.imag = numpy.concatenate((vis.imag,new.imag),axis=1)
22 | vis.amp = numpy.concatenate((vis.amp,new.amp),axis=1)
23 | vis.weights = numpy.concatenate((vis.weights,new.weights),axis=1)
24 |
25 | vis.real = vis.real[:,numpy.argsort(vis.freq)][:,::-1]
26 | vis.imag = vis.imag[:,numpy.argsort(vis.freq)][:,::-1]
27 | vis.amp = vis.amp[:,numpy.argsort(vis.freq)][:,::-1]
28 | vis.weights = vis.weights[:,numpy.argsort(vis.freq)][:,::-1]
29 | vis.freq = vis.freq[numpy.argsort(vis.freq)][::-1]
30 |
31 | vis.u *= vis.freq.mean()
32 | vis.v *= vis.freq.mean()
33 |
34 | return Visibilities(vis.u, vis.v, vis.freq, vis.real, vis.imag, \
35 | vis.weights, baseline=vis.baseline)
36 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_draine_1cm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | #1/3
11 | graphite_parallel = Dust()
12 | graphite_parallel.set_optical_constants_from_draine("optical_constants/graphite_parallel_0.01.txt")
13 | graphite_parallel.set_density(2.24)
14 | graphite_parallel.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | #2/3
17 | graphite_perpendicular = Dust()
18 | graphite_perpendicular.set_optical_constants_from_draine("optical_constants/graphite_perpendicular_0.01.txt")
19 | graphite_perpendicular.set_density(2.24)
20 | graphite_perpendicular.calculate_optical_constants_on_wavelength_grid(\
21 | water_ice.lam)
22 |
23 | silicates = Dust()
24 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
25 | silicates.set_density(3.3)
26 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
27 |
28 | species = [silicates,graphite_parallel,graphite_perpendicular]
29 | abundances = numpy.array([0.65,0.35*1./3,0.35*2./3])
30 | print(abundances)
31 |
32 | dust = mix_dust(species, abundances)
33 |
34 | amin = 0.005e-4
35 | amax = 1.000e0
36 | pl = 3.5
37 |
38 | dust.calculate_size_distribution_opacity(amin, amax, pl, nang=1, \
39 | coat_volume_fraction=0.0)
40 |
41 | dust.write('draine_1cm.hdf5')
42 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_draine_100um.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | #1/3
11 | graphite_parallel = Dust()
12 | graphite_parallel.set_optical_constants_from_draine("optical_constants/graphite_parallel_0.01.txt")
13 | graphite_parallel.set_density(2.24)
14 | graphite_parallel.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | #2/3
17 | graphite_perpendicular = Dust()
18 | graphite_perpendicular.set_optical_constants_from_draine("optical_constants/graphite_perpendicular_0.01.txt")
19 | graphite_perpendicular.set_density(2.24)
20 | graphite_perpendicular.calculate_optical_constants_on_wavelength_grid(\
21 | water_ice.lam)
22 |
23 | silicates = Dust()
24 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
25 | silicates.set_density(3.3)
26 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
27 |
28 | species = [silicates,graphite_parallel,graphite_perpendicular]
29 | abundances = numpy.array([0.65,0.35*1./3,0.35*2./3])
30 | print(abundances)
31 |
32 | dust = mix_dust(species, abundances)
33 |
34 | amin = 0.005e-4
35 | amax = 1.000e-2
36 | pl = 3.5
37 |
38 | dust.calculate_size_distribution_opacity(amin, amax, pl, nang=1, \
39 | coat_volume_fraction=0.0)
40 |
41 | dust.write('draine_100um.hdf5')
42 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_draine_10um.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | #1/3
11 | graphite_parallel = Dust()
12 | graphite_parallel.set_optical_constants_from_draine("optical_constants/graphite_parallel_0.01.txt")
13 | graphite_parallel.set_density(2.24)
14 | graphite_parallel.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | #2/3
17 | graphite_perpendicular = Dust()
18 | graphite_perpendicular.set_optical_constants_from_draine("optical_constants/graphite_perpendicular_0.01.txt")
19 | graphite_perpendicular.set_density(2.24)
20 | graphite_perpendicular.calculate_optical_constants_on_wavelength_grid(\
21 | water_ice.lam)
22 |
23 | silicates = Dust()
24 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
25 | silicates.set_density(3.3)
26 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
27 |
28 | species = [silicates,graphite_parallel,graphite_perpendicular]
29 | abundances = numpy.array([0.65,0.35*1./3,0.35*2./3])
30 | print(abundances)
31 |
32 | dust = mix_dust(species, abundances)
33 |
34 | amin = 0.005e-4
35 | amax = 1.000e-3
36 | pl = 3.5
37 |
38 | dust.calculate_size_distribution_opacity(amin, amax, pl, nang=1, \
39 | coat_volume_fraction=0.0)
40 |
41 | dust.write('draine_10um.hdf5')
42 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_draine_1mm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | #1/3
11 | graphite_parallel = Dust()
12 | graphite_parallel.set_optical_constants_from_draine("optical_constants/graphite_parallel_0.01.txt")
13 | graphite_parallel.set_density(2.24)
14 | graphite_parallel.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | #2/3
17 | graphite_perpendicular = Dust()
18 | graphite_perpendicular.set_optical_constants_from_draine("optical_constants/graphite_perpendicular_0.01.txt")
19 | graphite_perpendicular.set_density(2.24)
20 | graphite_perpendicular.calculate_optical_constants_on_wavelength_grid(\
21 | water_ice.lam)
22 |
23 | silicates = Dust()
24 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
25 | silicates.set_density(3.3)
26 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
27 |
28 | species = [silicates,graphite_parallel,graphite_perpendicular]
29 | abundances = numpy.array([0.65,0.35*1./3,0.35*2./3])
30 | print(abundances)
31 |
32 | dust = mix_dust(species, abundances)
33 |
34 | amin = 0.005e-4
35 | amax = 1.000e-1
36 | pl = 3.5
37 |
38 | dust.calculate_size_distribution_opacity(amin, amax, pl, nang=1, \
39 | coat_volume_fraction=0.0)
40 |
41 | dust.write('draine_1mm.hdf5')
42 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_draine_1um.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | #1/3
11 | graphite_parallel = Dust()
12 | graphite_parallel.set_optical_constants_from_draine("optical_constants/graphite_parallel_0.01.txt")
13 | graphite_parallel.set_density(2.24)
14 | graphite_parallel.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | #2/3
17 | graphite_perpendicular = Dust()
18 | graphite_perpendicular.set_optical_constants_from_draine("optical_constants/graphite_perpendicular_0.01.txt")
19 | graphite_perpendicular.set_density(2.24)
20 | graphite_perpendicular.calculate_optical_constants_on_wavelength_grid(\
21 | water_ice.lam)
22 |
23 | silicates = Dust()
24 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
25 | silicates.set_density(3.3)
26 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
27 |
28 | species = [silicates,graphite_parallel,graphite_perpendicular]
29 | abundances = numpy.array([0.65,0.35*1./3,0.35*2./3])
30 | print(abundances)
31 |
32 | dust = mix_dust(species, abundances)
33 |
34 | amin = 0.005e-4
35 | amax = 1.000e-4
36 | pl = 3.5
37 |
38 | dust.calculate_size_distribution_opacity(amin, amax, pl, nang=1, \
39 | coat_volume_fraction=0.0)
40 |
41 | dust.write('draine_1um.hdf5')
42 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_draine_2mm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | #1/3
11 | graphite_parallel = Dust()
12 | graphite_parallel.set_optical_constants_from_draine("optical_constants/graphite_parallel_0.01.txt")
13 | graphite_parallel.set_density(2.24)
14 | graphite_parallel.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | #2/3
17 | graphite_perpendicular = Dust()
18 | graphite_perpendicular.set_optical_constants_from_draine("optical_constants/graphite_perpendicular_0.01.txt")
19 | graphite_perpendicular.set_density(2.24)
20 | graphite_perpendicular.calculate_optical_constants_on_wavelength_grid(\
21 | water_ice.lam)
22 |
23 | silicates = Dust()
24 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
25 | silicates.set_density(3.3)
26 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
27 |
28 | species = [silicates,graphite_parallel,graphite_perpendicular]
29 | abundances = numpy.array([0.65,0.35*1./3,0.35*2./3])
30 | print(abundances)
31 |
32 | dust = mix_dust(species, abundances)
33 |
34 | amin = 0.005e-4
35 | amax = 2.000e-1
36 | pl = 3.5
37 |
38 | dust.calculate_size_distribution_opacity(amin, amax, pl, nang=1, \
39 | coat_volume_fraction=0.0)
40 |
41 | dust.write('draine_2mm.hdf5')
42 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_draine_3mm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | water_ice = Dust()
7 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
8 | water_ice.set_density(0.92)
9 |
10 | #1/3
11 | graphite_parallel = Dust()
12 | graphite_parallel.set_optical_constants_from_draine("optical_constants/graphite_parallel_0.01.txt")
13 | graphite_parallel.set_density(2.24)
14 | graphite_parallel.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
15 |
16 | #2/3
17 | graphite_perpendicular = Dust()
18 | graphite_perpendicular.set_optical_constants_from_draine("optical_constants/graphite_perpendicular_0.01.txt")
19 | graphite_perpendicular.set_density(2.24)
20 | graphite_perpendicular.calculate_optical_constants_on_wavelength_grid(\
21 | water_ice.lam)
22 |
23 | silicates = Dust()
24 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
25 | silicates.set_density(3.3)
26 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
27 |
28 | species = [silicates,graphite_parallel,graphite_perpendicular]
29 | abundances = numpy.array([0.65,0.35*1./3,0.35*2./3])
30 | print(abundances)
31 |
32 | dust = mix_dust(species, abundances)
33 |
34 | amin = 0.005e-4
35 | amax = 3.000e-1
36 | pl = 3.5
37 |
38 | dust.calculate_size_distribution_opacity(amin, amax, pl, nang=1, \
39 | coat_volume_fraction=0.0)
40 |
41 | dust.write('draine_3mm.hdf5')
42 |
--------------------------------------------------------------------------------
/pdspy/interferometry/concatenate.py:
--------------------------------------------------------------------------------
1 | from .libinterferometry import Visibilities
2 | import numpy
3 |
4 | def concatenate(visibilities):
5 |
6 | for i, vis in enumerate(visibilities):
7 | if i == 0:
8 | u = vis.u.copy()
9 | v = vis.v.copy()
10 | real = vis.real.copy()
11 | imag = vis.imag.copy()
12 | amp = vis.amp.copy()
13 | weights = vis.weights.copy()
14 | freq = vis.freq.copy()
15 | if type(vis.baseline) != type(None):
16 | baseline = vis.baseline.copy()
17 | incl_baselines = True
18 | else:
19 | incl_baselines = False
20 | else:
21 | u = numpy.concatenate((u, vis.u.copy()))
22 | v = numpy.concatenate((v, vis.v.copy()))
23 | real = numpy.concatenate((real, vis.real.copy()))
24 | imag = numpy.concatenate((imag, vis.imag.copy()))
25 | amp = numpy.concatenate((amp, vis.amp.copy()))
26 | weights = numpy.concatenate((weights, vis.weights.copy()))
27 | if incl_baselines:
28 | if type(vis.baseline) != type(None):
29 | baseline = numpy.concatenate((baseline,vis.baseline.copy()))
30 | else:
31 | incl_baselines = False
32 |
33 | if incl_baselines:
34 | return Visibilities(u, v, freq, real, imag, weights, baseline=baseline)
35 | else:
36 | return Visibilities(u, v, freq, real, imag, weights)
37 |
--------------------------------------------------------------------------------
/pdspy/dust/run_opacity_tool.py:
--------------------------------------------------------------------------------
1 | from .Dust import Dust
2 | import os
3 | import numpy
4 |
5 | def run_opacity_tool(amin=0.05, amax=3000., apow=3.5, na=50, fcarbon=0.13, \
6 | Vcarbon=0.15, porosity=0.25, fmax=0.8, lmin=0.05, lmax=5000, nlam=300, \
7 | filename=None, verbose=False):
8 |
9 | original_dir = os.environ["PWD"]
10 | os.mkdir("/tmp/temp_opacitytool")
11 | os.chdir("/tmp/temp_opacitytool")
12 |
13 | try:
14 | command = "OpacityTool -amin {0:f} -amax {1:f} -apow {2:f} -na {3:d} "\
15 | "-fcarbon {4:f} -Vcarbon {5:f} -porosity {6:f} -fmax {7:f} "\
16 | "-lmin {8:f} -lmax {9:f} -nlam {10:d}".format(amin, amax, apow,\
17 | na, fcarbon, Vcarbon, porosity, fmax, lmin, lmax, nlam)
18 |
19 | if not verbose:
20 | os.system(command + " > log.txt")
21 | else:
22 | os.system(command)
23 |
24 | data = numpy.loadtxt("particle.dat")
25 |
26 | d = Dust()
27 | d.set_properties(data[:,0], data[:,1], data[:,2])
28 |
29 | if not verbose:
30 | os.system("rm particle.dat log.txt")
31 | else:
32 | os.system("rm particle.dat")
33 | os.chdir(original_dir)
34 | os.rmdir("/tmp/temp_opacitytool")
35 |
36 | if filename != None:
37 | d.write(filename)
38 | else:
39 | return d
40 | except:
41 | os.system("rm particle.dat log.txt")
42 | os.chdir(original_dir)
43 | os.rmdir("/tmp/temp_opacitytool")
44 |
--------------------------------------------------------------------------------
/pdspy/table/table.py:
--------------------------------------------------------------------------------
1 | from .column import MaskedColumn
2 | import astropy.table
3 | import astropy.utils
4 | import h5py
5 | import os
6 |
7 | class Table(astropy.table.Table):
8 |
9 | def __init__(self, *args, **kwargs):
10 | super(Table, self).__init__(*args, **kwargs)
11 |
12 | self.MaskedColumn = MaskedColumn
13 | if self._masked:
14 | self._column_class = MaskedColumn
15 |
16 | @staticmethod
17 | def read_hdf5(*args, **kwargs):
18 | try:
19 | self = Table(astropy.table.Table.read(*args, path="table", \
20 | **kwargs), masked=True)
21 | self.mask = astropy.table.Table.read(*args, path="mask", **kwargs)
22 | except OSError:
23 | self = Table(astropy.table.Table.read(*args, path="table",**kwargs))
24 |
25 | for col in self.colnames:
26 | if 'S' in self[col].dtype.str:
27 | self.replace_column(col, self[col].astype(str))
28 |
29 | return self
30 |
31 | def write_hdf5(self, *args, **kwargs):
32 | for col in self.colnames:
33 | if 'U' in self[col].dtype.str:
34 | self.replace_column(col, self[col].astype(bytes))
35 |
36 | self.write(*args, path='table', overwrite=True, **kwargs)
37 |
38 | for col in self.colnames:
39 | if 'S' in self[col].dtype.str:
40 | self.replace_column(col, self[col].astype(str))
41 |
42 | if self.masked:
43 | self.mask.write(*args, path='mask', append=True, **kwargs)
44 |
45 | return
46 |
--------------------------------------------------------------------------------
/pdspy/imaging/extract_pv_diagram.py:
--------------------------------------------------------------------------------
1 | from ..constants.astronomy import arcsec
2 | from ..constants.physics import c
3 | from . import Image
4 | try:
5 | import pvextractor
6 | except:
7 | pass
8 | import numpy
9 |
10 | def extract_pv_diagram(image, xy=(0.,0.), pa=0., length=100, width=1):
11 |
12 | ny, nx, nfreq, npol = image.image.shape
13 |
14 | # Create a data cube that is appropriately shaped.
15 |
16 | cube = numpy.empty((nfreq, ny, nx))
17 | for i in range(nfreq):
18 | cube[i,:,:] = image.image[:,:,i,0]
19 |
20 | # Create the Path object.
21 |
22 | x0, y0 = xy
23 |
24 | line = [(x0-length/2*numpy.sin(pa),y0-length/2*numpy.cos(pa)), \
25 | (x0+length/2*numpy.sin(pa), y0+length/2*numpy.cos(pa))]
26 |
27 | path = pvextractor.Path(line, width=width)
28 |
29 | # Extract the PV diagram along the Path
30 |
31 | pv = pvextractor.extract_pv_slice(cube, path)
32 |
33 | # Convert back to my Image class.
34 |
35 | pvdiagram = numpy.empty((1, pv.data.shape[1], pv.data.shape[0], 1))
36 | for i in range(pv.data.shape[0]):
37 | pvdiagram[0,:,i,0] = pv.data[i,:]
38 |
39 | # Get the velocity.
40 |
41 | velocity = c * (image.header["RESTFRQ"] - image.freq) / \
42 | image.header["RESTFRQ"]
43 |
44 | # Get the x coordinates.
45 |
46 | x0 = 0.
47 | dx = image.header["CDELT2"] * numpy.pi/180 / arcsec
48 | nx0 = int(pv.data.shape[1] / 2) + 1
49 |
50 | x = (numpy.arange(pv.data.shape[1]) - (nx0-1))*dx + x0
51 |
52 | return Image(pvdiagram, x=x, velocity=velocity, freq=image.freq)
53 |
--------------------------------------------------------------------------------
/pdspy/modeling/Star.py:
--------------------------------------------------------------------------------
1 | import numpy
2 | import h5py
3 | from ..constants.physics import sigma
4 | from ..constants.astronomy import L_sun, R_sun
5 |
6 | class Star:
7 | def __init__(self, mass=0.5, luminosity=1.0, temperature=4000., x=0.0, \
8 | y=0.0, z=0.0):
9 | self.mass = mass
10 | self.luminosity = luminosity
11 | self.temperature = temperature
12 | self.radius = (luminosity*L_sun/ \
13 | (4*numpy.pi*sigma*temperature**4))**(1./2)/R_sun
14 | self.x = x
15 | self.y = y
16 | self.z = z
17 |
18 | def read(self, filename=None, usefile=None):
19 | if (usefile == None):
20 | f = h5py.File(filename, "r")
21 | else:
22 | f = usefile
23 |
24 | self.mass = f['mass'][()]
25 | self.luminosity = f['luminosity'][()]
26 | self.temperature = f['temperature'][()]
27 | self.radius = f['radius'][()]
28 | self.x = f['x'][()]
29 | self.y = f['y'][()]
30 | self.z = f['z'][()]
31 |
32 | if (usefile == None):
33 | f.close()
34 |
35 | def write(self, filename=None, usefile=None):
36 | if (usefile == None):
37 | f = h5py.File(filename, "w")
38 | else:
39 | f = usefile
40 |
41 | f['mass'] = self.mass
42 | f['luminosity'] = self.luminosity
43 | f['temperature'] = self.temperature
44 | f['radius'] = self.radius
45 |
46 | f['x'] = self.x
47 | f['y'] = self.y
48 | f['z'] = self.z
49 |
50 | if (usefile == None):
51 | f.close()
52 |
--------------------------------------------------------------------------------
/pdspy/imaging/readpvfits.py:
--------------------------------------------------------------------------------
1 | from ..constants.astronomy import arcsec
2 | from ..constants.physics import c
3 | from .libimaging import Image
4 | from astropy.utils.exceptions import AstropyWarning
5 | import astropy.io.fits as fits
6 | import astropy.wcs as wcs
7 | import warnings
8 | import numpy
9 |
10 | def readpvfits(filename):
11 |
12 | # Open the fits file.
13 |
14 | data = fits.open(filename)
15 |
16 | # Figure out the dimensions of each axis and create an array to put the data
17 | # into, and put the data into that array.
18 |
19 | npol, nv, nx = data[0].data.shape
20 |
21 | image = numpy.zeros((1,nx,nv,npol))
22 |
23 | for i in range(npol):
24 | for j in range(nv):
25 | image[0,:,j,i] = data[0].data[i,j,:]
26 |
27 | # Read in the x and y coordinate information, including the WCS info if it
28 | # is available.
29 |
30 | header = data[0].header
31 |
32 | #x, y = numpy.meshgrid(numpy.linspace(0,nx-1,nx), numpy.linspace(0,ny-1,ny))
33 | x, y = None, None
34 |
35 | x0 = data[0].header["CRVAL1"]
36 | dx = data[0].header["CDELT1"]
37 | nx0 = data[0].header["CRPIX1"]
38 |
39 | x = (numpy.arange(nx) - (nx0-1))*dx + x0
40 |
41 | nu0 = data[0].header["CRVAL2"]
42 | dnu = data[0].header["CDELT2"]
43 | n0 = data[0].header["CRPIX2"]
44 | freq = (numpy.arange(nv)-(n0-1))*dnu + nu0
45 | restfreq = data[0].header["RESTFRQ"]
46 |
47 | velocity = c * (restfreq - freq) / restfreq
48 |
49 | data.close()
50 |
51 | return Image(image, x=x, y=y, header=header, wcs=None, velocity=velocity, \
52 | freq=freq)
53 |
--------------------------------------------------------------------------------
/pdspy/dust/data/plot_kabs.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import Dust, DustGenerator
4 | import numpy
5 | import matplotlib
6 | import matplotlib.pyplot as plt
7 |
8 | # Maximum dust grain sizes.
9 |
10 | a_max = numpy.logspace(0.,5.,1000)
11 |
12 | # Grain size distribution power-law
13 |
14 | p = numpy.linspace(2.5, 4.5, 10)
15 |
16 | # Read in the dust generator class.
17 |
18 | dust_gen = DustGenerator("diana_wice.hdf5")
19 |
20 | # Change a few of the parameters to make the plot look nice.
21 |
22 | matplotlib.rcParams["font.family"] = "serif"
23 | matplotlib.rcParams["font.size"] = 14
24 | matplotlib.rcParams["text.usetex"] = "True"
25 | matplotlib.rcParams["text.latex.preamble"] = r"\usepackage{upgreek}"
26 | matplotlib.rcParams["legend.fontsize"] = 14
27 |
28 | # Start the plotting.
29 |
30 | fig, ax = plt.subplots(nrows=1, ncols=1)
31 |
32 | # Loop through each of the values for p.
33 |
34 | for i in range(p.size):
35 | # Set up a list to put beta in.
36 |
37 | kabs = []
38 |
39 | # Loop through and calculate beta.
40 |
41 | for j in range(a_max.size):
42 | # Get the dust generator properties.
43 |
44 | dust = dust_gen(a_max[j] / 1.0e4, p[i])
45 |
46 | # Add to the array.
47 |
48 | kabs.append(dust.kabs[103])
49 |
50 | # Plot beta.
51 |
52 | ax.semilogx(a_max, kabs, "-", label="$p = {0:3.1f}$".format(p[i]))
53 |
54 | # Add a legend.
55 |
56 | plt.legend(loc="lower left")
57 |
58 | # Adjust the figure.
59 |
60 | ax.set_xlabel("$a_{max}$ [$\mu$m]")
61 | ax.set_ylabel(r"$\kappa_{abs}$")
62 |
63 | # Save the figure.
64 |
65 | fig.savefig("kabs_plot.pdf")
66 |
--------------------------------------------------------------------------------
/pdspy/dust/data/test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import matplotlib.pyplot as plt
5 | import numpy
6 | import time
7 |
8 | troilite = Dust()
9 | troilite.set_optical_constants_from_henn("optical_constants/troilite.txt")
10 | troilite.set_density(4.83)
11 |
12 | organics = Dust()
13 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
14 | organics.set_density(1.5)
15 |
16 | water_ice = Dust()
17 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
18 | water_ice.set_density(0.92)
19 |
20 | silicates = Dust()
21 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
22 | silicates.set_density(3.3)
23 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
24 |
25 | species = [silicates,troilite,organics,water_ice]
26 | mass_fraction = numpy.array([6.4e-3,7.68e-4,2.13e-3,1.4e-3])
27 | rho = numpy.array([silicates.rho,troilite.rho,organics.rho,water_ice.rho])
28 | abundances = (mass_fraction/rho)/(mass_fraction/rho).sum()
29 |
30 | dust1 = mix_dust(species, abundances)
31 | dust2 = mix_dust(species, abundances)
32 |
33 | amin = 0.005e-4
34 | amax = 1.000e0
35 | pl = 3.5
36 |
37 | starttime = time.time()
38 | dust1.calculate_size_distribution_opacity(amin, amax, pl, \
39 | coat_volume_fraction=0.0, nang=2)
40 | endtime = time.time()
41 | print(endtime - starttime)
42 |
43 | pl = 3.0
44 |
45 | starttime = time.time()
46 | dust2.calculate_size_distribution_opacity(amin, amax, pl, \
47 | coat_volume_fraction=0.0, nang=2)
48 | endtime = time.time()
49 | print(endtime - starttime)
50 |
51 | plt.loglog(dust1.lam, dust1.ksca, 'b-')
52 | plt.loglog(dust2.lam, dust2.ksca, 'r-')
53 | plt.show()
54 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_pollack_1um.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | iron = Dust()
7 | iron.set_optical_constants_from_henn("optical_constants/iron.txt")
8 | iron.set_density(7.87)
9 |
10 | olivine = Dust()
11 | olivine.set_optical_constants_from_henn("optical_constants/olivine.txt")
12 | olivine.set_density(3.49)
13 |
14 | orthopyroxene = Dust()
15 | orthopyroxene.set_optical_constants_from_henn("optical_constants/orthopyroxene.txt")
16 | orthopyroxene.set_density(3.4)
17 |
18 | troilite = Dust()
19 | troilite.set_optical_constants_from_henn("optical_constants/troilite.txt")
20 | troilite.set_density(4.83)
21 |
22 | organics = Dust()
23 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
24 | organics.set_density(1.5)
25 |
26 | water_ice = Dust()
27 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
28 | water_ice.set_density(0.92)
29 |
30 | silicates = Dust()
31 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
32 | silicates.set_density(3.3)
33 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
34 |
35 | species = [silicates,troilite,organics,water_ice]
36 | #mass_fraction = numpy.array([6.4e-3,7.68e-4,2.13e-3,1.4e-3])
37 | mass_fraction = numpy.array([3.41e-3,7.68e-4,4.13e-3,5.55e-3])
38 | rho = numpy.array([silicates.rho,troilite.rho,organics.rho,water_ice.rho])
39 | abundances = (mass_fraction/rho)/(mass_fraction/rho).sum()
40 |
41 | dust = mix_dust(species, abundances)
42 |
43 | amin = 0.005e-4
44 | amax = 1.000e-4
45 | pl = 3.5
46 |
47 | dust.calculate_size_distribution_opacity(amin, amax, pl, \
48 | coat_volume_fraction=0.0)
49 |
50 | dust.write('pollack_1um.hdf5')
51 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_pollack.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | iron = Dust()
7 | iron.set_optical_constants_from_henn("optical_constants/iron.txt")
8 | iron.set_density(7.87)
9 |
10 | olivine = Dust()
11 | olivine.set_optical_constants_from_henn("optical_constants/olivine.txt")
12 | olivine.set_density(3.49)
13 |
14 | orthopyroxene = Dust()
15 | orthopyroxene.set_optical_constants_from_henn("optical_constants/orthopyroxene.txt")
16 | orthopyroxene.set_density(3.4)
17 |
18 | troilite = Dust()
19 | troilite.set_optical_constants_from_henn("optical_constants/troilite.txt")
20 | troilite.set_density(4.83)
21 |
22 | organics = Dust()
23 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
24 | organics.set_density(1.5)
25 |
26 | water_ice = Dust()
27 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
28 | water_ice.set_density(0.92)
29 |
30 | silicates = Dust()
31 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
32 | silicates.set_density(3.3)
33 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
34 |
35 | organics = Dust()
36 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
37 | organics.set_density(1.5)
38 |
39 | species = [silicates,troilite,organics,water_ice]
40 | #mass_fraction = numpy.array([6.4e-3,7.68e-4,2.13e-3,1.4e-3])
41 | mass_fraction = numpy.array([3.41e-3,7.68e-4,4.13e-3,5.55e-3])
42 | rho = numpy.array([silicates.rho,troilite.rho,organics.rho,water_ice.rho])
43 | abundances = (mass_fraction/rho)/(mass_fraction/rho).sum()
44 |
45 | dust = mix_dust(species, abundances)
46 |
47 | # Create the dust generator class.
48 |
49 | dust_gen = DustGenerator(dust)
50 |
51 | dust_gen.write("pollack.hdf5")
52 |
--------------------------------------------------------------------------------
/pdspy/dust/data/plot_beta.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import Dust, DustGenerator
4 | import numpy
5 | import matplotlib
6 | import matplotlib.pyplot as plt
7 |
8 | # Maximum dust grain sizes.
9 |
10 | a_max = numpy.logspace(0.,5.,1000)
11 |
12 | # Grain size distribution power-law
13 |
14 | p = numpy.linspace(2.5, 4.5, 10)
15 |
16 | # Read in the dust generator class.
17 |
18 | dust_gen = DustGenerator("diana_wice.hdf5")
19 |
20 | # Change a few of the parameters to make the plot look nice.
21 |
22 | matplotlib.rcParams["font.family"] = "serif"
23 | matplotlib.rcParams["font.size"] = 14
24 | matplotlib.rcParams["text.usetex"] = "True"
25 | matplotlib.rcParams["text.latex.preamble"] = r"\usepackage{upgreek}"
26 | matplotlib.rcParams["legend.fontsize"] = 14
27 |
28 | # Start the plotting.
29 |
30 | fig, ax = plt.subplots(nrows=1, ncols=1)
31 |
32 | # Loop through each of the values for p.
33 |
34 | for i in range(p.size):
35 | # Set up a list to put beta in.
36 |
37 | beta = []
38 |
39 | # Loop through and calculate beta.
40 |
41 | for j in range(a_max.size):
42 | # Get the dust generator properties.
43 |
44 | dust = dust_gen(a_max[j] / 1.0e4, p[i])
45 |
46 | # Calculate beta.
47 |
48 | tmp_beta = -(numpy.log10(dust.kabs[108])-numpy.log10(dust.kabs[102]))/\
49 | (numpy.log10(dust.lam[108]) - numpy.log10(dust.lam[102]))
50 |
51 | # Add to the array.
52 |
53 | beta.append(tmp_beta)
54 |
55 | # Plot beta.
56 |
57 | ax.semilogx(a_max, beta, "-", label="$p = {0:3.1f}$".format(p[i]))
58 |
59 | # Add a legend.
60 |
61 | plt.legend(loc="lower left")
62 |
63 | # Adjust the figure.
64 |
65 | ax.set_xlabel("$a_{max}$ [$\mu$m]")
66 | ax.set_ylabel(r"$\beta$")
67 |
68 | # Save the figure.
69 |
70 | fig.savefig("beta_plot.pdf")
71 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_pollack_1cm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | iron = Dust()
7 | iron.set_optical_constants_from_henn("optical_constants/iron.txt")
8 | iron.set_density(7.87)
9 |
10 | olivine = Dust()
11 | olivine.set_optical_constants_from_henn("optical_constants/olivine.txt")
12 | olivine.set_density(3.49)
13 |
14 | orthopyroxene = Dust()
15 | orthopyroxene.set_optical_constants_from_henn("optical_constants/orthopyroxene.txt")
16 | orthopyroxene.set_density(3.4)
17 |
18 | troilite = Dust()
19 | troilite.set_optical_constants_from_henn("optical_constants/troilite.txt")
20 | troilite.set_density(4.83)
21 |
22 | organics = Dust()
23 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
24 | organics.set_density(1.5)
25 |
26 | water_ice = Dust()
27 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
28 | water_ice.set_density(0.92)
29 |
30 | silicates = Dust()
31 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
32 | silicates.set_density(3.3)
33 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
34 |
35 | organics = Dust()
36 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
37 | organics.set_density(1.5)
38 |
39 | species = [silicates,troilite,organics,water_ice]
40 | #mass_fraction = numpy.array([6.4e-3,7.68e-4,2.13e-3,1.4e-3])
41 | mass_fraction = numpy.array([3.41e-3,7.68e-4,4.13e-3,5.55e-3])
42 | rho = numpy.array([silicates.rho,troilite.rho,organics.rho,water_ice.rho])
43 | abundances = (mass_fraction/rho)/(mass_fraction/rho).sum()
44 |
45 | dust = mix_dust(species, abundances)
46 |
47 | amin = 0.005e-4
48 | amax = 1.000e0
49 | pl = 3.5
50 |
51 | dust.calculate_size_distribution_opacity(amin, amax, pl, \
52 | coat_volume_fraction=0.0)
53 |
54 | dust.write('pollack_1cm.hdf5')
55 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_pollack_1mm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | iron = Dust()
7 | iron.set_optical_constants_from_henn("optical_constants/iron.txt")
8 | iron.set_density(7.87)
9 |
10 | olivine = Dust()
11 | olivine.set_optical_constants_from_henn("optical_constants/olivine.txt")
12 | olivine.set_density(3.49)
13 |
14 | orthopyroxene = Dust()
15 | orthopyroxene.set_optical_constants_from_henn("optical_constants/orthopyroxene.txt")
16 | orthopyroxene.set_density(3.4)
17 |
18 | troilite = Dust()
19 | troilite.set_optical_constants_from_henn("optical_constants/troilite.txt")
20 | troilite.set_density(4.83)
21 |
22 | organics = Dust()
23 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
24 | organics.set_density(1.5)
25 |
26 | water_ice = Dust()
27 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
28 | water_ice.set_density(0.92)
29 |
30 | silicates = Dust()
31 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
32 | silicates.set_density(3.3)
33 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
34 |
35 | organics = Dust()
36 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
37 | organics.set_density(1.5)
38 |
39 | species = [silicates,troilite,organics,water_ice]
40 | #mass_fraction = numpy.array([6.4e-3,7.68e-4,2.13e-3,1.4e-3])
41 | mass_fraction = numpy.array([3.41e-3,7.68e-4,4.13e-3,5.55e-3])
42 | rho = numpy.array([silicates.rho,troilite.rho,organics.rho,water_ice.rho])
43 | abundances = (mass_fraction/rho)/(mass_fraction/rho).sum()
44 |
45 | dust = mix_dust(species, abundances)
46 |
47 | amin = 0.005e-4
48 | amax = 1.000e-1
49 | pl = 3.5
50 |
51 | dust.calculate_size_distribution_opacity(amin, amax, pl, \
52 | coat_volume_fraction=0.0)
53 |
54 | dust.write('pollack_1mm.hdf5')
55 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_pollack_100um.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | iron = Dust()
7 | iron.set_optical_constants_from_henn("optical_constants/iron.txt")
8 | iron.set_density(7.87)
9 |
10 | olivine = Dust()
11 | olivine.set_optical_constants_from_henn("optical_constants/olivine.txt")
12 | olivine.set_density(3.49)
13 |
14 | orthopyroxene = Dust()
15 | orthopyroxene.set_optical_constants_from_henn("optical_constants/orthopyroxene.txt")
16 | orthopyroxene.set_density(3.4)
17 |
18 | troilite = Dust()
19 | troilite.set_optical_constants_from_henn("optical_constants/troilite.txt")
20 | troilite.set_density(4.83)
21 |
22 | organics = Dust()
23 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
24 | organics.set_density(1.5)
25 |
26 | water_ice = Dust()
27 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
28 | water_ice.set_density(0.92)
29 |
30 | silicates = Dust()
31 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
32 | silicates.set_density(3.3)
33 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
34 |
35 | organics = Dust()
36 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
37 | organics.set_density(1.5)
38 |
39 | species = [silicates,troilite,organics,water_ice]
40 | #mass_fraction = numpy.array([6.4e-3,7.68e-4,2.13e-3,1.4e-3])
41 | mass_fraction = numpy.array([3.41e-3,7.68e-4,4.13e-3,5.55e-3])
42 | rho = numpy.array([silicates.rho,troilite.rho,organics.rho,water_ice.rho])
43 | abundances = (mass_fraction/rho)/(mass_fraction/rho).sum()
44 |
45 | dust = mix_dust(species, abundances)
46 |
47 | amin = 0.005e-4
48 | amax = 1.000e-2
49 | pl = 3.5
50 |
51 | dust.calculate_size_distribution_opacity(amin, amax, pl, \
52 | coat_volume_fraction=0.0)
53 |
54 | dust.write('pollack_100um.hdf5')
55 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_pollack_10cm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | iron = Dust()
7 | iron.set_optical_constants_from_henn("optical_constants/iron.txt")
8 | iron.set_density(7.87)
9 |
10 | olivine = Dust()
11 | olivine.set_optical_constants_from_henn("optical_constants/olivine.txt")
12 | olivine.set_density(3.49)
13 |
14 | orthopyroxene = Dust()
15 | orthopyroxene.set_optical_constants_from_henn("optical_constants/orthopyroxene.txt")
16 | orthopyroxene.set_density(3.4)
17 |
18 | troilite = Dust()
19 | troilite.set_optical_constants_from_henn("optical_constants/troilite.txt")
20 | troilite.set_density(4.83)
21 |
22 | organics = Dust()
23 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
24 | organics.set_density(1.5)
25 |
26 | water_ice = Dust()
27 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
28 | water_ice.set_density(0.92)
29 |
30 | silicates = Dust()
31 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
32 | silicates.set_density(3.3)
33 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
34 |
35 | organics = Dust()
36 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
37 | organics.set_density(1.5)
38 |
39 | species = [silicates,troilite,organics,water_ice]
40 | #mass_fraction = numpy.array([6.4e-3,7.68e-4,2.13e-3,1.4e-3])
41 | mass_fraction = numpy.array([3.41e-3,7.68e-4,4.13e-3,5.55e-3])
42 | rho = numpy.array([silicates.rho,troilite.rho,organics.rho,water_ice.rho])
43 | abundances = (mass_fraction/rho)/(mass_fraction/rho).sum()
44 |
45 | dust = mix_dust(species, abundances)
46 |
47 | amin = 0.005e-4
48 | amax = 1.000e1
49 | pl = 3.5
50 |
51 | dust.calculate_size_distribution_opacity(amin, amax, pl, \
52 | coat_volume_fraction=0.0)
53 |
54 | dust.write('pollack_10cm.hdf5')
55 |
--------------------------------------------------------------------------------
/pdspy/dust/data/make_pollack_10um.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import *
4 | import numpy
5 |
6 | iron = Dust()
7 | iron.set_optical_constants_from_henn("optical_constants/iron.txt")
8 | iron.set_density(7.87)
9 |
10 | olivine = Dust()
11 | olivine.set_optical_constants_from_henn("optical_constants/olivine.txt")
12 | olivine.set_density(3.49)
13 |
14 | orthopyroxene = Dust()
15 | orthopyroxene.set_optical_constants_from_henn("optical_constants/orthopyroxene.txt")
16 | orthopyroxene.set_density(3.4)
17 |
18 | troilite = Dust()
19 | troilite.set_optical_constants_from_henn("optical_constants/troilite.txt")
20 | troilite.set_density(4.83)
21 |
22 | organics = Dust()
23 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
24 | organics.set_density(1.5)
25 |
26 | water_ice = Dust()
27 | water_ice.set_optical_constants_from_henn("optical_constants/water_ice.txt")
28 | water_ice.set_density(0.92)
29 |
30 | silicates = Dust()
31 | silicates.set_optical_constants_from_draine("optical_constants/astronomical_silicates.txt")
32 | silicates.set_density(3.3)
33 | silicates.calculate_optical_constants_on_wavelength_grid(water_ice.lam)
34 |
35 | organics = Dust()
36 | organics.set_optical_constants_from_henn("optical_constants/organics.txt")
37 | organics.set_density(1.5)
38 |
39 | species = [silicates,troilite,organics,water_ice]
40 | #mass_fraction = numpy.array([6.4e-3,7.68e-4,2.13e-3,1.4e-3])
41 | mass_fraction = numpy.array([3.41e-3,7.68e-4,4.13e-3,5.55e-3])
42 | rho = numpy.array([silicates.rho,troilite.rho,organics.rho,water_ice.rho])
43 | abundances = (mass_fraction/rho)/(mass_fraction/rho).sum()
44 |
45 | dust = mix_dust(species, abundances)
46 |
47 | amin = 0.005e-4
48 | amax = 1.000e-3
49 | pl = 3.5
50 |
51 | dust.calculate_size_distribution_opacity(amin, amax, pl, \
52 | coat_volume_fraction=0.0)
53 |
54 | dust.write('pollack_10um.hdf5')
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://conda.anaconda.org/conda-forge)
2 | [](https://anaconda.org/conda-forge/pdspy)
3 | [](https://anaconda.org/conda-forge/pdspy)
4 | [](https://pdspy.readthedocs.io/en/latest/?badge=latest)
5 |
6 | # pdspy: A MCMC Tool for Continuum and Spectral Line Radiative Transfer Modeling
7 |
8 | Welcome to the GitHub page for pdspy! This code is meant to fit Monte Carlo Radiative Transfer models for protostellar/protoplanetary disks to ALMA continuum and spectral line datasets using Markov Chain Monte Carlo fitting.
9 |
10 | Further capabilities (e.g. fitting spectral line data with a radiative equilibrium calculation) are being developed. If you are interested in new features, do let me know and I would be happy to either add them myself, or to work with you to add them. The documentation is currently included below, but will be ported to a more extensive, better laid out format soon.
11 |
12 | If you are interested in making use of the code, please check out the [documentation](http://pdspy.readthedocs.io).
13 |
14 | For more extensive details on what the code does, please see these papers:
15 |
16 | + [Disk Masses for Embedded Class I Protostars in the Taurus Molecular Cloud](https://ui.adsabs.harvard.edu/abs/2017ApJ...851...45S/abstract)
17 | + [High-precision Dynamical Masses of Pre-main-sequence Stars with ALMA and Gaia](https://ui.adsabs.harvard.edu/abs/2019ApJ...874..136S/abstract)
18 |
19 | If you have any questions about using the code (or this documentation), requests for features, or suggestions for improvement, please don't hesitate to send me an e-mail.
20 |
--------------------------------------------------------------------------------
/pdspy/modeling/check_parameters.py:
--------------------------------------------------------------------------------
1 | from .base_parameters import base_parameters
2 |
3 | def check_parameters(parameters, nvis=3):
4 | # Make sure the code is backwards compatible to a time when only a single
5 | # gas file was being supplied.
6 |
7 | if "gas_file" in parameters:
8 | parameters["gas_file1"] = parameters["gas_file"]
9 | parameters["logabundance1"] = parameters["logabundance"]
10 |
11 | # Make sure that the envelope dust is the same as the disk dust, if it is
12 | # not specified.
13 |
14 | if "dust_file" in parameters and not "envelope_dust" in parameters:
15 | parameters["envelope_dust"] = parameters["dust_file"]
16 |
17 | # Now loop through and make sure all of the parameters are present and
18 | # accounted for.
19 |
20 | for key in base_parameters:
21 | if not key in parameters:
22 | parameters[key] = base_parameters[key]
23 |
24 | # Make sure there are enough instances of freezeout for all of the gas
25 | # files provided.
26 |
27 | index = 1
28 | while index > 0:
29 | if "gas_file"+str(index) in parameters:
30 | if not "logabundance{0:d}".format(index) in parameters:
31 | parameters["logabundance"+str(index)] = \
32 | base_parameters["logabundance1"]
33 | if not "freezeout{0:d}".format(index) in parameters:
34 | parameters["freezeout"+str(index)] = \
35 | base_parameters["freezeout1"]
36 |
37 | index += 1
38 | else:
39 | index = -1
40 |
41 | # Make sure there are enough instances of flux_unc for all of the
42 | # data files that are being fit.
43 |
44 | for i in range(nvis):
45 | if not "flux_unc{0:d}".format(i+1) in parameters:
46 | parameters["flux_unc{0:d}".format(i+1)] = parameters["flux_unc1"]
47 |
48 | return parameters
49 |
--------------------------------------------------------------------------------
/pdspy/dust/mix_dust.py:
--------------------------------------------------------------------------------
1 | import numpy
2 | import scipy
3 | from .Dust import Dust
4 | from ..constants.math import pi
5 |
6 | def mix_dust(dust, abundance, medium=None, rule="Bruggeman", filling=1.):
7 |
8 | if rule == "Bruggeman":
9 | meff = numpy.zeros(dust[0].lam.size,dtype=complex)
10 | rho = 0.0
11 |
12 | for i in range(dust[0].lam.size):
13 | temp = scipy.optimize.fsolve(bruggeman,numpy.array([1.0,0.0]),\
14 | args=(dust,abundance,i, filling))
15 | meff[i] = temp[0]+1j*temp[1]
16 |
17 | for i in range(len(dust)):
18 | rho += dust[i].rho*abundance[i]
19 |
20 | rho *= filling
21 |
22 | elif rule == "MaxGarn":
23 | numerator = 0.0+1j*0.0
24 | denominator = 0.0+1j*0.0
25 | rho = 0.0
26 |
27 | for i in range(len(dust)):
28 | gamma = 3. / (dust[i].m**2 + 2)
29 |
30 | numerator += abundance[i] * gamma * dust[i].m**2
31 | denominator += abundance[i] * gamma
32 |
33 | rho += dust[i].rho*abundance[i]
34 |
35 | mmix = numpy.sqrt(numerator / denominator)
36 |
37 | F = (mmix**2 - 1.) / (mmix**2 + 2.)
38 |
39 | meff = numpy.sqrt((1. + 2.*filling*F) / (1. - filling*F))
40 |
41 | rho *= filling
42 |
43 | new = Dust()
44 | new.set_density(rho)
45 | new.set_optical_constants(dust[0].lam, meff.real, meff.imag)
46 |
47 | return new
48 |
49 | def bruggeman(meff, dust, abundance, index, filling):
50 |
51 | m_eff = meff[0]+1j*meff[1]
52 | tot = 0+0j
53 |
54 | for j in range(len(dust)):
55 | tot += filling * abundance[j]*(dust[j].m[index]**2-m_eff**2)/ \
56 | (dust[j].m[index]**2+2*m_eff**2)
57 |
58 | # Add in the void.
59 |
60 | tot += (1 - filling) * (1. - m_eff**2) / (1. + 2*m_eff**2)
61 |
62 | return numpy.array([tot.real,tot.imag])
63 |
--------------------------------------------------------------------------------
/tests/test_dartois_disk.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import pdspy.modeling as modeling
4 | import pdspy.interferometry as uv
5 | import pdspy.dust as dust
6 | import pdspy.gas as gas
7 |
8 | import matplotlib.pyplot as plt
9 |
10 | import numpy
11 |
12 | # Set up a radiative transfer model:
13 |
14 | m = modeling.YSOModel()
15 |
16 | # Add a grid. Spherical typically makes the most sense.
17 |
18 | nr, ntheta, nphi = 100, 100, 2
19 | rmin, rmax = 0.1, 300
20 |
21 | m.set_spherical_grid(rmin, rmax, nr, ntheta, nphi, code="radmc3d")
22 |
23 | # Add a star to the model.
24 |
25 | m.add_star(mass=0.5, luminosity=1., temperature=4000.)
26 |
27 | #Set up dust properties for the disk.
28 |
29 | dust_gen = dust.DustGenerator(dust.__path__[0]+"/data/diana_wice.hdf5")
30 |
31 | a_max = 100 # microns
32 | p = 3.5
33 |
34 | d = dust_gen(a_max / 1e4, p) # dust_gen wants units of cm
35 |
36 | # Also set up the gas properties of the disk.
37 |
38 | g = gas.Gas()
39 | g.set_properties_from_lambda(gas.__path__[0]+"/data/co.dat")
40 |
41 | gases = [g]
42 |
43 | # Add a disk to the model.
44 |
45 | m.add_dartois_pringle_disk(mass=0.0003, rmin=0.1, rmax=50., plrho=1., h0=5., \
46 | plh=1., dust=d, tmid0=20., tatm0=100, zq0=0.1, pltgas=0.25, delta=1, \
47 | gas=gases, abundance=[1.0e-4], freezeout=[20.], aturb=0.1)
48 |
49 | # Finally, we need to set the wavelength grid.
50 |
51 | m.grid.set_wavelength_grid(0.1, 1.0e5, 500, log=True)
52 |
53 | # Now generate a plot of the number density.
54 |
55 | r, theta = numpy.meshgrid(m.grid.r, m.grid.theta[::-1], indexing='ij')
56 |
57 | with numpy.errstate(divide="ignore"):
58 | z = numpy.log10(m.grid.number_density[0][:,:,0])
59 | vmin = numpy.nanmax(z) - 10.
60 | vmax = numpy.nanmax(z)
61 |
62 | fig, ax = plt.subplots(nrows=1, ncols=1, subplot_kw={'projection':'polar'})
63 |
64 | ax.pcolor(theta, r, z, shading="auto", vmin=vmin, vmax=vmax)
65 |
66 | ax.set_thetalim(0.,numpy.pi/2)
67 |
68 | plt.show()
69 |
70 |
--------------------------------------------------------------------------------
/pdspy/spectroscopy/spectroscopy.py:
--------------------------------------------------------------------------------
1 | import numpy
2 | import astropy
3 | import h5py
4 | from ..constants.physics import c
5 |
6 | class Spectrum:
7 |
8 | def __init__(self, wave=None, flux=None, unc=None):
9 | if (type(wave) != type(None)):
10 | self.wave = wave
11 | self.freq = c / wave / 1.0e-4
12 | self.flux = flux
13 | if type(unc) == type(None):
14 | unc = numpy.zeros(wave.size)
15 | self.unc = unc
16 | else:
17 | self.unc = unc
18 |
19 | def asFITS(self):
20 | hdulist = astropy.io.fits.HDUList([])
21 |
22 | hdu = pyfits.PrimaryHDU(numpy.concatenate(( \
23 | self.wave.reshape((1,self.wave.size)), \
24 | self.flux.reshape((1,self.wave.size)), \
25 | self.unc.reshape((1,self.wave.size)))))
26 | hdulist.append(hdu)
27 |
28 | return hdulist
29 |
30 | def read(self, filename=None, usefile=None):
31 | if (usefile == None):
32 | f = h5py.File(filename, "r")
33 | else:
34 | f = usefile
35 |
36 | wave = f['wave'][...]
37 | flux = f['flux'][...]
38 | unc = f['unc'][...]
39 |
40 | self.__init__(wave, flux, unc)
41 |
42 | if (usefile == None):
43 | f.close()
44 |
45 | def write(self, filename=None, usefile=None):
46 | if (usefile == None):
47 | f = h5py.File(filename, "w")
48 | else:
49 | f = usefile
50 |
51 | if hasattr(self, "wave"):
52 | wave_dset = f.create_dataset("wave", (self.wave.size,), dtype='f')
53 | wave_dset[...] = self.wave
54 | flux_dset = f.create_dataset("flux", (self.flux.size,), dtype='f')
55 | flux_dset[...] = self.flux
56 | unc_dset = f.create_dataset("unc", (self.unc.size,), dtype='f')
57 | unc_dset[...] = self.unc
58 |
59 | if (usefile == None):
60 | f.close()
61 |
--------------------------------------------------------------------------------
/pdspy/interferometry/interpolate_model.py:
--------------------------------------------------------------------------------
1 | import numpy
2 | import scipy.interpolate
3 | from ..constants.astronomy import arcsec
4 | from .libinterferometry import Visibilities
5 | from galario import double
6 | try:
7 | import trift
8 | except:
9 | pass
10 |
11 | def interpolate_model(u, v, freq, model, nthreads=1, dRA=0., dDec=0., \
12 | code="galario", nxy=1024, dxy=0.01):
13 |
14 | if code == "galario":
15 | real = []
16 | imag = []
17 |
18 | double.threads(nthreads)
19 |
20 | dxy = (model.x[1] - model.x[0])*arcsec
21 |
22 | for i in range(len(model.freq)):
23 | vis = double.sampleImage(model.image[::-1,:,i,0].copy(order='C'), \
24 | dxy, u, v, dRA=dRA*arcsec, dDec=dDec*arcsec)
25 |
26 | real.append(vis.real.reshape((u.size,1)))
27 | imag.append(-vis.imag.reshape((u.size,1)))
28 |
29 | real = numpy.concatenate(real, axis=1)
30 | imag = numpy.concatenate(imag, axis=1)
31 |
32 | elif code == "galario-unstructured":
33 | real = []
34 | imag = []
35 |
36 | double.threads(nthreads)
37 |
38 | vol = None
39 | for i in range(len(model.freq)):
40 | vis = double.sampleUnstructuredImage(model.x*arcsec, \
41 | -model.y*arcsec, model.image[:,i].copy(order='C'), nxy, \
42 | dxy*arcsec, u, v, dRA=dRA*arcsec, dDec=dDec*arcsec)
43 |
44 | real.append(vis.real.reshape((u.size,1)))
45 | imag.append(-vis.imag.reshape((u.size,1)))
46 |
47 | real = numpy.concatenate(real, axis=1)
48 | imag = numpy.concatenate(imag, axis=1)
49 |
50 | elif code == "trift":
51 | vis = trift.cpu.trift(model.x*arcsec, model.y*arcsec, \
52 | model.image, u, v, dRA*arcsec, dDec*arcsec, \
53 | nthreads=nthreads, mode="extended")
54 |
55 | real, imag = vis.real, vis.imag
56 |
57 | return Visibilities(u, v, freq, real, imag, numpy.ones(real.shape))
58 |
--------------------------------------------------------------------------------
/pdspy/dust/redden.py:
--------------------------------------------------------------------------------
1 | from . import __file__
2 | from scipy.interpolate import interp1d
3 | import numpy
4 | import os
5 |
6 | def redden(wave, flux, Av, law="steenman", Rv='3.1', magnitudes=False):
7 |
8 | # Read in the extinction coefficients.
9 |
10 | if law == 'steenman':
11 | data = numpy.loadtxt(os.path.dirname(__file__)+ \
12 | "/reddening/steenman_the.dat", usecols=[1,2])
13 | elif law == 'mcclure':
14 | if Av <= 1.:
15 | data = numpy.loadtxt(os.path.dirname(__file__)+ \
16 | "/reddening/mcclure.dat", usecols=[0,1])
17 | else:
18 | data = numpy.loadtxt(os.path.dirname(__file__)+ \
19 | "/reddening/mcclure.dat", usecols=[0,2])
20 | elif law == 'draine':
21 | if Rv == '3.1':
22 | data = numpy.loadtxt(os.path.dirname(__file__)+ \
23 | "/reddening/draine_3.1.dat", skiprows=80, \
24 | usecols=(0,3))
25 |
26 | data = data[::-1,:]
27 | data[:,1] /= data[605,1]
28 |
29 | elif Rv == '4.0':
30 | data = numpy.loadtxt(os.path.dirname(__file__)+ \
31 | "/reddening/draine_4.0.dat", skiprows=80, \
32 | usecols=(0,3))
33 |
34 | data = data[::-1,:]
35 | data[:,1] /= data[605,1]
36 |
37 | elif Rv == '5.1':
38 | data = numpy.loadtxt(os.path.dirname(__file__)+ \
39 | "/reddening/draine_5.1.dat", skiprows=80, \
40 | usecols=(0,3))
41 |
42 | data = data[::-1,:]
43 | data[:,1] /= data[605,1]
44 |
45 | waves = data[:,0]
46 | coeffs = data[:,1]
47 |
48 | # Interpolate the data to the wavelength range supplied.
49 |
50 | coeffs = interp1d(numpy.log10(waves), numpy.log10(coeffs), \
51 | fill_value="extrapolate")
52 |
53 | if magnitudes:
54 | return flux + Av * 10.**coeffs(numpy.log10(wave))
55 | else:
56 | coeff = 10.**coeffs(numpy.log10(wave))
57 |
58 | # Now adjust the provided flux.
59 |
60 | return flux / 10.**(Av * coeff / 2.5)
61 |
--------------------------------------------------------------------------------
/pdspy/plotting/colormaps.py:
--------------------------------------------------------------------------------
1 | import matplotlib.colors as colors
2 |
3 | # Rainbow1 colormap.
4 |
5 | rainbow1_cdict = {'red': ((0, 1, 1),
6 | (0.15, 0, 0),
7 | (0.45, 0, 0),
8 | (0.5, 0, 0),
9 | (0.55, 1, 1),
10 | (0.75, 1, 1),
11 | (0.875, 1, 1),
12 | (1, 0, 0)),
13 | 'green': ((0, 1, 1),
14 | (0.15, 0, 0),
15 | (0.45, 1, 1),
16 | (0.5, 1, 1),
17 | (0.55, 1, 1),
18 | (0.75, 0, 0),
19 | (0.875, 0, 0),
20 | (1, 0, 0)),
21 | 'blue': ((0, 1, 1),
22 | (0.15, 1, 1),
23 | (0.45, 1, 1),
24 | (0.5, 0, 0),
25 | (0.55, 0, 0),
26 | (0.75, 0, 0),
27 | (0.875, 1, 1),
28 | (1, 0, 0))}
29 |
30 | rainbow1 = colors.LinearSegmentedColormap('rainbow3',rainbow1_cdict,256)
31 |
32 | # Rainbow3 colormap.
33 |
34 | rainbow3_cdict = {'red': ((0, 0, 0),
35 | (0.15, 0, 0),
36 | (0.45, 0, 0),
37 | (0.5, 0, 0),
38 | (0.55, 1, 1),
39 | (0.75, 1, 1),
40 | (0.875, 1, 1),
41 | (1, 1, 1)),
42 | 'green': ((0, 0, 0),
43 | (0.15, 0, 0),
44 | (0.45, 1, 1),
45 | (0.5, 1, 1),
46 | (0.55, 1, 1),
47 | (0.75, 0, 0),
48 | (0.875, 0, 0),
49 | (1, 1, 1)),
50 | 'blue': ((0, 0, 0),
51 | (0.15, 1, 1),
52 | (0.45, 1, 1),
53 | (0.5, 0, 0),
54 | (0.55, 0, 0),
55 | (0.75, 0, 0),
56 | (0.875, 1, 1),
57 | (1, 1, 1))}
58 |
59 | rainbow3 = colors.LinearSegmentedColormap('rainbow3',rainbow3_cdict,256)
60 |
--------------------------------------------------------------------------------
/pdspy/dust/data/plot_draine.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import Dust
4 | import matplotlib
5 | import matplotlib.pyplot as plt
6 |
7 | # List of the files to be plotted.
8 |
9 | species_list = ["draine_1um.hdf5", "draine_10um.hdf5", "draine_100um.hdf5", \
10 | "draine_1mm.hdf5", "draine_3mm.hdf5", "draine_1cm.hdf5"]
11 |
12 | # Change a few of the parameters to make the plot look nice.
13 |
14 | matplotlib.rcParams["font.family"] = "serif"
15 | matplotlib.rcParams["font.size"] = 14
16 | matplotlib.rcParams["text.usetex"] = "True"
17 | matplotlib.rcParams["text.latex.preamble"] = r"\usepackage{upgreek}"
18 | matplotlib.rcParams["legend.fontsize"] = 14
19 |
20 | # Start the plotting.
21 |
22 | fig, ax = plt.subplots(nrows=2, ncols=2)
23 |
24 | for species in species_list:
25 | dust = Dust()
26 | dust.set_properties_from_file(species)
27 |
28 | # Make a label for each line.
29 |
30 | size = species.split('_')[1].split('.')[0]
31 | if (len(size.split('um')) == 2):
32 | label = r"$a_{max} = %s$ $\upmu$m" % size.split('um')[0]
33 | elif (len(size.split('mm')) == 2):
34 | label = "$a_{max} = %s$ mm" % size.split('mm')[0]
35 | elif (len(size.split('cm')) == 2):
36 | label = "$a_{max} = %s$ cm" % size.split('cm')[0]
37 |
38 | # Plot the opacities.
39 |
40 | ax[0,0].loglog(dust.lam*1e4, dust.kabs, label=label)
41 | ax[0,1].loglog(dust.lam*1e4, dust.ksca)
42 | ax[1,0].loglog(dust.lam*1e4, dust.kext)
43 | ax[1,1].semilogx(dust.lam*1e4, dust.albedo)
44 |
45 | ax[0,0].set_xlabel(r"$\lambda$ [$\upmu$m]")
46 | ax[0,0].set_ylabel("$\kappa_{abs}$ [cm$^2$ g$^{-1}$]")
47 | ax[0,1].set_xlabel(r"$\lambda$ [$\upmu$m]")
48 | ax[0,1].set_ylabel("$\kappa_{sca}$ [cm$^2$ g$^{-1}$]")
49 | ax[1,0].set_xlabel(r"$\lambda$ [$\upmu$m]")
50 | ax[1,0].set_ylabel("$\kappa_{ext}$ [cm$^2$ g$^{-1}$]")
51 | ax[1,1].set_xlabel(r"$\lambda$ [$\upmu$m]")
52 | ax[1,1].set_ylabel("Albedo")
53 |
54 | ax[0,0].legend(loc="lower left")
55 |
56 | ax[0,0].axis([1e-1,1e5,1e-4,1e5])
57 | ax[0,1].axis([1e-1,1e5,1e-4,1e5])
58 | ax[1,0].axis([1e-1,1e5,1e-4,1e5])
59 | ax[1,1].axis([1e-1,1e5,0,1])
60 |
61 | fig.set_size_inches((10,10))
62 | fig.subplots_adjust(wspace=0.25, left=0.08, top=0.97, right=0.98, bottom=0.06)
63 | fig.savefig("draine_plot.pdf")
64 |
--------------------------------------------------------------------------------
/pdspy/plotting/cubeshow.py:
--------------------------------------------------------------------------------
1 | from matplotlib.widgets import Slider, Button, RadioButtons
2 | import matplotlib.pyplot as plt
3 |
4 | """
5 | Display a 3d ndarray with a slider to move along the third dimension.
6 |
7 | Extra keyword arguments are passed to imshow
8 |
9 | Original from here: http://nbarbey.github.io/2011/07/08/matplotlib-slider.html
10 | """
11 |
12 | def cubeshow(cube, axis=2, **kwargs):
13 | # check dim
14 | if not cube.ndim == 3:
15 | raise ValueError("cube should be an ndarray with ndim == 3")
16 |
17 | # Generate a figure with a set of axes.
18 |
19 | fig = plt.figure()
20 |
21 | ax = plt.subplot(111)
22 |
23 | fig.subplots_adjust(bottom=0.17, top=0.98)
24 |
25 | # Pick out just the first image to show.
26 |
27 | s = [slice(0, 1) if i == axis else slice(None) for i in range(3)]
28 | im = cube[tuple(s)].squeeze()
29 |
30 | # Show the image.
31 |
32 | l = ax.imshow(im, **kwargs)
33 |
34 | # Create the slider
35 |
36 | axslide = fig.add_axes([0.3, 0.02, 0.4, 0.075])
37 |
38 | slider = Slider(axslide, '', 0, cube.shape[axis] - 1, valinit=0, \
39 | valfmt=' %i', valstep=1)
40 |
41 | def update(val):
42 | ind = int(slider.val)
43 | s = [slice(ind, ind + 1) if i == axis else slice(None)
44 | for i in range(3)]
45 | im = cube[tuple(s)].squeeze()
46 | l.set_data(im)
47 | fig.canvas.draw()
48 |
49 | slider.on_changed(update)
50 |
51 | # Create a button to go to the next frame.
52 |
53 | axnext = fig.add_axes([0.81, 0.02, 0.1, 0.075])
54 |
55 | bnext = Button(axnext, 'Next')
56 |
57 | def next_image(event):
58 | if slider.val < cube.shape[axis]-1:
59 | slider.set_val(slider.val+1)
60 | elif slider.val == cube.shape[axis]-1:
61 | slider.set_val(0)
62 |
63 | bnext.on_clicked(next_image)
64 |
65 | # Create a button to go to the previous frame.
66 |
67 | axprev = fig.add_axes([0.09, 0.02, 0.1, 0.075])
68 |
69 | bprev = Button(axprev, 'Prev.')
70 |
71 | def prev_image(event):
72 | if slider.val > 0:
73 | slider.set_val(slider.val-1)
74 | elif slider.val == 0:
75 | slider.set_val(cube.shape[axis]-1)
76 |
77 | bprev.on_clicked(prev_image)
78 |
79 | # Show the plot.
80 |
81 | plt.show(block=True)
82 |
--------------------------------------------------------------------------------
/pdspy/spectroscopy/btsettl_photometry.py:
--------------------------------------------------------------------------------
1 | from pdspy.constants.astronomy import R_sun, pc
2 | import scipy.interpolate
3 | import astropy.table
4 | import numpy
5 |
6 | def btsettl_photometry(Teff=5770., Logg=4.4, Rstar=1.0, dpc=140., \
7 | system="Johnson", filters="B", AB=False):
8 |
9 | # Create the filename.
10 |
11 | path = '/'.join(__file__.split("/")[0:-1])+"/btsettl_data/"
12 |
13 | basename = "colmag.BT-Settl.server."
14 |
15 | filename = basename + system + "."
16 |
17 | if AB:
18 | filename += "AB.txt"
19 | else:
20 | filename += "Vega.txt"
21 |
22 | # Get the column names.
23 |
24 | f = open(path+filename, "r")
25 | lines = f.readlines()
26 | f.close()
27 |
28 | for i, line in enumerate(lines):
29 | if line[0] != "!":
30 | break
31 |
32 | colnames = lines[i-1].split()[1:]
33 |
34 | # Get the data.
35 |
36 | data = numpy.loadtxt(path+filename, comments='!')
37 |
38 | # Make the data into a table.
39 |
40 | table = astropy.table.Table(data[1:,0:16], names=colnames)
41 |
42 | # Make sure we only include the Teff's with all the log(g)'s.
43 |
44 | """
45 | teff = numpy.unique(table["Teff"])
46 | logg = numpy.unique(table["Logg"])
47 |
48 | for T in teff:
49 | if len(table["Teff"][table["Teff"] == T]) < len(logg):
50 | table.remove_rows(numpy.where(table["Teff"] == T)[0])
51 | """
52 |
53 | # Now loop through the filters and get the photometry.
54 |
55 | """
56 | teff = numpy.array(numpy.unique(table["Teff"]))
57 | logg = numpy.array(numpy.unique(table["Logg"]))
58 | """
59 |
60 | mag = []
61 |
62 | for filter in filters.split(','):
63 | #data = numpy.array(table[filter]).reshape((teff.size, logg.size))
64 |
65 | # Now do the 2D interpolation.
66 |
67 | #f = scipy.interpolate.interp2d(logg, teff, data)
68 |
69 | f = scipy.interpolate.LinearNDInterpolator((table["Teff"], \
70 | table["Logg"]), table[filter], rescale=False)
71 |
72 | # Calculate the photometry now.
73 |
74 | mag.append(f([[Teff,Logg]])[0])
75 |
76 | # Turn the photometry into an array.
77 |
78 | mag = numpy.array(mag)
79 |
80 | # Turn into an absolute magnitude.
81 |
82 | M = mag - 5 * numpy.log10(Rstar*R_sun / pc) + 5.
83 |
84 | # Now get the apparent magnitude.
85 |
86 | photometry = M + 5*(numpy.log10(dpc) - 1.)
87 |
88 | return photometry
89 |
--------------------------------------------------------------------------------
/pdspy/dust/data/compare_c2d.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import Dust, DustGenerator
4 | import matplotlib
5 | import matplotlib.pyplot as plt
6 |
7 | # List of the files to be plotted.
8 |
9 | species_list = ["pollack_1um.hdf5", "pollack_10um.hdf5", "draine_1um.hdf5", \
10 | "c2d.hdf5"]
11 |
12 | # Change a few of the parameters to make the plot look nice.
13 |
14 | matplotlib.rcParams["font.family"] = "serif"
15 | matplotlib.rcParams["font.size"] = 14
16 | matplotlib.rcParams["text.usetex"] = "True"
17 | matplotlib.rcParams["text.latex.preamble"] = r"\usepackage{upgreek}"
18 | matplotlib.rcParams["legend.fontsize"] = 14
19 |
20 | # Start the plotting.
21 |
22 | fig, ax = plt.subplots(nrows=2, ncols=2)
23 |
24 | for i, species in enumerate(species_list):
25 | dust = Dust()
26 | dust.set_properties_from_file(species)
27 |
28 | # If we're using the Draine opacities, multiply by 100.
29 |
30 | if species == "draine_1um.hdf5":
31 | dust.kabs *= 100
32 | dust.ksca *= 100
33 | dust.kext *= 100
34 |
35 | # Make a label for each line.
36 |
37 | if species == "pollack_1um.hdf5":
38 | label = "Pollack et al. 1994, $a_{max} = 1$ $\mu$m"
39 | if species == "pollack_10um.hdf5":
40 | label = "Pollack et al. 1994, $a_{max} = 10$ $\mu$m"
41 | elif species == "draine_1um.hdf5":
42 | label = "70\% astronomical silicate, 30\% graphite"
43 | elif species == "c2d.hdf5":
44 | label = "c2d opacities"
45 |
46 | # Plot the opacities.
47 |
48 | ax[0,0].loglog(dust.lam*1e4, dust.kabs, label=label)
49 | ax[0,1].loglog(dust.lam*1e4, dust.ksca)
50 | ax[1,0].loglog(dust.lam*1e4, dust.kext)
51 | ax[1,1].semilogx(dust.lam*1e4, dust.albedo)
52 |
53 | ax[0,0].set_xlabel(r"$\lambda$ [$\upmu$m]")
54 | ax[0,0].set_ylabel("$\kappa_{abs}$ [cm$^2$ g$^{-1}$]")
55 | ax[0,1].set_xlabel(r"$\lambda$ [$\upmu$m]")
56 | ax[0,1].set_ylabel("$\kappa_{sca}$ [cm$^2$ g$^{-1}$]")
57 | ax[1,0].set_xlabel(r"$\lambda$ [$\upmu$m]")
58 | ax[1,0].set_ylabel("$\kappa_{ext}$ [cm$^2$ g$^{-1}$]")
59 | ax[1,1].set_xlabel(r"$\lambda$ [$\upmu$m]")
60 | ax[1,1].set_ylabel("Albedo")
61 |
62 | ax[0,0].legend(loc="lower left", fontsize="small")
63 |
64 | ax[0,0].axis([1e-1,1e5,1e-4,1e5])
65 | ax[0,1].axis([1e-1,1e5,1e-4,1e5])
66 | ax[1,0].axis([1e-1,1e5,1e-4,1e5])
67 | ax[1,1].axis([1e-1,1e5,0,1])
68 |
69 | fig.set_size_inches((10,10))
70 | fig.subplots_adjust(wspace=0.25, left=0.08, top=0.97, right=0.98, bottom=0.06)
71 | fig.savefig("c2d_plot.pdf")
72 |
--------------------------------------------------------------------------------
/pdspy/plotting/plot_scattered_light.py:
--------------------------------------------------------------------------------
1 | import matplotlib.pyplot as plt
2 | import matplotlib.ticker as ticker
3 | import numpy
4 |
5 | def plot_scattered_light(images, model, parameters, params, index=0, \
6 | fig=None):
7 |
8 | # If no axes are provided, create them.
9 |
10 | if fig == None:
11 | fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(4.5,4))
12 | else:
13 | fig, ax = fig
14 |
15 | # Scale the image appropriately.
16 |
17 | c = scale_image(images["data"][index], mode="arcsinh")
18 |
19 | # Show the image.
20 |
21 | ax.imshow(c[:,:,0,0], origin="lower", interpolation="nearest", cmap="gray")
22 |
23 | # Scale the model image.
24 |
25 | c = scale_image(model.images[images["lam"][index]], \
26 | mode=images["plot_mode"][index])
27 |
28 | # Contour the model image over the data.
29 |
30 | levels = numpy.array([0.05,0.25,0.45,0.65,0.85,1.0]) * \
31 | (c.max() - c.min()) + c.min()
32 |
33 | ax.contour(c[:,:,0,0], colors='gray', levels=levels)
34 |
35 | # Adjust the ticks.
36 |
37 | transform3 = ticker.FuncFormatter(Transform(0, images["npix"][index], \
38 | images["pixelsize"][index], '%.1f"'))
39 |
40 | ticks = images["ticks"][index]
41 |
42 | ax.set_xticks(images["npix"][index]/2+ticks/images["pixelsize"][index])
43 | ax.set_yticks(images["npix"][index]/2+ticks/images["pixelsize"][index])
44 | ax.get_xaxis().set_major_formatter(transform3)
45 | ax.get_yaxis().set_major_formatter(transform3)
46 |
47 | # Adjust the axes labels.
48 |
49 | ax.set_xlabel("$\Delta$RA")
50 | ax.set_ylabel("$\Delta$Dec")
51 |
52 | # Return the figure and axes.
53 |
54 | return fig, ax
55 |
56 | # Define a useful class for plotting.
57 |
58 | class Transform:
59 | def __init__(self, xmin, xmax, dx, fmt):
60 | self.xmin = xmin
61 | self.xmax = xmax
62 | self.dx = dx
63 | self.fmt = fmt
64 |
65 | def __call__(self, x, p):
66 | return self.fmt% ((x-(self.xmax-self.xmin)/2)*self.dx)
67 |
68 | # Define a function to scale an image to look nice.
69 |
70 | def scale_image(image, mode="linear"):
71 | vmin = image.image.min()
72 | vmax = numpy.percentile(image.image, 95)
73 |
74 | a = 1000.
75 | b = (image.image - vmin) / (vmax - vmin)
76 |
77 | if mode == "linear":
78 | c = b
79 | elif mode == "arcsinh":
80 | c = numpy.arcsinh(10*b)/3.
81 | elif mode == "log":
82 | c = numpy.log10(a*b+1)/numpy.log10(a)
83 | else:
84 | print("Not a valid mode!")
85 |
86 | return c
87 |
--------------------------------------------------------------------------------
/docs/installation.rst:
--------------------------------------------------------------------------------
1 | ============
2 | Installation
3 | ============
4 |
5 | Installing the code with Anaconda
6 | """""""""""""""""""""""""""""""""
7 |
8 | Anaconda is probably the easiest way to install pdspy because the dependency GALARIO is easily conda-installable. pdspy is available on the conda-forge channel and can be installed from the command line with:
9 |
10 | ::
11 |
12 | conda install pdspy -c conda-forge
13 |
14 | Installing the code with pip
15 | """"""""""""""""""""""""""""
16 |
17 | 1. In a terminal, run:
18 | ::
19 |
20 | pip install pdspy
21 |
22 | 2. Install GALARIO. Unfortunately, GALARIO is not pip-installable by default, so you will need to follow the instructions `here `_. Alternatively, a pip-installable version of GALARIO is in the works and can be installed like so:
23 | ::
24 |
25 | pip install git+https://github.com/psheehan/galario.git@add_unstructured
26 |
27 | but note that this is a fork of GALARIO and is not yet completely merged.
28 |
29 | Installing the code manually
30 | """"""""""""""""""""""""""""
31 |
32 | If you would like the most cutting-edge version of pdspy, with updates that go beyond the pre-packaged versions, you can download and compile the code yourself following these instructions:
33 |
34 | 1. Download the code from this webpage. Git clone is recommended if you would like to be able to pull updates:
35 | ::
36 |
37 | git clone https://github.com/psheehan/pdspy.git
38 |
39 | 2. Install the Python dependencies:
40 |
41 | * numpy
42 | * scipy
43 | * matplotlib
44 | * emcee
45 | * corner
46 | * hyperion
47 | * h5py
48 | * mpi4py
49 | * galario
50 | * Cython
51 | * astropy < 4.0
52 | * schwimmbad
53 | * dynesty
54 |
55 | 3. In a terminal, go to the directory where the code was downloaded, and into the code directory. Run:
56 | ::
57 |
58 | python setup.py install
59 |
60 | or
61 |
62 | ::
63 |
64 | pip install -e .
65 |
66 | or
67 |
68 | ::
69 |
70 | conda build pdspy -c conda-forge
71 | conda install pdspy -c conda-forge --use-local
72 |
73 | depending on what method you prefer best.
74 |
75 | Other dependencies
76 | """"""""""""""""""
77 |
78 | The other codes that are needed to run pdspy are `Hyperion `_ and `RADMC-3D `_. If you are a `Homebrew `_ user, you can do this with:
79 |
80 | ::
81 |
82 | brew tap psheehan/science
83 | brew install hyperion
84 | brew install radmc3d
85 |
86 |
--------------------------------------------------------------------------------
/pdspy/spectroscopy/find_lines.py:
--------------------------------------------------------------------------------
1 | from numpy import arange,array,where
2 | from numpy import abs as absv
3 | from .line_flux import line_flux
4 | import matplotlib.pyplot as plt
5 |
6 | def find_lines(data,thresh=3):
7 |
8 | nside = 8
9 | nleft = 8
10 | nright = 8
11 |
12 | index = 8
13 |
14 | B = 1.0/1200
15 |
16 | while index < data.wave.size-8:
17 |
18 | lines = array([data.wave[index]])
19 |
20 | results,chisq = line_flux(data,lines,nleft=nleft,nright=nright, \
21 | quiet=True)
22 | results_fw,chisq_fw = line_flux(data,lines,nleft=nleft,nright=nright,\
23 | quiet=True,fixed_width=True)
24 |
25 | chisq_test = (chisq <= thresh) & (chisq_fw <= thresh)
26 | SN_test = (results[0,1]/results[0,2] >= 5) & \
27 | (results_fw[0,1]/results_fw[0,2] >= 5)
28 | width_test = (results[0,3] >= lines[0]*B/2) & (results[0,3] <= \
29 | lines[0]*3*B)
30 | flux_test = absv(results[0,1]-results_fw[0,1])/results[0,1] <= 0.2
31 |
32 | #if (chisq_test & flux_test) & (SN_test & width_test):
33 | if (chisq_test & SN_test):
34 | print(" {0:f} {1:e} {2:e} {3:f} {4:f}".format( \
35 | results[0,0],results[0,1],results[0,2],results[0,3],chisq))
36 |
37 | results,chisq = line_flux(data,lines,nleft=nleft,nright=nright, \
38 | plotout="{0:6.3f}.pdf".format(results[0,0]),quiet=True)
39 |
40 | index = where(absv(data.wave-data.wave[index]-0.05) == \
41 | absv(data.wave-data.wave[index]-0.05).min())[0][0]
42 | nside = 6
43 | else:
44 | index = where(absv(data.wave-data.wave[index]-0.05) == \
45 | absv(data.wave-data.wave[index]-0.05).min())[0][0]
46 | # else:
47 | # if (nleft > 3) & (nright == nside):
48 | # nleft = nleft - 1
49 | # else:
50 | # nleft = nside
51 | # if (nright > 3) & (nleft == nside):
52 | # nright = nright-1
53 | # else:
54 | # nright = nside
55 | # if nside > 3:
56 | # nside = nside - 1
57 | # nleft = nside
58 | # nright = nside
59 | # else:
60 | # nside = 8
61 | # nleft = nside
62 | # nright = nside
63 | # index = where(absv(data.wave-data.wave[index]-0.05) ==\
64 | # absv(data.wave-data.wave[index]-0.05).min())[0][0]
65 |
--------------------------------------------------------------------------------
/docs/upgrading.rst:
--------------------------------------------------------------------------------
1 | =======================
2 | Upgrading to v2 from v1
3 | =======================
4 |
5 | **tl;dr -** pdspy v2.0.0 represents a major upgrade to the pdspy infrastructure, and is not backwards compatible with models that were run using earlier versions. Use the :code:`upgrade_to_pdspy2.py` script to upgrade your pre-v2 models.
6 |
7 | What's new?
8 | """""""""""
9 |
10 | Version 2 of the pdspy code fixes longstanding issues with the orientation parameters (x0, y0, pa, etc.). Previously x0 and y0 were entirely backwards from their traditional definitions, and pa was even worse. Moreover, for models with density reductions, e.g. gaps, outflow cavities, etc., the mass of the component with the density reduction was not being calculated accurately. Now the values that are reported from the modeling are entirely accurate.
11 |
12 | Why is it not backwards compatible?
13 | ===================================
14 |
15 | The definition of a number of parameters fundamentally changed and so if you try to run models with the results of v1.* fits, they will not give correct results using v2.* code.
16 |
17 | What needs to be updated?
18 | =========================
19 |
20 | There are a few places in particular that you need to look to make sure that your files are up-to-date and ready for v2:
21 |
22 | * config.py
23 |
24 | * *x0/y0*: These are now defined such that in a CASA image x0 is positive to the left and y0 is positive up.
25 |
26 | * Visibility HDF5 files: These files *must* be recreated from their UVFITS or CAASA MS origins. In order to get images oriented correctly when made from the visibility data, pdspy now takes the complex conjugate of the data when reading from UVFITS or MS files. The HDF5 visibility files store and read the data exactly as-is, which means that they need to be recreated in order to have the proper orientation.
27 |
28 | This sounds like a pain...
29 | ==========================
30 |
31 | You're telling me... and I'm sorry for the difficulty, but hope that these changes will make pdspy a more accurate tool. The safest thing to do would be to update your config.py file and your data files as described above and restart running your models, or to stick with v1 until you are done with your current modeling tasks and are ready to start fresh. If you do need to upgrade and can't wait for your models to finish, there is a helper script :code:`upgrade_to_pdspy2` that *should* take care of the transition for you in most cases. To use, simply go to the directory of an existing model and run the script. *Note:* The script will make permanent changes to files in that directory, and though it makes a backup copy of everything, it would perhaps be wise to make your own backup beforehand.
32 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # Configuration file for the Sphinx documentation builder.
2 | #
3 | # This file only contains a selection of the most common options. For a full
4 | # list see the documentation:
5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html
6 |
7 | # -- Path setup --------------------------------------------------------------
8 |
9 | # If extensions (or modules to document with autodoc) are in another directory,
10 | # add these directories to sys.path here. If the directory is relative to the
11 | # documentation root, use os.path.abspath to make it absolute, like shown here.
12 |
13 | import os
14 | import sys
15 | sys.path.insert(0, os.path.abspath("../"))
16 |
17 |
18 | # -- Mock imports ------------------------------------------------------------
19 |
20 | autodoc_mock_imports = ["numpy","hyperion","scipy","scikit-learn","h5py",
21 | "matplotlib","emcee","corner","mpi4py","astropy","schwimmbad","dynesty",
22 | "pdspy.dust.bhmie","pdspy.dust.bhcoat","pdspy.dust.dmilay",
23 | "pdspy.interferometry.libinterferometry","pdspy.imaging.libimaging",
24 | "pdspy.radmc3d.read","galario","mpl_toolkits","sklearn","casatools"]
25 |
26 | # -- Project information -----------------------------------------------------
27 |
28 | project = 'pdspy'
29 | copyright = '2020, Patrick Sheehan'
30 | author = 'Patrick Sheehan'
31 |
32 | # The full version, including alpha/beta/rc tags
33 | release = '2.0.0'
34 |
35 |
36 | # -- General configuration ---------------------------------------------------
37 |
38 | # Add any Sphinx extension module names here, as strings. They can be
39 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
40 | # ones.
41 | extensions = [
42 | 'recommonmark',
43 | 'sphinx.ext.autodoc',
44 | ]
45 |
46 | # Add any paths that contain templates here, relative to this directory.
47 | templates_path = ['_templates']
48 |
49 | # List of patterns, relative to source directory, that match files and
50 | # directories to ignore when looking for source files.
51 | # This pattern also affects html_static_path and html_extra_path.
52 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
53 |
54 |
55 | # -- Options for HTML output -------------------------------------------------
56 |
57 | # The theme to use for HTML and HTML Help pages. See the documentation for
58 | # a list of builtin themes.
59 | #
60 | html_theme = 'sphinx_rtd_theme'
61 |
62 | # Add any paths that contain custom static files (such as style sheets) here,
63 | # relative to this directory. They are copied after the builtin static files,
64 | # so a file named "default.css" will overwrite the builtin "default.css".
65 | html_static_path = ['_static']
66 |
67 | master_doc = "index"
68 |
--------------------------------------------------------------------------------
/pdspy/modeling/get_surrogate_model.py:
--------------------------------------------------------------------------------
1 | import schwimmbad
2 | import pickle
3 | import numpy
4 | import time
5 | import os
6 |
7 | def get_surrogate_model(params, model="pringle+ulrich+diana", \
8 | quantity="temperature", nthreads=1):
9 |
10 | # Load the keys for the parameters of the surrogate model.
11 |
12 | keys = list(numpy.loadtxt(os.path.dirname(os.path.abspath(__file__))+\
13 | "/surrogate_models/{0:s}/{1:s}/keys.txt".format(model, quantity), \
14 | dtype=str))
15 |
16 | # Load in the PCA that was found.
17 |
18 | pca = pickle.load(open(os.path.dirname(os.path.abspath(__file__))+\
19 | "/surrogate_models/{0:s}/{1:s}/pca.pkl".format(model, quantity), \
20 | "rb"))
21 |
22 | # Also the transformed data
23 |
24 | y_grid = numpy.load(os.path.dirname(os.path.abspath(__file__))+\
25 | "/surrogate_models/{0:s}/{1:s}/transformed_data.npy".\
26 | format(model, quantity))
27 |
28 | # Also load in the Gaussian process fits.
29 |
30 | gps = pickle.load(open(os.path.dirname(os.path.abspath(__file__))+\
31 | "/surrogate_models/{0:s}/{1:s}/gps.pkl".format(model, quantity), \
32 | "rb"))
33 |
34 | # Load the samples and make sure the best fit values are used for the
35 | # hyperparameters.
36 |
37 | ncomponents = y_grid.shape[1]
38 | ncomponents = 9
39 |
40 | samples = []
41 | for i in range(ncomponents):
42 | samples += [numpy.load(os.path.dirname(os.path.abspath(__file__))+\
43 | "/surrogate_models/{0:s}/{1:s}/gp_samples_component{2:d}.pkl."
44 | "npy".format(model, quantity, i))]
45 |
46 | # Load in the data.
47 |
48 | x = []
49 | data = []
50 |
51 | x.append([(params[k] - -9.)**3 if k == "logM_env" else params[k] for k in \
52 | keys])
53 |
54 | x = numpy.array(x)
55 | shape = (99,100,1)
56 |
57 | # Set the parameter vector for the GPs randomly from the posteriors.
58 |
59 | for i in range(ncomponents):
60 | w = numpy.random.randint(samples[i].shape[0])
61 |
62 | gps[i].set_parameter_vector(samples[i][w])
63 |
64 | # Reconstruct the data from the PCA + GP fit.
65 |
66 | sample = lambda i: gps[i].sample_conditional(y_grid[:,i], x)[0] if \
67 | i < ncomponents else 0.
68 |
69 | t1 = time.time()
70 | with schwimmbad.JoblibPool(nthreads) as pool:
71 | components = [list(pool.map(sample, range(15)))]
72 |
73 | projected = pca.inverse_transform(components)
74 | t2 = time.time()
75 | print("Time to reconstruct = {0:f} seconds".format(t2 - t1))
76 |
77 | # Return the projected quantity.
78 |
79 | return 10.**projected[0].reshape(shape)
80 |
--------------------------------------------------------------------------------
/pdspy/imaging/match_source_lists.py:
--------------------------------------------------------------------------------
1 | import numpy
2 | import astropy
3 | import astropy.coordinates
4 |
5 | #def match_source_lists(*lists, tol=0.3, table_names=['1', '2']):
6 | def match_source_lists(tol=0.3, table_names=['1', '2'], *lists):
7 |
8 | for i in range(len(lists)-1):
9 | if i == 0:
10 | list1 = lists[i]
11 | else:
12 | list1 = joined_list
13 | list2 = lists[i+1]
14 |
15 | coord1 = astropy.coordinates.SkyCoord(list1["ra"].tolist(), \
16 | list1['dec'].tolist(), frame='icrs')
17 | coord2 = astropy.coordinates.SkyCoord(list2["ra"].tolist(), \
18 | list2["dec"].tolist(), frame='icrs')
19 |
20 | idx, d2d, d3d = astropy.coordinates.match_coordinates_sky(coord1,coord2)
21 |
22 | ids, counts = numpy.unique(idx[d2d.arcsec < tol], return_counts=True)
23 | for j in range(len(ids)):
24 | if counts[j] > 1:
25 | min_d2d = min(d2d[idx == ids[j]].arcsec)
26 | d2d[(d2d.arcsec != min_d2d) & (idx == ids[j])] = \
27 | astropy.coordinates.Angle("0d00m{0:f}s".format(2*tol))
28 |
29 | list1["id"] = numpy.arange(len(list1)) + len(list2)
30 | list2["id"] = numpy.arange(len(list2))
31 | list1["id"][d2d.arcsec < tol] = idx[d2d.arcsec < tol]
32 |
33 | if i == 0:
34 | names = table_names[0:2]
35 | else:
36 | names = ["",table_names[i+1]]
37 |
38 | joined_list = astropy.table.join(list1, list2, join_type='outer', \
39 | keys='id', table_names=names, \
40 | uniq_col_name='{col_name}_{table_name}')
41 |
42 | del list1["id"]
43 | del list2["id"]
44 | del joined_list["id"]
45 |
46 | if i == 0:
47 | joined_list["ra"] = numpy.where(\
48 | joined_list["ra_"+names[0]].mask, \
49 | joined_list["ra_"+names[1]], joined_list["ra_"+names[0]])
50 | joined_list["dec"] = numpy.where(\
51 | joined_list["dec_"+names[0]].mask, \
52 | joined_list["dec_"+names[1]], joined_list["dec_"+names[0]])
53 | else:
54 | for name in list2.colnames:
55 | if name in joined_list.colnames:
56 | joined_list.rename_column(name, name+"_"+names[1])
57 |
58 | joined_list["ra"] = numpy.where(\
59 | joined_list["ra_"].mask, joined_list["ra_"+names[1]], \
60 | joined_list["ra_"])
61 | joined_list["dec"] = numpy.where(\
62 | joined_list["dec_"].mask, joined_list["dec_"+names[1]], \
63 | joined_list["dec_"])
64 |
65 | del joined_list["ra_"]
66 | del joined_list["dec_"]
67 |
68 | del joined_list["ra"]
69 | del joined_list["dec"]
70 |
71 | return joined_list
72 |
--------------------------------------------------------------------------------
/pdspy/dust/data/plot_diana.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import pdspy.dust
4 | import matplotlib
5 | import matplotlib.pyplot as plt
6 |
7 | # List of the files to be plotted.
8 |
9 | species_list = ["diana_1um.hdf5", "diana_10um.hdf5", "diana_100um.hdf5", \
10 | "diana_1mm.hdf5", "diana_1cm.hdf5", "diana_10cm.hdf5"]
11 |
12 | # Maximum dust grain sizes.
13 |
14 | a_max = [1., 10., 100., 1000., 10000., 100000.]
15 |
16 | # Read in the dust generator class.
17 |
18 | dust_gen = pdspy.dust.DustGenerator("diana.hdf5")
19 |
20 | # Change a few of the parameters to make the plot look nice.
21 |
22 | matplotlib.rcParams["font.family"] = "serif"
23 | matplotlib.rcParams["font.size"] = 14
24 | matplotlib.rcParams["text.usetex"] = "True"
25 | matplotlib.rcParams["text.latex.preamble"] = r"\usepackage{upgreek}"
26 | matplotlib.rcParams["legend.fontsize"] = 14
27 |
28 | # Start the plotting.
29 |
30 | fig, ax = plt.subplots(nrows=2, ncols=2)
31 |
32 | for i, species in enumerate(species_list):
33 | dust = pdspy.dust.Dust()
34 | dust.set_properties_from_file(species)
35 |
36 | # Get the dust generator properties.
37 |
38 | dust1 = dust_gen(a_max[i] / 1.0e4, 3.5)
39 | """
40 | dust1 = pdspy.dust.run_opacity_tool(amax=a_max[i], fmax=0.8)
41 | """
42 |
43 | # Make a label for each line.
44 |
45 | size = species.split('_')[1].split('.')[0]
46 | if (len(size.split('um')) == 2):
47 | label = r"$a_{max} = %s$ $\upmu$m" % size.split('um')[0]
48 | elif (len(size.split('mm')) == 2):
49 | label = "$a_{max} = %s$ mm" % size.split('mm')[0]
50 | elif (len(size.split('cm')) == 2):
51 | label = "$a_{max} = %s$ cm" % size.split('cm')[0]
52 |
53 | # Plot the opacities.
54 |
55 | ax[0,0].loglog(dust.lam*1e4, dust.kabs, label=label)
56 | ax[0,1].loglog(dust.lam*1e4, dust.ksca)
57 | ax[1,0].loglog(dust.lam*1e4, dust.kext)
58 | ax[1,1].semilogx(dust.lam*1e4, dust.albedo)
59 |
60 | ax[0,0].loglog(dust1.lam*1e4, dust1.kabs, '--')
61 | ax[0,1].loglog(dust1.lam*1e4, dust1.ksca, '--')
62 | ax[1,0].loglog(dust1.lam*1e4, dust1.kext, '--')
63 | ax[1,1].semilogx(dust1.lam*1e4, dust1.albedo, '--')
64 |
65 | ax[0,0].set_xlabel(r"$\lambda$ [$\upmu$m]")
66 | ax[0,0].set_ylabel("$\kappa_{abs}$ [cm$^2$ g$^{-1}$]")
67 | ax[0,1].set_xlabel(r"$\lambda$ [$\upmu$m]")
68 | ax[0,1].set_ylabel("$\kappa_{sca}$ [cm$^2$ g$^{-1}$]")
69 | ax[1,0].set_xlabel(r"$\lambda$ [$\upmu$m]")
70 | ax[1,0].set_ylabel("$\kappa_{ext}$ [cm$^2$ g$^{-1}$]")
71 | ax[1,1].set_xlabel(r"$\lambda$ [$\upmu$m]")
72 | ax[1,1].set_ylabel("Albedo")
73 |
74 | ax[0,0].legend(loc="lower left")
75 |
76 | ax[0,0].axis([1e-1,1e5,1e-4,1e5])
77 | ax[0,1].axis([1e-1,1e5,1e-4,1e5])
78 | ax[1,0].axis([1e-1,1e5,1e-4,1e5])
79 | ax[1,1].axis([1e-1,1e5,0,1])
80 |
81 | fig.set_size_inches((10,10))
82 | fig.subplots_adjust(wspace=0.25, left=0.08, top=0.97, right=0.98, bottom=0.06)
83 | fig.savefig("diana_plot.pdf")
84 |
--------------------------------------------------------------------------------
/pdspy/dust/data/plot_diana_wice.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import pdspy.dust
4 | import matplotlib
5 | import matplotlib.pyplot as plt
6 |
7 | # List of the files to be plotted.
8 |
9 | species_list = ["diana_wice_1um.hdf5", "diana_wice_10um.hdf5", \
10 | "diana_wice_100um.hdf5", "diana_wice_1mm.hdf5", "diana_wice_1cm.hdf5", \
11 | "diana_wice_10cm.hdf5"]
12 |
13 | # Maximum dust grain sizes.
14 |
15 | a_max = [1., 10., 100., 1000., 10000., 100000.]
16 |
17 | # Read in the dust generator class.
18 |
19 | dust_gen = pdspy.dust.DustGenerator("diana_wice.hdf5")
20 |
21 | # Change a few of the parameters to make the plot look nice.
22 |
23 | matplotlib.rcParams["font.family"] = "serif"
24 | matplotlib.rcParams["font.size"] = 14
25 | matplotlib.rcParams["text.usetex"] = "True"
26 | matplotlib.rcParams["text.latex.preamble"] = r"\usepackage{upgreek}"
27 | matplotlib.rcParams["legend.fontsize"] = 14
28 |
29 | # Start the plotting.
30 |
31 | fig, ax = plt.subplots(nrows=2, ncols=2)
32 |
33 | for i, species in enumerate(species_list):
34 | dust = pdspy.dust.Dust()
35 | dust.set_properties_from_file(species)
36 |
37 | # Get the dust generator properties.
38 |
39 | dust1 = dust_gen(a_max[i] / 1.0e4, 3.5)
40 | """
41 | dust1 = pdspy.dust.run_opacity_tool(amax=a_max[i], fmax=0.8)
42 | """
43 |
44 | # Make a label for each line.
45 |
46 | size = species.split('_')[2].split('.')[0]
47 | if (len(size.split('um')) == 2):
48 | label = r"$a_{max} = %s$ $\upmu$m" % size.split('um')[0]
49 | elif (len(size.split('mm')) == 2):
50 | label = "$a_{max} = %s$ mm" % size.split('mm')[0]
51 | elif (len(size.split('cm')) == 2):
52 | label = "$a_{max} = %s$ cm" % size.split('cm')[0]
53 |
54 | # Plot the opacities.
55 |
56 | ax[0,0].loglog(dust.lam*1e4, dust.kabs, label=label)
57 | ax[0,1].loglog(dust.lam*1e4, dust.ksca)
58 | ax[1,0].loglog(dust.lam*1e4, dust.kext)
59 | ax[1,1].semilogx(dust.lam*1e4, dust.albedo)
60 |
61 | ax[0,0].loglog(dust1.lam*1e4, dust1.kabs, '--')
62 | ax[0,1].loglog(dust1.lam*1e4, dust1.ksca, '--')
63 | ax[1,0].loglog(dust1.lam*1e4, dust1.kext, '--')
64 | ax[1,1].semilogx(dust1.lam*1e4, dust1.albedo, '--')
65 |
66 | ax[0,0].set_xlabel(r"$\lambda$ [$\upmu$m]")
67 | ax[0,0].set_ylabel("$\kappa_{abs}$ [cm$^2$ g$^{-1}$]")
68 | ax[0,1].set_xlabel(r"$\lambda$ [$\upmu$m]")
69 | ax[0,1].set_ylabel("$\kappa_{sca}$ [cm$^2$ g$^{-1}$]")
70 | ax[1,0].set_xlabel(r"$\lambda$ [$\upmu$m]")
71 | ax[1,0].set_ylabel("$\kappa_{ext}$ [cm$^2$ g$^{-1}$]")
72 | ax[1,1].set_xlabel(r"$\lambda$ [$\upmu$m]")
73 | ax[1,1].set_ylabel("Albedo")
74 |
75 | ax[0,0].legend(loc="lower left")
76 |
77 | ax[0,0].axis([1e-1,1e5,1e-4,1e5])
78 | ax[0,1].axis([1e-1,1e5,1e-4,1e5])
79 | ax[1,0].axis([1e-1,1e5,1e-4,1e5])
80 | ax[1,1].axis([1e-1,1e5,0,1])
81 |
82 | fig.set_size_inches((10,10))
83 | fig.subplots_adjust(wspace=0.25, left=0.08, top=0.97, right=0.98, bottom=0.06)
84 | fig.savefig("diana_wice_plot.pdf")
85 |
--------------------------------------------------------------------------------
/pdspy/dust/data/plot_pollack.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from pdspy.dust import Dust, DustGenerator
4 | import matplotlib
5 | import matplotlib.pyplot as plt
6 |
7 | # List of the files to be plotted.
8 |
9 | #species_list = ["pollack_1um.hdf5", "pollack_10um.hdf5", "pollack_100um.hdf5", \
10 | # "pollack_1mm.hdf5", "pollack_1cm.hdf5", "pollack_10cm.hdf5"]
11 | species_list = ["pollack_1um.hdf5", "pollack_10um.hdf5", "pollack_100um.hdf5", \
12 | "pollack_1mm.hdf5", "pollack_1cm.hdf5", "pollack_10cm.hdf5"]
13 |
14 | # Maximum dust grain sizes.
15 |
16 | a_max = [1., 10., 100., 1000., 10000., 100000.]
17 |
18 | # Read in the dust generator class.
19 |
20 | dust_gen = DustGenerator("pollack_new.hdf5")
21 |
22 | # Change a few of the parameters to make the plot look nice.
23 |
24 | matplotlib.rcParams["font.family"] = "serif"
25 | matplotlib.rcParams["font.size"] = 14
26 | matplotlib.rcParams["text.usetex"] = "True"
27 | matplotlib.rcParams["text.latex.preamble"] = r"\usepackage{upgreek}"
28 | matplotlib.rcParams["legend.fontsize"] = 14
29 |
30 | # Start the plotting.
31 |
32 | fig, ax = plt.subplots(nrows=2, ncols=2)
33 |
34 | for i, species in enumerate(species_list):
35 | dust = Dust()
36 | dust.set_properties_from_file(species)
37 |
38 | # Get the dust generator properties.
39 |
40 | dust1 = dust_gen(a_max[i] / 1.0e4, 2.5)
41 |
42 | # Make a label for each line.
43 |
44 | size = species.split('_')[1].split('.')[0]
45 | if (len(size.split('um')) == 2):
46 | label = r"$a_{max} = %s$ $\upmu$m" % size.split('um')[0]
47 | elif (len(size.split('mm')) == 2):
48 | label = "$a_{max} = %s$ mm" % size.split('mm')[0]
49 | elif (len(size.split('cm')) == 2):
50 | label = "$a_{max} = %s$ cm" % size.split('cm')[0]
51 |
52 | # Plot the opacities.
53 |
54 | ax[0,0].loglog(dust.lam*1e4, dust.kabs, label=label)
55 | ax[0,1].loglog(dust.lam*1e4, dust.ksca)
56 | ax[1,0].loglog(dust.lam*1e4, dust.kext)
57 | ax[1,1].semilogx(dust.lam*1e4, dust.albedo)
58 |
59 | ax[0,0].loglog(dust1.lam*1e4, dust1.kabs, '--')
60 | ax[0,1].loglog(dust1.lam*1e4, dust1.ksca, '--')
61 | ax[1,0].loglog(dust1.lam*1e4, dust1.kext, '--')
62 | ax[1,1].semilogx(dust1.lam*1e4, dust1.albedo, '--')
63 |
64 | ax[0,0].set_xlabel(r"$\lambda$ [$\upmu$m]")
65 | ax[0,0].set_ylabel("$\kappa_{abs}$ [cm$^2$ g$^{-1}$]")
66 | ax[0,1].set_xlabel(r"$\lambda$ [$\upmu$m]")
67 | ax[0,1].set_ylabel("$\kappa_{sca}$ [cm$^2$ g$^{-1}$]")
68 | ax[1,0].set_xlabel(r"$\lambda$ [$\upmu$m]")
69 | ax[1,0].set_ylabel("$\kappa_{ext}$ [cm$^2$ g$^{-1}$]")
70 | ax[1,1].set_xlabel(r"$\lambda$ [$\upmu$m]")
71 | ax[1,1].set_ylabel("Albedo")
72 |
73 | ax[0,0].legend(loc="lower left")
74 |
75 | ax[0,0].axis([1e-1,1e5,1e-4,1e5])
76 | ax[0,1].axis([1e-1,1e5,1e-4,1e5])
77 | ax[1,0].axis([1e-1,1e5,1e-4,1e5])
78 | ax[1,1].axis([1e-1,1e5,0,1])
79 |
80 | fig.set_size_inches((10,10))
81 | fig.subplots_adjust(wspace=0.25, left=0.08, top=0.97, right=0.98, bottom=0.06)
82 | fig.savefig("pollack_plot.pdf")
83 |
--------------------------------------------------------------------------------
/.github/workflows/python-build-test-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will upload a Python Package using Twine when a release is created
2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
3 |
4 | # This workflow uses actions that are not certified by GitHub.
5 | # They are provided by a third-party and are governed by
6 | # separate terms of service, privacy policy, and support
7 | # documentation.
8 |
9 | name: Test build pdspy package across platforms and versions
10 |
11 | on:
12 | push:
13 | branches: [master]
14 | paths-ignore:
15 | - 'docs/*'
16 | - '.readthedocs.yaml'
17 | release:
18 | branches: [master]
19 |
20 | jobs:
21 | build_wheels:
22 | name: Test build status
23 |
24 | runs-on: ${{ matrix.os }}
25 |
26 | strategy:
27 | matrix:
28 | os: [ubuntu-latest, macos-latest]
29 |
30 | steps:
31 | - uses: actions/checkout@v2
32 |
33 | #- name: Symlink gfortran (macOS)
34 | # if: runner.os == 'macOS'
35 | # run: |
36 | # make sure gfortran is available
37 | # https://github.com/actions/virtual-environments/issues/2524
38 | # https://github.com/cbg-ethz/dce/blob/master/.github/workflows/pkgdown.yaml
39 | # sudo ln -s /usr/local/bin/gfortran-11 /usr/local/bin/gfortran
40 | # sudo mkdir /usr/local/gfortran
41 | # sudo ln -s /usr/local/Cellar/gcc@11/*/lib/gcc/11 /usr/local/gfortran/lib
42 | # gfortran --version
43 |
44 | - name: Build wheels
45 | uses: pypa/cibuildwheel@v2.19.2
46 |
47 | - uses: actions/upload-artifact@v2
48 | with:
49 | path: ./wheelhouse/*.whl
50 |
51 | build_sdist:
52 | name: Build source distribution
53 | runs-on: ubuntu-latest
54 | steps:
55 | - uses: actions/checkout@v2
56 |
57 | - uses: actions/setup-python@v2
58 | name: Install Python
59 | with:
60 | python-version: '3.8'
61 |
62 | - name: Install numpy and Cython
63 | run:
64 | pip install numpy
65 | pip install cython
66 |
67 | - name: Build sdist
68 | run: python setup.py sdist
69 |
70 | - uses: actions/upload-artifact@v2
71 | with:
72 | path: dist/*.tar.gz
73 |
74 | upload_pypi:
75 | needs: [build_wheels, build_sdist]
76 | runs-on: ubuntu-latest
77 | # upload to PyPI on every tag starting with 'v'
78 | #if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v')
79 | # alternatively, to publish when a GitHub Release is created, use the following rule:
80 | if: github.event_name == 'release' && github.event.action == 'published'
81 | steps:
82 | - uses: actions/download-artifact@v2
83 | with:
84 | name: artifact
85 | path: dist
86 |
87 | - uses: pypa/gh-action-pypi-publish@v1.4.2
88 | with:
89 | user: __token__
90 | password: ${{ secrets.PYPI_API_TOKEN }}
91 |
--------------------------------------------------------------------------------
/pdspy/imaging/readimfits.py:
--------------------------------------------------------------------------------
1 | from ..constants.physics import c
2 | from ..constants.astronomy import arcsec
3 | from .libimaging import Image
4 | from astropy.utils.exceptions import AstropyWarning
5 | import astropy.io.fits as fits
6 | import astropy.wcs as wcs
7 | import warnings
8 | import numpy
9 |
10 | def readimfits(filename):
11 |
12 | # Open the fits file.
13 |
14 | data = fits.open(filename)
15 |
16 | # Figure out the dimensions of each axis and create an array to put the data
17 | # into, and put the data into that array.
18 |
19 | if len(data[0].data.shape) == 4:
20 | npol, nfreq, ny, nx = data[0].data.shape
21 | elif len(data[0].data.shape) == 3:
22 | nfreq, ny, nx = data[0].data.shape
23 | npol = 1
24 | elif len(data[0].data.shape) == 2:
25 | ny, nx = data[0].data.shape
26 | npol, nfreq = 1, 1
27 |
28 | image = numpy.zeros((ny,nx,nfreq,npol))
29 |
30 | for i in range(npol):
31 | for j in range(nfreq):
32 | if len(data[0].data.shape) == 4:
33 | image[:,:,j,i] = data[0].data[i,j,:,:].reshape(ny,nx)
34 | if len(data[0].data.shape) == 3:
35 | image[:,:,j,i] = data[0].data[j,:,:].reshape(ny,nx)
36 | if len(data[0].data.shape) == 2:
37 | image[:,:,j,i] = data[0].data[:,:].reshape(ny,nx)
38 |
39 | # Read in the x and y coordinate information, including the WCS info if it
40 | # is available.
41 |
42 | header = data[0].header
43 |
44 | # Check whether there is a CASA beam table.
45 |
46 | if len(data) > 1:
47 | if data[1].columns[0].name == 'BMAJ':
48 | header["BMAJ"] = data[1].data["BMAJ"].mean()*arcsec * 180./numpy.pi
49 | header["BMIN"] = data[1].data["BMIN"].mean()*arcsec * 180./numpy.pi
50 | header["BPA"] = data[1].data["BPA"].mean()
51 |
52 | # Turn off the WCS warnings that come from the PCX_Y values because they
53 | # are annoying...
54 | with warnings.catch_warnings():
55 | warnings.simplefilter('ignore', category=AstropyWarning)
56 |
57 | w = wcs.WCS(header)
58 | try:
59 | w = w.dropaxis(2)
60 | except:
61 | pass
62 | try:
63 | w = w.dropaxis(3)
64 | except:
65 | pass
66 |
67 | #x, y = numpy.meshgrid(numpy.linspace(0,nx-1,nx), numpy.linspace(0,ny-1,ny))
68 | x, y = None, None
69 |
70 | if len(data[0].data.shape) >= 3:
71 | if header["CTYPE3"] in ["VELOCITY","VRAD"]:
72 | v0 = data[0].header["CRVAL3"]
73 | dv = data[0].header["CDELT3"]
74 | n0 = data[0].header["CRPIX3"]
75 | velocity = (numpy.arange(nfreq)-(n0-1))*dv/1000.+v0/1000.
76 |
77 | nu0 = data[0].header["RESTFREQ"]
78 | freq = nu0 - velocity*1e5 * nu0 / c
79 | elif header["CTYPE3"] == "FREQ":
80 | nu0 = data[0].header["CRVAL3"]
81 | dnu = data[0].header["CDELT3"]
82 | n0 = data[0].header["CRPIX3"]
83 | freq = (numpy.arange(nfreq)-(n0-1))*dnu + nu0
84 |
85 | velocity = None
86 | else:
87 | velocity, freq = None, None
88 |
89 | data.close()
90 |
91 | return Image(image, x=x, y=y, header=header, wcs=w, velocity=velocity, \
92 | freq=freq)
93 |
--------------------------------------------------------------------------------
/pdspy/imaging/imaging.py:
--------------------------------------------------------------------------------
1 | import numpy
2 | import astropy
3 | import h5py
4 | from ..constants.physics import c
5 |
6 | class Image:
7 |
8 | def __init__(self,image=None,x=None,y=None,header=None,wave=None, \
9 | freq=None,unc=None,velocity=None):
10 |
11 | if (type(image) != type(None)):
12 | self.image = image
13 |
14 | if (type(x) != type(None)):
15 | self.x = x
16 | self.y = y
17 | if (type(header) != type(None)):
18 | self.header = header
19 | if (type(unc) != type(None)):
20 | self.unc = unc
21 | if (type(velocity) != type(None)):
22 | self.velocity = velocity
23 |
24 | if (type(wave) == type(None)) and (type(freq) != type(None)):
25 | self.freq = freq
26 | self.wave = c / freq
27 | elif (type(wave) != type(None)) and (type(freq) == type(None)):
28 | self.wave = wave
29 | self.freq = c / wave
30 | elif (type(wave) != type(None)) and (type(freq) != type(None)):
31 | self.wave = wave
32 | self.freq = freq
33 |
34 | def asFITS(self):
35 | hdulist = astropy.io.fits.HDUList([])
36 | for i in range(self.image[0,0,:].size):
37 | hdu = astropy.io.fits.PrimaryHDU(self.image[:,:,i])
38 |
39 | if hasattr(self, "header"):
40 | hdu.header = self.header[i]
41 |
42 | hdulist.append(hdu)
43 |
44 | return hdulist
45 |
46 | def read(self, filename=None, usefile=None):
47 | if (usefile == None):
48 | f = h5py.File(filename, "r")
49 | else:
50 | f = usefile
51 |
52 | if ('x' in f):
53 | x = f['x'][...]
54 | y = f['y'][...]
55 | else:
56 | x = None
57 | y = None
58 |
59 | if ('freq' in f):
60 | freq = f['freq'][...]
61 | else:
62 | freq = None
63 |
64 | image = f['image'][...]
65 |
66 | if ('unc' in f):
67 | unc = f['unc'][...]
68 | else:
69 | unc = None
70 |
71 | self.__init__(image, x=x, y=y, unc=unc, freq=freq)
72 |
73 | if (usefile == None):
74 | f.close()
75 |
76 | def write(self, filename=None, usefile=None):
77 | if (usefile == None):
78 | f = h5py.File(filename, "w")
79 | else:
80 | f = usefile
81 |
82 | if hasattr(self, "x"):
83 | x_dset = f.create_dataset("x", (self.x.size,), dtype='f')
84 | x_dset[...] = self.x
85 | y_dset = f.create_dataset("y", (self.y.size,), dtype='f')
86 | y_dset[...] = self.y
87 |
88 | if hasattr(self, "freq"):
89 | freq_dset = f.create_dataset("freq", (self.freq.size,), dtype='f')
90 | freq_dset[...] = self.freq
91 |
92 | image_dset = f.create_dataset("image", self.image.shape, dtype='f')
93 | image_dset[...] = self.image
94 |
95 | if hasattr(self, "unc"):
96 | unc_dset = f.create_dataset("uncertainty", self.unc.shape, \
97 | dtype='f')
98 | unc_dset[...] = self.unc
99 |
100 | if (usefile == None):
101 | f.close()
102 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 | from setuptools.extension import Extension
3 | from Cython.Build import cythonize
4 | import numpy as np
5 |
6 | # Set up the extension modules.
7 |
8 | libinterferometry = cythonize([\
9 | Extension('pdspy.interferometry.libinterferometry',\
10 | ["pdspy/interferometry/libinterferometry.pyx"],\
11 | libraries=["m"], extra_compile_args=['-ffast-math'], \
12 | include_dirs=[np.get_include()], \
13 | define_macros=[('NPY_NO_DEPRECATED_API', 0)])])[0]
14 |
15 | libimaging = cythonize([Extension('pdspy.imaging.libimaging',\
16 | ["pdspy/imaging/libimaging.pyx"], libraries=[], \
17 | extra_compile_args=[], include_dirs=[np.get_include()])])[0]
18 |
19 | bhmie = Extension('pdspy.dust.bhmie', sources=['pdspy/dust/bhmie.f90'])
20 |
21 | bhcoat = Extension('pdspy.dust.bhcoat', sources=['pdspy/dust/bhcoat.f90'])
22 |
23 | dmilay = Extension('pdspy.dust.dmilay', sources=['pdspy/dust/DMiLay.f90'])
24 |
25 | read = cythonize([Extension('pdspy.radmc3d.read', ["pdspy/radmc3d/read.pyx"], \
26 | libraries=[], extra_compile_args=[], \
27 | include_dirs=[np.get_include()])])[0]
28 |
29 | # Now define the setup for the package.
30 |
31 | setup(name="pdspy", \
32 | version="2.0.8", \
33 | author="Patrick Sheehan", \
34 | author_email="psheehan@northwestern.edu", \
35 | description="Radiative transfer modeling of protoplanetary disks", \
36 | long_description=open("README.md","r").read(), \
37 | long_description_content_type="text/markdown", \
38 | url="https://github.com/psheehan/pdspy", \
39 | packages=[\
40 | "pdspy",\
41 | "pdspy.constants", \
42 | "pdspy.dust",\
43 | "pdspy.gas",\
44 | "pdspy.imaging",\
45 | "pdspy.interferometry", \
46 | "pdspy.mcmc",\
47 | "pdspy.misc",\
48 | "pdspy.modeling",\
49 | "pdspy.plotting", \
50 | "pdspy.radmc3d",\
51 | "pdspy.spectroscopy",\
52 | "pdspy.stars",\
53 | "pdspy.statistics", \
54 | "pdspy.table", \
55 | "pdspy.utils"], \
56 | package_dir={\
57 | "pdspy.dust": 'pdspy/dust', \
58 | "pdspy.gas": 'pdspy/gas', \
59 | "pdspy.spectroscopy": 'pdspy/spectroscopy', \
60 | "pdspy.stars": 'pdspy/stars'}, \
61 | package_data={\
62 | 'pdspy.dust': ['data/*','reddening/*.dat'], \
63 | 'pdspy.imaging': ['*.pyx'], \
64 | 'pdspy.interferometry': ['*.pyx'], \
65 | 'pdspy.gas': ['data/*.dat'], \
66 | 'pdspy.radmc3d': ['*.pyx'], \
67 | 'pdspy.spectroscopy': ['btsettle_data/*.txt']}, \
68 | #ext_modules=[libinterferometry, libimaging, bhmie, \
69 | #bhcoat, dmilay, read], \
70 | ext_modules=[libinterferometry, libimaging, read], \
71 | scripts=[\
72 | 'bin/config_template.py',\
73 | 'bin/upgrade_to_pdspy2.py',\
74 | 'bin/generate_surrogate_model.py',\
75 | 'bin/disk_model_emcee3.py',\
76 | 'bin/disk_model_nested.py',\
77 | 'bin/disk_model_dynesty.py',\
78 | 'bin/disk_model_powerlaw.py',\
79 | 'bin/flared_model_emcee3.py',\
80 | 'bin/flared_model_nested.py', \
81 | 'bin/flared_model_dynesty.py'], \
82 | install_requires=['numpy','scipy','matplotlib','emcee','corner',\
83 | 'hyperion','h5py','mpi4py','Cython','astropy','schwimmbad','dynesty',\
84 | 'scikit-learn'])
85 |
--------------------------------------------------------------------------------
/pdspy/modeling/PringleDisk.py:
--------------------------------------------------------------------------------
1 | import numpy
2 | import h5py
3 | from scipy.integrate import trapz
4 | from ..constants.physics import G, m_p
5 | from ..constants.astronomy import AU, M_sun
6 | from ..constants.math import pi
7 | from ..dust import Dust
8 | from ..gas import Gas
9 | from .Disk import Disk
10 |
11 | class PringleDisk(Disk):
12 | def surface_density(self, r, normalize=True):
13 | # Get the disk parameters.
14 |
15 | rr = r * AU
16 | rin = self.rmin * AU
17 | rout = self.rmax * AU
18 | mass = self.mass * M_sun
19 | gamma = self.plrho - self.plh
20 | if self.gamma_taper != None:
21 | gamma_taper = self.gamma_taper
22 | else:
23 | gamma_taper = gamma
24 |
25 | # Set up the surface density.
26 |
27 | Sigma0 = (2-gamma)*mass/(2*pi*rout**2)*numpy.exp((rin/rout)**(2-gamma))
28 |
29 | Sigma = Sigma0 * (rr/rout)**(-gamma) * \
30 | numpy.exp(-(rr/rout)**(2-gamma_taper))
31 |
32 | Sigma[r <= rin/AU] = 0e0
33 |
34 | # In case of r == 0 (a singularity), get the value from slightly off 0.
35 |
36 | dr = rr[r > 0].min()
37 | Sigma[r == 0] = Sigma0 * (0.7*dr/rout)**(-gamma) * \
38 | numpy.exp(-(0.7*dr/rout)**(2-gamma))
39 |
40 | # Add gaps to the disk.
41 |
42 | for i in range(len(self.gap_rin)):
43 | if self.gaussian_gaps:
44 | gap_r = (self.gap_rin[i] + self.gap_rout[i])/2
45 | gap_w = self.gap_rout[i] - self.gap_rin[i]
46 |
47 | Sigma /= 1 + 1./self.gap_delta[i] * numpy.exp(-4*numpy.log(2.)*\
48 | (r - gap_r)**2 / gap_w**2)
49 | else:
50 | Sigma[(r >= self.gap_rin[i]) & \
51 | (r <= self.gap_rout[i])] *= self.gap_delta[i]
52 |
53 | ##### Normalize the surface density correctly.
54 |
55 | if normalize:
56 | r_high = numpy.logspace(numpy.log10(self.rmin), \
57 | numpy.log10(10*self.rmax), 1000)
58 | Sigma_high = self.surface_density(r_high, normalize=False)
59 |
60 | scale = mass / (2*numpy.pi*trapz(r_high*AU*Sigma_high, r_high*AU))
61 |
62 | Sigma *= scale
63 |
64 | return Sigma
65 |
66 | def scale_height(self, r):
67 | return self.h0 * AU * (r / self.rmax)**self.plh
68 |
69 | def temperature(self, r, theta, phi):
70 | ##### Disk Parameters
71 |
72 | rin = self.rmin * AU
73 | rout = self.rmax * AU
74 | t0 = self.t0
75 | plt = self.plt
76 |
77 | ##### Set up the coordinates
78 |
79 | rt, tt, pp = numpy.meshgrid(r*AU, theta, phi,indexing='ij')
80 |
81 | rr = rt*numpy.sin(tt)
82 | zz = rt*numpy.cos(tt)
83 |
84 | ##### Make the dust density model for a protoplanetary disk.
85 |
86 | t = t0 * (rr / (1*AU))**(-plt)
87 |
88 | t[rr <= rin] = 0e0
89 |
90 | t[t > 10000] = 10000
91 |
92 | return t
93 |
94 | def temperature_1d(self, r):
95 | rin = self.rmin * AU
96 | rout = self.rmax * AU
97 | t0 = self.t0
98 | plt = self.plt
99 |
100 | T = t0 * r**(-plt)
101 |
102 | T[r <= rin/AU] = 0.0
103 |
104 | dr = r[r > 0].min()
105 | T[r == 0] = t0 * (0.7*dr)**(-plt)
106 |
107 | return T
108 |
--------------------------------------------------------------------------------
/pdspy/utils/propose_point_emcee.py:
--------------------------------------------------------------------------------
1 | import numpy
2 |
3 | def propose_point_emcee(parameters, model="disk"):
4 | m_env = numpy.random.uniform(-6., parameters["logM_env"]["limits"][1],1)[0]
5 |
6 | # Set up R_env, R_disk, and R_in as they depend on eachother.
7 |
8 | if model == "disk":
9 | r_env = numpy.random.uniform(max(parameters["logR_env"]["limits"][0], \
10 | 0.5*m_env+4.), parameters["logR_env"]["limits"][1],1)[0]
11 | elif model == "flared":
12 | r_env = numpy.random.uniform(parameters["logR_env"]["limits"][0],\
13 | parameters["logR_env"]["limits"][1],1)[0]
14 |
15 | r_disk = numpy.random.uniform(max(numpy.log10(5.), \
16 | parameters["logR_disk"]["limits"][0]), min(numpy.log10(500.), \
17 | r_env, parameters["logR_disk"]["limits"][1]),1)[0]
18 | r_in = numpy.random.uniform(parameters["logR_in"]["limits"][0],\
19 | min(parameters["logR_in"]["limits"][1], \
20 | numpy.log10((10.**r_disk)/2)),1)[0]
21 |
22 | # Also set up R_cav as it depends on those as well.
23 |
24 | r_cav = numpy.random.uniform(max(r_in,parameters["logR_cav"]["limits"][0]),\
25 | min(numpy.log10(0.75*10.**r_disk),\
26 | parameters["logR_cav"]["limits"][1]),1)[0]
27 |
28 | # Same thing for R_gap and w_gap.
29 |
30 | r_gap1 = numpy.random.uniform(numpy.log10(10.**r_in+\
31 | parameters["w_gap1"]["limits"][0]/2), \
32 | numpy.log10(0.75*10.**r_disk),1)[0]
33 |
34 | w_gap1 = numpy.random.uniform(parameters["w_gap1"]["limits"][0],\
35 | min(parameters["w_gap1"]["limits"][1],\
36 | 2*(10.**r_gap1-10.**r_in)), 1)[0]
37 |
38 | # If we are using logTatm0 and logTmid0, they depend on eachother.
39 |
40 | if "logTatm0" in parameters:
41 | tatm0 = numpy.random.uniform(parameters["logTatm0"]\
42 | ["limits"][0],parameters["logTatm0"]["limits"][1],1)[0]
43 | tmid0 = numpy.random.uniform(parameters["logTmid0"]["limits"][0],\
44 | min(parameters["logTatm0"]["limits"][1], tatm0),1)[0]
45 |
46 | # Loop through and generate the point proposal.
47 |
48 | p = []
49 |
50 | for key in sorted(parameters.keys()):
51 | if parameters[key]["fixed"]:
52 | pass
53 | elif key == "logR_in":
54 | p.append(r_in)
55 | elif key == "logR_disk":
56 | p.append(r_disk)
57 | elif key == "logR_env":
58 | p.append(r_env)
59 | elif key == "logR_cav":
60 | p.append(r_cav)
61 | elif key == "logR_gap1":
62 | p.append(r_gap1)
63 | elif key == "w_gap1":
64 | p.append(w_gap1)
65 | elif key == "logM_disk" and model == "disk":
66 | p.append(numpy.random.uniform(-6.,parameters[key]["limits"][1], \
67 | 1)[0])
68 | elif key == "logM_env":
69 | p.append(m_env)
70 | elif key == "h_0":
71 | p.append(numpy.random.uniform(parameters[key]["limits"][0], \
72 | 0.2, 1)[0])
73 | elif key == "logTatm0":
74 | p.append(tatm0)
75 | elif key == "logTmid0":
76 | p.append(tmid0)
77 | elif key[0:8] == "flux_unc":
78 | p.append(numpy.random.normal(parameters[key]["value"], 0.001, 1)[0])
79 | else:
80 | p.append(numpy.random.uniform(parameters[key]["limits"][0], \
81 | parameters[key]["limits"][1], 1)[0])
82 |
83 | # Return the proposed point.
84 |
85 | return p
86 |
--------------------------------------------------------------------------------
/examples/run_radiative_transfer_model.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import pdspy.modeling as modeling
4 | import pdspy.interferometry as uv
5 | import pdspy.dust as dust
6 |
7 | import matplotlib.pyplot as plt
8 |
9 | import numpy
10 |
11 | # Set up a radiative transfer model:
12 |
13 | m = modeling.YSOModel()
14 |
15 | # Add a grid. Spherical typically makes the most sense.
16 |
17 | nr, ntheta, nphi = 100, 100, 2
18 | rmin, rmax = 0.1, 300
19 |
20 | m.set_spherical_grid(rmin, rmax, nr, ntheta, nphi, code="radmc3d")
21 |
22 | # Add a star to the model.
23 |
24 | m.add_star(mass=0.5, luminosity=1., temperature=4000.)
25 |
26 | #Set up dust properties for the disk.
27 |
28 | dust_gen = dust.DustGenerator(dust.__path__[0]+"/data/diana_wice.hdf5")
29 |
30 | a_max = 100 # microns
31 | p = 3.5
32 |
33 | d = dust_gen(a_max / 1e4, p) # dust_gen wants units of cm
34 |
35 | # Add a disk to the model.
36 |
37 | m.add_disk(mass=0.01, rmin=0.1, rmax=50., plrho=1., h0=0.1, plh=1., dust=d)
38 |
39 | # Finally, we need to set the wavelength grid.
40 |
41 | m.grid.set_wavelength_grid(0.1, 1.0e5, 500, log=True)
42 |
43 | # Now that we have the model set up, we need to run the radiative transfer
44 | # temperature calculation.
45 |
46 | m.run_thermal(nphot=1e6, modified_random_walk=True, verbose=True, setthreads=1,\
47 | code="radmc3d")
48 |
49 | # With that, we can now run an image.
50 |
51 | m.run_image(name="870um", nphot=1e5, npix=256, pixelsize=0.01, lam="870", \
52 | incl=45, pa=30, dpc=140, code="radmc3d", verbose=True, \
53 | setthreads=2)
54 |
55 | # Or visibilities:
56 |
57 | m.run_visibilities(name="870um", nphot=1e5, npix=256, pixelsize=0.01, \
58 | lam="870", incl=45, pa=30, dpc=140, code="radmc3d", verbose=True, \
59 | setthreads=2)
60 |
61 | # Or a spectrum:
62 |
63 | m.set_camera_wavelength(numpy.logspace(-1, 4, 50))
64 |
65 | m.run_sed(name="SED", nphot=1e4, loadlambda=True, incl=45, pa=30, dpc=140, \
66 | code="radmc3d", verbose=True, setthreads=2)
67 |
68 | # You can access the synthetic observations through:
69 |
70 | m.images
71 | m.visibilities
72 | m.spectra
73 |
74 | # For example:
75 |
76 | plt.loglog(m.spectra["SED"].wave, m.spectra["SED"].flux, "b-")
77 | plt.show()
78 |
79 | # Or an image. Note that an image is actually a 4D array - the last two dimensions are for frequency (in case of image cubes) and polarization.
80 |
81 | plt.imshow(m.images["870um"].image[:,:,0,0], origin="lower", \
82 | interpolation="nearest")
83 | plt.show()
84 |
85 | # Image objects also have a few other parts that may be of use:
86 |
87 | m.images["870um"].x
88 | m.images["870um"].y
89 | m.images["870um"].freq
90 |
91 | # Finally, lets average the visibility data azimuthally and plot it. Binsize is
92 | # in units of klambda. As is m1d.uvdist
93 |
94 | m1d = uv.average(m.visibilities["870um"], gridsize=10000, binsize=3500, \
95 | radial=True)
96 |
97 | plt.semilogx(m1d.uvdist, m1d.amp, "-")
98 |
99 | plt.show()
100 |
101 | # Visibility classes also have a few other parts that may be of use:
102 |
103 | m.visibilities["870um"].u
104 | m.visibilities["870um"].v
105 | m.visibilities["870um"].uvdist
106 | m.visibilities["870um"].real
107 | m.visibilities["870um"].imag
108 | m.visibilities["870um"].amp
109 | m.visibilities["870um"].weights
110 | m.visibilities["870um"].freq
111 |
112 | # Finally, if you want to access the actual density and temperature structures,
113 | # you can find them here:
114 |
115 | m.grid.r
116 | m.grid.theta
117 | m.grid.phi
118 |
119 | m.grid.density[0] # should be (r, theta, phi)
120 | m.grid.temperature[0]
121 |
--------------------------------------------------------------------------------
/pdspy/dust/data/optical_constants/graphite.txt:
--------------------------------------------------------------------------------
1 | 5.1825018009E+02 1.7900000000E+00 2.5554500000E-02
2 | 4.5767637703E+02 1.7900000000E+00 2.5756600000E-02
3 | 4.0418248031E+02 1.7900000000E+00 2.6165700000E-02
4 | 3.5916572984E+02 1.7900000000E+00 2.6372700000E-02
5 | 3.2315502716E+02 1.7900000000E+00 2.6791500000E-02
6 | 2.8538487004E+02 1.7900000000E+00 2.7432300000E-02
7 | 2.5202819691E+02 1.7900000000E+00 2.8310600000E-02
8 | 2.2535465188E+02 1.7900000000E+00 2.8987700000E-02
9 | 2.0150402605E+02 1.7900000000E+00 2.9681100000E-02
10 | 1.8017758303E+02 1.7900000000E+00 3.1117800000E-02
11 | 1.5813251821E+02 1.7900000000E+00 3.2624200000E-02
12 | 1.4125371144E+02 1.7900000000E+00 3.4185000000E-02
13 | 1.2589257838E+02 1.7900000000E+00 3.5619000000E-02
14 | 1.1220183764E+02 1.7900000000E+00 3.6350000000E-02
15 | 1.0000000000E+02 1.7900000000E+00 3.7655000000E-02
16 | 8.9124971034E+01 1.7870000000E+00 3.7642000000E-02
17 | 7.9432533977E+01 1.7840000000E+00 3.5711000000E-02
18 | 7.0794455378E+01 1.7810000000E+00 3.4111000000E-02
19 | 6.3095861542E+01 1.7780000000E+00 3.2733000000E-02
20 | 5.6234113863E+01 1.7740000000E+00 3.2593000000E-02
21 | 5.0118781512E+01 1.7710000000E+00 3.3774000000E-02
22 | 4.4668381933E+01 1.7670000000E+00 3.5587000000E-02
23 | 3.9360471066E+01 1.7630000000E+00 3.7998300000E-02
24 | 3.4622801885E+01 1.7590000000E+00 4.0870900000E-02
25 | 3.1046837259E+01 1.7560000000E+00 4.3761000000E-02
26 | 2.7485515133E+01 1.7530000000E+00 4.6642500000E-02
27 | 2.4646811196E+01 1.7500000000E+00 4.9487800000E-02
28 | 2.2101254688E+01 1.7480000000E+00 5.2506600000E-02
29 | 1.9818619990E+01 1.7460000000E+00 5.5456400000E-02
30 | 1.7321656227E+01 1.7440000000E+00 5.8572000000E-02
31 | 1.5124016939E+01 1.7420000000E+00 6.3214000000E-02
32 | 1.3663050057E+01 1.7410000000E+00 6.8382900000E-02
33 | 1.2416190713E+01 1.7380000000E+00 7.4041000000E-02
34 | 1.1044842059E+01 1.7340000000E+00 8.2863000000E-02
35 | 1.0044194456E+01 1.7280000000E+00 9.1025000000E-02
36 | 8.9126559715E+00 1.7160000000E+00 1.0090000000E-01
37 | 7.7760497667E+00 1.6970000000E+00 1.0680000000E-01
38 | 6.9204152249E+00 1.6810000000E+00 1.0400000000E-01
39 | 6.1538461538E+00 1.6700000000E+00 9.6063000000E-02
40 | 5.3966540745E+00 1.6660000000E+00 8.8005000000E-02
41 | 4.8007681229E+00 1.6670000000E+00 8.5660000000E-02
42 | 4.4286979628E+00 1.6680000000E+00 8.7206000000E-02
43 | 3.9401103231E+00 1.6680000000E+00 9.3402000000E-02
44 | 3.5486160397E+00 1.6640000000E+00 1.0050000000E-01
45 | 3.1625553447E+00 1.6550000000E+00 1.0480000000E-01
46 | 2.8153153153E+00 1.6500000000E+00 1.0460000000E-01
47 | 2.5233409034E+00 1.6490000000E+00 1.0530000000E-01
48 | 2.2609088854E+00 1.6510000000E+00 1.0960000000E-01
49 | 1.9968051118E+00 1.6540000000E+00 1.1880000000E-01
50 | 1.7636684303E+00 1.6550000000E+00 1.3190000000E-01
51 | 1.5790304753E+00 1.6560000000E+00 1.4640000000E-01
52 | 1.4042971493E+00 1.6560000000E+00 1.6490000000E-01
53 | 1.2642225032E+00 1.6550000000E+00 1.8420000000E-01
54 | 1.1270145385E+00 1.6530000000E+00 2.0890000000E-01
55 | 1.0032102729E+00 1.6480000000E+00 2.3840000000E-01
56 | 8.9325591782E-01 1.6410000000E+00 2.7310000000E-01
57 | 7.9434426881E-01 1.6280000000E+00 3.1480000000E-01
58 | 7.0796460177E-01 1.6070000000E+00 3.6250000000E-01
59 | 6.3095463436E-01 1.5730000000E+00 4.1570000000E-01
60 | 5.6433408578E-01 1.5240000000E+00 4.6630000000E-01
61 | 4.9895220038E-01 1.4520000000E+00 5.1260000000E-01
62 | 4.4668780989E-01 1.3750000000E+00 5.4220000000E-01
63 | 3.9810502010E-01 1.2840000000E+00 5.5570000000E-01
64 | 3.5481124042E-01 1.1900000000E+00 5.4510000000E-01
65 | 3.1622553205E-01 1.1070000000E+00 5.1100000000E-01
66 | 2.8184098532E-01 1.0440000000E+00 4.6380000000E-01
67 | 2.5118685790E-01 9.9920000000E-01 4.1830000000E-01
68 | 2.2387391421E-01 9.6090000000E-01 3.8240000000E-01
69 | 1.9952513019E-01 9.1460000000E-01 3.4690000000E-01
70 |
--------------------------------------------------------------------------------
/pdspy/plotting/plot_2D_visibilities.py:
--------------------------------------------------------------------------------
1 | import matplotlib.pyplot as plt
2 | import matplotlib.ticker as ticker
3 |
4 | def plot_2D_visibilities(visibilities, model, parameters, params, index=0, \
5 | fig=None):
6 |
7 | # Generate a figure and axes if none is provided.
8 |
9 | if fig == None:
10 | fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(9.,4.))
11 | else:
12 | fig, ax = fig
13 |
14 | # Calculate the pixel range to show.
15 |
16 | ticks = visibilities["ticks"][index]
17 |
18 | xmin, xmax = int(round(visibilities["npix"][index]/2+ticks[0]/\
19 | (visibilities["binsize"][index]/1000))), \
20 | int(round(visibilities["npix"][index]/2+ticks[-1]/\
21 | (visibilities["binsize"][index]/1000)))
22 | ymin, ymax = int(round(visibilities["npix"][index]/2+ticks[0]/\
23 | (visibilities["binsize"][index]/1000))), \
24 | int(round(visibilities["npix"][index]/2+ticks[-1]/\
25 | (visibilities["binsize"][index]/1000)))
26 |
27 | # How to scale the real part.
28 |
29 | vmin = min(0, visibilities["data1d"][index].real.min())
30 | vmax = visibilities["data1d"][index].real.max()
31 |
32 | # Show the real component.
33 |
34 | ax[0].imshow(visibilities["data2d"][index].real.reshape(\
35 | (visibilities["npix"][index],visibilities["npix"][index]))\
36 | [xmin:xmax,xmin:xmax][:,::-1], origin="lower", \
37 | interpolation="nearest", vmin=vmin, vmax=vmax, cmap="jet")
38 |
39 | ax[0].contour(model.visibilities[visibilities["lam"][index]+"_2d"].real.\
40 | reshape((visibilities["npix"][index],visibilities["npix"][index]))\
41 | [xmin:xmax,xmin:xmax][:,::-1], cmap="jet")
42 |
43 | # How to scale the imaginary part.
44 |
45 | vmin = -visibilities["data1d"][index].real.max()
46 | vmax = visibilities["data1d"][index].real.max()
47 |
48 | # Show the imaginary component.
49 |
50 | ax[1].imshow(visibilities["data2d"][index].imag.reshape(\
51 | (visibilities["npix"][index],visibilities["npix"][index]))\
52 | [xmin:xmax,xmin:xmax][:,::-1], origin="lower", \
53 | interpolation="nearest", vmin=vmin, vmax=vmax, cmap="jet")
54 |
55 | ax[1].contour(model.visibilities[visibilities["lam"][index]+"_2d"].imag.\
56 | reshape((visibilities["npix"][index],visibilities["npix"][index]))\
57 | [xmin:xmax,xmin:xmax][:,::-1], cmap="jet")
58 |
59 | # Adjust the axes ticks.
60 |
61 | transform1 = ticker.FuncFormatter(Transform(xmin, xmax, \
62 | visibilities["binsize"][index]/1000, '%.0f'))
63 |
64 | ax[0].set_xticks(visibilities["npix"][index]/2+ticks[1:-1]/\
65 | (visibilities["binsize"][index]/1000)-xmin)
66 | ax[0].set_yticks(visibilities["npix"][index]/2+ticks[1:-1]/\
67 | (visibilities["binsize"][index]/1000)-ymin)
68 | ax[0].get_xaxis().set_major_formatter(transform1)
69 | ax[0].get_yaxis().set_major_formatter(transform1)
70 |
71 | ax[1].set_xticks(visibilities["npix"][index]/2+ticks[1:-1]/\
72 | (visibilities["binsize"][index]/1000)-xmin)
73 | ax[1].set_yticks(visibilities["npix"][index]/2+ticks[1:-1]/\
74 | (visibilities["binsize"][index]/1000)-ymin)
75 | ax[1].get_xaxis().set_major_formatter(transform1)
76 | ax[1].get_yaxis().set_major_formatter(transform1)
77 |
78 | # Adjust the plot and save it.
79 |
80 | ax[0].set_xlabel("U [k$\lambda$]")
81 | ax[0].set_ylabel("V [k$\lambda$]")
82 |
83 | ax[1].set_xlabel("U [k$\lambda$]")
84 | ax[1].set_ylabel("V [k$\lambda$]")
85 |
86 | # Return the figure and axes.
87 |
88 | return fig, ax
89 |
90 | # Define a useful class for plotting.
91 |
92 | class Transform:
93 | def __init__(self, xmin, xmax, dx, fmt):
94 | self.xmin = xmin
95 | self.xmax = xmax
96 | self.dx = dx
97 | self.fmt = fmt
98 |
99 | def __call__(self, x, p):
100 | return self.fmt% ((x-(self.xmax-self.xmin+1)/2)*self.dx)
101 |
--------------------------------------------------------------------------------
/pdspy/plotting/plot_SED.py:
--------------------------------------------------------------------------------
1 | from pdspy.constants.astronomy import Jy
2 | from pdspy.constants.physics import c as c_l
3 | import matplotlib.pyplot as plt
4 |
5 | def plot_SED(spectra, model, SED=False, fig=None, model_color="g",
6 | linewidth=1, fontsize="medium"):
7 | r"""
8 | Plot the SED generated by a radiative transfer modeling run with pdspy, typically generated by the output of `modeling.run_disk_model`.
9 |
10 | Args:
11 | :attr:`spectra` (list):
12 | List of `Spectrum` objects with data for the object you are studying.
13 | :attr:`model` (`modeling.Model`):
14 | The radiative transfer model that you would like to plot the SED of. The `Model.spectra` dictionary must include a `"SED"` key. Typically this is the output of modeling.run_disk_model.
15 | :attr:`SED` (bool, optional):
16 | Whether to plot as a traditional SED (`True`), i.e. as :math:`\nu F_{\nu}`, or as a spectrum, i.e. :math:`F_{\nu}`. Default: `False`
17 | :attr:`fig` (`tuple`, `(matplotlib.Figure, matplotlib.Axes)`, optional):
18 | If you've already created a figure and axes to put the plot in, you can supply them here. Otherwise, `plot_SED` will generate them for you. Default: `None`
19 | :attr:`model_color` (str, optional):
20 | The color to use for plotting the model SED. Default: `"g"`
21 | :attr:`linewidth` (int, optional):
22 | What linewidth to use for plotting the model. Default: 1
23 | :attr:`fontsize` (`str` or `int`):
24 | What fontsize to use for labels, ticks, etc. Default: `"medium"`
25 |
26 | Returns:
27 | :attr:`fig` (`matplotlib.Figure`):
28 | The matplotlib figure that was used for the plot.
29 | :attr:`ax` (`matplotlib.Axes`):
30 | The matplotlib axes that were used for the plot.
31 | """
32 |
33 | # If no axes are provided, create them.
34 |
35 | if fig == None:
36 | fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(4.5,4))
37 | else:
38 | fig, ax = fig
39 |
40 | # Plot the SED.
41 |
42 | for j in range(len(spectra["file"])):
43 | if spectra["bin?"][j]:
44 | if SED:
45 | ax.plot(spectra["data"][j].wave, \
46 | c_l / spectra["data"][j].wave / 1.0e-4 * \
47 | spectra["data"][j].flux * Jy, "k-")
48 | else:
49 | ax.plot(spectra["data"][j].wave, spectra["data"][j].flux, \
50 | "k-")
51 | else:
52 | if SED:
53 | ax.errorbar(spectra["data"][j].wave, \
54 | c_l / spectra["data"][j].wave / 1.0e-4 * \
55 | spectra["data"][j].flux * Jy, fmt="ko", \
56 | yerr=c_l / spectra["data"][j].wave / 1.0e-4 * \
57 | spectra["data"][j].unc * Jy, markeredgecolor="k")
58 | else:
59 | ax.errorbar(spectra["data"][j].wave, \
60 | spectra["data"][j].flux, fmt="ko", \
61 | yerr=spectra["data"][j].unc, markeredgecolor="k")
62 |
63 | if len(spectra["file"]) > 0:
64 | if SED:
65 | ax.plot(model.spectra["SED"].wave, c_l/model.spectra["SED"].wave / \
66 | 1.0e-4 * model.spectra["SED"].flux * Jy, "-", \
67 | color=model_color, linewidth=linewidth)
68 | else:
69 | ax.plot(model.spectra["SED"].wave, model.spectra["SED"].flux, "-", \
70 | color=model_color, linewidth=linewidth)
71 |
72 | # Add axes labels and adjust the plot.
73 |
74 | if SED:
75 | ax.axis([0.1,1.0e4,1e-13,1e-8])
76 | else:
77 | ax.axis([0.1,1.0e4,1e-6,1e3])
78 |
79 | ax.set_xscale("log", nonpositive='clip')
80 | ax.set_yscale("log", nonpositive='clip')
81 |
82 | ax.set_xlabel("$\lambda$ [$\mu$m]", fontsize=fontsize)
83 | if SED:
84 | ax.set_ylabel(r"$\nu F_{\nu}$ [ergs s$^{-1}$ cm$^{-2}$]", \
85 | fontsize=fontsize)
86 | else:
87 | ax.set_ylabel(r"$F_{\nu}$ [Jy]", fontsize=fontsize)
88 |
89 | # Return the figure and axes.
90 |
91 | return fig, ax
92 |
--------------------------------------------------------------------------------
/pdspy/interferometry/invert.py:
--------------------------------------------------------------------------------
1 | import numpy
2 | from . import center
3 | from .libinterferometry import grid
4 | from ..imaging import Image
5 | from ..constants.astronomy import arcsec
6 | from scipy.fftpack import ifft2, fftshift, ifftshift, fftfreq
7 |
8 | def invert(data, imsize=256, pixel_size=0.25, convolution="pillbox", mfs=False,\
9 | weighting="natural", robust=2, npixels=0, centering=None, \
10 | mode='continuum', beam=False, uvtaper=None):
11 |
12 | # If we are calculating the beam, set all of the real values to 1 and the
13 | # imaginary data to 0.
14 |
15 | if beam:
16 | real = data.real.copy()
17 | imag = data.imag.copy()
18 |
19 | data.real[:,:] = 1.
20 | data.imag[:,:] = 0.
21 |
22 | # Apply a uv-taper to the data, if requested.
23 |
24 | if type(uvtaper) != type(None):
25 | taper = numpy.exp(-0.5*data.uvdist**2/(uvtaper*1e3)**2)
26 |
27 | weights = data.weights.copy()
28 | for i in range(data.freq.size):
29 | data.weights[:,i] *= taper
30 |
31 | # Grid the data before imaging.
32 |
33 | binsize = 1.0 / (pixel_size * imsize * arcsec)
34 | gridded_data = grid(data, gridsize=imsize, binsize=binsize, \
35 | convolution=convolution, mfs=mfs, imaging=True, \
36 | weighting=weighting, robust=robust, npixels=npixels, mode=mode)
37 |
38 | # If making an image of the beam, restore the data to what it was before.
39 |
40 | if beam:
41 | data.real = real
42 | data.imag = imag
43 |
44 | # If using uvtaper, restore the weights.
45 |
46 | if type(uvtaper) != type(None):
47 | data.weights = weights
48 |
49 | # Center the data, if requested.
50 |
51 | if type(centering) != type(None):
52 | gridded_data = center(gridded_data, centering)
53 |
54 | # Set up information for the final image.
55 |
56 | x = fftshift(fftfreq(imsize, binsize)) / arcsec
57 | y = fftshift(fftfreq(imsize, binsize)) / arcsec
58 | xx, yy = numpy.meshgrid(x, y)
59 | r = numpy.sqrt(xx**2 + yy**2)
60 |
61 | image = numpy.zeros((imsize,imsize,gridded_data.real.shape[1],1))
62 |
63 | # Loop through frequency space and do the Fourier transform.
64 |
65 | for i in range(gridded_data.real.shape[1]):
66 | u = gridded_data.u.reshape((imsize, imsize))
67 | v = gridded_data.v.reshape((imsize, imsize))
68 | real = gridded_data.real[:,i].reshape((imsize, imsize))
69 | imag = gridded_data.imag[:,i].reshape((imsize, imsize))
70 | weights = gridded_data.weights[:,i].reshape((imsize, imsize))
71 |
72 | comp = real + 1j*imag
73 |
74 | if convolution == "pillbox":
75 | conv_func = pillbox
76 | elif convolution == "expsinc":
77 | conv_func = exp_sinc
78 |
79 | im = fftshift(ifft2(ifftshift(comp))).real * imsize**2
80 |
81 | convolve = fftshift(ifft2(ifftshift(conv_func(u, v, binsize, \
82 | binsize)))).real
83 |
84 | image[:,:,i,0] = (im/convolve)[:,::-1]
85 |
86 | # Make sure the beam peaks at exactly 1. Should be just a small
87 | # correction.
88 |
89 | if beam:
90 | image[:,:,i,0] /= image[:,:,i,0].max()
91 |
92 | return Image(image, x=x, y=y, freq=gridded_data.freq)
93 |
94 | def pillbox(u, v, delta_u, delta_v):
95 |
96 | m = 1
97 |
98 | arr = numpy.ones(u.shape, dtype=float)*u.size
99 |
100 | arr[numpy.abs(u) >= m * delta_u / 2] = 0
101 | arr[numpy.abs(v) >= m * delta_v / 2] = 0
102 |
103 | return arr
104 |
105 | def exp_sinc(u, v, delta_u, delta_v):
106 |
107 | alpha1 = 1.55
108 | alpha2 = 2.52
109 | m = 6
110 |
111 | arr = numpy.sinc(u / (alpha1 * delta_u)) * \
112 | numpy.exp(-1 * (u / (alpha2 * delta_u))**2)* \
113 | numpy.sinc(v / (alpha1 * delta_v)) * \
114 | numpy.exp(-1 * (v / (alpha2 * delta_v))**2)
115 |
116 | arr[numpy.abs(u) >= m * delta_u / 2] = 0
117 | arr[numpy.abs(v) >= m * delta_v / 2] = 0
118 |
119 | arr = arr/arr.sum() * arr.size
120 |
121 | return arr
122 |
--------------------------------------------------------------------------------
/pdspy/interferometry/readuvfits.py:
--------------------------------------------------------------------------------
1 | from astropy.io.fits import open
2 | from ..constants.physics import c
3 | from .libinterferometry import Visibilities
4 | import numpy
5 |
6 | def readuvfits(filename, fmt="casa", fast=False):
7 |
8 | data = open(filename)
9 |
10 | header = data[0].header
11 | u = data[0].data.field(0).astype(numpy.float64)
12 | v = data[0].data.field(1).astype(numpy.float64)
13 |
14 | order = numpy.argsort(u)
15 |
16 | u = u[order]
17 | v = v[order]
18 |
19 | if fmt in ["casa","noema"]:
20 | arr = data[0].data.field("data").astype(numpy.float)
21 |
22 | for i in range(min(2,data[0].data.field("data").shape[5])):
23 | if i == 0:
24 | real = [arr[:,0,0,j,:,0,0] for j in range(arr.shape[3])]
25 | imag = [arr[:,0,0,j,:,0,1] for j in range(arr.shape[3])]
26 | weights = [arr[:,0,0,j,:,0,2] for j in range(arr.shape[3])]
27 | baselines = data[0].data.field(5)
28 |
29 | real = numpy.concatenate(real, axis=1)
30 | imag = numpy.concatenate(imag, axis=1)
31 | weights = numpy.concatenate(weights, axis=1)
32 |
33 | real = real[order,:]
34 | imag = imag[order,:]
35 | weights = weights[order,:]
36 | baselines = baselines[order]
37 | else:
38 | new_real = [arr[:,0,0,j,:,1,0] for j in range(arr.shape[3])]
39 | new_imag = [arr[:,0,0,j,:,1,1] for j in range(arr.shape[3])]
40 | new_weights = [arr[:,0,0,j,:,1,2] for j in range(arr.shape[3])]
41 |
42 | new_real = numpy.concatenate(new_real, axis=1)
43 | new_imag = numpy.concatenate(new_imag, axis=1)
44 | new_weights = numpy.concatenate(new_weights, axis=1)
45 |
46 | new_real = new_real[order,:]
47 | new_imag = new_imag[order,:]
48 | new_weights = new_weights[order,:]
49 |
50 | real = real*weights + new_real*new_weights
51 | imag = imag*weights + new_imag*new_weights
52 | weights += new_weights
53 | real[weights != 0] /= weights[weights != 0]
54 | imag[weights != 0] /= weights[weights != 0]
55 | elif fmt == "miriad":
56 | real = (data[0].data.field("data"))[:,0,0,:,0,0].astype(numpy.float64)
57 | imag = (data[0].data.field("data"))[:,0,0,:,0,1].astype(numpy.float64)
58 | weights = (data[0].data.field("data"))[:,0,0,:,0,2].\
59 | astype(numpy.float64)
60 | baselines = data[0].data.field(3)
61 | ant2 = numpy.mod(baselines,256)
62 | ant1 = (baselines-ant2)/256
63 | baseline = numpy.repeat(" 6.1-6.1",u.size)
64 | baseline[((ant1 < 7) & (ant2 >= 7)) ^ ((ant1 >= 7) & (ant2 < 7))] = \
65 | " 6.1-10.4"
66 | baseline[(ant1 < 7) & (ant2 < 7)] = "10.4-10.4"
67 |
68 | u = numpy.concatenate((u, -u))
69 | v = numpy.concatenate((v, -v))
70 | real = numpy.concatenate((real, real))
71 | imag = numpy.concatenate((imag, -imag))
72 | weights = numpy.concatenate((weights, weights))
73 | baseline = numpy.concatenate((baseline, baseline))
74 |
75 | if fmt == "casa":
76 | IF = data[1].data.field('if freq')[0]
77 | delta_freq = data[1].data.field('ch width')[0]
78 | else:
79 | IF = 0.
80 | delta_freq = header["CDELT4"]
81 | freq0 = header["CRVAL4"]
82 | pix0 = header["CRPIX4"]
83 | nfreq = header["NAXIS4"]
84 |
85 | if isinstance(IF, float):
86 | IF = numpy.array([IF])
87 | delta_freq = numpy.array([delta_freq])
88 |
89 | freq = [freq0 + IF[i] + (numpy.arange(nfreq)-(pix0-1))*delta_freq[i] \
90 | for i in range(IF.size)]
91 |
92 | freq = numpy.concatenate(freq)
93 | nfreq = header["NAXIS4"]*IF.size
94 |
95 | u *= freq.mean()
96 | v *= freq.mean()
97 |
98 | weights *= nfreq
99 |
100 | data.close()
101 |
102 | uvdata = Visibilities(u, v, freq, real, -imag, weights, baseline=baseline)
103 |
104 | uvdata.set_header(header)
105 |
106 | return uvdata
107 |
--------------------------------------------------------------------------------
/pdspy/modeling/SettledPringleDisk.py:
--------------------------------------------------------------------------------
1 | import numpy
2 | import h5py
3 | from ..constants.physics import G, m_p
4 | from ..constants.astronomy import AU, M_sun
5 | from ..constants.math import pi
6 | from ..dust import Dust
7 | from ..gas import Gas
8 | from .SettledDisk import SettledDisk
9 |
10 | class SettledPringleDisk(SettledDisk):
11 | def surface_density(self, r, normalize=True):
12 | # Get the disk parameters.
13 |
14 | rr = r * AU
15 | rin = self.rmin * AU
16 | rout = self.rmax * AU
17 | mass = self.mass * M_sun
18 | gamma = self.plrho - self.plh
19 | if self.gamma_taper != None:
20 | gamma_taper = self.gamma_taper
21 | else:
22 | gamma_taper = gamma
23 |
24 | # Set up the surface density.
25 |
26 | Sigma0 = (2-gamma)*mass/(2*pi*rout**2)*numpy.exp((rin/rout)**(2-gamma))
27 |
28 | Sigma = Sigma0 * (rr/rout)**(-gamma) * \
29 | numpy.exp(-(rr/rout)**(2-gamma_taper))
30 |
31 | Sigma[r <= rin/AU] = 0e0
32 |
33 | # In case of r == 0 (a singularity), get the value from slightly off 0.
34 |
35 | dr = rr[r > 0].min()
36 | Sigma[r == 0] = Sigma0 * (0.7*dr/rout)**(-gamma) * \
37 | numpy.exp(-(0.7*dr/rout)**(2-gamma))
38 |
39 | # Add gaps to the disk.
40 |
41 | for i in range(len(self.gap_rin)):
42 | if self.gaussian_gaps:
43 | gap_r = (self.gap_rin[i] + self.gap_rout[i])/2
44 | gap_w = self.gap_rout[i] - self.gap_rin[i]
45 |
46 | Sigma /= 1 + 1./self.gap_delta[i] * numpy.exp(-4*numpy.log(2.)*\
47 | (r - gap_r)**2 / gap_w**2)
48 | else:
49 | Sigma[(r >= self.gap_rin[i]) & \
50 | (r <= self.gap_rout[i])] *= self.gap_delta[i]
51 |
52 | ##### Normalize the surface density correctly.
53 |
54 | if normalize:
55 | r_high = numpy.logspace(numpy.log10(self.rmin), \
56 | numpy.log10(self.rmax), 1000)
57 | Sigma_high = self.surface_density(r_high, normalize=False)
58 |
59 | scale = mass / (2*numpy.pi*trapz(r_high*AU*Sigma_high, r_high*AU))
60 |
61 | Sigma *= scale
62 |
63 | return Sigma
64 |
65 | def scale_height(self, r):
66 | return self.h0 * AU * (r / self.rmax)**self.plh
67 |
68 | def temperature(self, r, theta, phi):
69 | ##### Disk Parameters
70 |
71 | rin = self.rmin * AU
72 | rout = self.rmax * AU
73 | t0 = self.t0
74 | plt = self.plt
75 |
76 | ##### Set up the coordinates
77 |
78 | rt, tt, pp = numpy.meshgrid(r*AU, theta, phi,indexing='ij')
79 |
80 | rr = rt*numpy.sin(tt)
81 | zz = rt*numpy.cos(tt)
82 |
83 | ##### Make the dust density model for a protoplanetary disk.
84 |
85 | t = t0 * (rr / (1*AU))**(-plt)
86 |
87 | t[rr <= rin] = 0e0
88 |
89 | t[t > 10000] = 10000
90 |
91 | return t
92 |
93 | def temperature_1d(self, r):
94 | rin = self.rmin * AU
95 | rout = self.rmax * AU
96 | t0 = self.t0
97 | plt = self.plt
98 |
99 | T = t0 * r**(-plt)
100 |
101 | T[r <= rin/AU] = 0.0
102 |
103 | dr = r[r > 0].min()
104 | T[r == 0] = t0 * (0.7*dr)**(-plt)
105 |
106 | return T
107 |
108 | def gas_temperature(self, r, theta, phi):
109 | ##### Disk Parameters
110 |
111 | rin = self.rmin * AU
112 | rout = self.rmax * AU
113 | pltgas = self.pltgas
114 | tmid0 = self.tmid0
115 | tatm0 = self.tatm0
116 | zq0 = self.zq0
117 | delta = self.delta
118 |
119 | ##### Set up the coordinates
120 |
121 | rt, tt, pp = numpy.meshgrid(r*AU, theta, phi,indexing='ij')
122 |
123 | rr = rt*numpy.sin(tt)
124 | zz = rt*numpy.cos(tt)
125 |
126 | ##### Make the dust density model for a protoplanetary disk.
127 |
128 | zq = zq0 * (rt / rin)**1.3
129 |
130 | tmid = tmid0 * (rr / rin)**(-pltgas)
131 | tatm = tatm0 * (rr / rin)**(-pltgas)
132 |
133 | t = numpy.zeros(tatm.shape)
134 | t[zz >= zq] = tatm[zz >= zq]
135 | t[zz < zq] = tatm[zz < zq] + (tmid[zz < zq] - tatm[zz < zq]) * \
136 | (numpy.cos(numpy.pi * zz[zz < zq] / (2*zq[zz < zq])))**2*delta
137 |
138 | return t
139 |
--------------------------------------------------------------------------------