Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/treetime/src/commands/timetree/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
21 changes: 18 additions & 3 deletions packages/treetime/src/timetree/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading