fosanalysis
A framework to evaluate distributed fiber optic sensor data
Loading...
Searching...
No Matches
protocols.py
Go to the documentation of this file.
1r"""
2Contains functionality for interfacing files and network ports.
3\author Bertram Richter
4\date 2023--2025
5"""
6
7from abc import abstractmethod
8from collections import OrderedDict
9import copy
10import datetime
11import warnings
12
13import numpy as np
14
15from . import utils
16
17warnings.warn(
18 "The fosanalysis.protocols module is deprecated. " +
19 "This interface will be removed in the next release. " +
20 "Please update to the new interface: fosanalysis.datahandling.",
21 category=DeprecationWarning
22 )
23
24class SensorRecord(dict):
25 r"""
26 A single record of the distributed fiber optic strain sensing data.
27 """
28 def __init__(self,
29 data: list,
30 **kwargs):
31 r"""
32 Constructs a SensorRecord object.
33 Being adictionary, it may hold further information.
34 \param data The actual data of the record.
35 \param **kwargs Any other properties can be passes as `kwargs`, such as `name`, or `timestamp`.
36 """
37 super().__init__()
38 self["data"] = data
39 self.update(kwargs)
40 def to_tsv(self, itemsep: str = "\t") -> str:
41 r"""
42 This function returns the TSV (tab separated values) representation of this record.
43 \param itemsep Separation character. Defaults to `"\t"` (tab).
44 """
45 data_str = [str(data) for data in self["data"]]
46 return itemsep.join([self["record_name"], self["message_type"], self["sensor_type"], *data_str])
47
49 r"""
50 Abstract class, which specifies the basic interfaces a protocol must implement.
51
52 \deprecated This class and its subclasses are deprecated and will be removed in the next release.
53 Please update to the new interface, see \ref datahandling.
54 """
55 @abstractmethod
56 def __init__(self, *args, **kwargs):
57 r"""
58 Constructs a Protocol object.
59 Needs to be reimplemented by sub-classes.
60 """
61 super().__init__(*args, **kwargs)
62
63 self.metadata = {}
64 warnings.warn(
65 "The fosanalysis.protocols.Protocol classes are deprecated. " +
66 "This interface will be removed in the next release. " +
67 "Please update to the new interface: fosanalysis.datahandling.",
68 #category=DeprecationWarning
69 )
70 @abstractmethod
71 def get_x_values(self) -> np.array:
72 r"""
73 Returns the values of the x-axis record (location data).
74 """
75 raise NotImplementedError()
76 @abstractmethod
77 def get_y_table(self, *args, **kwargs) -> list:
78 r"""
79 Returns the table of the strain data.
80 """
81 raise NotImplementedError()
82
84 r"""
85 Data inferface for the `.tsv` measurement files exported by the
86 ODiSI 6100 series interrogators by Luna Inc \cite LunaInnovations2020.
87 Both gage files (`*_gages.tsv`) and full (`*_full.tsv`) are supported.
88
89 \deprecated This class and its subclasses are deprecated and will be removed in the next release.
90 Please update to the new interface, see \ref datahandling.
91 """
92 def __init__(self,
93 file: str,
94 only_header: bool = False,
95 itemsep: str = "\t",
96 *args, **kwargs):
97 r"""
98 Construct the interface object and parse a `.tsv` file.
99 \param file \copydoc file
100 It is immediately read by \ref read_file().
101 \param only_header \copydoc only_header
102 \param itemsep \copydoc file
103 \param *args Additional positional arguments, will be passed to the superconstructor.
104 \param **kwargs Additional keyword arguments, will be passed to the superconstructor.
105 """
106 super().__init__(*args, **kwargs)
107
116 self.segments = OrderedDict()
117
123 self.gages = OrderedDict()
124
125 self.metadata = {}
126
129 self.file = file
130
132 self.itemsep = itemsep
133
138 self.only_header = only_header
139 if file is not None:
140 self.read_file(only_header)
141 def read_file(self, only_header: bool):
142 r"""
143 Parse the content of \ref file and extract the measurement data.
144 It can be called multiple times for reading base data or the whole file.
145 The content is added to the \ref gages and \ref segments dictionaries.
146 The metadata is stored as dictionary in \ref metadata.
147 \param only_header \copydoc only_header
148 """
149 in_header = True
150 status_gages_segments = None
151 gages = OrderedDict()
152 segments = OrderedDict()
153 with open(self.file, "r") as f:
154 for line in f:
155 line_list = line.strip().split(self.itemsep)
156 # Skip blank lines
157 if not any(line_list):
158 continue
159 if in_header:
160 # Find the header to body separator
161 if "---" in line_list[0]:
162 # Switch reading modes from header to data
163 in_header = False
164 else:
165 # Read in metadata
166 fieldname = line_list[0][:-1] # First entry and strip the colon (:)
167 self.metadata[fieldname] = line_list[1] if len(line_list) > 1 else None
168 else:
169 record_name, message_type, sensor_type, *data = line_list
170 # If only_header is True and the line begins with a timestamp, stop the reading.
171 if only_header and message_type.lower() == "measurement":
172 break
173 if status_gages_segments is None:
174 # Decide if input data is a full or a gage/segment
175 status_gages_segments = (record_name.lower() == "Gage/Segment Name".lower())
176 if status_gages_segments:
177 # The reading data gets separated into gages and the segments
178 gages, segments = self._read_gage_segments_info(gages,
179 segments,
180 data)
181 else:
182 segments["full"] = {"start": 0,
183 "end": len(data),
184 "length": len(data),
185 "x": None,
186 "y_data": []}
187 self._read_gage_segment_data(gages,
188 segments,
189 record_name,
190 message_type,
191 sensor_type,
192 data)
193 else:
194 self._read_gage_segment_data(gages,
195 segments,
196 record_name,
197 message_type,
198 sensor_type,
199 data)
200 self.gages = gages
201 self.segments = segments
203 gages: dict,
204 segments: dict,
205 data: list):
206 r"""
207 Read gage and segment line to discover the gages and segments.
208 The gages are written into \ref gages.
209 The segments are written into \ref segments.
210 This information is used later on to split the data by \ref _read_gage_segment_data().
211 \param gages Dictionary, to which data of named gages is written.
212 \param segments Dictionary, to which data of named segments is written.
213 \param data List of split line, assumed to contain the gage and segment names.
214 """
215 segment_name = None
216 # loop over all the entries in the line
217 for index, value in enumerate(data):
218 # A new segments always has <segment name>[0]
219 if "[0]" in value:
220 # New segment
221 if segment_name is not None:
222 # Finish the last segment
223 segments[segment_name]["end"] = index
224 segments[segment_name]["length"] = index - segments[segment_name]["start"]
225 # get the segment name and start a new segment
226 segment_name = value.split("[")[0]
227 segments[segment_name] = {"start": index, "end": None, "x": None, "y_data": []}
228 elif segment_name is None:
229 # Gage reading
230 gages[value] = {"index": index, "x": None, "y_data": []}
231 # end the last segment
232 if segment_name is not None:
233 segments[segment_name]["end"] = len(data)
234 segments[segment_name]["length"] = len(data) - segments[segment_name]["start"]
235 return gages, segments
237 gages: dict,
238 segments: dict,
239 record_name: str,
240 message_type: str,
241 sensor_type: str,
242 data: list):
243 r"""
244 Private method to run the extraction for all gages and segments.
245 \param gages Dictionary, containing gage information.
246 This includes, the position of the gage in the data.
247 \param segments Dictionary, containing segment information.
248 This includes, the start and the length of the segment.
249 \param record_name The first entry in line, passed to \ref _store_data().
250 Contains the information such as:
251 - `"x-axis"` for the coordinate line,
252 - `"tare"` for the tare data,
253 - a datetime string for regular measurement lines.
254 \param message_type The second entry in line, passed to \ref _store_data().
255 For regular measurement lines this is `"measurement"`.
256 Else, it is emtpy.
257 \param sensor_type The third entry in line, passed to \ref _store_data().
258 For regular measurement lines this is `"strain"`.
259 Else, it is emtpy.
260 \param data The rest of the line, split up as a list of `str`.
261 This contains the measurement data.
262 """
263 for gage in gages.values():
264 self._store_data(gage, record_name, message_type, sensor_type, data)
265 for segment in segments.values():
266 self._store_data(segment, record_name, message_type, sensor_type, data)
267 def _store_data(self,
268 gage_segment: dict,
269 record_name: str,
270 message_type: str,
271 sensor_type: str,
272 data: list):
273 r"""
274 Private method to store the data into the dictionary.
275 Here, the differenciation between a gage and segment is done.
276 \param gage_segment Dictionary, containing information, which data to extract.
277 A segment is assumed, if the dictionary contains the key `"length"`.
278 Otherwise, it is assumed to be a gage.
279 \param record_name The first entry in line, passed to \ref _store_data().
280 Contains the information such as:
281 - `"x-axis"` for the coordinate line
282 - `"tare"` for the tare data
283 - a datetime string for regular measurement lines
284 \param message_type The second entry in line, passed to \ref _store_data().
285 For regular measurement lines this is `"measurement"`.
286 Else, it is emtpy.
287 \param sensor_type The third entry in line, passed to \ref _store_data().
288 For regular measurement lines this is `"strain"`.
289 Else, it is emtpy.
290 \param data The rest of the line, split up as a list of `str`.
291 This contains the measurement data.
292 """
293 data = np.asarray(data, dtype=float)
294 if "length" in gage_segment:
295 start = gage_segment["start"]
296 end = gage_segment["start"]+gage_segment["length"]
297 data = copy.deepcopy(data[start:end])
298 else:
299 data = copy.deepcopy(data[gage_segment["index"]])
300 if record_name.lower() == "x-axis":
301 gage_segment["x"] = data
302 elif record_name.lower() == "tare":
303 gage_segment["tare"] = data
304 else:
305 record = SensorRecord(
306 record_name=record_name.lower(),
307 timestamp=datetime.datetime.fromisoformat(record_name),
308 message_type=message_type.lower(),
309 sensor_type=sensor_type.lower(),
310 data=data,)
311 gage_segment["y_data"].append(record)
312 def _get_dict(self,
313 name: str = None,
314 is_gage: bool =False) -> dict:
315 r"""
316 Private method to return the dictionary matching the search criteria.
317 \param name Name of the gage or segment.
318 Defaults to the first gage or segment, depending on `is_gage`.
319 This name needs to exactly match the key in the dictionary.
320 \param is_gage Switch, whether `name` is a gage or a segment.
321 Defaults to `False`.
322 If `True`, look in \ref gages for `name`.
323 If `False`, look in \ref segments for `name`.
324
325 If no matching segment/gage is found, a `RuntimeError` is raised.
326 """
327 target = self.gages if is_gage else self.segments
328 name = name if name is not None else next(iter(target))
329 result = target.get(name, None)
330 if result is None:
331 requesttype = "gage" if is_gage else "segment"
332 message = "No {} with the name '{}' known!"
333 raise RuntimeError(message.format(requesttype, name))
334 return result
335 def get_tare(self,
336 name: str = None,
337 is_gage: bool = False) -> np.array:
338 r"""
339 Returns the values of the tare record (calibration data).
340 \copydetails _get_dict()
341 """
342 target = self._get_dict(name, is_gage)
343 return target.get("tare", None)
344 def get_x_values(self,
345 name: str = None,
346 is_gage: bool = False) -> np.array:
347 r"""
348 Returns the values of the x-axis record (location data).
349 \copydetails _get_dict()
350 """
351 target = self._get_dict(name, is_gage)
352 return target.get("x", None)
353 def get_y_table(self,
354 name: str = None,
355 is_gage: bool = False,
356 record_list: list = None) -> list:
357 r"""
358 Returns the table of the strain data.
359 \copydetails _get_dict()
360 \param record_list List of records, defaults to to the first segment found.
361 """
362 if record_list is None:
363 target = self._get_dict(name, is_gage)
364 record_list = target.get("y_data", None)
365 return [record["data"] for record in record_list]
366 def get_data(self,
367 start = None,
368 end = None,
369 name: str = None,
370 is_gage: bool = False,
371 single: bool = False,
372 ) -> tuple:
373 r"""
374 Get the positional data (x-axis), timestamps and strain data for
375 a gage/segment and a time interval.
376
377 \copydetails get_record_slice()
378
379 \param single Switch, whether a single reading is requested.
380 Defaults to `False`, requesting a range of readings.
381 If set to `True`, only `start` is required, which is expected
382 either an `int` or a `datetime.datetime`.
383 For the datetime, the closest reading is returned.
384 The `strain` will then be a 1D array.
385
386 \return Returns a tuple like `(x, timestamps, strain)`.
387 \retval x Array of positional data for the chosen gage/segment.
388 \retval timestamps Array of time stamps for the chosen time interval.
389 \retval strain Array of strain data for the chosen gage/segment and time interval.
390 """
391 x = self.get_x_values(name, is_gage)
392 if single:
393 if isinstance(start, datetime.datetime):
394 record, index = self.get_record_from_time_stamp(start, name, is_gage)
395 elif isinstance(start, int):
396 target = self._get_dict(name, is_gage)
397 record_list = target.get("y_data", None)
398 record = record_list[start]
399 return x, record["timestamp"], record["data"]
400 else:
401 record_slice = self.get_record_slice(start, end, name, is_gage)
402 timestamps = np.array(self.get_time_stamps(record_list=record_slice))
403 strain = np.array(self.get_y_table(record_list=record_slice))
404 return x, timestamps, strain
406 name: str = None,
407 is_gage: bool = False,
408 record_list: list = None) -> list:
409 r"""
410 Get the time stamps of all stored records.
411 \copydetails _get_dict()
412 \param record_list List of records, defaults to to the first segment found.
413 """
414 if record_list is None:
415 target = self._get_dict(name, is_gage)
416 record_list = target.get("y_data", None)
417 return [record["timestamp"] for record in record_list]
419 time_stamp: datetime.datetime,
420 name: str = None,
421 is_gage: bool = False,
422 position: str = "closest",
423 ) -> tuple:
424 r"""
425 Get the \ref SensorRecord and its index, which is closest to the given time_stamp.
426 \param time_stamp The time stamp, for which the closest \ref SensorRecord should be returned.
427
428 \copydetails _get_dict()
429 \param position Position of the data. Available options:
430 - `"closest"` (default) get the entry, which is closest to the given value.
431 - `"searchsorted"` get the entry as reported by `np.searchsorted`.
432 If the time_stamp is larger that any time stamp, the last
433 record is returned but the index is equal to the length
434 of the time stamp list (does not have a corresponding value).
435
436 \return Returns a tuple like `(sensor_record, index)` with
437 \retval sensor_record the \ref SensorRecord, which time stamp is closest to the given `time_stamp` and
438 \retval index the corresponding index in of the \ref SensorRecord.
439 """
440 target = self._get_dict(name, is_gage)
441 timestamps = self.get_time_stamps(name, is_gage)
442 if position == "closest":
443 index, accurate_time_stamp = utils.misc.find_closest_value(timestamps, time_stamp)
444 elif position == "searchsorted":
445 index = np.searchsorted(timestamps, time_stamp)
446 if index == len(timestamps):
447 record = target.get("y_data", None)[-1]
448 else:
449 record = target.get("y_data", None)[index]
450 return record, index
452 start = None,
453 end = None,
454 name: str = None,
455 is_gage: bool = False,) -> list:
456 r"""
457 Get a portion of the records in the table and return it as a list of \ref SensorRecord.
458 \param start The first record to be included.
459 Defaults to `None` (no restriction), i.e., the first reading.
460 \param end The first record to not be included anymore.
461 Defaults to `None` (no restriction), i.e., the last reading.
462 \copydetails _get_dict()
463
464 Both `start` and `end` can be of the following types and be combined arbitrarily.
465 - `int`: Index of the record according to Python indexing logic.
466 - `datetime.datetime`: The first record after the given `datetime.datetime`
467 is included for `start` and excluded for `end`.
468 - `datetime.timedelta`: Time duration, in relation to the other parameter.
469 If the parameter is `None`, it defaults to the first/last reading time.
470 This works both for the other parameter being `int` or `datetime.datetime`.
471 If both parameters are `datetime.timedelta`, the data section
472 runs from `start` after the first reading until `end` before the last reading.
473
474
475 In the following table, the possible combinations are shown.
476 There,
477 \f$i\f$ is an index according to the Python indexing logic
478 (the first is \f$0\f$ and the last is \f$-1\f$),
479 \f$t\f$ is a time stamp (`datetime.datetime`),
480 \f$\Delta t\f$ is a time delta (`datetime.timedelta`),
481 \f$t(i)\f$ is the time stamp of the \f$i\f$th reading, and
482 \f$i(t)\f$ is index of the reading with the smallest time stamp bigger than \f$t\f$.
483 | `start` | `end` | Start index | End index |
484 |:---|:---|:---|:---|
485 | `None` | `None` | \f$0\f$ | \f$-1\f$ |
486 | `None` | \f$i_e\f$ | \f$0\f$ | \f$i_e\f$ |
487 | `None` | \f$t_e\f$ | \f$0\f$ | \f$i(t_e)\f$ |
488 | `None` | \f$\Delta t_e\f$ | \f$0\f$ | \f$i(t(0) + \Delta t_e)\f$ |
489 | \f$i_s\f$ | `None` | \f$i_s\f$ | \f$-1\f$ |
490 | \f$i_s\f$ | \f$i_e\f$ | \f$i_s\f$ | \f$i_e\f$ |
491 | \f$i_s\f$ | \f$t_e\f$ | \f$i_s\f$ | \f$i(t_e)\f$ |
492 | \f$i_s\f$ | \f$\Delta t_e\f$ | \f$i_s\f$ | \f$i(t(i_s) + \Delta t_e)\f$ |
493 | \f$t_s\f$ | `None` | \f$i(t_s)\f$ | \f$-1\f$ |
494 | \f$t_s\f$ | \f$i_e\f$ | \f$i(t_s)\f$ | \f$i_e\f$ |
495 | \f$t_s\f$ | \f$t_e\f$ | \f$i(t_s)\f$ | \f$i(t_e)\f$ |
496 | \f$t_s\f$ | \f$\Delta t_e\f$ | \f$i(t_s)\f$ | \f$i(t_s + \Delta t_e)\f$ |
497 | \f$\Delta t_s\f$ | `None` | \f$i(t(-1)-\Delta t_s)\f$ | -1 |
498 | \f$\Delta t_s\f$ | \f$i_e\f$ | \f$i(t(i_e)-\Delta t_s)\f$ | \f$i_e\f$ |
499 | \f$\Delta t_s\f$ | \f$t_e\f$ | \f$i(t_e - \Delta t_s)\f$ | \f$i(t_e)\f$ |
500 | \f$\Delta t_s\f$ | \f$\Delta t_e\f$ | \f$i(t(0) + \Delta t_s)\f$ | \f$i(t(-1) - \Delta t_e)\f$ |
501 """
502 target = self._get_dict(name, is_gage)
503 record_list = target.get("y_data", None)
504 if record_list is None:
505 requesttype = "gage" if is_gage else "segment"
506 message = "No data found for {} with the name '{}'!"
507 raise RuntimeError(message.format(requesttype, name))
508 # Get the start index
509 if isinstance(start, int):
510 start_index = start
511 elif isinstance(start, datetime.datetime):
512 record_start, start_index = self.get_record_from_time_stamp(
513 start,
514 name,
515 is_gage,
516 position="searchsorted",
517 )
518 elif isinstance(start, datetime.timedelta):
519 if isinstance(end, datetime.datetime):
520 start_tmp = end - start
521 elif isinstance(end, int):
522 start_tmp = self.get_time_stamps(name, is_gage)[end] - start
523 elif isinstance(end, datetime.timedelta):
524 start_tmp = self.get_time_stamps(name, is_gage)[0] + start
525 else:
526 start_tmp = self.get_time_stamps(name, is_gage)[-1] - start
527 record_start, start_index = self.get_record_from_time_stamp(
528 start_tmp,
529 name,
530 is_gage,
531 position="searchsorted",
532 )
533 else:
534 start_index = 0
535 # Get the end index
536 if isinstance(end, int):
537 end_index = end
538 elif isinstance(end, datetime.datetime):
539 record_end, end_index = self.get_record_from_time_stamp(
540 end,
541 name,
542 is_gage,
543 position="searchsorted",
544 )
545 elif isinstance(end, datetime.timedelta):
546 if isinstance(start, datetime.datetime):
547 end_tmp = start + end
548 elif isinstance(start, int):
549 end_tmp = self.get_time_stamps(name, is_gage)[start] + end
550 elif isinstance(start, datetime.timedelta):
551 end_tmp = self.get_time_stamps(name, is_gage)[-1] - end
552 else:
553 end_tmp = self.get_time_stamps(name, is_gage)[0] + end
554 record_end, end_index = self.get_record_from_time_stamp(
555 end_tmp,
556 name,
557 is_gage,
558 position="searchsorted",
559 )
560 else:
561 end_index = len(record_list)
562 return record_list[start_index:end_index]
564 x: float = 0.0,
565 name: str = None,
566 is_gage: bool = False,) -> tuple:
567 r"""
568 Get the strain time series for a fixed position.
569 Therefore, the closest x-value to the given position is found and the according strain values are collected.
570 \param x Position, for which the time series should be retrieved.
571 This is used to search the nearest position in the segment.
572 For time series of gages (`is_gage=True`), this has no influence.
573 \copydetails _get_dict()
574 \return Returns a tuple of `(x_value, time_stamps, time_series)`.
575 \retval x_value The accurate position, that was found.
576 \retval time_stamps List of time stamps.
577 \retval time_series List of strain values for at the position of `x_value`.
578 """
579 time_stamps = self.get_time_stamps(name, is_gage)
580 x_values = self.get_x_values(name, is_gage)
581 y_data = self.get_y_table(name, is_gage)
582 try:
583 iterator = iter(x_values)
584 except TypeError:
585 # not iterable: a gage
586 x_value = x_values
587 time_series = y_data
588 else:
589 index, x_value = utils.misc.find_closest_value(x_values, x)
590 time_series = np.array([data[index] for data in y_data])
591 return x_value, time_stamps, time_series
592 def get_metadata(self) -> dict:
593 r"""
594 Get the metadata dictionary.
595 """
596 return self.metadata
597
598
600 input_file: str,
601 output_file: str,
602 list_of_time_intervals: list,
603 ) -> None:
604 r"""
605 Extracts the parts of the measurement data into smaller `.tsv` files.
606 The parts are given by time intervals.
607 The file header is copied as is.
608 A measurement line is copied to the `output_file` if its timestamp
609 \f$t\f$ falls within at least one of the given time intervals:
610 \f$t_{\mathrm{s}} \leq t \leq t_{\mathrm{e}}\f$.
611 Overlapping intervals are supported.
612
613 \note The `output_file` is overwritten without asking for confirmation!
614
615 \deprecated This function is deprecated and was moved to `fosanalysis.datahandling.tsvustils.extract_time_intervals()`.
616 Please use the updated function call
617
618 \param input_file String with the path of the input file (.tsv)
619 \param output_file String with the path of the output file (.tsv)
620 \param list_of_time_intervals List of time intervals.
621 Each interval is given as tuple of its the limits
622 (start time \f$t_{\mathrm{s}}\f$, end time \f$t_{\mathrm{e}}\f$).
623 Both limits can be either `datetime.datetime` or `None`.
624 Setting one or both of the limits to `None` results in an (half) unlimited open interval.
625 It is not necessary that the exact interval boundaries appear in the data.
626 """
627 warnings.warn(
628 "This function is deprecated and was moved to `fosanalysis.datahandling.tsvustils.extract_time_intervals()`. " +
629 "This interface will be removed in the next release. " +
630 "Please update to the new interface.",
631 #category=DeprecationWarning
632 )
633 with open(input_file, "r") as infile, open(output_file, "w") as outfile:
634 for line in infile:
635 entries = line.split("\t")
636 try:
637 timestamp = datetime.datetime.fromisoformat(entries[0].strip())
638 for start_time, end_time in list_of_time_intervals:
639 if (start_time is None or timestamp >= start_time) and (end_time is None or timestamp <= end_time):
640 outfile.write(line)
641 break
642 except ValueError:
643 outfile.write(line)
Data inferface for the .tsv measurement files exported by the ODiSI 6100 series interrogators by Luna...
Definition protocols.py:83
list get_time_stamps(self, str name=None, bool is_gage=False, list record_list=None)
Get the time stamps of all stored records.
Definition protocols.py:408
dict _get_dict(self, str name=None, bool is_gage=False)
Private method to return the dictionary matching the search criteria.
Definition protocols.py:314
list get_record_slice(self, start=None, end=None, str name=None, bool is_gage=False)
Get a portion of the records in the table and return it as a list of SensorRecord.
Definition protocols.py:455
segments
Dictionary of segments.
Definition protocols.py:116
_read_gage_segment_data(self, dict gages, dict segments, str record_name, str message_type, str sensor_type, list data)
Private method to run the extraction for all gages and segments.
Definition protocols.py:242
tuple get_record_from_time_stamp(self, datetime.datetime time_stamp, str name=None, bool is_gage=False, str position="closest")
Get the SensorRecord and its index, which is closest to the given time_stamp.
Definition protocols.py:423
read_file(self, bool only_header)
Parse the content of file and extract the measurement data.
Definition protocols.py:141
file
Fully specified file path, from which the data is read.
Definition protocols.py:129
_read_gage_segments_info(self, dict gages, dict segments, list data)
Read gage and segment line to discover the gages and segments.
Definition protocols.py:205
np.array get_x_values(self, str name=None, bool is_gage=False)
Returns the values of the x-axis record (location data).
Definition protocols.py:346
only_header
Switch to omit processing the complete file.
Definition protocols.py:138
__init__(self, str file, bool only_header=False, str itemsep="\t", *args, **kwargs)
Construct the interface object and parse a .tsv file.
Definition protocols.py:96
itemsep
String, which separates items (columns) in the file.
Definition protocols.py:132
tuple get_data(self, start=None, end=None, str name=None, bool is_gage=False, bool single=False)
Get the positional data (x-axis), timestamps and strain data for a gage/segment and a time interval.
Definition protocols.py:372
tuple get_time_series(self, float x=0.0, str name=None, bool is_gage=False)
Get the strain time series for a fixed position.
Definition protocols.py:566
dict get_metadata(self)
Get the metadata dictionary.
Definition protocols.py:592
np.array get_tare(self, str name=None, bool is_gage=False)
Returns the values of the tare record (calibration data).
Definition protocols.py:337
gages
Dictionary of gages Each gage is stored as a sub-dictionary with its name as a key.
Definition protocols.py:123
list get_y_table(self, str name=None, bool is_gage=False, list record_list=None)
Returns the table of the strain data.
Definition protocols.py:356
_store_data(self, dict gage_segment, str record_name, str message_type, str sensor_type, list data)
Private method to store the data into the dictionary.
Definition protocols.py:272
Abstract class, which specifies the basic interfaces a protocol must implement.
Definition protocols.py:48
dict metadata
Dictionary containting metadata information.
Definition protocols.py:63
np.array get_x_values(self)
Returns the values of the x-axis record (location data).
Definition protocols.py:71
list get_y_table(self, *args, **kwargs)
Returns the table of the strain data.
Definition protocols.py:77
__init__(self, *args, **kwargs)
Constructs a Protocol object.
Definition protocols.py:56
A single record of the distributed fiber optic strain sensing data.
Definition protocols.py:24
str to_tsv(self, str itemsep="\t")
This function returns the TSV (tab separated values) representation of this record.
Definition protocols.py:40
__init__(self, list data, **kwargs)
Constructs a SensorRecord object.
Definition protocols.py:30
Abstract base class, which deals with superflous constructor arguments.
Definition base.py:11
None extract_time_intervals(str input_file, str output_file, list list_of_time_intervals)
Extracts the parts of the measurement data into smaller .tsv files.
Definition protocols.py:603