forked from DarkEnergySurvey/ugali
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' of github.com:kadrlica/ugali
- Loading branch information
Showing
24 changed files
with
3,255 additions
and
430 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,94 @@ | ||
#!/usr/bin/env python | ||
""" | ||
Test isochrone functionality | ||
Test isochrone functionality. These tests require that ugali has been | ||
installed with the '--isochrones' option. | ||
""" | ||
import os | ||
import numpy as np | ||
|
||
import ugali.analysis.isochrone as isochrone | ||
from ugali import isochrone | ||
|
||
default_kwargs = dict(age = 12,metallicity = 0.0002, distance_modulus = 18) | ||
test_kwargs = dict(age = 13, metallicity = 0.0008, distance_modulus = 16) | ||
# Default parameters | ||
default_kwargs = dict(age=12,metallicity=0.0002, distance_modulus=18) | ||
# Alternate parameters | ||
alt_kwargs = dict(age=10, metallicity=0.0001, distance_modulus=16) | ||
# Parameter abbreviations | ||
abbr_kwargs = dict(a=10, z=0.0001, mod=17) | ||
|
||
padova = ['Padova','Bressan2012','Marigo2017'] | ||
dotter = ['Dotter','Dotter2008','Dotter2016'] | ||
isochrones = padova + dotter | ||
survey = ['des','sdss'] | ||
|
||
def set_parameters(name): | ||
iso = isochrone.factory(name,**default_kwargs) | ||
|
||
# Test that parameters are set in construction | ||
for k,v in default_kwargs.items(): | ||
assert getattr(iso,k) == v | ||
|
||
for k,v in test_kwargs.items(): | ||
# Test that parameters are set through setattr | ||
for k,v in alt_kwargs.items(): | ||
setattr(iso,k,v) | ||
assert getattr(iso,k) == v | ||
|
||
# Test that parameters are set through setp | ||
for k,v in default_kwargs.items(): | ||
iso.setp(k,v) | ||
assert getattr(iso,k) == v | ||
|
||
iso.sample() | ||
|
||
def test_padova(): set_parameters('Padova') | ||
def test_dotter(): set_parameters('Dotter') | ||
def test_exists(): | ||
""" Check that the isochrone directory exists. """ | ||
isodir = isochrone.get_iso_dir() | ||
assert os.path.exists(isodir) | ||
assert len(os.listdir(isodir)) | ||
|
||
|
||
def test_abbr(name='Padova'): | ||
""" Test that parameters can be set by abbreviation. """ | ||
iso = isochrone.factory(name,**abbr_kwargs) | ||
|
||
for k,v in abbr_kwargs.items(): | ||
setattr(iso,k,v) | ||
|
||
for k,v in abbr_kwargs.items(): | ||
iso.setp(k,v) | ||
|
||
|
||
def test_padova(): | ||
for name in padova: | ||
set_parameters(name) | ||
|
||
def test_dotter(): | ||
for name in dotter: | ||
set_parameters(name) | ||
|
||
|
||
def test_composite(): | ||
isochrones = [ | ||
dict(name='Padova',**default_kwargs), | ||
dict(name='Dotter',**default_kwargs) | ||
] | ||
iso = isochrone.factory("Composite",isochrones=isochrones) | ||
|
||
iso.distance_modulus = test_kwargs['distance_modulus'] | ||
assert iso.distance_modulus == test_kwargs['distance_modulus'] | ||
iso.distance_modulus = alt_kwargs['distance_modulus'] | ||
assert iso.distance_modulus == alt_kwargs['distance_modulus'] | ||
|
||
assert np.all(iso.age == np.ones(len(isochrones))*default_kwargs['age']) | ||
assert np.all(iso.metallicity == np.ones(len(isochrones))*default_kwargs['metallicity']) | ||
|
||
iso.sample() | ||
|
||
def test_surveys(): | ||
""" Create isochrones with different surveys """ | ||
for s in survey: | ||
for name in ['Dotter2016']: | ||
iso = isochrone.factory(name,survey=s) | ||
|
||
if __name__ == "__main__": | ||
import argparse | ||
parser = argparse.ArgumentParser(description=__doc__) | ||
args = parser.parse_args() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ | |
objects : | ||
mask : | ||
""" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#!/usr/bin/env python | ||
""" | ||
Module for dealing with Isochrones. | ||
""" | ||
from ugali.isochrone.model import get_iso_dir | ||
from ugali.isochrone.composite import factory | ||
from ugali.isochrone.composite import CompositeIsochrone, Padova, Dotter | ||
from ugali.isochrone.parsec import Bressan2012, Marigo2017 | ||
from ugali.isochrone.dartmouth import Dotter2008 | ||
from ugali.isochrone.mesa import Dotter2016 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
#!/usr/bin/env python | ||
""" | ||
Generic python script. | ||
""" | ||
__author__ = "Alex Drlica-Wagner" | ||
|
||
import sys | ||
import os | ||
from collections import OrderedDict as odict | ||
from functools import wraps | ||
|
||
import numpy as np | ||
|
||
from ugali.analysis.model import Model, Parameter | ||
from ugali.utils.logger import logger | ||
from ugali.isochrone.model import IsochroneModel, Isochrone | ||
from ugali.isochrone.mesa import Dotter2016 | ||
from ugali.isochrone.parsec import Marigo2017 | ||
|
||
class CompositeIsochrone(IsochroneModel): | ||
_params = odict([ | ||
('distance_modulus', Parameter(15.0, [10.0, 30.0]) ), | ||
]) | ||
_mapping = odict([ | ||
('mod','distance_modulus'), | ||
('a','age'), | ||
('z','metallicity'), | ||
]) | ||
|
||
defaults = (IsochroneModel.defaults) + ( | ||
('type','PadovaIsochrone','Default type of isochrone to create'), | ||
('weights',None,'Relative weights for each isochrone'), | ||
) | ||
|
||
def __init__(self, isochrones, **kwargs): | ||
super(CompositeIsochrone,self).__init__(**kwargs) | ||
|
||
self.isochrones = [] | ||
for i in isochrones: | ||
if isinstance(i,Isochrone): | ||
iso = i | ||
else: | ||
name = i.pop('name',self.type) | ||
#iso = isochroneFactory(name=name,**i) | ||
iso = factory(name=name,**i) | ||
# Tie the distance modulus | ||
iso.params['distance_modulus'] = self.params['distance_modulus'] | ||
self.isochrones.append(iso) | ||
|
||
if self.weights is None: self.weights = np.ones(len(self.isochrones)) | ||
self.weights /= np.sum(np.asarray(self.weights)) | ||
self.weights = self.weights.tolist() | ||
|
||
if len(self.isochrones) != len(self.weights): | ||
msg = 'Length of isochrone and weight arrays must be equal' | ||
raise ValueError(msg) | ||
|
||
def __getitem__(self, key): | ||
return self.isochrones[key] | ||
|
||
def __str__(self,indent=0): | ||
ret = super(CompositeIsochrone,self).__str__(indent) | ||
ret += '\n{0:>{2}}{1}'.format('','Isochrones:',indent+2) | ||
for i in self: | ||
ret += '\n{0}'.format(i.__str__(indent+4)) | ||
return ret | ||
|
||
@property | ||
def age(self): | ||
return np.array([i.age for i in self]) | ||
|
||
@property | ||
def metallicity(self): | ||
return np.array([i.metallicity for i in self]) | ||
|
||
def composite_decorator(func): | ||
""" | ||
Decorator for wrapping functions that calculate a weighted sum | ||
""" | ||
@wraps(func) | ||
def wrapper(self, *args, **kwargs): | ||
total = [] | ||
for weight,iso in zip(self.weights,self.isochrones): | ||
subfunc = getattr(iso,func.__name__) | ||
total.append(weight*subfunc(*args,**kwargs)) | ||
return np.sum(total,axis=0) | ||
return wrapper | ||
|
||
def sample(self, **kwargs): | ||
samples = [iso.sample(**kwargs) for iso in self.isochrones] | ||
for weight,sample in zip(self.weights,samples): | ||
sample[1] *= weight | ||
|
||
return np.hstack(samples) | ||
|
||
def separation(self, *args, **kwargs): | ||
separations = [iso.separation(*args,**kwargs) for iso in self.isochrones] | ||
return np.nanmin(separations,axis=0) | ||
|
||
def todict(self): | ||
ret = super(CompositeIsochrone,self).todict() | ||
ret['isochrones'] = [iso.todict() for iso in self.isochrones] | ||
return ret | ||
|
||
@composite_decorator | ||
def stellar_mass(self, *args, **kwargs): pass | ||
|
||
@composite_decorator | ||
def stellar_luminosity(self, *args, **kwargs): pass | ||
|
||
@composite_decorator | ||
def observable_fraction(self, *args, **kwargs): pass | ||
|
||
@composite_decorator | ||
def observableFractionX(self, *args, **kwargs): pass | ||
|
||
@composite_decorator | ||
def signalMMD(self, *args, **kwargs): pass | ||
|
||
# ADW: For temporary backwards compatibility | ||
stellarMass = stellar_mass | ||
stellarLuminosity = stellar_luminosity | ||
observableFraction = observable_fraction | ||
|
||
# ADW: It would be better if the factory were in isochrone.__init__ | ||
# but then you get into a circular import situation with the | ||
# CompositeIsochrone. This is an unfortunate design decision... | ||
|
||
# ADW: It'd be better for us to move away from generic aliases... | ||
class Dotter(Dotter2016): pass | ||
class Padova(Marigo2017): pass | ||
class Composite(CompositeIsochrone): pass | ||
|
||
def factory(name, **kwargs): | ||
from ugali.utils.factory import factory | ||
|
||
module = 'ugali.isochrone' | ||
# First try this module | ||
try: return factory(name, module=__name__, **kwargs) | ||
except KeyError: pass | ||
try: return factory(name, module=module+'.composite', **kwargs) | ||
except KeyError: pass | ||
# Then try parsec | ||
try: return factory(name, module=module+'.parsec', **kwargs) | ||
except KeyError: pass | ||
# Then try mesa | ||
try: return factory(name, module=module+'.mesa', **kwargs) | ||
except KeyError: pass | ||
# Then try desd | ||
try: return factory(name, module=module+'.dartmouth', **kwargs) | ||
except KeyError: pass | ||
|
||
raise KeyError('Unrecognized class: %s'%name) |
Oops, something went wrong.