appl121105_iotorus.neutralmodelΒΆ

''' Neutral model.

An wrapper class for neutral model.
'''
import numpy as np

from pyana.pep import iotorus

from . import moon_io

class NeutralModelTwoPeak2:
    ''' A wrapping of neutral cloud model

    High performance version of :class:`NeutralModelTwoPeak`.

    >>> io = moon_io.Io()   # t=0, phase=0
    >>> nm = NeutralModelTwoPeak2(io)

    >>> print('%.2f' % nm.get_density(420000, 0, 0))
    10623.05

    If you want to know the different time, you
    can use ``t`` keyword. For example, after/before 3 hours,

    >>> n = nm.get_density([420000, 420000], [0, 0], [0, 0], tarr=[10800, -10800])
    >>> print('%.2f %.2f' % (n[0], n[1]))
    17.43 1849.77

    >>> n = nm.get_density([380000, 380000], [-175000, 175000], [0, 0])
    >>> print('%.2f %.2f' % (n[0], n[1]))
    16.53 1421.22

    '''
    def __init__(self, io):
        tpm = iotorus.TwoPeakModel()
        self.model = iotorus.RotatingNeutralCloud2(tpm)
        self.io = io

    def get_density(self, xarr, yarr, zarr, tarr=None):
        ''' Get density in cm^-3

        :param x: x coordinates in km/s.
        :returns: Density at (x, y, z) in cm^-3.
        '''
        rj = 71492.
        xrj = np.array(xarr) / rj
        yrj = np.array(yarr) / rj
        zrj = np.array(zarr) / rj

        if tarr == None:
            tarr = np.zeros_like(xrj)

        phase = np.deg2rad(self.io.get_phase(tarr))
        return self.model.get_density(xrj, yrj, zrj, iophase=phase)


class NeutralModelTwoPeak:
    ''' A wrapping (adapter) of neutral cloud model.

    Adapting :class:`pyana.pep.iotorus.RotatingNeutralCloud`
    with :class:`pyana.pep.iotorus.TwoPeakModel`.

    First, :class:`moon_io.Io` is needed to instance
    NeutralModel.  It is because neutral model depends on
    the Io position.

    >>> io = moon_io.Io()   # t=0, phase=0
    >>> nm = NeutralModelTwoPeak(io)

    Now you can get the density.
    The distance is approximately the Io position.

    >>> print('%.2f' % nm.get_density(420000, 0, 0))
    10623.05

    If you want to know the different time, you
    can use ``t`` keyword. For example, after/before 3 hours,

    >>> print('%.2f' % nm.get_density(420000, 0, 0, t=10800))
    17.43
    >>> print('%.2f' % nm.get_density(420000, 0, 0, t=-10800))
    1849.77

    After 3 hours, the position is behind Io.
    Before 3 hours, the position is in front of Io.
    The banana extends preferably toward the Io,
    the density profile looks ok.

    Also, you can check this values as follows.
    3 hours corresponds to 0.43 radiand (roughly).
    Thus, the corresponding position for t=10800 is
    (x, y, z) = (420000 * cos(0.43), -420000 * sin(0.43), 0)
    and t=-10800 is
    (x, y, z) = (420000 * cos(0.43), 420000 * sin(0.43), 0)

    >>> print('%.2f' % nm.get_density(380000, -175000, 0))
    16.53
    >>> print('%.2f' % nm.get_density(380000, 175000, 0))
    1421.22

    '''
    def __init__(self, io, rjlimit=10):
        tpm = iotorus.TwoPeakModel()
        self.model = iotorus.RotatingNeutralCloud(tpm)
        self.io = io
        self.rjlimit2 = rjlimit * rjlimit

    def get_density(self, x, y, z, t=0):
        ''' Get density in cm^-3

        :param x: x coordinates in km/s.
        :returns: Density at (x, y, z) in cm^-3.
        '''
        rj = 71492.
        xrj = np.array(x) / rj
        yrj = np.array(y) / rj
        zrj = np.array(z) / rj

        if xrj * xrj + yrj * yrj + zrj * zrj > self.rjlimit2:
            return 0

        phase = np.deg2rad(self.io.get_phase(t))
        self.model.set_iophase(phase)
        return self.model.get_density(xrj, yrj, zrj)

import unittest
import doctest


def doctests():
    return unittest.TestSuite((
        doctest.DocTestSuite(),
        ))
if __name__ == '__main__':
    unittest.main(defaultTest='doctests')