bids_modeling/
auto_model.rs1use bids_core::error::Result;
8use bids_layout::BidsLayout;
9use serde_json::{Value, json};
10
11pub fn auto_model(layout: &BidsLayout) -> Result<Vec<Value>> {
34 let tasks = layout.get_tasks()?;
35 let subjects = layout.get_subjects()?;
36 let sessions = layout.get_sessions()?;
37 let root_name = layout
38 .root()
39 .file_name()
40 .and_then(|n| n.to_str())
41 .unwrap_or("dataset");
42
43 let mut models = Vec::new();
44
45 for task_name in &tasks {
46 let model_name = format!("{root_name}_{task_name}");
47
48 let event_files = layout
50 .get()
51 .suffix("events")
52 .extension("tsv")
53 .task(task_name)
54 .collect()?;
55
56 let mut trial_types = std::collections::BTreeSet::new();
57 for ef in &event_files {
58 if let Ok(rows) = ef.get_df() {
59 for row in &rows {
60 if let Some(tt) = row.get("trial_type")
61 && !tt.is_empty()
62 {
63 trial_types.insert(tt.clone());
64 }
65 }
66 }
67 }
68
69 let trial_type_factors: Vec<String> = trial_types
70 .iter()
71 .map(|tt| format!("trial_type.{tt}"))
72 .collect();
73
74 let run_node = json!({
76 "Level": "Run",
77 "Name": "run",
78 "GroupBy": ["run", "subject"],
79 "Transformations": {
80 "Transformer": "pybids-transforms-v1",
81 "Instructions": [{"Name": "Factor", "Input": ["trial_type"]}]
82 },
83 "Model": {"Type": "glm", "X": trial_type_factors},
84 "DummyContrasts": {"Test": "t"}
85 });
86
87 let mut nodes = vec![run_node];
88
89 if sessions.len() > 1 {
91 nodes.push(json!({
92 "Level": "Session",
93 "Name": "session",
94 "GroupBy": ["session", "contrast"],
95 "Model": {"Type": "meta", "X": [1]},
96 "DummyContrasts": {"Test": "t"}
97 }));
98 }
99
100 if subjects.len() > 1 {
101 nodes.push(json!({
102 "Level": "Subject",
103 "Name": "subject",
104 "GroupBy": ["subject", "contrast"],
105 "Model": {"Type": "meta", "X": [1]},
106 "DummyContrasts": {"Test": "t"}
107 }));
108 }
109
110 nodes.push(json!({
111 "Level": "Dataset",
112 "Name": "dataset",
113 "GroupBy": ["contrast"],
114 "Model": {"Type": "glm", "X": [1]},
115 "DummyContrasts": {"Test": "t"}
116 }));
117
118 let model = json!({
119 "Name": model_name,
120 "Description": format!("Autogenerated model for {} task from {}", task_name, root_name),
121 "BIDSModelVersion": "1.0.0",
122 "Input": {"task": [task_name]},
123 "Nodes": nodes
124 });
125
126 models.push(model);
127 }
128
129 Ok(models)
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
139 fn test_auto_model_signature() {
140 let _: fn(&BidsLayout) -> Result<Vec<Value>> = auto_model;
142 }
143}