Grid Management
The grids used by Starlord are designed for linear interpolation in up to 5 dimensions, as is done with scipy.interpolate.RegularGridInterpolator. Unlike that interpolator, Starlord grids have an associated npz storage schema, which includes grid metadata for Starlord to use in constructing the interpolator and during code generation. The components of a grid are:
- name:
The name of the grid, which is also the name of its npz file.
- inputs:
Up to 5 1-d arrays that define the axes (interpolation inputs) of the grid.
- outputs:
The values to be interpolated as arrays with each dimension matching the length of the associated input.
- derived:
Values that can be calculated from the outputs; the npz file stores the Cython code to generate each value in terms of the grid’s outputs and inputs, or even those of other grids. For
ModelBuilderinputs, these can be treated the same as outputs.- design:
Describes how the grid is structured as a string containing the inputs, outputs, and derived value names. E.g.
x, y, z -> A, B, C; Derived1, Derived2- input_mappings:
During code generation, these determine what is used for each input into the interpolator (e.g. what to sub in for
x,y, andz).
Grid Creation
You can create your own grids with starlord.GridGenerator.create_grid(). The name, inputs, and outputs are required, but the others may be omitted if you aren’t going to use them. The function will check its inputs for validity and then generate the metadata for you. Here’s an example of how you can generate a grid:
from collections import OrderedDict
import numpy as np
import starlord
# Generating some input axes
x = np.linspace(0, 10, 100)
y = np.logspace(-1, 1., 20)
# Calculate some outputs (normally these would be some complex model outputs)
# I'm using numpy broadcasting but you can use nested for loops if you prefer
out1 = np.sqrt(x[:, None]) + y[None, :]**2
out2 = 2 * x[:, None]**3 + np.sqrt(y[None, :])
starlord.GridGenerator.create_grid(
grid_name="demo_grid",
inputs=OrderedDict(x=x, y=y),
outputs=dict(out1=out1, out2=out2),
derived=dict(ratio="d.demo_grid.out1 / d.demo_grid.out2"),
input_mappings=dict(x="p.x", y="10**p.log_y"),
)
In this example, we made a grid named demo_grid with the input axes x and y and made up two outputs axes out1 and out2 (very imaginative naming here). We also added a derived variable ratio that is just the ratio of out1 to out2; in making a model we could refer to ratio as if it were a regular output and Starlord would handle calculating it automatically. Finally, we set the default input of x to p.x (which is what it would be if we hadn’t specified anything) and of y to 10**p.log_y, to show how we could define the interpolation on a linear scale but sample on a log scale.
Note
In astronomy, grids are sometimes stored as a list of grid points (often in csv files), where the input axes are one set of columns and the output values are another. So long as these are proper regular grids, they can be converted into a set of input axes and output nd-arrays with starlord.GridGenerator.restructure_grid().
Usage
import starlord
# Load from Starlord's known grids list (those in its directory)
grid1 = starlord.GridGenerator.get_grid("grid1")
# Load from a particular file
grid2 = starlord.GridGenerator("./path/to/grid2.npz")
# Create an interpolator and use it
get_foo = grid1.build_grid("foo")
xt = np.array([0.5, 2.3])
print(xt, get_foo(xt))
Note
A starlord.GridGenerator will build starlord.GridInterpolator objects. These are much faster than scipy.interpolate options, but are less flexible – they do not support Numpy-style array broadcasting. This was an intentional trade-off to achieve maximum sampling speeds.