nkl/data/endf/
read.rs

1use std::io::BufRead;
2
3use super::{
4    parse_endf_integer, parse_float, parse_integer, Cont, EndfError, Intg, List, Tab1, Tab2, Text,
5};
6
7// Maximum endf line length: 80 chars + optional `\r` + `\n`.
8const ENDF_MAX_LINE_LENGTH: usize = 82;
9
10/// Reader specialized for ENDF format files.
11#[derive(Debug)]
12pub struct EndfReader<B: BufRead> {
13    buf: B,
14}
15
16impl<B: BufRead> EndfReader<B> {
17    /// Creates an `EndfReader` from specified source.
18    ///
19    /// # Examples
20    ///
21    /// ```no_run
22    /// use std::fs::File;
23    /// use std::io::BufReader;
24    /// use nkl::data::endf::EndfReader;
25    ///
26    /// let path = "path/to/file.endf";
27    /// let file = File::open(path).expect("could not open endf file");
28    /// let buf_reader = BufReader::new(file);
29    /// let endf_reader = EndfReader::new(buf_reader);
30    /// ```
31    pub fn new(buf: B) -> Self {
32        Self { buf }
33    }
34
35    /// Reads a line from the `EndfReader`.
36    ///
37    /// # Examples
38    ///
39    /// ```no_run
40    /// use std::fs::File;
41    /// use std::io::BufReader;
42    /// use nkl::data::endf::EndfReader;
43    ///
44    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
45    /// let mut reader = EndfReader::new(BufReader::new(File::open("file.endf")?));
46    /// let line = reader.read_line()?;
47    /// # Ok(())
48    /// # }
49    /// ```
50    pub fn read_line(&mut self) -> Result<Vec<u8>, EndfError> {
51        let mut buf = Vec::with_capacity(ENDF_MAX_LINE_LENGTH);
52        match self.buf.read_until(b'\n', &mut buf) {
53            Ok(0) => Err(EndfError::EndOfFile),
54            Err(error) => Err(error.into()),
55            Ok(_) => Ok(buf),
56        }
57    }
58
59    /// Reads a **CONT** record from the `EndfReader`.
60    ///
61    /// # Examples
62    ///
63    /// ```no_run
64    /// use std::fs::File;
65    /// use std::io::BufReader;
66    /// use nkl::data::endf::EndfReader;
67    ///
68    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
69    /// let mut reader = EndfReader::new(BufReader::new(File::open("file.endf")?));
70    /// let cont = reader.read_cont()?;
71    /// # Ok(())
72    /// # }
73    /// ```
74    ///
75    /// # Errors
76    ///
77    /// Errors if:
78    /// - I/O error occurs
79    /// - malformed/invalid data
80    pub fn read_cont(&mut self) -> Result<Cont, EndfError> {
81        let mut buf = Vec::with_capacity(ENDF_MAX_LINE_LENGTH);
82        match self.buf.read_until(b'\n', &mut buf) {
83            Ok(0) => Err(EndfError::EndOfFile),
84            Err(error) => Err(error.into()),
85            Ok(_) => {
86                let c1 = parse_float(&buf, 1)?;
87                let c2 = parse_float(&buf, 2)?;
88                let l1 = parse_integer(&buf, 3)?;
89                let l2 = parse_integer(&buf, 4)?;
90                let n1 = parse_integer(&buf, 5)?;
91                let n2 = parse_integer(&buf, 6)?;
92                Ok(Cont(c1, c2, l1, l2, n1, n2))
93            }
94        }
95    }
96
97    /// Reads a **INTG** record from the `EndfReader`.
98    ///
99    /// `ndigit` denotes the number of digits for values.
100    ///
101    /// # Examples
102    ///
103    /// ```no_run
104    /// use std::fs::File;
105    /// use std::io::BufReader;
106    /// use nkl::data::endf::EndfReader;
107    ///
108    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
109    /// let mut reader = EndfReader::new(BufReader::new(File::open("file.endf")?));
110    /// let intg = reader.read_intg(2)?;
111    /// # Ok(())
112    /// # }
113    /// ```
114    ///
115    /// # Errors
116    ///
117    /// Errors if:
118    /// - I/O error occurs
119    /// - malformed/invalid data
120    ///
121    /// # Panics
122    ///
123    /// Panics if `ndigit` ∉ `[2, 6]`
124    pub fn read_intg(&mut self, ndigit: usize) -> Result<Intg, EndfError> {
125        assert!(ndigit >= 2);
126        assert!(ndigit <= 6);
127        let mut buf = Vec::with_capacity(ENDF_MAX_LINE_LENGTH);
128        match self.buf.read_until(b'\n', &mut buf) {
129            Ok(0) => Err(EndfError::EndOfFile),
130            Err(error) => Err(error.into()),
131            Ok(_) => {
132                let ii = match buf.get(0..5) {
133                    Some(slice) => match parse_endf_integer(slice) {
134                        Ok(integer) => integer,
135                        Err(_) => return Err(EndfError::Data),
136                    },
137                    None => return Err(EndfError::Format),
138                };
139                let jj = match buf.get(5..10) {
140                    Some(slice) => match parse_endf_integer(slice) {
141                        Ok(integer) => integer,
142                        Err(_) => return Err(EndfError::Data),
143                    },
144                    None => return Err(EndfError::Format),
145                };
146                let mut kij = Vec::new();
147                let mut ptr = if ndigit <= 5 { 11 } else { 10 };
148                loop {
149                    if ptr + ndigit + 1 > 66 {
150                        break;
151                    }
152                    let slice = &buf[ptr..ptr + ndigit + 1];
153                    let value = match parse_endf_integer(slice) {
154                        Ok(value) => value,
155                        Err(_) => return Err(EndfError::Data),
156                    };
157                    kij.push(value);
158                    ptr += ndigit + 1;
159                }
160                Ok(Intg(ii, jj, kij))
161            }
162        }
163    }
164
165    /// Reads a **LIST** record from the `EndfReader`.
166    ///
167    /// # Examples
168    ///
169    /// ```no_run
170    /// use std::fs::File;
171    /// use std::io::BufReader;
172    /// use nkl::data::endf::EndfReader;
173    ///
174    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
175    /// let mut reader = EndfReader::new(BufReader::new(File::open("file.endf")?));
176    /// let list = reader.read_list()?;
177    /// # Ok(())
178    /// # }
179    /// ```
180    ///
181    /// # Errors
182    ///
183    /// Errors if:
184    /// - I/O error occurs
185    /// - malformed/invalid data
186    pub fn read_list(&mut self) -> Result<List, EndfError> {
187        let mut buf = Vec::with_capacity(ENDF_MAX_LINE_LENGTH);
188        match self.buf.read_until(b'\n', &mut buf) {
189            Ok(0) => Err(EndfError::EndOfFile),
190            Err(error) => Err(error.into()),
191            Ok(_) => {
192                let c1 = parse_float(&buf, 1)?;
193                let c2 = parse_float(&buf, 2)?;
194                let l1 = parse_integer(&buf, 3)?;
195                let l2 = parse_integer(&buf, 4)?;
196                let npl = parse_integer(&buf, 5)?;
197                let n2 = parse_integer(&buf, 6)?;
198                let npl: usize = match npl.try_into() {
199                    Ok(npl) => npl,
200                    Err(_) => return Err(EndfError::Data),
201                };
202                let mut b = Vec::with_capacity(npl);
203                while b.len() < npl {
204                    buf.clear();
205                    match self.buf.read_until(b'\n', &mut buf) {
206                        Ok(0) => return Err(EndfError::EndOfFile),
207                        Err(error) => return Err(error.into()),
208                        Ok(_) => {
209                            for col in 0..6 {
210                                if b.len() == npl {
211                                    break;
212                                }
213                                let float = parse_float(&buf, col + 1)?;
214                                b.push(float);
215                            }
216                        }
217                    }
218                }
219                Ok(List(c1, c2, l1, l2, npl, n2, b))
220            }
221        }
222    }
223
224    /// Reads a **TAB1** record from the `EndfReader`.
225    ///
226    /// # Examples
227    ///
228    /// ```no_run
229    /// use std::fs::File;
230    /// use std::io::BufReader;
231    /// use nkl::data::endf::EndfReader;
232    ///
233    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
234    /// let mut reader = EndfReader::new(BufReader::new(File::open("file.endf")?));
235    /// let tab1 = reader.read_tab1()?;
236    /// # Ok(())
237    /// # }
238    /// ```
239    ///
240    /// # Errors
241    ///
242    /// Errors if:
243    /// - I/O error occurs
244    /// - malformed/invalid data
245    pub fn read_tab1(&mut self) -> Result<Tab1, EndfError> {
246        let mut buf = Vec::with_capacity(ENDF_MAX_LINE_LENGTH);
247        match self.buf.read_until(b'\n', &mut buf) {
248            Ok(0) => Err(EndfError::EndOfFile),
249            Err(error) => Err(error.into()),
250            Ok(_) => {
251                let c1 = parse_float(&buf, 1)?;
252                let c2 = parse_float(&buf, 2)?;
253                let l1 = parse_integer(&buf, 3)?;
254                let l2 = parse_integer(&buf, 4)?;
255                let nr = parse_integer(&buf, 5)?;
256                let np = parse_integer(&buf, 6)?;
257                let nr: usize = match nr.try_into() {
258                    Ok(nr) => nr,
259                    Err(_) => return Err(EndfError::Data),
260                };
261                let np: usize = match np.try_into() {
262                    Ok(np) => np,
263                    Err(_) => return Err(EndfError::Data),
264                };
265                let mut int = Vec::with_capacity(nr);
266                while int.len() < nr {
267                    buf.clear();
268                    match self.buf.read_until(b'\n', &mut buf) {
269                        Ok(0) => return Err(EndfError::EndOfFile),
270                        Err(error) => return Err(error.into()),
271                        Ok(_) => {
272                            for col in 0..3 {
273                                if int.len() == nr {
274                                    break;
275                                }
276                                let nbt = parse_integer(&buf, 2 * col + 1)?;
277                                let nbt: u32 = match nbt.try_into() {
278                                    Ok(nbt) => nbt,
279                                    Err(_) => return Err(EndfError::Data),
280                                };
281                                let scheme = parse_integer(&buf, 2 * col + 2)?;
282                                let scheme: usize = match scheme.try_into() {
283                                    Ok(scheme) => scheme,
284                                    Err(_) => return Err(EndfError::Data),
285                                };
286                                int.push((nbt, scheme));
287                            }
288                        }
289                    }
290                }
291                let mut tab = Vec::with_capacity(np);
292                while tab.len() < np {
293                    buf.clear();
294                    match self.buf.read_until(b'\n', &mut buf) {
295                        Ok(0) => return Err(EndfError::EndOfFile),
296                        Err(error) => return Err(error.into()),
297                        Ok(_) => {
298                            for col in 0..3 {
299                                if tab.len() == np {
300                                    break;
301                                }
302                                let x = parse_float(&buf, 2 * col + 1)?;
303                                let y = parse_float(&buf, 2 * col + 2)?;
304                                tab.push((x, y));
305                            }
306                        }
307                    }
308                }
309                Ok(Tab1(c1, c2, l1, l2, nr, np, int, tab))
310            }
311        }
312    }
313
314    /// Reads a **TAB2** record from the `EndfReader`.
315    ///
316    /// # Examples
317    ///
318    /// ```no_run
319    /// use std::fs::File;
320    /// use std::io::BufReader;
321    /// use nkl::data::endf::EndfReader;
322    ///
323    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
324    /// let mut reader = EndfReader::new(BufReader::new(File::open("file.endf")?));
325    /// let tab2 = reader.read_tab2()?;
326    /// # Ok(())
327    /// # }
328    /// ```
329    ///
330    /// # Errors
331    ///
332    /// Errors if:
333    /// - I/O error occurs
334    /// - malformed/invalid data
335    pub fn read_tab2(&mut self) -> Result<Tab2, EndfError> {
336        let mut buf = Vec::with_capacity(ENDF_MAX_LINE_LENGTH);
337        match self.buf.read_until(b'\n', &mut buf) {
338            Ok(0) => Err(EndfError::EndOfFile),
339            Err(error) => Err(error.into()),
340            Ok(_) => {
341                let c1 = parse_float(&buf, 1)?;
342                let c2 = parse_float(&buf, 2)?;
343                let l1 = parse_integer(&buf, 3)?;
344                let l2 = parse_integer(&buf, 4)?;
345                let nr = parse_integer(&buf, 5)?;
346                let nz = parse_integer(&buf, 6)?;
347                let nr: usize = match nr.try_into() {
348                    Ok(nr) => nr,
349                    Err(_) => return Err(EndfError::Data),
350                };
351                let nz: usize = match nz.try_into() {
352                    Ok(nz) => nz,
353                    Err(_) => return Err(EndfError::Data),
354                };
355                let mut int = Vec::with_capacity(nr);
356                while int.len() < nr {
357                    buf.clear();
358                    match self.buf.read_until(b'\n', &mut buf) {
359                        Ok(0) => return Err(EndfError::EndOfFile),
360                        Err(error) => return Err(error.into()),
361                        Ok(_) => {
362                            for col in 0..3 {
363                                if int.len() == nr {
364                                    break;
365                                }
366                                let nbt = parse_integer(&buf, 2 * col + 1)?;
367                                let nbt: u32 = match nbt.try_into() {
368                                    Ok(nbt) => nbt,
369                                    Err(_) => return Err(EndfError::Data),
370                                };
371                                let scheme = parse_integer(&buf, 2 * col + 2)?;
372                                let scheme: usize = match scheme.try_into() {
373                                    Ok(scheme) => scheme,
374                                    Err(_) => return Err(EndfError::Data),
375                                };
376                                int.push((nbt, scheme));
377                            }
378                        }
379                    }
380                }
381                Ok(Tab2(c1, c2, l1, l2, nr, nz, int))
382            }
383        }
384    }
385
386    /// Reads a **TEXT** record from the `EndfReader`.
387    ///
388    /// # Examples
389    ///
390    /// ```no_run
391    /// use std::fs::File;
392    /// use std::io::BufReader;
393    /// use nkl::data::endf::EndfReader;
394    ///
395    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
396    /// let mut reader = EndfReader::new(BufReader::new(File::open("file.endf")?));
397    /// let text = reader.read_text()?;
398    /// # Ok(())
399    /// # }
400    /// ```
401    ///
402    /// # Errors
403    ///
404    /// Errors if:
405    /// - I/O error occurs
406    /// - malformed/invalid data
407    pub fn read_text(&mut self) -> Result<Text, EndfError> {
408        let mut buf = Vec::with_capacity(ENDF_MAX_LINE_LENGTH);
409        match self.buf.read_until(b'\n', &mut buf) {
410            Ok(0) => Err(EndfError::EndOfFile),
411            Err(error) => Err(error.into()),
412            Ok(_) => {
413                let hl = match String::from_utf8(buf[..66].to_vec()) {
414                    Ok(string) => string,
415                    Err(_) => return Err(EndfError::Data),
416                };
417                Ok(Text(hl))
418            }
419        }
420    }
421}