# Best Practice for Lookup Table Definition

**URL:** <https://discourse.julialang.org/t/best-practice-for-lookup-table-definition/39543>\
**Category:** General Usage\
**Created:** [May 15, 2020, 6:03pm UTC](https://discourse.julialang.org/t/best-practice-for-lookup-table-definition/39543 "2020-05-15T18:03:31Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![forever\_learning](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/forever_learning/32/14880_2.png) [@forever\_learning](https://discourse.julialang.org/u/forever_learning)\
**Post date:** [May 15, 2020, 6:03pm UTC](https://discourse.julialang.org/t/best-practice-for-lookup-table-definition/39543/1 "2020-05-15T18:03:31Z")

</div>

Hello,

I am looking for some guidance on what the idiomatic way to define a small database of objects/materials might be. For example, this might pertain to a small set of materials and their associated material properties, or, as shown below, a table of battery cells available for selection and use in a larger analysis. There might be anywhere from 3-30 elements in a small database like this and they are small enough to be written (and later extended) by hand.

I am looking for advice on both the creation/definition of these lookup tables / databases and the form they end up taking (I am totally flexible to go in any direction at the moment). The dictionary of structs created below works perfectly fine but seems for some reason to be missing out on the similarity of the objects within the dictionary.

In the end this database definition ideally has these characteristics, roughly in order of importance:

- Follows Julia best-practices, this is largely a learning experience for myself and partially for additional users. I am trying to move some of these larger system analyses from Matlab to Julia and would like to be able to make the case for potential future Julia use to colleagues
- Ease of use. It should be straightforward to select an element/row by name and pass all of its properties to a function
- Accessible (both readable and extendable) by additional users who likely are not familiar with Julia
- Traceable to a specification, so the numbers seen in the database correlate to numbers available on the spec sheet and any wrangling to fit the struct fields is visible and obvious. This wrangling may be slightly different for each added element depending on the information available in the specification.
- Single file that defines the entire database
- Flexible to various datatypes. For example, the energy and power fields in the example below might be 2 elements, they might be 20. This is tough to represent in spreadsheet databases like Excel or csv.
- Fast during runtime
- It would be great if this file had the look/feel of a static configuration file. I have a feeling this might directly contradict the above desired characteristics.

```julia
module BatteryCell

using Unitful.DefaultSymbols
using Unitful: hr

export LUT

abstract type AbstractCell end

ED(A::AbstractCell) = A.energy / A.volume
PD(A::AbstractCell) = A.power / A.volume
#...other heuristics available

struct BatteryCell <: AbstractCell
    volume::typeof(1.0m^3)
    voltage::typeof(1.0V)
    power::Vector{typeof(1.0W)}
    energy::Vector{typeof(1.0J)}
    #...a few more fields here
end

cyl_vol(l,d) = l * π * (d/2)^2
pris_vol(l,w,h) = l * w * h

#Make lookup table for use
LUT = Dict{String,BatteryCell}()

#Now add cell definitions in one at a time? Is it more idiomatic to wrap all this in a function call?
# LFP_26650 https://www.batteryspace.com/lifepo4-26650-rechargeable-cell-3-2v-3300-mah-19-8a-rate-10wh---un38-3-passed-ndgr.aspx
len = 65.5mm
dia = 26.3mm
vol = cyl_vol(len,dia)
volt = 3.2V
power = volt * [0, 0.2, 0.5, 1, 2, 3]hr^(-1) * 3200mA*hr #W from provided c-rates
energy = volt * [3250,3250,3200,3150,3100,3050]mA*hr
LUT["LFP_26650"] = BatteryCell(vol,mass,volt,resist,cost,power,energy)

# LFP_18650 https://www.batteryspace.com/lifepo4-18650-rechargeable-cell-3-2v-1500-mah-8-4a-rate-4-32wh-ul-listed-un38-3-passed-ndgr.aspx
len = 65.5mm
dia = 18.6mm
vol = cyl_vol(len,dia)
volt = 3.2V
power = volt * [0, 0.2, 0.5, 1, 2, 3]hr^(-1) * 3200mA*hr #W from provided c-rates
energy = volt * [1500,1500,1450,1400,1400,1400]mA*hr       
LUT["LFP_18650"] = BatteryCell(vol,mass,volt,resist,cost,power,energy)

# LFP_G100 https://www.batteryspace.com/prod-specs/5907-100Ah.pdf
len = 140mm
wid = 62mm
height = 243mm
vol = pris_vol(len,wid,height)
volt = 3.2V
power = [3.2, 3.2, 3.2, 3.0]V .* [0, 0.5, 1, 3]hr^(-1) * 100A*hr
energy = [3.2, 3.2, 3.2, 3.0]V .* [110, 110, 110, 100]A*hr
LUT["LFP_G100"] = BatteryCell(vol,mass,volt,resist,cost,power,energy)

#...10ish more candidate battery cells...

end

```

I realize there are a ton of different ways to get this done, each with their own pros/cons. Thank you all for any advice you may have to offer!

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [May 15, 2020, 8:18pm UTC](https://discourse.julialang.org/t/best-practice-for-lookup-table-definition/39543/2 "2020-05-15T20:18:39Z")

</div>

Using a dictionary with structs as values, as you have done, is entirely reasonable. What do you mean by “but seems for some reason to be missing out on the similarity of the objects within the dictionary”?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [May 16, 2020, 7:02am UTC](https://discourse.julialang.org/t/best-practice-for-lookup-table-definition/39543/3 "2020-05-16T07:02:48Z")

</div>

First, I would go easy on the globals and just define an (outer) constructor that figures out `vol` and `power` from the rest of the fields with extra information (whenever applicable).

Then make a `Dict` with simply the syntax

```julia
Dict(["LFP_26650" => BatteryCell(len = 65.5mm,
                                 dia = 26.3mm,
                                 volt = 3.2V,
                                 ...),
      ...
      ])

```

For 30+ items, I think a dictionary is fine.

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [May 16, 2020, 8:53am UTC](https://discourse.julialang.org/t/best-practice-for-lookup-table-definition/39543/4 "2020-05-16T08:53:58Z")

</div>

To expand on the solution above, I would perhaps define a macro in order to build `BatteryCell` instances more easily:

```julia
# Minimal example
struct BatteryCell
    vol
end

```

```julia
macro battery_cell(exprs)
    display(exprs)
    quote
        let
            $exprs
            BatteryCell(vol)
        end
    end
end

# @battery_cell begin
# len = 65.5
# dia = 26.3
# vol = len * π * dia^2 / 4
# end
#
# expands roughly to:
# let
# begin
# var"#49#len" = 65.5
# var"#50#dia" = 26.3
# var"#51#vol" = (var"#49#len" * Main.π * var"#50#dia" ^ 2) / 4
# end
# Main.BatteryCell(var"#51#vol")
# end

```

Then the LUT can be defined in a [“code is data, data is code”](https://en.wikipedia.org/wiki/Code_as_data) way:

```julia
const INSTRUMENTS = Dict(
    :LFP_26650 => @battery_cell(begin
                               len = 65.5
                               dia = 26.3
                               vol = len * pi * dia^2 / 4
                               end),

    :LFP_G100 => @battery_cell(begin
                               len = 140.
                               wid = 62.
                               hgt = 243.
                               vol = len * wid * hgt
                               end)
)

```
