def process_dicom_series(dicom_series_dict, series_uid, parent_sorting_field='PatientName', return_extra=True, individual_file=False, initial_sop_class_name_default='UNKNOWN'):
    if (not individual_file):
        logger.info(f'  Processing series UID: {series_uid}')
        dicom_file_list = dicom_series_dict[series_uid]
    else:
        logger.info(f'  Processing individual file: {individual_file}')
        dicom_file_list = [individual_file]
    logger.info(f'  Number of DICOM files: {len(dicom_file_list)}')
    initial_dicom = pydicom.read_file(dicom_file_list[0])
    parent_sorting_data = re.sub('[^\\w]', '_', str(initial_dicom[parent_sorting_field].value)).upper()
    if (parent_sorting_data == ''):
        logger.error(f'Could not find any data in {parent_sorting_field}. This is very bad, the data cannot be sorted properly.')
        '\n        ! TO DO\n        Implement a routine to let a user correlate a root directory with a name\n        '
        parent_sorting_data = 'TEMP'
    try:
        initial_dicom_sop_class_name = initial_dicom.SOPClassUID.name
    except AttributeError:
        logger.warning(f'Could not find DICOM SOP Class UID, using {initial_sop_class_name_default}.')
        initial_dicom_sop_class_name = initial_sop_class_name_default
    try:
        study_uid = initial_dicom.StudyInstanceUID
    except AttributeError:
        study_uid = '00001'
    '\n    ! TO DO\n    Need to check for secondary capture image storage\n    This can include JPEGs with written information on them\n    This is typically not very useful\n    We can dump it to file\n    Or just save the DICOM file in the folder of interest\n\n    Not a big problem, sort out another day\n    '
    if (('Image' in initial_dicom_sop_class_name) and (initial_dicom_sop_class_name != 'Secondary Capture Image Storage')):
        sorted_file_list = safe_sort_dicom_image_list(dicom_file_list)
        try:
            image = sitk.ReadImage(sorted_file_list)
        except RuntimeError:
            logger.warning('  Could not read image into SimpleITK.')
            logger.info('  Processing files individually.')
            for dicom_file in dicom_file_list:
                return process_dicom_series(dicom_series_dict, series_uid, parent_sorting_field=parent_sorting_field, return_extra=return_extra, individual_file=dicom_file, initial_sop_class_name_default=initial_sop_class_name_default)
        dicom_file_metadata = {'parent_sorting_data': parent_sorting_data, 'study_uid': study_uid}
        '\n        ! TO DO - integrity check\n            Read in all the files here, check the slice location and determine if any are missing\n        '
        if (initial_dicom.Modality == 'PT'):
            None
        '\n        ! CHECKPOINT\n        Some DCE MRI sequences have the same series UID\n        Here we check the sequence name, and split if necessary\n        '
        if (initial_dicom.Modality == 'MR'):
            try:
                sequence_names = np.unique([pydicom.read_file(x).SequenceName for x in dicom_file_list])
                sequence_dict = {}
                for dcm_name in dicom_file_list:
                    dcm_obj = pydicom.read_file(dcm_name)
                    var = dcm_obj.SequenceName
                    if (var not in sequence_dict.keys()):
                        sequence_dict[var] = [dcm_name]
                    else:
                        sequence_dict[var].append(dcm_name)
            except AttributeError:
                try:
                    logger.warning('    MRI sequence name not found. The SeriesDescription will be used instead.')
                    sequence_names = np.unique([pydicom.read_file(x).SeriesDescription for x in dicom_file_list])
                    sequence_dict = {}
                    for dcm_name in dicom_file_list:
                        dcm_obj = pydicom.read_file(dcm_name)
                        var = dcm_obj.SeriesDescription
                        if (var not in sequence_dict.keys()):
                            sequence_dict[var] = [dcm_name]
                        else:
                            sequence_dict[var].append(dcm_name)
                except AttributeError:
                    logger.warning('    MRI SeriesDescription not found. The AcquisitionComments will be used instead.')
                    sequence_names = np.unique([pydicom.read_file(x).AcquisitionComments for x in dicom_file_list])
                    sequence_dict = {}
                    for dcm_name in dicom_file_list:
                        dcm_obj = pydicom.read_file(dcm_name)
                        var = dcm_obj.AcquisitionComments
                        if (var not in sequence_dict.keys()):
                            sequence_dict[var] = [dcm_name]
                        else:
                            sequence_dict[var].append(dcm_name)
            if (initial_dicom.Manufacturer == 'GE MEDICAL SYSTEMS'):
                if (initial_dicom.SeriesDescription == 'Diffusion Weighted'):
                    num_images_per_seq = initial_dicom[(33, 4175)].value
                    sequence_names = np.unique([f"DWI_{str(((pydicom.read_file(x)['InstanceNumber'].value - 1) // num_images_per_seq))}" for x in dicom_file_list])
                    sequence_name_index_dict = {name: index for (index, name) in enumerate(sequence_names)}
                    sequence_dict = {}
                    for dcm_name in dicom_file_list:
                        dcm_obj = pydicom.read_file(dcm_name)
                        var = f"DWI_{str(((dcm_obj['InstanceNumber'].value - 1) // num_images_per_seq))}"
                        var_to_index = sequence_name_index_dict[var]
                        if (var_to_index not in sequence_dict.keys()):
                            sequence_dict[var_to_index] = [dcm_name]
                        else:
                            sequence_dict[var_to_index].append(dcm_name)
                    sequence_names = sorted(sequence_dict.keys())
            if (np.alen(sequence_names) > 1):
                logger.warning('  Two MR sequences were found under a single series UID.')
                logger.warning('  These will be split into separate images.')
                for sequence_name in sequence_names:
                    dicom_file_list_by_sequence = sequence_dict[sequence_name]
                    logger.info(sequence_name)
                    logger.info(len(dicom_file_list_by_sequence))
                    sorted_file_list = safe_sort_dicom_image_list(dicom_file_list_by_sequence)
                    initial_dicom = pydicom.read_file(sorted_file_list[0], force=True)
                    image_by_sequence = sitk.ReadImage(sorted_file_list)
                    dicom_file_metadata_by_sequence = {'parent_sorting_data': parent_sorting_data, 'study_uid': study_uid}
                    (yield ('IMAGES', dicom_file_metadata_by_sequence, initial_dicom, image_by_sequence))
                return
        (yield ('IMAGES', dicom_file_metadata, initial_dicom, image))
    if ('Structure' in initial_dicom_sop_class_name):
        logger.info(f'      Number of files: {len(dicom_file_list)}')
        for (index, dicom_file) in enumerate(dicom_file_list):
            dicom_object = pydicom.read_file(dicom_file, force=True)
            '\n            ! TO DO\n            What happens if there is an RT structure set with different referenced sequences?\n            '
            referenced_frame_of_reference_item = dicom_object.ReferencedFrameOfReferenceSequence[0]
            rt_referenced_series_item = referenced_frame_of_reference_item.RTReferencedStudySequence[0]
            rt_referenced_series_again_item = rt_referenced_series_item.RTReferencedSeriesSequence[0]
            image_series_uid = rt_referenced_series_again_item.SeriesInstanceUID
            logger.info(f'      Item {index}: Matched SeriesInstanceUID = {image_series_uid}')
            sorted_file_list = safe_sort_dicom_image_list(dicom_series_dict[image_series_uid])
            image = sitk.ReadImage(sorted_file_list)
            initial_dicom = pydicom.read_file(sorted_file_list[0], force=True)
            (structure_name_list, structure_image_list) = transform_point_set_from_dicom_struct(image, dicom_object)
            dicom_file_metadata = {'parent_sorting_data': parent_sorting_data, 'study_uid': study_uid, 'structure_name_list': structure_name_list}
            (yield ('STRUCTURES', dicom_file_metadata, dicom_object, structure_image_list))
    if ('Dose' in initial_dicom_sop_class_name):
        logger.info(f'      Number of files: {len(dicom_file_list)}')
        for (index, dicom_file) in enumerate(dicom_file_list):
            dicom_object = pydicom.read_file(dicom_file, force=True)
            '\n            ! CHECKPOINT\n            There should only be a single RT dose file (with each series UID)\n            If there are more, yield each\n            '
            initial_dicom = pydicom.read_file(dicom_file, force=True)
            dicom_file_metadata = {'parent_sorting_data': parent_sorting_data, 'study_uid': study_uid}
            raw_dose_image = sitk.ReadImage(dicom_file, sitk.sitkFloat32)
            dose_grid_scaling = dicom_object.DoseGridScaling
            logger.debug(f'  Dose grid scaling: {dose_grid_scaling} Gy')
            scaled_dose_image = (raw_dose_image * dose_grid_scaling)
            (yield ('DOSES', dicom_file_metadata, dicom_object, scaled_dose_image))
        '\n        ! TO DO\n        1. (DONE) Implement conversion of dose files (to NIFTI images)\n        2. Implement conversion of RT plan files to text dump\n        3. Do something with other files (e.g. Deformable Image Registration stuff)\n        '
    return
def process_dicom_series(dicom_series_dict, series_uid, parent_sorting_field='PatientName', return_extra=True, individual_file=False, initial_sop_class_name_default='UNKNOWN'):
    if (not individual_file):
        logger.info(f'  Processing series UID: {series_uid}')
        dicom_file_list = dicom_series_dict[series_uid]
    else:
        logger.info(f'  Processing individual file: {individual_file}')
        dicom_file_list = [individual_file]
    logger.info(f'  Number of DICOM files: {len(dicom_file_list)}')
    initial_dicom = pydicom.read_file(dicom_file_list[0])
    parent_sorting_data = re.sub('[^\\w]', '_', str(initial_dicom[parent_sorting_field].value)).upper()
    if (parent_sorting_data == ):
        logger.error(f'Could not find any data in {parent_sorting_field}. This is very bad, the data cannot be sorted properly.')
        '\n        ! TO DO\n        Implement a routine to let a user correlate a root directory with a name\n        '
        parent_sorting_data = 'TEMP'
    try:
        initial_dicom_sop_class_name = initial_dicom.SOPClassUID.name
    except AttributeError:
        logger.warning(f'Could not find DICOM SOP Class UID, using {initial_sop_class_name_default}.')
        initial_dicom_sop_class_name = initial_sop_class_name_default
    try:
        study_uid = initial_dicom.StudyInstanceUID
    except AttributeError:
        study_uid = '00001'
    '\n    ! TO DO\n    Need to check for secondary capture image storage\n    This can include JPEGs with written information on them\n    This is typically not very useful\n    We can dump it to file\n    Or just save the DICOM file in the folder of interest\n\n    Not a big problem, sort out another day\n    '
    if (('Image' in initial_dicom_sop_class_name) and (initial_dicom_sop_class_name != 'Secondary Capture Image Storage')):
        sorted_file_list = safe_sort_dicom_image_list(dicom_file_list)
        try:
            image = sitk.ReadImage(sorted_file_list)
        except RuntimeError:
            logger.warning('  Could not read image into SimpleITK.')
            logger.info('  Processing files individually.')
            for dicom_file in dicom_file_list:
                return process_dicom_series(dicom_series_dict, series_uid, parent_sorting_field=parent_sorting_field, return_extra=return_extra, individual_file=dicom_file, initial_sop_class_name_default=initial_sop_class_name_default)
        dicom_file_metadata = {'parent_sorting_data': parent_sorting_data, 'study_uid': study_uid}
        '\n        ! TO DO - integrity check\n            Read in all the files here, check the slice location and determine if any are missing\n        '
        if (initial_dicom.Modality == 'PT'):
            None
        '\n        ! CHECKPOINT\n        Some DCE MRI sequences have the same series UID\n        Here we check the sequence name, and split if necessary\n        '
        if (initial_dicom.Modality == 'MR'):
            try:
                sequence_names = np.unique([pydicom.read_file(x).SequenceName for x in dicom_file_list])
                sequence_dict = {}
                for dcm_name in dicom_file_list:
                    dcm_obj = pydicom.read_file(dcm_name)
                    var = dcm_obj.SequenceName
                    if (var not in sequence_dict.keys()):
                        sequence_dict[var] = [dcm_name]
                    else:
                        sequence_dict[var].append(dcm_name)
            except AttributeError:
                try:
                    logger.warning('    MRI sequence name not found. The SeriesDescription will be used instead.')
                    sequence_names = np.unique([pydicom.read_file(x).SeriesDescription for x in dicom_file_list])
                    sequence_dict = {}
                    for dcm_name in dicom_file_list:
                        dcm_obj = pydicom.read_file(dcm_name)
                        var = dcm_obj.SeriesDescription
                        if (var not in sequence_dict.keys()):
                            sequence_dict[var] = [dcm_name]
                        else:
                            sequence_dict[var].append(dcm_name)
                except AttributeError:
                    logger.warning('    MRI SeriesDescription not found. The AcquisitionComments will be used instead.')
                    sequence_names = np.unique([pydicom.read_file(x).AcquisitionComments for x in dicom_file_list])
                    sequence_dict = {}
                    for dcm_name in dicom_file_list:
                        dcm_obj = pydicom.read_file(dcm_name)
                        var = dcm_obj.AcquisitionComments
                        if (var not in sequence_dict.keys()):
                            sequence_dict[var] = [dcm_name]
                        else:
                            sequence_dict[var].append(dcm_name)
            if (initial_dicom.Manufacturer == 'GE MEDICAL SYSTEMS'):
                if (initial_dicom.SeriesDescription == 'Diffusion Weighted'):
                    num_images_per_seq = initial_dicom[(33, 4175)].value
                    sequence_names = np.unique([f"DWI_{str(((pydicom.read_file(x)['InstanceNumber'].value - 1) // num_images_per_seq))}" for x in dicom_file_list])
                    sequence_name_index_dict = {name: index for (index, name) in enumerate(sequence_names)}
                    sequence_dict = {}
                    for dcm_name in dicom_file_list:
                        dcm_obj = pydicom.read_file(dcm_name)
                        var = f"DWI_{str(((dcm_obj['InstanceNumber'].value - 1) // num_images_per_seq))}"
                        var_to_index = sequence_name_index_dict[var]
                        if (var_to_index not in sequence_dict.keys()):
                            sequence_dict[var_to_index] = [dcm_name]
                        else:
                            sequence_dict[var_to_index].append(dcm_name)
                    sequence_names = sorted(sequence_dict.keys())
            if (np.alen(sequence_names) > 1):
                logger.warning('  Two MR sequences were found under a single series UID.')
                logger.warning('  These will be split into separate images.')
                for sequence_name in sequence_names:
                    dicom_file_list_by_sequence = sequence_dict[sequence_name]
                    logger.info(sequence_name)
                    logger.info(len(dicom_file_list_by_sequence))
                    sorted_file_list = safe_sort_dicom_image_list(dicom_file_list_by_sequence)
                    initial_dicom = pydicom.read_file(sorted_file_list[0], force=True)
                    image_by_sequence = sitk.ReadImage(sorted_file_list)
                    dicom_file_metadata_by_sequence = {'parent_sorting_data': parent_sorting_data, 'study_uid': study_uid}
                    (yield ('IMAGES', dicom_file_metadata_by_sequence, initial_dicom, image_by_sequence))
                return
        (yield ('IMAGES', dicom_file_metadata, initial_dicom, image))
    if ('Structure' in initial_dicom_sop_class_name):
        logger.info(f'      Number of files: {len(dicom_file_list)}')
        for (index, dicom_file) in enumerate(dicom_file_list):
            dicom_object = pydicom.read_file(dicom_file, force=True)
            '\n            ! TO DO\n            What happens if there is an RT structure set with different referenced sequences?\n            '
            referenced_frame_of_reference_item = dicom_object.ReferencedFrameOfReferenceSequence[0]
            rt_referenced_series_item = referenced_frame_of_reference_item.RTReferencedStudySequence[0]
            rt_referenced_series_again_item = rt_referenced_series_item.RTReferencedSeriesSequence[0]
            image_series_uid = rt_referenced_series_again_item.SeriesInstanceUID
            logger.info(f'      Item {index}: Matched SeriesInstanceUID = {image_series_uid}')
            sorted_file_list = safe_sort_dicom_image_list(dicom_series_dict[image_series_uid])
            image = sitk.ReadImage(sorted_file_list)
            initial_dicom = pydicom.read_file(sorted_file_list[0], force=True)
            (structure_name_list, structure_image_list) = transform_point_set_from_dicom_struct(image, dicom_object)
            dicom_file_metadata = {'parent_sorting_data': parent_sorting_data, 'study_uid': study_uid, 'structure_name_list': structure_name_list}
            (yield ('STRUCTURES', dicom_file_metadata, dicom_object, structure_image_list))
    if ('Dose' in initial_dicom_sop_class_name):
        logger.info(f'      Number of files: {len(dicom_file_list)}')
        for (index, dicom_file) in enumerate(dicom_file_list):
            dicom_object = pydicom.read_file(dicom_file, force=True)
            '\n            ! CHECKPOINT\n            There should only be a single RT dose file (with each series UID)\n            If there are more, yield each\n            '
            initial_dicom = pydicom.read_file(dicom_file, force=True)
            dicom_file_metadata = {'parent_sorting_data': parent_sorting_data, 'study_uid': study_uid}
            raw_dose_image = sitk.ReadImage(dicom_file, sitk.sitkFloat32)
            dose_grid_scaling = dicom_object.DoseGridScaling
            logger.debug(f'  Dose grid scaling: {dose_grid_scaling} Gy')
            scaled_dose_image = (raw_dose_image * dose_grid_scaling)
            (yield ('DOSES', dicom_file_metadata, dicom_object, scaled_dose_image))
        '\n        ! TO DO\n        1. (DONE) Implement conversion of dose files (to NIFTI images)\n        2. Implement conversion of RT plan files to text dump\n        3. Do something with other files (e.g. Deformable Image Registration stuff)\n        '
    return