Skip to content

Issue 1165: Checking datasets for MObs and Conforming w/ New Limb Darkening Updates #1217

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Aug 11, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
2e6cb15
- Added testing suite for ld.py
tamimfatahi Aug 8, 2023
a854291
Minor bug squashed
tamimfatahi Aug 8, 2023
9df27e6
Adding additional MicroObservatory default values
tamimfatahi Aug 8, 2023
170fd22
Adding additional MicroObservatory default values and reverting inits…
tamimfatahi Aug 8, 2023
0a0edec
Closes #1165: Updated to-str method to report description accurately.…
jpl-jengelke Aug 8, 2023
6ecb637
Moving test_ld.py file to top level directory
tamimfatahi Aug 9, 2023
bad0f31
Changing grammar for GUI. Closes #1124
tamimfatahi Aug 9, 2023
1e95b72
Allowing CBB and CV filters to be standard with custom ranges from us…
tamimfatahi Aug 9, 2023
54c6dba
Updating test to conform with new changes.
tamimfatahi Aug 9, 2023
be54e8b
Modifying incorrect argument format in inputs.py file.
tamimfatahi Aug 9, 2023
a7d8e26
Issue #1165: Minor grammar change in user feedback...
jpl-jengelke Aug 9, 2023
67a17df
Updating filters.py by adding in aliases and removing unknown FWHM.
tamimfatahi Aug 10, 2023
03f2ea6
Merge remote-tracking branch 'origin/issue_1165' into issue_1165
tamimfatahi Aug 10, 2023
8d7dd70
Moving test_ld.py file to top level directory
tamimfatahi Aug 10, 2023
960e4a4
Modifying ld.py back to previous changes
tamimfatahi Aug 10, 2023
578fae1
Merge remote-tracking branch 'origin/issue_1165' into issue_1165
tamimfatahi Aug 10, 2023
96099d3
Updating ld.py to include both filter and names in description that …
tamimfatahi Aug 11, 2023
f7705d3
Updating exotic.py to work with new additions in ld.py.
tamimfatahi Aug 11, 2023
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: 3 additions & 2 deletions exotic/api/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
"PanSTARRS Y": {"name": "Y", "fwhm": ("946.4", "1054.4")},
"PanSTARRS w": {"name": "N/A", "fwhm": ("404.2", "845.8")},

"Clear (unfiltered) reduced to V sequence": {"name": "CV", "fwhm": (None, None)},
"Clear with blue-blocking": {"name": "CBB", "fwhm": (None, None)},

# MObs Clear Filter; Source(s): Martin Fowler
"MObs CV": {"name": "CV", "fwhm": ("350.0", "850.0")},

Expand Down Expand Up @@ -72,7 +75,5 @@
"LCO Pan-STARRS Y": "PanSTARRS Y",
"LCO Pan-STARRS w": "PanSTARRS w",

"Clear (unfiltered) reduced to V sequence": "MObs CV",

"Exop": "Astrodon ExoPlanet-BB",
}
152 changes: 25 additions & 127 deletions exotic/api/ld.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ class LimbDarkening:
fwhm_alias = fwhm_alias

# lookup table: fwhm_map references filters irrespective of spacing and punctuation
# 1 - join optimized str lookups in lookup table
fwhm_lookup = {''.join(k.strip().lower().split()): k for k in fwhm.keys()}
fwhm_lookup.update({''.join(k.strip().lower().split()): v for k, v in fwhm_alias.items()})
# 1 - combine optimized str lookups in lookup table
fwhm_lookup = {k.strip().replace(' ', '').lower(): k for k in fwhm.keys()}
fwhm_lookup.update({k.strip().replace(' ', '').lower(): v for k, v in fwhm_alias.items()})
# 2 - ignore punctuation in lookup table
fwhm_lookup = {re.sub(ld_re_punct_p, '', k): v for k, v in fwhm_lookup.items()}

def __init__(self, stellar):
self.filter_name = self.filter_desc = None
self.ld0 = self.ld1 = self.ld2 = self.ld3 = None
self.ld0 = self.ld1 = self.ld2 = self.ld3 = [0, 0]
self.priors = {
'T*': stellar.get('teff'),
'T*_uperr': stellar.get('teffUncPos'),
Expand Down Expand Up @@ -96,15 +96,13 @@ def check_standard(self, filter_: dict = None, loose: bool = False, loose_len: i
# eliminate errant spaces on edges
filter_[k] = filter_[k].strip()
if k == 'name' and filter_[k]: # format 'name' (if exists) to uppercase, no spaces
filter_[k] = ''.join(filter_[k].upper().split())
filter_[k] = filter_[k].upper().replace(' ', '')
if filter_['filter']: # make matcher by removing spaces, remove punctuation and lowercase
filter_matcher = ''.join(filter_['filter'].lower().split())
filter_matcher = filter_['filter'].lower().replace(' ', '')
filter_matcher = re.sub(ld_re_punct_p, '', filter_matcher)
# identify defined filters via optimized lookup table
if filter_matcher and filter_matcher in LimbDarkening.fwhm_lookup:
filter_['filter'] = LimbDarkening.fwhm_lookup[filter_matcher] # sets to actual filter reference key
# add always disabled alias values
filter_nonspecific_names = LimbDarkening.filter_nonspecific_ids + LimbDarkening.filter_generic_ids
for f in LimbDarkening.fwhm.values():
# match to wavelength values (strict)
if (filter_['wl_min'] and filter_['wl_min'] == f['fwhm'][0] and
Expand All @@ -118,9 +116,15 @@ def check_standard(self, filter_: dict = None, loose: bool = False, loose_len: i
# match 'name' or 'filter' (strict) to actual name abbreviation, e.g. 'name'
elif filter_['name'] == f['name'].strip().upper() or \
(filter_['filter'] and filter_['filter'][:5].upper() == f['name'].strip().upper()):
if filter_['name'] in LimbDarkening.filter_nonspecific_ids or \
(filter_['filter'] and filter_['filter'][:5].upper() in LimbDarkening.filter_nonspecific_ids):
if filter_['wl_min'] and filter_['wl_max'] and LimbDarkening.check_fwhm(filter_):
filter_alias = f
filter_alias['fwhm'] = (filter_['wl_min'], filter_['wl_max'])
break
# exclude unknown vals for 'name'
if filter_['name'] in filter_nonspecific_names or \
(filter_['filter'] and filter_['filter'][:5].upper() in filter_nonspecific_names):
elif filter_['name'] in LimbDarkening.filter_generic_ids or \
(filter_['filter'] and filter_['filter'][:5].upper() in LimbDarkening.filter_generic_ids):
pass
else:
filter_alias = f
Expand Down Expand Up @@ -169,7 +173,7 @@ def check_fwhm(filter_: dict = None) -> bool:
return False
for k in ('wl_min', 'wl_max'): # clean inputs
filter_[k] = filter_.get(k)
filter_[k] = ''.join(str(filter_[k]).strip().split()).rstrip('.') if filter_[k] else filter_[k]
filter_[k] = str(filter_[k]).strip().replace(' ', '').rstrip('.') if filter_[k] else filter_[k]
if not 200. <= float(filter_[k]) <= 4000.: # also fails if nan
raise ValueError(f"FWHM '{k}' is outside of bounds (200., 4000.). ...")
else: # add .0 to end of str to aid literal matching
Expand Down Expand Up @@ -207,119 +211,13 @@ def set_ld(self, ld0, ld1, ld2, ld3):
self.ld3 = ld3
return

def output_ld(self):
print("\nEXOTIC-calculated nonlinear limb-darkening coefficients: ")
print(f"{self.ld0[0]:5f} +/- + {self.ld0[1]:5f}")
print(f"{self.ld1[0]:5f} +/- + {self.ld1[1]:5f}")
print(f"{self.ld2[0]:5f} +/- + {self.ld2[1]:5f}")
print(f"{self.ld3[0]:5f} +/- + {self.ld3[1]:5f}")
return


def test_ld(ld_obj_, filter_):
try:
ld_obj_.check_standard(filter_)
ld_obj_.calculate_ld()
except BaseException as be:
log.exception(be)
log.error("Continuing with default operations. ...")
filter_['filter'] = "Custom"
if filter_['wl_min'] and filter_['wl_max']:
ld_obj_.set_filter('N/A', filter_['filter'], float(filter_['wl_min']), float(filter_['wl_max']))
ld_obj_.calculate_ld()
else:
ld_ = [(filter_[key]["value"], filter_[key]["uncertainty"]) for key in filter_.keys()
if key in ['u0', 'u1', 'u2', 'u3']]
ld_obj_.set_filter('N/A', filter_['filter'], filter_['wl_min'], filter_['wl_max'])
ld_obj_.set_ld(ld_[0], ld_[1], ld_[2], ld_[3])
return


if __name__ == "__main__": # tests
stellar_params = {
'teff': 6001.0,
'teffUncPos': 88.0,
'teffUncNeg': -88.0,
'met': -0.16,
'metUncPos': 0.08,
'metUncNeg': -0.08,
'logg': 4.22,
'loggUncPos': 0.04,
'loggUncNeg': -0.04
}

# Test existing filter
filter_info1 = {
'filter': "CV",
'wl_min': None,
'wl_max': None,
'u0': {"value": None, "uncertainty": None},
'u1': {"value": None, "uncertainty": None},
'u2': {"value": None, "uncertainty": None},
'u3': {"value": None, "uncertainty": None}
}

# Test alias filter
filter_info2 = {
'filter': "LCO SDSS u'",
'wl_min': None,
'wl_max': None,
'u0': {"value": None, "uncertainty": None},
'u1': {"value": None, "uncertainty": None},
'u2': {"value": None, "uncertainty": None},
'u3': {"value": None, "uncertainty": None}
}

# Test given only FWHM
filter_info3 = {
'filter': None,
'wl_min': "350",
'wl_max': "850.0",
'u0': {"value": None, "uncertainty": None},
'u1': {"value": None, "uncertainty": None},
'u2': {"value": None, "uncertainty": None},
'u3': {"value": None, "uncertainty": None}
}

# Test custom-entered ld coefficients
filter_info4 = {
'filter': None,
'wl_min': None,
'wl_max': None,
'u0': {"value": 2.118, "uncertainty": 0.051},
'u1': {"value": -3.88, "uncertainty": 0.21},
'u2': {"value": 4.39, "uncertainty": 0.27},
'u3': {"value": -1.63, "uncertainty": 0.12}
}

filter_info5 = {
'filter': 'N/A',
'wl_min': 351.2,
'wl_max': 3999.,
'u0': {"value": 2.118, "uncertainty": 0.051},
'u1': {"value": -3.88, "uncertainty": 0.21},
'u2': {"value": 4.39, "uncertainty": 0.27},
'u3': {"value": -1.63, "uncertainty": 0.12}
}

ld_obj = LimbDarkening(stellar_params)
LimbDarkening.standard_list()

print(ld_obj.check_fwhm(filter_info5))
print(ld_obj.check_standard(filter_info5, True, 4))
print(ld_obj.check_standard(filter_info5))
print(str(filter_info5))
test_ld(ld_obj, filter_info5)
print(str(filter_info5))
print(f"{ld_obj.filter_desc}, {ld_obj.filter_name}, {ld_obj.wl_min}, {ld_obj.wl_max}")

LimbDarkening.check_fwhm(filter_info5)
LimbDarkening.check_fwhm(filter_info3)
test_ld(ld_obj, filter_info1)
# test_ld(ld_obj, filter_info2)
# test_ld(ld_obj, filter_info3)
# test_ld(ld_obj, filter_info4)

ld = [ld_obj.ld0[0], ld_obj.ld1[0], ld_obj.ld2[0], ld_obj.ld3[0]]
ld_unc = [ld_obj.ld0[1], ld_obj.ld1[1], ld_obj.ld2[1], ld_obj.ld3[1]]
ld_obj.output_ld()
def __str__(self):
return (f"\nFilter Name: {self.filter_name}"
f"\nFilter Description: {self.filter_desc}"
f"\nMinimum Wavelength (nm): {self.wl_min}"
f"\nMaxiumum Wavelength (nm):: {self.wl_max}"
"\nEXOTIC-calculated nonlinear limb-darkening coefficients: "
f"\n\t- {self.ld0[0]:5f} +/- + {self.ld0[1]:5f}"
f"\n\t- {self.ld1[0]:5f} +/- + {self.ld1[1]:5f}"
f"\n\t- {self.ld2[0]:5f} +/- + {self.ld2[1]:5f}"
f"\n\t- {self.ld3[0]:5f} +/- + {self.ld3[1]:5f}")
103 changes: 53 additions & 50 deletions exotic/exotic.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def julian_date(hdr, time_unit, exp):
return julian_time + offset

def get_exp_time(hdr):
exp_list = [ "EXPTIME", "EXPOSURE", "EXP" ]
exp_list = ["EXPTIME", "EXPOSURE", "EXP"]
exp_time = next((exptime for exptime in exp_list if exptime in hdr), None)
return hdr[exp_time] if exp_time is not None else 0.0

Expand Down Expand Up @@ -525,8 +525,7 @@ def radec_hours_to_degree(ra, dec):


def standard_filter(ld, filter_):
if not filter_['filter']:
LimbDarkening.standard_list()
LimbDarkening.standard_list()

while True:
if not filter_['filter']:
Expand All @@ -539,30 +538,16 @@ def standard_filter(ld, filter_):
filter_['filter'] = None


def check_fwhm(wl, type_):
if not isinstance(wl, float):
try:
wl = float(wl)
except (ValueError, TypeError):
wl = user_input(f"FWHM {type_} wavelength (nm):", type_=float)

return wl


def custom_range(ld, filter_):
filter_['filter'] = "Custom"

def custom_range(ld, observed_filter):
while True:
filter_['wl_min'] = check_fwhm(filter_['wl_min'], 'Minimum')
filter_['wl_max'] = check_fwhm(filter_['wl_max'], 'Maximum')

if filter_['wl_max'] < filter_['wl_min']:
log_info("\nError: The entered FWHM upper value is less than the lower value. Please try again.", warn=True)
filter_['wl_min'] = filter_['wl_max'] = None
else:
if ld.check_fwhm(observed_filter):
break
else:
observed_filter['wl_min'] = user_input(f"FWHM minimum wavelength (nm):", type_=str)
observed_filter['wl_max'] = user_input(f"FWHM maximum wavelength (nm):", type_=str)

ld.set_filter('N/A', filter_['filter'], filter_['wl_min'], filter_['wl_max'])
if not ld.check_standard(observed_filter):
ld.set_filter('N/A', "Custom", float(observed_filter['wl_min']), float(observed_filter['wl_max']))


def user_entered_ld(ld, filter_):
Expand All @@ -576,14 +561,20 @@ def user_entered_ld(ld, filter_):
ld.set_ld(ld_[0], ld_[1], ld_[2], ld_[3])


def nonlinear_ld(ld, filter_):
u_e = False
def nonlinear_ld(ld, info_dict):
user_entered = False
observed_filter = {
'filter': info_dict['filter'],
'name': None,
'wl_min': info_dict['wl_min'],
'wl_max': info_dict['wl_max']
}
ld.check_fwhm(observed_filter)

if (filter_['filter'] and filter_['filter'].upper() != 'N/A' and ld.check_standard(filter_)) and \
not (filter_['wl_min'] or filter_['wl_max']):
if ld.check_standard(observed_filter):
pass
elif filter_['wl_min'] or filter_['wl_max']:
custom_range(ld, filter_)
elif observed_filter['wl_min'] or observed_filter['wl_max']:
custom_range(ld, observed_filter)
else:
opt = user_input("\nWould you like EXOTIC to calculate your limb darkening parameters "
"with uncertainties? (y/n):", type_=str, values=['y', 'n'])
Expand All @@ -592,17 +583,35 @@ def nonlinear_ld(ld, filter_):
opt = user_input("Please enter 1 to use a standard filter or 2 for a customized filter:",
type_=int, values=[1, 2])
if opt == 1:
filter_['filter'] = None
standard_filter(ld, filter_)
observed_filter['filter'] = None
standard_filter(ld, observed_filter)
elif opt == 2:
custom_range(ld, filter_)
custom_range(ld, observed_filter)
else:
user_entered_ld(ld, filter_)
u_e = True
user_entered_ld(ld, observed_filter)
user_entered = True

if not u_e:
if not user_entered:
ld.calculate_ld()

info_dict['filter'] = ld.filter_name
info_dict['filter_desc'] = ld.filter_desc
info_dict['wl_min'] = ld.wl_min
info_dict['wl_max'] = ld.wl_max


def get_ld_values(planet_dict, info_dict):
ld_obj = LimbDarkening(planet_dict)
nonlinear_ld(ld_obj, info_dict)

ld0 = ld_obj.ld0
ld1 = ld_obj.ld1
ld2 = ld_obj.ld2
ld3 = ld_obj.ld3
ld = [ld0[0], ld1[0], ld2[0], ld3[0]]

return ld, ld0, ld1, ld2, ld3


def corruption_check(files):
valid_files = []
Expand Down Expand Up @@ -1853,20 +1862,6 @@ def main():
else:
pDict = get_planetary_parameters(CandidatePlanetBool, userpDict, pdict=pDict)

ld_obj = LimbDarkening(pDict)
nonlinear_ld(ld_obj, exotic_infoDict)

exotic_infoDict['filter'] = ld_obj.filter_name
exotic_infoDict['filter_desc'] = ld_obj.filter_desc
exotic_infoDict['wl_min'] = ld_obj.wl_min
exotic_infoDict['wl_max'] = ld_obj.wl_max

ld0 = ld_obj.ld0
ld1 = ld_obj.ld1
ld2 = ld_obj.ld2
ld3 = ld_obj.ld3
ld = [ld0[0], ld1[0], ld2[0], ld3[0]]

# check for Nans + Zeros
for k in pDict:
if k == 'rprs' and (pDict[k] == 0 or np.isnan(pDict[k])):
Expand Down Expand Up @@ -1925,6 +1920,13 @@ def main():
exotic_infoDict['second_obs'] += ",MOBS"
else:
exotic_infoDict['second_obs'] = "MOBS"
# exotic_infoDict['filter'] = "MObs CV"
exotic_infoDict['elev'] = 1268
exotic_infoDict['lat'] = 31.675467
exotic_infoDict['long'] = -110.951376
exotic_infoDict['pixel_bin'] = "2x2"

ld, ld0, ld1, ld2, ld3 = get_ld_values(pDict, exotic_infoDict)

# check for EPW_MD5 checksum
if 'EPW_MD5' in header:
Expand Down Expand Up @@ -2433,6 +2435,7 @@ def main():
else:
goodTimes, goodFluxes, goodNormUnc, goodAirmasses = [], [], [], []
bestCompStar, comp_coords = None, None
ld, ld0, ld1, ld2, ld3 = get_ld_values(pDict, exotic_infoDict)

with exotic_infoDict['prered_file'].open('r') as f:
for processed_data in f:
Expand Down
4 changes: 2 additions & 2 deletions exotic/exotic_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ def save_input():
root.title(f"EXOTIC v{__version__}")

window_label = tk.Label(root,
text="To make analyzing these data in the future more easy, EXOTIC will create an initialization file for you.",
text="To make analyzing data easier in the future, EXOTIC will create an initialization file for you.",
font="Helvetica 14 bold",
justify=tk.LEFT,
padx=20) # .pack()
Expand Down Expand Up @@ -1337,7 +1337,7 @@ def save_inputs():
initparams = tk.IntVar()

window_label = tk.Label(root,
text="To make analyzing these data in the future more easy, EXOTIC will create an initialization file for you.",
text="To make analyzing data easier in the future, EXOTIC will create an initialization file for you.",
font="Helvetica 14 bold",
justify=tk.LEFT,
padx=20) # .pack()
Expand Down
Loading