diff --git a/packages/treetime/src/commands/timetree/args.rs b/packages/treetime/src/commands/timetree/args.rs index f448d346..aaccd2b0 100644 --- a/packages/treetime/src/commands/timetree/args.rs +++ b/packages/treetime/src/commands/timetree/args.rs @@ -122,7 +122,10 @@ pub struct TreetimeTimetreeArgs { /// /// When set, TreeTime will find the optimal Tc using Brent's method. This is similar /// to Python v0's `--coalescent=opt`, but uses a closed-form solution. - #[cfg_attr(feature = "clap", clap(long, conflicts_with = "coalescent", conflicts_with = "coalescent_skyline"))] + #[cfg_attr( + feature = "clap", + clap(long, conflicts_with = "coalescent", conflicts_with = "coalescent_skyline") + )] pub coalescent_opt: bool, /// Use skyline coalescent model instead of constant Tc. diff --git a/packages/treetime/src/timetree/pipeline.rs b/packages/treetime/src/timetree/pipeline.rs index 46eac1df..030c6da7 100644 --- a/packages/treetime/src/timetree/pipeline.rs +++ b/packages/treetime/src/timetree/pipeline.rs @@ -434,20 +434,35 @@ fn estimate_coalescent_tc( // On a degenerate tree prefer the previous round's Tc, then the user seed, // then no prior at all (rather than an invented timescale). Err(e) => { - warn!("Tc optimization failed: {e}, keeping previous Tc"); - Ok(current.cloned().or_else(|| (*seed).map(Distribution::constant))) + let fallback = current.cloned().or_else(|| (*seed).map(Distribution::constant)); + report_coalescent_failure("Coalescent Tc optimization", &e, fallback.is_some()); + Ok(fallback) }, }, CoalescentMode::Skyline => match optimize_skyline(graph, skyline_params) { Ok(result) => Ok(Some(result.tc_distribution)), Err(e) => { - warn!("Skyline optimization failed: {e}, keeping previous Tc"); + report_coalescent_failure("Skyline coalescent optimization", &e, current.is_some()); Ok(current.cloned()) }, }, } } +/// Reports a coalescent optimization failure and states the resulting prior. +/// +/// When no previous value or seed is available the fallback is empty, so the run +/// proceeds without a coalescent prior. Make that downgrade explicit instead of the +/// misleading "keeping previous Tc" the previous message logged even when there was +/// no previous value to keep. +fn report_coalescent_failure(what: &str, error: &Report, has_fallback: bool) { + if has_fallback { + warn!("{what} failed: {error}; retaining the previous coalescent prior for this round"); + } else { + warn!("{what} failed: {error}; proceeding with no coalescent prior this run"); + } +} + struct PartitionInitResult { partitions: PartitionTimetreeAllVec, gtr: GTR,