Skip to content

Commit 27e12eb

Browse files
committed
add linear fallback mode. It is slower than before, but more generic
1 parent b5be696 commit 27e12eb

File tree

7 files changed

+449
-50
lines changed

7 files changed

+449
-50
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Version 0.6.0
22
* switch to cubic interpolation for isochrones and bolometric corrections
3+
* add `linear=True` option to keep legacy poly-linear interpolation behavior
34
* improved robustness at grid boundaries
45

56
# Version 0.5.0

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ In order to create an interpolator object for two filters (your can provide a li
4343

4444
```ii = minimint.Interpolator(['DECam_g','DECam_r'])```
4545

46+
To force legacy poly-linear interpolation (instead of cubic), use:
47+
48+
```ii = minimint.Interpolator(['DECam_g','DECam_r'], linear=True)```
49+
4650
The interpolator is a callable, so you can call it on mass, log10(age), feh
4751

4852
``` ii(mass, logage, feh)```

examples/Example.ipynb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
},
4343
{
4444
"cell_type": "code",
45-
"execution_count": 4,
45+
"execution_count": 6,
4646
"metadata": {},
4747
"outputs": [],
4848
"source": [
@@ -52,7 +52,7 @@
5252
},
5353
{
5454
"cell_type": "code",
55-
"execution_count": 5,
55+
"execution_count": 7,
5656
"metadata": {},
5757
"outputs": [
5858
{
@@ -61,7 +61,7 @@
6161
"(20.0, -5.0)"
6262
]
6363
},
64-
"execution_count": 5,
64+
"execution_count": 7,
6565
"metadata": {},
6666
"output_type": "execute_result"
6767
},
@@ -95,7 +95,7 @@
9595
},
9696
{
9797
"cell_type": "code",
98-
"execution_count": 6,
98+
"execution_count": 8,
9999
"metadata": {},
100100
"outputs": [
101101
{
@@ -104,7 +104,7 @@
104104
"(-0.2, 1.5)"
105105
]
106106
},
107-
"execution_count": 6,
107+
"execution_count": 8,
108108
"metadata": {},
109109
"output_type": "execute_result"
110110
},

py/minimint/bolom.py

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ def _interpolator_4cubic(grid, ws, idxs):
2121
ws: list of 4 weight arrays, each of shape (N, 4)
2222
idxs: list of 4 index arrays, each of shape (N, 4)
2323
"""
24+
# 4D tensor-product cubic:
25+
# f=Σ_i Σ_j Σ_k Σ_l w0_i w1_j w2_k w3_l f(i,j,k,l)
2426
res = np.zeros(ws[0].shape[0])
2527
for i in range(4):
2628
w_i = ws[0][:, i]
@@ -43,6 +45,8 @@ def _interpolator_5cubic(grid, ws, idxs):
4345
Perform 5D cubic interpolation for bolometric corrections.
4446
The dimensions are usually logTeff, logg, [Fe/H], [alpha/Fe], and Av.
4547
"""
48+
# 5D tensor-product cubic:
49+
# f=Σ_i Σ_j Σ_k Σ_l Σ_m Π_d w_d * f(vertex)
4650
res = np.zeros(ws[0].shape[0])
4751
for i in range(4):
4852
w_i = ws[0][:, i]
@@ -131,7 +135,7 @@ def read_bolom(filt, iprefix):
131135

132136
class BCInterpolator:
133137

134-
def __init__(self, prefix, filts):
138+
def __init__(self, prefix, filts, linear=False):
135139
filts = set(filts)
136140
vec = np.load(prefix + '/' + POINTS_NPY)
137141
ndim = vec.shape[0]
@@ -149,6 +153,7 @@ def __init__(self, prefix, filts):
149153
for a in itertools.product(*[[0, 1]] * self.ndim):
150154
self.box_list.append((a))
151155
self.box_list = np.array(self.box_list)
156+
self.linear = bool(linear)
152157
self._warned_feh_floor = False
153158
for f in filts:
154159
curd = np.zeros(size) - np.nan
@@ -170,6 +175,8 @@ def __call__(self, p):
170175
bad = np.zeros(p.shape[0], dtype=bool)
171176
ws = []
172177
idxs = []
178+
pos1 = np.zeros(p.shape, dtype=int)
179+
xs = np.zeros(p.shape)
173180
for i in range(self.ndim):
174181
p_dim = p[:, i]
175182
# For BC interpolation, clamp very metal-poor values to the BC
@@ -185,14 +192,26 @@ def __call__(self, p):
185192
p_dim = clipped
186193
pos = np.searchsorted(self.uvecs[i], p_dim, 'right') - 1
187194
bad = bad | (pos < 0) | (pos >= (len(self.uvecs[i]) - 1))
188-
# Clip pos for cubic neighbors
189-
pos_clipped = np.clip(pos, 0, len(self.uvecs[i]) - 2)
190-
w, idx = _get_cubic_coeffs(p_dim, self.uvecs[i], pos_clipped)
191-
ws.append(w)
192-
idxs.append(idx)
195+
pos1[:, i] = np.clip(pos, 0, len(self.uvecs[i]) - 2)
196+
xs[:, i] = (p_dim - self.uvecs[i][pos1[:, i]]) / (
197+
self.uvecs[i][pos1[:, i] + 1] - self.uvecs[i][pos1[:, i]])
198+
if not self.linear:
199+
w, idx = _get_cubic_coeffs(p_dim, self.uvecs[i], pos1[:, i])
200+
ws.append(w)
201+
idxs.append(idx)
193202

194203
for f in self.filts:
195-
if self.ndim == 4:
204+
if self.linear:
205+
curinds = pos1[None, :, :] + self.box_list[:, None, :]
206+
# N-D poly-linear interpolation over BC grid:
207+
# BC(p) = Σ_v [Π_d x_d^a_{v,d}(1-x_d)^(1-a_{v,d})] * BC(vertex_v)
208+
curcoeffs = (
209+
xs[None, :, :]**self.box_list[:, None, :] *
210+
(1 - xs[None, :, :])**(1 - self.box_list)[:, None, :]
211+
).prod(axis=2)
212+
curinds1 = np.ravel_multi_index(curinds.T, self.dats[f].shape)
213+
curres = (self.dats[f].flat[curinds1] * curcoeffs.T).sum(axis=1)
214+
elif self.ndim == 4:
196215
curres = _interpolator_4cubic(self.dats[f], ws, idxs)
197216
elif self.ndim == 5:
198217
curres = _interpolator_5cubic(self.dats[f], ws, idxs)

0 commit comments

Comments
 (0)