Source code for pacfish.qualitycontrol.ConsistencyChecker

# SPDX-FileCopyrightText: 2021 International Photoacoustics Standardisation Consortium (IPASC)
# SPDX-FileCopyrightText: 2021 Janek Gröhl
# SPDX-FileCopyrightText: 2021 Lina Hacker
# SPDX-License-Identifier: BSD 3-Clause License

import numpy as np
import numbers
from pacfish import MetadataAcquisitionTags, MetadataDeviceTags


[docs]class ConsistencyChecker: """ The purpose of this class is to go beyond the capabilities of the CompletenessChecker and to test the consistency of the metadata. To this end, every meta datum is assigned a possible value range by definition. The Consistency checker unit_tests if the assigned values fall inside this value range. """ def __init__(self, verbose: bool = False, log_file_path: str = None): """ Parameters ---------- verbose: bool A flag to indicate whether the log should be printed to the console. log_file_path: str A string with the path to where the log file should be written to. If 'None', then no log file is written. """ self.save_file_name = "logfile.md" self.verbose = verbose self.log_file_path = log_file_path
[docs] def check_binary_data(self, binary_data) -> bool: """ This method unit_tests if the given binary data has the correct data type and if each value in the binary data in a Number. Parameters ---------- binary_data: np.ndarray The binary data to check """ is_consistent = True if not isinstance(binary_data, np.ndarray): is_consistent = False for number in np.reshape(binary_data, (-1, )): if not isinstance(number, numbers.Number): is_consistent = False return is_consistent
[docs] def check_acquisition_meta_data(self, acquisition_meta_data: dict) -> bool: """ Tests the given dictionary with acquisition metadata for consistency. Parameters ---------- acquisition_meta_data: dict A dictionary containing all the acquisition metadata to check Return ------ bool Returns `True` if all data is consistent """ is_consistent = True # Input data validation if acquisition_meta_data is None: raise ValueError("the field acquisition_meta_data must not be None!") if not isinstance(acquisition_meta_data, dict): raise TypeError("The field acquisition_meta_data was not of " + "type dict") if len(list(acquisition_meta_data.keys())) == 0: # An empty dictionary must not pass the consistency check is_consistent = False num_inconsistencies = 0 log_message = "" log_message += "#Consistency Report for Acquisition Meta Data\n\n" for metadatum in MetadataAcquisitionTags.TAGS: if metadatum.tag in acquisition_meta_data: value = acquisition_meta_data[metadatum.tag] result = metadatum.evaluate_value_range(value) if result is False: is_consistent = False log_message += metadatum.tag + " was found not to be consistent.\n" log_message += f"\t had the value: {value}\n" num_inconsistencies += 1 log_message += "\n##Results\n\n" if num_inconsistencies == 0: log_message += "No inconsistencies were found in the meta data.\n\n" else: log_message += "!! " + str(num_inconsistencies) + " inconsistencies were found in the meta data!!\n\n" if self.verbose: print(log_message) if self.log_file_path is not None: with open(self.log_file_path + self.save_file_name, "a") as log_file_handle: log_file_handle.writelines(log_message) return is_consistent
[docs] def check_device_meta_data(self, device_meta_data: dict) -> bool: """ Tests the given dictionary with device metadata for consistency. Parameters ---------- device_meta_data: dict A dictionary containing all the device metadata to check Return ------ bool Returns `True` if all data is consistent """ # Input data validation if device_meta_data is None: raise ValueError("the field device_meta_data must not be None!") if not isinstance(device_meta_data, dict): raise TypeError("The field device_meta_data was not of type dict") is_consistent = True num_inconsistencies = 0 log_message = "" log_message += "#Consistency Report for Device Meta Data\n\n" log_message += "##General Tags\n\n" general_tags = [MetadataDeviceTags.UNIQUE_IDENTIFIER, MetadataDeviceTags.FIELD_OF_VIEW] if MetadataDeviceTags.GENERAL.tag not in device_meta_data: num_inconsistencies += 1 is_consistent = False log_message += MetadataDeviceTags.GENERAL.tag + " tags were not found in the device dictionary.\n" else: for metadatum in general_tags: if metadatum.tag in device_meta_data[MetadataDeviceTags.GENERAL.tag]: try: result = metadatum.evaluate_value_range( device_meta_data[MetadataDeviceTags.GENERAL.tag][metadatum.tag]) except TypeError: result = False if result is False: is_consistent = False log_message += metadatum.tag + " was found not to be consistent.\n" num_inconsistencies += 1 log_message += "##Detection Elements\n\n" detection_tags = [MetadataDeviceTags.DETECTOR_GEOMETRY, MetadataDeviceTags.DETECTOR_ORIENTATION, MetadataDeviceTags.DETECTOR_POSITION, MetadataDeviceTags.FREQUENCY_RESPONSE, MetadataDeviceTags.ANGULAR_RESPONSE] if MetadataDeviceTags.DETECTORS.tag not in device_meta_data: num_inconsistencies += 1 is_consistent = False log_message += MetadataDeviceTags.DETECTORS.tag + " were not found in the device dictionary.\n" else: for metadatum in detection_tags: for detector_dict in device_meta_data[MetadataDeviceTags.DETECTORS.tag]: if metadatum.tag in device_meta_data[MetadataDeviceTags.DETECTORS.tag][detector_dict]: result = metadatum.evaluate_value_range( device_meta_data[MetadataDeviceTags.DETECTORS.tag][detector_dict][metadatum.tag]) if result is False: is_consistent = False num_inconsistencies += 1 log_message += metadatum.tag + " was found not to be consistent.\n" log_message += "##Illumination Elements\n\n" illumination_tags = [MetadataDeviceTags.ILLUMINATOR_GEOMETRY, MetadataDeviceTags.ILLUMINATOR_ORIENTATION, MetadataDeviceTags.ILLUMINATOR_POSITION, MetadataDeviceTags.WAVELENGTH_RANGE, MetadataDeviceTags.BEAM_ENERGY_PROFILE, MetadataDeviceTags.PULSE_WIDTH, MetadataDeviceTags.BEAM_STABILITY_PROFILE, MetadataDeviceTags.BEAM_INTENSITY_PROFILE, MetadataDeviceTags.BEAM_DIVERGENCE_ANGLES] if MetadataDeviceTags.ILLUMINATORS.tag not in device_meta_data: num_inconsistencies += 1 is_consistent = False log_message += MetadataDeviceTags.ILLUMINATORS.tag + " were not found in the device dictionary.\n" else: for metadatum in illumination_tags: for illumination_dict in device_meta_data[MetadataDeviceTags.ILLUMINATORS.tag]: if metadatum.tag in device_meta_data[MetadataDeviceTags.ILLUMINATORS.tag][illumination_dict]: result = metadatum.evaluate_value_range( device_meta_data[MetadataDeviceTags.ILLUMINATORS.tag][illumination_dict][metadatum.tag]) if result is False: is_consistent = False num_inconsistencies += 1 log_message += metadatum.tag + " was found not to be consistent.\n" log_message += "##Results\n\n" if num_inconsistencies == 0: log_message += "No inconsistencies were found in the meta data.\n\n" else: log_message += "!! " + str(num_inconsistencies) + " inconsistencies were found in the meta data!!\n\n" if self.verbose: print(log_message) if self.log_file_path is not None: with open(self.log_file_path + self.save_file_name, "a") as log_file_handle: log_file_handle.writelines(log_message) return is_consistent