From b1a1250a4ab99d308f698149966f23d6af90bd1a Mon Sep 17 00:00:00 2001 From: ivan-aksamentov Date: Tue, 7 Jul 2026 08:29:03 +0200 Subject: [PATCH] feat(pathogen): add per-dataset minimizer cutoff exponent - Add optional cutoff field to MinimizerIndexConfig for datasets needing wider k-mer retention than the default --- .../nextclade-schemas/input-pathogen-json.schema.json | 8 ++++++++ .../nextclade-schemas/input-pathogen-json.schema.yaml | 6 ++++++ .../nextclade-auspice-extensions.schema.json | 8 ++++++++ .../nextclade-auspice-extensions.schema.yaml | 6 ++++++ packages/nextclade/src/analyze/virus_properties.rs | 7 ++++++- 5 files changed, 34 insertions(+), 1 deletion(-) diff --git a/packages/nextclade-schemas/input-pathogen-json.schema.json b/packages/nextclade-schemas/input-pathogen-json.schema.json index 5483a618a..60d3f898f 100644 --- a/packages/nextclade-schemas/input-pathogen-json.schema.json +++ b/packages/nextclade-schemas/input-pathogen-json.schema.json @@ -464,6 +464,14 @@ "items": { "type": "string" } + }, + "cutoff": { + "description": "Minimizer acceptance threshold given as an exponent: the retained fraction of k-mers is `2^cutoff / 2^32`. When absent, a default cutoff is used.", + "type": [ + "integer", + "null" + ], + "format": "int64" } } }, diff --git a/packages/nextclade-schemas/input-pathogen-json.schema.yaml b/packages/nextclade-schemas/input-pathogen-json.schema.yaml index 5f04ed1fd..fd3ddf085 100644 --- a/packages/nextclade-schemas/input-pathogen-json.schema.yaml +++ b/packages/nextclade-schemas/input-pathogen-json.schema.yaml @@ -292,6 +292,12 @@ definitions: type: array items: type: string + cutoff: + description: 'Minimizer acceptance threshold given as an exponent: the retained fraction of k-mers is `2^cutoff / 2^32`. When absent, a default cutoff is used.' + type: + - integer + - 'null' + format: int64 LabelledMutationsConfig: description: Mapping from specific mutations to human-readable labels (e.g. clade-defining or drug-resistance mutations). examples: diff --git a/packages/nextclade-schemas/nextclade-auspice-extensions.schema.json b/packages/nextclade-schemas/nextclade-auspice-extensions.schema.json index 3f9f96cbe..df33d36b8 100644 --- a/packages/nextclade-schemas/nextclade-auspice-extensions.schema.json +++ b/packages/nextclade-schemas/nextclade-auspice-extensions.schema.json @@ -798,6 +798,14 @@ "items": { "type": "string" } + }, + "cutoff": { + "description": "Minimizer acceptance threshold given as an exponent: the retained fraction of k-mers is `2^cutoff / 2^32`. When absent, a default cutoff is used.", + "type": [ + "integer", + "null" + ], + "format": "int64" } } }, diff --git a/packages/nextclade-schemas/nextclade-auspice-extensions.schema.yaml b/packages/nextclade-schemas/nextclade-auspice-extensions.schema.yaml index fa44b4abd..2d8aa5100 100644 --- a/packages/nextclade-schemas/nextclade-auspice-extensions.schema.yaml +++ b/packages/nextclade-schemas/nextclade-auspice-extensions.schema.yaml @@ -511,6 +511,12 @@ definitions: type: array items: type: string + cutoff: + description: 'Minimizer acceptance threshold given as an exponent: the retained fraction of k-mers is `2^cutoff / 2^32`. When absent, a default cutoff is used.' + type: + - integer + - 'null' + format: int64 LabelledMutationsConfig: description: Mapping from specific mutations to human-readable labels (e.g. clade-defining or drug-resistance mutations). examples: diff --git a/packages/nextclade/src/analyze/virus_properties.rs b/packages/nextclade/src/analyze/virus_properties.rs index a57b70235..47c1df002 100644 --- a/packages/nextclade/src/analyze/virus_properties.rs +++ b/packages/nextclade/src/analyze/virus_properties.rs @@ -150,6 +150,10 @@ pub struct MinimizerIndexConfig { #[serde(default, skip_serializing_if = "Vec::is_empty")] pub references: Vec, + /// Minimizer acceptance threshold given as an exponent: the retained fraction of k-mers is `2^cutoff / 2^32`. When absent, a default cutoff is used. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cutoff: Option, + #[serde(flatten)] pub other: serde_json::Value, } @@ -482,12 +486,13 @@ mod tests { #[test] fn test_virus_properties_parses_minimizer_index() { - let json = r#"{"schemaVersion":"3.0.0","minimizerIndex":{"references":["minimizer_refs/additional_refs.fasta"]}}"#; + let json = r#"{"schemaVersion":"3.0.0","minimizerIndex":{"references":["minimizer_refs/additional_refs.fasta"],"cutoff":31}}"#; let props = VirusProperties::from_str(&json).unwrap(); let mi = props .minimizer_index .expect("minimizerIndex should parse into the typed field"); assert_eq!(vec_of_owned!["minimizer_refs/additional_refs.fasta"], mi.references); + assert_eq!(Some(31), mi.cutoff); assert!(props.other.get("minimizerIndex").is_none()); }