# Curing divergences for a 3-parameter sigmoid model

**URL:** <https://discourse.mc-stan.org/t/curing-divergences-for-a-3-parameter-sigmoid-model/39838>\
**Category:** Modeling\
**Tags:** fitting-issues, specification\
**Created:** [July 4, 2025, 9:17pm UTC](https://discourse.mc-stan.org/t/curing-divergences-for-a-3-parameter-sigmoid-model/39838 "2025-07-04T21:17:23Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![RBAkins](https://avatars.discourse-cdn.com/v4/letter/r/e480ec/32.png) [@RBAkins](https://discourse.mc-stan.org/u/RBAkins)\
**Post date:** [July 4, 2025, 9:17pm UTC](https://discourse.mc-stan.org/t/curing-divergences-for-a-3-parameter-sigmoid-model/39838/1 "2025-07-04T21:17:23Z")

</div>

Hello all. I am trying to fit a nonlinear model specified as follows:  
y = d + \frac{1-d}{1+\exp(-b(\log(x) - \log(c)))}  
which is the 3-parameter log-logistic function for a curve with an upper limit of 1, a lower limit of d, an inflection point of c, and a slope of b. I have placed the following priors:  
d\sim \mathcal{N}(0, 0.5) \\ \log(c)\sim \mathcal{N}(0, 5) \\ b\sim \mathcal{N}(0, 20)  
where d\in(0, 1) and b\in\mathbb{R}\_{\le 0}, enforcing decreasing curves.

In Stan, I have written:

```stan
data {
    int<lower=1> N;
    vector[N] log_x;
    vector<lower=0>[N] y;
}
parameters {
    real<lower=0, upper=1> d;
    real log_c;
    real<upper=0> b;
    real<lower=0> sigma;
}
model {
    d ~ normal(0, 0.5);
    log_c ~ normal(0, 5);
    b ~ normal(0, 20);
    sigma ~ normal(0, 1);

    vector[N] mu;
    for (i in 1:N) {
        mu[i] = d + (1 - d) * inv_logit(b*(log_x[i] - log_c));
    }

    y ~ normal(mu, sigma);
}

```

Testing this model, I have simulated data in R that are similar to one of my use cases:

```r
# Simulated data
set.seed(1)
sigmoid_fxn <- function(log_x, d, log_c, b) d + (1 - d) / (1 + exp(-b*(log_x - log_c)))
data <- data.frame(x = rep(10 / 3^(7:0), each = 3))
data["log_x"] <- log(data$x)
data["y"] <- sigmoid_fxn(data[["log_x"]], 0.1, log(5), -10)
data["y"] <- data["y"] + (runif(3 * length(data["y"])) * 0.1 - 0.05)
# Model fit
library(rstan)
fit <- stan(file = "sigmoid.stan",
            data = list(N = dim(data)[1],
                        log_x = data[["log_x"]],
                        y = data[["y"]]),
            control = list(adapt_delta = 0.95),
            chains = 4, cores = 4, iter = 10000, seed = 1)

```

Which fails even with adapt\_delta increased to 0.95.

```r
Warning messages:
1: There were 225 divergent transitions after warmup. See
https://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
to find out why this is a problem and how to eliminate them. 
2: Examine the pairs() plot to diagnose sampling problems

```

Examining the pairs plot of the unconstrained variables suggests a problem:

```r
library(bayesplot)
color_scheme_set("darkgray")
np <- nuts_params(fit)
mcmc_pairs(fit, pars = c("d", "log_c", "b", "sigma"), np = np,
		   transformations = list(d = \(d) log(d / (1 - d)),
		   				          b = \(b) log(-b),
    	       					  sigma = log))

```

 ![2025-07-04_pairs-plot](https://canada1.discourse-cdn.com/flex030/uploads/mc_stan/original/3X/9/e/9ecae0c71cb86b7ba5675e26c77659fb2b8eff40.png)

It seems to me that the problem is centered on the narrow tip of the lower bound d. However, I am not sure how to move forward from here to solve this problem. Is there a reparameterization I can try to fix this problem, or another technique that I can use? I would appreciate any advice that you have–thank you.

---

<div class="post-metadata">

**Author:** ![jsocolar](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.mc-stan.org/jsocolar/32/2486_2.png) [@jsocolar](https://discourse.mc-stan.org/u/jsocolar)\
**Post date:** [July 4, 2025, 10:30pm UTC](https://discourse.mc-stan.org/t/curing-divergences-for-a-3-parameter-sigmoid-model/39838/2 "2025-07-04T22:30:05Z")

</div>

Does the model still yield a bunch of divergences if you simulate the data under the model you are fitting?

Ignoring the simulation for a second and focusing just on the stan model, I note that you have a normal likelihood but a lower bounded response. Is this what you intend?

---

<div class="post-metadata">

**Author:** ![martinmodrak](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.mc-stan.org/martinmodrak/32/133_2.png) [@martinmodrak](https://discourse.mc-stan.org/u/martinmodrak)\
**Post date:** [July 5, 2025, 6:30pm UTC](https://discourse.mc-stan.org/t/curing-divergences-for-a-3-parameter-sigmoid-model/39838/3 "2025-07-05T18:30:39Z")

</div>

Hi, sigmoid are unfortunately very hard to fit unless your data cover the full dynamic rangeof the sigmoid. See e.g. [Dose Response Model with partial pooling on maximum value - #3 by martinmodrak](https://discourse.mc-stan.org/t/dose-response-model-with-partial-pooling-on-maximum-value/17086/3) which provides links and some followup discussion and ideas. I also believe therecwas a StanConnect bio/med talk on the topic but I am not fully sure.

Best of luck with the model!

---

<div class="post-metadata">

**Author:** ![RBAkins](https://avatars.discourse-cdn.com/v4/letter/r/e480ec/32.png) [@RBAkins](https://discourse.mc-stan.org/u/RBAkins)\
**Post date:** [July 5, 2025, 8:11pm UTC](https://discourse.mc-stan.org/t/curing-divergences-for-a-3-parameter-sigmoid-model/39838/4 "2025-07-05T20:11:05Z")

</div>

Thank you for pointing out the likelihood. From reviewing the literature, it seems that a gamma distribution is a reasonable choice. I have assumed Var(y) = \phi \* \mathbb{E}(y) , where \phi is a noise parameter, and reparameterized the Stan gamma distribution as \alpha = \mathbb{E}(y) / \phi and \beta = 1 / \phi. In Stan:

```stan
...
model {
    d ~ normal(0, 0.5);
    log_c ~ normal(0, 5);
    b ~ normal(0, 20);
    phi ~ normal(0, 1);

    vector[N] mu;
    for (i in 1:N) {
        mu[i] = d + (1 - d) * inv_logit(b*(log_x[i] - log_c));
    }
	
	// gamma likelihood reparameterization
    y ~ gamma(mu / phi, 1 / phi);
}

```

This seems to resolve the sampling problem for curves with an inflection point towards the center of the tested dose range. I think that the problem for curves outside of this ideal range is due to the available data, rather than the model specification. Thank you for your help!

---

<div class="post-metadata">

**Author:** ![RBAkins](https://avatars.discourse-cdn.com/v4/letter/r/e480ec/32.png) [@RBAkins](https://discourse.mc-stan.org/u/RBAkins)\
**Post date:** [July 5, 2025, 8:13pm UTC](https://discourse.mc-stan.org/t/curing-divergences-for-a-3-parameter-sigmoid-model/39838/5 "2025-07-05T20:13:35Z")

</div>

Thank you for the link, this has some excellent discussion.
