123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- #date sorts studies from orthanc dataset into target study dataset
- #takes transferQuery as the list of images that should be available on orthanc
- import os
- import json
- import re
- import sys
- import datetime
- import re
- def main(parameterFile):
- fhome=os.path.expanduser('~')
- fsetup=os.path.join(fhome,'.labkey','setup.json')
- with open(fsetup,'r') as f:
- setup=json.load(f)
- sys.path.insert(0,setup['paths']['nixWrapper'])
- import nixWrapper
- nixWrapper.loadLibrary("labkeyInterface")
- import labkeyInterface
- import labkeyDatabaseBrowser
- import labkeyFileBrowser
- fconfig=os.path.join(fhome,'.labkey','network.json')
- net=labkeyInterface.labkeyInterface()
- net.init(fconfig)
- db=labkeyDatabaseBrowser.labkeyDB(net)
- fb=labkeyFileBrowser.labkeyFileBrowser(net)
- with open(parameterFile,'r') as f:
- pars=json.load(f)
- i=0
- #from orthancDatabase/Imaging dataset
- projectOrthanc=pars['Orthanc']['project']
- inputQuery=pars['Orthanc']['queryName']
- inputSchema=pars['Orthanc']['schemaName']
- inputParticipantField=pars['Orthanc']['participantField']
- #to target project dataset
- projectStudy=pars['Database']['project']
- #'iPNUMMretro/Study'
- #for prospective, set
- #projectStudy='IPNUMMprospektiva/Study'
- outputQuery=pars['Database']['queryName']
- outputSchema=pars['Database']['schemaName']
- #select patientId that are contained in the demographics dataset
- transferQuery=pars['Database']['transferQuery']
- dbParticipantField=pars['Database']['participantField']
- missingSchema=pars['Database']['missingImagesSchema']
- missingQuery=pars['Database']['missingImagesQuery']
- #delete all rows from missingQuery (should be rebuilt for every run)
- dsMissing=db.selectRows(projectStudy,missingSchema,missingQuery,[])
- db.modifyRows('delete',projectStudy,missingSchema,missingQuery,dsMissing['rows'])
- #make a list of images from transferQuery
- dsImage=db.selectRows(projectStudy,outputSchema,transferQuery,[])
- for im in dsImage['rows']:
- #for orthanc
- inputIdFilter={'variable':inputParticipantField,\
- 'value':im[dbParticipantField],\
- 'oper':'eq'}
- #for database
- idFilter={'variable':dbParticipantField,\
- 'value':im[dbParticipantField],\
- 'oper':'eq'}
- seqNum=im['imagingVisitId']
- seqFilter={'variable':'SequenceNum','value':str(seqNum),'oper':'eq'}
-
- #for speedup one should check if a match was already done in Database/queryName
- #ds1 are the matching outputs in target dataset
- ds1=db.selectRows(projectStudy,outputSchema,outputQuery,\
- [idFilter,seqFilter])
- if len(ds1['rows'])>1:
- #never happens (idFilter and seqFilter)
- print('ERROR: too many matches in {} for {}/{}'.\
- format(outputQuery,im[dbParticipantField],seqNum))
- continue
- if len(ds1['rows'])>0:
- #just the one match, fine
- print('Entry for {}/{} already resolved'.\
- format(im[dbParticipantField],seqNum))
-
- entry=ds1['rows'][0]
- try:
- if len(entry['PETWB_orthancId'])>0 and len(entry['CT_orthancId'])>0:
- continue
- except:
- pass
- print('Debug mode for missing cases')
- #have to convert from datetime to %Y%m%d format
- #dateFilter={'variable':'imageDate','value':im['imageDate'],'oper':'eq'}
- dsOrthanc=db.selectRows(projectOrthanc,inputSchema,inputQuery,[inputIdFilter])
- #what if dsOrthanc['rows'] is empty?
- #this is part of QA and is reported in missingImages Schema/Query
-
- #convert dates
- sDates={r['orthancSeries']:datetime.datetime.strptime(r['studyDate'],'%Y/%m/%d %H:%M:%S')
- for r in dsOrthanc['rows']}
- sDates={x:sDates[x].strftime('%Y%m%d') for x in sDates}
- #unique dates (for date mismatch)
- dates=list(set(sDates.values()))
-
- #select dates
- sDatesMatch={x:sDates[x] for x in sDates if sDates[x]==im['imageDate']}
-
- #select
- rowsMatch=[r for r in dsOrthanc['rows'] if r['orthancSeries'] in list(sDatesMatch.keys())]
- #select CT matches
- rowsCT=[r for r in rowsMatch if r['seriesDescription'].find('CT WB')==0]
- #should not include fov
- rowsCT=[r for r in rowsCT if r['seriesDescription'].find('fov')<0]
- print('entry[{}/{}] rowsCT : {}'.format(im[dbParticipantField],seqNum,rowsCT))
-
- #should be one and one only
- rowsPET=[r for r in rowsMatch if r['seriesDescription']=='PET WB']
- print('entry[{}/{}] rowsPET: {}'.format(im[dbParticipantField],seqNum,rowsPET))
-
- #deal with erroneous outcomes (ie- no CT, more then 1 CT, no PET, more than 1 PET)
- if len(rowsPET)!=1 or len(rowsCT)!=1:
- mode='insert'
- #copy values en mass
- vals=[dbParticipantField,'imagingVisitId','imageDate']
- orow={v:im[v] for v in vals}
- orow['imageDateMismatch']=','.join(dates)
-
- #generate description of failure
- failDesc=''
- if len(rowsPET)==0:
- failDesc+='[MISSSING PET]'
- if len(rowsPET)>1:
- failDesc+='[MULTIPLE PET]'
- if len(rowsCT)==0:
- failDesc+='[MISSSING CT]'
- if len(rowsCT)>1:
- failDesc+='[MULTIPLE CT]'
- orow['failureDescription']=failDesc
- #generate fail entries
- db.modifyRows(mode,projectStudy,missingSchema,\
- missingQuery,[orow])
- #don't break, but fill only for singular outcomes
-
- #figure out which row in output study to update
- filters=[]
- print('Participant {} Sequence number {}'.\
- format(im[dbParticipantField],str(seqNum)))
- #refresh the matching study list (after CT we have found PET)
- ds1=db.selectRows(projectStudy,outputSchema,outputQuery,\
- [idFilter,seqFilter])
- mode='update'
- outRow={}
- if len(ds1['rows'])==0:
- mode='insert'
-
- outRow[dbParticipantField]=im[dbParticipantField]
- outRow['SequenceNum']=seqNum
-
- else:
- #never happens if we check for sd1 before matches are found
- outRow=ds1['rows'][0]
-
- if len(rowsPET)==1:
- outRow['PETWB_orthancId']=rowsPET[0]['orthancSeries']
- outRow['studyDate']=rowsPET[0]['studyDate']
- if len(rowsCT)==1:
- outRow['CT_orthancId']=rowsCT[0]['orthancSeries']
- outRow['studyDate']=rowsCT[0]['studyDate']
- outRow['imagingVisitId']=im['imagingVisitId']
- outRow['visitCode']='VISIT_'+str(im['imagingVisitId'])
- modifyStatus=db.modifyRows(mode,projectStudy,outputSchema,\
- outputQuery,[outRow])
- print('{}'.format(modifyStatus))
-
- print("Done")
- if __name__=='__main__':
- main(sys.argv[1])
|