How can I assing an Unitful.jl quantity in an idempotent way?

Hi all!

So I need to manipulate some physical quantities. Unitful.jl seems to do a very good job at it, but IIUC the idiomatic way to “build” a physical quantity is to multiply the number and the unit:
12 * u"m".

The point is that I need to attach a quantity from a DataFrame I read from a CSV:

f = open(model_single_instruction_file)
df_model_master = DataFrame(CSV.File(f));
close(f)

df_model_master[!,mean_power_sym] = df_model_master[:,mean_power_sym] .* u"W";
df_model_master[!, std_power_sym] = df_model_master[:, std_power_sym] .* u"W";

But here’s the thing: if, for whatever reason, the second chunk of code gets reevaluated, the unit becomes W^2, then W^3 and so on. Is there a way to make this idempotent? I thought for instance to directly build the unit calling Unitful.Quantity(), but I don’t know how to do it. May this be an idea?

Thanks!

Hello!

Could the question be rephrased into “how can the organization of the code be modified to avoid evaluating the same stateful code more than once?”?

The problem here is that you are mutating a state (the DataFrame) and you do it repeatedly, likely because of how your code is organized (in a Jupyter notebook perhaps?).

Could the code instead be written in a more functional manner? Or could you introduce a check if the unit is already there, and if so, don’t apply it again?

Otherwise, the multiplicative factor you need is

u"m" / (unit(column))

this should be safe to multiply with no matter if the unit is already there or not:

julia> (1hr)/unit(1hr) # if the unit is already there, tihs factor is 1
1

julia> unit(1)


julia> (1hr)/unit(1) # if the unit is not there, the factor is 1hr
1 hr
3 Likes

Nice trick, thanks! Anyway, you’re right in saying that I need the code to be evaluated only once. I have been advised to use modules to do that but I’m struggling to grasp how to use them in a local project. I don’t want to go too OT, but for instance having declared a module locally, the only way I can use it is first to includeing it, then using it. This however produces some error (like defining the same variables twice). Anyways, for now they should prevent reevaluation, but this example is useful nevertheless. Thanks! :+1:

While using Unitful, it may also be useful to know about ustrip. Here is an example related to the OP:

julia> ustrip(1u"m")
1

julia> v = [12.3u"W", 4.56u"W"]
2-element Vector{Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}:
 12.3 W
 4.56 W

julia> v = ustrip.(v)*u"W"
2-element Vector{Quantity{Float64, 𝐋^2 𝐌 𝐓^-3, Unitful.FreeUnits{(W,), 𝐋^2 𝐌 𝐓^-3, nothing}}}:
 12.3 W
 4.56 W

julia> v = v*u"W"
2-element Vector{Quantity{Float64, 𝐋^4 𝐌^2 𝐓^-6, Unitful.FreeUnits{(W^2,), 𝐋^4 𝐌^2 𝐓^-6, nothing}}}:
 12.3 W^2
 4.56 W^2
1 Like

This too, thanks! It is even more concise.