scirs2_integrate/visualization/
specialized.rs

1//! Specialized visualization tools for different scientific domains
2//!
3//! This module provides visualization tools for specialized scientific domains
4//! including quantum mechanics, fluid dynamics, and financial analysis.
5
6use super::types::*;
7use crate::error::{IntegrateError, IntegrateResult};
8use scirs2_core::ndarray::{Array1, Array2, Array3, Axis};
9
10/// Quantum state visualization tools
11pub struct QuantumVisualizer;
12
13impl QuantumVisualizer {
14    /// Create wave function visualization
15    pub fn visualize_wavefunction(
16        x: &Array1<f64>,
17        probability_density: &Array1<f64>,
18        time: f64,
19    ) -> IntegrateResult<HeatMapPlot> {
20        let mut metadata = PlotMetadata::default();
21        metadata.title = format!("Quantum State at t = {:.3}", time);
22        metadata.xlabel = "Position".to_string();
23        metadata.ylabel = "Probability Density".to_string();
24
25        Ok(HeatMapPlot {
26            x: x.clone(),
27            y: Array1::from_elem(1, 0.0), // 1D visualization
28            z: Array2::from_shape_vec((1, probability_density.len()), probability_density.to_vec())
29                .map_err(|e| IntegrateError::ComputationError(format!("Shape error: {e}")))?,
30            metadata,
31        })
32    }
33
34    /// Create complex phase visualization
35    pub fn visualize_complex_phase(
36        real_parts: &[f64],
37        imag_parts: &[f64],
38        phases: &[f64],
39    ) -> IntegrateResult<PhaseSpacePlot> {
40        let mut metadata = PlotMetadata::default();
41        metadata.title = "Complex Wave Function Phase".to_string();
42        metadata.xlabel = "Real Part".to_string();
43        metadata.ylabel = "Imaginary Part".to_string();
44
45        Ok(PhaseSpacePlot {
46            x: real_parts.to_vec(),
47            y: imag_parts.to_vec(),
48            colors: Some(phases.to_vec()),
49            metadata,
50        })
51    }
52
53    /// Create expectation value evolution plot
54    pub fn visualize_expectation_evolution(
55        times: &[f64],
56        positions: &[f64],
57        momenta: &[f64],
58    ) -> IntegrateResult<PhaseSpacePlot> {
59        let mut metadata = PlotMetadata::default();
60        metadata.title = "Quantum Expectation Values Evolution".to_string();
61        metadata.xlabel = "Position Expectation".to_string();
62        metadata.ylabel = "Momentum Expectation".to_string();
63
64        Ok(PhaseSpacePlot {
65            x: positions.to_vec(),
66            y: momenta.to_vec(),
67            colors: Some(times.to_vec()),
68            metadata,
69        })
70    }
71
72    /// Create energy level diagram
73    pub fn visualize_energy_levels(
74        energies: &Array1<f64>,
75        wavefunctions: &Array2<f64>,
76    ) -> IntegrateResult<VectorFieldPlot> {
77        let n_levels = energies.len().min(5); // Show up to 5 levels
78        let n_points = wavefunctions.nrows();
79
80        let x_coords = Array1::linspace(-1.0, 1.0, n_points);
81        let mut x_grid = Array2::zeros((n_levels, n_points));
82        let mut y_grid = Array2::zeros((n_levels, n_points));
83        let mut u = Array2::zeros((n_levels, n_points));
84        let mut v = Array2::zeros((n_levels, n_points));
85        let mut magnitude = Array2::zeros((n_levels, n_points));
86
87        for level in 0..n_levels {
88            for i in 0..n_points {
89                x_grid[[level, i]] = x_coords[i];
90                y_grid[[level, i]] = energies[level];
91                u[[level, i]] = wavefunctions[[i, level]];
92                v[[level, i]] = 0.0; // No y-component for energy levels
93                magnitude[[level, i]] = wavefunctions[[i, level]].abs();
94            }
95        }
96
97        let mut metadata = PlotMetadata::default();
98        metadata.title = "Energy Level Diagram".to_string();
99        metadata.xlabel = "Position".to_string();
100        metadata.ylabel = "Energy".to_string();
101
102        Ok(VectorFieldPlot {
103            x_grid,
104            y_grid,
105            u,
106            v,
107            magnitude,
108            metadata,
109        })
110    }
111}
112
113/// Fluid dynamics visualization tools
114pub struct FluidVisualizer;
115
116impl FluidVisualizer {
117    /// Create velocity field visualization
118    pub fn visualize_velocity_field(state: &FluidState) -> IntegrateResult<VectorFieldPlot> {
119        if state.velocity.len() < 2 {
120            return Err(IntegrateError::ValueError(
121                "Need at least 2 velocity components".to_string(),
122            ));
123        }
124
125        let u = &state.velocity[0];
126        let v = &state.velocity[1];
127        let (ny, nx) = u.dim();
128
129        let mut x_grid = Array2::zeros((ny, nx));
130        let mut y_grid = Array2::zeros((ny, nx));
131        let mut magnitude = Array2::zeros((ny, nx));
132
133        for i in 0..ny {
134            for j in 0..nx {
135                x_grid[[i, j]] = j as f64 * state.dx;
136                y_grid[[i, j]] = i as f64 * state.dy;
137                magnitude[[i, j]] = (u[[i, j]].powi(2) + v[[i, j]].powi(2)).sqrt();
138            }
139        }
140
141        let mut metadata = PlotMetadata::default();
142        metadata.title = format!("Velocity Field at t = {:.3}", state.time);
143        metadata.xlabel = "X Position".to_string();
144        metadata.ylabel = "Y Position".to_string();
145
146        Ok(VectorFieldPlot {
147            x_grid,
148            y_grid,
149            u: u.clone(),
150            v: v.clone(),
151            magnitude,
152            metadata,
153        })
154    }
155
156    /// Create pressure field heatmap
157    pub fn visualize_pressure_field(state: &FluidState) -> IntegrateResult<HeatMapPlot> {
158        let (ny, nx) = state.pressure.dim();
159        let x = Array1::from_iter((0..nx).map(|i| i as f64 * state.dx));
160        let y = Array1::from_iter((0..ny).map(|i| i as f64 * state.dy));
161
162        let mut metadata = PlotMetadata::default();
163        metadata.title = format!("Pressure Field at t = {:.3}", state.time);
164        metadata.xlabel = "X Position".to_string();
165        metadata.ylabel = "Y Position".to_string();
166
167        Ok(HeatMapPlot {
168            x,
169            y,
170            z: state.pressure.clone(),
171            metadata,
172        })
173    }
174
175    /// Create vorticity visualization
176    pub fn visualize_vorticity(state: &FluidState) -> IntegrateResult<HeatMapPlot> {
177        if state.velocity.len() < 2 {
178            return Err(IntegrateError::ValueError(
179                "Need at least 2 velocity components".to_string(),
180            ));
181        }
182
183        let u = &state.velocity[0];
184        let v = &state.velocity[1];
185        let (ny, nx) = u.dim();
186
187        let mut vorticity = Array2::zeros((ny, nx));
188
189        // Compute vorticity using finite differences
190        for i in 1..ny - 1 {
191            for j in 1..nx - 1 {
192                let dvdx = (v[[i, j + 1]] - v[[i, j - 1]]) / (2.0 * state.dx);
193                let dudy = (u[[i + 1, j]] - u[[i - 1, j]]) / (2.0 * state.dy);
194                vorticity[[i, j]] = dvdx - dudy;
195            }
196        }
197
198        let x = Array1::from_iter((0..nx).map(|i| i as f64 * state.dx));
199        let y = Array1::from_iter((0..ny).map(|i| i as f64 * state.dy));
200
201        let mut metadata = PlotMetadata::default();
202        metadata.title = format!("Vorticity Field at t = {:.3}", state.time);
203        metadata.xlabel = "X Position".to_string();
204        metadata.ylabel = "Y Position".to_string();
205
206        Ok(HeatMapPlot {
207            x,
208            y,
209            z: vorticity,
210            metadata,
211        })
212    }
213
214    /// Create streamline visualization  
215    pub fn visualize_streamlines(
216        state: &FluidState,
217        n_streamlines: usize,
218    ) -> IntegrateResult<Vec<PhaseSpacePlot>> {
219        if state.velocity.len() < 2 {
220            return Err(IntegrateError::ValueError(
221                "Need at least 2 velocity components".to_string(),
222            ));
223        }
224
225        let u = &state.velocity[0];
226        let v = &state.velocity[1];
227        let (ny, nx) = u.dim();
228
229        let mut streamlines = Vec::new();
230
231        // Create evenly spaced starting points
232        for i in 0..n_streamlines {
233            let start_x = (i as f64 / (n_streamlines - 1) as f64) * (nx - 1) as f64 * state.dx;
234            let start_y = 0.5 * (ny - 1) as f64 * state.dy; // Start at middle height
235
236            let mut x_line = vec![start_x];
237            let mut y_line = vec![start_y];
238
239            let mut current_x = start_x;
240            let mut current_y = start_y;
241
242            // Integrate streamline using simple Euler method
243            let dt = 0.01 * state.dx.min(state.dy);
244            for _ in 0..1000 {
245                // Maximum steps
246                let i_idx = (current_y / state.dy) as usize;
247                let j_idx = (current_x / state.dx) as usize;
248
249                if i_idx >= ny - 1 || j_idx >= nx - 1 || i_idx == 0 || j_idx == 0 {
250                    break;
251                }
252
253                let vel_x = u[[i_idx, j_idx]];
254                let vel_y = v[[i_idx, j_idx]];
255
256                current_x += vel_x * dt;
257                current_y += vel_y * dt;
258
259                x_line.push(current_x);
260                y_line.push(current_y);
261
262                // Stop if velocity is too small
263                if vel_x.abs() + vel_y.abs() < 1e-6 {
264                    break;
265                }
266            }
267
268            let mut metadata = PlotMetadata::default();
269            metadata.title = format!("Streamline {} at t = {:.3}", i, state.time);
270            metadata.xlabel = "X Position".to_string();
271            metadata.ylabel = "Y Position".to_string();
272
273            streamlines.push(PhaseSpacePlot {
274                x: x_line,
275                y: y_line,
276                colors: None,
277                metadata,
278            });
279        }
280
281        Ok(streamlines)
282    }
283
284    /// Create 3D fluid visualization
285    pub fn visualize_3d_velocity_magnitude(state: &FluidState3D) -> IntegrateResult<SurfacePlot> {
286        if state.velocity.len() < 3 {
287            return Err(IntegrateError::ValueError(
288                "Need 3 velocity components for 3D".to_string(),
289            ));
290        }
291
292        let u = &state.velocity[0];
293        let v = &state.velocity[1];
294        let w = &state.velocity[2];
295        let (nz, ny, nx) = u.dim();
296
297        // Take a slice at z = nz/2
298        let z_slice = nz / 2;
299        let mut x_grid = Array2::zeros((ny, nx));
300        let mut y_grid = Array2::zeros((ny, nx));
301        let mut magnitude = Array2::zeros((ny, nx));
302
303        for i in 0..ny {
304            for j in 0..nx {
305                x_grid[[i, j]] = j as f64 * state.dx;
306                y_grid[[i, j]] = i as f64 * state.dy;
307                let vel_mag = (u[[z_slice, i, j]].powi(2)
308                    + v[[z_slice, i, j]].powi(2)
309                    + w[[z_slice, i, j]].powi(2))
310                .sqrt();
311                magnitude[[i, j]] = vel_mag;
312            }
313        }
314
315        let mut metadata = PlotMetadata::default();
316        metadata.title = format!("3D Velocity Magnitude at t = {:.3}", state.time);
317        metadata.xlabel = "X Position".to_string();
318        metadata.ylabel = "Y Position".to_string();
319
320        Ok(SurfacePlot {
321            x: x_grid,
322            y: y_grid,
323            z: magnitude,
324            metadata,
325        })
326    }
327}
328
329/// Financial analysis visualization tools
330pub struct FinanceVisualizer;
331
332impl FinanceVisualizer {
333    /// Create option price surface
334    pub fn visualize_option_surface(
335        strikes: &Array1<f64>,
336        maturities: &Array1<f64>,
337        prices: &Array2<f64>,
338    ) -> IntegrateResult<SurfacePlot> {
339        let (n_maturities, n_strikes) = prices.dim();
340        let mut x_grid = Array2::zeros((n_maturities, n_strikes));
341        let mut y_grid = Array2::zeros((n_maturities, n_strikes));
342
343        for i in 0..n_maturities {
344            for j in 0..n_strikes {
345                x_grid[[i, j]] = strikes[j];
346                y_grid[[i, j]] = maturities[i];
347            }
348        }
349
350        let mut metadata = PlotMetadata::default();
351        metadata.title = "Option Price Surface".to_string();
352        metadata.xlabel = "Strike Price".to_string();
353        metadata.ylabel = "Time to Maturity".to_string();
354
355        Ok(SurfacePlot {
356            x: x_grid,
357            y: y_grid,
358            z: prices.clone(),
359            metadata,
360        })
361    }
362
363    /// Create Greeks surface visualization
364    pub fn visualize_greeks_surface(
365        strikes: &Array1<f64>,
366        spot_prices: &Array1<f64>,
367        greek_values: &Array2<f64>,
368        greek_name: &str,
369    ) -> IntegrateResult<HeatMapPlot> {
370        let mut metadata = PlotMetadata::default();
371        metadata.title = format!("{} Surface", greek_name);
372        metadata.xlabel = "Strike Price".to_string();
373        metadata.ylabel = "Spot Price".to_string();
374
375        Ok(HeatMapPlot {
376            x: strikes.clone(),
377            y: spot_prices.clone(),
378            z: greek_values.clone(),
379            metadata,
380        })
381    }
382
383    /// Create volatility smile visualization
384    pub fn visualize_volatility_smile(
385        strikes: &Array1<f64>,
386        implied_volatilities: &Array1<f64>,
387        maturity: f64,
388    ) -> IntegrateResult<PhaseSpacePlot> {
389        let mut metadata = PlotMetadata::default();
390        metadata.title = format!("Volatility Smile (T = {:.3})", maturity);
391        metadata.xlabel = "Strike Price".to_string();
392        metadata.ylabel = "Implied Volatility".to_string();
393
394        Ok(PhaseSpacePlot {
395            x: strikes.to_vec(),
396            y: implied_volatilities.to_vec(),
397            colors: None,
398            metadata,
399        })
400    }
401
402    /// Create risk metrics visualization
403    pub fn visualize_risk_metrics(
404        time_points: &Array1<f64>,
405        var_values: &Array1<f64>,
406        cvar_values: &Array1<f64>,
407    ) -> IntegrateResult<PhaseSpacePlot> {
408        let mut metadata = PlotMetadata::default();
409        metadata.title = "Risk Metrics Evolution".to_string();
410        metadata.xlabel = "Value at Risk".to_string();
411        metadata.ylabel = "Conditional Value at Risk".to_string();
412
413        Ok(PhaseSpacePlot {
414            x: var_values.to_vec(),
415            y: cvar_values.to_vec(),
416            colors: Some(time_points.to_vec()),
417            metadata,
418        })
419    }
420
421    /// Create portfolio performance visualization
422    pub fn visualize_portfolio_performance(
423        dates: &[String],
424        returns: &Array1<f64>,
425        benchmark_returns: &Array1<f64>,
426    ) -> IntegrateResult<PhaseSpacePlot> {
427        // Calculate cumulative returns
428        let mut cum_returns = vec![1.0]; // Start with 1.0
429        let mut cum_benchmark = vec![1.0];
430
431        for i in 0..returns.len() {
432            cum_returns.push(cum_returns[i] * (1.0 + returns[i]));
433            cum_benchmark.push(cum_benchmark[i] * (1.0 + benchmark_returns[i]));
434        }
435
436        let mut metadata = PlotMetadata::default();
437        metadata.title = "Portfolio vs Benchmark Performance".to_string();
438        metadata.xlabel = "Portfolio Cumulative Return".to_string();
439        metadata.ylabel = "Benchmark Cumulative Return".to_string();
440
441        Ok(PhaseSpacePlot {
442            x: cum_returns,
443            y: cum_benchmark,
444            colors: Some((0..dates.len() + 1).map(|i| i as f64).collect()),
445            metadata,
446        })
447    }
448}
449
450/// Create specialized quantum visualization
451pub fn specialized_visualizations(
452    visualization_type: &str,
453    data: &Array2<f64>,
454) -> IntegrateResult<HeatMapPlot> {
455    match visualization_type {
456        "quantum_probability" => {
457            let x = Array1::linspace(-5.0, 5.0, data.ncols());
458            let probability_density = data.row(0).to_owned();
459            QuantumVisualizer::visualize_wavefunction(&x, &probability_density, 0.0)
460        }
461        _ => Err(IntegrateError::ValueError(format!(
462            "Unknown visualization type: {}",
463            visualization_type
464        ))),
465    }
466}
467
468/// Create bifurcation diagram generator for specialized systems
469pub struct BifurcationDiagramGenerator {
470    /// Parameter range for bifurcation analysis
471    pub parameter_range: (f64, f64),
472    /// Number of parameter samples
473    pub n_parameter_samples: usize,
474    /// Number of initial transient steps to skip
475    pub transient_steps: usize,
476    /// Number of sampling steps after transients
477    pub sampling_steps: usize,
478    /// Tolerance for detecting fixed points
479    pub fixed_point_tolerance: f64,
480    /// Tolerance for detecting periodic orbits
481    pub period_tolerance: f64,
482}
483
484impl BifurcationDiagramGenerator {
485    /// Create new bifurcation diagram generator
486    pub fn new(parameterrange: (f64, f64), n_parameter_samples: usize) -> Self {
487        Self {
488            parameter_range: parameterrange,
489            n_parameter_samples,
490            transient_steps: 1000,
491            sampling_steps: 500,
492            fixed_point_tolerance: 1e-8,
493            period_tolerance: 1e-6,
494        }
495    }
496
497    /// Generate enhanced bifurcation diagram
498    pub fn generate_enhanced_diagram<F>(
499        &self,
500        map_function: F,
501        initial_condition: f64,
502    ) -> IntegrateResult<BifurcationDiagram>
503    where
504        F: Fn(f64, f64) -> f64, // (x, parameter) -> x_next
505    {
506        let mut parameter_values = Vec::new();
507        let mut state_values = Vec::new();
508        let mut stability_flags = Vec::new();
509
510        let param_step = (self.parameter_range.1 - self.parameter_range.0)
511            / (self.n_parameter_samples - 1) as f64;
512
513        for i in 0..self.n_parameter_samples {
514            let param = self.parameter_range.0 + i as f64 * param_step;
515
516            // Run transients
517            let mut x = initial_condition;
518            for _ in 0..self.transient_steps {
519                x = map_function(x, param);
520            }
521
522            // Sample attractor
523            let mut attractor_states = Vec::new();
524            for _ in 0..self.sampling_steps {
525                x = map_function(x, param);
526                attractor_states.push(x);
527            }
528
529            // Simple attractor analysis
530            let unique_count = self.count_unique_states(&attractor_states);
531            let is_stable = unique_count <= 2;
532
533            // Store representative states
534            if unique_count == 1 {
535                parameter_values.push(param);
536                state_values.push(attractor_states[attractor_states.len() - 1]);
537                stability_flags.push(is_stable);
538            } else {
539                // Store multiple points for periodic/chaotic attractors
540                let sample_rate = (attractor_states.len() / 10).max(1);
541                for (idx, &state) in attractor_states.iter().step_by(sample_rate).enumerate() {
542                    if idx < 10 {
543                        // Limit number of points per parameter
544                        parameter_values.push(param);
545                        state_values.push(state);
546                        stability_flags.push(is_stable);
547                    }
548                }
549            }
550        }
551
552        Ok(BifurcationDiagram {
553            parameters: parameter_values,
554            states: vec![state_values],
555            stability: stability_flags,
556            bifurcation_points: vec![], // Simplified - not computing bifurcation points
557        })
558    }
559
560    fn count_unique_states(&self, states: &[f64]) -> usize {
561        let mut unique_states = states.to_vec();
562        unique_states.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
563        unique_states.dedup_by(|a, b| (*a - *b).abs() < self.fixed_point_tolerance);
564        unique_states.len()
565    }
566}