1use crate::DataError;
4use crate::descriptors::{CMExportType, PhaseCM};
5use serde::{Deserialize, Serialize};
6use std::{
7 fs::File,
8 io::{Read, Write},
9 path::{Path, PathBuf},
10};
11
12pub type ScalarValueType = f64; pub trait RawData: Sized {
17 fn read_raw(path: impl AsRef<Path>) -> Option<Self>;
29
30 fn write_raw(&self, path: &str) -> Result<(), DataError>;
42}
43
44#[repr(C)]
49#[derive(Deserialize, Serialize, Clone, Copy, Default)]
50pub struct FluxFileHeader {
51 pub n_zone: u32,
53 pub n_fluxes: u32,
55}
56
57#[repr(C)]
62#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
63pub struct RawFlux {
64 pub id_source: u32,
66 pub id_target: u32,
68 pub flux_source_target: f64,
70 pub flux_target_source: f64,
72}
73
74#[derive(Deserialize, Serialize, Clone)]
79pub struct RawDataFlux {
80 pub header: FluxFileHeader,
82 pub fluxes: Vec<RawFlux>,
84}
85
86#[repr(C)]
90#[derive(Deserialize, Serialize, Clone, Copy, Default)]
91pub struct ScalarFileHeader {
92 pub n_zone: u32,
94}
95
96#[repr(C)]
100#[derive(Deserialize, Serialize, Clone, Copy)]
101pub struct RawScalar {
102 pub value: ScalarValueType,
104}
105
106#[derive(Deserialize, Serialize, Clone)]
111pub struct RawDataScalar {
112 pub header: ScalarFileHeader,
114 pub values: Vec<RawScalar>,
116}
117
118#[derive(Deserialize, Serialize, Clone)]
124pub struct RawPhase {
125 pub flow: RawDataFlux,
127
128 pub volume: RawDataScalar,
130
131 pub identifier: PhaseCM,
133}
134
135impl RawPhase {
136 pub fn new_liquid(n_zone: usize, n_fluxes: usize) -> Self {
137 Self::new(n_zone, n_fluxes, PhaseCM::Liquid)
138 }
139 pub fn new_gas(n_zone: usize, n_fluxes: usize) -> Self {
140 Self::new(n_zone, n_fluxes, PhaseCM::Gas)
141 }
142
143 pub fn new(n_zone: usize, n_fluxes: usize, phase: PhaseCM) -> Self {
144 Self {
145 flow: RawDataFlux::new(n_zone, n_fluxes),
146 volume: RawDataScalar::new(n_zone),
147 identifier: phase,
148 }
149 }
150
151 pub fn write(&self, root: impl AsRef<std::path::Path>) -> Result<(String, String), DataError> {
152 let path = PathBuf::from(root.as_ref())
153 .join(CMExportType::Flow(self.identifier).default_filename());
154 self.flow.write_raw(path.to_str().unwrap())?;
155
156 let path = PathBuf::from(root.as_ref())
157 .join(CMExportType::Volume(self.identifier).default_filename());
158 self.volume.write_raw(path.to_str().unwrap())?;
159
160 Ok((
161 CMExportType::Flow(self.identifier).default_filename(),
162 CMExportType::Volume(self.identifier).default_filename(),
163 ))
164 }
165}
166
167impl Default for RawFlux {
168 fn default() -> Self {
169 Self {
170 id_source: 0,
171 id_target: 0,
172 flux_source_target: 0.,
173 flux_target_source: 0.,
174 }
175 }
176}
177
178impl From<ScalarValueType> for RawScalar {
179 #[inline(always)]
180 fn from(value: ScalarValueType) -> Self {
181 Self { value }
182 }
183}
184
185impl RawDataScalar {
186 pub fn new(n_zone: usize) -> Self {
187 Self {
188 header: ScalarFileHeader {
189 n_zone: n_zone.try_into().unwrap(),
190 },
191 values: Vec::with_capacity(n_zone),
192 }
193 }
194}
195
196impl From<Vec<ScalarValueType>> for RawDataScalar {
197 fn from(value: Vec<ScalarValueType>) -> Self {
198 value.as_slice().into()
199 }
200}
201
202impl From<&[ScalarValueType]> for RawDataScalar {
209 fn from(value: &[ScalarValueType]) -> Self {
210 let len: u32 = value.len().try_into().unwrap_or_else(|_| {
211 panic!("Array length is too large to convert into u32");
212 });
213 Self {
214 header: ScalarFileHeader { n_zone: len },
215 values: value.iter().copied().map(Into::into).collect(),
216 }
217 }
218}
219
220impl RawDataFlux {
221 pub fn new(n_zone: usize, n_fluxes: usize) -> Self {
222 Self {
223 header: FluxFileHeader {
224 n_zone: n_zone as u32,
225 n_fluxes: n_fluxes as u32,
226 },
227 fluxes: vec![RawFlux::default(); n_fluxes],
228 }
229 }
230}
231
232impl RawData for RawDataScalar {
233 fn read_raw(path: impl AsRef<std::path::Path>) -> Option<Self> {
234 let mut file = File::open(path).ok()?;
235 let mut buffer = Vec::new();
236 file.read_to_end(&mut buffer).ok()?;
237
238 let mut offset = 0;
239 let header = ScalarFileHeader::from_bytes(&buffer, &mut offset)?;
240
241 let mut values = Vec::new();
242 while offset < buffer.len() {
243 values.push(RawScalar::from_bytes(&buffer, &mut offset)?);
244 }
245
246 Some(RawDataScalar { header, values })
247 }
248
249 fn write_raw(&self, path: &str) -> Result<(), DataError> {
250 let mut file = File::create(Path::new(path))?;
251 let mut buffer = Vec::new();
252
253 self.header.to_bytes(&mut buffer);
254 for value in &self.values {
255 value.to_bytes(&mut buffer);
256 }
257
258 file.write_all(&buffer)?;
259 Ok(())
260 }
261}
262
263impl RawData for RawDataFlux {
264 fn read_raw(path: impl AsRef<std::path::Path>) -> Option<Self> {
265 let mut file = File::open(path).ok()?;
266 let mut buffer = Vec::new();
267 file.read_to_end(&mut buffer).ok()?;
268
269 let mut offset = 0;
270 let header = FluxFileHeader::from_bytes(&buffer, &mut offset)?;
271
272 let mut fluxes = Vec::new();
273 while offset < buffer.len() {
274 fluxes.push(RawFlux::from_bytes(&buffer, &mut offset)?);
275 }
276
277 if fluxes.len() as u32 != header.n_fluxes {
278 return None;
279 }
280
281 Some(RawDataFlux { header, fluxes })
282 }
283
284 fn write_raw(&self, path: &str) -> Result<(), DataError> {
285 let mut file = File::create(Path::new(path))?;
286 let mut buffer = Vec::new();
287 self.header.to_bytes(&mut buffer);
288 for flux in &self.fluxes {
289 flux.to_bytes(&mut buffer);
290 }
291
292 file.write_all(&buffer)?;
293 Ok(())
294 }
295}
296
297pub trait FromBytes: Sized {
298 fn from_bytes(buffer: &[u8], offset: &mut usize) -> Option<Self>;
299}
300
301pub trait ToBytes {
302 fn to_bytes(&self, buffer: &mut Vec<u8>);
303}
304
305impl FromBytes for ScalarFileHeader {
306 fn from_bytes(buffer: &[u8], offset: &mut usize) -> Option<Self> {
307 if *offset + size_of::<u32>() > buffer.len() {
308 return None;
309 }
310 let n_zone = u32::from_le_bytes(
311 buffer[*offset..*offset + size_of::<u32>()]
312 .try_into()
313 .unwrap(),
314 );
315 *offset += size_of::<u32>();
316 Some(ScalarFileHeader { n_zone })
317 }
318}
319
320impl ToBytes for ScalarFileHeader {
321 fn to_bytes(&self, buffer: &mut Vec<u8>) {
322 buffer.extend_from_slice(&self.n_zone.to_le_bytes());
323 }
324}
325
326impl FromBytes for FluxFileHeader {
327 fn from_bytes(buffer: &[u8], offset: &mut usize) -> Option<Self> {
328 if *offset + 2 * size_of::<u32>() > buffer.len() {
329 return None;
330 }
331 let n_zone = u32::from_le_bytes(
332 buffer[*offset..*offset + size_of::<u32>()]
333 .try_into()
334 .unwrap(),
335 );
336 *offset += size_of::<u32>();
337 let n_max = u32::from_le_bytes(
338 buffer[*offset..*offset + size_of::<u32>()]
339 .try_into()
340 .unwrap(),
341 );
342 *offset += size_of::<u32>();
343 Some(FluxFileHeader {
344 n_zone,
345 n_fluxes: n_max,
346 })
347 }
348}
349
350impl ToBytes for FluxFileHeader {
351 fn to_bytes(&self, buffer: &mut Vec<u8>) {
352 buffer.extend_from_slice(&self.n_zone.to_le_bytes());
353 buffer.extend_from_slice(&self.n_fluxes.to_le_bytes());
354 }
355}
356
357impl FromBytes for RawScalar {
358 fn from_bytes(buffer: &[u8], offset: &mut usize) -> Option<Self> {
359 if *offset + size_of::<ScalarValueType>() > buffer.len() {
360 return None;
361 }
362 let value = ScalarValueType::from_le_bytes(
363 buffer[*offset..*offset + size_of::<ScalarValueType>()]
364 .try_into()
365 .unwrap(),
366 );
367 *offset += size_of::<ScalarValueType>();
368 Some(RawScalar { value })
369 }
370}
371
372impl ToBytes for RawScalar {
373 fn to_bytes(&self, buffer: &mut Vec<u8>) {
374 buffer.extend_from_slice(&self.value.to_le_bytes());
375 }
376}
377
378impl FromBytes for RawFlux {
379 fn from_bytes(buffer: &[u8], offset: &mut usize) -> Option<Self> {
380 if *offset + 2 * size_of::<u32>() + 2 * size_of::<f64>() > buffer.len() {
381 return None;
382 }
383 let id_source = u32::from_le_bytes(
384 buffer[*offset..*offset + size_of::<u32>()]
385 .try_into()
386 .unwrap(),
387 );
388 *offset += size_of::<u32>();
389 let id_target = u32::from_le_bytes(
390 buffer[*offset..*offset + size_of::<u32>()]
391 .try_into()
392 .unwrap(),
393 );
394 *offset += size_of::<u32>();
395 let flux_source_target = f64::from_le_bytes(
396 buffer[*offset..*offset + size_of::<f64>()]
397 .try_into()
398 .unwrap(),
399 );
400 *offset += size_of::<f64>();
401 let flux_target_source = f64::from_le_bytes(
402 buffer[*offset..*offset + size_of::<f64>()]
403 .try_into()
404 .unwrap(),
405 );
406 *offset += size_of::<f64>();
407
408 if flux_source_target < 0. || flux_target_source < 0. {
409 return None;
410 }
411
412 Some(RawFlux {
413 id_source,
414 id_target,
415 flux_source_target,
416 flux_target_source,
417 })
418 }
419}
420
421impl ToBytes for RawFlux {
422 fn to_bytes(&self, buffer: &mut Vec<u8>) {
423 buffer.extend_from_slice(&self.id_source.to_le_bytes());
424 buffer.extend_from_slice(&self.id_target.to_le_bytes());
425 buffer.extend_from_slice(&self.flux_source_target.to_le_bytes());
426 buffer.extend_from_slice(&self.flux_target_source.to_le_bytes());
427 }
428}
429
430#[cfg(test)]
431mod tests {
432 use crate::rawdata::{FromBytes, RawData, ToBytes};
433
434 use super::*;
435
436 #[test]
437 fn test_flux_file_header_serialization() {
438 let header = FluxFileHeader {
439 n_zone: 10,
440 n_fluxes: 100,
441 };
442
443 let mut buffer = Vec::new();
444 header.to_bytes(&mut buffer);
445 let mut offset = 0;
446 let deserialized = FluxFileHeader::from_bytes(&buffer, &mut offset).unwrap();
447
448 assert_eq!(header.n_zone, deserialized.n_zone);
449 assert_eq!(header.n_fluxes, deserialized.n_fluxes);
450 }
451
452 #[test]
453 fn test_scalar_file_header_serialization() {
454 let header = ScalarFileHeader { n_zone: 5 };
455
456 let mut buffer = Vec::new();
457 header.to_bytes(&mut buffer);
458 let mut offset = 0;
459 let deserialized = ScalarFileHeader::from_bytes(&buffer, &mut offset).unwrap();
460
461 assert_eq!(header.n_zone, deserialized.n_zone);
462 }
463
464 #[test]
465 fn test_raw_flux_serialization() {
466 let raw_flux = RawFlux {
467 id_source: 1,
468 id_target: 2,
469 flux_source_target: 0.1,
470 flux_target_source: 2.71,
471 };
472
473 let mut buffer = Vec::new();
474 raw_flux.to_bytes(&mut buffer);
475 let mut offset = 0;
476 let deserialized = RawFlux::from_bytes(&buffer, &mut offset).unwrap();
477
478 assert_eq!(raw_flux.id_source, deserialized.id_source);
479 assert_eq!(raw_flux.id_target, deserialized.id_target);
480 assert_eq!(raw_flux.flux_source_target, deserialized.flux_source_target);
481 assert_eq!(raw_flux.flux_target_source, deserialized.flux_target_source);
482 }
483
484 #[test]
485 fn test_raw_scalar_serialization() {
486 let raw_scalar = RawScalar { value: 0.1 };
487
488 let mut buffer = Vec::new();
489 raw_scalar.to_bytes(&mut buffer);
490 let mut offset = 0;
491 let deserialized = RawScalar::from_bytes(&buffer, &mut offset).unwrap();
492
493 assert_eq!(raw_scalar.value, deserialized.value);
494 }
495
496 #[test]
497 fn test_raw_data_scalar_serialization() {
498 let raw_data_scalar = RawDataScalar {
499 header: ScalarFileHeader { n_zone: 5 },
500 values: vec![RawScalar { value: 0.1 }, RawScalar { value: 2.71 }],
501 };
502
503 let mut buffer = Vec::new();
504 raw_data_scalar.header.to_bytes(&mut buffer);
505 for value in &raw_data_scalar.values {
506 value.to_bytes(&mut buffer);
507 }
508
509 let mut offset = 0;
510 let header = ScalarFileHeader::from_bytes(&buffer, &mut offset).unwrap();
511 let mut values = Vec::new();
512 while offset < buffer.len() {
513 values.push(RawScalar::from_bytes(&buffer, &mut offset).unwrap());
514 }
515
516 assert_eq!(raw_data_scalar.header.n_zone, header.n_zone);
517 assert_eq!(raw_data_scalar.values.len(), values.len());
518 assert_eq!(raw_data_scalar.values[0].value, values[0].value);
519 assert_eq!(raw_data_scalar.values[1].value, values[1].value);
520 }
521
522 #[test]
523 fn test_raw_data_flux_serialization() {
524 let raw_data_flux = RawDataFlux {
525 header: FluxFileHeader {
526 n_zone: 10,
527 n_fluxes: 100,
528 },
529 fluxes: vec![RawFlux {
530 id_source: 1,
531 id_target: 2,
532 flux_source_target: 0.1,
533 flux_target_source: 2.71,
534 }],
535 };
536
537 let mut buffer = Vec::new();
538 raw_data_flux.header.to_bytes(&mut buffer);
539 for flux in &raw_data_flux.fluxes {
540 flux.to_bytes(&mut buffer);
541 }
542
543 let mut offset = 0;
544 let header = FluxFileHeader::from_bytes(&buffer, &mut offset).unwrap();
545 let mut fluxes = Vec::new();
546 while offset < buffer.len() {
547 fluxes.push(RawFlux::from_bytes(&buffer, &mut offset).unwrap());
548 }
549
550 assert_eq!(raw_data_flux.header.n_zone, header.n_zone);
551 assert_eq!(raw_data_flux.header.n_fluxes, header.n_fluxes);
552 assert_eq!(raw_data_flux.fluxes.len(), fluxes.len());
553 assert_eq!(raw_data_flux.fluxes[0].id_source, fluxes[0].id_source);
554 assert_eq!(raw_data_flux.fluxes[0].id_target, fluxes[0].id_target);
555 assert_eq!(
556 raw_data_flux.fluxes[0].flux_source_target,
557 fluxes[0].flux_source_target
558 );
559 assert_eq!(
560 raw_data_flux.fluxes[0].flux_target_source,
561 fluxes[0].flux_target_source
562 );
563 }
564
565 #[test]
566 fn test_raw_data_trait() {
567 let raw_data_scalar = RawDataScalar {
568 header: ScalarFileHeader { n_zone: 5 },
569 values: vec![RawScalar { value: 0.1 }, RawScalar { value: 2.71 }],
570 };
571
572 let path = "./test.raw";
573 raw_data_scalar.write_raw(path).unwrap();
574 let deserialized = RawDataScalar::read_raw(path).unwrap();
575
576 assert_eq!(raw_data_scalar.header.n_zone, deserialized.header.n_zone);
577 assert_eq!(raw_data_scalar.values.len(), deserialized.values.len());
578 assert_eq!(
579 raw_data_scalar.values[0].value,
580 deserialized.values[0].value
581 );
582 assert_eq!(
583 raw_data_scalar.values[1].value,
584 deserialized.values[1].value
585 );
586
587 std::fs::remove_file(path).unwrap();
588 }
589
590 #[test]
591 fn test_raw_data_flux_write() {
592 let raw_data_flux = RawDataFlux {
593 header: FluxFileHeader {
594 n_zone: 10,
595 n_fluxes: 2,
596 },
597 fluxes: vec![
598 RawFlux {
599 id_source: 1,
600 id_target: 2,
601 flux_source_target: 0.1,
602 flux_target_source: 2.71,
603 },
604 RawFlux {
605 id_source: 1,
606 id_target: 2,
607 flux_source_target: 0.1,
608 flux_target_source: 2.71,
609 },
610 ],
611 };
612
613 let path = "./tes2t.raw";
614 raw_data_flux.write_raw(path).unwrap();
615 let deserialized = RawDataFlux::read_raw(path).unwrap();
616
617 assert_eq!(raw_data_flux.header.n_zone, deserialized.header.n_zone);
618 assert_eq!(raw_data_flux.header.n_fluxes, deserialized.header.n_fluxes);
619 assert_eq!(raw_data_flux.fluxes.len(), deserialized.fluxes.len());
620 assert_eq!(
621 raw_data_flux.fluxes[0].id_source,
622 deserialized.fluxes[0].id_source
623 );
624 assert_eq!(
625 raw_data_flux.fluxes[0].id_target,
626 deserialized.fluxes[0].id_target
627 );
628 assert_eq!(
629 raw_data_flux.fluxes[0].flux_source_target,
630 deserialized.fluxes[0].flux_source_target
631 );
632 assert_eq!(
633 raw_data_flux.fluxes[0].flux_target_source,
634 deserialized.fluxes[0].flux_target_source
635 );
636
637 std::fs::remove_file(path).unwrap();
638 }
639}