# Utility methods and types

This module provides miscellaneous utility methods and types that are used throughout the `CryoGrid.jl`

codebase. Note that the `Utils`

module is not exported by the top-level `CryoGrid`

module. It may, however, be explicitly imported by the user via `using CryoGrid.Utils`

or `import CryoGrid.Utils`

when needed.

`CryoGrid.Utils.Named`

— Type`Named{name,T}`

Wraps a value of type `T`

with a `name`

type parameter.

`CryoGrid.Utils.NamedTupleWrapper`

— Type`NamedTupleWrapper`

Base type for container types that hold a `NamedTuple`

of arbitrary field values. `NamedTupleWrapper`

provides dispatches for `getproperty`

and `propertynames`

that forward property name queries to the `NamedTuple`

container. Subtypes are by default assumed to have a field named `values`

that corresponds to the `NamedTuple`

container, but this can be overriden by providing a dispatch for `Base.values`

.

`CryoGrid.Utils.applyunits`

— Method`applyunits(u::Unitful.Units, x::Number)`

Conditionally applies unit `u`

to `x`

if and only if `x`

is a unit-free quantity. If `x`

is a unitful quantity, asserts that the unit matches `u`

.

`CryoGrid.Utils.convert_t`

— Method```
convert_t(t::DateTime)
convert_t(t::Float64)
```

Convenience method for converting between `Dates.DateTime`

and solver time.

`CryoGrid.Utils.convert_tspan`

— Method```
convert_tspan(tspan::Tuple{DateTime,DateTime})
convert_tspan(tspan::Tuple{Float64,Float64})
```

Convenience method for converting between `Dates.DateTime`

and solver time.

`CryoGrid.Utils.fastiterate`

— Method`fastiterate(f!::F, iters::NTuple{N,Any}...) where {F,N}`

Same as `fastmap`

but simply invokes `f!`

on each argument set without constructing a tuple.

`CryoGrid.Utils.fastmap`

— Method`fastmap(f::F, iter::NTuple{N,Any}...) where {F,N}`

Same as `map`

for `NTuple`

s but with guaranteed type stability. `fastmap`

is a `@generated`

function which unrolls calls to `f`

into a loop-free tuple construction expression.

`CryoGrid.Utils.getscalar`

— Method```
getscalar(x)
getscalar(x, i)
```

Helper method for generalizing between arrays and scalars. Without an index, retrieves the first element of `x`

if `x`

is an array, otherwise simply returning `x`

. If an index `i`

, is specified, returns the `i`

th value of `x`

if `x`

is an array, or `x`

otherwise. Note that this method is not strictly necessary since Julia allows for scalar quantities to be accessed at the first index like an array; however, the point is to make it expliclty clear in scalar-typed code that a state variable is treated as such and is not a vector valued quantity.

`CryoGrid.Utils.pstrip`

— Method`pstrip(obj; keep_units=false)`

Strips `Param`

types and units from `obj`

. If `keep_units=true`

, then `Param`

types will be stripped but units preserved.

`CryoGrid.Utils.tuplejoin`

— Method`tuplejoin([x, y], z...)`

Concatenates one or more tuples together; should generally be type stable.

`CryoGrid.Utils.@UFloat_str`

— MacroSimilar to Unitful.@u_str (i.e. u"kg") but produces the type of the quantity rather than the instance. NOT conditional on debug mode.

`CryoGrid.Utils.@UT_str`

— MacroSimilar to Unitful.@u_str (i.e. u"kg") but produces the type of the unit rather than the instance. NOT conditional on debug mode.

`CryoGrid.Utils.@pstrip`

— Macro`@pstrip(expr, kwargs...)`

Convenience macro for `Utils.pstrip`

; equivalent to `pstrip(expr, kwargs...)`

.

`CryoGrid.Utils.@setscalar`

— MacroConvenience macro for setting scalar (single-element) arrays/vectors. It turns an expression of the form: `a.b = ...`

into `a.b[1] = ...`

This is primarily intended for code clarity, i.e to clearly discern scalar and non-scalar values.

`CryoGrid.Utils.@sym_str`

— Macro`sym_str(val)`

Convenience macro, `sym"val"`

, for creating a `Symbol`

from `val`

. Equivalent to `Symbol(val)`

. Use in situations where normal Julia `:val`

syntax is not possible, e.g. `sym"1"`

instead of `Symbol(1)`

or `sym"my.var"`

instead of `Symbol("my.var")`

.

`CryoGrid.Utils.@threaded`

— MacroPrepends `expr`

with `Threads.@threads`

if and only if `Threads.nthreads() > 1`

, thus avoiding the overhead of `@threads`

when running in single-threaded mode.

Credit to @ranocha (Hendrik Ranocha) https://discourse.julialang.org/t/overhead-of-threads-threads/53964/22