Skip to content

Commit

Permalink
Merge pull request #76 from HeloiseS/dev1.6
Browse files Browse the repository at this point in the history
Merging Dev1.6 for the upcoming hoki v1.6 release
  • Loading branch information
HeloiseS authored May 4, 2021
2 parents 94dac1f + 52eaa28 commit d2a14bd
Show file tree
Hide file tree
Showing 55 changed files with 5,320 additions and 270 deletions.
50 changes: 25 additions & 25 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# This is a basic workflow to help you get started with Actions

name: CI
name: Dependency Testing

# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
Expand All @@ -16,28 +15,29 @@ jobs:
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python3 -m pip install --upgrade pip
python3 -m pip install tox
- name: Run Tox
run: tox

# - name: Upload coverage to codecov
# uses: codecov/codecov-action@v1
# with:
# token: ${{ secrets.CODECOV_TOKEN }}
# file: ./coverage.xml
# fail_ci_if_error: False
# The matrix of python versions to run
strategy:
matrix:
python-version: ['3.6','3.7'] #If adjusted here, make sure to also adjust the bindings in tox.ini
name: Python ${{ matrix.python-version }}

# The steps to run for each python version
steps:
# Checks out the repository
- uses: actions/checkout@v2
name: Checkout package
# Setups the required python version
- name: Setup python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
architecture: x64
# Installs tox and tox-gh-actions to run tox testing
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install tox tox-gh-actions
# Run tests with tox (tests multiple subpackages)
- name: Run tests with tox
run: tox
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,5 @@ hoki/version.py

# Mac OSX
.DS_Store

corner_plot.png
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ This way it'll show you each test as they pass or FAIL. In the pip and github ve

.. code-block:: none
`astropy`, `numpy`, `pandas`, `matplotlib`, `pyyaml`, `wheel`, `emcee`, `corner`, `numba`
`numpy`, `pandas`, `matplotlib`, `pyyaml`, `wheel`, `emcee`, `corner`
**Note:** Python 2 is not supported

Expand Down
1 change: 0 additions & 1 deletion hoki/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,3 @@ class UnsupportedPythonError(Exception):
#__all__ += ['module_input', 'module_output']
# or you can keep everything from the subpackage with the following instead
# __all__ += example_mod.__all__

4 changes: 2 additions & 2 deletions hoki/_astropy_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

__all__ = ['__version__']

# this indicates whether or not we are in the package's setup.py
# this indicates whether or not we are in the package'dc setup.py
try:
_ASTROPY_SETUP_
except NameError:
Expand Down Expand Up @@ -45,7 +45,7 @@
except ConfigurationDefaultMissingError as e:
wmsg = (e.args[0] +
" Cannot install default profile. If you are "
"importing from source, this is expected.")
"importing from models_path, this is expected.")
warn(ConfigurationDefaultMissingWarning(wmsg))
del e
except Exception:
Expand Down
Empty file added hoki/age/__init__.py
Empty file.
Empty file added hoki/age/tests/__init__.py
Empty file.
182 changes: 182 additions & 0 deletions hoki/age/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import hoki.age.utils as au
from hoki.age.wizard import AgeWizard
import hoki.load as load
import pkg_resources
import numpy as np
import pandas as pd
import pytest
from hoki.utils.exceptions import HokiFatalError, HokiUserWarning, HokiFormatError

# Loading Data

data_path = pkg_resources.resource_filename('hoki', 'data')
hr_file = data_path + '/hrs-sin-imf_chab100.zem4.dat'
cmd_file = data_path + '/cmd_bv_z002_bin_imf135_300'
myhrd = load.model_output(hr_file, hr_type='TL')
mycmd = load.unpickle(cmd_file)

#### Creating Test Inputs

# Version 1 AgeWizard
fake_hrd_input = pd.DataFrame.from_dict({'name': ['star1', 'star2', 'star3'],
'logT': np.array([4.58, 4.48, 4.14]),
'logL': np.array([4.83, 5.07, 5.40])})

bad_hrd_input = pd.DataFrame.from_dict({'logT': np.array(['bla']),
'logL': np.array([4.83])})

no_name_input = pd.DataFrame.from_dict({'logT': np.array([4.58, 4.48, 4.14]),
'logL': np.array([4.83, 5.07, 5.40])})

bad_hrd_input2 = pd.DataFrame.from_dict({'logT': np.array([4.58, 'bla']),
'logL': np.array([4.83, 2.0])})

fake_cmd_input = pd.DataFrame.from_dict({'name': ['star1', 'star2', 'STAR3'],
'col': np.array([-0.3, 0.5, -0.25]),
'mag': np.array([-5, -10, -1])})

bad_cmd_input = pd.DataFrame.from_dict({'col': np.array(['bla']),
'mag': np.array([-5])})

# Version 2 AgeWizard
stars_none = pd.DataFrame.from_dict({'name': np.array(['118-1', '118-2', '118-3', '118-4']),
'logL': np.array([5.0, 5.1, 4.9, 5.9]),
'logT': np.array([4.48, 4.45, 4.46, 4.47]),
})

stars_SYM = pd.DataFrame.from_dict({'name': np.array(['118-1', '118-2', '118-3', '118-4']),
'logL': np.array([5.0, 5.1, 4.9, 5.9]),
'logL_err': np.array([0.1, 0.2, 0.1, 0.1]),
'logT': np.array([4.48, 4.45, 4.46, 4.47]),
'logT_err': np.array([0.1, 0.2, 0.1, 0.1]),
})

stars_SYM_T_err_missing = pd.DataFrame.from_dict({'name': np.array(['118-1', '118-2', '118-3', '118-4']),
'logL': np.array([5.0, 5.1, 4.9, 5.9]),
'logL_err': np.array([0.1, 0.2, 0.1, 0.1]),
'logT': np.array([4.48, 4.45, 4.46, 4.47]),
'logT_err': np.array([0.1, 0.2, 0.1, 0.1]),
})

#########
# MISC #
#########

class TestNormalise1D(object):
def test_it_runs(self):
au.normalise_1d(np.array([0, 1, 4, 5, 0, 1, 7, 8]))

def test_basic(self):
norm = au.normalise_1d(np.array([0, 0, 1, 0, 0, 0, 0]))
assert norm[2] == 1, 'Normalisation done wrong'
assert sum(norm) == 1, "Normalisaton done wrong"

class TestErrorFlag(object):
def test_no_err(self):
assert au._error_flag(stars_none) is None, "Error Flag should be None"

def test_ERR(self):
assert au._error_flag(stars_SYM) == 'ERR', "Error Flag should be ERR"


#######################
# FINDING COORDINATES #
#######################


class TestFindCoordinates(object):
def test_hrd_input(self):
T_coord, L_coord = au.find_coordinates(obs_df=fake_hrd_input, model=myhrd)
assert np.sum(
np.isclose([T_coord[0], T_coord[1], T_coord[2]], [45, 44, 40])) == 3, "Temperature coordinates wrong"
assert np.sum(
np.isclose([L_coord[0], L_coord[1], L_coord[2]], [77, 80, 83])) == 3, "Luminosity coordinates wrong"

def test_cmd_input(self):
col_coord, mag_range = au.find_coordinates(obs_df=fake_cmd_input, model=mycmd)
assert np.sum(
np.isclose([col_coord[0], col_coord[1], col_coord[2]], [27, 35, 27])) == 3, "color coordinates wrong"
assert np.sum(
np.isclose([mag_range[0], mag_range[1], mag_range[2]], [90, 40, 130])) == 3, "magnitude coordinates wrong"


class TestFindCMDCoordinates(object):
def test_fake_input(self):
col_coord, mag_range = au._find_cmd_coordinates(obs_df=fake_cmd_input, mycmd=mycmd)
assert np.sum(
np.isclose([col_coord[0], col_coord[1], col_coord[2]], [27, 35, 27])) == 3, "color coordinates wrong"
assert np.sum(
np.isclose([mag_range[0], mag_range[1], mag_range[2]], [90, 40, 130])) == 3, "magnitude coordinates wrong"

def test_bad_input(self):
with pytest.raises(HokiFormatError):
col_coord, mag_range = au._find_cmd_coordinates(obs_df=bad_hrd_input, mycmd=mycmd)

def test_bad_input_2(self):
col_coord, mag_range = au._find_cmd_coordinates(obs_df=bad_cmd_input, mycmd=mycmd)
assert np.isclose(mag_range[0], 90), "This L coordinate is wrong - test_bad_input."


class TestFindHRDCoordinates(object):
def test_fake_input(self):
T_coord, L_coord = au._find_hrd_coordinates(obs_df=fake_hrd_input, myhrd=myhrd)
assert np.sum(
np.isclose([T_coord[0], T_coord[1], T_coord[2]], [45, 44, 40])) == 3, "Temperature coordinates wrong"
assert np.sum(
np.isclose([L_coord[0], L_coord[1], L_coord[2]], [77, 80, 83])) == 3, "Luminosity coordinates wrong"

def test_bad_input(self):
with pytest.raises(HokiFormatError):
__, __ = au._find_hrd_coordinates(obs_df=bad_cmd_input, mycmd=mycmd)

def test_bad_input(self):
T_coord, L_coord = au._find_hrd_coordinates(obs_df=bad_hrd_input, myhrd=myhrd)
#assert np.isnan(T_coord[0]), "This should be a nan"
assert np.isclose(L_coord[0], 77), "This L coordinate is wrong - test_bad_input."


###############################
# CALCULATING INDIVIDUAL PDFS #
###############################


class TestCalculatePDFs(object):
def test_fake_input(self):
pdf_df = au.calculate_individual_pdfs(fake_hrd_input, myhrd)
assert 'star1' in pdf_df.columns, "Column name issue"
assert int(sum(pdf_df.star1)) == 1, "PDF not calculated correctly"

def test_input_without_name(self):
pdf_df = au.calculate_individual_pdfs(no_name_input, myhrd)

assert 's1' in pdf_df.columns, "Column names not created right"

def test_bad_input(self):
pdf_df = au.calculate_individual_pdfs(bad_hrd_input2, myhrd)
assert not np.isnan(sum(pdf_df.s0)), "something went wrong"

def test_symmetric_errors(self):
pdf_df = au.calculate_individual_pdfs(stars_SYM, myhrd)
assert not np.isnan(sum(pdf_df['118-4'])), "something went wrong with symmetric errors"

#####################################
# PUTTING PDFS TOGETHER IN SOME WAY #
#####################################


class TestCalculateSamplePDF(object):
def test_basic(self):
distributions = au.calculate_distributions(fake_hrd_input, myhrd)
combined = au.calculate_sample_pdf(distributions)
assert np.isclose(combined.pdf[9], 0.2715379752638662), "combined PDF not right"

def test_drop_bad(self):
distributions = au.calculate_distributions(fake_hrd_input, myhrd)
combined = au.calculate_sample_pdf(distributions, not_you=[3])
assert np.isclose(combined.pdf[9], 0.2715379752638662), "combined PDF not right"

def test_drop_good(self):
distributions = au.calculate_distributions(fake_hrd_input, myhrd)
combined = au.calculate_sample_pdf(distributions, not_you=['star1'])
assert np.isclose(combined.pdf[9], 0.774602971512809), "combined PDF not right"

95 changes: 95 additions & 0 deletions hoki/age/tests/test_wizard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import hoki.age.utils as au
from hoki.age.wizard import AgeWizard
import hoki.load as load
import pkg_resources
import numpy as np
import pandas as pd
import pytest
from hoki.utils.exceptions import HokiFatalError, HokiUserWarning, HokiFormatError


# Loading Data

data_path = pkg_resources.resource_filename('hoki', 'data')
hr_file = data_path + '/hrs-sin-imf_chab100.zem4.dat'
cmd_file = data_path + '/cmd_bv_z002_bin_imf135_300'
myhrd = load.model_output(hr_file, hr_type='TL')
mycmd = load.unpickle(cmd_file)
# Creating Test Inputs

fake_hrd_input = pd.DataFrame.from_dict({'name': ['star1', 'star2', 'star3'],
'logT': np.array([4.58, 4.48, 4.14]),
'logL': np.array([4.83, 5.07, 5.40])})

bad_hrd_input = pd.DataFrame.from_dict({'logT': np.array(['bla']),
'logL': np.array([4.83])})

no_name_input = pd.DataFrame.from_dict({'logT': np.array([4.58, 4.48, 4.14]),
'logL': np.array([4.83, 5.07, 5.40])})

bad_hrd_input2 = pd.DataFrame.from_dict({'logT': np.array([4.58, 'bla']),
'logL': np.array([4.83, 2.0])})

fake_cmd_input = pd.DataFrame.from_dict({'name': ['star1', 'star2', 'STAR3'],
'col': np.array([-0.3, 0.5, -0.25]),
'mag': np.array([-5, -10, -1])})

bad_cmd_input = pd.DataFrame.from_dict({'col': np.array(['bla']),
'mag': np.array([-5])})


stars_SYM = pd.DataFrame.from_dict({'name': np.array(['118-1', '118-2', '118-3', '118-4']),
'logL': np.array([5.0, 5.1, 4.9, 5.9]),
'logL_err': np.array([0.1, 0.2, 0.1, 0.1]),
'logT': np.array([4.48, 4.45, 4.46, 4.47]),
'logT_err': np.array([0.1, 0.2, 0.1, 0.1]),
})

class TestAgeWizardBasic(object):
def test_init_basic(self):
assert AgeWizard(obs_df=fake_hrd_input, model=hr_file), "Loading HRD file path failed"
assert AgeWizard(obs_df=fake_hrd_input, model=myhrd), "Loading with hoki.hrdiagrams.HRDiagram failed"
assert AgeWizard(obs_df=fake_cmd_input, model=mycmd), 'Loading with hoki.cmd.CMD'
assert AgeWizard(obs_df=fake_cmd_input, model=cmd_file), 'Loading CMD from frile failed'

def test_bad_init(self):
with pytest.raises(HokiFatalError):
__, __ = AgeWizard(obs_df=fake_cmd_input, model='sdfghj'), 'HokiFatalError should be raised'

with pytest.raises(HokiFormatError):
__, __ = AgeWizard(obs_df='edrftgyhu', model=cmd_file), 'HokiFormatError should be raised'

def test_combine_pdfs_not_you(self):
wiz = AgeWizard(fake_hrd_input, myhrd)
wiz.calculate_sample_pdf(not_you=['star1'])
cpdf = wiz.sample_pdf.pdf
assert np.sum(np.isclose([cpdf[0], cpdf[9]], [0.0, 0.7231526323765232])) == 2, "combined pdf is not right"

def test_most_likely_age(self):
wiz = AgeWizard(obs_df=fake_hrd_input, model=hr_file)
assert np.isclose(wiz.most_likely_age[0], 6.9), "Most likely age wrong"

def test_most_likely_ages(self):
wiz = AgeWizard(obs_df=fake_hrd_input, model=hr_file)
a = wiz.most_likely_ages
assert np.sum(np.isclose([a[0], a[1], a[2]], [6.9, 6.9, 6.9])) == 3, "Most likely ages not right"

def test_combine_pdfs(self):
wiz = AgeWizard(fake_hrd_input, myhrd)
wiz.calculate_sample_pdf()
assert np.isclose(wiz.sample_pdf.pdf[9],0.551756734145878), "Something is wrong with the combined_Age PDF"

def test_calculate_p_given_age_range(self):
wiz = AgeWizard(fake_hrd_input, myhrd)
probas = wiz.calculate_p_given_age_range([6.7, 6.9])
assert np.sum(np.isclose([probas[0], probas[1], probas[2]],
[0.515233714952414, 0.7920611550946726, 0.6542441096583737])) == 3, \
"probability given age range is messed up"


class TestAgeWizardErrors(object):
def test_agewizard_with_errors_runs(self):
wiz = AgeWizard(stars_SYM, myhrd, nsamples=200)
wiz.calculate_sample_pdf()


Loading

0 comments on commit d2a14bd

Please sign in to comment.