fosanalysis
A framework to evaluate distributed fiber optic sensor data
Loading...
Searching...
No Matches
filehandler.py
Go to the documentation of this file.
1r"""
2Contains class implementations to get file content of ODiSI generated data.
3Depending on the file extension the according file reader will be called.
4The FileHandler reads all data including metadata, tare, x-axis and strain.
5
6\author Anett Kielreiter
7\date 2024
8"""
9
10import os
11from datetime import datetime
12from collections.abc import Generator
13
14from . import filereader
15
16
18 r"""
19 File handler class to get measurement data from sensors.
20 Currently raw data and exported TSV files from
21 ODiSI 6100 series interrogators by Luna Inc LunaInnovations2020
22 are supported, see \cite LunaInnovations2020.
23 """
24 def __init__(self, filename: str, chunk_size: int = 1000):
25 r"""
26 Provides the handler for parsing measuring data files.
27 Different types of files are supported (atm *.dat and *.tsv )
28 \param filename Path to file to get measurement data.
29 \param chunk_size \copybrief chunk_size For more, see \ref chunk_size.
30 """
31
32 self.reader = None
33
35 self.metadata = None
36
38 self.sensors = None
39
44 self.chunk_size = chunk_size
45
46 ext = os.path.splitext(filename)[1].lower()
47 if ext == ".tsv":
48 self.reader = filereader.TsvReader(filename)
49 elif ext == ".dat":
50 self.reader = filereader.DatReader(filename)
51 else:
52 raise ValueError("No valid file format")
53
54 self.sensors, self.metadata = self.reader.read_meta_infos()
55
56 def close_file(self):
57 r"""
58 Close the handle to the file and reset all function variables.
59 """
60 if self.reader is not None:
61 self.reader.file.close()
62 self.reader = None
63 self.metadata = None
64 self.sensors = None
65
66#region Functions to get measurements (All, parts or by gage/segment names)
67
69 self,
70 channel: int = None,
71 start_time: datetime = None,
72 end_time: datetime = None,
73 segments_gages=None
74 ) -> tuple[list, dict]:
75 r"""
76 Reads all measurement files and returns the strain values, x_axis,
77 tare and timestamps filtered by given parameters.
78 The values are read in blocks to avoid memory issues.
79 The values will be split to gages/segments,
80 if segments_gages are given.
81 \param channel Selected channel of the file, defines the sensor.
82 \param start_time Read measurements from given timestamp.
83 \param end_time Read measurements till given timestamp.
84 \param segments_gages String or list of strings of gages/segments.
85 \return List of available timestamps.
86 \return Data of measurement (strain, xaxis, tare) as dict.
87 If no segment/gage selected, the dict contains ['All'] key.
88 """
89 timestamps = []
90 meas_dict = {}
91 if channel is not None:
92 sensor = next((x for x in self.sensors if x.channel == channel), None)
93 if sensor is None:
94 return [], {}
95 else:
96 sensor = self.sensors[0]
97 if segments_gages is not None and isinstance(segments_gages, str):
98 segments_gages = [segments_gages]
99
100 self.reader.file.seek(0) # reset the file pointer
101 for times, strain in self.yield_measurements_in_chunks(
102 self.chunk_size,
103 channel,
104 start_time,
105 end_time):
106 if segments_gages is not None:
107 self._split_to_gages_segments(meas_dict, sensor,
108 segments_gages, strain)
109 else:
110 if 'All' not in meas_dict:
111 meas_dict['All'] = {}
112 if meas_dict['All'].get('x_axis', None) is None:
113 meas_dict['All']['strain'] = strain
114 meas_dict['All']['x_axis'] = sensor.x_axis
115 meas_dict['All']['tare'] = sensor.tare
116 else:
117 meas_dict['All']['strain'].extend(strain)
118 timestamps.extend(times)
119
120 return timestamps, meas_dict
121
122 def yield_dat_file_values(self) -> Generator[dict]:
123 r"""
124 Generator to iterate over all .dat files of current measurement.
125 Reads all values of the file and separate it to the channels.
126 \return Dict with all measurement data (timestamps, strain) by channel.
127 """
128 if not self.reader.measurement_files:
129 return {}
130
131 for dat_file in self.reader.measurement_files:
132 data_dict = self.reader.read_dat_file(dat_file)
133 yield data_dict
134
136 self,
137 chunk_size: int = None,
138 channel: int = None,
139 start_time: datetime = None,
140 end_time: datetime = None
141 ) -> Generator[list, list]:
142 r"""
143 Generator to iterate over the whole file
144 and yields data with size of chunk.
145 Returns lists of timestamps and strain values.
146 \param chunk_size Maximum number of lines to read in lists, see \ref chunk_size.
147 \param channel Selected channel of the file, defines the sensor.
148 \param start_time Read measurements from given timestamp.
149 \param end_time Read measurements till given timestamp.
150 \return List of available timestamps.
151 \return Strain data as list.
152 """
153 timestamps = []
154 strain = []
155 chunk_size = self.chunk_size if chunk_size is None else chunk_size
156 if channel is None:
157 channel = self.sensors[0].channel
158
159 self.reader.file.seek(0) # reset the file pointer
160 for entry in self.reader.read_next_measurement(start_time=start_time,
161 end_time=end_time,
162 channel=channel):
163 timestamps.append(entry[0])
164 strain.append(entry[1])
165
166 if len(timestamps) >= chunk_size:
167 yield timestamps, strain
168 timestamps = []
169 strain = []
170 if len(timestamps) > 0:
171 yield timestamps, strain
172
174 self,
175 segments_gages,
176 chunk_size: int = None,
177 channel: int = None,
178 start_time: datetime = None,
179 end_time: datetime = None
180 ) -> Generator[list, dict]:
181 r"""
182 Generator to iterate over a dictionary with all strain data,
183 x-axis and tare for the given segment or gage names of chunk_size.
184 Separately from it, it returns the timestamps of file.
185 \param segments_gages String or list of gage/segment name(s).
186 \param chunk_size Number of lines to be read in one chunk as int.
187 \param channel Selected channel of the file, defines the sensor.
188 \param start_time Read measurements from given timestamp.
189 \param end_time Read measurements till given timestamp.
190 \return timestamps List of available timestamps.
191 \return meas_dict Dict with all measurement data of segment/gage.
192 """
193 chunk_size = self.chunk_size if chunk_size is None else chunk_size
194 if channel is not None:
195 sensor = next((x for x in self.sensors if x.channel == channel),
196 None)
197 if sensor is None:
198 return [], {}
199 else:
200 sensor = self.sensors[0]
201 if isinstance(segments_gages, str):
202 segments_gages = [segments_gages]
203
204 for timestamps, strain in self.yield_measurements_in_chunks(channel,
205 chunk_size,
206 start_time,
207 end_time):
208 meas_dict = {}
209 self._split_to_gages_segments(meas_dict, sensor,
210 segments_gages, strain)
211 yield timestamps, meas_dict
212
214 self,
215 meas_dict: dict,
216 sensor: filereader.SensorInfo,
217 segments_gages,
218 strain: list
219 ):
220 r"""
221 Fill the meas_dict dictionary with all strain data, x-axis and tare
222 for the given segment or gage names.
223 \param meas_dict Dict with all measurement data of segment/gage.
224 \param sensor Sensor object with axis, tare, etc.
225 \param segments_gages String or list of gage/segment name(s).
226 \param strain Strain values as list of arrays.
227 """
228 for name in segments_gages:
229 if name not in meas_dict:
230 meas_dict[name] = {}
231 start, end = self._get_range_of_segment_gage(name, sensor)
232 if start is None:
233 break
234 if meas_dict[name].get('x_axis', None) is None:
235 meas_dict[name]['strain'] = ([i[start:end] for i in strain])
236 meas_dict[name]['x_axis'] = sensor.x_axis[start:end]
237 meas_dict[name]['tare'] = sensor.tare[start:end]
238 else:
239 meas_dict[name]['strain'].extend(
240 ([i[start:end] for i in strain]))
241
243 self,
244 name: str,
246 ) -> tuple[int, int]:
247 r"""
248 Get start and end index of gage/segment.
249 \param name Name of the segment/gage.
250 \param sensor Sensor object with axis, tare, etc.
251 \return start Start index of segment or index of gage.
252 \return end End index of segment or index+1 if gage.
253 """
254 if name in sensor.gages:
255 target = sensor.gages
256 elif name in sensor.segments:
257 target = sensor.segments
258 else:
259 return None, None
260 start = target[name]['index']
261
262 if name in sensor.segments:
263 end = start + target[name]['length']
264 else:
265 end = start + 1
266 return start, end
File handler class to get measurement data from sensors.
sensors
List of SensorInfo object available in file, contains all sensor specific infos (incl.
__init__(self, str filename, int chunk_size=1000)
Provides the handler for parsing measuring data files.
Generator[list, dict] yield_gages_segments_in_chunks(self, segments_gages, int chunk_size=None, int channel=None, datetime start_time=None, datetime end_time=None)
Generator to iterate over a dictionary with all strain data, x-axis and tare for the given segment or...
chunk_size
Size of chunks when reading multiple readings at once.
metadata
Dictionary, which stores metadata for each file imported.
tuple[list, dict] get_measurements(self, int channel=None, datetime start_time=None, datetime end_time=None, segments_gages=None)
_split_to_gages_segments(self, dict meas_dict, filereader.SensorInfo sensor, segments_gages, list strain)
Fill the meas_dict dictionary with all strain data, x-axis and tare for the given segment or gage nam...
Generator[list, list] yield_measurements_in_chunks(self, int chunk_size=None, int channel=None, datetime start_time=None, datetime end_time=None)
Generator to iterate over the whole file and yields data with size of chunk.
tuple[int, int] _get_range_of_segment_gage(self, str name, filereader.SensorInfo sensor)
Get start and end index of gage/segment.
Generator[dict] yield_dat_file_values(self)
Generator to iterate over all .dat files of current measurement.
close_file(self)
Close the handle to the file and reset all function variables.
reader
Holds the file reader for selected file.
File reader class for the .dat measurement files recorded by the ODiSI 6100 series interrogators by L...
Class to hold sensor specific data (name, serial number, ...).
Definition filereader.py:24
File reader class for the .tsv measurement files exported by the ODiSI 6100 series interrogators by L...