Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
branches:
only:
- master

language: python

python:
Expand All @@ -24,3 +28,4 @@ deploy:
on:
tags: true
branch: master

1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
7/13/18: Add codecov yaml files (issue #101)
7/11/18: Update code to python3
3/17/16: Update documentation to Sphinx standard and add documentation build files (issue #17)
2/17/16: Changes to correlation function plots & documentation (issue #77)
Expand Down
27 changes: 20 additions & 7 deletions stile/file_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
has_fits = True
except ImportError:
has_fits = False
try:
import astropy.table
has_astropy = True
from .stile_utils import Table
except ImportError:
has_astropy = False
import numpy
import os
from . import stile_utils
Expand Down Expand Up @@ -51,7 +57,10 @@ def ReadFITSTable(file_name, hdu=1, fields=None):
skip some fields.
:returns: The contents of the requested HDU.
"""
return stile_utils.FormatArray(ReadFITSImage(file_name, hdu), fields=fields)
if has_astropy:
return stile_utils.FormatArray(Table.read(file_name, hdu), fields=fields)
else:
return stile_utils.FormatArray(ReadFITSImage(file_name, hdu), fields=fields)


def ReadASCIITable(file_name, **kwargs):
Expand Down Expand Up @@ -167,7 +176,7 @@ def WriteASCIITable(file_name, data_array, fields=None, print_header=False):
warnings.warn('No named data type, so requested header cannot be printed.')
numpy.savetxt(file_name, data, fmt=_format_str(data.dtype))
else:
numpy.savetxt(file_name, data, fmt=_format_str(data.dtype))
numpy.savetxt(file_name, data, fmt=' '.join(_format_str(data.dtype)))

# And, of course, PyFITS *also* uses a different format specification character set.
_fits_dict = {'b': 'L', # boolean
Expand Down Expand Up @@ -210,11 +219,15 @@ def WriteFITSTable(file_name, data_array, fields=None):
data = _handleFields(data_array, fields)
cols = [fits_handler.Column(name=data.dtype.names[i], format=_coerceFitsFormat(data.dtype[i]),
array=data[data.dtype.names[i]]) for i in range(len(data.dtype))]
table = fits_handler.new_table(cols)
hdulist = fits_handler.HDUList(fits_handler.PrimaryHDU(), table)
hdulist.append(table)
hdulist.verify()
hdulist.writeto(file_name)
if hasattr(fits_handler, 'new_table'):
table = fits_handler.new_table(cols)
hdulist = fits_handler.HDUList(fits_handler.PrimaryHDU(), table)
hdulist.append(table)
hdulist.verify()
hdulist.writeto(file_name)
else:
table = fits_handler.TableHDU.from_columns(cols)
table.writeto(file_name)


def WriteTable(file_name, data_array, fields=None):
Expand Down
9 changes: 9 additions & 0 deletions stile/stile_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ def __str__(self):
ret_str += '\t%f %f\n'%(self.percentiles[index], self.values[index])

return ret_str

try:
import astropy.table
class Table(astropy.table.Table):
@property
def shape(self):
return (len(self), len(self.colnames))
except ImportError:
pass

fieldNames = {
'dec': 'the declination of the object',
Expand Down
21 changes: 17 additions & 4 deletions stile/treecorr_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from . import file_io
import treecorr
from treecorr.corr2 import corr2_valid_params

use_2form = any([key[:2]=='n2' for key in corr2_valid_params])

def Parser():
import argparse
Expand Down Expand Up @@ -104,6 +104,16 @@ def ReadTreeCorrResultsFile(file_name):
fields = [field for field in fields if field != '.']
return stile_utils.FormatArray(output, fields=fields)

# This next bit of code is so we work with both the 'n2_*' and the 'nn_*' treecorr args
def fixform(key):
if key[-4:]=='_col':
return key
elif key[1]=='2' and not use_2form and not key[0]=='m':
return key[0]+key[0]+key[2:]
elif key[0]==key[1] and use_2form:
return key[0]+'2'+key[2:]
return key


def PickTreeCorrKeys(input_dict):
"""
Expand All @@ -121,7 +131,10 @@ def PickTreeCorrKeys(input_dict):
treecorr_dict = input_dict['treecorr_kwargs']
else:
treecorr_dict = {}
for key in corr2_valid_params:
if key in input_dict:
treecorr_dict[key] = input_dict[key]
for key in input_dict:
newkey = fixform(key)
if newkey in corr2_valid_params:
treecorr_dict[newkey] = input_dict[key]
okeys = set(input_dict.keys())
nkeys = set(treecorr_dict.keys())
return treecorr_dict
10 changes: 4 additions & 6 deletions tests/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@ def FormatSame(arr1,arr2):
Then return a tuple of the two arrays, which can then be passed to the numpy.testing functions.
"""
if not arr1.shape==arr2.shape:
return False
return (arr1, arr2)
arr1 = numpy.array(arr1) # to protect against FITSrecs
if not len(arr1.dtype.names)==len(arr2.dtype.names):
return False
if not arr1.shape==arr2.shape:
return False
if not len(arr1.dtype.names)==len(arr2.dtype.names) or not arr1.shape==arr2.shape:
return (arr1, arr2)
arr1 = arr1.astype(arr1.dtype.newbyteorder('='))
arr2 = arr2.astype(arr2.dtype.newbyteorder('='))
arr2.dtype.names = arr1.dtype.names
return (arr1,arr2)
return (arr1, arr2)

40 changes: 36 additions & 4 deletions tests/test_correlation_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,38 @@ def setUp(self):
dtype=[("R_nom [deg]", float), ("<R> [deg]", float), ("<gamT>", float), ("<gamX>", float),
("sigma", float), ("weight", float), ("npairs", float)])

self.expected_result_meanlogr = numpy.array(
[(0.053888, 0.054459, -2.9109, 0.022059, -4.2588e-02, 0.025785, 182., 182.),
(0.062596, 0.062105, -2.7799, 0.0037377, 2.9950e-02, 0.020788, 280., 280.),
(0.072711, 0.072468, -2.6254, 0.018572, -4.1915e-02, 0.017547, 393., 393.),
(0.08446, 0.084946, -2.4664, -0.0092076, -6.1220e-03, 0.015557, 500., 500.),
(0.098107, 0.098256, -2.321, 0.019855, 9.5542e-03, 0.014469, 578., 578.),
(0.11396, 0.11411, -2.1713, 0.0076978, 4.3697e-03, 0.010679, 1061., 1061.),
(0.13237, 0.13435, -2.0082, 0.0097326, -4.2636e-03, 0.010371, 1125., 1125.),
(0.15376, 0.15209, -1.8839, 0.0024, -7.1487e-03, 0.0090482, 1478., 1478.),
(0.17861, 0.17727, -1.7306, 0.0029644, -1.9988e-03, 0.0072297, 2315., 2315.),
(0.20747, 0.20774, -1.5723, 0.0016518, -2.6162e-03, 0.0065797, 2795., 2795.),
(0.241, 0.24133, -1.4225, -0.012766, 2.9823e-04, 0.0052742, 4350., 4350.),
(0.27994, 0.28572, -1.2533, 0.0013257, -1.1404e-03, 0.0046513, 5593., 5593.),
(0.32517, 0.3273, -1.1179, -0.0025167, 3.0612e-04, 0.0045542, 5834., 5834.),
(0.37772, 0.37581, -0.98021, -0.0034272, -5.5511e-03, 0.0034589, 10114., 10114.),
(0.43875, 0.43984, -0.82263, 0.00019999, -2.4145e-03, 0.0030951, 12631., 12631.),
(0.50965, 0.49764, -0.69848, -0.0037836, 5.5003e-04, 0.0030254, 13220., 13220.),
(0.592, 0.58802, -0.53226, 0.0021309, 9.0001e-05, 0.0036726, 8971., 8971.),
(0.68766, 0.68766, -0.37447, 0., 0.0000e+00, 0., 0., 0.),
(0.79877, 0.79877, -0.22468, 0., 0.0000e+00, 0., 0., 0.),
(0.92784, 0.92784, -0.074893, 0., 0.0000e+00, 0., 0., 0.)],
dtype=[("R_nom [deg]", float), ("meanR [deg]", float),
("meanlogR [deg]", float), ("gamT", float), ("gamX", float),
("sigma", float), ("weight", float), ("npairs", float)])

def test_getCF(self):
"""Test getCF() directly, without first processing by child classes."""
# Note: bin_slop 1 is not optimal for bins this small, but an earlier version of TreeCorr
# did this by default with the settings here; we define bin_slop 1 for backwards
# compatibility
stile_args = {'ra_units': 'degrees', 'dec_units': 'degrees', 'min_sep': 0.05, 'max_sep': 1,
'sep_units': 'degrees', 'nbins': 20}
'sep_units': 'degrees', 'nbins': 20, 'bin_slop': 1}
cf = stile.sys_tests.CorrelationFunctionSysTest()
dh = temp_data_handler()
lens_data = stile.ReadASCIITable('../examples/example_lens_catalog.dat',
Expand All @@ -66,9 +94,13 @@ def test_getCF(self):
g1=source_data['g1'], g2=source_data['g2'],
ra_units='degrees', dec_units='degrees')
results = cf.getCF('ng', lens_catalog, source_catalog, **stile_args)
numpy.testing.assert_array_equal(*helper.FormatSame(results, self.expected_result))
if "meanlogR [deg]" in results.dtype.names:
expected = self.expected_result_meanlogr
else:
expected = self.expected_result
numpy.testing.assert_array_equal(*helper.FormatSame(results, expected))
results2 = cf.getCF('ng', lens_data, source_data, config=stile_args)
self.assertEqual(self.expected_result.dtype.names, results.dtype.names)
self.assertEqual(expected.dtype.names, results.dtype.names)
# Missing necessary data file
numpy.testing.assert_equal(results, results2)
self.assertRaises(TypeError,
Expand Down Expand Up @@ -113,7 +145,7 @@ def test_plot(self):
pl.savefig('examine.png')
def test_generator(self):
"""Make sure the CorrelationFunctionSysTest() generator returns the right objects"""
object_list = ['GalaxyShear', 'BrightStarShear', 'StarXGalaxyDensity', 'StarXGalaxyShear',
object_list = ['GalaxyShear', 'BrightStarShear', 'StarXGalaxyDensity', 'StarXGalaxyShear',
'StarXStarShear', 'GalaxyDensityCorrelation', 'StarDensityCorrelation']
for object_type in object_list:
object_1 = stile.CorrelationFunctionSysTest(object_type)
Expand Down
Binary file modified tests/test_data/image_and_table.fits
Binary file not shown.
Binary file modified tests/test_data/table.fits
Binary file not shown.
Binary file modified tests/test_data/two_tables.fits
Binary file not shown.
49 changes: 35 additions & 14 deletions tests/test_file_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import os
import helper
import unittest
from stile import file_io
from astropy.io import fits
try:
import stile
except:
Expand Down Expand Up @@ -49,16 +51,16 @@ def setUp(self):
(55, 'tenth', 'jj', 55.0)], dtype='l, S7, S2, d')

# contents of test_data/[table.fits, image_and_table.fits, two_tables.fits (hdu 2)]
self.fits_table = numpy.array([(1.5, 'hello', 2), (3, 'goodbye', 5)],
dtype=[('q', float), ('status', 'S7'), ('final', int)])
self.fits_table = numpy.array([(1.5, 'hello ', 2), (3, 'goodbye', 5)],
dtype=[('q', numpy.float64), ('status', 'S7'), ('final', numpy.int32)])
# contents of first extension of test_data/two_tables.fits
self.fits_table_2 = numpy.array([(1.5, 2), (3.7, 4), (1050.2, 5)],
dtype=[('red', float), ('blue', int)])
dtype=[('red', numpy.float64), ('blue', numpy.int32)])
# contents of test_data/[image_int.fits, image_and_table.fits]
self.fits_int_image = numpy.array([[1, 2], [3, 4]])
# contents of test_data/image_float.fits
self.fits_float_image = numpy.array([[1.0, 2.1], [3.4, 1.6]])

def test_ReadFITSImage(self):
"""Test the ability to read in a FITS image."""
if stile.file_io.has_fits:
Expand Down Expand Up @@ -119,13 +121,16 @@ def test_WriteASCIITable(self):
raise RuntimeError('Arrays are equal, but should not have the same format')
except AssertionError:
pass
numpy.testing.assert_equal(results.astype('f'), self.table1.astype('f'))
results = results.astype(self.table1.dtype)
numpy.testing.assert_equal(results, self.table1)

# check field reordering
field_list = ['f3', 'f4', 'f6', 'f0', 'f2', 'f1', 'f5']
stile.file_io.WriteASCIITable(filename, self.table1, fields=field_list)
results = stile.ReadASCIITable(filename)
numpy.testing.assert_equal(results.astype('f'), self.table1[field_list].astype('f'))
results.dtype.names = field_list
results = results.astype(self.table1[field_list].dtype)
numpy.testing.assert_equal(results, self.table1[field_list])
os.close(handle)
if not stile.file_io.has_fits:
# If there is a FITS handler, this table would be written as a FITS table, so we
Expand All @@ -145,23 +150,39 @@ def test_WriteFITSTable(self):
stile.WriteFITSTable(filename, self.fits_table)
try:
self.assertTrue(
stile.file_io.fits_handler.FITSDiff('test_data/table.fits', 'temp.fits'))
stile.file_io.fits_handler.FITSDiff('test_data/table.fits', filename).identical)
except AttributeError:
# FITSDiff seems to not exist for one of my pyfits installations
numpy.testing.assert_equal(stile.ReadFITSTable('test_data/table.fits'),
stile.ReadFITSTable(filename))
try:
numpy.testing.assert_equal(stile.ReadFITSTable('test_data/table.fits'),
stile.ReadFITSTable(filename))
except AssertionError:
old_write = stile.ReadFITSTable('test_data/table.fits')
new_write = stile.ReadFITSTable(filename)
for colname in new_write.dtype.names:
self.assertIn(colname, old_write.dtype.names)
if isinstance(old_write[colname][0], str):
self.assertTrue(all([a.strip()==b.strip() for a,b in zip(old_write[colname], new_write[colname])]))
else:
numpy.testing.assert_equal(old_write[colname], new_write[colname])

os.close(handle)

# Now see if WriteTable properly sends things through WriteFITSTable
handle, filename = tempfile.mkstemp()
stile.WriteTable(filename, self.fits_table_2)
numpy.testing.assert_equal(stile.ReadFITSTable('test_data/two_tables.fits'),
stile.ReadFITSTable(filename))
res = stile.ReadFITSTable(filename)
try:
numpy.testing.assert_array_equal(stile.ReadFITSTable('test_data/two_tables.fits'),
stile.ReadFITSTable(filename))
except AssertionError: # Sometimes this fails because of dtype reasons
old_write = stile.ReadFITSTable('test_data/two_tables.fits')
new_write = stile.ReadFITSTable(filename)
for colname in new_write.dtype.names:
self.assertIn(colname, old_write.dtype.names)
numpy.testing.assert_equal(old_write[colname], new_write[colname])

os.close(handle)
handle, filename = tempfile.mkstemp()
self.assertRaises(TypeError, stile.WriteFITSTable, filename, [])
os.close(handle)

if __name__ == '__main__':
if not stile.file_io.has_fits:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def test_statsystest_basic(self):
self.check_results(result)
result = test_obj(tuple(test_vec))
self.check_results(result)
result = test_obj(test_vec.reshape((0.5*self.n_points_test, 2)))
result = test_obj(test_vec.reshape((int(0.5*self.n_points_test), 2)))
self.check_results(result)

def test_statsystest_exceptions(self):
Expand Down
19 changes: 15 additions & 4 deletions tests/test_treecorr_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ def setUp(self):
'k_col': 9, 'w_col': 10, 'flip_g1': False, 'flip_g2': False,
'pairwise': False, 'min_sep': 0.1, 'max_sep': 10, 'nbins': 10,
'bin_size': 0.99, 'sep_units': 'degrees', 'bin_slop': 0.8,
'n2_file_name': 'o1.dat', 'n2_statistic': 'compensated',
'ng_file_name': 'o2.dat', 'ng_statistic': 'compensated',
'g2_file_name': 'o3.dat', 'nk_file_name': 'o4.dat', 'nk_statistic': 'simple',
'k2_file_name': 'o5.dat', 'kg_file_name': 'o6.dat', 'precision': 3,
'nk_file_name': 'o4.dat', 'nk_statistic': 'simple',
'kg_file_name': 'o6.dat', 'precision': 3,
'm2_file_name': 'o7.dat', 'm2_uform': 'Crittenden', 'nm_file_name': 'o8.dat',
'norm_file_name': 'o9.dat', 'verbose': 3, 'num_threads': 16,
'split_method': 'median'}
self.dict3_has2 = {'n2_file_name': 'o1.dat', 'n2_statistic': 'compensated',
'g2_file_name': 'o3.dat', 'k2_file_name': 'o5.dat'}
self.dict3_no2 = {'nn_file_name': 'o1.dat', 'nn_statistic': 'compensated',
'gg_file_name': 'o3.dat', 'kk_file_name': 'o5.dat'}
# The output of a run of TreeCorr.
self.treecorr_output = numpy.array(
[(5.389e-02, 5.443e-02, 2.206e-02, -4.259e-02, 2.578e-02, 1.820e+02, 1.820e+02),
Expand Down Expand Up @@ -61,7 +64,7 @@ def test_ReadTreeCorrResultsFile(self):
arr = stile.ReadTreeCorrResultsFile('test_data/TreeCorr_output.dat')
numpy.testing.assert_equal(arr, self.treecorr_output)
# Seems to depend on which version of NumPy which error is raised
self.assertRaises((TypeError, StopIteration), stile.ReadTreeCorrResultsFile,
self.assertRaises((TypeError, StopIteration, ValueError), stile.ReadTreeCorrResultsFile,
'test_data/empty_file.dat')

def test_PickTreeCorrKeys(self):
Expand All @@ -73,6 +76,14 @@ def test_PickTreeCorrKeys(self):
self.assertEqual(new_dict, self.dict2,
msg='All entries from the dict should have been copied to the '+
'new dict')
if stile.treecorr_utils.use_2form:
new_dict = stile.treecorr_utils.PickTreeCorrKeys(self.dict3_no2)
for key in new_dict:
self.assertIn(key[0]+'2'+key[2:], self.dict3_has2)
else:
new_dict = stile.treecorr_utils.PickTreeCorrKeys(self.dict3_has2)
for key in new_dict:
self.assertIn(key[0]+key[0]+key[2:], self.dict3_no2)


if __name__ == '__main__':
Expand Down