-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Automatic conversion of fundamental units to derived variables #132
Comments
There are several issues here (please, open separate threads the next time).
This is an open issue (see e.g. #123). The thing is that units:::R_ut_format(units:::R_ut_parse("J/s/W"))
#> [1] "1" but also (from #123): units:::R_ut_format(units:::R_ut_parse("mile/gallon"))
#> [1] "425143.683171079 m⁻²" There are ongoing efforts to move things (e.g., user-defined units) to the C part, because One solution for this would be to provide a function For now, you could add the following after your computations: units(compressor_efficiency) <- 1 This will convert the efficiency to unitless, or fail with an error if units were misused in previous steps.
I don't think so. But: units_options(negative_power=TRUE)
as_units("J/K/kg")
#> 1 J*K^-1*kg^-1
There is another option for this ( |
Units appear now more consistently as e.g. I'm in favour of makeing more aggressive simplification possible, need to look into how we could do this. |
This function to_si <- function(x) {
u_str = as.character(units(x))
u = units:::R_ut_parse(u_str)
ft = units:::R_ut_format(u, ascii = TRUE)
new = as_units(strsplit(ft, " ")[[1]][2])
set_units(x, new, mode = "standard")
} converts to SI units. Shall we use that in case the user actively sets option > to_si(set_units(1, gallon/mile))
2.352146e-06 [m^2]
> to_si(set_units(1, gallon*mile))
6.09203 [m^4]
|
This feels like it should be its own option. Perhaps called standardize_to_si.
I can think of lots of cases where a user might want to simplify, but not convert to si.
… On Jun 30, 2018, at 7:58 AM, Edzer Pebesma ***@***.***> wrote:
This function
to_si <- function(x) {
u_str = as.character(units(x))
u = units:::R_ut_parse(u_str)
ft = units:::R_ut_format(u, ascii = TRUE)
new = as_units(strsplit(ft, " ")[[1]][2])
set_units(x, new, mode = "standard")
}
converts to SI units. Shall we use that in case the user actively sets option simplify to TRUE? @Enchufa2 @t-kalinowski
> to_si(set_units(1, gallon/mile))
2.352146e-06 [m^2]
> to_si(set_units(1, gallon*mile))
6.09203 [m^4]
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
I agree with @t-kalinowski. I also think that there may be cases in which someone may want to simplify some things and not others, convert to SI some things and not others. So it's nice to have these features as options, but having them as functions would be useful too. |
The thing is that we have the opportunity to use > units_options(simplify = TRUE)
> set_units(1, mg/kg)
1e-06 [1]
> units_options(simplify = NA)
> set_units(1, mg/kg)
1 [mg/kg]
> units_options(simplify = FALSE)
> set_units(1, mg/kg)
1 [mg/kg] Further simplification is now done always, by the package, by symbols comparison. We could branch this further and
To me, this sounds the simplest and most elegant approach. |
We have: > units_options(simplify = TRUE)
> set_units(1, "gallon*in/dgallon")
10 in
> units_options(simplify = NA)
> set_units(1, "gallon*in/dgallon")
1 gallon*in/dgallon
> units_options(simplify = FALSE)
> set_units(1, "gallon*in/dgallon")
1 gallon*in/dgallon So you mean that the first result should be I'm not convinced either about Another thing you could do is to export
|
Thanks, valid point about
> units_options(simplify = FALSE)
> u
2 [m/s]
> u * 1/u
1 [m*s/m/s] we have
Maybe then add an option, say, |
Another option is what @t-kalinowski proposed, and I think it's fine. Regarding the name, what about |
OK, we now have > library(units)
udunits system database from /usr/share/xml/udunits
> units_options(convert_to_base=TRUE)
> set_units(1, gallon/km)
1 [gallon/km]
> set_units(1, gallon/km) * 1 # calls .simplify_units
3.785412e-06 [m^2] where we convert to base when we simplify. Is that the right place, or should this not happen directly in |
Mmmh, if I set the global option to > library(units)
udunits system database from /usr/share/xml/udunits
> units_options(convert_to_base=TRUE)
> set_units(1, gallon/km)
3.785412e-06 [m^2]
> set_units(1, gallon/km) * 1 # calls .simplify_units
3.785412e-06 [m^2] That's why I was stressing the need to export simplification functions, including this new |
So, I guess this issue can be closed? |
What do you think about my concern? Now, if |
OK, I'll leave this open; needs a lot more love & patience to get this |
Well, apparently I've bumped into an issue that I opened a few years. What a coincidence! I was actually looking for the functionality of I think it could be very interesting. Perhaps it is not necessary to consider it as a general option, but as a simple function that we can call in case of need. In the future, if necessary, it could be included as a general option. I don't have experience with the use of udunits from C and I suppose that as you say there is the possibility to install different base systems. I have simply taken the function reported a few years ago by @edzer and modified it a bit. I have conducted several tests and from what I understood, when evaluating units, we can find four typologies of string when capturing the units. For example:
With this in mind the function would be:
I think it could be very interesting to include it as a function available to the user. We would have a quick way to be able to convert to SI in case of need. |
Well, it seem that the function that I reported above gets some errors. For example:
I suppose the solution will be simple, but I don't know the internal function that takes care of these problems. Any idea? |
Perhaps something like this: library(units)
convert_to_base <- function(x) {
canonicalize <- function(s) {
s |>
R_ut_parse() |>
R_ut_format(TRUE, TRUE, TRUE) |>
gsub(" ", " * ", x = _)
}
u <- units(x)
u <- sprintf(
"( %s ) / ( %s )",
canonicalize(u$numerator),
canonicalize(u$denominator)
)
# message(u)
u <- as_units(str2lang(u))
u <- u / as.numeric(u)
# message(class(u))
# str(unclass(u))
units(x) <- u
x
}
environment(convert_to_base) <- asNamespace("units")
x <- set_units(25, "g/mol")
convert_to_base(x)
#> 0.025 [kg/mol]
set_units(25, ug/mol) |> convert_to_base()
#> 2.5e-08 [kg/mol]
set_units(25, mg/mol) |> convert_to_base()
#> 2.5e-05 [kg/mol]
set_units(25, g/mol) |> convert_to_base()
#> 0.025 [kg/mol]
set_units(25, kg/mol) |> convert_to_base()
#> 25 [kg/mol] |
Thank you very much @t-kalinowski for the suggestions. The code you reported has helped me a lot. Unfortunately, it is perhaps a bit more complicated because of the freedom on the part of the user. Your code, for example, requires imperatively that the numerator or denominator does not contain a convert_to_base <- function(x, simplify = T, merge_num_den = F) {
R_ut_parse <- utils::getFromNamespace("R_ut_parse", "units")
R_ut_format <- utils::getFromNamespace("R_ut_format", "units")
u_strBase <- function(u_str, spfy = T) {
u_new <- u_str |>
R_ut_parse() |>
R_ut_format(names = F, definition = T, ascii = T)
u_new <- strsplit(x = u_new, split = " @ ")[[1]][1]
u_new <- strsplit(x = u_new, split = " ")[[1]]
u_new <- u_new[length(u_new)]
if (spfy) {
u_new <- u_new |>
R_ut_parse() |>
R_ut_format(names = F, definition = F, ascii = T)
}
u_new <- u_new |>
gsub(".", " ", fixed = T, x = _)
return(u_new)
}
u <- base::units(x)
u <- sapply(u, function(i) paste0(i, collapse = "*", recycle0 = T))
u[u == ""] <- "1"
u["numerator"] <- sprintf("(%s)", u["numerator"])
u["denominator"] <- sprintf("(%s)", u["denominator"])
if (merge_num_den) u <- paste(u, collapse = "/")
u_base <- sapply(u, function(j) u_strBase(u_str = j, spfy = simplify))
if (merge_num_den) {
u_base <- sprintf("(%s)", u_base)
} else {
unitless <- (u_base == "1")
u_base["numerator"] <- sprintf("(%s)", u_base["numerator"])
u_base["denominator"] <- sprintf("(%s)-1", u_base["denominator"])
u_base <- u_base[!unitless]
u_base <- paste(u_base, collapse = " ")
}
units::set_units(x, u_base, mode = "standard", implicit_exponents = T)
} The basic operation would be as follows: Furthermore, I implemented some other functionalities. The option
Concerning the second option, @edzer @Enchufa2 and @t-kalinowski , I hope this will help you implement the Finally, here are some tests I have carried out on this function: u <- "kJ/kg"
set_units(32, u, mode = "standard") |> convert_to_base()
#> 32000 [J/kg]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = T)
#> 32000 [Gy]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = F, simplify = F)
#> 32000 [kg*m^2/kg/s^2]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = T, simplify = F)
#> 32000 [m^2/s^2]
u <- "fahrenheit"
set_units(32, u, mode = "standard") |> convert_to_base()
#> 273.15 [K]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = T)
#> 273.15 [K]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = F, simplify = F)
#> 273.15 [K]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = T, simplify = F)
#> 273.15 [K]
u <- "celsius"
set_units(32, u, mode = "standard") |> convert_to_base()
#> 305.15 [K]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = T)
#> 305.15 [K]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = F, simplify = F)
#> 305.15 [K]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = T, simplify = F)
#> 305.15 [K]
u <- "degree_C"
set_units(32, u, mode = "standard") |> convert_to_base()
#> 305.15 [K]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = T)
#> 305.15 [K]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = F, simplify = F)
#> 305.15 [K]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = T, simplify = F)
#> 305.15 [K]
u <- "kJ/(kg*fahrenheit)"
set_units(32, u, mode = "standard") |> convert_to_base()
#> 57600 [J/K/kg]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = T)
#> 57600 [m^2/K/s^2]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = F, simplify = F)
#> 57600 [kg*m^2/K/kg/s^2]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = T, simplify = F)
#> 57600 [m^2/K/s^2]
u <- "J/s"
set_units(32, u, mode = "standard") |> convert_to_base()
#> 32 [J/s]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = T)
#> 32 [W]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = F, simplify = F)
#> 32 [kg*m^2/s^3]
set_units(32, u, mode = "standard") |> convert_to_base(merge_num_den = T, simplify = F)
#> 32 [kg*m^2/s^3] |
This definitely helps. Thanks all for the discussion and prototypes. I'll try to find some time to put things together. But this will be during the next half-term, because I'm a bit overloaded now. |
Good afternoon. I'm starting to use the library units (I think it's a very useful tool).
I have a couple of doubts about the library.
I'm programming a small script to evaluate the performance in refrigeration compressors.
I have the following problem:
I evaluate the compressor efficiency with the following expression:
compressor_efficiency<-(mref*Dhs)/Wcomp
Previous to this calculation I define the following variables:
When I evaluate the compressor efficiency:
compressor_efficiency<-(mref*Dhs)/Wcomp
The units are:
This unit is dimensionless. Is there any way to indicate that internally interpret J / s as W? The result would be:
Another doubt would be the following:
When I define a new variable, entropy:
entropy<-set_units(vector_data_entropy, 'J/(kg*K)')
The printed result is:
Is there an option to print it in the following form?
I think that is much clearer in this way separating numerator and denominator.
Finally, it is not very important but I would like to know if there is an option to print the units with parentheses:
Thanks in advance
The text was updated successfully, but these errors were encountered: