Esempio n. 1
0
def trf_input_method(patient_id="", key_namespace="", **_):
    indexed_trf_directory = get_indexed_trf_directory()

    patient_id = st.text_input("Patient ID",
                               patient_id,
                               key=f"{key_namespace}_patient_id")
    patient_id

    filepaths = list(
        indexed_trf_directory.glob(f"*/{patient_id}_*/*/*/*/*.trf"))

    raw_timestamps = [
        "_".join(path.parent.name.split("_")[0:2]) for path in filepaths
    ]
    timestamps = list(
        pd.to_datetime(raw_timestamps, format="%Y-%m-%d_%H%M%S").astype(str))

    timestamp_filepath_map = dict(zip(timestamps, filepaths))

    timestamps = sorted(timestamps, reverse=True)

    if len(timestamps) == 0:
        if patient_id != "":
            st.write(
                st_exceptions.NoRecordsFound(
                    f"No TRF log file found for patient ID {patient_id}"))
        return {"patient_id": patient_id}

    if len(timestamps) == 1:
        default_timestamp = timestamps[0]
    else:
        default_timestamp = []

    selected_trf_deliveries = st.multiselect(
        "Select TRF delivery timestamp(s)",
        timestamps,
        default=default_timestamp,
        key=f"{key_namespace}_trf_deliveries",
    )

    if not selected_trf_deliveries:
        return {}
    """
    #### TRF filepath(s)
    """

    selected_filepaths = [
        timestamp_filepath_map[timestamp]
        for timestamp in selected_trf_deliveries
    ]
    [str(path.resolve()) for path in selected_filepaths]
    """
    #### Log file header(s)
    """

    headers = []
    tables = []
    for path in selected_filepaths:
        header, table = read_trf(path)
        headers.append(header)
        tables.append(table)

    headers = pd.concat(headers)
    headers.reset_index(inplace=True)
    headers.drop("index", axis=1, inplace=True)

    headers
    """
    #### Corresponding Mosaiq SQL Details
    """

    mosaiq_details = get_logfile_mosaiq_info(headers)
    mosaiq_details = mosaiq_details.drop("beam_completed", axis=1)

    mosaiq_details

    patient_names = set()
    for _, row in mosaiq_details.iterrows():
        row
        patient_name = utl_patient.convert_patient_name_from_split(
            row["last_name"], row["first_name"])
        patient_names.add(patient_name)

    patient_name = filter_patient_names(patient_names)

    deliveries = cached_deliveries_loading(tables, delivery_from_trf)

    individual_identifiers = [
        f"{path.parent.parent.parent.parent.name} {path.parent.name}"
        for path in selected_filepaths
    ]

    identifier = f"TRF ({individual_identifiers[0]})"

    return {
        "site": None,
        "patient_id": patient_id,
        "patient_name": patient_name,
        "data_paths": selected_filepaths,
        "identifier": identifier,
        "deliveries": deliveries,
    }
Esempio n. 2
0
def dicom_input_method(  # pylint: disable = too-many-return-statements
        key_namespace="",
        patient_id="",
        site=None,
        **_):
    monaco_site = site

    FILE_UPLOAD = "File upload"
    MONACO_SEARCH = "Search Monaco file export location"

    dicom_export_locations = get_dicom_export_locations()

    import_method = st.radio(
        "DICOM import method",
        [FILE_UPLOAD, MONACO_SEARCH],
        key=f"{key_namespace}_dicom_file_import_method",
    )

    if import_method == FILE_UPLOAD:
        dicom_plan_bytes = st.file_uploader(
            "Upload DICOM RT Plan File",
            key=f"{key_namespace}_dicom_plan_uploader")

        if dicom_plan_bytes is None:
            return {}

        try:
            dicom_plan = pydicom.read_file(dicom_plan_bytes, force=True)
        except:  # pylint: disable = bare-except
            st.write(WrongFileType("Does not appear to be a DICOM file"))
            return {}

        if dicom_plan.SOPClassUID != DICOM_PLAN_UID:
            st.write(
                WrongFileType(
                    "The DICOM type needs to be an RT DICOM Plan file"))
            return {}

        data_paths = ["Uploaded DICOM file"]

    if import_method == MONACO_SEARCH:
        monaco_site = st_misc.site_picker(
            "Monaco Export Location",
            default=monaco_site,
            key=f"{key_namespace}_monaco_site",
        )

        monaco_export_directory = dicom_export_locations[monaco_site]
        st.write(monaco_export_directory.resolve())

        patient_id = st.text_input("Patient ID",
                                   patient_id,
                                   key=f"{key_namespace}_patient_id")

        found_dicom_files = list(
            monaco_export_directory.glob(f"{patient_id}_*.dcm"))

        dicom_plans = {}

        for path in found_dicom_files:
            dcm = load_dicom_file_if_plan(path)
            if dcm is not None:
                dicom_plans[path.name] = dcm

        dicom_plan_options = list(dicom_plans.keys())

        if len(dicom_plan_options) == 0 and patient_id != "":
            st.write(
                st_exceptions.NoRecordsFound(
                    f"No exported DICOM RT plans found for Patient ID {patient_id} "
                    f"within the directory {monaco_export_directory}"))
            return {"patient_id": patient_id}

        if len(dicom_plan_options) == 1:
            selected_plan = dicom_plan_options[0]
        else:
            selected_plan = st.radio(
                "Select DICOM Plan",
                dicom_plan_options,
                key=f"{key_namespace}_select_monaco_export_plan",
            )

        f"DICOM file being used: `{selected_plan}`"

        dicom_plan = dicom_plans[selected_plan]
        data_paths = [monaco_export_directory.joinpath(selected_plan)]

    patient_id = str(dicom_plan.PatientID)
    f"Patient ID: `{patient_id}`"

    patient_name = str(dicom_plan.PatientName)
    patient_name = utl_patient.convert_patient_name(patient_name)

    f"Patient Name: `{patient_name}`"

    rt_plan_name = str(dicom_plan.RTPlanName)
    f"Plan Name: `{rt_plan_name}`"

    try:
        deliveries_all_fractions = pymedphys.Delivery.from_dicom(
            dicom_plan, fraction_number="all")
    except AttributeError:
        st.write(WrongFileType("Does not appear to be a photon DICOM plan"))
        return {}

    fractions = list(deliveries_all_fractions.keys())
    if len(fractions) == 1:
        delivery = deliveries_all_fractions[fractions[0]]
    else:
        fraction_choices = {}

        for fraction, delivery in deliveries_all_fractions.items():
            rounded_mu = round(delivery.mu[-1], 1)

            fraction_choices[
                f"Perscription {fraction} with {rounded_mu} MU"] = fraction

        fraction_selection = st.radio(
            "Select relevant perscription",
            list(fraction_choices.keys()),
            key=f"{key_namespace}_dicom_perscription_chooser",
        )

        fraction_number = fraction_choices[fraction_selection]
        delivery = deliveries_all_fractions[fraction_number]

    deliveries = [delivery]

    identifier = f"DICOM ({rt_plan_name})"

    return {
        "site": monaco_site,
        "patient_id": patient_id,
        "patient_name": patient_name,
        "data_paths": data_paths,
        "identifier": identifier,
        "deliveries": deliveries,
    }
Esempio n. 3
0
def icom_input_method(patient_id="",
                      key_namespace="",
                      advanced_mode_local=False,
                      **_):
    icom_directories = get_default_icom_directories()

    if advanced_mode_local:
        "iCOM patient directories", icom_directories

    icom_directories = [pathlib.Path(path) for path in icom_directories]

    if advanced_mode_local:
        patient_id = st.text_input("Patient ID",
                                   patient_id,
                                   key=f"{key_namespace}_patient_id")
        patient_id

    icom_deliveries = []
    for path in icom_directories:
        icom_deliveries += list(path.glob(f"{patient_id}_*/*.xz"))

    icom_deliveries = sorted(icom_deliveries)

    icom_files_to_choose_from = [path.stem for path in icom_deliveries]

    timestamps = list(
        pd.to_datetime(icom_files_to_choose_from,
                       format="%Y%m%d_%H%M%S").astype(str))

    choice_path_map = dict(zip(timestamps, icom_deliveries))
    """
    Here you need to select the timestamps that correspond to a single
    fraction of the plan selected above. Most of the time
    you will only need to select one timestamp here, however in some
    cases you may need to select multiple timestamps.

    This can occur if for example a single fraction was delivered in separate
    beams due to either a beam interrupt, or the fraction being spread
    over multiple energies
    """

    if len(timestamps) == 0:
        if patient_id != "":
            st.write(
                st_exceptions.NoRecordsFound(
                    f"No iCOM delivery record found for patient ID {patient_id}"
                ))
        return {"patient_id": patient_id}

    if len(timestamps) == 1:
        default_timestamp = [timestamps[0]]
    else:
        default_timestamp = []

    timestamps = sorted(timestamps, reverse=True)

    try:
        selected_icom_deliveries = st.multiselect(
            "Select iCOM delivery timestamp(s)",
            timestamps,
            default=default_timestamp,
            key=f"{key_namespace}_icom_deliveries",
        )
    except st.errors.StreamlitAPIException:
        f"Default timestamp = `{default_timestamp}`"
        f"All timestamps = `{timestamps}`"
        raise

    icom_filenames = [
        path.replace(" ", "_").replace("-", "").replace(":", "")
        for path in selected_icom_deliveries
    ]

    icom_paths = []
    for selected in selected_icom_deliveries:
        icom_paths.append(choice_path_map[selected])

    if advanced_mode_local:
        [str(path.resolve()) for path in icom_paths]

    patient_names = set()
    for icom_path in icom_paths:
        patient_name = str(icom_path.parent.name).split("_")[-1]
        try:
            patient_name = utl_patient.convert_patient_name_from_split(
                *patient_name.split(", "))
        except:  # pylint: disable = bare-except
            pass

        patient_names.add(patient_name)

    patient_name = filter_patient_names(patient_names)

    icom_streams = load_icom_streams(icom_paths)
    deliveries = cached_deliveries_loading(icom_streams, delivery_from_icom)

    if selected_icom_deliveries:
        identifier = f"iCOM ({icom_filenames[0]})"
    else:
        identifier = None

    if len(deliveries) == 0:
        st.write(InputRequired("Please select at least one iCOM delivery"))

    results = {
        "site": None,
        "patient_id": patient_id,
        "patient_name": patient_name,
        "selected_icom_deliveries": selected_icom_deliveries,
        "data_paths": icom_paths,
        "identifier": identifier,
        "deliveries": deliveries,
    }

    return results
Esempio n. 4
0
def monaco_input_method(patient_id="",
                        key_namespace="",
                        advanced_mode_local=False,
                        site=None,
                        **_):
    (
        monaco_site,
        monaco_directory,
        patient_id,
        plan_directory,
        patient_directory,
    ) = st_monaco.monaco_patient_directory_picker(patient_id, key_namespace,
                                                  advanced_mode_local, site)

    patient_name = read_monaco_patient_name(str(patient_directory))

    f"Patient Name: `{patient_name}`"

    all_tel_paths = list(plan_directory.glob("**/*tel.1"))
    all_tel_paths = sorted(all_tel_paths, key=os.path.getmtime)

    plan_names_to_choose_from = [
        str(path.relative_to(plan_directory)) for path in all_tel_paths
    ]

    if len(plan_names_to_choose_from) == 0:
        if patient_id != "":
            st.write(
                st_exceptions.NoRecordsFound(
                    f"No Monaco plans found for patient ID {patient_id}"))
        return {"patient_id": patient_id}
    """
    Select the Monaco plan that correspond to a patient's single fraction.
    If a patient has multiple fraction types (such as a plan with a boost)
    then these fraction types need to be analysed separately.
    """

    selected_monaco_plan = st.radio(
        "Select a Monaco plan",
        plan_names_to_choose_from,
        key=f"{key_namespace}_monaco_plans",
    )

    tel_paths = []

    if selected_monaco_plan is not None:
        current_plans = list(
            monaco_directory.glob(
                f"*~{patient_id}/plan/{selected_monaco_plan}"))
        current_plans = [path.resolve() for path in current_plans]
        if len(current_plans) != 1:
            st.write("Plans found:", current_plans)
            raise ValueError("Exactly one plan should have been found")
        tel_paths += current_plans

    if advanced_mode_local:
        [str(path.resolve()) for path in tel_paths]

    deliveries = cached_deliveries_loading(tel_paths, delivery_from_tel)

    if tel_paths:
        plan_names = ", ".join([path.parent.name for path in tel_paths])
        identifier = f"Monaco ({plan_names})"
    else:
        identifier = None

    if len(deliveries) == 1 and len(deliveries[0].mu) == 0:
        st.write(
            NoControlPointsFound(
                "This is likely due to an as of yet unsupported "
                "Monaco file format. At this point in time 3DCRT "
                "is not yet supported for reading directly from "
                "Monaco. DICOM is though, please export the plan "
                "to RT DICOM and import the data that way."))

    results = {
        "site": monaco_site,
        "patient_id": patient_id,
        "patient_name": patient_name,
        "selected_monaco_plan": selected_monaco_plan,
        "data_paths": tel_paths,
        "identifier": identifier,
        "deliveries": deliveries,
    }

    return results