def main(): # Specify import statements import requests import sys import importlib import shutil import logging import hashlib import UserInterface import time # Retrieve variables from invoking function selector = importlib.import_module( os.path.basename(sys.modules['__main__'].__file__).split('.')[0]) # Specify branch to download branch = 'master' logging.debug('user name {}'.format(os.getenv('username'))) os.chdir(os.path.dirname(__file__)) logging.debug('current directory is {}'.format(os.getcwd())) # Get branch content try: if selector.token != '': r = requests.get( selector.api + '/contents?ref=' + branch, headers={'Authorization': 'token {}'.format(selector.token)}) else: r = requests.get(selector.api + '/contents?ref=' + branch) file_list = r.json() except requests.ConnectionError: logging.exception('Could not access GitHub repository') raise # If local is empty, prompt user to select the location if selector.local == '': browser = UserInterface.CommonDialog() local = browser.folder_browser('Select folder location for scripts:') else: local = selector.local # Clear directory if os.path.exists(local): if os.path.isfile(local): logging.error('This is a file, not directory {}'.format(local)) elif os.path.isdir(local): # Leave the master directory in place, and remove the contents os.chdir('../..') while os.listdir(local): for filename in os.listdir(local): file_path = os.path.join(local, filename) try: if os.path.isfile(file_path) or os.path.islink( file_path): os.unlink(file_path) time.sleep(1) elif os.path.isdir(file_path): shutil.rmtree(file_path, ignore_errors=True) time.sleep(1) except Exception as e: logging.debug('Failed to delete %s. Reason: %s' % (file_path, e)) else: os.mkdir(local) if os.path.exists(local): logging.info('Local directory is: {}'.format(local)) else: logging.warning('Local directory failed to create: {}'.format(local)) sys.exit('Exiting') # Loop through folders in branch, creating folders and pulling content for l in file_list: if l.get('type'): if l['type'] == u'dir': if selector.token != '': r = requests.get(selector.api + '/contents' + l['path'] + '?ref=' + branch, headers={ 'Authorization': 'token {}'.format(selector.token) }) else: r = requests.get(selector.api + '/contents' + l['path'] + '?ref=' + branch) sublist = r.json() for s in sublist: file_list.append(s) if not os.path.exists(os.path.join(local, l['path'])): os.mkdir(os.path.join(local, l['path'])) # Update progress bar text and length bar = UserInterface.ProgressBar('Downloading files', 'Update Progress', len(file_list) * 2) # Loop through files in branch, downloading each for l in file_list: bar.update('Downloading {}'.format(l['path'])) if l['type'] == u'file': if l.get('download_url'): logging.info('Downloading {} to {}'.format( l['download_url'], os.path.join(local, l['path']))) if os.path.exists(os.path.join(local, l['path'])): os.remove(os.path.join(local, l['path'])) if selector.token != '': r = requests.get(l['download_url'], headers={ 'Authorization': 'token {}'.format(selector.token) }) else: r = requests.get(l['download_url']) open(os.path.join(local, l['path']), 'wb').write(r.content) # Loop through files again, verifying passed = True for l in file_list: bar.update('Verifying Hashes') if l['type'] == u'file': if l.get('download_url'): fh = open(os.path.join(local, l['path']), 'rb') content = fh.read() fh.close() sha = hashlib.sha1( bytearray('blob {}\0'.format(len(content)), 'utf8') + content).hexdigest() if l['sha'] == sha: logging.info('Hash {} verified: {}'.format( l['path'], l['sha'])) else: logging.warning('Hash {} incorrect: {} != {}'.format( l['path'], l['sha'], sha)) passed = False # Show success message bar.close() if passed: UserInterface.MessageBox( 'Script download and checksum verification successful', 'Success') else: UserInterface.WarningBox('Scripts download, but verification failed', 'Warning')
def main(): ''' Attempt to load and optimize a patient ''' import sys import csv import os import connect from OptimizationOperations import optimize_plan from collections import namedtuple import UserInterface # Plan optimization parameters OptimizationParameters = { "InitialMaxIt": 50, "InitialIntIt": 10, "SecondMaxIt": 30, "SecondIntIt": 15, "DoseDim1": 0.5, "DoseDim2": 0.4, "DoseDim3": 0.3, "DoseDim4": 0.2, "NIterations": 12 } # Open the csv delimited file containing the list of patients to be reoptimized # Ensure that the first row is a header for the columns Row = namedtuple('Row', ('FirstName', 'LastName', 'PatientID', 'Case', 'PlanName', 'BeamsetName')) browser = UserInterface.CommonDialog() filecsv = browser.open_file('Select a plan list file', 'CSV Files (*.csv)|*.csv') if filecsv != '': with open(filecsv, 'r') as f: r = csv.reader(f, delimiter=',') r.next() # Skip header rows = [Row(*l) for l in r] file_name = r'output.txt' path = r'\\uwhis.hosp.wisc.edu\ufs\UWHealth\RadOnc\ShareAll\RayScripts\dev_logs' output_file = os.path.join(path, file_name) file_object = open(output_file, 'w') output_message = "PatientID" + "\tPlan Name" + "\tBeamSet Name" + "\tStatus\n" file_object.write(output_message) file_object.close() # Header was skipped. Start with rows[0], the first data line in the csv i = 0 db = connect.get_current("PatientDB") # TODO : look for existing, then add a beamset. for r in rows: # for i in range(1,10): last_name = r.LastName first_name = r.FirstName patient_id = r.PatientID plan_name = r.PlanName beamset_name = r.BeamsetName case_name = r.Case # Select patient based on name patient_info = db.QueryPatientInfo( Filter={ 'FirstName': '^{0}$'.format(first_name), 'LastName': '^{0}$'.format(last_name), 'PatientID': '^{0}$'.format(patient_id) }) if len( patient_info ) != 1: # If no (or more than one) patient matches the criteria, exit the script print("No patient named {0} {1} found in the database".format( first_name, last_name)) sys.exit() #try: patient = db.LoadPatient(PatientInfo=patient_info[0]) case = patient.Cases[case_name] case.SetCurrent() plan = case.TreatmentPlans[plan_name] plan.SetCurrent() beamset = plan.BeamSets[beamset_name] beamset.SetCurrent() optimize_plan(patient, case, plan, beamset, **OptimizationParameters) patient.Save() file_object = open("output.txt", 'a') output_message = patient_id + "\t" + plan_name + "\t" + beamset_name + "\tsuccess\n" file_object.write(output_message) file_object.close() #except: # file_object = open("output.txt", 'a') # output_message = patient_id + "\t" + plan_name + "\t" + beamset_name + "\tFAIL\n" # file_object.write(output_message) # file_object.close() i += 1
def main(): # Get current date, time and initialize variables now = datetime.datetime.now() name = '' mrn = '' size = [] res = [] path = '' pad = True status = None patient_db = None machine_db = None # If running from within RayStation, write to temp folder and import try: # Import RayStation packages import connect import UserInterface # Connect to RayStation DB logging.debug('Attempting to connect to RsyStation DB') machine_db = connect.get_current('MachineDB') patient_db = connect.get_current('PatientDB') # If an existing patient is loaded, warn the user before saving try: patient = connect.get_current('Patient') case = connect.get_current('Case') box = UserInterface.WarningeBox( 'An existing patient is loaded, and will be saved and closed') patient.Save() except Exception: logging.info('No patient is loaded') # Start script status window status = UserInterface.ScriptStatus(steps=[ 'Enter Phantom Dimensions', 'Generate Temporary CT Files', 'Import Files into RayStation', 'Set Imaging Equipment', 'Create External Contour', 'Export CT (optional)' ], docstring=__doc__, help=__help__) status.next_step( text= 'For this step, enter the desired phantom details in the displayed input box.' ) # Display input dialog and retrieve phantom size inputs = UserInterface.InputDialog(inputs={ 'a': 'Enter phantom name:', 'b': 'Enter phantom ID:', 'c': 'Enter number of voxels in IEC X,Z,Y:', 'd': 'Enter resolution in IEC X,Z,Y (mm):' }, required=['a', 'b', 'c', 'd'], initial={ 'a': 'Water Phantom', 'b': '{0}{1:0>2}{2:0>2}'.format( now.year, now.month, now.day), 'c': '600, 400, 600', 'd': '1, 1, 1' }) # Wait a second to make sure the script selector is displayed before the input dialog time.sleep(1) logging.debug('Displaying input dialog') response = inputs.show() # Check if dialog was closed if response == {}: logging.warning('Input dialog closed') status.finish(text='The input dialog was closed, script cancelled') else: logging.debug('Parsing inputs and generating temp folder') name = response['a'].strip() mrn = response['b'].strip() size = map(int, response['c'].split(',')) res = map(int, response['d'].split(',')) status.next_step( text= 'Generating temporary CT files based on provided dimensions...' ) path = tempfile.mkdtemp() logging.debug('Temporary folder generated at {}'.format(path)) # Prompt for name, ID, image size and resolution (in mm), IEC [X,Z,Y] except (ImportError, OSError, SystemError): logging.info( 'Likely running outside RayStation, prompting user to enter info via raw_input()' ) name = raw_input('Enter phantom name: ').strip() mrn = raw_input('Enter phantom ID: ').strip() size = map( int, raw_input('Enter number of voxels in IEC X,Z,Y (600, 400, 600): '). split(',')) res = map( int, raw_input('Enter mm resolution in IEC X,Z,Y (1, 1, 1): ').split( ',')) path = raw_input('Enter path to write CT to: ').strip() if not os.path.exists(path): logging.debug( 'Provided path does not exist, creating {}'.format(path)) os.mkdir(path) # Only continue if inputs were provided if name != '' and mrn != '' and len(size) == 3 and len(res) == 3: # Start timer tic = time.time() # Pad X/Z dimensions by a voxel (will be air) if pad: logging.debug('Padding image in X/Z dimensions') size[0] += 2 size[1] += 2 # Create new dict, and add basic image attributes logging.debug('Initializing DICOM header') ds = pydicom.dataset.Dataset() ds.file_meta = pydicom.dataset.Dataset() ds.file_meta.TransferSyntaxUID = '1.2.840.10008.1.2' ds.file_meta.ImplementationClassUID = '1.2.40.0.13.1.1' ds.file_meta.ImplementationVersionName = 'dcm4che-2.0' ds.SpecificCharacterSet = 'ISO_IR 100' ds.file_meta.MediaStorageSOPClassUID = '1.2.840.10008.5.1.4.1.1.2' ds.Modality = 'CT' ds.SOPClassUID = ds.file_meta.MediaStorageSOPClassUID ds.is_little_endian = True ds.is_implicit_VR = True ds.RescaleIntercept = -1024 ds.RescaleSlope = 1 ds.InstanceCreationDate = '{0}{1:0>2}{2:0>2}'.format( now.year, now.month, now.day) ds.InstanceCreationTime = '{0:0>2}{1:0>2}{2:0>2}'.format( now.hour, now.minute, now.second) ds.StudyDate = '{0}{1:0>2}{2:0>2}'.format(now.year, now.month, now.day) ds.StudyTime = '{0:0>2}{1:0>2}{2:0>2}'.format(now.hour, now.minute, now.second) ds.AcquisitionDate = '{0}{1:0>2}{2:0>2}'.format( now.year, now.month, now.day) ds.AcquisitionTime = '{0:0>2}{1:0>2}{2:0>2}'.format( now.hour, now.minute, now.second) ds.ImageType = 'ORIGINAL\PRIMARY\AXIAL' ds.Manufacturer = 'pydicom' ds.ManufacturerModelName = 'CreateReferenceCT' ds.SoftwareVersion = '1.0' ds.SeriesDescription = 'Uniform Phantom' ds.PatientName = name ds.PatientID = mrn ds.SliceThickness = res[2] ds.StudyInstanceUID = pydicom.uid.generate_uid() ds.SeriesInstanceUID = pydicom.uid.generate_uid() ds.FrameOfReferenceUID = pydicom.uid.generate_uid() ds.PatientPosition = 'HFS' ds.ImageOrientationPatient = [1, 0, 0, 0, 1, 0] ds.ImagePositionPatient = [ -((size[0] - 0.5) * res[0]) / 2, -res[1] / 2, ((size[2] - 0.5) * res[2]) / 2 ] ds.ImagesInAcquisition = size[2] ds.SamplesPerPixel = 1 ds.PhotometricInterpretation = 'MONOCHROME2' ds.Rows = size[1] ds.Columns = size[0] ds.PixelSpacing = [res[0], res[1]] ds.BitsAllocated = 16 ds.BitsStored = 16 ds.HighBit = 15 ds.PixelRepresentation = 0 # Create image logging.debug('Initializing rectangular phantom image') if pad: img = numpy.zeros(shape=(size[1], size[0]), dtype=numpy.uint16) for i in range(1, size[1] - 1): for j in range(1, size[0] - 1): img[i, j] = 1024 else: img = numpy.ones(shape=(size[1], size[0]), dtype=numpy.uint16) * 1024 ds.PixelData = img.tostring() # Only display progress bar if isinstance(status, UserInterface.ScriptStatus): bar = UserInterface.ProgressBar(text='Writing CT files', steps=size[2]) else: bar = None # Loop through CT Images for i in range(size[2]): # Generate unique IDs ds.file_meta.MediaStorageSOPInstanceUID = pydicom.uid.generate_uid( ) ds.SOPInstanceUID = ds.file_meta.MediaStorageSOPInstanceUID # Set position info for this image ds.SliceLocation = -((size[2] - 1) * res[2]) / 2 + i * res[2] ds.ImagePositionPatient[2] = -ds.SliceLocation ds.InstanceNumber = i + 1 # Write CT image if isinstance(bar, UserInterface.ProgressBar): bar.update('Writing image ct_{0:0>3}.dcm'.format(i + 1)) if path != '': logging.debug('Writing image {0}/ct_{1:0>3}.dcm'.format( path, i + 1)) ds.save_as( os.path.normpath('{0}/ct_{1:0>3}.dcm'.format(path, i + 1))) if isinstance(bar, UserInterface.ProgressBar): bar.close() # If in RayStation, import DICOM files if isinstance(status, UserInterface.ScriptStatus) and patient_db is not None: status.next_step( text='Importing the temporary CT into RayStation...') logging.debug( 'Executing ImportPatientFromPath against {}'.format(path)) patient_db.ImportPatientFromPath(Path=path, Patient={'Name': name}, SeriesFilter={}, ImportFilters=[]) patient = connect.get_current('Patient') case = connect.get_current('Case') examination = connect.get_current('Examination') logging.info('Import successful, patient name: {}, MRN: {}'.format( patient.Name, patient.PatientID)) # Set imaging equipment if machine_db is not None: try: import clr clr.AddReference('System.Collections') import System.Collections.Generic ct_dict = machine_db.GetCtImagingSystemsNameAndCommissionTime( ) e = ct_dict.GetEnumerator() e.MoveNext() status.next_step( 'Setting imaging equipment to {}...'.format( e.Current.Key)) logging.debug('Setting imaging equipment to {}'.format( e.Current.Key)) examination.EquipmentInfo.SetImagingSystemReference( ImagingSystemName=e.Current.Key) except Exception as error: logging.warning(str(error)) # Create external ROI status.next_step(text='Generating External Contour...') logging.debug('Executing PatientModel.CreateRoi for External') external = case.PatientModel.CreateRoi(Name='External', Color='Blue', Type='External', TissueName='', RbeCellTypeName=None, RoiMaterial=None) logging.debug('Executing CreateExternalGeometry for External') external.CreateExternalGeometry(Examination=examination, ThresholdLevel=None) logging.debug('Saving patient') patient.Save() # Prompt user to export logging.debug('Displaying export question box') status.next_step( text= 'At this step, you can choose to export the phantom CT and structure set. ' + 'Answer Yes or No in the displayed message box.') answer = UserInterface.QuestionBox( 'Do you wish to export the phantom to a folder?') if answer.yes: logging.debug( 'User chose Yes to export CT and structure set, now displaying folder browser' ) common = UserInterface.CommonDialog() export = common.folder_browser('Select a folder to export to:') try: status.update_text('Exporting CT and structure set...') logging.debug( 'Executing ScriptableDicomExport to export to {}'. format(export)) case.ScriptableDicomExport( ExportFolderPath=export, Examinations=[examination.Name], RtStructureSetsForExaminations=[examination.Name], DicomFilter='', IgnorePreConditionWarnings=True) except Exception as error: logging.warning(str(error)) # Finish up logging.debug( 'Cleanup started, deleting temporary folder {}'.format(path)) shutil.rmtree(path, ignore_errors=True) status.finish( text= 'Script execution successful. Note, the phantom material was not set to water.' + ' If you plan on running other QA scripts, you may want to do so.' ) logging.debug( 'CreateReferenceCT finished successfully in {:.3f} seconds'.format( time.time() - tic)) else: logging.warning('Patient name, MRN, size, or resolution invalid')
else: calc = False export = False # Append steps for m in machines: machine = machine_db.GetTreatmentMachine(machineName=m, lockMode=None) for q in machine.PhotonBeamQualities: status.add_step('Create {} {} MV plans'.format(m, q.NominalEnergy)) status.add_step('Create {} Electrons plan'.format(m)) # Define the export location if 'Calculate dose' in response['g'] and 'Export dose' in response['g']: common = UserInterface.CommonDialog() path = common.folder_browser( 'Select the path to export RT Dose files to (or cancel to skip export):' ) if path == '': logging.warning('Folder not selected, export will be skipped') export = False else: logging.info('Export path selected: {}'.format(path)) export = True # Start timer tic = time.time()