-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathutils.R
371 lines (344 loc) · 11.6 KB
/
utils.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
#' @title geomean
#' @description
#' Calculate the geometric mean
#' @param x values
#' @param na.rm logical defining removal of `NA` values
#' @return Geometric mean
#' @export
geomean <- function(x, na.rm = TRUE) {
logX <- log(x[x > 0])
exp(mean(logX, na.rm = na.rm))
}
#' @title geomeanMultipliedBySD
#' @description
#' Calculate the geometric mean * geometric SD
#' @param x values
#' @param na.rm logical defining removal of `NA` values
#' @return Geometric mean * geometric SD
#' @export
geomeanMultipliedBySD <- function(x, na.rm = TRUE) {
logX <- log(x[x > 0])
exp(mean(logX, na.rm = na.rm) + stats::sd(logX, na.rm = na.rm))
}
#' @title geomeanDividedBySD
#' @description
#' Calculate the geometric mean / geometric SD
#' @param x values
#' @param na.rm logical defining removal of `NA` values
#' @return Geometric mean / geometric SD
#' @export
geomeanDividedBySD <- function(x, na.rm = TRUE) {
logX <- log(x[x > 0])
exp(mean(logX, na.rm = na.rm) - stats::sd(logX, na.rm = na.rm))
}
#' @title calculateGeometricErrorRange
#' @param values Numeric values of the geometric mean
#' @param errorValues Numeric values of the geometric error
#' @return A named list, with `ymin` and `ymax`, of the range calculated from the geometric mean and errors.
#' @description
#' Calculate the range from the geometric mean and error.
#' @export
calculateGeometricErrorRange <- function(values, errorValues) {
return(list(
ymin = values / errorValues,
ymax = values * errorValues
))
}
#' @title calculateArithmeticErrorRange
#' @param values Numeric values of the arithmetic mean
#' @param errorValues Numeric values of the arithmetic error
#' @return A named list, with `ymin` and `ymax`, of the range calculated from the arithmetic mean and errors.
#' @description
#' Calculate the range from the arithmetic mean and error.
#' @export
calculateArithmeticErrorRange <- function(values, errorValues) {
return(list(
ymin = values - errorValues,
ymax = values + errorValues
))
}
#' @title trimFileName
#' @param path character string containing the name of the path or file to trim
#' @param extension character string containing the extension file
#' @param sep character string separating path elements. "/" is default value.
#' @return fileName character string of the trimmed filed name
#' @description
#' Trim path and extension of a file
#' @examples
#' \dontrun{
#' pathName <- "folder/subfolder/testFile.txt"
#' trimFileName(pathName, extension = "txt")
#' }
#' @export
trimFileName <- function(path, extension = NULL, sep = "/") {
fileName <- sub(
pattern = paste0("^.*[", sep, "]"),
replacement = "",
x = path
)
if (!is.null(extension)) {
fileName <- sub(
pattern = paste0("[.].*", extension),
"[.].*$",
replacement = "",
x = fileName
)
}
return(fileName)
}
#' @title removeForbiddenLetters
#' @param text character string to be evaluated
#' @param forbiddenLetters characters to be removed if in the \code{text}.
#' Default value of \code{forbiddenLetters} is \code{"[[:punct:]]"}
#' meaning that all punctuation characters are forbidden.
#' @param replacement character replacing the \code{forbiddenLetters}.
#' Default value of \code{forbiddenLetters} is "_".
#' @return \code{text} character string with forbidden letters replaced
#' @description
#' Trim path and extension of a file
#' @examples
#' \dontrun{
#' removeForbiddenLetters(text)
#' }
#' @export
removeForbiddenLetters <- function(text, forbiddenLetters = "[[:punct:][:blank:]]", replacement = "_") {
# Remove accents from characters
text <- iconv(x = text, to = "ASCII//TRANSLIT")
gsub(
pattern = forbiddenLetters,
replacement = replacement,
x = text
)
}
#' @title generateResultFileNames
#' @return A list of filenames to be output by each core
#' @param numberOfCores to be used in parallel computation
#' @param folderName where result files will be saved
#' @param fileName prefix of result file names
#' @param separator used between file name prefix and index
#' @param extension for result file type. default is CSV
#' @description
#' #Generate a list containing names of CSV result files that will be output by each core in parallel computation
#' @export
generateResultFileNames <- function(numberOfCores, folderName, fileName, separator = "-", extension = ".csv") {
allResultsFileNames <- sapply(
X = 1:numberOfCores, function(x, folderName, fileName) {
return(file.path(folderName, paste0(fileName, separator, x, extension)))
},
folderName = folderName,
fileName = fileName,
USE.NAMES = FALSE
)
return(allResultsFileNames)
}
#' @title lastPathElement
#' @param path simulation path
#' @return last path element as character string
#' @export
#' @import ospsuite
#' @import utils
lastPathElement <- function(path) {
pathArray <- ospsuite::toPathArray(path)
lastElement <- utils::tail(pathArray, 1)
return(lastElement)
}
#' @title replaceInfWithNA
#' @param data numeric vector
#' @return numeric vector
#' @keywords internal
replaceInfWithNA <- function(data) {
infData <- is.infinite(data)
Ninf <- sum(infData)
if (Ninf > 0) {
logDebug(paste0(Ninf, " values were infinite and transformed into missing values (NA)"))
}
data[infData] <- NA
return(data)
}
#' @title removeMissingValues
#' @param data data.frame
#' @param dataMapping name of variable on which the missing values are checked
#' @return filtered data.frame
#' @keywords internal
removeMissingValues <- function(data, dataMapping = NULL) {
if (isEmpty(data)) {
return(data)
}
data[, dataMapping] <- replaceInfWithNA(data[, dataMapping])
naData <- is.na(data[, dataMapping])
Nna <- sum(naData)
data <- data[!naData, ]
if (Nna > 0) {
logDebug(paste0(Nna, " values were missing (NA) from variable '", dataMapping, "' and removed from the analysis"))
}
return(data)
}
#' @title removeNegativeValues
#' @param data data.frame
#' @param dataMapping name of variable on which the missing values are checked
#' @return filtered data.frame
#' @keywords internal
removeNegativeValues <- function(data, dataMapping = NULL) {
if (isEmpty(data)) {
return(data)
}
negativeData <- data[, dataMapping] <= 0
Nnegative <- sum(negativeData, na.rm = TRUE)
data <- data[!negativeData, ]
if (Nnegative > 0) {
logDebug(paste0(Nnegative, " values from variable '", dataMapping, "' were negative and removed from the analysis"))
}
return(data)
}
#' @title newOutputColor
#' @description
#' Find a color for new `Output` objects
#' @return A color from OSP Suite Color Map
#' @keywords internal
newOutputColor <- function() {
outputNames <- getObjectNamesInGlobalEnv("Output")
usedColors <- sapply(
outputNames,
function(outputName) {
output <- get(outputName)
return(output$color)
}
)
# OSP Suite color map includes 50 unique colors used here
remainingColors <- setdiff(tlf::ColorMaps$ospDefault, usedColors)
if (!isEmpty(remainingColors)) {
return(head(remainingColors, 1))
}
# If the colors were already used, in previous Outputs,
# Use new round of osp suite colors
colorIndex <- 1 + (length(outputNames) %% length(tlf::ColorMaps$ospDefault))
return(tlf::ColorMaps$ospDefault[colorIndex])
}
#' @title getAllowedCores
#'
#' @description Get allowed number of CPU cores for computation
#'
#' @return Allowed number of CPU cores for computation
#' @keywords internal
getAllowedCores <- function() {
return(
getAllowedCoresLinuxKubernetes() %||%
getOSPSuiteSetting(settingName = "numberOfCores")
)
}
#' @title getAllowedCoresLinuxKubernetes
#'
#' @description
#' Relevant only when reporting engine is executed on a Linux Kubernetes cluster.
#'
#' @return Allowed number of CPU cores for computation
#' @keywords internal
getAllowedCoresLinuxKubernetes <- function() {
cores <- tryCatch(
{
# get cpu allowance from files
cfs_quota_us <- as.numeric(system("cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us", intern = TRUE))
cfs_period_us <- as.numeric(system("cat /sys/fs/cgroup/cpu/cpu.cfs_period_us", intern = TRUE))
cores <- floor(cfs_quota_us / cfs_period_us)
if (cores < 1) {
return(NULL)
}
return(cores)
},
error = function(cond) {
return(NULL)
},
warning = function(cond) {
return(NULL)
}
)
return(cores)
}
#' @title parseVariableToObject
#' @description Create an expression of type `objectName$variableName <- variableName`
#' @param objectName Name of the object whose field is updated
#' @param variableName Name of the variable and field of `objectName`
#' @param keepIfNull logical `objectName$variableName <- variableName \%||\% objectName$variableName`
#' @return An expression to `eval()`
#' @importFrom ospsuite.utils %||%
#' @keywords internal
parseVariableToObject <- function(objectName, variableName, keepIfNull = FALSE) {
if (keepIfNull) {
return(parse(text = paste0(objectName, "$", variableName, " <- ", variableName, " %||% ", objectName, "$", variableName)))
}
return(parse(text = paste0(objectName, "$", variableName, " <- ", variableName)))
}
#' @title parseVariableFromObject
#' @description Create an expression of type `variableName <- objectName$variableName`
#' @param objectName Name of the object whose field is updated
#' @param variableName Name of the variable and field of `objectName`
#' @param keepIfNull logical `variableName <- objectName$variableName \%||\% variableName`
#' @return An expression to `eval()`
#' @keywords internal
parseVariableFromObject <- function(objectName, variableName, keepIfNull = FALSE) {
if (keepIfNull) {
return(parse(text = paste0(variableName, " <- ", objectName, "$", variableName)))
}
return(parse(text = paste0(variableName, " <- ", objectName, "$", variableName)))
}
#' @title calculateGMFE
#' @description Calculate Geometric Mean Fold Error between `x` and `y`.
#' Strictly positive pairs of values are kept in the calculation
#' @param x x values to compare
#' @param y y values to compare
#' @return GMFE
#' @export
calculateGMFE <- function(x, y) {
positiveValues <- (y > 0 & x > 0)
log10Error <- log10(y[positiveValues]) - log10(x[positiveValues])
return(10^(sum(abs(log10Error)) / length(log10Error)))
}
#' @title getObjectNameAsString
#' @description Return the name of an object as a string
#' @param object the name of which is to be returned
#' @return the name of the `object` as a string
#' @keywords internal
getObjectNameAsString <- function(object) {
return(deparse(substitute(object)))
}
#' @title saveFigure
#' @description Save figure and catches
#' @param plotObject A `ggplot` object
#' @param fileName Name of the file in which `plotObject` is saved
#' @param simulationSetName Name of the simulation set for `PlotTask` results
#' @keywords internal
saveFigure <- function(plotObject, fileName, simulationSetName = NULL) {
tryCatch(
{
ggplot2::ggsave(
filename = fileName,
plot = plotObject,
width = reEnv$defaultPlotFormat$width,
height = reEnv$defaultPlotFormat$height,
dpi = reEnv$defaultPlotFormat$dpi,
units = reEnv$defaultPlotFormat$units
)
},
error = function(e) {
stop(messages$ggsaveError(fileName, simulationSetName, e))
}
)
return(invisible())
}
#' @title getObjectNamesInGlobalEnv
#' @description Get object names of certain type/class in the Global Environment
#' @param objectType Object type or class
#' @return Array of Number of `Output` objects in the Global Environment
#' @keywords internal
getObjectNamesInGlobalEnv <- function(objectType) {
objectNames <- ls(envir = .GlobalEnv)
if (isEmpty(objectNames)) {
return(NULL)
}
objectNames[sapply(
objectNames,
function(objectName) {
isOfType(get(objectName, envir = .GlobalEnv), objectType)
}
)]
}