Naming Simulations
Here we overview functionality that helps you quickly produce containers of parameters and name them using a consistent and intuitive naming scheme.
Naming Schemes
A robust naming scheme allows you to create quick names for simulations, create lists of simulations, check existing simulations, etc. More importantly it allows you to easily create simulation-based names consistently and deterministically.
This is what the function savename
does. Of course, you don't have to use it only for using names to save files. You could use it for anything that fits you (like e.g. adding identifiers to tabular data).
DrWatson.savename
— Function.savename([prefix,], c [, suffix]; kwargs...)
Create a shorthand name, commonly used for saving a file, based on the parameters in the container c
(Dict
, NamedTuple
or any other Julia composite type, e.g. created with Parameters.jl). If provided use the prefix
and end the name with .suffix
(i.e. you don't have to include the .
in your suffix
).
The function chains keys and values into a string of the form:
key1=val1_key2=val2_key3=val3
while the keys are always sorted alphabetically. If you provide the prefix/suffix the function will do:
prefix_key1=val1_key2=val2_key3=val3.suffix
assuming you chose the default connector
, see below. Notice that prefix
can be any path and in addition if it ends as a path (/
or \
) then the connector
is ommited.
savename
can be very conveniently combined with @dict
or @ntuple
.
Keywords
allowedtypes = default_allowed(c)
: Only values of type subtyping anything inallowedtypes
are used in the name. By default this is(Real, String, Symbol)
.accesses = allaccess(c)
: You can also specify which specific keys you want to use with the keywordaccesses
. By default this is all possible keysc
can be accessed with, seeallaccess
.digits = 3
: Floating point values are rounded todigits
. In addition if the following holds:
then the integer value is used in the name instead.round(val; digits = digits) == round(Int, val)
connector = "_"
: string used to connect the various entries.
Examples
d = (a = 0.153456453, b = 5.0, mode = "double")
savename(d; digits = 4) == "a=0.1535_b=5_mode=double"
savename("n", d) == "n_a=0.153_b=5_mode=double"
savename("n/", d) == "n/a=0.153_b=5_mode=double"
savename(d, "n") == "a=0.153_b=5_mode=double.n"
savename("data/n", d, "n") == "data/n_a=0.153_b=5_mode=double.n"
savename("n", d, "n"; connector = "-") == "n-a=0.153-b=5-mode=double.n"
savename(d, allowedtypes = (String,)) == "mode=double"
rick = (never = "gonna", give = "you", up = "!");
savename(rick) == "give=you_never=gonna_up=!" # keys are sorted!
DrWatson.@dict
— Macro.@dict vars...
Create a dictionary out of the given variables that has as keys the variable names and as values their values.
Notice: @dict a b
is the correct way to call the macro. @dict a, b
is incorrect. If you want to use commas you have to do @dict(a, b)
.
Examples
julia> ω = 5; χ = "test"; ζ = π/3;
julia> @dict ω χ ζ
Dict{Symbol,Any} with 3 entries:
:ω => 5
:χ => "test"
:ζ => 1.0472
DrWatson.@strdict
— Macro.@strdict vars...
Same as @dict
but the key type is String
.
DrWatson.@ntuple
— Macro.@ntuple vars...
Create a NamedTuple
out of the given variables that has as keys the variable names and as values their values.
Examples
julia> ω = 5; χ = "test"; ζ = 3.14;
julia> @ntuple ω χ ζ
(ω = 5, χ = "test", ζ = 3.14)
Notice that this naming scheme integrates perfectly with Parameters.jl.
Two convenience functions are also provided to easily switch between named tuples and dictionaries:
DrWatson.ntuple2dict
— Function.ntuple2dict(nt) -> dict
Convert a NamedTuple
to a dictionary.
DrWatson.dict2ntuple
— Function.dict2ntuple(dict) -> ntuple
Convert a dictionary (with Symbol
or String
as key type) to a NamedTuple
.
Customizing savename
You can customize savename
for your own Types. For example you could make it so that it only uses some specific keys instead of all of them, only specific types, or you could make it access data in a different way (maybe even loading files!). You can even make it have a custom prefix
!
To do that you may extend the following functions:
DrWatson.allaccess
— Function.allaccess(c)
Return all the keys c
can be accessed using access
. For dictionaries/named tuples this is keys(c)
, for everything else it is fieldnames(typeof(c))
.
DrWatson.access
— Function.access(c, key)
Access c
with given key. For AbstractDict
this is getindex
, for anything else it is getproperty
.
access(c, keys...)
When given multiple keys, access
is called recursively, i.e. access(c, key1, key2) = access(access(c, key1), key2)
and so on. For example, if c, c.k1
are NamedTuple
s then access(c, k1, k2) == c.k1.k2
.
Please only extend the single key method when customizing access
for your own Types.
DrWatson.default_allowed
— Function.default_allowed(c) = (Real, String, Symbol)
Return the (super-)Types that will be used as allowedtypes
in savename
or other similar functions.
DrWatson.default_prefix
— Function.default_prefix(c) = ""
Return the prefix
that will be used by default in savename
or other similar functions.
See Real World Examples for an example of customizing savename
.