1use lazy_static::lazy_static;
2use std::collections::HashMap;
3use std::io;
4use std::io::Write;
5use std::path::PathBuf;
6use tempfile::Builder;
7use tera::{Context, Tera};
8
9lazy_static! {
10 pub static ref TEMPLATES: Tera = {
11 let mut tera = Tera::default();
12 let _ = tera.add_raw_template(
13 "pstemplate.py_t",
14 r#"ifg = ps.{{ methodname }}.parse_raw(
15 "{{ filename }}",
16{%- if filename2 %} "{{ filename2 }}", {% endif %}
17{%- if filename3 %} "{{ filename3 }}", {% endif %}
18{% if skiprows %} skiprows={{ skiprows }}, {%- else %} skiprows=0, {% endif %}
19{% if decimal %} decimal="{{ decimal }}", {%- else %} ".", {% endif %}
20{% if delimiter %} delimiter="{{ delimiter }}", {%- else %} ",", {% endif %}
21{% if meta_len %} meta_len={{ meta_len }} {%- else %} meta_len=0 {% endif %}
22)
23
24SKIP_IF = ("ref", "sam", "reference", "sample", "noeval")
25
26for entry in SKIP_IF:
27 try:
28 if entry in ifg.meta['comment']:
29 import sys
30 sys.exit("file skipped due to user comment")
31 except KeyError:
32 pass
33
34{% if chdomain -%} ifg.chdomain() {%- endif %}
35
36{% if slice_start and slice_stop -%} ifg.slice({{ slice_start }}, {{ slice_stop }}){%- endif %}
37{%- if slice_start and not slice_stop -%} ifg.slice(start={{ slice_start }}){%- endif %}
38{%- if not slice_start and slice_stop -%} ifg.slice(stop={{ slice_stop }}){%- endif %}
39
40x_before_transform = np.copy(ifg.x)
41y_before_transform = np.copy(ifg.y_norm)
42
43{%if detach %}
44ifg.plot()
45plt.show(block=True)
46{% endif %}
47
48
49{% for cmd in before_evaluate_triggers %}
50{{ cmd }}
51{% endfor %}
52
53{% if methodname == "FFTMethod" %}
54ifg.autorun({{ reference_frequency }}, {{ order }}, show_graph=False, enable_printing=False)
55{% elif methodname == "WFTMethod" %}
56ifg.cover(
57 {% if windows %}{{ windows }}{% else %}300{% endif %},
58 {% if fwhm and not std %}fwhm={{ fwhm }},{% endif %}
59 {% if std and not fwhm %}std={{ std }},{% endif %}
60 {%if not std and not fwhm %}fwhm=0.05{% endif %}
61)
62
63ifg.calculate({{ reference_frequency }}, {{ order }}, parallel={% if parallel %}True{% else %}False{% endif %}, fastmath=False)
64{% elif methodname == "MinMaxMethod" %}
65ifg.init_edit_session(
66 {% if min and max %}
67 side="both"
68 {% elif min %}
69 side="min"
70 {% elif max %}
71 side="max"
72 {% else %}
73 side="both"
74 {% endif %}
75)
76plt.show(block=True)
77ifg.calculate({{ reference_frequency }}, {{ order }}, scan=True,
78 {% if min and max %}
79 onesided=False
80 {% elif min %}
81 onesided=True
82 {% elif max %}
83 onesided=True
84 {% else %}
85 onesided=False
86{% endif %})
87{% else %}
88print("{{ methodname }} is not yet implemented..")
89{% endif %}
90
91{% if heatmap and methodname == "WFTMethod" %}
92ifg.heatmap()
93plt.show(block=True)
94{% endif %}
95
96fragment = ps.utils._prepare_json_fragment(ifg, "{{ filename_raw }}", x_before_transform, y_before_transform, verbosity={{ verbosity }})
97ps.utils._write_or_update_json_fragment("{{ workdir }}/{{ result_file }}", fragment, "{{ filename_raw }}")
98
99{% for cmd in after_evaluate_triggers %}
100{{ cmd }}
101{% endfor %}"#,
102 );
103 tera
104 };
105}
106
107pub fn write_tempfile(name: &str, content: &str, path: &str) -> std::io::Result<()> {
108 let tempfile = Builder::new().tempfile_in(path)?;
109
110 let mut _file = tempfile.persist(format!("{}/{}_pstemp.py", path, name))?;
111 writeln!(_file, "{}", content)?;
112
113 Ok(())
114}
115
116pub fn render_template(
117 file: &str,
118 path: &str,
119 text_options: &HashMap<String, String>,
120 number_options: &HashMap<String, Box<f64>>,
121 bool_options: &HashMap<String, Box<bool>>,
122 before_evaluate_triggers: &[String],
123 after_evaluate_triggers: &[String],
124 result_file: &str,
125 verbosity: u8,
126) -> Result<std::string::String, tera::Error> {
127 let mut context = Context::new();
128
129 for (key, entry) in number_options {
130 context.insert(key, &entry);
131 }
132
133 for (key, entry) in text_options {
134 context.insert(key, &entry);
135 }
136
137 for (key, entry) in bool_options {
138 context.insert(key, &entry);
139 }
140 context.insert("verbosity", &verbosity);
142 context.insert("result_file", result_file);
143 context.insert("filename_raw", &file);
144 context.insert("workdir", &path);
145 context.insert("filename", &format!("{}/{}", path, file));
146
147 context.insert("before_evaluate_triggers", &before_evaluate_triggers);
149 context.insert("after_evaluate_triggers", &after_evaluate_triggers);
150
151 TEMPLATES.render("pstemplate.py_t", &context)
153}
154
155fn write_default_yaml(path: &str) -> std::io::Result<()> {
156 let cfg_path = PathBuf::from(path).join("eval.yaml");
157 std::fs::write(
158 cfg_path,
159 r#"load_options:
160 - extensions:
161 - "trt"
162 - "txt"
163 - exclude_patterns:
164 - "*_randomfile.trt"
165 - "*_to_skip.trt"
166 - skip:
167 - "filename.trt"
168 - "file_to_skip.trt"
169 - skiprows: 8 # lines
170 - decimal: ","
171 - delimiter: ";"
172 - meta_len: 6 # lines
173
174preprocess:
175 - input_unit: "nm"
176 - chdomain: true
177 - slice_start: 2 # PHz
178 - slice_stop: 4 # PHz
179
180method:
181 - wft
182
183method_details:
184 # globally available options
185 # - auto
186 # - only_phase
187 # - detach
188
189 # options for -- MinMaxMethod --
190 # - min
191 # - max
192 # - both
193
194 # options for -- WFTMethod --
195 # - heatmap
196 # - windows: 200
197 # - fwhm: 0.05 # PHz
198 # - std: 0.05 # PHz
199 # - parallel
200
201 # options for -- FFTMethod --
202 # there is no option currently available
203
204 # options for -- CosFitMethod --
205 # not implemented yet
206
207 # options for -- SPPMethod --
208 # not implemented yet
209
210before_evaluate:
211 - "print('before_evaluate')"
212
213evaluate:
214 - reference_frequency: 2.355 # PHz
215 - order: 3 # up to TOD
216
217after_evaluate:
218 - "print('and after..')"
219
220"#
221 .as_bytes(),
222 )?;
223 Ok(())
224}
225
226pub fn maybe_write_default_yaml(path: &str) {
227 println!(
228 "[INFO] No `eval.yaml` file was detected in the target path.
229 If you named it something different, use the `-c` option.
230 Type 'y' or 'yes' if you want to generate a default one, or anything else to quit."
231 );
232
233 let mut input_text = String::new();
234 io::stdin()
235 .read_line(&mut input_text)
236 .expect("failed to read from stdin");
237
238 match input_text.to_lowercase().trim() {
239 "yes" | "y" => {
240 let _r = write_default_yaml(path);
241 println!("[INFO] Created `eval.yaml` config file.");
242 }
243 _ => {}
244 };
245}