PainterQubits/Unitful.jl: pacote para se trabalhar com quantidades, unidades e dimensões
jw3126/UnitfulRecipes.jl: pacote com "receitas" para se traçar gráficos vai [JuliaPlots/Plots.jl]](https://github.com/JuliaPlots/Plots.jl).
rmsrosa/UnitfulBuckinghamPi.jl: pacote para se obter os grupos adimensionais garantidos pelo Teorema de Buckingham-Pi.
using Unitful
using UnitfulBuckinghamPi
using Plots
using UnitfulRecipes
É bastante simple definir e operar com quantidades, unidades e dimensões através do pacote PainterQubits/Unitful.jl.
Basta adicionarmos uma strings prefixada com u
, com a unidade desejada na string. Por exemplo:
h0 = 10.0u"m" # quantidade em metros
10.0 m
h0.val # valor da quantidade
10.0
unit(h0) # unidade da quantidade
m
dimension(h0) # dimensão da quantidade
𝐋
typeof(h0) # tipo
Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}
uconvert(u"cm", h0) # convertendo para outras unidades (de mesma dimensão)
1000.0 cm
v0 = 3u"m/s"
3 m s⁻¹
deslocamento = 198u"km"; tempo = 1.8u"hr"; velocidade = deslocamento / tempo
110.0 km hr⁻¹
g = -9.8u"m/s^2"
-9.8 m s⁻²
h(t, h0, v0) = h0 + v0 * t + g * t^2/2
h (generic function with 1 method)
t = (0:0.02:2.0)u"s" # iterador com unidade
(0.0:0.02:2.0) s
h.(t, h0, v0)
101-element Vector{Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}}: 10.0 m 10.05804 m 10.11216 m 10.16236 m 10.20864 m 10.251000000000001 m 10.289439999999999 m 10.32396 m 10.354560000000001 m 10.381239999999998 m 10.404 m 10.42284 m 10.43776 m ⋮ -0.18516000000000155 m -0.47600000000000264 m -0.7707600000000028 m -1.0694400000000037 m -1.3720400000000037 m -1.678560000000001 m -1.9890000000000008 m -2.3033599999999996 m -2.6216399999999993 m -2.9438400000000016 m -3.269960000000003 m -3.6000000000000014 m
plot(t, t -> h(t, h0, v0))
t
, assim como o vetor h.(t, h_0, v_0)
obtido através da função.plot(t, h.(t, h0, v0))
Observe, acima, que as unidades são automaticamente denotadas nos eixos, mas podemos fazer isso e acrescentar mais informações no compando plot
.
Novamente, observe que, mesmo qualificando os eixos, as unidades são automaticamente incluídas.
plot(t, h.(t, h0, v0), title="lançamento vertical de um objeto", titlefont=10,
xlims = (0.0, 4.0), ylims=(0.0, 12.0), label = "altura do objeto",
xlabel = "tempo", ylabel="altura")
Podemos somar quantidades de mesma dimensão, independente das unidades.
Podos multiplicar quantidades, unidades quaisquer, inclusive entre si.
Podemos multiplicar dimensões entre si.
Podemos converter uma quantidade entre unidades diferentes de mesma dimensão.
Oberve que dimensões são em negrito e que negrito pode ser obtida com barra invertida, seguida de "bf" (de boldface), seguida da letra desejada e, finalmente, apertando ESC. Por exemplo, a dimensão de tempo T se obtém, em células de código, com \bfT
+ ESC
1u"km" + 100u"m" + 10u"ft" + 2u"inch"
2757747//2500 m
Observe que como só usamos inteiros, a conversão resultou em um número racional.
Para obtermos um ponto flutuante, podemos ter multiplicar as unidades pelos números correspondente em ponto flutuante (ou pelo menos um deles, pois a conversão dos outros será forçada automaticamente).
1.0u"km" + 13u"inch"
1000.3302 m
3.0u"m" * 2.0u"1/s"
6.0 m s⁻¹
3.0u"m" * u"m/s^2"
3.0 m² s⁻²
u"𝐋" * u"𝐓"
𝐋 𝐓
uconvert(u"hr", 4352.0u"s")
1.208888888888889 hr
Não podemos somar quantidades com unidades diferentes.
Não podemos somar unidades entre si, nem dimensões entre si, muito menos entre elas.
Não podemos multiplicar uma dimensão por uma quantidade ou unidade.
Não podemos converter uma quantidade em uma unidade de outra dimensão.
1.0u"m" + 2.0u"s"
DimensionError: 1.0 m and 2.0 s are not dimensionally compatible. Stacktrace: [1] +(x::Quantity{Float64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, y::Quantity{Float64, 𝐓, Unitful.FreeUnits{(s,), 𝐓, nothing}}) @ Unitful ~/.julia/packages/Unitful/0oqX5/src/quantities.jl:137 [2] top-level scope @ In[23]:1 [3] eval @ ./boot.jl:360 [inlined] [4] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base ./loading.jl:1116
u"m" + u"m"
MethodError: no method matching +(::Unitful.FreeUnits{(m,), 𝐋, nothing}, ::Unitful.FreeUnits{(m,), 𝐋, nothing}) Closest candidates are: +(::Any, ::Any, ::Any, ::Any...) at operators.jl:560 Stacktrace: [1] top-level scope @ In[24]:1 [2] eval @ ./boot.jl:360 [inlined] [3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base ./loading.jl:1116
1u"m" * u"s" * u"𝐓"
MethodError: no method matching *(::Quantity{Int64, 𝐋 𝐓, Unitful.FreeUnits{(m, s), 𝐋 𝐓, nothing}}, ::Unitful.Dimensions{(Unitful.Dimension{:Time}(1//1),)}) Closest candidates are: *(::Any, ::Any, ::Any, ::Any...) at operators.jl:560 *(::Quantity, ::Gain) at /Users/rrosa/.julia/packages/Unitful/0oqX5/src/logarithm.jl:222 *(::Quantity, ::Level) at /Users/rrosa/.julia/packages/Unitful/0oqX5/src/logarithm.jl:211 ... Stacktrace: [1] *(::Quantity{Int64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, ::Unitful.FreeUnits{(s,), 𝐓, nothing}, ::Unitful.Dimensions{(Unitful.Dimension{:Time}(1//1),)}) @ Base ./operators.jl:560 [2] top-level scope @ In[25]:1 [3] eval @ ./boot.jl:360 [inlined] [4] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base ./loading.jl:1116
uconvert(u"g", 10u"m")
DimensionError: g and m are not dimensionally compatible. Stacktrace: [1] #s57#155 @ ~/.julia/packages/Unitful/0oqX5/src/conversion.jl:12 [inlined] [2] var"#s57#155"(::Any, s::Any, t::Any) @ Unitful ./none:0 [3] (::Core.GeneratedFunctionStub)(::Any, ::Vararg{Any, N} where N) @ Core ./boot.jl:571 [4] uconvert(a::Unitful.FreeUnits{(g,), 𝐌, nothing}, x::Quantity{Int64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}) @ Unitful ~/.julia/packages/Unitful/0oqX5/src/conversion.jl:78 [5] top-level scope @ In[26]:1 [6] eval @ ./boot.jl:360 [inlined] [7] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base ./loading.jl:1116
Podemos aproveitar a estrutura do pacote Unitful.jl
e explorar a capacidade de metaprogramação do Julia para montar um pacote que resolva os grupos adimensionais garantidos pelo Teorema de Buckingham-Pi.
Isso foi feito no pacote rmsrosa/UnitfulBuckinghamPi.jl.
Tudo o que precisamos fazer é registrar as quantidades, unidades, dimensões como parâmetros do pacote, através das macros @setparameters
e @addparameters
.
Em seguida, encontramos os grupos adimensionais com a função pi_groups()
.
Esse pacote foi inspirado no pacote em python desenvolvido Ian Rose e descrito em Automated dimensional analysis.
Primeiramente, definimos os parâmetros.
Em seguida, os registramos no pacote.
Finalmente, obtemos os grupos adimensionais.
# parâmetros
ℓ = 2u"m" # quantidade
g = 9.8u"m/s^2" # quantidade
m = u"g" # unidade
T = u"𝐓" # dimensão
θ = u"NoDims" # "dimensão" adimensional
nothing
# registro
@setparameters ℓ g m T θ
┌ Info: Parameter(s) registered: └ @ UnitfulBuckinghamPi /Users/rrosa/.julia/packages/UnitfulBuckinghamPi/OeIXt/src/UnitfulBuckinghamPi.jl:127 ┌ Info: ℓ = 2 m └ @ UnitfulBuckinghamPi /Users/rrosa/.julia/packages/UnitfulBuckinghamPi/OeIXt/src/UnitfulBuckinghamPi.jl:129 ┌ Info: g = 9.8 m s⁻² └ @ UnitfulBuckinghamPi /Users/rrosa/.julia/packages/UnitfulBuckinghamPi/OeIXt/src/UnitfulBuckinghamPi.jl:129 ┌ Info: m = g └ @ UnitfulBuckinghamPi /Users/rrosa/.julia/packages/UnitfulBuckinghamPi/OeIXt/src/UnitfulBuckinghamPi.jl:129 ┌ Info: T = 𝐓 └ @ UnitfulBuckinghamPi /Users/rrosa/.julia/packages/UnitfulBuckinghamPi/OeIXt/src/UnitfulBuckinghamPi.jl:129 ┌ Info: θ = NoDims └ @ UnitfulBuckinghamPi /Users/rrosa/.julia/packages/UnitfulBuckinghamPi/OeIXt/src/UnitfulBuckinghamPi.jl:129
# grupos adimensionais na forma de string
pi_groups(:String)
2-element Vector{String}: "g^(1//2)*ℓ^(-1//2)*T^(1//1)" "θ^(1//1)"
# grupos adimensionais na forma de expressão do Julia
Π = pi_groups(:Expr)
2-element Vector{Expr}: :(g ^ (1 // 2) * ℓ ^ (-1 // 2) * T ^ (1 // 1)) :(θ ^ (1 // 1))
Como $T$ é uma dimensão e os outros parâmetros em $\Pi[1]$ são quantidades, não podemos "avaliar" ("evaluate") $\Pi[1]$, pois não podemos multipicar uma dimensão por uma unidade ou quantidade.
Mas como $\Pi[2]$ não envolve tal multiplicação, então nesse caso não temos problema.
eval(Π[2])
NoDims
eval(Π[1])
MethodError: no method matching *(::Quantity{Float64, 𝐓⁻¹, Unitful.FreeUnits{(s⁻¹,), 𝐓⁻¹, nothing}}, ::Unitful.Dimensions{(Unitful.Dimension{:Time}(1//1),)}) Closest candidates are: *(::Any, ::Any, ::Any, ::Any...) at operators.jl:560 *(::Quantity, ::Gain) at /Users/rrosa/.julia/packages/Unitful/0oqX5/src/logarithm.jl:222 *(::Quantity, ::Level) at /Users/rrosa/.julia/packages/Unitful/0oqX5/src/logarithm.jl:211 ... Stacktrace: [1] *(::Quantity{Float64, 𝐋¹ᐟ² 𝐓⁻¹, Unitful.FreeUnits{(m¹ᐟ², s⁻¹), 𝐋¹ᐟ² 𝐓⁻¹, nothing}}, ::Quantity{Float64, 𝐋⁻¹ᐟ², Unitful.FreeUnits{(m⁻¹ᐟ²,), 𝐋⁻¹ᐟ², nothing}}, ::Unitful.Dimensions{(Unitful.Dimension{:Time}(1//1),)}) @ Base ./operators.jl:560 [2] top-level scope @ none:1 [3] eval @ ./boot.jl:360 [inlined] [4] eval(x::Expr) @ Base.MainInclude ./client.jl:446 [5] top-level scope @ In[32]:1 [6] eval @ ./boot.jl:360 [inlined] [7] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base ./loading.jl:1116
T=u"𝐓"
por uma unidade, que denotamos por $\tau$.τ = u"s"
s
@setparameters ℓ g m τ θ
┌ Info: Parameter(s) registered: └ @ UnitfulBuckinghamPi /Users/rrosa/.julia/packages/UnitfulBuckinghamPi/OeIXt/src/UnitfulBuckinghamPi.jl:127 ┌ Info: ℓ = 2 m └ @ UnitfulBuckinghamPi /Users/rrosa/.julia/packages/UnitfulBuckinghamPi/OeIXt/src/UnitfulBuckinghamPi.jl:129 ┌ Info: g = 9.8 m s⁻² └ @ UnitfulBuckinghamPi /Users/rrosa/.julia/packages/UnitfulBuckinghamPi/OeIXt/src/UnitfulBuckinghamPi.jl:129 ┌ Info: m = g └ @ UnitfulBuckinghamPi /Users/rrosa/.julia/packages/UnitfulBuckinghamPi/OeIXt/src/UnitfulBuckinghamPi.jl:129 ┌ Info: τ = s └ @ UnitfulBuckinghamPi /Users/rrosa/.julia/packages/UnitfulBuckinghamPi/OeIXt/src/UnitfulBuckinghamPi.jl:129 ┌ Info: θ = NoDims └ @ UnitfulBuckinghamPi /Users/rrosa/.julia/packages/UnitfulBuckinghamPi/OeIXt/src/UnitfulBuckinghamPi.jl:129
Π = pi_groups()
2-element Vector{Expr}: :(g ^ (1 // 2) * ℓ ^ (-1 // 2) * τ ^ (1 // 1)) :(θ ^ (1 // 1))
eval(Π[1])
2.2135943621178655
eval(Π[2])
NoDims
dimension(eval(Π[1]))
NoDims
UnitfulBuckinghamPi.jl
.