[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnuastro-commits] master 1a91475 2/2: Wrappers for GSL's 1D interpolati
From: |
Mohammad Akhlaghi |
Subject: |
[gnuastro-commits] master 1a91475 2/2: Wrappers for GSL's 1D interpolation added to library |
Date: |
Tue, 29 May 2018 21:25:06 -0400 (EDT) |
branch: master
commit 1a91475545152a77590411b5bab13491145b67f1
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>
Wrappers for GSL's 1D interpolation added to library
Two basic wrappers were added to make it easy for using GSL's 1D
interpolation functions with datasets stored in Gnuastro's `gal_data_t'.
Some minor corrections in the indexs of the manual were also found and are
also commited here.
Also, while working on text files, I noticed that the error message when
trying to read a text table wasn't too clear, so it is made more clear with
this commit.
---
NEWS | 6 +-
doc/gnuastro.texi | 251 +++++++++++++++++++++++++++++++++------
lib/gnuastro/interpolate.h | 20 +++-
lib/interpolate.c | 289 +++++++++++++++++++++++++++++++++++++++++++++
lib/txt.c | 2 +-
5 files changed, 525 insertions(+), 43 deletions(-)
diff --git a/NEWS b/NEWS
index 1f2ca39..db4fa6b 100644
--- a/NEWS
+++ b/NEWS
@@ -82,6 +82,8 @@ GNU Astronomy Utilities NEWS -*-
outline -*-
gal_eps_suffix_is_eps: Returns 1 if given suffix is EPS.
gal_eps_to_pt: Converts dataset size to PostScript points.
gal_eps_write: Writes a dataset into an EPS file.
+ gal_interpolate_1d_blank: Fill blank elements through interpolation.
+ gal_interpolate_1d_make_gsl_spline: Allocate and initalize `gsl_spline'.
gal_jpeg_name_is_jpeg: Returns 1 if given filename is JPEG.
gal_jpeg_suffix_is_jpeg: Returns 1 if given suffix is JPEG.
gal_jpeg_read: Reads input JPEG image into `gal_data_t'.
@@ -95,8 +97,8 @@ GNU Astronomy Utilities NEWS -*-
outline -*-
gal_pointer_allocate_mmap: Allocate space in a file, not in RAM.
gal_qsort_index_single_d: Sort indexs of single array in decreasing order.
gal_qsort_index_single_i: Sort indexs of single array in decreasing order.
- gal_qsort_index_multi_d: Sort indexs in multiple arrays (on different
threads).
- gal_qsort_index_multi_i: Sort indexs in multiple arrays (on different
threads).
+ gal_qsort_index_multi_d: Sort indexs in multiple arrays (different
threads).
+ gal_qsort_index_multi_i: Sort indexs in multiple arrays (different
threads).
gal_tiff_name_is_tiff: check if name contains a TIFF suffix.
gal_tiff_suffix_is_tiff: check if suffix is a TIFF suffix.
gal_tiff_dir_string_read: convert a string to a TIFF directory number.
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index d1f9924..e8f9ba5 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -1423,13 +1423,13 @@ tablets which allow you to do this.
@cindex Inconsistent results
According to Wikipedia ``a software bug is an error, flaw, failure, or
fault in a computer program or system that causes it to produce an
-incorrect or unexpected result, or to behave in unintended ways''. So
-when you see that a program is crashing, not reading your input
-correctly, giving the wrong results, or not writing your output
-correctly, you have found a bug. In such cases, it is best if you
-report the bug to the developers. The programs will also report bugs
-in known impossible situations (which are caused by something
-unexpected) and will ask the users to report the bug.
+incorrect or unexpected result, or to behave in unintended ways''. So when
+you see that a program is crashing, not reading your input correctly,
+giving the wrong results, or not writing your output correctly, you have
+found a bug. In such cases, it is best if you report the bug to the
+developers. The programs will also inform you if known impossible
+situations occur (which are caused by something unexpected) and will ask
+the users to report the bug issue.
@cindex Bug reporting
Prior to actually filing a bug report, it is best to search previous
@@ -4987,6 +4987,8 @@ line.
@item Debian-based OSs (@command{apt-get})
@cindex Debian
@cindex Ubuntu
address@hidden @command{apt-get}
address@hidden Advanced Packaging Tool (APT, Debian)
Debian-based GNU/Linux
address@hidden@url{https://en.wikipedia.org/wiki/List_of_Linux_distributions#Debian-based}}
(for example Ubuntu or its derivatives) are arguably the largest, and most
@@ -5002,6 +5004,9 @@ $ sudo apt-get install ghostscript libtool-bin
libjpeg-dev \
@item macOS (@command{brew})
@cindex macOS
address@hidden Homebrew
address@hidden MacPorts
address@hidden @command{brew}
macOS is the operating system used on Apple devices
(@url{https://en.wikipedia.org/wiki/MacOS}). macOS does not come with a
package manager pre-installed, but several widely used, third-party package
@@ -5025,6 +5030,7 @@ $ brew install wcslib
@item Arch Linux (@command{pacman})
@cindex Arch Linux
address@hidden @command{pacman}
Arch Linux is a smaller GNU/Linux distribution. As discussed in
@url{https://en.wikipedia.org/wiki/Arch_Linux, Wikipedia}, it follows ``the
KISS principle ("keep it simple, stupid") as the general guideline, and
@@ -23677,7 +23683,7 @@ $ asttable --info table.fits
@end example
@end deftypefun
address@hidden {gal_data_t *} gal_table_read (char @code{*filename}, char
@code{*hdu}, gal_list_str_t @code{*cols}, int @code{searchin}, int
@code{ignorecase}, size_t @code{minmapsize}, size_t @code{colmatch})
address@hidden {gal_data_t *} gal_table_read (char @code{*filename}, char
@code{*hdu}, gal_list_str_t @code{*cols}, int @code{searchin}, int
@code{ignorecase}, size_t @code{minmapsize}, size_t @code{*colmatch})
Read the specified columns in a text file (named @code{filename}) into a
linked list of data structures. If the file is FITS, then @code{hdu} will
also be used, otherwise, @code{hdu} is ignored.
@@ -26872,7 +26878,7 @@ inside @code{indexs}. If @code{withrivers} is non-zero,
then pixels that
are immediately touching more than one positive value will be given a
@code{GAL_LABEL_RIVER} label.
address@hidden GNU C Library
address@hidden GNU C library
Note that the @code{indexs->array} is not re-allocated to its new size at
the address@hidden that according to the GNU C Library, even a
@code{realloc} to a smaller size can also cause a re-write of the whole
@@ -26942,34 +26948,35 @@ is much faster.
@node Interpolation, Git wrappers, Convolution functions, Gnuastro library
@subsection Interpolation (@file{interpolate.h})
-During data analysis, it often happens that parts of the data cannot be
-given a value. For example your image was saturated due to a very bright
-start and you have to mask that star's footprint. One other common
-situation in Gnuastro is when we do processing on tiles (for example to
-estimate the Sky value and its Standard deviation, see @ref{Sky
-value}). Some tiles must not be used for the estimation of the Sky value,
-for example because they cover a large galaxy. So we need to fill them in
-with blank values. But ultimately, we need a Sky value for every
-pixel. This job (assigning a value to blank element(s) based on their
-nearby neighbors with a value) is known as interpolation.
-
-There are many ways to do interpolation, but (mainly due to lack of time),
-currently Gnuastro only contains the (median of) nearest-neighbor
-method. The power of this method of interpolation is its non-parametric
-nature. The produced values are also always within the range of the known
-values and strong outliers do not get created. We will hopefully implement
-other methods too (wrappers around the GNU Scientific Library's very
-complete set of functions), but currently the developers are too busy. So
-if you do have the chance to help, your contribution would be very welcome
-and appreciated.
address@hidden Sky line
address@hidden Interpolation
+During data analysis, it happens that parts of the data cannot be given a
+value, but one is necessary for the higher-level analysis. For example a
+very bright star saturated part of your image and you need to fill in the
+saturated pixels with some values. Another common usage case are masked
+sky-lines in 1D specra that similarly need to be assigned a value for
+higher-level analysis. In other situations, you might want a value in an
+arbitrary point: between the elements/pixels where you have data. The
+functions described in this section are for such operations.
+
address@hidden GNU Scientific Library
+The parametric interpolations discussed below are wrappers around the
+interpolation functions of the GNU Scientific Library (or GSL, see @ref{GNU
+Scientific Library}). To identify the different GSL interpolation types,
+Gnuastro's @file{gnuastro/interpolate.h} header file contains macros that
+are discussed below. The GSL wrappers provided here are not yet complete
+because we are too busy. If you need them, please consider helping us in
+adding them to Gnuastro's library. Your would be very welcome and
+appreciated.
@deftypefun {gal_data_t *} gal_interpolate_close_neighbors (gal_data_t
@code{*input}, struct gal_tile_two_layer_params @code{*tl}, size_t
@code{numneighbors}, size_t @code{numthreads}, int @code{onlyblank}, int
@code{aslinkedlist})
Interpolate the values in the image using the median value of their
address@hidden closest neighbors. If @code{onlyblank} is non-zero,
-then only blank elements will be interpolated and pixels that already have
-a value will be left untouched. This function is multi-threaded and will
-run on @code{numthreads} threads (see @code{gal_threads_number} in
address@hidden programming}).
address@hidden closest neighbors. This function is non-parametric and
+thus agnostic to the input's number of dimension. If @code{onlyblank} is
+non-zero, then only blank elements will be interpolated and pixels that
+already have a value will be left untouched. This function is
+multi-threaded and will run on @code{numthreads} threads (see
address@hidden in @ref{Multithreaded programming}).
@code{tl} is Gnuastro's two later tessellation structure used to define
tiles over an image and is fully described in @ref{Tile grid}. When
@@ -26979,11 +26986,177 @@ properties, for example to not interpolate over
channel borders.
If several datasets have the same set of blank values, you don't need to
call this function multiple times. When @code{aslinkedlist} is non-zero,
-then @code{input} will be seen as a @ref{List of gal_data_t} and for all
-the same neighbor position checking will be done for all the datasets in
-the list. Of course, the values for each dataset will be different, so a
-different value will be written in the each dataset, but the neighbor
-checking that is the most CPU intensive part will only be done once.
+then @code{input} will be seen as a @ref{List of gal_data_t}. In this case,
+the same neighbors will be used for all the datasets in the list. Of
+course, the values for each dataset will be different, so a different value
+will be written in the each dataset, but the neighbor checking that is the
+most CPU intensive part will only be done once.
+
+This is a non-parametric and robust function for interpolation. The
+interpolated values are also always within the range of the non-blank
+values and strong outliers do not get created. However, this type of
+interpolation must be used with care when there are gradients. This is
+because it is non-parametric and if there aren't enough neighbors,
+step-like features can be created.
address@hidden deftypefun
+
address@hidden Macro GAL_INTERPOLATE_1D_INVALID
+This is just a place holder to manage errors.
address@hidden deffn
address@hidden Macro GAL_INTERPOLATE_1D_LINEAR
+[From GSL:] Linear interpolation. This interpolation method does not
+require any additional memory.
address@hidden deffn
address@hidden Macro GAL_INTERPOLATE_1D_POLYNOMIAL
address@hidden Polynomial interpolation
address@hidden Interpolation: Polynomial
+[From GSL:] Polynomial interpolation. This method should only be used for
+interpolating small numbers of points because polynomial interpolation
+introduces large oscillations, even for well-behaved datasets. The number
+of terms in the interpolating polynomial is equal to the number of points.
address@hidden deffn
address@hidden Macro GAL_INTERPOLATE_1D_CSPLINE
address@hidden Interpolation: Spline
address@hidden Cubic spline interpolation
address@hidden Spline (cubic) interpolation
+[From GSL:] Cubic spline with natural boundary conditions. The resulting
+curve is piecewise cubic on each interval, with matching first and second
+derivatives at the supplied data-points. The second derivative is chosen
+to be zero at the first point and last point.
address@hidden deffn
address@hidden Macro GAL_INTERPOLATE_1D_CSPLINE_PERIODIC
+[From GSL:] Cubic spline with periodic boundary conditions. The resulting
+curve is piecewise cubic on each interval, with matching first and second
+derivatives at the supplied data-points. The derivatives at the first and
+last points are also matched. Note that the last point in the data must
+have the same y-value as the first point, otherwise the resulting periodic
+interpolation will have a discontinuity at the boundary.
address@hidden deffn
address@hidden Macro GAL_INTERPOLATE_1D_AKIMA
address@hidden Interpolation: Akima spline
address@hidden Akima spline interpolation
address@hidden Spline (Akima) interpolation
+[From GSL:] Non-rounded Akima spline with natural boundary conditions. This
+method uses the non-rounded corner algorithm of Wodicka.
address@hidden deffn
address@hidden Macro GAL_INTERPOLATE_1D_AKIMA_PERIODIC
+[From GSL:] Non-rounded Akima spline with periodic boundary
+conditions. This method uses the non-rounded corner algorithm of Wodicka.
address@hidden deffn
address@hidden Macro GAL_INTERPOLATE_1D_STEFFEN
address@hidden Steffen interpolation
address@hidden Interpolation: Steffen
address@hidden Interpolation: monotonic
+[From GSL:] Steffen’s
address@hidden@url{http://adsabs.harvard.edu/abs/1990A%26A...239..443S}}
+guarantees the monotonicity of the interpolating function between the given
+data points. Therefore, minima and maxima can only occur exactly at the
+data points, and there can never be spurious oscillations between data
+points. The interpolated function is piecewise cubic in each interval. The
+resulting curve and its first derivative are guaranteed to be continuous,
+but the second derivative may be discontinuous.
address@hidden deffn
+
address@hidden {gsl_spline *} gal_interpolate_1d_make_gsl_spline (gal_data_t
@code{*X}, gal_data_t @code{*Y}, int @code{type_1d})
address@hidden GNU Scientific Library
+Allocate and initialize a GNU Scientific Library (GSL) 1D @code{gsl_spline}
+structure using the non-blank elements of @code{Y}. @code{type_1d}
+identifies the interpolation scheme and must be one of the
address@hidden macros defined above.
+
+If @code{X==NULL}, the X-axis is assumed to be integers starting from zero
+(the index of each element in @code{Y}). Otherwise, the values in @code{X}
+will be used to initialize the interpolation structure. Note that when
+given, @code{X} must @emph{not} contain any blank elements and it must be
+sorted (in increasing order).
+
+Each interpolation scheme needs a minimum number of elements to
+successfully operate. If the number of non-blank values in @code{Y} is less
+than this number, this function will return a @code{NULL} pointer.
+
+To be as generic and modular as possible, GSL's tools are low-level.
+Therefore before doing the interpolation, many steps are necessary (like
+preparing your dataset, then allocating and initializing
address@hidden). The metadata available in Gnuastro's @ref{Generic data
+container} make it easy to hide all those preparations within this
+function.
+
+Once @code{gsl_spline} has been initialized by this function, the
+interpolation can be evaluated for any X value within the non-blank range
+of the input using @code{gsl_spline_eval} or @code{gsl_spline_eval_e}.
+
+For example in the small program below, we read the first two columns of
+the table in @file{table.txt} and feed them to this function to later estimate
+the values in the second column for three selected points. You can use
address@hidden to compile and run this function, see @ref{Library demo
+programs} for more.
+
address@hidden first-in-first-out
address@hidden
+#include <stdio.h>
+#include <stdlib.h>
+#include <gnuastro/table.h>
+#include <gnuastro/interpolate.h>
+
+int
+main(void)
address@hidden
+ size_t i;
+ gal_data_t *X, *Y;
+ gsl_spline *spline;
+ gsl_interp_accel *acc;
+ gal_list_str_t *cols=NULL;
+
+ /* Change the values based on your input table. */
+ double address@hidden, 2.5, address@hidden;
+
+ /* Read the first two columns from `tab.txt'.
+ IMPORTANT: the list is first-in-first-out, so the output
+ column order is the inverse of the input order. */
+ gal_list_str_add(&cols, "1", 0);
+ gal_list_str_add(&cols, "2", 0);
+ Y=gal_table_read("table.txt", NULL, cols, GAL_TABLE_SEARCH_NAME,
+ 0, -1, NULL);
+ X=Y->next;
+
+ /* Allocate the GSL interpolation accelerator and make the
+ `gsl_spline' structure. */
+ acc=gsl_interp_accel_alloc();
+ spline=gal_interpolate_1d_make_gsl_spline(X, Y,
+ GAL_INTERPOLATE_1D_STEFFEN);
+
+ /* Calculate the respective value for all the given points,
+ if `spline' could be allocated. */
+ if(spline)
+ for(i=0; i<(sizeof points)/(sizeof *points); ++i)
+ printf("%f: %f\n", points[i],
+ gsl_spline_eval(spline, points[i], acc));
+
+ /* Clean up and return. */
+ gal_data_free(X);
+ gal_data_free(Y);
+ gsl_spline_free(spline);
+ gsl_interp_accel_free(acc);
+ gal_list_str_free(cols, 0);
+ return EXIT_SUCCESS;
address@hidden
address@hidden example
address@hidden deftypefun
+
address@hidden void gal_interpolate_1d_blank (gal_data_t @code{*in}, int
@code{type_1d})
+Fill the blank elements of @code{in} using the rest of the elements and the
+given interpolation. The interpolation scheme can be set through
address@hidden, which accepts any of the @code{GAL_INTERPOLATE_1D_*} macros
+above. The interpolation is internally done in 64-bit floating point type
+(@code{double}). However the evaluated/interpolated values (originally
+blank) will be written (in @code{in}) with its original numeric datatype,
+using C's standard type conversion.
+
+By definition, interpolation is only defined ``between'' valid
+points. Therefore, if any number of elements on the start or end of the 1D
+array are blank, those elements will not be interpolated and will remain
+blank. To see if any blank (non-interpolated) elements remain, you can use
address@hidden on @code{in} after this function is finished.
@end deftypefun
diff --git a/lib/gnuastro/interpolate.h b/lib/gnuastro/interpolate.h
index 0a5438d..53979a1 100644
--- a/lib/gnuastro/interpolate.h
+++ b/lib/gnuastro/interpolate.h
@@ -27,6 +27,7 @@ along with Gnuastro. If not, see
<http://www.gnu.org/licenses/>.
must be included before the C++ preparations below */
#include <gnuastro/data.h>
#include <gnuastro/tile.h>
+#include <gsl/gsl_spline.h>
/* C++ Preparations */
#undef __BEGIN_C_DECLS
@@ -45,6 +46,20 @@ __BEGIN_C_DECLS /* From C++ preparations */
+/* Types of interpolation. */
+enum gal_interpolate_1D_types
+{
+ GAL_INTERPOLATE_1D_INVALID,
+
+ GAL_INTERPOLATE_1D_LINEAR,
+ GAL_INTERPOLATE_1D_POLYNOMIAL,
+ GAL_INTERPOLATE_1D_CSPLINE,
+ GAL_INTERPOLATE_1D_CSPLINE_PERIODIC,
+ GAL_INTERPOLATE_1D_AKIMA,
+ GAL_INTERPOLATE_1D_AKIMA_PERIODIC,
+ GAL_INTERPOLATE_1D_STEFFEN,
+};
+
gal_data_t *
@@ -53,8 +68,11 @@ gal_interpolate_close_neighbors(gal_data_t *input,
size_t numneighbors, size_t numthreads,
int onlyblank, int aslinkedlist);
+gsl_spline *
+gal_interpolate_1d_make_gsl_spline(gal_data_t *X, gal_data_t *Y, int type_1d);
-
+void
+gal_interpolate_1d_blank(gal_data_t *in, int type_1d);
__END_C_DECLS /* From C++ preparations */
diff --git a/lib/interpolate.c b/lib/interpolate.c
index 4d9dceb..29cfddc 100644
--- a/lib/interpolate.c
+++ b/lib/interpolate.c
@@ -45,6 +45,7 @@ along with Gnuastro. If not, see
<http://www.gnu.org/licenses/>.
/*********************************************************************/
/******************** Nearest neighbor ********************/
+/*************** (Dimension agnostic) ****************/
/*********************************************************************/
/* These are bit-flags, so we're using hexadecimal notation. */
#define INTERPOLATE_FLAGS_NO 0
@@ -447,3 +448,291 @@ gal_interpolate_close_neighbors(gal_data_t *input,
gal_list_void_free(prm.ngb_vals, 1);
return prm.out;
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*********************************************************************/
+/******************** 1D on grid ********************/
+/*********************************************************************/
+gsl_spline *
+gal_interpolate_1d_make_gsl_spline(gal_data_t *X, gal_data_t *Y, int type_1d)
+{
+ size_t i, c;
+ double *x, *y;
+ gal_data_t *Xd, *Yd;
+ gsl_spline *spline=NULL;
+ const gsl_interp_type *itype=NULL;
+ int Yhasblank=gal_blank_present(Y, 0);
+
+ /* A small sanity check. */
+ if(Y->ndim!=1)
+ error(EXIT_FAILURE, 0, "%s: input dataset is not 1D (it is %zuD)",
+ __func__, Y->ndim);
+ if(X)
+ {
+ if( gal_dimension_is_different(X, Y) )
+ error(EXIT_FAILURE, 0, "%s: when two inputs are given, they must "
+ "have the same dimensions. X has %zu elements, while Y has "
+ "%zu", __func__, X->size, Y->size);
+ if(gal_blank_present(X, 0))
+ error(EXIT_FAILURE, 0, "%s: the X dataset has blank elements",
+ __func__);
+ }
+
+ /* Set the interpolation type. */
+ switch(type_1d)
+ {
+ case GAL_INTERPOLATE_1D_LINEAR:
+ itype=gsl_interp_linear; break;
+ case GAL_INTERPOLATE_1D_POLYNOMIAL:
+ itype=gsl_interp_polynomial; break;
+ case GAL_INTERPOLATE_1D_CSPLINE:
+ itype=gsl_interp_cspline; break;
+ case GAL_INTERPOLATE_1D_CSPLINE_PERIODIC:
+ itype=gsl_interp_cspline_periodic; break;
+ case GAL_INTERPOLATE_1D_AKIMA:
+ itype=gsl_interp_akima; break;
+ case GAL_INTERPOLATE_1D_AKIMA_PERIODIC:
+ itype=gsl_interp_akima_periodic; break;
+ case GAL_INTERPOLATE_1D_STEFFEN:
+ itype=gsl_interp_steffen; break;
+ default:
+ error(EXIT_FAILURE, 0, "%s: code %d not recognizable for the GSL "
+ "interpolation type", __func__, type_1d);
+ }
+
+ /* Initializations. Note that if Y doesn't have any blank elements and is
+ already in `double' type, then we don't need to make a copy. */
+ Yd = ( (Yhasblank || Y->type!=GAL_TYPE_FLOAT64)
+ ? gal_data_copy_to_new_type(Y, GAL_TYPE_FLOAT64)
+ : Y );
+ Xd = ( X
+ /* Has to be `Yhasblank', we KNOW X doesn't have blank values. */
+ ? ( (Yhasblank || X->type!=GAL_TYPE_FLOAT64)
+ ? gal_data_copy_to_new_type(X, GAL_TYPE_FLOAT64)
+ : X )
+ : gal_data_alloc(NULL, GAL_TYPE_FLOAT64, 1, Y->dsize, NULL,
+ 0, -1, NULL, NULL, NULL) );
+
+ /* Fill in the X axis values while also removing NaN/blank elements. */
+ c=0;
+ x=Xd->array;
+ y=Yd->array;
+ for(i=0;i<Yd->size;++i)
+ if( !isnan(y[i]) )
+ {
+ y[ c ] = y[i];
+ x[ c++ ] = X ? x[i] : i;
+ }
+
+ /* Make sure we have enough valid points for interpolation. */
+ if( c>=gsl_interp_type_min_size(itype) )
+ {
+ spline=gsl_spline_alloc(itype, c);
+ gsl_spline_init(spline, x, y, c);
+ }
+ else
+ spline=NULL;
+
+ /* Clean up and return. */
+ if(Xd!=X) gal_data_free(Xd);
+ if(Yd!=Y) gal_data_free(Yd);
+ return spline;
+}
+
+
+
+
+
+/* Return 0 if all blanks were filled. */
+static int
+interpolate_1d_blank_write(gal_data_t *in, gsl_spline *spline,
+ gsl_interp_accel *acc)
+{
+ double tmp;
+ int hasblank;
+ uint8_t *su8 =in->array, *u8 =in->array, *u8f =u8 +in->size;
+ int8_t *si8 =in->array, *i8 =in->array, *i8f =i8 +in->size;
+ uint16_t *su16=in->array, *u16=in->array, *u16f=u16+in->size;
+ int16_t *si16=in->array, *i16=in->array, *i16f=i16+in->size;
+ uint32_t *su32=in->array, *u32=in->array, *u32f=u32+in->size;
+ int32_t *si32=in->array, *i32=in->array, *i32f=i32+in->size;
+ uint64_t *su64=in->array, *u64=in->array, *u64f=u64+in->size;
+ int64_t *si64=in->array, *i64=in->array, *i64f=i64+in->size;
+ float *sf32=in->array, *f32=in->array, *f32f=f32+in->size;
+ double *sf64=in->array, *f64=in->array, *f64f=f64+in->size;
+
+ switch(in->type)
+ {
+ case GAL_TYPE_UINT8:
+ do
+ if(*u8==GAL_BLANK_UINT8)
+ {
+ /* If the evaluation is good, this function will return 0. */
+ if( gsl_spline_eval_e(spline, u8-su8, acc, &tmp)==0 )
+ *u8=tmp;
+ else hasblank=1;
+ }
+ while(++u8<u8f);
+ break;
+ case GAL_TYPE_INT8:
+ do
+ if(*i8==GAL_BLANK_INT8)
+ {
+ if( gsl_spline_eval_e(spline, i8-si8, acc, &tmp)==0 )
+ *u16=tmp;
+ else hasblank=1;
+ }
+ while(++i8<i8f);
+ break;
+ case GAL_TYPE_UINT16:
+ do
+ if(*u16==GAL_BLANK_UINT16)
+ {
+ if( gsl_spline_eval_e(spline, u16-su16, acc, &tmp)==0 )
+ *u16=tmp;
+ else hasblank=1;
+ }
+ while(++u16<u16f);
+ break;
+ case GAL_TYPE_INT16:
+ do
+ if(*i16==GAL_BLANK_INT16)
+ {
+ if( gsl_spline_eval_e(spline, i16-si16, acc, &tmp)==0 )
+ *i16=tmp;
+ else hasblank=1;
+ }
+ while(++i16<i16f);
+ break;
+ case GAL_TYPE_UINT32:
+ do
+ if(*u32==GAL_BLANK_UINT32)
+ {
+ if( gsl_spline_eval_e(spline, u32-su32, acc, &tmp)==0 )
+ *u32=tmp;
+ else hasblank=1;
+ }
+ while(++u32<u32f);
+ break;
+ case GAL_TYPE_INT32:
+ do
+ if(*i32==GAL_BLANK_INT32)
+ {
+ if( gsl_spline_eval_e(spline, i32-si32, acc, &tmp)==0 )
+ *i32=tmp;
+ else hasblank=1;
+ }
+ while(++i32<i32f);
+ break;
+ case GAL_TYPE_UINT64:
+ do
+ if(*u64==GAL_BLANK_UINT64)
+ {
+ if( gsl_spline_eval_e(spline, u64-su64, acc, &tmp)==0 )
+ *u64=tmp;
+ else hasblank=1;
+ }
+ while(++u64<u64f);
+ break;
+ case GAL_TYPE_INT64:
+ do
+ if(*i64==GAL_BLANK_INT64)
+ {
+ if( gsl_spline_eval_e(spline, i64-si64, acc, &tmp)==0 )
+ *i64=tmp;
+ else hasblank=1;
+ }
+ while(++i64<i64f);
+ break;
+ case GAL_TYPE_FLOAT32:
+ do
+ if(isnan(*f32))
+ {
+ if( gsl_spline_eval_e(spline, f32-sf32, acc, &tmp)==0 )
+ *f32=tmp;
+ else hasblank=1;
+ }
+ while(++f32<f32f);
+ break;
+ case GAL_TYPE_FLOAT64:
+ do
+ if(isnan(*f64))
+ {
+ if( gsl_spline_eval_e(spline, f64-sf64, acc, f64) )
+ hasblank=1;
+ }
+ while(++f64<f64f);
+ break;
+ default:
+ error(EXIT_FAILURE, 0, "%s: code %d is not a recognized data type",
+ __func__, in->type);
+ }
+ return hasblank;
+}
+
+
+
+
+
+void
+gal_interpolate_1d_blank(gal_data_t *in, int type_1d)
+{
+ int hasblank;
+ gsl_spline *spline;
+ gsl_interp_accel *acc;
+
+ /* If there are no blank elements, just return. */
+ if(!gal_blank_present(in, 1)) return;
+
+ /* Initialize the necessary structures. */
+ spline=gal_interpolate_1d_make_gsl_spline(NULL, in, type_1d);
+
+ /* If any interpolation structure was actually made. */
+ if(spline)
+ {
+ /* Write the values in the blank elements. */
+ acc=gsl_interp_accel_alloc();
+ hasblank=interpolate_1d_blank_write(in, spline, acc);
+
+ /* For a check.
+ {
+ size_t i;
+ double *d;
+ gal_data_t *check=gal_data_copy_to_new_type(in, GAL_TYPE_FLOAT64);
+ d=check->array;
+ for(i=0;i<check->size;++i)
+ printf("%-10zu%f\n", i, d[i]);
+ gal_data_free(check);
+ }
+ */
+
+ /* Set the blank flags, note that `GAL_DATA_FLAG_BLANK_CH' is already set
+ by the top call to `gal_blank_present'. */
+ if(hasblank)
+ in->flag |= GAL_DATA_FLAG_HASBLANK;
+ else
+ in->flag &= ~GAL_DATA_FLAG_HASBLANK;
+
+ /* Clean up. */
+ gsl_spline_free(spline);
+ gsl_interp_accel_free(acc);
+ }
+}
diff --git a/lib/txt.c b/lib/txt.c
index 3005d53..097be54 100644
--- a/lib/txt.c
+++ b/lib/txt.c
@@ -546,7 +546,7 @@ txt_get_info(char *filename, int format, size_t *numdata,
size_t *dsize)
fp=fopen(filename, "r");
if(fp==NULL)
error(EXIT_FAILURE, errno, "%s: couldn't open to read as a plain "
- "text %s in %s", filename, format_err, __func__);
+ "text %s (from Gnuastro's `%s')", filename, format_err, __func__);
/* Allocate the space necessary to keep each line as we parse it. Note