-
Notifications
You must be signed in to change notification settings - Fork 12
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
Utilities dimensions #495
Utilities dimensions #495
Conversation
R/utilities-dimensions.R
Outdated
#' of both dimensions. | ||
#' If the values cannot be transformed between the dimensions, an error is thrown. | ||
#' @export | ||
dimensionsConversionFactor <- function(dimension1, dimension2, mw = NULL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very useful if you want e.g. to plot your data in molar or mass concentrations. Is there a better way to check if the dimensions can be converted than to explicitly consider every possible use case?
Maybe some things can be done better (using some .NET methods)? |
Something is broken here.. |
@PavelBal I have merge develop into the code here. Still it won't work but we have a clean slate |
R/utilities-dimensions.R
Outdated
#' #' @include enum.R | ||
#' #' | ||
#' #' @export | ||
#' Dimensions <- enum(allAvailableDimensions()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a problem here. It is being loaded directly before initialization. This works when you load ospsuite.core first but does not work in ospsuite.core
R/utilities-dimensions.R
Outdated
validateUnit(fromUnit, dimension) | ||
validateUnit(toUnit, dimension) | ||
|
||
dimensionTask <- getDimensionTask() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure why you need sthg like this ? toUnit converts already everything from you. .The goal is to abstract exactly all of this away
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea is to use the conversion capabilities of OSPS without having the simulation objects (quantities). E.g. read the data from excel and plot it in another unit. toUnit
requires a Quantity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nope
toUnit <- function(quantityOrDimension, values, targetUnit, molWeight = NULL) {
Specifically the parameter is called quantityOrDimension.
None of the proposed changes regarding reimplementing conversion by hand belong in Core. Helper function to ensure that dimension and unit etc.. exists, yes. The rest probably not :)
R/utilities-dimensions.R
Outdated
#' of both dimensions. | ||
#' If the values cannot be transformed between the dimensions, an error is thrown. | ||
#' @export | ||
dimensionsConversionFactor <- function(dimension1, dimension2, mw = NULL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh my. what is this monster?
R/utilities-dimensions.R
Outdated
if (is.null(mw)) { | ||
stop(messages$errorCannotConvertDimensionsNoMW(dimension1, dimension2)) | ||
} | ||
return(1 * 1e-6 * mw * 1e-3) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not something I want to see here. I need to understand the usage of such concept. We have already everything encapsulated in Core
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be happy to see another way. E.g. - I read data in mg/dl and want to convert it to mol/l. How? Without having a Quantity object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are plenty of method exposted directly in core doing this. Creating a conversation factor from one dimension to another dimension does not make sense BTW. It needs to be from one unit to another unit
In core see
double[] ConvertToUnit(string dimensionName, string targetUnit, double[] valuesInBaseUnit, double molWeight);
double[] ConvertToUnit(string dimensionName, string targetUnit, double[] valuesInBaseUnit);
double[] ConvertToUnit(string dimensionName, string targetUnit, double valueInBaseUnit, double molWeight);
double[] ConvertToUnit(string dimensionName, string targetUnit, double valueInBaseUnit);
and
double[] ConvertToBaseUnit(string dimensionName, string displayUnit, double[] valuesInDisplayUnit, double molWeight);
double[] ConvertToBaseUnit(string dimensionName, string displayUnit, double[] valuesInDisplayUnit);
double[] ConvertToBaseUnit(string dimensionName, string displayUnit, double valueInDisplayUnit, double molWeight);
double[] ConvertToBaseUnit(string dimensionName, string displayUnit, double valueInDisplayUnit);
All exposed via the DImensionTag. IT deals EXPLICITELY with those use cases
R/utilities-dimensions.R
Outdated
#' | ||
#' @return String name of the base unit. | ||
#' @export | ||
getBaseUnit <- function(dimension) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should move to core
R/utilities-dimensions.R
Outdated
dimensionTask <- getDimensionTask() | ||
# Get the dimension object | ||
dimension <- rClr::clrCall(dimensionTask, "DimensionByName", enc2utf8(dimension)) | ||
unit <- rClr::clrCall(dimension, "get_BaseUnit") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is clrGet...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to
unit <- rClr::clrGet(dimension,") "BaseUnit
R/utilities-dimensions.R
Outdated
#' @param dimension String name of the dimension. | ||
#' @details Check if the provided dimension is supported. If not, throw an error | ||
#' @export | ||
validateDimension <- function(dimension) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should not we have one method (validateDimension or existDimension with a flag instead of two?) we have the same concept already somewhere else
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you show where? I only remember the concept of "isXXX" returning a boolean, and "validateXXX" throwing an error if "isXXX" is false:
isOfType
and validateIsOfType
R/utilities-dimensions.R
Outdated
#' @details Check if the unit is valid for the dimension. | ||
#' @export | ||
hasUnit <- function(unit, dimension) { | ||
validateIsString(c(unit, dimension)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should move ot core too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sitll needs to be moved to utilities-units
R/utilities-dimensions.R
Outdated
#' @param dimension String name of the dimension. | ||
#' @details Returns \code{TRUE} if the provided dimension is supported otherwise \code{FALSE} | ||
#' @export | ||
hasDimension <- function(dimension) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PavelBal I have renamed this to hasDimension and it is using the core method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you prefer the core method? We still have the enum Dimensions (or do you think we do not need it? I would disagree) which is created by calling allAvailableDimensions
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it called HasDimension
btw? What does or does not have the dimension? :D @msevestre
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are looking at this from the system point of view " Does OSPSUITE HAVE The dimension xxx"
so if(ospsuite::hasDimension("Mass"))
reads better than if(ospsuite::existsDImension("Mass"))
in my opinion
But this is also because we had hasUnit. and not existsUnit. Naming is hard and consistency is even harder
R/utilities-dimensions.R
Outdated
validateIsString(unit) | ||
validateDimension(dimension) | ||
dimensionTask <- getDimensionTask() | ||
rClr::clrCall(dimensionTask, "HasUnit", enc2utf8(dimension), enc2utf8(unit)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
usign hasUnit from core
R/utilities-dimensions.R
Outdated
getBaseUnit <- function(dimension) { | ||
validateDimension(dimension) | ||
dimensionTask <- getDimensionTask() | ||
rClr::clrCall(dimensionTask, "BaseUnitFor", enc2utf8(dimension)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using baseUnitFor from core
R/utilities-dimensions.R
Outdated
if (is.null(mw)) { | ||
stop(messages$errorCannotConvertDimensionsNoMW(dimension1, dimension2)) | ||
} | ||
return(1 * 1e-6 * mw * 1e-3) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are plenty of method exposted directly in core doing this. Creating a conversation factor from one dimension to another dimension does not make sense BTW. It needs to be from one unit to another unit
In core see
double[] ConvertToUnit(string dimensionName, string targetUnit, double[] valuesInBaseUnit, double molWeight);
double[] ConvertToUnit(string dimensionName, string targetUnit, double[] valuesInBaseUnit);
double[] ConvertToUnit(string dimensionName, string targetUnit, double valueInBaseUnit, double molWeight);
double[] ConvertToUnit(string dimensionName, string targetUnit, double valueInBaseUnit);
and
double[] ConvertToBaseUnit(string dimensionName, string displayUnit, double[] valuesInDisplayUnit, double molWeight);
double[] ConvertToBaseUnit(string dimensionName, string displayUnit, double[] valuesInDisplayUnit);
double[] ConvertToBaseUnit(string dimensionName, string displayUnit, double valueInDisplayUnit, double molWeight);
double[] ConvertToBaseUnit(string dimensionName, string displayUnit, double valueInDisplayUnit);
All exposed via the DImensionTag. IT deals EXPLICITELY with those use cases
R/utilities-dimensions.R
Outdated
validateUnit(fromUnit, dimension) | ||
validateUnit(toUnit, dimension) | ||
|
||
dimensionTask <- getDimensionTask() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nope
toUnit <- function(quantityOrDimension, values, targetUnit, molWeight = NULL) {
Specifically the parameter is called quantityOrDimension.
None of the proposed changes regarding reimplementing conversion by hand belong in Core. Helper function to ensure that dimension and unit etc.. exists, yes. The rest probably not :)
Codecov Report
@@ Coverage Diff @@
## develop #495 +/- ##
===========================================
- Coverage 88.52% 85.00% -3.53%
===========================================
Files 72 73 +1
Lines 1325 1380 +55
===========================================
Hits 1173 1173
- Misses 152 207 +55
Continue to review full report at Codecov.
|
@@ -18,4 +18,6 @@ initPackage <- function() { | |||
apiConfig$pkParametersFilePath <- filePathFor("OSPSuite.PKParameters.xml") | |||
|
|||
rClr::clrCallStatic("OSPSuite.R.Api", "InitializeOnce", apiConfig$ref) | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This allows to populate the enum after loading the package..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not like this because it was creating the variable int he PARENT environment which was global. Now what I changed is that I am initializing the variable in a method and so now the variable are not global anymore
R/utilities-units.R
Outdated
#' @param toUnit String name of the unit to convert to | ||
#' @param dimension Dimension of the units (conversion between mass and molar possible when | ||
#' \code{MW} is provided) | ||
#' @param MW Optional molecule weight in g/mol to use when converting, for example, from molar to mass amount or concentration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think MW should be passed as g/mol, this is the only unit a user expects.
@msevestre
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MW Optional molecule weight in g/mol
yes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes? :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I see your point. The problem is that we always pass parameters in core unit
height should be dm etc..
Introducing a change like this would not be logical, specifically because the weight generally comes from simulation$molWeightFor which returns in core unit.
I am still not 100% sure I understand why we need such a method. If this is just for the MW, then we could add another flag to toUnit (mw.in.base.unit = true) by default or sthg like this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No its not for the MW, its for conversion of values that are not in base units - and most probably these would be the values that do not come from a simulation (that can be converted with toUnit). It is for data that are defined in other units - loaded from excel, generated by hand, or whatsoever.. And in this case MW most definitely will be in g/mol (even in the data exporter we always assume MW is in g/mol).
I see your point that this will be inconsistent with the rest of methods. But I also do not see the use case for this function with MW being in the base unit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LEt's discuss WEdnesday. I do not understand why a user would not convert an array using toUnit instead of dealing with some weird factors
R/utilities-units.R
Outdated
#' @include enum.R | ||
#' | ||
#' @export | ||
Dimensions <- list() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initialize empty and then populate after package is loaded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like not to rely on this too much for now because @abdullahhamadeh is going to implement a parsign method see #478
@@ -15,7 +76,7 @@ | |||
#' | |||
#' valuesInBaseUnit <- toBaseUnit(par, c(1000, 2000, 3000), "ml") | |||
#' @export | |||
toBaseUnit <- function(quantityOrDimension, values, unit, molWeight = NULL) { | |||
toBaseUnit <- function(quantityOrDimension, values, unit, molWeight = NULL, molWeightUnit = NULL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be consistent, both "toBaseUnit" and "toUnit" allow now molWeight in custom unit.
R/utilities-units.R
Outdated
#' @export | ||
toUnit <- function(quantityOrDimension, values, targetUnit, molWeight = NULL) { | ||
toUnit <- function(quantityOrDimension, values, targetUnit, sourceUnit = NULL, molWeight = NULL, molWeightUnit = NULL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be the new signature that allows to convert from non-base units.
R/utilities-units.R
Outdated
@@ -74,8 +147,20 @@ toUnit <- function(quantityOrDimension, values, targetUnit, molWeight = NULL) { | |||
} | |||
|
|||
if (is.null(molWeight)) { | |||
#Convert values to base unit first if the source unit is provided | |||
if (!is.null(sourceUnit)){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is repeated in both if-cases, but I cannot think of a better solution now.
R/utilities-units.R
Outdated
#' enum of all units for each dimension | ||
#' | ||
#' @export | ||
DimensionsUnits <- list() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about this naming for the enum with the units?
@msevestre I don't get it, why is the build failing? Obviously it somehow uses the old dlls, but I cannot figure out why. It works on my local machine. |
@PavelBal Ok I am going to check it out |
Moved methods to utilities-units Using core methods
d4339a4
to
5c9144d
Compare
@@ -77,6 +80,8 @@ export(loadAgingDataFromCSV) | |||
export(loadDataRepositoryFromPKML) | |||
export(loadPopulation) | |||
export(loadSimulation) | |||
export(ospDimensions) | |||
export(ospUnits) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PavelBal This is how we decied to name those guys to avoid any conflicts and it's also easy to type to get intellisense
@@ -18,4 +18,6 @@ initPackage <- function() { | |||
apiConfig$pkParametersFilePath <- filePathFor("OSPSuite.PKParameters.xml") | |||
|
|||
rClr::clrCallStatic("OSPSuite.R.Api", "InitializeOnce", apiConfig$ref) | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not like this because it was creating the variable int he PARENT environment which was global. Now what I changed is that I am initializing the variable in a method and so now the variable are not global anymore
validateIsString(unit) | ||
validateDimension(dimension) | ||
dimensionTask <- getDimensionTask() | ||
rClr::clrCall(dimensionTask, "HasUnit", enc2utf8(dimension), encodeUnit(unit)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this needs to be encodeUnit for unuit
|
||
initializeDimensionAndUnitLists <- function() { | ||
#This initializes the two lists in the parent environment which is the package environments | ||
ospDimensions <<- getDimensionsEnum() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PavelBal Here is how we do not polute the global namespace (I think...)
@msevestre No tests so far.