Skip to content

Commit

Permalink
speeding up
Browse files Browse the repository at this point in the history
  • Loading branch information
profxj committed May 13, 2016
1 parent 264d5b4 commit cd2655d
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 85 deletions.
23 changes: 17 additions & 6 deletions linetools/isgm/abscomponent.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,25 +108,31 @@ def from_component(cls, component, **kwargs):
A=component.A, name=component.name, **kwargs)

@classmethod
def from_dict(cls, idict, **kwargs):
def from_dict(cls, idict, coord=None, **kwargs):
""" Instantiate from a dict
Parameters
----------
idict : dict
use_line_list : str, optional
Name of the Linelist to use when generating the SpectralLines
Returns
-------
"""
slf = cls(SkyCoord(ra=idict['RA']*u.deg, dec=idict['DEC']*u.deg),
tuple(idict['Zion']), idict['zcomp'], idict['vlim']*u.km/u.s,
if coord is not None:
radec = coord
else:
radec = SkyCoord(ra=idict['RA']*u.deg, dec=idict['DEC']*u.deg)
# Init
slf = cls(radec, tuple(idict['Zion']), idict['zcomp'], idict['vlim']*u.km/u.s,
Ej=idict['Ej']/u.cm, A=idict['A'],
Ntup = tuple([idict[key] for key in ['flag_N', 'logN', 'sig_logN']]),
comment=idict['comment'], name=idict['Name'])
# Add lines
for key in idict['lines'].keys():
iline = SpectralLine.from_dict(idict['lines'][key])
iline = SpectralLine.from_dict(idict['lines'][key], coord=coord, **kwargs)
slf.add_absline(iline, **kwargs)
# Return
return slf
Expand Down Expand Up @@ -201,7 +207,7 @@ def __init__(self, radec, Zion, z, vlim, Ej=0./u.cm, A=None,
# Other
self._abslines = []

def add_absline(self, absline, tol=0.1*u.arcsec, skip_vel=False):
def add_absline(self, absline, tol=0.1*u.arcsec, skip_vel=False, chk_sep=True, **kwargs):
"""Add an AbsLine object to the component if it satisfies
all of the rules.
Expand All @@ -215,9 +221,14 @@ def add_absline(self, absline, tol=0.1*u.arcsec, skip_vel=False):
Tolerance on matching coordinates
skip_vel : bool, optional
Skip velocity test? Not recommended
chk_sep : bool, optional
Perform coordinate check (expensive)
"""
# Perform easy checks
testc = bool(self.coord.separation(absline.attrib['coord']) < tol)
if chk_sep:
testc = bool(self.coord.separation(absline.attrib['coord']) < tol)
else:
testc = True
testZ = self.Zion[0] == absline.data['Z']
testi = self.Zion[1] == absline.data['ion']
testE = bool(self.Ej == absline.data['Ej'])
Expand Down
22 changes: 17 additions & 5 deletions linetools/isgm/abssystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,16 @@ def from_components(cls, components, vlim=None):
return slf

@classmethod
def from_dict(cls, idict, skip_components=False, **kwargs):
def from_dict(cls, idict, skip_components=False, use_coord=False, **kwargs):
""" Instantiate from a dict. Usually read from the hard-drive
Parameters
----------
idict : dict
skip_components : bool, optional
use_coord : bool, optinal
Use coordinates from the system to build the components (and lines)
Speeds up performance, but you should know things are OK before using this
Returns
-------
Expand All @@ -148,10 +151,14 @@ def from_dict(cls, idict, skip_components=False, **kwargs):
)
if not skip_components:
# Components
components = ltiu.build_components_from_dict(idict, **kwargs)
if use_coord: # Speed up performance
coord = slf.coord
else:
coord = None
components = ltiu.build_components_from_dict(idict, coord=coord, **kwargs)
for component in components:
# This is to insure the components follow the rules
slf.add_component(component)
slf.add_component(component, **kwargs)

# Return
return slf
Expand Down Expand Up @@ -195,7 +202,7 @@ def __init__(self, abs_type, radec, zabs, vlim, zem=0.,
# Refs (list of references)
self.Refs = []

def add_component(self, abscomp, toler=0.2*u.arcsec):
def add_component(self, abscomp, toler=0.2*u.arcsec, chk_sep=True, **kwargs):
"""Add an AbsComponent object if it satisfies all of the rules.
For velocities, we demand that the new component has a velocity
Expand All @@ -208,9 +215,14 @@ def add_component(self, abscomp, toler=0.2*u.arcsec):
comp : AbsComponent
toler : Angle, optional
Tolerance on matching coordinates
chk_sep : bool, optional
Perform coordinate check (expensive)
"""
# Coordinates
test = bool(self.coord.separation(abscomp.coord) < toler)
if chk_sep:
test = bool(self.coord.separation(abscomp.coord) < toler)
else:
test = True
# Now redshift/velocity
zlim_comp = (1+abscomp.zcomp)*abscomp.vlim/const.c.to('km/s')
zlim_sys = (1+self.zabs)*self.vlim/const.c.to('km/s')
Expand Down
4 changes: 2 additions & 2 deletions linetools/isgm/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,14 @@ def build_components_from_dict(idict, coord=None, **kwargs):
if 'components' in idict.keys():
# Components
for key in idict['components']:
components.append(AbsComponent.from_dict(idict['components'][key], **kwargs))
components.append(AbsComponent.from_dict(idict['components'][key], coord=coord, **kwargs))
elif 'lines' in idict.keys(): # to be deprecated
lines = []
for key in idict['lines']:
if isinstance(idict['lines'][key], AbsLine):
line = idict['lines'][key]
elif isinstance(idict['lines'][key], dict):
line = AbsLine.from_dict(idict['lines'][key])
line = AbsLine.from_dict(idict['lines'][key], coord=coord)
else:
raise IOError("Need those lines")
if coord is not None:
Expand Down
84 changes: 46 additions & 38 deletions linetools/lists/linelist.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
# (e.g. MgII). Currently, priority is given to the first one loaded
# but that may not be the best approach...


class LineList(object):
"""
This Class is designed to organize and handle information about
Expand Down Expand Up @@ -83,7 +84,8 @@ def __init__(self, llst_key, verbose=False, closest=False, set_lines=True,
# This sets self._data
self.set_lines(use_ISM_table=use_ISM_table, verbose=verbose,
use_cache=use_cache)

# Memoize
self.memoize = {} # To speed up multiple calls

def load_data(self, use_ISM_table=True, tol=1e-3 * u.AA, use_cache=True):
"""Grab the data for the lines of interest
Expand Down Expand Up @@ -685,47 +687,53 @@ def __getitem__(self, k, tol=1e-3 * u.AA):
dict (from row in the data table if only 1 line is found) or
QTable (tuple when more than 1 lines are found)
'''
if isinstance(k, (float, Quantity)): # Wavelength
if isinstance(k, float): # Assuming Ang
inwv = k * u.AA
else:
inwv = k
mt = np.where(np.abs(inwv - self.wrest) < tol)[0]
elif isinstance(k, basestring): # Name
if k == 'unknown':
return self.unknown_line()
try:
return self.memoize[k]
except KeyError:
if isinstance(k, (float, Quantity)): # Wavelength
if isinstance(k, float): # Assuming Ang
inwv = k * u.AA
else:
inwv = k
mt = np.where(np.abs(inwv - self.wrest) < tol)[0]
elif isinstance(k, basestring): # Name
if k == 'unknown':
return self.unknown_line()
else:
mt = np.where(str(k) == self.name)[0]
elif isinstance(k, tuple): # Zion
mt = (self._data['Z'] == k[0]) & (self._data['ion'] == k[1])
else:
mt = np.where(str(k) == self.name)[0]
elif isinstance(k, tuple): # Zion
mt = (self._data['Z'] == k[0]) & (self._data['ion'] == k[1])
else:
raise ValueError('Not prepared for this type', k)

# No Match?
if len(mt) == 0:
# Take closest??
if self.closest and (not isinstance(k, basestring)):
mt = [np.argmin(np.abs(inwv - self.wrest))]
if self.verbose:
print('WARNING: Using {:.4f} for your input {:.4f}'.format(self.wrest[mt[0]],
inwv))
raise ValueError('Not prepared for this type', k)

# No Match?
if len(mt) == 0:
# Take closest??
if self.closest and (not isinstance(k, basestring)):
mt = [np.argmin(np.abs(inwv - self.wrest))]
if self.verbose:
print('WARNING: Using {:.4f} for your input {:.4f}'.format(self.wrest[mt[0]],
inwv))
else:
if self.verbose:
print('No such line in the list', k)
return None

# Now we have something
if len(mt) == 1:
# Pass back as dict
self.memoize[k] = dict(zip(self._data.dtype.names, self._data[mt][0]))
# return self._data[mt][0] # Pass back as a Row not a Table
elif isinstance(k, tuple):
self.memoize[k] = self._data[mt]
else:
if self.verbose:
print('No such line in the list', k)
return None

# Now we have something
if len(mt) == 1:
# Pass back as dict
return dict(zip(self._data.dtype.names, self._data[mt][0]))
# return self._data[mt][0] # Pass back as a Row not a Table
elif isinstance(k, tuple):
return self._data[mt]
else:
raise ValueError(
'{:s}: Multiple lines in the list'.format(self.__class__))
raise ValueError(
'{:s}: Multiple lines in the list'.format(self.__class__))
# Finish
return self.memoize[k]

# Printing
def __repr__(self):
return '<LineList: {:s}; {} transitions>'.format(self.list, len(self._data))


81 changes: 47 additions & 34 deletions linetools/spectralline.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@
from linetools.lists.linelist import LineList
from linetools import utils as ltu

# A few globals to speed performace
zero_coord = SkyCoord(ra=0.*u.deg, dec=0.*u.deg) # Coords
init_analy = {
'spec': None, # Analysis inputs (e.g. spectrum; from .clm file or AbsID)
'wvlim': [0., 0.]*u.AA, # Wavelength interval about the line (observed)
'vlim': [0., 0.]*u.km/u.s, # Rest-frame velocity limit of line, relative to self.attrib['z']
'flag_kin': 0, # Use for kinematic analysis?
'do_analysis': 1 # Analyze?
}
init_attrib = {
'coord': zero_coord, # Coords
'z': 0., 'sig_z': 0., # Redshift
'v': 0.*u.km/u.s, 'sig_v': 0.*u.km/u.s, # rest-frame velocity relative to z
'EW': 0.*u.AA, 'sig_EW': 0.*u.AA, 'flag_EW': 0 # EW
}

#abs_attrib = {'N': 0./u.cm**2, 'sig_N': 0./u.cm**2, 'flag_N': 0, # Column ## NOT ENOUGH SPEED-UP
# 'b': 0.*u.km/u.s, 'sig_b': 0.*u.km/u.s # Doppler
# }

# Class for Spectral line
class SpectralLine(object):
"""
Expand Down Expand Up @@ -57,7 +77,7 @@ class SpectralLine(object):
"""

@classmethod
def from_dict(cls, idict, warn_only=False):
def from_dict(cls, idict, coord=None, warn_only=False, skip_data_chk=False, **kwargs):
""" Initialize from a dict (usually read from disk)
Parameters
Expand All @@ -76,29 +96,31 @@ def from_dict(cls, idict, warn_only=False):
if idict['ltype'] == 'Abs':
# TODO: remove this try/except eventually
try:
sline = AbsLine(idict['name'])
except: # This is to be compatible JSON files already written with old notation
sline = AbsLine(idict['trans'])
sline = AbsLine(idict['name'], **kwargs)
except KeyError: # This is to be compatible JSON files already written with old notation
pdb.set_trace()
sline = AbsLine(idict['trans'], **kwargs)
else:
raise ValueError("Not prepared for type {:s}.".format(idict['ltype']))
# Check data
for key in idict['data']:
if isinstance(idict['data'][key], dict): # Assume Quantity
val = idict['data'][key]['value']
else:
val = idict['data'][key]
try:
assert sline.data[key] == val
except AssertionError:
if warn_only:
warnings.warn("Different data value for {:s}: {}, {}".format(key,sline.data[key],val))
if not skip_data_chk:
for key in idict['data']:
if isinstance(idict['data'][key], dict): # Assume Quantity
val = idict['data'][key]['value']
else:
val = idict['data'][key]
try:
assert sline.data[key] == val
except AssertionError:
if warn_only:
warnings.warn("Different data value for {:s}: {}, {}".format(key,sline.data[key],val))
# Set analy
for key in idict['analy']:
if isinstance(idict['analy'][key], dict): # Assume Quantity
#sline.analy[key] = Quantity(idict['analy'][key]['value'],
# unit=idict['analy'][key]['unit'])
sline.analy[key] = ltu.convert_quantity_in_dict(
idict['analy'][key])
#pdb.set_trace()
sline.analy[key] = ltu.convert_quantity_in_dict(idict['analy'][key])
elif key == 'spec_file':
warnings.warn("You will need to load {:s} into attrib['spec'] yourself".format(
idict['analy'][key]))
Expand All @@ -107,18 +129,20 @@ def from_dict(cls, idict, warn_only=False):
# Set attrib
for key in idict['attrib']:
if isinstance(idict['attrib'][key], dict):
sline.attrib[key] = ltu.convert_quantity_in_dict(
idict['attrib'][key])
sline.attrib[key] = ltu.convert_quantity_in_dict(idict['attrib'][key])
elif key in ['RA','DEC']:
sline.attrib['coord'] = SkyCoord(ra=idict['attrib']['RA']*u.deg,
dec=idict['attrib']['DEC']*u.deg)
if coord is None:
sline.attrib['coord'] = SkyCoord(ra=idict['attrib']['RA']*u.deg,
dec=idict['attrib']['DEC']*u.deg)
else:
sline.attrib['coord'] = coord
else:
sline.attrib[key] = idict['attrib'][key]
return sline

# Initialize with wavelength
def __init__(self, ltype, trans, linelist=None, closest=False, z=0.,
verbose=True):
verbose=True, **kwargs):

# Required
self.ltype = ltype
Expand All @@ -131,19 +155,8 @@ def __init__(self, ltype, trans, linelist=None, closest=False, z=0.,

# Other
self.data = {} # Atomic/Molecular Data (e.g. f-value, A coefficient, Elow)
self.analy = {
'spec': None, # Analysis inputs (e.g. spectrum; from .clm file or AbsID)
'wvlim': [0., 0.]*u.AA, # Wavelength interval about the line (observed)
'vlim': [0., 0.]*u.km/u.s, # Rest-frame velocity limit of line, relative to self.attrib['z']
'flag_kin': 0, # Use for kinematic analysis?
'do_analysis': 1 # Analyze?
}
self.attrib = {
'coord': SkyCoord(ra=0.*u.deg, dec=0.*u.deg), # Coords
'z': z, 'sig_z': 0., # Redshift
'v': 0.*u.km/u.s, 'sig_v': 0.*u.km/u.s, # rest-frame velocity relative to z
'EW': 0.*u.AA, 'sig_EW': 0.*u.AA, 'flag_EW': 0 # EW
}
self.analy = init_analy
self.attrib = init_attrib #{

# Fill data
self.fill_data(trans, linelist=linelist, closest=closest, verbose=verbose)
Expand Down

0 comments on commit cd2655d

Please sign in to comment.