import os
import os.path as ospath
import glob
import time
import warnings
import numpy as np
import matplotlib.pyplot as plt
from lfd.analysis.profiles.convolution import convolve
from lfd.analysis.profiles.objectprofiles import *
from lfd.analysis.profiles.seeing import *
from lfd.analysis.profiles.consts import *
from lfd.analysis.utils import *
__all__ = ["get_rabina_profile", "meshgrid"]
[docs]def meshgrid(data, x, y, tgt, fold=None, axes=True):
"""Given a structured numpy array returns two 1D arrays and one 2D array.
The two 1D arrays contain elements of data and represent the x and y axes,
respectively, of the returned 2D. Similar to numpy's meshgrid. The 2D array
containes target column data reshaped such that it matches the chosen x and
y. Optionally, if there are multiple additional columns with which the
target data varies with, it is possible to "fold" over those columns; that
is subselect only those elements of the target data that correspond to rows
in the structured numpy array for which element values equal the given fold
values.
Parameters
----------
data : `np.array`
A structured array of data
x : `str`
A string representing the column that will be selected as the x axis.
Must be a valid dtype name of data.
y : `str`
A string representing the column that will be selected as the y axis.
Must be a valid dtype name of data.
tgt : `str`
A string representing the column that will be reshaped into 2D array
matching the entries of x and y.
fold : `dict`
An optional dictionary of key:value pairs that represent column names
and values on which to fold the total data on. Folding subselects
particular target column elements of data based matched values provided
in the dictionary.
axes : `bool`
If True, default, both axes and grid are returned. If false, only the
gridded data is returned.
Returns
-------
x : `np.array`
A 1D array containing data elements that represent the x axis of the
targeted reshaped data
y : `np.array`
A 1D array containing data elements that represent the y axis of the
targeted reshaped data
gridded : `np.array`
A 2D array
Examples
--------
>>> data
array(
[(3., 1., 5., 'DiskSource', 'GausKolmogorov', 'FluxPerAngle', 1.43, 8.1, 8.1, 3.5),
(3., 1., 6., 'DiskSource', 'GausKolmogorov', 'FluxPerAngle', 1.43, 9.8, 9.8, 1.5),
(3., 2., 5., 'DiskSource', 'GausKolmogorov', 'FluxPerAngle', 1.43, 4.5, 4.5, 2.6),
(3., 2., 6., 'DiskSource', 'GausKolmogorov', 'FluxPerAngle', 1.43, 4.4, 4.4, 1.5),
(4., 1., 5., 'DiskSource', 'GausKolmogorov', 'FluxPerAngle', 1.43, 8.1, 8.1, 3.5),
(4., 1., 6., 'DiskSource', 'GausKolmogorov', 'FluxPerAngle', 1.43, 9.8, 9.8, 1.5),
(4., 2., 5., 'DiskSource', 'GausKolmogorov', 'FluxPerAngle', 1.43, 4.5, 4.5, 2.6),
(4., 2., 6., 'DiskSource', 'GausKolmogorov', 'FluxPerAngle', 1.43, 4.4, 4.4, 1.5)],
dtype=[('fwhm', '<f8'), ('h', '<f8'), ('radius', '<f8'), ('source', '<U12'),
('seeing', '<U14'), ('defocus', '<U12'), ('sfwhm', '<f8'), ('dfwhm', '<f8'),
('ofwhm', '<f8'), ('depth', '<f8')])
>>> x, y, z = meshgrid(meas, 'h', 'fwhm', 'ofwhm', fold={'radius':5})
>>> x
array([1., 2.])
>>> y
array([3., 4.])
>>> z
array([[8.1, 4.5],
[8.1, 4.5]])
"""
unsafe=False
foldedData = data
if fold is not None:
unsafe = True
for k, v in fold.items():
foldedData = foldedData[foldedData[k] == v]
xset = set(data[x])
yset = set(data[y])
xarr = np.fromiter(xset, float, len(xset))
yarr = np.fromiter(yset, float, len(yset))
xarr.sort()
yarr.sort()
xind = data.dtype.names.index(x)
yind = data.dtype.names.index(y)
if xind >= yind:
gridded = foldedData[tgt].reshape((len(yset), len(xset)))
else:
gridded = foldedData[tgt].reshape((len(xset), len(yset))).T
if axes:
return xarr, yarr, gridded
return gridded
[docs]def get_rabina_profile(angle, useCV2=False):
"""Returns image of projected Rabina profile as a function of angle between
the observers line of sight and the velocity vector of the meteor.
Parameters
----------
angle: `float`
angle, in radians, between LOS and vector of the meteor.
useCV2: `bool`, optional
If True will use cv2 to open the Rabina profile, otherwise matplotlib.
Default is False.
Notes
-----
Pre-rendered Rabina profiles exist for angles in 0.1 increments from 0 to
1.5 inclusive. This is approximately every 6 degrees from 0 to 90 degrees.
See `gen_rabina_profile.py` in persistent cache on how to pre-render
Rabina profiles for other angles.
Profiles are searched for in both ephemeral and persistent cache locations.
If multiple matching files are found, those from peristent cache only are
returned.
Raises
------
ValueError:
when the given angle was not in the range 0-1.5 (step 0.1) inclusive.
FileNotFoundError:
when the searched for Rabina profile was not found. This can happen
only when a 3rd party has manually cleared the persistent cache.
"""
rounded = int(angle*10)
if rounded not in range(0, 16, 1):
raise ValueError("No premade Rabina profiles exist outside of the 0 to 1.5 radians!")
rabinaPaths = search_cached(f"lfd_rabina{rounded}_r.png")
if len(rabinaPaths) > 1:
rabinaPaths = search_cached(f"lfd_rabina{rounded}_r.png", ephemeral=False)
if useCV2:
import cv2
return cv2.imread(rabinaPaths[0], cv2.IMREAD_GRAYSCALE)
return plt.imread(rabinaPaths[0])
def tableRabina(angle=1.5):
profile = get_prerendered_rabina_profile_path(angle)
for h in HEIGHTS:
o = RabinaSource(profile, h)
d = FluxPerAngle(h, *SDSS)
ofwhm = o.calc_fwhm()
c = convolve(o, d)
dfwhm1 = c.calc_fwhm()
o = RabinaSource(profile, h)
s = GausKolmogorov(SDSSSEEING)
d = FluxPerAngle(h, *SDSS)
c = convolve(o, s, d)
obsfwhm1 = c.calc_fwhm()
o = RabinaSource(profile, h)
d = FluxPerAngle(h, *LSST)
c = convolve(o, d)
dfwhm2 = c.calc_fwhm()
o = RabinaSource(profile, h)
s = GausKolmogorov(LSSTSEEING)
d = FluxPerAngle(h, *LSST)
c = convolve(o, s, d)
obsfwhm2 = c.calc_fwhm()
res = "{0}&\t{1:.2f}&\t{2:.2f}&\t{3:.2f}&\t{4:.2f}&\t{5:.2f}\\\\"
print(res.format(int(h), ofwhm, dfwhm1, obsfwhm1, dfwhm2, obsfwhm2))