biodivine_lib_param_bn/sbml/import/
_read_transitions.rs1use crate::sbml::import::_read_mathml::{MathMl, read_mathml};
2use crate::sbml::import::{MATHML, SBML_QUAL, child_tags, read_unique_child};
3use roxmltree::{ExpandedName, Node};
4
5#[derive(Clone, Debug, PartialEq, Eq)]
7pub struct SbmlTransitionInput {
8 pub id: Option<String>, pub qual_species: String,
10 pub transition_effect: Option<String>,
11 pub sign: Option<String>,
12 pub essential: Option<bool>,
13}
14
15#[derive(Clone, Debug, PartialEq, Eq)]
17pub struct SbmlTransitionOutput {
18 pub id: Option<String>, pub qual_species: String,
20 pub transition_effect: Option<String>,
21}
22
23#[derive(Clone, Debug, PartialEq, Eq)]
25pub struct SbmlTransitionTerm {
26 pub result_level: u32,
27 pub math: Option<MathMl>,
28}
29
30#[derive(Clone, Debug, PartialEq, Eq)]
31pub struct SbmlTransition {
32 pub id: Option<String>,
33 pub inputs: Vec<SbmlTransitionInput>,
34 pub outputs: Vec<SbmlTransitionOutput>,
35 pub default_term: Option<SbmlTransitionTerm>, pub function_terms: Vec<SbmlTransitionTerm>,
37}
38
39pub fn read_transitions(model: Node) -> Result<Vec<SbmlTransition>, String> {
40 let mut result = Vec::new();
41
42 let list = read_unique_child(model, (SBML_QUAL, "listOfTransitions"))?;
43
44 let transitions = list
45 .children()
46 .filter(|node| node.tag_name() == ExpandedName::from((SBML_QUAL, "transition")));
47
48 for transition in transitions {
49 result.push(read_transition(transition)?)
50 }
51
52 Ok(result)
53}
54
55pub fn read_transition(transition: Node) -> Result<SbmlTransition, String> {
56 let id = transition
57 .attribute((SBML_QUAL, "id"))
58 .map(|it| it.to_string());
59
60 let inputs = read_unique_child(transition, (SBML_QUAL, "listOfInputs")).ok();
62 let outputs = read_unique_child(transition, (SBML_QUAL, "listOfOutputs"))?;
63 let terms = read_unique_child(transition, (SBML_QUAL, "listOfFunctionTerms")).ok();
65
66 let inputs = if let Some(inputs) = inputs {
67 child_tags(inputs, (SBML_QUAL, "input"))
68 } else {
69 Vec::new()
70 };
71 let outputs = child_tags(outputs, (SBML_QUAL, "output"));
72
73 let default_term = if let Some(terms) = terms {
74 let default_term = read_unique_child(terms, (SBML_QUAL, "defaultTerm"))?;
75 Some(read_transition_term(default_term, &id)?)
76 } else {
77 None
78 };
79
80 let terms = if let Some(terms) = terms {
81 child_tags(terms, (SBML_QUAL, "functionTerm"))
82 } else {
83 Vec::new()
84 };
85
86 let mut transition = SbmlTransition {
87 id: id.clone(),
88 inputs: Vec::new(),
89 outputs: Vec::new(),
90 default_term,
91 function_terms: Vec::new(),
92 };
93
94 if transition
95 .default_term
96 .as_ref()
97 .map(|t| t.math.is_some())
98 .unwrap_or(false)
99 {
100 return Err(format!("Default term in transition {:?} has math.", id));
101 }
102
103 for input in inputs {
104 transition.inputs.push(read_transition_input(input, &id)?);
105 }
106
107 for output in outputs {
108 transition
109 .outputs
110 .push(read_transition_output(output, &id)?);
111 }
112
113 for term in terms {
114 transition
115 .function_terms
116 .push(read_transition_term(term, &id)?);
117 }
118
119 Ok(transition)
120}
121
122fn read_transition_input(
123 input: Node,
124 transition_id: &Option<String>,
125) -> Result<SbmlTransitionInput, String> {
126 let species = input.attribute((SBML_QUAL, "qualitativeSpecies"));
127 let effect = input.attribute((SBML_QUAL, "transitionEffect"));
128 let sign = input.attribute((SBML_QUAL, "sign"));
129 let id = input.attribute((SBML_QUAL, "id"));
130 let essential = input.attribute("essential");
133 if species.is_none() {
134 return Err(format!(
135 "Transition {:?} is missing an input species.",
136 transition_id
137 ));
138 }
139
140 Ok(SbmlTransitionInput {
141 id: id.map(|s| s.to_string()),
142 qual_species: species.unwrap().to_string(),
143 transition_effect: effect.map(|s| s.to_string()),
144 sign: sign.map(|s| s.to_string()),
145 essential: essential.map(|s| s == "true"),
146 })
147}
148
149fn read_transition_output(
150 output: Node,
151 transition_id: &Option<String>,
152) -> Result<SbmlTransitionOutput, String> {
153 let species = output.attribute((SBML_QUAL, "qualitativeSpecies"));
154 let effect = output.attribute((SBML_QUAL, "transitionEffect"));
155 let id = output.attribute((SBML_QUAL, "id"));
156 if species.is_none() {
157 return Err(format!(
158 "Transition output in {:?} is missing an output species.",
159 transition_id
160 ));
161 }
162
163 Ok(SbmlTransitionOutput {
164 id: id.map(|s| s.to_string()),
165 qual_species: species.unwrap().to_string(),
166 transition_effect: effect.map(|s| s.to_string()),
167 })
168}
169
170fn read_transition_term(
171 term: Node,
172 transition_id: &Option<String>,
173) -> Result<SbmlTransitionTerm, String> {
174 let result_level = term.attribute((SBML_QUAL, "resultLevel"));
175 if result_level.is_none() {
176 return Err(format!(
177 "Term result level not specified in transition {:?}.",
178 transition_id
179 ));
180 }
181 let result_level = result_level.unwrap();
182 let level = result_level.parse::<u32>();
183 if level.is_err() {
184 return Err(format!(
185 "Term result level is not a number in transition {:?}. {} given.",
186 transition_id, result_level
187 ));
188 }
189
190 let math = read_unique_child(term, (MATHML, "math")).ok();
191 let math = math.map(read_mathml).transpose()?;
192
193 Ok(SbmlTransitionTerm {
194 result_level: level.unwrap(),
195 math,
196 })
197}