From fb098c78406280b9110633f7ca533eaaf2aa23f3 Mon Sep 17 00:00:00 2001 From: Ivan Juarez-Reyes <53101717+ijuare@users.noreply.github.com> Date: Mon, 22 Dec 2025 17:26:41 -0600 Subject: [PATCH 1/5] Update parametric.py Corrected power law + peak primary pdf. --- gwinferno/models/parametric/parametric.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gwinferno/models/parametric/parametric.py b/gwinferno/models/parametric/parametric.py index 1bc312e..07c8bcb 100644 --- a/gwinferno/models/parametric/parametric.py +++ b/gwinferno/models/parametric/parametric.py @@ -50,7 +50,7 @@ def plpeak_primary_pdf(m1, alpha, mmin, mmax, mpp, sigpp, lam, delta=None): if delta is None: return (1 - lam) * powerlaw_pdf(m1, alpha, mmin, mmax) + lam * truncnorm_pdf(m1, mpp, sigpp, mmin, mmax) else: - return (1 - lam) * powerlaw_pdf(m1, alpha, mmin, mmax) * smooth(delta, m1, mmin) + lam * truncnorm_pdf(m1, mpp, sigpp, mmin, mmax) + return ( (1 - lam) * powerlaw_pdf(m1, alpha, mmin, mmax) + lam * truncnorm_pdf(m1, mpp, sigpp, mmin, mmax) ) * smooth(delta, m1, mmin) """ From d0643fc4de21ad15b3463e8890f32c00b6068837 Mon Sep 17 00:00:00 2001 From: Ivan Juarez-Reyes <53101717+ijuare@users.noreply.github.com> Date: Mon, 22 Dec 2025 17:30:09 -0600 Subject: [PATCH 2/5] Update distributions.py Corrected smoothing function --- gwinferno/distributions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gwinferno/distributions.py b/gwinferno/distributions.py index 40db691..b701005 100644 --- a/gwinferno/distributions.py +++ b/gwinferno/distributions.py @@ -18,7 +18,8 @@ def smooth(dx, x, xmin): func = jnp.exp(dx / (x - xmin) + dx / (x - xmin - dx)) s1 = jnp.where(jnp.less(x, xmin), 0, 1) s2 = jnp.where(jnp.less(x, xmin + dx) | jnp.greater_equal(x, xmin), (func + 1) ** (-1), s1) - return s2 + s3 = jnp.where(jnp.greater_equal(x, xmin + dx), 1, s2) + return s3 def logistic_function(x, L, k, x0): From bf0f1fc62d70ebfad245ff9ac7b1e51bc4f509f1 Mon Sep 17 00:00:00 2001 From: Ivan Juarez-Reyes <53101717+ijuare@users.noreply.github.com> Date: Wed, 25 Feb 2026 12:23:48 -0800 Subject: [PATCH 3/5] Update distributions.py Added left-truncated and right-truncated norm evaluations to truncnorm_pdf function --- gwinferno/distributions.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gwinferno/distributions.py b/gwinferno/distributions.py index 40db691..c449adb 100644 --- a/gwinferno/distributions.py +++ b/gwinferno/distributions.py @@ -124,19 +124,22 @@ def truncnorm_pdf(xx, mu, sig, low, high, log=False): $$ p(x) \propto \mathcal{N}(x | \mu, \sigma)\Theta(x-x_\mathrm{min})\Theta(x_\mathrm{max}-x) $$ `log=True` makes this a log-normal distribution! + + If 'low == -jnp.inf', then return a right-truncated norm + If 'high == jnp.inf', then return a left-truncated norm """ if log: prob = jnp.exp(-jnp.power(jnp.log(xx) - mu, 2) / (2 * sig**2)) continuous_norm = 1 / (xx * sig * (2 * jnp.pi) ** 0.5) - left_tail_cdf = 0.5 * (1 + erf((jnp.log(low) - mu) / (sig * (2**0.5)))) - right_tail_cdf = 0.5 * (1 + erf((jnp.log(high) - mu) / (sig * (2**0.5)))) + left_tail_cdf = 0 if low == -jnp.inf else 0.5 * (1 + erf((jnp.log(low) - mu) / (sig * (2**0.5)))) + right_tail_cdf = 1 if high == jnp.inf else 0.5 * (1 + erf((jnp.log(high) - mu) / (sig * (2**0.5)))) denom = right_tail_cdf - left_tail_cdf else: prob = jnp.exp(-jnp.power(xx - mu, 2) / (2 * sig**2)) continuous_norm = 1 / (sig * (2 * jnp.pi) ** 0.5) - left_tail_cdf = 0.5 * (1 + erf((low - mu) / (sig * (2**0.5)))) - right_tail_cdf = 0.5 * (1 + erf((high - mu) / (sig * (2**0.5)))) + left_tail_cdf = 0 if low == -jnp.inf else 0.5 * (1 + erf((low - mu) / (sig * (2**0.5)))) + right_tail_cdf = 1 if high == jnp.inf else 0.5 * (1 + erf((high - mu) / (sig * (2**0.5)))) denom = right_tail_cdf - left_tail_cdf norm = continuous_norm / denom From 0d5dda75d0b70811532c88ea127b54e5372f510f Mon Sep 17 00:00:00 2001 From: Ivan Juarez-Reyes <53101717+ijuare@users.noreply.github.com> Date: Wed, 25 Feb 2026 12:36:07 -0800 Subject: [PATCH 4/5] Update parametric.py Added broken power law + two peaks mass model --- gwinferno/models/parametric/parametric.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gwinferno/models/parametric/parametric.py b/gwinferno/models/parametric/parametric.py index 07c8bcb..c537ce5 100644 --- a/gwinferno/models/parametric/parametric.py +++ b/gwinferno/models/parametric/parametric.py @@ -53,6 +53,13 @@ def plpeak_primary_pdf(m1, alpha, mmin, mmax, mpp, sigpp, lam, delta=None): return ( (1 - lam) * powerlaw_pdf(m1, alpha, mmin, mmax) + lam * truncnorm_pdf(m1, mpp, sigpp, mmin, mmax) ) * smooth(delta, m1, mmin) +def brokenpl_twopeaks_primary_pdf(m1, alpha1, alpha2, mmin, mmax, mbreak, mpp1, sigpp1, mpp2, sigpp2, lam0, lam1, delta=None): + if delta is None: + return lam0 * broken_powerlaw_pdf(m1, alpha1, alpha2, mmin, mbreak, mmax) + lam1 * truncnorm_pdf(m1, mpp1, sigpp1, mmin, high=jnp.inf) + (1-lam0-lam1) * truncnorm_pdf(m1, mpp2, sigpp2, mmin, high=jnp.inf) + else: + return ( lam0 * broken_powerlaw_pdf(m1, alpha1, alpha2, mmin, mbreak, mmax) + lam1 * truncnorm_pdf(m1, mpp1, sigpp1, mmin, high=jnp.inf) + (1-lam0-lam1) * truncnorm_pdf(m1, mpp2, sigpp2, mmin, high=jnp.inf) ) * smooth(delta, m1, mmin) + + """ *************************************** SPIN MODELS From 824c51d5ba5cdc5f2d6ccf89ca25a27a84a5e36f Mon Sep 17 00:00:00 2001 From: Ivan Juarez-Reyes <53101717+ijuare@users.noreply.github.com> Date: Fri, 27 Feb 2026 13:00:44 -0800 Subject: [PATCH 5/5] Update distributions.py Changed evaluation of left- and right-truncated norms from conditional to jnp.where --- gwinferno/distributions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gwinferno/distributions.py b/gwinferno/distributions.py index a79f7b7..4b889dd 100644 --- a/gwinferno/distributions.py +++ b/gwinferno/distributions.py @@ -133,14 +133,14 @@ def truncnorm_pdf(xx, mu, sig, low, high, log=False): if log: prob = jnp.exp(-jnp.power(jnp.log(xx) - mu, 2) / (2 * sig**2)) continuous_norm = 1 / (xx * sig * (2 * jnp.pi) ** 0.5) - left_tail_cdf = 0 if low == -jnp.inf else 0.5 * (1 + erf((jnp.log(low) - mu) / (sig * (2**0.5)))) - right_tail_cdf = 1 if high == jnp.inf else 0.5 * (1 + erf((jnp.log(high) - mu) / (sig * (2**0.5)))) + left_tail_cdf = jnp.where(low > -jnp.inf, 0.5 * (1 + erf((jnp.log(low) - mu) / (sig * (2**0.5)))), 0) + right_tail_cdf = jnp.where(high < jnp.inf, 0.5 * (1 + erf((jnp.log(high) - mu) / (sig * (2**0.5)))), 1) denom = right_tail_cdf - left_tail_cdf else: prob = jnp.exp(-jnp.power(xx - mu, 2) / (2 * sig**2)) continuous_norm = 1 / (sig * (2 * jnp.pi) ** 0.5) - left_tail_cdf = 0 if low == -jnp.inf else 0.5 * (1 + erf((low - mu) / (sig * (2**0.5)))) - right_tail_cdf = 1 if high == jnp.inf else 0.5 * (1 + erf((high - mu) / (sig * (2**0.5)))) + left_tail_cdf = jnp.where(low > -jnp.inf, 0.5 * (1 + erf((low - mu) / (sig * (2**0.5)))), 0) + right_tail_cdf = jnp.where(high < jnp.inf, 0.5 * (1 + erf((high - mu) / (sig * (2**0.5)))), 1) denom = right_tail_cdf - left_tail_cdf norm = continuous_norm / denom