Skip to content

Commit 0e90fd9

Browse files
dweindldilpath
andauthored
Handle observableTransformation in petab.v1.simulate.sample_noise (#383)
Previously, `petab.v1.simulate.sample_noise` silently ignored `observableTransformation`. For example, in case of observableTransformation=log and noiseDistribution=normal, it incorrectly sampled from a normal instead of a log-normal distribution. Fixes #382. --------- Co-authored-by: Dilan Pathirana <59329744+dilpath@users.noreply.github.com>
1 parent 2337e2d commit 0e90fd9

File tree

1 file changed

+22
-3
lines changed

1 file changed

+22
-3
lines changed

petab/v1/simulate.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,20 +241,39 @@ def sample_noise(
241241
simulated_value,
242242
)
243243

244-
# default noise distribution is petab.C.NORMAL
245-
noise_distribution = petab_problem.observable_df.loc[
244+
observable_row = petab_problem.observable_df.loc[
246245
measurement_row[petab.C.OBSERVABLE_ID]
247-
].get(petab.C.NOISE_DISTRIBUTION, petab.C.NORMAL)
246+
]
247+
# default noise distribution is petab.C.NORMAL
248+
noise_distribution = observable_row.get(
249+
petab.C.NOISE_DISTRIBUTION, petab.C.NORMAL
250+
)
248251
# an empty noise distribution column in an observables table can result in
249252
# `noise_distribution == float('nan')`
250253
if pd.isna(noise_distribution):
251254
noise_distribution = petab.C.NORMAL
252255

256+
observable_transformation = observable_row.get(
257+
petab.C.OBSERVABLE_TRANSFORMATION, petab.C.LIN
258+
)
259+
transform = lambda x: x # noqa: E731
260+
# observableTransformation=log -> the log of the simulated value is
261+
# distributed according to `noise_distribution`
262+
if observable_transformation == petab.C.LOG:
263+
simulated_value = np.log(simulated_value)
264+
transform = np.exp
265+
elif observable_transformation == petab.C.LOG10:
266+
simulated_value = np.log10(simulated_value)
267+
transform = lambda x: np.power(10, x) # noqa: E731
268+
253269
# below is e.g.: `np.random.normal(loc=simulation, scale=noise_value)`
254270
simulated_value_with_noise = getattr(rng, noise_distribution)(
255271
loc=simulated_value, scale=noise_value * noise_scaling_factor
256272
)
257273

274+
# apply observable transformation, ensure `float` type
275+
simulated_value_with_noise = float(transform(simulated_value_with_noise))
276+
258277
if zero_bounded and np.sign(simulated_value) != np.sign(
259278
simulated_value_with_noise
260279
):

0 commit comments

Comments
 (0)