Beispiel #1
0
def importFromDICOMWeb(dicomWebEndpoint, studyInstanceUID, seriesInstanceUID=None, accessToken=None):
  """
  Downloads and imports DICOM series from a DICOMweb instance.
  Example usage:
    from DICOMLib import DICOMUtils

    loadedUIDs = DICOMUtils.importFromDICOMWeb(dicomWebEndpoint="https://yourdicomweburl/dicomWebEndpoint",
                                             studyInstanceUID="2.16.840.1.113669.632.20.1211.10000509338")
                                             accessToken="YOUR_ACCESS_TOKEN")
  :param dicomWebEndpoint: Endpoint URL for retrieving the study/series from DICOMweb
  :param studyInstanceUID: UID for the study to be downloaded
  :param seriesInstanceUID: UID for the series to be downloaded. If not specified, all series will be downloaded from the study
  :param accessToken: Optional access token for the query
  :return: List of imported study UIDs
  """

  from dicomweb_client.api import DICOMwebClient
  import random

  if accessToken is None:
    client = DICOMwebClient(url = dicomWebEndpoint)
  else:
    client = DICOMwebClient(
              url = dicomWebEndpoint,
              headers = { "Authorization": "Bearer {}".format(accessToken) },
              )

  seriesList = client.search_for_series(study_instance_uid=studyInstanceUID)
  seriesInstanceUIDs = []
  if not seriesInstanceUID is None:
    seriesInstanceUIDs = [seriesInstanceUID]
  else:
    for series in seriesList:
      currentSeriesInstanceUID = series['0020000E']['Value'][0]
      seriesInstanceUIDs.append(currentSeriesInstanceUID)

  fileNumber = 0
  for currentSeriesInstanceUID in seriesInstanceUIDs:
    instances = client.retrieve_series(
      study_instance_uid=studyInstanceUID,
      series_instance_uid=currentSeriesInstanceUID)

    outputDirectoryBase = slicer.dicomDatabase.databaseDirectory + "/DICOMweb"
    if not os.access(outputDirectoryBase, os.F_OK):
      os.makedirs(outputDirectoryBase)
    outputDirectoryBase += "/" + qt.QDateTime.currentDateTime().toString("yyyyMMdd-hhmmss")
    outputDirectory = qt.QTemporaryDir(outputDirectoryBase)  # Add unique substring to directory
    outputDirectory.setAutoRemove(False)
    outputDirectoryPath = outputDirectory.path()

    for instance in instances:
      filename = outputDirectoryPath + "/" + str(fileNumber) + ".dcm"
      instance.save_as(filename)
      fileNumber += 1
      slicer.app.processEvents()
    importDicom(outputDirectoryPath)

  return seriesInstanceUIDs
Beispiel #2
0
def _search_for_series(args):
    '''Searches for Series and writes metadata to standard output.'''
    params = _parse_search_parameters(args)
    client = DICOMwebClient(args.url,
                            username=args.username,
                            password=args.password,
                            ca_bundle=args.ca_bundle,
                            cert=args.cert)
    series = client.search_for_series(args.study_instance_uid, **params)
    _print_metadata(series, args.prettify, args.dicomize)
Beispiel #3
0
def importFromDICOMWeb(dicomWebEndpoint,
                       studyInstanceUID,
                       seriesInstanceUID=None,
                       accessToken=None):
    """
    Downloads and imports DICOM series from a DICOMweb instance.
    Progress is displayed and if errors occur then they are displayed in a popup window in the end.
    If all the instances in a series are already imported then the series will not be retrieved and imported again.

    :param dicomWebEndpoint: Endpoint URL for retrieving the study/series from DICOMweb
    :param studyInstanceUID: UID for the study to be downloaded
    :param seriesInstanceUID: UID for the series to be downloaded. If not specified, all series will be downloaded from the study
    :param accessToken: Optional access token for the query
    :return: List of imported study UIDs

    Example: calling from PythonSlicer console

    .. code-block:: python

      from DICOMLib import DICOMUtils
      loadedUIDs = DICOMUtils.importFromDICOMWeb(dicomWebEndpoint="https://yourdicomweburl/dicomWebEndpoint",
                                               studyInstanceUID="2.16.840.1.113669.632.20.1211.10000509338")
                                               accessToken="YOUR_ACCESS_TOKEN")

    """

    from dicomweb_client.api import DICOMwebClient

    seriesImported = []
    errors = []
    clientLogger = logging.getLogger('dicomweb_client')
    originalClientLogLevel = clientLogger.level

    progressDialog = slicer.util.createProgressDialog(
        parent=slicer.util.mainWindow(), value=0, maximum=100)
    try:
        progressDialog.labelText = f'Retrieving series list...'
        slicer.app.processEvents()

        if accessToken is None:
            client = DICOMwebClient(url=dicomWebEndpoint)
        else:
            client = DICOMwebClient(
                url=dicomWebEndpoint,
                headers={"Authorization": f"Bearer {accessToken}"},
            )

        seriesList = client.search_for_series(
            study_instance_uid=studyInstanceUID)
        seriesInstanceUIDs = []
        if seriesInstanceUID is not None:
            seriesInstanceUIDs = [seriesInstanceUID]
        else:
            for series in seriesList:
                currentSeriesInstanceUID = series['0020000E']['Value'][0]
                seriesInstanceUIDs.append(currentSeriesInstanceUID)

        # Turn off detailed logging, because it would slow down the file transfer
        clientLogger.setLevel(logging.WARNING)

        fileNumber = 0
        cancelled = False
        for seriesIndex, currentSeriesInstanceUID in enumerate(
                seriesInstanceUIDs):
            progressDialog.labelText = f'Retrieving series {seriesIndex+1} of {len(seriesInstanceUIDs)}...'
            slicer.app.processEvents()

            try:
                seriesInfo = client.retrieve_series_metadata(
                    study_instance_uid=studyInstanceUID,
                    series_instance_uid=currentSeriesInstanceUID)
                numberOfInstances = len(seriesInfo)

                # Skip retrieve and import of this series if it is already imported
                alreadyImportedInstances = slicer.dicomDatabase.instancesForSeries(
                    currentSeriesInstanceUID)
                seriesAlreadyImported = True
                for serieInfo in seriesInfo:
                    sopInstanceUID = serieInfo['00080018']['Value'][0]
                    if sopInstanceUID not in alreadyImportedInstances:
                        seriesAlreadyImported = False
                        break
                if seriesAlreadyImported:
                    seriesImported.append(currentSeriesInstanceUID)
                    continue

                instances = client.iter_series(
                    study_instance_uid=studyInstanceUID,
                    series_instance_uid=currentSeriesInstanceUID)

                slicer.app.processEvents()
                cancelled = progressDialog.wasCanceled
                if cancelled:
                    break

                outputDirectoryBase = slicer.dicomDatabase.databaseDirectory + "/DICOMweb"
                if not os.access(outputDirectoryBase, os.F_OK):
                    os.makedirs(outputDirectoryBase)
                outputDirectoryBase += "/" + qt.QDateTime.currentDateTime(
                ).toString("yyyyMMdd-hhmmss")
                outputDirectory = qt.QTemporaryDir(
                    outputDirectoryBase)  # Add unique substring to directory
                outputDirectory.setAutoRemove(False)
                outputDirectoryPath = outputDirectory.path()

                for instanceIndex, instance in enumerate(instances):
                    progressDialog.setValue(
                        int(100 * instanceIndex / numberOfInstances))
                    slicer.app.processEvents()
                    cancelled = progressDialog.wasCanceled
                    if cancelled:
                        break
                    filename = outputDirectoryPath + "/" + str(
                        fileNumber) + ".dcm"
                    instance.save_as(filename)
                    fileNumber += 1

                if cancelled:
                    # cancel was requested in instance retrieve loop,
                    # stop the entire import process
                    break

                importDicom(outputDirectoryPath)
                seriesImported.append(currentSeriesInstanceUID)

            except Exception as e:
                import traceback
                errors.append(
                    f"Error importing series {currentSeriesInstanceUID}: {str(e)} ({traceback.format_exc()})"
                )

    except Exception as e:
        import traceback
        errors.append(f"{str(e)} ({traceback.format_exc()})")

    finally:
        progressDialog.close()
        clientLogger.setLevel(originalClientLogLevel)

    if errors:
        slicer.util.errorDisplay(
            f"Errors occurred during DICOMweb import of {len(errors)} series.",
            detailedText="\n\n".join(errors))
    elif cancelled and (len(seriesImported) < len(seriesInstanceUIDs)):
        slicer.util.infoDisplay(
            f"DICOMweb import has been interrupted after completing {len(seriesImported)} out of {len(seriesInstanceUIDs)} series."
        )

    return seriesImported
Beispiel #4
0
def importFromDICOMWeb(dicomWebEndpoint,
                       studyInstanceUID,
                       seriesInstanceUID=None,
                       accessToken=None):
    """
  Downloads and imports DICOM series from a DICOMweb instance.
  Example usage:
    from DICOMLib import DICOMUtils

    loadedUIDs = DICOMUtils.importFromDICOMWeb(dicomWebEndpoint="https://yourdicomweburl/dicomWebEndpoint",
                                             studyInstanceUID="2.16.840.1.113669.632.20.1211.10000509338")
                                             accessToken="YOUR_ACCESS_TOKEN")
  :param dicomWebEndpoint: Endpoint URL for retrieving the study/series from DICOMweb
  :param studyInstanceUID: UID for the study to be downloaded
  :param seriesInstanceUID: UID for the series to be downloaded. If not specified, all series will be downloaded from the study
  :param accessToken: Optional access token for the query
  :return: List of imported study UIDs
  """

    from dicomweb_client.api import DICOMwebClient
    import random

    progressDialog = slicer.util.createProgressDialog(
        parent=slicer.util.mainWindow(), value=0, maximum=100)
    progressDialog.labelText = f'Retrieving series list...'
    slicer.app.processEvents()

    if accessToken is None:
        client = DICOMwebClient(url=dicomWebEndpoint,
                                callback=progressCallback)
    else:
        client = DICOMwebClient(
            url=dicomWebEndpoint,
            headers={"Authorization": f"Bearer {accessToken}"},
        )

    seriesList = client.search_for_series(study_instance_uid=studyInstanceUID)
    seriesInstanceUIDs = []
    if not seriesInstanceUID is None:
        seriesInstanceUIDs = [seriesInstanceUID]
    else:
        for series in seriesList:
            currentSeriesInstanceUID = series['0020000E']['Value'][0]
            seriesInstanceUIDs.append(currentSeriesInstanceUID)

    fileNumber = 0
    cancelled = False
    for seriesIndex, currentSeriesInstanceUID in enumerate(seriesInstanceUIDs):
        progressDialog.labelText = f'Retrieving series {seriesIndex+1} of {len(seriesInstanceUIDs)}...'
        slicer.app.processEvents()
        instances = client.retrieve_series(
            study_instance_uid=studyInstanceUID,
            series_instance_uid=currentSeriesInstanceUID)

        progressDialog.setValue(
            int(100 * seriesIndex / len(seriesInstanceUIDs)))
        slicer.app.processEvents()
        cancelled = progressDialog.wasCanceled
        if cancelled:
            break

        outputDirectoryBase = slicer.dicomDatabase.databaseDirectory + "/DICOMweb"
        if not os.access(outputDirectoryBase, os.F_OK):
            os.makedirs(outputDirectoryBase)
        outputDirectoryBase += "/" + qt.QDateTime.currentDateTime().toString(
            "yyyyMMdd-hhmmss")
        outputDirectory = qt.QTemporaryDir(
            outputDirectoryBase)  # Add unique substring to directory
        outputDirectory.setAutoRemove(False)
        outputDirectoryPath = outputDirectory.path()

        for instanceIndex, instance in enumerate(instances):
            filename = outputDirectoryPath + "/" + str(fileNumber) + ".dcm"
            instance.save_as(filename)
            fileNumber += 1

        importDicom(outputDirectoryPath)
        if cancelled:
            break

    progressDialog.close()
    return seriesInstanceUIDs
    def get_files(self, ds, **kwargs):
        print("Starting module LocalGetRefSeriesOperator")

        if self.search_policy != 'reference_uid':
            print(
                "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
            )
            print("")
            print("Parameter 'modality' has to be set for search_policy: {} !".
                  format(self.search_policy))
            print("Abort.")
            print("")
            print(
                "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
            )
            exit(1)

        client = DICOMwebClient(url=self.pacs_dcmweb,
                                qido_url_prefix="rs",
                                wado_url_prefix="rs",
                                stow_url_prefix="rs")

        run_dir = os.path.join(WORKFLOW_DIR, kwargs['dag_run'].run_id)
        batch_folder = [
            f for f in glob.glob(os.path.join(run_dir, BATCH_NAME, '*'))
        ]
        download_series_list = []

        for batch_element_dir in batch_folder:
            print("batch_element_dir: {}".format(batch_element_dir))
            dcm_files = sorted(
                glob.glob(os.path.join(batch_element_dir, "initial-input",
                                       "*.dcm*"),
                          recursive=True))
            if len(dcm_files) > 0:
                incoming_dcm = pydicom.dcmread(dcm_files[0])

                if self.search_policy == 'reference_uid':
                    if (0x0008, 0x1115) in incoming_dcm:
                        for ref_series in incoming_dcm[0x0008, 0x1115]:
                            if (0x0020, 0x000E) not in ref_series:
                                print(
                                    "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                                )
                                print("")
                                print(
                                    "Could not extract SeriesUID from referenced DICOM series."
                                )
                                print("Abort.")
                                print("")
                                print(
                                    "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                                )
                                exit(1)
                            reference_series_uid = ref_series[0x0020,
                                                              0x000E].value
                            pacs_series = client.search_for_series(
                                search_filters={
                                    '0020000E': reference_series_uid
                                })
                            if len(pacs_series) != 1:
                                print(
                                    "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                                )
                                print("")
                                print(
                                    "Could not find referenced SeriesUID in the PACS: {} !"
                                    .format(reference_series_uid))
                                print("Abort.")
                                print("")
                                print(
                                    "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                                )
                                exit(1)
                            download_series_list.append({
                                "reference_study_uid":
                                pacs_series[0]['0020000D']['Value'][0],
                                "reference_series_uid":
                                reference_series_uid,
                                "target_dir":
                                os.path.join(batch_element_dir,
                                             self.operator_out_dir)
                            })
                    else:
                        print(
                            "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                        )
                        print("")
                        print(
                            "Could not find referenced dcm-series within the metadata!"
                        )
                        print("Abort.")
                        print("")
                        print(
                            "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                        )
                        exit(1)
                if self.search_policy == 'study_uid':
                    pacs_series = client.search_for_series(
                        search_filters={
                            '0020000D': incoming_dcm.StudyInstanceUID,
                            '00080060': self.modality.upper()
                        })
                    if len(pacs_series) != 1:
                        print(
                            "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                        )
                        print("")
                        print(
                            "Could not identify the searched modality: {} from the studyUID: {} !"
                            .format(self.modality,
                                    incoming_dcm.StudyInstanceUID))
                        print(
                            "Number of possible DICOMs in the PACS: {}".format(
                                len(pacs_series)))
                        print("Abort.")
                        print("")
                        print(
                            "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                        )
                        exit(1)
                    download_series_list.append({
                        "reference_study_uid":
                        pacs_series[0]['0020000D']['Value'][0],
                        "reference_series_uid":
                        pacs_series[0]['0020000E']['Value'][0],
                        "target_dir":
                        os.path.join(batch_element_dir, self.operator_out_dir)
                    })

                if self.search_policy == 'patient_uid':
                    if not (0x0010, 0x0020) in incoming_dcm:
                        print(
                            "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                        )
                        print("")
                        print(
                            "Could not extract PatientUID from referenced DICOM series."
                        )
                        print("Abort.")
                        print("")
                        print(
                            "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                        )
                        exit(1)

                    patient_uid = incoming_dcm[0x0010, 0x0020].value
                    pacs_series = client.search_for_series(
                        search_filters={
                            '00100020': patient_uid,
                            '00080060': self.modality.upper()
                        })
                    if len(pacs_series) != 1:
                        print(
                            "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                        )
                        print("")
                        print(
                            "Could not identify the searched modality: {} from the PatientUID: {} !"
                            .format(self.modality, patient_uid))
                        print(
                            "Number of possible DICOMs in the PACS: {}".format(
                                len(pacs_series)))
                        print("Abort.")
                        print("")
                        print(
                            "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
                        )
                        exit(1)
                    download_series_list.append({
                        "reference_study_uid":
                        pacs_series[0]['0020000D']['Value'][0],
                        "reference_series_uid":
                        pacs_series[0]['0020000E']['Value'][0],
                        "target_dir":
                        os.path.join(batch_element_dir, self.operator_out_dir)
                    })

        if len(download_series_list) == 0:
            print(
                "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
            )
            print("")
            print("No series to download could be found!")
            print("Abort.")
            print("")
            print(
                "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
            )
            exit(1)

        for series in download_series_list:
            print("Downloading series: {}".format(
                series["reference_series_uid"]))
            HelperDcmWeb.downloadSeries(
                studyUID=series["reference_study_uid"],
                seriesUID=series["reference_series_uid"],
                target_dir=series['target_dir'])
    def get_files(self, ds, **kwargs):
        print("Starting module LocalGetRefSeriesOperator")

        if self.search_policy != 'reference_uid' and self.modality is None:
            print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
            print("")
            print("Parameter 'modality' has to be set for search_policy: {} !".format(self.search_policy))
            print("Abort.")
            print("")
            print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
            exit(1)

        client = DICOMwebClient(url=self.pacs_dcmweb, qido_url_prefix="rs", wado_url_prefix="rs", stow_url_prefix="rs")

        run_dir = os.path.join(WORKFLOW_DIR, kwargs['dag_run'].run_id)
        batch_folder = [f for f in glob.glob(os.path.join(run_dir, BATCH_NAME, '*'))]
        download_series_list = []

        for batch_element_dir in batch_folder:
            dcm_files = sorted(glob.glob(os.path.join(batch_element_dir, self.operator_in_dir, "*.dcm*"), recursive=True))
            if len(dcm_files) > 0:
                incoming_dcm = pydicom.dcmread(dcm_files[0])

                if self.search_policy == 'reference_uid':
                    if (0x0008, 0x1115) in incoming_dcm:
                        for ref_series in incoming_dcm[0x0008, 0x1115]:
                            if (0x0020, 0x000E) not in ref_series:
                                print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
                                print("")
                                print("Could not extract SeriesUID from referenced DICOM series.")
                                print("Abort.")
                                print("")
                                print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
                                exit(1)
                            reference_series_uid = ref_series[0x0020, 0x000E].value
                            pacs_series = client.search_for_series(search_filters={'0020000E': reference_series_uid})
                            print(f"Found series: {len(pacs_series)} for reference_series_uid: {reference_series_uid}")
                            if len(pacs_series) != 1:
                                print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
                                print("")
                                print(f"Could not find referenced SeriesUID in the PACS: {reference_series_uid} !")
                                print("Abort.")
                                print("")
                                print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
                                exit(1)
                            download_series_list.append(
                                {
                                    "reference_study_uid": pacs_series[0]['0020000D']['Value'][0],
                                    "reference_series_uid": reference_series_uid,
                                    "target_dir": os.path.join(batch_element_dir, self.operator_out_dir)
                                }
                            )
                    else:
                        print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
                        print("")
                        print("Could not find referenced dcm-series within the metadata!")
                        print("Abort.")
                        print("")
                        print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
                        exit(1)
                if self.search_policy == 'study_uid':
                    pacs_series = client.search_for_series(search_filters={'0020000D': incoming_dcm.StudyInstanceUID, '00080060': self.modality.upper()})
                    print(f"Found series: {len(pacs_series)} for modality {self.modality.upper()} in study: {incoming_dcm.StudyInstanceUID}")
                    if len(pacs_series) == 0 or (self.expected_file_count != "all" and len(pacs_series) != self.expected_file_count):
                        print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
                        print("")
                        print(f"Could not identify the searched modality: {self.modality} from the studyUID: {incoming_dcm.StudyInstanceUID} !")
                        print(f"Expected {self.expected_file_count} series of modality {self.modality} - found {len(pacs_series)} series")
                        print("Abort.")
                        print("")
                        print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
                        exit(1)
                    for series in pacs_series:
                        download_series_list.append(
                            {
                                "reference_study_uid": series['0020000D']['Value'][0],
                                "reference_series_uid": series['0020000E']['Value'][0],
                                "target_dir": os.path.join(batch_element_dir, self.operator_out_dir)
                            }
                        )

                if self.search_policy == 'patient_uid':
                    if not (0x0010, 0x0020) in incoming_dcm:
                        print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
                        print("")
                        print("Could not extract PatientUID from referenced DICOM series.")
                        print("Abort.")
                        print("")
                        print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
                        exit(1)

                    patient_uid = incoming_dcm[0x0010, 0x0020].value
                    pacs_series = client.search_for_series(search_filters={'00100020': patient_uid, '00080060': self.modality.upper()})
                    print(f"Found series: {len(pacs_series)} for modality {self.modality.upper()} in patient_uid: {patient_uid}")
                    if len(pacs_series) == 0 or (self.expected_file_count != "all" and len(pacs_series) != self.expected_file_count):
                        print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
                        print("")
                        print(f"Could not identify the searched modality: {self.modality} from the studyUID: {incoming_dcm.StudyInstanceUID} !")
                        print(f"Expected {self.expected_file_count} series of modality {self.modality} - found {len(pacs_series)} series")
                        print("Abort.")
                        print("")
                        print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
                        exit(1)
                    for series in pacs_series:
                        download_series_list.append(
                            {
                                "reference_study_uid": series['0020000D']['Value'][0],
                                "reference_series_uid": series['0020000E']['Value'][0],
                                "target_dir": os.path.join(batch_element_dir, self.operator_out_dir)
                            }
                        )

        if len(download_series_list) == 0:
            print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
            print("")
            print("No series to download could be found!")
            print("Abort.")
            print("")
            print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
            exit(1)

        results = ThreadPool(self.parallel_downloads).imap_unordered(self.download_series, download_series_list)

        for result in results:
            print(result)