diff --git a/README.md b/README.md index ac81ccbbbaf317e298cdee6bc6da1425b21b5b6b..5a0ffa2c98638bbe9a80466dd8119d3d41a0adaf 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ tox -e debug tests.requests.test_prometheus ``` ## Releasenotes +- 0.14.5 - Added `gn_indices` and support for global node indices > 16. - 0.14.4 - Fixed bug on `writer_version` retrieval - 0.14.3 - Added `rcu_pcb_id` and `rcu_pcb_version` to Hdf5 file header - 0.14.2 - Added `station_name` attribute to Hdf5 file header diff --git a/VERSION b/VERSION index 3393b5fd47d4a67117689c126a00bb8f657362e5..436d0ce0df76b64a5a27258541e310ffa4bf3750 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.14.4 +0.14.5 diff --git a/lofar_station_client/statistics/collector.py b/lofar_station_client/statistics/collector.py index 985dd76caae08084f6c3c1399d70037da8341c37..55fbc70eea7a832d8ae5197fc6e6b65d0c463af1 100644 --- a/lofar_station_client/statistics/collector.py +++ b/lofar_station_client/statistics/collector.py @@ -99,6 +99,8 @@ class SSTCollector(StatisticsCollector): "nof_payload_errors": numpy.zeros( (self.MAX_FPGAS,), dtype=numpy.uint64 ), + # gn_index of each FPGA, for verification purposes + "gn_indices": numpy.full((self.MAX_FPGAS,), -1, dtype=numpy.uint64), # Last value array we've constructed out of the packets "sst_values": numpy.zeros( (self.MAX_INPUTS, self.MAX_SUBBANDS), dtype=numpy.uint64 @@ -120,6 +122,10 @@ class SSTCollector(StatisticsCollector): def _parse_packet(self, packet): fields = SSTPacket(packet) + self.parameters["gn_indices"][ + fields.gn_index % self.MAX_FPGAS + ] = fields.gn_index + # determine which input this packet contains data for if fields.signal_input_index >= self.MAX_INPUTS: # packet describes an input that is out of bounds for us @@ -132,13 +138,17 @@ class SSTCollector(StatisticsCollector): if fields.payload_error: # cannot trust the data if a payload error is reported - self.parameters["nof_payload_errors"][fields.gn_index] += numpy.uint64(1) + self.parameters["nof_payload_errors"][ + fields.gn_index % self.MAX_FPGAS + ] += numpy.uint64(1) # don't raise, as packet is valid return # process the packet - self.parameters["nof_valid_payloads"][fields.gn_index] += numpy.uint64(1) + self.parameters["nof_valid_payloads"][ + fields.gn_index % self.MAX_FPGAS + ] += numpy.uint64(1) self.parameters["sst_values"][input_index][ : fields.nof_statistics_per_packet ] = fields.payload() @@ -206,6 +216,8 @@ class XSTCollector(StatisticsCollector): "nof_payload_errors": numpy.zeros( (self.MAX_FPGAS,), dtype=numpy.uint64 ), + # gn_index of each FPGA, for verification purposes + "gn_indices": numpy.full((self.MAX_FPGAS,), -1, dtype=numpy.uint64), # Last value array we've constructed out of the packets "xst_blocks": numpy.zeros( ( @@ -261,9 +273,15 @@ class XSTCollector(StatisticsCollector): def _parse_packet(self, packet): fields = XSTPacket(packet) + self.parameters["gn_indices"][ + fields.gn_index % self.MAX_FPGAS + ] = fields.gn_index + if fields.payload_error: # cannot trust the data if a payload error is reported - self.parameters["nof_payload_errors"][fields.gn_index] += numpy.uint64(1) + self.parameters["nof_payload_errors"][ + fields.gn_index % self.MAX_FPGAS + ] += numpy.uint64(1) # don't raise, as packet is valid return @@ -337,7 +355,9 @@ class XSTCollector(StatisticsCollector): ) # process the packet - self.parameters["nof_valid_payloads"][fields.gn_index] += numpy.uint64(1) + self.parameters["nof_valid_payloads"][ + fields.gn_index % self.MAX_FPGAS + ] += numpy.uint64(1) self.parameters["xst_blocks"][ subband_slot, block_index, : fields.nof_statistics_per_packet @@ -427,6 +447,8 @@ class BSTCollector(StatisticsCollector): (self.MAX_FPGAS,), dtype=numpy.uint64, ), + # gn_index of each FPGA, for verification purposes + "gn_indices": numpy.full((self.MAX_FPGAS,), -1, dtype=numpy.uint64), # Last value array we've constructed out of the packets "bst_values": numpy.zeros( (self.MAX_BLOCKS, self.MAX_BEAMLETS), @@ -445,6 +467,10 @@ class BSTCollector(StatisticsCollector): def _parse_packet(self, packet): fields = BSTPacket(packet) + self.parameters["gn_indices"][ + fields.gn_index % self.MAX_FPGAS + ] = fields.gn_index + # To get the block_index we floor divide this beamlet_index by the max amount # of beamlets per block block_index = fields.beamlet_index // self.MAX_BEAMLETS @@ -459,13 +485,17 @@ class BSTCollector(StatisticsCollector): if fields.payload_error: # cannot trust the data if a payload error is reported - self.parameters["nof_payload_errors"][fields.gn_index] += numpy.uint64(1) + self.parameters["nof_payload_errors"][ + fields.gn_index % self.MAX_FPGAS + ] += numpy.uint64(1) # don't raise, as packet is valid return # process the packet - self.parameters["nof_valid_payloads"][fields.gn_index] += numpy.uint64(1) + self.parameters["nof_valid_payloads"][ + fields.gn_index % self.MAX_FPGAS + ] += numpy.uint64(1) self.parameters["bst_values"][block_index][ : self.MAX_BEAMLETS ] = fields.payload() diff --git a/lofar_station_client/statistics/statistics_data.py b/lofar_station_client/statistics/statistics_data.py index b7a99fa08a6a95f3503d4df33b381f05b8eb78c0..ab0b8ef99e07e0e91fc5c3d22111d1056428820c 100644 --- a/lofar_station_client/statistics/statistics_data.py +++ b/lofar_station_client/statistics/statistics_data.py @@ -121,12 +121,16 @@ class StatisticsData(ndarray): BST the number of the beamlet for which this packet holds statistics. """ - nof_valid_payloads: int = attribute() + nof_valid_payloads: ndarray = attribute() """ Number of packets received so far that we could parse correctly and do not have - a payload error """ + a payload error. One value per FPGA. """ - nof_payload_errors: int = attribute() - """ Number of packets that reported a payload error """ + nof_payload_errors: ndarray = attribute() + """ Number of packets that reported a payload error. One value per FPGA. """ + + gn_indices: ndarray = attribute() + """ Global node index (gn) as reported by each FPGA, for each element in the payload + counters. """ tile_beam_pointing_direction: str = attribute(optional=True) """ Direction of the tile beam """ diff --git a/lofar_station_client/statistics/writer/hdf5.py b/lofar_station_client/statistics/writer/hdf5.py index c5796abfb0316ed339d75d9ae2de2994d3324399..e40ec455b42c9742269f0100cf9155b9a4a00806 100644 --- a/lofar_station_client/statistics/writer/hdf5.py +++ b/lofar_station_client/statistics/writer/hdf5.py @@ -254,6 +254,7 @@ class HDF5Writer(ABC): fields = { "nof_payload_errors": self.current_matrix.parameters["nof_payload_errors"], "nof_valid_payloads": self.current_matrix.parameters["nof_valid_payloads"], + "gn_indices": self.current_matrix.parameters["gn_indices"], } # add the packet headers @@ -369,11 +370,6 @@ class HDF5Writer(ABC): tstamp = self.current_timestamp.isoformat(timespec="milliseconds") matrix = self.get_values_matrix() - # Stores the header of the packet received for this matrix as a list of - # attributes - matrix.nof_payload_errors = self.current_matrix.parameters["nof_payload_errors"] - matrix.nof_valid_payloads = self.current_matrix.parameters["nof_valid_payloads"] - # Stores the header of the packet received for this matrix as a list of # attributes header_attributes = self.hdf5_matrix_header(self.statistics_packet_header)