I have noticed that the code for the piecewise linear interpolation in InputInterface::_interp_cosmo_data
does not work as intended. In particular the follwoing line is not doing what is intended
|
ix = np.argmin( np.abs( x - val_log ) ) |
Judging from the logic of the code, this line is supposed to return the index ix
of the data point which is to the left of the point in question, but what it actually returns is the index of the data point which is the closest, which might also lie to the right of the point in question.
This will in general lead to discontinuities right in the middle between two data points (cf. plots below). Assuming that the x-values are in increasing order, it is also important to check whether the closest data point has a value x[ix]
that is bigger than val
. If so, ix
has to be decreased by one. Note that this will automatically include the rather artificial decrease of ix
when ix
points to the end of the x-array. Therefore, it is sufficient to replace the line if ix == N - 1:
by if x[ix] >= log_val:
. In the case the initial x-array is not sorted in increasing order, both arrays x
and y
have to be sorted first.
Attached you will find plots that show the issue in a minimal working example. The red line denotes the original test function and the red dots refer to the discrete data points. The blue line shows the result of the buggy interpolation, whereas the yellow line shows the interpolation after the fix is applied.
For x
in increasing order the plot is shown here, the corresponding plot for x in decreasing order is shown
here.
The code for this MWE can be found here (note to change the file type from .py.txt
back to .py
as github does not allow for .py
files to be uploaded.
I suggest to fix this issue by changing
def _interp_cosmo_data(self, val, xc, yc):
x = self._sCosmoDataLog[:,xc]
y = self._sCosmoDataLog[:,yc]
N = self._sCosmoDataShp[0]
val_log = log10(val)
# Extract the index corresponding to
# the data entries above and below 'val'
ix = np.argmin( np.abs( x - val_log ) )
if ix == N - 1:
ix -= 1
m = (y[ix+1] - y[ix])/(x[ix+1] - x[ix])
b = y[ix] - m*x[ix]
return 10**(m*val_log + b)
to
def _interp_cosmo_data(self, val, xc, yc):
x = self._sCosmoDataLog[:,xc]
y = self._sCosmoDataLog[:,yc]
N = self._sCosmoDataShp[0]
# Sort x and y in increasing order
o = np.argsort(x)
x = x[o]
y = y[o]
val_log = log10(val)
# Extract the index corresponding to
# the data entries above and below 'val'
ix = np.argmin( np.abs( x - val_log ) )
if x[ix] >= val_log:
ix -= 1
m = (y[ix+1] - y[ix])/(x[ix+1] - x[ix])
b = y[ix] - m*x[ix]
return 10**(m*val_log + b)
in acropolis/input.py
starting at line 98.
Note that as long as the original function is sampled well enough, this bug is not as severe, but it should be fixed anyway.
Cheers,
Patrick