Skip to content
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

Question/discuss: simplification of units after division #240

Open
kreintjes opened this issue Nov 1, 2021 · 4 comments
Open

Question/discuss: simplification of units after division #240

kreintjes opened this issue Nov 1, 2021 · 4 comments
Assignees

Comments

@kreintjes
Copy link
Contributor

kreintjes commented Nov 1, 2021

We have been using the RubyUnits gem for quite some time now in our application to perform calculations with units. Sometimes it happens we divide two RubyUnit objects with the same units. In this case the unit information is lost, e.g. Unit.new('10 kg') / Unit.new('5 kg') equals 2 instead of 2 kg/kg. I think this is technically correct, but sometimes it would be preferable to keep the unit information to better understand the data you're looking at.

Real world example from our application: we calculate the amount of CO2-emission normalised by something, e.g. the amount of produced product. Both could be measured in weight in kilograms, for example the amount of CO2 per kg produced paper. Now our app shows "CO2 per paper: 2" instead of "CO2 per paper: 2 kg/kg". (We also plot this information in charts and tables over time).

Could you explain why RubyUnits does this and if this is by design? Would you be open to change this behaviour or make it configurable?

Currently RubyUnits also feels a bit inconsistent regarding this behaviour, since it isn't always applied. For example when I initiate a RubyUnits object and pass "kg/kg" myself, this isn't simplified (Unit.new('2 kg/kg') => 2 kg/kg). Also if we do a division with different units of the same quantity, then the result could be simplified as well, but this doesn't happen (Unit.new('10 kg') / Unit.new('2 g') => 5 kg/g instead of 5000). Following the current behaviour of RubyUnits I would expect these cases to be simplified as well.

Although my suggestion would be to not simplify the unit after a division (or multiplication) at all, but only when explicitly asking for it (e.g. by calling to_base).

@olbrich olbrich self-assigned this Nov 2, 2021
@olbrich
Copy link
Owner

olbrich commented Nov 2, 2021

I'm thinking about this.
In the meantime, one clarification... to_base converts the units to SI and will also simplify the result, it is not the same as just simplifying the units.

@kreintjes
Copy link
Contributor Author

@olbrich any update on this?

In the mean time we have applied some hacks to prevent this behaviour (by overriding self.eliminate_terms with a custom implementation), but it would be nice if we could remove those in the future. Although merging #241 at least gives us the ability to implement this a bit nicer, once it is released on RubyGems.

I'm thinking about this. In the meantime, one clarification... to_base converts the units to SI and will also simplify the result, it is not the same as just simplifying the units.

I understand. We might have two methods: simplify and to_base where the latter does both. Or maybe we could have a setting or something like that. At least it would be very helpful for us if it doesn't happen automatically after every calculation (division or multiplication).

No rush or anything, but it would be nice to know what direction you're thinking in.

@olbrich
Copy link
Owner

olbrich commented Nov 26, 2021

@kreintjes I'm thinking about using something like #210, where you could define a custom unit that you could define a unit like kg/kg and then convert to it when needed. I think for that to work you might have to know in advance when you were going to need those units.

An alternative approach if you just want to format the output a particular way....

(Unit.new('10 kg') / Unit.new('5 kg')).to_s('%0.2f kgCO2/kgPaper')

It might also be helpful for you to just define a unit for 'kgCO2' and 'kgPaper' like...

Unit.define('kgCO2') {|unit| unit.definition = Unit.new('1 kg')}
Unit.define('kgPaper') {|unit| unit.definition = Unit.new('1 kg')}

(Unit.new('10 kgCO2') / Unit.new('5 kgPaper')) #=> 2 kgCO2/kgPaper

You are correct that elimination of terms is inconsistent.

Another possible solution would be changing the signature for convert_to to def convert_to(other, eliminate: true), which would allow you to suppress elimination on an individual conversion.

Still thinking about this...

@olbrich olbrich pinned this issue Nov 26, 2021
@kreintjes
Copy link
Contributor Author

@olbrich thanks for the response. Our issue indeed seems similar to #210 although not exactly. I'm not sure if the proposed solution is workable for us. In our application users can enter custom calculations (which are parsed using the Dentaku gem), so users can perform calculations with all kinds of quantities/units leading to all kinds of results. The kg/kg was just an example, but we could have the same problem with l(iter)/l(iter) and m(eter)/m(eter) to name a few.

We also support lots of different quantities for various reasons: types of fuel, amount of distance with various vehicles but also all kinds of items a company can produce. So for example, they could view a chart of their amount of emitted CO2 per produced kilograms of cement. Or the amount of diesel consumed for transporting liters or kilograms of beer. Although I must say most of our users do the same and for them this issue doesn't even occur. But when they do want something special, we do not (necessarily) know beforehand what (combinations of) units/quantities they use.

For that reason disabling the automatic elimination for calculations with an option/setting would work best for us. Although our current solution with a special Unit class that overrides eliminate_terms seems to work for now :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants