rgsl/types/n_tuples.rs
1//
2// A rust binding for the GSL library by Guillaume Gomez (guillaume1.gomez@gmail.com)
3//
4
5/*!
6# N-tuples
7
8This chapter describes functions for creating and manipulating ntuples, sets of values associated with events. The ntuples are stored in
9files. Their values can be extracted in any combination and booked in a histogram using a selection function.
10
11The values to be stored are held in a user-defined data structure, and an ntuple is created associating this data structure with a file.
12The values are then written to the file (normally inside a loop) using the ntuple functions described below.
13
14A histogram can be created from ntuple data by providing a selection function and a value function. The selection function specifies
15whether an event should be included in the subset to be analyzed or not. The value function computes the entry to be added to the histogram
16for each event.
17
18## Histogramming ntuple values
19
20Once an ntuple has been created its contents can be histogrammed in various ways using the function gsl_ntuple_project. Two user-defined
21functions must be provided, a function to select events and a function to compute scalar values. The selection function and the value
22function both accept the ntuple row as a first argument and other parameters as a second argument.
23
24The selection function determines which ntuple rows are selected for histogramming.
25
26## References and Further Reading
27
28Further information on the use of ntuples can be found in the documentation for the CERN packages PAW and HBOOK (available online).
29!*/
30
31use crate::Value;
32use ffi::FFI;
33use std::ffi::CString;
34use std::mem::MaybeUninit;
35use std::os::raw::{c_char, c_void};
36use std::path::Path;
37
38pub struct WriteNTuples {
39 n: *mut sys::gsl_ntuple,
40}
41
42impl WriteNTuples {
43 /// This function creates a new write-only ntuple file filename for ntuples of size size and
44 /// returns a pointer to the newly created ntuple struct. Any existing file with the same name
45 /// is truncated to zero length and overwritten. A pointer to memory for the current ntuple
46 /// row ntuple_data must be supplied-this is used to copy ntuples in and out of the file.
47 #[doc(alias = "gsl_ntuple_create")]
48 pub fn create<P: AsRef<Path>>(filename: P) -> Option<WriteNTuples> {
49 let filename = filename.as_ref();
50 let filename = filename.to_str().expect("Failed to convert path to str");
51 let c_str = CString::new(filename.as_bytes()).unwrap();
52 let tmp = unsafe {
53 sys::gsl_ntuple_create(c_str.as_ptr() as *mut c_char, std::ptr::null_mut(), 0)
54 };
55
56 if tmp.is_null() {
57 None
58 } else {
59 Some(Self { n: tmp })
60 }
61 }
62
63 /// This function writes the current ntuple ntuple->ntuple_data of size ntuple->size to the
64 /// corresponding file.
65 #[doc(alias = "gsl_ntuple_write")]
66 pub fn write<T: Sized>(&mut self, data: &T) -> Result<(), Value> {
67 let ret = unsafe {
68 (*self.n).ntuple_data = data as *const T as usize as *mut _;
69 (*self.n).size = std::mem::size_of::<T>() as _;
70 sys::gsl_ntuple_write(self.n)
71 };
72 result_handler!(ret, ())
73 }
74
75 /// This function is a synonym for NTuples::write.
76 #[doc(alias = "gsl_ntuple_bookdata")]
77 pub fn bookdata<T: Sized>(&mut self, data: &T) -> Result<(), Value> {
78 let ret = unsafe {
79 (*self.n).ntuple_data = data as *const T as usize as *mut _;
80 (*self.n).size = std::mem::size_of::<T>() as _;
81 sys::gsl_ntuple_bookdata(self.n)
82 };
83 result_handler!(ret, ())
84 }
85}
86
87impl Drop for WriteNTuples {
88 #[doc(alias = "gsl_ntuple_close")]
89 fn drop(&mut self) {
90 unsafe { sys::gsl_ntuple_close(self.n) };
91 }
92}
93
94pub struct ReadNTuples {
95 n: *mut sys::gsl_ntuple,
96}
97
98impl ReadNTuples {
99 /// This function opens an existing ntuple file filename for reading and returns a pointer to a
100 /// corresponding ntuple struct. The ntuples in the file must have size size. A pointer to
101 /// memory for the current ntuple row ntuple_data must be supplied—this is used to copy ntuples
102 /// in and out of the file.
103 #[doc(alias = "gsl_ntuple_open")]
104 pub fn open<P: AsRef<Path>>(filename: P) -> Option<ReadNTuples> {
105 let filename = filename.as_ref();
106 let filename = filename.to_str().expect("Failed to convert path to str");
107 let c_str = CString::new(filename.as_bytes()).unwrap();
108 let tmp =
109 unsafe { sys::gsl_ntuple_open(c_str.as_ptr() as *mut c_char, std::ptr::null_mut(), 0) };
110
111 if tmp.is_null() {
112 None
113 } else {
114 Some(Self { n: tmp })
115 }
116 }
117
118 /// This function reads the current row of the ntuple file for ntuple and stores the values in
119 /// ntuple->data.
120 #[doc(alias = "gsl_ntuple_read")]
121 pub fn read<T: Sized>(&mut self) -> Result<T, Value> {
122 let mut data = MaybeUninit::<T>::uninit();
123
124 let ret = unsafe {
125 (*self.n).ntuple_data = data.as_mut_ptr() as *mut _;
126 (*self.n).size = std::mem::size_of::<T>() as _;
127 sys::gsl_ntuple_read(self.n)
128 };
129 result_handler!(ret, unsafe { data.assume_init() })
130 }
131}
132
133impl Drop for ReadNTuples {
134 #[doc(alias = "gsl_ntuple_close")]
135 fn drop(&mut self) {
136 unsafe { sys::gsl_ntuple_close(self.n) };
137 }
138}
139
140macro_rules! impl_project {
141 ($name:ident) => {
142 impl $name {
143 /// This function updates the histogram `h` from the ntuple `ntuple` using the functions
144 /// `value_func` and `select_func`. For each ntuple row where the selection function
145 /// `select_func` is non-zero the corresponding value of that row is computed using the function
146 /// `value_func` and added to the histogram. Those ntuple rows where `select_func` returns
147 /// `false` are ignored. New entries are added to the histogram, so subsequent calls can be used
148 /// to accumulate further data in the same histogram.
149 #[doc(alias = "gsl_ntuple_project")]
150 pub fn project<T: Sized, V: Fn(&T) -> f64, S: Fn(&T) -> bool>(
151 &self,
152 h: &mut ::Histogram,
153 value_func: V,
154 select_func: S,
155 ) -> Result<(), Value> {
156 unsafe extern "C" fn value_trampoline<T: Sized, F: Fn(&T) -> f64>(
157 x: *mut c_void,
158 params: *mut c_void,
159 ) -> f64 {
160 let f: &F = &*(params as *const F);
161 let x: &T = &*(x as *const T);
162 f(x)
163 }
164 unsafe extern "C" fn select_trampoline<T: Sized, F: Fn(&T) -> bool>(
165 x: *mut c_void,
166 params: *mut c_void,
167 ) -> i32 {
168 let f: &F = &*(params as *const F);
169 let x: &T = &*(x as *const T);
170 if f(x) {
171 1
172 } else {
173 0
174 }
175 }
176
177 let f: Box<V> = Box::new(value_func);
178 let mut value_function = sys::gsl_ntuple_value_fn {
179 function: unsafe { std::mem::transmute(value_trampoline::<T, V> as usize) },
180 params: Box::into_raw(f) as *mut _,
181 };
182 let f: Box<S> = Box::new(select_func);
183 let mut select_function = sys::gsl_ntuple_select_fn {
184 function: unsafe { std::mem::transmute(select_trampoline::<T, S> as usize) },
185 params: Box::into_raw(f) as *mut _,
186 };
187 let ret = unsafe {
188 sys::gsl_ntuple_project(
189 h.unwrap_unique(),
190 self.n,
191 &mut value_function,
192 &mut select_function,
193 )
194 };
195 result_handler!(ret, ())
196 }
197 }
198 };
199}
200
201impl_project!(WriteNTuples);
202impl_project!(ReadNTuples);