From 5f4b6e4a551862768642b25ec9007a1445550d9d Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Mon, 3 Feb 2025 06:41:44 +0100 Subject: [PATCH 01/51] Initial import. --- core/pkt.py | 386 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 386 insertions(+) create mode 100644 core/pkt.py diff --git a/core/pkt.py b/core/pkt.py new file mode 100644 index 0000000..547934d --- /dev/null +++ b/core/pkt.py @@ -0,0 +1,386 @@ +# Copyright (C) 2025 the astropix team. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import annotations + +"""Basic packet description for the astropix chips. +""" + +import binascii +import struct + +from core.decode import Decode + + +# Table to reverse the bit order within a byte---we pre-compute this once and +# forever to speedup the computation at runtime and avoid doing the same +# calculation over and over again. +_BIT_REVERSE_TABLE = bytes.maketrans( + bytes(range(256)), + bytes(int(f'{i:08b}'[::-1], 2) for i in range(256)) +) + + +def reverse_bit_order(data: bytearray) -> None: + """Reverses the bit order within of a bytearray.""" + return data.translate(_BIT_REVERSE_TABLE) + + +class BitPattern(str): + + """Small convenience class representing a bit pattern, that we can slice + (interpreting the result as the binary representation of an integer) without + caring about the byte boundaries. + + This is not very memory-efficient and probably not blazingly fast either, but + it allows to reason about the incoming bits in a straighforward fashion, and + I doubt we will ever need to optimize this. (If that is the case, there are + probably ways, using either numpy or the bitarray third-party package.) + """ + + def __new__(cls, data: bytes) -> None: + """Strings are immutable, so use __new__ to start. + """ + return super().__new__(cls, ''.join(f'{byte:08b}' for byte in data)) + + def __getitem__(self, index): + """Slice the underlying string and convert to integer in base 2. + """ + return int(super().__getitem__(index), 2) + + +class AstroPixHitBase: + + """Base class for a generic AstroPix hit. + + While the original decode routine was working in terms of the various bytes + in the binary representation of the hit, since there seem to be no meaning + altogether in the byte boundaries (at least for AstroPix 4), and the various + fields are arbitrary subsets of a multi-byte word, it seemed more naturale to + describe the hit as a sequence of fields, each one with its own length in bits. + + + """ + + SIZE = None + FIELD_DICT = None + + def __init__(self, data: bytearray) -> None: + """Constructor. + """ + # Since we don't need the underlying bit pattern to be mutable, turn the + # bytearray object into a bytes object. + self._data = bytes(data) + # Build a bit pattern to extract the fields and loop over the hit fields + # to set all the class members. + bit_pattern = BitPattern(self._data) + pos = 0 + for name, width in self.FIELD_DICT.items(): + self.__setattr__(name, bit_pattern[pos:pos + width]) + pos += width + + @staticmethod + def gray_to_decimal(gray: int) -> int: + """Convert a Gray code (integer) to decimal. + + A Gray code (or reflected binary code) is a binary numeral system where + two consecutive values differ by only one bit, which makes it useful in + error correction and minimizing logic transitions in digital circuits. + This function is provided as a convenience to translate counter values + encoded in Gray code into actual decimal values. + """ + decimal = gray # First bit is the same + mask = gray + while mask: + mask >>= 1 + decimal ^= mask # XOR each shifted bit + return decimal + + def _format_attributes(self, attrs: tuple[str], fmts: tuple[str] = None) -> tuple[str]: + """Helper function to join a given set of class attributes in a properly + formatted string. + + Arguments + --------- + attrs : tuple + The names of the class attributes we want to include in the representation. + + fmts : tuple, optional + If present determines the formatting of the given attributes. + """ + vals = (getattr(self, attr) for attr in attrs) + if fmts is None: + fmts = ('%s' for _ in attrs) + return tuple(fmt % val for val, fmt in zip(vals, fmts)) + + def _repr(self, attrs: tuple[str], fmts: tuple[str] = None) -> str: + """Helper function to provide sensible string formatting for the packets. + + The basic idea is that concrete classes would use this to implement their + `__repr__()` and/or `__str__()` special dunder methods. + + Arguments + --------- + attrs : tuple + The names of the class attributes we want to include in the representation. + + fmts : tuple, optional + If present determines the formatting of the given attributes. + """ + vals = self._format_attributes(attrs, fmts) + info = ', '.join([f'{attr}={val}' for attr, val in zip(attrs, vals)]) + return f'{self.__class__.__name__}({info})' + + def _text(self, attrs: tuple[str], fmts: tuple[str], separator: str) -> str: + """Helper function for text formatting. + + Note the output includes a trailing endline. + + Arguments + --------- + attrs : tuple + The names of the class attributes we want to include in the representation. + + fmts : tuple, + Determines the formatting of the given attributes. + + separator : str + The separator between different fields. + """ + vals = self._format_attributes(attrs, fmts) + return f'{separator.join(vals)}\n' + + +class AstroPix4Hit(AstroPixHitBase): + + """Class describing an AstroPix4 hit. + """ + + SIZE = 8 + FIELD_DICT = { + 'chip_id': 5, + 'payload': 3, + 'row': 5, + 'column': 5, + 'ts_neg1': 1, + 'ts_coarse1': 14, + 'ts_fine1': 3, + 'ts_tdc1': 5, + 'ts_neg2': 1, + 'ts_coarse2': 14, + 'ts_fine2': 3, + 'ts_tdc2': 5 + } + _FIELD_NAMES = tuple(FIELD_DICT.keys()) + ('ts_dec1', 'ts_dec2', 'tot_us', 'timestamp') + CLOCK_CYCLES_PER_US = 20 + CLOCK_ROLLOVER = 2**17 + + def __init__(self, data: bytearray, timestamp: float = None) -> None: + """Constructor. + """ + super().__init__(data) + # Calculate the values of the two timestamps in clock cycles. + self.ts_dec1 = self._compose_timestamp(self.ts_coarse1, self.ts_fine1) + self.ts_dec2 = self._compose_timestamp(self.ts_coarse2, self.ts_fine2) + # Take into account possible rollovers. + if self.ts_dec2 < self.ts_dec1: + self.ts_dec2 += self.CLOCK_ROLLOVER + # Calculate the actual TOT in us. + self.tot_us = (self.ts_dec2 - self.ts_dec1) / self.CLOCK_CYCLES_PER_US + self.timestamp = timestamp + + @staticmethod + def _compose_timestamp(ts_coarse: int, ts_fine: int) -> int: + """Compose the actual decimal representation of the timestamp counter, + putting together the coarse and fine counters (in Gray code). + + Arguments + --------- + ts_coarse : int + The value of the coarse counter (MSBs) in Gray code. + + ts_fine : int + The value of the fine counter (3 LSBs) in Gray code. + + Returns + ------- + int + The actual decimal value of the timestamp counter, in clock cycles. + """ + return AstroPixHitBase.gray_to_decimal((ts_coarse << 3) + ts_fine) + + def to_csv(self, fields=_FIELD_NAMES) -> str: + """Return the hit representation in csv format. + """ + return self._text(fields, fmts=None, separator=',') + + def __str__(self): + """String formatting. + """ + return self._repr(self._FIELD_NAMES) + + +class AstroPix4Readout: + + """Class describing an AstroPix4 readout, i.e., a full readout from the NEXYS board. + + This comes in the form of a fixed-length bytearray object that is padded at the + end with a fixed byte (0xff). + + What remains when the padding bytes have been removed should be a sequence of + frames of the form + + bcbc ... hit data ... bcbcbcbcbcbc + + where the hit data are 8-byte long and encapsulate all the information within + a single hit. + """ + + PADDING_BYTE = bytes.fromhex('ff') + HIT_HEADER = bytes.fromhex('bcbc') + HIT_TRAILER = bytes.fromhex('bcbcbcbcbcbc') + HIT_DATA_SIZE = AstroPix4Hit.SIZE + HIT_HEADER_LENGTH = len(HIT_HEADER) + HIT_TRAILER_LENGTH = len(HIT_TRAILER) + HIT_LENGTH = HIT_HEADER_LENGTH + HIT_DATA_SIZE + HIT_TRAILER_LENGTH + + def __init__(self, data: bytearray) -> None: + """Constructor. + """ + # Strip all the trailing padding bytes from the input bytearray object. + self._data = data.rstrip(self.PADDING_BYTE) + # Check that the length of the readout is a multiple of the frame length. + if not len(self) % self.HIT_LENGTH == 0: + raise RuntimeError(f'Readout length ({len(self)}) not a multiple of {self.HIT_LENGTH}') + self.hits = self.__decode() + + def __decode(self, reverse: bool = True) -> list[AstroPix4Hit]: + """Decode the underlying data and turn them into a list of hits. + """ + hits = [] + pos = 0 + # Loop over the underlying data. + while pos < len(self): + # Select the data portion corresponding to the next frame. + hit_data = self._data[pos:pos + self.HIT_LENGTH] + + # Check that the frame header and trailer are what we expect. + header = hit_data[:self.HIT_HEADER_LENGTH] + if header != self.HIT_HEADER: + raise RuntimeError(f'Wrong frame header {header}, expected {self.HIT_HEADER}') + trailer = hit_data[-self.HIT_TRAILER_LENGTH:] + if trailer != self.HIT_TRAILER: + raise RuntimeError(f'Wrong frame trailer {header}, expected {self.HIT_TRAILER}') + + # Trim the hit data and get rid of the header and trailer. + hit_data = hit_data[self.HIT_HEADER_LENGTH:-self.HIT_TRAILER_LENGTH] + # If necessary, reverse the bit order in the hit data. + if reverse: + hit_data = reverse_bit_order(hit_data) + # Create a fully-fledged AstroPix4Hit object. + hits.append(AstroPix4Hit(hit_data)) + pos += self.HIT_LENGTH + return hits + + def num_hits(self) -> int: + """Return the number of hits in the readout. + """ + return len(self) // self.HIT_LENGTH + + def __len__(self) -> int: + """Return the length of the underlying data in bytes. + """ + return len(self._data) + + def __str__(self) -> str: + """String formatting. + """ + return f'{self.__class__.__name__}({self.num_hits()} hits, {len(self)} bytes)' + + +def test_new_parsing(data): + """Test the new parsing functionality. + """ + readout = AstroPix4Readout(data) + print(readout) + assert readout.num_hits() == 2 + for hit in readout.hits: + print(hit) + print(hit.to_csv()) + + +def test_readout(readout): + """Small test program to try and replicate what beam_test.py is doing on mock data. + + """ + # Convert the bytearray object from the board into a string + string_readout = str(binascii.hexlify(readout)) + + # When we get here, string_readout is a string looking like "b'.....'" + # First thing first, we do remove the leading "b'" and the trailing "'" + string_readout = string_readout[2:-1] + + # Now we split the thing into the single events. This goes as follows: + # * replace all the ff with bc + # * split by bc + # This leaves a loong list of strings, among which most are just empty, and the + # ones that are not are the representations of our event. + string_list = [i for i in string_readout.replace('ff','bc').split('bc') if i!=''] + + # Flag to catch potential deciding errors. This should remain True unless + # something goes wrong. + decoding_bool = True + + # Loop over the events. + for event in string_list: + # e0 is apparently the event header---if we do have a mismatch we signal + # a decoding error. + if event[0:2] != 'e0': + decoding_bool = False + print(event) + + assert decoding_bool == True + + # A couple of hard-coded variables, straight from asic.py + sampleclockperiod = 5 + num_chips = 1 + decode = Decode(sampleclockperiod, nchips=num_chips, bytesperhit=8) + + list_hits = decode.hits_from_readoutstream(readout) + df = decode.decode_astropix4_hits(list_hits, printer=True) + print(df) + return df + + +if __name__ == '__main__': + decoded_header = 'dec_ord,id,payload,row,col,ts1,tsfine1,ts2,tsfine2,tsneg1,tsneg2,tstdc1,tstdc2,ts_dec1,ts_dec2,tot_us' + decoded_fields = (0,0,7,0,5,5167,3,5418,6,1,0,0,0,49581,52836,162.75) + #readout_data = bytearray(text_data) + + mock_readout = bytearray.fromhex('bcbce08056e80da85403bcbcbcbcbcbcbcbce080d26f04ca3005bcbcbcbcbcbcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') + + byte_values = ( + (7, 1, 106, 23, 176, 21, 42, 192), + (7, 1, 75, 246, 32, 83, 12, 160) + ) + + for key, value in zip(decoded_header.split(','), decoded_fields): + print(f'{key} = {value}') + + print('Old...') + test_readout(mock_readout) + + print('New...') + test_new_parsing(mock_readout) From 08b5f99079d704097bba502a25aab72511b57621 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Mon, 3 Feb 2025 08:55:45 +0100 Subject: [PATCH 02/51] Initial import. --- tests/test_fmt.py | 120 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 tests/test_fmt.py diff --git a/tests/test_fmt.py b/tests/test_fmt.py new file mode 100644 index 0000000..8daa4b4 --- /dev/null +++ b/tests/test_fmt.py @@ -0,0 +1,120 @@ +# Copyright (C) 2025 the astropix team. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +"""Unit tests for the fmt.py module. +""" + +import binascii + +from core.decode import Decode +from core.fmt import BitPattern, AstroPix4Readout + + +# Mock data from a small test run with AstroPix4---the bytearray below should +# be exactly what might come out from a NEXYS board with the AstroPix 4 firmware. +# (For completeness, data were taken on 2024, December 19, and the array if +# taken verbatim from the log file. The readout contains exactly 2 hits.) +sample_readout_data = bytearray.fromhex('bcbce08056e80da85403bcbcbcbcbcbcbcbce080d26f04ca3005bcbcbcbcbcbcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') + +# And here are the corresponding decoded quantities from the cvs file. +decoded_header = 'dec_ord,id,payload,row,col,ts1,tsfine1,ts2,tsfine2,tsneg1,tsneg2,tstdc1,tstdc2,ts_dec1,ts_dec2,tot_us' +decoded_data0 = (0,7,0,5,5167,3,5418,6,1,0,0,0,49581,52836,162.75) +decoded_data1 = (0,7,0,5,6124,2,4876,5,0,1,0,0,54716,61369,332.65) + + +def original_decode(readout_data: bytearray): + """Original decoding function copied verbatim from beam_test.py. + + This, along with the code in decode.py, was used as a guide for the new code + in fmt.py. + """ + # Convert the bytearray object from the board into a string + string_readout = str(binascii.hexlify(readout_data)) + + # When we get here, string_readout is a string looking like "b'.....'" + # First thing first, we do remove the leading "b'" and the trailing "'" + string_readout = string_readout[2:-1] + + # Now we split the thing into the single events. This goes as follows: + # * replace all the ff with bc + # * split by bc + # This leaves a loong list of strings, among which most are just empty, and the + # ones that are not are the representations of our event. + string_list = [i for i in string_readout.replace('ff','bc').split('bc') if i!=''] + + # Flag to catch potential deciding errors. This should remain True unless + # something goes wrong. + decoding_bool = True + + # Loop over the events. + for event in string_list: + # e0 is apparently the event header---if we do have a mismatch we signal + # a decoding error. + if event[0:2] != 'e0': + decoding_bool = False + + assert decoding_bool == True + + # A couple of hard-coded variables, straight from asic.py + sampleclockperiod = 5 + num_chips = 1 + decode = Decode(sampleclockperiod, nchips=num_chips, bytesperhit=8) + + list_hits = decode.hits_from_readoutstream(readout_data) + df = decode.decode_astropix4_hits(list_hits, printer=True) + return df + + +def test_bit_pattern(): + """Small test fucntion for the BitPattern class. + """ + data = bytes.fromhex('bcff') + pattern = BitPattern(data) + print(pattern) + # Test the text representation---note the class inherits the comparison operators + # from the str class. + assert pattern == '1011110011111111' + # Same for __len__(). + assert len(pattern) == 16 + # Test slicing within the byte boundaries. + assert pattern[0:4] == 11 + assert pattern[4:8] == 12 + assert pattern[8:12] == 15 + assert pattern[12:16] == 15 + # Test slicing across bytes. + assert pattern[6:10] == 3 + + +def test_original_decoding(): + """Test that our poor-man copy of the original decode returns the same thing + we found into the csv file. + """ + df = original_decode(sample_readout_data) + print(df) + assert tuple(df.iloc[0]) == decoded_data0 + assert tuple(df.iloc[1]) == decoded_data1 + + +def test_new_decoding(): + """Test the new decoding stuff. + """ + readout = AstroPix4Readout(sample_readout_data) + print(readout) + assert readout.num_hits() == 2 + for hit in readout.hits: + print(hit) + print(hit.to_csv()) + From c25a287bcca358c88e4b8d96222850907652fe92 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Mon, 3 Feb 2025 08:56:19 +0100 Subject: [PATCH 03/51] Test code moved into an actual unit test module. --- core/{pkt.py => fmt.py} | 82 +---------------------------------------- 1 file changed, 1 insertion(+), 81 deletions(-) rename core/{pkt.py => fmt.py} (62%) diff --git a/core/pkt.py b/core/fmt.py similarity index 62% rename from core/pkt.py rename to core/fmt.py index 547934d..b932e62 100644 --- a/core/pkt.py +++ b/core/fmt.py @@ -15,14 +15,10 @@ from __future__ import annotations + """Basic packet description for the astropix chips. """ -import binascii -import struct - -from core.decode import Decode - # Table to reverse the bit order within a byte---we pre-compute this once and # forever to speedup the computation at runtime and avoid doing the same @@ -308,79 +304,3 @@ def __str__(self) -> str: """String formatting. """ return f'{self.__class__.__name__}({self.num_hits()} hits, {len(self)} bytes)' - - -def test_new_parsing(data): - """Test the new parsing functionality. - """ - readout = AstroPix4Readout(data) - print(readout) - assert readout.num_hits() == 2 - for hit in readout.hits: - print(hit) - print(hit.to_csv()) - - -def test_readout(readout): - """Small test program to try and replicate what beam_test.py is doing on mock data. - - """ - # Convert the bytearray object from the board into a string - string_readout = str(binascii.hexlify(readout)) - - # When we get here, string_readout is a string looking like "b'.....'" - # First thing first, we do remove the leading "b'" and the trailing "'" - string_readout = string_readout[2:-1] - - # Now we split the thing into the single events. This goes as follows: - # * replace all the ff with bc - # * split by bc - # This leaves a loong list of strings, among which most are just empty, and the - # ones that are not are the representations of our event. - string_list = [i for i in string_readout.replace('ff','bc').split('bc') if i!=''] - - # Flag to catch potential deciding errors. This should remain True unless - # something goes wrong. - decoding_bool = True - - # Loop over the events. - for event in string_list: - # e0 is apparently the event header---if we do have a mismatch we signal - # a decoding error. - if event[0:2] != 'e0': - decoding_bool = False - print(event) - - assert decoding_bool == True - - # A couple of hard-coded variables, straight from asic.py - sampleclockperiod = 5 - num_chips = 1 - decode = Decode(sampleclockperiod, nchips=num_chips, bytesperhit=8) - - list_hits = decode.hits_from_readoutstream(readout) - df = decode.decode_astropix4_hits(list_hits, printer=True) - print(df) - return df - - -if __name__ == '__main__': - decoded_header = 'dec_ord,id,payload,row,col,ts1,tsfine1,ts2,tsfine2,tsneg1,tsneg2,tstdc1,tstdc2,ts_dec1,ts_dec2,tot_us' - decoded_fields = (0,0,7,0,5,5167,3,5418,6,1,0,0,0,49581,52836,162.75) - #readout_data = bytearray(text_data) - - mock_readout = bytearray.fromhex('bcbce08056e80da85403bcbcbcbcbcbcbcbce080d26f04ca3005bcbcbcbcbcbcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') - - byte_values = ( - (7, 1, 106, 23, 176, 21, 42, 192), - (7, 1, 75, 246, 32, 83, 12, 160) - ) - - for key, value in zip(decoded_header.split(','), decoded_fields): - print(f'{key} = {value}') - - print('Old...') - test_readout(mock_readout) - - print('New...') - test_new_parsing(mock_readout) From 4bd3658d32430348b7640ad5e5c99c3a3dfe78c4 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Mon, 3 Feb 2025 09:02:17 +0100 Subject: [PATCH 04/51] Completed unit test. --- tests/test_fmt.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/test_fmt.py b/tests/test_fmt.py index 8daa4b4..68b74db 100644 --- a/tests/test_fmt.py +++ b/tests/test_fmt.py @@ -116,5 +116,11 @@ def test_new_decoding(): assert readout.num_hits() == 2 for hit in readout.hits: print(hit) - print(hit.to_csv()) - + hit0, hit1 = readout.hits + # Compare the hit objects with the conten of the csv files---note we are + # assuming that if the TOT value in us is ok, then all the intermediate timestamp + # fields are ok, as well. + assert (hit0.chip_id, hit0.payload, hit0.row, hit0.column) == decoded_data0[0:4] + assert hit0.tot_us == decoded_data0[-1] + assert (hit1.chip_id, hit1.payload, hit1.row, hit1.column) == decoded_data1[0:4] + assert hit1.tot_us == decoded_data1[-1] From a0837553d9a9514a8852d3535272d26b5cd67d4c Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Mon, 3 Feb 2025 11:47:20 +0100 Subject: [PATCH 05/51] First prototype of a binary output file. --- core/fmt.py | 101 +++++++++++++++++++++++++++++++++++++++++++++- tests/test_fmt.py | 53 +++++++++++++++++++++++- 2 files changed, 152 insertions(+), 2 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index b932e62..2433873 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -15,10 +15,15 @@ from __future__ import annotations - """Basic packet description for the astropix chips. """ +from contextlib import contextmanager +import json +import struct + +from modules.setup_logger import logger + # Table to reverse the bit order within a byte---we pre-compute this once and # forever to speedup the computation at runtime and avoid doing the same @@ -87,6 +92,16 @@ def __init__(self, data: bytearray) -> None: self.__setattr__(name, bit_pattern[pos:pos + width]) pos += width + def write(self, otuput_file) -> None: + """Write the binary data to a file. + """ + otuput_file.write(self._data) + + def __eq__(self, other) -> bool: + """Comparison operator---this is handy in the unit tests. + """ + return self._data == other._data + @staticmethod def gray_to_decimal(gray: int) -> int: """Convert a Gray code (integer) to decimal. @@ -304,3 +319,87 @@ def __str__(self) -> str: """String formatting. """ return f'{self.__class__.__name__}({self.num_hits()} hits, {len(self)} bytes)' + + +class FileHeader: + + """Class describing a file header. + """ + + MAGIC_WORD = '%APXDF' + _HEADER_LENGTH_FMT = 'I' + ENCODING = 'utf-8' + + def __init__(self, info) -> None: + """Constructor. + """ + self._info = info + + def write(self, output_file) -> None: + """Serialize the header structure to an output binary file. + """ + output_file.write(self.MAGIC_WORD.encode(self.ENCODING)) + data = json.dumps(self._info).encode(self.ENCODING) + num_bytes = len(data) + output_file.write(struct.pack(self._HEADER_LENGTH_FMT, num_bytes)) + output_file.write(data) + + @classmethod + def read(cls, input_file) -> 'FileHeader': + """De-serialize the header structure from an input binary file. + """ + magic = input_file.read(len(cls.MAGIC_WORD)).decode(cls.ENCODING) + if magic != cls.MAGIC_WORD: + raise RuntimeError(f'Invalid magic word ({magic}), expected {cls.MAGIC_WORD}') + buf = input_file.read(struct.calcsize(cls._HEADER_LENGTH_FMT)) + num_bytes = struct.unpack(cls._HEADER_LENGTH_FMT, buf)[0] + header_info = json.loads(input_file.read(num_bytes).decode(cls.ENCODING)) + return cls(header_info) + + def __eq__(self, other) -> bool: + """Comparison operator---this is useful in the unit tests in order to make + sure that the serialization/deserialization roundtrips. + """ + return self._info == other._info + + def __str__(self) -> str: + """String representation. + """ + return f'{self._info}' + + +class AstroPixBinaryFile: + + """Class describing a binary file containing packets. + """ + + def __init__(self, hit_class: type) -> None: + """Constructor. + """ + self._hit_class = hit_class + self._input_file = None + + @contextmanager + def open(self, file_path: str): + """Open the file. + """ + logger.debug(f'Opening input packet file {file_path}...') + with open(file_path, 'rb') as input_file: + self._input_file = input_file + self.header = FileHeader.read(self._input_file) + yield self + self._input_file = None + logger.debug(f'Input file {file_path} closed.') + + def __iter__(self) -> 'AstroPixBinaryFile': + """Return the iterator object (self). + """ + return self + + def __next__(self) -> AstroPixHitBase: + """Read the next packet in the buffer. + """ + data = self._input_file.read(self._hit_class.SIZE) + if not data: + raise StopIteration + return self._hit_class(data) \ No newline at end of file diff --git a/tests/test_fmt.py b/tests/test_fmt.py index 68b74db..51483e9 100644 --- a/tests/test_fmt.py +++ b/tests/test_fmt.py @@ -18,9 +18,10 @@ """ import binascii +import tempfile from core.decode import Decode -from core.fmt import BitPattern, AstroPix4Readout +from core.fmt import BitPattern, AstroPix4Hit, AstroPix4Readout, FileHeader, AstroPixBinaryFile # Mock data from a small test run with AstroPix4---the bytearray below should @@ -124,3 +125,53 @@ def test_new_decoding(): assert hit0.tot_us == decoded_data0[-1] assert (hit1.chip_id, hit1.payload, hit1.row, hit1.column) == decoded_data1[0:4] assert hit1.tot_us == decoded_data1[-1] + + +def test_file_header(): + """Test the file header. + """ + # Create a dummy header. + header = FileHeader(dict(version=1, content='hits')) + print(header) + + # Write the header to an output file. + with tempfile.NamedTemporaryFile('wb', delete=True, delete_on_close=False) as output_file: + print(f'Writing header to {output_file.name}...') + header.write(output_file) + output_file.close() + + # Read back the header from the output file. + print(f'Reading header from {output_file.name}...') + with open(output_file.name, 'rb') as input_file: + twin = FileHeader.read(input_file) + print(twin) + + # Make sure that the whole thing roundtrips. + assert twin == header + + +def test_file(): + """Try writing and reading a fully-fledged output file. + """ + # Create a dummy header. + header = FileHeader(dict(version=1, content='hits')) + print(header) + # Grab our test AstroPix4 hits. + readout = AstroPix4Readout(sample_readout_data) + + # Write the output file. + with tempfile.NamedTemporaryFile('wb', delete=True, delete_on_close=False) as output_file: + print(f'Writing data to {output_file.name}...') + header.write(output_file) + for hit in readout.hits: + hit.write(output_file) + output_file.close() + + # Read back the input file---note this is done in the context of the first + # with, so that tempfile can cleanup after the fact. + print(f'Reading data from {output_file.name}...') + with AstroPixBinaryFile(AstroPix4Hit).open(output_file.name) as input_file: + print(input_file.header) + for i, hit in enumerate(input_file): + print(hit) + assert hit == readout.hits[i] \ No newline at end of file From 3d8b41101b29d3b0c8b6c921133e99de41e93c7b Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Mon, 3 Feb 2025 11:48:40 +0100 Subject: [PATCH 06/51] Minor. --- core/fmt.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/fmt.py b/core/fmt.py index 2433873..9603a25 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -13,11 +13,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from __future__ import annotations """Basic packet description for the astropix chips. """ +from __future__ import annotations + from contextlib import contextmanager import json import struct From 70a676751130fc6170397f111b003ca1f4fc5470 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Mon, 3 Feb 2025 12:38:55 +0100 Subject: [PATCH 07/51] Minor. --- core/fmt.py | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index 9603a25..7c50a27 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -325,24 +325,45 @@ def __str__(self) -> str: class FileHeader: """Class describing a file header. + + The content of the header can be literally anything that is json-serializable, + i.e., the only request that we make is that ``json.dumps(self._content)`` + is not raising an exception. + + The basic contract is that when the ``write()`` method is called we write + into the output binary file: + + * the header magic word (``%APXDF`` for AstroPix Data Format); + * the length of the header content in bytes; + * the actual header content. + + In the opposite direction, when the ``read()`` hook is called, we do: + + * read the first small chunk of the binary file and make sure the magic word is correct; + * read the header length; + * read and deserialize the header conten, returning a full fledges ``FileHeader`` object. + + Arguments + --------- + content : anything that is serializable + The header content. """ MAGIC_WORD = '%APXDF' _HEADER_LENGTH_FMT = 'I' ENCODING = 'utf-8' - def __init__(self, info) -> None: + def __init__(self, content) -> None: """Constructor. """ - self._info = info + self._content = content def write(self, output_file) -> None: """Serialize the header structure to an output binary file. """ output_file.write(self.MAGIC_WORD.encode(self.ENCODING)) - data = json.dumps(self._info).encode(self.ENCODING) - num_bytes = len(data) - output_file.write(struct.pack(self._HEADER_LENGTH_FMT, num_bytes)) + data = json.dumps(self._content).encode(self.ENCODING) + output_file.write(struct.pack(self._HEADER_LENGTH_FMT, len(data))) output_file.write(data) @classmethod @@ -352,26 +373,31 @@ def read(cls, input_file) -> 'FileHeader': magic = input_file.read(len(cls.MAGIC_WORD)).decode(cls.ENCODING) if magic != cls.MAGIC_WORD: raise RuntimeError(f'Invalid magic word ({magic}), expected {cls.MAGIC_WORD}') - buf = input_file.read(struct.calcsize(cls._HEADER_LENGTH_FMT)) - num_bytes = struct.unpack(cls._HEADER_LENGTH_FMT, buf)[0] - header_info = json.loads(input_file.read(num_bytes).decode(cls.ENCODING)) - return cls(header_info) + header_length = input_file.read(struct.calcsize(cls._HEADER_LENGTH_FMT)) + header_length = struct.unpack(cls._HEADER_LENGTH_FMT, header_length)[0] + content = json.loads(input_file.read(header_length).decode(cls.ENCODING)) + return cls(content) def __eq__(self, other) -> bool: """Comparison operator---this is useful in the unit tests in order to make sure that the serialization/deserialization roundtrips. """ - return self._info == other._info + return self._content == other._content def __str__(self) -> str: """String representation. """ - return f'{self._info}' + return f'{self._content}' class AstroPixBinaryFile: """Class describing a binary file containing packets. + + .. warning:: + + At this point this only supports input files. Shall we consider extending + the interface for writing output files as well? """ def __init__(self, hit_class: type) -> None: From 9a43eb0f00e0dc04d547b37e2e156e101484391e Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Mon, 3 Feb 2025 13:39:45 +0100 Subject: [PATCH 08/51] Minor. --- tests/test_fmt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_fmt.py b/tests/test_fmt.py index 51483e9..62e6fdc 100644 --- a/tests/test_fmt.py +++ b/tests/test_fmt.py @@ -174,4 +174,4 @@ def test_file(): print(input_file.header) for i, hit in enumerate(input_file): print(hit) - assert hit == readout.hits[i] \ No newline at end of file + assert hit == readout.hits[i] From 3a5aa329ac4649f6193b0a3794211e34947af5e5 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Mon, 3 Feb 2025 14:07:49 +0100 Subject: [PATCH 09/51] Cleanup. --- core/fmt.py | 60 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index 7c50a27..ab1661f 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -22,6 +22,7 @@ from contextlib import contextmanager import json import struct +import typing from modules.setup_logger import logger @@ -50,6 +51,11 @@ class BitPattern(str): it allows to reason about the incoming bits in a straighforward fashion, and I doubt we will ever need to optimize this. (If that is the case, there are probably ways, using either numpy or the bitarray third-party package.) + + Arguments + --------- + data : bytes + The binary representation of the bit pattern. """ def __new__(cls, data: bytes) -> None: @@ -73,7 +79,10 @@ class AstroPixHitBase: fields are arbitrary subsets of a multi-byte word, it seemed more naturale to describe the hit as a sequence of fields, each one with its own length in bits. - + Arguments + --------- + data : bytearray + The portion of a full AstroPix readout representing a single hit. """ SIZE = None @@ -93,12 +102,17 @@ def __init__(self, data: bytearray) -> None: self.__setattr__(name, bit_pattern[pos:pos + width]) pos += width - def write(self, otuput_file) -> None: + def write(self, otuput_file: typing.BinaryIO) -> None: """Write the binary data to a file. + + Arguments + --------- + output_file : BinaryIO + A file object opened in "wb" mode. """ otuput_file.write(self._data) - def __eq__(self, other) -> bool: + def __eq__(self, other: 'AstroPixHitBase') -> bool: """Comparison operator---this is handy in the unit tests. """ return self._data == other._data @@ -238,7 +252,7 @@ def to_csv(self, fields=_FIELD_NAMES) -> str: """ return self._text(fields, fmts=None, separator=',') - def __str__(self): + def __str__(self) -> str: """String formatting. """ return self._repr(self._FIELD_NAMES) @@ -258,6 +272,11 @@ class AstroPix4Readout: where the hit data are 8-byte long and encapsulate all the information within a single hit. + + Arguments + --------- + data : bytearray + A full readout from a NEXYS board. """ PADDING_BYTE = bytes.fromhex('ff') @@ -280,6 +299,11 @@ def __init__(self, data: bytearray) -> None: def __decode(self, reverse: bool = True) -> list[AstroPix4Hit]: """Decode the underlying data and turn them into a list of hits. + + Arguments + --------- + reverse : bool (default True) + If True, the bit order within each byte is reversed. """ hits = [] pos = 0 @@ -353,13 +377,18 @@ class FileHeader: _HEADER_LENGTH_FMT = 'I' ENCODING = 'utf-8' - def __init__(self, content) -> None: + def __init__(self, content: typing.Any) -> None: """Constructor. """ self._content = content - def write(self, output_file) -> None: + def write(self, output_file: typing.BinaryIO) -> None: """Serialize the header structure to an output binary file. + + Arguments + --------- + output_file : BinaryIO + A file object opened in "wb" mode. """ output_file.write(self.MAGIC_WORD.encode(self.ENCODING)) data = json.dumps(self._content).encode(self.ENCODING) @@ -367,8 +396,13 @@ def write(self, output_file) -> None: output_file.write(data) @classmethod - def read(cls, input_file) -> 'FileHeader': + def read(cls, input_file: typing.BinaryIO) -> 'FileHeader': """De-serialize the header structure from an input binary file. + + Arguments + --------- + input_file : BinaryIO + A file object opened in "rb" mode. """ magic = input_file.read(len(cls.MAGIC_WORD)).decode(cls.ENCODING) if magic != cls.MAGIC_WORD: @@ -378,7 +412,7 @@ def read(cls, input_file) -> 'FileHeader': content = json.loads(input_file.read(header_length).decode(cls.ENCODING)) return cls(content) - def __eq__(self, other) -> bool: + def __eq__(self, other: 'FileHeader') -> bool: """Comparison operator---this is useful in the unit tests in order to make sure that the serialization/deserialization roundtrips. """ @@ -398,6 +432,11 @@ class AstroPixBinaryFile: At this point this only supports input files. Shall we consider extending the interface for writing output files as well? + + Arguments + --------- + hit_class : type + The class representing the hit type encoded in the file, e.g., ``AstroPix4Hit``. """ def __init__(self, hit_class: type) -> None: @@ -409,6 +448,11 @@ def __init__(self, hit_class: type) -> None: @contextmanager def open(self, file_path: str): """Open the file. + + Arguments + --------- + file_path : str + Path to the file to be read. """ logger.debug(f'Opening input packet file {file_path}...') with open(file_path, 'rb') as input_file: From 98d21eefcd0bc1ed796d281733f0cf271717eb16 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Mon, 3 Feb 2025 14:28:34 +0100 Subject: [PATCH 10/51] Minor. --- core/fmt.py | 4 ++-- tests/test_fmt.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index ab1661f..1a4b335 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -258,9 +258,9 @@ def __str__(self) -> str: return self._repr(self._FIELD_NAMES) -class AstroPix4Readout: +class AstroPixReadout: - """Class describing an AstroPix4 readout, i.e., a full readout from the NEXYS board. + """Class describing an AstroPix readout, i.e., a full readout from the NEXYS board. This comes in the form of a fixed-length bytearray object that is padded at the end with a fixed byte (0xff). diff --git a/tests/test_fmt.py b/tests/test_fmt.py index 62e6fdc..8d17b91 100644 --- a/tests/test_fmt.py +++ b/tests/test_fmt.py @@ -21,7 +21,7 @@ import tempfile from core.decode import Decode -from core.fmt import BitPattern, AstroPix4Hit, AstroPix4Readout, FileHeader, AstroPixBinaryFile +from core.fmt import BitPattern, AstroPix4Hit, AstroPixReadout, FileHeader, AstroPixBinaryFile # Mock data from a small test run with AstroPix4---the bytearray below should @@ -112,7 +112,7 @@ def test_original_decoding(): def test_new_decoding(): """Test the new decoding stuff. """ - readout = AstroPix4Readout(sample_readout_data) + readout = AstroPixReadout(sample_readout_data) print(readout) assert readout.num_hits() == 2 for hit in readout.hits: @@ -157,7 +157,7 @@ def test_file(): header = FileHeader(dict(version=1, content='hits')) print(header) # Grab our test AstroPix4 hits. - readout = AstroPix4Readout(sample_readout_data) + readout = AstroPixReadout(sample_readout_data) # Write the output file. with tempfile.NamedTemporaryFile('wb', delete=True, delete_on_close=False) as output_file: From 3ae04dee3b4fcfd6b8d8afdb49acb1837bad02bc Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Mon, 3 Feb 2025 14:51:19 +0100 Subject: [PATCH 11/51] Minor. --- core/fmt.py | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/core/fmt.py b/core/fmt.py index 1a4b335..a84edbe 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -189,6 +189,39 @@ def _text(self, attrs: tuple[str], fmts: tuple[str], separator: str) -> str: return f'{separator.join(vals)}\n' +class AstroPix3Hit(AstroPixHitBase): + + """Class describing an AstroPix3 hit. + + .. warning:: + + This is copied from decode.py and totally untested. + """ + + SIZE = 5 + FIELD_DICT = { + 'chip_id': 5, + 'payload': 3, + 'column': 1, + 'reserved1': 1, + 'location': 6, + 'timestamp': 8, + 'reserved2': 4, + 'tot_msb': 4, + 'tot_lsb': 8 + } + _FIELD_NAMES = tuple(FIELD_DICT.keys()) + ('tot', 'tot_us') + CLOCK_CYCLES_PER_US = 200. + + def __init__(self, data: bytearray) -> None: + """Constructor. + """ + super().__init__(data) + # Calculate the TOT in physical units. + self.tot = (self.tot_msb << 8) + self.tot_lsb + self.tot_us = self.tot / self.CLOCK_CYCLES_PER_US + + class AstroPix4Hit(AstroPixHitBase): """Class describing an AstroPix4 hit. @@ -210,7 +243,7 @@ class AstroPix4Hit(AstroPixHitBase): 'ts_tdc2': 5 } _FIELD_NAMES = tuple(FIELD_DICT.keys()) + ('ts_dec1', 'ts_dec2', 'tot_us', 'timestamp') - CLOCK_CYCLES_PER_US = 20 + CLOCK_CYCLES_PER_US = 20. CLOCK_ROLLOVER = 2**17 def __init__(self, data: bytearray, timestamp: float = None) -> None: From e087b08652dc6723436f68697d39971d526fc803 Mon Sep 17 00:00:00 2001 From: Luca BALDINI Date: Tue, 4 Feb 2025 14:41:05 +0100 Subject: [PATCH 12/51] Initial import. --- apx4_read.py | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 apx4_read.py diff --git a/apx4_read.py b/apx4_read.py new file mode 100644 index 0000000..8189084 --- /dev/null +++ b/apx4_read.py @@ -0,0 +1,219 @@ +""" +Updated version of beam_test.py using the astropix.py module + +Author: Autumn Bauman +Maintained by: Amanda Steinhebel, amanda.l.steinhebel@nasa.gov +""" + +#from msilib.schema import File +#from http.client import SWITCHING_PROTOCOLS +from astropix import astropixRun +import modules.hitplotter as hitplotter +import os +import binascii +import time +import logging +import argparse + +from core.fmt import AstroPixReadout, FileHeader, AstroPixBinaryFile, AstroPix4Hit + +from modules.setup_logger import logger + + + + + +def main(args): + + time_at_start=time.strftime("%Y%m%d_%H%M%S") + output_folder = os.path.join(args.outdir, time_at_start) + logger.info(f'Creating output folder {output_folder}...') + os.makedirs(output_folder) + + # Prepare everything, create the object + astro = astropixRun(chipversion=args.chipVer, inject=args.inject) + + #Initiate asic with pixel mask as defined in yaml and analog pixel in row0 defined with input argument -a + astro.asic_init(yaml=args.yaml, analog_col = args.analog) + + astro.init_voltages(vthreshold=args.threshold) + + #If injection, ensure injection pixel is enabled and initialize + if args.inject is not None: + astro.enable_pixel(args.inject[1],args.inject[0]) + astro.init_injection(inj_voltage=args.vinj, onchip=onchipBool) + + #Enable final configuration + astro.enable_spi() + astro.asic_configure() + + + if args.chipVer==4: + astro.update_asic_tdac_row(0) + logger.info("Chip configured") + astro.dump_fpga() + + if args.inject is not None: + astro.start_injection() + + max_errors = args.errormax + i = 0 + errors = 0 # Sets the threshold + if args.maxtime is not None: + end_time=time.time()+(args.maxtime*60.) + fname="" if not args.name else args.name+"_" + + # Save final configuration to output file + ymlpathout=args.outdir +"/"+args.yaml+"_"+time_at_start+".yml" + try: + astro.write_conf_to_yaml(ymlpathout) + except FileNotFoundError: + ypath = args.yaml.split('/') + ymlpathout=args.outdir+"/"+ypath[1]+"_"+time_at_start+".yml" + astro.write_conf_to_yaml(ymlpathout) + + astro.dump_fpga() + + data_file_name = f'{time_at_start}_data.apx' + data_file_path = os.path.join(output_folder, data_file_name) + logger.info(f'Opening binary file {data_file_path}...') + + output_file = open(data_file_path, 'wb') + header_data = {} + header_data['conf'] = astro.get_header_data() + header_data['args'] = args.__dict__ + header = FileHeader(header_data) + header.write(output_file) + + try: # By enclosing the main loop in try/except we are able to capture keyboard interupts cleanly + while errors <= max_errors: # Loop continues + + # This might be possible to do in the loop declaration, but its a lot easier to simply add in this logic + if args.maxruns is not None: + if i >= args.maxruns: break + if args.maxtime is not None: + if time.time() >= end_time: break + + readout_data = astro.get_readout() + + if readout_data: + readout = AstroPixReadout(readout_data, time.time()) + logger.info(readout) + for hit in readout.hits: + logger.info(hit) + hit.write(output_file) + + # Ends program cleanly when a keyboard interupt is sent. + except KeyboardInterrupt: + logger.info("Keyboard interupt. Program halt!") + # Catches other exceptions + except Exception as e: + logger.exception(f"Encountered Unexpected Exception! \n{e}") + finally: + output_file.close() + logger.info('Output file closed.') + if args.inject is not None: astro.stop_injection() + astro.close_connection() # Closes SPI + logger.info("Program terminated successfully") + # END OF PROGRAM + + # Test: playback the file. + with AstroPixBinaryFile(AstroPix4Hit).open(data_file_path) as input_file: + print('\n\n') + print('File header:', input_file.header) + for hit in input_file: + print(hit.tot_us) + + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description='Astropix Driver Code') + parser.add_argument('-n', '--name', default='', required=False, + help='Option to give additional name to output files upon running') + + parser.add_argument('-o', '--outdir', default='.', required=False, + help='Output Directory for all datafiles') + + parser.add_argument('-y', '--yaml', action='store', required=False, type=str, default = 'testconfig', + help = 'filepath (in config/ directory) .yml file containing chip configuration. Default: config/testconfig.yml (All pixels off)') + + parser.add_argument('-V', '--chipVer', default=2, required=False, type=int, + help='Chip version - provide an int') + + parser.add_argument('-s', '--showhits', action='store_true', + default=False, required=False, + help='Display hits in real time during data taking') + + parser.add_argument('-p', '--plotsave', action='store_true', default=False, required=False, + help='Save plots as image files. If set, will be saved in same dir as data. Default: FALSE') + + parser.add_argument('-c', '--saveascsv', action='store_true', + default=False, required=False, + help='save output files as CSV. If False, save as txt. Default: FALSE') + + parser.add_argument('-f', '--newfilter', action='store_true', + default=False, required=False, + help='Turns on filtering of strings looking for header of e0 in V4. If False, no filtering. Default: FALSE') + + parser.add_argument('-i', '--inject', action='store', default=None, type=int, nargs=2, + help = 'Turn on injection in the given row and column. Default: No injection') + + parser.add_argument('-v','--vinj', action='store', default = None, type=float, + help = 'Specify injection voltage (in mV). DEFAULT None (uses value in yml)') + + parser.add_argument('-a', '--analog', action='store', required=False, type=int, default = 0, + help = 'Turn on analog output in the given column. Default: Column 0.') + + parser.add_argument('-t', '--threshold', type = float, action='store', default=None, + help = 'Threshold voltage for digital ToT (in mV). DEFAULT value in yml OR 100mV if voltagecard not in yml') + + parser.add_argument('-E', '--errormax', action='store', type=int, default='100', + help='Maximum index errors allowed during decoding. DEFAULT 100') + + parser.add_argument('-r', '--maxruns', type=int, action='store', default=None, + help = 'Maximum number of readouts') + + parser.add_argument('-M', '--maxtime', type=float, action='store', default=None, + help = 'Maximum run time (in minutes)') + + parser.add_argument('--timeit', action="store_true", default=False, + help='Prints runtime from seeing a hit to finishing the decode to terminal') + + parser.add_argument('-L', '--loglevel', type=str, choices = ['D', 'I', 'E', 'W', 'C'], action="store", default='I', + help='Set loglevel used. Options: D - debug, I - info, E - error, W - warning, C - critical. DEFAULT: I') + + parser.add_argument + args = parser.parse_args() + + # Sets the loglevel + ll = args.loglevel + if ll == 'D': + loglevel = logging.DEBUG + elif ll == 'I': + loglevel = logging.INFO + elif ll == 'E': + loglevel = logging.ERROR + elif ll == 'W': + loglevel = logging.WARNING + elif ll == 'C': + loglevel = logging.CRITICAL + + # Logging + formatter = logging.Formatter('%(asctime)s:%(msecs)d.%(name)s.%(levelname)s:%(message)s') + #fh = logging.FileHandler(logname) + #fh.setFormatter(formatter) + sh = logging.StreamHandler() + sh.setFormatter(formatter) + + logging.getLogger().addHandler(sh) + #logging.getLogger().addHandler(fh) + logging.getLogger().setLevel(loglevel) + + logger = logging.getLogger(__name__) + + #If using v2, use injection created by injection card + #If using v3, use injection created with integrated DACs on chip + onchipBool = True if args.chipVer > 2 else False + + main(args) From c428522d68a514ed2c9f8c515b15514f6e80c9eb Mon Sep 17 00:00:00 2001 From: Luca BALDINI Date: Tue, 4 Feb 2025 14:42:01 +0100 Subject: [PATCH 13/51] Added function to get the header data before they are turned into a string. --- astropix.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/astropix.py b/astropix.py index 866fbf4..e83a2a8 100644 --- a/astropix.py +++ b/astropix.py @@ -367,6 +367,31 @@ def hits_present(self): return True else: return False + + def get_header_data(self): + """Return a dictionary with all the data for the data file header. + """ + vdacs=['thpmos', 'cardConf2','vcasc2', 'BL', 'cardConf5', 'cardConf6','vminuspix','thpix'] + vcardconfig = {} + for i,v in enumerate(vdacs): + vcardconfig[v] = self.vcard_vdac[i] + digitalconfig = {} + for key in self.asic.asic_config['digitalconfig']: + digitalconfig[key]=self.asic.asic_config['digitalconfig'][key][1] + biasconfig = {} + for key in self.asic.asic_config['biasconfig']: + biasconfig[key]=self.asic.asic_config['biasconfig'][key][1] + idacconfig = {} + for key in self.asic.asic_config['idacs']: + idacconfig[key]=self.asic.asic_config['idacs'][key][1] + if self.chipversion>2: + vdacconfig = {} + for key in self.asic.asic_config['vdacs']: + vdacconfig[key]=self.asic.asic_config['vdacs'][key][1] + arrayconfig = {} + for key in self.asic.asic_config['recconfig']: + arrayconfig[key]=self.asic.asic_config['recconfig'][key][1] + return (vcardconfig, digitalconfig, biasconfig, idacconfig, vdacconfig, arrayconfig) def get_log_header(self): """ From 1a2e44a7aa9fae6407d90926277afa0df90552fd Mon Sep 17 00:00:00 2001 From: Luca BALDINI Date: Tue, 4 Feb 2025 14:42:47 +0100 Subject: [PATCH 14/51] Timestamp added. --- core/fmt.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index a84edbe..96374a5 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -310,6 +310,9 @@ class AstroPixReadout: --------- data : bytearray A full readout from a NEXYS board. + + timestamp : float (optional) + A timestamp (s since the epoch) assigned by the hist machine. """ PADDING_BYTE = bytes.fromhex('ff') @@ -320,7 +323,7 @@ class AstroPixReadout: HIT_TRAILER_LENGTH = len(HIT_TRAILER) HIT_LENGTH = HIT_HEADER_LENGTH + HIT_DATA_SIZE + HIT_TRAILER_LENGTH - def __init__(self, data: bytearray) -> None: + def __init__(self, data: bytearray, timestamp: int = None) -> None: """Constructor. """ # Strip all the trailing padding bytes from the input bytearray object. @@ -328,6 +331,7 @@ def __init__(self, data: bytearray) -> None: # Check that the length of the readout is a multiple of the frame length. if not len(self) % self.HIT_LENGTH == 0: raise RuntimeError(f'Readout length ({len(self)}) not a multiple of {self.HIT_LENGTH}') + self.timestamp = timestamp self.hits = self.__decode() def __decode(self, reverse: bool = True) -> list[AstroPix4Hit]: @@ -359,7 +363,7 @@ def __decode(self, reverse: bool = True) -> list[AstroPix4Hit]: if reverse: hit_data = reverse_bit_order(hit_data) # Create a fully-fledged AstroPix4Hit object. - hits.append(AstroPix4Hit(hit_data)) + hits.append(AstroPix4Hit(hit_data, self.timestamp)) pos += self.HIT_LENGTH return hits @@ -376,7 +380,7 @@ def __len__(self) -> int: def __str__(self) -> str: """String formatting. """ - return f'{self.__class__.__name__}({self.num_hits()} hits, {len(self)} bytes)' + return f'{self.__class__.__name__}({self.num_hits()} hits, {len(self)} bytes, timestamp = {self.timestamp} s)' class FileHeader: From ef51f918a4780cd85542243972fbccbd0458751d Mon Sep 17 00:00:00 2001 From: Luca BALDINI Date: Tue, 4 Feb 2025 14:48:43 +0100 Subject: [PATCH 15/51] Minor. --- apx4_read.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apx4_read.py b/apx4_read.py index 8189084..4d8b207 100644 --- a/apx4_read.py +++ b/apx4_read.py @@ -109,12 +109,12 @@ def main(args): # Catches other exceptions except Exception as e: logger.exception(f"Encountered Unexpected Exception! \n{e}") - finally: - output_file.close() - logger.info('Output file closed.') - if args.inject is not None: astro.stop_injection() - astro.close_connection() # Closes SPI - logger.info("Program terminated successfully") + + output_file.close() + logger.info('Output file closed.') + if args.inject is not None: astro.stop_injection() + astro.close_connection() # Closes SPI + logger.info("Program terminated successfully") # END OF PROGRAM # Test: playback the file. From 91ac58c52fc806e82a59f5efaf283d7384a31f1e Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Tue, 4 Feb 2025 15:39:41 +0100 Subject: [PATCH 16/51] Cleanup. --- apx4_read.py | 283 ++++++++++++++++++++++++++------------------------- 1 file changed, 144 insertions(+), 139 deletions(-) diff --git a/apx4_read.py b/apx4_read.py index 4d8b207..c01b5c8 100644 --- a/apx4_read.py +++ b/apx4_read.py @@ -1,219 +1,224 @@ -""" -Updated version of beam_test.py using the astropix.py module +# Copyright (C) 2025 the astropix team. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . -Author: Autumn Bauman -Maintained by: Amanda Steinhebel, amanda.l.steinhebel@nasa.gov -""" -#from msilib.schema import File -#from http.client import SWITCHING_PROTOCOLS from astropix import astropixRun -import modules.hitplotter as hitplotter import os -import binascii import time import logging import argparse from core.fmt import AstroPixReadout, FileHeader, AstroPixBinaryFile, AstroPix4Hit -from modules.setup_logger import logger +def setup_logger(level: str, file_path: str = None): + """Setup the logger. + + .. warning:: + + This should probably be factored out in a module that all the scripts + ca use, rather than coding the same thing over and over again. + + Arguments + --------- + level : str + The logging level (D, I, W, E, C) + + file_path : str (optional) + The path to the output log file. + """ + _logging_dict = {'D': logging.DEBUG, 'I': logging.INFO, 'W': logging.WARNING, + 'E': logging.ERROR, 'C': logging.CRITICAL} + + try: + level = _logging_dict[level] + except KeyError: + raise RuntimeError(f'Unrecognized logging level "{level}"') + + formatter = logging.Formatter('%(asctime)s:%(msecs)d.%(name)s.%(levelname)s:%(message)s') + stream_handler = logging.StreamHandler() + stream_handler.setFormatter(formatter) + logging.getLogger().addHandler(stream_handler) + if file_path is not None: + file_handler = logging.FileHandler(file_path) + file_handler.setFormatter(formatter) + logging.getLogger().addHandler(file_handler) + + logging.getLogger().setLevel(level) + logger = logging.getLogger(__name__) + return logger + + +def playback_file(file_path: str, num_hits: int = 10) -> None: + """Small test code to playback a file. + """ + with AstroPixBinaryFile(AstroPix4Hit).open(file_path) as input_file: + print(f'\nStarting playback of binary file {file_path}...') + print(f'File header: {input_file.header}') + for i, hit in enumerate(input_file): + if i < num_hits: + print(hit) + elif hit == num_hits: + print('...') + print(f'{i} hits found') - def main(args): + """Configure and run an AstroPix 4 chip. + """ + # A couple of hard-coded parameters---this is currently only supporting AstroPix v4! + chip_version = 4 + ci_on_chip = True - time_at_start=time.strftime("%Y%m%d_%H%M%S") - output_folder = os.path.join(args.outdir, time_at_start) - logger.info(f'Creating output folder {output_folder}...') - os.makedirs(output_folder) + # Latch the start date and time---this will be used for naming the output products. + start_datetime = time.strftime("%Y%m%d_%H%M%S") - # Prepare everything, create the object - astro = astropixRun(chipversion=args.chipVer, inject=args.inject) + # Create the output folder. + output_folder = os.path.join(args.outdir, start_datetime) + os.makedirs(output_folder) - #Initiate asic with pixel mask as defined in yaml and analog pixel in row0 defined with input argument -a - astro.asic_init(yaml=args.yaml, analog_col = args.analog) + # Setup the logger. + log_file_name = f'{start_datetime}.log' + log_file_path = os.path.join(output_folder, log_file_name) + logger = setup_logger(args.loglevel, log_file_path) - astro.init_voltages(vthreshold=args.threshold) + # Setup the data acquisition. + logger.info('Configuring the chip...') + astro = astropixRun(chipversion=args.chipVer, inject=args.inject) + astro.asic_init(yaml=args.yaml, analog_col=args.analog) + astro.init_voltages(vthreshold=args.threshold) - #If injection, ensure injection pixel is enabled and initialize + # If injection, ensure injection pixel is enabled and initialize. if args.inject is not None: - astro.enable_pixel(args.inject[1],args.inject[0]) - astro.init_injection(inj_voltage=args.vinj, onchip=onchipBool) + astro.enable_pixel(args.inject[1], args.inject[0]) + astro.init_injection(inj_voltage=args.vinj, onchip=ci_on_chip) - #Enable final configuration - astro.enable_spi() + # Enable final configuration. + astro.enable_spi() astro.asic_configure() - - - if args.chipVer==4: + if chip_version == 4: astro.update_asic_tdac_row(0) - logger.info("Chip configured") + logger.info('Chip fully configured!') + + # What is this doing? astro.dump_fpga() if args.inject is not None: astro.start_injection() - max_errors = args.errormax - i = 0 - errors = 0 # Sets the threshold - if args.maxtime is not None: - end_time=time.time()+(args.maxtime*60.) - fname="" if not args.name else args.name+"_" - - # Save final configuration to output file - ymlpathout=args.outdir +"/"+args.yaml+"_"+time_at_start+".yml" + # Save final configuration to output file + ymlpathout=args.outdir +"/"+args.yaml+"_"+start_datetime+".yml" try: astro.write_conf_to_yaml(ymlpathout) except FileNotFoundError: ypath = args.yaml.split('/') - ymlpathout=args.outdir+"/"+ypath[1]+"_"+time_at_start+".yml" + ymlpathout=args.outdir+"/"+ypath[1]+"_"+start_datetime+".yml" astro.write_conf_to_yaml(ymlpathout) + # Do we really need a second call to this? astro.dump_fpga() - data_file_name = f'{time_at_start}_data.apx' - data_file_path = os.path.join(output_folder, data_file_name) - logger.info(f'Opening binary file {data_file_path}...') - - output_file = open(data_file_path, 'wb') + # Setup exit conditions + if args.maxtime is not None: + stop_time = time.time() + args.maxtime * 60. + else: + stop_time = None + if args.maxruns is not None: + max_num_readouts = args.maxruns + else: + max_num_readouts = None + + # Preparation of the file header. Note we can put literally anything that is + # serializable in the header, and for the time being we are just grabbing + # anything that used to end up in the original log (i.e., data) file. + # This is an area where we might want to put some thought as to what the most + # sensible way to handle things is. header_data = {} header_data['conf'] = astro.get_header_data() header_data['args'] = args.__dict__ header = FileHeader(header_data) + + # Open the output file and write the header. + data_file_name = f'{start_datetime}_data.apx' + data_file_path = os.path.join(output_folder, data_file_name) + logger.info(f'Opening binary file {data_file_path}...') + output_file = open(data_file_path, 'wb') header.write(output_file) - - try: # By enclosing the main loop in try/except we are able to capture keyboard interupts cleanly - while errors <= max_errors: # Loop continues - - # This might be possible to do in the loop declaration, but its a lot easier to simply add in this logic - if args.maxruns is not None: - if i >= args.maxruns: break - if args.maxtime is not None: - if time.time() >= end_time: break - - readout_data = astro.get_readout() + # Start the event loop. + # By enclosing the main loop in try/except we are able to capture keyboard interupts cleanly + num_readouts = 0 + try: + while 1: + # Check the stop conditions. + if stop_time is not None and time.time() >= stop_time: + break + if max_num_readouts is not None and num_readouts >= max_num_readouts: + break + # Go ahead and readout data. + readout_data = astro.get_readout() if readout_data: readout = AstroPixReadout(readout_data, time.time()) - logger.info(readout) + logger.debug(readout) for hit in readout.hits: - logger.info(hit) + logger.debug(hit) hit.write(output_file) + num_readouts += 1 # Ends program cleanly when a keyboard interupt is sent. except KeyboardInterrupt: - logger.info("Keyboard interupt. Program halt!") - # Catches other exceptions - except Exception as e: - logger.exception(f"Encountered Unexpected Exception! \n{e}") + logger.info('Keyboard interupt, exiting...') output_file.close() logger.info('Output file closed.') - if args.inject is not None: astro.stop_injection() - astro.close_connection() # Closes SPI - logger.info("Program terminated successfully") - # END OF PROGRAM - # Test: playback the file. - with AstroPixBinaryFile(AstroPix4Hit).open(data_file_path) as input_file: - print('\n\n') - print('File header:', input_file.header) - for hit in input_file: - print(hit.tot_us) + # Teardown the hardware. + if args.inject is not None: + astro.stop_injection() + astro.close_connection() + logger.info("Program terminated successfully!") + playback_file(data_file_path) - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Astropix Driver Code') - parser.add_argument('-n', '--name', default='', required=False, - help='Option to give additional name to output files upon running') - parser.add_argument('-o', '--outdir', default='.', required=False, - help='Output Directory for all datafiles') +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description='Astropix 4 simple run control') + parser.add_argument('-o', '--outdir', default='.', required=False, + help='Output Directory for all data files') parser.add_argument('-y', '--yaml', action='store', required=False, type=str, default = 'testconfig', help = 'filepath (in config/ directory) .yml file containing chip configuration. Default: config/testconfig.yml (All pixels off)') - - parser.add_argument('-V', '--chipVer', default=2, required=False, type=int, - help='Chip version - provide an int') - - parser.add_argument('-s', '--showhits', action='store_true', - default=False, required=False, - help='Display hits in real time during data taking') - - parser.add_argument('-p', '--plotsave', action='store_true', default=False, required=False, - help='Save plots as image files. If set, will be saved in same dir as data. Default: FALSE') - - parser.add_argument('-c', '--saveascsv', action='store_true', - default=False, required=False, - help='save output files as CSV. If False, save as txt. Default: FALSE') - - parser.add_argument('-f', '--newfilter', action='store_true', - default=False, required=False, - help='Turns on filtering of strings looking for header of e0 in V4. If False, no filtering. Default: FALSE') - parser.add_argument('-i', '--inject', action='store', default=None, type=int, nargs=2, help = 'Turn on injection in the given row and column. Default: No injection') - parser.add_argument('-v','--vinj', action='store', default = None, type=float, help = 'Specify injection voltage (in mV). DEFAULT None (uses value in yml)') - parser.add_argument('-a', '--analog', action='store', required=False, type=int, default = 0, help = 'Turn on analog output in the given column. Default: Column 0.') - parser.add_argument('-t', '--threshold', type = float, action='store', default=None, help = 'Threshold voltage for digital ToT (in mV). DEFAULT value in yml OR 100mV if voltagecard not in yml') - - parser.add_argument('-E', '--errormax', action='store', type=int, default='100', - help='Maximum index errors allowed during decoding. DEFAULT 100') - parser.add_argument('-r', '--maxruns', type=int, action='store', default=None, help = 'Maximum number of readouts') - parser.add_argument('-M', '--maxtime', type=float, action='store', default=None, help = 'Maximum run time (in minutes)') - - parser.add_argument('--timeit', action="store_true", default=False, - help='Prints runtime from seeing a hit to finishing the decode to terminal') - parser.add_argument('-L', '--loglevel', type=str, choices = ['D', 'I', 'E', 'W', 'C'], action="store", default='I', help='Set loglevel used. Options: D - debug, I - info, E - error, W - warning, C - critical. DEFAULT: I') parser.add_argument args = parser.parse_args() - # Sets the loglevel - ll = args.loglevel - if ll == 'D': - loglevel = logging.DEBUG - elif ll == 'I': - loglevel = logging.INFO - elif ll == 'E': - loglevel = logging.ERROR - elif ll == 'W': - loglevel = logging.WARNING - elif ll == 'C': - loglevel = logging.CRITICAL - - # Logging - formatter = logging.Formatter('%(asctime)s:%(msecs)d.%(name)s.%(levelname)s:%(message)s') - #fh = logging.FileHandler(logname) - #fh.setFormatter(formatter) - sh = logging.StreamHandler() - sh.setFormatter(formatter) - - logging.getLogger().addHandler(sh) - #logging.getLogger().addHandler(fh) - logging.getLogger().setLevel(loglevel) - - logger = logging.getLogger(__name__) - - #If using v2, use injection created by injection card - #If using v3, use injection created with integrated DACs on chip - onchipBool = True if args.chipVer > 2 else False - main(args) From 4105f295dd8727267c74be93428731fc4f59514a Mon Sep 17 00:00:00 2001 From: Luca BALDINI Date: Tue, 4 Feb 2025 15:59:17 +0100 Subject: [PATCH 17/51] Cleanup. --- apx4_read.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/apx4_read.py b/apx4_read.py index c01b5c8..1ccc62a 100644 --- a/apx4_read.py +++ b/apx4_read.py @@ -71,9 +71,9 @@ def playback_file(file_path: str, num_hits: int = 10) -> None: for i, hit in enumerate(input_file): if i < num_hits: print(hit) - elif hit == num_hits: + elif i == num_hits: print('...') - print(f'{i} hits found') + print(f'{i + 1} hits found') def main(args): @@ -97,7 +97,7 @@ def main(args): # Setup the data acquisition. logger.info('Configuring the chip...') - astro = astropixRun(chipversion=args.chipVer, inject=args.inject) + astro = astropixRun(chipversion=chip_version, inject=args.inject) astro.asic_init(yaml=args.yaml, analog_col=args.analog) astro.init_voltages(vthreshold=args.threshold) @@ -120,13 +120,10 @@ def main(args): astro.start_injection() # Save final configuration to output file - ymlpathout=args.outdir +"/"+args.yaml+"_"+start_datetime+".yml" - try: - astro.write_conf_to_yaml(ymlpathout) - except FileNotFoundError: - ypath = args.yaml.split('/') - ymlpathout=args.outdir+"/"+ypath[1]+"_"+start_datetime+".yml" - astro.write_conf_to_yaml(ymlpathout) + config_file_name = f'{args.yaml}_{start_datetime}.yml' + config_file_path = os.path.join(output_folder, config_file_name) + logger.info(f'Copying configuration to {config_file_path}...') + astro.write_conf_to_yaml(config_file_path) # Do we really need a second call to this? astro.dump_fpga() @@ -182,6 +179,7 @@ def main(args): except KeyboardInterrupt: logger.info('Keyboard interupt, exiting...') + logger.info(f'Data acquisition interrupted after {num_readouts} readouts.') output_file.close() logger.info('Output file closed.') From f97ce29dd7e3a28decad271677b5277590b5a8bf Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Tue, 4 Feb 2025 18:26:34 +0100 Subject: [PATCH 18/51] Added apx to csv converter. --- core/fmt.py | 42 +++++++++++++++++++++++++--- tests/data/20250204_144725_data.apx | Bin 0 -> 7639 bytes tests/test_fmt.py | 18 ++++++++++-- 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 tests/data/20250204_144725_data.apx diff --git a/core/fmt.py b/core/fmt.py index 96374a5..43d61ed 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -280,6 +280,12 @@ def _compose_timestamp(ts_coarse: int, ts_fine: int) -> int: """ return AstroPixHitBase.gray_to_decimal((ts_coarse << 3) + ts_fine) + @classmethod + def text_header(cls, fields=_FIELD_NAMES, separator=',') -> str: + """Return a proper header for a text file representing a list of hits. + """ + return ','.join(fields) + def to_csv(self, fields=_FIELD_NAMES) -> str: """Return the hit representation in csv format. """ @@ -312,7 +318,7 @@ class AstroPixReadout: A full readout from a NEXYS board. timestamp : float (optional) - A timestamp (s since the epoch) assigned by the hist machine. + A timestamp (s since the epoch) assigned by the hist machine. """ PADDING_BYTE = bytes.fromhex('ff') @@ -476,6 +482,8 @@ class AstroPixBinaryFile: The class representing the hit type encoded in the file, e.g., ``AstroPix4Hit``. """ + _EXTENSION = '.apx' + def __init__(self, hit_class: type) -> None: """Constructor. """ @@ -491,13 +499,15 @@ def open(self, file_path: str): file_path : str Path to the file to be read. """ - logger.debug(f'Opening input packet file {file_path}...') + if not file_path.endswith(self._EXTENSION): + raise RuntimeError(f'Input file {file_path} has not the {self._EXTENSION} extension') + logger.info(f'Opening input packet file {file_path}...') with open(file_path, 'rb') as input_file: self._input_file = input_file self.header = FileHeader.read(self._input_file) yield self self._input_file = None - logger.debug(f'Input file {file_path} closed.') + logger.info(f'Input file {file_path} closed.') def __iter__(self) -> 'AstroPixBinaryFile': """Return the iterator object (self). @@ -510,4 +520,28 @@ def __next__(self) -> AstroPixHitBase: data = self._input_file.read(self._hit_class.SIZE) if not data: raise StopIteration - return self._hit_class(data) \ No newline at end of file + return self._hit_class(data) + + +def _convert_apxdf(file_path: str, hit_class: type, converter: typing.Callable, + header: str = None, output_file_path: str = None, open_mode: str = 'w', + default_extension: str = None) -> str: + """Generic conversion factory for AstroPixBinaryFile objects. + """ + if output_file_path is None and default_extension is not None: + output_file_path = file_path.replace('.apx', default_extension) + with AstroPixBinaryFile(hit_class).open(file_path) as input_file, \ + open(output_file_path, open_mode) as output_file: + if header is not None: + output_file.write(header) + for hit in input_file: + output_file.write(converter(hit)) + return output_file_path + + +def apxdf_to_csv(file_path: str, hit_class: type = AstroPix4Hit, + output_file_path: str = None) -> str: + """Convert an AstroPix binary file to csv. + """ + header = f'# {AstroPix4Hit.text_header()}\n' + return _convert_apxdf(file_path, hit_class, hit_class.to_csv, header, output_file_path, 'w', '.csv') diff --git a/tests/data/20250204_144725_data.apx b/tests/data/20250204_144725_data.apx new file mode 100644 index 0000000000000000000000000000000000000000..0cf87a9f11f11d53d07daa1e4bba4830f54d8c6a GIT binary patch literal 7639 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 rVBmPo#(X5?vDz^-f+M#p Date: Tue, 4 Feb 2025 18:33:16 +0100 Subject: [PATCH 19/51] A couple of methods moved to a base class. --- core/fmt.py | 37 +++++++++++++++++++++---------------- tests/test_fmt.py | 15 +++++++++------ 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index 43d61ed..01a1101 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -87,6 +87,7 @@ class AstroPixHitBase: SIZE = None FIELD_DICT = None + _FIELD_NAMES = None def __init__(self, data: bytearray) -> None: """Constructor. @@ -188,6 +189,26 @@ def _text(self, attrs: tuple[str], fmts: tuple[str], separator: str) -> str: vals = self._format_attributes(attrs, fmts) return f'{separator.join(vals)}\n' + @classmethod + def text_header(cls, fields=None, separator=',') -> str: + """Return a proper header for a text file representing a list of hits. + """ + if fields is None: + fields = cls._FIELD_NAMES + return ','.join(fields) + + def to_csv(self, fields=None) -> str: + """Return the hit representation in csv format. + """ + if fields is None: + fields = self._FIELD_NAMES + return self._text(fields, fmts=None, separator=',') + + def __str__(self) -> str: + """String formatting. + """ + return self._repr(self._FIELD_NAMES) + class AstroPix3Hit(AstroPixHitBase): @@ -280,22 +301,6 @@ def _compose_timestamp(ts_coarse: int, ts_fine: int) -> int: """ return AstroPixHitBase.gray_to_decimal((ts_coarse << 3) + ts_fine) - @classmethod - def text_header(cls, fields=_FIELD_NAMES, separator=',') -> str: - """Return a proper header for a text file representing a list of hits. - """ - return ','.join(fields) - - def to_csv(self, fields=_FIELD_NAMES) -> str: - """Return the hit representation in csv format. - """ - return self._text(fields, fmts=None, separator=',') - - def __str__(self) -> str: - """String formatting. - """ - return self._repr(self._FIELD_NAMES) - class AstroPixReadout: diff --git a/tests/test_fmt.py b/tests/test_fmt.py index 86d9cc3..f3c8750 100644 --- a/tests/test_fmt.py +++ b/tests/test_fmt.py @@ -21,6 +21,8 @@ import os import tempfile +import pytest + from core.decode import Decode from core.fmt import BitPattern, AstroPix4Hit, AstroPixReadout, FileHeader, \ AstroPixBinaryFile, apxdf_to_csv @@ -181,9 +183,10 @@ def test_file(): assert hit == readout.hits[i] -# def test_csv_convert(): -# """Read a sample .apx file and convert it to csv. -# """ -# file_path = os.path.join(os.path.dirname(__file__), 'data', '20250204_144725_data.apx') -# file_path = apxdf_to_csv(file_path, AstroPix4Hit) -# print(file_path) +@pytest.mark.skip +def test_csv_convert(): + """Read a sample .apx file and convert it to csv. + """ + file_path = os.path.join(os.path.dirname(__file__), 'data', '20250204_144725_data.apx') + file_path = apxdf_to_csv(file_path, AstroPix4Hit) + assert isinstance(file_path, str) From 495239dea520f7a57ab9947f1f2cb909968ccf0d Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Tue, 4 Feb 2025 20:40:59 +0100 Subject: [PATCH 20/51] Minor. --- tests/test_fmt.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_fmt.py b/tests/test_fmt.py index f3c8750..593bd0c 100644 --- a/tests/test_fmt.py +++ b/tests/test_fmt.py @@ -20,6 +20,7 @@ import binascii import os import tempfile +import time import pytest @@ -116,7 +117,7 @@ def test_original_decoding(): def test_new_decoding(): """Test the new decoding stuff. """ - readout = AstroPixReadout(sample_readout_data) + readout = AstroPixReadout(sample_readout_data, timestamp=time.time()) print(readout) assert readout.num_hits() == 2 for hit in readout.hits: @@ -162,7 +163,7 @@ def test_file(): header = FileHeader(dict(version=1, content='hits')) print(header) # Grab our test AstroPix4 hits. - readout = AstroPixReadout(sample_readout_data) + readout = AstroPixReadout(sample_readout_data, timestamp=time.time()) # Write the output file. kwargs = dict(suffix=AstroPixBinaryFile._EXTENSION, delete_on_close=False, delete=True) From c8497272e4c46bdb24efb79ceb5548876459daad Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 5 Feb 2025 08:24:42 +0100 Subject: [PATCH 21/51] Minor. --- apx4_read.py | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/apx4_read.py b/apx4_read.py index 1ccc62a..7f9e349 100644 --- a/apx4_read.py +++ b/apx4_read.py @@ -20,7 +20,7 @@ import logging import argparse -from core.fmt import AstroPixReadout, FileHeader, AstroPixBinaryFile, AstroPix4Hit +from core.fmt import AstroPixReadout, FileHeader, AstroPixBinaryFile, AstroPix4Hit, apxdf_to_csv @@ -64,6 +64,8 @@ def setup_logger(level: str, file_path: str = None): def playback_file(file_path: str, num_hits: int = 10) -> None: """Small test code to playback a file. + + Move this to the unit tests! """ with AstroPixBinaryFile(AstroPix4Hit).open(file_path) as input_file: print(f'\nStarting playback of binary file {file_path}...') @@ -169,9 +171,11 @@ def main(args): readout_data = astro.get_readout() if readout_data: readout = AstroPixReadout(readout_data, time.time()) - logger.debug(readout) + if args.showhits: + print(readout) for hit in readout.hits: - logger.debug(hit) + if args.showhits: + print(hit) hit.write(output_file) num_readouts += 1 @@ -189,32 +193,37 @@ def main(args): astro.close_connection() logger.info("Program terminated successfully!") - playback_file(data_file_path) - - + if args.saveascsv: + file_path = apxdf_to_csv(data_file_path, AstroPix4Hit) if __name__ == "__main__": parser = argparse.ArgumentParser(description='Astropix 4 simple run control') parser.add_argument('-o', '--outdir', default='.', required=False, - help='Output Directory for all data files') + help='Output Directory for all data files') parser.add_argument('-y', '--yaml', action='store', required=False, type=str, default = 'testconfig', - help = 'filepath (in config/ directory) .yml file containing chip configuration. Default: config/testconfig.yml (All pixels off)') + help = 'filepath (in config/ directory) .yml file containing chip configuration. ' + 'Default: config/testconfig.yml (All pixels off)') + parser.add_argument('-s', '--showhits', action='store_true', default=False, required=False, + help='Display hits in real time during data taking') + parser.add_argument('-c', '--saveascsv', action='store_true', default=False, required=False, + help='Convert output file to csv.') parser.add_argument('-i', '--inject', action='store', default=None, type=int, nargs=2, - help = 'Turn on injection in the given row and column. Default: No injection') + help = 'Turn on injection in the given row and column. Default: No injection') parser.add_argument('-v','--vinj', action='store', default = None, type=float, - help = 'Specify injection voltage (in mV). DEFAULT None (uses value in yml)') + help = 'Specify injection voltage (in mV). DEFAULT None (uses value in yml)') parser.add_argument('-a', '--analog', action='store', required=False, type=int, default = 0, - help = 'Turn on analog output in the given column. Default: Column 0.') + help = 'Turn on analog output in the given column. Default: Column 0.') parser.add_argument('-t', '--threshold', type = float, action='store', default=None, - help = 'Threshold voltage for digital ToT (in mV). DEFAULT value in yml OR 100mV if voltagecard not in yml') + help = 'Threshold voltage for digital ToT (in mV). DEFAULT value in yml OR 100mV if voltagecard not in yml') parser.add_argument('-r', '--maxruns', type=int, action='store', default=None, - help = 'Maximum number of readouts') + help = 'Maximum number of readouts') parser.add_argument('-M', '--maxtime', type=float, action='store', default=None, - help = 'Maximum run time (in minutes)') + help = 'Maximum run time (in minutes)') parser.add_argument('-L', '--loglevel', type=str, choices = ['D', 'I', 'E', 'W', 'C'], action="store", default='I', - help='Set loglevel used. Options: D - debug, I - info, E - error, W - warning, C - critical. DEFAULT: I') + help='Set loglevel used. ' + 'Options: D - debug, I - info, E - error, W - warning, C - critical. DEFAULT: I') parser.add_argument args = parser.parse_args() From 5c34f5c0a39923fb3b59fd8a89886564c1d12776 Mon Sep 17 00:00:00 2001 From: Luca BALDINI Date: Wed, 5 Feb 2025 09:03:01 +0100 Subject: [PATCH 22/51] Cleanup. --- apx4_read.py | 45 +++++++++++++++++++++++---------------------- core/fmt.py | 22 +++++++++++++++------- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/apx4_read.py b/apx4_read.py index 7f9e349..40f969e 100644 --- a/apx4_read.py +++ b/apx4_read.py @@ -146,7 +146,7 @@ def main(args): # This is an area where we might want to put some thought as to what the most # sensible way to handle things is. header_data = {} - header_data['conf'] = astro.get_header_data() + header_data['configuration'] = astro.get_header_data() header_data['args'] = args.__dict__ header = FileHeader(header_data) @@ -170,31 +170,32 @@ def main(args): # Go ahead and readout data. readout_data = astro.get_readout() if readout_data: - readout = AstroPixReadout(readout_data, time.time()) - if args.showhits: - print(readout) - for hit in readout.hits: - if args.showhits: - print(hit) - hit.write(output_file) num_readouts += 1 + _show = num_readouts % args.prescale == 0 + readout = AstroPixReadout(readout_data, num_readouts, time.time()) + if _show: + print(f'{num_readouts} readouts acquired, last is {readout}.') + for i, hit in enumerate(readout.hits): + if _show: + print(f'Hit {i} -> {hit}') + hit.write(output_file) # Ends program cleanly when a keyboard interupt is sent. except KeyboardInterrupt: logger.info('Keyboard interupt, exiting...') + finally: + logger.info(f'Data acquisition interrupted after {num_readouts} readouts.') + output_file.close() + logger.info('Output file closed.') - logger.info(f'Data acquisition interrupted after {num_readouts} readouts.') - output_file.close() - logger.info('Output file closed.') - - # Teardown the hardware. - if args.inject is not None: - astro.stop_injection() - astro.close_connection() - logger.info("Program terminated successfully!") + # Teardown the hardware. + if args.inject is not None: + astro.stop_injection() + astro.close_connection() + logger.info("Program terminated successfully!") - if args.saveascsv: - file_path = apxdf_to_csv(data_file_path, AstroPix4Hit) + if args.saveascsv: + file_path = apxdf_to_csv(data_file_path, AstroPix4Hit) if __name__ == "__main__": @@ -205,9 +206,9 @@ def main(args): parser.add_argument('-y', '--yaml', action='store', required=False, type=str, default = 'testconfig', help = 'filepath (in config/ directory) .yml file containing chip configuration. ' 'Default: config/testconfig.yml (All pixels off)') - parser.add_argument('-s', '--showhits', action='store_true', default=False, required=False, - help='Display hits in real time during data taking') - parser.add_argument('-c', '--saveascsv', action='store_true', default=False, required=False, + parser.add_argument('-p', '--prescale', type=int, default=25, + help='Prescale factor for displaying hits in real time during data taking') + parser.add_argument('-c', '--saveascsv', action='store_true', default=False, help='Convert output file to csv.') parser.add_argument('-i', '--inject', action='store', default=None, type=int, nargs=2, help = 'Turn on injection in the given row and column. Default: No injection') diff --git a/core/fmt.py b/core/fmt.py index 01a1101..fba55ca 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -263,11 +263,11 @@ class AstroPix4Hit(AstroPixHitBase): 'ts_fine2': 3, 'ts_tdc2': 5 } - _FIELD_NAMES = tuple(FIELD_DICT.keys()) + ('ts_dec1', 'ts_dec2', 'tot_us', 'timestamp') + _FIELD_NAMES = tuple(FIELD_DICT.keys()) + ('ts_dec1', 'ts_dec2', 'tot_us', 'trigger_id', 'timestamp') CLOCK_CYCLES_PER_US = 20. CLOCK_ROLLOVER = 2**17 - def __init__(self, data: bytearray, timestamp: float = None) -> None: + def __init__(self, data: bytearray, trigger_id: int = None, timestamp: float = None) -> None: """Constructor. """ super().__init__(data) @@ -279,6 +279,7 @@ def __init__(self, data: bytearray, timestamp: float = None) -> None: self.ts_dec2 += self.CLOCK_ROLLOVER # Calculate the actual TOT in us. self.tot_us = (self.ts_dec2 - self.ts_dec1) / self.CLOCK_CYCLES_PER_US + self.trigger_id = trigger_id self.timestamp = timestamp @staticmethod @@ -322,6 +323,9 @@ class AstroPixReadout: data : bytearray A full readout from a NEXYS board. + trigger_id : int (optional) + A sequential id for the readout that can be propagated to child hits. + timestamp : float (optional) A timestamp (s since the epoch) assigned by the hist machine. """ @@ -334,7 +338,7 @@ class AstroPixReadout: HIT_TRAILER_LENGTH = len(HIT_TRAILER) HIT_LENGTH = HIT_HEADER_LENGTH + HIT_DATA_SIZE + HIT_TRAILER_LENGTH - def __init__(self, data: bytearray, timestamp: int = None) -> None: + def __init__(self, data: bytearray, trigger_id: int = None, timestamp: float = None) -> None: """Constructor. """ # Strip all the trailing padding bytes from the input bytearray object. @@ -342,6 +346,7 @@ def __init__(self, data: bytearray, timestamp: int = None) -> None: # Check that the length of the readout is a multiple of the frame length. if not len(self) % self.HIT_LENGTH == 0: raise RuntimeError(f'Readout length ({len(self)}) not a multiple of {self.HIT_LENGTH}') + self.trigger_id = trigger_id self.timestamp = timestamp self.hits = self.__decode() @@ -374,7 +379,7 @@ def __decode(self, reverse: bool = True) -> list[AstroPix4Hit]: if reverse: hit_data = reverse_bit_order(hit_data) # Create a fully-fledged AstroPix4Hit object. - hits.append(AstroPix4Hit(hit_data, self.timestamp)) + hits.append(AstroPix4Hit(hit_data, self.trigger_id, self.timestamp)) pos += self.HIT_LENGTH return hits @@ -391,7 +396,8 @@ def __len__(self) -> int: def __str__(self) -> str: """String formatting. """ - return f'{self.__class__.__name__}({self.num_hits()} hits, {len(self)} bytes, timestamp = {self.timestamp} s)' + return f'{self.__class__.__name__}({self.num_hits()} hits, {len(self)} bytes, ' \ + f'trigger_id = {self.trigger_id}, timestamp = {self.timestamp} s)' class FileHeader: @@ -506,7 +512,7 @@ def open(self, file_path: str): """ if not file_path.endswith(self._EXTENSION): raise RuntimeError(f'Input file {file_path} has not the {self._EXTENSION} extension') - logger.info(f'Opening input packet file {file_path}...') + logger.info(f'Opening input file {file_path}...') with open(file_path, 'rb') as input_file: self._input_file = input_file self.header = FileHeader.read(self._input_file) @@ -535,12 +541,14 @@ def _convert_apxdf(file_path: str, hit_class: type, converter: typing.Callable, """ if output_file_path is None and default_extension is not None: output_file_path = file_path.replace('.apx', default_extension) + logger.info(f'Converting AstroPix file to {output_file_path}...') with AstroPixBinaryFile(hit_class).open(file_path) as input_file, \ open(output_file_path, open_mode) as output_file: if header is not None: output_file.write(header) - for hit in input_file: + for i, hit in enumerate(input_file): output_file.write(converter(hit)) + logger.info(f'Done, {i + 1} hit(s) written') return output_file_path From e42afda0c59e42a8462bda2af128db7dcc0bfc2d Mon Sep 17 00:00:00 2001 From: Luca BALDINI Date: Wed, 5 Feb 2025 09:44:54 +0100 Subject: [PATCH 23/51] Trigger id and timestamp in the output binary file. --- apx4_read.py | 2 +- core/fmt.py | 47 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/apx4_read.py b/apx4_read.py index 40f969e..ac6ba8e 100644 --- a/apx4_read.py +++ b/apx4_read.py @@ -172,7 +172,7 @@ def main(args): if readout_data: num_readouts += 1 _show = num_readouts % args.prescale == 0 - readout = AstroPixReadout(readout_data, num_readouts, time.time()) + readout = AstroPixReadout(readout_data, num_readouts, time.time_ns()) if _show: print(f'{num_readouts} readouts acquired, last is {readout}.') for i, hit in enumerate(readout.hits): diff --git a/core/fmt.py b/core/fmt.py index fba55ca..cfdee9b 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -85,7 +85,8 @@ class AstroPixHitBase: The portion of a full AstroPix readout representing a single hit. """ - SIZE = None + READ_SIZE = None + WRITE_SIZE = None FIELD_DICT = None _FIELD_NAMES = None @@ -103,7 +104,7 @@ def __init__(self, data: bytearray) -> None: self.__setattr__(name, bit_pattern[pos:pos + width]) pos += width - def write(self, otuput_file: typing.BinaryIO) -> None: + def write(self, output_file: typing.BinaryIO) -> None: """Write the binary data to a file. Arguments @@ -111,7 +112,7 @@ def write(self, otuput_file: typing.BinaryIO) -> None: output_file : BinaryIO A file object opened in "wb" mode. """ - otuput_file.write(self._data) + output_file.write(self._data) def __eq__(self, other: 'AstroPixHitBase') -> bool: """Comparison operator---this is handy in the unit tests. @@ -219,7 +220,8 @@ class AstroPix3Hit(AstroPixHitBase): This is copied from decode.py and totally untested. """ - SIZE = 5 + READ_SIZE = 5 + WRITE_SIZE = READ_SIZE FIELD_DICT = { 'chip_id': 5, 'payload': 3, @@ -248,7 +250,12 @@ class AstroPix4Hit(AstroPixHitBase): """Class describing an AstroPix4 hit. """ - SIZE = 8 + READ_SIZE = 8 + _TRIGGER_ID_FMT = 'L' + _TRIGGER_ID_SIZE = struct.calcsize(_TRIGGER_ID_FMT) + _TIMESTAMP_FMT = 'Q' + _TIMESTAMP_SIZE = struct.calcsize(_TIMESTAMP_FMT) + WRITE_SIZE = READ_SIZE + _TRIGGER_ID_SIZE + _TIMESTAMP_SIZE FIELD_DICT = { 'chip_id': 5, 'payload': 3, @@ -263,6 +270,7 @@ class AstroPix4Hit(AstroPixHitBase): 'ts_fine2': 3, 'ts_tdc2': 5 } + _FIELD_NAMES = tuple(FIELD_DICT.keys()) + ('ts_dec1', 'ts_dec2', 'tot_us', 'trigger_id', 'timestamp') CLOCK_CYCLES_PER_US = 20. CLOCK_ROLLOVER = 2**17 @@ -302,6 +310,29 @@ def _compose_timestamp(ts_coarse: int, ts_fine: int) -> int: """ return AstroPixHitBase.gray_to_decimal((ts_coarse << 3) + ts_fine) + def write(self, output_file: typing.BinaryIO) -> None: + """Overloaded method, since we want to write additional fields. + + Arguments + --------- + output_file : BinaryIO + A file object opened in "wb" mode. + """ + output_file.write(self._data) + output_file.write(struct.pack(self._TRIGGER_ID_FMT, self.trigger_id)) + output_file.write(struct.pack(self._TIMESTAMP_FMT, self.timestamp)) + + @classmethod + def from_file_data(cls, data) -> 'AstroPix4Hit': + """Read a hit from an input binary file. + """ + pos = cls.READ_SIZE + trigger_id = struct.unpack(cls._TRIGGER_ID_FMT, data[pos:pos + cls._TRIGGER_ID_SIZE]) + pos += cls._TRIGGER_ID_SIZE + timestamp = struct.unpack(cls._TIMESTAMP_FMT, data[pos:pos + cls._TIMESTAMP_SIZE]) + data = data[:cls.READ_SIZE] + return cls(data, trigger_id, timestamp) + class AstroPixReadout: @@ -333,7 +364,7 @@ class AstroPixReadout: PADDING_BYTE = bytes.fromhex('ff') HIT_HEADER = bytes.fromhex('bcbc') HIT_TRAILER = bytes.fromhex('bcbcbcbcbcbc') - HIT_DATA_SIZE = AstroPix4Hit.SIZE + HIT_DATA_SIZE = AstroPix4Hit.READ_SIZE HIT_HEADER_LENGTH = len(HIT_HEADER) HIT_TRAILER_LENGTH = len(HIT_TRAILER) HIT_LENGTH = HIT_HEADER_LENGTH + HIT_DATA_SIZE + HIT_TRAILER_LENGTH @@ -528,10 +559,10 @@ def __iter__(self) -> 'AstroPixBinaryFile': def __next__(self) -> AstroPixHitBase: """Read the next packet in the buffer. """ - data = self._input_file.read(self._hit_class.SIZE) + data = self._input_file.read(self._hit_class.WRITE_SIZE) if not data: raise StopIteration - return self._hit_class(data) + return self._hit_class.from_file_data(data) def _convert_apxdf(file_path: str, hit_class: type, converter: typing.Callable, From 9d3945955e9045f83db46e96765fc21b60d7d6a8 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 5 Feb 2025 10:18:05 +0100 Subject: [PATCH 24/51] New data files --- tests/data/20250204_144725_data.apx | Bin 7639 -> 0 bytes tests/data/20250205_094324_data.apx | Bin 0 -> 16846 bytes tests/data/20250205_094324_data.csv | 776 ++++++++++++++++++++++++++++ 3 files changed, 776 insertions(+) delete mode 100644 tests/data/20250204_144725_data.apx create mode 100644 tests/data/20250205_094324_data.apx create mode 100644 tests/data/20250205_094324_data.csv diff --git a/tests/data/20250204_144725_data.apx b/tests/data/20250204_144725_data.apx deleted file mode 100644 index 0cf87a9f11f11d53d07daa1e4bba4830f54d8c6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7639 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 literal 0 HcmV?d00001 diff --git a/tests/data/20250205_094324_data.csv b/tests/data/20250205_094324_data.csv new file mode 100644 index 0000000..426d56a --- /dev/null +++ b/tests/data/20250205_094324_data.csv @@ -0,0 +1,776 @@ +# chip_id,payload,row,column,ts_neg1,ts_coarse1,ts_fine1,ts_tdc1,ts_neg2,ts_coarse2,ts_fine2,ts_tdc2,ts_dec1,ts_dec2,tot_us,trigger_id,timestamp +0,7,0,2,1,13862,3,0,0,14327,1,0,74205,76497,114.6,1,1738745007402289500 +0,7,0,2,1,7270,6,0,1,5283,5,0,48603,50710,105.35,2,1738745007480410400 +0,7,0,2,1,3751,5,0,0,2607,7,0,22998,25002,100.2,3,1738745007556312800 +0,7,0,2,0,8679,7,0,0,8230,7,0,128469,130597,106.4,4,1738745007634288600 +0,7,0,2,0,11045,0,0,0,10987,4,0,102863,105064,110.05,5,1738745007712398800 +0,7,0,2,0,14181,3,0,1,13804,4,0,77261,79288,101.35,6,1738745007788344100 +0,7,0,2,0,5541,4,0,0,5931,0,0,51656,53648,99.6,7,1738745007866403700 +0,7,0,2,0,2788,7,0,0,2818,0,0,26053,28640,129.35,8,1738745007944341900 +0,7,0,2,0,36,1,0,0,492,4,0,449,2631,109.1,9,1738745008020266700 +0,7,0,2,1,10860,3,0,0,11946,6,0,105917,108132,110.75,10,1738745008098440200 +0,7,0,2,0,13484,3,0,1,15377,1,0,80317,82161,92.2,11,1738745008176276900 +0,7,0,2,0,6125,5,0,1,5712,2,0,54710,56572,93.1,12,1738745008252412900 +0,7,0,2,1,2349,6,0,0,2274,5,0,29108,31257,107.45,13,1738745008330370200 +0,7,0,2,0,367,0,0,0,930,5,0,3503,5657,107.7,14,1738745008408258200 +0,7,0,2,0,12207,2,0,0,11572,7,0,108972,110906,96.7,15,1738745008486392800 +0,7,0,2,1,15599,4,0,1,15652,1,0,83368,85566,109.9,16,1738745008562271600 +0,7,0,2,0,4654,6,0,1,5095,4,0,57764,59944,109.0,17,1738745008640265500 +0,7,0,2,0,2158,1,0,1,6319,3,0,32161,34386,111.25,18,1738745008718210200 +0,7,0,2,1,682,3,0,0,1663,3,0,6557,8877,116.0,19,1738745008794202200 +0,7,0,2,1,11754,7,0,0,11297,6,0,112026,114187,108.05,20,1738745008872288300 +0,7,0,2,1,16171,7,0,0,16045,4,0,86421,88503,104.1,21,1738745008950222200 +0,7,0,2,1,4971,6,0,0,4579,1,0,60820,62958,106.9,22,1738745009026369900 +0,7,0,2,1,6569,1,0,1,7017,5,0,35214,37494,114.0,23,1738745009104294500 +0,7,0,2,1,1769,3,0,1,1865,2,0,9613,11379,88.3,24,1738745009182210800 +0,7,0,2,0,9256,4,0,0,9631,4,0,115079,116904,91.25,25,1738745009258248600 +0,7,0,2,1,15976,7,0,1,15060,7,0,89477,91333,92.8,26,1738745009336317300 +0,7,0,2,1,4264,0,0,1,12384,2,0,63872,66051,108.95,27,1738745009414180200 +0,7,0,2,1,7160,3,0,0,6756,0,0,38269,40384,105.75,28,1738745009490209600 +0,7,0,2,1,1336,5,0,0,1207,0,0,12665,14639,98.7,29,1738745009568235600 +0,7,0,2,0,9593,7,0,1,10130,0,0,118133,120607,123.7,30,1738745009646227000 +0,7,0,2,1,15289,2,0,0,14703,4,0,92531,94807,113.8,31,1738745009722253100 +0,7,0,2,1,12539,3,0,0,12627,0,0,66925,68847,96.1,32,1738745009800416100 +0,7,0,2,1,7739,2,0,1,8161,5,0,41324,43529,110.25,33,1738745009878349800 +0,7,0,2,0,1146,5,0,1,3299,1,0,15718,17902,109.2,34,1738745009956246900 +0,7,0,2,0,9914,7,0,0,8756,0,0,121189,123199,100.5,35,1738745010032246800 +0,7,0,2,1,14842,0,0,0,14450,5,0,95584,97561,98.85,36,1738745010110233600 +0,7,0,2,0,13118,3,0,1,13028,3,0,69981,72253,113.6,37,1738745010186248700 +0,7,0,2,0,8062,7,0,1,7625,2,0,44378,46195,90.85,38,1738745010264226700 +0,7,0,2,1,3519,7,0,0,3840,5,0,18773,20486,85.65,39,1738745010342217700 +0,7,0,2,1,8959,3,0,0,9081,4,0,124242,126327,104.25,40,1738745010420225600 +0,7,0,2,1,10301,3,0,1,10664,4,0,98637,100743,105.3,41,1738745010496213200 +0,7,0,2,0,12925,2,0,0,14065,4,0,73036,75016,99.0,42,1738745010574399200 +0,7,0,2,0,7356,5,0,0,5158,4,0,47430,49624,109.7,43,1738745010652221800 +0,7,0,2,0,4092,7,0,1,3674,2,0,21829,23708,93.95,44,1738745010728227700 +0,7,0,2,0,8500,0,0,1,8420,1,0,127295,129598,115.15,45,1738745010806224200 +0,7,0,2,0,10612,2,0,1,11194,3,0,101692,104093,120.05,46,1738745010884340900 +0,7,0,2,0,14260,5,0,0,13581,5,0,76089,77897,90.4,47,1738745010960329000 +0,7,0,2,0,5365,7,0,0,5480,1,0,50485,52609,106.2,48,1738745011038358300 +0,7,0,2,0,2613,1,0,0,3005,3,0,24881,26957,103.8,49,1738745011116366000 +0,7,0,2,1,8311,3,0,1,228,5,0,130349,132550,110.05,50,1738745011192183400 +0,7,0,2,1,10935,6,0,1,11832,7,0,104747,106874,106.35,51,1738745011270197500 +0,7,0,2,1,13814,5,0,1,13415,1,0,79142,81361,110.95,52,1738745011348179700 +0,7,0,2,0,5942,7,0,1,5800,6,0,53541,55684,107.15,53,1738745011426180800 +0,7,0,2,0,2930,1,0,0,2533,1,0,27934,30158,111.2,54,1738745011502335300 +0,7,0,2,0,434,3,0,0,791,4,0,2333,4311,98.9,55,1738745011580175400 +0,7,0,2,1,12019,4,0,1,12151,0,0,107799,109871,103.6,56,1738745011658185600 +0,7,0,2,0,15411,7,0,1,15799,4,0,82197,84264,103.35,57,1738745011734201500 +0,7,0,2,0,5747,0,0,0,4796,6,0,56592,59067,123.75,58,1738745011812195500 +0,7,0,2,0,2225,3,0,0,6251,4,0,30989,33384,119.75,59,1738745011890315100 +0,7,0,2,1,1009,7,0,1,602,3,0,5386,7325,96.95,60,1738745011966189400 +0,7,0,2,1,11568,5,0,1,11452,0,0,110854,112960,105.3,61,1738745012044178500 +0,7,0,2,1,15728,6,0,0,16335,5,0,85252,87126,93.7,62,1738745012122181400 +0,7,0,2,1,5008,1,0,1,4453,3,0,59646,62002,117.8,63,1738745012198238400 +0,7,0,2,0,6352,2,0,1,6499,4,0,34044,36328,114.2,64,1738745012276158200 +0,7,0,2,0,1553,4,0,0,1947,1,0,8439,10385,97.3,65,1738745012354155000 +0,7,0,2,0,11345,6,0,1,9462,7,0,113908,116005,104.85,66,1738745012430161800 +0,7,0,2,0,16017,1,0,0,14858,6,0,88305,90212,95.35,67,1738745012508157400 +0,7,0,2,1,4563,3,0,0,4175,7,0,62701,64597,94.8,68,1738745012586168100 +0,7,0,2,1,6931,2,0,0,6806,0,0,37100,39135,101.75,69,1738745012662155200 +0,7,0,2,1,1874,7,0,1,1532,2,0,11493,13635,107.1,70,1738745012740154000 +0,7,0,2,1,9618,2,0,0,9988,0,0,116963,118847,94.2,71,1738745012818161000 +0,7,0,2,1,15062,1,0,1,15202,6,0,91358,93668,115.5,72,1738745012894286600 +0,7,0,2,1,12310,2,0,0,12690,3,0,65756,67810,102.7,73,1738745012972165600 +0,7,0,2,0,6743,4,0,1,7890,2,0,40151,42211,103.0,74,1738745013050214700 +0,7,0,2,0,1175,6,0,0,3082,4,0,14548,16487,96.95,75,1738745013126262000 +0,7,0,2,1,10197,0,0,0,9845,4,0,120015,122167,107.6,76,1738745013204141900 +0,7,0,2,1,14613,3,0,1,14570,6,0,94413,96868,122.75,77,1738745013282132900 +0,7,0,2,1,12629,4,0,1,13289,4,0,68808,71048,112.0,78,1738745013360143000 +0,7,0,2,1,8084,7,0,0,7534,0,0,43205,45663,122.9,79,1738745013436155100 +0,7,0,2,0,3284,1,0,1,3402,4,0,17601,19559,97.9,80,1738745013514134300 +0,7,0,2,1,8732,3,0,0,9119,4,0,123069,125096,101.35,81,1738745013592151400 +0,7,0,2,0,14428,2,0,0,10312,4,0,97468,99207,86.95,82,1738745013668150400 +0,7,0,2,1,12957,7,0,0,13868,7,0,71861,74170,115.45,83,1738745013746153800 +0,7,0,2,0,7645,7,0,0,7247,4,0,46261,48215,97.7,84,1738745013824143100 +0,7,0,2,1,3871,0,0,0,3774,7,0,20655,22874,110.95,85,1738745013900103200 +0,7,0,2,0,9055,3,0,0,8641,1,0,126125,128014,94.45,86,1738745013978242600 +0,7,0,2,0,10655,4,0,0,10509,5,0,100520,102326,90.3,87,1738745014056255700 +0,7,0,2,0,14046,7,0,1,14192,0,0,74917,77056,106.95,88,1738745014132118300 +0,7,0,2,1,5150,1,0,1,5511,0,0,49313,51247,96.7,89,1738745014210116300 +0,7,0,2,1,3674,3,0,1,2758,1,0,23709,25633,96.2,90,1738745014288112700 +0,7,0,2,0,8346,6,0,0,48,1,0,129179,131329,107.5,91,1738745014364116300 +0,7,0,2,1,11227,5,0,1,10820,4,0,103574,105528,97.7,92,1738745014442109200 +0,7,0,2,1,13595,2,0,1,13482,1,0,77971,80286,115.75,93,1738745014520121200 +0,7,0,2,0,5465,1,0,1,6125,2,0,52366,54707,117.05,94,1738745014598115500 +0,7,0,2,0,2969,3,0,1,2323,4,0,26765,28904,106.95,95,1738745014674105900 +0,7,0,2,0,216,4,0,0,358,2,0,1159,3548,119.45,96,1738745014752109500 +0,7,0,2,0,11800,7,0,0,12256,2,0,106629,109059,121.5,97,1738745014830104700 +0,7,0,2,1,13400,0,0,1,15592,2,0,81024,83331,115.35,98,1738745014906241000 +0,7,0,2,0,5768,3,0,0,4661,2,0,55421,57651,111.5,99,1738745014984117400 +0,7,0,2,1,2504,5,0,0,2242,5,0,29817,31718,95.05,100,1738745015062225800 +0,7,0,2,1,777,7,0,1,646,7,0,4213,6181,98.4,101,1738745015138089600 +0,7,0,2,0,12105,6,0,1,11610,1,0,109684,111457,88.65,102,1738745015216088200 +0,7,0,2,1,15755,1,0,1,16172,2,0,84078,86460,119.1,103,1738745015294082000 +0,7,0,2,1,4811,6,0,0,4898,6,0,58475,60955,124.0,104,1738745015370083400 +0,7,0,2,0,6154,4,0,0,6591,7,0,32871,35157,114.3,105,1738745015448205100 +0,7,0,2,0,586,6,0,1,1759,4,0,7268,9384,105.8,106,1738745015526096300 +0,7,0,2,1,11402,3,0,0,9219,2,0,112738,114707,98.45,107,1738745015602090500 +0,7,0,2,1,16334,3,0,1,16085,5,0,87133,88886,87.65,108,1738745015680090600 +0,7,0,2,0,4366,5,0,0,4230,7,0,61529,63525,99.8,109,1738745015758090300 +0,7,0,2,1,6479,5,0,0,6997,3,0,35926,37682,87.8,110,1738745015834083400 +0,7,0,2,0,1935,2,0,0,1301,2,0,10323,12492,108.45,111,1738745015912059700 +0,7,0,2,1,9421,1,0,1,9571,0,0,115790,118255,123.25,112,1738745015990060000 +0,7,0,2,1,14861,6,0,1,15291,7,0,90187,92522,116.75,113,1738745016066197000 +0,7,0,2,0,4172,4,0,1,12381,5,0,64583,66377,89.7,114,1738745016144065800 +0,7,0,2,0,6796,7,0,0,7709,1,0,38981,41137,107.8,115,1738745016222064900 +0,7,0,2,0,1484,0,0,1,1237,7,0,13376,15157,89.05,116,1738745016300061600 +0,7,0,2,0,9988,3,0,1,10121,7,0,118845,120714,93.45,117,1738745016376035900 +0,7,0,2,1,15172,4,0,1,14788,4,0,93240,95288,102.4,118,1738745016454059100 +0,7,0,2,1,12677,5,0,1,12575,5,0,67638,69462,91.2,119,1738745016532071200 +0,7,0,2,0,7877,1,0,1,8030,1,0,42033,44193,108.0,120,1738745016608054500 +0,7,0,2,1,3079,1,0,0,3206,0,0,16430,18399,98.45,121,1738745016686058800 +0,7,0,2,1,9799,2,0,1,8902,3,0,121900,123938,101.9,122,1738745016764062300 +0,7,0,2,0,14470,5,0,0,14336,3,0,96294,98301,100.35,123,1738745016840065900 +0,7,0,2,0,13254,7,0,0,13008,4,0,70693,72455,88.1,124,1738745016918189200 +0,7,0,2,0,7426,0,0,1,7316,6,0,45087,47300,110.65,125,1738745016996031800 +0,7,0,2,0,3394,3,0,0,4063,5,0,19485,21673,109.4,126,1738745017072043700 +0,7,0,2,1,9090,4,0,1,8975,7,0,124952,126890,96.9,127,1738745017150059900 +0,7,0,2,1,10435,7,0,1,10688,1,0,99349,101374,101.25,128,1738745017228036900 +0,7,0,2,0,13827,1,0,0,14270,0,0,73745,76127,119.1,129,1738745017304031500 +0,7,0,2,1,7233,3,0,1,5324,5,0,48141,50246,105.25,130,1738745017382031000 +0,7,0,2,0,3713,6,0,1,2587,0,0,22539,24720,109.05,131,1738745017460187600 +0,7,0,2,1,8640,5,0,1,8307,3,0,128006,130322,115.8,132,1738745017536032400 +0,7,0,2,0,11008,6,0,1,10902,4,0,102404,104664,113.0,133,1738745017614175000 +0,7,0,2,0,14272,1,0,0,13763,3,0,76798,78866,103.4,134,1738745017692180000 +0,7,0,2,0,5248,3,0,1,5897,2,0,51197,53363,108.3,135,1738745017768176500 +0,7,0,2,1,2625,4,0,1,3021,0,0,25591,27568,98.85,136,1738745017846027700 +0,7,0,2,0,8193,7,0,1,436,0,0,131061,133439,118.9,137,1738745017924237200 +0,7,0,2,0,10945,0,0,0,11979,6,0,105456,107627,108.55,138,1738745018000235300 +0,7,0,2,1,13699,3,0,1,15388,3,0,79853,82109,112.8,139,1738745018078014700 +0,7,0,2,0,5955,5,0,0,5754,7,0,54249,56677,121.4,140,1738745018156017900 +0,7,0,2,1,2818,7,0,1,2184,6,0,28645,30843,109.9,141,1738745018234012200 +0,7,0,2,1,450,6,0,1,836,0,0,3044,5056,100.6,142,1738745018310445700 +0,7,0,2,0,11910,1,0,0,12037,7,0,108510,110538,101.4,143,1738745018388013700 +0,7,0,2,0,15430,3,0,1,15830,1,0,82909,84769,93.0,144,1738745018466011500 +0,7,0,2,1,5639,4,0,0,4744,3,0,57303,59266,98.15,145,1738745018542015200 +0,7,0,2,0,2247,7,0,1,6343,4,0,31701,33832,106.55,146,1738745018620077500 +0,7,0,2,1,903,0,0,0,516,2,0,6096,8131,101.75,147,1738745018698157400 +0,7,0,2,1,11589,3,0,0,11507,7,0,111565,113386,91.05,148,1738745018774154500 +0,7,0,2,0,15621,5,0,0,16265,7,0,85961,87946,99.25,149,1738745018852135600 +0,7,0,2,1,5060,5,0,1,4553,6,0,60358,62580,111.1,150,1738745018930141700 +0,7,0,2,0,6276,3,0,1,6406,1,0,34754,36830,103.8,151,1738745019006038500 +0,7,0,2,1,1612,1,0,1,1872,4,0,9150,11512,118.1,152,1738745019084020000 +0,7,0,2,0,11276,2,0,0,9353,5,0,114620,116617,99.85,153,1738745019161995000 +0,7,0,2,1,16077,4,0,1,14932,1,0,89015,90942,96.35,154,1738745019239987400 +0,7,0,2,0,4493,6,0,0,4098,5,0,63412,65510,104.9,155,1738745019315983500 +0,7,0,2,1,6991,0,0,0,6745,4,0,37807,40072,113.25,156,1738745019393988600 +0,7,0,2,0,1807,3,0,0,1157,6,0,12205,14388,109.15,157,1738745019471984100 +0,7,0,2,1,9679,4,0,0,10193,4,0,117672,120055,119.15,158,1738745019547998600 +0,7,0,2,1,14990,7,0,1,15108,4,0,92069,94151,104.1,159,1738745019625997700 +0,7,0,2,0,12366,3,0,1,12767,5,0,66466,68438,98.6,160,1738745019703981100 +0,7,0,2,1,6666,3,0,0,7838,5,0,40861,42841,99.0,161,1738745019780165700 +0,7,0,2,1,1226,2,0,0,3143,0,0,15260,17360,105.0,162,1738745019858098900 +0,7,0,2,0,10123,4,0,0,9786,0,0,120727,122527,90.0,163,1738745019935959500 +0,7,0,2,0,14667,6,0,0,14551,0,0,95124,97071,97.35,164,1738745020011963900 +0,7,0,2,1,12553,0,0,0,13189,2,0,69519,71628,105.45,165,1738745020089959500 +0,7,0,2,0,8137,3,0,0,7549,0,0,43917,45744,91.35,166,1738745020167969100 +0,7,0,2,1,3208,4,0,0,3860,7,0,18311,20677,118.3,167,1738745020243965000 +0,7,0,2,0,8776,7,0,1,9039,0,0,123781,126032,112.55,168,1738745020321965700 +0,7,0,2,0,14344,1,0,0,10382,4,0,98177,100263,104.3,169,1738745020399972800 +0,7,0,2,1,13016,1,0,0,13901,4,0,72574,74679,105.25,170,1738745020475957100 +0,7,0,2,1,7576,6,0,0,7182,5,0,46971,49062,104.55,171,1738745020554017000 +0,7,0,2,1,3929,7,0,1,3696,5,0,21365,23814,122.45,172,1738745020631960700 +0,7,0,2,0,8985,6,0,1,8321,1,0,126836,129038,110.1,173,1738745020707938500 +0,7,0,2,1,10715,1,0,1,11079,5,0,101230,103382,107.6,174,1738745020785936000 +0,7,0,2,0,13979,2,0,1,13568,5,0,75628,77830,110.1,175,1738745020863942900 +0,7,0,2,1,5210,4,0,1,5619,7,0,50023,51946,96.15,176,1738745020942075700 +0,7,0,2,1,3610,7,0,1,2749,0,0,24421,26288,93.35,177,1738745021018069400 +0,7,0,2,0,8410,1,0,1,125,6,0,129889,131764,93.75,178,1738745021095931400 +0,7,0,2,0,11166,3,0,0,11777,7,0,104285,106506,111.05,179,1738745021173932900 +0,7,0,2,0,13662,4,0,0,13406,4,0,78680,81063,119.15,180,1738745021249943000 +0,7,0,2,1,5407,5,0,1,6024,0,0,53078,55168,104.5,181,1738745021327935900 +0,7,0,2,0,3039,6,0,0,2392,6,0,27476,29563,104.35,182,1738745021405942100 +0,7,0,2,1,157,1,0,0,768,0,0,1870,4096,111.3,183,1738745021481941700 +0,7,0,2,0,11869,2,0,0,12280,4,0,107340,109191,92.55,184,1738745021559937300 +0,7,0,2,0,13340,4,0,0,15756,5,0,81735,84038,115.15,185,1738745021637969200 +0,7,0,2,1,5852,6,0,1,4801,5,0,56132,58377,112.25,186,1738745021713940700 +0,7,0,2,1,2460,0,0,1,6157,0,0,30528,32847,115.95,187,1738745021791913500 +0,7,0,2,0,852,3,0,0,602,5,0,4925,7321,119.8,188,1738745021869969900 +0,7,0,2,0,12052,5,0,0,11662,6,0,110393,112548,107.75,189,1738745021945914200 +0,7,0,2,0,15829,5,0,1,16235,7,0,84790,86634,92.2,190,1738745022023914300 +0,7,0,2,0,4757,6,0,1,4908,7,0,59188,60997,90.45,191,1738745022101916400 +0,7,0,2,0,6231,0,0,0,6590,7,0,33583,35162,78.95,192,1738745022178052300 +0,7,0,2,1,535,2,0,1,1665,7,0,7980,10229,112.45,193,1738745022255963900 +0,7,0,2,0,11478,4,0,0,9308,7,0,113447,115525,103.9,194,1738745022333920700 +0,7,0,2,0,16278,6,0,1,15899,5,0,87844,89961,105.85,195,1738745022412046600 +0,7,0,2,1,4438,0,0,1,4261,4,0,62240,63944,85.2,196,1738745022487920300 +0,7,0,2,0,6418,3,0,0,7045,3,0,36637,38861,111.2,197,1738745022567021500 +0,7,0,2,0,2002,5,0,0,1357,6,0,11033,13236,110.15,198,1738745022643893000 +0,7,0,2,0,9363,7,0,1,9532,4,0,116501,118456,97.75,199,1738745022719892500 +0,7,0,2,0,14931,3,0,0,15319,1,0,90898,92974,103.8,200,1738745022797896600 +0,7,0,2,1,4113,1,0,0,12440,5,0,65294,67449,107.75,201,1738745022876027000 +0,7,0,2,1,6865,6,0,1,7719,7,0,39691,41429,86.9,202,1738745022951902900 +0,7,0,2,1,1424,5,0,1,1075,1,0,14086,16110,101.2,203,1738745023030010600 +0,7,0,2,0,10064,7,0,1,9893,0,0,119557,121295,86.9,204,1738745023107888900 +0,7,0,2,1,15152,0,0,0,14742,2,0,93951,96035,104.2,205,1738745023183889200 +0,7,0,2,0,12784,3,0,0,13139,0,0,68349,70416,103.35,206,1738745023261892000 +0,7,0,2,1,7856,4,0,1,7950,4,0,42744,44967,111.15,207,1738745023339901300 +0,7,0,2,1,3185,7,0,0,3548,4,0,17141,19271,106.5,208,1738745023415935900 +0,7,0,2,0,9777,1,0,1,8891,0,0,122609,124560,97.55,209,1738745023493898200 +0,7,0,2,1,14579,3,0,1,10355,2,0,97005,99052,102.35,210,1738745023571867800 +0,7,0,2,0,13235,2,0,0,12860,7,0,71404,73402,99.9,211,1738745023647861200 +0,7,0,2,0,7538,5,0,1,7421,4,0,45798,47799,100.05,212,1738745023725861200 +0,7,0,2,0,3378,6,0,1,3987,5,0,20196,22294,104.9,213,1738745023803865900 +0,7,0,2,0,9206,1,0,1,8524,5,0,125662,127929,113.35,214,1738745023879865600 +0,7,0,2,1,10422,3,0,0,10694,3,0,100061,101341,64.0,215,1738745023957996500 +0,7,0,2,1,13943,4,0,1,14260,6,0,74455,76091,81.8,216,1738745024035871700 +0,7,0,2,0,7223,7,0,0,5271,7,0,48853,50986,106.65,217,1738745024113866300 +0,7,0,2,0,3831,0,0,0,2638,0,0,23248,25504,112.8,218,1738745024189865500 +0,7,0,2,1,8629,3,0,0,8291,3,0,128717,130541,91.2,219,1738745024267885200 +0,7,0,2,0,11125,2,0,0,10991,1,0,103116,105041,96.25,220,1738745024345865900 +0,7,0,2,1,14132,7,0,1,13748,4,0,77509,79559,102.5,221,1738745024421854400 +0,7,0,2,0,5620,2,0,1,5962,3,0,51907,54173,113.3,222,1738745024499937200 +0,7,0,2,0,2748,0,0,1,2878,0,0,26303,28320,100.85,223,1738745024576061800 +0,7,0,2,1,124,2,0,0,452,5,0,700,3014,115.7,224,1738745024653921400 +0,7,0,2,1,10813,4,0,1,12006,4,0,106167,107992,91.25,225,1738745024731838400 +0,7,0,2,0,13565,7,0,1,15436,1,0,80565,82878,115.65,226,1738745024809840200 +0,7,0,2,0,6077,1,0,1,5741,0,0,54961,56752,89.55,227,1738745024885843800 +0,7,0,2,1,2431,3,0,1,2295,2,0,29357,31443,104.3,228,1738745024963968600 +0,7,0,2,1,319,4,0,1,903,6,0,3752,6100,117.4,229,1738745025041963700 +0,7,0,2,1,12286,7,0,1,11618,7,0,109221,111130,95.45,230,1738745025117789100 +0,7,0,2,1,15550,6,0,1,15657,4,0,83620,85623,100.15,231,1738745025195966200 +0,7,0,2,1,4730,3,0,0,5104,5,0,58013,60153,107.0,232,1738745025273838900 +0,7,0,2,1,2106,6,0,1,6294,0,0,32411,34592,109.05,233,1738745025349837800 +0,7,0,2,0,763,4,0,1,1659,1,0,6807,8849,102.1,234,1738745025427836200 +0,7,0,2,1,11707,7,0,0,11322,1,0,112277,114334,102.85,235,1738745025505816600 +0,7,0,2,1,16249,0,0,1,16120,7,0,86671,88709,101.9,236,1738745025583833400 +0,7,0,2,0,4921,3,0,1,4529,3,0,61069,63218,107.45,237,1738745025659955500 +0,7,0,2,0,6649,5,0,1,6991,4,0,35465,37800,116.75,238,1738745025737842000 +0,7,0,2,1,1720,5,0,0,1835,0,0,9862,11887,101.25,239,1738745025815828400 +0,7,0,2,0,9336,1,0,1,9704,7,0,115329,117370,102.05,240,1738745025891949000 +0,7,0,2,1,15912,3,0,0,15004,4,0,89725,91975,112.5,241,1738745025969939300 +0,7,0,2,1,4328,6,0,0,12348,5,0,64123,65862,86.95,242,1738745026047814900 +0,7,0,2,0,7081,5,0,0,6672,2,0,38518,40707,109.45,243,1738745026123809000 +0,7,0,2,0,1385,7,0,0,1197,5,0,12917,14774,92.85,244,1738745026201814500 +0,7,0,2,0,9515,0,0,0,10158,2,0,118383,120412,101.45,245,1738745026279812400 +0,7,0,2,0,15339,3,0,1,14697,6,0,92781,94836,102.75,246,1738745026355792600 +0,7,0,2,0,12459,5,0,1,12580,5,0,67177,69177,100.0,247,1738745026433795200 +0,7,0,2,0,7786,7,0,1,8159,5,0,41573,43862,114.45,248,1738745026511805100 +0,7,0,2,1,1066,1,0,0,3320,2,0,15969,17788,90.95,249,1738745026587786700 +0,7,0,2,0,9966,3,0,0,8786,3,0,121437,123677,112.0,250,1738745026665781900 +0,7,0,2,0,14766,6,0,0,14374,1,0,95835,97825,99.5,251,1738745026743789200 +0,7,0,2,0,13167,5,0,0,12975,2,0,70230,72108,93.9,252,1738745026819820500 +0,7,0,2,0,7983,6,0,0,7560,7,0,44628,46981,117.65,253,1738745026897786500 +0,7,0,2,1,3565,0,0,0,3872,2,0,19023,20988,98.25,254,1738745026975911200 +0,7,0,2,0,8877,3,0,0,9068,1,0,124493,126398,95.25,255,1738745027051923300 +0,7,0,2,1,10348,4,0,0,10721,1,0,98887,100878,99.55,256,1738745027129780000 +0,7,0,2,0,12844,7,0,0,14050,4,0,73285,75239,97.7,257,1738745027207786300 +0,7,0,2,1,7404,0,0,0,5215,5,0,47680,50006,116.3,258,1738745027285781700 +0,7,0,2,1,4004,3,0,1,3615,1,0,22077,24401,116.2,259,1738745027361794900 +0,7,0,2,1,8548,7,0,0,8256,7,0,127546,130053,125.35,260,1738745027439762800 +0,7,0,2,1,10533,7,0,1,11190,7,0,101941,104154,110.65,261,1738745027517772400 +0,7,0,2,0,14309,7,0,1,13583,1,0,76341,77905,78.2,262,1738745027593784800 +0,7,0,2,0,5287,1,0,1,5484,1,0,50734,52670,96.8,263,1738745027671892100 +0,7,0,2,0,2663,2,0,1,3061,7,0,25132,27338,110.3,264,1738745027749765700 +0,7,0,2,1,8230,4,0,1,230,5,0,130599,132569,98.5,265,1738745027825769100 +0,7,0,2,0,10982,6,0,0,11899,4,0,104996,107159,108.15,266,1738745027903766400 +0,7,0,2,1,13734,0,0,0,13356,4,0,79392,81479,104.35,267,1738745027981779400 +0,7,0,2,1,5986,1,0,0,5812,7,0,53790,55610,91.0,268,1738745028057781400 +0,7,0,2,1,2850,4,0,1,2483,4,0,28184,30440,112.8,269,1738745028135770600 +0,7,0,2,1,483,7,0,1,874,4,0,2581,4711,106.5,270,1738745028213761400 +0,7,0,2,1,11939,6,0,1,12076,2,0,108052,110147,104.75,271,1738745028289793100 +0,7,0,2,1,15457,1,0,1,15846,5,0,82446,84518,103.6,272,1738745028367756300 +0,7,0,2,1,5665,2,0,1,4773,5,0,56844,58934,104.5,273,1738745028445741400 +0,7,0,2,0,2272,4,0,0,6163,1,0,31239,33006,88.35,274,1738745028521742100 +0,7,0,2,0,928,6,0,1,612,2,0,5636,7619,99.15,275,1738745028599876800 +0,7,0,2,1,11552,0,0,1,11450,4,0,111103,112999,94.8,276,1738745028677740300 +0,7,0,2,0,15712,3,0,1,16361,4,0,85501,87432,96.55,277,1738745028753745700 +0,7,0,2,0,5024,4,0,0,4384,3,0,59896,61949,102.65,278,1738745028831753700 +0,7,0,2,1,6369,7,0,1,6447,4,0,34293,36439,107.3,279,1738745028909736500 +0,7,0,2,1,1569,3,0,0,1955,2,0,8690,10732,102.1,280,1738745028985864900 +0,7,0,2,1,11363,3,0,0,9396,6,0,114157,116420,113.15,281,1738745029063744300 +0,7,0,2,1,16035,2,0,1,14947,3,0,88556,90642,104.3,282,1738745029141730500 +0,7,0,2,1,4578,5,0,1,4195,1,0,62950,65006,102.8,283,1738745029219745300 +0,7,0,2,0,6946,7,0,1,6888,5,0,37349,39545,109.8,284,1738745029295705700 +0,7,0,2,0,1894,1,0,1,1513,6,0,11742,13707,98.25,285,1738745029375063400 +0,7,0,2,1,9638,3,0,1,10035,2,0,117213,119059,92.3,286,1738745029451717700 +0,7,0,2,1,15078,5,0,0,15228,4,0,91609,93511,95.1,287,1738745029527711200 +0,7,0,2,0,12327,7,0,1,12779,7,0,66005,68202,109.85,288,1738745029605717000 +0,7,0,2,0,6759,0,0,1,7834,0,0,40400,42848,122.4,289,1738745029683715500 +0,7,0,2,1,1189,3,0,0,3101,4,0,14797,16567,88.5,290,1738745029759712500 +0,7,0,2,0,10213,3,0,0,9836,1,0,120269,122302,101.65,291,1738745029837710900 +0,7,0,2,1,14628,5,0,0,14542,3,0,94662,97186,126.2,292,1738745029915721900 +0,7,0,2,1,12644,2,0,0,13220,3,0,69059,71229,108.5,293,1738745029991716000 +0,7,0,2,0,8108,0,0,1,7453,4,0,43455,45239,89.2,294,1738745030069715400 +0,7,0,2,0,3308,3,0,0,3442,5,0,17853,19737,94.2,295,1738745030147707800 +0,7,0,2,1,8748,4,0,0,9191,0,0,123320,125487,108.35,296,1738745030223719500 +0,7,0,2,0,14445,6,0,0,10472,4,0,97716,99719,100.15,297,1738745030301720700 +0,7,0,2,0,12973,0,0,0,13886,4,0,72112,74072,98.0,298,1738745030377678400 +0,7,0,2,1,7663,3,0,0,7269,1,0,46509,48590,104.05,299,1738745030457695600 +0,7,0,2,0,3887,7,0,1,3839,5,0,20906,23209,115.15,300,1738745030533700600 +0,7,0,2,1,9070,7,0,1,8675,3,0,126373,128493,106.0,301,1738745030611694100 +0,7,0,2,1,10670,2,0,1,11049,7,0,100771,102794,101.15,302,1738745030689692300 +0,7,0,2,0,14058,1,0,0,14125,1,0,75166,77390,111.2,303,1738745030765709000 +0,7,0,2,0,5162,2,0,1,5601,4,0,49564,51720,107.8,304,1738745030843721600 +0,7,0,2,0,3691,4,0,0,2794,7,0,23959,26010,102.55,305,1738745030921717000 +0,7,0,2,0,8363,6,0,1,96,1,0,129428,131585,107.85,306,1738745030997831000 +0,7,0,2,1,11243,0,0,0,10857,6,0,103824,105867,102.15,307,1738745031075690500 +0,7,0,2,1,13609,3,0,1,13458,6,0,78221,80100,93.95,308,1738745031153683700 +0,7,0,2,0,5481,4,0,0,6134,1,0,52616,54561,97.25,309,1738745031229688700 +0,7,0,2,1,2984,7,0,0,2339,7,0,27013,29162,107.45,310,1738745031307695600 +0,7,0,2,1,232,6,0,0,449,5,0,1412,3062,82.5,311,1738745031385664400 +0,7,0,2,1,11832,1,0,1,12261,4,0,106878,109111,111.65,312,1738745031461666700 +0,7,0,2,0,13432,2,0,0,15591,5,0,81276,83414,106.9,313,1738745031539657400 +0,7,0,2,0,5817,5,0,1,4704,0,0,55670,57856,109.3,314,1738745031617666300 +0,7,0,2,1,2553,7,0,0,2151,5,0,30069,32214,107.25,315,1738745031693653300 +0,7,0,2,1,827,0,0,0,702,2,0,4463,6492,101.45,316,1738745031771679500 +0,7,0,2,0,12155,2,0,1,11768,2,0,109932,111996,103.2,317,1738745031849682300 +0,7,0,2,0,15803,6,0,0,16145,4,0,84331,86263,96.6,318,1738745031927678800 +0,7,0,2,1,4858,7,0,1,4970,4,0,58725,60824,104.95,319,1738745032003662700 +0,7,0,2,1,6202,3,0,0,6634,4,0,33122,35431,115.45,320,1738745032081677700 +0,7,0,2,1,638,1,0,0,1758,6,0,7518,9380,93.1,321,1738745032159662000 +0,7,0,2,1,11454,6,0,1,9257,3,0,112987,115085,104.9,322,1738745032235638200 +0,7,0,2,1,16383,5,0,1,15906,2,0,87382,89628,112.3,323,1738745032313640000 +0,7,0,2,0,4415,6,0,1,4285,7,0,61780,63818,101.9,324,1738745032391639100 +0,7,0,2,0,6525,0,0,1,7165,3,0,36175,38221,102.3,325,1738745032467813600 +0,7,0,2,0,1981,3,0,0,1337,2,0,10573,12659,104.3,326,1738745032545640200 +0,7,0,2,1,9468,4,0,0,9558,0,0,116039,117983,97.2,327,1738745032623634900 +0,7,0,2,1,14908,7,0,0,15250,4,0,90437,92391,97.7,328,1738745032699640100 +0,7,0,2,0,4220,0,0,0,12473,1,0,64832,67214,119.1,329,1738745032777636700 +0,7,0,2,0,6836,3,0,1,7784,1,0,39229,41598,118.45,330,1738745032855638500 +0,7,0,2,1,1524,2,0,1,1128,0,0,13628,15744,105.8,331,1738745032931773200 +0,7,0,2,1,10037,5,0,1,9875,7,0,119094,121066,98.6,332,1738745033009666800 +0,7,0,2,1,15221,6,0,1,14824,3,0,93492,95618,106.3,333,1738745033087622200 +0,7,0,2,0,12727,0,0,0,13119,1,0,67887,69969,104.1,334,1738745033163599700 +0,7,0,2,0,7927,3,0,1,8134,5,0,42285,43993,85.4,335,1738745033241631700 +0,7,0,2,1,3126,4,0,1,3480,7,0,16679,18565,94.3,336,1738745033319618300 +0,7,0,2,1,9846,7,0,1,8924,7,0,122149,124090,97.05,337,1738745033395610400 +0,7,0,2,1,14518,0,0,0,10338,1,0,96544,98846,115.1,338,1738745033473750500 +0,7,0,2,1,13298,3,0,1,12922,5,0,70941,73062,106.05,339,1738745033551614400 +0,7,0,2,0,7474,5,0,0,7343,2,0,45337,47532,109.75,340,1738745033629617800 +0,7,0,2,1,3443,5,0,1,4073,5,0,19734,21897,108.15,341,1738745033705781800 +0,7,0,2,0,9139,6,0,1,8479,6,0,125204,127147,97.15,342,1738745033783608100 +0,7,0,2,1,10481,1,0,1,10617,3,0,99598,101746,107.4,343,1738745033861619700 +0,7,0,2,1,13873,3,0,0,14270,5,0,73997,76121,106.2,344,1738745033937608300 +0,7,0,2,0,7280,4,0,0,5356,2,0,48391,50620,111.45,345,1738745034015606400 +0,7,0,2,0,3760,7,0,1,2594,0,0,22789,25056,113.35,346,1738745034093617100 +0,7,0,2,1,8656,0,0,0,8234,7,0,128255,130661,120.3,347,1738745034169587800 +0,7,0,2,0,11024,3,0,1,10943,1,0,102653,104785,106.6,348,1738745034247587800 +0,7,0,2,0,14160,4,0,1,13793,3,0,77048,79346,114.9,349,1738745034325581500 +0,7,0,2,1,5521,7,0,0,5899,0,0,51445,53359,95.7,350,1738745034401741800 +0,7,0,2,0,2769,2,0,1,2937,6,0,25843,28020,108.85,351,1738745034479584900 +0,7,0,2,1,19,1,0,0,500,6,0,238,2756,125.9,352,1738745034557644400 +0,7,0,2,1,10835,2,0,1,11983,5,0,105708,107606,94.9,353,1738745034633586500 +0,7,0,2,1,13458,5,0,1,15402,7,0,80102,82330,111.4,354,1738745034711810300 +0,7,0,2,0,6098,6,0,1,5752,7,0,54500,56698,109.9,355,1738745034789812800 +0,7,0,2,1,2326,0,0,1,2200,6,0,28895,30852,97.85,356,1738745034865750100 +0,7,0,2,0,342,2,0,1,1014,1,0,3292,5409,105.85,357,1738745034943734600 +0,7,0,2,1,12182,4,0,0,11560,7,0,108760,110981,111.05,358,1738745035021801300 +0,7,0,2,0,15575,7,0,0,15723,5,0,83157,85398,112.05,359,1738745035097697800 +0,7,0,2,1,4631,6,0,0,5012,1,0,57556,59585,101.45,360,1738745035175675500 +0,7,0,2,1,2133,1,0,0,6359,2,0,31950,34003,102.65,361,1738745035253754700 +0,7,0,2,0,661,2,0,1,1549,1,0,6348,8270,96.1,362,1738745035331620100 +0,7,0,2,0,11732,5,0,1,11353,0,0,111814,113807,99.65,363,1738745035407564400 +0,7,0,2,0,16148,7,0,1,16030,6,0,86213,88228,100.75,364,1738745035485561900 +0,7,0,2,0,4956,0,0,1,4604,0,0,60607,62784,108.85,365,1738745035563577100 +0,7,0,2,0,6556,2,0,0,6964,6,0,35004,37179,108.75,366,1738745035639571000 +0,7,0,2,1,1757,4,0,0,1897,4,0,9399,11656,112.85,367,1738745035717734300 +0,7,0,2,0,9245,6,0,0,9705,1,0,114868,117361,124.65,368,1738745035795509400 +0,7,0,2,0,15965,1,0,0,15100,5,0,89265,91462,109.85,369,1738745035871698500 +0,7,0,2,1,4255,3,0,0,12297,5,0,63661,65654,99.65,370,1738745035949588400 +0,7,0,2,0,7135,6,0,0,6688,2,0,38059,40451,119.6,371,1738745036027663800 +0,7,0,2,1,1310,5,0,1,1170,6,0,12454,14564,105.5,372,1738745036103551400 +0,7,0,2,1,9566,6,0,0,10195,7,0,117924,120042,105.9,373,1738745036181713100 +0,7,0,2,1,15258,0,0,1,15111,3,0,92319,94162,92.15,374,1738745036259586600 +0,7,0,2,0,12506,2,0,1,12634,1,0,66716,68766,102.5,375,1738745036335566300 +0,7,0,2,1,7707,4,0,1,8118,5,0,41111,43302,109.55,376,1738745036413543000 +0,7,0,2,1,1115,7,0,0,3143,6,0,15509,17364,92.75,377,1738745036491549300 +0,7,0,2,1,9883,0,0,0,8728,1,0,120976,123009,101.65,378,1738745036567536900 +0,7,0,2,0,14809,3,0,0,14440,7,0,95373,97669,114.8,379,1738745036645545200 +0,7,0,2,1,13081,7,0,0,12959,2,0,69770,71852,104.1,380,1738745036723588000 +0,7,0,2,1,8024,5,0,0,7630,5,0,44166,46169,100.15,381,1738745036801548100 +0,7,0,2,0,3480,2,0,0,3875,1,0,18563,20974,120.55,382,1738745036877569700 +0,7,0,2,1,8904,1,0,1,8994,4,0,124030,126488,122.9,383,1738745036955515300 +0,7,0,2,0,10248,2,0,0,10666,3,0,98428,100765,116.85,384,1738745037033519000 +0,7,0,2,1,12873,4,0,1,13897,3,0,72823,74637,90.7,385,1738745037109511300 +0,7,0,2,0,7305,7,0,1,5133,3,0,47221,49229,100.4,386,1738745037187526700 +0,7,0,2,0,4041,0,0,0,3668,0,0,21616,23744,106.4,387,1738745037265514600 +0,7,0,2,0,8459,3,0,1,8329,3,0,127085,129138,102.65,388,1738745037341518200 +0,7,0,2,0,10571,5,0,0,11207,0,0,101481,103471,99.5,389,1738745037419519900 +0,7,0,2,0,14218,7,0,1,13607,3,0,75877,78290,120.65,390,1738745037497655000 +0,7,0,2,0,5322,2,0,1,5499,7,0,50275,52586,115.55,391,1738745037573514000 +0,7,0,2,1,2574,3,0,1,2980,6,0,24669,27076,120.35,392,1738745037651509600 +0,7,0,2,0,8270,2,0,1,217,4,0,130140,132232,104.6,393,1738745037729515500 +0,7,0,2,0,10895,4,0,0,10767,4,0,104535,106408,93.65,394,1738745037805519200 +0,7,0,2,1,13775,6,0,1,13390,2,0,78932,80988,102.8,395,1738745037883484400 +0,7,0,2,0,5903,0,0,1,5777,0,0,53328,55536,110.4,396,1738745037961486600 +0,7,0,2,1,2893,3,0,1,2510,2,0,27725,29788,103.15,397,1738745038037647500 +0,7,0,2,0,397,4,0,0,828,0,0,2120,4416,114.8,398,1738745038115502000 +0,7,0,2,1,11980,7,0,0,12113,1,0,107589,109809,111.0,399,1738745038193622500 +0,7,0,2,0,15372,1,0,0,15503,3,0,81985,83885,95.0,400,1738745038271487000 +0,7,0,2,1,5700,1,0,1,4859,3,0,56382,58733,117.55,401,1738745038347441000 +0,7,0,2,0,2180,3,0,0,2094,6,0,30781,32347,78.3,402,1738745038425469800 +0,7,0,2,1,965,5,0,1,592,6,0,5174,7419,112.25,403,1738745038501512700 +0,7,0,2,0,11525,7,0,0,11665,3,0,110645,112397,87.6,404,1738745038579558000 +0,7,0,2,0,15687,0,0,1,16331,6,0,85039,87147,105.4,405,1738745038657520100 +0,7,0,2,1,4999,3,0,0,4867,2,0,59437,61420,99.15,406,1738745038735490100 +0,7,0,2,0,6342,4,0,0,6492,0,0,33831,36031,110.0,407,1738745038811478600 +0,7,0,2,1,1542,7,0,0,1679,0,0,8229,10159,96.5,408,1738745038889464000 +0,7,0,2,1,11334,1,0,0,9457,6,0,113697,115979,114.1,409,1738745038967494600 +0,7,0,2,1,16002,3,0,0,15873,7,0,88093,90101,100.4,410,1738745039043737700 +0,7,0,2,0,4546,7,0,0,4161,0,0,62490,64527,101.85,411,1738745039121457400 +0,7,0,2,0,6915,5,0,1,7067,5,0,36886,38761,93.75,412,1738745039199654100 +0,7,0,2,1,1859,2,0,0,1496,5,0,11283,13446,108.15,413,1738745039275617100 +0,7,0,2,0,9601,0,0,0,9997,4,0,116751,118856,105.25,414,1738745039353601700 +0,7,0,2,1,15041,2,0,1,15216,7,0,91148,93445,114.85,415,1738745039431467000 +0,7,0,2,1,12289,4,0,1,12433,3,0,65544,67341,89.85,416,1738745039507593500 +0,7,0,2,1,6720,7,0,0,7763,2,0,39941,41747,90.3,417,1738745039585470100 +0,7,0,2,0,1152,0,0,1,3097,3,0,14336,16525,109.45,418,1738745039663847000 +0,7,0,2,1,10048,3,0,0,9811,5,0,119805,122089,114.2,419,1738745039739473700 +0,7,0,2,0,15104,7,0,1,14743,2,0,94202,96044,92.1,420,1738745039817467200 +0,7,0,2,1,12737,5,0,1,13134,3,0,68598,70562,98.2,421,1738745039895569800 +0,7,0,2,1,7809,6,0,1,7451,0,0,42996,45200,110.2,422,1738745039973442200 +0,7,0,2,0,3139,1,0,1,3395,0,0,17390,19472,104.1,423,1738745040049435400 +0,7,0,2,0,9731,2,0,1,9096,4,0,122860,125048,109.4,424,1738745040127450900 +0,7,0,2,1,14530,4,0,1,10317,1,0,97255,99249,99.7,425,1738745040205437000 +0,7,0,2,0,13186,6,0,1,13852,2,0,71652,73916,113.2,426,1738745040281440500 +0,7,0,2,1,7490,1,0,1,7234,7,0,46049,48154,105.25,427,1738745040359439700 +0,7,0,2,0,3334,3,0,1,3743,0,0,20445,22703,112.9,428,1738745040437540800 +0,7,0,2,0,9158,5,0,0,8516,6,0,125913,127940,101.35,429,1738745040513441000 +0,7,0,2,1,10375,7,0,0,11035,0,0,100309,102544,111.75,430,1738745040591440400 +0,7,0,2,0,13895,2,0,0,14153,4,0,74707,76919,110.6,431,1738745040669443300 +0,7,0,2,1,7173,1,0,1,5268,5,0,49102,51001,94.95,432,1738745040745442500 +0,7,0,2,1,3781,2,0,1,2639,2,0,23500,25516,100.8,433,1738745040823667200 +0,7,0,2,0,8580,5,0,1,3,3,0,128966,131090,106.2,434,1738745040901850700 +0,7,0,2,0,11076,7,0,0,10948,1,0,103365,105409,102.2,435,1738745040977411800 +0,7,0,2,1,14092,0,0,0,13748,2,0,77759,79555,89.8,436,1738745041055544900 +0,7,0,2,0,5580,3,0,0,6082,1,0,52157,54302,107.25,437,1738745041133409200 +0,7,0,2,1,2700,4,0,0,2318,7,0,26552,28762,110.5,438,1738745041209429400 +0,7,0,2,1,77,7,0,1,459,5,0,949,2966,100.85,439,1738745041287412800 +0,7,0,2,0,10765,2,0,1,11927,3,0,106419,108333,95.7,440,1738745041365543800 +0,7,0,2,1,13519,3,0,1,15601,4,0,80813,83208,119.75,441,1738745041443405400 +0,7,0,2,0,6031,6,0,0,4613,5,0,55211,57398,109.35,442,1738745041519406300 +0,7,0,2,0,2382,4,0,0,2242,4,0,29607,31719,105.6,443,1738745041597544600 +0,7,0,2,1,270,6,0,0,643,0,0,4004,6160,107.8,444,1738745041675409700 +0,7,0,2,0,12234,0,0,0,11712,5,0,109471,111622,107.55,445,1738745041751402600 +0,7,0,2,0,15498,3,0,0,15620,7,0,83869,85957,104.4,446,1738745041829385000 +0,7,0,2,0,4682,4,0,0,5109,4,0,58264,60104,92.0,447,1738745041907437400 +0,7,0,2,0,2059,7,0,1,6300,7,0,32661,34629,98.4,448,1738745041983399800 +0,7,0,2,0,715,1,0,0,1734,0,0,7057,9248,109.55,449,1738745042061518300 +0,7,0,2,1,11657,3,0,1,9231,6,0,112525,114772,112.35,450,1738745042139391600 +0,7,0,2,0,16201,6,0,1,16089,6,0,86923,88948,101.25,451,1738745042215513100 +0,7,0,2,1,4872,5,0,0,4233,4,0,61318,63607,114.45,452,1738745042293378800 +0,7,0,2,1,6600,6,0,1,6993,5,0,35716,37641,96.25,453,1738745042371439800 +0,7,0,2,0,1688,0,0,1,1808,1,0,10111,12033,96.1,454,1738745042447396500 +0,7,0,2,1,9304,2,0,0,9675,7,0,115580,117653,103.65,455,1738745042525377600 +0,7,0,2,0,15897,4,0,0,15238,6,0,89975,92196,111.05,456,1738745042603387200 +0,7,0,2,0,4313,7,0,0,12357,5,0,64373,66505,106.6,457,1738745042679368900 +0,7,0,2,0,7065,0,0,0,6661,4,0,38768,40904,106.8,458,1738745042757367600 +0,7,0,2,1,1371,3,0,0,1088,6,0,13165,15364,109.95,459,1738745042835361500 +0,7,0,2,1,9499,6,0,1,10220,6,0,118635,120251,80.8,460,1738745042911354800 +0,7,0,2,1,15322,5,0,0,14678,4,0,93030,95015,99.25,461,1738745042989355500 +0,7,0,2,0,12442,6,0,0,12593,0,0,67428,69360,96.6,462,1738745043067483200 +0,7,0,2,0,7774,1,0,0,8181,1,0,41822,43726,95.2,463,1738745043145364200 +0,7,0,2,0,1054,2,0,1,3222,3,0,16220,18210,99.5,464,1738745043221366100 +0,7,0,2,0,9951,4,0,0,8784,0,0,121687,123648,98.05,465,1738745043299363400 +0,7,0,2,0,14751,7,0,1,14388,5,0,96085,97990,95.25,466,1738745043377477500 +0,7,0,2,1,13149,0,0,1,12996,1,0,70479,72641,108.1,467,1738745043453394600 +0,7,0,2,0,7965,3,0,0,7351,6,0,44877,47403,126.3,468,1738745043531361600 +0,7,0,2,1,3549,5,0,0,3933,2,0,19273,21324,102.55,469,1738745043609351400 +0,7,0,2,1,8860,7,0,1,8988,3,0,124741,126786,102.25,470,1738745043685344600 +0,7,0,2,1,10332,2,0,0,10566,3,0,99139,101410,113.55,471,1738745043763341000 +0,7,0,2,1,12820,1,0,1,13969,7,0,73534,75530,99.8,472,1738745043841336200 +0,7,0,2,0,7380,2,0,1,5214,2,0,47932,50012,104.0,473,1738745043917690400 +0,7,0,2,0,3989,4,0,0,3607,1,0,22327,24366,101.95,474,1738745043995359600 +0,7,0,2,0,8533,7,0,0,8398,3,0,127797,129954,107.85,475,1738745044073348800 +0,7,0,2,1,10519,0,0,0,11151,2,0,102191,104364,108.65,476,1738745044149342100 +0,7,0,2,0,14295,3,0,1,13646,5,0,76589,78758,108.45,477,1738745044227334500 +0,7,0,2,1,5271,4,0,0,5399,0,0,50984,53039,102.75,478,1738745044305330700 +0,7,0,2,1,2646,5,0,0,3052,7,0,25382,27205,91.15,479,1738745044381341600 +0,7,0,2,1,8214,2,0,0,153,2,0,130851,132979,106.4,480,1738745044459335300 +0,7,0,2,1,10962,3,0,1,11901,0,0,105245,107184,96.95,481,1738745044537331700 +0,7,0,2,0,13714,2,0,1,13352,0,0,79644,81535,94.55,482,1738745044615319300 +0,7,0,2,1,5971,5,0,0,5876,5,0,54038,56006,98.4,483,1738745044691332900 +0,7,0,2,0,2835,7,0,1,2483,1,0,28437,30446,100.45,484,1738745044769313800 +0,7,0,2,0,465,0,0,1,883,0,0,2831,4847,100.8,485,1738745044847327800 +0,7,0,2,0,11921,3,0,1,11530,0,0,108301,110688,119.35,486,1738745044923303900 +0,7,0,2,1,15441,4,0,1,15782,5,0,82696,84441,87.25,487,1738745045001343800 +0,7,0,2,1,5648,5,0,0,4752,6,0,57094,59140,102.3,488,1738745045079457200 +0,7,0,2,0,2256,0,0,1,6214,0,0,31488,33759,113.55,489,1738745045155317400 +0,7,0,2,1,944,1,0,1,546,5,0,5886,7705,90.95,490,1738745045233326900 +0,7,0,2,0,11632,6,0,0,11481,4,0,111355,113527,108.6,491,1738745045311468100 +0,7,0,2,1,15665,5,0,0,16264,0,0,85750,87936,109.3,492,1738745045387260300 +0,7,0,2,0,5105,6,0,1,4475,1,0,60148,62097,97.45,493,1738745045465505400 +0,7,0,2,0,6323,1,0,1,6424,1,0,34542,36734,109.6,494,1738745045543346900 +0,7,0,2,0,1651,2,0,1,2006,3,0,8940,11042,105.1,495,1738745045619300400 +0,7,0,2,0,11314,4,0,0,9365,2,0,114407,116531,106.2,496,1738745045697285300 +0,7,0,2,1,16114,7,0,0,14881,0,0,88805,90608,90.15,497,1738745045775289500 +0,7,0,2,1,4530,0,0,1,4145,4,0,63200,65271,103.55,498,1738745045851284200 +0,7,0,2,0,7030,3,0,0,6876,4,0,37597,39751,107.7,499,1738745045929286900 +0,7,0,2,0,1846,5,0,1,1438,1,0,11993,14174,109.05,500,1738745046007286400 +0,7,0,2,1,9719,7,0,0,10070,4,0,117461,119591,106.5,501,1738745046085282700 +0,7,0,2,1,15031,2,0,1,15161,5,0,91859,93833,98.7,502,1738745046161280900 +0,7,0,2,0,12405,0,0,0,12731,5,0,66255,67945,84.5,503,1738745046239288500 +0,7,0,2,0,6709,2,0,0,7856,7,0,40652,42746,104.7,504,1738745046315403900 +0,7,0,2,0,1268,4,0,0,3189,3,0,15047,17101,102.7,505,1738745046393286100 +0,7,0,2,0,10164,7,0,1,9773,4,0,120517,122440,96.15,506,1738745046471282300 +0,7,0,2,0,14708,0,0,1,14503,6,0,94912,96724,90.6,507,1738745046549259600 +0,7,0,2,1,12604,3,0,1,13217,6,0,69309,71179,93.5,508,1738745046625266600 +0,7,0,2,0,8188,4,0,0,7516,5,0,43704,45894,109.5,509,1738745046703261400 +0,7,0,2,1,3261,5,0,1,3345,0,0,18102,20239,106.85,510,1738745046781294100 +0,7,0,2,1,8829,6,0,1,9134,0,0,123572,125344,88.6,511,1738745046857299600 +0,7,0,2,1,14399,1,0,0,10429,2,0,97966,100019,102.65,512,1738745046935264000 +0,7,0,2,1,13055,6,0,1,13906,6,0,72363,74523,108.0,513,1738745047013416200 +0,7,0,2,0,7614,5,0,0,7221,6,0,46758,48843,104.25,514,1738745047089263300 +0,7,0,2,1,3966,6,0,0,3785,0,0,21156,23439,114.15,515,1738745047167259500 +0,7,0,2,1,9022,0,0,0,8633,0,0,126624,128655,101.55,516,1738745047245257200 +0,7,0,2,0,10746,3,0,0,11047,5,0,101021,102870,92.45,517,1738745047321257900 +0,7,0,2,0,14010,4,0,0,14099,6,0,75416,77588,108.6,518,1738745047399264600 +0,7,0,2,0,5243,7,0,0,5616,7,0,49813,51962,107.45,519,1738745047477380100 +0,7,0,2,0,3643,2,0,1,2784,6,0,24211,26107,94.8,520,1738745047553238800 +0,7,0,2,1,8441,3,0,0,74,0,0,129677,131999,116.1,521,1738745047631237200 +0,7,0,2,1,11193,2,0,1,10784,2,0,104076,105987,95.55,522,1738745047709463600 +0,7,0,2,1,13688,5,0,0,13566,5,0,78470,80550,104.0,523,1738745047787237900 +0,7,0,2,1,5432,6,0,1,6024,7,0,52868,55173,115.25,524,1738745047863238700 +0,7,0,2,1,3064,0,0,0,2400,7,0,27264,29189,96.25,525,1738745047941247000 +0,7,0,2,0,168,3,0,0,310,5,0,1661,3801,107.0,526,1738745048019252600 +0,7,0,2,0,11880,4,0,1,12245,5,0,107128,109366,111.9,527,1738745048095233600 +0,7,0,2,0,13353,7,0,0,15546,0,0,81525,83615,104.5,528,1738745048173248400 +0,7,0,2,0,5865,3,0,1,4643,5,0,55922,57833,95.55,529,1738745048251241700 +0,7,0,2,1,2475,1,0,1,2058,4,0,30318,32664,117.3,530,1738745048327220200 +0,7,0,2,1,875,6,0,1,727,0,0,4715,6959,112.2,531,1738745048405356500 +0,7,0,2,1,12074,5,0,0,11671,7,0,110182,112426,112.2,532,1738745048483214300 +0,7,0,2,1,15850,2,0,0,16254,2,0,84579,86691,105.6,533,1738745048559219700 +0,7,0,2,0,4782,0,0,0,4909,3,0,58975,61005,101.5,534,1738745048637219700 +0,7,0,2,0,6254,3,0,0,6647,5,0,33373,35542,108.45,535,1738745048715212200 +0,7,0,2,1,559,4,0,0,1675,2,0,7767,10131,118.2,536,1738745048791204000 +0,7,0,2,0,11503,7,0,1,9337,0,0,113237,115343,105.3,537,1738745048869219400 +0,7,0,2,1,16303,0,0,0,15872,6,0,87632,90107,123.75,538,1738745048947215900 +0,7,0,2,1,4461,3,0,0,4319,2,0,62029,64339,115.5,539,1738745049023206000 +0,7,0,2,1,6445,7,0,0,7138,4,0,36426,38375,97.45,540,1738745049101334600 +0,7,0,2,1,2028,5,0,0,1383,7,0,10822,12842,101.0,541,1738745049179216900 +0,7,0,2,0,9388,2,0,1,9501,7,0,116291,118602,115.55,542,1738745049257214900 +0,7,0,2,1,14948,1,0,1,15312,1,0,90686,92929,112.15,543,1738745049333190600 +0,7,0,2,0,4132,2,0,0,12473,1,0,65084,67214,106.5,544,1738745049411188200 +0,7,0,2,1,6885,4,0,1,7791,0,0,39479,41552,103.65,545,1738745049489184100 +0,7,0,2,0,1445,7,0,0,1076,7,0,13877,16069,109.6,546,1738745049565185900 +0,7,0,2,1,10085,0,0,0,9903,1,0,119344,121262,95.9,547,1738745049643190100 +0,7,0,2,1,15143,1,0,0,14824,7,0,93742,95621,93.95,548,1738745049721246900 +0,7,0,2,0,12775,5,0,1,13170,2,0,68137,70371,111.7,549,1738745049797193600 +0,7,0,2,1,7846,7,0,1,8035,5,0,42533,44521,99.4,550,1738745049875186800 +0,7,0,2,1,3174,2,0,1,3561,4,0,16931,19063,106.6,551,1738745049953192300 +0,7,0,2,0,9762,1,0,0,8935,3,0,122398,124370,98.6,552,1738745050029181900 +0,7,0,2,0,14562,2,0,1,10367,4,0,96796,98984,109.4,553,1738745050107189700 +0,7,0,2,0,13219,5,0,1,12851,2,0,71190,73452,113.1,554,1738745050185187700 +0,7,0,2,0,7523,7,0,0,7356,7,0,45589,47429,92.0,555,1738745050261166800 +0,7,0,2,1,3363,0,0,0,4001,0,0,19984,22031,102.35,556,1738745050339389400 +0,7,0,2,0,9185,3,0,0,8553,1,0,125453,127601,107.4,557,1738745050417113200 +0,7,0,2,1,10401,4,0,0,10542,7,0,99848,101978,106.5,558,1738745050493157200 +0,7,0,2,0,13920,7,0,1,14330,7,0,74245,76442,109.85,559,1738745050571157300 +0,7,0,2,1,7200,1,0,1,5302,5,0,48641,50905,113.2,560,1738745050649185700 +0,7,0,2,1,3744,3,0,1,2650,7,0,23037,25445,120.4,561,1738745050725165100 +0,7,0,2,0,8672,2,0,0,8305,0,0,128508,130319,90.55,562,1738745050803160100 +0,7,0,2,1,11041,5,0,0,10968,2,0,102902,105340,121.9,563,1738745050881160700 +0,7,0,2,0,14177,6,0,0,13744,4,0,77300,79608,115.4,564,1738745050959168700 +0,7,0,2,0,5539,0,0,0,5990,2,0,51695,53795,105.0,565,1738745051035207800 +0,7,0,2,0,2787,2,0,1,2872,4,0,26092,28295,110.15,566,1738745051113284700 +0,7,0,2,1,35,4,0,0,506,2,0,488,2716,111.4,567,1738745051191166900 +0,7,0,2,0,10850,7,0,0,11942,1,0,105957,108065,105.4,568,1738745051267157400 +0,7,0,2,0,13474,1,0,0,15388,0,0,80353,82111,87.9,569,1738745051345137300 +0,7,0,2,1,6118,3,0,1,5677,0,0,54749,56911,108.1,570,1738745051423140300 +0,7,0,2,1,2342,6,0,1,2279,6,0,29147,31275,106.4,571,1738745051499132300 +0,7,0,2,1,359,5,0,1,1000,6,0,3542,5508,98.3,572,1738745051577140800 +0,7,0,2,1,12199,6,0,0,11554,0,0,109012,111072,103.0,573,1738745051655537200 +0,7,0,2,1,15589,0,0,0,15671,0,0,83407,85712,115.25,574,1738745051731136100 +0,7,0,2,0,4645,3,0,1,5036,0,0,57805,59839,101.7,575,1738745051809137500 +0,7,0,2,0,2149,4,0,0,6359,4,0,32200,34007,90.35,576,1738745051887143500 +0,7,0,2,0,676,7,0,0,1647,6,0,6597,8788,109.55,577,1738745051963151700 +0,7,0,2,0,11748,0,0,1,11322,7,0,112064,114330,113.3,578,1738745052041131200 +0,7,0,2,1,16172,1,0,0,16051,4,0,86462,88343,94.05,579,1738745052119137600 +0,7,0,2,0,4972,7,0,1,4491,7,0,60858,63381,126.15,580,1738745052195132200 +0,7,0,2,1,6573,5,0,1,6965,5,0,35254,37174,96.0,581,1738745052273181900 +0,7,0,2,1,1773,6,0,0,1837,4,0,9652,11848,109.8,582,1738745052351134000 +0,7,0,2,0,9263,1,0,0,9697,3,0,115118,117261,107.15,583,1738745052429119700 +0,7,0,2,0,15983,3,0,0,15099,3,0,89517,91501,99.2,584,1738745052505109600 +0,7,0,2,0,4270,5,0,1,12409,2,0,63910,66188,113.9,585,1738745052583111200 +0,7,0,2,0,7150,7,0,0,6776,0,0,38309,40319,100.5,586,1738745052661113100 +0,7,0,2,0,1326,0,0,0,1180,0,0,12704,14527,91.15,587,1738745052737114400 +0,7,0,2,1,9578,3,0,0,10226,0,0,118173,120095,96.1,588,1738745052815105600 +0,7,0,2,0,15274,4,0,1,14631,5,0,92568,94678,105.5,589,1738745052893116500 +0,7,0,2,1,12523,7,0,0,12664,3,0,66965,68989,101.2,590,1738745052969110700 +0,7,0,2,0,7723,2,0,0,8110,3,0,41363,43426,103.15,591,1738745053047107300 +0,7,0,2,1,1129,1,0,0,3248,3,0,15758,18173,120.75,592,1738745053125236900 +0,7,0,2,1,9897,2,0,1,8737,1,0,121228,123377,107.45,593,1738745053201085400 +0,7,0,2,0,14824,5,0,1,14457,4,0,95622,97655,101.65,594,1738745053279095200 +0,7,0,2,1,13096,7,0,0,12977,5,0,70021,71945,96.2,595,1738745053357086600 +0,7,0,2,1,8040,0,0,0,7644,5,0,44416,46265,92.45,596,1738745053433101000 +0,7,0,2,0,3512,3,0,1,3870,7,0,18813,20645,91.6,597,1738745053511088100 +0,7,0,2,1,8952,4,0,0,9062,5,0,124280,126425,107.25,598,1738745053589083900 +0,7,0,2,1,10297,7,0,1,10668,5,0,98677,100793,105.8,599,1738745053665114600 +0,7,0,2,1,12921,6,0,1,13890,2,0,73076,74723,82.35,600,1738745053743125600 +0,7,0,2,1,7355,1,0,1,5246,1,0,47470,49825,117.75,601,1738745053821195500 +0,7,0,2,0,4091,6,0,0,3624,6,0,21867,24187,116.0,602,1738745053897086200 +0,7,0,2,0,8506,5,0,1,8421,3,0,127334,129586,112.6,603,1738745053975089700 +0,7,0,2,0,10618,6,0,0,11258,4,0,101732,103783,102.55,604,1738745054053087900 +0,7,0,2,1,14270,0,0,0,13588,7,0,76127,78021,94.7,605,1738745054131066800 +0,7,0,2,0,5374,3,0,1,5412,6,0,50525,52795,113.5,606,1738745054207068600 +0,7,0,2,1,2623,4,0,1,3060,4,0,24919,27335,120.8,607,1738745054285065900 +0,7,0,2,1,8319,5,0,0,69,0,0,130390,132047,82.85,608,1738745054363065200 +0,7,0,2,1,10943,3,0,0,11873,3,0,104786,107021,111.75,609,1738745054439190000 +0,7,0,2,1,13821,3,0,1,13433,1,0,79181,81265,104.2,610,1738745054517192200 +0,7,0,2,1,5949,2,0,0,5791,6,0,53580,55467,94.35,611,1738745054595095500 +0,7,0,2,1,2940,5,0,1,2546,1,0,27974,29982,100.4,612,1738745054671059000 +0,7,0,2,1,444,6,0,0,881,1,0,2372,4849,123.85,613,1738745054749081500 +0,7,0,2,0,12020,0,0,1,12130,1,0,107839,110049,110.5,614,1738745054827068200 +0,7,0,2,0,15412,3,0,0,15752,7,0,82237,84090,92.65,615,1738745054903064100 +0,7,0,2,1,5748,4,0,1,4832,5,0,56632,58873,112.05,616,1738745054981058700 +0,7,0,2,0,2229,7,0,0,6195,6,0,31029,33044,100.75,617,1738745055059195500 +0,7,0,2,1,1013,2,0,1,604,4,0,5427,7352,96.25,618,1738745055135164900 +0,7,0,2,0,11575,3,0,1,11502,2,0,110893,113244,117.55,619,1738745055213050500 +0,7,0,2,1,15735,7,0,0,16366,1,0,85290,87457,108.35,620,1738745055291032800 +0,7,0,2,1,5046,7,0,1,4460,1,0,59685,62017,116.6,621,1738745055367155900 +0,7,0,2,0,6390,6,0,0,6520,0,0,34084,36223,106.95,622,1738745055445031800 +0,7,0,2,0,1586,1,0,1,1968,0,0,8478,10496,100.9,623,1738745055523039700 +0,7,0,2,0,11378,2,0,0,9455,7,0,113948,116138,109.5,624,1738745055601038400 +0,7,0,2,1,16051,4,0,1,14896,0,0,88343,90368,101.25,625,1738745055677049400 +0,7,0,2,1,4595,7,0,0,4221,3,0,62741,64845,105.2,626,1738745055755043600 +0,7,0,2,1,6963,0,0,1,6837,4,0,37136,39223,104.35,627,1738745055833036600 +0,7,0,2,1,1905,3,0,0,1531,2,0,11533,13676,107.15,628,1738745055908995400 +0,7,0,2,0,9649,6,0,0,10085,4,0,117003,119351,117.4,629,1738745055987017900 +0,7,0,2,1,15088,7,0,0,15186,6,0,91397,93412,100.75,630,1738745056065009800 +0,7,0,2,1,12336,2,0,0,12732,1,0,65795,67905,105.5,631,1738745056141018500 +0,7,0,2,1,6736,1,0,1,7922,6,0,40190,42267,103.85,632,1738745056219020500 +0,7,0,2,0,1168,3,0,1,1055,5,0,14589,16214,81.25,633,1738745056297012000 +0,7,0,2,0,10193,4,0,0,9811,2,0,120055,122092,101.85,634,1738745056373006800 +0,7,0,2,0,14609,7,0,1,14523,5,0,94453,96617,108.2,635,1738745056451016400 +0,7,0,2,1,12627,0,0,0,13255,3,0,68847,70701,92.7,636,1738745056529195100 +0,7,0,2,1,8083,3,0,0,7428,1,0,43245,45118,93.65,637,1738745056605018300 +0,7,0,2,0,3283,4,0,0,3445,4,0,17640,19767,106.35,638,1738745056683015900 +0,7,0,2,1,8722,7,0,1,9147,2,0,123109,125292,109.15,639,1738745056761024200 +0,7,0,2,1,14418,1,0,0,10474,4,0,97505,99736,111.55,640,1738745056837014400 +0,7,0,2,1,12950,3,0,0,13877,1,0,71901,74033,106.6,641,1738745056915009800 +0,7,0,2,1,7638,2,0,1,7261,5,0,46300,48310,100.5,642,1738745056992997100 +0,7,0,2,0,3863,5,0,0,3774,3,0,20694,22877,109.15,643,1738745057069124300 +0,7,0,2,0,9047,7,0,1,8657,4,0,126165,128247,104.1,644,1738745057147116700 +0,7,0,2,0,10645,0,0,1,11057,1,0,100559,102670,105.55,645,1738745057224987400 +0,7,0,2,0,14037,3,0,1,14166,6,0,74957,77019,103.1,646,1738745057303012900 +0,7,0,2,1,5141,4,0,1,5556,2,0,49352,51516,108.2,647,1738745057378982600 +0,7,0,2,0,3668,7,0,1,2787,4,0,23749,26088,116.95,648,1738745057457109400 +0,7,0,2,0,8340,0,0,0,22,3,0,129216,131293,103.85,649,1738745057535115400 +0,7,0,2,1,11228,1,0,1,10846,1,0,103614,105633,100.95,650,1738745057611114900 +0,7,0,2,1,13596,2,0,1,13448,5,0,78012,79993,99.05,651,1738745057689019500 +0,7,0,2,1,5469,5,0,0,6132,0,0,52406,54591,109.25,652,1738745057767154800 +0,7,0,2,0,2973,2,0,0,2312,3,0,26803,28797,99.7,653,1738745057843021000 +0,7,0,2,0,223,1,0,0,328,1,0,1198,3198,100.0,654,1738745057921011100 +0,7,0,2,0,11807,2,0,0,12213,5,0,106668,108854,109.3,655,1738745057998963300 +0,7,0,2,1,13407,4,0,0,15555,5,0,81064,82966,95.1,656,1738745058074980000 +0,7,0,2,0,5790,7,0,1,5645,6,0,55461,57268,90.35,657,1738745058152993000 +0,7,0,2,0,2526,0,0,0,2131,1,0,29856,31982,106.3,658,1738745058230986500 +0,7,0,2,1,794,3,0,1,699,6,0,4253,6507,112.7,659,1738745058307125300 +0,7,0,2,1,12122,5,0,0,11733,1,0,109721,111822,105.05,660,1738745058385099800 +0,7,0,2,1,15771,5,0,1,15619,2,0,84118,85996,93.9,661,1738745058463120000 +0,7,0,2,1,4827,2,0,0,4950,2,0,58515,60636,106.05,662,1738745058538977200 +0,7,0,2,0,6169,1,0,1,6579,4,0,32910,35095,109.25,663,1738745058616983600 +0,7,0,2,0,601,2,0,1,1738,5,0,7308,9318,100.5,664,1738745058695639600 +0,7,0,2,1,11416,4,0,0,9245,5,0,112775,114870,104.75,665,1738745058770958200 +0,7,0,2,0,16344,6,0,1,15956,2,0,87172,89283,105.55,666,1738745058848960700 +0,7,0,2,1,4376,0,0,1,4535,7,0,61568,63189,81.05,667,1738745058926961200 +0,7,0,2,1,6472,3,0,1,7155,3,0,35965,38162,109.85,668,1738745059004953200 +0,7,0,2,0,1928,5,0,0,1330,4,0,10361,12568,110.35,669,1738745059080948400 +0,7,0,2,0,9417,7,0,0,9577,5,0,115829,118153,116.2,670,1738745059159063700 +0,7,0,2,0,14857,2,0,1,15241,5,0,90227,92278,102.55,671,1738745059237034300 +0,7,0,2,1,4171,1,0,1,12528,5,0,64622,66822,110.0,672,1738745059312938300 +0,7,0,2,1,6795,2,0,1,6668,4,0,39020,40888,93.4,673,1738745059390937800 +0,7,0,2,0,1482,5,0,1,1225,7,0,13414,15242,91.4,674,1738745059468941100 +0,7,0,2,0,9994,7,0,0,10140,0,0,118885,120640,87.75,675,1738745059544935000 +0,7,0,2,1,15182,0,0,0,14671,7,0,93279,95146,93.35,676,1738745059622939400 +0,7,0,2,1,12686,3,0,1,13080,0,0,67677,69760,104.15,677,1738745059700934900 +0,7,0,2,0,7886,5,0,0,8010,0,0,42073,44128,102.75,678,1738745059776965600 +0,7,0,2,1,3087,7,0,0,3464,1,0,16469,18558,104.45,679,1738745059854950500 +0,7,0,2,1,9807,2,0,1,8914,0,0,121939,124128,109.45,680,1738745059932935100 +0,7,0,2,1,14477,3,0,0,10291,1,0,96333,98577,112.2,681,1738745060008913500 +0,7,0,2,1,13261,6,0,0,12892,5,0,70731,72889,107.9,682,1738745060086913600 +0,7,0,2,0,7436,5,0,1,7308,2,0,45126,47171,102.25,683,1738745060164908300 +0,7,0,2,0,3404,7,0,0,3955,3,0,19525,21229,85.2,684,1738745060240927500 +0,7,0,2,1,9100,0,0,1,8975,1,0,124992,126894,95.1,685,1738745060318909600 +0,7,0,2,0,10436,3,0,1,10694,4,0,99389,101336,97.35,686,1738745060397052900 +0,7,0,2,1,13828,4,0,0,14230,5,0,73784,75993,110.45,687,1738745060472945600 +0,7,0,2,0,7237,7,0,1,5332,6,0,48181,50372,109.55,688,1738745060550908500 +0,7,0,2,0,3717,0,0,1,2576,1,0,22576,24830,112.7,689,1738745060628914700 +0,7,0,2,1,8647,1,0,0,8265,3,0,128046,130162,105.8,690,1738745060706917100 +0,7,0,2,1,11015,2,0,1,11154,2,0,102444,104220,88.8,691,1738745060782914300 +0,7,0,2,1,14150,5,0,0,13781,3,0,76838,79053,110.75,692,1738745060860904200 +0,7,0,2,1,5510,6,0,1,5902,4,0,51236,53336,105.0,693,1738745060938910300 +0,7,0,2,0,2754,0,0,0,2903,2,0,25631,27859,111.4,694,1738745061015011900 +0,7,0,2,1,2,3,0,1,184,7,0,29,1669,82.0,695,1738745061092968500 +0,7,0,2,1,10819,4,0,1,12004,5,0,105495,107974,123.95,696,1738745061170883000 +0,7,0,2,0,13443,7,0,0,13342,1,0,79893,81758,93.25,697,1738745061246895800 +0,7,0,2,1,6083,1,0,1,5842,3,0,54289,56093,90.2,698,1738745061324910000 +0,7,0,2,1,2305,3,0,0,2207,0,0,28685,30895,110.5,699,1738745061402915800 +0,7,0,2,0,321,2,0,0,849,6,0,3084,4875,89.55,700,1738745061478908200 +0,7,0,2,1,12160,7,0,0,12040,2,0,108549,110467,95.9,701,1738745061557056000 +0,7,0,2,1,15552,2,0,1,15839,5,0,82947,84822,93.75,702,1738745061634901700 +0,7,0,2,1,5632,1,0,0,5007,3,0,57342,59474,106.6,703,1738745061710930000 +0,7,0,2,0,2240,2,0,0,6238,4,0,31740,33624,94.2,704,1738745061788866800 +0,7,0,2,1,897,4,0,1,1560,7,0,6135,8325,109.5,705,1738745061866888500 +0,7,0,2,0,11585,7,0,1,11473,4,0,111605,113416,90.55,706,1738745061942890700 +0,7,0,2,1,15617,0,0,1,16304,2,0,86000,87804,90.2,707,1738745062020858300 +0,7,0,2,0,5059,3,0,1,4547,7,0,60397,62485,104.4,708,1738745062098864300 +0,7,0,2,1,6275,5,0,0,6932,4,0,34793,37063,113.5,709,1738745062176863700 +0,7,0,2,1,1602,7,0,0,1870,4,0,9189,11352,108.15,710,1738745062252879200 +0,7,0,2,1,11266,2,0,0,9348,2,0,114659,116675,100.8,711,1738745062330858700 +0,7,0,2,1,16070,1,0,0,14941,2,0,89054,90956,95.1,712,1738745062408880700 +0,7,0,2,1,4486,2,0,0,12293,0,0,63452,65584,106.6,713,1738745062484857400 +0,7,0,2,0,6983,4,0,1,6870,1,0,37847,39713,93.3,714,1738745062562860100 +0,7,0,2,0,1799,6,0,0,1165,2,0,12244,14412,108.4,715,1738745062640864300 +0,7,0,2,1,9671,0,0,0,10201,7,0,117712,119946,111.7,716,1738745062717881300 +0,7,0,2,1,14981,3,0,1,14596,4,0,92109,94264,107.75,717,1738745062794838100 +0,7,0,2,0,12357,4,0,1,12633,3,0,66504,68749,112.25,718,1738745062872840600 +0,7,0,2,1,6660,7,0,1,8068,1,0,40901,43070,108.45,719,1738745062948848400 +0,7,0,2,0,1220,2,0,0,3150,4,0,15299,17319,101.0,720,1738745063026850600 +0,7,0,2,1,10124,3,0,1,8752,5,0,120765,123142,118.85,721,1738745063104851600 +0,7,0,2,1,14668,2,0,1,14543,5,0,95164,97193,101.45,722,1738745063180958800 +0,7,0,2,0,12557,5,0,1,12936,2,0,69558,71804,112.3,723,1738745063258835900 +0,7,0,2,1,8141,6,0,0,7622,2,0,43956,46115,107.95,724,1738745063336848700 +0,7,0,2,0,3215,0,0,1,3847,4,0,18351,20520,108.45,725,1738745063412838200 +0,7,0,2,0,8783,3,0,0,9160,0,0,123821,125824,100.15,726,1738745063490835600 +0,7,0,2,1,14351,4,0,1,10653,2,0,98216,100531,115.75,727,1738745063568836200 +0,7,0,2,1,13006,7,0,1,14020,5,0,72613,74809,109.8,728,1738745063646841800 +0,7,0,2,0,7566,1,0,1,5131,4,0,47009,49256,112.35,729,1738745063722828500 +0,7,0,2,0,3914,3,0,1,3674,1,0,21405,23710,115.25,730,1738745063800813700 +0,7,0,2,1,8970,6,0,1,8589,7,0,126875,128949,103.7,731,1738745063878807200 +0,7,0,2,1,10699,5,0,1,11123,5,0,101270,103145,93.75,732,1738745063954819900 +0,7,0,2,1,13963,6,0,1,14104,0,0,75668,77695,101.35,733,1738745064032807300 +0,7,0,2,1,5193,1,0,0,5455,0,0,50062,52304,112.1,734,1738745064110813000 +0,7,0,2,0,3593,3,0,0,2737,3,0,24461,26354,94.65,735,1738745064186811300 +0,7,0,2,1,8392,4,0,1,204,1,0,129927,132161,111.7,736,1738745064264817900 +0,7,0,2,1,11144,7,0,1,10769,3,0,104325,106253,96.4,737,1738745064342811100 +0,7,0,2,0,13640,0,0,1,13521,6,0,78720,80651,96.55,738,1738745064418811900 +0,7,0,2,0,5400,3,0,1,6025,6,0,53117,55179,103.1,739,1738745064496813800 +0,7,0,2,0,3032,6,0,1,2383,5,0,27515,29609,104.7,740,1738745064574806100 +0,7,0,2,1,153,7,0,0,261,5,0,1909,4041,106.6,741,1738745064650789200 +0,7,0,2,0,11865,3,0,1,12158,6,0,107378,109915,126.85,742,1738745064728787900 +0,7,0,2,1,13339,1,0,1,15511,4,0,81774,83752,98.9,743,1738745064806797700 +0,7,0,2,0,5851,2,0,0,4701,2,0,56172,58188,100.8,744,1738745064882830000 +0,7,0,2,0,2458,4,0,1,6155,2,0,30567,32876,115.45,745,1738745064960790900 +0,7,0,2,0,858,7,0,1,590,5,0,4965,7257,114.6,746,1738745065038798900 +0,7,0,2,0,12058,0,0,0,11757,7,0,110432,112053,81.05,747,1738745065116821700 +0,7,0,2,1,15838,1,0,1,16173,4,0,84830,86455,81.25,748,1738745065192951800 +0,7,0,2,1,4766,5,0,0,4927,4,0,59225,61096,93.55,749,1738745065270782500 +0,7,0,2,1,6239,5,0,1,6489,7,0,33622,35978,117.8,750,1738745065348806700 +0,7,0,2,1,543,2,0,0,1712,7,0,8019,9978,97.95,751,1738745065424787900 +0,7,0,2,1,11485,1,0,1,9281,2,0,113486,115699,110.65,752,1738745065502786100 +0,7,0,2,1,16285,2,0,1,15898,5,0,87884,89958,103.7,753,1738745065580913300 +0,7,0,2,0,4444,5,0,0,4308,1,0,62278,64318,102.0,754,1738745065656890100 +0,7,0,2,1,6428,6,0,0,6814,0,0,36676,39072,119.8,755,1738745065734773600 +0,7,0,2,0,2004,0,0,0,1475,1,0,11071,13329,112.9,756,1738745065812778900 +0,7,0,2,0,9364,3,0,1,9482,2,0,116541,118684,107.15,757,1738745065888763800 +0,7,0,2,1,14932,5,0,0,15332,2,0,90937,92732,89.75,758,1738745065966759300 +0,7,0,2,0,4117,7,0,1,12675,4,0,65333,67607,113.7,759,1738745066044759700 +0,7,0,2,1,6869,2,0,1,7746,2,0,39731,41955,111.2,760,1738745066120769500 +0,7,0,2,1,1431,3,0,0,1035,0,0,14125,16272,107.35,761,1738745066198762400 +0,7,0,2,0,10071,2,0,0,9963,7,0,119596,121450,92.7,762,1738745066276776700 +0,7,0,2,0,15126,5,0,1,14485,3,0,93990,96461,123.55,763,1738745066352772700 +0,7,0,2,0,12758,6,0,0,13093,4,0,68388,70088,85.0,764,1738745066430761500 +0,7,0,2,1,7826,0,0,0,7948,5,0,42783,44985,110.1,765,1738745066508762500 +0,7,0,2,0,3154,2,0,1,3419,0,0,17180,19600,121.0,766,1738745066584898800 +0,7,0,2,1,9746,4,0,0,9092,7,0,122648,124986,116.9,767,1738745066662845600 +0,7,0,2,0,14547,7,0,0,10439,0,0,97045,99375,116.5,768,1738745066740734600 +0,7,0,2,1,13203,1,0,1,12808,7,0,71441,73605,108.2,769,1738745066818772000 +0,7,0,2,1,7505,1,0,1,7416,4,0,45838,47751,95.65,770,1738745066894746200 +0,7,0,2,1,3345,2,0,1,4079,5,0,20236,21929,84.65,771,1738745066972748000 +0,7,0,2,0,9168,5,0,1,8567,7,0,125702,127701,99.95,772,1738745067050745600 +0,7,0,2,1,10384,6,0,0,11032,0,0,100100,102528,121.4,773,1738745067126753100 +0,7,0,2,0,13936,0,0,1,14325,1,0,74495,76494,99.95,774,1738745067204862200 +0,7,0,2,0,7216,2,0,1,5255,5,0,48892,51158,113.3,775,1738745067282732900 From 7cc044e5c49c05f28ecaef4140b8528c0bc9fd19 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 5 Feb 2025 10:27:14 +0100 Subject: [PATCH 25/51] Avoiding native size in the format specifiers for the hit additional data. --- core/fmt.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index cfdee9b..a0e1ea0 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -251,9 +251,9 @@ class AstroPix4Hit(AstroPixHitBase): """ READ_SIZE = 8 - _TRIGGER_ID_FMT = 'L' + _TRIGGER_ID_FMT = ' None: + def __init__(self, data: bytearray, trigger_id: int = None, timestamp: int = None) -> None: """Constructor. """ super().__init__(data) @@ -357,8 +357,8 @@ class AstroPixReadout: trigger_id : int (optional) A sequential id for the readout that can be propagated to child hits. - timestamp : float (optional) - A timestamp (s since the epoch) assigned by the hist machine. + timestamp : int (optional) + A timestamp (ns since the epoch, from time.time_ns()) assigned by the host machine. """ PADDING_BYTE = bytes.fromhex('ff') @@ -369,7 +369,7 @@ class AstroPixReadout: HIT_TRAILER_LENGTH = len(HIT_TRAILER) HIT_LENGTH = HIT_HEADER_LENGTH + HIT_DATA_SIZE + HIT_TRAILER_LENGTH - def __init__(self, data: bytearray, trigger_id: int = None, timestamp: float = None) -> None: + def __init__(self, data: bytearray, trigger_id: int = None, timestamp: int = None) -> None: """Constructor. """ # Strip all the trailing padding bytes from the input bytearray object. @@ -428,7 +428,7 @@ def __str__(self) -> str: """String formatting. """ return f'{self.__class__.__name__}({self.num_hits()} hits, {len(self)} bytes, ' \ - f'trigger_id = {self.trigger_id}, timestamp = {self.timestamp} s)' + f'trigger_id = {self.trigger_id}, timestamp = {self.timestamp} ns)' class FileHeader: From 4694b1dd9c5ff5e6218fbeac52ee7415af359ffe Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 5 Feb 2025 10:42:09 +0100 Subject: [PATCH 26/51] Cleanup --- apx4_read.py | 16 -------------- core/fmt.py | 55 +++++++++++++++++++++++++++++++++++++++++------ tests/test_fmt.py | 18 ++++++++++++++-- 3 files changed, 65 insertions(+), 24 deletions(-) diff --git a/apx4_read.py b/apx4_read.py index ac6ba8e..e1e3261 100644 --- a/apx4_read.py +++ b/apx4_read.py @@ -62,22 +62,6 @@ def setup_logger(level: str, file_path: str = None): return logger -def playback_file(file_path: str, num_hits: int = 10) -> None: - """Small test code to playback a file. - - Move this to the unit tests! - """ - with AstroPixBinaryFile(AstroPix4Hit).open(file_path) as input_file: - print(f'\nStarting playback of binary file {file_path}...') - print(f'File header: {input_file.header}') - for i, hit in enumerate(input_file): - if i < num_hits: - print(hit) - elif i == num_hits: - print('...') - print(f'{i + 1} hits found') - - def main(args): """Configure and run an AstroPix 4 chip. """ diff --git a/core/fmt.py b/core/fmt.py index a0e1ea0..555f125 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -79,6 +79,17 @@ class AstroPixHitBase: fields are arbitrary subsets of a multi-byte word, it seemed more naturale to describe the hit as a sequence of fields, each one with its own length in bits. + .. warning:: + + In order to support the addition of a sequential trigger identitier and + a timestamp (both assigned by the DAQ host machine) in the AstroPix4 setup, + we make an explicit distinction between the size of the hit as enclosed in + a readout from the NEXYS board (``READ_SIZE``), and that of a hit that + gets written in an output binary file (``WRITE_SIZE``). Subclasses are + reponsible for setting sensible values for the ``READ_SIZE`` and ``WRITE_SIZE``, + as well as for overloading the ``write()`` and ``from_file_data()`` methods + to handle the additional fields that need to be written and/or read. + Arguments --------- data : bytearray @@ -107,6 +118,10 @@ def __init__(self, data: bytearray) -> None: def write(self, output_file: typing.BinaryIO) -> None: """Write the binary data to a file. + Subclasses can overload this method when it is necessary to add more stuff + (e.g., a trigger identifier, or a timestamp) to the binary blob coming + from the NEXYS board. + Arguments --------- output_file : BinaryIO @@ -114,6 +129,22 @@ def write(self, output_file: typing.BinaryIO) -> None: """ output_file.write(self._data) + @classmethod + def from_file_data(cls, data: bytes) -> 'AstroPixHitBase': + """Read a hit from an input binary file. + + By default this is basically calling the class constructor, but when + ``READ_SIZE`` and ``WRITE_SIZE`` are different because ``write()`` is doing + something non-trivial, then this method should be overloaded to do something + sensible with the additional bytes. + + Arguments + --------- + data : bytes + The block of binary data (of size ``cls.WRITE_SIZE``) from the binary file. + """ + return cls(data) + def __eq__(self, other: 'AstroPixHitBase') -> bool: """Comparison operator---this is handy in the unit tests. """ @@ -280,8 +311,8 @@ def __init__(self, data: bytearray, trigger_id: int = None, timestamp: int = Non """ super().__init__(data) # Calculate the values of the two timestamps in clock cycles. - self.ts_dec1 = self._compose_timestamp(self.ts_coarse1, self.ts_fine1) - self.ts_dec2 = self._compose_timestamp(self.ts_coarse2, self.ts_fine2) + self.ts_dec1 = self._compose_ts(self.ts_coarse1, self.ts_fine1) + self.ts_dec2 = self._compose_ts(self.ts_coarse2, self.ts_fine2) # Take into account possible rollovers. if self.ts_dec2 < self.ts_dec1: self.ts_dec2 += self.CLOCK_ROLLOVER @@ -291,7 +322,7 @@ def __init__(self, data: bytearray, trigger_id: int = None, timestamp: int = Non self.timestamp = timestamp @staticmethod - def _compose_timestamp(ts_coarse: int, ts_fine: int) -> int: + def _compose_ts(ts_coarse: int, ts_fine: int) -> int: """Compose the actual decimal representation of the timestamp counter, putting together the coarse and fine counters (in Gray code). @@ -311,7 +342,11 @@ def _compose_timestamp(ts_coarse: int, ts_fine: int) -> int: return AstroPixHitBase.gray_to_decimal((ts_coarse << 3) + ts_fine) def write(self, output_file: typing.BinaryIO) -> None: - """Overloaded method, since we want to write additional fields. + """Overloaded method. + + This is the place where, in addition to the 8 bytes of binary data from the + NEXYS board, we do write the trigger identifier and the timestamp assigned + by the DAQ host machine. Arguments --------- @@ -323,8 +358,16 @@ def write(self, output_file: typing.BinaryIO) -> None: output_file.write(struct.pack(self._TIMESTAMP_FMT, self.timestamp)) @classmethod - def from_file_data(cls, data) -> 'AstroPix4Hit': - """Read a hit from an input binary file. + def from_file_data(cls, data: bytes) -> 'AstroPix4Hit': + """Overloaded method. + + This is where we unpack the trigger identifier and the timestamp assigned + by the DAQ host machine before we initialize the hit object. + + Arguments + --------- + data : bytes + The block of binary data from the binary file. """ pos = cls.READ_SIZE trigger_id = struct.unpack(cls._TRIGGER_ID_FMT, data[pos:pos + cls._TRIGGER_ID_SIZE]) diff --git a/tests/test_fmt.py b/tests/test_fmt.py index 593bd0c..f409cfa 100644 --- a/tests/test_fmt.py +++ b/tests/test_fmt.py @@ -117,7 +117,7 @@ def test_original_decoding(): def test_new_decoding(): """Test the new decoding stuff. """ - readout = AstroPixReadout(sample_readout_data, timestamp=time.time()) + readout = AstroPixReadout(sample_readout_data, trigger_id=0, timestamp=time.time_ns()) print(readout) assert readout.num_hits() == 2 for hit in readout.hits: @@ -163,7 +163,7 @@ def test_file(): header = FileHeader(dict(version=1, content='hits')) print(header) # Grab our test AstroPix4 hits. - readout = AstroPixReadout(sample_readout_data, timestamp=time.time()) + readout = AstroPixReadout(sample_readout_data, trigger_id=0, timestamp=time.time_ns()) # Write the output file. kwargs = dict(suffix=AstroPixBinaryFile._EXTENSION, delete_on_close=False, delete=True) @@ -184,6 +184,20 @@ def test_file(): assert hit == readout.hits[i] +def test_playback(num_hits: int = 10): + """Test the full playback of a real file. + """ + file_path = os.path.join(os.path.dirname(__file__), 'data', '20250205_094324_data.apx') + with AstroPixBinaryFile(AstroPix4Hit).open(file_path) as input_file: + print(f'\nStarting playback of binary file {file_path}...') + print(f'File header: {input_file.header}') + for i, hit in enumerate(input_file): + if i < num_hits: + print(hit) + elif i == num_hits: + print('...') + print(f'{i + 1} hits found') + @pytest.mark.skip def test_csv_convert(): """Read a sample .apx file and convert it to csv. From 311918c9bdb65e4d2c1d1a985f23926c82bd33eb Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 5 Feb 2025 10:46:45 +0100 Subject: [PATCH 27/51] Added unit test. --- tests/test_fmt.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/test_fmt.py b/tests/test_fmt.py index f409cfa..c622b90 100644 --- a/tests/test_fmt.py +++ b/tests/test_fmt.py @@ -198,10 +198,14 @@ def test_playback(num_hits: int = 10): print('...') print(f'{i + 1} hits found') -@pytest.mark.skip + def test_csv_convert(): """Read a sample .apx file and convert it to csv. """ - file_path = os.path.join(os.path.dirname(__file__), 'data', '20250204_144725_data.apx') - file_path = apxdf_to_csv(file_path, AstroPix4Hit) - assert isinstance(file_path, str) + file_path = os.path.join(os.path.dirname(__file__), 'data', '20250205_094324_data.apx') + kwargs = dict(suffix='.csv', delete_on_close=False, delete=True) + with tempfile.NamedTemporaryFile('w', **kwargs) as output_file: + output_file.close() + print(f'Converting {file_path} to {output_file.name}...') + out = apxdf_to_csv(file_path, AstroPix4Hit, output_file_path=output_file.name) + assert out == output_file.name From 491b4e738ef61ac1c189324d07dc5d1cd76a80eb Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 5 Feb 2025 10:55:39 +0100 Subject: [PATCH 28/51] Unit test added. --- tests/test_fmt.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/test_fmt.py b/tests/test_fmt.py index c622b90..3d4ac34 100644 --- a/tests/test_fmt.py +++ b/tests/test_fmt.py @@ -22,7 +22,8 @@ import tempfile import time -import pytest +import matplotlib.pyplot as plt +import numpy as np from core.decode import Decode from core.fmt import BitPattern, AstroPix4Hit, AstroPixReadout, FileHeader, \ @@ -199,6 +200,24 @@ def test_playback(num_hits: int = 10): print(f'{i + 1} hits found') +def test_plot_file(): + """Basic test plotting the content of the sample binary file. + """ + file_path = os.path.join(os.path.dirname(__file__), 'data', '20250205_094324_data.csv') + chip_id, payload, row, column, ts_neg1, ts_coarse1, ts_fine1, ts_tdc1, ts_neg2, \ + ts_coarse2, ts_fine2, ts_tdc2, ts_dec1, ts_dec2, tot_us, trigger_id, timestamp = \ + np.loadtxt(file_path, delimiter=',', unpack=True) + dt = np.diff(timestamp) / 1.e6 + + plt.figure('TOT') + plt.hist(tot_us, bins=25) + plt.xlabel('TOT [$\\mu$s]') + + plt.figure('Time differences') + plt.hist(dt, bins=25) + plt.xlabel('$\\Delta$T [ms]') + + def test_csv_convert(): """Read a sample .apx file and convert it to csv. """ @@ -209,3 +228,8 @@ def test_csv_convert(): print(f'Converting {file_path} to {output_file.name}...') out = apxdf_to_csv(file_path, AstroPix4Hit, output_file_path=output_file.name) assert out == output_file.name + + +if __name__ == '__main__': + test_plot_file() + plt.show() \ No newline at end of file From 660c383116662afdc5705183004cbadb30f916a2 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Mon, 10 Feb 2025 10:49:22 +0100 Subject: [PATCH 29/51] write() method implemented for the AstroPixReadout class. --- core/fmt.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/core/fmt.py b/core/fmt.py index 555f125..5c13120 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -411,6 +411,14 @@ class AstroPixReadout: HIT_HEADER_LENGTH = len(HIT_HEADER) HIT_TRAILER_LENGTH = len(HIT_TRAILER) HIT_LENGTH = HIT_HEADER_LENGTH + HIT_DATA_SIZE + HIT_TRAILER_LENGTH + READOUT_HEADER = bytes.fromhex('fedcba') + _READOUT_LENGTH_FMT = ' None: """Constructor. @@ -457,6 +465,23 @@ def __decode(self, reverse: bool = True) -> list[AstroPix4Hit]: pos += self.HIT_LENGTH return hits + def write(self, output_file: typing.BinaryIO) -> None: + """Write the complete readout to a binary file. + + Arguments + --------- + output_file : BinaryIO + A file object opened in "wb" mode. + """ + output_file.write(self.READOUT_HEADER) + # This is the number of bytes in the readout, not including the header. + num_bytes = len(data) + self._READOUT_LENGTH_SIZE + self._TRIGGER_ID_SIZE + \ + self._TIMESTAMP_SIZE + output_file.write(struct.pack(self._READOUT_LENGTH_FMT, num_bytes)) + output_file.write(self._data) + output_file.write(struct.pack(self._TRIGGER_ID_FMT, self.trigger_id)) + output_file.write(struct.pack(self._TIMESTAMP_FMT, self.timestamp)) + def num_hits(self) -> int: """Return the number of hits in the readout. """ From be3e6afaa13e41900dc6ddb8b0cf2eb985ef34ee Mon Sep 17 00:00:00 2001 From: Luca BALDINI Date: Fri, 28 Feb 2025 10:53:33 +0100 Subject: [PATCH 30/51] Minor. --- apx4_read.py | 9 +++------ core/fmt.py | 15 +++++---------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/apx4_read.py b/apx4_read.py index e1e3261..9f1a032 100644 --- a/apx4_read.py +++ b/apx4_read.py @@ -159,10 +159,7 @@ def main(args): readout = AstroPixReadout(readout_data, num_readouts, time.time_ns()) if _show: print(f'{num_readouts} readouts acquired, last is {readout}.') - for i, hit in enumerate(readout.hits): - if _show: - print(f'Hit {i} -> {hit}') - hit.write(output_file) + readout.write(output_file) # Ends program cleanly when a keyboard interupt is sent. except KeyboardInterrupt: @@ -178,8 +175,8 @@ def main(args): astro.close_connection() logger.info("Program terminated successfully!") - if args.saveascsv: - file_path = apxdf_to_csv(data_file_path, AstroPix4Hit) + #if args.saveascsv: + # file_path = apxdf_to_csv(data_file_path, AstroPix4Hit) if __name__ == "__main__": diff --git a/core/fmt.py b/core/fmt.py index 5c13120..8ffe578 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -426,11 +426,11 @@ def __init__(self, data: bytearray, trigger_id: int = None, timestamp: int = Non # Strip all the trailing padding bytes from the input bytearray object. self._data = data.rstrip(self.PADDING_BYTE) # Check that the length of the readout is a multiple of the frame length. - if not len(self) % self.HIT_LENGTH == 0: - raise RuntimeError(f'Readout length ({len(self)}) not a multiple of {self.HIT_LENGTH}') + #if not len(self) % self.HIT_LENGTH == 0: + # raise RuntimeError(f'Readout length ({len(self)}) not a multiple of {self.HIT_LENGTH}') self.trigger_id = trigger_id self.timestamp = timestamp - self.hits = self.__decode() + #self.hits = self.__decode() def __decode(self, reverse: bool = True) -> list[AstroPix4Hit]: """Decode the underlying data and turn them into a list of hits. @@ -475,18 +475,13 @@ def write(self, output_file: typing.BinaryIO) -> None: """ output_file.write(self.READOUT_HEADER) # This is the number of bytes in the readout, not including the header. - num_bytes = len(data) + self._READOUT_LENGTH_SIZE + self._TRIGGER_ID_SIZE + \ + num_bytes = len(self._data) + self._READOUT_LENGTH_SIZE + self._TRIGGER_ID_SIZE + \ self._TIMESTAMP_SIZE output_file.write(struct.pack(self._READOUT_LENGTH_FMT, num_bytes)) output_file.write(self._data) output_file.write(struct.pack(self._TRIGGER_ID_FMT, self.trigger_id)) output_file.write(struct.pack(self._TIMESTAMP_FMT, self.timestamp)) - def num_hits(self) -> int: - """Return the number of hits in the readout. - """ - return len(self) // self.HIT_LENGTH - def __len__(self) -> int: """Return the length of the underlying data in bytes. """ @@ -495,7 +490,7 @@ def __len__(self) -> int: def __str__(self) -> str: """String formatting. """ - return f'{self.__class__.__name__}({self.num_hits()} hits, {len(self)} bytes, ' \ + return f'{self.__class__.__name__}({len(self)} bytes, ' \ f'trigger_id = {self.trigger_id}, timestamp = {self.timestamp} ns)' From 938cd954fb866c14a7b221e869acc7664e00b67e Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Tue, 6 May 2025 14:42:55 +0200 Subject: [PATCH 31/51] Minor. --- apx4_read.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apx4_read.py b/apx4_read.py index e1e3261..4153642 100644 --- a/apx4_read.py +++ b/apx4_read.py @@ -30,7 +30,7 @@ def setup_logger(level: str, file_path: str = None): .. warning:: This should probably be factored out in a module that all the scripts - ca use, rather than coding the same thing over and over again. + can use, rather than coding the same thing over and over again. Arguments --------- From 0f61531db06c967596e88a2c37e1e628b311d742 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Tue, 6 May 2025 14:43:45 +0200 Subject: [PATCH 32/51] loguru used. --- core/fmt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/fmt.py b/core/fmt.py index 555f125..15468a7 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -24,7 +24,7 @@ import struct import typing -from modules.setup_logger import logger +from loguru import logger # Table to reverse the bit order within a byte---we pre-compute this once and From 3e348f6c98227b2f49bde9f78a433bf99196c084 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Tue, 6 May 2025 14:44:04 +0200 Subject: [PATCH 33/51] Initial import. --- apx4_convert.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 apx4_convert.py diff --git a/apx4_convert.py b/apx4_convert.py new file mode 100644 index 0000000..efabfb5 --- /dev/null +++ b/apx4_convert.py @@ -0,0 +1,29 @@ +# Copyright (C) 2025 the astropix team. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +import argparse + +from loguru import logger + +from core.fmt import AstroPix4Hit, apxdf_to_csv + + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Astropix 4 file converter') + parser.add_argument('infile', type=str, help='path to the input file') + args = parser.parse_args() + apxdf_to_csv(args.infile, AstroPix4Hit) \ No newline at end of file From 35ec1c3f1b9eed4aff62df8d62e915ae25db667d Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Tue, 6 May 2025 15:36:40 +0200 Subject: [PATCH 34/51] Minor. --- core/fmt.py | 115 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 70 insertions(+), 45 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index c56f86e..3cdda4e 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -397,40 +397,86 @@ class AstroPixReadout: data : bytearray A full readout from a NEXYS board. - trigger_id : int (optional) + trigger_id : int A sequential id for the readout that can be propagated to child hits. - timestamp : int (optional) + timestamp : int A timestamp (ns since the epoch, from time.time_ns()) assigned by the host machine. """ - PADDING_BYTE = bytes.fromhex('ff') - HIT_HEADER = bytes.fromhex('bcbc') - HIT_TRAILER = bytes.fromhex('bcbcbcbcbcbc') - HIT_DATA_SIZE = AstroPix4Hit.READ_SIZE - HIT_HEADER_LENGTH = len(HIT_HEADER) - HIT_TRAILER_LENGTH = len(HIT_TRAILER) - HIT_LENGTH = HIT_HEADER_LENGTH + HIT_DATA_SIZE + HIT_TRAILER_LENGTH - READOUT_HEADER = bytes.fromhex('fedcba') - _READOUT_LENGTH_FMT = ' None: + def __init__(self, data: bytearray, trigger_id: int, timestamp: int) -> None: """Constructor. """ # Strip all the trailing padding bytes from the input bytearray object. self._data = data.rstrip(self.PADDING_BYTE) - # Check that the length of the readout is a multiple of the frame length. - #if not len(self) % self.HIT_LENGTH == 0: - # raise RuntimeError(f'Readout length ({len(self)}) not a multiple of {self.HIT_LENGTH}') + # Set the trigger_id and timestamp class members. (Note these are not part + # of the readout, but they are set by the host machine.) self.trigger_id = trigger_id self.timestamp = timestamp - #self.hits = self.__decode() + + def _write_size(self) -> int: + """Return the size of the readout in bytes on disk, including the the additional + fields (readout length, trigger_id, and timestamps) assigned by the host + machine, but not the readout header. + + Note that, since the size of the underlying data is not fixed, we need to + calculate this dynamically at runtime. + """ + return self._LENGTH_SIZE + self._TRIGGER_ID_SIZE + self._TIMESTAMP_SIZE + len(self._data) + + def write(self, output_file: typing.BinaryIO) -> None: + """Write the complete readout to a binary file. + + Arguments + --------- + output_file : BinaryIO + A file object opened in "wb" mode. + """ + # Write the (fixed) readout header to the output file. + output_file.write(self.READOUT_HEADER) + # Write the total size on disk, including everything but the header. + output_file.write(struct.pack(self._LENGTH_FMT, self._write_size())) + # Write the actual readout data. + output_file.write(self._data) + # Write the trigger identifier and the timestamp assigned by the host machine. + output_file.write(struct.pack(self._TRIGGER_ID_FMT, self.trigger_id)) + output_file.write(struct.pack(self._TIMESTAMP_FMT, self.timestamp)) + + @classmethod + def from_file(cls, input_file: typing.BinaryIO) -> AstroPixReadout: + """Read a readout from an input binary file. + """ + # Read (and check) the fixed-length readout header. + _header = input_file.read(cls._HEADER_SIZE) + if len(_header) == 0: + return None + if _header != cls._HEADER: + raise RuntimeError(f'Invalid readout header ({_header}), expected {cls._HEADER}') + # Read the amount of data to be read from the file. + _length = struct.unpack(cls._LENGTH_FMT, input_file.read(cls._LENGTH_SIZE))[0] + data = input_file.read(_length - cls._LENGTH_SIZE) + return data def __decode(self, reverse: bool = True) -> list[AstroPix4Hit]: """Decode the underlying data and turn them into a list of hits. @@ -465,28 +511,6 @@ def __decode(self, reverse: bool = True) -> list[AstroPix4Hit]: pos += self.HIT_LENGTH return hits - def write(self, output_file: typing.BinaryIO) -> None: - """Write the complete readout to a binary file. - - Arguments - --------- - output_file : BinaryIO - A file object opened in "wb" mode. - """ - output_file.write(self.READOUT_HEADER) - # This is the number of bytes in the readout, not including the header. - num_bytes = len(self._data) + self._READOUT_LENGTH_SIZE + self._TRIGGER_ID_SIZE + \ - self._TIMESTAMP_SIZE - output_file.write(struct.pack(self._READOUT_LENGTH_FMT, num_bytes)) - output_file.write(self._data) - output_file.write(struct.pack(self._TRIGGER_ID_FMT, self.trigger_id)) - output_file.write(struct.pack(self._TIMESTAMP_FMT, self.timestamp)) - - def __len__(self) -> int: - """Return the length of the underlying data in bytes. - """ - return len(self._data) - def __str__(self) -> str: """String formatting. """ @@ -619,13 +643,13 @@ def __iter__(self) -> 'AstroPixBinaryFile': """ return self - def __next__(self) -> AstroPixHitBase: + def __next__(self) -> AstroPixReadout: """Read the next packet in the buffer. """ - data = self._input_file.read(self._hit_class.WRITE_SIZE) - if not data: + readout = AstroPixReadout.from_file(self._input_file) + if readout is None: raise StopIteration - return self._hit_class.from_file_data(data) + return readout def _convert_apxdf(file_path: str, hit_class: type, converter: typing.Callable, @@ -640,8 +664,9 @@ def _convert_apxdf(file_path: str, hit_class: type, converter: typing.Callable, open(output_file_path, open_mode) as output_file: if header is not None: output_file.write(header) - for i, hit in enumerate(input_file): - output_file.write(converter(hit)) + for i, readout in enumerate(input_file): + print(i, readout) + #output_file.write(converter(readout)) logger.info(f'Done, {i + 1} hit(s) written') return output_file_path From 7e24eee9eced03f81236ef3721d9dfe56be1dfc1 Mon Sep 17 00:00:00 2001 From: Luca BALDINI Date: Tue, 6 May 2025 15:41:28 +0200 Subject: [PATCH 35/51] Minor. --- core/fmt.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index 3cdda4e..dc2351b 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -429,7 +429,7 @@ def __init__(self, data: bytearray, trigger_id: int, timestamp: int) -> None: """Constructor. """ # Strip all the trailing padding bytes from the input bytearray object. - self._data = data.rstrip(self.PADDING_BYTE) + self._data = data.rstrip(self._PADDING_BYTE) # Set the trigger_id and timestamp class members. (Note these are not part # of the readout, but they are set by the host machine.) self.trigger_id = trigger_id @@ -454,7 +454,7 @@ def write(self, output_file: typing.BinaryIO) -> None: A file object opened in "wb" mode. """ # Write the (fixed) readout header to the output file. - output_file.write(self.READOUT_HEADER) + output_file.write(self._HEADER) # Write the total size on disk, including everything but the header. output_file.write(struct.pack(self._LENGTH_FMT, self._write_size())) # Write the actual readout data. @@ -514,7 +514,7 @@ def __decode(self, reverse: bool = True) -> list[AstroPix4Hit]: def __str__(self) -> str: """String formatting. """ - return f'{self.__class__.__name__}({len(self)} bytes, ' \ + return f'{self.__class__.__name__}({len(self._data)} bytes, ' \ f'trigger_id = {self.trigger_id}, timestamp = {self.timestamp} ns)' From 09bead388c20731a6b1b5ec997fb30ddf28d0cf0 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 7 May 2025 08:42:32 +0200 Subject: [PATCH 36/51] Refactoring. --- core/fmt.py | 100 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 42 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index dc2351b..6e5c4d6 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -19,6 +19,7 @@ from __future__ import annotations +from abc import ABC, abstractmethod from contextlib import contextmanager import json import struct @@ -377,12 +378,16 @@ def from_file_data(cls, data: bytes) -> 'AstroPix4Hit': return cls(data, trigger_id, timestamp) -class AstroPixReadout: +class AbstractAstroPixReadout(ABC): - """Class describing an AstroPix readout, i.e., a full readout from the NEXYS board. + """Abstract base class for a generic AstroPix readout. - This comes in the form of a fixed-length bytearray object that is padded at the - end with a fixed byte (0xff). + This is basically a wrapper around the bytearray object that is returned by + the NEXYS board, and it provides some basic functionality to write the readout + to a binary file. + + A full readout comes in the form of a fixed-length bytearray object that is + padded at the end with a fixed byte (0xff). What remains when the padding bytes have been removed should be a sequence of frames of the form @@ -394,14 +399,15 @@ class AstroPixReadout: Arguments --------- - data : bytearray - A full readout from a NEXYS board. - trigger_id : int - A sequential id for the readout that can be propagated to child hits. + A sequential id for the readout, assigned by the host DAQ machine. timestamp : int - A timestamp (ns since the epoch, from time.time_ns()) assigned by the host machine. + A timestamp for the readout, assigned by the host DAQ machine, in ns since + the epoch, from time.time_ns(). + + data : bytearray + The readout data from the NEXYS board. """ # The padding byte used to pad the readout. @@ -410,41 +416,24 @@ class AstroPixReadout: # before the thing gets written to disk. _HEADER = bytes.fromhex('fedcba') _HEADER_SIZE = len(_HEADER) - # Basic bookkeeping for all the additional fields. - _LENGTH_FMT = ' None: + def __init__(self, trigger_id: int, timestamp: int, hit_data: bytearray) -> None: """Constructor. """ - # Strip all the trailing padding bytes from the input bytearray object. - self._data = data.rstrip(self._PADDING_BYTE) - # Set the trigger_id and timestamp class members. (Note these are not part - # of the readout, but they are set by the host machine.) self.trigger_id = trigger_id self.timestamp = timestamp + # Strip all the trailing padding bytes from the input bytearray object. + self._hit_data = hit_data.rstrip(self._PADDING_BYTE) - def _write_size(self) -> int: - """Return the size of the readout in bytes on disk, including the the additional - fields (readout length, trigger_id, and timestamps) assigned by the host - machine, but not the readout header. - - Note that, since the size of the underlying data is not fixed, we need to - calculate this dynamically at runtime. - """ - return self._LENGTH_SIZE + self._TRIGGER_ID_SIZE + self._TIMESTAMP_SIZE + len(self._data) - + @abstractmethod def write(self, output_file: typing.BinaryIO) -> None: """Write the complete readout to a binary file. @@ -453,21 +442,48 @@ def write(self, output_file: typing.BinaryIO) -> None: output_file : BinaryIO A file object opened in "wb" mode. """ + + @classmethod + @abstractmethod + def from_file(cls, input_file: typing.BinaryIO) -> AbstractAstroPixReadout: + """Create a Readout object reading the underlying data from an input binary file. + + Arguments + --------- + input_file : BinaryIO + A file object opened in "rb" mode. + """ + + +class AstroPix4Readout(AbstractAstroPixReadout): + + """Class describing an AstroPix 4 readout. + """ + + #HIT_HEADER = bytes.fromhex('bcbc') + #HIT_TRAILER = bytes.fromhex('bcbcbcbcbcbc') + #HIT_DATA_SIZE = AstroPix4Hit.READ_SIZE + #HIT_HEADER_LENGTH = len(HIT_HEADER) + #HIT_TRAILER_LENGTH = len(HIT_TRAILER) + #HIT_LENGTH = HIT_HEADER_LENGTH + HIT_DATA_SIZE + HIT_TRAILER_LENGTH + + def write(self, output_file: typing.BinaryIO) -> None: + """ + """ # Write the (fixed) readout header to the output file. output_file.write(self._HEADER) - # Write the total size on disk, including everything but the header. - output_file.write(struct.pack(self._LENGTH_FMT, self._write_size())) - # Write the actual readout data. - output_file.write(self._data) - # Write the trigger identifier and the timestamp assigned by the host machine. + # Write the trigger id and the timestamp assigned by the host machine. output_file.write(struct.pack(self._TRIGGER_ID_FMT, self.trigger_id)) output_file.write(struct.pack(self._TIMESTAMP_FMT, self.timestamp)) + # Write the size on disk, in bytes, for the variable-size part of the event. + output_file.write(struct.pack(self._LENGTH_FMT, len(self._hit_data))) + # Write the actual readout data. + output_file.write(self._hit_data) @classmethod - def from_file(cls, input_file: typing.BinaryIO) -> AstroPixReadout: - """Read a readout from an input binary file. + def from_file(cls, input_file: typing.BinaryIO) -> AstroPix4Readout: + """ """ - # Read (and check) the fixed-length readout header. _header = input_file.read(cls._HEADER_SIZE) if len(_header) == 0: return None From a56eacc39c446acf1a50c2ebc6858fcb704d5f01 Mon Sep 17 00:00:00 2001 From: Luca BALDINI Date: Wed, 7 May 2025 08:57:16 +0200 Subject: [PATCH 37/51] Minor. --- apx4_read.py | 4 ++-- core/fmt.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apx4_read.py b/apx4_read.py index 6fde958..3fef540 100644 --- a/apx4_read.py +++ b/apx4_read.py @@ -20,7 +20,7 @@ import logging import argparse -from core.fmt import AstroPixReadout, FileHeader, AstroPixBinaryFile, AstroPix4Hit, apxdf_to_csv +from core.fmt import AstroPix4Readout, FileHeader, AstroPixBinaryFile, AstroPix4Hit, apxdf_to_csv @@ -156,7 +156,7 @@ def main(args): if readout_data: num_readouts += 1 _show = num_readouts % args.prescale == 0 - readout = AstroPixReadout(readout_data, num_readouts, time.time_ns()) + readout = AstroPix4Readout(num_readouts, time.time_ns(), readout_data) if _show: print(f'{num_readouts} readouts acquired, last is {readout}.') readout.write(output_file) diff --git a/core/fmt.py b/core/fmt.py index 6e5c4d6..2bb2fb0 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -530,7 +530,7 @@ def __decode(self, reverse: bool = True) -> list[AstroPix4Hit]: def __str__(self) -> str: """String formatting. """ - return f'{self.__class__.__name__}({len(self._data)} bytes, ' \ + return f'{self.__class__.__name__}({len(self._hit_data)} bytes, ' \ f'trigger_id = {self.trigger_id}, timestamp = {self.timestamp} ns)' From e6288ce8f708b12e12e045b90dc4c5677bee582d Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 7 May 2025 09:46:47 +0200 Subject: [PATCH 38/51] First version of csv converter that roundtrips now that we write readouts (instead of hits) to file. --- core/fmt.py | 109 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 26 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index 2bb2fb0..996dfcc 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -448,53 +448,110 @@ def write(self, output_file: typing.BinaryIO) -> None: def from_file(cls, input_file: typing.BinaryIO) -> AbstractAstroPixReadout: """Create a Readout object reading the underlying data from an input binary file. + By contract this should return None when there are no more data to be + read from the input file, so that downstream code can use the information + to stop iterating over the file. + Arguments --------- input_file : BinaryIO A file object opened in "rb" mode. """ + @staticmethod + def pack_and_write(output_file: typing.BinaryIO, value: typing.Any, fmt) -> None: + """Convenience function to pack and write a fixed-size field to an output file. + + Arguments + --------- + output_file : BinaryIO + A file object opened in "wb" mode. + + value : any + The value to be written. + + fmt : str + The format string for the field to be written. + """ + output_file.write(struct.pack(fmt, value)) + + @staticmethod + def read_and_unpack(input_file: typing.BinaryIO, fmt: str, size: int = None) -> typing.Any: + """Convenience function to read and unpack a fixed-size field from an input file. + + Arguments + --------- + input_file : BinaryIO + A file object opened in "rb" mode. + + fmt : str + The format string for the field to be read. + + size : int, optional + The size of the field to be read. If not provided, it is calculated + from the format string. + """ + if size is None: + size = struct.calcsize(fmt) + return struct.unpack(fmt, input_file.read(size))[0] + class AstroPix4Readout(AbstractAstroPixReadout): """Class describing an AstroPix 4 readout. """ - #HIT_HEADER = bytes.fromhex('bcbc') - #HIT_TRAILER = bytes.fromhex('bcbcbcbcbcbc') - #HIT_DATA_SIZE = AstroPix4Hit.READ_SIZE - #HIT_HEADER_LENGTH = len(HIT_HEADER) - #HIT_TRAILER_LENGTH = len(HIT_TRAILER) - #HIT_LENGTH = HIT_HEADER_LENGTH + HIT_DATA_SIZE + HIT_TRAILER_LENGTH + HIT_HEADER = bytes.fromhex('bcbc') + HIT_TRAILER = bytes.fromhex('bcbcbcbcbcbc') + HIT_DATA_SIZE = AstroPix4Hit.READ_SIZE + HIT_HEADER_LENGTH = len(HIT_HEADER) + HIT_TRAILER_LENGTH = len(HIT_TRAILER) + HIT_LENGTH = HIT_HEADER_LENGTH + HIT_DATA_SIZE + HIT_TRAILER_LENGTH def write(self, output_file: typing.BinaryIO) -> None: + """Implementation of the write() class method. + + We do write to file, in order: + * the readout header magic word; + * the trigger identifier; + * the timestamp; + * the length of the underlying hit data; + * the actual hit data. """ - """ - # Write the (fixed) readout header to the output file. output_file.write(self._HEADER) - # Write the trigger id and the timestamp assigned by the host machine. - output_file.write(struct.pack(self._TRIGGER_ID_FMT, self.trigger_id)) - output_file.write(struct.pack(self._TIMESTAMP_FMT, self.timestamp)) - # Write the size on disk, in bytes, for the variable-size part of the event. - output_file.write(struct.pack(self._LENGTH_FMT, len(self._hit_data))) - # Write the actual readout data. + self.pack_and_write(output_file, self.trigger_id, self._TRIGGER_ID_FMT) + self.pack_and_write(output_file, self.timestamp, self._TIMESTAMP_FMT) + self.pack_and_write(output_file, len(self._hit_data), self._LENGTH_FMT) output_file.write(self._hit_data) @classmethod def from_file(cls, input_file: typing.BinaryIO) -> AstroPix4Readout: - """ + """Implementation of the from_file() class method. + + This is reading all the relevant data from the input file and returns a + fully-fledged AstroPix4Readout object. The function returns None if there + are no more readouts to be read from the input file. Also, note that the + value of the readout header is checked at runtime, and a RuntimeError is + raised if it is not what we expect. """ _header = input_file.read(cls._HEADER_SIZE) + # If the header is empty, this means we are at the end of the file, and we + # return None to signal that there are no more readouts to be read. This + # can be used downstream, e.g., to raise a StopIteration exception with + # the implementation of an iterator protocol. if len(_header) == 0: return None + # If the header is not empty, we check that it is what we expect, and raise + # a RuntimeError if it is not. if _header != cls._HEADER: raise RuntimeError(f'Invalid readout header ({_header}), expected {cls._HEADER}') - # Read the amount of data to be read from the file. - _length = struct.unpack(cls._LENGTH_FMT, input_file.read(cls._LENGTH_SIZE))[0] - data = input_file.read(_length - cls._LENGTH_SIZE) - return data + # Go ahead, read all the fields, and create the AstroPix4Readout object. + trigger_id = cls.read_and_unpack(input_file, cls._TRIGGER_ID_FMT, cls._TRIGGER_ID_SIZE) + timestamp = cls.read_and_unpack(input_file, cls._TIMESTAMP_FMT, cls._TIMESTAMP_SIZE) + data = input_file.read(cls.read_and_unpack(input_file, cls._LENGTH_FMT, cls._LENGTH_SIZE)) + return AstroPix4Readout(trigger_id, timestamp, data) - def __decode(self, reverse: bool = True) -> list[AstroPix4Hit]: + def decode(self, reverse: bool = True) -> list[AstroPix4Hit]: """Decode the underlying data and turn them into a list of hits. Arguments @@ -505,9 +562,9 @@ def __decode(self, reverse: bool = True) -> list[AstroPix4Hit]: hits = [] pos = 0 # Loop over the underlying data. - while pos < len(self): + while pos < len(self._hit_data): # Select the data portion corresponding to the next frame. - hit_data = self._data[pos:pos + self.HIT_LENGTH] + hit_data = self._hit_data[pos:pos + self.HIT_LENGTH] # Check that the frame header and trailer are what we expect. header = hit_data[:self.HIT_HEADER_LENGTH] @@ -659,10 +716,10 @@ def __iter__(self) -> 'AstroPixBinaryFile': """ return self - def __next__(self) -> AstroPixReadout: + def __next__(self) -> AstroPix4Readout: """Read the next packet in the buffer. """ - readout = AstroPixReadout.from_file(self._input_file) + readout = AstroPix4Readout.from_file(self._input_file) if readout is None: raise StopIteration return readout @@ -681,8 +738,8 @@ def _convert_apxdf(file_path: str, hit_class: type, converter: typing.Callable, if header is not None: output_file.write(header) for i, readout in enumerate(input_file): - print(i, readout) - #output_file.write(converter(readout)) + for hit in readout.decode(): + output_file.write(converter(hit)) logger.info(f'Done, {i + 1} hit(s) written') return output_file_path From 7793c6b0da5e991520ced10fa48d02aa30f819f0 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 7 May 2025 10:29:25 +0200 Subject: [PATCH 39/51] Emergency breakpoint. --- core/fmt.py | 132 ++++++++++++---------------------------------------- 1 file changed, 31 insertions(+), 101 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index 996dfcc..343849a 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -49,7 +49,7 @@ class BitPattern(str): caring about the byte boundaries. This is not very memory-efficient and probably not blazingly fast either, but - it allows to reason about the incoming bits in a straighforward fashion, and + it allows to reason about the incoming bits in a straightforward fashion, and I doubt we will ever need to optimize this. (If that is the case, there are probably ways, using either numpy or the bitarray third-party package.) @@ -70,37 +70,25 @@ def __getitem__(self, index): return int(super().__getitem__(index), 2) -class AstroPixHitBase: +class AbstractAstroPixHit(ABC): - """Base class for a generic AstroPix hit. + """Abstract base class for a generic AstroPix hit. While the original decode routine was working in terms of the various bytes in the binary representation of the hit, since there seem to be no meaning altogether in the byte boundaries (at least for AstroPix 4), and the various - fields are arbitrary subsets of a multi-byte word, it seemed more naturale to + fields are arbitrary subsets of a multi-byte word, it seemed more natural to describe the hit as a sequence of fields, each one with its own length in bits. - .. warning:: - - In order to support the addition of a sequential trigger identitier and - a timestamp (both assigned by the DAQ host machine) in the AstroPix4 setup, - we make an explicit distinction between the size of the hit as enclosed in - a readout from the NEXYS board (``READ_SIZE``), and that of a hit that - gets written in an output binary file (``WRITE_SIZE``). Subclasses are - reponsible for setting sensible values for the ``READ_SIZE`` and ``WRITE_SIZE``, - as well as for overloading the ``write()`` and ``from_file_data()`` methods - to handle the additional fields that need to be written and/or read. - Arguments --------- data : bytearray The portion of a full AstroPix readout representing a single hit. """ - READ_SIZE = None - WRITE_SIZE = None - FIELD_DICT = None + _LAYOUT = None _FIELD_NAMES = None + SIZE = None def __init__(self, data: bytearray) -> None: """Constructor. @@ -112,44 +100,23 @@ def __init__(self, data: bytearray) -> None: # to set all the class members. bit_pattern = BitPattern(self._data) pos = 0 - for name, width in self.FIELD_DICT.items(): + for name, width in self._LAYOUT.items(): self.__setattr__(name, bit_pattern[pos:pos + width]) pos += width - def write(self, output_file: typing.BinaryIO) -> None: - """Write the binary data to a file. - - Subclasses can overload this method when it is necessary to add more stuff - (e.g., a trigger identifier, or a timestamp) to the binary blob coming - from the NEXYS board. - - Arguments - --------- - output_file : BinaryIO - A file object opened in "wb" mode. - """ - output_file.write(self._data) - - @classmethod - def from_file_data(cls, data: bytes) -> 'AstroPixHitBase': - """Read a hit from an input binary file. - - By default this is basically calling the class constructor, but when - ``READ_SIZE`` and ``WRITE_SIZE`` are different because ``write()`` is doing - something non-trivial, then this method should be overloaded to do something - sensible with the additional bytes. + @staticmethod + def calculate_size(layout: dict[str, int]) -> int: + """Calculate the size of a hit in bytes. Arguments --------- - data : bytes - The block of binary data (of size ``cls.WRITE_SIZE``) from the binary file. + layout : dict + The layout of the hit, as a dictionary of field names and their + respective widths in bits. """ - return cls(data) - - def __eq__(self, other: 'AstroPixHitBase') -> bool: - """Comparison operator---this is handy in the unit tests. - """ - return self._data == other._data + size, reminder = divmod(sum(layout.values()), 8) + print(size, reminder) + return (sum(layout.values()) + 7) // 8 @staticmethod def gray_to_decimal(gray: int) -> int: @@ -237,13 +204,18 @@ def to_csv(self, fields=None) -> str: fields = self._FIELD_NAMES return self._text(fields, fmts=None, separator=',') + def __eq__(self, other: 'AbstractAstroPixHit') -> bool: + """Comparison operator---this is handy in the unit tests. + """ + return self._data == other._data + def __str__(self) -> str: """String formatting. """ return self._repr(self._FIELD_NAMES) -class AstroPix3Hit(AstroPixHitBase): +class AstroPix3Hit(AbstractAstroPixHit): """Class describing an AstroPix3 hit. @@ -252,9 +224,7 @@ class AstroPix3Hit(AstroPixHitBase): This is copied from decode.py and totally untested. """ - READ_SIZE = 5 - WRITE_SIZE = READ_SIZE - FIELD_DICT = { + _LAYOUT = { 'chip_id': 5, 'payload': 3, 'column': 1, @@ -265,7 +235,8 @@ class AstroPix3Hit(AstroPixHitBase): 'tot_msb': 4, 'tot_lsb': 8 } - _FIELD_NAMES = tuple(FIELD_DICT.keys()) + ('tot', 'tot_us') + _FIELD_NAMES = tuple(_LAYOUT.keys()) + ('tot', 'tot_us') + SIZE = 5 CLOCK_CYCLES_PER_US = 200. def __init__(self, data: bytearray) -> None: @@ -277,18 +248,12 @@ def __init__(self, data: bytearray) -> None: self.tot_us = self.tot / self.CLOCK_CYCLES_PER_US -class AstroPix4Hit(AstroPixHitBase): +class AstroPix4Hit(AbstractAstroPixHit): """Class describing an AstroPix4 hit. """ - READ_SIZE = 8 - _TRIGGER_ID_FMT = ' int: int The actual decimal value of the timestamp counter, in clock cycles. """ - return AstroPixHitBase.gray_to_decimal((ts_coarse << 3) + ts_fine) - - def write(self, output_file: typing.BinaryIO) -> None: - """Overloaded method. - - This is the place where, in addition to the 8 bytes of binary data from the - NEXYS board, we do write the trigger identifier and the timestamp assigned - by the DAQ host machine. - - Arguments - --------- - output_file : BinaryIO - A file object opened in "wb" mode. - """ - output_file.write(self._data) - output_file.write(struct.pack(self._TRIGGER_ID_FMT, self.trigger_id)) - output_file.write(struct.pack(self._TIMESTAMP_FMT, self.timestamp)) - - @classmethod - def from_file_data(cls, data: bytes) -> 'AstroPix4Hit': - """Overloaded method. - - This is where we unpack the trigger identifier and the timestamp assigned - by the DAQ host machine before we initialize the hit object. - - Arguments - --------- - data : bytes - The block of binary data from the binary file. - """ - pos = cls.READ_SIZE - trigger_id = struct.unpack(cls._TRIGGER_ID_FMT, data[pos:pos + cls._TRIGGER_ID_SIZE]) - pos += cls._TRIGGER_ID_SIZE - timestamp = struct.unpack(cls._TIMESTAMP_FMT, data[pos:pos + cls._TIMESTAMP_SIZE]) - data = data[:cls.READ_SIZE] - return cls(data, trigger_id, timestamp) + return AbstractAstroPixHit.gray_to_decimal((ts_coarse << 3) + ts_fine) class AbstractAstroPixReadout(ABC): @@ -503,7 +433,7 @@ class AstroPix4Readout(AbstractAstroPixReadout): HIT_HEADER = bytes.fromhex('bcbc') HIT_TRAILER = bytes.fromhex('bcbcbcbcbcbc') - HIT_DATA_SIZE = AstroPix4Hit.READ_SIZE + HIT_DATA_SIZE = AstroPix4Hit.SIZE HIT_HEADER_LENGTH = len(HIT_HEADER) HIT_TRAILER_LENGTH = len(HIT_TRAILER) HIT_LENGTH = HIT_HEADER_LENGTH + HIT_DATA_SIZE + HIT_TRAILER_LENGTH From 467871a434021151485765a15c9f00a583c14ee9 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 7 May 2025 10:29:44 +0200 Subject: [PATCH 40/51] Initial import. --- .../data/20250507_085829/20250507_085829.log | 33 + .../20250507_085829/20250507_085829_data.apx | Bin 0 -> 28471 bytes .../20250507_085829/20250507_085829_data.csv | 776 ++++++++++++++++++ .../config_v4_none_20250507_085829.yml | 201 +++++ 4 files changed, 1010 insertions(+) create mode 100644 tests/data/20250507_085829/20250507_085829.log create mode 100644 tests/data/20250507_085829/20250507_085829_data.apx create mode 100644 tests/data/20250507_085829/20250507_085829_data.csv create mode 100644 tests/data/20250507_085829/config_v4_none_20250507_085829.yml diff --git a/tests/data/20250507_085829/20250507_085829.log b/tests/data/20250507_085829/20250507_085829.log new file mode 100644 index 0000000..81489f4 --- /dev/null +++ b/tests/data/20250507_085829/20250507_085829.log @@ -0,0 +1,33 @@ +2025-05-07 08:58:29,282:282.__main__.INFO:Configuring the chip... +2025-05-07 08:58:31,321:321.core.nexysio.INFO:Digilent USB A opened +  +2025-05-07 08:58:31,321:321.astropix.INFO:Opened FPGA, testing... +2025-05-07 08:58:31,336:336.astropix.INFO:FPGA test successful. +2025-05-07 08:58:31,349:349.core.asic.WARNING:astropix4 Telescope config not found! +2025-05-07 08:58:31,349:349.core.asic.INFO:astropix4 Sample clock setup with 10 ns period found! +2025-05-07 08:58:31,349:349.core.asic.INFO:astropix4 matrix dimensions found! +2025-05-07 08:58:31,350:350.core.asic.INFO:astropix4 configcards found! +2025-05-07 08:58:31,350:350.core.asic.INFO:astropix4 config found! +2025-05-07 08:58:31,350:350.core.asic.INFO:astropix4 tdac config found! +2025-05-07 08:58:31,350:350.astropix.INFO:update_asic_config() got no arguments, nothing to do. +2025-05-07 08:58:31,350:350.astropix.INFO:enabling analog output in column 2 +2025-05-07 08:58:31,350:350.astropix.INFO:LOADING TO ASIC... +2025-05-07 08:58:31,461:461.core.asic.INFO:Wrote configbits successfully +2025-05-07 08:58:31,461:461.astropix.INFO:ASIC SUCCESSFULLY CONFIGURED +2025-05-07 08:58:31,463:463.core.asic.INFO:Set internal vdac: vinj to 0.300000 V (dacval: 170) +2025-05-07 08:58:31,474:474.core.spi.INFO:SPI: Send routing cmd +2025-05-07 08:58:31,478:478.astropix.INFO:SPI ENABLED +2025-05-07 08:58:31,589:589.core.asic.INFO:Wrote configbits successfully +2025-05-07 08:58:31,590:590.__main__.INFO:Chip fully configured! +2025-05-07 08:58:31,596:596.core.injectionboard.INFO: +Write Injection Config +=============================== +2025-05-07 08:58:31,596:596.core.injectionboard.INFO:Start injection +2025-05-07 08:58:31,597:597.astropix.INFO:Began injection +2025-05-07 08:58:31,597:597.__main__.INFO:Copying configuration to E:\data\astropix-output\20250507_085829\config_v4_none_20250507_085829.yml... +2025-05-07 08:58:31,608:608.__main__.INFO:Opening binary file E:\data\astropix-output\20250507_085829\20250507_085829_data.apx... +2025-05-07 08:59:31,608:608.__main__.INFO:Data acquisition interrupted after 775 readouts. +2025-05-07 08:59:31,609:609.__main__.INFO:Output file closed. +2025-05-07 08:59:31,610:610.core.injectionboard.INFO:Stop injection +2025-05-07 08:59:31,612:612.astropix.INFO:Stopped injection +2025-05-07 08:59:31,613:613.__main__.INFO:Program terminated successfully! diff --git a/tests/data/20250507_085829/20250507_085829_data.apx b/tests/data/20250507_085829/20250507_085829_data.apx new file mode 100644 index 0000000000000000000000000000000000000000..12c5024979397e15a9fadf438c1dabc9ab5afacd GIT binary patch literal 28471 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 WHz5NgJX`xSCDwn4pC9_ZM*k1PByC0j literal 0 HcmV?d00001 diff --git a/tests/data/20250507_085829/20250507_085829_data.csv b/tests/data/20250507_085829/20250507_085829_data.csv new file mode 100644 index 0000000..9ea2d51 --- /dev/null +++ b/tests/data/20250507_085829/20250507_085829_data.csv @@ -0,0 +1,776 @@ +# chip_id,payload,row,column,ts_neg1,ts_coarse1,ts_fine1,ts_tdc1,ts_neg2,ts_coarse2,ts_fine2,ts_tdc2,ts_dec1,ts_dec2,tot_us,trigger_id,timestamp +0,7,0,2,1,1852,0,0,1,1526,1,0,11967,13601,81.7,1,1746601111682511600 +0,7,0,2,1,9724,7,0,1,9476,5,0,117434,118726,64.6,2,1746601111758245700 +0,7,0,2,0,15036,4,0,1,15181,6,0,91832,93259,71.35,3,1746601111836079300 +0,7,0,2,0,12413,2,0,1,12691,0,0,66227,67823,79.8,4,1746601111914048100 +0,7,0,2,1,6717,0,0,0,7920,6,0,40624,42244,81.0,5,1746601111992057200 +0,7,0,2,0,1279,7,0,0,3113,1,0,15018,16782,88.2,6,1746601112068092300 +0,7,0,2,0,10175,4,0,1,9794,7,0,120488,121882,69.7,7,1746601112146124500 +0,7,0,2,1,14718,6,0,1,14489,5,0,94884,96393,75.45,8,1746601112224052400 +0,7,0,2,1,12606,1,0,1,13126,3,0,69281,70621,67.0,9,1746601112300086400 +0,7,0,2,1,8186,2,0,1,7476,6,0,43676,45371,84.75,10,1746601112377989800 +0,7,0,2,0,3258,5,0,0,3531,0,0,18073,19344,63.55,11,1746601112455967000 +0,7,0,2,1,8827,4,0,0,9116,3,0,123543,125117,78.7,12,1746601112532258100 +0,7,0,2,1,14395,1,0,1,10320,1,0,97937,99073,56.8,13,1746601112610060600 +0,7,0,2,1,13051,0,0,1,13839,4,0,72336,73815,73.95,14,1746601112688025300 +0,7,0,2,0,7609,7,0,1,7259,5,0,46730,48278,77.4,15,1746601112764037400 +0,7,0,2,1,3961,4,0,1,3743,2,0,21128,22700,78.6,16,1746601112842159400 +0,7,0,2,0,9016,6,0,0,8651,3,0,126596,128109,75.65,17,1746601112920155000 +0,7,0,2,0,10744,0,0,0,11025,1,0,100992,102641,82.45,18,1746601112996025900 +0,7,0,2,0,14008,0,0,1,14275,3,0,75392,76781,69.45,19,1746601113074131600 +0,7,0,2,1,5224,5,0,0,5514,2,0,49785,51299,75.7,20,1746601113152159800 +0,7,0,2,1,3624,4,0,1,2625,3,0,24184,25586,70.1,21,1746601113228032900 +0,7,0,2,1,8425,1,0,1,25,2,0,129649,131212,78.15,22,1746601113306029100 +0,7,0,2,1,11177,0,0,1,10837,7,0,104048,105674,81.3,23,1746601113384078600 +0,7,0,2,1,13675,5,0,0,13456,6,0,78441,80123,84.1,24,1746601113460025400 +0,7,0,2,0,5419,4,0,0,6099,0,0,52840,54511,83.55,25,1746601113538006800 +0,7,0,2,0,3050,3,0,0,2360,7,0,27234,29050,90.8,26,1746601113616018200 +0,7,0,2,0,170,0,0,1,345,6,0,1632,3211,78.95,27,1746601113692128500 +0,7,0,2,1,11886,6,0,1,12189,5,0,107099,108726,81.35,28,1746601113770014800 +0,7,0,2,0,13358,5,0,0,15582,5,0,81497,83110,80.65,29,1746601113847996000 +0,7,0,2,1,5871,5,0,0,4635,2,0,55894,57491,79.85,30,1746601113926003300 +0,7,0,2,0,2479,1,0,1,2160,0,0,30289,32000,85.55,31,1746601114002028000 +0,7,0,2,1,879,0,0,0,921,0,0,4688,6000,65.6,32,1746601114079988500 +0,7,0,2,1,12077,7,0,0,11590,2,0,110154,111580,71.3,33,1746601114156178700 +0,7,0,2,1,15853,4,0,1,16191,0,0,84552,86352,90.0,34,1746601114234168400 +0,7,0,2,0,4780,2,0,0,5061,0,0,58947,60367,71.0,35,1746601114312026700 +0,7,0,2,0,6252,0,0,1,6273,1,0,33344,34801,72.85,36,1746601114389999900 +0,7,0,2,0,548,6,0,1,1739,7,0,7739,9322,79.15,37,1746601114465978200 +0,7,0,2,0,11492,4,0,1,9223,1,0,113208,114734,76.3,38,1746601114543989700 +0,7,0,2,1,16293,6,0,1,15943,4,0,87604,89128,76.2,39,1746601114622012500 +0,7,0,2,0,4453,1,0,0,4232,3,0,62001,63613,80.6,40,1746601114698158100 +0,7,0,2,1,6439,0,0,1,6978,4,0,36399,37863,73.2,41,1746601114776013000 +0,7,0,2,1,2023,7,0,1,1809,6,0,10794,12043,62.45,42,1746601114854018400 +0,7,0,2,1,9382,4,0,0,9585,2,0,116263,118028,88.25,43,1746601114929993900 +0,7,0,2,1,14950,3,0,1,15002,7,0,90658,92005,67.35,44,1746601115007967200 +0,7,0,2,1,4134,0,0,0,12483,7,0,65056,66581,76.25,45,1746601115085982200 +0,7,0,2,1,6882,6,0,1,7731,5,0,39451,41238,89.35,46,1746601115162039200 +0,7,0,2,0,1442,5,0,0,1102,7,0,13849,15450,80.05,47,1746601115240095000 +0,7,0,2,1,10083,6,0,0,9856,7,0,119316,120837,76.05,48,1746601115317954700 +0,7,0,2,0,15139,0,0,0,14809,2,0,93712,95372,83.0,49,1746601115395951800 +0,7,0,2,0,12769,2,0,0,13070,0,0,68108,69727,80.95,50,1746601115471959400 +0,7,0,2,1,7841,5,0,1,8143,2,0,42505,43948,72.15,51,1746601115549962900 +0,7,0,2,0,3168,4,0,1,3209,5,0,16903,18313,70.5,52,1746601115627985600 +0,7,0,2,0,9760,1,0,0,8776,6,0,122369,123780,70.55,53,1746601115704094700 +0,7,0,2,0,14560,0,0,0,14387,7,0,96768,98026,62.9,54,1746601115782133800 +0,7,0,2,0,13280,7,0,0,12888,4,0,71162,72839,83.85,55,1746601115859968400 +0,7,0,2,0,7456,4,0,0,7311,1,0,45560,47185,81.25,56,1746601115935975100 +0,7,0,2,0,3425,3,0,0,4095,1,0,19954,21841,94.35,57,1746601116013962100 +0,7,0,2,0,9121,1,0,0,8987,2,0,125425,126828,70.15,58,1746601116091960500 +0,7,0,2,1,10467,3,0,1,10564,3,0,99821,101437,80.8,59,1746601116168071600 +0,7,0,2,0,13859,5,0,1,13959,1,0,74217,75729,75.6,60,1746601116246036900 +0,7,0,2,1,7266,4,0,1,5187,1,0,48615,50158,77.15,61,1746601116323944900 +0,7,0,2,0,3746,1,0,0,2565,7,0,23009,24629,81.0,62,1746601116400095600 +0,7,0,2,0,8678,0,0,0,8410,6,0,128479,129892,70.65,63,1746601116478103300 +0,7,0,2,1,11046,7,0,1,11185,6,0,102874,104180,65.3,64,1746601116556006100 +0,7,0,2,0,14182,4,0,0,13641,6,0,77272,78731,72.95,65,1746601116631963000 +0,7,0,2,1,5543,2,0,1,5384,6,0,51667,53124,72.85,66,1746601116709945700 +0,7,0,2,0,2791,0,0,0,3011,5,0,26064,27625,78.05,67,1746601116787933300 +0,7,0,2,0,39,0,0,0,243,1,0,464,1297,41.65,68,1746601116865974500 +0,7,0,2,0,10853,4,0,1,11980,4,0,105928,107591,83.15,69,1746601116941948300 +0,7,0,2,1,13476,4,0,1,13353,4,0,80327,81527,60.0,70,1746601117019928300 +0,7,0,2,0,6116,1,0,0,5704,3,0,54721,56445,86.2,71,1746601117097951100 +0,7,0,2,1,2340,0,0,0,2443,5,0,29120,30614,74.7,72,1746601117173925700 +0,7,0,2,0,364,5,0,0,842,2,0,3513,5020,75.35,73,1746601117252021400 +0,7,0,2,1,12205,4,0,0,12063,1,0,108983,110417,71.7,74,1746601117330020700 +0,7,0,2,0,15597,2,0,1,15837,5,0,83379,84809,71.5,75,1746601117406020000 +0,7,0,2,1,4653,0,0,1,5003,4,0,57776,59496,86.0,76,1746601117484026400 +0,7,0,2,1,2159,2,0,0,6212,4,0,32172,33735,78.15,77,1746601117561936900 +0,7,0,2,0,687,4,0,0,1541,6,0,6568,8244,83.8,78,1746601117637913700 +0,7,0,2,0,11758,7,0,0,11480,1,0,112037,113534,74.85,79,1746601117715912900 +0,7,0,2,1,16174,1,0,1,16270,5,0,86433,87974,77.05,80,1746601117793914900 +0,7,0,2,1,4974,0,0,1,4441,1,0,60832,62321,74.45,81,1746601117869915800 +0,7,0,2,1,6570,5,0,1,6415,2,0,35225,36780,77.75,82,1746601117947921100 +0,7,0,2,1,1770,4,0,1,1995,2,0,9624,11155,76.55,83,1746601118025918800 +0,7,0,2,0,9259,3,0,0,9362,6,0,115090,116507,70.85,84,1746601118101910100 +0,7,0,2,0,15979,1,0,1,14928,3,0,89489,90882,69.65,85,1746601118180008800 +0,7,0,2,0,4265,7,0,1,12343,3,0,63882,65837,97.75,86,1746601118257882300 +0,7,0,2,0,7145,4,0,1,6867,1,0,38280,39697,70.85,87,1746601118335898600 +0,7,0,2,1,1320,6,0,0,1416,2,0,12676,14211,76.75,88,1746601118411890200 +0,7,0,2,0,9576,1,0,0,10093,7,0,118145,119370,61.25,89,1746601118489886300 +0,7,0,2,0,15272,0,0,0,15144,0,0,92544,93823,63.95,90,1746601118567898200 +0,7,0,2,1,12536,5,0,1,12799,4,0,66937,68264,66.35,91,1746601118643886500 +0,7,0,2,1,7737,4,0,1,8073,2,0,41335,43123,89.4,92,1746601118721876000 +0,7,0,2,1,1145,3,0,1,3177,1,0,15730,17009,63.95,93,1746601118799888700 +0,7,0,2,1,9913,0,0,1,9742,7,0,121200,122789,79.45,94,1746601118875883000 +0,7,0,2,0,14843,6,0,0,14531,2,0,95595,97260,83.25,95,1746601118953891100 +0,7,0,2,1,13115,4,0,1,12976,6,0,69992,71940,97.4,96,1746601119031882300 +0,7,0,2,1,8058,2,0,0,7530,1,0,44387,45665,63.9,97,1746601119108016900 +0,7,0,2,1,3514,0,0,0,3328,3,0,18784,20477,84.65,98,1746601119185980600 +0,7,0,2,0,8958,1,0,1,9212,3,0,124254,125629,68.75,99,1746601119263853600 +0,7,0,2,0,10302,5,0,1,10424,3,0,98649,99970,66.05,100,1746601119339865800 +0,7,0,2,1,12927,5,0,1,13942,7,0,73046,74458,70.6,101,1746601119417861100 +0,7,0,2,0,7359,3,0,1,7293,1,0,47442,48462,51.0,102,1746601119495862600 +0,7,0,2,1,4093,0,0,1,3662,7,0,21839,23642,90.15,103,1746601119571985500 +0,7,0,2,1,8509,5,0,0,8320,1,0,127305,129025,86.0,104,1746601119649872000 +0,7,0,2,0,10621,4,0,1,11046,7,0,101704,102874,58.5,105,1746601119727859900 +0,7,0,2,0,14268,2,0,0,14107,4,0,76099,77672,78.65,106,1746601119805865300 +0,7,0,2,0,5372,1,0,1,5623,4,0,50497,51927,71.5,107,1746601119881859000 +0,7,0,2,1,2620,0,0,1,2733,7,0,24896,26186,64.5,108,1746601119959855200 +0,7,0,2,0,8308,5,0,0,117,7,0,130361,131786,71.25,109,1746601120037857100 +0,7,0,2,0,10933,5,0,0,11777,3,0,104758,106509,87.55,110,1746601120113837000 +0,7,0,2,1,13813,1,0,0,13552,6,0,79153,80635,74.1,111,1746601120191872900 +0,7,0,2,1,5943,0,0,0,6021,3,0,53551,55245,84.7,112,1746601120269829600 +0,7,0,2,0,2935,5,0,0,2498,1,0,27945,29726,89.05,113,1746601120345845200 +0,7,0,2,0,439,4,0,0,354,7,0,2344,3557,60.65,114,1746601120423828100 +0,7,0,2,0,12022,2,0,1,12232,3,0,107811,109442,81.55,115,1746601120501849200 +0,7,0,2,0,15414,0,0,1,15540,1,0,82208,83649,72.05,116,1746601120577834000 +0,7,0,2,0,5746,6,0,0,4733,7,0,56603,58037,71.7,117,1746601120655834500 +0,7,0,2,0,2226,4,0,0,2073,0,0,31000,32624,81.2,118,1746601120733844600 +0,7,0,2,1,1011,6,0,1,727,1,0,5396,6958,78.1,119,1746601120809836900 +0,7,0,2,0,11571,0,0,1,11655,2,0,110864,112595,86.55,120,1746601120887827300 +0,7,0,2,1,15729,3,0,0,16321,4,0,85261,87048,89.35,121,1746601120965808300 +0,7,0,2,0,5041,5,0,1,4907,6,0,59657,61035,68.9,122,1746601121041805300 +0,7,0,2,1,6385,4,0,1,6495,5,0,34056,36009,97.65,123,1746601121119939000 +0,7,0,2,0,1584,3,0,1,1785,5,0,8450,9590,57.0,124,1746601121197816600 +0,7,0,2,0,11376,0,0,0,9330,7,0,113920,115429,75.45,125,1746601121273808700 +0,7,0,2,1,16016,6,0,1,15904,1,0,88315,89601,64.3,126,1746601121351814600 +0,7,0,2,0,4560,4,0,1,4318,6,0,62712,64347,81.75,127,1746601121429812000 +0,7,0,2,0,6929,6,0,0,7059,7,0,37108,38677,78.45,128,1746601121507824100 +0,7,0,2,0,1873,1,0,0,1314,6,0,11505,12772,63.35,129,1746601121583830200 +0,7,0,2,1,9619,1,0,0,9516,1,0,116974,118337,68.15,130,1746601121661814500 +0,7,0,2,0,15059,5,0,0,15352,5,0,91369,92806,71.85,131,1746601121737948700 +0,7,0,2,0,12306,5,0,0,12435,5,0,65766,67350,79.2,132,1746601121815926600 +0,7,0,2,1,6738,3,0,0,7779,7,0,40162,41493,66.55,133,1746601121893789700 +0,7,0,2,1,1170,0,0,0,1121,1,0,14560,15857,64.85,134,1746601121971799300 +0,7,0,2,1,10198,7,0,0,9970,6,0,120026,121572,77.3,135,1746601122047808000 +0,7,0,2,0,14614,4,0,0,14740,1,0,94424,96062,81.9,136,1746601122125761300 +0,7,0,2,0,12630,4,0,0,13118,4,0,68824,69976,57.6,137,1746601122203775100 +0,7,0,2,0,8087,0,0,0,7957,7,0,43216,44853,81.85,138,1746601122279787000 +0,7,0,2,1,3285,0,0,1,3580,3,0,17615,19133,75.9,139,1746601122357786200 +0,7,0,2,0,8725,5,0,0,8931,6,0,123081,124395,65.7,140,1746601122435794600 +0,7,0,2,1,14420,4,0,0,10321,1,0,97479,99086,80.35,141,1746601122511792900 +0,7,0,2,0,12948,1,0,1,12853,1,0,71873,73422,77.45,142,1746601122589783700 +0,7,0,2,1,7636,0,0,0,7374,7,0,46272,48037,88.25,143,1746601122667835900 +0,7,0,2,1,3868,7,0,1,4011,7,0,20666,22122,72.8,144,1746601122743784800 +0,7,0,2,0,9052,4,0,1,8566,3,0,126136,127709,78.65,145,1746601122821804500 +0,7,0,2,0,10653,3,0,1,10536,7,0,100530,102010,74.0,146,1746601122899755500 +0,7,0,2,1,14045,0,0,0,14301,6,0,74928,76619,84.55,147,1746601122977768300 +0,7,0,2,1,5149,0,0,0,5371,0,0,49328,50543,60.75,148,1746601123053766900 +0,7,0,2,0,3679,5,0,1,2640,7,0,23721,25349,81.4,149,1746601123131906600 +0,7,0,2,0,8351,4,0,1,8297,6,0,129192,130443,62.55,150,1746601123207881500 +0,7,0,2,0,11230,1,0,1,10956,3,0,103585,105405,91.0,151,1746601123285879700 +0,7,0,2,0,13598,0,0,0,13741,6,0,77984,79435,72.55,152,1746601123363763000 +0,7,0,2,1,5466,5,0,0,5998,2,0,52377,53852,73.75,153,1746601123441765900 +0,7,0,2,0,2970,5,0,1,2925,0,0,26777,28080,65.15,154,1746601123517757200 +0,7,0,2,0,219,3,0,1,506,7,0,1170,2714,77.2,155,1746601123595772900 +0,7,0,2,0,11803,0,0,1,12029,3,0,106640,107853,60.65,156,1746601123673770000 +0,7,0,2,0,13401,7,0,1,15454,5,0,81034,82777,87.15,157,1746601123749893300 +0,7,0,2,0,5785,4,0,0,5692,5,0,55432,57017,79.25,158,1746601123827735900 +0,7,0,2,1,2520,7,0,1,2285,3,0,29829,31309,74.0,159,1746601123905741500 +0,7,0,2,0,792,1,0,1,954,1,0,4225,5790,78.25,160,1746601123981732200 +0,7,0,2,1,12104,0,0,1,11633,0,0,109695,111344,82.45,161,1746601124059740100 +0,7,0,2,0,15752,7,0,0,15675,0,0,84090,85648,77.9,162,1746601124137684400 +0,7,0,2,1,4808,4,0,1,5109,1,0,58488,60110,81.1,163,1746601124213761900 +0,7,0,2,0,6153,2,0,1,6309,1,0,32883,34353,73.5,164,1746601124291734600 +0,7,0,2,0,585,0,0,0,1641,1,0,7280,8817,76.85,165,1746601124370008300 +0,7,0,2,0,11403,6,0,1,11313,1,0,112747,114417,83.5,166,1746601124445875400 +0,7,0,2,0,16331,4,0,1,16111,0,0,87144,88656,75.6,167,1746601124523837000 +0,7,0,2,1,4362,6,0,0,4517,3,0,61540,63026,74.3,168,1746601124601866100 +0,7,0,2,0,6474,1,0,0,7019,4,0,35937,37480,77.15,169,1746601124677727700 +0,7,0,2,0,1934,2,0,0,1835,7,0,10332,11882,77.5,170,1746601124755746600 +0,7,0,2,0,9422,5,0,1,9720,7,0,115801,117381,79.0,171,1746601124833714900 +0,7,0,2,0,14863,4,0,0,14995,7,0,90199,91925,86.3,172,1746601124911726300 +0,7,0,2,1,4175,3,0,1,12344,6,0,64594,65915,66.05,173,1746601124987710300 +0,7,0,2,1,6799,0,0,0,6712,2,0,38992,40579,79.35,174,1746601125065715600 +0,7,0,2,0,1485,7,0,0,1238,7,0,13386,15141,87.75,175,1746601125143849800 +0,7,0,2,1,9997,4,0,0,10120,6,0,118856,120708,92.6,176,1746601125219716400 +0,7,0,2,1,15180,6,0,1,14631,1,0,93252,94673,71.05,177,1746601125297710700 +0,7,0,2,1,12684,1,0,0,12631,6,0,67649,68820,58.55,178,1746601125375843200 +0,7,0,2,1,7876,2,0,1,8110,2,0,42044,43427,69.15,179,1746601125451728000 +0,7,0,2,0,3076,5,0,1,3244,1,0,16441,17985,77.2,180,1746601125529845800 +0,7,0,2,1,9796,4,0,1,8742,6,0,121912,123355,72.15,181,1746601125607713000 +0,7,0,2,1,14469,1,0,1,14376,5,0,96305,97913,80.4,182,1746601125683652900 +0,7,0,2,1,13253,0,0,1,12954,3,0,70704,71837,56.65,183,1746601125761628400 +0,7,0,2,1,7431,7,0,0,7613,0,0,45098,46768,83.5,184,1746601125839704900 +0,7,0,2,0,3399,4,0,0,3943,1,0,19496,21038,77.1,185,1746601125915733500 +0,7,0,2,0,9094,2,0,0,8976,2,0,124963,126723,88.0,186,1746601125993726000 +0,7,0,2,1,10438,0,0,0,10742,7,0,99360,101082,86.1,187,1746601126071680600 +0,7,0,2,0,13826,3,0,0,13987,3,0,73757,75282,76.25,188,1746601126149745100 +0,7,0,2,0,7234,5,0,0,5155,2,0,48153,49644,74.55,189,1746601126225805600 +0,7,0,2,1,3715,4,0,1,3702,4,0,22551,23847,64.8,190,1746601126303678500 +0,7,0,2,0,8643,1,0,1,8421,6,0,128017,129588,78.55,191,1746601126381680800 +0,7,0,2,1,11011,0,0,1,11175,3,0,102416,103981,78.25,192,1746601126457686000 +0,7,0,2,1,14145,7,0,1,13629,6,0,76810,78155,67.25,193,1746601126535686700 +0,7,0,2,0,5505,4,0,1,5409,7,0,51208,52746,76.9,194,1746601126613692700 +0,7,0,2,1,2752,3,0,1,3028,3,0,25602,27453,92.55,195,1746601126689679200 +0,7,0,2,0,0,0,0,0,228,7,0,0,1477,73.85,196,1746601126767782800 +0,7,0,2,0,10944,6,0,1,11863,6,0,105467,107307,92.0,197,1746601126845665900 +0,7,0,2,0,13696,5,0,0,13398,0,0,79865,81119,62.7,198,1746601126921663000 +0,7,0,2,0,5953,6,0,0,5845,2,0,54260,56115,92.75,199,1746601126999666800 +0,7,0,2,0,2817,1,0,0,2557,7,0,28657,30026,68.45,200,1746601127077670700 +0,7,0,2,1,451,0,0,0,807,1,0,3055,4561,75.3,201,1746601127153613000 +0,7,0,2,1,11907,5,0,1,12154,3,0,108521,109922,70.05,202,1746601127231843100 +0,7,0,2,1,15427,4,0,1,15779,4,0,82920,84456,76.8,203,1746601127309661900 +0,7,0,2,0,5634,3,0,0,4848,0,0,57314,58624,65.5,204,1746601127385663000 +0,7,0,2,0,2242,0,0,0,6242,1,0,31712,33310,79.9,205,1746601127463661100 +0,7,0,2,0,902,7,0,0,545,4,0,6106,7688,79.1,206,1746601127541661200 +0,7,0,2,1,11590,4,0,1,11466,7,0,111576,113562,99.3,207,1746601127619641700 +0,7,0,2,1,15623,7,0,1,16380,0,0,85973,87360,69.35,208,1746601127695632200 +0,7,0,2,0,5063,0,0,0,4408,1,0,60368,61822,72.7,209,1746601127773769000 +0,7,0,2,0,6277,0,0,0,6437,6,0,34767,36404,81.85,210,1746601127851677100 +0,7,0,2,1,1605,5,0,1,1937,3,0,9161,10482,66.05,211,1746601127927638800 +0,7,0,2,0,11268,4,0,1,9400,4,0,114631,116359,86.4,212,1746601128005945500 +0,7,0,2,1,16068,1,0,0,14898,6,0,89025,90395,68.5,213,1746601128083642500 +0,7,0,2,1,4484,0,0,0,4159,6,0,63424,65195,88.55,214,1746601128159638700 +0,7,0,2,0,6988,6,0,0,7041,0,0,37819,38896,53.85,215,1746601128237770700 +0,7,0,2,1,1804,4,0,0,1424,2,0,12216,14083,93.35,216,1746601128315632500 +0,7,0,2,0,9677,6,0,0,10086,2,0,117684,119331,82.35,217,1746601128391629500 +0,7,0,2,0,14989,1,0,0,15220,1,0,92081,93502,71.05,218,1746601128469633300 +0,7,0,2,0,12367,3,0,1,12697,1,0,66477,67726,62.45,219,1746601128547637300 +0,7,0,2,0,6671,4,0,0,7825,4,0,40872,42760,94.4,220,1746601128623607500 +0,7,0,2,1,1230,4,0,1,3131,6,0,15271,16747,73.8,221,1746601128701616300 +0,7,0,2,1,10126,1,0,1,9854,7,0,120737,122202,73.25,222,1746601128779615600 +0,7,0,2,1,14670,0,0,0,14575,0,0,95136,96848,85.6,223,1746601128855615300 +0,7,0,2,1,12554,7,0,0,13222,1,0,69530,71201,83.55,224,1746601128933610100 +0,7,0,2,0,8138,4,0,1,7468,6,0,43928,45499,78.55,225,1746601129011613000 +0,7,0,2,0,3211,2,0,1,3410,1,0,18323,19681,67.9,226,1746601129087619000 +0,7,0,2,0,8779,0,0,0,9144,6,0,123792,125307,75.75,227,1746601129165638300 +0,7,0,2,1,14345,6,0,1,10482,6,0,98187,99611,71.2,228,1746601129243637100 +0,7,0,2,0,13001,5,0,0,13854,3,0,72585,73890,65.25,229,1746601129319727400 +0,7,0,2,0,7560,6,0,0,7217,2,0,46980,48883,95.15,230,1746601129397621300 +0,7,0,2,0,3912,1,0,1,3821,4,0,21377,23112,86.75,231,1746601129475623000 +0,7,0,2,0,8968,0,0,1,8656,2,0,126848,128252,70.2,232,1746601129553584400 +0,7,0,2,1,10712,5,0,1,11065,3,0,101241,102770,76.45,233,1746601129629767400 +0,7,0,2,1,13976,4,0,0,14197,7,0,75640,77109,73.45,234,1746601129707713000 +0,7,0,2,1,5209,3,0,1,5567,6,0,50034,51540,75.3,235,1746601129785744100 +0,7,0,2,1,3609,0,0,0,2746,5,0,24432,26265,91.65,236,1746601129861596000 +0,7,0,2,1,8411,6,0,1,57,3,0,129899,131442,77.15,237,1746601129939576900 +0,7,0,2,0,11163,5,0,0,10854,4,0,104297,105944,82.35,238,1746601130017599800 +0,7,0,2,0,13658,6,0,1,13492,0,0,78692,80191,74.95,239,1746601130093573800 +0,7,0,2,0,5402,1,0,1,6103,1,0,53089,54481,69.6,240,1746601130171593300 +0,7,0,2,1,3038,1,0,0,2364,6,0,27486,28996,75.5,241,1746601130249595100 +0,7,0,2,0,158,5,0,1,370,3,0,1881,3357,73.8,242,1746601130325723200 +0,7,0,2,1,11870,4,0,1,12183,5,0,107352,108758,70.3,243,1746601130403723400 +0,7,0,2,1,13343,3,0,1,15549,1,0,81746,83633,94.35,244,1746601130482151300 +0,7,0,2,0,5855,0,0,0,4617,3,0,56144,57458,65.7,245,1746601130557705000 +0,7,0,2,0,2461,6,0,1,2161,7,0,30539,32010,73.55,246,1746601130635575400 +0,7,0,2,0,861,4,0,1,669,5,0,4936,6326,69.5,247,1746601130713710200 +0,7,0,2,1,12060,6,0,0,11766,7,0,110404,111909,75.25,248,1746601130789551400 +0,7,0,2,0,15836,1,0,1,16144,1,0,84801,86270,73.45,249,1746601130867565300 +0,7,0,2,1,4764,0,0,0,4934,7,0,59200,60453,62.65,250,1746601130945567700 +0,7,0,2,0,6228,5,0,0,6573,1,0,33593,35249,82.8,251,1746601131023696300 +0,7,0,2,0,533,4,0,1,1783,4,0,7991,9512,76.05,252,1746601131099570500 +0,7,0,2,1,11477,3,0,0,9239,2,0,113458,114899,72.05,253,1746601131177567000 +0,7,0,2,0,16277,0,0,0,15987,3,0,87856,89362,75.3,254,1746601131255580700 +0,7,0,2,1,4439,7,0,1,4349,0,0,62250,64176,96.3,255,1746601131331579700 +0,7,0,2,1,6423,4,0,0,7162,0,0,36648,38240,79.6,256,1746601131409556100 +0,7,0,2,0,2006,3,0,0,1319,3,0,11042,12754,85.6,257,1746601131487538000 +0,7,0,2,0,9366,1,0,1,9545,7,0,116513,117877,68.2,258,1746601131563542700 +0,7,0,2,1,14930,3,0,0,15248,1,0,90909,92414,75.25,259,1746601131641542100 +0,7,0,2,0,4114,5,0,1,12352,1,0,65305,66558,62.65,260,1746601131719680300 +0,7,0,2,1,6866,4,0,0,6670,4,0,39704,40871,58.35,261,1746601131795533400 +0,7,0,2,0,1427,1,0,1,1129,5,0,14097,15753,82.8,262,1746601131873563300 +0,7,0,2,1,10067,0,0,1,9915,0,0,119568,121199,81.55,263,1746601131951535700 +0,7,0,2,1,15121,7,0,1,14832,5,0,93962,95494,76.6,264,1746601132027523700 +0,7,0,2,0,12753,4,0,1,12552,5,0,68360,69510,57.5,265,1746601132105541600 +0,7,0,2,1,7824,2,0,1,8059,1,0,42755,44398,82.15,266,1746601132183574400 +0,7,0,2,1,3152,0,0,0,3496,7,0,17152,18821,83.45,267,1746601132259548900 +0,7,0,2,0,9776,3,0,0,8945,0,0,122621,124175,77.7,268,1746601132337540400 +0,7,0,2,0,14576,4,0,1,10273,7,0,97016,98805,89.45,269,1746601132415525900 +0,7,0,2,1,13233,4,0,0,12873,2,0,71415,72819,70.2,270,1746601132493677900 +0,7,0,2,0,7537,0,0,0,7319,1,0,45808,47313,75.25,271,1746601132569515700 +0,7,0,2,1,3379,0,0,0,4011,7,0,20207,22122,95.75,272,1746601132647520500 +0,7,0,2,0,9203,5,0,1,8474,7,0,125673,127130,72.85,273,1746601132723686100 +0,7,0,2,1,10418,4,0,1,10530,3,0,100071,101917,92.3,274,1746601132801546300 +0,7,0,2,0,13938,2,0,0,14271,5,0,74467,76118,82.55,275,1746601132879500700 +0,7,0,2,0,7218,0,0,0,5323,5,0,48864,50281,70.85,276,1746601132957634900 +0,7,0,2,1,3830,2,0,1,2589,1,0,23260,24753,74.65,277,1746601133033506900 +0,7,0,2,0,8630,4,0,1,8281,2,0,128728,130188,73.0,278,1746601133111517400 +0,7,0,2,1,11127,6,0,1,10915,6,0,103124,104939,90.75,279,1746601133189495100 +0,7,0,2,0,14135,1,0,1,13774,7,0,77521,78938,70.85,280,1746601133265681000 +0,7,0,2,1,5621,1,0,1,5948,3,0,51918,53570,82.6,281,1746601133343472100 +0,7,0,2,0,2741,5,0,0,2938,5,0,26313,28006,84.65,282,1746601133421501500 +0,7,0,2,1,116,4,0,1,425,0,0,711,2447,86.8,283,1746601133497480100 +0,7,0,2,1,10804,3,0,1,11843,5,0,106178,107497,65.95,284,1746601133575495300 +0,7,0,2,1,13556,0,0,1,15422,2,0,80576,82268,84.6,285,1746601133653495600 +0,7,0,2,1,6076,6,0,0,5851,6,0,54971,56171,60.0,286,1746601133729487700 +0,7,0,2,0,2428,4,0,0,2179,5,0,29368,30742,68.7,287,1746601133807468300 +0,7,0,2,1,317,2,0,1,1007,5,0,3763,5545,89.1,288,1746601133885497800 +0,7,0,2,0,12285,0,0,1,11566,0,0,109232,111008,88.8,289,1746601133963469100 +0,7,0,2,1,15551,0,0,0,15814,3,0,83631,84957,66.3,290,1746601134039468100 +0,7,0,2,1,4735,5,0,1,5015,3,0,58025,59602,78.85,291,1746601134117581700 +0,7,0,2,0,2111,4,0,1,6341,4,0,32424,33847,71.15,292,1746601134195512100 +0,7,0,2,1,766,3,0,0,1564,7,0,6818,8378,78.0,293,1746601134271450200 +0,7,0,2,0,11710,0,0,0,11332,3,0,112288,113725,71.85,294,1746601134349578100 +0,7,0,2,0,16250,7,0,1,16044,2,0,86682,88508,91.3,295,1746601134427471800 +0,7,0,2,1,4922,4,0,0,4570,7,0,61080,62618,76.9,296,1746601134503607100 +0,7,0,2,0,6651,2,0,1,6960,0,0,35475,37120,82.25,297,1746601134581620500 +0,7,0,2,0,1723,1,0,0,1997,3,0,9873,11186,65.65,298,1746601134659677700 +0,7,0,2,1,9337,2,0,1,9630,0,0,115340,116896,77.8,299,1746601134735840900 +0,7,0,2,1,15929,5,0,1,14972,7,0,89737,90810,53.65,300,1746601134813461600 +0,7,0,2,0,4344,5,0,1,12339,3,0,64134,65810,83.8,301,1746601134891445000 +0,7,0,2,1,7096,1,0,0,6774,3,0,38529,40226,84.85,302,1746601134967497700 +0,7,0,2,1,1400,0,0,1,1168,6,0,12928,14587,82.95,303,1746601135045469000 +0,7,0,2,0,9512,7,0,0,10053,3,0,118394,119757,68.15,304,1746601135123586200 +0,7,0,2,0,15336,4,0,0,14641,4,0,92792,94472,84.0,305,1746601135199461200 +0,7,0,2,1,12457,2,0,1,12618,6,0,67187,68708,76.05,306,1746601135277500100 +0,7,0,2,0,7785,0,0,1,8073,3,0,41584,43122,76.9,307,1746601135355552500 +0,7,0,2,1,1067,6,0,0,3313,7,0,15979,17674,84.75,308,1746601135431632400 +0,7,0,2,0,9963,4,0,0,8730,3,0,121448,123037,79.45,309,1746601135509739800 +0,7,0,2,1,14763,4,0,1,14456,7,0,95848,97658,90.5,310,1746601135587544800 +0,7,0,2,0,13162,1,0,0,12951,2,0,70241,71891,82.5,311,1746601135665423500 +0,7,0,2,1,7978,0,0,1,7633,6,0,44640,46324,84.2,312,1746601135741466300 +0,7,0,2,1,3566,7,0,1,3843,5,0,19034,20502,73.4,313,1746601135819432500 +0,7,0,2,0,8878,5,0,1,9154,1,0,124505,125921,70.8,314,1746601135897484400 +0,7,0,2,0,10351,2,0,1,10368,1,0,98899,100350,72.55,315,1746601135973436300 +0,7,0,2,1,12847,0,0,0,14078,4,0,73296,75096,90.0,316,1746601136051442000 +0,7,0,2,0,7405,2,0,1,7172,2,0,47692,49091,69.95,317,1746601136129446100 +0,7,0,2,0,4013,4,0,1,3664,7,0,22088,23802,85.7,318,1746601136205636300 +0,7,0,2,0,8557,4,0,1,8619,6,0,127560,128619,52.95,319,1746601136283421700 +0,7,0,2,1,10540,1,0,1,11263,1,0,101953,103761,90.4,320,1746601136361398200 +0,7,0,2,0,14308,0,0,0,13585,0,0,76351,78064,85.65,321,1746601136437405800 +0,7,0,2,1,5284,5,0,0,5458,6,0,50745,52452,85.35,322,1746601136515541100 +0,7,0,2,1,2661,4,0,1,2963,1,0,25143,26862,85.95,323,1746601136593572300 +0,7,0,2,0,8229,3,0,1,201,5,0,130610,132214,80.2,324,1746601136669519400 +0,7,0,2,0,10981,0,0,0,11785,5,0,105008,106614,80.3,325,1746601136747552100 +0,7,0,2,1,13735,2,0,1,13521,2,0,79404,80652,62.4,326,1746601136825566000 +0,7,0,2,0,5991,4,0,0,5766,7,0,53800,55333,76.65,327,1746601136901399400 +0,7,0,2,1,2854,6,0,1,2497,6,0,28196,29707,75.55,328,1746601136979424500 +0,7,0,2,0,486,0,0,1,287,6,0,2592,3924,66.6,329,1746601137057417100 +0,7,0,2,1,11938,3,0,1,12238,3,0,108061,109474,70.65,330,1746601137133389600 +0,7,0,2,0,15458,5,0,1,15763,4,0,82457,84200,87.15,331,1746601137211545300 +0,7,0,2,1,5666,4,0,0,4829,5,0,56856,58550,84.7,332,1746601137289542900 +0,7,0,2,0,2275,1,0,1,6149,3,0,31249,32818,78.45,333,1746601137367397900 +0,7,0,2,1,931,0,0,0,710,0,0,5648,7135,74.35,334,1746601137443371200 +0,7,0,2,1,11617,7,0,1,11668,6,0,111114,112443,66.45,335,1746601137521372200 +0,7,0,2,0,15649,4,0,1,16240,5,0,85512,86777,63.25,336,1746601137599370800 +0,7,0,2,1,5088,2,0,0,4886,7,0,59907,61221,65.7,337,1746601137675503800 +0,7,0,2,0,6304,0,0,1,6467,1,0,34304,35857,77.65,338,1746601137753535200 +0,7,0,2,1,1568,1,0,1,1666,2,0,8702,10211,75.45,339,1746601137831531500 +0,7,0,2,0,11360,5,0,0,9311,0,0,114169,115536,68.35,340,1746601137907539500 +0,7,0,2,1,16033,7,0,0,14870,3,0,88565,90333,88.4,341,1746601137985488300 +0,7,0,2,1,4577,1,0,1,4290,5,0,62961,64486,76.25,342,1746601138063369700 +0,7,0,2,0,6945,0,0,0,7068,5,0,37360,38726,68.3,343,1746601138139365600 +0,7,0,2,0,1891,6,0,0,1374,2,0,11755,13148,69.65,344,1746601138217547800 +0,7,0,2,0,9635,4,0,0,9486,3,0,117224,118690,73.3,345,1746601138293352200 +0,7,0,2,0,15074,3,0,0,15184,5,0,91618,93433,90.75,346,1746601138371511500 +0,7,0,2,0,12322,0,0,1,12443,7,0,66016,67434,70.9,347,1746601138449369000 +0,7,0,2,1,6758,2,0,1,7759,2,0,40412,41900,74.4,348,1746601138527384600 +0,7,0,2,0,1190,4,0,1,3101,1,0,14808,16561,87.65,349,1746601138603366600 +0,7,0,2,1,10214,4,0,1,9792,3,0,120280,121858,78.9,350,1746601138681469000 +0,7,0,2,0,14631,1,0,0,14474,0,0,94673,96352,83.95,351,1746601138759363100 +0,7,0,2,1,12645,0,0,1,13250,1,0,69071,70686,80.75,352,1746601138835464200 +0,7,0,2,1,8101,7,0,1,7435,6,0,43466,45163,84.85,353,1746601138913351900 +0,7,0,2,1,3300,4,0,1,3419,0,0,17863,19600,86.85,354,1746601138991347400 +0,7,0,2,1,8740,3,0,1,9113,2,0,123330,125068,86.9,355,1746601139069344700 +0,7,0,2,1,14436,0,0,0,10436,2,0,97728,99388,83.0,356,1746601139145647000 +0,7,0,2,0,12972,6,0,1,12810,2,0,72123,73628,75.25,357,1746601139223535700 +0,7,0,2,1,7660,4,0,0,7263,4,0,46520,48296,88.8,358,1746601139301542300 +0,7,0,2,1,3885,6,0,1,3743,5,0,20916,22697,89.05,359,1746601139377442000 +0,7,0,2,0,9069,1,0,0,8540,1,0,126385,127809,71.2,360,1746601139455323000 +0,7,0,2,0,10669,0,0,0,10514,0,0,100784,102175,69.55,361,1746601139533343800 +0,7,0,2,1,14063,5,0,0,14144,2,0,75177,76803,81.3,362,1746601139609320200 +0,7,0,2,0,5167,4,0,0,5291,5,0,49576,50793,60.85,363,1746601139687326500 +0,7,0,2,0,3694,2,0,1,2632,0,0,23971,25472,75.05,364,1746601139765449800 +0,7,0,2,0,8366,0,0,0,8199,7,0,129440,131029,79.45,365,1746601139841327100 +0,7,0,2,0,11242,7,0,1,10974,2,0,103834,105308,73.7,366,1746601139919499600 +0,7,0,2,1,13610,4,0,0,13461,5,0,78232,80073,92.05,367,1746601139997315200 +0,7,0,2,1,5483,6,0,0,5977,1,0,52628,54129,75.05,368,1746601140073263200 +0,7,0,2,0,2987,0,0,1,2307,3,0,27024,28690,83.3,369,1746601140151290800 +0,7,0,2,0,233,3,0,0,504,4,0,1421,2695,63.7,370,1746601140229249700 +0,7,0,2,0,11817,5,0,0,11914,4,0,106889,108440,77.55,371,1746601140307315800 +0,7,0,2,1,13417,4,0,0,15437,5,0,81288,82870,79.1,372,1746601140383360800 +0,7,0,2,1,5800,1,0,1,4635,2,0,55681,57491,90.5,373,1746601140461384200 +0,7,0,2,1,2536,0,0,1,2269,3,0,30080,31565,74.25,374,1746601140537427300 +0,7,0,2,0,824,6,0,0,942,7,0,4475,5722,62.35,375,1746601140615447600 +0,7,0,2,1,12152,4,0,0,11715,1,0,109944,111633,84.45,376,1746601140693258600 +0,7,0,2,1,15801,2,0,0,15663,0,0,84339,85584,62.25,377,1746601140771347300 +0,7,0,2,1,4857,0,0,0,4938,0,0,58736,60512,88.8,378,1746601140847293200 +0,7,0,2,0,6201,0,0,1,6383,7,0,33136,34218,54.1,379,1746601140925272400 +0,7,0,2,0,635,4,0,0,1611,1,0,7528,9105,78.85,380,1746601141003411600 +0,7,0,2,0,11451,4,0,0,11278,7,0,113000,114597,79.85,381,1746601141079315700 +0,7,0,2,0,16378,1,0,0,15956,6,0,87393,89284,94.55,382,1746601141157272700 +0,7,0,2,0,4410,0,0,1,4503,5,0,61792,63273,74.05,383,1746601141235294800 +0,7,0,2,1,6526,5,0,0,7167,2,0,36185,38227,102.1,384,1746601141311392000 +0,7,0,2,1,1982,4,0,1,1812,5,0,10584,12089,75.25,385,1746601141389295300 +0,7,0,2,1,9471,3,0,1,9558,5,0,116050,117977,96.35,386,1746601141467274900 +0,7,0,2,0,14911,1,0,0,14995,2,0,90449,91923,73.7,387,1746601141543272100 +0,7,0,2,0,4221,6,0,1,12360,6,0,64843,66436,79.65,388,1746601141621410400 +0,7,0,2,0,6845,5,0,1,6756,2,0,39241,40387,57.3,389,1746601141699430500 +0,7,0,2,1,1532,4,0,1,1232,6,0,13639,15108,73.45,390,1746601141775424800 +0,7,0,2,0,10044,1,0,0,10132,1,0,119105,120638,76.65,391,1746601141853370400 +0,7,0,2,0,15220,1,0,1,14672,4,0,93502,94983,74.05,392,1746601141931267900 +0,7,0,2,0,12724,5,0,1,13111,0,0,67897,69935,101.9,393,1746601142009267000 +0,7,0,2,1,7924,4,0,0,8133,7,0,42296,43978,84.1,394,1746601142085432000 +0,7,0,2,1,3125,3,0,1,3212,2,0,16690,18364,83.7,395,1746601142163270100 +0,7,0,2,1,9845,0,0,0,8900,6,0,122160,123963,90.15,396,1746601142239305500 +0,7,0,2,1,14519,6,0,0,14365,6,0,96555,98123,78.4,397,1746601142317406700 +0,7,0,2,0,13303,4,0,0,13022,5,0,70952,72537,79.25,398,1746601142395260900 +0,7,0,2,0,7478,7,0,0,7582,6,0,45349,46939,79.5,399,1746601142473425100 +0,7,0,2,0,3446,0,0,1,3959,4,0,19744,21207,73.15,400,1746601142549265500 +0,7,0,2,1,9138,3,0,0,9023,1,0,125213,126638,71.25,401,1746601142627416800 +0,7,0,2,1,10482,5,0,1,10745,2,0,99609,101004,69.75,402,1746601142705264900 +0,7,0,2,1,13874,4,0,0,14001,2,0,74008,75507,74.95,403,1746601142781344500 +0,7,0,2,0,7283,3,0,0,5155,7,0,48402,49642,62.0,404,1746601142859355200 +0,7,0,2,0,3763,0,0,0,3636,1,0,22800,24257,72.85,405,1746601142937260600 +0,7,0,2,0,8689,7,0,1,8435,6,0,128266,129771,75.25,406,1746601143013243000 +0,7,0,2,1,11057,4,0,0,10886,0,0,102664,104480,90.8,407,1746601143091379200 +0,7,0,2,1,14192,2,0,0,13634,2,0,77059,78819,88.0,408,1746601143169389100 +0,7,0,2,1,5552,0,0,0,5381,4,0,51456,53192,86.8,409,1746601143245350900 +0,7,0,2,1,2800,0,0,0,2982,7,0,25856,27098,62.1,410,1746601143323215500 +0,7,0,2,0,16,4,0,0,132,5,0,248,1990,87.1,411,1746601143401380300 +0,7,0,2,1,10833,4,0,0,11851,6,0,105719,107412,84.65,412,1746601143477353100 +0,7,0,2,1,13457,3,0,1,13370,6,0,80114,81563,72.45,413,1746601143555220500 +0,7,0,2,1,6097,0,0,1,5830,2,0,54512,56284,88.6,414,1746601143633217000 +0,7,0,2,0,2323,6,0,1,2455,6,0,28907,30507,80.0,415,1746601143711257800 +0,7,0,2,0,339,4,0,0,877,7,0,3304,4682,68.9,416,1746601143787376400 +0,7,0,2,0,12178,2,0,0,12051,2,0,108771,110355,79.2,417,1746601143865367300 +0,7,0,2,0,15570,1,0,0,15849,6,0,83169,84596,71.35,418,1746601143943217200 +0,7,0,2,1,4630,1,0,1,4778,1,0,57566,58977,70.55,419,1746601144019243600 +0,7,0,2,0,2134,5,0,0,6259,4,0,31961,33512,77.55,420,1746601144097199200 +0,7,0,2,0,662,4,0,0,616,6,0,6360,7556,59.8,421,1746601144175192700 +0,7,0,2,1,11735,1,0,0,11502,5,0,111825,113241,70.8,422,1746601144251321300 +0,7,0,2,0,16149,0,0,0,16258,0,0,86223,88032,90.45,423,1746601144329364600 +0,7,0,2,1,4949,7,0,1,4384,2,0,60618,61948,66.5,424,1746601144407309800 +0,7,0,2,0,6549,5,0,0,6446,1,0,35017,36446,71.45,425,1746601144483215600 +0,7,0,2,0,1748,3,0,1,2022,5,0,9410,10790,69.0,426,1746601144561200600 +0,7,0,2,0,9236,0,0,1,9400,4,0,114880,116359,73.95,427,1746601144639178900 +0,7,0,2,0,15964,6,0,1,15089,4,0,89275,91400,106.25,428,1746601144715332600 +0,7,0,2,0,4252,4,0,0,4145,2,0,63672,65267,79.75,429,1746601144793335900 +0,7,0,2,1,7132,4,0,1,6828,0,0,38072,39359,64.35,430,1746601144871174200 +0,7,0,2,0,1309,1,0,0,1458,0,0,12465,14048,79.15,431,1746601144947198800 +0,7,0,2,1,9567,0,0,0,10066,2,0,117935,119580,82.25,432,1746601145025169700 +0,7,0,2,1,15263,7,0,1,15161,5,0,92330,93833,75.15,433,1746601145103203700 +0,7,0,2,1,12511,4,0,1,12758,3,0,66728,68386,82.9,434,1746601145181169000 +0,7,0,2,1,7710,2,0,0,7891,6,0,41123,42219,54.8,435,1746601145257314800 +0,7,0,2,1,1118,0,0,0,3165,7,0,15520,17226,85.3,436,1746601145335200800 +0,7,0,2,0,9882,3,0,0,9839,6,0,120989,122283,64.7,437,1746601145413125200 +0,7,0,2,0,14810,5,0,1,14544,4,0,95385,97031,82.3,438,1746601145489344000 +0,7,0,2,0,13083,6,0,0,13247,3,0,69780,71341,78.05,439,1746601145567333000 +0,7,0,2,0,8027,1,0,0,7537,5,0,44177,45814,81.85,440,1746601145645431500 +0,7,0,2,0,3481,0,0,1,3383,2,0,18575,20179,80.2,441,1746601145721158200 +0,7,0,2,0,8921,5,0,0,9213,5,0,124041,125622,79.05,442,1746601145799310100 +0,7,0,2,1,10265,4,0,1,10401,4,0,98440,99848,70.4,443,1746601145877266300 +0,7,0,2,1,12888,1,0,1,13949,7,0,72833,74421,79.4,444,1746601145953318000 +0,7,0,2,0,7320,0,0,1,7217,5,0,47232,48886,82.7,445,1746601146031168700 +0,7,0,2,0,4040,2,0,0,3774,7,0,21628,22874,62.3,446,1746601146109308100 +0,7,0,2,0,8456,4,0,1,8587,1,0,127096,128913,90.85,447,1746601146185266600 +0,7,0,2,1,10569,2,0,1,11213,1,0,101491,103502,100.55,448,1746601146263318700 +0,7,0,2,0,14217,0,0,0,14106,6,0,75888,77668,89.0,449,1746601146341303300 +0,7,0,2,1,5321,0,0,0,5543,1,0,50288,51665,68.85,450,1746601146417308000 +0,7,0,2,0,2571,5,0,0,2747,6,0,24681,26260,78.95,451,1746601146495297900 +0,7,0,2,1,8266,4,0,0,85,0,0,130151,131888,86.85,452,1746601146573238800 +0,7,0,2,1,10890,3,0,1,10850,4,0,104546,105959,70.65,453,1746601146651123600 +0,7,0,2,0,13770,0,0,0,13535,6,0,78944,80724,89.0,454,1746601146727281600 +0,7,0,2,0,5902,6,0,0,6079,2,0,53339,54956,80.85,455,1746601146805292600 +0,7,0,2,0,2894,4,0,1,2408,5,0,27736,29305,78.45,456,1746601146881142400 +0,7,0,2,0,399,2,0,0,362,1,0,2131,3486,67.75,457,1746601146959125300 +0,7,0,2,0,11983,1,0,1,12264,6,0,107601,109179,78.9,458,1746601147037138600 +0,7,0,2,1,15373,3,0,0,15547,0,0,81997,83600,80.15,459,1746601147113284700 +0,7,0,2,0,5709,4,0,1,4681,3,0,56392,58253,93.05,460,1746601147191350500 +0,7,0,2,0,2188,4,0,1,2092,2,0,30791,32323,76.6,461,1746601147269132600 +0,7,0,2,0,972,1,0,1,722,5,0,5185,6937,87.6,462,1746601147347286800 +0,7,0,2,1,11532,0,0,1,11692,6,0,110656,112196,77.0,463,1746601147423239600 +0,7,0,2,1,15684,7,0,1,16229,6,0,85050,86580,76.5,464,1746601147501274900 +0,7,0,2,1,4996,4,0,1,4923,2,0,59448,61075,81.35,465,1746601147579133400 +0,7,0,2,0,6341,2,0,0,6581,2,0,33843,35123,64.0,466,1746601147655097700 +0,7,0,2,0,1541,0,0,1,1722,0,0,8240,9887,82.35,467,1746601147733129700 +0,7,0,2,0,11335,3,0,1,9258,4,0,113709,115096,69.35,468,1746601147811335700 +0,7,0,2,0,16007,5,0,1,15977,4,0,88105,89480,68.75,469,1746601147887217100 +0,7,0,2,1,4550,7,0,0,4256,7,0,62501,63994,74.65,470,1746601147965096500 +0,7,0,2,1,6918,1,0,1,7163,7,0,36897,38250,67.65,471,1746601148043117800 +0,7,0,2,1,1858,0,0,1,1405,1,0,11295,12977,84.1,472,1746601148119212800 +0,7,0,2,0,9602,5,0,0,9508,4,0,116761,118328,78.35,473,1746601148197108800 +0,7,0,2,0,15042,4,0,0,15332,7,0,91160,92730,78.5,474,1746601148275102300 +0,7,0,2,0,12291,2,0,0,12451,3,0,65555,67090,76.75,475,1746601148351221000 +0,7,0,2,1,6723,0,0,1,7762,4,0,39952,41752,90.0,476,1746601148429095200 +0,7,0,2,1,1153,1,0,0,1109,7,0,14350,15562,60.6,477,1746601148507196900 +0,7,0,2,1,10177,5,0,1,9919,3,0,119817,121170,67.65,478,1746601148585072300 +0,7,0,2,1,14592,7,0,1,14816,5,0,94213,95737,76.2,479,1746601148661098800 +0,7,0,2,0,12608,0,0,1,13163,7,0,68608,70250,82.1,480,1746601148739090400 +0,7,0,2,0,7808,1,0,0,7995,2,0,43006,44691,84.25,481,1746601148817076300 +0,7,0,2,0,3136,5,0,0,3582,4,0,17401,19111,85.5,482,1746601148893070600 +0,7,0,2,1,9728,4,0,1,8878,1,0,122872,124510,81.9,483,1746601148971071000 +0,7,0,2,1,14529,3,0,0,10343,5,0,97266,98857,79.55,484,1746601149049120300 +0,7,0,2,1,13185,0,0,1,12900,2,0,71664,73155,74.55,485,1746601149125089200 +0,7,0,2,1,7491,6,0,0,7393,7,0,46059,47626,78.35,486,1746601149203081300 +0,7,0,2,1,3331,4,0,1,4008,7,0,20456,22138,84.1,487,1746601149281210600 +0,7,0,2,0,9154,6,0,0,8488,3,0,125924,127362,71.9,488,1746601149357076100 +0,7,0,2,0,10370,1,0,0,10619,5,0,100321,101737,70.8,489,1746601149435064200 +0,7,0,2,0,13894,1,0,0,14265,7,0,74718,76149,71.55,490,1746601149513049000 +0,7,0,2,1,7174,5,0,1,5342,4,0,49113,50343,61.5,491,1746601149589050100 +0,7,0,2,1,3783,5,0,1,2673,0,0,23510,25328,90.9,492,1746601149667072100 +0,7,0,2,1,8583,1,0,1,8290,1,0,128977,130529,77.6,493,1746601149745066200 +0,7,0,2,0,11079,0,0,0,10918,7,0,103376,104922,77.3,494,1746601149821203100 +0,7,0,2,1,14085,7,0,0,13799,7,0,77770,79317,77.35,495,1746601149899206900 +0,7,0,2,0,5573,5,0,1,5939,3,0,52169,53522,67.65,496,1746601149977225700 +0,7,0,2,0,2692,2,0,1,2943,2,0,26563,27987,71.2,497,1746601150055066500 +0,7,0,2,0,68,1,0,1,480,3,0,961,2562,80.05,498,1746601150131068000 +0,7,0,2,0,10764,2,0,0,12024,2,0,106428,107900,73.6,499,1746601150209066300 +0,7,0,2,1,13516,5,0,0,15388,0,0,80825,82111,64.3,500,1746601150287217400 +0,7,0,2,1,6029,4,0,0,5695,5,0,55223,57001,88.9,501,1746601150363033100 +0,7,0,2,0,2381,1,0,1,2273,4,0,29617,31240,81.15,502,1746601150441037400 +0,7,0,2,0,269,0,0,0,979,0,0,4016,5359,67.15,503,1746601150519272000 +0,7,0,2,0,12239,5,0,1,11632,7,0,109481,111354,93.65,504,1746601150595188300 +0,7,0,2,1,15503,4,0,0,15712,6,0,83880,85499,80.95,505,1746601150673186900 +0,7,0,2,0,4686,2,0,0,5093,3,0,58275,59954,83.95,506,1746601150751153100 +0,7,0,2,0,2062,0,0,1,6369,7,0,32672,34293,81.05,507,1746601150827181200 +0,7,0,2,0,714,6,0,1,1646,3,0,7067,8797,86.5,508,1746601150905045900 +0,7,0,2,0,11658,4,0,0,11377,5,0,112536,113929,69.65,509,1746601150983034600 +0,7,0,2,0,16202,4,0,0,16018,1,0,86936,88289,67.65,510,1746601151059176800 +0,7,0,2,1,4875,1,0,1,4607,4,0,61329,62807,73.9,511,1746601151137041500 +0,7,0,2,1,6603,0,0,0,6940,3,0,35728,37053,66.25,512,1746601151215144300 +0,7,0,2,1,1673,7,0,0,1918,0,0,10122,11615,74.65,513,1746601151291020600 +0,7,0,2,1,9289,4,0,0,9631,1,0,115592,116910,65.9,514,1746601151369018700 +0,7,0,2,0,15880,2,0,0,15055,2,0,89987,91219,61.6,515,1746601151447153900 +0,7,0,2,0,4296,0,0,1,12346,3,0,64384,65890,75.3,516,1746601151523080900 +0,7,0,2,1,7064,2,0,1,6781,1,0,38780,40270,74.5,517,1746601151601046800 +0,7,0,2,1,1368,5,0,0,1169,6,0,13177,14580,70.15,518,1746601151678993400 +0,7,0,2,0,9497,5,0,0,10235,1,0,118646,120174,76.4,519,1746601151757328900 +0,7,0,2,0,15321,0,0,1,14694,2,0,93040,94755,85.75,520,1746601151833000500 +0,7,0,2,0,12443,0,0,1,12647,1,0,67439,69073,81.7,521,1746601151911154800 +0,7,0,2,1,7771,7,0,0,8160,3,0,41834,43522,84.4,522,1746601151988999600 +0,7,0,2,1,1051,4,0,1,3283,7,0,16232,17642,70.5,523,1746601152065129000 +0,7,0,2,1,9946,3,0,1,8737,2,0,121698,123379,84.05,524,1746601152143013400 +0,7,0,2,0,14746,0,0,1,14446,7,0,96096,97701,80.25,525,1746601152221040000 +0,7,0,2,0,13150,2,0,0,12933,1,0,70492,71729,61.85,526,1746601152296972600 +0,7,0,2,0,7966,5,0,0,7666,6,0,44889,46363,73.7,527,1746601152374936900 +0,7,0,2,0,3551,5,0,1,3857,7,0,19286,20725,71.95,528,1746601152452968900 +0,7,0,2,0,8863,0,0,0,9071,1,0,124752,126382,81.5,529,1746601152528972600 +0,7,0,2,0,10333,3,0,0,10674,6,0,99149,100635,74.3,530,1746601152607107400 +0,7,0,2,0,12829,4,0,0,13996,0,0,73544,75328,89.2,531,1746601152684990200 +0,7,0,2,0,7388,4,0,0,5139,0,0,47943,49391,72.4,532,1746601152760986200 +0,7,0,2,0,3996,2,0,0,3673,7,0,22339,23690,67.55,533,1746601152838987500 +0,7,0,2,0,8540,0,0,1,8328,2,0,127808,129148,67.0,534,1746601152916984100 +0,7,0,2,1,10516,7,0,1,11180,1,0,102202,104001,89.95,535,1746601152994985700 +0,7,0,2,1,14293,4,0,1,13622,6,0,76599,78116,75.85,536,1746601153071133400 +0,7,0,2,1,5269,2,0,0,5448,2,0,50995,52348,67.65,537,1746601153149246100 +0,7,0,2,0,2645,0,0,1,2998,4,0,25392,26919,76.35,538,1746601153225052100 +0,7,0,2,1,8215,2,0,0,248,1,0,130860,132478,80.9,539,1746601153303115200 +0,7,0,2,1,10967,5,0,0,11786,3,0,105257,106594,66.85,540,1746601153381138000 +0,7,0,2,0,13718,5,0,0,13416,7,0,79654,81285,81.55,541,1746601153459066500 +0,7,0,2,1,5974,1,0,1,5774,7,0,54049,55386,66.85,542,1746601153535165500 +0,7,0,2,0,2838,1,0,0,2525,0,0,28449,29872,71.15,543,1746601153613104300 +0,7,0,2,1,466,7,0,1,823,7,0,2842,4394,77.6,544,1746601153691068300 +0,7,0,2,1,11922,4,0,1,12155,0,0,108312,109935,81.15,545,1746601153766984700 +0,7,0,2,0,15443,7,0,0,15804,3,0,82709,84290,79.05,546,1746601153845062700 +0,7,0,2,0,5651,1,0,0,4831,3,0,57105,58541,71.8,547,1746601153923204100 +0,7,0,2,1,2257,2,0,1,6202,1,0,31500,33121,81.05,548,1746601153998961200 +0,7,0,2,0,913,4,0,0,571,7,0,5896,7829,96.65,549,1746601154077003200 +0,7,0,2,0,11601,4,0,0,11649,3,0,111368,112626,62.9,550,1746601154155149500 +0,7,0,2,0,15632,1,0,0,16344,0,0,85761,87168,70.35,551,1746601154230920700 +0,7,0,2,1,5104,0,0,1,4401,7,0,60159,61706,77.35,552,1746601154308940000 +0,7,0,2,0,6320,7,0,1,6469,5,0,34554,35894,67.0,553,1746601154386923100 +0,7,0,2,0,1648,5,0,0,1944,7,0,8953,10373,71.0,554,1746601154462972200 +0,7,0,2,1,11313,3,0,0,9455,6,0,114418,116139,86.05,555,1746601154540957300 +0,7,0,2,0,16113,0,0,1,14869,3,0,88816,90317,75.05,556,1746601154618915600 +0,7,0,2,0,4531,7,0,1,4190,1,0,63210,64673,73.15,557,1746601154696936200 +0,7,0,2,0,7027,4,0,0,6828,4,0,37608,39352,87.2,558,1746601154772943500 +0,7,0,2,1,1842,4,0,0,1494,2,0,12007,13532,76.25,559,1746601154851033600 +0,7,0,2,0,9714,0,0,0,10013,7,0,117472,118965,74.65,560,1746601154928918300 +0,7,0,2,0,15026,0,0,0,15182,5,0,91872,93273,70.05,561,1746601155004921000 +0,7,0,2,0,12406,5,0,1,12733,7,0,66265,67914,82.45,562,1746601155082937700 +0,7,0,2,1,6711,4,0,1,7915,2,0,40663,42387,86.2,563,1746601155161032400 +0,7,0,2,1,1271,3,0,1,3108,1,0,15058,16833,88.75,564,1746601155237025700 +0,7,0,2,1,10167,0,0,1,9814,0,0,120528,122079,77.55,565,1746601155314898000 +0,7,0,2,0,14709,6,0,0,14476,0,0,94923,96320,69.85,566,1746601155392865800 +0,7,0,2,0,12597,4,0,1,13299,2,0,69320,70931,80.55,567,1746601155468912300 +0,7,0,2,1,8180,6,0,1,7438,6,0,43716,45147,71.55,568,1746601155547026400 +0,7,0,2,1,3252,0,0,0,3455,7,0,18112,19797,84.25,569,1746601155624904300 +0,7,0,2,0,8828,0,0,0,8836,5,0,123583,124870,64.35,570,1746601155700916500 +0,7,0,2,0,14396,5,0,0,10461,4,0,97977,99511,76.7,571,1746601155779054200 +0,7,0,2,1,13053,5,0,1,13887,3,0,72374,74066,84.6,572,1746601155856918900 +0,7,0,2,1,7613,3,0,1,7245,7,0,46770,48202,71.6,573,1746601155932914500 +0,7,0,2,1,3965,0,0,1,3969,1,0,21168,22513,67.25,574,1746601156010892100 +0,7,0,2,0,9023,7,0,0,8608,2,0,126634,128515,94.05,575,1746601156088939600 +0,7,0,2,0,10751,4,0,0,10549,3,0,101032,102093,53.05,576,1746601156166993300 +0,7,0,2,0,14014,3,0,0,14150,4,0,75426,76839,70.65,577,1746601156243023300 +0,7,0,2,0,5246,0,0,0,5525,5,0,49824,51401,78.85,578,1746601156320870800 +0,7,0,2,0,3642,3,0,0,2761,1,0,24221,25713,74.6,579,1746601156396958000 +0,7,0,2,1,8442,5,0,0,8206,3,0,129689,130978,64.45,580,1746601156474897400 +0,7,0,2,0,11195,4,0,1,10876,1,0,104087,105793,85.3,581,1746601156552991500 +0,7,0,2,1,13691,3,0,0,13716,5,0,78482,79673,59.55,582,1746601156630991800 +0,7,0,2,1,5435,0,0,1,6138,1,0,52880,54625,87.25,583,1746601156706872800 +0,7,0,2,0,3065,6,0,1,2846,4,0,27275,28504,61.45,584,1746601156784876200 +0,7,0,2,1,185,4,0,0,378,3,0,1672,3426,87.7,585,1746601156863015800 +0,7,0,2,0,11896,2,0,0,11909,2,0,107139,108492,67.65,586,1746601156938881800 +0,7,0,2,0,13368,0,0,1,15577,2,0,81536,83084,77.4,587,1746601157016866500 +0,7,0,2,1,5864,6,0,0,4628,0,0,55931,57536,80.25,588,1746601157095019900 +0,7,0,2,0,2472,5,0,0,2115,1,0,30329,31761,71.6,589,1746601157170930700 +0,7,0,2,1,872,4,0,0,656,7,0,4728,6394,83.3,590,1746601157248964800 +0,7,0,2,0,12073,1,0,0,11731,2,0,110193,111852,82.95,591,1746601157326847500 +0,7,0,2,1,15849,0,0,0,16158,5,0,84592,86182,79.5,592,1746601157403138300 +0,7,0,2,1,4779,7,0,1,4953,2,0,58986,60556,78.5,593,1746601157481000500 +0,7,0,2,1,6251,4,0,0,6555,1,0,33384,34961,78.85,594,1746601157558962100 +0,7,0,2,0,554,3,0,0,1754,2,0,7778,9372,79.7,595,1746601157634970100 +0,7,0,2,1,11498,0,0,0,9232,3,0,113248,114941,84.65,596,1746601157713020900 +0,7,0,2,0,16302,7,0,0,15951,1,0,87642,89169,76.35,597,1746601157791011800 +0,7,0,2,0,4462,4,0,0,4488,7,0,62040,63365,66.25,598,1746601157868790600 +0,7,0,2,0,6447,5,0,1,7038,1,0,36438,37537,54.95,599,1746601157944842000 +0,7,0,2,0,2031,1,0,1,1334,2,0,10833,12579,87.3,600,1746601158022833600 +0,7,0,2,1,9391,0,0,1,9692,1,0,116304,117569,63.25,601,1746601158100830900 +0,7,0,2,1,14957,5,0,0,15294,4,0,90697,92504,90.35,602,1746601158176844500 +0,7,0,2,1,4140,4,0,1,12509,4,0,65095,66743,82.4,603,1746601158254842400 +0,7,0,2,1,6892,1,0,1,7682,6,0,39489,40987,74.9,604,1746601158332939500 +0,7,0,2,1,1444,0,0,0,1105,1,0,13887,15601,85.7,605,1746601158408841100 +0,7,0,2,0,10084,7,0,1,10134,2,0,119354,120611,62.85,606,1746601158486836100 +0,7,0,2,0,15140,4,0,1,14661,4,0,93752,95176,71.2,607,1746601158564992100 +0,7,0,2,1,12773,2,0,1,13081,0,0,68147,69775,81.4,608,1746601158640943300 +0,7,0,2,0,7845,1,0,0,8134,5,0,42545,43993,72.4,609,1746601158718843100 +0,7,0,2,0,3175,2,0,0,3460,2,0,16940,18492,77.6,610,1746601158796995900 +0,7,0,2,0,9767,5,0,1,8951,7,0,122409,124202,89.65,611,1746601158872980000 +0,7,0,2,1,14567,4,0,1,10241,3,0,96808,98317,75.45,612,1746601158950971100 +0,7,0,2,1,13222,1,0,1,12871,6,0,71201,72747,77.3,613,1746601159028952300 +0,7,0,2,1,7526,0,0,0,7575,0,0,45600,46895,64.75,614,1746601159104818600 +0,7,0,2,0,3362,7,0,1,3919,3,0,19994,21421,71.35,615,1746601159182974000 +0,7,0,2,0,9186,4,0,1,8991,0,0,125464,126800,66.8,616,1746601159260904700 +0,7,0,2,0,10403,3,0,0,10582,2,0,99858,101596,86.9,617,1746601159336954100 +0,7,0,2,0,13923,1,0,0,13967,6,0,74257,75691,71.7,618,1746601159414960500 +0,7,0,2,0,7201,3,0,0,5192,5,0,48653,50054,70.05,619,1746601159492968900 +0,7,0,2,0,3809,4,0,1,2571,6,0,23048,24683,81.75,620,1746601159568914100 +0,7,0,2,0,8608,4,0,0,8260,1,0,128519,130110,79.55,621,1746601159646920000 +0,7,0,2,0,11104,0,0,0,10896,3,0,102912,104701,89.45,622,1746601159724817400 +0,7,0,2,1,14176,0,0,0,13777,5,0,77311,79094,89.15,623,1746601159802823300 +0,7,0,2,0,5536,6,0,1,5399,1,0,51707,53038,66.55,624,1746601159878886800 +0,7,0,2,1,2784,4,0,0,2911,3,0,26104,27821,85.85,625,1746601159954756000 +0,7,0,2,1,33,3,0,1,400,3,0,498,2301,90.15,626,1746601160034769900 +0,7,0,2,0,10849,1,0,0,11884,6,0,105969,107076,55.35,627,1746601160110912300 +0,7,0,2,1,13475,6,0,1,13318,2,0,80363,81884,76.05,628,1746601160188790700 +0,7,0,2,0,6115,4,0,1,5839,2,0,54760,56236,73.8,629,1746601160266975100 +0,7,0,2,1,2338,4,0,1,2196,2,0,29159,30915,87.8,630,1746601160342769200 +0,7,0,2,0,354,1,0,1,966,2,0,3553,5155,80.1,631,1746601160420783600 +0,7,0,2,0,12198,0,0,0,12056,6,0,109023,110459,71.8,632,1746601160498766300 +0,7,0,2,1,15590,5,0,0,15813,7,0,83417,84938,76.05,633,1746601160574764800 +0,7,0,2,1,4646,4,0,0,4997,2,0,57816,59443,81.35,634,1746601160652882500 +0,7,0,2,0,2151,2,0,0,6264,2,0,32211,33411,60.0,635,1746601160730770300 +0,7,0,2,0,679,0,0,1,525,7,0,6608,8117,75.45,636,1746601160806799800 +0,7,0,2,0,11749,6,0,0,11330,0,0,112075,113695,81.0,637,1746601160885054400 +0,7,0,2,0,16165,5,0,1,16269,2,0,86473,87987,75.7,638,1746601160962791200 +0,7,0,2,1,4964,7,0,1,4422,1,0,60869,62430,78.05,639,1746601161038914300 +0,7,0,2,0,6564,0,0,0,6412,3,0,35264,36797,76.65,640,1746601161116774400 +0,7,0,2,0,1772,0,0,0,1887,4,0,9663,11432,88.45,641,1746601161194959800 +0,7,0,2,1,9260,7,0,0,9357,7,0,115130,116661,76.55,642,1746601161270920600 +0,7,0,2,1,15980,4,0,1,14930,5,0,89528,90905,68.85,643,1746601161348847800 +0,7,0,2,1,4269,1,0,0,12291,7,0,63921,65557,81.8,644,1746601161426758400 +0,7,0,2,1,7151,0,0,0,6725,6,0,38319,39988,83.45,645,1746601161504857600 +0,7,0,2,0,1327,6,0,0,1454,2,0,12715,13916,60.05,646,1746601161580904000 +0,7,0,2,0,9583,5,0,0,10065,7,0,118185,119562,68.85,647,1746601161658904700 +0,7,0,2,0,15278,6,0,1,15157,1,0,92580,93902,66.1,648,1746601161736742300 +0,7,0,2,1,12526,1,0,1,12759,4,0,66977,68392,70.75,649,1746601161812885900 +0,7,0,2,1,7726,0,0,0,7822,3,0,41376,42914,76.9,650,1746601161890845000 +0,7,0,2,0,1130,5,0,0,3146,4,0,15769,17304,76.75,651,1746601161968878500 +0,7,0,2,1,9899,4,0,0,8707,7,0,121239,122901,83.1,652,1746601162044854600 +0,7,0,2,1,14827,1,0,1,14581,5,0,95633,96969,66.8,653,1746601162122840900 +0,7,0,2,0,13099,0,0,1,13195,5,0,70032,71574,77.1,654,1746601162200718600 +0,7,0,2,1,8041,7,0,1,7625,7,0,44426,46197,88.55,655,1746601162276726600 +0,7,0,2,0,3497,4,0,1,3357,6,0,18824,20299,73.75,656,1746601162354749600 +0,7,0,2,0,8936,2,0,1,9160,1,0,124291,125825,76.7,657,1746601162432723500 +0,7,0,2,0,10280,1,0,0,10431,7,0,98689,100010,66.05,658,1746601162510739200 +0,7,0,2,1,12920,2,0,1,13893,0,0,73084,74703,80.95,659,1746601162586775900 +0,7,0,2,0,7352,5,0,1,7195,2,0,47481,49004,76.15,660,1746601162664976700 +0,7,0,2,0,4089,5,0,0,3807,7,0,21878,23381,75.15,661,1746601162742701100 +0,7,0,2,0,8505,1,0,0,8631,3,0,127345,128722,68.85,662,1746601162818727000 +0,7,0,2,1,10617,0,0,1,11076,7,0,101744,103365,81.05,663,1746601162896709400 +0,7,0,2,1,14267,7,0,1,13621,1,0,76138,78129,99.55,664,1746601162974700200 +0,7,0,2,0,5371,4,0,0,5611,4,0,50536,51816,64.0,665,1746601163050697200 +0,7,0,2,1,2618,2,0,0,2716,1,0,24931,26433,75.1,666,1746601163128705700 +0,7,0,2,0,8314,1,0,0,92,3,0,130401,131906,75.25,667,1746601163206956600 +0,7,0,2,1,10942,2,0,1,10761,7,0,104796,106378,79.1,668,1746601163282697700 +0,7,0,2,0,13822,4,0,0,13507,5,0,79192,80873,84.05,669,1746601163360694400 +0,7,0,2,1,5951,5,0,0,6028,5,0,53590,55225,81.75,670,1746601163438849700 +0,7,0,2,0,2943,1,0,0,2418,4,0,27985,29415,71.5,671,1746601163514696100 +0,7,0,2,0,447,0,0,1,302,4,0,2384,3672,64.4,672,1746601163592717100 +0,7,0,2,1,12029,5,0,1,12238,5,0,107849,109478,81.45,673,1746601163670895400 +0,7,0,2,0,15421,4,0,1,15505,6,0,82248,83723,73.75,674,1746601163746819400 +0,7,0,2,0,5756,2,0,1,4707,5,0,56643,57878,61.75,675,1746601163824679700 +0,7,0,2,1,2236,0,0,0,6144,1,0,31040,32769,86.45,676,1746601163902903200 +0,7,0,2,0,1012,7,0,1,750,3,0,5434,6749,65.75,677,1746601163978674300 +0,7,0,2,0,11572,4,0,1,11397,1,0,110904,112689,89.25,678,1746601164056670900 +0,7,0,2,0,15733,4,0,1,16251,0,0,85303,86672,68.45,679,1746601164134822400 +0,7,0,2,0,5045,0,0,1,4917,7,0,59696,61130,71.7,680,1746601164210688800 +0,7,0,2,1,6391,0,0,0,6635,5,0,34095,35433,66.9,681,1746601164288671100 +0,7,0,2,0,1591,5,0,0,1684,4,0,8489,10040,77.55,682,1746601164366823800 +0,7,0,2,1,11382,4,0,1,9411,2,0,113959,115731,88.6,683,1746601164444669800 +0,7,0,2,1,16054,1,0,1,15926,3,0,88353,89821,73.4,684,1746601164520892800 +0,7,0,2,0,4598,0,0,0,4306,4,0,62752,64280,76.4,685,1746601164598804500 +0,7,0,2,1,6962,6,0,0,7077,4,0,37147,38455,65.4,686,1746601164676651400 +0,7,0,2,0,1906,5,0,1,1332,0,0,11545,12607,53.1,687,1746601164752665200 +0,7,0,2,1,9651,2,0,0,9509,1,0,117011,118321,65.5,688,1746601164830644500 +0,7,0,2,0,15091,1,0,0,15351,3,0,91409,92882,73.65,689,1746601164908755800 +0,7,0,2,0,12337,0,0,0,12439,1,0,65807,67374,78.35,690,1746601164984646300 +0,7,0,2,0,6769,5,0,1,7762,7,0,40201,41754,77.65,691,1746601165062650800 +0,7,0,2,0,1201,4,0,1,1076,2,0,14600,16067,73.35,692,1746601165140652900 +0,7,0,2,0,10224,3,0,1,9902,4,0,120066,121255,59.45,693,1746601165216660000 +0,7,0,2,1,14640,0,0,0,14750,0,0,94464,96095,81.55,694,1746601165294662100 +0,7,0,2,1,12624,7,0,0,13181,1,0,68858,70321,73.15,695,1746601165372644000 +0,7,0,2,0,8080,4,0,0,7989,4,0,43256,44744,74.4,696,1746601165448646500 +0,7,0,2,0,3281,3,0,0,3540,1,0,17650,19262,80.6,697,1746601165526650000 +0,7,0,2,0,8721,0,0,0,8856,2,0,123120,124796,83.8,698,1746601165604627600 +0,7,0,2,0,14417,0,0,0,10292,0,0,97520,98623,55.15,699,1746601165682627900 +0,7,0,2,0,12947,4,0,0,12826,3,0,71912,73570,82.9,700,1746601165758626100 +0,7,0,2,1,7634,4,0,0,7389,7,0,46311,47946,81.75,701,1746601165836679700 +0,7,0,2,1,3858,1,0,0,3984,4,0,20705,22279,78.7,702,1746601165914604100 +0,7,0,2,0,9046,0,0,0,8521,5,0,126175,127881,85.3,703,1746601165990623300 +0,7,0,2,1,10646,7,0,1,10504,2,0,100570,102275,85.25,704,1746601166068623100 +0,7,0,2,0,14038,4,0,0,14248,0,0,74968,76160,59.6,705,1746601166146625400 +0,7,0,2,0,5143,2,0,0,5267,1,0,49363,50961,79.9,706,1746601166222625800 +0,7,0,2,0,3671,1,0,1,2671,7,0,23761,25173,70.6,707,1746601166300626300 +0,7,0,2,0,8341,1,0,1,8235,1,0,129230,130670,72.0,708,1746601166378649900 +0,7,0,2,0,11221,5,0,0,11006,5,0,103625,105126,75.05,709,1746601166454642100 +0,7,0,2,1,13589,4,0,0,13820,1,0,78024,79169,57.25,710,1746601166532586800 +0,7,0,2,0,5460,1,0,1,5960,3,0,52417,54146,86.45,711,1746601166610545400 +0,7,0,2,1,2964,0,0,1,2834,2,0,26816,28444,81.4,712,1746601166686600100 +0,7,0,2,0,220,5,0,0,349,4,0,1209,3255,102.3,713,1746601166764597900 +0,7,0,2,0,11804,5,0,0,11985,4,0,106681,107767,54.3,714,1746601166842752600 +0,7,0,2,1,13405,3,0,1,15394,7,0,81074,82405,66.55,715,1746601166918603200 +0,7,0,2,1,5789,0,0,0,5651,5,0,55472,57110,81.9,716,1746601166996596100 +0,7,0,2,1,2527,6,0,1,2295,1,0,29867,31441,78.7,717,1746601167074743300 +0,7,0,2,0,799,4,0,0,949,2,0,4264,5836,78.6,718,1746601167150749200 +0,7,0,2,1,12126,7,0,0,11603,5,0,109733,111382,82.45,719,1746601167228812600 +0,7,0,2,0,15774,1,0,1,15672,6,0,84129,85636,75.35,720,1746601167306600300 +0,7,0,2,1,4830,0,0,0,5099,5,0,58528,60009,74.05,721,1746601167382713300 +0,7,0,2,0,6170,5,0,1,6281,3,0,32921,34701,89.0,722,1746601167460577200 +0,7,0,2,1,602,4,0,0,1623,6,0,7320,9003,84.15,723,1746601167538550700 +0,7,0,2,0,11419,3,0,0,11385,3,0,112786,114034,62.4,724,1746601167616583000 +0,7,0,2,1,16347,0,0,0,16086,3,0,87184,88866,84.1,725,1746601167692710400 +0,7,0,2,0,4377,6,0,0,4590,7,0,61579,62885,65.3,726,1746601167770583700 +0,7,0,2,0,6489,4,0,0,7007,3,0,35976,37714,86.9,727,1746601167848582900 +0,7,0,2,1,1944,6,0,1,1833,3,0,10372,11890,75.9,728,1746601167924574500 +0,7,0,2,1,9432,0,0,0,9693,6,0,115840,117579,86.95,729,1746601168002576800 +0,7,0,2,0,14856,0,0,1,14993,2,0,90239,91916,83.85,730,1746601168080575100 +0,7,0,2,0,4168,5,0,0,12324,6,0,64633,65988,67.75,731,1746601168156592200 +0,7,0,2,0,6792,5,0,0,6765,1,0,39033,40369,66.8,732,1746601168234569500 +0,7,0,2,1,1481,1,0,1,1259,1,0,13425,14958,76.65,733,1746601168312592800 +0,7,0,2,0,9993,1,0,1,10228,6,0,118897,120123,61.3,734,1746601168388550400 +0,7,0,2,1,15179,6,0,0,14624,2,0,93291,94716,71.25,735,1746601168466554200 +0,7,0,2,0,12683,4,0,0,12584,3,0,67688,69245,77.85,736,1746601168548515400 +0,7,0,2,0,7882,2,0,0,8104,1,0,42083,43393,65.5,737,1746601168620564500 +0,7,0,2,0,3082,1,0,0,3311,6,0,16481,17835,67.7,738,1746601168698618700 +0,7,0,2,1,9806,1,0,1,8829,4,0,121950,123575,81.25,739,1746601168776554000 +0,7,0,2,0,14478,5,0,0,14461,0,0,96345,97615,63.5,740,1746601168854542500 +0,7,0,2,1,13262,4,0,1,13036,2,0,70744,72259,75.75,741,1746601168930550800 +0,7,0,2,1,7439,3,0,0,7658,0,0,45138,46495,67.85,742,1746601169008544600 +0,7,0,2,1,3407,0,0,0,3956,5,0,19536,21190,82.7,743,1746601169086545800 +0,7,0,2,0,9101,7,0,0,9002,0,0,125002,126560,77.9,744,1746601169162570500 +0,7,0,2,1,10445,4,0,0,10707,1,0,99400,101137,86.85,745,1746601169240675100 +0,7,0,2,0,13836,2,0,0,13995,5,0,73795,75369,78.7,746,1746601169318563700 +0,7,0,2,0,7244,0,0,0,5210,1,0,48192,50017,91.25,747,1746601169394533000 +0,7,0,2,0,3716,6,0,0,3612,6,0,22587,24388,90.05,748,1746601169472526000 +0,7,0,2,0,8644,5,0,0,8442,2,0,128057,129692,81.75,749,1746601169550525000 +0,7,0,2,1,11013,4,0,1,11245,1,0,102455,103857,70.1,750,1746601169626657100 +0,7,0,2,0,14149,1,0,0,13688,0,0,76849,78464,80.75,751,1746601169704692200 +0,7,0,2,0,5511,0,0,1,5472,7,0,51247,52730,74.15,752,1746601169782555100 +0,7,0,2,1,2759,5,0,1,2985,5,0,25641,27017,68.8,753,1746601169858531700 +0,7,0,2,1,7,4,0,1,172,3,0,40,1602,78.1,754,1746601169936531300 +0,7,0,2,0,10822,2,0,0,11884,7,0,105507,107077,78.5,755,1746601170014524400 +0,7,0,2,1,13446,0,0,0,13359,2,0,79904,81491,79.35,756,1746601170090545800 +0,7,0,2,1,6082,2,0,1,5796,2,0,54300,55747,72.35,757,1746601170168560000 +0,7,0,2,0,2306,4,0,0,2479,1,0,28696,30289,79.65,758,1746601170246523300 +0,7,0,2,1,323,7,0,0,880,7,0,3093,4858,88.25,759,1746601170324501200 +0,7,0,2,0,12163,1,0,1,12092,5,0,108561,110265,85.2,760,1746601170400667100 +0,7,0,2,1,15555,0,0,1,15803,2,0,82960,84332,68.6,761,1746601170478498100 +0,7,0,2,1,4609,5,0,0,4859,0,0,57353,58735,69.1,762,1746601170556499800 +0,7,0,2,0,2113,4,0,0,6204,0,0,31752,33088,66.8,763,1746601170632500900 +0,7,0,2,1,640,1,0,1,575,4,0,6145,7848,85.15,764,1746601170710524400 +0,7,0,2,0,11712,0,0,1,11432,7,0,111616,113029,70.65,765,1746601170788520700 +0,7,0,2,1,15616,6,0,1,16359,3,0,86011,87506,74.75,766,1746601170864533000 +0,7,0,2,0,5056,4,0,1,4424,1,0,60408,62337,96.45,767,1746601170942537800 +0,7,0,2,0,6273,7,0,1,6490,3,0,34805,35997,59.6,768,1746601171020508700 +0,7,0,2,0,1601,0,0,1,2024,3,0,9200,10877,83.85,769,1746601171096570000 +0,7,0,2,1,11267,3,0,1,9464,5,0,114669,116089,71.0,770,1746601171174478900 +0,7,0,2,0,16067,5,0,0,14865,7,0,89065,90357,64.6,771,1746601171252617600 +0,7,0,2,0,4482,4,0,1,4158,6,0,63463,65188,86.25,772,1746601171328494100 +0,7,0,2,1,6978,1,0,0,6887,7,0,37857,39466,80.45,773,1746601171406502100 +0,7,0,2,1,1794,0,0,0,1435,1,0,12256,14190,96.7,774,1746601171484470900 +0,7,0,2,0,9670,7,0,1,10105,0,0,117722,119439,85.85,775,1746601171560475000 diff --git a/tests/data/20250507_085829/config_v4_none_20250507_085829.yml b/tests/data/20250507_085829/config_v4_none_20250507_085829.yml new file mode 100644 index 0000000..2026d80 --- /dev/null +++ b/tests/data/20250507_085829/config_v4_none_20250507_085829.yml @@ -0,0 +1,201 @@ +astropix4: + telescope: + nchips: 1 + geometry: + cols: 16 + rows: 35 + config: + digitalconfig: + interrupt_pushpull: + - 1 + - 0 + clkmux: + - 1 + - 0 + timerend: + - 4 + - 0 + slowdownldpix: + - 4 + - 0 + slowdownldcol: + - 5 + - 0 + maxcyc: + - 6 + - 63 + resetckdiv: + - 4 + - 15 + nu1: + - 32 + - 0 + tdacmux: + - 1 + - 0 + Reset: + - 1 + - 0 + PCH: + - 1 + - 0 + enRamPCH: + - 1 + - 1 + nu2: + - 5 + - 0 + enLVDSterm: + - 1 + - 1 + enPLL: + - 1 + - 1 + enLVDS: + - 1 + - 0 + nu3: + - 5 + - 0 + biasconfig: + DisHiDR: + - 1 + - 0 + q01: + - 1 + - 0 + qon0: + - 1 + - 0 + qon1: + - 1 + - 1 + qon2: + - 1 + - 0 + qon3: + - 1 + - 1 + idacs: + blres: + - 6 + - 0 + vpdac: + - 6 + - 0 + vn1: + - 6 + - 20 + vnfb: + - 6 + - 1 + vnfoll: + - 6 + - 2 + nu5: + - 6 + - 0 + vndel: + - 6 + - 30 + incp: + - 6 + - 10 + ipvco: + - 6 + - 0 + vn2: + - 6 + - 0 + vnfoll2: + - 6 + - 1 + vnbias: + - 6 + - 10 + vpload: + - 6 + - 5 + nu13: + - 6 + - 0 + vncomp: + - 6 + - 2 + vpfoll: + - 6 + - 10 + nu16: + - 6 + - 0 + vprec: + - 6 + - 10 + vnrec: + - 6 + - 10 + vdacs: + blpix: + - 10 + - 568 + thpix: + - 10 + - 610 + vcasc2: + - 10 + - 625 + vtest: + - 10 + - 682 + vinj: + - 10 + - 170 + recconfig: + col0: + - 38 + - 68719476735 + col1: + - 38 + - 68719476734 + col2: + - 38 + - 274877906940 + col3: + - 38 + - 68719476734 + col4: + - 38 + - 68719476734 + col5: + - 38 + - 68719476734 + col6: + - 38 + - 68719476734 + col7: + - 38 + - 68719476734 + col8: + - 38 + - 68719476734 + col9: + - 38 + - 68719476734 + col10: + - 38 + - 68719476734 + col11: + - 38 + - 68719476734 + col12: + - 38 + - 68719476734 + col13: + - 38 + - 68719476734 + col14: + - 38 + - 68719476734 + col15: + - 38 + - 68719476734 From 2efbf4843ecc53083126e4aa5cde4f70ba155c72 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 7 May 2025 10:30:22 +0200 Subject: [PATCH 41/51] Obsolete files removed, --- tests/data/20250205_094324_data.apx | Bin 16846 -> 0 bytes tests/data/20250205_094324_data.csv | 776 ---------------------------- 2 files changed, 776 deletions(-) delete mode 100644 tests/data/20250205_094324_data.apx delete mode 100644 tests/data/20250205_094324_data.csv diff --git a/tests/data/20250205_094324_data.apx b/tests/data/20250205_094324_data.apx deleted file mode 100644 index 7f50369999ea3b868c134a281882d5b95149a48b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16846 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 diff --git a/tests/data/20250205_094324_data.csv b/tests/data/20250205_094324_data.csv deleted file mode 100644 index 426d56a..0000000 --- a/tests/data/20250205_094324_data.csv +++ /dev/null @@ -1,776 +0,0 @@ -# chip_id,payload,row,column,ts_neg1,ts_coarse1,ts_fine1,ts_tdc1,ts_neg2,ts_coarse2,ts_fine2,ts_tdc2,ts_dec1,ts_dec2,tot_us,trigger_id,timestamp -0,7,0,2,1,13862,3,0,0,14327,1,0,74205,76497,114.6,1,1738745007402289500 -0,7,0,2,1,7270,6,0,1,5283,5,0,48603,50710,105.35,2,1738745007480410400 -0,7,0,2,1,3751,5,0,0,2607,7,0,22998,25002,100.2,3,1738745007556312800 -0,7,0,2,0,8679,7,0,0,8230,7,0,128469,130597,106.4,4,1738745007634288600 -0,7,0,2,0,11045,0,0,0,10987,4,0,102863,105064,110.05,5,1738745007712398800 -0,7,0,2,0,14181,3,0,1,13804,4,0,77261,79288,101.35,6,1738745007788344100 -0,7,0,2,0,5541,4,0,0,5931,0,0,51656,53648,99.6,7,1738745007866403700 -0,7,0,2,0,2788,7,0,0,2818,0,0,26053,28640,129.35,8,1738745007944341900 -0,7,0,2,0,36,1,0,0,492,4,0,449,2631,109.1,9,1738745008020266700 -0,7,0,2,1,10860,3,0,0,11946,6,0,105917,108132,110.75,10,1738745008098440200 -0,7,0,2,0,13484,3,0,1,15377,1,0,80317,82161,92.2,11,1738745008176276900 -0,7,0,2,0,6125,5,0,1,5712,2,0,54710,56572,93.1,12,1738745008252412900 -0,7,0,2,1,2349,6,0,0,2274,5,0,29108,31257,107.45,13,1738745008330370200 -0,7,0,2,0,367,0,0,0,930,5,0,3503,5657,107.7,14,1738745008408258200 -0,7,0,2,0,12207,2,0,0,11572,7,0,108972,110906,96.7,15,1738745008486392800 -0,7,0,2,1,15599,4,0,1,15652,1,0,83368,85566,109.9,16,1738745008562271600 -0,7,0,2,0,4654,6,0,1,5095,4,0,57764,59944,109.0,17,1738745008640265500 -0,7,0,2,0,2158,1,0,1,6319,3,0,32161,34386,111.25,18,1738745008718210200 -0,7,0,2,1,682,3,0,0,1663,3,0,6557,8877,116.0,19,1738745008794202200 -0,7,0,2,1,11754,7,0,0,11297,6,0,112026,114187,108.05,20,1738745008872288300 -0,7,0,2,1,16171,7,0,0,16045,4,0,86421,88503,104.1,21,1738745008950222200 -0,7,0,2,1,4971,6,0,0,4579,1,0,60820,62958,106.9,22,1738745009026369900 -0,7,0,2,1,6569,1,0,1,7017,5,0,35214,37494,114.0,23,1738745009104294500 -0,7,0,2,1,1769,3,0,1,1865,2,0,9613,11379,88.3,24,1738745009182210800 -0,7,0,2,0,9256,4,0,0,9631,4,0,115079,116904,91.25,25,1738745009258248600 -0,7,0,2,1,15976,7,0,1,15060,7,0,89477,91333,92.8,26,1738745009336317300 -0,7,0,2,1,4264,0,0,1,12384,2,0,63872,66051,108.95,27,1738745009414180200 -0,7,0,2,1,7160,3,0,0,6756,0,0,38269,40384,105.75,28,1738745009490209600 -0,7,0,2,1,1336,5,0,0,1207,0,0,12665,14639,98.7,29,1738745009568235600 -0,7,0,2,0,9593,7,0,1,10130,0,0,118133,120607,123.7,30,1738745009646227000 -0,7,0,2,1,15289,2,0,0,14703,4,0,92531,94807,113.8,31,1738745009722253100 -0,7,0,2,1,12539,3,0,0,12627,0,0,66925,68847,96.1,32,1738745009800416100 -0,7,0,2,1,7739,2,0,1,8161,5,0,41324,43529,110.25,33,1738745009878349800 -0,7,0,2,0,1146,5,0,1,3299,1,0,15718,17902,109.2,34,1738745009956246900 -0,7,0,2,0,9914,7,0,0,8756,0,0,121189,123199,100.5,35,1738745010032246800 -0,7,0,2,1,14842,0,0,0,14450,5,0,95584,97561,98.85,36,1738745010110233600 -0,7,0,2,0,13118,3,0,1,13028,3,0,69981,72253,113.6,37,1738745010186248700 -0,7,0,2,0,8062,7,0,1,7625,2,0,44378,46195,90.85,38,1738745010264226700 -0,7,0,2,1,3519,7,0,0,3840,5,0,18773,20486,85.65,39,1738745010342217700 -0,7,0,2,1,8959,3,0,0,9081,4,0,124242,126327,104.25,40,1738745010420225600 -0,7,0,2,1,10301,3,0,1,10664,4,0,98637,100743,105.3,41,1738745010496213200 -0,7,0,2,0,12925,2,0,0,14065,4,0,73036,75016,99.0,42,1738745010574399200 -0,7,0,2,0,7356,5,0,0,5158,4,0,47430,49624,109.7,43,1738745010652221800 -0,7,0,2,0,4092,7,0,1,3674,2,0,21829,23708,93.95,44,1738745010728227700 -0,7,0,2,0,8500,0,0,1,8420,1,0,127295,129598,115.15,45,1738745010806224200 -0,7,0,2,0,10612,2,0,1,11194,3,0,101692,104093,120.05,46,1738745010884340900 -0,7,0,2,0,14260,5,0,0,13581,5,0,76089,77897,90.4,47,1738745010960329000 -0,7,0,2,0,5365,7,0,0,5480,1,0,50485,52609,106.2,48,1738745011038358300 -0,7,0,2,0,2613,1,0,0,3005,3,0,24881,26957,103.8,49,1738745011116366000 -0,7,0,2,1,8311,3,0,1,228,5,0,130349,132550,110.05,50,1738745011192183400 -0,7,0,2,1,10935,6,0,1,11832,7,0,104747,106874,106.35,51,1738745011270197500 -0,7,0,2,1,13814,5,0,1,13415,1,0,79142,81361,110.95,52,1738745011348179700 -0,7,0,2,0,5942,7,0,1,5800,6,0,53541,55684,107.15,53,1738745011426180800 -0,7,0,2,0,2930,1,0,0,2533,1,0,27934,30158,111.2,54,1738745011502335300 -0,7,0,2,0,434,3,0,0,791,4,0,2333,4311,98.9,55,1738745011580175400 -0,7,0,2,1,12019,4,0,1,12151,0,0,107799,109871,103.6,56,1738745011658185600 -0,7,0,2,0,15411,7,0,1,15799,4,0,82197,84264,103.35,57,1738745011734201500 -0,7,0,2,0,5747,0,0,0,4796,6,0,56592,59067,123.75,58,1738745011812195500 -0,7,0,2,0,2225,3,0,0,6251,4,0,30989,33384,119.75,59,1738745011890315100 -0,7,0,2,1,1009,7,0,1,602,3,0,5386,7325,96.95,60,1738745011966189400 -0,7,0,2,1,11568,5,0,1,11452,0,0,110854,112960,105.3,61,1738745012044178500 -0,7,0,2,1,15728,6,0,0,16335,5,0,85252,87126,93.7,62,1738745012122181400 -0,7,0,2,1,5008,1,0,1,4453,3,0,59646,62002,117.8,63,1738745012198238400 -0,7,0,2,0,6352,2,0,1,6499,4,0,34044,36328,114.2,64,1738745012276158200 -0,7,0,2,0,1553,4,0,0,1947,1,0,8439,10385,97.3,65,1738745012354155000 -0,7,0,2,0,11345,6,0,1,9462,7,0,113908,116005,104.85,66,1738745012430161800 -0,7,0,2,0,16017,1,0,0,14858,6,0,88305,90212,95.35,67,1738745012508157400 -0,7,0,2,1,4563,3,0,0,4175,7,0,62701,64597,94.8,68,1738745012586168100 -0,7,0,2,1,6931,2,0,0,6806,0,0,37100,39135,101.75,69,1738745012662155200 -0,7,0,2,1,1874,7,0,1,1532,2,0,11493,13635,107.1,70,1738745012740154000 -0,7,0,2,1,9618,2,0,0,9988,0,0,116963,118847,94.2,71,1738745012818161000 -0,7,0,2,1,15062,1,0,1,15202,6,0,91358,93668,115.5,72,1738745012894286600 -0,7,0,2,1,12310,2,0,0,12690,3,0,65756,67810,102.7,73,1738745012972165600 -0,7,0,2,0,6743,4,0,1,7890,2,0,40151,42211,103.0,74,1738745013050214700 -0,7,0,2,0,1175,6,0,0,3082,4,0,14548,16487,96.95,75,1738745013126262000 -0,7,0,2,1,10197,0,0,0,9845,4,0,120015,122167,107.6,76,1738745013204141900 -0,7,0,2,1,14613,3,0,1,14570,6,0,94413,96868,122.75,77,1738745013282132900 -0,7,0,2,1,12629,4,0,1,13289,4,0,68808,71048,112.0,78,1738745013360143000 -0,7,0,2,1,8084,7,0,0,7534,0,0,43205,45663,122.9,79,1738745013436155100 -0,7,0,2,0,3284,1,0,1,3402,4,0,17601,19559,97.9,80,1738745013514134300 -0,7,0,2,1,8732,3,0,0,9119,4,0,123069,125096,101.35,81,1738745013592151400 -0,7,0,2,0,14428,2,0,0,10312,4,0,97468,99207,86.95,82,1738745013668150400 -0,7,0,2,1,12957,7,0,0,13868,7,0,71861,74170,115.45,83,1738745013746153800 -0,7,0,2,0,7645,7,0,0,7247,4,0,46261,48215,97.7,84,1738745013824143100 -0,7,0,2,1,3871,0,0,0,3774,7,0,20655,22874,110.95,85,1738745013900103200 -0,7,0,2,0,9055,3,0,0,8641,1,0,126125,128014,94.45,86,1738745013978242600 -0,7,0,2,0,10655,4,0,0,10509,5,0,100520,102326,90.3,87,1738745014056255700 -0,7,0,2,0,14046,7,0,1,14192,0,0,74917,77056,106.95,88,1738745014132118300 -0,7,0,2,1,5150,1,0,1,5511,0,0,49313,51247,96.7,89,1738745014210116300 -0,7,0,2,1,3674,3,0,1,2758,1,0,23709,25633,96.2,90,1738745014288112700 -0,7,0,2,0,8346,6,0,0,48,1,0,129179,131329,107.5,91,1738745014364116300 -0,7,0,2,1,11227,5,0,1,10820,4,0,103574,105528,97.7,92,1738745014442109200 -0,7,0,2,1,13595,2,0,1,13482,1,0,77971,80286,115.75,93,1738745014520121200 -0,7,0,2,0,5465,1,0,1,6125,2,0,52366,54707,117.05,94,1738745014598115500 -0,7,0,2,0,2969,3,0,1,2323,4,0,26765,28904,106.95,95,1738745014674105900 -0,7,0,2,0,216,4,0,0,358,2,0,1159,3548,119.45,96,1738745014752109500 -0,7,0,2,0,11800,7,0,0,12256,2,0,106629,109059,121.5,97,1738745014830104700 -0,7,0,2,1,13400,0,0,1,15592,2,0,81024,83331,115.35,98,1738745014906241000 -0,7,0,2,0,5768,3,0,0,4661,2,0,55421,57651,111.5,99,1738745014984117400 -0,7,0,2,1,2504,5,0,0,2242,5,0,29817,31718,95.05,100,1738745015062225800 -0,7,0,2,1,777,7,0,1,646,7,0,4213,6181,98.4,101,1738745015138089600 -0,7,0,2,0,12105,6,0,1,11610,1,0,109684,111457,88.65,102,1738745015216088200 -0,7,0,2,1,15755,1,0,1,16172,2,0,84078,86460,119.1,103,1738745015294082000 -0,7,0,2,1,4811,6,0,0,4898,6,0,58475,60955,124.0,104,1738745015370083400 -0,7,0,2,0,6154,4,0,0,6591,7,0,32871,35157,114.3,105,1738745015448205100 -0,7,0,2,0,586,6,0,1,1759,4,0,7268,9384,105.8,106,1738745015526096300 -0,7,0,2,1,11402,3,0,0,9219,2,0,112738,114707,98.45,107,1738745015602090500 -0,7,0,2,1,16334,3,0,1,16085,5,0,87133,88886,87.65,108,1738745015680090600 -0,7,0,2,0,4366,5,0,0,4230,7,0,61529,63525,99.8,109,1738745015758090300 -0,7,0,2,1,6479,5,0,0,6997,3,0,35926,37682,87.8,110,1738745015834083400 -0,7,0,2,0,1935,2,0,0,1301,2,0,10323,12492,108.45,111,1738745015912059700 -0,7,0,2,1,9421,1,0,1,9571,0,0,115790,118255,123.25,112,1738745015990060000 -0,7,0,2,1,14861,6,0,1,15291,7,0,90187,92522,116.75,113,1738745016066197000 -0,7,0,2,0,4172,4,0,1,12381,5,0,64583,66377,89.7,114,1738745016144065800 -0,7,0,2,0,6796,7,0,0,7709,1,0,38981,41137,107.8,115,1738745016222064900 -0,7,0,2,0,1484,0,0,1,1237,7,0,13376,15157,89.05,116,1738745016300061600 -0,7,0,2,0,9988,3,0,1,10121,7,0,118845,120714,93.45,117,1738745016376035900 -0,7,0,2,1,15172,4,0,1,14788,4,0,93240,95288,102.4,118,1738745016454059100 -0,7,0,2,1,12677,5,0,1,12575,5,0,67638,69462,91.2,119,1738745016532071200 -0,7,0,2,0,7877,1,0,1,8030,1,0,42033,44193,108.0,120,1738745016608054500 -0,7,0,2,1,3079,1,0,0,3206,0,0,16430,18399,98.45,121,1738745016686058800 -0,7,0,2,1,9799,2,0,1,8902,3,0,121900,123938,101.9,122,1738745016764062300 -0,7,0,2,0,14470,5,0,0,14336,3,0,96294,98301,100.35,123,1738745016840065900 -0,7,0,2,0,13254,7,0,0,13008,4,0,70693,72455,88.1,124,1738745016918189200 -0,7,0,2,0,7426,0,0,1,7316,6,0,45087,47300,110.65,125,1738745016996031800 -0,7,0,2,0,3394,3,0,0,4063,5,0,19485,21673,109.4,126,1738745017072043700 -0,7,0,2,1,9090,4,0,1,8975,7,0,124952,126890,96.9,127,1738745017150059900 -0,7,0,2,1,10435,7,0,1,10688,1,0,99349,101374,101.25,128,1738745017228036900 -0,7,0,2,0,13827,1,0,0,14270,0,0,73745,76127,119.1,129,1738745017304031500 -0,7,0,2,1,7233,3,0,1,5324,5,0,48141,50246,105.25,130,1738745017382031000 -0,7,0,2,0,3713,6,0,1,2587,0,0,22539,24720,109.05,131,1738745017460187600 -0,7,0,2,1,8640,5,0,1,8307,3,0,128006,130322,115.8,132,1738745017536032400 -0,7,0,2,0,11008,6,0,1,10902,4,0,102404,104664,113.0,133,1738745017614175000 -0,7,0,2,0,14272,1,0,0,13763,3,0,76798,78866,103.4,134,1738745017692180000 -0,7,0,2,0,5248,3,0,1,5897,2,0,51197,53363,108.3,135,1738745017768176500 -0,7,0,2,1,2625,4,0,1,3021,0,0,25591,27568,98.85,136,1738745017846027700 -0,7,0,2,0,8193,7,0,1,436,0,0,131061,133439,118.9,137,1738745017924237200 -0,7,0,2,0,10945,0,0,0,11979,6,0,105456,107627,108.55,138,1738745018000235300 -0,7,0,2,1,13699,3,0,1,15388,3,0,79853,82109,112.8,139,1738745018078014700 -0,7,0,2,0,5955,5,0,0,5754,7,0,54249,56677,121.4,140,1738745018156017900 -0,7,0,2,1,2818,7,0,1,2184,6,0,28645,30843,109.9,141,1738745018234012200 -0,7,0,2,1,450,6,0,1,836,0,0,3044,5056,100.6,142,1738745018310445700 -0,7,0,2,0,11910,1,0,0,12037,7,0,108510,110538,101.4,143,1738745018388013700 -0,7,0,2,0,15430,3,0,1,15830,1,0,82909,84769,93.0,144,1738745018466011500 -0,7,0,2,1,5639,4,0,0,4744,3,0,57303,59266,98.15,145,1738745018542015200 -0,7,0,2,0,2247,7,0,1,6343,4,0,31701,33832,106.55,146,1738745018620077500 -0,7,0,2,1,903,0,0,0,516,2,0,6096,8131,101.75,147,1738745018698157400 -0,7,0,2,1,11589,3,0,0,11507,7,0,111565,113386,91.05,148,1738745018774154500 -0,7,0,2,0,15621,5,0,0,16265,7,0,85961,87946,99.25,149,1738745018852135600 -0,7,0,2,1,5060,5,0,1,4553,6,0,60358,62580,111.1,150,1738745018930141700 -0,7,0,2,0,6276,3,0,1,6406,1,0,34754,36830,103.8,151,1738745019006038500 -0,7,0,2,1,1612,1,0,1,1872,4,0,9150,11512,118.1,152,1738745019084020000 -0,7,0,2,0,11276,2,0,0,9353,5,0,114620,116617,99.85,153,1738745019161995000 -0,7,0,2,1,16077,4,0,1,14932,1,0,89015,90942,96.35,154,1738745019239987400 -0,7,0,2,0,4493,6,0,0,4098,5,0,63412,65510,104.9,155,1738745019315983500 -0,7,0,2,1,6991,0,0,0,6745,4,0,37807,40072,113.25,156,1738745019393988600 -0,7,0,2,0,1807,3,0,0,1157,6,0,12205,14388,109.15,157,1738745019471984100 -0,7,0,2,1,9679,4,0,0,10193,4,0,117672,120055,119.15,158,1738745019547998600 -0,7,0,2,1,14990,7,0,1,15108,4,0,92069,94151,104.1,159,1738745019625997700 -0,7,0,2,0,12366,3,0,1,12767,5,0,66466,68438,98.6,160,1738745019703981100 -0,7,0,2,1,6666,3,0,0,7838,5,0,40861,42841,99.0,161,1738745019780165700 -0,7,0,2,1,1226,2,0,0,3143,0,0,15260,17360,105.0,162,1738745019858098900 -0,7,0,2,0,10123,4,0,0,9786,0,0,120727,122527,90.0,163,1738745019935959500 -0,7,0,2,0,14667,6,0,0,14551,0,0,95124,97071,97.35,164,1738745020011963900 -0,7,0,2,1,12553,0,0,0,13189,2,0,69519,71628,105.45,165,1738745020089959500 -0,7,0,2,0,8137,3,0,0,7549,0,0,43917,45744,91.35,166,1738745020167969100 -0,7,0,2,1,3208,4,0,0,3860,7,0,18311,20677,118.3,167,1738745020243965000 -0,7,0,2,0,8776,7,0,1,9039,0,0,123781,126032,112.55,168,1738745020321965700 -0,7,0,2,0,14344,1,0,0,10382,4,0,98177,100263,104.3,169,1738745020399972800 -0,7,0,2,1,13016,1,0,0,13901,4,0,72574,74679,105.25,170,1738745020475957100 -0,7,0,2,1,7576,6,0,0,7182,5,0,46971,49062,104.55,171,1738745020554017000 -0,7,0,2,1,3929,7,0,1,3696,5,0,21365,23814,122.45,172,1738745020631960700 -0,7,0,2,0,8985,6,0,1,8321,1,0,126836,129038,110.1,173,1738745020707938500 -0,7,0,2,1,10715,1,0,1,11079,5,0,101230,103382,107.6,174,1738745020785936000 -0,7,0,2,0,13979,2,0,1,13568,5,0,75628,77830,110.1,175,1738745020863942900 -0,7,0,2,1,5210,4,0,1,5619,7,0,50023,51946,96.15,176,1738745020942075700 -0,7,0,2,1,3610,7,0,1,2749,0,0,24421,26288,93.35,177,1738745021018069400 -0,7,0,2,0,8410,1,0,1,125,6,0,129889,131764,93.75,178,1738745021095931400 -0,7,0,2,0,11166,3,0,0,11777,7,0,104285,106506,111.05,179,1738745021173932900 -0,7,0,2,0,13662,4,0,0,13406,4,0,78680,81063,119.15,180,1738745021249943000 -0,7,0,2,1,5407,5,0,1,6024,0,0,53078,55168,104.5,181,1738745021327935900 -0,7,0,2,0,3039,6,0,0,2392,6,0,27476,29563,104.35,182,1738745021405942100 -0,7,0,2,1,157,1,0,0,768,0,0,1870,4096,111.3,183,1738745021481941700 -0,7,0,2,0,11869,2,0,0,12280,4,0,107340,109191,92.55,184,1738745021559937300 -0,7,0,2,0,13340,4,0,0,15756,5,0,81735,84038,115.15,185,1738745021637969200 -0,7,0,2,1,5852,6,0,1,4801,5,0,56132,58377,112.25,186,1738745021713940700 -0,7,0,2,1,2460,0,0,1,6157,0,0,30528,32847,115.95,187,1738745021791913500 -0,7,0,2,0,852,3,0,0,602,5,0,4925,7321,119.8,188,1738745021869969900 -0,7,0,2,0,12052,5,0,0,11662,6,0,110393,112548,107.75,189,1738745021945914200 -0,7,0,2,0,15829,5,0,1,16235,7,0,84790,86634,92.2,190,1738745022023914300 -0,7,0,2,0,4757,6,0,1,4908,7,0,59188,60997,90.45,191,1738745022101916400 -0,7,0,2,0,6231,0,0,0,6590,7,0,33583,35162,78.95,192,1738745022178052300 -0,7,0,2,1,535,2,0,1,1665,7,0,7980,10229,112.45,193,1738745022255963900 -0,7,0,2,0,11478,4,0,0,9308,7,0,113447,115525,103.9,194,1738745022333920700 -0,7,0,2,0,16278,6,0,1,15899,5,0,87844,89961,105.85,195,1738745022412046600 -0,7,0,2,1,4438,0,0,1,4261,4,0,62240,63944,85.2,196,1738745022487920300 -0,7,0,2,0,6418,3,0,0,7045,3,0,36637,38861,111.2,197,1738745022567021500 -0,7,0,2,0,2002,5,0,0,1357,6,0,11033,13236,110.15,198,1738745022643893000 -0,7,0,2,0,9363,7,0,1,9532,4,0,116501,118456,97.75,199,1738745022719892500 -0,7,0,2,0,14931,3,0,0,15319,1,0,90898,92974,103.8,200,1738745022797896600 -0,7,0,2,1,4113,1,0,0,12440,5,0,65294,67449,107.75,201,1738745022876027000 -0,7,0,2,1,6865,6,0,1,7719,7,0,39691,41429,86.9,202,1738745022951902900 -0,7,0,2,1,1424,5,0,1,1075,1,0,14086,16110,101.2,203,1738745023030010600 -0,7,0,2,0,10064,7,0,1,9893,0,0,119557,121295,86.9,204,1738745023107888900 -0,7,0,2,1,15152,0,0,0,14742,2,0,93951,96035,104.2,205,1738745023183889200 -0,7,0,2,0,12784,3,0,0,13139,0,0,68349,70416,103.35,206,1738745023261892000 -0,7,0,2,1,7856,4,0,1,7950,4,0,42744,44967,111.15,207,1738745023339901300 -0,7,0,2,1,3185,7,0,0,3548,4,0,17141,19271,106.5,208,1738745023415935900 -0,7,0,2,0,9777,1,0,1,8891,0,0,122609,124560,97.55,209,1738745023493898200 -0,7,0,2,1,14579,3,0,1,10355,2,0,97005,99052,102.35,210,1738745023571867800 -0,7,0,2,0,13235,2,0,0,12860,7,0,71404,73402,99.9,211,1738745023647861200 -0,7,0,2,0,7538,5,0,1,7421,4,0,45798,47799,100.05,212,1738745023725861200 -0,7,0,2,0,3378,6,0,1,3987,5,0,20196,22294,104.9,213,1738745023803865900 -0,7,0,2,0,9206,1,0,1,8524,5,0,125662,127929,113.35,214,1738745023879865600 -0,7,0,2,1,10422,3,0,0,10694,3,0,100061,101341,64.0,215,1738745023957996500 -0,7,0,2,1,13943,4,0,1,14260,6,0,74455,76091,81.8,216,1738745024035871700 -0,7,0,2,0,7223,7,0,0,5271,7,0,48853,50986,106.65,217,1738745024113866300 -0,7,0,2,0,3831,0,0,0,2638,0,0,23248,25504,112.8,218,1738745024189865500 -0,7,0,2,1,8629,3,0,0,8291,3,0,128717,130541,91.2,219,1738745024267885200 -0,7,0,2,0,11125,2,0,0,10991,1,0,103116,105041,96.25,220,1738745024345865900 -0,7,0,2,1,14132,7,0,1,13748,4,0,77509,79559,102.5,221,1738745024421854400 -0,7,0,2,0,5620,2,0,1,5962,3,0,51907,54173,113.3,222,1738745024499937200 -0,7,0,2,0,2748,0,0,1,2878,0,0,26303,28320,100.85,223,1738745024576061800 -0,7,0,2,1,124,2,0,0,452,5,0,700,3014,115.7,224,1738745024653921400 -0,7,0,2,1,10813,4,0,1,12006,4,0,106167,107992,91.25,225,1738745024731838400 -0,7,0,2,0,13565,7,0,1,15436,1,0,80565,82878,115.65,226,1738745024809840200 -0,7,0,2,0,6077,1,0,1,5741,0,0,54961,56752,89.55,227,1738745024885843800 -0,7,0,2,1,2431,3,0,1,2295,2,0,29357,31443,104.3,228,1738745024963968600 -0,7,0,2,1,319,4,0,1,903,6,0,3752,6100,117.4,229,1738745025041963700 -0,7,0,2,1,12286,7,0,1,11618,7,0,109221,111130,95.45,230,1738745025117789100 -0,7,0,2,1,15550,6,0,1,15657,4,0,83620,85623,100.15,231,1738745025195966200 -0,7,0,2,1,4730,3,0,0,5104,5,0,58013,60153,107.0,232,1738745025273838900 -0,7,0,2,1,2106,6,0,1,6294,0,0,32411,34592,109.05,233,1738745025349837800 -0,7,0,2,0,763,4,0,1,1659,1,0,6807,8849,102.1,234,1738745025427836200 -0,7,0,2,1,11707,7,0,0,11322,1,0,112277,114334,102.85,235,1738745025505816600 -0,7,0,2,1,16249,0,0,1,16120,7,0,86671,88709,101.9,236,1738745025583833400 -0,7,0,2,0,4921,3,0,1,4529,3,0,61069,63218,107.45,237,1738745025659955500 -0,7,0,2,0,6649,5,0,1,6991,4,0,35465,37800,116.75,238,1738745025737842000 -0,7,0,2,1,1720,5,0,0,1835,0,0,9862,11887,101.25,239,1738745025815828400 -0,7,0,2,0,9336,1,0,1,9704,7,0,115329,117370,102.05,240,1738745025891949000 -0,7,0,2,1,15912,3,0,0,15004,4,0,89725,91975,112.5,241,1738745025969939300 -0,7,0,2,1,4328,6,0,0,12348,5,0,64123,65862,86.95,242,1738745026047814900 -0,7,0,2,0,7081,5,0,0,6672,2,0,38518,40707,109.45,243,1738745026123809000 -0,7,0,2,0,1385,7,0,0,1197,5,0,12917,14774,92.85,244,1738745026201814500 -0,7,0,2,0,9515,0,0,0,10158,2,0,118383,120412,101.45,245,1738745026279812400 -0,7,0,2,0,15339,3,0,1,14697,6,0,92781,94836,102.75,246,1738745026355792600 -0,7,0,2,0,12459,5,0,1,12580,5,0,67177,69177,100.0,247,1738745026433795200 -0,7,0,2,0,7786,7,0,1,8159,5,0,41573,43862,114.45,248,1738745026511805100 -0,7,0,2,1,1066,1,0,0,3320,2,0,15969,17788,90.95,249,1738745026587786700 -0,7,0,2,0,9966,3,0,0,8786,3,0,121437,123677,112.0,250,1738745026665781900 -0,7,0,2,0,14766,6,0,0,14374,1,0,95835,97825,99.5,251,1738745026743789200 -0,7,0,2,0,13167,5,0,0,12975,2,0,70230,72108,93.9,252,1738745026819820500 -0,7,0,2,0,7983,6,0,0,7560,7,0,44628,46981,117.65,253,1738745026897786500 -0,7,0,2,1,3565,0,0,0,3872,2,0,19023,20988,98.25,254,1738745026975911200 -0,7,0,2,0,8877,3,0,0,9068,1,0,124493,126398,95.25,255,1738745027051923300 -0,7,0,2,1,10348,4,0,0,10721,1,0,98887,100878,99.55,256,1738745027129780000 -0,7,0,2,0,12844,7,0,0,14050,4,0,73285,75239,97.7,257,1738745027207786300 -0,7,0,2,1,7404,0,0,0,5215,5,0,47680,50006,116.3,258,1738745027285781700 -0,7,0,2,1,4004,3,0,1,3615,1,0,22077,24401,116.2,259,1738745027361794900 -0,7,0,2,1,8548,7,0,0,8256,7,0,127546,130053,125.35,260,1738745027439762800 -0,7,0,2,1,10533,7,0,1,11190,7,0,101941,104154,110.65,261,1738745027517772400 -0,7,0,2,0,14309,7,0,1,13583,1,0,76341,77905,78.2,262,1738745027593784800 -0,7,0,2,0,5287,1,0,1,5484,1,0,50734,52670,96.8,263,1738745027671892100 -0,7,0,2,0,2663,2,0,1,3061,7,0,25132,27338,110.3,264,1738745027749765700 -0,7,0,2,1,8230,4,0,1,230,5,0,130599,132569,98.5,265,1738745027825769100 -0,7,0,2,0,10982,6,0,0,11899,4,0,104996,107159,108.15,266,1738745027903766400 -0,7,0,2,1,13734,0,0,0,13356,4,0,79392,81479,104.35,267,1738745027981779400 -0,7,0,2,1,5986,1,0,0,5812,7,0,53790,55610,91.0,268,1738745028057781400 -0,7,0,2,1,2850,4,0,1,2483,4,0,28184,30440,112.8,269,1738745028135770600 -0,7,0,2,1,483,7,0,1,874,4,0,2581,4711,106.5,270,1738745028213761400 -0,7,0,2,1,11939,6,0,1,12076,2,0,108052,110147,104.75,271,1738745028289793100 -0,7,0,2,1,15457,1,0,1,15846,5,0,82446,84518,103.6,272,1738745028367756300 -0,7,0,2,1,5665,2,0,1,4773,5,0,56844,58934,104.5,273,1738745028445741400 -0,7,0,2,0,2272,4,0,0,6163,1,0,31239,33006,88.35,274,1738745028521742100 -0,7,0,2,0,928,6,0,1,612,2,0,5636,7619,99.15,275,1738745028599876800 -0,7,0,2,1,11552,0,0,1,11450,4,0,111103,112999,94.8,276,1738745028677740300 -0,7,0,2,0,15712,3,0,1,16361,4,0,85501,87432,96.55,277,1738745028753745700 -0,7,0,2,0,5024,4,0,0,4384,3,0,59896,61949,102.65,278,1738745028831753700 -0,7,0,2,1,6369,7,0,1,6447,4,0,34293,36439,107.3,279,1738745028909736500 -0,7,0,2,1,1569,3,0,0,1955,2,0,8690,10732,102.1,280,1738745028985864900 -0,7,0,2,1,11363,3,0,0,9396,6,0,114157,116420,113.15,281,1738745029063744300 -0,7,0,2,1,16035,2,0,1,14947,3,0,88556,90642,104.3,282,1738745029141730500 -0,7,0,2,1,4578,5,0,1,4195,1,0,62950,65006,102.8,283,1738745029219745300 -0,7,0,2,0,6946,7,0,1,6888,5,0,37349,39545,109.8,284,1738745029295705700 -0,7,0,2,0,1894,1,0,1,1513,6,0,11742,13707,98.25,285,1738745029375063400 -0,7,0,2,1,9638,3,0,1,10035,2,0,117213,119059,92.3,286,1738745029451717700 -0,7,0,2,1,15078,5,0,0,15228,4,0,91609,93511,95.1,287,1738745029527711200 -0,7,0,2,0,12327,7,0,1,12779,7,0,66005,68202,109.85,288,1738745029605717000 -0,7,0,2,0,6759,0,0,1,7834,0,0,40400,42848,122.4,289,1738745029683715500 -0,7,0,2,1,1189,3,0,0,3101,4,0,14797,16567,88.5,290,1738745029759712500 -0,7,0,2,0,10213,3,0,0,9836,1,0,120269,122302,101.65,291,1738745029837710900 -0,7,0,2,1,14628,5,0,0,14542,3,0,94662,97186,126.2,292,1738745029915721900 -0,7,0,2,1,12644,2,0,0,13220,3,0,69059,71229,108.5,293,1738745029991716000 -0,7,0,2,0,8108,0,0,1,7453,4,0,43455,45239,89.2,294,1738745030069715400 -0,7,0,2,0,3308,3,0,0,3442,5,0,17853,19737,94.2,295,1738745030147707800 -0,7,0,2,1,8748,4,0,0,9191,0,0,123320,125487,108.35,296,1738745030223719500 -0,7,0,2,0,14445,6,0,0,10472,4,0,97716,99719,100.15,297,1738745030301720700 -0,7,0,2,0,12973,0,0,0,13886,4,0,72112,74072,98.0,298,1738745030377678400 -0,7,0,2,1,7663,3,0,0,7269,1,0,46509,48590,104.05,299,1738745030457695600 -0,7,0,2,0,3887,7,0,1,3839,5,0,20906,23209,115.15,300,1738745030533700600 -0,7,0,2,1,9070,7,0,1,8675,3,0,126373,128493,106.0,301,1738745030611694100 -0,7,0,2,1,10670,2,0,1,11049,7,0,100771,102794,101.15,302,1738745030689692300 -0,7,0,2,0,14058,1,0,0,14125,1,0,75166,77390,111.2,303,1738745030765709000 -0,7,0,2,0,5162,2,0,1,5601,4,0,49564,51720,107.8,304,1738745030843721600 -0,7,0,2,0,3691,4,0,0,2794,7,0,23959,26010,102.55,305,1738745030921717000 -0,7,0,2,0,8363,6,0,1,96,1,0,129428,131585,107.85,306,1738745030997831000 -0,7,0,2,1,11243,0,0,0,10857,6,0,103824,105867,102.15,307,1738745031075690500 -0,7,0,2,1,13609,3,0,1,13458,6,0,78221,80100,93.95,308,1738745031153683700 -0,7,0,2,0,5481,4,0,0,6134,1,0,52616,54561,97.25,309,1738745031229688700 -0,7,0,2,1,2984,7,0,0,2339,7,0,27013,29162,107.45,310,1738745031307695600 -0,7,0,2,1,232,6,0,0,449,5,0,1412,3062,82.5,311,1738745031385664400 -0,7,0,2,1,11832,1,0,1,12261,4,0,106878,109111,111.65,312,1738745031461666700 -0,7,0,2,0,13432,2,0,0,15591,5,0,81276,83414,106.9,313,1738745031539657400 -0,7,0,2,0,5817,5,0,1,4704,0,0,55670,57856,109.3,314,1738745031617666300 -0,7,0,2,1,2553,7,0,0,2151,5,0,30069,32214,107.25,315,1738745031693653300 -0,7,0,2,1,827,0,0,0,702,2,0,4463,6492,101.45,316,1738745031771679500 -0,7,0,2,0,12155,2,0,1,11768,2,0,109932,111996,103.2,317,1738745031849682300 -0,7,0,2,0,15803,6,0,0,16145,4,0,84331,86263,96.6,318,1738745031927678800 -0,7,0,2,1,4858,7,0,1,4970,4,0,58725,60824,104.95,319,1738745032003662700 -0,7,0,2,1,6202,3,0,0,6634,4,0,33122,35431,115.45,320,1738745032081677700 -0,7,0,2,1,638,1,0,0,1758,6,0,7518,9380,93.1,321,1738745032159662000 -0,7,0,2,1,11454,6,0,1,9257,3,0,112987,115085,104.9,322,1738745032235638200 -0,7,0,2,1,16383,5,0,1,15906,2,0,87382,89628,112.3,323,1738745032313640000 -0,7,0,2,0,4415,6,0,1,4285,7,0,61780,63818,101.9,324,1738745032391639100 -0,7,0,2,0,6525,0,0,1,7165,3,0,36175,38221,102.3,325,1738745032467813600 -0,7,0,2,0,1981,3,0,0,1337,2,0,10573,12659,104.3,326,1738745032545640200 -0,7,0,2,1,9468,4,0,0,9558,0,0,116039,117983,97.2,327,1738745032623634900 -0,7,0,2,1,14908,7,0,0,15250,4,0,90437,92391,97.7,328,1738745032699640100 -0,7,0,2,0,4220,0,0,0,12473,1,0,64832,67214,119.1,329,1738745032777636700 -0,7,0,2,0,6836,3,0,1,7784,1,0,39229,41598,118.45,330,1738745032855638500 -0,7,0,2,1,1524,2,0,1,1128,0,0,13628,15744,105.8,331,1738745032931773200 -0,7,0,2,1,10037,5,0,1,9875,7,0,119094,121066,98.6,332,1738745033009666800 -0,7,0,2,1,15221,6,0,1,14824,3,0,93492,95618,106.3,333,1738745033087622200 -0,7,0,2,0,12727,0,0,0,13119,1,0,67887,69969,104.1,334,1738745033163599700 -0,7,0,2,0,7927,3,0,1,8134,5,0,42285,43993,85.4,335,1738745033241631700 -0,7,0,2,1,3126,4,0,1,3480,7,0,16679,18565,94.3,336,1738745033319618300 -0,7,0,2,1,9846,7,0,1,8924,7,0,122149,124090,97.05,337,1738745033395610400 -0,7,0,2,1,14518,0,0,0,10338,1,0,96544,98846,115.1,338,1738745033473750500 -0,7,0,2,1,13298,3,0,1,12922,5,0,70941,73062,106.05,339,1738745033551614400 -0,7,0,2,0,7474,5,0,0,7343,2,0,45337,47532,109.75,340,1738745033629617800 -0,7,0,2,1,3443,5,0,1,4073,5,0,19734,21897,108.15,341,1738745033705781800 -0,7,0,2,0,9139,6,0,1,8479,6,0,125204,127147,97.15,342,1738745033783608100 -0,7,0,2,1,10481,1,0,1,10617,3,0,99598,101746,107.4,343,1738745033861619700 -0,7,0,2,1,13873,3,0,0,14270,5,0,73997,76121,106.2,344,1738745033937608300 -0,7,0,2,0,7280,4,0,0,5356,2,0,48391,50620,111.45,345,1738745034015606400 -0,7,0,2,0,3760,7,0,1,2594,0,0,22789,25056,113.35,346,1738745034093617100 -0,7,0,2,1,8656,0,0,0,8234,7,0,128255,130661,120.3,347,1738745034169587800 -0,7,0,2,0,11024,3,0,1,10943,1,0,102653,104785,106.6,348,1738745034247587800 -0,7,0,2,0,14160,4,0,1,13793,3,0,77048,79346,114.9,349,1738745034325581500 -0,7,0,2,1,5521,7,0,0,5899,0,0,51445,53359,95.7,350,1738745034401741800 -0,7,0,2,0,2769,2,0,1,2937,6,0,25843,28020,108.85,351,1738745034479584900 -0,7,0,2,1,19,1,0,0,500,6,0,238,2756,125.9,352,1738745034557644400 -0,7,0,2,1,10835,2,0,1,11983,5,0,105708,107606,94.9,353,1738745034633586500 -0,7,0,2,1,13458,5,0,1,15402,7,0,80102,82330,111.4,354,1738745034711810300 -0,7,0,2,0,6098,6,0,1,5752,7,0,54500,56698,109.9,355,1738745034789812800 -0,7,0,2,1,2326,0,0,1,2200,6,0,28895,30852,97.85,356,1738745034865750100 -0,7,0,2,0,342,2,0,1,1014,1,0,3292,5409,105.85,357,1738745034943734600 -0,7,0,2,1,12182,4,0,0,11560,7,0,108760,110981,111.05,358,1738745035021801300 -0,7,0,2,0,15575,7,0,0,15723,5,0,83157,85398,112.05,359,1738745035097697800 -0,7,0,2,1,4631,6,0,0,5012,1,0,57556,59585,101.45,360,1738745035175675500 -0,7,0,2,1,2133,1,0,0,6359,2,0,31950,34003,102.65,361,1738745035253754700 -0,7,0,2,0,661,2,0,1,1549,1,0,6348,8270,96.1,362,1738745035331620100 -0,7,0,2,0,11732,5,0,1,11353,0,0,111814,113807,99.65,363,1738745035407564400 -0,7,0,2,0,16148,7,0,1,16030,6,0,86213,88228,100.75,364,1738745035485561900 -0,7,0,2,0,4956,0,0,1,4604,0,0,60607,62784,108.85,365,1738745035563577100 -0,7,0,2,0,6556,2,0,0,6964,6,0,35004,37179,108.75,366,1738745035639571000 -0,7,0,2,1,1757,4,0,0,1897,4,0,9399,11656,112.85,367,1738745035717734300 -0,7,0,2,0,9245,6,0,0,9705,1,0,114868,117361,124.65,368,1738745035795509400 -0,7,0,2,0,15965,1,0,0,15100,5,0,89265,91462,109.85,369,1738745035871698500 -0,7,0,2,1,4255,3,0,0,12297,5,0,63661,65654,99.65,370,1738745035949588400 -0,7,0,2,0,7135,6,0,0,6688,2,0,38059,40451,119.6,371,1738745036027663800 -0,7,0,2,1,1310,5,0,1,1170,6,0,12454,14564,105.5,372,1738745036103551400 -0,7,0,2,1,9566,6,0,0,10195,7,0,117924,120042,105.9,373,1738745036181713100 -0,7,0,2,1,15258,0,0,1,15111,3,0,92319,94162,92.15,374,1738745036259586600 -0,7,0,2,0,12506,2,0,1,12634,1,0,66716,68766,102.5,375,1738745036335566300 -0,7,0,2,1,7707,4,0,1,8118,5,0,41111,43302,109.55,376,1738745036413543000 -0,7,0,2,1,1115,7,0,0,3143,6,0,15509,17364,92.75,377,1738745036491549300 -0,7,0,2,1,9883,0,0,0,8728,1,0,120976,123009,101.65,378,1738745036567536900 -0,7,0,2,0,14809,3,0,0,14440,7,0,95373,97669,114.8,379,1738745036645545200 -0,7,0,2,1,13081,7,0,0,12959,2,0,69770,71852,104.1,380,1738745036723588000 -0,7,0,2,1,8024,5,0,0,7630,5,0,44166,46169,100.15,381,1738745036801548100 -0,7,0,2,0,3480,2,0,0,3875,1,0,18563,20974,120.55,382,1738745036877569700 -0,7,0,2,1,8904,1,0,1,8994,4,0,124030,126488,122.9,383,1738745036955515300 -0,7,0,2,0,10248,2,0,0,10666,3,0,98428,100765,116.85,384,1738745037033519000 -0,7,0,2,1,12873,4,0,1,13897,3,0,72823,74637,90.7,385,1738745037109511300 -0,7,0,2,0,7305,7,0,1,5133,3,0,47221,49229,100.4,386,1738745037187526700 -0,7,0,2,0,4041,0,0,0,3668,0,0,21616,23744,106.4,387,1738745037265514600 -0,7,0,2,0,8459,3,0,1,8329,3,0,127085,129138,102.65,388,1738745037341518200 -0,7,0,2,0,10571,5,0,0,11207,0,0,101481,103471,99.5,389,1738745037419519900 -0,7,0,2,0,14218,7,0,1,13607,3,0,75877,78290,120.65,390,1738745037497655000 -0,7,0,2,0,5322,2,0,1,5499,7,0,50275,52586,115.55,391,1738745037573514000 -0,7,0,2,1,2574,3,0,1,2980,6,0,24669,27076,120.35,392,1738745037651509600 -0,7,0,2,0,8270,2,0,1,217,4,0,130140,132232,104.6,393,1738745037729515500 -0,7,0,2,0,10895,4,0,0,10767,4,0,104535,106408,93.65,394,1738745037805519200 -0,7,0,2,1,13775,6,0,1,13390,2,0,78932,80988,102.8,395,1738745037883484400 -0,7,0,2,0,5903,0,0,1,5777,0,0,53328,55536,110.4,396,1738745037961486600 -0,7,0,2,1,2893,3,0,1,2510,2,0,27725,29788,103.15,397,1738745038037647500 -0,7,0,2,0,397,4,0,0,828,0,0,2120,4416,114.8,398,1738745038115502000 -0,7,0,2,1,11980,7,0,0,12113,1,0,107589,109809,111.0,399,1738745038193622500 -0,7,0,2,0,15372,1,0,0,15503,3,0,81985,83885,95.0,400,1738745038271487000 -0,7,0,2,1,5700,1,0,1,4859,3,0,56382,58733,117.55,401,1738745038347441000 -0,7,0,2,0,2180,3,0,0,2094,6,0,30781,32347,78.3,402,1738745038425469800 -0,7,0,2,1,965,5,0,1,592,6,0,5174,7419,112.25,403,1738745038501512700 -0,7,0,2,0,11525,7,0,0,11665,3,0,110645,112397,87.6,404,1738745038579558000 -0,7,0,2,0,15687,0,0,1,16331,6,0,85039,87147,105.4,405,1738745038657520100 -0,7,0,2,1,4999,3,0,0,4867,2,0,59437,61420,99.15,406,1738745038735490100 -0,7,0,2,0,6342,4,0,0,6492,0,0,33831,36031,110.0,407,1738745038811478600 -0,7,0,2,1,1542,7,0,0,1679,0,0,8229,10159,96.5,408,1738745038889464000 -0,7,0,2,1,11334,1,0,0,9457,6,0,113697,115979,114.1,409,1738745038967494600 -0,7,0,2,1,16002,3,0,0,15873,7,0,88093,90101,100.4,410,1738745039043737700 -0,7,0,2,0,4546,7,0,0,4161,0,0,62490,64527,101.85,411,1738745039121457400 -0,7,0,2,0,6915,5,0,1,7067,5,0,36886,38761,93.75,412,1738745039199654100 -0,7,0,2,1,1859,2,0,0,1496,5,0,11283,13446,108.15,413,1738745039275617100 -0,7,0,2,0,9601,0,0,0,9997,4,0,116751,118856,105.25,414,1738745039353601700 -0,7,0,2,1,15041,2,0,1,15216,7,0,91148,93445,114.85,415,1738745039431467000 -0,7,0,2,1,12289,4,0,1,12433,3,0,65544,67341,89.85,416,1738745039507593500 -0,7,0,2,1,6720,7,0,0,7763,2,0,39941,41747,90.3,417,1738745039585470100 -0,7,0,2,0,1152,0,0,1,3097,3,0,14336,16525,109.45,418,1738745039663847000 -0,7,0,2,1,10048,3,0,0,9811,5,0,119805,122089,114.2,419,1738745039739473700 -0,7,0,2,0,15104,7,0,1,14743,2,0,94202,96044,92.1,420,1738745039817467200 -0,7,0,2,1,12737,5,0,1,13134,3,0,68598,70562,98.2,421,1738745039895569800 -0,7,0,2,1,7809,6,0,1,7451,0,0,42996,45200,110.2,422,1738745039973442200 -0,7,0,2,0,3139,1,0,1,3395,0,0,17390,19472,104.1,423,1738745040049435400 -0,7,0,2,0,9731,2,0,1,9096,4,0,122860,125048,109.4,424,1738745040127450900 -0,7,0,2,1,14530,4,0,1,10317,1,0,97255,99249,99.7,425,1738745040205437000 -0,7,0,2,0,13186,6,0,1,13852,2,0,71652,73916,113.2,426,1738745040281440500 -0,7,0,2,1,7490,1,0,1,7234,7,0,46049,48154,105.25,427,1738745040359439700 -0,7,0,2,0,3334,3,0,1,3743,0,0,20445,22703,112.9,428,1738745040437540800 -0,7,0,2,0,9158,5,0,0,8516,6,0,125913,127940,101.35,429,1738745040513441000 -0,7,0,2,1,10375,7,0,0,11035,0,0,100309,102544,111.75,430,1738745040591440400 -0,7,0,2,0,13895,2,0,0,14153,4,0,74707,76919,110.6,431,1738745040669443300 -0,7,0,2,1,7173,1,0,1,5268,5,0,49102,51001,94.95,432,1738745040745442500 -0,7,0,2,1,3781,2,0,1,2639,2,0,23500,25516,100.8,433,1738745040823667200 -0,7,0,2,0,8580,5,0,1,3,3,0,128966,131090,106.2,434,1738745040901850700 -0,7,0,2,0,11076,7,0,0,10948,1,0,103365,105409,102.2,435,1738745040977411800 -0,7,0,2,1,14092,0,0,0,13748,2,0,77759,79555,89.8,436,1738745041055544900 -0,7,0,2,0,5580,3,0,0,6082,1,0,52157,54302,107.25,437,1738745041133409200 -0,7,0,2,1,2700,4,0,0,2318,7,0,26552,28762,110.5,438,1738745041209429400 -0,7,0,2,1,77,7,0,1,459,5,0,949,2966,100.85,439,1738745041287412800 -0,7,0,2,0,10765,2,0,1,11927,3,0,106419,108333,95.7,440,1738745041365543800 -0,7,0,2,1,13519,3,0,1,15601,4,0,80813,83208,119.75,441,1738745041443405400 -0,7,0,2,0,6031,6,0,0,4613,5,0,55211,57398,109.35,442,1738745041519406300 -0,7,0,2,0,2382,4,0,0,2242,4,0,29607,31719,105.6,443,1738745041597544600 -0,7,0,2,1,270,6,0,0,643,0,0,4004,6160,107.8,444,1738745041675409700 -0,7,0,2,0,12234,0,0,0,11712,5,0,109471,111622,107.55,445,1738745041751402600 -0,7,0,2,0,15498,3,0,0,15620,7,0,83869,85957,104.4,446,1738745041829385000 -0,7,0,2,0,4682,4,0,0,5109,4,0,58264,60104,92.0,447,1738745041907437400 -0,7,0,2,0,2059,7,0,1,6300,7,0,32661,34629,98.4,448,1738745041983399800 -0,7,0,2,0,715,1,0,0,1734,0,0,7057,9248,109.55,449,1738745042061518300 -0,7,0,2,1,11657,3,0,1,9231,6,0,112525,114772,112.35,450,1738745042139391600 -0,7,0,2,0,16201,6,0,1,16089,6,0,86923,88948,101.25,451,1738745042215513100 -0,7,0,2,1,4872,5,0,0,4233,4,0,61318,63607,114.45,452,1738745042293378800 -0,7,0,2,1,6600,6,0,1,6993,5,0,35716,37641,96.25,453,1738745042371439800 -0,7,0,2,0,1688,0,0,1,1808,1,0,10111,12033,96.1,454,1738745042447396500 -0,7,0,2,1,9304,2,0,0,9675,7,0,115580,117653,103.65,455,1738745042525377600 -0,7,0,2,0,15897,4,0,0,15238,6,0,89975,92196,111.05,456,1738745042603387200 -0,7,0,2,0,4313,7,0,0,12357,5,0,64373,66505,106.6,457,1738745042679368900 -0,7,0,2,0,7065,0,0,0,6661,4,0,38768,40904,106.8,458,1738745042757367600 -0,7,0,2,1,1371,3,0,0,1088,6,0,13165,15364,109.95,459,1738745042835361500 -0,7,0,2,1,9499,6,0,1,10220,6,0,118635,120251,80.8,460,1738745042911354800 -0,7,0,2,1,15322,5,0,0,14678,4,0,93030,95015,99.25,461,1738745042989355500 -0,7,0,2,0,12442,6,0,0,12593,0,0,67428,69360,96.6,462,1738745043067483200 -0,7,0,2,0,7774,1,0,0,8181,1,0,41822,43726,95.2,463,1738745043145364200 -0,7,0,2,0,1054,2,0,1,3222,3,0,16220,18210,99.5,464,1738745043221366100 -0,7,0,2,0,9951,4,0,0,8784,0,0,121687,123648,98.05,465,1738745043299363400 -0,7,0,2,0,14751,7,0,1,14388,5,0,96085,97990,95.25,466,1738745043377477500 -0,7,0,2,1,13149,0,0,1,12996,1,0,70479,72641,108.1,467,1738745043453394600 -0,7,0,2,0,7965,3,0,0,7351,6,0,44877,47403,126.3,468,1738745043531361600 -0,7,0,2,1,3549,5,0,0,3933,2,0,19273,21324,102.55,469,1738745043609351400 -0,7,0,2,1,8860,7,0,1,8988,3,0,124741,126786,102.25,470,1738745043685344600 -0,7,0,2,1,10332,2,0,0,10566,3,0,99139,101410,113.55,471,1738745043763341000 -0,7,0,2,1,12820,1,0,1,13969,7,0,73534,75530,99.8,472,1738745043841336200 -0,7,0,2,0,7380,2,0,1,5214,2,0,47932,50012,104.0,473,1738745043917690400 -0,7,0,2,0,3989,4,0,0,3607,1,0,22327,24366,101.95,474,1738745043995359600 -0,7,0,2,0,8533,7,0,0,8398,3,0,127797,129954,107.85,475,1738745044073348800 -0,7,0,2,1,10519,0,0,0,11151,2,0,102191,104364,108.65,476,1738745044149342100 -0,7,0,2,0,14295,3,0,1,13646,5,0,76589,78758,108.45,477,1738745044227334500 -0,7,0,2,1,5271,4,0,0,5399,0,0,50984,53039,102.75,478,1738745044305330700 -0,7,0,2,1,2646,5,0,0,3052,7,0,25382,27205,91.15,479,1738745044381341600 -0,7,0,2,1,8214,2,0,0,153,2,0,130851,132979,106.4,480,1738745044459335300 -0,7,0,2,1,10962,3,0,1,11901,0,0,105245,107184,96.95,481,1738745044537331700 -0,7,0,2,0,13714,2,0,1,13352,0,0,79644,81535,94.55,482,1738745044615319300 -0,7,0,2,1,5971,5,0,0,5876,5,0,54038,56006,98.4,483,1738745044691332900 -0,7,0,2,0,2835,7,0,1,2483,1,0,28437,30446,100.45,484,1738745044769313800 -0,7,0,2,0,465,0,0,1,883,0,0,2831,4847,100.8,485,1738745044847327800 -0,7,0,2,0,11921,3,0,1,11530,0,0,108301,110688,119.35,486,1738745044923303900 -0,7,0,2,1,15441,4,0,1,15782,5,0,82696,84441,87.25,487,1738745045001343800 -0,7,0,2,1,5648,5,0,0,4752,6,0,57094,59140,102.3,488,1738745045079457200 -0,7,0,2,0,2256,0,0,1,6214,0,0,31488,33759,113.55,489,1738745045155317400 -0,7,0,2,1,944,1,0,1,546,5,0,5886,7705,90.95,490,1738745045233326900 -0,7,0,2,0,11632,6,0,0,11481,4,0,111355,113527,108.6,491,1738745045311468100 -0,7,0,2,1,15665,5,0,0,16264,0,0,85750,87936,109.3,492,1738745045387260300 -0,7,0,2,0,5105,6,0,1,4475,1,0,60148,62097,97.45,493,1738745045465505400 -0,7,0,2,0,6323,1,0,1,6424,1,0,34542,36734,109.6,494,1738745045543346900 -0,7,0,2,0,1651,2,0,1,2006,3,0,8940,11042,105.1,495,1738745045619300400 -0,7,0,2,0,11314,4,0,0,9365,2,0,114407,116531,106.2,496,1738745045697285300 -0,7,0,2,1,16114,7,0,0,14881,0,0,88805,90608,90.15,497,1738745045775289500 -0,7,0,2,1,4530,0,0,1,4145,4,0,63200,65271,103.55,498,1738745045851284200 -0,7,0,2,0,7030,3,0,0,6876,4,0,37597,39751,107.7,499,1738745045929286900 -0,7,0,2,0,1846,5,0,1,1438,1,0,11993,14174,109.05,500,1738745046007286400 -0,7,0,2,1,9719,7,0,0,10070,4,0,117461,119591,106.5,501,1738745046085282700 -0,7,0,2,1,15031,2,0,1,15161,5,0,91859,93833,98.7,502,1738745046161280900 -0,7,0,2,0,12405,0,0,0,12731,5,0,66255,67945,84.5,503,1738745046239288500 -0,7,0,2,0,6709,2,0,0,7856,7,0,40652,42746,104.7,504,1738745046315403900 -0,7,0,2,0,1268,4,0,0,3189,3,0,15047,17101,102.7,505,1738745046393286100 -0,7,0,2,0,10164,7,0,1,9773,4,0,120517,122440,96.15,506,1738745046471282300 -0,7,0,2,0,14708,0,0,1,14503,6,0,94912,96724,90.6,507,1738745046549259600 -0,7,0,2,1,12604,3,0,1,13217,6,0,69309,71179,93.5,508,1738745046625266600 -0,7,0,2,0,8188,4,0,0,7516,5,0,43704,45894,109.5,509,1738745046703261400 -0,7,0,2,1,3261,5,0,1,3345,0,0,18102,20239,106.85,510,1738745046781294100 -0,7,0,2,1,8829,6,0,1,9134,0,0,123572,125344,88.6,511,1738745046857299600 -0,7,0,2,1,14399,1,0,0,10429,2,0,97966,100019,102.65,512,1738745046935264000 -0,7,0,2,1,13055,6,0,1,13906,6,0,72363,74523,108.0,513,1738745047013416200 -0,7,0,2,0,7614,5,0,0,7221,6,0,46758,48843,104.25,514,1738745047089263300 -0,7,0,2,1,3966,6,0,0,3785,0,0,21156,23439,114.15,515,1738745047167259500 -0,7,0,2,1,9022,0,0,0,8633,0,0,126624,128655,101.55,516,1738745047245257200 -0,7,0,2,0,10746,3,0,0,11047,5,0,101021,102870,92.45,517,1738745047321257900 -0,7,0,2,0,14010,4,0,0,14099,6,0,75416,77588,108.6,518,1738745047399264600 -0,7,0,2,0,5243,7,0,0,5616,7,0,49813,51962,107.45,519,1738745047477380100 -0,7,0,2,0,3643,2,0,1,2784,6,0,24211,26107,94.8,520,1738745047553238800 -0,7,0,2,1,8441,3,0,0,74,0,0,129677,131999,116.1,521,1738745047631237200 -0,7,0,2,1,11193,2,0,1,10784,2,0,104076,105987,95.55,522,1738745047709463600 -0,7,0,2,1,13688,5,0,0,13566,5,0,78470,80550,104.0,523,1738745047787237900 -0,7,0,2,1,5432,6,0,1,6024,7,0,52868,55173,115.25,524,1738745047863238700 -0,7,0,2,1,3064,0,0,0,2400,7,0,27264,29189,96.25,525,1738745047941247000 -0,7,0,2,0,168,3,0,0,310,5,0,1661,3801,107.0,526,1738745048019252600 -0,7,0,2,0,11880,4,0,1,12245,5,0,107128,109366,111.9,527,1738745048095233600 -0,7,0,2,0,13353,7,0,0,15546,0,0,81525,83615,104.5,528,1738745048173248400 -0,7,0,2,0,5865,3,0,1,4643,5,0,55922,57833,95.55,529,1738745048251241700 -0,7,0,2,1,2475,1,0,1,2058,4,0,30318,32664,117.3,530,1738745048327220200 -0,7,0,2,1,875,6,0,1,727,0,0,4715,6959,112.2,531,1738745048405356500 -0,7,0,2,1,12074,5,0,0,11671,7,0,110182,112426,112.2,532,1738745048483214300 -0,7,0,2,1,15850,2,0,0,16254,2,0,84579,86691,105.6,533,1738745048559219700 -0,7,0,2,0,4782,0,0,0,4909,3,0,58975,61005,101.5,534,1738745048637219700 -0,7,0,2,0,6254,3,0,0,6647,5,0,33373,35542,108.45,535,1738745048715212200 -0,7,0,2,1,559,4,0,0,1675,2,0,7767,10131,118.2,536,1738745048791204000 -0,7,0,2,0,11503,7,0,1,9337,0,0,113237,115343,105.3,537,1738745048869219400 -0,7,0,2,1,16303,0,0,0,15872,6,0,87632,90107,123.75,538,1738745048947215900 -0,7,0,2,1,4461,3,0,0,4319,2,0,62029,64339,115.5,539,1738745049023206000 -0,7,0,2,1,6445,7,0,0,7138,4,0,36426,38375,97.45,540,1738745049101334600 -0,7,0,2,1,2028,5,0,0,1383,7,0,10822,12842,101.0,541,1738745049179216900 -0,7,0,2,0,9388,2,0,1,9501,7,0,116291,118602,115.55,542,1738745049257214900 -0,7,0,2,1,14948,1,0,1,15312,1,0,90686,92929,112.15,543,1738745049333190600 -0,7,0,2,0,4132,2,0,0,12473,1,0,65084,67214,106.5,544,1738745049411188200 -0,7,0,2,1,6885,4,0,1,7791,0,0,39479,41552,103.65,545,1738745049489184100 -0,7,0,2,0,1445,7,0,0,1076,7,0,13877,16069,109.6,546,1738745049565185900 -0,7,0,2,1,10085,0,0,0,9903,1,0,119344,121262,95.9,547,1738745049643190100 -0,7,0,2,1,15143,1,0,0,14824,7,0,93742,95621,93.95,548,1738745049721246900 -0,7,0,2,0,12775,5,0,1,13170,2,0,68137,70371,111.7,549,1738745049797193600 -0,7,0,2,1,7846,7,0,1,8035,5,0,42533,44521,99.4,550,1738745049875186800 -0,7,0,2,1,3174,2,0,1,3561,4,0,16931,19063,106.6,551,1738745049953192300 -0,7,0,2,0,9762,1,0,0,8935,3,0,122398,124370,98.6,552,1738745050029181900 -0,7,0,2,0,14562,2,0,1,10367,4,0,96796,98984,109.4,553,1738745050107189700 -0,7,0,2,0,13219,5,0,1,12851,2,0,71190,73452,113.1,554,1738745050185187700 -0,7,0,2,0,7523,7,0,0,7356,7,0,45589,47429,92.0,555,1738745050261166800 -0,7,0,2,1,3363,0,0,0,4001,0,0,19984,22031,102.35,556,1738745050339389400 -0,7,0,2,0,9185,3,0,0,8553,1,0,125453,127601,107.4,557,1738745050417113200 -0,7,0,2,1,10401,4,0,0,10542,7,0,99848,101978,106.5,558,1738745050493157200 -0,7,0,2,0,13920,7,0,1,14330,7,0,74245,76442,109.85,559,1738745050571157300 -0,7,0,2,1,7200,1,0,1,5302,5,0,48641,50905,113.2,560,1738745050649185700 -0,7,0,2,1,3744,3,0,1,2650,7,0,23037,25445,120.4,561,1738745050725165100 -0,7,0,2,0,8672,2,0,0,8305,0,0,128508,130319,90.55,562,1738745050803160100 -0,7,0,2,1,11041,5,0,0,10968,2,0,102902,105340,121.9,563,1738745050881160700 -0,7,0,2,0,14177,6,0,0,13744,4,0,77300,79608,115.4,564,1738745050959168700 -0,7,0,2,0,5539,0,0,0,5990,2,0,51695,53795,105.0,565,1738745051035207800 -0,7,0,2,0,2787,2,0,1,2872,4,0,26092,28295,110.15,566,1738745051113284700 -0,7,0,2,1,35,4,0,0,506,2,0,488,2716,111.4,567,1738745051191166900 -0,7,0,2,0,10850,7,0,0,11942,1,0,105957,108065,105.4,568,1738745051267157400 -0,7,0,2,0,13474,1,0,0,15388,0,0,80353,82111,87.9,569,1738745051345137300 -0,7,0,2,1,6118,3,0,1,5677,0,0,54749,56911,108.1,570,1738745051423140300 -0,7,0,2,1,2342,6,0,1,2279,6,0,29147,31275,106.4,571,1738745051499132300 -0,7,0,2,1,359,5,0,1,1000,6,0,3542,5508,98.3,572,1738745051577140800 -0,7,0,2,1,12199,6,0,0,11554,0,0,109012,111072,103.0,573,1738745051655537200 -0,7,0,2,1,15589,0,0,0,15671,0,0,83407,85712,115.25,574,1738745051731136100 -0,7,0,2,0,4645,3,0,1,5036,0,0,57805,59839,101.7,575,1738745051809137500 -0,7,0,2,0,2149,4,0,0,6359,4,0,32200,34007,90.35,576,1738745051887143500 -0,7,0,2,0,676,7,0,0,1647,6,0,6597,8788,109.55,577,1738745051963151700 -0,7,0,2,0,11748,0,0,1,11322,7,0,112064,114330,113.3,578,1738745052041131200 -0,7,0,2,1,16172,1,0,0,16051,4,0,86462,88343,94.05,579,1738745052119137600 -0,7,0,2,0,4972,7,0,1,4491,7,0,60858,63381,126.15,580,1738745052195132200 -0,7,0,2,1,6573,5,0,1,6965,5,0,35254,37174,96.0,581,1738745052273181900 -0,7,0,2,1,1773,6,0,0,1837,4,0,9652,11848,109.8,582,1738745052351134000 -0,7,0,2,0,9263,1,0,0,9697,3,0,115118,117261,107.15,583,1738745052429119700 -0,7,0,2,0,15983,3,0,0,15099,3,0,89517,91501,99.2,584,1738745052505109600 -0,7,0,2,0,4270,5,0,1,12409,2,0,63910,66188,113.9,585,1738745052583111200 -0,7,0,2,0,7150,7,0,0,6776,0,0,38309,40319,100.5,586,1738745052661113100 -0,7,0,2,0,1326,0,0,0,1180,0,0,12704,14527,91.15,587,1738745052737114400 -0,7,0,2,1,9578,3,0,0,10226,0,0,118173,120095,96.1,588,1738745052815105600 -0,7,0,2,0,15274,4,0,1,14631,5,0,92568,94678,105.5,589,1738745052893116500 -0,7,0,2,1,12523,7,0,0,12664,3,0,66965,68989,101.2,590,1738745052969110700 -0,7,0,2,0,7723,2,0,0,8110,3,0,41363,43426,103.15,591,1738745053047107300 -0,7,0,2,1,1129,1,0,0,3248,3,0,15758,18173,120.75,592,1738745053125236900 -0,7,0,2,1,9897,2,0,1,8737,1,0,121228,123377,107.45,593,1738745053201085400 -0,7,0,2,0,14824,5,0,1,14457,4,0,95622,97655,101.65,594,1738745053279095200 -0,7,0,2,1,13096,7,0,0,12977,5,0,70021,71945,96.2,595,1738745053357086600 -0,7,0,2,1,8040,0,0,0,7644,5,0,44416,46265,92.45,596,1738745053433101000 -0,7,0,2,0,3512,3,0,1,3870,7,0,18813,20645,91.6,597,1738745053511088100 -0,7,0,2,1,8952,4,0,0,9062,5,0,124280,126425,107.25,598,1738745053589083900 -0,7,0,2,1,10297,7,0,1,10668,5,0,98677,100793,105.8,599,1738745053665114600 -0,7,0,2,1,12921,6,0,1,13890,2,0,73076,74723,82.35,600,1738745053743125600 -0,7,0,2,1,7355,1,0,1,5246,1,0,47470,49825,117.75,601,1738745053821195500 -0,7,0,2,0,4091,6,0,0,3624,6,0,21867,24187,116.0,602,1738745053897086200 -0,7,0,2,0,8506,5,0,1,8421,3,0,127334,129586,112.6,603,1738745053975089700 -0,7,0,2,0,10618,6,0,0,11258,4,0,101732,103783,102.55,604,1738745054053087900 -0,7,0,2,1,14270,0,0,0,13588,7,0,76127,78021,94.7,605,1738745054131066800 -0,7,0,2,0,5374,3,0,1,5412,6,0,50525,52795,113.5,606,1738745054207068600 -0,7,0,2,1,2623,4,0,1,3060,4,0,24919,27335,120.8,607,1738745054285065900 -0,7,0,2,1,8319,5,0,0,69,0,0,130390,132047,82.85,608,1738745054363065200 -0,7,0,2,1,10943,3,0,0,11873,3,0,104786,107021,111.75,609,1738745054439190000 -0,7,0,2,1,13821,3,0,1,13433,1,0,79181,81265,104.2,610,1738745054517192200 -0,7,0,2,1,5949,2,0,0,5791,6,0,53580,55467,94.35,611,1738745054595095500 -0,7,0,2,1,2940,5,0,1,2546,1,0,27974,29982,100.4,612,1738745054671059000 -0,7,0,2,1,444,6,0,0,881,1,0,2372,4849,123.85,613,1738745054749081500 -0,7,0,2,0,12020,0,0,1,12130,1,0,107839,110049,110.5,614,1738745054827068200 -0,7,0,2,0,15412,3,0,0,15752,7,0,82237,84090,92.65,615,1738745054903064100 -0,7,0,2,1,5748,4,0,1,4832,5,0,56632,58873,112.05,616,1738745054981058700 -0,7,0,2,0,2229,7,0,0,6195,6,0,31029,33044,100.75,617,1738745055059195500 -0,7,0,2,1,1013,2,0,1,604,4,0,5427,7352,96.25,618,1738745055135164900 -0,7,0,2,0,11575,3,0,1,11502,2,0,110893,113244,117.55,619,1738745055213050500 -0,7,0,2,1,15735,7,0,0,16366,1,0,85290,87457,108.35,620,1738745055291032800 -0,7,0,2,1,5046,7,0,1,4460,1,0,59685,62017,116.6,621,1738745055367155900 -0,7,0,2,0,6390,6,0,0,6520,0,0,34084,36223,106.95,622,1738745055445031800 -0,7,0,2,0,1586,1,0,1,1968,0,0,8478,10496,100.9,623,1738745055523039700 -0,7,0,2,0,11378,2,0,0,9455,7,0,113948,116138,109.5,624,1738745055601038400 -0,7,0,2,1,16051,4,0,1,14896,0,0,88343,90368,101.25,625,1738745055677049400 -0,7,0,2,1,4595,7,0,0,4221,3,0,62741,64845,105.2,626,1738745055755043600 -0,7,0,2,1,6963,0,0,1,6837,4,0,37136,39223,104.35,627,1738745055833036600 -0,7,0,2,1,1905,3,0,0,1531,2,0,11533,13676,107.15,628,1738745055908995400 -0,7,0,2,0,9649,6,0,0,10085,4,0,117003,119351,117.4,629,1738745055987017900 -0,7,0,2,1,15088,7,0,0,15186,6,0,91397,93412,100.75,630,1738745056065009800 -0,7,0,2,1,12336,2,0,0,12732,1,0,65795,67905,105.5,631,1738745056141018500 -0,7,0,2,1,6736,1,0,1,7922,6,0,40190,42267,103.85,632,1738745056219020500 -0,7,0,2,0,1168,3,0,1,1055,5,0,14589,16214,81.25,633,1738745056297012000 -0,7,0,2,0,10193,4,0,0,9811,2,0,120055,122092,101.85,634,1738745056373006800 -0,7,0,2,0,14609,7,0,1,14523,5,0,94453,96617,108.2,635,1738745056451016400 -0,7,0,2,1,12627,0,0,0,13255,3,0,68847,70701,92.7,636,1738745056529195100 -0,7,0,2,1,8083,3,0,0,7428,1,0,43245,45118,93.65,637,1738745056605018300 -0,7,0,2,0,3283,4,0,0,3445,4,0,17640,19767,106.35,638,1738745056683015900 -0,7,0,2,1,8722,7,0,1,9147,2,0,123109,125292,109.15,639,1738745056761024200 -0,7,0,2,1,14418,1,0,0,10474,4,0,97505,99736,111.55,640,1738745056837014400 -0,7,0,2,1,12950,3,0,0,13877,1,0,71901,74033,106.6,641,1738745056915009800 -0,7,0,2,1,7638,2,0,1,7261,5,0,46300,48310,100.5,642,1738745056992997100 -0,7,0,2,0,3863,5,0,0,3774,3,0,20694,22877,109.15,643,1738745057069124300 -0,7,0,2,0,9047,7,0,1,8657,4,0,126165,128247,104.1,644,1738745057147116700 -0,7,0,2,0,10645,0,0,1,11057,1,0,100559,102670,105.55,645,1738745057224987400 -0,7,0,2,0,14037,3,0,1,14166,6,0,74957,77019,103.1,646,1738745057303012900 -0,7,0,2,1,5141,4,0,1,5556,2,0,49352,51516,108.2,647,1738745057378982600 -0,7,0,2,0,3668,7,0,1,2787,4,0,23749,26088,116.95,648,1738745057457109400 -0,7,0,2,0,8340,0,0,0,22,3,0,129216,131293,103.85,649,1738745057535115400 -0,7,0,2,1,11228,1,0,1,10846,1,0,103614,105633,100.95,650,1738745057611114900 -0,7,0,2,1,13596,2,0,1,13448,5,0,78012,79993,99.05,651,1738745057689019500 -0,7,0,2,1,5469,5,0,0,6132,0,0,52406,54591,109.25,652,1738745057767154800 -0,7,0,2,0,2973,2,0,0,2312,3,0,26803,28797,99.7,653,1738745057843021000 -0,7,0,2,0,223,1,0,0,328,1,0,1198,3198,100.0,654,1738745057921011100 -0,7,0,2,0,11807,2,0,0,12213,5,0,106668,108854,109.3,655,1738745057998963300 -0,7,0,2,1,13407,4,0,0,15555,5,0,81064,82966,95.1,656,1738745058074980000 -0,7,0,2,0,5790,7,0,1,5645,6,0,55461,57268,90.35,657,1738745058152993000 -0,7,0,2,0,2526,0,0,0,2131,1,0,29856,31982,106.3,658,1738745058230986500 -0,7,0,2,1,794,3,0,1,699,6,0,4253,6507,112.7,659,1738745058307125300 -0,7,0,2,1,12122,5,0,0,11733,1,0,109721,111822,105.05,660,1738745058385099800 -0,7,0,2,1,15771,5,0,1,15619,2,0,84118,85996,93.9,661,1738745058463120000 -0,7,0,2,1,4827,2,0,0,4950,2,0,58515,60636,106.05,662,1738745058538977200 -0,7,0,2,0,6169,1,0,1,6579,4,0,32910,35095,109.25,663,1738745058616983600 -0,7,0,2,0,601,2,0,1,1738,5,0,7308,9318,100.5,664,1738745058695639600 -0,7,0,2,1,11416,4,0,0,9245,5,0,112775,114870,104.75,665,1738745058770958200 -0,7,0,2,0,16344,6,0,1,15956,2,0,87172,89283,105.55,666,1738745058848960700 -0,7,0,2,1,4376,0,0,1,4535,7,0,61568,63189,81.05,667,1738745058926961200 -0,7,0,2,1,6472,3,0,1,7155,3,0,35965,38162,109.85,668,1738745059004953200 -0,7,0,2,0,1928,5,0,0,1330,4,0,10361,12568,110.35,669,1738745059080948400 -0,7,0,2,0,9417,7,0,0,9577,5,0,115829,118153,116.2,670,1738745059159063700 -0,7,0,2,0,14857,2,0,1,15241,5,0,90227,92278,102.55,671,1738745059237034300 -0,7,0,2,1,4171,1,0,1,12528,5,0,64622,66822,110.0,672,1738745059312938300 -0,7,0,2,1,6795,2,0,1,6668,4,0,39020,40888,93.4,673,1738745059390937800 -0,7,0,2,0,1482,5,0,1,1225,7,0,13414,15242,91.4,674,1738745059468941100 -0,7,0,2,0,9994,7,0,0,10140,0,0,118885,120640,87.75,675,1738745059544935000 -0,7,0,2,1,15182,0,0,0,14671,7,0,93279,95146,93.35,676,1738745059622939400 -0,7,0,2,1,12686,3,0,1,13080,0,0,67677,69760,104.15,677,1738745059700934900 -0,7,0,2,0,7886,5,0,0,8010,0,0,42073,44128,102.75,678,1738745059776965600 -0,7,0,2,1,3087,7,0,0,3464,1,0,16469,18558,104.45,679,1738745059854950500 -0,7,0,2,1,9807,2,0,1,8914,0,0,121939,124128,109.45,680,1738745059932935100 -0,7,0,2,1,14477,3,0,0,10291,1,0,96333,98577,112.2,681,1738745060008913500 -0,7,0,2,1,13261,6,0,0,12892,5,0,70731,72889,107.9,682,1738745060086913600 -0,7,0,2,0,7436,5,0,1,7308,2,0,45126,47171,102.25,683,1738745060164908300 -0,7,0,2,0,3404,7,0,0,3955,3,0,19525,21229,85.2,684,1738745060240927500 -0,7,0,2,1,9100,0,0,1,8975,1,0,124992,126894,95.1,685,1738745060318909600 -0,7,0,2,0,10436,3,0,1,10694,4,0,99389,101336,97.35,686,1738745060397052900 -0,7,0,2,1,13828,4,0,0,14230,5,0,73784,75993,110.45,687,1738745060472945600 -0,7,0,2,0,7237,7,0,1,5332,6,0,48181,50372,109.55,688,1738745060550908500 -0,7,0,2,0,3717,0,0,1,2576,1,0,22576,24830,112.7,689,1738745060628914700 -0,7,0,2,1,8647,1,0,0,8265,3,0,128046,130162,105.8,690,1738745060706917100 -0,7,0,2,1,11015,2,0,1,11154,2,0,102444,104220,88.8,691,1738745060782914300 -0,7,0,2,1,14150,5,0,0,13781,3,0,76838,79053,110.75,692,1738745060860904200 -0,7,0,2,1,5510,6,0,1,5902,4,0,51236,53336,105.0,693,1738745060938910300 -0,7,0,2,0,2754,0,0,0,2903,2,0,25631,27859,111.4,694,1738745061015011900 -0,7,0,2,1,2,3,0,1,184,7,0,29,1669,82.0,695,1738745061092968500 -0,7,0,2,1,10819,4,0,1,12004,5,0,105495,107974,123.95,696,1738745061170883000 -0,7,0,2,0,13443,7,0,0,13342,1,0,79893,81758,93.25,697,1738745061246895800 -0,7,0,2,1,6083,1,0,1,5842,3,0,54289,56093,90.2,698,1738745061324910000 -0,7,0,2,1,2305,3,0,0,2207,0,0,28685,30895,110.5,699,1738745061402915800 -0,7,0,2,0,321,2,0,0,849,6,0,3084,4875,89.55,700,1738745061478908200 -0,7,0,2,1,12160,7,0,0,12040,2,0,108549,110467,95.9,701,1738745061557056000 -0,7,0,2,1,15552,2,0,1,15839,5,0,82947,84822,93.75,702,1738745061634901700 -0,7,0,2,1,5632,1,0,0,5007,3,0,57342,59474,106.6,703,1738745061710930000 -0,7,0,2,0,2240,2,0,0,6238,4,0,31740,33624,94.2,704,1738745061788866800 -0,7,0,2,1,897,4,0,1,1560,7,0,6135,8325,109.5,705,1738745061866888500 -0,7,0,2,0,11585,7,0,1,11473,4,0,111605,113416,90.55,706,1738745061942890700 -0,7,0,2,1,15617,0,0,1,16304,2,0,86000,87804,90.2,707,1738745062020858300 -0,7,0,2,0,5059,3,0,1,4547,7,0,60397,62485,104.4,708,1738745062098864300 -0,7,0,2,1,6275,5,0,0,6932,4,0,34793,37063,113.5,709,1738745062176863700 -0,7,0,2,1,1602,7,0,0,1870,4,0,9189,11352,108.15,710,1738745062252879200 -0,7,0,2,1,11266,2,0,0,9348,2,0,114659,116675,100.8,711,1738745062330858700 -0,7,0,2,1,16070,1,0,0,14941,2,0,89054,90956,95.1,712,1738745062408880700 -0,7,0,2,1,4486,2,0,0,12293,0,0,63452,65584,106.6,713,1738745062484857400 -0,7,0,2,0,6983,4,0,1,6870,1,0,37847,39713,93.3,714,1738745062562860100 -0,7,0,2,0,1799,6,0,0,1165,2,0,12244,14412,108.4,715,1738745062640864300 -0,7,0,2,1,9671,0,0,0,10201,7,0,117712,119946,111.7,716,1738745062717881300 -0,7,0,2,1,14981,3,0,1,14596,4,0,92109,94264,107.75,717,1738745062794838100 -0,7,0,2,0,12357,4,0,1,12633,3,0,66504,68749,112.25,718,1738745062872840600 -0,7,0,2,1,6660,7,0,1,8068,1,0,40901,43070,108.45,719,1738745062948848400 -0,7,0,2,0,1220,2,0,0,3150,4,0,15299,17319,101.0,720,1738745063026850600 -0,7,0,2,1,10124,3,0,1,8752,5,0,120765,123142,118.85,721,1738745063104851600 -0,7,0,2,1,14668,2,0,1,14543,5,0,95164,97193,101.45,722,1738745063180958800 -0,7,0,2,0,12557,5,0,1,12936,2,0,69558,71804,112.3,723,1738745063258835900 -0,7,0,2,1,8141,6,0,0,7622,2,0,43956,46115,107.95,724,1738745063336848700 -0,7,0,2,0,3215,0,0,1,3847,4,0,18351,20520,108.45,725,1738745063412838200 -0,7,0,2,0,8783,3,0,0,9160,0,0,123821,125824,100.15,726,1738745063490835600 -0,7,0,2,1,14351,4,0,1,10653,2,0,98216,100531,115.75,727,1738745063568836200 -0,7,0,2,1,13006,7,0,1,14020,5,0,72613,74809,109.8,728,1738745063646841800 -0,7,0,2,0,7566,1,0,1,5131,4,0,47009,49256,112.35,729,1738745063722828500 -0,7,0,2,0,3914,3,0,1,3674,1,0,21405,23710,115.25,730,1738745063800813700 -0,7,0,2,1,8970,6,0,1,8589,7,0,126875,128949,103.7,731,1738745063878807200 -0,7,0,2,1,10699,5,0,1,11123,5,0,101270,103145,93.75,732,1738745063954819900 -0,7,0,2,1,13963,6,0,1,14104,0,0,75668,77695,101.35,733,1738745064032807300 -0,7,0,2,1,5193,1,0,0,5455,0,0,50062,52304,112.1,734,1738745064110813000 -0,7,0,2,0,3593,3,0,0,2737,3,0,24461,26354,94.65,735,1738745064186811300 -0,7,0,2,1,8392,4,0,1,204,1,0,129927,132161,111.7,736,1738745064264817900 -0,7,0,2,1,11144,7,0,1,10769,3,0,104325,106253,96.4,737,1738745064342811100 -0,7,0,2,0,13640,0,0,1,13521,6,0,78720,80651,96.55,738,1738745064418811900 -0,7,0,2,0,5400,3,0,1,6025,6,0,53117,55179,103.1,739,1738745064496813800 -0,7,0,2,0,3032,6,0,1,2383,5,0,27515,29609,104.7,740,1738745064574806100 -0,7,0,2,1,153,7,0,0,261,5,0,1909,4041,106.6,741,1738745064650789200 -0,7,0,2,0,11865,3,0,1,12158,6,0,107378,109915,126.85,742,1738745064728787900 -0,7,0,2,1,13339,1,0,1,15511,4,0,81774,83752,98.9,743,1738745064806797700 -0,7,0,2,0,5851,2,0,0,4701,2,0,56172,58188,100.8,744,1738745064882830000 -0,7,0,2,0,2458,4,0,1,6155,2,0,30567,32876,115.45,745,1738745064960790900 -0,7,0,2,0,858,7,0,1,590,5,0,4965,7257,114.6,746,1738745065038798900 -0,7,0,2,0,12058,0,0,0,11757,7,0,110432,112053,81.05,747,1738745065116821700 -0,7,0,2,1,15838,1,0,1,16173,4,0,84830,86455,81.25,748,1738745065192951800 -0,7,0,2,1,4766,5,0,0,4927,4,0,59225,61096,93.55,749,1738745065270782500 -0,7,0,2,1,6239,5,0,1,6489,7,0,33622,35978,117.8,750,1738745065348806700 -0,7,0,2,1,543,2,0,0,1712,7,0,8019,9978,97.95,751,1738745065424787900 -0,7,0,2,1,11485,1,0,1,9281,2,0,113486,115699,110.65,752,1738745065502786100 -0,7,0,2,1,16285,2,0,1,15898,5,0,87884,89958,103.7,753,1738745065580913300 -0,7,0,2,0,4444,5,0,0,4308,1,0,62278,64318,102.0,754,1738745065656890100 -0,7,0,2,1,6428,6,0,0,6814,0,0,36676,39072,119.8,755,1738745065734773600 -0,7,0,2,0,2004,0,0,0,1475,1,0,11071,13329,112.9,756,1738745065812778900 -0,7,0,2,0,9364,3,0,1,9482,2,0,116541,118684,107.15,757,1738745065888763800 -0,7,0,2,1,14932,5,0,0,15332,2,0,90937,92732,89.75,758,1738745065966759300 -0,7,0,2,0,4117,7,0,1,12675,4,0,65333,67607,113.7,759,1738745066044759700 -0,7,0,2,1,6869,2,0,1,7746,2,0,39731,41955,111.2,760,1738745066120769500 -0,7,0,2,1,1431,3,0,0,1035,0,0,14125,16272,107.35,761,1738745066198762400 -0,7,0,2,0,10071,2,0,0,9963,7,0,119596,121450,92.7,762,1738745066276776700 -0,7,0,2,0,15126,5,0,1,14485,3,0,93990,96461,123.55,763,1738745066352772700 -0,7,0,2,0,12758,6,0,0,13093,4,0,68388,70088,85.0,764,1738745066430761500 -0,7,0,2,1,7826,0,0,0,7948,5,0,42783,44985,110.1,765,1738745066508762500 -0,7,0,2,0,3154,2,0,1,3419,0,0,17180,19600,121.0,766,1738745066584898800 -0,7,0,2,1,9746,4,0,0,9092,7,0,122648,124986,116.9,767,1738745066662845600 -0,7,0,2,0,14547,7,0,0,10439,0,0,97045,99375,116.5,768,1738745066740734600 -0,7,0,2,1,13203,1,0,1,12808,7,0,71441,73605,108.2,769,1738745066818772000 -0,7,0,2,1,7505,1,0,1,7416,4,0,45838,47751,95.65,770,1738745066894746200 -0,7,0,2,1,3345,2,0,1,4079,5,0,20236,21929,84.65,771,1738745066972748000 -0,7,0,2,0,9168,5,0,1,8567,7,0,125702,127701,99.95,772,1738745067050745600 -0,7,0,2,1,10384,6,0,0,11032,0,0,100100,102528,121.4,773,1738745067126753100 -0,7,0,2,0,13936,0,0,1,14325,1,0,74495,76494,99.95,774,1738745067204862200 -0,7,0,2,0,7216,2,0,1,5255,5,0,48892,51158,113.3,775,1738745067282732900 From 9c05b5d7cef7df846991fb00ed59af6d53caa28a Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 7 May 2025 15:35:14 +0200 Subject: [PATCH 42/51] Refactoring. --- core/fmt.py | 104 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 29 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index 343849a..ca5c977 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -80,6 +80,24 @@ class AbstractAstroPixHit(ABC): fields are arbitrary subsets of a multi-byte word, it seemed more natural to describe the hit as a sequence of fields, each one with its own length in bits. + Note this is an abstract class that cannot be instantiated. Concrete subclasses + must by contract: + + * define the _LAYOUT class member, a dictionary mapping the names of the + fields in the underlying binary data structure to the corresponding width + in bits; + * define the _ATTRIBUTES class member, which typically contains all the keys + in the _LAYOUT dictionary, and, possibly, additional strings for class member + defined in the constructor---this is used to control the string formatting + and the file I/O; + * explicitely calculate the size (in bytes) of the hit structure. This can + be done by summing up the widths of the fields in _LAYOUT, and the staticmethod + ``_calculate_size()`` does just that. (Note this could be automatically done + at runtime, but since for simple, fixed-width hit strutures this is the same + for all the instances, it seemed more natural to accept the nuisance of doing + that in the class definition, avoiding the overhead that would be implied by + doing that over and over again for each object.) + Arguments --------- data : bytearray @@ -87,7 +105,7 @@ class AbstractAstroPixHit(ABC): """ _LAYOUT = None - _FIELD_NAMES = None + _ATTRIBUTES = None SIZE = None def __init__(self, data: bytearray) -> None: @@ -105,8 +123,12 @@ def __init__(self, data: bytearray) -> None: pos += width @staticmethod - def calculate_size(layout: dict[str, int]) -> int: - """Calculate the size of a hit in bytes. + def _calculate_size(layout: dict[str, int]) -> int: + """Calculate the size of a concrete hit data structure in bytes. + + This is achieved by summing up all the values in the _LAYOUT dictionary, + and does not include the size of the hit header and trailer within the + readout. Arguments --------- @@ -114,9 +136,11 @@ def calculate_size(layout: dict[str, int]) -> int: The layout of the hit, as a dictionary of field names and their respective widths in bits. """ - size, reminder = divmod(sum(layout.values()), 8) - print(size, reminder) - return (sum(layout.values()) + 7) // 8 + num_bits = sum(layout.values()) + size, reminder = divmod(num_bits, 8) + if reminder != 0: + raise RuntimeError(f'Invalid layout {layout}: size in bit ({num_bits}) is not a multiple of 8') + return size @staticmethod def gray_to_decimal(gray: int) -> int: @@ -190,19 +214,19 @@ def _text(self, attrs: tuple[str], fmts: tuple[str], separator: str) -> str: return f'{separator.join(vals)}\n' @classmethod - def text_header(cls, fields=None, separator=',') -> str: + def text_header(cls, attrs=None, separator=',') -> str: """Return a proper header for a text file representing a list of hits. """ - if fields is None: - fields = cls._FIELD_NAMES - return ','.join(fields) + if attrs is None: + attrs = cls._ATTRIBUTES + return ','.join(attrs) - def to_csv(self, fields=None) -> str: + def to_csv(self, attrs=None) -> str: """Return the hit representation in csv format. """ - if fields is None: - fields = self._FIELD_NAMES - return self._text(fields, fmts=None, separator=',') + if attrs is None: + attrs = self._ATTRIBUTES + return self._text(attrs, fmts=None, separator=',') def __eq__(self, other: 'AbstractAstroPixHit') -> bool: """Comparison operator---this is handy in the unit tests. @@ -212,7 +236,7 @@ def __eq__(self, other: 'AbstractAstroPixHit') -> bool: def __str__(self) -> str: """String formatting. """ - return self._repr(self._FIELD_NAMES) + return self._repr(self._ATTRIBUTES) class AstroPix3Hit(AbstractAstroPixHit): @@ -235,8 +259,8 @@ class AstroPix3Hit(AbstractAstroPixHit): 'tot_msb': 4, 'tot_lsb': 8 } - _FIELD_NAMES = tuple(_LAYOUT.keys()) + ('tot', 'tot_us') - SIZE = 5 + _ATTRIBUTES = tuple(_LAYOUT.keys()) + ('tot', 'tot_us') + SIZE = AbstractAstroPixHit._calculate_size(_LAYOUT) CLOCK_CYCLES_PER_US = 200. def __init__(self, data: bytearray) -> None: @@ -267,8 +291,8 @@ class AstroPix4Hit(AbstractAstroPixHit): 'ts_fine2': 3, 'ts_tdc2': 5 } - _FIELD_NAMES = tuple(_LAYOUT.keys()) + ('ts_dec1', 'ts_dec2', 'tot_us', 'trigger_id', 'timestamp') - SIZE = 8 + _ATTRIBUTES = tuple(_LAYOUT.keys()) + ('ts_dec1', 'ts_dec2', 'tot_us', 'trigger_id', 'timestamp') + SIZE = AbstractAstroPixHit._calculate_size(_LAYOUT) CLOCK_CYCLES_PER_US = 20. CLOCK_ROLLOVER = 2**17 @@ -317,15 +341,8 @@ class AbstractAstroPixReadout(ABC): to a binary file. A full readout comes in the form of a fixed-length bytearray object that is - padded at the end with a fixed byte (0xff). - - What remains when the padding bytes have been removed should be a sequence of - frames of the form - - bcbc ... hit data ... bcbcbcbcbcbc - - where the hit data are 8-byte long and encapsulate all the information within - a single hit. + padded at the end with a padding byte (0xff). The hit data are surrounded by a + (generally variable) number of idle bytes (0xbc). Arguments --------- @@ -342,7 +359,9 @@ class AbstractAstroPixReadout(ABC): # The padding byte used to pad the readout. _PADDING_BYTE = bytes.fromhex('ff') - # The readout header---this is prepended to the buffer read from the NEXYS board + # The idle byte, + _IDLE_BYTE = bytes.fromhex('bc') + # The readout header, which is prepended to the buffer read from the NEXYS board # before the thing gets written to disk. _HEADER = bytes.fromhex('fedcba') _HEADER_SIZE = len(_HEADER) @@ -388,6 +407,16 @@ def from_file(cls, input_file: typing.BinaryIO) -> AbstractAstroPixReadout: A file object opened in "rb" mode. """ + @abstractmethod + def decode(self, reverse: bool = True) -> list[AbstractAstroPixHit]: + """Decode the underlying data and turn them into a list of hits. + + Arguments + --------- + reverse : bool (default True) + If True, the bit order within each byte is reversed. + """ + @staticmethod def pack_and_write(output_file: typing.BinaryIO, value: typing.Any, fmt) -> None: """Convenience function to pack and write a fixed-size field to an output file. @@ -484,6 +513,23 @@ def from_file(cls, input_file: typing.BinaryIO) -> AstroPix4Readout: def decode(self, reverse: bool = True) -> list[AstroPix4Hit]: """Decode the underlying data and turn them into a list of hits. + Here is some important details about the underlying generation of idle bytes, + verbatim from a comment by Nicolas to the github pull request + https://github.com/AstroPix/astropix-python/pull/22 + + Regarding the number of IDLE bytes ("BC"), you typically see two when you start + reading from the chip. This happens because the chip's SPI interface is clocked + by the SPI master in the DAQ. The data isn't immediately available because it + has to be transferred from an asynchronous FIFO to a FSM and then to the SPI + arbiter which needs few clock cycles. While the chip is preparing the data, it + sends out two IDLE bytes. After these 16 spi clock cycles, data is ready and + the chip can start transmitting. As the data is being read, the chip uses the + clock cycles to fetch new data, allowing multiple data words to be transmitted + without IDLE bytes in between or just one. The "line break" shown by @grant-sommer + is due to the fact that the firmware reads a certain number of bytes which is + not synchronized to beginning or ending of dataframes coming from the chip, + so it might just stop reading in the middle of a frame. + Arguments --------- reverse : bool (default True) From 90852e6732da2954c4142be8a6f2127dae5509d6 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 7 May 2025 14:01:09 +0200 Subject: [PATCH 43/51] Minor. --- core/fmt.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index ca5c977..2ded42a 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -21,6 +21,7 @@ from abc import ABC, abstractmethod from contextlib import contextmanager +from enum import Enum import json import struct import typing @@ -332,6 +333,16 @@ def _compose_ts(ts_coarse: int, ts_fine: int) -> int: return AbstractAstroPixHit.gray_to_decimal((ts_coarse << 3) + ts_fine) +class ReadoutProtocol(Enum): + + """Enum class encapsulating the special bytes used in the AstroPix readout. + """ + + PADDING_BYTE = bytes.fromhex('ff') + IDLE_BYTE = bytes.fromhex('bc') + HEADER = bytes.fromhex('fedcba') + + class AbstractAstroPixReadout(ABC): """Abstract base class for a generic AstroPix readout. @@ -358,7 +369,7 @@ class AbstractAstroPixReadout(ABC): """ # The padding byte used to pad the readout. - _PADDING_BYTE = bytes.fromhex('ff') + #_PADDING_BYTE = bytes.fromhex('ff') # The idle byte, _IDLE_BYTE = bytes.fromhex('bc') # The readout header, which is prepended to the buffer read from the NEXYS board @@ -380,7 +391,7 @@ def __init__(self, trigger_id: int, timestamp: int, hit_data: bytearray) -> None self.trigger_id = trigger_id self.timestamp = timestamp # Strip all the trailing padding bytes from the input bytearray object. - self._hit_data = hit_data.rstrip(self._PADDING_BYTE) + self._hit_data = hit_data.rstrip(ReadoutProtocol.PADDING_BYTE.value) @abstractmethod def write(self, output_file: typing.BinaryIO) -> None: From 0186bfc3cf6c105f5d63f1460716637ffbe5d809 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 7 May 2025 14:53:43 +0200 Subject: [PATCH 44/51] Refactoring. --- core/fmt.py | 147 +++++++++++++++++----------------------------------- 1 file changed, 47 insertions(+), 100 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index 2ded42a..2d00f53 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -21,7 +21,6 @@ from abc import ABC, abstractmethod from contextlib import contextmanager -from enum import Enum import json import struct import typing @@ -333,16 +332,6 @@ def _compose_ts(ts_coarse: int, ts_fine: int) -> int: return AbstractAstroPixHit.gray_to_decimal((ts_coarse << 3) + ts_fine) -class ReadoutProtocol(Enum): - - """Enum class encapsulating the special bytes used in the AstroPix readout. - """ - - PADDING_BYTE = bytes.fromhex('ff') - IDLE_BYTE = bytes.fromhex('bc') - HEADER = bytes.fromhex('fedcba') - - class AbstractAstroPixReadout(ABC): """Abstract base class for a generic AstroPix readout. @@ -368,20 +357,25 @@ class AbstractAstroPixReadout(ABC): The readout data from the NEXYS board. """ + # The class representing the hit type encoded in the file, e.g., ``AstroPix4Hit``. + HIT_CLASS = None + # The padding byte used to pad the readout. - #_PADDING_BYTE = bytes.fromhex('ff') - # The idle byte, - _IDLE_BYTE = bytes.fromhex('bc') + PADDING_BYTE = bytes.fromhex('ff') + + # The idle byte, output by the chip while gathering data. + IDLE_BYTE = bytes.fromhex('bc') + # The readout header, which is prepended to the buffer read from the NEXYS board # before the thing gets written to disk. _HEADER = bytes.fromhex('fedcba') _HEADER_SIZE = len(_HEADER) + # Basic bookkeeping for the additional fields assigned by the host machine. _TRIGGER_ID_FMT = ' None self.trigger_id = trigger_id self.timestamp = timestamp # Strip all the trailing padding bytes from the input bytearray object. - self._hit_data = hit_data.rstrip(ReadoutProtocol.PADDING_BYTE.value) - - @abstractmethod - def write(self, output_file: typing.BinaryIO) -> None: - """Write the complete readout to a binary file. - - Arguments - --------- - output_file : BinaryIO - A file object opened in "wb" mode. - """ - - @classmethod - @abstractmethod - def from_file(cls, input_file: typing.BinaryIO) -> AbstractAstroPixReadout: - """Create a Readout object reading the underlying data from an input binary file. - - By contract this should return None when there are no more data to be - read from the input file, so that downstream code can use the information - to stop iterating over the file. - - Arguments - --------- - input_file : BinaryIO - A file object opened in "rb" mode. - """ - - @abstractmethod - def decode(self, reverse: bool = True) -> list[AbstractAstroPixHit]: - """Decode the underlying data and turn them into a list of hits. - - Arguments - --------- - reverse : bool (default True) - If True, the bit order within each byte is reversed. - """ + self._hit_data = hit_data.rstrip(self.PADDING_BYTE) @staticmethod def pack_and_write(output_file: typing.BinaryIO, value: typing.Any, fmt) -> None: @@ -465,28 +424,13 @@ def read_and_unpack(input_file: typing.BinaryIO, fmt: str, size: int = None) -> size = struct.calcsize(fmt) return struct.unpack(fmt, input_file.read(size))[0] - -class AstroPix4Readout(AbstractAstroPixReadout): - - """Class describing an AstroPix 4 readout. - """ - - HIT_HEADER = bytes.fromhex('bcbc') - HIT_TRAILER = bytes.fromhex('bcbcbcbcbcbc') - HIT_DATA_SIZE = AstroPix4Hit.SIZE - HIT_HEADER_LENGTH = len(HIT_HEADER) - HIT_TRAILER_LENGTH = len(HIT_TRAILER) - HIT_LENGTH = HIT_HEADER_LENGTH + HIT_DATA_SIZE + HIT_TRAILER_LENGTH - def write(self, output_file: typing.BinaryIO) -> None: - """Implementation of the write() class method. - - We do write to file, in order: - * the readout header magic word; - * the trigger identifier; - * the timestamp; - * the length of the underlying hit data; - * the actual hit data. + """Write the complete readout to a binary file. + + Arguments + --------- + output_file : BinaryIO + A file object opened in "wb" mode. """ output_file.write(self._HEADER) self.pack_and_write(output_file, self.trigger_id, self._TRIGGER_ID_FMT) @@ -495,14 +439,17 @@ def write(self, output_file: typing.BinaryIO) -> None: output_file.write(self._hit_data) @classmethod - def from_file(cls, input_file: typing.BinaryIO) -> AstroPix4Readout: - """Implementation of the from_file() class method. - - This is reading all the relevant data from the input file and returns a - fully-fledged AstroPix4Readout object. The function returns None if there - are no more readouts to be read from the input file. Also, note that the - value of the readout header is checked at runtime, and a RuntimeError is - raised if it is not what we expect. + def from_file(cls, input_file: typing.BinaryIO) -> AbstractAstroPixReadout: + """Create a Readout object reading the underlying data from an input binary file. + + By contract this should return None when there are no more data to be + read from the input file, so that downstream code can use the information + to stop iterating over the file. + + Arguments + --------- + input_file : BinaryIO + A file object opened in "rb" mode. """ _header = input_file.read(cls._HEADER_SIZE) # If the header is empty, this means we are at the end of the file, and we @@ -519,10 +466,10 @@ def from_file(cls, input_file: typing.BinaryIO) -> AstroPix4Readout: trigger_id = cls.read_and_unpack(input_file, cls._TRIGGER_ID_FMT, cls._TRIGGER_ID_SIZE) timestamp = cls.read_and_unpack(input_file, cls._TIMESTAMP_FMT, cls._TIMESTAMP_SIZE) data = input_file.read(cls.read_and_unpack(input_file, cls._LENGTH_FMT, cls._LENGTH_SIZE)) - return AstroPix4Readout(trigger_id, timestamp, data) + return cls(trigger_id, timestamp, data) - def decode(self, reverse: bool = True) -> list[AstroPix4Hit]: - """Decode the underlying data and turn them into a list of hits. + def decode(self, reverse: bool = True) -> list[AbstractAstroPixHit]: + """Generic decoding function to be used by subclasses. Here is some important details about the underlying generation of idle bytes, verbatim from a comment by Nicolas to the github pull request @@ -548,27 +495,19 @@ def decode(self, reverse: bool = True) -> list[AstroPix4Hit]: """ hits = [] pos = 0 - # Loop over the underlying data. while pos < len(self._hit_data): - # Select the data portion corresponding to the next frame. - hit_data = self._hit_data[pos:pos + self.HIT_LENGTH] - - # Check that the frame header and trailer are what we expect. - header = hit_data[:self.HIT_HEADER_LENGTH] - if header != self.HIT_HEADER: - raise RuntimeError(f'Wrong frame header {header}, expected {self.HIT_HEADER}') - trailer = hit_data[-self.HIT_TRAILER_LENGTH:] - if trailer != self.HIT_TRAILER: - raise RuntimeError(f'Wrong frame trailer {header}, expected {self.HIT_TRAILER}') - - # Trim the hit data and get rid of the header and trailer. - hit_data = hit_data[self.HIT_HEADER_LENGTH:-self.HIT_TRAILER_LENGTH] + # Skip the idle bytes---note we need to address the input buffer with + # a proper slice, otherwise we get an int. + while self._hit_data[pos:pos + 1] == self.IDLE_BYTE: + pos += 1 + hit_data = self._hit_data[pos:pos + self.HIT_CLASS.SIZE] # If necessary, reverse the bit order in the hit data. if reverse: hit_data = reverse_bit_order(hit_data) - # Create a fully-fledged AstroPix4Hit object. - hits.append(AstroPix4Hit(hit_data, self.trigger_id, self.timestamp)) - pos += self.HIT_LENGTH + hits.append(self.HIT_CLASS(hit_data, self.trigger_id, self.timestamp)) + pos += self.HIT_CLASS.SIZE + while self._hit_data[pos:pos + 1] == self.IDLE_BYTE: + pos += 1 return hits def __str__(self) -> str: @@ -578,6 +517,14 @@ def __str__(self) -> str: f'trigger_id = {self.trigger_id}, timestamp = {self.timestamp} ns)' +class AstroPix4Readout(AbstractAstroPixReadout): + + """Class describing an AstroPix 4 readout. + """ + + HIT_CLASS = AstroPix4Hit + + class FileHeader: """Class describing a file header. From 9ed5a0b6ab0ecb9decd788104d31d5c133637465 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 7 May 2025 15:01:31 +0200 Subject: [PATCH 45/51] Small refactoring. --- core/fmt.py | 47 +++++++++++------------------------------------ 1 file changed, 11 insertions(+), 36 deletions(-) diff --git a/core/fmt.py b/core/fmt.py index 2d00f53..1366862 100644 --- a/core/fmt.py +++ b/core/fmt.py @@ -342,7 +342,8 @@ class AbstractAstroPixReadout(ABC): A full readout comes in the form of a fixed-length bytearray object that is padded at the end with a padding byte (0xff). The hit data are surrounded by a - (generally variable) number of idle bytes (0xbc). + (generally variable) number of idle bytes (0xbc), see the documentation of the + decode() class method. Arguments --------- @@ -357,7 +358,7 @@ class AbstractAstroPixReadout(ABC): The readout data from the NEXYS board. """ - # The class representing the hit type encoded in the file, e.g., ``AstroPix4Hit``. + # The class representing the hit type encoded in the readout, e.g., ``AstroPix4Hit``. HIT_CLASS = None # The padding byte used to pad the readout. @@ -373,11 +374,8 @@ class AbstractAstroPixReadout(ABC): # Basic bookkeeping for the additional fields assigned by the host machine. _TRIGGER_ID_FMT = ' None: """Constructor. @@ -388,24 +386,7 @@ def __init__(self, trigger_id: int, timestamp: int, hit_data: bytearray) -> None self._hit_data = hit_data.rstrip(self.PADDING_BYTE) @staticmethod - def pack_and_write(output_file: typing.BinaryIO, value: typing.Any, fmt) -> None: - """Convenience function to pack and write a fixed-size field to an output file. - - Arguments - --------- - output_file : BinaryIO - A file object opened in "wb" mode. - - value : any - The value to be written. - - fmt : str - The format string for the field to be written. - """ - output_file.write(struct.pack(fmt, value)) - - @staticmethod - def read_and_unpack(input_file: typing.BinaryIO, fmt: str, size: int = None) -> typing.Any: + def read_and_unpack(input_file: typing.BinaryIO, fmt: str) -> typing.Any: """Convenience function to read and unpack a fixed-size field from an input file. Arguments @@ -415,14 +396,8 @@ def read_and_unpack(input_file: typing.BinaryIO, fmt: str, size: int = None) -> fmt : str The format string for the field to be read. - - size : int, optional - The size of the field to be read. If not provided, it is calculated - from the format string. """ - if size is None: - size = struct.calcsize(fmt) - return struct.unpack(fmt, input_file.read(size))[0] + return struct.unpack(fmt, input_file.read(struct.calcsize(fmt)))[0] def write(self, output_file: typing.BinaryIO) -> None: """Write the complete readout to a binary file. @@ -433,9 +408,9 @@ def write(self, output_file: typing.BinaryIO) -> None: A file object opened in "wb" mode. """ output_file.write(self._HEADER) - self.pack_and_write(output_file, self.trigger_id, self._TRIGGER_ID_FMT) - self.pack_and_write(output_file, self.timestamp, self._TIMESTAMP_FMT) - self.pack_and_write(output_file, len(self._hit_data), self._LENGTH_FMT) + output_file.write(struct.pack(self._TRIGGER_ID_FMT, self.trigger_id)) + output_file.write(struct.pack(self._TIMESTAMP_FMT, self.timestamp)) + output_file.write(struct.pack(self._LENGTH_FMT, len(self._hit_data))) output_file.write(self._hit_data) @classmethod @@ -463,9 +438,9 @@ def from_file(cls, input_file: typing.BinaryIO) -> AbstractAstroPixReadout: if _header != cls._HEADER: raise RuntimeError(f'Invalid readout header ({_header}), expected {cls._HEADER}') # Go ahead, read all the fields, and create the AstroPix4Readout object. - trigger_id = cls.read_and_unpack(input_file, cls._TRIGGER_ID_FMT, cls._TRIGGER_ID_SIZE) - timestamp = cls.read_and_unpack(input_file, cls._TIMESTAMP_FMT, cls._TIMESTAMP_SIZE) - data = input_file.read(cls.read_and_unpack(input_file, cls._LENGTH_FMT, cls._LENGTH_SIZE)) + trigger_id = cls.read_and_unpack(input_file, cls._TRIGGER_ID_FMT) + timestamp = cls.read_and_unpack(input_file, cls._TIMESTAMP_FMT) + data = input_file.read(cls.read_and_unpack(input_file, cls._LENGTH_FMT)) return cls(trigger_id, timestamp, data) def decode(self, reverse: bool = True) -> list[AbstractAstroPixHit]: From 1740d4fdbb333c1723ac289176125c74baeff30c Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Wed, 7 May 2025 15:27:48 +0200 Subject: [PATCH 46/51] Minor. --- apx4_read.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apx4_read.py b/apx4_read.py index 3fef540..4bde7c5 100644 --- a/apx4_read.py +++ b/apx4_read.py @@ -175,8 +175,8 @@ def main(args): astro.close_connection() logger.info("Program terminated successfully!") - #if args.saveascsv: - # file_path = apxdf_to_csv(data_file_path, AstroPix4Hit) + if args.saveascsv: + file_path = apxdf_to_csv(data_file_path, AstroPix4Hit) if __name__ == "__main__": From 58ef9799ceb735ad753fd490fa10754d1397e4dc Mon Sep 17 00:00:00 2001 From: Luca BALDINI Date: Fri, 30 May 2025 14:34:46 +0200 Subject: [PATCH 47/51] Using the new astropix-analysis stuff. --- apx4_read.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/apx4_read.py b/apx4_read.py index 4bde7c5..8d48bfe 100644 --- a/apx4_read.py +++ b/apx4_read.py @@ -20,7 +20,8 @@ import logging import argparse -from core.fmt import AstroPix4Readout, FileHeader, AstroPixBinaryFile, AstroPix4Hit, apxdf_to_csv +from astropix_analysis.fmt import AstroPix4Hit, AstroPix4Readout +from astropix_analysis.fileio import FileHeader, apx_to_csv @@ -143,29 +144,29 @@ def main(args): # Start the event loop. # By enclosing the main loop in try/except we are able to capture keyboard interupts cleanly - num_readouts = 0 + readout_id = 0 try: while 1: # Check the stop conditions. if stop_time is not None and time.time() >= stop_time: break - if max_num_readouts is not None and num_readouts >= max_num_readouts: + if max_num_readouts is not None and readout_id >= max_num_readouts: break # Go ahead and readout data. readout_data = astro.get_readout() if readout_data: - num_readouts += 1 - _show = num_readouts % args.prescale == 0 - readout = AstroPix4Readout(num_readouts, time.time_ns(), readout_data) - if _show: - print(f'{num_readouts} readouts acquired, last is {readout}.') + readout = AstroPix4Readout(readout_data, readout_id) + readout_id += 1 + if readout_id % args.prescale == 0: + print(f'{readout_id} readouts acquired, last is {readout}.') readout.write(output_file) + # Ends program cleanly when a keyboard interupt is sent. except KeyboardInterrupt: logger.info('Keyboard interupt, exiting...') finally: - logger.info(f'Data acquisition interrupted after {num_readouts} readouts.') + logger.info(f'Data acquisition interrupted after {readout_id} readouts.') output_file.close() logger.info('Output file closed.') @@ -176,7 +177,7 @@ def main(args): logger.info("Program terminated successfully!") if args.saveascsv: - file_path = apxdf_to_csv(data_file_path, AstroPix4Hit) + file_path = apx_to_csv(data_file_path, AstroPix4Readout) if __name__ == "__main__": From 30a0989cd5ee899d11bebe65ad98957b358782fb Mon Sep 17 00:00:00 2001 From: Luca BALDINI Date: Fri, 30 May 2025 14:37:32 +0200 Subject: [PATCH 48/51] Obsolete files removed. --- core/fmt.py | 661 --------------- .../data/20250507_085829/20250507_085829.log | 33 - .../20250507_085829/20250507_085829_data.apx | Bin 28471 -> 0 bytes .../20250507_085829/20250507_085829_data.csv | 776 ------------------ .../config_v4_none_20250507_085829.yml | 201 ----- tests/test_fmt.py | 235 ------ 6 files changed, 1906 deletions(-) delete mode 100644 core/fmt.py delete mode 100644 tests/data/20250507_085829/20250507_085829.log delete mode 100644 tests/data/20250507_085829/20250507_085829_data.apx delete mode 100644 tests/data/20250507_085829/20250507_085829_data.csv delete mode 100644 tests/data/20250507_085829/config_v4_none_20250507_085829.yml delete mode 100644 tests/test_fmt.py diff --git a/core/fmt.py b/core/fmt.py deleted file mode 100644 index 1366862..0000000 --- a/core/fmt.py +++ /dev/null @@ -1,661 +0,0 @@ -# Copyright (C) 2025 the astropix team. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -"""Basic packet description for the astropix chips. -""" - -from __future__ import annotations - -from abc import ABC, abstractmethod -from contextlib import contextmanager -import json -import struct -import typing - -from loguru import logger - - -# Table to reverse the bit order within a byte---we pre-compute this once and -# forever to speedup the computation at runtime and avoid doing the same -# calculation over and over again. -_BIT_REVERSE_TABLE = bytes.maketrans( - bytes(range(256)), - bytes(int(f'{i:08b}'[::-1], 2) for i in range(256)) -) - - -def reverse_bit_order(data: bytearray) -> None: - """Reverses the bit order within of a bytearray.""" - return data.translate(_BIT_REVERSE_TABLE) - - -class BitPattern(str): - - """Small convenience class representing a bit pattern, that we can slice - (interpreting the result as the binary representation of an integer) without - caring about the byte boundaries. - - This is not very memory-efficient and probably not blazingly fast either, but - it allows to reason about the incoming bits in a straightforward fashion, and - I doubt we will ever need to optimize this. (If that is the case, there are - probably ways, using either numpy or the bitarray third-party package.) - - Arguments - --------- - data : bytes - The binary representation of the bit pattern. - """ - - def __new__(cls, data: bytes) -> None: - """Strings are immutable, so use __new__ to start. - """ - return super().__new__(cls, ''.join(f'{byte:08b}' for byte in data)) - - def __getitem__(self, index): - """Slice the underlying string and convert to integer in base 2. - """ - return int(super().__getitem__(index), 2) - - -class AbstractAstroPixHit(ABC): - - """Abstract base class for a generic AstroPix hit. - - While the original decode routine was working in terms of the various bytes - in the binary representation of the hit, since there seem to be no meaning - altogether in the byte boundaries (at least for AstroPix 4), and the various - fields are arbitrary subsets of a multi-byte word, it seemed more natural to - describe the hit as a sequence of fields, each one with its own length in bits. - - Note this is an abstract class that cannot be instantiated. Concrete subclasses - must by contract: - - * define the _LAYOUT class member, a dictionary mapping the names of the - fields in the underlying binary data structure to the corresponding width - in bits; - * define the _ATTRIBUTES class member, which typically contains all the keys - in the _LAYOUT dictionary, and, possibly, additional strings for class member - defined in the constructor---this is used to control the string formatting - and the file I/O; - * explicitely calculate the size (in bytes) of the hit structure. This can - be done by summing up the widths of the fields in _LAYOUT, and the staticmethod - ``_calculate_size()`` does just that. (Note this could be automatically done - at runtime, but since for simple, fixed-width hit strutures this is the same - for all the instances, it seemed more natural to accept the nuisance of doing - that in the class definition, avoiding the overhead that would be implied by - doing that over and over again for each object.) - - Arguments - --------- - data : bytearray - The portion of a full AstroPix readout representing a single hit. - """ - - _LAYOUT = None - _ATTRIBUTES = None - SIZE = None - - def __init__(self, data: bytearray) -> None: - """Constructor. - """ - # Since we don't need the underlying bit pattern to be mutable, turn the - # bytearray object into a bytes object. - self._data = bytes(data) - # Build a bit pattern to extract the fields and loop over the hit fields - # to set all the class members. - bit_pattern = BitPattern(self._data) - pos = 0 - for name, width in self._LAYOUT.items(): - self.__setattr__(name, bit_pattern[pos:pos + width]) - pos += width - - @staticmethod - def _calculate_size(layout: dict[str, int]) -> int: - """Calculate the size of a concrete hit data structure in bytes. - - This is achieved by summing up all the values in the _LAYOUT dictionary, - and does not include the size of the hit header and trailer within the - readout. - - Arguments - --------- - layout : dict - The layout of the hit, as a dictionary of field names and their - respective widths in bits. - """ - num_bits = sum(layout.values()) - size, reminder = divmod(num_bits, 8) - if reminder != 0: - raise RuntimeError(f'Invalid layout {layout}: size in bit ({num_bits}) is not a multiple of 8') - return size - - @staticmethod - def gray_to_decimal(gray: int) -> int: - """Convert a Gray code (integer) to decimal. - - A Gray code (or reflected binary code) is a binary numeral system where - two consecutive values differ by only one bit, which makes it useful in - error correction and minimizing logic transitions in digital circuits. - This function is provided as a convenience to translate counter values - encoded in Gray code into actual decimal values. - """ - decimal = gray # First bit is the same - mask = gray - while mask: - mask >>= 1 - decimal ^= mask # XOR each shifted bit - return decimal - - def _format_attributes(self, attrs: tuple[str], fmts: tuple[str] = None) -> tuple[str]: - """Helper function to join a given set of class attributes in a properly - formatted string. - - Arguments - --------- - attrs : tuple - The names of the class attributes we want to include in the representation. - - fmts : tuple, optional - If present determines the formatting of the given attributes. - """ - vals = (getattr(self, attr) for attr in attrs) - if fmts is None: - fmts = ('%s' for _ in attrs) - return tuple(fmt % val for val, fmt in zip(vals, fmts)) - - def _repr(self, attrs: tuple[str], fmts: tuple[str] = None) -> str: - """Helper function to provide sensible string formatting for the packets. - - The basic idea is that concrete classes would use this to implement their - `__repr__()` and/or `__str__()` special dunder methods. - - Arguments - --------- - attrs : tuple - The names of the class attributes we want to include in the representation. - - fmts : tuple, optional - If present determines the formatting of the given attributes. - """ - vals = self._format_attributes(attrs, fmts) - info = ', '.join([f'{attr}={val}' for attr, val in zip(attrs, vals)]) - return f'{self.__class__.__name__}({info})' - - def _text(self, attrs: tuple[str], fmts: tuple[str], separator: str) -> str: - """Helper function for text formatting. - - Note the output includes a trailing endline. - - Arguments - --------- - attrs : tuple - The names of the class attributes we want to include in the representation. - - fmts : tuple, - Determines the formatting of the given attributes. - - separator : str - The separator between different fields. - """ - vals = self._format_attributes(attrs, fmts) - return f'{separator.join(vals)}\n' - - @classmethod - def text_header(cls, attrs=None, separator=',') -> str: - """Return a proper header for a text file representing a list of hits. - """ - if attrs is None: - attrs = cls._ATTRIBUTES - return ','.join(attrs) - - def to_csv(self, attrs=None) -> str: - """Return the hit representation in csv format. - """ - if attrs is None: - attrs = self._ATTRIBUTES - return self._text(attrs, fmts=None, separator=',') - - def __eq__(self, other: 'AbstractAstroPixHit') -> bool: - """Comparison operator---this is handy in the unit tests. - """ - return self._data == other._data - - def __str__(self) -> str: - """String formatting. - """ - return self._repr(self._ATTRIBUTES) - - -class AstroPix3Hit(AbstractAstroPixHit): - - """Class describing an AstroPix3 hit. - - .. warning:: - - This is copied from decode.py and totally untested. - """ - - _LAYOUT = { - 'chip_id': 5, - 'payload': 3, - 'column': 1, - 'reserved1': 1, - 'location': 6, - 'timestamp': 8, - 'reserved2': 4, - 'tot_msb': 4, - 'tot_lsb': 8 - } - _ATTRIBUTES = tuple(_LAYOUT.keys()) + ('tot', 'tot_us') - SIZE = AbstractAstroPixHit._calculate_size(_LAYOUT) - CLOCK_CYCLES_PER_US = 200. - - def __init__(self, data: bytearray) -> None: - """Constructor. - """ - super().__init__(data) - # Calculate the TOT in physical units. - self.tot = (self.tot_msb << 8) + self.tot_lsb - self.tot_us = self.tot / self.CLOCK_CYCLES_PER_US - - -class AstroPix4Hit(AbstractAstroPixHit): - - """Class describing an AstroPix4 hit. - """ - - _LAYOUT = { - 'chip_id': 5, - 'payload': 3, - 'row': 5, - 'column': 5, - 'ts_neg1': 1, - 'ts_coarse1': 14, - 'ts_fine1': 3, - 'ts_tdc1': 5, - 'ts_neg2': 1, - 'ts_coarse2': 14, - 'ts_fine2': 3, - 'ts_tdc2': 5 - } - _ATTRIBUTES = tuple(_LAYOUT.keys()) + ('ts_dec1', 'ts_dec2', 'tot_us', 'trigger_id', 'timestamp') - SIZE = AbstractAstroPixHit._calculate_size(_LAYOUT) - CLOCK_CYCLES_PER_US = 20. - CLOCK_ROLLOVER = 2**17 - - def __init__(self, data: bytearray, trigger_id: int = None, timestamp: int = None) -> None: - """Constructor. - """ - super().__init__(data) - # Calculate the values of the two timestamps in clock cycles. - self.ts_dec1 = self._compose_ts(self.ts_coarse1, self.ts_fine1) - self.ts_dec2 = self._compose_ts(self.ts_coarse2, self.ts_fine2) - # Take into account possible rollovers. - if self.ts_dec2 < self.ts_dec1: - self.ts_dec2 += self.CLOCK_ROLLOVER - # Calculate the actual TOT in us. - self.tot_us = (self.ts_dec2 - self.ts_dec1) / self.CLOCK_CYCLES_PER_US - self.trigger_id = trigger_id - self.timestamp = timestamp - - @staticmethod - def _compose_ts(ts_coarse: int, ts_fine: int) -> int: - """Compose the actual decimal representation of the timestamp counter, - putting together the coarse and fine counters (in Gray code). - - Arguments - --------- - ts_coarse : int - The value of the coarse counter (MSBs) in Gray code. - - ts_fine : int - The value of the fine counter (3 LSBs) in Gray code. - - Returns - ------- - int - The actual decimal value of the timestamp counter, in clock cycles. - """ - return AbstractAstroPixHit.gray_to_decimal((ts_coarse << 3) + ts_fine) - - -class AbstractAstroPixReadout(ABC): - - """Abstract base class for a generic AstroPix readout. - - This is basically a wrapper around the bytearray object that is returned by - the NEXYS board, and it provides some basic functionality to write the readout - to a binary file. - - A full readout comes in the form of a fixed-length bytearray object that is - padded at the end with a padding byte (0xff). The hit data are surrounded by a - (generally variable) number of idle bytes (0xbc), see the documentation of the - decode() class method. - - Arguments - --------- - trigger_id : int - A sequential id for the readout, assigned by the host DAQ machine. - - timestamp : int - A timestamp for the readout, assigned by the host DAQ machine, in ns since - the epoch, from time.time_ns(). - - data : bytearray - The readout data from the NEXYS board. - """ - - # The class representing the hit type encoded in the readout, e.g., ``AstroPix4Hit``. - HIT_CLASS = None - - # The padding byte used to pad the readout. - PADDING_BYTE = bytes.fromhex('ff') - - # The idle byte, output by the chip while gathering data. - IDLE_BYTE = bytes.fromhex('bc') - - # The readout header, which is prepended to the buffer read from the NEXYS board - # before the thing gets written to disk. - _HEADER = bytes.fromhex('fedcba') - _HEADER_SIZE = len(_HEADER) - - # Basic bookkeeping for the additional fields assigned by the host machine. - _TRIGGER_ID_FMT = ' None: - """Constructor. - """ - self.trigger_id = trigger_id - self.timestamp = timestamp - # Strip all the trailing padding bytes from the input bytearray object. - self._hit_data = hit_data.rstrip(self.PADDING_BYTE) - - @staticmethod - def read_and_unpack(input_file: typing.BinaryIO, fmt: str) -> typing.Any: - """Convenience function to read and unpack a fixed-size field from an input file. - - Arguments - --------- - input_file : BinaryIO - A file object opened in "rb" mode. - - fmt : str - The format string for the field to be read. - """ - return struct.unpack(fmt, input_file.read(struct.calcsize(fmt)))[0] - - def write(self, output_file: typing.BinaryIO) -> None: - """Write the complete readout to a binary file. - - Arguments - --------- - output_file : BinaryIO - A file object opened in "wb" mode. - """ - output_file.write(self._HEADER) - output_file.write(struct.pack(self._TRIGGER_ID_FMT, self.trigger_id)) - output_file.write(struct.pack(self._TIMESTAMP_FMT, self.timestamp)) - output_file.write(struct.pack(self._LENGTH_FMT, len(self._hit_data))) - output_file.write(self._hit_data) - - @classmethod - def from_file(cls, input_file: typing.BinaryIO) -> AbstractAstroPixReadout: - """Create a Readout object reading the underlying data from an input binary file. - - By contract this should return None when there are no more data to be - read from the input file, so that downstream code can use the information - to stop iterating over the file. - - Arguments - --------- - input_file : BinaryIO - A file object opened in "rb" mode. - """ - _header = input_file.read(cls._HEADER_SIZE) - # If the header is empty, this means we are at the end of the file, and we - # return None to signal that there are no more readouts to be read. This - # can be used downstream, e.g., to raise a StopIteration exception with - # the implementation of an iterator protocol. - if len(_header) == 0: - return None - # If the header is not empty, we check that it is what we expect, and raise - # a RuntimeError if it is not. - if _header != cls._HEADER: - raise RuntimeError(f'Invalid readout header ({_header}), expected {cls._HEADER}') - # Go ahead, read all the fields, and create the AstroPix4Readout object. - trigger_id = cls.read_and_unpack(input_file, cls._TRIGGER_ID_FMT) - timestamp = cls.read_and_unpack(input_file, cls._TIMESTAMP_FMT) - data = input_file.read(cls.read_and_unpack(input_file, cls._LENGTH_FMT)) - return cls(trigger_id, timestamp, data) - - def decode(self, reverse: bool = True) -> list[AbstractAstroPixHit]: - """Generic decoding function to be used by subclasses. - - Here is some important details about the underlying generation of idle bytes, - verbatim from a comment by Nicolas to the github pull request - https://github.com/AstroPix/astropix-python/pull/22 - - Regarding the number of IDLE bytes ("BC"), you typically see two when you start - reading from the chip. This happens because the chip's SPI interface is clocked - by the SPI master in the DAQ. The data isn't immediately available because it - has to be transferred from an asynchronous FIFO to a FSM and then to the SPI - arbiter which needs few clock cycles. While the chip is preparing the data, it - sends out two IDLE bytes. After these 16 spi clock cycles, data is ready and - the chip can start transmitting. As the data is being read, the chip uses the - clock cycles to fetch new data, allowing multiple data words to be transmitted - without IDLE bytes in between or just one. The "line break" shown by @grant-sommer - is due to the fact that the firmware reads a certain number of bytes which is - not synchronized to beginning or ending of dataframes coming from the chip, - so it might just stop reading in the middle of a frame. - - Arguments - --------- - reverse : bool (default True) - If True, the bit order within each byte is reversed. - """ - hits = [] - pos = 0 - while pos < len(self._hit_data): - # Skip the idle bytes---note we need to address the input buffer with - # a proper slice, otherwise we get an int. - while self._hit_data[pos:pos + 1] == self.IDLE_BYTE: - pos += 1 - hit_data = self._hit_data[pos:pos + self.HIT_CLASS.SIZE] - # If necessary, reverse the bit order in the hit data. - if reverse: - hit_data = reverse_bit_order(hit_data) - hits.append(self.HIT_CLASS(hit_data, self.trigger_id, self.timestamp)) - pos += self.HIT_CLASS.SIZE - while self._hit_data[pos:pos + 1] == self.IDLE_BYTE: - pos += 1 - return hits - - def __str__(self) -> str: - """String formatting. - """ - return f'{self.__class__.__name__}({len(self._hit_data)} bytes, ' \ - f'trigger_id = {self.trigger_id}, timestamp = {self.timestamp} ns)' - - -class AstroPix4Readout(AbstractAstroPixReadout): - - """Class describing an AstroPix 4 readout. - """ - - HIT_CLASS = AstroPix4Hit - - -class FileHeader: - - """Class describing a file header. - - The content of the header can be literally anything that is json-serializable, - i.e., the only request that we make is that ``json.dumps(self._content)`` - is not raising an exception. - - The basic contract is that when the ``write()`` method is called we write - into the output binary file: - - * the header magic word (``%APXDF`` for AstroPix Data Format); - * the length of the header content in bytes; - * the actual header content. - - In the opposite direction, when the ``read()`` hook is called, we do: - - * read the first small chunk of the binary file and make sure the magic word is correct; - * read the header length; - * read and deserialize the header conten, returning a full fledges ``FileHeader`` object. - - Arguments - --------- - content : anything that is serializable - The header content. - """ - - MAGIC_WORD = '%APXDF' - _HEADER_LENGTH_FMT = 'I' - ENCODING = 'utf-8' - - def __init__(self, content: typing.Any) -> None: - """Constructor. - """ - self._content = content - - def write(self, output_file: typing.BinaryIO) -> None: - """Serialize the header structure to an output binary file. - - Arguments - --------- - output_file : BinaryIO - A file object opened in "wb" mode. - """ - output_file.write(self.MAGIC_WORD.encode(self.ENCODING)) - data = json.dumps(self._content).encode(self.ENCODING) - output_file.write(struct.pack(self._HEADER_LENGTH_FMT, len(data))) - output_file.write(data) - - @classmethod - def read(cls, input_file: typing.BinaryIO) -> 'FileHeader': - """De-serialize the header structure from an input binary file. - - Arguments - --------- - input_file : BinaryIO - A file object opened in "rb" mode. - """ - magic = input_file.read(len(cls.MAGIC_WORD)).decode(cls.ENCODING) - if magic != cls.MAGIC_WORD: - raise RuntimeError(f'Invalid magic word ({magic}), expected {cls.MAGIC_WORD}') - header_length = input_file.read(struct.calcsize(cls._HEADER_LENGTH_FMT)) - header_length = struct.unpack(cls._HEADER_LENGTH_FMT, header_length)[0] - content = json.loads(input_file.read(header_length).decode(cls.ENCODING)) - return cls(content) - - def __eq__(self, other: 'FileHeader') -> bool: - """Comparison operator---this is useful in the unit tests in order to make - sure that the serialization/deserialization roundtrips. - """ - return self._content == other._content - - def __str__(self) -> str: - """String representation. - """ - return f'{self._content}' - - -class AstroPixBinaryFile: - - """Class describing a binary file containing packets. - - .. warning:: - - At this point this only supports input files. Shall we consider extending - the interface for writing output files as well? - - Arguments - --------- - hit_class : type - The class representing the hit type encoded in the file, e.g., ``AstroPix4Hit``. - """ - - _EXTENSION = '.apx' - - def __init__(self, hit_class: type) -> None: - """Constructor. - """ - self._hit_class = hit_class - self._input_file = None - - @contextmanager - def open(self, file_path: str): - """Open the file. - - Arguments - --------- - file_path : str - Path to the file to be read. - """ - if not file_path.endswith(self._EXTENSION): - raise RuntimeError(f'Input file {file_path} has not the {self._EXTENSION} extension') - logger.info(f'Opening input file {file_path}...') - with open(file_path, 'rb') as input_file: - self._input_file = input_file - self.header = FileHeader.read(self._input_file) - yield self - self._input_file = None - logger.info(f'Input file {file_path} closed.') - - def __iter__(self) -> 'AstroPixBinaryFile': - """Return the iterator object (self). - """ - return self - - def __next__(self) -> AstroPix4Readout: - """Read the next packet in the buffer. - """ - readout = AstroPix4Readout.from_file(self._input_file) - if readout is None: - raise StopIteration - return readout - - -def _convert_apxdf(file_path: str, hit_class: type, converter: typing.Callable, - header: str = None, output_file_path: str = None, open_mode: str = 'w', - default_extension: str = None) -> str: - """Generic conversion factory for AstroPixBinaryFile objects. - """ - if output_file_path is None and default_extension is not None: - output_file_path = file_path.replace('.apx', default_extension) - logger.info(f'Converting AstroPix file to {output_file_path}...') - with AstroPixBinaryFile(hit_class).open(file_path) as input_file, \ - open(output_file_path, open_mode) as output_file: - if header is not None: - output_file.write(header) - for i, readout in enumerate(input_file): - for hit in readout.decode(): - output_file.write(converter(hit)) - logger.info(f'Done, {i + 1} hit(s) written') - return output_file_path - - -def apxdf_to_csv(file_path: str, hit_class: type = AstroPix4Hit, - output_file_path: str = None) -> str: - """Convert an AstroPix binary file to csv. - """ - header = f'# {AstroPix4Hit.text_header()}\n' - return _convert_apxdf(file_path, hit_class, hit_class.to_csv, header, output_file_path, 'w', '.csv') diff --git a/tests/data/20250507_085829/20250507_085829.log b/tests/data/20250507_085829/20250507_085829.log deleted file mode 100644 index 81489f4..0000000 --- a/tests/data/20250507_085829/20250507_085829.log +++ /dev/null @@ -1,33 +0,0 @@ -2025-05-07 08:58:29,282:282.__main__.INFO:Configuring the chip... -2025-05-07 08:58:31,321:321.core.nexysio.INFO:Digilent USB A opened -  -2025-05-07 08:58:31,321:321.astropix.INFO:Opened FPGA, testing... -2025-05-07 08:58:31,336:336.astropix.INFO:FPGA test successful. -2025-05-07 08:58:31,349:349.core.asic.WARNING:astropix4 Telescope config not found! -2025-05-07 08:58:31,349:349.core.asic.INFO:astropix4 Sample clock setup with 10 ns period found! -2025-05-07 08:58:31,349:349.core.asic.INFO:astropix4 matrix dimensions found! -2025-05-07 08:58:31,350:350.core.asic.INFO:astropix4 configcards found! -2025-05-07 08:58:31,350:350.core.asic.INFO:astropix4 config found! -2025-05-07 08:58:31,350:350.core.asic.INFO:astropix4 tdac config found! -2025-05-07 08:58:31,350:350.astropix.INFO:update_asic_config() got no arguments, nothing to do. -2025-05-07 08:58:31,350:350.astropix.INFO:enabling analog output in column 2 -2025-05-07 08:58:31,350:350.astropix.INFO:LOADING TO ASIC... -2025-05-07 08:58:31,461:461.core.asic.INFO:Wrote configbits successfully -2025-05-07 08:58:31,461:461.astropix.INFO:ASIC SUCCESSFULLY CONFIGURED -2025-05-07 08:58:31,463:463.core.asic.INFO:Set internal vdac: vinj to 0.300000 V (dacval: 170) -2025-05-07 08:58:31,474:474.core.spi.INFO:SPI: Send routing cmd -2025-05-07 08:58:31,478:478.astropix.INFO:SPI ENABLED -2025-05-07 08:58:31,589:589.core.asic.INFO:Wrote configbits successfully -2025-05-07 08:58:31,590:590.__main__.INFO:Chip fully configured! -2025-05-07 08:58:31,596:596.core.injectionboard.INFO: -Write Injection Config -=============================== -2025-05-07 08:58:31,596:596.core.injectionboard.INFO:Start injection -2025-05-07 08:58:31,597:597.astropix.INFO:Began injection -2025-05-07 08:58:31,597:597.__main__.INFO:Copying configuration to E:\data\astropix-output\20250507_085829\config_v4_none_20250507_085829.yml... -2025-05-07 08:58:31,608:608.__main__.INFO:Opening binary file E:\data\astropix-output\20250507_085829\20250507_085829_data.apx... -2025-05-07 08:59:31,608:608.__main__.INFO:Data acquisition interrupted after 775 readouts. -2025-05-07 08:59:31,609:609.__main__.INFO:Output file closed. -2025-05-07 08:59:31,610:610.core.injectionboard.INFO:Stop injection -2025-05-07 08:59:31,612:612.astropix.INFO:Stopped injection -2025-05-07 08:59:31,613:613.__main__.INFO:Program terminated successfully! diff --git a/tests/data/20250507_085829/20250507_085829_data.apx b/tests/data/20250507_085829/20250507_085829_data.apx deleted file mode 100644 index 12c5024979397e15a9fadf438c1dabc9ab5afacd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28471 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 WHz5NgJX`xSCDwn4pC9_ZM*k1PByC0j diff --git a/tests/data/20250507_085829/20250507_085829_data.csv b/tests/data/20250507_085829/20250507_085829_data.csv deleted file mode 100644 index 9ea2d51..0000000 --- a/tests/data/20250507_085829/20250507_085829_data.csv +++ /dev/null @@ -1,776 +0,0 @@ -# chip_id,payload,row,column,ts_neg1,ts_coarse1,ts_fine1,ts_tdc1,ts_neg2,ts_coarse2,ts_fine2,ts_tdc2,ts_dec1,ts_dec2,tot_us,trigger_id,timestamp -0,7,0,2,1,1852,0,0,1,1526,1,0,11967,13601,81.7,1,1746601111682511600 -0,7,0,2,1,9724,7,0,1,9476,5,0,117434,118726,64.6,2,1746601111758245700 -0,7,0,2,0,15036,4,0,1,15181,6,0,91832,93259,71.35,3,1746601111836079300 -0,7,0,2,0,12413,2,0,1,12691,0,0,66227,67823,79.8,4,1746601111914048100 -0,7,0,2,1,6717,0,0,0,7920,6,0,40624,42244,81.0,5,1746601111992057200 -0,7,0,2,0,1279,7,0,0,3113,1,0,15018,16782,88.2,6,1746601112068092300 -0,7,0,2,0,10175,4,0,1,9794,7,0,120488,121882,69.7,7,1746601112146124500 -0,7,0,2,1,14718,6,0,1,14489,5,0,94884,96393,75.45,8,1746601112224052400 -0,7,0,2,1,12606,1,0,1,13126,3,0,69281,70621,67.0,9,1746601112300086400 -0,7,0,2,1,8186,2,0,1,7476,6,0,43676,45371,84.75,10,1746601112377989800 -0,7,0,2,0,3258,5,0,0,3531,0,0,18073,19344,63.55,11,1746601112455967000 -0,7,0,2,1,8827,4,0,0,9116,3,0,123543,125117,78.7,12,1746601112532258100 -0,7,0,2,1,14395,1,0,1,10320,1,0,97937,99073,56.8,13,1746601112610060600 -0,7,0,2,1,13051,0,0,1,13839,4,0,72336,73815,73.95,14,1746601112688025300 -0,7,0,2,0,7609,7,0,1,7259,5,0,46730,48278,77.4,15,1746601112764037400 -0,7,0,2,1,3961,4,0,1,3743,2,0,21128,22700,78.6,16,1746601112842159400 -0,7,0,2,0,9016,6,0,0,8651,3,0,126596,128109,75.65,17,1746601112920155000 -0,7,0,2,0,10744,0,0,0,11025,1,0,100992,102641,82.45,18,1746601112996025900 -0,7,0,2,0,14008,0,0,1,14275,3,0,75392,76781,69.45,19,1746601113074131600 -0,7,0,2,1,5224,5,0,0,5514,2,0,49785,51299,75.7,20,1746601113152159800 -0,7,0,2,1,3624,4,0,1,2625,3,0,24184,25586,70.1,21,1746601113228032900 -0,7,0,2,1,8425,1,0,1,25,2,0,129649,131212,78.15,22,1746601113306029100 -0,7,0,2,1,11177,0,0,1,10837,7,0,104048,105674,81.3,23,1746601113384078600 -0,7,0,2,1,13675,5,0,0,13456,6,0,78441,80123,84.1,24,1746601113460025400 -0,7,0,2,0,5419,4,0,0,6099,0,0,52840,54511,83.55,25,1746601113538006800 -0,7,0,2,0,3050,3,0,0,2360,7,0,27234,29050,90.8,26,1746601113616018200 -0,7,0,2,0,170,0,0,1,345,6,0,1632,3211,78.95,27,1746601113692128500 -0,7,0,2,1,11886,6,0,1,12189,5,0,107099,108726,81.35,28,1746601113770014800 -0,7,0,2,0,13358,5,0,0,15582,5,0,81497,83110,80.65,29,1746601113847996000 -0,7,0,2,1,5871,5,0,0,4635,2,0,55894,57491,79.85,30,1746601113926003300 -0,7,0,2,0,2479,1,0,1,2160,0,0,30289,32000,85.55,31,1746601114002028000 -0,7,0,2,1,879,0,0,0,921,0,0,4688,6000,65.6,32,1746601114079988500 -0,7,0,2,1,12077,7,0,0,11590,2,0,110154,111580,71.3,33,1746601114156178700 -0,7,0,2,1,15853,4,0,1,16191,0,0,84552,86352,90.0,34,1746601114234168400 -0,7,0,2,0,4780,2,0,0,5061,0,0,58947,60367,71.0,35,1746601114312026700 -0,7,0,2,0,6252,0,0,1,6273,1,0,33344,34801,72.85,36,1746601114389999900 -0,7,0,2,0,548,6,0,1,1739,7,0,7739,9322,79.15,37,1746601114465978200 -0,7,0,2,0,11492,4,0,1,9223,1,0,113208,114734,76.3,38,1746601114543989700 -0,7,0,2,1,16293,6,0,1,15943,4,0,87604,89128,76.2,39,1746601114622012500 -0,7,0,2,0,4453,1,0,0,4232,3,0,62001,63613,80.6,40,1746601114698158100 -0,7,0,2,1,6439,0,0,1,6978,4,0,36399,37863,73.2,41,1746601114776013000 -0,7,0,2,1,2023,7,0,1,1809,6,0,10794,12043,62.45,42,1746601114854018400 -0,7,0,2,1,9382,4,0,0,9585,2,0,116263,118028,88.25,43,1746601114929993900 -0,7,0,2,1,14950,3,0,1,15002,7,0,90658,92005,67.35,44,1746601115007967200 -0,7,0,2,1,4134,0,0,0,12483,7,0,65056,66581,76.25,45,1746601115085982200 -0,7,0,2,1,6882,6,0,1,7731,5,0,39451,41238,89.35,46,1746601115162039200 -0,7,0,2,0,1442,5,0,0,1102,7,0,13849,15450,80.05,47,1746601115240095000 -0,7,0,2,1,10083,6,0,0,9856,7,0,119316,120837,76.05,48,1746601115317954700 -0,7,0,2,0,15139,0,0,0,14809,2,0,93712,95372,83.0,49,1746601115395951800 -0,7,0,2,0,12769,2,0,0,13070,0,0,68108,69727,80.95,50,1746601115471959400 -0,7,0,2,1,7841,5,0,1,8143,2,0,42505,43948,72.15,51,1746601115549962900 -0,7,0,2,0,3168,4,0,1,3209,5,0,16903,18313,70.5,52,1746601115627985600 -0,7,0,2,0,9760,1,0,0,8776,6,0,122369,123780,70.55,53,1746601115704094700 -0,7,0,2,0,14560,0,0,0,14387,7,0,96768,98026,62.9,54,1746601115782133800 -0,7,0,2,0,13280,7,0,0,12888,4,0,71162,72839,83.85,55,1746601115859968400 -0,7,0,2,0,7456,4,0,0,7311,1,0,45560,47185,81.25,56,1746601115935975100 -0,7,0,2,0,3425,3,0,0,4095,1,0,19954,21841,94.35,57,1746601116013962100 -0,7,0,2,0,9121,1,0,0,8987,2,0,125425,126828,70.15,58,1746601116091960500 -0,7,0,2,1,10467,3,0,1,10564,3,0,99821,101437,80.8,59,1746601116168071600 -0,7,0,2,0,13859,5,0,1,13959,1,0,74217,75729,75.6,60,1746601116246036900 -0,7,0,2,1,7266,4,0,1,5187,1,0,48615,50158,77.15,61,1746601116323944900 -0,7,0,2,0,3746,1,0,0,2565,7,0,23009,24629,81.0,62,1746601116400095600 -0,7,0,2,0,8678,0,0,0,8410,6,0,128479,129892,70.65,63,1746601116478103300 -0,7,0,2,1,11046,7,0,1,11185,6,0,102874,104180,65.3,64,1746601116556006100 -0,7,0,2,0,14182,4,0,0,13641,6,0,77272,78731,72.95,65,1746601116631963000 -0,7,0,2,1,5543,2,0,1,5384,6,0,51667,53124,72.85,66,1746601116709945700 -0,7,0,2,0,2791,0,0,0,3011,5,0,26064,27625,78.05,67,1746601116787933300 -0,7,0,2,0,39,0,0,0,243,1,0,464,1297,41.65,68,1746601116865974500 -0,7,0,2,0,10853,4,0,1,11980,4,0,105928,107591,83.15,69,1746601116941948300 -0,7,0,2,1,13476,4,0,1,13353,4,0,80327,81527,60.0,70,1746601117019928300 -0,7,0,2,0,6116,1,0,0,5704,3,0,54721,56445,86.2,71,1746601117097951100 -0,7,0,2,1,2340,0,0,0,2443,5,0,29120,30614,74.7,72,1746601117173925700 -0,7,0,2,0,364,5,0,0,842,2,0,3513,5020,75.35,73,1746601117252021400 -0,7,0,2,1,12205,4,0,0,12063,1,0,108983,110417,71.7,74,1746601117330020700 -0,7,0,2,0,15597,2,0,1,15837,5,0,83379,84809,71.5,75,1746601117406020000 -0,7,0,2,1,4653,0,0,1,5003,4,0,57776,59496,86.0,76,1746601117484026400 -0,7,0,2,1,2159,2,0,0,6212,4,0,32172,33735,78.15,77,1746601117561936900 -0,7,0,2,0,687,4,0,0,1541,6,0,6568,8244,83.8,78,1746601117637913700 -0,7,0,2,0,11758,7,0,0,11480,1,0,112037,113534,74.85,79,1746601117715912900 -0,7,0,2,1,16174,1,0,1,16270,5,0,86433,87974,77.05,80,1746601117793914900 -0,7,0,2,1,4974,0,0,1,4441,1,0,60832,62321,74.45,81,1746601117869915800 -0,7,0,2,1,6570,5,0,1,6415,2,0,35225,36780,77.75,82,1746601117947921100 -0,7,0,2,1,1770,4,0,1,1995,2,0,9624,11155,76.55,83,1746601118025918800 -0,7,0,2,0,9259,3,0,0,9362,6,0,115090,116507,70.85,84,1746601118101910100 -0,7,0,2,0,15979,1,0,1,14928,3,0,89489,90882,69.65,85,1746601118180008800 -0,7,0,2,0,4265,7,0,1,12343,3,0,63882,65837,97.75,86,1746601118257882300 -0,7,0,2,0,7145,4,0,1,6867,1,0,38280,39697,70.85,87,1746601118335898600 -0,7,0,2,1,1320,6,0,0,1416,2,0,12676,14211,76.75,88,1746601118411890200 -0,7,0,2,0,9576,1,0,0,10093,7,0,118145,119370,61.25,89,1746601118489886300 -0,7,0,2,0,15272,0,0,0,15144,0,0,92544,93823,63.95,90,1746601118567898200 -0,7,0,2,1,12536,5,0,1,12799,4,0,66937,68264,66.35,91,1746601118643886500 -0,7,0,2,1,7737,4,0,1,8073,2,0,41335,43123,89.4,92,1746601118721876000 -0,7,0,2,1,1145,3,0,1,3177,1,0,15730,17009,63.95,93,1746601118799888700 -0,7,0,2,1,9913,0,0,1,9742,7,0,121200,122789,79.45,94,1746601118875883000 -0,7,0,2,0,14843,6,0,0,14531,2,0,95595,97260,83.25,95,1746601118953891100 -0,7,0,2,1,13115,4,0,1,12976,6,0,69992,71940,97.4,96,1746601119031882300 -0,7,0,2,1,8058,2,0,0,7530,1,0,44387,45665,63.9,97,1746601119108016900 -0,7,0,2,1,3514,0,0,0,3328,3,0,18784,20477,84.65,98,1746601119185980600 -0,7,0,2,0,8958,1,0,1,9212,3,0,124254,125629,68.75,99,1746601119263853600 -0,7,0,2,0,10302,5,0,1,10424,3,0,98649,99970,66.05,100,1746601119339865800 -0,7,0,2,1,12927,5,0,1,13942,7,0,73046,74458,70.6,101,1746601119417861100 -0,7,0,2,0,7359,3,0,1,7293,1,0,47442,48462,51.0,102,1746601119495862600 -0,7,0,2,1,4093,0,0,1,3662,7,0,21839,23642,90.15,103,1746601119571985500 -0,7,0,2,1,8509,5,0,0,8320,1,0,127305,129025,86.0,104,1746601119649872000 -0,7,0,2,0,10621,4,0,1,11046,7,0,101704,102874,58.5,105,1746601119727859900 -0,7,0,2,0,14268,2,0,0,14107,4,0,76099,77672,78.65,106,1746601119805865300 -0,7,0,2,0,5372,1,0,1,5623,4,0,50497,51927,71.5,107,1746601119881859000 -0,7,0,2,1,2620,0,0,1,2733,7,0,24896,26186,64.5,108,1746601119959855200 -0,7,0,2,0,8308,5,0,0,117,7,0,130361,131786,71.25,109,1746601120037857100 -0,7,0,2,0,10933,5,0,0,11777,3,0,104758,106509,87.55,110,1746601120113837000 -0,7,0,2,1,13813,1,0,0,13552,6,0,79153,80635,74.1,111,1746601120191872900 -0,7,0,2,1,5943,0,0,0,6021,3,0,53551,55245,84.7,112,1746601120269829600 -0,7,0,2,0,2935,5,0,0,2498,1,0,27945,29726,89.05,113,1746601120345845200 -0,7,0,2,0,439,4,0,0,354,7,0,2344,3557,60.65,114,1746601120423828100 -0,7,0,2,0,12022,2,0,1,12232,3,0,107811,109442,81.55,115,1746601120501849200 -0,7,0,2,0,15414,0,0,1,15540,1,0,82208,83649,72.05,116,1746601120577834000 -0,7,0,2,0,5746,6,0,0,4733,7,0,56603,58037,71.7,117,1746601120655834500 -0,7,0,2,0,2226,4,0,0,2073,0,0,31000,32624,81.2,118,1746601120733844600 -0,7,0,2,1,1011,6,0,1,727,1,0,5396,6958,78.1,119,1746601120809836900 -0,7,0,2,0,11571,0,0,1,11655,2,0,110864,112595,86.55,120,1746601120887827300 -0,7,0,2,1,15729,3,0,0,16321,4,0,85261,87048,89.35,121,1746601120965808300 -0,7,0,2,0,5041,5,0,1,4907,6,0,59657,61035,68.9,122,1746601121041805300 -0,7,0,2,1,6385,4,0,1,6495,5,0,34056,36009,97.65,123,1746601121119939000 -0,7,0,2,0,1584,3,0,1,1785,5,0,8450,9590,57.0,124,1746601121197816600 -0,7,0,2,0,11376,0,0,0,9330,7,0,113920,115429,75.45,125,1746601121273808700 -0,7,0,2,1,16016,6,0,1,15904,1,0,88315,89601,64.3,126,1746601121351814600 -0,7,0,2,0,4560,4,0,1,4318,6,0,62712,64347,81.75,127,1746601121429812000 -0,7,0,2,0,6929,6,0,0,7059,7,0,37108,38677,78.45,128,1746601121507824100 -0,7,0,2,0,1873,1,0,0,1314,6,0,11505,12772,63.35,129,1746601121583830200 -0,7,0,2,1,9619,1,0,0,9516,1,0,116974,118337,68.15,130,1746601121661814500 -0,7,0,2,0,15059,5,0,0,15352,5,0,91369,92806,71.85,131,1746601121737948700 -0,7,0,2,0,12306,5,0,0,12435,5,0,65766,67350,79.2,132,1746601121815926600 -0,7,0,2,1,6738,3,0,0,7779,7,0,40162,41493,66.55,133,1746601121893789700 -0,7,0,2,1,1170,0,0,0,1121,1,0,14560,15857,64.85,134,1746601121971799300 -0,7,0,2,1,10198,7,0,0,9970,6,0,120026,121572,77.3,135,1746601122047808000 -0,7,0,2,0,14614,4,0,0,14740,1,0,94424,96062,81.9,136,1746601122125761300 -0,7,0,2,0,12630,4,0,0,13118,4,0,68824,69976,57.6,137,1746601122203775100 -0,7,0,2,0,8087,0,0,0,7957,7,0,43216,44853,81.85,138,1746601122279787000 -0,7,0,2,1,3285,0,0,1,3580,3,0,17615,19133,75.9,139,1746601122357786200 -0,7,0,2,0,8725,5,0,0,8931,6,0,123081,124395,65.7,140,1746601122435794600 -0,7,0,2,1,14420,4,0,0,10321,1,0,97479,99086,80.35,141,1746601122511792900 -0,7,0,2,0,12948,1,0,1,12853,1,0,71873,73422,77.45,142,1746601122589783700 -0,7,0,2,1,7636,0,0,0,7374,7,0,46272,48037,88.25,143,1746601122667835900 -0,7,0,2,1,3868,7,0,1,4011,7,0,20666,22122,72.8,144,1746601122743784800 -0,7,0,2,0,9052,4,0,1,8566,3,0,126136,127709,78.65,145,1746601122821804500 -0,7,0,2,0,10653,3,0,1,10536,7,0,100530,102010,74.0,146,1746601122899755500 -0,7,0,2,1,14045,0,0,0,14301,6,0,74928,76619,84.55,147,1746601122977768300 -0,7,0,2,1,5149,0,0,0,5371,0,0,49328,50543,60.75,148,1746601123053766900 -0,7,0,2,0,3679,5,0,1,2640,7,0,23721,25349,81.4,149,1746601123131906600 -0,7,0,2,0,8351,4,0,1,8297,6,0,129192,130443,62.55,150,1746601123207881500 -0,7,0,2,0,11230,1,0,1,10956,3,0,103585,105405,91.0,151,1746601123285879700 -0,7,0,2,0,13598,0,0,0,13741,6,0,77984,79435,72.55,152,1746601123363763000 -0,7,0,2,1,5466,5,0,0,5998,2,0,52377,53852,73.75,153,1746601123441765900 -0,7,0,2,0,2970,5,0,1,2925,0,0,26777,28080,65.15,154,1746601123517757200 -0,7,0,2,0,219,3,0,1,506,7,0,1170,2714,77.2,155,1746601123595772900 -0,7,0,2,0,11803,0,0,1,12029,3,0,106640,107853,60.65,156,1746601123673770000 -0,7,0,2,0,13401,7,0,1,15454,5,0,81034,82777,87.15,157,1746601123749893300 -0,7,0,2,0,5785,4,0,0,5692,5,0,55432,57017,79.25,158,1746601123827735900 -0,7,0,2,1,2520,7,0,1,2285,3,0,29829,31309,74.0,159,1746601123905741500 -0,7,0,2,0,792,1,0,1,954,1,0,4225,5790,78.25,160,1746601123981732200 -0,7,0,2,1,12104,0,0,1,11633,0,0,109695,111344,82.45,161,1746601124059740100 -0,7,0,2,0,15752,7,0,0,15675,0,0,84090,85648,77.9,162,1746601124137684400 -0,7,0,2,1,4808,4,0,1,5109,1,0,58488,60110,81.1,163,1746601124213761900 -0,7,0,2,0,6153,2,0,1,6309,1,0,32883,34353,73.5,164,1746601124291734600 -0,7,0,2,0,585,0,0,0,1641,1,0,7280,8817,76.85,165,1746601124370008300 -0,7,0,2,0,11403,6,0,1,11313,1,0,112747,114417,83.5,166,1746601124445875400 -0,7,0,2,0,16331,4,0,1,16111,0,0,87144,88656,75.6,167,1746601124523837000 -0,7,0,2,1,4362,6,0,0,4517,3,0,61540,63026,74.3,168,1746601124601866100 -0,7,0,2,0,6474,1,0,0,7019,4,0,35937,37480,77.15,169,1746601124677727700 -0,7,0,2,0,1934,2,0,0,1835,7,0,10332,11882,77.5,170,1746601124755746600 -0,7,0,2,0,9422,5,0,1,9720,7,0,115801,117381,79.0,171,1746601124833714900 -0,7,0,2,0,14863,4,0,0,14995,7,0,90199,91925,86.3,172,1746601124911726300 -0,7,0,2,1,4175,3,0,1,12344,6,0,64594,65915,66.05,173,1746601124987710300 -0,7,0,2,1,6799,0,0,0,6712,2,0,38992,40579,79.35,174,1746601125065715600 -0,7,0,2,0,1485,7,0,0,1238,7,0,13386,15141,87.75,175,1746601125143849800 -0,7,0,2,1,9997,4,0,0,10120,6,0,118856,120708,92.6,176,1746601125219716400 -0,7,0,2,1,15180,6,0,1,14631,1,0,93252,94673,71.05,177,1746601125297710700 -0,7,0,2,1,12684,1,0,0,12631,6,0,67649,68820,58.55,178,1746601125375843200 -0,7,0,2,1,7876,2,0,1,8110,2,0,42044,43427,69.15,179,1746601125451728000 -0,7,0,2,0,3076,5,0,1,3244,1,0,16441,17985,77.2,180,1746601125529845800 -0,7,0,2,1,9796,4,0,1,8742,6,0,121912,123355,72.15,181,1746601125607713000 -0,7,0,2,1,14469,1,0,1,14376,5,0,96305,97913,80.4,182,1746601125683652900 -0,7,0,2,1,13253,0,0,1,12954,3,0,70704,71837,56.65,183,1746601125761628400 -0,7,0,2,1,7431,7,0,0,7613,0,0,45098,46768,83.5,184,1746601125839704900 -0,7,0,2,0,3399,4,0,0,3943,1,0,19496,21038,77.1,185,1746601125915733500 -0,7,0,2,0,9094,2,0,0,8976,2,0,124963,126723,88.0,186,1746601125993726000 -0,7,0,2,1,10438,0,0,0,10742,7,0,99360,101082,86.1,187,1746601126071680600 -0,7,0,2,0,13826,3,0,0,13987,3,0,73757,75282,76.25,188,1746601126149745100 -0,7,0,2,0,7234,5,0,0,5155,2,0,48153,49644,74.55,189,1746601126225805600 -0,7,0,2,1,3715,4,0,1,3702,4,0,22551,23847,64.8,190,1746601126303678500 -0,7,0,2,0,8643,1,0,1,8421,6,0,128017,129588,78.55,191,1746601126381680800 -0,7,0,2,1,11011,0,0,1,11175,3,0,102416,103981,78.25,192,1746601126457686000 -0,7,0,2,1,14145,7,0,1,13629,6,0,76810,78155,67.25,193,1746601126535686700 -0,7,0,2,0,5505,4,0,1,5409,7,0,51208,52746,76.9,194,1746601126613692700 -0,7,0,2,1,2752,3,0,1,3028,3,0,25602,27453,92.55,195,1746601126689679200 -0,7,0,2,0,0,0,0,0,228,7,0,0,1477,73.85,196,1746601126767782800 -0,7,0,2,0,10944,6,0,1,11863,6,0,105467,107307,92.0,197,1746601126845665900 -0,7,0,2,0,13696,5,0,0,13398,0,0,79865,81119,62.7,198,1746601126921663000 -0,7,0,2,0,5953,6,0,0,5845,2,0,54260,56115,92.75,199,1746601126999666800 -0,7,0,2,0,2817,1,0,0,2557,7,0,28657,30026,68.45,200,1746601127077670700 -0,7,0,2,1,451,0,0,0,807,1,0,3055,4561,75.3,201,1746601127153613000 -0,7,0,2,1,11907,5,0,1,12154,3,0,108521,109922,70.05,202,1746601127231843100 -0,7,0,2,1,15427,4,0,1,15779,4,0,82920,84456,76.8,203,1746601127309661900 -0,7,0,2,0,5634,3,0,0,4848,0,0,57314,58624,65.5,204,1746601127385663000 -0,7,0,2,0,2242,0,0,0,6242,1,0,31712,33310,79.9,205,1746601127463661100 -0,7,0,2,0,902,7,0,0,545,4,0,6106,7688,79.1,206,1746601127541661200 -0,7,0,2,1,11590,4,0,1,11466,7,0,111576,113562,99.3,207,1746601127619641700 -0,7,0,2,1,15623,7,0,1,16380,0,0,85973,87360,69.35,208,1746601127695632200 -0,7,0,2,0,5063,0,0,0,4408,1,0,60368,61822,72.7,209,1746601127773769000 -0,7,0,2,0,6277,0,0,0,6437,6,0,34767,36404,81.85,210,1746601127851677100 -0,7,0,2,1,1605,5,0,1,1937,3,0,9161,10482,66.05,211,1746601127927638800 -0,7,0,2,0,11268,4,0,1,9400,4,0,114631,116359,86.4,212,1746601128005945500 -0,7,0,2,1,16068,1,0,0,14898,6,0,89025,90395,68.5,213,1746601128083642500 -0,7,0,2,1,4484,0,0,0,4159,6,0,63424,65195,88.55,214,1746601128159638700 -0,7,0,2,0,6988,6,0,0,7041,0,0,37819,38896,53.85,215,1746601128237770700 -0,7,0,2,1,1804,4,0,0,1424,2,0,12216,14083,93.35,216,1746601128315632500 -0,7,0,2,0,9677,6,0,0,10086,2,0,117684,119331,82.35,217,1746601128391629500 -0,7,0,2,0,14989,1,0,0,15220,1,0,92081,93502,71.05,218,1746601128469633300 -0,7,0,2,0,12367,3,0,1,12697,1,0,66477,67726,62.45,219,1746601128547637300 -0,7,0,2,0,6671,4,0,0,7825,4,0,40872,42760,94.4,220,1746601128623607500 -0,7,0,2,1,1230,4,0,1,3131,6,0,15271,16747,73.8,221,1746601128701616300 -0,7,0,2,1,10126,1,0,1,9854,7,0,120737,122202,73.25,222,1746601128779615600 -0,7,0,2,1,14670,0,0,0,14575,0,0,95136,96848,85.6,223,1746601128855615300 -0,7,0,2,1,12554,7,0,0,13222,1,0,69530,71201,83.55,224,1746601128933610100 -0,7,0,2,0,8138,4,0,1,7468,6,0,43928,45499,78.55,225,1746601129011613000 -0,7,0,2,0,3211,2,0,1,3410,1,0,18323,19681,67.9,226,1746601129087619000 -0,7,0,2,0,8779,0,0,0,9144,6,0,123792,125307,75.75,227,1746601129165638300 -0,7,0,2,1,14345,6,0,1,10482,6,0,98187,99611,71.2,228,1746601129243637100 -0,7,0,2,0,13001,5,0,0,13854,3,0,72585,73890,65.25,229,1746601129319727400 -0,7,0,2,0,7560,6,0,0,7217,2,0,46980,48883,95.15,230,1746601129397621300 -0,7,0,2,0,3912,1,0,1,3821,4,0,21377,23112,86.75,231,1746601129475623000 -0,7,0,2,0,8968,0,0,1,8656,2,0,126848,128252,70.2,232,1746601129553584400 -0,7,0,2,1,10712,5,0,1,11065,3,0,101241,102770,76.45,233,1746601129629767400 -0,7,0,2,1,13976,4,0,0,14197,7,0,75640,77109,73.45,234,1746601129707713000 -0,7,0,2,1,5209,3,0,1,5567,6,0,50034,51540,75.3,235,1746601129785744100 -0,7,0,2,1,3609,0,0,0,2746,5,0,24432,26265,91.65,236,1746601129861596000 -0,7,0,2,1,8411,6,0,1,57,3,0,129899,131442,77.15,237,1746601129939576900 -0,7,0,2,0,11163,5,0,0,10854,4,0,104297,105944,82.35,238,1746601130017599800 -0,7,0,2,0,13658,6,0,1,13492,0,0,78692,80191,74.95,239,1746601130093573800 -0,7,0,2,0,5402,1,0,1,6103,1,0,53089,54481,69.6,240,1746601130171593300 -0,7,0,2,1,3038,1,0,0,2364,6,0,27486,28996,75.5,241,1746601130249595100 -0,7,0,2,0,158,5,0,1,370,3,0,1881,3357,73.8,242,1746601130325723200 -0,7,0,2,1,11870,4,0,1,12183,5,0,107352,108758,70.3,243,1746601130403723400 -0,7,0,2,1,13343,3,0,1,15549,1,0,81746,83633,94.35,244,1746601130482151300 -0,7,0,2,0,5855,0,0,0,4617,3,0,56144,57458,65.7,245,1746601130557705000 -0,7,0,2,0,2461,6,0,1,2161,7,0,30539,32010,73.55,246,1746601130635575400 -0,7,0,2,0,861,4,0,1,669,5,0,4936,6326,69.5,247,1746601130713710200 -0,7,0,2,1,12060,6,0,0,11766,7,0,110404,111909,75.25,248,1746601130789551400 -0,7,0,2,0,15836,1,0,1,16144,1,0,84801,86270,73.45,249,1746601130867565300 -0,7,0,2,1,4764,0,0,0,4934,7,0,59200,60453,62.65,250,1746601130945567700 -0,7,0,2,0,6228,5,0,0,6573,1,0,33593,35249,82.8,251,1746601131023696300 -0,7,0,2,0,533,4,0,1,1783,4,0,7991,9512,76.05,252,1746601131099570500 -0,7,0,2,1,11477,3,0,0,9239,2,0,113458,114899,72.05,253,1746601131177567000 -0,7,0,2,0,16277,0,0,0,15987,3,0,87856,89362,75.3,254,1746601131255580700 -0,7,0,2,1,4439,7,0,1,4349,0,0,62250,64176,96.3,255,1746601131331579700 -0,7,0,2,1,6423,4,0,0,7162,0,0,36648,38240,79.6,256,1746601131409556100 -0,7,0,2,0,2006,3,0,0,1319,3,0,11042,12754,85.6,257,1746601131487538000 -0,7,0,2,0,9366,1,0,1,9545,7,0,116513,117877,68.2,258,1746601131563542700 -0,7,0,2,1,14930,3,0,0,15248,1,0,90909,92414,75.25,259,1746601131641542100 -0,7,0,2,0,4114,5,0,1,12352,1,0,65305,66558,62.65,260,1746601131719680300 -0,7,0,2,1,6866,4,0,0,6670,4,0,39704,40871,58.35,261,1746601131795533400 -0,7,0,2,0,1427,1,0,1,1129,5,0,14097,15753,82.8,262,1746601131873563300 -0,7,0,2,1,10067,0,0,1,9915,0,0,119568,121199,81.55,263,1746601131951535700 -0,7,0,2,1,15121,7,0,1,14832,5,0,93962,95494,76.6,264,1746601132027523700 -0,7,0,2,0,12753,4,0,1,12552,5,0,68360,69510,57.5,265,1746601132105541600 -0,7,0,2,1,7824,2,0,1,8059,1,0,42755,44398,82.15,266,1746601132183574400 -0,7,0,2,1,3152,0,0,0,3496,7,0,17152,18821,83.45,267,1746601132259548900 -0,7,0,2,0,9776,3,0,0,8945,0,0,122621,124175,77.7,268,1746601132337540400 -0,7,0,2,0,14576,4,0,1,10273,7,0,97016,98805,89.45,269,1746601132415525900 -0,7,0,2,1,13233,4,0,0,12873,2,0,71415,72819,70.2,270,1746601132493677900 -0,7,0,2,0,7537,0,0,0,7319,1,0,45808,47313,75.25,271,1746601132569515700 -0,7,0,2,1,3379,0,0,0,4011,7,0,20207,22122,95.75,272,1746601132647520500 -0,7,0,2,0,9203,5,0,1,8474,7,0,125673,127130,72.85,273,1746601132723686100 -0,7,0,2,1,10418,4,0,1,10530,3,0,100071,101917,92.3,274,1746601132801546300 -0,7,0,2,0,13938,2,0,0,14271,5,0,74467,76118,82.55,275,1746601132879500700 -0,7,0,2,0,7218,0,0,0,5323,5,0,48864,50281,70.85,276,1746601132957634900 -0,7,0,2,1,3830,2,0,1,2589,1,0,23260,24753,74.65,277,1746601133033506900 -0,7,0,2,0,8630,4,0,1,8281,2,0,128728,130188,73.0,278,1746601133111517400 -0,7,0,2,1,11127,6,0,1,10915,6,0,103124,104939,90.75,279,1746601133189495100 -0,7,0,2,0,14135,1,0,1,13774,7,0,77521,78938,70.85,280,1746601133265681000 -0,7,0,2,1,5621,1,0,1,5948,3,0,51918,53570,82.6,281,1746601133343472100 -0,7,0,2,0,2741,5,0,0,2938,5,0,26313,28006,84.65,282,1746601133421501500 -0,7,0,2,1,116,4,0,1,425,0,0,711,2447,86.8,283,1746601133497480100 -0,7,0,2,1,10804,3,0,1,11843,5,0,106178,107497,65.95,284,1746601133575495300 -0,7,0,2,1,13556,0,0,1,15422,2,0,80576,82268,84.6,285,1746601133653495600 -0,7,0,2,1,6076,6,0,0,5851,6,0,54971,56171,60.0,286,1746601133729487700 -0,7,0,2,0,2428,4,0,0,2179,5,0,29368,30742,68.7,287,1746601133807468300 -0,7,0,2,1,317,2,0,1,1007,5,0,3763,5545,89.1,288,1746601133885497800 -0,7,0,2,0,12285,0,0,1,11566,0,0,109232,111008,88.8,289,1746601133963469100 -0,7,0,2,1,15551,0,0,0,15814,3,0,83631,84957,66.3,290,1746601134039468100 -0,7,0,2,1,4735,5,0,1,5015,3,0,58025,59602,78.85,291,1746601134117581700 -0,7,0,2,0,2111,4,0,1,6341,4,0,32424,33847,71.15,292,1746601134195512100 -0,7,0,2,1,766,3,0,0,1564,7,0,6818,8378,78.0,293,1746601134271450200 -0,7,0,2,0,11710,0,0,0,11332,3,0,112288,113725,71.85,294,1746601134349578100 -0,7,0,2,0,16250,7,0,1,16044,2,0,86682,88508,91.3,295,1746601134427471800 -0,7,0,2,1,4922,4,0,0,4570,7,0,61080,62618,76.9,296,1746601134503607100 -0,7,0,2,0,6651,2,0,1,6960,0,0,35475,37120,82.25,297,1746601134581620500 -0,7,0,2,0,1723,1,0,0,1997,3,0,9873,11186,65.65,298,1746601134659677700 -0,7,0,2,1,9337,2,0,1,9630,0,0,115340,116896,77.8,299,1746601134735840900 -0,7,0,2,1,15929,5,0,1,14972,7,0,89737,90810,53.65,300,1746601134813461600 -0,7,0,2,0,4344,5,0,1,12339,3,0,64134,65810,83.8,301,1746601134891445000 -0,7,0,2,1,7096,1,0,0,6774,3,0,38529,40226,84.85,302,1746601134967497700 -0,7,0,2,1,1400,0,0,1,1168,6,0,12928,14587,82.95,303,1746601135045469000 -0,7,0,2,0,9512,7,0,0,10053,3,0,118394,119757,68.15,304,1746601135123586200 -0,7,0,2,0,15336,4,0,0,14641,4,0,92792,94472,84.0,305,1746601135199461200 -0,7,0,2,1,12457,2,0,1,12618,6,0,67187,68708,76.05,306,1746601135277500100 -0,7,0,2,0,7785,0,0,1,8073,3,0,41584,43122,76.9,307,1746601135355552500 -0,7,0,2,1,1067,6,0,0,3313,7,0,15979,17674,84.75,308,1746601135431632400 -0,7,0,2,0,9963,4,0,0,8730,3,0,121448,123037,79.45,309,1746601135509739800 -0,7,0,2,1,14763,4,0,1,14456,7,0,95848,97658,90.5,310,1746601135587544800 -0,7,0,2,0,13162,1,0,0,12951,2,0,70241,71891,82.5,311,1746601135665423500 -0,7,0,2,1,7978,0,0,1,7633,6,0,44640,46324,84.2,312,1746601135741466300 -0,7,0,2,1,3566,7,0,1,3843,5,0,19034,20502,73.4,313,1746601135819432500 -0,7,0,2,0,8878,5,0,1,9154,1,0,124505,125921,70.8,314,1746601135897484400 -0,7,0,2,0,10351,2,0,1,10368,1,0,98899,100350,72.55,315,1746601135973436300 -0,7,0,2,1,12847,0,0,0,14078,4,0,73296,75096,90.0,316,1746601136051442000 -0,7,0,2,0,7405,2,0,1,7172,2,0,47692,49091,69.95,317,1746601136129446100 -0,7,0,2,0,4013,4,0,1,3664,7,0,22088,23802,85.7,318,1746601136205636300 -0,7,0,2,0,8557,4,0,1,8619,6,0,127560,128619,52.95,319,1746601136283421700 -0,7,0,2,1,10540,1,0,1,11263,1,0,101953,103761,90.4,320,1746601136361398200 -0,7,0,2,0,14308,0,0,0,13585,0,0,76351,78064,85.65,321,1746601136437405800 -0,7,0,2,1,5284,5,0,0,5458,6,0,50745,52452,85.35,322,1746601136515541100 -0,7,0,2,1,2661,4,0,1,2963,1,0,25143,26862,85.95,323,1746601136593572300 -0,7,0,2,0,8229,3,0,1,201,5,0,130610,132214,80.2,324,1746601136669519400 -0,7,0,2,0,10981,0,0,0,11785,5,0,105008,106614,80.3,325,1746601136747552100 -0,7,0,2,1,13735,2,0,1,13521,2,0,79404,80652,62.4,326,1746601136825566000 -0,7,0,2,0,5991,4,0,0,5766,7,0,53800,55333,76.65,327,1746601136901399400 -0,7,0,2,1,2854,6,0,1,2497,6,0,28196,29707,75.55,328,1746601136979424500 -0,7,0,2,0,486,0,0,1,287,6,0,2592,3924,66.6,329,1746601137057417100 -0,7,0,2,1,11938,3,0,1,12238,3,0,108061,109474,70.65,330,1746601137133389600 -0,7,0,2,0,15458,5,0,1,15763,4,0,82457,84200,87.15,331,1746601137211545300 -0,7,0,2,1,5666,4,0,0,4829,5,0,56856,58550,84.7,332,1746601137289542900 -0,7,0,2,0,2275,1,0,1,6149,3,0,31249,32818,78.45,333,1746601137367397900 -0,7,0,2,1,931,0,0,0,710,0,0,5648,7135,74.35,334,1746601137443371200 -0,7,0,2,1,11617,7,0,1,11668,6,0,111114,112443,66.45,335,1746601137521372200 -0,7,0,2,0,15649,4,0,1,16240,5,0,85512,86777,63.25,336,1746601137599370800 -0,7,0,2,1,5088,2,0,0,4886,7,0,59907,61221,65.7,337,1746601137675503800 -0,7,0,2,0,6304,0,0,1,6467,1,0,34304,35857,77.65,338,1746601137753535200 -0,7,0,2,1,1568,1,0,1,1666,2,0,8702,10211,75.45,339,1746601137831531500 -0,7,0,2,0,11360,5,0,0,9311,0,0,114169,115536,68.35,340,1746601137907539500 -0,7,0,2,1,16033,7,0,0,14870,3,0,88565,90333,88.4,341,1746601137985488300 -0,7,0,2,1,4577,1,0,1,4290,5,0,62961,64486,76.25,342,1746601138063369700 -0,7,0,2,0,6945,0,0,0,7068,5,0,37360,38726,68.3,343,1746601138139365600 -0,7,0,2,0,1891,6,0,0,1374,2,0,11755,13148,69.65,344,1746601138217547800 -0,7,0,2,0,9635,4,0,0,9486,3,0,117224,118690,73.3,345,1746601138293352200 -0,7,0,2,0,15074,3,0,0,15184,5,0,91618,93433,90.75,346,1746601138371511500 -0,7,0,2,0,12322,0,0,1,12443,7,0,66016,67434,70.9,347,1746601138449369000 -0,7,0,2,1,6758,2,0,1,7759,2,0,40412,41900,74.4,348,1746601138527384600 -0,7,0,2,0,1190,4,0,1,3101,1,0,14808,16561,87.65,349,1746601138603366600 -0,7,0,2,1,10214,4,0,1,9792,3,0,120280,121858,78.9,350,1746601138681469000 -0,7,0,2,0,14631,1,0,0,14474,0,0,94673,96352,83.95,351,1746601138759363100 -0,7,0,2,1,12645,0,0,1,13250,1,0,69071,70686,80.75,352,1746601138835464200 -0,7,0,2,1,8101,7,0,1,7435,6,0,43466,45163,84.85,353,1746601138913351900 -0,7,0,2,1,3300,4,0,1,3419,0,0,17863,19600,86.85,354,1746601138991347400 -0,7,0,2,1,8740,3,0,1,9113,2,0,123330,125068,86.9,355,1746601139069344700 -0,7,0,2,1,14436,0,0,0,10436,2,0,97728,99388,83.0,356,1746601139145647000 -0,7,0,2,0,12972,6,0,1,12810,2,0,72123,73628,75.25,357,1746601139223535700 -0,7,0,2,1,7660,4,0,0,7263,4,0,46520,48296,88.8,358,1746601139301542300 -0,7,0,2,1,3885,6,0,1,3743,5,0,20916,22697,89.05,359,1746601139377442000 -0,7,0,2,0,9069,1,0,0,8540,1,0,126385,127809,71.2,360,1746601139455323000 -0,7,0,2,0,10669,0,0,0,10514,0,0,100784,102175,69.55,361,1746601139533343800 -0,7,0,2,1,14063,5,0,0,14144,2,0,75177,76803,81.3,362,1746601139609320200 -0,7,0,2,0,5167,4,0,0,5291,5,0,49576,50793,60.85,363,1746601139687326500 -0,7,0,2,0,3694,2,0,1,2632,0,0,23971,25472,75.05,364,1746601139765449800 -0,7,0,2,0,8366,0,0,0,8199,7,0,129440,131029,79.45,365,1746601139841327100 -0,7,0,2,0,11242,7,0,1,10974,2,0,103834,105308,73.7,366,1746601139919499600 -0,7,0,2,1,13610,4,0,0,13461,5,0,78232,80073,92.05,367,1746601139997315200 -0,7,0,2,1,5483,6,0,0,5977,1,0,52628,54129,75.05,368,1746601140073263200 -0,7,0,2,0,2987,0,0,1,2307,3,0,27024,28690,83.3,369,1746601140151290800 -0,7,0,2,0,233,3,0,0,504,4,0,1421,2695,63.7,370,1746601140229249700 -0,7,0,2,0,11817,5,0,0,11914,4,0,106889,108440,77.55,371,1746601140307315800 -0,7,0,2,1,13417,4,0,0,15437,5,0,81288,82870,79.1,372,1746601140383360800 -0,7,0,2,1,5800,1,0,1,4635,2,0,55681,57491,90.5,373,1746601140461384200 -0,7,0,2,1,2536,0,0,1,2269,3,0,30080,31565,74.25,374,1746601140537427300 -0,7,0,2,0,824,6,0,0,942,7,0,4475,5722,62.35,375,1746601140615447600 -0,7,0,2,1,12152,4,0,0,11715,1,0,109944,111633,84.45,376,1746601140693258600 -0,7,0,2,1,15801,2,0,0,15663,0,0,84339,85584,62.25,377,1746601140771347300 -0,7,0,2,1,4857,0,0,0,4938,0,0,58736,60512,88.8,378,1746601140847293200 -0,7,0,2,0,6201,0,0,1,6383,7,0,33136,34218,54.1,379,1746601140925272400 -0,7,0,2,0,635,4,0,0,1611,1,0,7528,9105,78.85,380,1746601141003411600 -0,7,0,2,0,11451,4,0,0,11278,7,0,113000,114597,79.85,381,1746601141079315700 -0,7,0,2,0,16378,1,0,0,15956,6,0,87393,89284,94.55,382,1746601141157272700 -0,7,0,2,0,4410,0,0,1,4503,5,0,61792,63273,74.05,383,1746601141235294800 -0,7,0,2,1,6526,5,0,0,7167,2,0,36185,38227,102.1,384,1746601141311392000 -0,7,0,2,1,1982,4,0,1,1812,5,0,10584,12089,75.25,385,1746601141389295300 -0,7,0,2,1,9471,3,0,1,9558,5,0,116050,117977,96.35,386,1746601141467274900 -0,7,0,2,0,14911,1,0,0,14995,2,0,90449,91923,73.7,387,1746601141543272100 -0,7,0,2,0,4221,6,0,1,12360,6,0,64843,66436,79.65,388,1746601141621410400 -0,7,0,2,0,6845,5,0,1,6756,2,0,39241,40387,57.3,389,1746601141699430500 -0,7,0,2,1,1532,4,0,1,1232,6,0,13639,15108,73.45,390,1746601141775424800 -0,7,0,2,0,10044,1,0,0,10132,1,0,119105,120638,76.65,391,1746601141853370400 -0,7,0,2,0,15220,1,0,1,14672,4,0,93502,94983,74.05,392,1746601141931267900 -0,7,0,2,0,12724,5,0,1,13111,0,0,67897,69935,101.9,393,1746601142009267000 -0,7,0,2,1,7924,4,0,0,8133,7,0,42296,43978,84.1,394,1746601142085432000 -0,7,0,2,1,3125,3,0,1,3212,2,0,16690,18364,83.7,395,1746601142163270100 -0,7,0,2,1,9845,0,0,0,8900,6,0,122160,123963,90.15,396,1746601142239305500 -0,7,0,2,1,14519,6,0,0,14365,6,0,96555,98123,78.4,397,1746601142317406700 -0,7,0,2,0,13303,4,0,0,13022,5,0,70952,72537,79.25,398,1746601142395260900 -0,7,0,2,0,7478,7,0,0,7582,6,0,45349,46939,79.5,399,1746601142473425100 -0,7,0,2,0,3446,0,0,1,3959,4,0,19744,21207,73.15,400,1746601142549265500 -0,7,0,2,1,9138,3,0,0,9023,1,0,125213,126638,71.25,401,1746601142627416800 -0,7,0,2,1,10482,5,0,1,10745,2,0,99609,101004,69.75,402,1746601142705264900 -0,7,0,2,1,13874,4,0,0,14001,2,0,74008,75507,74.95,403,1746601142781344500 -0,7,0,2,0,7283,3,0,0,5155,7,0,48402,49642,62.0,404,1746601142859355200 -0,7,0,2,0,3763,0,0,0,3636,1,0,22800,24257,72.85,405,1746601142937260600 -0,7,0,2,0,8689,7,0,1,8435,6,0,128266,129771,75.25,406,1746601143013243000 -0,7,0,2,1,11057,4,0,0,10886,0,0,102664,104480,90.8,407,1746601143091379200 -0,7,0,2,1,14192,2,0,0,13634,2,0,77059,78819,88.0,408,1746601143169389100 -0,7,0,2,1,5552,0,0,0,5381,4,0,51456,53192,86.8,409,1746601143245350900 -0,7,0,2,1,2800,0,0,0,2982,7,0,25856,27098,62.1,410,1746601143323215500 -0,7,0,2,0,16,4,0,0,132,5,0,248,1990,87.1,411,1746601143401380300 -0,7,0,2,1,10833,4,0,0,11851,6,0,105719,107412,84.65,412,1746601143477353100 -0,7,0,2,1,13457,3,0,1,13370,6,0,80114,81563,72.45,413,1746601143555220500 -0,7,0,2,1,6097,0,0,1,5830,2,0,54512,56284,88.6,414,1746601143633217000 -0,7,0,2,0,2323,6,0,1,2455,6,0,28907,30507,80.0,415,1746601143711257800 -0,7,0,2,0,339,4,0,0,877,7,0,3304,4682,68.9,416,1746601143787376400 -0,7,0,2,0,12178,2,0,0,12051,2,0,108771,110355,79.2,417,1746601143865367300 -0,7,0,2,0,15570,1,0,0,15849,6,0,83169,84596,71.35,418,1746601143943217200 -0,7,0,2,1,4630,1,0,1,4778,1,0,57566,58977,70.55,419,1746601144019243600 -0,7,0,2,0,2134,5,0,0,6259,4,0,31961,33512,77.55,420,1746601144097199200 -0,7,0,2,0,662,4,0,0,616,6,0,6360,7556,59.8,421,1746601144175192700 -0,7,0,2,1,11735,1,0,0,11502,5,0,111825,113241,70.8,422,1746601144251321300 -0,7,0,2,0,16149,0,0,0,16258,0,0,86223,88032,90.45,423,1746601144329364600 -0,7,0,2,1,4949,7,0,1,4384,2,0,60618,61948,66.5,424,1746601144407309800 -0,7,0,2,0,6549,5,0,0,6446,1,0,35017,36446,71.45,425,1746601144483215600 -0,7,0,2,0,1748,3,0,1,2022,5,0,9410,10790,69.0,426,1746601144561200600 -0,7,0,2,0,9236,0,0,1,9400,4,0,114880,116359,73.95,427,1746601144639178900 -0,7,0,2,0,15964,6,0,1,15089,4,0,89275,91400,106.25,428,1746601144715332600 -0,7,0,2,0,4252,4,0,0,4145,2,0,63672,65267,79.75,429,1746601144793335900 -0,7,0,2,1,7132,4,0,1,6828,0,0,38072,39359,64.35,430,1746601144871174200 -0,7,0,2,0,1309,1,0,0,1458,0,0,12465,14048,79.15,431,1746601144947198800 -0,7,0,2,1,9567,0,0,0,10066,2,0,117935,119580,82.25,432,1746601145025169700 -0,7,0,2,1,15263,7,0,1,15161,5,0,92330,93833,75.15,433,1746601145103203700 -0,7,0,2,1,12511,4,0,1,12758,3,0,66728,68386,82.9,434,1746601145181169000 -0,7,0,2,1,7710,2,0,0,7891,6,0,41123,42219,54.8,435,1746601145257314800 -0,7,0,2,1,1118,0,0,0,3165,7,0,15520,17226,85.3,436,1746601145335200800 -0,7,0,2,0,9882,3,0,0,9839,6,0,120989,122283,64.7,437,1746601145413125200 -0,7,0,2,0,14810,5,0,1,14544,4,0,95385,97031,82.3,438,1746601145489344000 -0,7,0,2,0,13083,6,0,0,13247,3,0,69780,71341,78.05,439,1746601145567333000 -0,7,0,2,0,8027,1,0,0,7537,5,0,44177,45814,81.85,440,1746601145645431500 -0,7,0,2,0,3481,0,0,1,3383,2,0,18575,20179,80.2,441,1746601145721158200 -0,7,0,2,0,8921,5,0,0,9213,5,0,124041,125622,79.05,442,1746601145799310100 -0,7,0,2,1,10265,4,0,1,10401,4,0,98440,99848,70.4,443,1746601145877266300 -0,7,0,2,1,12888,1,0,1,13949,7,0,72833,74421,79.4,444,1746601145953318000 -0,7,0,2,0,7320,0,0,1,7217,5,0,47232,48886,82.7,445,1746601146031168700 -0,7,0,2,0,4040,2,0,0,3774,7,0,21628,22874,62.3,446,1746601146109308100 -0,7,0,2,0,8456,4,0,1,8587,1,0,127096,128913,90.85,447,1746601146185266600 -0,7,0,2,1,10569,2,0,1,11213,1,0,101491,103502,100.55,448,1746601146263318700 -0,7,0,2,0,14217,0,0,0,14106,6,0,75888,77668,89.0,449,1746601146341303300 -0,7,0,2,1,5321,0,0,0,5543,1,0,50288,51665,68.85,450,1746601146417308000 -0,7,0,2,0,2571,5,0,0,2747,6,0,24681,26260,78.95,451,1746601146495297900 -0,7,0,2,1,8266,4,0,0,85,0,0,130151,131888,86.85,452,1746601146573238800 -0,7,0,2,1,10890,3,0,1,10850,4,0,104546,105959,70.65,453,1746601146651123600 -0,7,0,2,0,13770,0,0,0,13535,6,0,78944,80724,89.0,454,1746601146727281600 -0,7,0,2,0,5902,6,0,0,6079,2,0,53339,54956,80.85,455,1746601146805292600 -0,7,0,2,0,2894,4,0,1,2408,5,0,27736,29305,78.45,456,1746601146881142400 -0,7,0,2,0,399,2,0,0,362,1,0,2131,3486,67.75,457,1746601146959125300 -0,7,0,2,0,11983,1,0,1,12264,6,0,107601,109179,78.9,458,1746601147037138600 -0,7,0,2,1,15373,3,0,0,15547,0,0,81997,83600,80.15,459,1746601147113284700 -0,7,0,2,0,5709,4,0,1,4681,3,0,56392,58253,93.05,460,1746601147191350500 -0,7,0,2,0,2188,4,0,1,2092,2,0,30791,32323,76.6,461,1746601147269132600 -0,7,0,2,0,972,1,0,1,722,5,0,5185,6937,87.6,462,1746601147347286800 -0,7,0,2,1,11532,0,0,1,11692,6,0,110656,112196,77.0,463,1746601147423239600 -0,7,0,2,1,15684,7,0,1,16229,6,0,85050,86580,76.5,464,1746601147501274900 -0,7,0,2,1,4996,4,0,1,4923,2,0,59448,61075,81.35,465,1746601147579133400 -0,7,0,2,0,6341,2,0,0,6581,2,0,33843,35123,64.0,466,1746601147655097700 -0,7,0,2,0,1541,0,0,1,1722,0,0,8240,9887,82.35,467,1746601147733129700 -0,7,0,2,0,11335,3,0,1,9258,4,0,113709,115096,69.35,468,1746601147811335700 -0,7,0,2,0,16007,5,0,1,15977,4,0,88105,89480,68.75,469,1746601147887217100 -0,7,0,2,1,4550,7,0,0,4256,7,0,62501,63994,74.65,470,1746601147965096500 -0,7,0,2,1,6918,1,0,1,7163,7,0,36897,38250,67.65,471,1746601148043117800 -0,7,0,2,1,1858,0,0,1,1405,1,0,11295,12977,84.1,472,1746601148119212800 -0,7,0,2,0,9602,5,0,0,9508,4,0,116761,118328,78.35,473,1746601148197108800 -0,7,0,2,0,15042,4,0,0,15332,7,0,91160,92730,78.5,474,1746601148275102300 -0,7,0,2,0,12291,2,0,0,12451,3,0,65555,67090,76.75,475,1746601148351221000 -0,7,0,2,1,6723,0,0,1,7762,4,0,39952,41752,90.0,476,1746601148429095200 -0,7,0,2,1,1153,1,0,0,1109,7,0,14350,15562,60.6,477,1746601148507196900 -0,7,0,2,1,10177,5,0,1,9919,3,0,119817,121170,67.65,478,1746601148585072300 -0,7,0,2,1,14592,7,0,1,14816,5,0,94213,95737,76.2,479,1746601148661098800 -0,7,0,2,0,12608,0,0,1,13163,7,0,68608,70250,82.1,480,1746601148739090400 -0,7,0,2,0,7808,1,0,0,7995,2,0,43006,44691,84.25,481,1746601148817076300 -0,7,0,2,0,3136,5,0,0,3582,4,0,17401,19111,85.5,482,1746601148893070600 -0,7,0,2,1,9728,4,0,1,8878,1,0,122872,124510,81.9,483,1746601148971071000 -0,7,0,2,1,14529,3,0,0,10343,5,0,97266,98857,79.55,484,1746601149049120300 -0,7,0,2,1,13185,0,0,1,12900,2,0,71664,73155,74.55,485,1746601149125089200 -0,7,0,2,1,7491,6,0,0,7393,7,0,46059,47626,78.35,486,1746601149203081300 -0,7,0,2,1,3331,4,0,1,4008,7,0,20456,22138,84.1,487,1746601149281210600 -0,7,0,2,0,9154,6,0,0,8488,3,0,125924,127362,71.9,488,1746601149357076100 -0,7,0,2,0,10370,1,0,0,10619,5,0,100321,101737,70.8,489,1746601149435064200 -0,7,0,2,0,13894,1,0,0,14265,7,0,74718,76149,71.55,490,1746601149513049000 -0,7,0,2,1,7174,5,0,1,5342,4,0,49113,50343,61.5,491,1746601149589050100 -0,7,0,2,1,3783,5,0,1,2673,0,0,23510,25328,90.9,492,1746601149667072100 -0,7,0,2,1,8583,1,0,1,8290,1,0,128977,130529,77.6,493,1746601149745066200 -0,7,0,2,0,11079,0,0,0,10918,7,0,103376,104922,77.3,494,1746601149821203100 -0,7,0,2,1,14085,7,0,0,13799,7,0,77770,79317,77.35,495,1746601149899206900 -0,7,0,2,0,5573,5,0,1,5939,3,0,52169,53522,67.65,496,1746601149977225700 -0,7,0,2,0,2692,2,0,1,2943,2,0,26563,27987,71.2,497,1746601150055066500 -0,7,0,2,0,68,1,0,1,480,3,0,961,2562,80.05,498,1746601150131068000 -0,7,0,2,0,10764,2,0,0,12024,2,0,106428,107900,73.6,499,1746601150209066300 -0,7,0,2,1,13516,5,0,0,15388,0,0,80825,82111,64.3,500,1746601150287217400 -0,7,0,2,1,6029,4,0,0,5695,5,0,55223,57001,88.9,501,1746601150363033100 -0,7,0,2,0,2381,1,0,1,2273,4,0,29617,31240,81.15,502,1746601150441037400 -0,7,0,2,0,269,0,0,0,979,0,0,4016,5359,67.15,503,1746601150519272000 -0,7,0,2,0,12239,5,0,1,11632,7,0,109481,111354,93.65,504,1746601150595188300 -0,7,0,2,1,15503,4,0,0,15712,6,0,83880,85499,80.95,505,1746601150673186900 -0,7,0,2,0,4686,2,0,0,5093,3,0,58275,59954,83.95,506,1746601150751153100 -0,7,0,2,0,2062,0,0,1,6369,7,0,32672,34293,81.05,507,1746601150827181200 -0,7,0,2,0,714,6,0,1,1646,3,0,7067,8797,86.5,508,1746601150905045900 -0,7,0,2,0,11658,4,0,0,11377,5,0,112536,113929,69.65,509,1746601150983034600 -0,7,0,2,0,16202,4,0,0,16018,1,0,86936,88289,67.65,510,1746601151059176800 -0,7,0,2,1,4875,1,0,1,4607,4,0,61329,62807,73.9,511,1746601151137041500 -0,7,0,2,1,6603,0,0,0,6940,3,0,35728,37053,66.25,512,1746601151215144300 -0,7,0,2,1,1673,7,0,0,1918,0,0,10122,11615,74.65,513,1746601151291020600 -0,7,0,2,1,9289,4,0,0,9631,1,0,115592,116910,65.9,514,1746601151369018700 -0,7,0,2,0,15880,2,0,0,15055,2,0,89987,91219,61.6,515,1746601151447153900 -0,7,0,2,0,4296,0,0,1,12346,3,0,64384,65890,75.3,516,1746601151523080900 -0,7,0,2,1,7064,2,0,1,6781,1,0,38780,40270,74.5,517,1746601151601046800 -0,7,0,2,1,1368,5,0,0,1169,6,0,13177,14580,70.15,518,1746601151678993400 -0,7,0,2,0,9497,5,0,0,10235,1,0,118646,120174,76.4,519,1746601151757328900 -0,7,0,2,0,15321,0,0,1,14694,2,0,93040,94755,85.75,520,1746601151833000500 -0,7,0,2,0,12443,0,0,1,12647,1,0,67439,69073,81.7,521,1746601151911154800 -0,7,0,2,1,7771,7,0,0,8160,3,0,41834,43522,84.4,522,1746601151988999600 -0,7,0,2,1,1051,4,0,1,3283,7,0,16232,17642,70.5,523,1746601152065129000 -0,7,0,2,1,9946,3,0,1,8737,2,0,121698,123379,84.05,524,1746601152143013400 -0,7,0,2,0,14746,0,0,1,14446,7,0,96096,97701,80.25,525,1746601152221040000 -0,7,0,2,0,13150,2,0,0,12933,1,0,70492,71729,61.85,526,1746601152296972600 -0,7,0,2,0,7966,5,0,0,7666,6,0,44889,46363,73.7,527,1746601152374936900 -0,7,0,2,0,3551,5,0,1,3857,7,0,19286,20725,71.95,528,1746601152452968900 -0,7,0,2,0,8863,0,0,0,9071,1,0,124752,126382,81.5,529,1746601152528972600 -0,7,0,2,0,10333,3,0,0,10674,6,0,99149,100635,74.3,530,1746601152607107400 -0,7,0,2,0,12829,4,0,0,13996,0,0,73544,75328,89.2,531,1746601152684990200 -0,7,0,2,0,7388,4,0,0,5139,0,0,47943,49391,72.4,532,1746601152760986200 -0,7,0,2,0,3996,2,0,0,3673,7,0,22339,23690,67.55,533,1746601152838987500 -0,7,0,2,0,8540,0,0,1,8328,2,0,127808,129148,67.0,534,1746601152916984100 -0,7,0,2,1,10516,7,0,1,11180,1,0,102202,104001,89.95,535,1746601152994985700 -0,7,0,2,1,14293,4,0,1,13622,6,0,76599,78116,75.85,536,1746601153071133400 -0,7,0,2,1,5269,2,0,0,5448,2,0,50995,52348,67.65,537,1746601153149246100 -0,7,0,2,0,2645,0,0,1,2998,4,0,25392,26919,76.35,538,1746601153225052100 -0,7,0,2,1,8215,2,0,0,248,1,0,130860,132478,80.9,539,1746601153303115200 -0,7,0,2,1,10967,5,0,0,11786,3,0,105257,106594,66.85,540,1746601153381138000 -0,7,0,2,0,13718,5,0,0,13416,7,0,79654,81285,81.55,541,1746601153459066500 -0,7,0,2,1,5974,1,0,1,5774,7,0,54049,55386,66.85,542,1746601153535165500 -0,7,0,2,0,2838,1,0,0,2525,0,0,28449,29872,71.15,543,1746601153613104300 -0,7,0,2,1,466,7,0,1,823,7,0,2842,4394,77.6,544,1746601153691068300 -0,7,0,2,1,11922,4,0,1,12155,0,0,108312,109935,81.15,545,1746601153766984700 -0,7,0,2,0,15443,7,0,0,15804,3,0,82709,84290,79.05,546,1746601153845062700 -0,7,0,2,0,5651,1,0,0,4831,3,0,57105,58541,71.8,547,1746601153923204100 -0,7,0,2,1,2257,2,0,1,6202,1,0,31500,33121,81.05,548,1746601153998961200 -0,7,0,2,0,913,4,0,0,571,7,0,5896,7829,96.65,549,1746601154077003200 -0,7,0,2,0,11601,4,0,0,11649,3,0,111368,112626,62.9,550,1746601154155149500 -0,7,0,2,0,15632,1,0,0,16344,0,0,85761,87168,70.35,551,1746601154230920700 -0,7,0,2,1,5104,0,0,1,4401,7,0,60159,61706,77.35,552,1746601154308940000 -0,7,0,2,0,6320,7,0,1,6469,5,0,34554,35894,67.0,553,1746601154386923100 -0,7,0,2,0,1648,5,0,0,1944,7,0,8953,10373,71.0,554,1746601154462972200 -0,7,0,2,1,11313,3,0,0,9455,6,0,114418,116139,86.05,555,1746601154540957300 -0,7,0,2,0,16113,0,0,1,14869,3,0,88816,90317,75.05,556,1746601154618915600 -0,7,0,2,0,4531,7,0,1,4190,1,0,63210,64673,73.15,557,1746601154696936200 -0,7,0,2,0,7027,4,0,0,6828,4,0,37608,39352,87.2,558,1746601154772943500 -0,7,0,2,1,1842,4,0,0,1494,2,0,12007,13532,76.25,559,1746601154851033600 -0,7,0,2,0,9714,0,0,0,10013,7,0,117472,118965,74.65,560,1746601154928918300 -0,7,0,2,0,15026,0,0,0,15182,5,0,91872,93273,70.05,561,1746601155004921000 -0,7,0,2,0,12406,5,0,1,12733,7,0,66265,67914,82.45,562,1746601155082937700 -0,7,0,2,1,6711,4,0,1,7915,2,0,40663,42387,86.2,563,1746601155161032400 -0,7,0,2,1,1271,3,0,1,3108,1,0,15058,16833,88.75,564,1746601155237025700 -0,7,0,2,1,10167,0,0,1,9814,0,0,120528,122079,77.55,565,1746601155314898000 -0,7,0,2,0,14709,6,0,0,14476,0,0,94923,96320,69.85,566,1746601155392865800 -0,7,0,2,0,12597,4,0,1,13299,2,0,69320,70931,80.55,567,1746601155468912300 -0,7,0,2,1,8180,6,0,1,7438,6,0,43716,45147,71.55,568,1746601155547026400 -0,7,0,2,1,3252,0,0,0,3455,7,0,18112,19797,84.25,569,1746601155624904300 -0,7,0,2,0,8828,0,0,0,8836,5,0,123583,124870,64.35,570,1746601155700916500 -0,7,0,2,0,14396,5,0,0,10461,4,0,97977,99511,76.7,571,1746601155779054200 -0,7,0,2,1,13053,5,0,1,13887,3,0,72374,74066,84.6,572,1746601155856918900 -0,7,0,2,1,7613,3,0,1,7245,7,0,46770,48202,71.6,573,1746601155932914500 -0,7,0,2,1,3965,0,0,1,3969,1,0,21168,22513,67.25,574,1746601156010892100 -0,7,0,2,0,9023,7,0,0,8608,2,0,126634,128515,94.05,575,1746601156088939600 -0,7,0,2,0,10751,4,0,0,10549,3,0,101032,102093,53.05,576,1746601156166993300 -0,7,0,2,0,14014,3,0,0,14150,4,0,75426,76839,70.65,577,1746601156243023300 -0,7,0,2,0,5246,0,0,0,5525,5,0,49824,51401,78.85,578,1746601156320870800 -0,7,0,2,0,3642,3,0,0,2761,1,0,24221,25713,74.6,579,1746601156396958000 -0,7,0,2,1,8442,5,0,0,8206,3,0,129689,130978,64.45,580,1746601156474897400 -0,7,0,2,0,11195,4,0,1,10876,1,0,104087,105793,85.3,581,1746601156552991500 -0,7,0,2,1,13691,3,0,0,13716,5,0,78482,79673,59.55,582,1746601156630991800 -0,7,0,2,1,5435,0,0,1,6138,1,0,52880,54625,87.25,583,1746601156706872800 -0,7,0,2,0,3065,6,0,1,2846,4,0,27275,28504,61.45,584,1746601156784876200 -0,7,0,2,1,185,4,0,0,378,3,0,1672,3426,87.7,585,1746601156863015800 -0,7,0,2,0,11896,2,0,0,11909,2,0,107139,108492,67.65,586,1746601156938881800 -0,7,0,2,0,13368,0,0,1,15577,2,0,81536,83084,77.4,587,1746601157016866500 -0,7,0,2,1,5864,6,0,0,4628,0,0,55931,57536,80.25,588,1746601157095019900 -0,7,0,2,0,2472,5,0,0,2115,1,0,30329,31761,71.6,589,1746601157170930700 -0,7,0,2,1,872,4,0,0,656,7,0,4728,6394,83.3,590,1746601157248964800 -0,7,0,2,0,12073,1,0,0,11731,2,0,110193,111852,82.95,591,1746601157326847500 -0,7,0,2,1,15849,0,0,0,16158,5,0,84592,86182,79.5,592,1746601157403138300 -0,7,0,2,1,4779,7,0,1,4953,2,0,58986,60556,78.5,593,1746601157481000500 -0,7,0,2,1,6251,4,0,0,6555,1,0,33384,34961,78.85,594,1746601157558962100 -0,7,0,2,0,554,3,0,0,1754,2,0,7778,9372,79.7,595,1746601157634970100 -0,7,0,2,1,11498,0,0,0,9232,3,0,113248,114941,84.65,596,1746601157713020900 -0,7,0,2,0,16302,7,0,0,15951,1,0,87642,89169,76.35,597,1746601157791011800 -0,7,0,2,0,4462,4,0,0,4488,7,0,62040,63365,66.25,598,1746601157868790600 -0,7,0,2,0,6447,5,0,1,7038,1,0,36438,37537,54.95,599,1746601157944842000 -0,7,0,2,0,2031,1,0,1,1334,2,0,10833,12579,87.3,600,1746601158022833600 -0,7,0,2,1,9391,0,0,1,9692,1,0,116304,117569,63.25,601,1746601158100830900 -0,7,0,2,1,14957,5,0,0,15294,4,0,90697,92504,90.35,602,1746601158176844500 -0,7,0,2,1,4140,4,0,1,12509,4,0,65095,66743,82.4,603,1746601158254842400 -0,7,0,2,1,6892,1,0,1,7682,6,0,39489,40987,74.9,604,1746601158332939500 -0,7,0,2,1,1444,0,0,0,1105,1,0,13887,15601,85.7,605,1746601158408841100 -0,7,0,2,0,10084,7,0,1,10134,2,0,119354,120611,62.85,606,1746601158486836100 -0,7,0,2,0,15140,4,0,1,14661,4,0,93752,95176,71.2,607,1746601158564992100 -0,7,0,2,1,12773,2,0,1,13081,0,0,68147,69775,81.4,608,1746601158640943300 -0,7,0,2,0,7845,1,0,0,8134,5,0,42545,43993,72.4,609,1746601158718843100 -0,7,0,2,0,3175,2,0,0,3460,2,0,16940,18492,77.6,610,1746601158796995900 -0,7,0,2,0,9767,5,0,1,8951,7,0,122409,124202,89.65,611,1746601158872980000 -0,7,0,2,1,14567,4,0,1,10241,3,0,96808,98317,75.45,612,1746601158950971100 -0,7,0,2,1,13222,1,0,1,12871,6,0,71201,72747,77.3,613,1746601159028952300 -0,7,0,2,1,7526,0,0,0,7575,0,0,45600,46895,64.75,614,1746601159104818600 -0,7,0,2,0,3362,7,0,1,3919,3,0,19994,21421,71.35,615,1746601159182974000 -0,7,0,2,0,9186,4,0,1,8991,0,0,125464,126800,66.8,616,1746601159260904700 -0,7,0,2,0,10403,3,0,0,10582,2,0,99858,101596,86.9,617,1746601159336954100 -0,7,0,2,0,13923,1,0,0,13967,6,0,74257,75691,71.7,618,1746601159414960500 -0,7,0,2,0,7201,3,0,0,5192,5,0,48653,50054,70.05,619,1746601159492968900 -0,7,0,2,0,3809,4,0,1,2571,6,0,23048,24683,81.75,620,1746601159568914100 -0,7,0,2,0,8608,4,0,0,8260,1,0,128519,130110,79.55,621,1746601159646920000 -0,7,0,2,0,11104,0,0,0,10896,3,0,102912,104701,89.45,622,1746601159724817400 -0,7,0,2,1,14176,0,0,0,13777,5,0,77311,79094,89.15,623,1746601159802823300 -0,7,0,2,0,5536,6,0,1,5399,1,0,51707,53038,66.55,624,1746601159878886800 -0,7,0,2,1,2784,4,0,0,2911,3,0,26104,27821,85.85,625,1746601159954756000 -0,7,0,2,1,33,3,0,1,400,3,0,498,2301,90.15,626,1746601160034769900 -0,7,0,2,0,10849,1,0,0,11884,6,0,105969,107076,55.35,627,1746601160110912300 -0,7,0,2,1,13475,6,0,1,13318,2,0,80363,81884,76.05,628,1746601160188790700 -0,7,0,2,0,6115,4,0,1,5839,2,0,54760,56236,73.8,629,1746601160266975100 -0,7,0,2,1,2338,4,0,1,2196,2,0,29159,30915,87.8,630,1746601160342769200 -0,7,0,2,0,354,1,0,1,966,2,0,3553,5155,80.1,631,1746601160420783600 -0,7,0,2,0,12198,0,0,0,12056,6,0,109023,110459,71.8,632,1746601160498766300 -0,7,0,2,1,15590,5,0,0,15813,7,0,83417,84938,76.05,633,1746601160574764800 -0,7,0,2,1,4646,4,0,0,4997,2,0,57816,59443,81.35,634,1746601160652882500 -0,7,0,2,0,2151,2,0,0,6264,2,0,32211,33411,60.0,635,1746601160730770300 -0,7,0,2,0,679,0,0,1,525,7,0,6608,8117,75.45,636,1746601160806799800 -0,7,0,2,0,11749,6,0,0,11330,0,0,112075,113695,81.0,637,1746601160885054400 -0,7,0,2,0,16165,5,0,1,16269,2,0,86473,87987,75.7,638,1746601160962791200 -0,7,0,2,1,4964,7,0,1,4422,1,0,60869,62430,78.05,639,1746601161038914300 -0,7,0,2,0,6564,0,0,0,6412,3,0,35264,36797,76.65,640,1746601161116774400 -0,7,0,2,0,1772,0,0,0,1887,4,0,9663,11432,88.45,641,1746601161194959800 -0,7,0,2,1,9260,7,0,0,9357,7,0,115130,116661,76.55,642,1746601161270920600 -0,7,0,2,1,15980,4,0,1,14930,5,0,89528,90905,68.85,643,1746601161348847800 -0,7,0,2,1,4269,1,0,0,12291,7,0,63921,65557,81.8,644,1746601161426758400 -0,7,0,2,1,7151,0,0,0,6725,6,0,38319,39988,83.45,645,1746601161504857600 -0,7,0,2,0,1327,6,0,0,1454,2,0,12715,13916,60.05,646,1746601161580904000 -0,7,0,2,0,9583,5,0,0,10065,7,0,118185,119562,68.85,647,1746601161658904700 -0,7,0,2,0,15278,6,0,1,15157,1,0,92580,93902,66.1,648,1746601161736742300 -0,7,0,2,1,12526,1,0,1,12759,4,0,66977,68392,70.75,649,1746601161812885900 -0,7,0,2,1,7726,0,0,0,7822,3,0,41376,42914,76.9,650,1746601161890845000 -0,7,0,2,0,1130,5,0,0,3146,4,0,15769,17304,76.75,651,1746601161968878500 -0,7,0,2,1,9899,4,0,0,8707,7,0,121239,122901,83.1,652,1746601162044854600 -0,7,0,2,1,14827,1,0,1,14581,5,0,95633,96969,66.8,653,1746601162122840900 -0,7,0,2,0,13099,0,0,1,13195,5,0,70032,71574,77.1,654,1746601162200718600 -0,7,0,2,1,8041,7,0,1,7625,7,0,44426,46197,88.55,655,1746601162276726600 -0,7,0,2,0,3497,4,0,1,3357,6,0,18824,20299,73.75,656,1746601162354749600 -0,7,0,2,0,8936,2,0,1,9160,1,0,124291,125825,76.7,657,1746601162432723500 -0,7,0,2,0,10280,1,0,0,10431,7,0,98689,100010,66.05,658,1746601162510739200 -0,7,0,2,1,12920,2,0,1,13893,0,0,73084,74703,80.95,659,1746601162586775900 -0,7,0,2,0,7352,5,0,1,7195,2,0,47481,49004,76.15,660,1746601162664976700 -0,7,0,2,0,4089,5,0,0,3807,7,0,21878,23381,75.15,661,1746601162742701100 -0,7,0,2,0,8505,1,0,0,8631,3,0,127345,128722,68.85,662,1746601162818727000 -0,7,0,2,1,10617,0,0,1,11076,7,0,101744,103365,81.05,663,1746601162896709400 -0,7,0,2,1,14267,7,0,1,13621,1,0,76138,78129,99.55,664,1746601162974700200 -0,7,0,2,0,5371,4,0,0,5611,4,0,50536,51816,64.0,665,1746601163050697200 -0,7,0,2,1,2618,2,0,0,2716,1,0,24931,26433,75.1,666,1746601163128705700 -0,7,0,2,0,8314,1,0,0,92,3,0,130401,131906,75.25,667,1746601163206956600 -0,7,0,2,1,10942,2,0,1,10761,7,0,104796,106378,79.1,668,1746601163282697700 -0,7,0,2,0,13822,4,0,0,13507,5,0,79192,80873,84.05,669,1746601163360694400 -0,7,0,2,1,5951,5,0,0,6028,5,0,53590,55225,81.75,670,1746601163438849700 -0,7,0,2,0,2943,1,0,0,2418,4,0,27985,29415,71.5,671,1746601163514696100 -0,7,0,2,0,447,0,0,1,302,4,0,2384,3672,64.4,672,1746601163592717100 -0,7,0,2,1,12029,5,0,1,12238,5,0,107849,109478,81.45,673,1746601163670895400 -0,7,0,2,0,15421,4,0,1,15505,6,0,82248,83723,73.75,674,1746601163746819400 -0,7,0,2,0,5756,2,0,1,4707,5,0,56643,57878,61.75,675,1746601163824679700 -0,7,0,2,1,2236,0,0,0,6144,1,0,31040,32769,86.45,676,1746601163902903200 -0,7,0,2,0,1012,7,0,1,750,3,0,5434,6749,65.75,677,1746601163978674300 -0,7,0,2,0,11572,4,0,1,11397,1,0,110904,112689,89.25,678,1746601164056670900 -0,7,0,2,0,15733,4,0,1,16251,0,0,85303,86672,68.45,679,1746601164134822400 -0,7,0,2,0,5045,0,0,1,4917,7,0,59696,61130,71.7,680,1746601164210688800 -0,7,0,2,1,6391,0,0,0,6635,5,0,34095,35433,66.9,681,1746601164288671100 -0,7,0,2,0,1591,5,0,0,1684,4,0,8489,10040,77.55,682,1746601164366823800 -0,7,0,2,1,11382,4,0,1,9411,2,0,113959,115731,88.6,683,1746601164444669800 -0,7,0,2,1,16054,1,0,1,15926,3,0,88353,89821,73.4,684,1746601164520892800 -0,7,0,2,0,4598,0,0,0,4306,4,0,62752,64280,76.4,685,1746601164598804500 -0,7,0,2,1,6962,6,0,0,7077,4,0,37147,38455,65.4,686,1746601164676651400 -0,7,0,2,0,1906,5,0,1,1332,0,0,11545,12607,53.1,687,1746601164752665200 -0,7,0,2,1,9651,2,0,0,9509,1,0,117011,118321,65.5,688,1746601164830644500 -0,7,0,2,0,15091,1,0,0,15351,3,0,91409,92882,73.65,689,1746601164908755800 -0,7,0,2,0,12337,0,0,0,12439,1,0,65807,67374,78.35,690,1746601164984646300 -0,7,0,2,0,6769,5,0,1,7762,7,0,40201,41754,77.65,691,1746601165062650800 -0,7,0,2,0,1201,4,0,1,1076,2,0,14600,16067,73.35,692,1746601165140652900 -0,7,0,2,0,10224,3,0,1,9902,4,0,120066,121255,59.45,693,1746601165216660000 -0,7,0,2,1,14640,0,0,0,14750,0,0,94464,96095,81.55,694,1746601165294662100 -0,7,0,2,1,12624,7,0,0,13181,1,0,68858,70321,73.15,695,1746601165372644000 -0,7,0,2,0,8080,4,0,0,7989,4,0,43256,44744,74.4,696,1746601165448646500 -0,7,0,2,0,3281,3,0,0,3540,1,0,17650,19262,80.6,697,1746601165526650000 -0,7,0,2,0,8721,0,0,0,8856,2,0,123120,124796,83.8,698,1746601165604627600 -0,7,0,2,0,14417,0,0,0,10292,0,0,97520,98623,55.15,699,1746601165682627900 -0,7,0,2,0,12947,4,0,0,12826,3,0,71912,73570,82.9,700,1746601165758626100 -0,7,0,2,1,7634,4,0,0,7389,7,0,46311,47946,81.75,701,1746601165836679700 -0,7,0,2,1,3858,1,0,0,3984,4,0,20705,22279,78.7,702,1746601165914604100 -0,7,0,2,0,9046,0,0,0,8521,5,0,126175,127881,85.3,703,1746601165990623300 -0,7,0,2,1,10646,7,0,1,10504,2,0,100570,102275,85.25,704,1746601166068623100 -0,7,0,2,0,14038,4,0,0,14248,0,0,74968,76160,59.6,705,1746601166146625400 -0,7,0,2,0,5143,2,0,0,5267,1,0,49363,50961,79.9,706,1746601166222625800 -0,7,0,2,0,3671,1,0,1,2671,7,0,23761,25173,70.6,707,1746601166300626300 -0,7,0,2,0,8341,1,0,1,8235,1,0,129230,130670,72.0,708,1746601166378649900 -0,7,0,2,0,11221,5,0,0,11006,5,0,103625,105126,75.05,709,1746601166454642100 -0,7,0,2,1,13589,4,0,0,13820,1,0,78024,79169,57.25,710,1746601166532586800 -0,7,0,2,0,5460,1,0,1,5960,3,0,52417,54146,86.45,711,1746601166610545400 -0,7,0,2,1,2964,0,0,1,2834,2,0,26816,28444,81.4,712,1746601166686600100 -0,7,0,2,0,220,5,0,0,349,4,0,1209,3255,102.3,713,1746601166764597900 -0,7,0,2,0,11804,5,0,0,11985,4,0,106681,107767,54.3,714,1746601166842752600 -0,7,0,2,1,13405,3,0,1,15394,7,0,81074,82405,66.55,715,1746601166918603200 -0,7,0,2,1,5789,0,0,0,5651,5,0,55472,57110,81.9,716,1746601166996596100 -0,7,0,2,1,2527,6,0,1,2295,1,0,29867,31441,78.7,717,1746601167074743300 -0,7,0,2,0,799,4,0,0,949,2,0,4264,5836,78.6,718,1746601167150749200 -0,7,0,2,1,12126,7,0,0,11603,5,0,109733,111382,82.45,719,1746601167228812600 -0,7,0,2,0,15774,1,0,1,15672,6,0,84129,85636,75.35,720,1746601167306600300 -0,7,0,2,1,4830,0,0,0,5099,5,0,58528,60009,74.05,721,1746601167382713300 -0,7,0,2,0,6170,5,0,1,6281,3,0,32921,34701,89.0,722,1746601167460577200 -0,7,0,2,1,602,4,0,0,1623,6,0,7320,9003,84.15,723,1746601167538550700 -0,7,0,2,0,11419,3,0,0,11385,3,0,112786,114034,62.4,724,1746601167616583000 -0,7,0,2,1,16347,0,0,0,16086,3,0,87184,88866,84.1,725,1746601167692710400 -0,7,0,2,0,4377,6,0,0,4590,7,0,61579,62885,65.3,726,1746601167770583700 -0,7,0,2,0,6489,4,0,0,7007,3,0,35976,37714,86.9,727,1746601167848582900 -0,7,0,2,1,1944,6,0,1,1833,3,0,10372,11890,75.9,728,1746601167924574500 -0,7,0,2,1,9432,0,0,0,9693,6,0,115840,117579,86.95,729,1746601168002576800 -0,7,0,2,0,14856,0,0,1,14993,2,0,90239,91916,83.85,730,1746601168080575100 -0,7,0,2,0,4168,5,0,0,12324,6,0,64633,65988,67.75,731,1746601168156592200 -0,7,0,2,0,6792,5,0,0,6765,1,0,39033,40369,66.8,732,1746601168234569500 -0,7,0,2,1,1481,1,0,1,1259,1,0,13425,14958,76.65,733,1746601168312592800 -0,7,0,2,0,9993,1,0,1,10228,6,0,118897,120123,61.3,734,1746601168388550400 -0,7,0,2,1,15179,6,0,0,14624,2,0,93291,94716,71.25,735,1746601168466554200 -0,7,0,2,0,12683,4,0,0,12584,3,0,67688,69245,77.85,736,1746601168548515400 -0,7,0,2,0,7882,2,0,0,8104,1,0,42083,43393,65.5,737,1746601168620564500 -0,7,0,2,0,3082,1,0,0,3311,6,0,16481,17835,67.7,738,1746601168698618700 -0,7,0,2,1,9806,1,0,1,8829,4,0,121950,123575,81.25,739,1746601168776554000 -0,7,0,2,0,14478,5,0,0,14461,0,0,96345,97615,63.5,740,1746601168854542500 -0,7,0,2,1,13262,4,0,1,13036,2,0,70744,72259,75.75,741,1746601168930550800 -0,7,0,2,1,7439,3,0,0,7658,0,0,45138,46495,67.85,742,1746601169008544600 -0,7,0,2,1,3407,0,0,0,3956,5,0,19536,21190,82.7,743,1746601169086545800 -0,7,0,2,0,9101,7,0,0,9002,0,0,125002,126560,77.9,744,1746601169162570500 -0,7,0,2,1,10445,4,0,0,10707,1,0,99400,101137,86.85,745,1746601169240675100 -0,7,0,2,0,13836,2,0,0,13995,5,0,73795,75369,78.7,746,1746601169318563700 -0,7,0,2,0,7244,0,0,0,5210,1,0,48192,50017,91.25,747,1746601169394533000 -0,7,0,2,0,3716,6,0,0,3612,6,0,22587,24388,90.05,748,1746601169472526000 -0,7,0,2,0,8644,5,0,0,8442,2,0,128057,129692,81.75,749,1746601169550525000 -0,7,0,2,1,11013,4,0,1,11245,1,0,102455,103857,70.1,750,1746601169626657100 -0,7,0,2,0,14149,1,0,0,13688,0,0,76849,78464,80.75,751,1746601169704692200 -0,7,0,2,0,5511,0,0,1,5472,7,0,51247,52730,74.15,752,1746601169782555100 -0,7,0,2,1,2759,5,0,1,2985,5,0,25641,27017,68.8,753,1746601169858531700 -0,7,0,2,1,7,4,0,1,172,3,0,40,1602,78.1,754,1746601169936531300 -0,7,0,2,0,10822,2,0,0,11884,7,0,105507,107077,78.5,755,1746601170014524400 -0,7,0,2,1,13446,0,0,0,13359,2,0,79904,81491,79.35,756,1746601170090545800 -0,7,0,2,1,6082,2,0,1,5796,2,0,54300,55747,72.35,757,1746601170168560000 -0,7,0,2,0,2306,4,0,0,2479,1,0,28696,30289,79.65,758,1746601170246523300 -0,7,0,2,1,323,7,0,0,880,7,0,3093,4858,88.25,759,1746601170324501200 -0,7,0,2,0,12163,1,0,1,12092,5,0,108561,110265,85.2,760,1746601170400667100 -0,7,0,2,1,15555,0,0,1,15803,2,0,82960,84332,68.6,761,1746601170478498100 -0,7,0,2,1,4609,5,0,0,4859,0,0,57353,58735,69.1,762,1746601170556499800 -0,7,0,2,0,2113,4,0,0,6204,0,0,31752,33088,66.8,763,1746601170632500900 -0,7,0,2,1,640,1,0,1,575,4,0,6145,7848,85.15,764,1746601170710524400 -0,7,0,2,0,11712,0,0,1,11432,7,0,111616,113029,70.65,765,1746601170788520700 -0,7,0,2,1,15616,6,0,1,16359,3,0,86011,87506,74.75,766,1746601170864533000 -0,7,0,2,0,5056,4,0,1,4424,1,0,60408,62337,96.45,767,1746601170942537800 -0,7,0,2,0,6273,7,0,1,6490,3,0,34805,35997,59.6,768,1746601171020508700 -0,7,0,2,0,1601,0,0,1,2024,3,0,9200,10877,83.85,769,1746601171096570000 -0,7,0,2,1,11267,3,0,1,9464,5,0,114669,116089,71.0,770,1746601171174478900 -0,7,0,2,0,16067,5,0,0,14865,7,0,89065,90357,64.6,771,1746601171252617600 -0,7,0,2,0,4482,4,0,1,4158,6,0,63463,65188,86.25,772,1746601171328494100 -0,7,0,2,1,6978,1,0,0,6887,7,0,37857,39466,80.45,773,1746601171406502100 -0,7,0,2,1,1794,0,0,0,1435,1,0,12256,14190,96.7,774,1746601171484470900 -0,7,0,2,0,9670,7,0,1,10105,0,0,117722,119439,85.85,775,1746601171560475000 diff --git a/tests/data/20250507_085829/config_v4_none_20250507_085829.yml b/tests/data/20250507_085829/config_v4_none_20250507_085829.yml deleted file mode 100644 index 2026d80..0000000 --- a/tests/data/20250507_085829/config_v4_none_20250507_085829.yml +++ /dev/null @@ -1,201 +0,0 @@ -astropix4: - telescope: - nchips: 1 - geometry: - cols: 16 - rows: 35 - config: - digitalconfig: - interrupt_pushpull: - - 1 - - 0 - clkmux: - - 1 - - 0 - timerend: - - 4 - - 0 - slowdownldpix: - - 4 - - 0 - slowdownldcol: - - 5 - - 0 - maxcyc: - - 6 - - 63 - resetckdiv: - - 4 - - 15 - nu1: - - 32 - - 0 - tdacmux: - - 1 - - 0 - Reset: - - 1 - - 0 - PCH: - - 1 - - 0 - enRamPCH: - - 1 - - 1 - nu2: - - 5 - - 0 - enLVDSterm: - - 1 - - 1 - enPLL: - - 1 - - 1 - enLVDS: - - 1 - - 0 - nu3: - - 5 - - 0 - biasconfig: - DisHiDR: - - 1 - - 0 - q01: - - 1 - - 0 - qon0: - - 1 - - 0 - qon1: - - 1 - - 1 - qon2: - - 1 - - 0 - qon3: - - 1 - - 1 - idacs: - blres: - - 6 - - 0 - vpdac: - - 6 - - 0 - vn1: - - 6 - - 20 - vnfb: - - 6 - - 1 - vnfoll: - - 6 - - 2 - nu5: - - 6 - - 0 - vndel: - - 6 - - 30 - incp: - - 6 - - 10 - ipvco: - - 6 - - 0 - vn2: - - 6 - - 0 - vnfoll2: - - 6 - - 1 - vnbias: - - 6 - - 10 - vpload: - - 6 - - 5 - nu13: - - 6 - - 0 - vncomp: - - 6 - - 2 - vpfoll: - - 6 - - 10 - nu16: - - 6 - - 0 - vprec: - - 6 - - 10 - vnrec: - - 6 - - 10 - vdacs: - blpix: - - 10 - - 568 - thpix: - - 10 - - 610 - vcasc2: - - 10 - - 625 - vtest: - - 10 - - 682 - vinj: - - 10 - - 170 - recconfig: - col0: - - 38 - - 68719476735 - col1: - - 38 - - 68719476734 - col2: - - 38 - - 274877906940 - col3: - - 38 - - 68719476734 - col4: - - 38 - - 68719476734 - col5: - - 38 - - 68719476734 - col6: - - 38 - - 68719476734 - col7: - - 38 - - 68719476734 - col8: - - 38 - - 68719476734 - col9: - - 38 - - 68719476734 - col10: - - 38 - - 68719476734 - col11: - - 38 - - 68719476734 - col12: - - 38 - - 68719476734 - col13: - - 38 - - 68719476734 - col14: - - 38 - - 68719476734 - col15: - - 38 - - 68719476734 diff --git a/tests/test_fmt.py b/tests/test_fmt.py deleted file mode 100644 index 3d4ac34..0000000 --- a/tests/test_fmt.py +++ /dev/null @@ -1,235 +0,0 @@ -# Copyright (C) 2025 the astropix team. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -"""Unit tests for the fmt.py module. -""" - -import binascii -import os -import tempfile -import time - -import matplotlib.pyplot as plt -import numpy as np - -from core.decode import Decode -from core.fmt import BitPattern, AstroPix4Hit, AstroPixReadout, FileHeader, \ - AstroPixBinaryFile, apxdf_to_csv - - -# Mock data from a small test run with AstroPix4---the bytearray below should -# be exactly what might come out from a NEXYS board with the AstroPix 4 firmware. -# (For completeness, data were taken on 2024, December 19, and the array if -# taken verbatim from the log file. The readout contains exactly 2 hits.) -sample_readout_data = bytearray.fromhex('bcbce08056e80da85403bcbcbcbcbcbcbcbce080d26f04ca3005bcbcbcbcbcbcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') - -# And here are the corresponding decoded quantities from the cvs file. -decoded_header = 'dec_ord,id,payload,row,col,ts1,tsfine1,ts2,tsfine2,tsneg1,tsneg2,tstdc1,tstdc2,ts_dec1,ts_dec2,tot_us' -decoded_data0 = (0,7,0,5,5167,3,5418,6,1,0,0,0,49581,52836,162.75) -decoded_data1 = (0,7,0,5,6124,2,4876,5,0,1,0,0,54716,61369,332.65) - - -def original_decode(readout_data: bytearray): - """Original decoding function copied verbatim from beam_test.py. - - This, along with the code in decode.py, was used as a guide for the new code - in fmt.py. - """ - # Convert the bytearray object from the board into a string - string_readout = str(binascii.hexlify(readout_data)) - - # When we get here, string_readout is a string looking like "b'.....'" - # First thing first, we do remove the leading "b'" and the trailing "'" - string_readout = string_readout[2:-1] - - # Now we split the thing into the single events. This goes as follows: - # * replace all the ff with bc - # * split by bc - # This leaves a loong list of strings, among which most are just empty, and the - # ones that are not are the representations of our event. - string_list = [i for i in string_readout.replace('ff','bc').split('bc') if i!=''] - - # Flag to catch potential deciding errors. This should remain True unless - # something goes wrong. - decoding_bool = True - - # Loop over the events. - for event in string_list: - # e0 is apparently the event header---if we do have a mismatch we signal - # a decoding error. - if event[0:2] != 'e0': - decoding_bool = False - - assert decoding_bool == True - - # A couple of hard-coded variables, straight from asic.py - sampleclockperiod = 5 - num_chips = 1 - decode = Decode(sampleclockperiod, nchips=num_chips, bytesperhit=8) - - list_hits = decode.hits_from_readoutstream(readout_data) - df = decode.decode_astropix4_hits(list_hits, printer=True) - return df - - -def test_bit_pattern(): - """Small test fucntion for the BitPattern class. - """ - data = bytes.fromhex('bcff') - pattern = BitPattern(data) - print(pattern) - # Test the text representation---note the class inherits the comparison operators - # from the str class. - assert pattern == '1011110011111111' - # Same for __len__(). - assert len(pattern) == 16 - # Test slicing within the byte boundaries. - assert pattern[0:4] == 11 - assert pattern[4:8] == 12 - assert pattern[8:12] == 15 - assert pattern[12:16] == 15 - # Test slicing across bytes. - assert pattern[6:10] == 3 - - -def test_original_decoding(): - """Test that our poor-man copy of the original decode returns the same thing - we found into the csv file. - """ - df = original_decode(sample_readout_data) - print(df) - assert tuple(df.iloc[0]) == decoded_data0 - assert tuple(df.iloc[1]) == decoded_data1 - - -def test_new_decoding(): - """Test the new decoding stuff. - """ - readout = AstroPixReadout(sample_readout_data, trigger_id=0, timestamp=time.time_ns()) - print(readout) - assert readout.num_hits() == 2 - for hit in readout.hits: - print(hit) - hit0, hit1 = readout.hits - # Compare the hit objects with the conten of the csv files---note we are - # assuming that if the TOT value in us is ok, then all the intermediate timestamp - # fields are ok, as well. - assert (hit0.chip_id, hit0.payload, hit0.row, hit0.column) == decoded_data0[0:4] - assert hit0.tot_us == decoded_data0[-1] - assert (hit1.chip_id, hit1.payload, hit1.row, hit1.column) == decoded_data1[0:4] - assert hit1.tot_us == decoded_data1[-1] - - -def test_file_header(): - """Test the file header. - """ - # Create a dummy header. - header = FileHeader(dict(version=1, content='hits')) - print(header) - - # Write the header to an output file. - kwargs = dict(suffix=AstroPixBinaryFile._EXTENSION, delete_on_close=False, delete=True) - with tempfile.NamedTemporaryFile('wb', **kwargs) as output_file: - print(f'Writing header to {output_file.name}...') - header.write(output_file) - output_file.close() - - # Read back the header from the output file. - print(f'Reading header from {output_file.name}...') - with open(output_file.name, 'rb') as input_file: - twin = FileHeader.read(input_file) - print(twin) - - # Make sure that the whole thing roundtrips. - assert twin == header - - -def test_file(): - """Try writing and reading a fully-fledged output file. - """ - # Create a dummy header. - header = FileHeader(dict(version=1, content='hits')) - print(header) - # Grab our test AstroPix4 hits. - readout = AstroPixReadout(sample_readout_data, trigger_id=0, timestamp=time.time_ns()) - - # Write the output file. - kwargs = dict(suffix=AstroPixBinaryFile._EXTENSION, delete_on_close=False, delete=True) - with tempfile.NamedTemporaryFile('wb', **kwargs) as output_file: - print(f'Writing data to {output_file.name}...') - header.write(output_file) - for hit in readout.hits: - hit.write(output_file) - output_file.close() - - # Read back the input file---note this is done in the context of the first - # with, so that tempfile can cleanup after the fact. - print(f'Reading data from {output_file.name}...') - with AstroPixBinaryFile(AstroPix4Hit).open(output_file.name) as input_file: - print(input_file.header) - for i, hit in enumerate(input_file): - print(hit) - assert hit == readout.hits[i] - - -def test_playback(num_hits: int = 10): - """Test the full playback of a real file. - """ - file_path = os.path.join(os.path.dirname(__file__), 'data', '20250205_094324_data.apx') - with AstroPixBinaryFile(AstroPix4Hit).open(file_path) as input_file: - print(f'\nStarting playback of binary file {file_path}...') - print(f'File header: {input_file.header}') - for i, hit in enumerate(input_file): - if i < num_hits: - print(hit) - elif i == num_hits: - print('...') - print(f'{i + 1} hits found') - - -def test_plot_file(): - """Basic test plotting the content of the sample binary file. - """ - file_path = os.path.join(os.path.dirname(__file__), 'data', '20250205_094324_data.csv') - chip_id, payload, row, column, ts_neg1, ts_coarse1, ts_fine1, ts_tdc1, ts_neg2, \ - ts_coarse2, ts_fine2, ts_tdc2, ts_dec1, ts_dec2, tot_us, trigger_id, timestamp = \ - np.loadtxt(file_path, delimiter=',', unpack=True) - dt = np.diff(timestamp) / 1.e6 - - plt.figure('TOT') - plt.hist(tot_us, bins=25) - plt.xlabel('TOT [$\\mu$s]') - - plt.figure('Time differences') - plt.hist(dt, bins=25) - plt.xlabel('$\\Delta$T [ms]') - - -def test_csv_convert(): - """Read a sample .apx file and convert it to csv. - """ - file_path = os.path.join(os.path.dirname(__file__), 'data', '20250205_094324_data.apx') - kwargs = dict(suffix='.csv', delete_on_close=False, delete=True) - with tempfile.NamedTemporaryFile('w', **kwargs) as output_file: - output_file.close() - print(f'Converting {file_path} to {output_file.name}...') - out = apxdf_to_csv(file_path, AstroPix4Hit, output_file_path=output_file.name) - assert out == output_file.name - - -if __name__ == '__main__': - test_plot_file() - plt.show() \ No newline at end of file From b3e3b2fbf10a55c9f730bae8c85343f64995bdd9 Mon Sep 17 00:00:00 2001 From: Luca Baldini Date: Fri, 30 May 2025 15:15:17 +0200 Subject: [PATCH 49/51] Old file removed. --- apx4_convert.py | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 apx4_convert.py diff --git a/apx4_convert.py b/apx4_convert.py deleted file mode 100644 index efabfb5..0000000 --- a/apx4_convert.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (C) 2025 the astropix team. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -import argparse - -from loguru import logger - -from core.fmt import AstroPix4Hit, apxdf_to_csv - - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Astropix 4 file converter') - parser.add_argument('infile', type=str, help='path to the input file') - args = parser.parse_args() - apxdf_to_csv(args.infile, AstroPix4Hit) \ No newline at end of file From aa0efa4903e2478a0a074aa645188f93c1a7d453 Mon Sep 17 00:00:00 2001 From: Luca BALDINI Date: Tue, 22 Jul 2025 15:20:30 +0200 Subject: [PATCH 50/51] Readout uid in the binary data stream. csv conversion temporarily disabled. --- apx4_read.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apx4_read.py b/apx4_read.py index 8d48bfe..58b5836 100644 --- a/apx4_read.py +++ b/apx4_read.py @@ -20,8 +20,8 @@ import logging import argparse -from astropix_analysis.fmt import AstroPix4Hit, AstroPix4Readout -from astropix_analysis.fileio import FileHeader, apx_to_csv +from astropix_analysis.fmt import AstroPix4Hit, AstroPix4Readout, readout_uid +from astropix_analysis.fileio import FileHeader#, apx_to_csv @@ -133,7 +133,7 @@ def main(args): header_data = {} header_data['configuration'] = astro.get_header_data() header_data['args'] = args.__dict__ - header = FileHeader(header_data) + header = FileHeader(readout_uid(AstroPix4Readout), header_data) # Open the output file and write the header. data_file_name = f'{start_datetime}_data.apx' @@ -176,8 +176,8 @@ def main(args): astro.close_connection() logger.info("Program terminated successfully!") - if args.saveascsv: - file_path = apx_to_csv(data_file_path, AstroPix4Readout) + #if args.saveascsv: + # file_path = apx_to_csv(data_file_path, AstroPix4Readout) if __name__ == "__main__": From 65117d335c0c0651fd93e238927c19e62ca509cd Mon Sep 17 00:00:00 2001 From: Luca BALDINI Date: Wed, 23 Jul 2025 13:45:29 +0200 Subject: [PATCH 51/51] minor --- SourceWrapper_Threshold_Scan.py | 151 ++++++++++++++++++++++++++++++++ apx4_read.py | 9 +- 2 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 SourceWrapper_Threshold_Scan.py diff --git a/SourceWrapper_Threshold_Scan.py b/SourceWrapper_Threshold_Scan.py new file mode 100644 index 0000000..85b98d8 --- /dev/null +++ b/SourceWrapper_Threshold_Scan.py @@ -0,0 +1,151 @@ +import argparse +import logging +import beam_test +import os +import numpy as np +import time +from astropix import astropixRun + + +def change_all_TuneDACs(file,TuneDAC): + with open(file, 'r') as stream: + data=stream.readlines() + + for i,line in enumerate(data): + if 'row' in line and len(line)>50: + for column in range(16): + line=line[:35+6*column]+bin(TuneDAC)[2:].zfill(3)[::-1]+line[38+6*column:] + data[i]=line + + with open(file,'w') as stream: + stream.writelines(data) + +def change_VPDAC(file,VPDAC): + with open(file, 'r') as stream: + data=stream.readlines() + + for i,line in enumerate(data): + if 'vpdac' in line: + line=line[:36]+str(VPDAC)+']\n' + data[i]=line + + with open(file,'w') as stream: + stream.writelines(data) + + +parser = argparse.ArgumentParser(description='Astropix Driver Code') +parser.add_argument('-n', '--name', default='', required=False, + help='Option to give additional name to output files upon running') + +parser.add_argument('-o', '--outdir', default='.', required=False, + help='Output Directory for all datafiles') + +parser.add_argument('-y', '--yaml', action='store', required=False, type=str, default = 'testconfig', + help = 'filepath (in config/ directory) .yml file containing chip configuration. Default: config/testconfig.yml (All pixels off)') + +parser.add_argument('-V', '--chipVer', default=2, required=False, type=int, + help='Chip version - provide an int') + +parser.add_argument('-s', '--showhits', action='store_true', + default=False, required=False, + help='Display hits in real time during data taking') + +parser.add_argument('-p', '--plotsave', action='store_true', default=False, required=False, + help='Save plots as image files. If set, will be saved in same dir as data. Default: FALSE') + +parser.add_argument('-c', '--saveascsv', action='store_true', + default=False, required=False, + help='save output files as CSV. If False, save as txt. Default: FALSE') + +parser.add_argument('-f', '--newfilter', action='store_true', + default=False, required=False, + help='Turns on filtering of strings looking for header of e0 in V4. If False, no filtering. Default: FALSE') + +parser.add_argument('-i', '--inject', action='store', default=None, type=int, nargs=2, + help = 'Turn on injection in the given row and column. Default: No injection') + +parser.add_argument('-v','--vinj', action='store', default = None, type=float, + help = 'Specify injection voltage (in mV). DEFAULT None (uses value in yml)') + +parser.add_argument('-a', '--analog', action='store', required=False, type=int, default = 0, + help = 'Turn on analog output in the given column. Default: Column 0.') + +parser.add_argument('-t', '--threshold', type = float, action='store', default=None, + help = 'Threshold voltage for digital ToT (in mV). DEFAULT value in yml OR 100mV if voltagecard not in yml') + +parser.add_argument('-E', '--errormax', action='store', type=int, default='100', + help='Maximum index errors allowed during decoding. DEFAULT 100') + +parser.add_argument('-r', '--maxruns', type=int, action='store', default=None, + help = 'Maximum number of readouts') + +parser.add_argument('-M', '--maxtime', type=float, action='store', default=None, + help = 'Maximum run time (in minutes)') + +parser.add_argument('--timeit', action="store_true", default=False, + help='Prints runtime from seeing a hit to finishing the decode to terminal') + +parser.add_argument('-L', '--loglevel', type=str, choices = ['D', 'I', 'E', 'W', 'C'], action="store", default='I', + help='Set loglevel used. Options: D - debug, I - info, E - error, W - warning, C - critical. DEFAULT: I') + +parser.add_argument +args = parser.parse_args() +logname = "./runlogs/AstropixRunlog_" + time.strftime("%Y%m%d-%H%M%S") + ".log" + +# Sets the loglevel +ll = args.loglevel +if ll == 'D': + loglevel = logging.DEBUG +elif ll == 'I': + loglevel = logging.INFO +elif ll == 'E': + loglevel = logging.ERROR +elif ll == 'W': + loglevel = logging.WARNING +elif ll == 'C': + loglevel = logging.CRITICAL + +# Logging +formatter = logging.Formatter('%(asctime)s:%(msecs)d.%(name)s.%(levelname)s:%(message)s') +fh = logging.FileHandler(logname) +fh.setFormatter(formatter) +sh = logging.StreamHandler() +sh.setFormatter(formatter) +logging.getLogger().addHandler(sh) +logging.getLogger().addHandler(fh) +logging.getLogger().setLevel(loglevel) + +logger = logging.getLogger(__name__) + +#If using v2, use injection created by injection card +#If using v3, use injection created with integrated DACs on chip +onchipBool = True if args.chipVer > 2 else False + +threshold_array=np.arange(40,241,5 ) ###### can change step here + +for VPDAC in [10,20,30,40]: +# for VPDAC in [10]: + change_VPDAC(f'config/{args.yaml}.yml',VPDAC) + for TuneDAC in [0,1,2,3,4,5,6,7]: + change_all_TuneDACs(f'config/{args.yaml}.yml', TuneDAC) + time.sleep(1) + for col in [0,1,2,3,4,5,6,7,8,9,10,11,12]: + # for col in [9]: + args.inject=[1,col] + ### outdir is currently specific to the machine used to run at goddard, change before running + args.outdir=f'E:/data/VPDAC_Testing_With_Grant/scan4/VPDAC_{VPDAC}/TuneDAC_{TuneDAC}/Col_{col}' + os.makedirs(args.outdir) + for threshold in threshold_array: + args.name=f'threshold_{threshold}mV' + print(f'{args.name}') + args.threshold=float(threshold) + success_bool=False + # beam_test.main(args) + while success_bool==False: + try: + beam_test.main(args) + success_bool=True + except: + print(f'An error occured on threshold {threshold}mV') + success_bool=False + time.sleep(1) \ No newline at end of file diff --git a/apx4_read.py b/apx4_read.py index 58b5836..38dc886 100644 --- a/apx4_read.py +++ b/apx4_read.py @@ -20,7 +20,7 @@ import logging import argparse -from astropix_analysis.fmt import AstroPix4Hit, AstroPix4Readout, readout_uid +from astropix_analysis.fmt import AstroPix4Hit, AstroPix4Readout from astropix_analysis.fileio import FileHeader#, apx_to_csv @@ -52,6 +52,7 @@ def setup_logger(level: str, file_path: str = None): formatter = logging.Formatter('%(asctime)s:%(msecs)d.%(name)s.%(levelname)s:%(message)s') stream_handler = logging.StreamHandler() stream_handler.setFormatter(formatter) + logging.getLogger().handlers.clear() logging.getLogger().addHandler(stream_handler) if file_path is not None: file_handler = logging.FileHandler(file_path) @@ -70,6 +71,7 @@ def main(args): chip_version = 4 ci_on_chip = True + # Latch the start date and time---this will be used for naming the output products. start_datetime = time.strftime("%Y%m%d_%H%M%S") @@ -97,7 +99,8 @@ def main(args): astro.enable_spi() astro.asic_configure() if chip_version == 4: - astro.update_asic_tdac_row(0) + for row_i in range(13): + astro.update_asic_tdac_row(row_i) logger.info('Chip fully configured!') # What is this doing? @@ -133,7 +136,7 @@ def main(args): header_data = {} header_data['configuration'] = astro.get_header_data() header_data['args'] = args.__dict__ - header = FileHeader(readout_uid(AstroPix4Readout), header_data) + header = FileHeader(AstroPix4Readout, header_data) # Open the output file and write the header. data_file_name = f'{start_datetime}_data.apx'