Instruments

[1]:
import os
import sys

import numpy as np
import pandas as pd

sys.path.insert(0, os.path.join(".."))

Meudon PDR code predictions

[2]:
from infobs.model import MeudonPDR

meudonpdr = MeudonPDR()

df_params = pd.DataFrame(
    {
        "Av": [1, 5, 10, 15, 20],
        "G0": [1e2, 1e2, 1e2, 1e2, 1e2],
        "Pth": [1e5, 1e5, 1e5, 1e5, 1e5],
        "angle": [0, 0, 0, 0, 0],
    }
)

df_params
[2]:
Av G0 Pth angle
0 1 100.0 100000.0 0
1 5 100.0 100000.0 0
2 10 100.0 100000.0 0
3 15 100.0 100000.0 0
4 20 100.0 100000.0 0
[3]:
meudonpdr.predict(df_params)
[3]:
Av G0 Pth angle kappa h2_v0_j2__v0_j0 h2_v0_j3__v0_j1 h2_v0_j4__v0_j2 h2_v0_j5__v0_j3 h2_v0_j6__v0_j4 ... shp_n10_j11_f11d5__n9_j10_f10d5 shp_n10_j10_f10d5__n9_j9_f9d5 shp_n10_j9_f9d5__n9_j8_f8d5 shp_n10_j9_f9d5__n9_j10_f10d5 shp_n10_j10_f10d5__n9_j10_f10d5 shp_n5_j4_f4d5__n2_j3_f3d5 shp_n6_j5_f5d5__n3_j4_f4d5 shp_n7_j6_f6d5__n4_j5_f5d5 shp_n8_j7_f7d5__n5_j6_f6d5 shp_n9_j8_f8d5__n6_j7_f7d5
0 1.0 100.0 100000.0 0.0 1.0 0.010243 0.002992 0.000057 0.000010 0.000002 ... 2.991196e-12 2.645448e-12 2.420507e-12 3.334513e-17 2.685572e-14 7.130854e-14 1.255194e-14 2.563640e-15 5.562906e-16 1.247624e-16
1 5.0 100.0 100000.0 0.0 1.0 0.009836 0.003158 0.000060 0.000010 0.000002 ... 2.927281e-12 2.588342e-12 2.376320e-12 3.258995e-17 2.626043e-14 7.143769e-14 1.253789e-14 2.521841e-15 5.556850e-16 1.238246e-16
2 10.0 100.0 100000.0 0.0 1.0 0.010026 0.003207 0.000059 0.000010 0.000002 ... 2.915170e-12 2.580306e-12 2.359131e-12 3.258680e-17 2.623749e-14 7.176126e-14 1.255073e-14 2.530706e-15 5.523370e-16 1.229295e-16
3 15.0 100.0 100000.0 0.0 1.0 0.010062 0.003317 0.000059 0.000010 0.000002 ... 2.913692e-12 2.583992e-12 2.372837e-12 3.241424e-17 2.622504e-14 7.204642e-14 1.255310e-14 2.542738e-15 5.539160e-16 1.230413e-16
4 20.0 100.0 100000.0 0.0 1.0 0.010102 0.003278 0.000058 0.000011 0.000002 ... 2.893779e-12 2.571290e-12 2.359847e-12 3.224938e-17 2.617005e-14 7.181391e-14 1.253679e-14 2.545107e-15 5.531721e-16 1.225758e-16

5 rows × 5025 columns

[4]:
df = meudonpdr.predict(
    df_params,
    lines=[
        "13c_o_j1__j0",
        "13c_o_j2__j1",
        "13c_o_j3__j2",
        "c_el3p_j1__el3p_j0",
        "c_el3p_j2__el3p_j1",
        "cp_el2p_j3_2__el2p_j1_2",
    ],
)

df
[4]:
Av G0 Pth angle kappa 13c_o_j1__j0 13c_o_j2__j1 13c_o_j3__j2 c_el3p_j1__el3p_j0 c_el3p_j2__el3p_j1 cp_el2p_j3_2__el2p_j1_2
0 1.0 100.0 100000.0 0.0 1.0 0.000276 0.000318 0.000128 0.237290 0.168541 7.993103
1 5.0 100.0 100000.0 0.0 1.0 10.176692 11.708745 3.919423 22.388675 11.729995 10.794163
2 10.0 100.0 100000.0 0.0 1.0 22.873276 21.915024 8.102161 21.884921 11.508051 10.750909
3 15.0 100.0 100000.0 0.0 1.0 29.498773 25.964494 10.321277 22.693579 11.846299 10.839103
4 20.0 100.0 100000.0 0.0 1.0 34.912525 29.605632 12.635616 23.212814 12.121948 10.800269

Instruments

[5]:
obstime = 1  # Minutes
linewidth = 10  # km/s

Ideal instrument

Note: By definition, the integration time obstime has no effect when using the ideal instrument.

[6]:
from infobs.instruments import IdealInstrument

ideal = IdealInstrument()

ideal.measure(df, obstime)
[6]:
Av G0 Pth angle kappa 13c_o_j1__j0 13c_o_j2__j1 13c_o_j3__j2 c_el3p_j1__el3p_j0 c_el3p_j2__el3p_j1 cp_el2p_j3_2__el2p_j1_2
0 1.0 100.0 100000.0 0.0 1.0 0.000276 0.000318 0.000128 0.237290 0.168541 7.993103
1 5.0 100.0 100000.0 0.0 1.0 10.176692 11.708745 3.919423 22.388675 11.729995 10.794163
2 10.0 100.0 100000.0 0.0 1.0 22.873276 21.915024 8.102161 21.884921 11.508051 10.750909
3 15.0 100.0 100000.0 0.0 1.0 29.498773 25.964494 10.321277 22.693579 11.846299 10.839103
4 20.0 100.0 100000.0 0.0 1.0 34.912525 29.605632 12.635616 23.212814 12.121948 10.800269

IRAM 30m EMIR

[7]:
from infobs.instruments import IRAM30mEMIR

emir = IRAM30mEMIR(linewidth)

emir.measure(emir.filter_lines(df), obstime)
[7]:
Av G0 Pth angle kappa 13c_o_j1__j0 13c_o_j2__j1 13c_o_j3__j2
0 1.0 100.0 100000.0 0.0 1.0 2.304100 1.186082 2.559229
1 5.0 100.0 100000.0 0.0 1.0 11.045154 12.614035 7.962028
2 10.0 100.0 100000.0 0.0 1.0 21.275261 20.809291 12.215755
3 15.0 100.0 100000.0 0.0 1.0 30.982845 27.994013 21.121263
4 20.0 100.0 100000.0 0.0 1.0 34.579477 24.472355 8.870162

Changing integration time

[8]:
emir.measure(emir.filter_lines(df), 10 * obstime)
[8]:
Av G0 Pth angle kappa 13c_o_j1__j0 13c_o_j2__j1 13c_o_j3__j2
0 1.0 100.0 100000.0 0.0 1.0 1.007058 -0.061244 -0.406238
1 5.0 100.0 100000.0 0.0 1.0 10.733919 11.054353 1.201543
2 10.0 100.0 100000.0 0.0 1.0 22.532765 20.564771 9.082299
3 15.0 100.0 100000.0 0.0 1.0 27.842653 29.493280 8.562712
4 20.0 100.0 100000.0 0.0 1.0 31.244859 32.500944 11.883908

Changing line width

linewidth mandatory argument.

[9]:
emir = IRAM30mEMIR(linewidth=2 * linewidth)

emir.measure(emir.filter_lines(df), obstime)
[9]:
Av G0 Pth angle kappa 13c_o_j1__j0 13c_o_j2__j1 13c_o_j3__j2
0 1.0 100.0 100000.0 0.0 1.0 -5.599257 0.029949 6.860503
1 5.0 100.0 100000.0 0.0 1.0 8.376963 15.003082 9.801187
2 10.0 100.0 100000.0 0.0 1.0 17.128225 18.203982 3.208072
3 15.0 100.0 100000.0 0.0 1.0 29.142781 33.710153 14.633763
4 20.0 100.0 100000.0 0.0 1.0 35.617939 34.560992 -0.637018

Integrated precipitable water vapor

ipwv optional argument. * Available values: 0 (excellent conditions), 1 (good conditions), 2 (normal conditions) * Default: 2

[10]:
emir = IRAM30mEMIR(linewidth, ipwv=0)

emir.measure(emir.filter_lines(df), obstime)
[10]:
Av G0 Pth angle kappa 13c_o_j1__j0 13c_o_j2__j1 13c_o_j3__j2
0 1.0 100.0 100000.0 0.0 1.0 3.637652 -0.302471 1.208588
1 5.0 100.0 100000.0 0.0 1.0 13.113089 11.641636 -1.319127
2 10.0 100.0 100000.0 0.0 1.0 23.734262 27.891698 8.298691
3 15.0 100.0 100000.0 0.0 1.0 27.723701 27.294525 13.622968
4 20.0 100.0 100000.0 0.0 1.0 31.520066 29.115825 14.508134

Implementing other instruments

[11]:
from infobs.instruments import StandardInstrument

Mount Fuji submillimeter-wave telescope for [CI] lines

[12]:
class Fuji(StandardInstrument):
    """
    Obstime must be interpreted as a relative integration time compared with the one achieved in T. Oka et al, 2004 (ApJ).
    For simplicity sake, we assume the noise RMS to be identical for both lines.
    """

    def __init__(self, linewidth: float, kelvin: bool = True):
        super().__init__(
            ["c_el3p_j1__el3p_j0", "c_el3p_j2__el3p_j1"], linewidth, kelvin
        )

    @property
    def dv(self):
        return 1.0  # km/s

    @property
    def ref_obstime(self):
        return {"c_el3p_j1__el3p_j0": 1, "c_el3p_j2__el3p_j1": 1}

    @property
    def rms(self):
        return {"c_el3p_j1__el3p_j0": 0.5, "c_el3p_j2__el3p_j1": 0.5}

    @property
    def percent(self):
        return {"c_el3p_j1__el3p_j0": 20, "c_el3p_j2__el3p_j1": 20}

    def __str__(self):
        return "Mount Fuji telescope"
[13]:
fuji = Fuji(linewidth)
fuji_obstime = 0.5

fuji.measure(fuji.filter_lines(df), fuji_obstime)
[13]:
Av G0 Pth angle kappa c_el3p_j1__el3p_j0 c_el3p_j2__el3p_j1
0 1.0 100.0 100000.0 0.0 1.0 -0.353822 -0.180102
1 5.0 100.0 100000.0 0.0 1.0 26.541506 10.524991
2 10.0 100.0 100000.0 0.0 1.0 18.180540 7.015612
3 15.0 100.0 100000.0 0.0 1.0 16.307703 11.164658
4 20.0 100.0 100000.0 0.0 1.0 27.354132 10.895989

SOFIA (Stratospheric Observatory for Infrared Astronomy) for [CII] line

[14]:
class SOFIA(StandardInstrument):
    """
    Obstime must be interpreted as a relative integration time compared with the one achieved in Pabst et al, 2017 (A&A).
    Calibration error is discussed in Risacher et al, 2016.
    """

    def __init__(self, linewidth: float, kelvin: bool = True):
        super().__init__(["cp_el2p_j3_2__el2p_j1_2"], linewidth, kelvin)

    @property
    def dv(self):
        return 0.193  # km/s

    @property
    def ref_obstime(self):
        return {"cp_el2p_j3_2__el2p_j1_2": 1}

    @property
    def rms(self):
        return {"cp_el2p_j3_2__el2p_j1_2": 2.25}

    @property
    def percent(self):
        return {"cp_el2p_j3_2__el2p_j1_2": 5}

    def __str__(self):
        return "SOFIA"
[15]:
sofia = SOFIA(linewidth)
sofia_obstime = 0.25

sofia.measure(sofia.filter_lines(df), fuji_obstime)
[15]:
Av G0 Pth angle kappa cp_el2p_j3_2__el2p_j1_2
0 1.0 100.0 100000.0 0.0 1.0 7.173556
1 5.0 100.0 100000.0 0.0 1.0 10.857059
2 10.0 100.0 100000.0 0.0 1.0 8.986045
3 15.0 100.0 100000.0 0.0 1.0 12.189415
4 20.0 100.0 100000.0 0.0 1.0 11.791652

Mixing instruments

[16]:
from infobs.instruments import MergedInstrument

merged = MergedInstrument([emir, fuji, sofia])
[17]:
merged.measure(merged.filter_lines(df), [obstime, fuji_obstime, sofia_obstime])
[17]:
Av G0 Pth angle kappa 13c_o_j1__j0 13c_o_j2__j1 13c_o_j3__j2 c_el3p_j1__el3p_j0 c_el3p_j2__el3p_j1 cp_el2p_j3_2__el2p_j1_2
0 1.0 100.0 100000.0 0.0 1.0 -1.394607 1.790921 1.990865 1.067935 0.169435 8.098664
1 5.0 100.0 100000.0 0.0 1.0 10.271918 8.804715 5.461707 20.382862 12.709262 10.241453
2 10.0 100.0 100000.0 0.0 1.0 21.093096 20.478475 8.369292 17.634216 9.516761 8.793674
3 15.0 100.0 100000.0 0.0 1.0 29.499523 24.465393 9.611141 22.491916 9.317297 10.023532
4 20.0 100.0 100000.0 0.0 1.0 33.713076 35.565098 13.903594 19.555128 12.418816 6.144656

You can use the same instrument with two different integration times with two instances of the same instrument using the restrict_lines method.

In the following example, the second transition of [CI] is integrated 10 times longer.

[18]:
fuji1 = Fuji(linewidth)
fuji1.restrict_lines(["c_el3p_j1__el3p_j0"])
fuji2 = Fuji(linewidth)
fuji2.restrict_lines(["c_el3p_j2__el3p_j1"])

merged = MergedInstrument([emir, fuji1, fuji2, sofia])

merged.measure(
    merged.filter_lines(df), [obstime, fuji_obstime, 10 * fuji_obstime, sofia_obstime]
)
[18]:
Av G0 Pth angle kappa 13c_o_j1__j0 13c_o_j2__j1 13c_o_j3__j2 c_el3p_j1__el3p_j0 c_el3p_j2__el3p_j1 cp_el2p_j3_2__el2p_j1_2
0 1.0 100.0 100000.0 0.0 1.0 0.429596 1.290377 3.208243 -0.546726 -0.145097 9.386241
1 5.0 100.0 100000.0 0.0 1.0 11.208933 11.345129 -2.303984 25.432893 14.693545 13.910911
2 10.0 100.0 100000.0 0.0 1.0 22.865378 19.874641 9.037263 24.292709 12.537440 11.606017
3 15.0 100.0 100000.0 0.0 1.0 25.463512 24.593912 12.059598 23.657297 18.576150 11.382027
4 20.0 100.0 100000.0 0.0 1.0 35.870254 32.683043 19.930144 29.086794 17.062069 11.930846

All these instruments can then be used to simulate observations (see simulator.ipynb example notebook).