populateImagingFromTransferList.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. #date sorts studies from orthanc dataset into target study dataset
  2. #takes transferQuery as the list of images that should be available on orthanc
  3. import os
  4. import json
  5. import re
  6. import sys
  7. import datetime
  8. import re
  9. def main(parameterFile):
  10. fhome=os.path.expanduser('~')
  11. fsetup=os.path.join(fhome,'.labkey','setup.json')
  12. with open(fsetup,'r') as f:
  13. setup=json.load(f)
  14. sys.path.insert(0,setup['paths']['nixWrapper'])
  15. import nixWrapper
  16. nixWrapper.loadLibrary("labkeyInterface")
  17. import labkeyInterface
  18. import labkeyDatabaseBrowser
  19. import labkeyFileBrowser
  20. fconfig=os.path.join(fhome,'.labkey','network.json')
  21. net=labkeyInterface.labkeyInterface()
  22. net.init(fconfig)
  23. db=labkeyDatabaseBrowser.labkeyDB(net)
  24. fb=labkeyFileBrowser.labkeyFileBrowser(net)
  25. with open(parameterFile,'r') as f:
  26. pars=json.load(f)
  27. i=0
  28. #from orthancDatabase/Imaging dataset
  29. projectOrthanc=pars['Orthanc']['project']
  30. inputQuery=pars['Orthanc']['queryName']
  31. inputSchema=pars['Orthanc']['schemaName']
  32. inputParticipantField=pars['Orthanc']['participantField']
  33. #to target project dataset
  34. projectStudy=pars['Database']['project']
  35. #'iPNUMMretro/Study'
  36. #for prospective, set
  37. #projectStudy='IPNUMMprospektiva/Study'
  38. outputQuery=pars['Database']['queryName']
  39. outputSchema=pars['Database']['schemaName']
  40. #select patientId that are contained in the demographics dataset
  41. transferQuery=pars['Database']['transferQuery']
  42. dbParticipantField=pars['Database']['participantField']
  43. missingSchema=pars['Database']['missingImagesSchema']
  44. missingQuery=pars['Database']['missingImagesQuery']
  45. #delete all rows from missingQuery (should be rebuilt for every run)
  46. dsMissing=db.selectRows(projectStudy,missingSchema,missingQuery,[])
  47. db.modifyRows('delete',projectStudy,missingSchema,missingQuery,dsMissing['rows'])
  48. #make a list of images from transferQuery
  49. dsImage=db.selectRows(projectStudy,outputSchema,transferQuery,[])
  50. for im in dsImage['rows']:
  51. #for orthanc
  52. inputIdFilter={'variable':inputParticipantField,\
  53. 'value':im[dbParticipantField],\
  54. 'oper':'eq'}
  55. #for database
  56. idFilter={'variable':dbParticipantField,\
  57. 'value':im[dbParticipantField],\
  58. 'oper':'eq'}
  59. seqNum=im['imagingVisitId']
  60. seqFilter={'variable':'SequenceNum','value':str(seqNum),'oper':'eq'}
  61. #for speedup one should check if a match was already done in Database/queryName
  62. #ds1 are the matching outputs in target dataset
  63. ds1=db.selectRows(projectStudy,outputSchema,outputQuery,\
  64. [idFilter,seqFilter])
  65. if len(ds1['rows'])>1:
  66. #never happens (idFilter and seqFilter)
  67. print('ERROR: too many matches in {} for {}/{}'.\
  68. format(outputQuery,im[dbParticipantField],seqNum))
  69. continue
  70. if len(ds1['rows'])>0:
  71. #just the one match, fine
  72. print('Entry for {}/{} already resolved'.\
  73. format(im[dbParticipantField],seqNum))
  74. entry=ds1['rows'][0]
  75. try:
  76. if len(entry['PETWB_orthancId'])>0 and len(entry['CT_orthancId'])>0:
  77. continue
  78. except:
  79. pass
  80. print('Debug mode for missing cases')
  81. #have to convert from datetime to %Y%m%d format
  82. #dateFilter={'variable':'imageDate','value':im['imageDate'],'oper':'eq'}
  83. dsOrthanc=db.selectRows(projectOrthanc,inputSchema,inputQuery,[inputIdFilter])
  84. #what if dsOrthanc['rows'] is empty?
  85. #this is part of QA and is reported in missingImages Schema/Query
  86. #convert dates
  87. sDates={r['orthancSeries']:datetime.datetime.strptime(r['studyDate'],'%Y/%m/%d %H:%M:%S')
  88. for r in dsOrthanc['rows']}
  89. sDates={x:sDates[x].strftime('%Y%m%d') for x in sDates}
  90. #unique dates (for date mismatch)
  91. dates=list(set(sDates.values()))
  92. #select dates
  93. sDatesMatch={x:sDates[x] for x in sDates if sDates[x]==im['imageDate']}
  94. #select
  95. rowsMatch=[r for r in dsOrthanc['rows'] if r['orthancSeries'] in list(sDatesMatch.keys())]
  96. #select CT matches
  97. rowsCT=[r for r in rowsMatch if r['seriesDescription'].find('CT WB')==0]
  98. #should not include fov
  99. rowsCT=[r for r in rowsCT if r['seriesDescription'].find('fov')<0]
  100. print('entry[{}/{}] rowsCT : {}'.format(im[dbParticipantField],seqNum,rowsCT))
  101. #should be one and one only
  102. rowsPET=[r for r in rowsMatch if r['seriesDescription']=='PET WB']
  103. print('entry[{}/{}] rowsPET: {}'.format(im[dbParticipantField],seqNum,rowsPET))
  104. #deal with erroneous outcomes (ie- no CT, more then 1 CT, no PET, more than 1 PET)
  105. if len(rowsPET)!=1 or len(rowsCT)!=1:
  106. mode='insert'
  107. #copy values en mass
  108. vals=[dbParticipantField,'imagingVisitId','imageDate']
  109. orow={v:im[v] for v in vals}
  110. orow['imageDateMismatch']=','.join(dates)
  111. #generate description of failure
  112. failDesc=''
  113. if len(rowsPET)==0:
  114. failDesc+='[MISSSING PET]'
  115. if len(rowsPET)>1:
  116. failDesc+='[MULTIPLE PET]'
  117. if len(rowsCT)==0:
  118. failDesc+='[MISSSING CT]'
  119. if len(rowsCT)>1:
  120. failDesc+='[MULTIPLE CT]'
  121. orow['failureDescription']=failDesc
  122. #generate fail entries
  123. db.modifyRows(mode,projectStudy,missingSchema,\
  124. missingQuery,[orow])
  125. #don't break, but fill only for singular outcomes
  126. #figure out which row in output study to update
  127. filters=[]
  128. print('Participant {} Sequence number {}'.\
  129. format(im[dbParticipantField],str(seqNum)))
  130. #refresh the matching study list (after CT we have found PET)
  131. ds1=db.selectRows(projectStudy,outputSchema,outputQuery,\
  132. [idFilter,seqFilter])
  133. mode='update'
  134. outRow={}
  135. if len(ds1['rows'])==0:
  136. mode='insert'
  137. outRow[dbParticipantField]=im[dbParticipantField]
  138. outRow['SequenceNum']=seqNum
  139. else:
  140. #never happens if we check for sd1 before matches are found
  141. outRow=ds1['rows'][0]
  142. if len(rowsPET)==1:
  143. outRow['PETWB_orthancId']=rowsPET[0]['orthancSeries']
  144. outRow['studyDate']=rowsPET[0]['studyDate']
  145. if len(rowsCT)==1:
  146. outRow['CT_orthancId']=rowsCT[0]['orthancSeries']
  147. outRow['studyDate']=rowsCT[0]['studyDate']
  148. outRow['imagingVisitId']=im['imagingVisitId']
  149. outRow['visitCode']='VISIT_'+str(im['imagingVisitId'])
  150. modifyStatus=db.modifyRows(mode,projectStudy,outputSchema,\
  151. outputQuery,[outRow])
  152. print('{}'.format(modifyStatus))
  153. print("Done")
  154. if __name__=='__main__':
  155. main(sys.argv[1])