OpenREM 1.0.0b2__py3-none-any.whl → 1.0.0b3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. openrem/locale/de/LC_MESSAGES/django.po +1060 -1059
  2. openrem/locale/django.pot +973 -972
  3. openrem/locale/es_MX/LC_MESSAGES/django.po +1049 -1048
  4. openrem/locale/it/LC_MESSAGES/django.po +1044 -1043
  5. openrem/locale/lt/LC_MESSAGES/django.po +989 -988
  6. openrem/locale/nb_NO/LC_MESSAGES/django.po +985 -984
  7. openrem/locale/pt_BR/LC_MESSAGES/django.po +1003 -1002
  8. openrem/manage.py +10 -10
  9. openrem/openremproject/__init__.py +1 -1
  10. openrem/openremproject/local_settings.py.linux +128 -128
  11. openrem/openremproject/local_settings.py.windows +144 -144
  12. openrem/openremproject/local_settings.py.windows-sqlite3 +129 -129
  13. openrem/openremproject/settings.py +278 -278
  14. openrem/openremproject/urls.py +32 -32
  15. openrem/openremproject/wsgi.py.example +28 -28
  16. openrem/remapp/__init__.py +2 -2
  17. openrem/remapp/admin.py +31 -31
  18. openrem/remapp/exports/ct_export.py +780 -753
  19. openrem/remapp/exports/dx_export.py +817 -805
  20. openrem/remapp/exports/export_common.py +931 -951
  21. openrem/remapp/exports/export_common_pandas.py +2422 -0
  22. openrem/remapp/exports/exportviews.py +815 -860
  23. openrem/remapp/exports/mg_csv_nhsbsp.py +292 -292
  24. openrem/remapp/exports/mg_export.py +673 -510
  25. openrem/remapp/exports/nm_export.py +796 -575
  26. openrem/remapp/exports/rf_export.py +1418 -1431
  27. openrem/remapp/extractors/ct_philips.py +424 -414
  28. openrem/remapp/extractors/ct_toshiba.py +2116 -2108
  29. openrem/remapp/extractors/dx.py +1033 -952
  30. openrem/remapp/extractors/extract_common.py +817 -817
  31. openrem/remapp/extractors/import_views.py +426 -426
  32. openrem/remapp/extractors/mam.py +685 -672
  33. openrem/remapp/extractors/nm_image.py +439 -431
  34. openrem/remapp/extractors/ptsizecsv2db.py +368 -368
  35. openrem/remapp/extractors/rdsr.py +667 -654
  36. openrem/remapp/extractors/rdsr_methods.py +1771 -1768
  37. openrem/remapp/extractors/rrdsr_methods.py +630 -622
  38. openrem/remapp/fixtures/openskin_safelist.json +11 -11
  39. openrem/remapp/forms.py +2286 -2277
  40. openrem/remapp/interface/chart_functions.py +2412 -2393
  41. openrem/remapp/interface/mod_filters.py +1241 -1243
  42. openrem/remapp/migrations/0001_initial.py.1-0-upgrade +1043 -1043
  43. openrem/remapp/models.py +3418 -3407
  44. openrem/remapp/netdicom/dicomviews.py +681 -683
  45. openrem/remapp/netdicom/qrscu.py +2646 -2646
  46. openrem/remapp/netdicom/tools.py +134 -134
  47. openrem/remapp/static/css/bootstrap-theme.css +587 -587
  48. openrem/remapp/static/css/bootstrap-theme.min.css +4 -4
  49. openrem/remapp/static/css/bootstrap.css +6800 -6800
  50. openrem/remapp/static/css/bootstrap.min.css +4 -4
  51. openrem/remapp/static/css/datepicker3.css +790 -790
  52. openrem/remapp/static/css/jquery.qtip.min.css +2 -2
  53. openrem/remapp/static/css/openrem-extra.css +442 -442
  54. openrem/remapp/static/css/openrem.css +96 -96
  55. openrem/remapp/static/css/registration.css +34 -34
  56. openrem/remapp/static/fonts/glyphicons-halflings-regular.svg +287 -287
  57. openrem/remapp/static/js/bootstrap-datepicker.js +1671 -1671
  58. openrem/remapp/static/js/bootstrap.js +2363 -2363
  59. openrem/remapp/static/js/bootstrap.min.js +6 -6
  60. openrem/remapp/static/js/charts/chartCommonFunctions.js +75 -75
  61. openrem/remapp/static/js/charts/chartFullScreen.js +41 -41
  62. openrem/remapp/static/js/charts/ctChartAjax.js +331 -331
  63. openrem/remapp/static/js/charts/dxChartAjax.js +290 -290
  64. openrem/remapp/static/js/charts/mgChartAjax.js +144 -144
  65. openrem/remapp/static/js/charts/nmChartAjax.js +64 -64
  66. openrem/remapp/static/js/charts/plotly-2.35.2.min.js +8 -0
  67. openrem/remapp/static/js/charts/rfChartAjax.js +128 -128
  68. openrem/remapp/static/js/chroma.min.js +32 -32
  69. openrem/remapp/static/js/datepicker.js +5 -5
  70. openrem/remapp/static/js/dicom.js +115 -115
  71. openrem/remapp/static/js/django_reverse/reverse.js +13 -13
  72. openrem/remapp/static/js/formatDate.js +7 -7
  73. openrem/remapp/static/js/html5shiv.min.js +8 -8
  74. openrem/remapp/static/js/jquery-1.11.0.min.js +4 -4
  75. openrem/remapp/static/js/npm.js +12 -12
  76. openrem/remapp/static/js/respond.min.js +4 -4
  77. openrem/remapp/static/js/skin-dose-maps/jquery.qtip.min.js +4 -4
  78. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dHUDObject.js +112 -112
  79. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dObject.js +367 -367
  80. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dPersonObject.js +158 -158
  81. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapColourScaleObject.js +153 -153
  82. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapObject.js +367 -367
  83. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapping.js +584 -584
  84. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapping3d.js +255 -255
  85. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMappingAjax.js +267 -212
  86. openrem/remapp/static/js/skin-dose-maps/three.min.js +835 -835
  87. openrem/remapp/static/js/sorttable.js +495 -495
  88. openrem/remapp/templates/base.html +253 -253
  89. openrem/remapp/templates/registration/changepassword.html +25 -25
  90. openrem/remapp/templates/registration/changepassworddone.html +12 -12
  91. openrem/remapp/templates/registration/login.html +42 -42
  92. openrem/remapp/templates/remapp/backgroundtaskmaximumrows_form.html +29 -29
  93. openrem/remapp/templates/remapp/base.html +1 -1
  94. openrem/remapp/templates/remapp/ctdetail.html +235 -235
  95. openrem/remapp/templates/remapp/ctfiltered.html +310 -310
  96. openrem/remapp/templates/remapp/dicomdeletesettings_form.html +31 -31
  97. openrem/remapp/templates/remapp/dicomqr.html +147 -147
  98. openrem/remapp/templates/remapp/dicomquerydetails.html +83 -83
  99. openrem/remapp/templates/remapp/dicomqueryimages.html +49 -49
  100. openrem/remapp/templates/remapp/dicomqueryseries.html +109 -109
  101. openrem/remapp/templates/remapp/dicomquerysummary.html +48 -48
  102. openrem/remapp/templates/remapp/dicomremoteqr_confirm_delete.html +60 -60
  103. openrem/remapp/templates/remapp/dicomremoteqr_form.html +32 -32
  104. openrem/remapp/templates/remapp/dicomstorescp_confirm_delete.html +53 -53
  105. openrem/remapp/templates/remapp/dicomstorescp_form.html +48 -48
  106. openrem/remapp/templates/remapp/dicomsummary.html +257 -257
  107. openrem/remapp/templates/remapp/displaychartoptions.html +184 -184
  108. openrem/remapp/templates/remapp/displayhomepageoptions.html +57 -57
  109. openrem/remapp/templates/remapp/displayname-count.html +6 -6
  110. openrem/remapp/templates/remapp/displayname-last-date.html +3 -3
  111. openrem/remapp/templates/remapp/displayname-modality.html +86 -105
  112. openrem/remapp/templates/remapp/displayname-skinmap.html +18 -18
  113. openrem/remapp/templates/remapp/displaynameupdate.html +100 -100
  114. openrem/remapp/templates/remapp/displaynameview.html +222 -219
  115. openrem/remapp/templates/remapp/dxdetail.html +176 -176
  116. openrem/remapp/templates/remapp/dxfiltered.html +324 -324
  117. openrem/remapp/templates/remapp/exports-active.html +25 -25
  118. openrem/remapp/templates/remapp/exports-complete.html +35 -35
  119. openrem/remapp/templates/remapp/exports-error.html +26 -26
  120. openrem/remapp/templates/remapp/exports-queue.html +18 -18
  121. openrem/remapp/templates/remapp/exports.html +191 -191
  122. openrem/remapp/templates/remapp/failed_summary_list.html +27 -27
  123. openrem/remapp/templates/remapp/filteredbase.html +162 -162
  124. openrem/remapp/templates/remapp/highdosemetricalertsettings_form.html +76 -76
  125. openrem/remapp/templates/remapp/home-list-modalities.html +94 -94
  126. openrem/remapp/templates/remapp/home.html +202 -202
  127. openrem/remapp/templates/remapp/list_filters.html +24 -24
  128. openrem/remapp/templates/remapp/mgdetail.html +160 -138
  129. openrem/remapp/templates/remapp/mgfiltered.html +311 -311
  130. openrem/remapp/templates/remapp/nmdetail.html +300 -300
  131. openrem/remapp/templates/remapp/nmfiltered.html +255 -255
  132. openrem/remapp/templates/remapp/notpatient.html +190 -190
  133. openrem/remapp/templates/remapp/notpatientindicators_form_base.html +81 -81
  134. openrem/remapp/templates/remapp/notpatientindicatorsid_confirm_delete.html +54 -54
  135. openrem/remapp/templates/remapp/notpatientindicatorsid_form.html +23 -23
  136. openrem/remapp/templates/remapp/notpatientindicatorsname_confirm_delete.html +54 -54
  137. openrem/remapp/templates/remapp/notpatientindicatorsname_form.html +23 -23
  138. openrem/remapp/templates/remapp/notpatientindicatorsname_form_base.html +85 -85
  139. openrem/remapp/templates/remapp/openskinsafelist_add.html +130 -130
  140. openrem/remapp/templates/remapp/openskinsafelist_confirm_delete.html +100 -100
  141. openrem/remapp/templates/remapp/openskinsafelist_form.html +207 -207
  142. openrem/remapp/templates/remapp/patientidsettings_form.html +83 -83
  143. openrem/remapp/templates/remapp/populate_summary_progress.html +83 -83
  144. openrem/remapp/templates/remapp/populate_summary_progress_error.html +36 -36
  145. openrem/remapp/templates/remapp/review_failed_imports.html +157 -157
  146. openrem/remapp/templates/remapp/review_failed_study.html +41 -41
  147. openrem/remapp/templates/remapp/review_studies_delete_button.html +20 -20
  148. openrem/remapp/templates/remapp/review_study.html +19 -19
  149. openrem/remapp/templates/remapp/review_summary_list.html +245 -245
  150. openrem/remapp/templates/remapp/rf_dose_alert_email_template.html +14 -1
  151. openrem/remapp/templates/remapp/rfalertnotificationsview.html +59 -59
  152. openrem/remapp/templates/remapp/rfdetail.html +547 -543
  153. openrem/remapp/templates/remapp/rfdetailbase.html +18 -18
  154. openrem/remapp/templates/remapp/rffiltered.html +404 -404
  155. openrem/remapp/templates/remapp/sizeimports.html +119 -119
  156. openrem/remapp/templates/remapp/sizeprocess.html +96 -96
  157. openrem/remapp/templates/remapp/sizeupload.html +110 -110
  158. openrem/remapp/templates/remapp/skindosemapcalcsettings_form.html +28 -28
  159. openrem/remapp/templates/remapp/standardname-modality.html +69 -69
  160. openrem/remapp/templates/remapp/standardnames_confirm_delete.html +71 -71
  161. openrem/remapp/templates/remapp/standardnames_form.html +87 -87
  162. openrem/remapp/templates/remapp/standardnamesettings_form.html +41 -41
  163. openrem/remapp/templates/remapp/standardnamesrefreshall.html +92 -92
  164. openrem/remapp/templates/remapp/standardnameview.html +103 -103
  165. openrem/remapp/templates/remapp/study_confirm_delete.html +147 -147
  166. openrem/remapp/templates/remapp/task_admin.html +265 -265
  167. openrem/remapp/templates/remapp/tasks.html +76 -76
  168. openrem/remapp/templatetags/formfilters.py +13 -13
  169. openrem/remapp/templatetags/proper_paginate.py +38 -38
  170. openrem/remapp/templatetags/remappduration.py +36 -36
  171. openrem/remapp/templatetags/sigdig.py +38 -38
  172. openrem/remapp/templatetags/sort_class_property_value.py +15 -15
  173. openrem/remapp/templatetags/update_variable.py +20 -20
  174. openrem/remapp/templatetags/url_replace.py +25 -25
  175. openrem/remapp/tests/test_charts_common.py +202 -202
  176. openrem/remapp/tests/test_charts_ct.py +7111 -7111
  177. openrem/remapp/tests/test_charts_dx.py +3513 -3513
  178. openrem/remapp/tests/test_charts_mg.py +1116 -1115
  179. openrem/remapp/tests/test_dcmdatetime.py +189 -189
  180. openrem/remapp/tests/test_dicom_qr.py +2580 -2580
  181. openrem/remapp/tests/test_display_name.py +274 -274
  182. openrem/remapp/tests/test_export_ct_xlsx.py +272 -248
  183. openrem/remapp/tests/test_export_dx_xlsx.py +137 -134
  184. openrem/remapp/tests/test_export_mammo_csv.py +242 -242
  185. openrem/remapp/tests/test_export_rf_xlsx.py +246 -246
  186. openrem/remapp/tests/test_files/DX-Im-DRGEM.dcm +0 -0
  187. openrem/remapp/tests/test_files/MG-RDSR-GEPristina-2D.dcm +0 -0
  188. openrem/remapp/tests/test_files/MG-RDSR-GEPristina-DBT.dcm +0 -0
  189. openrem/remapp/tests/test_files/MG-RDSR-Giotto-DBT.dcm +0 -0
  190. openrem/remapp/tests/test_files/skin_map_alphenix.py +590 -590
  191. openrem/remapp/tests/test_files/skin_map_zee.py +354 -354
  192. openrem/remapp/tests/test_filters_ct.py +321 -321
  193. openrem/remapp/tests/test_filters_dx.py +92 -92
  194. openrem/remapp/tests/test_filters_mammo.py +183 -183
  195. openrem/remapp/tests/test_filters_rf.py +118 -118
  196. openrem/remapp/tests/test_get_values.py +72 -72
  197. openrem/remapp/tests/test_hash_id.py +65 -65
  198. openrem/remapp/tests/test_import_ct_esr_ge.py +3034 -3034
  199. openrem/remapp/tests/test_import_ct_philips_rdsr.py +42 -42
  200. openrem/remapp/tests/test_import_ct_rdsr_multiple.py +256 -256
  201. openrem/remapp/tests/test_import_ct_rdsr_siemens.py +827 -827
  202. openrem/remapp/tests/test_import_ct_rdsr_spectrumdynamics.py +91 -91
  203. openrem/remapp/tests/test_import_ct_rdsr_toshiba_dosecheck.py +67 -67
  204. openrem/remapp/tests/test_import_ct_rdsr_toshiba_multivaluesd.py +33 -33
  205. openrem/remapp/tests/test_import_ct_rdsr_toshiba_pixelmed.py +118 -118
  206. openrem/remapp/tests/test_import_ct_sc_philips.py +44 -44
  207. openrem/remapp/tests/test_import_dual_rdsr.py +110 -110
  208. openrem/remapp/tests/test_import_dx.py +1267 -1191
  209. openrem/remapp/tests/test_import_dx_rdsr.py +1250 -1253
  210. openrem/remapp/tests/test_import_mam.py +438 -438
  211. openrem/remapp/tests/test_import_mg_im_hol_proj.py +46 -46
  212. openrem/remapp/tests/test_import_mg_rdsr.py +586 -586
  213. openrem/remapp/tests/test_import_nm_image.py +420 -420
  214. openrem/remapp/tests/test_import_nm_siemens_rdsr.py +396 -396
  215. openrem/remapp/tests/test_import_px.py +161 -161
  216. openrem/remapp/tests/test_import_rf_rdsr.py +420 -418
  217. openrem/remapp/tests/test_missing_date.py +42 -42
  218. openrem/remapp/tests/test_not_patient.py +60 -60
  219. openrem/remapp/tests/test_openskin.py +272 -272
  220. openrem/remapp/tests/test_patient_id_settings.py +72 -72
  221. openrem/remapp/tests/test_pt_size_import.py +232 -232
  222. openrem/remapp/tests/test_rf_detail.py +113 -113
  223. openrem/remapp/tests/test_rf_high_dose_alert.py +361 -361
  224. openrem/remapp/tools/background.py +361 -361
  225. openrem/remapp/tools/check_standard_name_status.py +47 -0
  226. openrem/remapp/tools/check_uid.py +70 -70
  227. openrem/remapp/tools/dcmdatetime.py +248 -248
  228. openrem/remapp/tools/default_import.py +44 -47
  229. openrem/remapp/tools/get_values.py +230 -230
  230. openrem/remapp/tools/hash_id.py +58 -58
  231. openrem/remapp/tools/make_skin_map.py +448 -406
  232. openrem/remapp/tools/not_patient_indicators.py +72 -72
  233. openrem/remapp/tools/openskin/calc_exp_map.py +173 -173
  234. openrem/remapp/tools/openskin/geomclass.py +475 -475
  235. openrem/remapp/tools/openskin/geomfunc.py +433 -432
  236. openrem/remapp/tools/openskin/skinmap.py +417 -417
  237. openrem/remapp/tools/populate_summary.py +185 -193
  238. openrem/remapp/tools/save_skin_map_structure.py +73 -73
  239. openrem/remapp/tools/send_high_dose_alert_emails.py +238 -207
  240. openrem/remapp/urls.py +456 -448
  241. openrem/remapp/version.py +11 -11
  242. openrem/remapp/views.py +1147 -1052
  243. openrem/remapp/views_admin.py +3876 -3936
  244. openrem/remapp/views_charts_ct.py +2110 -2058
  245. openrem/remapp/views_charts_dx.py +1906 -1836
  246. openrem/remapp/views_charts_mg.py +1349 -1196
  247. openrem/remapp/views_charts_nm.py +535 -535
  248. openrem/remapp/views_charts_rf.py +1219 -1241
  249. openrem/remapp/views_openskin.py +379 -384
  250. openrem/sample-config/openrem-consumer.service +12 -12
  251. openrem/sample-config/openrem-gunicorn.service +13 -13
  252. openrem/sample-config/openrem-server +14 -13
  253. openrem/sample-config/openrem_orthanc_config_linux.lua +454 -454
  254. openrem/sample-config/openrem_orthanc_config_windows.lua +455 -455
  255. openrem/sample-config/queue-init.bat +73 -73
  256. openrem/scripts/openrem_ctphilips.py +25 -25
  257. openrem/scripts/openrem_cttoshiba.py +28 -28
  258. openrem/scripts/openrem_dx.py +22 -22
  259. openrem/scripts/openrem_mg.py +22 -22
  260. openrem/scripts/openrem_nm.py +22 -22
  261. openrem/scripts/openrem_ptsizecsv.py +17 -17
  262. openrem/scripts/openrem_qr.py +12 -12
  263. openrem/scripts/openrem_rdsr.py +25 -25
  264. {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/METADATA +39 -29
  265. openrem-1.0.0b3.dist-info/RECORD +379 -0
  266. {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/WHEEL +1 -1
  267. {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info/licenses}/COPYING-GPLv3 +674 -674
  268. {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info/licenses}/LICENSE +22 -22
  269. OpenREM-1.0.0b2.dist-info/RECORD +0 -373
  270. openrem/remapp/static/js/charts/plotly-2.17.1.min.js +0 -8
  271. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_ctphilips.py +0 -0
  272. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_cttoshiba.py +0 -0
  273. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_dx.py +0 -0
  274. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_mg.py +0 -0
  275. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_nm.py +0 -0
  276. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_ptsizecsv.py +0 -0
  277. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_qr.py +0 -0
  278. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_rdsr.py +0 -0
  279. {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/top_level.txt +0 -0
@@ -1,1191 +1,1267 @@
1
- # This Python file uses the following encoding: utf-8
2
- # test_get_values.py
3
-
4
- import os
5
- from collections import Counter
6
- import datetime
7
- from django.contrib.auth.models import User, Group
8
- from django.test import TestCase
9
- from pydicom.dataset import Dataset
10
- from pydicom.dataelem import DataElement
11
- from pydicom.multival import MultiValue
12
- import logging
13
- from testfixtures import LogCapture
14
-
15
- from remapp.extractors import dx
16
- from remapp.models import (
17
- GeneralStudyModuleAttr,
18
- ProjectionXRayRadiationDose,
19
- IrradEventXRayData,
20
- IrradEventXRaySourceData,
21
- PatientIDSettings,
22
- XrayFilters,
23
- )
24
- from openremproject import settings
25
-
26
- settings.LOGGING["loggers"]["remapp"]["level"] = "DEBUG"
27
-
28
-
29
- class DXFilterTests(TestCase):
30
- def test_multiple_filter_kodak_drxevolution(self):
31
- """
32
- Test the material extraction process when the materials are in a MultiValue format
33
- """
34
- ds = Dataset()
35
- multi = MultiValue(str, ["ALUMINUM", "COPPER"])
36
- data_el = DataElement(0x187050, "CS", multi, already_converted=True)
37
- ds[0x187050] = data_el
38
- ds.FilterThicknessMinimum = "1.0\\0.1"
39
- ds.FilterThicknessMaximum = "1.0\\0.1"
40
- ds.FilterType = "WEDGE"
41
-
42
- g = GeneralStudyModuleAttr.objects.create()
43
- g.save()
44
- proj = ProjectionXRayRadiationDose.objects.create(
45
- general_study_module_attributes=g
46
- )
47
- proj.save()
48
- event = IrradEventXRayData.objects.create(projection_xray_radiation_dose=proj)
49
- event.save()
50
- source = IrradEventXRaySourceData.objects.create(
51
- irradiation_event_xray_data=event
52
- )
53
- source.save()
54
-
55
- dx._xray_filters_prep(ds, source)
56
-
57
- self.assertEqual(
58
- source.xrayfilters_set.order_by("id").count(),
59
- 2,
60
- "Wrong number of filters recorded",
61
- )
62
- self.assertEqual(
63
- source.xrayfilters_set.order_by("id")[0].xray_filter_material.code_meaning,
64
- "Aluminum or Aluminum compound",
65
- )
66
- self.assertEqual(
67
- source.xrayfilters_set.order_by("id")[1].xray_filter_material.code_meaning,
68
- "Copper or Copper compound",
69
- )
70
-
71
- def test_single_filter(self):
72
- """
73
- Test the material extraction process when there is just one filter
74
- """
75
- ds = Dataset()
76
- ds.FilterType = "FLAT"
77
- ds.FilterMaterial = "LEAD"
78
- ds.FilterThicknessMinimum = "1.0"
79
- ds.FilterThicknessMaximum = "1.0"
80
-
81
- g = GeneralStudyModuleAttr.objects.create()
82
- g.save()
83
- proj = ProjectionXRayRadiationDose.objects.create(
84
- general_study_module_attributes=g
85
- )
86
- proj.save()
87
- event = IrradEventXRayData.objects.create(projection_xray_radiation_dose=proj)
88
- event.save()
89
- source = IrradEventXRaySourceData.objects.create(
90
- irradiation_event_xray_data=event
91
- )
92
- source.save()
93
-
94
- dx._xray_filters_prep(ds, source)
95
-
96
- self.assertEqual(source.xrayfilters_set.order_by("id").count(), 1)
97
- self.assertEqual(
98
- source.xrayfilters_set.order_by("id")[0].xray_filter_material.code_meaning,
99
- "Lead or Lead compound",
100
- )
101
-
102
-
103
- class ImportCarestreamDR7500(TestCase):
104
- def setUp(self):
105
-
106
- self.user = User.objects.create_user(
107
- username="jacob", email="jacob@…", password="top_secret"
108
- )
109
- eg = Group(name="exportgroup")
110
- eg.save()
111
- eg.user_set.add(self.user)
112
- eg.save()
113
-
114
- pid = PatientIDSettings.objects.create()
115
- pid.name_stored = True
116
- pid.name_hashed = False
117
- pid.id_stored = True
118
- pid.id_hashed = False
119
- pid.dob_stored = True
120
- pid.save()
121
-
122
- dx_ge_xr220_1 = os.path.join("test_files", "DX-Im-GE_XR220-1.dcm")
123
- dx_ge_xr220_2 = os.path.join("test_files", "DX-Im-GE_XR220-2.dcm")
124
- dx_ge_xr220_3 = os.path.join("test_files", "DX-Im-GE_XR220-3.dcm")
125
- dx_carestream_dr7500_1 = os.path.join(
126
- "test_files", "DX-Im-Carestream_DR7500-1.dcm"
127
- )
128
- dx_carestream_dr7500_2 = os.path.join(
129
- "test_files", "DX-Im-Carestream_DR7500-2.dcm"
130
- )
131
- root_tests = os.path.dirname(os.path.abspath(__file__))
132
-
133
- with LogCapture("remapp.extractors", level=logging.DEBUG) as self.log:
134
- dx.dx(os.path.join(root_tests, dx_ge_xr220_1))
135
- dx.dx(os.path.join(root_tests, dx_ge_xr220_2))
136
- dx.dx(os.path.join(root_tests, dx_ge_xr220_3))
137
- dx.dx(os.path.join(root_tests, dx_carestream_dr7500_1))
138
- dx.dx(os.path.join(root_tests, dx_carestream_dr7500_2))
139
- dx.dx(os.path.join(root_tests, dx_ge_xr220_2))
140
-
141
- def test_dr7500_and_xr220(self):
142
- studies = GeneralStudyModuleAttr.objects.order_by("id")
143
-
144
- # Test that two studies have been imported
145
- self.assertEqual(studies.count(), 2)
146
-
147
- # Test that the second attempt to import dx_ge_xr220_2 results in debug message
148
- self.log.check_present(
149
- (
150
- "remapp.extractors.dx",
151
- "DEBUG",
152
- "DX instance UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.26.0 of "
153
- "study UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.24.0 "
154
- "previously processed, stopping.",
155
- )
156
- )
157
-
158
- # Test that study level data is recorded correctly
159
- self.assertEqual(studies[0].study_date, datetime.date(2014, 9, 30))
160
- self.assertEqual(studies[1].study_date, datetime.date(2014, 6, 20))
161
- self.assertEqual(studies[0].study_time, datetime.time(14, 10, 24))
162
- self.assertEqual(studies[1].study_time, datetime.time(10, 48, 5))
163
- self.assertEqual(studies[1].study_description, "AEC")
164
- self.assertEqual(studies[1].operator_name, "PHYSICS")
165
-
166
- self.assertEqual(
167
- studies[0].generalequipmentmoduleattr_set.get().institution_name,
168
- "Digital Mobile Hospital",
169
- )
170
- self.assertEqual(
171
- studies[1].generalequipmentmoduleattr_set.get().institution_name,
172
- "Carestream Clinic",
173
- )
174
- self.assertEqual(
175
- studies[0].generalequipmentmoduleattr_set.get().institution_address,
176
- "Kvitfjell",
177
- )
178
- self.assertEqual(
179
- studies[0].generalequipmentmoduleattr_set.get().manufacturer,
180
- "GE Healthcare",
181
- )
182
- self.assertEqual(
183
- studies[1].generalequipmentmoduleattr_set.get().manufacturer, "KODAK"
184
- )
185
- self.assertEqual(
186
- studies[0].generalequipmentmoduleattr_set.get().station_name, "01234MOB54"
187
- )
188
- self.assertEqual(
189
- studies[1].generalequipmentmoduleattr_set.get().station_name, "KODAK7500"
190
- )
191
- self.assertEqual(
192
- studies[0].generalequipmentmoduleattr_set.get().manufacturer_model_name,
193
- "Optima XR220",
194
- )
195
- self.assertEqual(
196
- studies[1].generalequipmentmoduleattr_set.get().manufacturer_model_name,
197
- "DR 7500",
198
- )
199
- self.assertEqual(
200
- studies[0].generalequipmentmoduleattr_set.get().software_versions,
201
- "dm_Platform_release_superbee-FW23.1-SB",
202
- )
203
- self.assertEqual(
204
- studies[1].generalequipmentmoduleattr_set.get().software_versions,
205
- "4.0.3.B8.P6",
206
- )
207
- self.assertEqual(
208
- studies[1].generalequipmentmoduleattr_set.get().device_serial_number,
209
- "00012345abc",
210
- )
211
-
212
- # Test the SOP instance UIDs have been recorded correctly
213
- sop_instance_uid_list0 = Counter(
214
- studies[0].objectuidsprocessed_set.values_list(
215
- "sop_instance_uid", flat=True
216
- )
217
- )
218
- sop_instance_uid_list1 = Counter(
219
- studies[1].objectuidsprocessed_set.values_list(
220
- "sop_instance_uid", flat=True
221
- )
222
- )
223
- uid_list0 = Counter(
224
- [
225
- "1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.20.0",
226
- "1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.26.0",
227
- "1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.28.0",
228
- ]
229
- )
230
- uid_list1 = Counter(
231
- [
232
- "1.2.276.0.7230010.3.1.4.8323329.11838.1483692281.541544",
233
- "1.2.276.0.7230010.3.1.4.8323329.11853.1483692311.916929",
234
- ]
235
- )
236
- self.assertEqual(sop_instance_uid_list0, uid_list0)
237
- self.assertEqual(sop_instance_uid_list1, uid_list1)
238
-
239
- # Test that patient level data is recorded correctly
240
- self.assertEqual(
241
- studies[0].patientmoduleattr_set.get().patient_name, "XR220^Samantha"
242
- )
243
- self.assertEqual(
244
- studies[1].patientmoduleattr_set.get().patient_name, "PHYSICS^TABLE AEC"
245
- )
246
- self.assertEqual(studies[0].patientmoduleattr_set.get().patient_id, "00098765")
247
- self.assertEqual(
248
- studies[1].patientmoduleattr_set.get().patient_id, "PHY12320140620YU"
249
- )
250
- self.assertEqual(
251
- studies[0].patientmoduleattr_set.get().patient_birth_date,
252
- datetime.date(1957, 11, 12),
253
- )
254
- self.assertEqual(
255
- studies[1].patientmoduleattr_set.get().patient_birth_date,
256
- datetime.date(2014, 6, 20),
257
- )
258
- self.assertAlmostEqual(
259
- float(studies[0].patientstudymoduleattr_set.get().patient_age_decimal),
260
- 56.9,
261
- )
262
-
263
- # Test that irradiation event data is stored correctly
264
- self.assertEqual(
265
- studies[0]
266
- .projectionxrayradiationdose_set.get()
267
- .irradeventxraydata_set.order_by("id")[0]
268
- .acquisition_protocol,
269
- "ABD_1_VIEW",
270
- )
271
- self.assertEqual(
272
- studies[0]
273
- .projectionxrayradiationdose_set.get()
274
- .irradeventxraydata_set.order_by("id")[1]
275
- .acquisition_protocol,
276
- "ABD_1_VIEW",
277
- )
278
- self.assertEqual(
279
- studies[0]
280
- .projectionxrayradiationdose_set.get()
281
- .irradeventxraydata_set.order_by("id")[2]
282
- .acquisition_protocol,
283
- "ABD_1_VIEW",
284
- )
285
- self.assertAlmostEqual(
286
- float(
287
- studies[0]
288
- .projectionxrayradiationdose_set.get()
289
- .irradeventxraydata_set.order_by("id")[0]
290
- .dose_area_product
291
- ),
292
- (0.41 / 100000),
293
- )
294
- self.assertAlmostEqual(
295
- float(
296
- studies[0]
297
- .projectionxrayradiationdose_set.get()
298
- .irradeventxraydata_set.order_by("id")[1]
299
- .dose_area_product
300
- ),
301
- (0.82 / 100000),
302
- )
303
- self.assertAlmostEqual(
304
- float(
305
- studies[0]
306
- .projectionxrayradiationdose_set.get()
307
- .irradeventxraydata_set.order_by("id")[2]
308
- .dose_area_product
309
- ),
310
- (2.05 / 100000),
311
- )
312
-
313
- self.assertEqual(
314
- studies[1]
315
- .projectionxrayradiationdose_set.get()
316
- .irradeventxraydata_set.order_by("id")[0]
317
- .acquisition_protocol,
318
- "AEC",
319
- )
320
- self.assertEqual(
321
- studies[1]
322
- .projectionxrayradiationdose_set.get()
323
- .irradeventxraydata_set.order_by("id")[1]
324
- .acquisition_protocol,
325
- "AEC",
326
- )
327
- self.assertAlmostEqual(
328
- float(
329
- studies[1]
330
- .projectionxrayradiationdose_set.get()
331
- .irradeventxraydata_set.order_by("id")[0]
332
- .dose_area_product
333
- ),
334
- (11.013 / 100000),
335
- )
336
- self.assertAlmostEqual(
337
- float(
338
- studies[1]
339
- .projectionxrayradiationdose_set.get()
340
- .irradeventxraydata_set.order_by("id")[1]
341
- .dose_area_product
342
- ),
343
- (10.157 / 100000),
344
- )
345
-
346
- # Check that dose related distance measurement data is stored correctly
347
- self.assertAlmostEqual(
348
- float(
349
- studies[1]
350
- .projectionxrayradiationdose_set.get()
351
- .irradeventxraydata_set.order_by("id")[0]
352
- .irradeventxraymechanicaldata_set.get()
353
- .doserelateddistancemeasurements_set.get()
354
- .distance_source_to_detector
355
- ),
356
- (11.5 * 100),
357
- )
358
- self.assertAlmostEqual(
359
- float(
360
- studies[1]
361
- .projectionxrayradiationdose_set.get()
362
- .irradeventxraydata_set.order_by("id")[1]
363
- .irradeventxraymechanicaldata_set.get()
364
- .doserelateddistancemeasurements_set.get()
365
- .distance_source_to_detector
366
- ),
367
- (11.5 * 100),
368
- )
369
-
370
- # Test that irradiation event source data is stored correctly
371
- self.assertAlmostEqual(
372
- float(
373
- studies[0]
374
- .projectionxrayradiationdose_set.get()
375
- .irradeventxraydata_set.order_by("id")[0]
376
- .irradeventxraysourcedata_set.get()
377
- .exposure_time
378
- ),
379
- 6,
380
- )
381
- self.assertAlmostEqual(
382
- float(
383
- studies[0]
384
- .projectionxrayradiationdose_set.get()
385
- .irradeventxraydata_set.order_by("id")[1]
386
- .irradeventxraysourcedata_set.get()
387
- .exposure_time
388
- ),
389
- 11,
390
- )
391
- self.assertAlmostEqual(
392
- float(
393
- studies[0]
394
- .projectionxrayradiationdose_set.get()
395
- .irradeventxraydata_set.order_by("id")[2]
396
- .irradeventxraysourcedata_set.get()
397
- .exposure_time
398
- ),
399
- 27,
400
- )
401
- self.assertAlmostEqual(
402
- float(
403
- studies[0]
404
- .projectionxrayradiationdose_set.get()
405
- .irradeventxraydata_set.order_by("id")[0]
406
- .irradeventxraysourcedata_set.get()
407
- .average_xray_tube_current
408
- ),
409
- 189,
410
- )
411
- self.assertAlmostEqual(
412
- float(
413
- studies[0]
414
- .projectionxrayradiationdose_set.get()
415
- .irradeventxraydata_set.order_by("id")[0]
416
- .irradeventxraysourcedata_set.get()
417
- .focal_spot_size
418
- ),
419
- 0.6,
420
- )
421
- self.assertAlmostEqual(
422
- float(
423
- studies[0]
424
- .projectionxrayradiationdose_set.get()
425
- .irradeventxraydata_set.order_by("id")[1]
426
- .irradeventxraysourcedata_set.get()
427
- .focal_spot_size
428
- ),
429
- 0.6,
430
- )
431
- self.assertAlmostEqual(
432
- float(
433
- studies[0]
434
- .projectionxrayradiationdose_set.get()
435
- .irradeventxraydata_set.order_by("id")[2]
436
- .irradeventxraysourcedata_set.get()
437
- .focal_spot_size
438
- ),
439
- 0.6,
440
- )
441
-
442
- self.assertAlmostEqual(
443
- float(
444
- studies[1]
445
- .projectionxrayradiationdose_set.get()
446
- .irradeventxraydata_set.order_by("id")[0]
447
- .irradeventxraysourcedata_set.get()
448
- .exposure_time
449
- ),
450
- 19,
451
- )
452
- self.assertAlmostEqual(
453
- float(
454
- studies[1]
455
- .projectionxrayradiationdose_set.get()
456
- .irradeventxraydata_set.order_by("id")[1]
457
- .irradeventxraysourcedata_set.get()
458
- .exposure_time
459
- ),
460
- 18,
461
- )
462
- self.assertAlmostEqual(
463
- float(
464
- studies[1]
465
- .projectionxrayradiationdose_set.get()
466
- .irradeventxraydata_set.order_by("id")[0]
467
- .irradeventxraysourcedata_set.get()
468
- .focal_spot_size
469
- ),
470
- 1.2,
471
- )
472
- self.assertAlmostEqual(
473
- float(
474
- studies[1]
475
- .projectionxrayradiationdose_set.get()
476
- .irradeventxraydata_set.order_by("id")[1]
477
- .irradeventxraysourcedata_set.get()
478
- .focal_spot_size
479
- ),
480
- 1.2,
481
- )
482
-
483
- self.assertAlmostEqual(
484
- float(
485
- studies[0]
486
- .projectionxrayradiationdose_set.get()
487
- .irradeventxraydata_set.order_by("id")[0]
488
- .irradeventxraysourcedata_set.get()
489
- .average_xray_tube_current
490
- ),
491
- 189,
492
- )
493
- self.assertAlmostEqual(
494
- float(
495
- studies[0]
496
- .projectionxrayradiationdose_set.get()
497
- .irradeventxraydata_set.order_by("id")[1]
498
- .irradeventxraysourcedata_set.get()
499
- .average_xray_tube_current
500
- ),
501
- 192,
502
- )
503
- self.assertAlmostEqual(
504
- float(
505
- studies[0]
506
- .projectionxrayradiationdose_set.get()
507
- .irradeventxraydata_set.order_by("id")[2]
508
- .irradeventxraysourcedata_set.get()
509
- .average_xray_tube_current
510
- ),
511
- 190,
512
- )
513
-
514
- self.assertAlmostEqual(
515
- float(
516
- studies[1]
517
- .projectionxrayradiationdose_set.get()
518
- .irradeventxraydata_set.order_by("id")[0]
519
- .irradeventxraysourcedata_set.get()
520
- .average_xray_tube_current
521
- ),
522
- 500,
523
- )
524
- self.assertAlmostEqual(
525
- float(
526
- studies[1]
527
- .projectionxrayradiationdose_set.get()
528
- .irradeventxraydata_set.order_by("id")[1]
529
- .irradeventxraysourcedata_set.get()
530
- .average_xray_tube_current
531
- ),
532
- 500,
533
- )
534
-
535
- self.assertEqual(
536
- studies[1]
537
- .projectionxrayradiationdose_set.get()
538
- .irradeventxraydata_set.order_by("id")[0]
539
- .irradeventxraysourcedata_set.get()
540
- .xrayfilters_set.get()
541
- .xray_filter_material.code_meaning,
542
- "Aluminum or Aluminum compound",
543
- )
544
- self.assertAlmostEqual(
545
- float(
546
- studies[1]
547
- .projectionxrayradiationdose_set.get()
548
- .irradeventxraydata_set.order_by("id")[0]
549
- .irradeventxraysourcedata_set.get()
550
- .xrayfilters_set.get()
551
- .xray_filter_thickness_minimum
552
- ),
553
- 0.94,
554
- )
555
- self.assertAlmostEqual(
556
- float(
557
- studies[1]
558
- .projectionxrayradiationdose_set.get()
559
- .irradeventxraydata_set.order_by("id")[0]
560
- .irradeventxraysourcedata_set.get()
561
- .xrayfilters_set.get()
562
- .xray_filter_thickness_maximum
563
- ),
564
- 1.06,
565
- )
566
-
567
- self.assertEqual(
568
- studies[1]
569
- .projectionxrayradiationdose_set.get()
570
- .irradeventxraydata_set.order_by("id")[1]
571
- .irradeventxraysourcedata_set.get()
572
- .xrayfilters_set.order_by("id")[0]
573
- .xray_filter_material.code_meaning,
574
- "Aluminum or Aluminum compound",
575
- )
576
- self.assertAlmostEqual(
577
- float(
578
- studies[1]
579
- .projectionxrayradiationdose_set.get()
580
- .irradeventxraydata_set.order_by("id")[1]
581
- .irradeventxraysourcedata_set.get()
582
- .xrayfilters_set.order_by("id")[0]
583
- .xray_filter_thickness_minimum
584
- ),
585
- 0.94,
586
- )
587
- self.assertAlmostEqual(
588
- float(
589
- studies[1]
590
- .projectionxrayradiationdose_set.get()
591
- .irradeventxraydata_set.order_by("id")[1]
592
- .irradeventxraysourcedata_set.get()
593
- .xrayfilters_set.order_by("id")[0]
594
- .xray_filter_thickness_maximum
595
- ),
596
- 1.06,
597
- )
598
-
599
- self.assertEqual(
600
- studies[1]
601
- .projectionxrayradiationdose_set.get()
602
- .irradeventxraydata_set.order_by("id")[1]
603
- .irradeventxraysourcedata_set.get()
604
- .xrayfilters_set.order_by("id")[1]
605
- .xray_filter_material.code_meaning,
606
- "Copper or Copper compound",
607
- )
608
- self.assertAlmostEqual(
609
- float(
610
- studies[1]
611
- .projectionxrayradiationdose_set.get()
612
- .irradeventxraydata_set.order_by("id")[1]
613
- .irradeventxraysourcedata_set.get()
614
- .xrayfilters_set.order_by("id")[1]
615
- .xray_filter_thickness_minimum
616
- ),
617
- 0.194,
618
- )
619
- self.assertAlmostEqual(
620
- float(
621
- studies[1]
622
- .projectionxrayradiationdose_set.get()
623
- .irradeventxraydata_set.order_by("id")[1]
624
- .irradeventxraysourcedata_set.get()
625
- .xrayfilters_set.order_by("id")[1]
626
- .xray_filter_thickness_maximum
627
- ),
628
- 0.206,
629
- )
630
-
631
- self.assertAlmostEqual(
632
- float(
633
- studies[1]
634
- .projectionxrayradiationdose_set.get()
635
- .irradeventxraydata_set.order_by("id")[0]
636
- .irradeventxraysourcedata_set.get()
637
- .grid_focal_distance
638
- ),
639
- 1828.8,
640
- )
641
- self.assertAlmostEqual(
642
- float(
643
- studies[1]
644
- .projectionxrayradiationdose_set.get()
645
- .irradeventxraydata_set.order_by("id")[1]
646
- .irradeventxraysourcedata_set.get()
647
- .grid_focal_distance
648
- ),
649
- 1828.8,
650
- )
651
-
652
- # Test exposure data is stored correctly
653
- self.assertAlmostEqual(
654
- float(
655
- studies[0]
656
- .projectionxrayradiationdose_set.get()
657
- .irradeventxraydata_set.order_by("id")[0]
658
- .irradeventxraysourcedata_set.get()
659
- .exposure_set.get()
660
- .exposure
661
- ),
662
- 1040,
663
- )
664
- self.assertAlmostEqual(
665
- float(
666
- studies[0]
667
- .projectionxrayradiationdose_set.get()
668
- .irradeventxraydata_set.order_by("id")[1]
669
- .irradeventxraysourcedata_set.get()
670
- .exposure_set.get()
671
- .exposure
672
- ),
673
- 2040,
674
- )
675
- self.assertAlmostEqual(
676
- float(
677
- studies[0]
678
- .projectionxrayradiationdose_set.get()
679
- .irradeventxraydata_set.order_by("id")[2]
680
- .irradeventxraysourcedata_set.get()
681
- .exposure_set.get()
682
- .exposure
683
- ),
684
- 5040,
685
- )
686
-
687
- self.assertAlmostEqual(
688
- float(
689
- studies[1]
690
- .projectionxrayradiationdose_set.get()
691
- .irradeventxraydata_set.order_by("id")[0]
692
- .irradeventxraysourcedata_set.get()
693
- .exposure_set.get()
694
- .exposure
695
- ),
696
- (10 * 1000),
697
- )
698
- self.assertAlmostEqual(
699
- float(
700
- studies[1]
701
- .projectionxrayradiationdose_set.get()
702
- .irradeventxraydata_set.order_by("id")[1]
703
- .irradeventxraysourcedata_set.get()
704
- .exposure_set.get()
705
- .exposure
706
- ),
707
- (9 * 1000),
708
- )
709
-
710
- # Test that irradiation event detector data is stored correctly
711
- self.assertAlmostEqual(
712
- float(
713
- studies[0]
714
- .projectionxrayradiationdose_set.get()
715
- .irradeventxraydata_set.order_by("id")[0]
716
- .irradeventxraydetectordata_set.get()
717
- .exposure_index
718
- ),
719
- 51.745061,
720
- )
721
- self.assertAlmostEqual(
722
- float(
723
- studies[0]
724
- .projectionxrayradiationdose_set.get()
725
- .irradeventxraydata_set.order_by("id")[1]
726
- .irradeventxraydetectordata_set.get()
727
- .exposure_index
728
- ),
729
- 108.843060,
730
- )
731
- self.assertAlmostEqual(
732
- float(
733
- studies[0]
734
- .projectionxrayradiationdose_set.get()
735
- .irradeventxraydata_set.order_by("id")[2]
736
- .irradeventxraydetectordata_set.get()
737
- .exposure_index
738
- ),
739
- 286.828227,
740
- )
741
-
742
- self.assertAlmostEqual(
743
- float(
744
- studies[0]
745
- .projectionxrayradiationdose_set.get()
746
- .irradeventxraydata_set.order_by("id")[0]
747
- .irradeventxraydetectordata_set.get()
748
- .target_exposure_index
749
- ),
750
- 438.469173,
751
- )
752
- self.assertAlmostEqual(
753
- float(
754
- studies[0]
755
- .projectionxrayradiationdose_set.get()
756
- .irradeventxraydata_set.order_by("id")[1]
757
- .irradeventxraydetectordata_set.get()
758
- .target_exposure_index
759
- ),
760
- 438.469173,
761
- )
762
- self.assertAlmostEqual(
763
- float(
764
- studies[0]
765
- .projectionxrayradiationdose_set.get()
766
- .irradeventxraydata_set.order_by("id")[2]
767
- .irradeventxraydetectordata_set.get()
768
- .target_exposure_index
769
- ),
770
- 438.469173,
771
- )
772
-
773
- self.assertAlmostEqual(
774
- float(
775
- studies[0]
776
- .projectionxrayradiationdose_set.get()
777
- .irradeventxraydata_set.order_by("id")[0]
778
- .irradeventxraydetectordata_set.get()
779
- .deviation_index
780
- ),
781
- (-9.3),
782
- )
783
- self.assertAlmostEqual(
784
- float(
785
- studies[0]
786
- .projectionxrayradiationdose_set.get()
787
- .irradeventxraydata_set.order_by("id")[1]
788
- .irradeventxraydetectordata_set.get()
789
- .deviation_index
790
- ),
791
- (-6.1),
792
- )
793
- self.assertAlmostEqual(
794
- float(
795
- studies[0]
796
- .projectionxrayradiationdose_set.get()
797
- .irradeventxraydata_set.order_by("id")[2]
798
- .irradeventxraydetectordata_set.get()
799
- .deviation_index
800
- ),
801
- (-1.8),
802
- )
803
-
804
- self.assertAlmostEqual(
805
- float(
806
- studies[0]
807
- .projectionxrayradiationdose_set.get()
808
- .irradeventxraydata_set.order_by("id")[0]
809
- .irradeventxraydetectordata_set.get()
810
- .sensitivity
811
- ),
812
- 97.213916,
813
- )
814
- self.assertAlmostEqual(
815
- float(
816
- studies[0]
817
- .projectionxrayradiationdose_set.get()
818
- .irradeventxraydata_set.order_by("id")[1]
819
- .irradeventxraydetectordata_set.get()
820
- .sensitivity
821
- ),
822
- 97.213916,
823
- )
824
- self.assertAlmostEqual(
825
- float(
826
- studies[0]
827
- .projectionxrayradiationdose_set.get()
828
- .irradeventxraydata_set.order_by("id")[2]
829
- .irradeventxraydetectordata_set.get()
830
- .sensitivity
831
- ),
832
- 97.213916,
833
- )
834
-
835
- self.assertAlmostEqual(
836
- float(
837
- studies[1]
838
- .projectionxrayradiationdose_set.get()
839
- .irradeventxraydata_set.order_by("id")[0]
840
- .irradeventxraydetectordata_set.get()
841
- .relative_xray_exposure
842
- ),
843
- 1460,
844
- )
845
- self.assertAlmostEqual(
846
- float(
847
- studies[1]
848
- .projectionxrayradiationdose_set.get()
849
- .irradeventxraydata_set.order_by("id")[1]
850
- .irradeventxraydetectordata_set.get()
851
- .relative_xray_exposure
852
- ),
853
- 1430,
854
- )
855
-
856
- # Test summary fields
857
- self.assertAlmostEqual(float(studies[0].total_dap_a), (3.28 / 100000))
858
- self.assertAlmostEqual(float(studies[0].total_dap), (3.28 / 100000))
859
- self.assertEqual(studies[0].number_of_events, 3)
860
- self.assertEqual(studies[0].number_of_planes, 1)
861
- self.assertAlmostEqual(float(studies[1].total_dap_a), (21.17 / 100000))
862
- self.assertAlmostEqual(float(studies[1].total_dap), (21.17 / 100000))
863
- self.assertEqual(studies[1].number_of_events, 2)
864
- self.assertEqual(studies[1].number_of_planes, 1)
865
-
866
- def test_filter_thickness_order(self):
867
-
868
- all_filters = XrayFilters.objects.order_by("id")
869
- for exposure in all_filters:
870
- self.assertGreaterEqual(
871
- exposure.xray_filter_thickness_maximum,
872
- exposure.xray_filter_thickness_minimum,
873
- )
874
-
875
- def test_multiple_filter_carestream_comma(self):
876
- """
877
- Testing the DR7500 file can be imported with illegal comma separated floats
878
- :return: None
879
- """
880
-
881
- study = GeneralStudyModuleAttr.objects.order_by("id")[1]
882
-
883
- source = (
884
- study.projectionxrayradiationdose_set.get()
885
- .irradeventxraydata_set.order_by("id")[1]
886
- .irradeventxraysourcedata_set.get()
887
- )
888
-
889
- self.assertEqual(
890
- source.xrayfilters_set.order_by("id").count(),
891
- 2,
892
- "Testing Kodak old style, two filters should have been stored, {0} were".format(
893
- source.xrayfilters_set.order_by("id").count()
894
- ),
895
- )
896
- self.assertEqual(
897
- source.xrayfilters_set.order_by("id")[0].xray_filter_material.code_meaning,
898
- "Aluminum or Aluminum compound",
899
- )
900
- self.assertAlmostEqual(
901
- float(
902
- source.xrayfilters_set.order_by("id")[0].xray_filter_thickness_minimum
903
- ),
904
- 0.94,
905
- )
906
- self.assertEqual(
907
- source.xrayfilters_set.order_by("id")[1].xray_filter_material.code_meaning,
908
- "Copper or Copper compound",
909
- )
910
- self.assertAlmostEqual(
911
- float(
912
- source.xrayfilters_set.order_by("id")[1].xray_filter_thickness_minimum
913
- ),
914
- 0.194,
915
- )
916
-
917
-
918
- class ImportCarestreamDRXRevolution(TestCase):
919
- def setUp(self):
920
- """
921
- Imports a known radigraphic image file derived from a Carestream DRX Revolution image.
922
- """
923
-
924
- pid = PatientIDSettings.objects.create()
925
- pid.name_stored = True
926
- pid.name_hashed = False
927
- pid.id_stored = True
928
- pid.id_hashed = False
929
- pid.dob_stored = True
930
- pid.save()
931
-
932
- dx_carestream_drx_revolution = os.path.join(
933
- "test_files", "DX-Im-Carestream_DRX.dcm"
934
- )
935
- root_tests = os.path.dirname(os.path.abspath(__file__))
936
- dx.dx(os.path.join(root_tests, dx_carestream_drx_revolution))
937
-
938
- def test_requested_procedure_name(self):
939
- """
940
- Tests the imported value of requested procedure code meaning against what is expected.
941
- """
942
- study = GeneralStudyModuleAttr.objects.order_by("id")[0]
943
-
944
- self.assertEqual(study.requested_procedure_code_meaning, "XR CHEST")
945
-
946
-
947
- class ImportDuplicateDX(TestCase):
948
- def setUp(self):
949
- """"""
950
-
951
- pid = PatientIDSettings.objects.create()
952
- pid.name_stored = True
953
- pid.name_hashed = False
954
- pid.id_stored = True
955
- pid.id_hashed = False
956
- pid.dob_stored = True
957
- pid.save()
958
-
959
- dx_ge_xr220_1 = os.path.join("test_files", "DX-Im-GE_XR220-1.dcm")
960
- root_tests = os.path.dirname(os.path.abspath(__file__))
961
-
962
- dx.dx(os.path.join(root_tests, dx_ge_xr220_1))
963
- study_one = GeneralStudyModuleAttr.objects.order_by("pk")[0]
964
- original_study_uid = study_one.study_instance_uid
965
- original_sop_instance_uid = (
966
- study_one.projectionxrayradiationdose_set.get()
967
- .irradeventxraydata_set.get()
968
- .irradiation_event_uid
969
- )
970
- study_one.study_instance_uid = "1.2.3.4.5.6.7.8"
971
- study_one.projectionxrayradiationdose_set.get().irradeventxraydata_set.get().irradiation_event_uid = (
972
- "2.3.4.5.6.7.8.9"
973
- )
974
- study_one.save()
975
-
976
- # Check there is one study in the database
977
- self.assertEqual(GeneralStudyModuleAttr.objects.all().count(), 1)
978
-
979
- # Import the image again...
980
- dx.dx(os.path.join(root_tests, dx_ge_xr220_1))
981
-
982
- # Check there are two studies now
983
- self.assertEqual(GeneralStudyModuleAttr.objects.all().count(), 2)
984
-
985
- study_one.study_instance_uid = original_study_uid
986
- study_one.projectionxrayradiationdose_set.get().irradeventxraydata_set.get().irradiation_event_uid = (
987
- original_sop_instance_uid
988
- )
989
- study_one.save()
990
-
991
- # Now we are ready to test import with duplicate study UIDs.
992
-
993
- def test_duplicate_study_dx(self):
994
- """Imports second image, original two both have modality set."""
995
-
996
- dx_ge_xr220_2 = os.path.join("test_files", "DX-Im-GE_XR220-2.dcm")
997
- root_tests = os.path.dirname(os.path.abspath(__file__))
998
-
999
- self.assertEqual(GeneralStudyModuleAttr.objects.all().count(), 2)
1000
-
1001
- study_1_pk = GeneralStudyModuleAttr.objects.order_by("pk").first().pk
1002
-
1003
- with LogCapture("remapp.extractors", level=logging.DEBUG) as log:
1004
- dx.dx(os.path.join(root_tests, dx_ge_xr220_2))
1005
-
1006
- log.check_present(
1007
- (
1008
- "remapp.extractors.dx",
1009
- "WARNING",
1010
- "Duplicate DX study UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.24.0 in "
1011
- "database - could be a problem! There are 2 copies.",
1012
- ),
1013
- (
1014
- "remapp.extractors.dx",
1015
- "DEBUG",
1016
- "Duplicate DX study UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.24.0 - "
1017
- "first instance (pk={0}) with modality type assigned (DX) selected to import new event "
1018
- "into.".format(study_1_pk),
1019
- ),
1020
- )
1021
-
1022
- number_of_events_study_1 = (
1023
- GeneralStudyModuleAttr.objects.order_by("pk")
1024
- .first()
1025
- .projectionxrayradiationdose_set.get()
1026
- .irradeventxraydata_set.all()
1027
- .count()
1028
- )
1029
- self.assertEqual(number_of_events_study_1, 2)
1030
- number_of_events_study_2 = (
1031
- GeneralStudyModuleAttr.objects.order_by("pk")[1]
1032
- .projectionxrayradiationdose_set.get()
1033
- .irradeventxraydata_set.all()
1034
- .count()
1035
- )
1036
- self.assertEqual(number_of_events_study_2, 1)
1037
-
1038
- def test_duplicate_study_dx_second_mod(self):
1039
- """Imports second image, later existing has modality set."""
1040
-
1041
- dx_ge_xr220_2 = os.path.join("test_files", "DX-Im-GE_XR220-2.dcm")
1042
- root_tests = os.path.dirname(os.path.abspath(__file__))
1043
-
1044
- self.assertEqual(GeneralStudyModuleAttr.objects.all().count(), 2)
1045
-
1046
- # Set first study modality to None
1047
- study_1 = GeneralStudyModuleAttr.objects.order_by("pk").first()
1048
- study_1.modality_type = None
1049
- study_1.save()
1050
-
1051
- study_2_pk = GeneralStudyModuleAttr.objects.order_by("pk")[1].pk
1052
-
1053
- with LogCapture("remapp.extractors", level=logging.DEBUG) as log:
1054
- dx.dx(os.path.join(root_tests, dx_ge_xr220_2))
1055
-
1056
- log.check_present(
1057
- (
1058
- "remapp.extractors.dx",
1059
- "WARNING",
1060
- "Duplicate DX study UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.24.0 in "
1061
- "database - could be a problem! There are 2 copies.",
1062
- ),
1063
- (
1064
- "remapp.extractors.dx",
1065
- "DEBUG",
1066
- "Duplicate DX study UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.24.0 - "
1067
- "first instance (pk={0}) with modality type assigned (DX) selected to import new event "
1068
- "into.".format(study_2_pk),
1069
- ),
1070
- )
1071
-
1072
- number_of_events_study_1 = (
1073
- GeneralStudyModuleAttr.objects.order_by("pk")
1074
- .first()
1075
- .projectionxrayradiationdose_set.get()
1076
- .irradeventxraydata_set.all()
1077
- .count()
1078
- )
1079
- self.assertEqual(number_of_events_study_1, 1)
1080
- number_of_events_study_2 = (
1081
- GeneralStudyModuleAttr.objects.order_by("pk")[1]
1082
- .projectionxrayradiationdose_set.get()
1083
- .irradeventxraydata_set.all()
1084
- .count()
1085
- )
1086
- self.assertEqual(number_of_events_study_2, 2)
1087
-
1088
- def test_duplicate_study_dx_no_mod(self):
1089
- """Imports second image, original two don't have modality set."""
1090
-
1091
- dx_ge_xr220_2 = os.path.join("test_files", "DX-Im-GE_XR220-2.dcm")
1092
- root_tests = os.path.dirname(os.path.abspath(__file__))
1093
-
1094
- self.assertEqual(GeneralStudyModuleAttr.objects.all().count(), 2)
1095
-
1096
- # Set modality type to None
1097
- for study in GeneralStudyModuleAttr.objects.order_by("pk"):
1098
- study.modality_type = None
1099
- study.save()
1100
-
1101
- with LogCapture("remapp.extractors", level=logging.DEBUG) as log:
1102
- dx.dx(os.path.join(root_tests, dx_ge_xr220_2))
1103
-
1104
- log.check_present(
1105
- (
1106
- "remapp.extractors.dx",
1107
- "WARNING",
1108
- "Duplicate DX study UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.24.0 in "
1109
- "database - could be a problem! There are 2 copies.",
1110
- ),
1111
- (
1112
- "remapp.extractors.dx",
1113
- "WARNING",
1114
- "Duplicate DX study UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.24.0, "
1115
- "none of which have modality_type assigned! Setting first instance to DX",
1116
- ),
1117
- )
1118
-
1119
- number_of_events_study_1 = (
1120
- GeneralStudyModuleAttr.objects.order_by("pk")
1121
- .first()
1122
- .projectionxrayradiationdose_set.get()
1123
- .irradeventxraydata_set.all()
1124
- .count()
1125
- )
1126
- self.assertEqual(number_of_events_study_1, 2)
1127
- number_of_events_study_2 = (
1128
- GeneralStudyModuleAttr.objects.order_by("pk")[1]
1129
- .projectionxrayradiationdose_set.get()
1130
- .irradeventxraydata_set.all()
1131
- .count()
1132
- )
1133
- self.assertEqual(number_of_events_study_2, 1)
1134
-
1135
-
1136
- class ImportSiemensDX(TestCase):
1137
- def setUp(self):
1138
- """
1139
- Imports a known radigraphic image file derived from a Siemens MultixFD image.
1140
- """
1141
-
1142
- pid = PatientIDSettings.objects.create()
1143
- pid.name_stored = True
1144
- pid.name_hashed = False
1145
- pid.id_stored = True
1146
- pid.id_hashed = False
1147
- pid.dob_stored = True
1148
- pid.save()
1149
-
1150
- dx_siemens_multix = os.path.join("test_files", "DX-Im-SiemensMultix.dcm")
1151
- root_tests = os.path.dirname(os.path.abspath(__file__))
1152
- dx.dx(os.path.join(root_tests, dx_siemens_multix))
1153
-
1154
- def test_siemens_dx_filter_data(self):
1155
- """Check filter type and thickness is extracted"""
1156
- studies = GeneralStudyModuleAttr.objects.order_by("id")
1157
-
1158
- # Test that one study have been imported
1159
- self.assertEqual(studies.count(), 1)
1160
-
1161
- self.assertEqual(
1162
- studies[0]
1163
- .projectionxrayradiationdose_set.get()
1164
- .irradeventxraydata_set.order_by("id")[0]
1165
- .irradeventxraysourcedata_set.get()
1166
- .xrayfilters_set.get()
1167
- .xray_filter_material.code_meaning,
1168
- "Copper or Copper compound",
1169
- )
1170
- self.assertAlmostEqual(
1171
- float(
1172
- studies[0]
1173
- .projectionxrayradiationdose_set.get()
1174
- .irradeventxraydata_set.order_by("id")[0]
1175
- .irradeventxraysourcedata_set.get()
1176
- .xrayfilters_set.get()
1177
- .xray_filter_thickness_minimum
1178
- ),
1179
- 0.2,
1180
- )
1181
- self.assertAlmostEqual(
1182
- float(
1183
- studies[0]
1184
- .projectionxrayradiationdose_set.get()
1185
- .irradeventxraydata_set.order_by("id")[0]
1186
- .irradeventxraysourcedata_set.get()
1187
- .xrayfilters_set.get()
1188
- .xray_filter_thickness_maximum
1189
- ),
1190
- 0.2,
1191
- )
1
+ # This Python file uses the following encoding: utf-8
2
+ # test_get_values.py
3
+
4
+ import os
5
+ from collections import Counter
6
+ import datetime
7
+ from django.contrib.auth.models import User, Group
8
+ from django.test import TestCase
9
+ from pydicom.dataset import Dataset
10
+ from pydicom.dataelem import DataElement
11
+ from pydicom.multival import MultiValue
12
+ import logging
13
+ from testfixtures import LogCapture
14
+
15
+ from django.core.exceptions import ObjectDoesNotExist
16
+
17
+ from remapp.extractors import dx
18
+ from remapp.models import (
19
+ GeneralStudyModuleAttr,
20
+ ProjectionXRayRadiationDose,
21
+ IrradEventXRayData,
22
+ IrradEventXRaySourceData,
23
+ PatientIDSettings,
24
+ XrayFilters,
25
+ StandardNameSettings,
26
+ StandardNames,
27
+ DicomDeleteSettings,
28
+ )
29
+ from openremproject import settings
30
+
31
+ settings.LOGGING["loggers"]["remapp"]["level"] = "DEBUG"
32
+
33
+
34
+ class DXFilterTests(TestCase):
35
+ def test_multiple_filter_kodak_drxevolution(self):
36
+ """
37
+ Test the material extraction process when the materials are in a MultiValue format
38
+ """
39
+ ds = Dataset()
40
+ multi = MultiValue(str, ["ALUMINUM", "COPPER"])
41
+ data_el = DataElement(0x187050, "CS", multi, already_converted=True)
42
+ ds[0x187050] = data_el
43
+ ds.FilterThicknessMinimum = "1.0\\0.1"
44
+ ds.FilterThicknessMaximum = "1.0\\0.1"
45
+ ds.FilterType = "WEDGE"
46
+
47
+ g = GeneralStudyModuleAttr.objects.create()
48
+ g.save()
49
+ proj = ProjectionXRayRadiationDose.objects.create(
50
+ general_study_module_attributes=g
51
+ )
52
+ proj.save()
53
+ event = IrradEventXRayData.objects.create(projection_xray_radiation_dose=proj)
54
+ event.save()
55
+ source = IrradEventXRaySourceData.objects.create(
56
+ irradiation_event_xray_data=event
57
+ )
58
+ source.save()
59
+
60
+ dx._xray_filters_prep(ds, source)
61
+
62
+ self.assertEqual(
63
+ source.xrayfilters_set.order_by("id").count(),
64
+ 2,
65
+ "Wrong number of filters recorded",
66
+ )
67
+ self.assertEqual(
68
+ source.xrayfilters_set.order_by("id")[0].xray_filter_material.code_meaning,
69
+ "Aluminum or Aluminum compound",
70
+ )
71
+ self.assertEqual(
72
+ source.xrayfilters_set.order_by("id")[1].xray_filter_material.code_meaning,
73
+ "Copper or Copper compound",
74
+ )
75
+
76
+ def test_single_filter(self):
77
+ """
78
+ Test the material extraction process when there is just one filter
79
+ """
80
+ ds = Dataset()
81
+ ds.FilterType = "FLAT"
82
+ ds.FilterMaterial = "LEAD"
83
+ ds.FilterThicknessMinimum = "1.0"
84
+ ds.FilterThicknessMaximum = "1.0"
85
+
86
+ g = GeneralStudyModuleAttr.objects.create()
87
+ g.save()
88
+ proj = ProjectionXRayRadiationDose.objects.create(
89
+ general_study_module_attributes=g
90
+ )
91
+ proj.save()
92
+ event = IrradEventXRayData.objects.create(projection_xray_radiation_dose=proj)
93
+ event.save()
94
+ source = IrradEventXRaySourceData.objects.create(
95
+ irradiation_event_xray_data=event
96
+ )
97
+ source.save()
98
+
99
+ dx._xray_filters_prep(ds, source)
100
+
101
+ self.assertEqual(source.xrayfilters_set.order_by("id").count(), 1)
102
+ self.assertEqual(
103
+ source.xrayfilters_set.order_by("id")[0].xray_filter_material.code_meaning,
104
+ "Lead or Lead compound",
105
+ )
106
+
107
+
108
+ class ImportCarestreamDR7500(TestCase):
109
+ def setUp(self):
110
+
111
+ self.user = User.objects.create_user(
112
+ username="jacob", email="jacob@…", password="top_secret"
113
+ )
114
+ eg = Group(name="exportgroup")
115
+ eg.save()
116
+ eg.user_set.add(self.user)
117
+ eg.save()
118
+
119
+ pid = PatientIDSettings.objects.create()
120
+ pid.name_stored = True
121
+ pid.name_hashed = False
122
+ pid.id_stored = True
123
+ pid.id_hashed = False
124
+ pid.dob_stored = True
125
+ pid.save()
126
+
127
+ # Ensure test images are not deleted after import
128
+ try:
129
+ DicomDeleteSettings.objects.get()
130
+ except ObjectDoesNotExist:
131
+ DicomDeleteSettings.objects.create()
132
+ dicom_delete_settintgs = DicomDeleteSettings.objects.get()
133
+ dicom_delete_settintgs.del_dx_im = False
134
+ dicom_delete_settintgs.save()
135
+
136
+ # Ensure standard name objects are created and the feature is enabled
137
+ try:
138
+ StandardNameSettings.objects.get()
139
+ except ObjectDoesNotExist:
140
+ StandardNameSettings.objects.create()
141
+ standard_name_settings = StandardNameSettings.objects.get()
142
+ standard_name_settings.enable_standard_names = True
143
+ standard_name_settings.save()
144
+
145
+ # Add a standard acquisition name entry for the acquisition protocol used in the DX-Im-GE_XR220 images
146
+ standard_name = StandardNames.objects.create()
147
+ standard_name.modality = "DX"
148
+ standard_name.standard_name = "AbdoView"
149
+ standard_name.acquisition_protocol = "ABD_1_VIEW"
150
+ standard_name.save()
151
+
152
+ dx_ge_xr220_1 = os.path.join("test_files", "DX-Im-GE_XR220-1.dcm")
153
+ dx_ge_xr220_2 = os.path.join("test_files", "DX-Im-GE_XR220-2.dcm")
154
+ dx_ge_xr220_3 = os.path.join("test_files", "DX-Im-GE_XR220-3.dcm")
155
+ dx_carestream_dr7500_1 = os.path.join(
156
+ "test_files", "DX-Im-Carestream_DR7500-1.dcm"
157
+ )
158
+ dx_carestream_dr7500_2 = os.path.join(
159
+ "test_files", "DX-Im-Carestream_DR7500-2.dcm"
160
+ )
161
+ root_tests = os.path.dirname(os.path.abspath(__file__))
162
+
163
+ with LogCapture("remapp.extractors", level=logging.DEBUG) as self.log:
164
+ dx.dx(os.path.join(root_tests, dx_ge_xr220_1))
165
+ dx.dx(os.path.join(root_tests, dx_ge_xr220_2))
166
+ dx.dx(os.path.join(root_tests, dx_ge_xr220_3))
167
+ dx.dx(os.path.join(root_tests, dx_carestream_dr7500_1))
168
+ dx.dx(os.path.join(root_tests, dx_carestream_dr7500_2))
169
+ dx.dx(os.path.join(root_tests, dx_ge_xr220_2))
170
+
171
+ def test_dr7500_and_xr220(self):
172
+ studies = GeneralStudyModuleAttr.objects.order_by("id")
173
+
174
+ # Test that two studies have been imported
175
+ self.assertEqual(studies.count(), 2)
176
+
177
+ # Test that the second attempt to import dx_ge_xr220_2 results in debug message
178
+ self.log.check_present(
179
+ (
180
+ "remapp.extractors.dx",
181
+ "DEBUG",
182
+ "DX instance UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.26.0 of "
183
+ "study UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.24.0 "
184
+ "previously processed, stopping.",
185
+ )
186
+ )
187
+
188
+ # Test that study level data is recorded correctly
189
+ self.assertEqual(studies[0].study_date, datetime.date(2014, 9, 30))
190
+ self.assertEqual(studies[1].study_date, datetime.date(2014, 6, 20))
191
+ self.assertEqual(studies[0].study_time, datetime.time(14, 10, 24))
192
+ self.assertEqual(studies[1].study_time, datetime.time(10, 48, 5))
193
+ self.assertEqual(studies[1].study_description, "AEC")
194
+ self.assertEqual(studies[1].operator_name, "PHYSICS")
195
+
196
+ self.assertEqual(
197
+ studies[0].generalequipmentmoduleattr_set.get().institution_name,
198
+ "Digital Mobile Hospital",
199
+ )
200
+ self.assertEqual(
201
+ studies[1].generalequipmentmoduleattr_set.get().institution_name,
202
+ "Carestream Clinic",
203
+ )
204
+ self.assertEqual(
205
+ studies[0].generalequipmentmoduleattr_set.get().institution_address,
206
+ "Kvitfjell",
207
+ )
208
+ self.assertEqual(
209
+ studies[0].generalequipmentmoduleattr_set.get().manufacturer,
210
+ "GE Healthcare",
211
+ )
212
+ self.assertEqual(
213
+ studies[1].generalequipmentmoduleattr_set.get().manufacturer, "KODAK"
214
+ )
215
+ self.assertEqual(
216
+ studies[0].generalequipmentmoduleattr_set.get().station_name, "01234MOB54"
217
+ )
218
+ self.assertEqual(
219
+ studies[1].generalequipmentmoduleattr_set.get().station_name, "KODAK7500"
220
+ )
221
+ self.assertEqual(
222
+ studies[0].generalequipmentmoduleattr_set.get().manufacturer_model_name,
223
+ "Optima XR220",
224
+ )
225
+ self.assertEqual(
226
+ studies[1].generalequipmentmoduleattr_set.get().manufacturer_model_name,
227
+ "DR 7500",
228
+ )
229
+ self.assertEqual(
230
+ studies[0].generalequipmentmoduleattr_set.get().software_versions,
231
+ "dm_Platform_release_superbee-FW23.1-SB",
232
+ )
233
+ self.assertEqual(
234
+ studies[1].generalequipmentmoduleattr_set.get().software_versions,
235
+ "4.0.3.B8.P6",
236
+ )
237
+ self.assertEqual(
238
+ studies[1].generalequipmentmoduleattr_set.get().device_serial_number,
239
+ "00012345abc",
240
+ )
241
+
242
+ # Test the SOP instance UIDs have been recorded correctly
243
+ sop_instance_uid_list0 = Counter(
244
+ studies[0].objectuidsprocessed_set.values_list(
245
+ "sop_instance_uid", flat=True
246
+ )
247
+ )
248
+ sop_instance_uid_list1 = Counter(
249
+ studies[1].objectuidsprocessed_set.values_list(
250
+ "sop_instance_uid", flat=True
251
+ )
252
+ )
253
+ uid_list0 = Counter(
254
+ [
255
+ "1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.20.0",
256
+ "1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.26.0",
257
+ "1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.28.0",
258
+ ]
259
+ )
260
+ uid_list1 = Counter(
261
+ [
262
+ "1.2.276.0.7230010.3.1.4.8323329.11838.1483692281.541544",
263
+ "1.2.276.0.7230010.3.1.4.8323329.11853.1483692311.916929",
264
+ ]
265
+ )
266
+ self.assertEqual(sop_instance_uid_list0, uid_list0)
267
+ self.assertEqual(sop_instance_uid_list1, uid_list1)
268
+
269
+ # Test that patient level data is recorded correctly
270
+ self.assertEqual(
271
+ studies[0].patientmoduleattr_set.get().patient_name, "XR220^Samantha"
272
+ )
273
+ self.assertEqual(
274
+ studies[1].patientmoduleattr_set.get().patient_name, "PHYSICS^TABLE AEC"
275
+ )
276
+ self.assertEqual(studies[0].patientmoduleattr_set.get().patient_id, "00098765")
277
+ self.assertEqual(
278
+ studies[1].patientmoduleattr_set.get().patient_id, "PHY12320140620YU"
279
+ )
280
+ self.assertEqual(
281
+ studies[0].patientmoduleattr_set.get().patient_birth_date,
282
+ datetime.date(1957, 11, 12),
283
+ )
284
+ self.assertEqual(
285
+ studies[1].patientmoduleattr_set.get().patient_birth_date,
286
+ datetime.date(2014, 6, 20),
287
+ )
288
+ self.assertAlmostEqual(
289
+ float(studies[0].patientstudymoduleattr_set.get().patient_age_decimal),
290
+ 56.9,
291
+ )
292
+
293
+ # Test that irradiation event data is stored correctly
294
+ self.assertEqual(
295
+ studies[0]
296
+ .projectionxrayradiationdose_set.get()
297
+ .irradeventxraydata_set.order_by("id")[0]
298
+ .acquisition_protocol,
299
+ "ABD_1_VIEW",
300
+ )
301
+ self.assertEqual(
302
+ studies[0]
303
+ .projectionxrayradiationdose_set.get()
304
+ .irradeventxraydata_set.order_by("id")[1]
305
+ .acquisition_protocol,
306
+ "ABD_1_VIEW",
307
+ )
308
+ self.assertEqual(
309
+ studies[0]
310
+ .projectionxrayradiationdose_set.get()
311
+ .irradeventxraydata_set.order_by("id")[2]
312
+ .acquisition_protocol,
313
+ "ABD_1_VIEW",
314
+ )
315
+ self.assertAlmostEqual(
316
+ float(
317
+ studies[0]
318
+ .projectionxrayradiationdose_set.get()
319
+ .irradeventxraydata_set.order_by("id")[0]
320
+ .dose_area_product
321
+ ),
322
+ (0.41 / 100000),
323
+ )
324
+ self.assertAlmostEqual(
325
+ float(
326
+ studies[0]
327
+ .projectionxrayradiationdose_set.get()
328
+ .irradeventxraydata_set.order_by("id")[1]
329
+ .dose_area_product
330
+ ),
331
+ (0.82 / 100000),
332
+ )
333
+ self.assertAlmostEqual(
334
+ float(
335
+ studies[0]
336
+ .projectionxrayradiationdose_set.get()
337
+ .irradeventxraydata_set.order_by("id")[2]
338
+ .dose_area_product
339
+ ),
340
+ (2.05 / 100000),
341
+ )
342
+
343
+ self.assertEqual(
344
+ studies[1]
345
+ .projectionxrayradiationdose_set.get()
346
+ .irradeventxraydata_set.order_by("id")[0]
347
+ .acquisition_protocol,
348
+ "AEC",
349
+ )
350
+ self.assertEqual(
351
+ studies[1]
352
+ .projectionxrayradiationdose_set.get()
353
+ .irradeventxraydata_set.order_by("id")[1]
354
+ .acquisition_protocol,
355
+ "AEC",
356
+ )
357
+ self.assertAlmostEqual(
358
+ float(
359
+ studies[1]
360
+ .projectionxrayradiationdose_set.get()
361
+ .irradeventxraydata_set.order_by("id")[0]
362
+ .dose_area_product
363
+ ),
364
+ (11.013 / 100000),
365
+ )
366
+ self.assertAlmostEqual(
367
+ float(
368
+ studies[1]
369
+ .projectionxrayradiationdose_set.get()
370
+ .irradeventxraydata_set.order_by("id")[1]
371
+ .dose_area_product
372
+ ),
373
+ (10.157 / 100000),
374
+ )
375
+
376
+ # Check that dose related distance measurement data is stored correctly
377
+ self.assertAlmostEqual(
378
+ float(
379
+ studies[1]
380
+ .projectionxrayradiationdose_set.get()
381
+ .irradeventxraydata_set.order_by("id")[0]
382
+ .irradeventxraymechanicaldata_set.get()
383
+ .doserelateddistancemeasurements_set.get()
384
+ .distance_source_to_detector
385
+ ),
386
+ (11.5 * 100),
387
+ )
388
+ self.assertAlmostEqual(
389
+ float(
390
+ studies[1]
391
+ .projectionxrayradiationdose_set.get()
392
+ .irradeventxraydata_set.order_by("id")[1]
393
+ .irradeventxraymechanicaldata_set.get()
394
+ .doserelateddistancemeasurements_set.get()
395
+ .distance_source_to_detector
396
+ ),
397
+ (11.5 * 100),
398
+ )
399
+
400
+ # Test that irradiation event source data is stored correctly
401
+ self.assertAlmostEqual(
402
+ float(
403
+ studies[0]
404
+ .projectionxrayradiationdose_set.get()
405
+ .irradeventxraydata_set.order_by("id")[0]
406
+ .irradeventxraysourcedata_set.get()
407
+ .exposure_time
408
+ ),
409
+ 6,
410
+ )
411
+ self.assertAlmostEqual(
412
+ float(
413
+ studies[0]
414
+ .projectionxrayradiationdose_set.get()
415
+ .irradeventxraydata_set.order_by("id")[1]
416
+ .irradeventxraysourcedata_set.get()
417
+ .exposure_time
418
+ ),
419
+ 11,
420
+ )
421
+ self.assertAlmostEqual(
422
+ float(
423
+ studies[0]
424
+ .projectionxrayradiationdose_set.get()
425
+ .irradeventxraydata_set.order_by("id")[2]
426
+ .irradeventxraysourcedata_set.get()
427
+ .exposure_time
428
+ ),
429
+ 27,
430
+ )
431
+ self.assertAlmostEqual(
432
+ float(
433
+ studies[0]
434
+ .projectionxrayradiationdose_set.get()
435
+ .irradeventxraydata_set.order_by("id")[0]
436
+ .irradeventxraysourcedata_set.get()
437
+ .average_xray_tube_current
438
+ ),
439
+ 189,
440
+ )
441
+ self.assertAlmostEqual(
442
+ float(
443
+ studies[0]
444
+ .projectionxrayradiationdose_set.get()
445
+ .irradeventxraydata_set.order_by("id")[0]
446
+ .irradeventxraysourcedata_set.get()
447
+ .focal_spot_size
448
+ ),
449
+ 0.6,
450
+ )
451
+ self.assertAlmostEqual(
452
+ float(
453
+ studies[0]
454
+ .projectionxrayradiationdose_set.get()
455
+ .irradeventxraydata_set.order_by("id")[1]
456
+ .irradeventxraysourcedata_set.get()
457
+ .focal_spot_size
458
+ ),
459
+ 0.6,
460
+ )
461
+ self.assertAlmostEqual(
462
+ float(
463
+ studies[0]
464
+ .projectionxrayradiationdose_set.get()
465
+ .irradeventxraydata_set.order_by("id")[2]
466
+ .irradeventxraysourcedata_set.get()
467
+ .focal_spot_size
468
+ ),
469
+ 0.6,
470
+ )
471
+
472
+ self.assertAlmostEqual(
473
+ float(
474
+ studies[1]
475
+ .projectionxrayradiationdose_set.get()
476
+ .irradeventxraydata_set.order_by("id")[0]
477
+ .irradeventxraysourcedata_set.get()
478
+ .exposure_time
479
+ ),
480
+ 19,
481
+ )
482
+ self.assertAlmostEqual(
483
+ float(
484
+ studies[1]
485
+ .projectionxrayradiationdose_set.get()
486
+ .irradeventxraydata_set.order_by("id")[1]
487
+ .irradeventxraysourcedata_set.get()
488
+ .exposure_time
489
+ ),
490
+ 18,
491
+ )
492
+ self.assertAlmostEqual(
493
+ float(
494
+ studies[1]
495
+ .projectionxrayradiationdose_set.get()
496
+ .irradeventxraydata_set.order_by("id")[0]
497
+ .irradeventxraysourcedata_set.get()
498
+ .focal_spot_size
499
+ ),
500
+ 1.2,
501
+ )
502
+ self.assertAlmostEqual(
503
+ float(
504
+ studies[1]
505
+ .projectionxrayradiationdose_set.get()
506
+ .irradeventxraydata_set.order_by("id")[1]
507
+ .irradeventxraysourcedata_set.get()
508
+ .focal_spot_size
509
+ ),
510
+ 1.2,
511
+ )
512
+
513
+ self.assertAlmostEqual(
514
+ float(
515
+ studies[0]
516
+ .projectionxrayradiationdose_set.get()
517
+ .irradeventxraydata_set.order_by("id")[0]
518
+ .irradeventxraysourcedata_set.get()
519
+ .average_xray_tube_current
520
+ ),
521
+ 189,
522
+ )
523
+ self.assertAlmostEqual(
524
+ float(
525
+ studies[0]
526
+ .projectionxrayradiationdose_set.get()
527
+ .irradeventxraydata_set.order_by("id")[1]
528
+ .irradeventxraysourcedata_set.get()
529
+ .average_xray_tube_current
530
+ ),
531
+ 192,
532
+ )
533
+ self.assertAlmostEqual(
534
+ float(
535
+ studies[0]
536
+ .projectionxrayradiationdose_set.get()
537
+ .irradeventxraydata_set.order_by("id")[2]
538
+ .irradeventxraysourcedata_set.get()
539
+ .average_xray_tube_current
540
+ ),
541
+ 190,
542
+ )
543
+
544
+ self.assertAlmostEqual(
545
+ float(
546
+ studies[1]
547
+ .projectionxrayradiationdose_set.get()
548
+ .irradeventxraydata_set.order_by("id")[0]
549
+ .irradeventxraysourcedata_set.get()
550
+ .average_xray_tube_current
551
+ ),
552
+ 500,
553
+ )
554
+ self.assertAlmostEqual(
555
+ float(
556
+ studies[1]
557
+ .projectionxrayradiationdose_set.get()
558
+ .irradeventxraydata_set.order_by("id")[1]
559
+ .irradeventxraysourcedata_set.get()
560
+ .average_xray_tube_current
561
+ ),
562
+ 500,
563
+ )
564
+
565
+ self.assertEqual(
566
+ studies[1]
567
+ .projectionxrayradiationdose_set.get()
568
+ .irradeventxraydata_set.order_by("id")[0]
569
+ .irradeventxraysourcedata_set.get()
570
+ .xrayfilters_set.get()
571
+ .xray_filter_material.code_meaning,
572
+ "Aluminum or Aluminum compound",
573
+ )
574
+ self.assertAlmostEqual(
575
+ float(
576
+ studies[1]
577
+ .projectionxrayradiationdose_set.get()
578
+ .irradeventxraydata_set.order_by("id")[0]
579
+ .irradeventxraysourcedata_set.get()
580
+ .xrayfilters_set.get()
581
+ .xray_filter_thickness_minimum
582
+ ),
583
+ 0.94,
584
+ )
585
+ self.assertAlmostEqual(
586
+ float(
587
+ studies[1]
588
+ .projectionxrayradiationdose_set.get()
589
+ .irradeventxraydata_set.order_by("id")[0]
590
+ .irradeventxraysourcedata_set.get()
591
+ .xrayfilters_set.get()
592
+ .xray_filter_thickness_maximum
593
+ ),
594
+ 1.06,
595
+ )
596
+
597
+ self.assertEqual(
598
+ studies[1]
599
+ .projectionxrayradiationdose_set.get()
600
+ .irradeventxraydata_set.order_by("id")[1]
601
+ .irradeventxraysourcedata_set.get()
602
+ .xrayfilters_set.order_by("id")[0]
603
+ .xray_filter_material.code_meaning,
604
+ "Aluminum or Aluminum compound",
605
+ )
606
+ self.assertAlmostEqual(
607
+ float(
608
+ studies[1]
609
+ .projectionxrayradiationdose_set.get()
610
+ .irradeventxraydata_set.order_by("id")[1]
611
+ .irradeventxraysourcedata_set.get()
612
+ .xrayfilters_set.order_by("id")[0]
613
+ .xray_filter_thickness_minimum
614
+ ),
615
+ 0.94,
616
+ )
617
+ self.assertAlmostEqual(
618
+ float(
619
+ studies[1]
620
+ .projectionxrayradiationdose_set.get()
621
+ .irradeventxraydata_set.order_by("id")[1]
622
+ .irradeventxraysourcedata_set.get()
623
+ .xrayfilters_set.order_by("id")[0]
624
+ .xray_filter_thickness_maximum
625
+ ),
626
+ 1.06,
627
+ )
628
+
629
+ self.assertEqual(
630
+ studies[1]
631
+ .projectionxrayradiationdose_set.get()
632
+ .irradeventxraydata_set.order_by("id")[1]
633
+ .irradeventxraysourcedata_set.get()
634
+ .xrayfilters_set.order_by("id")[1]
635
+ .xray_filter_material.code_meaning,
636
+ "Copper or Copper compound",
637
+ )
638
+ self.assertAlmostEqual(
639
+ float(
640
+ studies[1]
641
+ .projectionxrayradiationdose_set.get()
642
+ .irradeventxraydata_set.order_by("id")[1]
643
+ .irradeventxraysourcedata_set.get()
644
+ .xrayfilters_set.order_by("id")[1]
645
+ .xray_filter_thickness_minimum
646
+ ),
647
+ 0.194,
648
+ )
649
+ self.assertAlmostEqual(
650
+ float(
651
+ studies[1]
652
+ .projectionxrayradiationdose_set.get()
653
+ .irradeventxraydata_set.order_by("id")[1]
654
+ .irradeventxraysourcedata_set.get()
655
+ .xrayfilters_set.order_by("id")[1]
656
+ .xray_filter_thickness_maximum
657
+ ),
658
+ 0.206,
659
+ )
660
+
661
+ self.assertAlmostEqual(
662
+ float(
663
+ studies[1]
664
+ .projectionxrayradiationdose_set.get()
665
+ .irradeventxraydata_set.order_by("id")[0]
666
+ .irradeventxraysourcedata_set.get()
667
+ .grid_focal_distance
668
+ ),
669
+ 1828.8,
670
+ )
671
+ self.assertAlmostEqual(
672
+ float(
673
+ studies[1]
674
+ .projectionxrayradiationdose_set.get()
675
+ .irradeventxraydata_set.order_by("id")[1]
676
+ .irradeventxraysourcedata_set.get()
677
+ .grid_focal_distance
678
+ ),
679
+ 1828.8,
680
+ )
681
+
682
+ # Test exposure data is stored correctly
683
+ self.assertAlmostEqual(
684
+ float(
685
+ studies[0]
686
+ .projectionxrayradiationdose_set.get()
687
+ .irradeventxraydata_set.order_by("id")[0]
688
+ .irradeventxraysourcedata_set.get()
689
+ .exposure_set.get()
690
+ .exposure
691
+ ),
692
+ 1040,
693
+ )
694
+ self.assertAlmostEqual(
695
+ float(
696
+ studies[0]
697
+ .projectionxrayradiationdose_set.get()
698
+ .irradeventxraydata_set.order_by("id")[1]
699
+ .irradeventxraysourcedata_set.get()
700
+ .exposure_set.get()
701
+ .exposure
702
+ ),
703
+ 2040,
704
+ )
705
+ self.assertAlmostEqual(
706
+ float(
707
+ studies[0]
708
+ .projectionxrayradiationdose_set.get()
709
+ .irradeventxraydata_set.order_by("id")[2]
710
+ .irradeventxraysourcedata_set.get()
711
+ .exposure_set.get()
712
+ .exposure
713
+ ),
714
+ 5040,
715
+ )
716
+
717
+ self.assertAlmostEqual(
718
+ float(
719
+ studies[1]
720
+ .projectionxrayradiationdose_set.get()
721
+ .irradeventxraydata_set.order_by("id")[0]
722
+ .irradeventxraysourcedata_set.get()
723
+ .exposure_set.get()
724
+ .exposure
725
+ ),
726
+ (10 * 1000),
727
+ )
728
+ self.assertAlmostEqual(
729
+ float(
730
+ studies[1]
731
+ .projectionxrayradiationdose_set.get()
732
+ .irradeventxraydata_set.order_by("id")[1]
733
+ .irradeventxraysourcedata_set.get()
734
+ .exposure_set.get()
735
+ .exposure
736
+ ),
737
+ (9 * 1000),
738
+ )
739
+
740
+ # Test that irradiation event detector data is stored correctly
741
+ self.assertAlmostEqual(
742
+ float(
743
+ studies[0]
744
+ .projectionxrayradiationdose_set.get()
745
+ .irradeventxraydata_set.order_by("id")[0]
746
+ .irradeventxraydetectordata_set.get()
747
+ .exposure_index
748
+ ),
749
+ 51.745061,
750
+ )
751
+ self.assertAlmostEqual(
752
+ float(
753
+ studies[0]
754
+ .projectionxrayradiationdose_set.get()
755
+ .irradeventxraydata_set.order_by("id")[1]
756
+ .irradeventxraydetectordata_set.get()
757
+ .exposure_index
758
+ ),
759
+ 108.843060,
760
+ )
761
+ self.assertAlmostEqual(
762
+ float(
763
+ studies[0]
764
+ .projectionxrayradiationdose_set.get()
765
+ .irradeventxraydata_set.order_by("id")[2]
766
+ .irradeventxraydetectordata_set.get()
767
+ .exposure_index
768
+ ),
769
+ 286.828227,
770
+ )
771
+
772
+ self.assertAlmostEqual(
773
+ float(
774
+ studies[0]
775
+ .projectionxrayradiationdose_set.get()
776
+ .irradeventxraydata_set.order_by("id")[0]
777
+ .irradeventxraydetectordata_set.get()
778
+ .target_exposure_index
779
+ ),
780
+ 438.469173,
781
+ )
782
+ self.assertAlmostEqual(
783
+ float(
784
+ studies[0]
785
+ .projectionxrayradiationdose_set.get()
786
+ .irradeventxraydata_set.order_by("id")[1]
787
+ .irradeventxraydetectordata_set.get()
788
+ .target_exposure_index
789
+ ),
790
+ 438.469173,
791
+ )
792
+ self.assertAlmostEqual(
793
+ float(
794
+ studies[0]
795
+ .projectionxrayradiationdose_set.get()
796
+ .irradeventxraydata_set.order_by("id")[2]
797
+ .irradeventxraydetectordata_set.get()
798
+ .target_exposure_index
799
+ ),
800
+ 438.469173,
801
+ )
802
+
803
+ self.assertAlmostEqual(
804
+ float(
805
+ studies[0]
806
+ .projectionxrayradiationdose_set.get()
807
+ .irradeventxraydata_set.order_by("id")[0]
808
+ .irradeventxraydetectordata_set.get()
809
+ .deviation_index
810
+ ),
811
+ (-9.3),
812
+ )
813
+ self.assertAlmostEqual(
814
+ float(
815
+ studies[0]
816
+ .projectionxrayradiationdose_set.get()
817
+ .irradeventxraydata_set.order_by("id")[1]
818
+ .irradeventxraydetectordata_set.get()
819
+ .deviation_index
820
+ ),
821
+ (-6.1),
822
+ )
823
+ self.assertAlmostEqual(
824
+ float(
825
+ studies[0]
826
+ .projectionxrayradiationdose_set.get()
827
+ .irradeventxraydata_set.order_by("id")[2]
828
+ .irradeventxraydetectordata_set.get()
829
+ .deviation_index
830
+ ),
831
+ (-1.8),
832
+ )
833
+
834
+ self.assertAlmostEqual(
835
+ float(
836
+ studies[0]
837
+ .projectionxrayradiationdose_set.get()
838
+ .irradeventxraydata_set.order_by("id")[0]
839
+ .irradeventxraydetectordata_set.get()
840
+ .sensitivity
841
+ ),
842
+ 97.213916,
843
+ )
844
+ self.assertAlmostEqual(
845
+ float(
846
+ studies[0]
847
+ .projectionxrayradiationdose_set.get()
848
+ .irradeventxraydata_set.order_by("id")[1]
849
+ .irradeventxraydetectordata_set.get()
850
+ .sensitivity
851
+ ),
852
+ 97.213916,
853
+ )
854
+ self.assertAlmostEqual(
855
+ float(
856
+ studies[0]
857
+ .projectionxrayradiationdose_set.get()
858
+ .irradeventxraydata_set.order_by("id")[2]
859
+ .irradeventxraydetectordata_set.get()
860
+ .sensitivity
861
+ ),
862
+ 97.213916,
863
+ )
864
+
865
+ self.assertAlmostEqual(
866
+ float(
867
+ studies[1]
868
+ .projectionxrayradiationdose_set.get()
869
+ .irradeventxraydata_set.order_by("id")[0]
870
+ .irradeventxraydetectordata_set.get()
871
+ .relative_xray_exposure
872
+ ),
873
+ 1460,
874
+ )
875
+ self.assertAlmostEqual(
876
+ float(
877
+ studies[1]
878
+ .projectionxrayradiationdose_set.get()
879
+ .irradeventxraydata_set.order_by("id")[1]
880
+ .irradeventxraydetectordata_set.get()
881
+ .relative_xray_exposure
882
+ ),
883
+ 1430,
884
+ )
885
+
886
+ # Test summary fields
887
+ self.assertAlmostEqual(float(studies[0].total_dap_a), (3.28 / 100000))
888
+ self.assertAlmostEqual(float(studies[0].total_dap), (3.28 / 100000))
889
+ self.assertEqual(studies[0].number_of_events, 3)
890
+ self.assertEqual(studies[0].number_of_planes, 1)
891
+ self.assertAlmostEqual(float(studies[1].total_dap_a), (21.17 / 100000))
892
+ self.assertAlmostEqual(float(studies[1].total_dap), (21.17 / 100000))
893
+ self.assertEqual(studies[1].number_of_events, 2)
894
+ self.assertEqual(studies[1].number_of_planes, 1)
895
+
896
+ def test_filter_thickness_order(self):
897
+
898
+ all_filters = XrayFilters.objects.order_by("id")
899
+ for exposure in all_filters:
900
+ self.assertGreaterEqual(
901
+ exposure.xray_filter_thickness_maximum,
902
+ exposure.xray_filter_thickness_minimum,
903
+ )
904
+
905
+ def test_multiple_filter_carestream_comma(self):
906
+ """
907
+ Testing the DR7500 file can be imported with illegal comma separated floats
908
+ :return: None
909
+ """
910
+
911
+ study = GeneralStudyModuleAttr.objects.order_by("id")[1]
912
+
913
+ source = (
914
+ study.projectionxrayradiationdose_set.get()
915
+ .irradeventxraydata_set.order_by("id")[1]
916
+ .irradeventxraysourcedata_set.get()
917
+ )
918
+
919
+ self.assertEqual(
920
+ source.xrayfilters_set.order_by("id").count(),
921
+ 2,
922
+ "Testing Kodak old style, two filters should have been stored, {0} were".format(
923
+ source.xrayfilters_set.order_by("id").count()
924
+ ),
925
+ )
926
+ self.assertEqual(
927
+ source.xrayfilters_set.order_by("id")[0].xray_filter_material.code_meaning,
928
+ "Aluminum or Aluminum compound",
929
+ )
930
+ self.assertAlmostEqual(
931
+ float(
932
+ source.xrayfilters_set.order_by("id")[0].xray_filter_thickness_minimum
933
+ ),
934
+ 0.94,
935
+ )
936
+ self.assertEqual(
937
+ source.xrayfilters_set.order_by("id")[1].xray_filter_material.code_meaning,
938
+ "Copper or Copper compound",
939
+ )
940
+ self.assertAlmostEqual(
941
+ float(
942
+ source.xrayfilters_set.order_by("id")[1].xray_filter_thickness_minimum
943
+ ),
944
+ 0.194,
945
+ )
946
+
947
+ def test_standard_acquisition_names(self):
948
+ """
949
+ Testing that all images within the GE 220 study have the correct standard acquisition name.
950
+ All three images within this study should have the standard study name "AbdoView".
951
+ :return: None
952
+ """
953
+ study = GeneralStudyModuleAttr.objects.filter(
954
+ procedure_code_meaning="ABD_1_VIEW"
955
+ )[0]
956
+
957
+ irradiations = (
958
+ study.projectionxrayradiationdose_set.get().irradeventxraydata_set.all()
959
+ )
960
+
961
+ for irradiation in irradiations:
962
+ std_acq_names = irradiation.standard_protocols.all()
963
+
964
+ for std_acq_name in std_acq_names:
965
+ self.assertEqual(std_acq_name.standard_name, "AbdoView")
966
+
967
+
968
+ class ImportCarestreamDRXRevolution(TestCase):
969
+ def setUp(self):
970
+ """
971
+ Imports a known radigraphic image file derived from a Carestream DRX Revolution image.
972
+ """
973
+
974
+ pid = PatientIDSettings.objects.create()
975
+ pid.name_stored = True
976
+ pid.name_hashed = False
977
+ pid.id_stored = True
978
+ pid.id_hashed = False
979
+ pid.dob_stored = True
980
+ pid.save()
981
+
982
+ dx_carestream_drx_revolution = os.path.join(
983
+ "test_files", "DX-Im-Carestream_DRX.dcm"
984
+ )
985
+ root_tests = os.path.dirname(os.path.abspath(__file__))
986
+ dx.dx(os.path.join(root_tests, dx_carestream_drx_revolution))
987
+
988
+ def test_requested_procedure_name(self):
989
+ """
990
+ Tests the imported value of requested procedure code meaning against what is expected.
991
+ """
992
+ study = GeneralStudyModuleAttr.objects.order_by("id")[0]
993
+
994
+ self.assertEqual(study.requested_procedure_code_meaning, "XR CHEST")
995
+
996
+
997
+ class ImportDuplicateDX(TestCase):
998
+ def setUp(self):
999
+ """"""
1000
+
1001
+ pid = PatientIDSettings.objects.create()
1002
+ pid.name_stored = True
1003
+ pid.name_hashed = False
1004
+ pid.id_stored = True
1005
+ pid.id_hashed = False
1006
+ pid.dob_stored = True
1007
+ pid.save()
1008
+
1009
+ dx_ge_xr220_1 = os.path.join("test_files", "DX-Im-GE_XR220-1.dcm")
1010
+ root_tests = os.path.dirname(os.path.abspath(__file__))
1011
+
1012
+ dx.dx(os.path.join(root_tests, dx_ge_xr220_1))
1013
+ study_one = GeneralStudyModuleAttr.objects.order_by("pk")[0]
1014
+ original_study_uid = study_one.study_instance_uid
1015
+ original_sop_instance_uid = (
1016
+ study_one.projectionxrayradiationdose_set.get()
1017
+ .irradeventxraydata_set.get()
1018
+ .irradiation_event_uid
1019
+ )
1020
+ study_one.study_instance_uid = "1.2.3.4.5.6.7.8"
1021
+ study_one.projectionxrayradiationdose_set.get().irradeventxraydata_set.get().irradiation_event_uid = (
1022
+ "2.3.4.5.6.7.8.9"
1023
+ )
1024
+ study_one.save()
1025
+
1026
+ # Check there is one study in the database
1027
+ self.assertEqual(GeneralStudyModuleAttr.objects.all().count(), 1)
1028
+
1029
+ # Import the image again...
1030
+ dx.dx(os.path.join(root_tests, dx_ge_xr220_1))
1031
+
1032
+ # Check there are two studies now
1033
+ self.assertEqual(GeneralStudyModuleAttr.objects.all().count(), 2)
1034
+
1035
+ study_one.study_instance_uid = original_study_uid
1036
+ study_one.projectionxrayradiationdose_set.get().irradeventxraydata_set.get().irradiation_event_uid = (
1037
+ original_sop_instance_uid
1038
+ )
1039
+ study_one.save()
1040
+
1041
+ # Now we are ready to test import with duplicate study UIDs.
1042
+
1043
+ def test_duplicate_study_dx(self):
1044
+ """Imports second image, original two both have modality set."""
1045
+
1046
+ dx_ge_xr220_2 = os.path.join("test_files", "DX-Im-GE_XR220-2.dcm")
1047
+ root_tests = os.path.dirname(os.path.abspath(__file__))
1048
+
1049
+ self.assertEqual(GeneralStudyModuleAttr.objects.all().count(), 2)
1050
+
1051
+ study_1_pk = GeneralStudyModuleAttr.objects.order_by("pk").first().pk
1052
+
1053
+ with LogCapture("remapp.extractors", level=logging.DEBUG) as log:
1054
+ dx.dx(os.path.join(root_tests, dx_ge_xr220_2))
1055
+
1056
+ log.check_present(
1057
+ (
1058
+ "remapp.extractors.dx",
1059
+ "WARNING",
1060
+ "Duplicate DX study UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.24.0 in "
1061
+ "database - could be a problem! There are 2 copies.",
1062
+ ),
1063
+ (
1064
+ "remapp.extractors.dx",
1065
+ "DEBUG",
1066
+ "Duplicate DX study UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.24.0 - "
1067
+ "first instance (pk={0}) with modality type assigned (DX) selected to import new event "
1068
+ "into.".format(study_1_pk),
1069
+ ),
1070
+ )
1071
+
1072
+ number_of_events_study_1 = (
1073
+ GeneralStudyModuleAttr.objects.order_by("pk")
1074
+ .first()
1075
+ .projectionxrayradiationdose_set.get()
1076
+ .irradeventxraydata_set.all()
1077
+ .count()
1078
+ )
1079
+ self.assertEqual(number_of_events_study_1, 2)
1080
+ number_of_events_study_2 = (
1081
+ GeneralStudyModuleAttr.objects.order_by("pk")[1]
1082
+ .projectionxrayradiationdose_set.get()
1083
+ .irradeventxraydata_set.all()
1084
+ .count()
1085
+ )
1086
+ self.assertEqual(number_of_events_study_2, 1)
1087
+
1088
+ def test_duplicate_study_dx_second_mod(self):
1089
+ """Imports second image, later existing has modality set."""
1090
+
1091
+ dx_ge_xr220_2 = os.path.join("test_files", "DX-Im-GE_XR220-2.dcm")
1092
+ root_tests = os.path.dirname(os.path.abspath(__file__))
1093
+
1094
+ self.assertEqual(GeneralStudyModuleAttr.objects.all().count(), 2)
1095
+
1096
+ # Set first study modality to None
1097
+ study_1 = GeneralStudyModuleAttr.objects.order_by("pk").first()
1098
+ study_1.modality_type = None
1099
+ study_1.save()
1100
+
1101
+ study_2_pk = GeneralStudyModuleAttr.objects.order_by("pk")[1].pk
1102
+
1103
+ with LogCapture("remapp.extractors", level=logging.DEBUG) as log:
1104
+ dx.dx(os.path.join(root_tests, dx_ge_xr220_2))
1105
+
1106
+ log.check_present(
1107
+ (
1108
+ "remapp.extractors.dx",
1109
+ "WARNING",
1110
+ "Duplicate DX study UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.24.0 in "
1111
+ "database - could be a problem! There are 2 copies.",
1112
+ ),
1113
+ (
1114
+ "remapp.extractors.dx",
1115
+ "DEBUG",
1116
+ "Duplicate DX study UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.24.0 - "
1117
+ "first instance (pk={0}) with modality type assigned (DX) selected to import new event "
1118
+ "into.".format(study_2_pk),
1119
+ ),
1120
+ )
1121
+
1122
+ number_of_events_study_1 = (
1123
+ GeneralStudyModuleAttr.objects.order_by("pk")
1124
+ .first()
1125
+ .projectionxrayradiationdose_set.get()
1126
+ .irradeventxraydata_set.all()
1127
+ .count()
1128
+ )
1129
+ self.assertEqual(number_of_events_study_1, 1)
1130
+ number_of_events_study_2 = (
1131
+ GeneralStudyModuleAttr.objects.order_by("pk")[1]
1132
+ .projectionxrayradiationdose_set.get()
1133
+ .irradeventxraydata_set.all()
1134
+ .count()
1135
+ )
1136
+ self.assertEqual(number_of_events_study_2, 2)
1137
+
1138
+ def test_duplicate_study_dx_no_mod(self):
1139
+ """Imports second image, original two don't have modality set."""
1140
+
1141
+ dx_ge_xr220_2 = os.path.join("test_files", "DX-Im-GE_XR220-2.dcm")
1142
+ root_tests = os.path.dirname(os.path.abspath(__file__))
1143
+
1144
+ self.assertEqual(GeneralStudyModuleAttr.objects.all().count(), 2)
1145
+
1146
+ # Set modality type to None
1147
+ for study in GeneralStudyModuleAttr.objects.order_by("pk"):
1148
+ study.modality_type = None
1149
+ study.save()
1150
+
1151
+ with LogCapture("remapp.extractors", level=logging.DEBUG) as log:
1152
+ dx.dx(os.path.join(root_tests, dx_ge_xr220_2))
1153
+
1154
+ log.check_present(
1155
+ (
1156
+ "remapp.extractors.dx",
1157
+ "WARNING",
1158
+ "Duplicate DX study UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.24.0 in "
1159
+ "database - could be a problem! There are 2 copies.",
1160
+ ),
1161
+ (
1162
+ "remapp.extractors.dx",
1163
+ "WARNING",
1164
+ "Duplicate DX study UID 1.3.6.1.4.1.5962.99.1.2282339064.1266597797.1479751121656.24.0, "
1165
+ "none of which have modality_type assigned! Setting first instance to DX",
1166
+ ),
1167
+ )
1168
+
1169
+ number_of_events_study_1 = (
1170
+ GeneralStudyModuleAttr.objects.order_by("pk")
1171
+ .first()
1172
+ .projectionxrayradiationdose_set.get()
1173
+ .irradeventxraydata_set.all()
1174
+ .count()
1175
+ )
1176
+ self.assertEqual(number_of_events_study_1, 2)
1177
+ number_of_events_study_2 = (
1178
+ GeneralStudyModuleAttr.objects.order_by("pk")[1]
1179
+ .projectionxrayradiationdose_set.get()
1180
+ .irradeventxraydata_set.all()
1181
+ .count()
1182
+ )
1183
+ self.assertEqual(number_of_events_study_2, 1)
1184
+
1185
+
1186
+ class ImportSiemensDX(TestCase):
1187
+ def setUp(self):
1188
+ """
1189
+ Imports a known radigraphic image file derived from a Siemens MultixFD image.
1190
+ """
1191
+
1192
+ pid = PatientIDSettings.objects.create()
1193
+ pid.name_stored = True
1194
+ pid.name_hashed = False
1195
+ pid.id_stored = True
1196
+ pid.id_hashed = False
1197
+ pid.dob_stored = True
1198
+ pid.save()
1199
+
1200
+ dx_siemens_multix = os.path.join("test_files", "DX-Im-SiemensMultix.dcm")
1201
+ root_tests = os.path.dirname(os.path.abspath(__file__))
1202
+ dx.dx(os.path.join(root_tests, dx_siemens_multix))
1203
+
1204
+ def test_siemens_dx_filter_data(self):
1205
+ """Check filter type and thickness is extracted"""
1206
+ studies = GeneralStudyModuleAttr.objects.order_by("id")
1207
+
1208
+ # Test that one study have been imported
1209
+ self.assertEqual(studies.count(), 1)
1210
+
1211
+ self.assertEqual(
1212
+ studies[0]
1213
+ .projectionxrayradiationdose_set.get()
1214
+ .irradeventxraydata_set.order_by("id")[0]
1215
+ .irradeventxraysourcedata_set.get()
1216
+ .xrayfilters_set.get()
1217
+ .xray_filter_material.code_meaning,
1218
+ "Copper or Copper compound",
1219
+ )
1220
+ self.assertAlmostEqual(
1221
+ float(
1222
+ studies[0]
1223
+ .projectionxrayradiationdose_set.get()
1224
+ .irradeventxraydata_set.order_by("id")[0]
1225
+ .irradeventxraysourcedata_set.get()
1226
+ .xrayfilters_set.get()
1227
+ .xray_filter_thickness_minimum
1228
+ ),
1229
+ 0.2,
1230
+ )
1231
+ self.assertAlmostEqual(
1232
+ float(
1233
+ studies[0]
1234
+ .projectionxrayradiationdose_set.get()
1235
+ .irradeventxraydata_set.order_by("id")[0]
1236
+ .irradeventxraysourcedata_set.get()
1237
+ .xrayfilters_set.get()
1238
+ .xray_filter_thickness_maximum
1239
+ ),
1240
+ 0.2,
1241
+ )
1242
+
1243
+
1244
+ class ImportDRGEMDX(TestCase):
1245
+ def setUp(self):
1246
+ """
1247
+ Imports a known radigraphic image file derived from a DRGEM DIAMOND image.
1248
+ """
1249
+
1250
+ pid = PatientIDSettings.objects.create()
1251
+ pid.name_stored = True
1252
+ pid.name_hashed = False
1253
+ pid.id_stored = True
1254
+ pid.id_hashed = False
1255
+ pid.dob_stored = True
1256
+ pid.save()
1257
+
1258
+ dx_drgem = os.path.join("test_files", "DX-Im-DRGEM.dcm")
1259
+ root_tests = os.path.dirname(os.path.abspath(__file__))
1260
+ dx.dx(os.path.join(root_tests, dx_drgem))
1261
+
1262
+ def test_drgem_dx_exposure_data(self):
1263
+ """Check exposure information is extracted"""
1264
+ studies = GeneralStudyModuleAttr.objects.order_by("id")
1265
+
1266
+ # Test that one study have been imported
1267
+ self.assertEqual(studies.count(), 1)