Skip to content

Commit 4b72553

Browse files
committed
new convert_to_base, closes #132
1 parent 3fabf36 commit 4b72553

File tree

6 files changed

+119
-0
lines changed

6 files changed

+119
-0
lines changed

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ S3method(units,units)
7474
S3method(weighted.mean,units)
7575
export(as_difftime)
7676
export(as_units)
77+
export(convert_to_base)
7778
export(deparse_unit)
7879
export(drop_units)
7980
export(install_unit)

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
* Implement `matrixOps.units`, with support for `%*%` (R >= 4.3.0); #226
1313

14+
* New `convert_to_base()` implements conversion to base units; #132 @jamarav
15+
1416
# version 0.8-7
1517

1618
* Deep copy of `ud_convert()` input to avoid side effects; #403

R/symbolic_units.R

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,60 @@ as.character.symbolic_units <- function(x, ...,
144144

145145
as_units(drop_units(value), .symbolic_units(new_numerator, new_denominator))
146146
}
147+
148+
#' Convert units to their base units
149+
#'
150+
#' Convert the units of a \code{units} object to their base units, as defined by
151+
#' the udunits database (SI units).
152+
#'
153+
#' @param x object of class \code{units}.
154+
#' @param simplify logical; if TRUE (default), the resulting units are simplified.
155+
#' @param keep_fraction logical; if TRUE (default), the result is kept as a fractio.n
156+
#'
157+
#' @return object of class \code{units} with units converted to base units.
158+
#' @export
159+
#'
160+
#' @examples
161+
#' x <- set_units(32, mJ/g)
162+
#' convert_to_base(x)
163+
#' convert_to_base(x, keep_fraction=FALSE)
164+
#' convert_to_base(x, simplify=FALSE)
165+
#' convert_to_base(x, simplify=FALSE, keep_fraction=FALSE)
166+
convert_to_base <- function(x, simplify = TRUE, keep_fraction = TRUE) {
167+
stopifnot(inherits(x, "units"))
168+
169+
u_strBase <- function(u_str, simplify) {
170+
u_new <- ud_parse(u_str, names=FALSE, definition=TRUE, ascii=TRUE)
171+
u_new <- strsplit(x = u_new, split = " @ ")[[1]][1]
172+
u_new <- strsplit(x = u_new, split = " ")[[1]]
173+
u_new <- u_new[length(u_new)]
174+
175+
if (simplify)
176+
u_new <- ud_parse(u_new, names=FALSE, definition=FALSE, ascii=TRUE)
177+
gsub(".", " ", u_new, fixed = TRUE)
178+
}
179+
180+
u <- sapply(units(x), function(i) paste0(i, collapse = "*", recycle0=TRUE))
181+
u[u == ""] <- "1"
182+
183+
u["numerator"] <- sprintf("(%s)", u["numerator"])
184+
u["denominator"] <- sprintf("(%s)", u["denominator"])
185+
186+
if (!keep_fraction) u <- paste(u, collapse = "/")
187+
188+
u_base <- sapply(u, function(j) u_strBase(u_str = j, simplify = simplify))
189+
190+
if (!keep_fraction) {
191+
u_base <- sprintf("(%s)", u_base)
192+
} else {
193+
is_unitless <- u_base == "1"
194+
195+
u_base["numerator"] <- sprintf("(%s)", u_base["numerator"])
196+
u_base["denominator"] <- sprintf("(%s)-1", u_base["denominator"])
197+
198+
u_base <- u_base[!is_unitless]
199+
u_base <- paste(u_base, collapse = " ")
200+
}
201+
202+
set_units(x, u_base, mode = "standard")
203+
}

R/udunits.R

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,7 @@ ud_is_parseable = function(u) {
7676
res <- try(R_ut_parse(u), silent = TRUE)
7777
! inherits(res, "try-error")
7878
}
79+
80+
ud_parse <- function(u, names=FALSE, definition=FALSE, ascii=FALSE) {
81+
R_ut_format(R_ut_parse(u), names, definition, ascii)
82+
}

man/convert_to_base.Rd

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test_symbolic_units.R

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,29 @@ test_that("symbolic_unit works", {
6363
expect_error(units:::symbolic_unit("qqq"))
6464
expect_silent(units:::symbolic_unit("m"))
6565
})
66+
67+
test_that("convert_to_base works", {
68+
u <- set_units(1:5, "kJ/kg", mode = "standard")
69+
expect_equal(convert_to_base(u), set_units(u, "J/kg"))
70+
expect_equal(convert_to_base(u, keep_fraction=FALSE), set_units(u, "Gy"))
71+
expect_equal(convert_to_base(u, keep_fraction=TRUE, simplify=FALSE), set_units(u, "m^2*kg/s^2/kg"))
72+
expect_equal(convert_to_base(u, keep_fraction=FALSE, simplify=FALSE), set_units(u, "m^2/s^2"))
73+
74+
u <- set_units(1:5, "celsius", mode = "standard")
75+
expect_equal(convert_to_base(u), set_units(u, "K"))
76+
expect_equal(convert_to_base(u, keep_fraction=FALSE), set_units(u, "K"))
77+
expect_equal(convert_to_base(u, keep_fraction=TRUE, simplify=FALSE), set_units(u, "K"))
78+
expect_equal(convert_to_base(u, keep_fraction=FALSE, simplify=FALSE), set_units(u, "K"))
79+
80+
u <- set_units(1:5, "kJ/(kg*fahrenheit)", mode = "standard")
81+
expect_equal(convert_to_base(u), set_units(u, "J/kg/K"))
82+
expect_equal(convert_to_base(u, keep_fraction=FALSE), set_units(u, "m^2/s^2/K"))
83+
expect_equal(convert_to_base(u, keep_fraction=TRUE, simplify=FALSE), set_units(u, "m^2*kg/s^2/kg/K"))
84+
expect_equal(convert_to_base(u, keep_fraction=FALSE, simplify=FALSE), set_units(u, "m^2/s^2/K"))
85+
86+
u <- set_units(1:5, "J/s", mode = "standard")
87+
expect_equal(convert_to_base(u), set_units(u, "J/s"))
88+
expect_equal(convert_to_base(u, keep_fraction=FALSE), set_units(u, "W"))
89+
expect_equal(convert_to_base(u, keep_fraction=TRUE, simplify=FALSE), set_units(u, "m^2*kg/s^3"))
90+
expect_equal(convert_to_base(u, keep_fraction=FALSE, simplify=FALSE), set_units(u, "m^2*kg/s^3"))
91+
})

0 commit comments

Comments
 (0)