1use std::collections::HashMap;
2
3use anyhow::{anyhow, Result};
4use serde::{Deserialize, Serialize};
5
6#[derive(Serialize, Deserialize, Debug)]
8pub struct Store {
9 inner: HashMap<String, Material>,
10}
11
12#[derive(Serialize, Deserialize, Debug)]
14pub struct Material {
15 pub shelf: String,
16 pub book: String,
17 pub page: String,
18 pub comments: String,
19 pub references: String,
20 pub data: Vec<DispersionData>,
21}
22
23#[derive(Debug)]
24enum DataType {
25 Real,
26 Imaginary,
27 Both,
28}
29
30#[derive(Serialize, Deserialize, Debug)]
32pub enum DispersionData {
33 TabulatedK {
34 data: Vec<[f64; 2]>,
35 },
36 TabulatedN {
37 data: Vec<[f64; 2]>,
38 },
39 TabulatedNK {
40 data: Vec<[f64; 3]>,
41 },
42
43 Formula1 {
45 wavelength_range: [f64; 2],
46 c: Vec<f64>,
47 },
48
49 Formula2 {
51 wavelength_range: [f64; 2],
52 c: Vec<f64>,
53 },
54
55 Formula3 {
57 wavelength_range: [f64; 2],
58 c: Vec<f64>,
59 },
60
61 Formula4 {
63 wavelength_range: [f64; 2],
64 c: Vec<f64>,
65 },
66
67 Formula5 {
69 wavelength_range: [f64; 2],
70 c: Vec<f64>,
71 },
72
73 Formula6 {
75 wavelength_range: [f64; 2],
76 c: Vec<f64>,
77 },
78
79 Formula7 {
81 wavelength_range: [f64; 2],
82 c: Vec<f64>,
83 },
84
85 Formula8 {
87 wavelength_range: [f64; 2],
88 c: Vec<f64>,
89 },
90
91 Formula9 {
93 wavelength_range: [f64; 2],
94 c: Vec<f64>,
95 },
96}
97
98impl Store {
99 pub fn new(database: HashMap<String, Material>) -> Self {
100 Store { inner: database }
101 }
102
103 pub fn get(&self, key: &str) -> Option<&Material> {
111 self.inner.get(key)
112 }
113
114 pub fn insert(&mut self, key: String, material: Material) {
120 self.inner.insert(key, material);
121 }
122
123 pub fn keys(&self) -> impl Iterator<Item = &String> {
125 self.inner.keys()
126 }
127
128 pub fn retain(&mut self, predicate: impl FnMut(&String, &mut Material) -> bool) {
134 self.inner.retain(predicate);
135 }
136
137 pub fn remove(&mut self, key: &str) -> Option<Material> {
142 self.inner.remove(key)
143 }
144
145 pub fn remove_many(&mut self, keys: &[String]) {
150 for key in keys {
151 self.inner.remove(key);
152 }
153 }
154}
155
156impl Default for Store {
157 fn default() -> Self {
158 let database = HashMap::new();
159 Self::new(database)
160 }
161}
162
163impl Material {
164 pub fn n(&self, wavelength: f64) -> Result<f64> {
179 let data = self
180 .data
181 .iter()
182 .find(|d| matches!(d.data_type(), DataType::Real | DataType::Both));
183 let (n, _) = match data {
184 Some(data) => data.interpolate(wavelength)?,
185 None => return Err(anyhow!("No real data found for item.")),
186 };
187 Ok(n)
188 }
189
190 pub fn k(&self, wavelength: f64) -> Result<Option<f64>> {
204 let data = self
205 .data
206 .iter()
207 .find(|d| matches!(d.data_type(), DataType::Imaginary | DataType::Both));
208 match data {
209 Some(data) => Ok(data.interpolate(wavelength)?.1),
210 None => Ok(None),
211 }
212 }
213}
214
215impl DispersionData {
216 pub fn interpolate(&self, wavelength: f64) -> Result<(f64, Option<f64>)> {
230 let n: f64 = match &self {
231 Self::Formula1 {
232 wavelength_range,
233 c,
234 } => {
235 if wavelength < wavelength_range[0] || wavelength > wavelength_range[1] {
237 return Err(anyhow!(
238 "The requested wavelength is outside the range of the available dispersion data."
239 ));
240 }
241 let mut sum = 0.0;
242 for i in (1..c.len()).step_by(2) {
243 sum += c[i] * wavelength.powi(2) / (wavelength.powi(2) - c[i + 1].powi(2));
244 }
245 (1.0 + c[0] + sum).sqrt()
246 }
247 Self::Formula2 {
248 wavelength_range,
249 c,
250 } => {
251 if wavelength < wavelength_range[0] || wavelength > wavelength_range[1] {
253 return Err(anyhow!(
254 "The requested wavelength is outside the range of the available dispersion data."
255 ));
256 }
257 let mut sum = 0.0;
258 for i in (1..c.len()).step_by(2) {
259 sum += c[i] * wavelength.powi(2) / (wavelength.powi(2) - c[i + 1]);
260 }
261 (1.0 + c[0] + sum).sqrt()
262 }
263 Self::Formula3 {
264 wavelength_range,
265 c,
266 } => {
267 if wavelength < wavelength_range[0] || wavelength > wavelength_range[1] {
269 return Err(anyhow!(
270 "The requested wavelength is outside the range of the available dispersion data."
271 ));
272 }
273
274 let mut sum = 0.0;
275 for i in (1..c.len()).step_by(2) {
276 sum += c[i] * wavelength.powf(c[i + 1]);
277 }
278 (c[0] + sum).sqrt()
279 }
280 Self::Formula4 {
281 wavelength_range,
282 c,
283 } => {
284 if wavelength < wavelength_range[0] || wavelength > wavelength_range[1] {
286 return Err(anyhow!(
287 "The requested wavelength is outside the range of the available dispersion data."
288 ));
289 }
290
291 let mut sum = 0.0;
292 for i in (1..c.len()).step_by(4) {
293 if i <= 9 {
295 sum += c[i] * wavelength.powf(c[i + 1])
296 / (wavelength.powi(2) - c[i + 2].powf(c[i + 3]));
297 } else {
298 sum += c[i] * wavelength.powf(c[i + 1]);
299 }
300 }
301 (c[0] + sum).sqrt()
302 }
303 Self::Formula5 {
304 wavelength_range,
305 c,
306 } => {
307 if wavelength < wavelength_range[0] || wavelength > wavelength_range[1] {
309 return Err(anyhow!(
310 "The requested wavelength is outside the range of the available dispersion data."
311 ));
312 }
313
314 let mut sum = 0.0;
315 for i in (1..c.len()).step_by(2) {
316 sum += c[i] * wavelength.powf(c[i + 1]);
317 }
318 c[0] + sum
319 }
320 Self::Formula6 {
321 wavelength_range,
322 c,
323 } => {
324 if wavelength < wavelength_range[0] || wavelength > wavelength_range[1] {
326 return Err(anyhow!(
327 "The requested wavelength is outside the range of the available dispersion data."
328 ));
329 }
330
331 let mut sum = 0.0;
332 for i in (1..c.len()).step_by(2) {
333 sum += c[i] / (c[i + 1] - wavelength.powi(-2));
334 }
335 1.0 + c[0] + sum
336 }
337 Self::Formula7 {
338 wavelength_range,
339 c,
340 } => {
341 if wavelength < wavelength_range[0] || wavelength > wavelength_range[1] {
343 return Err(anyhow!(
344 "The requested wavelength is outside the range of the available dispersion data."
345 ));
346 }
347 let mut sum = 0.0;
348 for i in (3..c.len()).step_by(2) {
349 sum += c[i] * wavelength.powi(i as i32 - 1);
350 }
351 c[0] + c[1] / (wavelength.powi(2) - 0.028)
352 + c[2] / (wavelength.powi(2) - 0.028).powi(2)
353 + sum
354 }
355 Self::Formula8 {
356 wavelength_range,
357 c,
358 } => {
359 if wavelength < wavelength_range[0] || wavelength > wavelength_range[1] {
361 return Err(anyhow!(
362 "The requested wavelength is outside the range of the available dispersion data."
363 ));
364 }
365
366 let sum = c[0]
367 + c[1] * wavelength.powi(2) / (wavelength.powi(2) - c[2])
368 + c[3] * wavelength.powi(2);
369 println!("sum: {}", sum);
370 ((2.0 * sum + 1.0) / (1.0 - sum)).sqrt()
371 }
372 Self::Formula9 {
373 wavelength_range,
374 c,
375 } => {
376 if wavelength < wavelength_range[0] || wavelength > wavelength_range[1] {
378 return Err(anyhow!(
379 "The requested wavelength is outside the range of the available dispersion data."
380 ));
381 }
382
383 (c[0]
384 + c[1] / (wavelength.powi(2) - c[2])
385 + c[3] * (wavelength - c[4]) / ((wavelength - c[4]).powi(2) + c[5]))
386 .sqrt()
387 }
388 _ => {
389 return Err(anyhow!("Tabulated dispersion data are not implemented."));
390 }
391 };
392
393 Ok((n, None))
394 }
395
396 fn data_type(&self) -> DataType {
412 match self {
413 self::DispersionData::TabulatedK { data: _ } => DataType::Imaginary,
414 self::DispersionData::TabulatedN { data: _ } => DataType::Real,
415 self::DispersionData::TabulatedNK { data: _ } => DataType::Both,
416 _ => DataType::Real,
417 }
418 }
419}
420
421#[cfg(test)]
422mod test {
423 use super::*;
424 use approx::assert_abs_diff_eq;
425
426 #[test]
427 fn test_interpolate_formula_1() {
428 let data = DispersionData::Formula1 {
430 wavelength_range: [0.210, 0.757],
431 c: vec![0.0, 0.496, 0.071, 0.190, 0.134],
432 };
433 let (n, k) = data.interpolate(0.5876).unwrap();
434 assert_abs_diff_eq!(n, 1.3053, epsilon = 1e-4);
435 assert!(k.is_none());
436 }
437
438 #[test]
439 fn test_interpolate_formula_2() {
440 let data = DispersionData::Formula2 {
442 wavelength_range: [0.3, 2.5],
443 c: vec![
444 0.0,
445 1.03961212,
446 0.00600069867,
447 0.231792344,
448 0.0200179144,
449 1.01046945,
450 103.560653,
451 ],
452 };
453
454 let (n, k) = data.interpolate(0.5876).unwrap();
455 assert_abs_diff_eq!(n, 1.51680, epsilon = 1e-5);
456 assert!(k.is_none());
457 }
458
459 #[test]
460 fn test_interpolate_formula_3() {
461 let data = DispersionData::Formula3 {
463 wavelength_range: [0.365, 0.9],
464 c: vec![
465 2.730459,
466 -0.01063385,
467 2.0,
468 0.01942756,
469 -2.0,
470 0.0008209873,
471 -4.0,
472 -5.210457e-05,
473 -6.0,
474 4.447534e-06,
475 -8.0,
476 ],
477 };
478 let (n, k) = data.interpolate(0.5876).unwrap();
479 assert_abs_diff_eq!(n, 1.6700, epsilon = 1e-4);
480 assert!(k.is_none());
481 }
482
483 #[test]
484 fn test_interpolate_formula_4() {
485 let data = DispersionData::Formula4 {
487 wavelength_range: [0.3, 1.06],
488 c: vec![2.1823, 0.0125, 0.0, 0.0300, 1.0, 0.0, 0.0, 0.0, 1.0],
489 };
490 let (n, k) = data.interpolate(0.5876).unwrap();
491 assert_abs_diff_eq!(n, 1.4906, epsilon = 1e-4);
492 assert!(k.is_none());
493 }
494
495 #[test]
496 fn test_interpolate_formula_5() {
497 let data = DispersionData::Formula5 {
499 wavelength_range: [0.31, 1.55],
500 c: vec![1.502787, 455872.4E-8, -2.0, 9.844856E-5, -4.0],
501 };
502 let (n, k) = data.interpolate(0.5876).unwrap();
503 assert_abs_diff_eq!(n, 1.5168, epsilon = 1e-4);
504 assert!(k.is_none());
505 }
506
507 #[test]
508 fn test_interpolate_formula_6() {
509 let data = DispersionData::Formula6 {
511 wavelength_range: [0.168, 1.6945],
512 c: vec![0.0, 0.0148956, 180.7, 0.0049037, 92.0],
513 };
514 let (n, k) = data.interpolate(0.5876).unwrap();
515 assert_abs_diff_eq!(n, 1.00013881, epsilon = 1e-8);
516 assert!(k.is_none());
517 }
518
519 #[test]
520 fn test_interpolate_formula_7() {
521 let data = DispersionData::Formula7 {
523 wavelength_range: [2.4373, 25.0],
524 c: vec![3.41983, 0.159906, -0.123109, 1.26878E-6, -1.95104E-9],
525 };
526 let (n, k) = data.interpolate(2.4373).unwrap();
527 assert_abs_diff_eq!(n, 3.4434, epsilon = 1e-4);
528 assert!(k.is_none());
529 }
530
531 #[test]
532 fn test_interpolate_formula_8() {
533 let data = DispersionData::Formula8 {
535 wavelength_range: [0.43, 0.66],
536 c: vec![0.47856, 0.07858, 0.08277, -0.00881],
537 };
538 let (n, k) = data.interpolate(0.5876).unwrap();
539 assert_abs_diff_eq!(n, 2.2636, epsilon = 1e-4);
540 assert!(k.is_none());
541 }
542
543 #[test]
544 fn test_interpolate_formula_9() {
545 let data = DispersionData::Formula9 {
547 wavelength_range: [0.3, 1.06],
548 c: vec![2.51527, 0.0240, 0.0300, 0.020, 1.52, 0.8771],
549 };
550 let (n, k) = data.interpolate(0.5876).unwrap();
551 assert_abs_diff_eq!(n, 1.6065, epsilon = 1e-4);
552 assert!(k.is_none());
553 }
554}