a b/archives/RadETL/R/RadiologyDB.R
1
###################################### RadDB Class #############################################
2
#' RadDB Class
3
#'
4
#' This is a class that creates an RCDM using an extracted RDS file.
5
#' Parallel processing is supported only in the current Occurrence table,
6
#' and it is recommended that the image table not be processed in parallel
7
#' because of the computer science problem that the number of images in the image table does not match.
8
#' Even if you set Pararell through the constructor, it is not supported by the Image method.
9
#'
10
#' @param core Number of cores to use
11
#' @seealso https://github.com/OHDSI/Radiology-CDM/wiki
12
#' @author Neon K.I.D
13
#' @example Examples/RadDB_Ex.R
14
#' @export
15
RadDB <- R6::R6Class(classname = "RadDB",
16
  private = list(
17
    cl = NULL,
18
    needFunc = c('as.bigint', 'as.float', 'getDate', 'pastePath', 'private'),
19
    needPkg = c('RadETL', 'rapportools'),
20
    mergeDfList = function(x, y) merge(x, y, all = TRUE),
21
    createRCDMOccurrence = function(data, ocid, idp = 2) {
22
      for(i in 1:length(data)) {
23
        if(is.empty(data[[i]]))
24
          stop("ERROR: There is an empty value in the data frame.")
25
        else {
26
          dcmRDS <- DicomRDS$new(data = data[[i]], idp = idp)
27
28
          # Dirpath Settings
29
          # Temp code, if source code open, please modify...
30
          sp <- strsplit(as.character(data[[i]]$path[1]), '/')
31
          rDirPath <- head(unlist(sp), -1)
32
          rDirPath <- Reduce(pastePath, rDirPath)
33
          #rDirPath <- file.path(rDirPath)
34
35
          #roID <- dcmRDS$createOccurrenceID()
36
          roID <- ocid
37
          studyDatetime <- dcmRDS$getStudyDateTime()
38
39
          # Searching AcquisitionDateTime...
40
          duringTime <- ''
41
          for(k in length(data):i) {
42
            dcmRDSk <- DicomRDS$new(data = data[[k]], idp = idp)
43
            duringTime <- dcmRDSk$getDuringTime(studyDateTime = studyDatetime)
44
            if(!is.empty(duringTime)) break else duringTime <- NA
45
            dcmRDSk$finalize()
46
          }
47
48
          pID <- dcmRDS$getPatientID()
49
          if(is.na(pID) || is.character(pID)) pID <- dcmRDS$getDirectoryID()
50
          coID <- 0
51
          dcID <- dcmRDS$getDeviceID()
52
          modality <- dcmRDS$getModality()
53
          pocID <- dcmRDS$getPosition()
54
          oriID <- dcmRDS$getOrientation()
55
56
          # Contrast Information,,
57
          # Reference is RadEx v4.0
58
          # 28768: Imaging without iv contrast
59
          # 28771: Imaging without then with IV contrast
60
          rpcID <- 10392
61
          for(j in i:length(data)) {
62
            dcmRDSj <- DicomRDS$new(data[[j]], idp)
63
            if(dcmRDSj$isPost4BrainCT()) {
64
              rpcID <- 10371
65
              break
66
            }
67
            dcmRDSj$finalize()
68
          }
69
70
          tCount <- length(data)
71
          ascID <- 6434           # is Brain CT
72
          imgComment <- dcmRDS$getComment()
73
          dosage <- dcmRDS$getDosageunit(modality = modality)
74
          dosageNum <- dcmRDS$getDosage(dosageUnit = dosage)
75
          timeUnit <- "sec"
76
          voID <- 0
77
          break
78
        }
79
      }
80
81
      radiology_occurrence_ID <- as.bigint(roID, 4)
82
      radiology_occurrence_date <- as.Date(getDate(dcmRDS$getStudyDate()))
83
      radiology_occurrence_datetime <- as.POSIXct(studyDatetime)
84
85
      Person_ID <- as.bigint(pID, 4)
86
      Condition_occurrence_id <- as.integer(coID)
87
      Device_concept_id <- as.bigint(dcID, 4)
88
89
      radiology_modality_concept_ID <- modality  # VARCHAR -> int
90
      Person_position_concept_id <- pocID        # VARCHAR -> Int
91
      Person_orientation_concept <- oriID        # VARCHAR -> will deprecate
92
      radiology_protocol_concept_id <- rpcID     # VARCHAR -> int
93
94
      Image_total_count <- as.integer(tCount)
95
      Anatomic_site_concept_id <- as.integer(ascID)
96
      radiology_Comment <- imgComment
97
98
      Image_dosage_unit_concept <- dosage
99
      Dosage_value_as_number <- as.numeric(dosageNum)
100
      Image_exposure_time_unit_concept <- timeUnit
101
      Image_exposure_time <- as.float(x = duringTime, digits = 5)
102
103
      Radiology_dirpath <- rDirPath
104
      Visit_occurrence_id <- as.bigint(voID, 4)
105
106
      data.frame(
107
        radiology_occurrence_ID,
108
        radiology_occurrence_date,
109
        radiology_occurrence_datetime,
110
        Person_ID,
111
        Condition_occurrence_id,
112
        Device_concept_id,
113
        radiology_modality_concept_ID,
114
        # Person_orientation_concept,
115
        radiology_protocol_concept_id,
116
        Person_position_concept_id,
117
        Image_total_count,
118
        Anatomic_site_concept_id,
119
        radiology_Comment,
120
        Image_dosage_unit_concept,
121
        Dosage_value_as_number,
122
        Image_exposure_time_unit_concept,
123
        Image_exposure_time,
124
        Visit_occurrence_id,
125
        Radiology_dirpath,
126
        stringsAsFactors = FALSE
127
      )
128
    },
129
130
    createRCDMImage = function(data, ocid, idp, validpixelonly = FALSE) {
131
      Radiology_occurrence_ID <- c()
132
      Person_ID <- c()
133
      Person_orientation_concept <- c()
134
      Image_type <- c()
135
      Radiology_phase_concept_id <- c()
136
      Image_no <- c()
137
      Phase_total_no <- c()
138
      image_resolution_Rows <- c()
139
      image_Resolution_Columns <- c()
140
      Image_Window_Level_Center <- c()
141
      Image_Window_Level_Width <- c()
142
      Image_slice_thickness <- c()
143
      image_filepath <- c()
144
145
      num <- 1
146
      pNum <- 1
147
      rID <- NA
148
      reNum <- 1
149
150
      # Current imageType, radiology_phase_concept
151
      curimType <- NA
152
      curPCID <- NA
153
154
      for(i in 1:length(data)) {
155
        if(!is.null(data[[i]])) {
156
          dcmRDS <- DicomRDS$new(data[[i]], idp)
157
          if(validpixelonly) {
158
            if(!dcmRDS$isPixelData())
159
              next
160
          }
161
          Person_ID[num] <- as.bigint(dcmRDS$getDirectoryID(), 4)
162
163
          # PatientPosition is null .... blank
164
          pocID <- dcmRDS$getOrientation()
165
166
          # Get ImageType, ORIGINAL is PRIMARY, DERIVED is SECONDARY
167
          imType <- dcmRDS$getImageType()
168
          modality <- dcmRDS$getModality()
169
170
          # Reference is RadEx v4.0
171
          # 28833: Imaging without iv contrast
172
          # 28694: Imaging without then with IV contrast
173
          rpcID <- 28833
174
          if(pmatch(x = imType, "SECONDARY", nomatch = FALSE) == 1) rpcID <- 5901
175
          else if(dcmRDS$isPost4BrainCT()) rpcID <- 28694
176
177
          Radiology_phase_concept_id[num] <- rpcID
178
          thickness <- dcmRDS$getThickness()
179
          Phase_total_no[num] <- 0
180
181
          rows <- dcmRDS$getImgRows()
182
          columns <- dcmRDS$getImgCols()
183
184
          # Checking Phase number..
185
          if(num == 1) {
186
            rID <- ocid
187
            curimType <- imType
188
            curPCID <- rpcID
189
          } else if(is.na(pmatch(x = rpcID, curPCID, nomatch = NA_character_))
190
                    || is.na(pmatch(x = imType, curimType, nomatch = NA_character_))) {
191
            for(k in reNum:num)
192
              Phase_total_no[k] <- pNum - 1
193
194
            curimType <- imType
195
            curPCID <- rpcID
196
197
            reNum <- num
198
            pNum <- 1
199
          } else if(i == length(data)) {
200
            for(k in reNum:num)
201
              Phase_total_no[k] <- pNum
202
          }
203
204
          Image_no[num] <- as.integer(pNum)
205
          Radiology_occurrence_ID[num] <- as.bigint(rID, 4)
206
          image_resolution_Rows[num] <- as.integer(rows)
207
          image_Resolution_Columns[num] <- as.integer(columns)
208
          Image_Window_Level_Center[num] <- dcmRDS$getWindowCenter()
209
          Image_Window_Level_Width[num] <- dcmRDS$getWindowWidth()
210
          Image_slice_thickness[num] <- if(is.empty(thickness)) '' else as.numeric(thickness)
211
          Image_type[num] <- imType
212
          Person_orientation_concept[num] <- pocID
213
          image_filepath[num] <- as.character(data[[i]]$path[1])
214
215
          num <- num + 1
216
          pNum <- pNum + 1
217
        }
218
      }
219
220
      Radiology_Image <- data.frame(
221
        Radiology_occurrence_ID,
222
        Person_ID,
223
        # Person_orientation_concept,
224
        Image_type,
225
        Radiology_phase_concept_id,
226
        Image_no,
227
        Phase_total_no,
228
        image_resolution_Rows,
229
        image_Resolution_Columns,
230
        Image_Window_Level_Center,
231
        Image_Window_Level_Width,
232
        Image_slice_thickness,
233
        image_filepath,
234
        stringsAsFactors = FALSE
235
      )
236
      return(Radiology_Image)
237
    }
238
  ),
239
240
  public = list(
241
    initialize = function(core, logfile = NA) {
242
      library(foreach)
243
244
      if(is.na(logfile))
245
        logfile <- switch(getOS(), cpm = 'C:/TEMP/radiologyDB.log', '/tmp/radiologyDB.log')
246
247
      # Parallel Processing
248
      private$cl <- parallel::makePSOCKcluster(core, outfile = logfile)
249
      doSNOW::registerDoSNOW(private$cl)
250
    },
251
252
    createRadiologyDB = function(path, idp = 2, o_start = 1) {
253
      fileList <- list.files(path = path, recursive = T, full.names = T, pattern = "\\.rds$")
254
      pb <- txtProgressBar(min = 0, max = length(fileList), style = 3)
255
256
      progress <- function(n) setTxtProgressBar(pb, n)
257
      opts <- list(progress=progress)
258
259
      # Occurrence
260
      ro <- data.frame()
261
      writeLines('Create Radiology Occurrence Data frame....')
262
      ocid <- o_start - 1
263
      ro <- foreach(f = 1:length(fileList), .options.snow = opts, .packages = private$needPkg, .export = private$needFunc) %dopar% {
264
        data <- readRDS(file = fileList[f])
265
        Sys.sleep(0.01)
266
267
        ocid <- ocid + f
268
        private$createRCDMOccurrence(data = data, ocid = ocid, idp = idp)
269
      }
270
      res_ocur <- Reduce(private$mergeDfList, ro)
271
272
      # Image
273
      ri <- data.frame()
274
      writeLines('Create Radiology Image Data frame....')
275
      ocid <- o_start - 1
276
      ri <- foreach(f = 1:length(fileList), .options.snow = opts, .packages = private$needPkg, .export = private$needFunc) %dopar% {
277
        data <- readRDS(file = fileList[f])
278
        Sys.sleep(0.01)
279
280
        ocid <- ocid + f
281
        private$createRCDMImage(data = data, ocid = ocid, idp = idp)
282
      }
283
      res_img <- Reduce(private$mergeDfList, ri)
284
285
      return(list(res_ocur, res_img))
286
    },
287
288
    finalize = function() {
289
      parallel::stopCluster(cl = private$cl)  # Requirement
290
    }
291
  )
292
)
293