Mon, 06 Jan 2025 21:37:03 -0500
Attempt to do more Serialize / Deserialize but run into csv problems
| 0 | 1 | //! Plotting helper utilities |
| 2 | ||
| 3 | use numeric_literals::replace_float_literals; | |
| 35 | 4 | use serde::Serialize; |
| 0 | 5 | use alg_tools::types::*; |
| 6 | use alg_tools::lingrid::LinGrid; | |
| 35 | 7 | use alg_tools::mapping::RealMapping; |
| 0 | 8 | use alg_tools::loc::Loc; |
| 9 | use alg_tools::tabledump::write_csv; | |
| 10 | use crate::measures::*; | |
| 11 | ||
| 12 | /// Helper trait for implementing dimension-dependent plotting routines. | |
| 13 | pub trait Plotting<const N : usize> { | |
| 14 | /// Plot several mappings and a discrete measure into a file. | |
| 15 | fn plot_into_file_spikes< | |
| 16 | F : Float, | |
| 17 | T1 : RealMapping<F, N>, | |
| 18 | T2 : RealMapping<F, N> | |
| 19 | > ( | |
| 35 | 20 | g : Option<&T1>, |
| 0 | 21 | ω : Option<&T2>, |
| 22 | grid : LinGrid<F, N>, | |
| 35 | 23 | μ : &RNDM<F, N>, |
| 0 | 24 | filename : String, |
| 25 | ); | |
| 26 | ||
| 27 | /// Plot a mapping into a file, sampling values on a given grid. | |
| 28 | fn plot_into_file< | |
| 29 | F : Float, | |
| 30 | T1 : RealMapping<F, N>, | |
| 31 | > ( | |
| 32 | g : &T1, | |
| 33 | grid : LinGrid<F, N>, | |
| 34 | filename : String, | |
| 35 | ); | |
| 36 | } | |
| 37 | ||
| 38 | /// Helper type for looking up a [`Plotting`] based on dimension. | |
| 39 | pub struct PlotLookup; | |
| 40 | ||
| 35 | 41 | #[derive(Serialize)] |
| 42 | struct CSVHelper1<F : Float> { | |
| 43 | x : F, | |
| 44 | f : F, | |
| 45 | } | |
| 46 | ||
| 47 | #[derive(Serialize)] | |
| 48 | struct CSVHelper1_2<F : Float>{ | |
| 49 | x : F, | |
| 50 | g : Option<F>, | |
| 51 | omega : Option<F> | |
| 52 | } | |
| 53 | ||
| 54 | #[derive(Serialize)] | |
| 55 | struct CSVSpike1<F : Float> { | |
| 56 | x : F, | |
| 57 | alpha : F, | |
| 58 | } | |
| 59 | ||
| 0 | 60 | impl Plotting<1> for PlotLookup { |
| 61 | fn plot_into_file_spikes< | |
| 62 | F : Float, | |
| 63 | T1 : RealMapping<F, 1>, | |
| 64 | T2 : RealMapping<F, 1> | |
| 65 | > ( | |
| 35 | 66 | g0 : Option<&T1>, |
| 0 | 67 | ω0 : Option<&T2>, |
| 68 | grid : LinGrid<F, 1>, | |
| 69 | μ : &DiscreteMeasure<Loc<F, 1>, F>, | |
| 70 | filename : String, | |
| 71 | ) { | |
| 35 | 72 | let data = grid.into_iter().map(|p@Loc([x]) : Loc<F, 1>| CSVHelper1_2 { |
| 73 | x, | |
| 74 | g : g0.map(|g| g.apply(&p)), | |
| 75 | omega : ω0.map(|ω| ω.apply(&p)) | |
| 0 | 76 | }); |
| 35 | 77 | let csv_f = format!("{}_functions.csv", filename); |
| 78 | write_csv(data, csv_f).expect("CSV save error"); | |
| 0 | 79 | |
| 35 | 80 | let spikes = μ.iter_spikes().map(|δ| { |
| 81 | let Loc([x]) = δ.x; | |
| 82 | CSVSpike1 { x, alpha : δ.α } | |
| 0 | 83 | }); |
| 35 | 84 | let csv_f = format!("{}_spikes.csv", filename); |
| 85 | write_csv(spikes, csv_f).expect("CSV save error"); | |
| 0 | 86 | } |
| 87 | ||
| 88 | fn plot_into_file< | |
| 89 | F : Float, | |
| 90 | T1 : RealMapping<F, 1>, | |
| 91 | > ( | |
| 92 | g : &T1, | |
| 93 | grid : LinGrid<F, 1>, | |
| 94 | filename : String, | |
| 95 | ) { | |
| 35 | 96 | let data = grid.into_iter().map(|p@Loc([x]) : Loc<F, 1>| CSVHelper1 { |
| 97 | x, | |
| 98 | f : g.apply(&p), | |
| 0 | 99 | }); |
| 100 | let csv_f = format!("{}.txt", filename); | |
| 35 | 101 | write_csv(data, csv_f).expect("CSV save error"); |
| 0 | 102 | } |
| 103 | ||
| 104 | } | |
| 105 | ||
| 35 | 106 | #[derive(Serialize)] |
| 107 | struct CSVHelper2<F : Float> { | |
| 108 | x : F, | |
| 109 | y : F, | |
| 110 | f : F, | |
| 0 | 111 | } |
| 112 | ||
| 35 | 113 | #[derive(Serialize)] |
| 114 | struct CSVHelper2_2<F : Float>{ | |
| 115 | x : F, | |
| 116 | y : F, | |
| 117 | g : Option<F>, | |
| 118 | omega : Option<F> | |
| 0 | 119 | } |
| 120 | ||
| 35 | 121 | #[derive(Serialize)] |
| 122 | struct CSVSpike2<F : Float> { | |
| 123 | x : F, | |
| 124 | y : F, | |
| 125 | alpha : F, | |
| 0 | 126 | } |
| 127 | ||
| 128 | ||
| 129 | impl Plotting<2> for PlotLookup { | |
| 130 | #[replace_float_literals(F::cast_from(literal))] | |
| 131 | fn plot_into_file_spikes< | |
| 132 | F : Float, | |
| 133 | T1 : RealMapping<F, 2>, | |
| 134 | T2 : RealMapping<F, 2> | |
| 135 | > ( | |
| 35 | 136 | g0 : Option<&T1>, |
| 0 | 137 | ω0 : Option<&T2>, |
| 138 | grid : LinGrid<F, 2>, | |
| 139 | μ : &DiscreteMeasure<Loc<F, 2>, F>, | |
| 140 | filename : String, | |
| 141 | ) { | |
| 35 | 142 | let data = grid.into_iter().map(|p@Loc([x, y]) : Loc<F, 2>| CSVHelper2_2 { |
| 143 | x, | |
| 144 | y, | |
| 145 | g : g0.map(|g| g.apply(&p)), | |
| 146 | omega : ω0.map(|ω| ω.apply(&p)) | |
| 147 | }); | |
| 148 | let csv_f = format!("{}_functions.csv", filename); | |
| 149 | write_csv(data, csv_f).expect("CSV save error"); | |
| 0 | 150 | |
| 35 | 151 | let spikes = μ.iter_spikes().map(|δ| { |
| 152 | let Loc([x, y]) = δ.x; | |
| 153 | CSVSpike2 { x, y, alpha : δ.α } | |
| 154 | }); | |
| 155 | let csv_f = format!("{}_spikes.csv", filename); | |
| 156 | write_csv(spikes, csv_f).expect("CSV save error"); | |
| 0 | 157 | } |
| 158 | ||
| 159 | fn plot_into_file< | |
| 160 | F : Float, | |
| 161 | T1 : RealMapping<F, 2>, | |
| 162 | > ( | |
| 163 | g : &T1, | |
| 164 | grid : LinGrid<F, 2>, | |
| 165 | filename : String, | |
| 166 | ) { | |
| 35 | 167 | let data = grid.into_iter().map(|p@Loc([x, y]) : Loc<F, 2>| CSVHelper2 { |
| 168 | x, | |
| 169 | y, | |
| 170 | f : g.apply(&p), | |
| 171 | }); | |
| 172 | let csv_f = format!("{}.txt", filename); | |
| 173 | write_csv(data, csv_f).expect("CSV save error"); | |
| 0 | 174 | } |
| 175 | ||
| 176 | } | |
| 177 | ||
| 178 | /// A helper structure for plotting a sequence of images. | |
| 179 | #[derive(Clone,Debug)] | |
| 180 | pub struct SeqPlotter<F : Float, const N : usize> { | |
| 181 | /// File name prefix | |
| 182 | prefix : String, | |
| 183 | /// Maximum number of plots to perform | |
| 184 | max_plots : usize, | |
| 185 | /// Sampling grid | |
| 186 | grid : LinGrid<F, N>, | |
| 187 | /// Current plot count | |
| 188 | plot_count : usize, | |
| 189 | } | |
| 190 | ||
| 191 | impl<F : Float, const N : usize> SeqPlotter<F, N> | |
| 192 | where PlotLookup : Plotting<N> { | |
| 193 | /// Creates a new sequence plotter instance | |
| 194 | pub fn new(prefix : String, max_plots : usize, grid : LinGrid<F, N>) -> Self { | |
| 195 | SeqPlotter { prefix, max_plots, grid, plot_count : 0 } | |
| 196 | } | |
| 197 | ||
| 198 | /// This calls [`PlotLookup::plot_into_file_spikes`] with a sequentially numbered file name. | |
| 199 | pub fn plot_spikes<T1, T2>( | |
| 200 | &mut self, | |
| 35 | 201 | iter : usize, |
| 202 | g : Option<&T1>, | |
| 0 | 203 | ω : Option<&T2>, |
| 35 | 204 | μ : &RNDM<F, N>, |
| 0 | 205 | ) where T1 : RealMapping<F, N>, |
| 206 | T2 : RealMapping<F, N> | |
| 207 | { | |
| 208 | if self.plot_count == 0 && self.max_plots > 0 { | |
| 209 | std::fs::create_dir_all(&self.prefix).expect("Unable to create plot directory"); | |
| 210 | } | |
| 211 | if self.plot_count < self.max_plots { | |
| 212 | PlotLookup::plot_into_file_spikes( | |
| 35 | 213 | g, |
| 214 | ω, | |
| 0 | 215 | self.grid, |
| 216 | μ, | |
| 35 | 217 | format!("{}out{:03}", self.prefix, iter) |
| 0 | 218 | ); |
| 219 | self.plot_count += 1; | |
| 220 | } | |
| 221 | } | |
| 222 | } |