1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
mod fld_file_loader;

pub use fld_file_loader::{DataCoordinates, DataDimensionality, FileData};
use std::collections::BTreeMap;

// pub fn load_b1_file(path_and_name: &str) -> FileData {
//     match FileData::load_file(path_and_name, 1) {
//         Ok(file_data) => file_data,
//         Err(msg) => panic!("Unable to read file! \n {}", msg),
//     }
// }

// pub fn load_complex_h_file(path_and_name: &str) -> FileData {
//     match FileData::load_file(path_and_name, 6) {
//         Ok(file_data) => file_data,
//         Err(msg) => panic!("Unable to read file! \n {}", msg),
//     }
// }

// pub fn load_complex_h_file_group(paths_and_names: &[&str]) -> Vec<FileData> {
//     paths_and_names
//         .iter()
//         .map(|pn| load_complex_h_file(&pn))
//         .collect()
// }

#[derive(Clone, Debug)]
pub struct B1Data {
    pub file_name: String,
    pub geo_keys: Vec<[i32; 3]>,
    pub b1_vals: Vec<f64>,
}

impl B1Data {
    pub fn from_file(path_and_name: String) -> Self {
        let file_data = match FileData::load_file(path_and_name, 1) {
            Ok(fd) => fd,
            Err(msg) => panic!("{}", msg),
        };

        let file_name = file_data.file_name;
        let geo_keys = file_data
            .geo_points
            .iter()
            .map(|geo_floats| gen_geo_key(geo_floats))
            .collect();

        let b1_vals = file_data.fld_points.iter().flatten().copied().collect();

        Self {
            file_name,
            geo_keys,
            b1_vals,
        }
    }
}

#[derive(Clone, Debug)]
pub struct HDataGroup {
    pub file_names: Vec<String>,
    pub geo_keys: Vec<[i32; 3]>,
    pub ch_h_vals: Vec<Vec<[f64; 6]>>,
    pub num_points: usize,
}

impl HDataGroup {
    pub fn from_files(paths_and_names: Vec<String>, assert_geo_equality: bool) -> Self {
        let file_datas: Vec<FileData> = paths_and_names
            .iter()
            .cloned()
            .map(|pn| match FileData::load_file(pn, 6) {
                Ok(fd) => fd,
                Err(msg) => panic!("{}", msg),
            })
            .collect();

        let num_points = file_datas[0].num_points;
        for fd in file_datas.iter().skip(1) {
            assert_eq!(
                num_points, fd.num_points,
                "H files do not have the same number of points!"
            );
        }

        let file_names = file_datas.iter().map(|fd| fd.file_name.clone()).collect();
        let geo_keys: Vec<[i32; 3]> = file_datas[0]
            .geo_points
            .iter()
            .map(|geo_floats| gen_geo_key(geo_floats))
            .collect();

        if assert_geo_equality {
            for fd in file_datas.iter().skip(1) {
                for (key, geo_pt) in geo_keys.iter().zip(fd.geo_points.iter()) {
                    assert_eq!(
                        key,
                        &gen_geo_key(geo_pt),
                        "H files do not cover the same geometry!"
                    );
                }
            }
        }

        let ch_h_vals = file_datas
            .iter()
            .map(|fd| {
                fd.fld_points
                    .iter()
                    .map(|fld_pt| {
                        [
                            fld_pt[0], fld_pt[1], fld_pt[2], fld_pt[3], fld_pt[4], fld_pt[5],
                        ]
                    })
                    .collect()
            })
            .collect();

        Self {
            file_names,
            geo_keys,
            ch_h_vals,
            num_points,
        }
    }

    pub fn single_dir_points(&self, direction: u8) -> Vec<Vec<[f64; 2]>> {
        assert!(direction < 3, "Direction must be 0, 1, or 2");

        let d_re = (direction * 2) as usize;
        let d_im = (direction * 2 + 1) as usize;

        self.ch_h_vals
            .iter()
            .map(|ch| ch.iter().map(|point| [point[d_re], point[d_im]]).collect())
            .collect()
    }

    pub fn double_dir_points(&self, directions: [u8; 2]) -> Vec<Vec<[f64; 4]>> {
        assert!(directions[0] < 3, "First Direction must be 0, 1, or 2");
        assert!(directions[1] < 3, "Second Direction must be 0, 1, or 2");
        assert_ne!(
            directions[0], directions[1],
            "First and Second Direction cannot be the same value!"
        );

        let d1_re = (directions[0] * 2) as usize;
        let d1_im = (directions[0] * 2 + 1) as usize;

        let d2_re = (directions[1] * 2) as usize;
        let d2_im = (directions[1] * 2 + 1) as usize;

        self.ch_h_vals
            .iter()
            .map(|ch| {
                ch.iter()
                    .map(|point| [point[d1_re], point[d1_im], point[d2_re], point[d2_im]])
                    .collect()
            })
            .collect()
    }

    pub fn grouped_double_dir_data_points(
        &self,
        directions: [u8; 2],
        grouping_axis: usize,
    ) -> Vec<Vec<Vec<[f64; 4]>>> {
        assert!(directions[0] < 3, "First Direction must be 0, 1, or 2");
        assert!(directions[1] < 3, "Second Direction must be 0, 1, or 2");
        assert_ne!(
            directions[0], directions[1],
            "First and Second Direction cannot be the same value!"
        );

        let d1_re = (directions[0] * 2) as usize;
        let d1_im = (directions[0] * 2 + 1) as usize;

        let d2_re = (directions[1] * 2) as usize;
        let d2_im = (directions[1] * 2 + 1) as usize;

        assert!(grouping_axis < 3, "Grouping Axis must be 0, 1, or 2!");
        let axis = grouping_axis as usize;

        // collect all relevant keys keeping track of how many of each key there are
        let mut axis_geo_keys: BTreeMap<i32, usize> = BTreeMap::new();
        for geo_key in &self.geo_keys {
            let axis_key = geo_key[axis];
            let num_points = axis_geo_keys.entry(axis_key).or_insert(0);
            *num_points += 1;
        }

        // for each channel, collect keys into their relevant groups
        let num_channels = self.ch_h_vals.len();
        let num_unique_axis_dims = axis_geo_keys.len();
        let mut ch_geo_pts: Vec<Vec<Vec<[f64; 4]>>> = Vec::with_capacity(num_channels);

        for ch in 0..num_channels {
            ch_geo_pts.push(Vec::with_capacity(num_unique_axis_dims));

            for (group_index, (axis_key, num_points)) in axis_geo_keys.iter().enumerate() {
                ch_geo_pts[ch].push(Vec::with_capacity(*num_points));

                for (h_pt, geo_key) in self.ch_h_vals[ch].iter().zip(&self.geo_keys) {
                    if geo_key[axis] == *axis_key {
                        ch_geo_pts[ch][group_index].push([
                            h_pt[d1_re],
                            h_pt[d1_im],
                            h_pt[d2_re],
                            h_pt[d2_im],
                        ]);
                    }
                }
            }
        }

        ch_geo_pts
    }
}

fn gen_geo_key(geo_floats: &[f64; 3]) -> [i32; 3] {
    [
        (geo_floats[0] * 1000.0) as i32,
        (geo_floats[1] * 1000.0) as i32,
        (geo_floats[2] * 1000.0) as i32,
    ]
}