Thank you for this suggestion, @bob-carpenter. I have experimented with such a model and have found good results!
coords = {"component": range(n_components)}
with pm.Model(coords=coords) as model:
line_area_norm = pm.Gamma(
"line_area_norm", alpha=2.0, beta=1.0, dims="component"
)
line_area = 100.0 * line_area_norm
fwhm_norm = pm.Gamma(
"fwhm_norm", alpha=2.0, beta=1.0, dims="component"
)
fwhm = 30.0 * fwhm_norm
center_lower = -20.0
center_offset_norm = pm.HalfNormal(
"center_offset_norm",
sigma=1.0,
dims="component",
)
center_offset = 20.0 * center_offset_norm
center = pm.Deterministic(
"center",
center_lower + pm.math.cumsum(center_offset, axis=0),
dims="component"
)
noise = pm.HalfNormal("noise", sigma=1.0)
amplitude = calc_amplitude(line_area, fwhm)
predicted = gaussian(x[:, None], amplitude, fwhm, center).sum(axis=1)
_ = pm.Normal(
"predicted", mu=predicted, sigma=noise, observed=observed
)
The model samples fine with both NUTS and SMC. Some NUTS chains collapse to a single model, but SMC seems to find both modes just fine.
