Skip to content

Commit

Permalink
ex16 - allowing posterior parsing (useful for FFPs)
Browse files Browse the repository at this point in the history
  • Loading branch information
rpoleski committed Jul 29, 2024
1 parent e1f1c7c commit ef009af
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 17 deletions.
6 changes: 4 additions & 2 deletions examples/example_16/ob03235_2_full.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,16 @@ fit_constraints:
#Alternative for binary source models:
#color source 1 : gauss 0.3 0.01 "OGLE I-band" "OB03235_MOA.txt"
#and/or
#color source 2 : gauss 0.3 0.01 "OGLE I-band" "OB03235_MOA.txt"

#color source 2 : gauss 0.3 0.01 "OGLE I-band" "OB03235_MOA.txt"
prior:
t_E: Mroz et al. 2017
# Other possibility:
# t_E: Mroz et al. 2020
pi_E_N: gauss 0.00 0.15
pi_E_E: gauss 0.00 0.15
posterior parsing:
abs: [u_0]
# After running EMCEE, calculate absolute values of parameters from that list.
min_values:
t_0: 2452840.
u_0: 0.
Expand Down
85 changes: 70 additions & 15 deletions examples/example_16/ulens_model_fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
except Exception:
raise ImportError('\nYou have to install MulensModel first!\n')

__version__ = '0.37.3'
__version__ = '0.38.0'


class UlensModelFit(object):
Expand Down Expand Up @@ -268,6 +268,13 @@ class UlensModelFit(object):
Mroz et al. 2020 -
https://ui.adsabs.harvard.edu/abs/2020ApJS..249...16M/abstract
``'posterior parsing'`` - additional settings that allow
modyfing posterior after it's calculated. Possile values:
``'abs': [...]`` - calculate absolute values for parameters
from given list. It's useful for e.g. ``'u_0'`` for
free-floating planet events.
plots: *dict*
Parameters of the plots to be made after the fit. Currently
allowed keys are ``triangle``, ``trace`` (only EMCEE fitting),
Expand Down Expand Up @@ -1118,6 +1125,15 @@ def _get_parameters_latex(self):
for key in ['t_0', 't_0_1', 't_0_2']:
conversion[key] = '\\Delta ' + conversion[key]

if self._fit_constraints is not None:
if 'posterior parsing' in self._fit_constraints:
if 'abs' in self._fit_constraints['posterior parsing']:
settings = self._fit_constraints['posterior parsing']['abs']
if not isinstance(settings, list):
raise ValueError("Error: fit_constraints -> posterior parsing -> abs - list expected")
for key in self._fit_constraints['posterior parsing']['abs']:
conversion[key] = "|" + conversion[key] + "|"

self._fit_parameters_latex = [
('$' + conversion[key] + '$') for key in self._fit_parameters]

Expand Down Expand Up @@ -1457,33 +1473,40 @@ def _parse_fit_constraints(self):
self._set_default_fit_constraints()
return

self._check_fit_constraints()
self._parse_fit_constraints_keys()
self._parse_fit_constraints_fluxes()
self._parse_fit_constraints_posterior()

if 'prior' in self._fit_constraints:
self._parse_fit_constraints_prior()

def _check_fit_constraints(self):
"""
Run checks on self._fit_constraints
"""
if self._fit_constraints is not None and self._fit_method == 'MultiNest':
raise NotImplementedError(
"Currently no fit_constraints are implemented for MultiNest "
"fit. Please contact Radek Poleski with a specific request.")

if isinstance(self._fit_constraints, list):
raise TypeError(
"In version 0.5.0 we've changed type of 'fit_constraints' " +
"from list to dict. Please correct you input and re-run " +
"the code. Most probably what you need is:\n" +
"fit_constraints = {'no_negative_blending_flux': True}")

self._parse_fit_constraints_keys()
self._parse_fit_constraints_fluxes()

if 'prior' in self._fit_constraints:
self._parse_fit_constraints_prior()

def _parse_fit_constraints_keys(self):
"""
Validate the keys in the provided fit_constraints.
"""
allowed_keys_flux = {
"no_negative_blending_flux", "negative_blending_flux_sigma_mag"}
allowed_keys_color = {'color', 'color source 1', 'color source 2'}
allowed_keys = {*allowed_keys_flux, *allowed_keys_color,
"prior", "posterior parsing"}

allowed_keys_color = {'color',
'color source 1',
'color source 2', }

allowed_keys = {*allowed_keys_flux,
*allowed_keys_color,
"prior"}
used_keys = set(self._fit_constraints.keys())
if len(used_keys - allowed_keys) > 0:
raise ValueError('unrecognized constraint: {:}'.format(
Expand All @@ -1500,9 +1523,9 @@ def _parse_fit_constraints_keys(self):
def _set_default_fit_constraints(self):
"""
Set default fitting constraints if none are provided.
"""
self._fit_constraints = {"no_negative_blending_flux": False}
self._parse_posterior_abs = list()

def _check_color_constraints_conflict(self, allowed_keys_color):
"""
Expand Down Expand Up @@ -1633,6 +1656,32 @@ def _parse_fit_constraints_prior(self):
if len(priors) > 0:
self._priors = priors

def _parse_fit_constraints_posterior(self):
"""
Parse constraints on what is done with posterior.
"""
if 'posterior parsing' not in self._fit_constraints:
return

if self._fit_method != "EMCEE":
raise ValueError('Input in "posterior parsing" is allowed only for EMCEE')

allowed_keys = {"abs"}
settings = self._fit_constraints['posterior parsing']
unknown = set(settings.keys()) - allowed_keys
if len(unknown) > 0:
raise KeyError(
"Unrecognized key in fit_constraints -> 'posterior parsing': " +
str(unknown))

if 'abs' in settings:
self._parse_posterior_abs = settings['abs']
for parameter in self._parse_posterior_abs:
if parameter not in self._fit_parameters:
raise ValueError(
"Error - you can calculate absolute value only of "
"a parameter which is fitted, not: " + parameter)

def _get_no_of_dataset(self, label):
"""
Returns the index of a dataset with a specific label.
Expand Down Expand Up @@ -2625,6 +2674,10 @@ def _extract_posterior_samples_EMCEE(self):
"""
n_burn = self._fitting_parameters['n_burn']
self._samples = self._sampler.chain[:, n_burn:, :]
for parameter in self._parse_posterior_abs:
index = self._fit_parameters.index(parameter)
self._samples[:, :, index] = np.fabs(self._samples[:, :, index])

n_fit = self._n_fit_parameters
self._samples_flat = self._samples.copy().reshape((-1, n_fit))
if 'trace' not in self._plots:
Expand Down Expand Up @@ -2672,6 +2725,8 @@ def _format_results(self, ids, results, yaml=False, begin=""):
format_ = "{:} : {:.7f} +{:.7f} -{:.7f}\n"
if yaml:
format_ = "{:} : [{:.7f}, +{:.7f}, -{:.7f}]\n"
if parameter in self._parse_posterior_abs:
parameter = "|{:}|".format(parameter)
text += (begin + format_).format(parameter, *results_)
return text[:-1]

Expand Down

2 comments on commit ef009af

@rapoliveira
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rpoleski I get the following error when fit_constraints other than posterior parsing are given (e.g. ob08092-o4_prior_1.yaml):

AttributeError: 'UlensModelFit' object has no attribute '_parse_posterior_abs'

The commit d0376cf in the open pull request solves that. Let me know if it's ok for you.

@rpoleski
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

Please sign in to comment.