Skip to content

Commit

Permalink
crystal calculator somehow finished
Browse files Browse the repository at this point in the history
  • Loading branch information
trappitsch committed Mar 15, 2024
1 parent f1cc3b2 commit 4ec2927
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 59 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target
/dist
.idea/
52 changes: 40 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "eframe_template"
name = "tisa_xtal_calculator"
version = "0.1.0"
authors = ["Emil Ernerfeldt <[email protected]>"]
authors = ["Reto Trappitsch <[email protected]>"]
edition = "2021"
rust-version = "1.72"

Expand All @@ -18,6 +18,7 @@ log = "0.4"

# You only need serde if you want app persistence:
serde = { version = "1", features = ["derive"] }
enterpolation = "0.2.1"

# native:
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
Expand Down
4 changes: 2 additions & 2 deletions assets/sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ var cacheName = 'egui-template-pwa';
var filesToCache = [
'./',
'./index.html',
'./eframe_template.js',
'./eframe_template_bg.wasm',
'./tisa_xtal_calculator.js',
'./tisa_xtal_calculator_bg.wasm',
];

/* Start the service worker and cache all of the app's content */
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<head>
<!-- change this to your project name -->
<title>eframe template</title>
<title>Ti:Sapphire Harmonic Generator Crystal Calculator</title>

<!-- config for our rust wasm binary. go to https://trunkrs.dev/assets/#rust for more customization -->
<link data-trunk rel="rust" data-wasm-opt="2" />
Expand Down
137 changes: 99 additions & 38 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
use egui::RichText;

use crate::{calculate_angle_walkoff, Harmonic};

// #[derive(PartialEq)]
// #[derive(serde::Deserialize, serde::Serialize)]
// enum Harmonic { Second, Third }

/// We derive Deserialize/Serialize so we can persist app state on shutdown.
#[derive(serde::Deserialize, serde::Serialize)]
#[serde(default)] // if we add new fields, give them default values when deserializing old state
pub struct TemplateApp {
// Example stuff:
label: String,
pub struct XtalCalculatorApp {
wavelength: f32,
harmonic: Harmonic,
#[serde(skip)] //
crystal: String,
angle: f32,
walkoff: f32,

#[serde(skip)] // This how you opt-out of serialization of a field
value: f32,
}

impl Default for TemplateApp {
impl Default for XtalCalculatorApp {
fn default() -> Self {
Self {
// Example stuff:
label: "Hello World!".to_owned(),
value: 2.7,
wavelength: 800.0,
harmonic: Harmonic::Second,
crystal: "".to_string(),
angle: 0.0,
walkoff: 0.0,
}
}
}

impl TemplateApp {
impl XtalCalculatorApp {
/// Called once before the first frame.
pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
// This is also where you can customize the look and feel of egui using
Expand All @@ -35,12 +47,7 @@ impl TemplateApp {
}
}

impl eframe::App for TemplateApp {
/// Called by the frame work to save state before shutdown.
fn save(&mut self, storage: &mut dyn eframe::Storage) {
eframe::set_value(storage, eframe::APP_KEY, self);
}

impl eframe::App for XtalCalculatorApp {
/// Called each time the UI needs repainting, which may be many times per second.
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
// Put your widgets into a `SidePanel`, `TopBottomPanel`, `CentralPanel`, `Window` or `Area`.
Expand All @@ -50,50 +57,82 @@ impl eframe::App for TemplateApp {
// The top panel is often a good place for a menu bar:

egui::menu::bar(ui, |ui| {
// NOTE: no File->Quit on web pages!
let is_web = cfg!(target_arch = "wasm32");
if !is_web {
ui.menu_button("File", |ui| {
if ui.button("Quit").clicked() {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
});
ui.add_space(16.0);
}

egui::widgets::global_dark_light_mode_buttons(ui);
});
});

egui::CentralPanel::default().show(ctx, |ui| {
// The central panel the region left after adding TopPanel's and SidePanel's
ui.heading("eframe template");
ui.heading(RichText::new("Ti:Sapphire Harmonic Generation Crystal Calculator").strong());
ui.add_space(VERTICAL_SPACE);

ui.label(INTRO_MESSAGE);
ui.add_space(VERTICAL_SPACE);

ui.collapsing("Usage", |ui| {
ui.label(USAGE_MESSAGE);
});
ui.add_space(VERTICAL_SPACE);

ui.horizontal(|ui| {
ui.label("Write something: ");
ui.text_edit_singleline(&mut self.label);
ui.label("Wavelength: ");
});

ui.add(egui::Slider::new(&mut self.value, 0.0..=10.0).text("value"));
if ui.button("Increment").clicked() {
self.value += 1.0;
}
let wavelength_slider = egui::Slider::new(&mut self.wavelength, 700.0..=1000.0)
.drag_value_speed(1.0)
.smallest_positive(1.0)
.suffix("nm");
ui.add(wavelength_slider);
ui.add_space(VERTICAL_SPACE);

ui.label("Select Harmonic: ");


ui.horizontal(|ui| {
ui.radio_value(&mut self.harmonic, Harmonic::Second, "Second");
ui.radio_value(&mut self.harmonic, Harmonic::Third, "Third");
});

ui.add_space(VERTICAL_SPACE);
ui.separator();
ui.add_space(VERTICAL_SPACE);

(self.angle, self.walkoff) = calculate_angle_walkoff(self.wavelength, &self.harmonic);

ui.label(RichText::new("Results").strong().size(14.0));
ui.add_space(VERTICAL_SPACE);

ui.horizontal(|ui| {
ui.label("Crystal: ");
ui.label(which_crystal(&self.harmonic));
});
ui.horizontal(|ui| {
ui.label("Angle: ");
ui.label(format!("{:.2}°", self.angle));
});
ui.horizontal(|ui| {
ui.label("Walk-off: ");
ui.label(format!("{:.2}mrad", self.walkoff));
});

ui.add(egui::github_link_file!(
"https://github.com/emilk/eframe_template/blob/master/",
"Source code."
));

ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| {
powered_by_egui_and_eframe(ui);
ui.hyperlink_to("Source code.",
"https://github.com/RIMS-Code/crystal_angle",
);
egui::warn_if_debug_build(ui);
});
});
}

/// Called by the framework to save state before shutdown.
fn save(&mut self, storage: &mut dyn eframe::Storage) {
eframe::set_value(storage, eframe::APP_KEY, self);
}
}


fn powered_by_egui_and_eframe(ui: &mut egui::Ui) {
ui.horizontal(|ui| {
ui.spacing_mut().item_spacing.x = 0.0;
Expand All @@ -107,3 +146,25 @@ fn powered_by_egui_and_eframe(ui: &mut egui::Ui) {
ui.label(".");
});
}

// Constants to configure the app
const INTRO_MESSAGE: &str = "This small app calculates crystal angles and walk-off angles \
for second and third harmonic generation with Ti:Sapphire lasers.\n
The following assumptions are made:\n
- LBO crystal for second harmonic generation\n\
- BBO crystal for third harmonic generation";

const USAGE_MESSAGE: &str = "Enter the wavelength in nanometers by either dragging the slider \
to the preferred value or by clicking on the box to the right of the slider and enter the value \
You can also click and drag on the box.\n
Next select from the radio buttons if you want to generate a second or third harmonic.";

const VERTICAL_SPACE: f32 = 12.0;


fn which_crystal(harmonic: &Harmonic) -> &'static str {
match harmonic {
Harmonic::Second => "LBO",
Harmonic::Third => "BBO",
}
}
62 changes: 61 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,64 @@
#![warn(clippy::all, rust_2018_idioms)]

mod app;
pub use app::TemplateApp;

pub use app::XtalCalculatorApp;

use enterpolation::linear::Linear;
use enterpolation::Generator;

#[derive(PartialEq)]
#[derive(serde::Deserialize, serde::Serialize)]
pub enum Harmonic { Second, Third }

struct CrystalData {
wavelengths: Vec<f32>,
angles: Vec<f32>,
walkoffs: Vec<f32>,
}




pub fn calculate_angle_walkoff(wavelength: f32, harmonic: &Harmonic) -> (f32, f32) {

let second_harmonic_lbo: CrystalData = CrystalData {
wavelengths: vec![
700.0, 710.0, 720.0, 730.0, 740.0, 750.0, 760.0, 770.0, 780.0, 790.0, 800.0, 810.0, 820.0, 830.0, 840.0, 850.0, 860.0, 870.0, 880.0, 890.0, 900.0, 910.0, 920.0, 930.0, 940.0, 950.0, 960.0, 970.0, 980.0, 990.0, 1000.0,
],
angles: vec![
43.4, 42.0, 40.7, 39.4, 38.2, 37.0, 35.9, 34.7, 33.7, 32.6, 31.6, 30.7, 29.7, 28.8, 27.9, 27.0, 26.1, 25.3, 24.4, 23.6, 22.8, 22.0, 21.3, 20.5, 19.8, 19.0, 18.3, 17.6, 16.9, 16.2, 15.6,
],
walkoffs: vec![
18.83, 18.71, 18.55, 18.36, 18.15, 17.91, 17.66, 17.38, 17.1, 16.79, 16.48, 16.16, 15.83, 15.49, 15.15, 14.8, 14.44, 14.08, 13.72, 13.36, 12.99, 12.62, 12.25, 11.88, 11.51, 11.14, 10.77, 10.39, 10.02, 9.65, 9.27,
],
};

let third_harmonic_bbo: CrystalData = CrystalData {
wavelengths: vec![
700.0, 710.0, 720.0, 730.0, 740.0, 750.0, 760.0, 770.0, 780.0, 790.0, 800.0, 810.0, 820.0, 830.0, 840.0, 850.0, 860.0, 870.0, 880.0, 890.0, 900.0, 910.0, 920.0, 930.0, 940.0, 950.0, 960.0, 970.0, 980.0, 990.0, 1000.0,
],
angles: vec![
53.3, 53.0, 51.8, 50.7, 49.6, 48.6, 47.7, 46.8, 45.9, 45.1, 44.3, 43.5, 42.8, 42.1, 41.5, 40.8, 40.2, 39.6, 39.1, 38.5, 38.0, 37.5, 37.0, 36.5, 36.0, 35.6, 35.2, 34.7, 34.3, 33.9, 33.5
],
walkoffs: vec![
85.81, 86.52, 87.01, 87.32, 87.48, 87.52, 87.45, 87.3, 87.06, 86.77, 86.42, 86.03, 85.6, 85.14, 84.66, 84.15, 83.62, 83.09, 82.54, 81.98, 81.41, 80.84, 80.27, 79.7, 79.12, 78.55, 77.98, 77.41, 76.85, 76.29, 75.73
],
};

let (wl_dat, ang_dat, wo_dat) = match harmonic {
Harmonic::Second => (second_harmonic_lbo.wavelengths, second_harmonic_lbo.angles, second_harmonic_lbo.walkoffs),
Harmonic::Third => (third_harmonic_bbo.wavelengths, third_harmonic_bbo.angles, third_harmonic_bbo.walkoffs),
};


let angle = interpolate(wl_dat.clone(), ang_dat, vec![wavelength])[0];
let walkoff = interpolate(wl_dat, wo_dat, vec![wavelength])[0];

(angle, walkoff)
}

fn interpolate(xs: Vec<f32>, ys: Vec<f32>, out_xs: Vec<f32>) -> Vec<f32> {
let linear = Linear::builder().elements(ys).knots(xs).build().unwrap();
linear.sample(out_xs).collect()
}
Loading

0 comments on commit 4ec2927

Please sign in to comment.