1use crate::{DeviceError, DeviceResult};
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::time::Duration;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct TweezerArrayConfig {
14 pub array_dimensions: (usize, usize, usize),
16 pub tweezer_spacing: (f64, f64, f64),
18 pub laser_wavelength: f64,
20 pub beam_waist: f64,
22 pub max_laser_power: f64,
24 pub trap_depth: f64,
26 pub loading_efficiency: f64,
28 pub movement_precision: f64,
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
34pub struct TweezerPosition {
35 pub x: f64,
37 pub y: f64,
39 pub z: f64,
41}
42
43#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
45pub enum AtomState {
46 Empty,
48 Loaded,
50 LoadingFailed,
52 Lost,
54 Unknown,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct TweezerInfo {
61 pub tweezer_id: usize,
63 pub position: TweezerPosition,
65 pub target_position: Option<TweezerPosition>,
67 pub laser_power: f64,
69 pub atom_state: AtomState,
71 pub loading_attempts: usize,
73 pub last_update: std::time::SystemTime,
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct TweezerArrayState {
80 pub config: TweezerArrayConfig,
82 pub tweezers: HashMap<usize, TweezerInfo>,
84 pub loading_stats: LoadingStatistics,
86 pub active_movements: Vec<MovementOperation>,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct LoadingStatistics {
93 pub total_attempts: usize,
95 pub successful_loads: usize,
97 pub failed_loads: usize,
99 pub fill_factor: f64,
101 pub average_loading_time: Duration,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct MovementOperation {
108 pub operation_id: String,
110 pub tweezer_id: usize,
112 pub start_position: TweezerPosition,
114 pub end_position: TweezerPosition,
116 pub parameters: MovementParameters,
118 pub start_time: std::time::SystemTime,
120 pub expected_completion: std::time::SystemTime,
122 pub status: MovementStatus,
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct MovementParameters {
129 pub speed: f64,
131 pub acceleration: f64,
133 pub trajectory: MovementTrajectory,
135 pub power_ramping: PowerRampingConfig,
137}
138
139#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
141pub enum MovementTrajectory {
142 Linear,
144 SCurve,
146 Parabolic,
148 Waypoints(Vec<TweezerPosition>),
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize)]
154pub struct PowerRampingConfig {
155 pub enabled: bool,
157 pub initial_factor: f64,
159 pub final_factor: f64,
161 pub ramping_duration: Duration,
163}
164
165#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
167pub enum MovementStatus {
168 Queued,
170 InProgress,
172 Completed,
174 Failed,
176 Cancelled,
178}
179
180pub struct TweezerArrayManager {
182 state: TweezerArrayState,
183 movement_queue: Vec<MovementOperation>,
184 optimization_settings: OptimizationSettings,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct OptimizationSettings {
190 pub auto_reload: bool,
192 pub max_reload_attempts: usize,
194 pub position_optimization: bool,
196 pub power_optimization: bool,
198 pub optimization_interval: Duration,
200}
201
202impl TweezerArrayManager {
203 pub fn new(config: TweezerArrayConfig) -> Self {
205 let total_tweezers =
206 config.array_dimensions.0 * config.array_dimensions.1 * config.array_dimensions.2;
207 let mut tweezers = HashMap::new();
208
209 for i in 0..total_tweezers {
211 let (x_idx, y_idx, z_idx) = Self::index_to_coordinates(i, &config.array_dimensions);
212 let position = TweezerPosition {
213 x: x_idx as f64 * config.tweezer_spacing.0,
214 y: y_idx as f64 * config.tweezer_spacing.1,
215 z: z_idx as f64 * config.tweezer_spacing.2,
216 };
217
218 let tweezer_info = TweezerInfo {
219 tweezer_id: i,
220 position,
221 target_position: None,
222 laser_power: 0.0,
223 atom_state: AtomState::Empty,
224 loading_attempts: 0,
225 last_update: std::time::SystemTime::now(),
226 };
227
228 tweezers.insert(i, tweezer_info);
229 }
230
231 let state = TweezerArrayState {
232 config,
233 tweezers,
234 loading_stats: LoadingStatistics::default(),
235 active_movements: Vec::new(),
236 };
237
238 Self {
239 state,
240 movement_queue: Vec::new(),
241 optimization_settings: OptimizationSettings::default(),
242 }
243 }
244
245 const fn index_to_coordinates(
247 index: usize,
248 dimensions: &(usize, usize, usize),
249 ) -> (usize, usize, usize) {
250 let z_idx = index / (dimensions.0 * dimensions.1);
251 let y_idx = (index % (dimensions.0 * dimensions.1)) / dimensions.0;
252 let x_idx = index % dimensions.0;
253 (x_idx, y_idx, z_idx)
254 }
255
256 const fn coordinates_to_index(
258 x: usize,
259 y: usize,
260 z: usize,
261 dimensions: &(usize, usize, usize),
262 ) -> usize {
263 z * dimensions.0 * dimensions.1 + y * dimensions.0 + x
264 }
265
266 pub async fn load_atoms(&mut self, tweezer_ids: &[usize]) -> DeviceResult<LoadingResult> {
268 let mut results = HashMap::new();
269 let start_time = std::time::SystemTime::now();
270
271 for &tweezer_id in tweezer_ids {
272 let loading_result = self.load_single_atom(tweezer_id).await?;
273 results.insert(tweezer_id, loading_result);
274 }
275
276 self.update_loading_statistics(&results, start_time);
278
279 Ok(LoadingResult {
280 attempted_tweezers: tweezer_ids.to_vec(),
281 successful_loads: results.values().filter(|&&success| success).count(),
282 failed_loads: results.values().filter(|&&success| !success).count(),
283 individual_results: results,
284 loading_time: start_time.elapsed().unwrap_or(Duration::ZERO),
285 })
286 }
287
288 async fn load_single_atom(&mut self, tweezer_id: usize) -> DeviceResult<bool> {
290 let (loading_attempts, base_success_rate) = {
292 let tweezer = self.state.tweezers.get(&tweezer_id).ok_or_else(|| {
293 DeviceError::InvalidInput(format!("Tweezer {tweezer_id} not found"))
294 })?;
295 (
296 tweezer.loading_attempts,
297 self.state.config.loading_efficiency,
298 )
299 };
300
301 let loading_success =
303 self.simulate_atom_loading_from_params(loading_attempts, base_success_rate);
304
305 let tweezer =
307 self.state.tweezers.get_mut(&tweezer_id).ok_or_else(|| {
308 DeviceError::InvalidInput(format!("Tweezer {tweezer_id} not found"))
309 })?;
310
311 tweezer.loading_attempts += 1;
312 tweezer.last_update = std::time::SystemTime::now();
313 tweezer.atom_state = if loading_success {
314 AtomState::Loaded
315 } else {
316 AtomState::LoadingFailed
317 };
318
319 Ok(loading_success)
320 }
321
322 fn simulate_atom_loading(&self, tweezer: &TweezerInfo) -> bool {
324 self.simulate_atom_loading_from_params(
325 tweezer.loading_attempts,
326 self.state.config.loading_efficiency,
327 )
328 }
329
330 fn simulate_atom_loading_from_params(
332 &self,
333 loading_attempts: usize,
334 base_success_rate: f64,
335 ) -> bool {
336 let attempt_penalty = 0.05 * (loading_attempts as f64).max(1.0);
338 let effective_success_rate = (base_success_rate - attempt_penalty).max(0.1);
339
340 use std::collections::hash_map::DefaultHasher;
342 use std::hash::{Hash, Hasher};
343
344 let mut hasher = DefaultHasher::new();
345 loading_attempts.hash(&mut hasher);
346 let hash = hasher.finish();
347 let random_value = (hash % 1000) as f64 / 1000.0;
348
349 random_value < effective_success_rate
350 }
351
352 pub async fn move_atom(
354 &mut self,
355 tweezer_id: usize,
356 target_position: TweezerPosition,
357 parameters: MovementParameters,
358 ) -> DeviceResult<String> {
359 let tweezer =
360 self.state.tweezers.get(&tweezer_id).ok_or_else(|| {
361 DeviceError::InvalidInput(format!("Tweezer {tweezer_id} not found"))
362 })?;
363
364 if tweezer.atom_state != AtomState::Loaded {
365 return Err(DeviceError::InvalidInput(
366 "Cannot move atom: no atom loaded in tweezer".to_string(),
367 ));
368 }
369
370 let movement_time =
371 self.calculate_movement_time(&tweezer.position, &target_position, ¶meters);
372 let operation_id = format!("move_{}", uuid::Uuid::new_v4());
373
374 let movement_op = MovementOperation {
375 operation_id: operation_id.clone(),
376 tweezer_id,
377 start_position: tweezer.position,
378 end_position: target_position,
379 parameters,
380 start_time: std::time::SystemTime::now(),
381 expected_completion: std::time::SystemTime::now() + movement_time,
382 status: MovementStatus::Queued,
383 };
384
385 self.movement_queue.push(movement_op);
386 Ok(operation_id)
387 }
388
389 fn calculate_movement_time(
391 &self,
392 start: &TweezerPosition,
393 end: &TweezerPosition,
394 parameters: &MovementParameters,
395 ) -> Duration {
396 let distance = Self::calculate_distance(start, end);
397 let time_seconds = distance / parameters.speed;
398 Duration::from_secs_f64(time_seconds)
399 }
400
401 fn calculate_distance(pos1: &TweezerPosition, pos2: &TweezerPosition) -> f64 {
403 let dx = pos2.x - pos1.x;
404 let dy = pos2.y - pos1.y;
405 let dz = pos2.z - pos1.z;
406 dz.mul_add(dz, dx.mul_add(dx, dy * dy)).sqrt()
407 }
408
409 pub async fn process_movements(&mut self) -> DeviceResult<()> {
411 let mut operations_to_start = Vec::new();
412 let mut operations_to_complete = Vec::new();
413 let mut completed_indices = Vec::new();
414
415 for (i, movement) in self.movement_queue.iter_mut().enumerate() {
417 match movement.status {
418 MovementStatus::Queued => {
419 movement.status = MovementStatus::InProgress;
420 operations_to_start.push(movement.clone());
421 }
422 MovementStatus::InProgress => {
423 if std::time::SystemTime::now() >= movement.expected_completion {
424 movement.status = MovementStatus::Completed;
425 operations_to_complete.push(movement.clone());
426 completed_indices.push(i);
427 }
428 }
429 _ => {}
430 }
431 }
432
433 for operation in operations_to_start {
435 self.start_movement_execution(&operation).await?;
436 }
437
438 for operation in operations_to_complete {
439 self.complete_movement(&operation)?;
440 }
441
442 for &i in completed_indices.iter().rev() {
444 self.movement_queue.remove(i);
445 }
446
447 Ok(())
448 }
449
450 async fn start_movement_execution(&mut self, movement: &MovementOperation) -> DeviceResult<()> {
452 if let Some(tweezer) = self.state.tweezers.get_mut(&movement.tweezer_id) {
455 tweezer.target_position = Some(movement.end_position);
456 }
457 Ok(())
458 }
459
460 fn complete_movement(&mut self, movement: &MovementOperation) -> DeviceResult<()> {
462 if let Some(tweezer) = self.state.tweezers.get_mut(&movement.tweezer_id) {
463 tweezer.position = movement.end_position;
464 tweezer.target_position = None;
465 tweezer.last_update = std::time::SystemTime::now();
466 }
467 Ok(())
468 }
469
470 fn update_loading_statistics(
472 &mut self,
473 results: &HashMap<usize, bool>,
474 start_time: std::time::SystemTime,
475 ) {
476 let successful = results.values().filter(|&&success| success).count();
477 let failed = results.values().filter(|&&success| !success).count();
478 let loading_time = start_time.elapsed().unwrap_or(Duration::ZERO);
479
480 self.state.loading_stats.total_attempts += results.len();
481 self.state.loading_stats.successful_loads += successful;
482 self.state.loading_stats.failed_loads += failed;
483
484 let total_ops = self.state.loading_stats.total_attempts;
486 let current_avg = self.state.loading_stats.average_loading_time;
487 let new_avg = (current_avg * (total_ops - 1) as u32 + loading_time) / total_ops as u32;
488 self.state.loading_stats.average_loading_time = new_avg;
489
490 let loaded_count = self
492 .state
493 .tweezers
494 .values()
495 .filter(|t| t.atom_state == AtomState::Loaded)
496 .count();
497 self.state.loading_stats.fill_factor =
498 loaded_count as f64 / self.state.tweezers.len() as f64;
499 }
500
501 pub const fn get_array_state(&self) -> &TweezerArrayState {
503 &self.state
504 }
505
506 pub const fn get_loading_statistics(&self) -> &LoadingStatistics {
508 &self.state.loading_stats
509 }
510
511 pub fn get_atom_positions(&self) -> Vec<(usize, TweezerPosition)> {
513 self.state
514 .tweezers
515 .iter()
516 .filter(|(_, tweezer)| tweezer.atom_state == AtomState::Loaded)
517 .map(|(&id, tweezer)| (id, tweezer.position))
518 .collect()
519 }
520
521 pub async fn optimize_array(&mut self) -> DeviceResult<OptimizationResult> {
523 let mut optimizations_applied = Vec::new();
524
525 if self.optimization_settings.auto_reload {
526 let reload_count = self.auto_reload_failed_tweezers().await?;
527 if reload_count > 0 {
528 optimizations_applied.push(format!("Reloaded {reload_count} failed tweezers"));
529 }
530 }
531
532 if self.optimization_settings.position_optimization {
533 let position_adjustments = self.optimize_positions().await?;
534 if position_adjustments > 0 {
535 optimizations_applied.push(format!("Adjusted {position_adjustments} positions"));
536 }
537 }
538
539 if self.optimization_settings.power_optimization {
540 let power_adjustments = self.optimize_power_levels().await?;
541 if power_adjustments > 0 {
542 optimizations_applied.push(format!("Optimized {power_adjustments} power levels"));
543 }
544 }
545
546 Ok(OptimizationResult {
547 optimizations_applied,
548 fill_factor_improvement: 0.0, loading_efficiency_improvement: 0.0,
550 })
551 }
552
553 async fn auto_reload_failed_tweezers(&mut self) -> DeviceResult<usize> {
555 let failed_tweezer_ids: Vec<usize> = self
556 .state
557 .tweezers
558 .iter()
559 .filter(|(_, tweezer)| {
560 tweezer.atom_state == AtomState::LoadingFailed
561 && tweezer.loading_attempts < self.optimization_settings.max_reload_attempts
562 })
563 .map(|(&id, _)| id)
564 .collect();
565
566 if !failed_tweezer_ids.is_empty() {
567 self.load_atoms(&failed_tweezer_ids).await?;
568 }
569
570 Ok(failed_tweezer_ids.len())
571 }
572
573 async fn optimize_positions(&mut self) -> DeviceResult<usize> {
575 Ok(0)
577 }
578
579 async fn optimize_power_levels(&mut self) -> DeviceResult<usize> {
581 Ok(0)
583 }
584}
585
586#[derive(Debug, Clone, Serialize, Deserialize)]
588pub struct LoadingResult {
589 pub attempted_tweezers: Vec<usize>,
591 pub successful_loads: usize,
593 pub failed_loads: usize,
595 pub individual_results: HashMap<usize, bool>,
597 pub loading_time: Duration,
599}
600
601#[derive(Debug, Clone, Serialize, Deserialize)]
603pub struct OptimizationResult {
604 pub optimizations_applied: Vec<String>,
606 pub fill_factor_improvement: f64,
608 pub loading_efficiency_improvement: f64,
610}
611
612impl Default for TweezerArrayConfig {
613 fn default() -> Self {
614 Self {
615 array_dimensions: (10, 10, 1),
616 tweezer_spacing: (5.0, 5.0, 0.0),
617 laser_wavelength: 1064.0,
618 beam_waist: 1.0,
619 max_laser_power: 100.0,
620 trap_depth: 1000.0,
621 loading_efficiency: 0.8,
622 movement_precision: 10.0,
623 }
624 }
625}
626
627impl Default for LoadingStatistics {
628 fn default() -> Self {
629 Self {
630 total_attempts: 0,
631 successful_loads: 0,
632 failed_loads: 0,
633 fill_factor: 0.0,
634 average_loading_time: Duration::ZERO,
635 }
636 }
637}
638
639impl Default for OptimizationSettings {
640 fn default() -> Self {
641 Self {
642 auto_reload: true,
643 max_reload_attempts: 3,
644 position_optimization: false,
645 power_optimization: false,
646 optimization_interval: Duration::from_secs(60),
647 }
648 }
649}
650
651impl Default for MovementParameters {
652 fn default() -> Self {
653 Self {
654 speed: 10.0, acceleration: 5.0, trajectory: MovementTrajectory::Linear,
657 power_ramping: PowerRampingConfig::default(),
658 }
659 }
660}
661
662impl Default for PowerRampingConfig {
663 fn default() -> Self {
664 Self {
665 enabled: false,
666 initial_factor: 1.0,
667 final_factor: 1.0,
668 ramping_duration: Duration::from_millis(100),
669 }
670 }
671}
672
673pub fn create_basic_array_config(rows: usize, cols: usize, spacing: f64) -> TweezerArrayConfig {
675 TweezerArrayConfig {
676 array_dimensions: (rows, cols, 1),
677 tweezer_spacing: (spacing, spacing, 0.0),
678 ..Default::default()
679 }
680}
681
682pub const fn create_fast_movement_params() -> MovementParameters {
684 MovementParameters {
685 speed: 50.0,
686 acceleration: 20.0,
687 trajectory: MovementTrajectory::SCurve,
688 power_ramping: PowerRampingConfig {
689 enabled: true,
690 initial_factor: 1.2,
691 final_factor: 1.0,
692 ramping_duration: Duration::from_millis(50),
693 },
694 }
695}
696
697#[cfg(test)]
698mod tests {
699 use super::*;
700
701 #[test]
702 fn test_tweezer_array_creation() {
703 let config = TweezerArrayConfig::default();
704 let manager = TweezerArrayManager::new(config);
705
706 assert_eq!(manager.state.tweezers.len(), 100); assert!(manager
708 .state
709 .tweezers
710 .values()
711 .all(|t| t.atom_state == AtomState::Empty));
712 }
713
714 #[test]
715 fn test_coordinate_conversion() {
716 let dimensions = (3, 3, 2);
717
718 let (x, y, z) = TweezerArrayManager::index_to_coordinates(10, &dimensions);
720 assert_eq!((x, y, z), (1, 0, 1));
721
722 let index = TweezerArrayManager::coordinates_to_index(1, 0, 1, &dimensions);
724 assert_eq!(index, 10);
725 }
726
727 #[test]
728 fn test_distance_calculation() {
729 let pos1 = TweezerPosition {
730 x: 0.0,
731 y: 0.0,
732 z: 0.0,
733 };
734 let pos2 = TweezerPosition {
735 x: 3.0,
736 y: 4.0,
737 z: 0.0,
738 };
739
740 let distance = TweezerArrayManager::calculate_distance(&pos1, &pos2);
741 assert_eq!(distance, 5.0);
742 }
743}
744
745mod uuid {
747 use std::fmt;
748
749 pub struct Uuid([u8; 16]);
750
751 impl Uuid {
752 pub fn new_v4() -> Self {
753 use std::collections::hash_map::DefaultHasher;
754 use std::hash::{Hash, Hasher};
755 use std::time::SystemTime;
756
757 let mut hasher = DefaultHasher::new();
758 SystemTime::now().hash(&mut hasher);
759 let hash = hasher.finish();
760
761 let mut bytes = [0u8; 16];
762 bytes[0..8].copy_from_slice(&hash.to_le_bytes());
763 bytes[8..16].copy_from_slice(&hash.to_be_bytes());
764
765 Self(bytes)
766 }
767 }
768
769 impl fmt::Display for Uuid {
770 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
771 write!(f, "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
772 self.0[0], self.0[1], self.0[2], self.0[3],
773 self.0[4], self.0[5],
774 self.0[6], self.0[7],
775 self.0[8], self.0[9],
776 self.0[10], self.0[11], self.0[12], self.0[13], self.0[14], self.0[15])
777 }
778 }
779}