CR2RE Pipeline Reference Manual 1.7.0
irplib_utils.h
1/* $Id: irplib_utils.h,v 1.60 2013-08-21 14:55:14 cgarcia Exp $
2 *
3 * This file is part of the irplib package
4 * Copyright (C) 2002,2003 European Southern Observatory
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19 */
20
21/*
22 * $Author: cgarcia $
23 * $Date: 2013-08-21 14:55:14 $
24 * $Revision: 1.60 $
25 * $Name: not supported by cvs2svn $
26 * $Log: not supported by cvs2svn $
27 * Revision 1.59 2013/03/15 09:06:06 jtaylor
28 * add irplib_aligned_{[mc]alloc,free}
29 *
30 * allow portable allocation of aligned memory for vectorization
31 *
32 * Revision 1.58 2013/03/15 09:05:28 jtaylor
33 * move isnan and isinf to header so it is inlineable and use gcc builtin for better performance
34 *
35 * Revision 1.57 2013/02/27 16:02:02 jtaylor
36 * add diagnostic pragma macros
37 *
38 * Revision 1.56 2012/08/06 06:14:18 llundin
39 * irplib_errorstate_warning(): Replaced by cpl_errorstate_dump_one_warning() from CPL 6.X
40 *
41 * Revision 1.55 2011/06/01 06:47:56 llundin
42 * skip_if_lt(): Fix previous edits switch of A and B in error message
43 *
44 * Revision 1.54 2011/05/26 08:08:56 llundin
45 * skip_if_lt(): Support printf-style error message, name-space protect temporary variables
46 *
47 * Revision 1.53 2011/05/09 07:51:18 llundin
48 * irplib_dfs_save_image_(): Modified from cpl_dfs_save_image(). irplib_dfs_save_image(): Use irplib_dfs_save_image_()
49 *
50 * Revision 1.52 2010/03/23 07:57:59 kmirny
51 * DFS08552, Documentation for irplib_frameset_sort
52 *
53 * Revision 1.51 2009/12/16 14:59:30 cgarcia
54 * Avoid name clash with index function
55 *
56 * Revision 1.50 2009/08/17 15:10:16 kmirny
57 *
58 * DFS07454 DFS07437
59 *
60 */
61
62#ifndef IRPLIB_UTILS_H
63#define IRPLIB_UTILS_H
64
65/*-----------------------------------------------------------------------------
66 Includes
67 -----------------------------------------------------------------------------*/
68
69#include <cpl.h>
70#include <math.h>
71#include <stdarg.h>
72
73/*-----------------------------------------------------------------------------
74 Defines
75 -----------------------------------------------------------------------------*/
76
77/* Concatenate two macro arguments */
78#define IRPLIB_CONCAT(a, b) a##_##b
79#define IRPLIB_CONCAT2X(a, b) IRPLIB_CONCAT(a, b)
80
81/*----------------------------------------------------------------------------*/
82/*
83 @brief Swap two double values
84 @param A The 1st double to swap
85 @param B The 2nd double to swap
86 @note A and B are evaluated twice, so side-effects should be avoided
87*/
88/*----------------------------------------------------------------------------*/
89#define IRPLIB_SWAP_DOUBLE(A, B) \
90 do { \
91 const double irplib_swap_double = (A); \
92 (A) = (B); \
93 (B) = irplib_swap_double; \
94 } while (0)
95
96#define IRPLIB_XSTRINGIFY CPL_XSTRINGIFY
97#define IRPLIB_STRINGIFY CPL_STRINGIFY
98
99#if !defined __GNUC__ && !defined __inline__
100#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
101#define __inline__ inline
102#else
103#define __inline__
104#endif
105#endif
106
107#define IRPLIB_DIAG_PRAGMA_PUSH_IGN CPL_DIAG_PRAGMA_PUSH_IGN
108#define IRPLIB_DIAG_PRAGMA_PUSH_ERR CPL_DIAG_PRAGMA_PUSH_ERR
109#define IRPLIB_DIAG_PRAGMA_POP CPL_DIAG_PRAGMA_POP
110
111/* FIXME: Remove when no longer used by any irplib-based pipelines */
112/* Useful for debugging */
113#define irplib_trace() \
114 do \
115 if (cpl_error_get_code()) { \
116 cpl_msg_debug(cpl_func, __FILE__ " at line " CPL_STRINGIFY(__LINE__) ": ERROR '%s' at %s", \
117 cpl_error_get_message(), \
118 cpl_error_get_where()); \
119 } \
120 else { \
121 cpl_msg_debug(cpl_func, __FILE__ \
122 " at line " CPL_STRINGIFY(__LINE__) ": OK"); \
123 } \
124 while (0)
125
126#define irplib_error_recover(ESTATE, ...) \
127 do \
128 if (!cpl_errorstate_is_equal(ESTATE)) { \
129 cpl_msg_warning(cpl_func, __VA_ARGS__); \
130 cpl_msg_indent_more(); \
131 cpl_errorstate_dump(ESTATE, CPL_FALSE, \
132 cpl_errorstate_dump_one_warning); \
133 cpl_msg_indent_less(); \
134 cpl_errorstate_set(ESTATE); \
135 } \
136 while (0)
137
138
139/*----------------------------------------------------------------------------*/
140/*
141 @brief Declare a function suitable for use with irplib_dfs_table_convert()
142 @param table_set_row The name of the function to declare
143 @see irplib_dfs_table_convert(), irplib_table_read_from_frameset()
144
145*/
146/*----------------------------------------------------------------------------*/
147#define IRPLIB_UTIL_SET_ROW(table_set_row) \
148 cpl_boolean table_set_row(cpl_table *, const char *, int, \
149 const cpl_frame *, const cpl_parameterlist *)
150
151
152/*----------------------------------------------------------------------------*/
153/*
154 @brief Declare a function suitable for use with irplib_dfs_table_convert()
155 @param table_check The name of the function to declare
156 @see irplib_dfs_table_convert()
157
158*/
159/*----------------------------------------------------------------------------*/
160#define IRPLIB_UTIL_CHECK(table_check) \
161 cpl_error_code table_check(cpl_table *, const cpl_frameset *, \
162 const cpl_parameterlist *)
163
164
165/*----------------------------------------------------------------------------*/
166/*
167 @brief Conditional skip to the (unqiue) return point of the function
168 @param CONDITION The condition to check
169 @see cpl_error_ensure()
170
171 skip_if() takes one argument, which is a logical expression.
172 If the logical expression is false skip_if() takes no action and
173 program execution continues.
174 If the logical expression is true this indicates an error. In this case
175 skip_if() will set the location of the error to the point where it
176 was invoked in the recipe code (unless the error location is already in the
177 recipe code). If no error code had been set, then skip_if() will set one.
178 Finally, skip_if() causes program execution to skip to the macro 'end_skip'.
179 The macro end_skip is located towards the end of the function, after
180 which all resource deallocation and the function return is located.
181
182 The use of skip_if() assumes the following coding practice:
183 1) Pointers used for dynamically allocated memory that they "own" shall always
184 point to either NULL or to allocated memory (including CPL-objects).
185 2) Such pointers may not be reused to point to memory whose deallocation
186 requires calls to different functions.
187 3) Pointers of type FILE should be set NULL when not pointing to an open
188 stream and their closing calls (fclose(), freopen(), etc.) following the
189 'end_skip' should be guarded against such NULL pointers.
190
191 Error checking with skip_if() is encouraged due to the following advantages:
192 1) It ensures that a CPL-error code is set.
193 2) It ensures that the location of the error in the _recipe_ code is noted.
194 3) The error checking may be confined to a single concise line.
195 4) It is not necessary to replicate memory deallocation for every error
196 condition.
197 5) If more extensive error reporting/handling is required it is not precluded
198 by the use of skip_if().
199 6) It allows for a single point of function return.
200 7) It allows for optional, uniformly formatted debugging/tracing information
201 at each macro invocation.
202
203 The implementation of skip_if() uses a goto/label construction.
204 According to Kerningham & Ritchie, The C Programming Language, 2nd edition,
205 Section 3.8:
206 "This organization is handy if the error-handling code is non-trivial,
207 and if errors can occur in several places."
208
209 The use of goto for any other purpose should be avoided.
210
211*/
212/*----------------------------------------------------------------------------*/
213#define skip_if(CONDITION) \
214 do { \
215 cpl_error_ensure(!cpl_error_get_code(), cpl_error_get_code(), \
216 goto cleanup, "Propagating a pre-existing error"); \
217 cpl_error_ensure(!(CONDITION), cpl_error_get_code(), goto cleanup, \
218 "Propagating error"); \
219 } while (0)
220
221/*----------------------------------------------------------------------------*/
222/*
223 @brief Skip if A != B
224 @param A The 1st double to compare
225 @param B The 2nd double to compare
226 @param MSG A printf-style error message, 1st arg should be a string literal
227 @see skip_if()
228 @note A and B are evaluated exactly once
229
230 If no CPL error is set, sets CPL_ERROR_DATA_NOT_FOUND on failure
231*/
232/*----------------------------------------------------------------------------*/
233#define skip_if_ne(A, B, ...) \
234 do { \
235 /* Name-space protected one-time only evaluation */ \
236 const double irplib_utils_a = (double)(A); \
237 const double irplib_utils_b = (double)(B); \
238 \
239 cpl_error_ensure(!cpl_error_get_code(), cpl_error_get_code(), \
240 goto cleanup, "Propagating a pre-existing error"); \
241 if (irplib_utils_a != irplib_utils_b) { \
242 char *irplib_utils_msg = cpl_sprintf(__VA_ARGS__); \
243 (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND, \
244 "Need %g (not %g) %s", irplib_utils_b, \
245 irplib_utils_a, irplib_utils_msg); \
246 cpl_free(irplib_utils_msg); \
247 goto cleanup; \
248 } \
249 } while (0)
250
251/*----------------------------------------------------------------------------*/
252/*
253 @brief Skip if A < B
254 @param A The 1st double to compare
255 @param B The 2nd double to compare
256 @param MSG A printf-style error message, 1st arg should be a string literal
257 @see skip_if()
258 @note A and B are evaluated exactly once
259
260 If no CPL error is set, sets CPL_ERROR_DATA_NOT_FOUND on failure
261*/
262/*----------------------------------------------------------------------------*/
263#define skip_if_lt(A, B, ...) \
264 do { \
265 /* Name-space protected one-time only evaluation */ \
266 const double irplib_utils_a = (double)(A); \
267 const double irplib_utils_b = (double)(B); \
268 \
269 cpl_error_ensure(!cpl_error_get_code(), cpl_error_get_code(), \
270 goto cleanup, "Propagating a pre-existing error"); \
271 if (irplib_utils_a < irplib_utils_b) { \
272 char *irplib_utils_msg = cpl_sprintf(__VA_ARGS__); \
273 (void)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND, \
274 "Need at least %g (not %g) %s", \
275 irplib_utils_b, irplib_utils_a, \
276 irplib_utils_msg); \
277 cpl_free(irplib_utils_msg); \
278 goto cleanup; \
279 } \
280 } while (0)
281
282/*----------------------------------------------------------------------------*/
283/*
284 @brief Conditional skip on coding bug
285 @param CONDITION The condition to check
286 @see skip_if()
287 @note unlike assert() this check cannot be disabled
288 */
289/*----------------------------------------------------------------------------*/
290#define bug_if(CONDITION) \
291 do { \
292 cpl_error_ensure(!cpl_error_get_code(), cpl_error_get_code(), \
293 goto cleanup, \
294 "Propagating an unexpected error, " \
295 "please report to " PACKAGE_BUGREPORT); \
296 cpl_error_ensure( \
297 !(CONDITION), CPL_ERROR_UNSPECIFIED, goto cleanup, \
298 "Internal error, please report to " PACKAGE_BUGREPORT); \
299 } while (0)
300
301/*----------------------------------------------------------------------------*/
302/*
303 @brief Conditional skip with error creation
304 @param CONDITION The condition to check
305 @param ERROR The error code to set
306 @param MSG A printf-style error message. As a matter of
307 user-friendliness the message should mention any
308 value that caused the @em CONDITION to fail.
309 @see skip_if()
310 @note unlike assert() this check cannot be disabled
311 */
312/*----------------------------------------------------------------------------*/
313#define error_if(CONDITION, ERROR, ...) \
314 cpl_error_ensure(cpl_error_get_code() == CPL_ERROR_NONE && !(CONDITION), \
315 ERROR, goto cleanup, __VA_ARGS__)
316
317/*----------------------------------------------------------------------------*/
318/*
319 @brief Propagate a preexisting error, if any
320 @param MSG A printf-style error message.
321 @see skip_if()
322 */
323/*----------------------------------------------------------------------------*/
324#define any_if(...) \
325 cpl_error_ensure(!cpl_error_get_code(), cpl_error_get_code(), \
326 goto cleanup, __VA_ARGS__)
327
328/*----------------------------------------------------------------------------*/
329/*
330 @brief Define the single point of resource deallocation and return
331 @see skip_if()
332 @note end_skip should be used exactly once in functions that use skip_if() etc
333*/
334/*----------------------------------------------------------------------------*/
335#define end_skip \
336 do { \
337 cleanup: \
338 if (cpl_error_get_code()) \
339 cpl_msg_debug(cpl_func, \
340 "Cleanup in " __FILE__ " line " CPL_STRINGIFY(__LINE__) " with error '%s' at %s", \
341 cpl_error_get_message(), cpl_error_get_where()); \
342 else \
343 cpl_msg_debug(cpl_func, "Cleanup in " __FILE__ \
344 " line " CPL_STRINGIFY(__LINE__)); \
345 } while (0)
346
347
348/*----------------------------------------------------------------------------*/
360/*----------------------------------------------------------------------------*/
361#define irplib_ensure(CONDITION, ec, ...) \
362 cpl_error_ensure(CONDITION, ec, goto cleanup, __VA_ARGS__)
363
364/*----------------------------------------------------------------------------*/
394/*----------------------------------------------------------------------------*/
395
396#define irplib_check(COMMAND, ...) \
397 do { \
398 cpl_errorstate irplib_check_prestate = cpl_errorstate_get(); \
399 skip_if(0); \
400 COMMAND; \
401 irplib_trace(); \
402 irplib_ensure(cpl_errorstate_is_equal(irplib_check_prestate), \
403 cpl_error_get_code(), __VA_ARGS__); \
404 irplib_trace(); \
405 } while (0)
406
407/*-----------------------------------------------------------------------------
408 Function prototypes
409 -----------------------------------------------------------------------------*/
410
411cpl_error_code irplib_dfs_save_image(cpl_frameset *,
412 const cpl_parameterlist *,
413 const cpl_frameset *,
414 const cpl_image *,
415 cpl_type_bpp,
416 const char *,
417 const char *,
418 const cpl_propertylist *,
419 const char *,
420 const char *,
421 const char *);
422
423
424cpl_error_code irplib_dfs_save_propertylist(cpl_frameset *,
425 const cpl_parameterlist *,
426 const cpl_frameset *,
427 const char *,
428 const char *,
429 const cpl_propertylist *,
430 const char *,
431 const char *,
432 const char *);
433
434cpl_error_code irplib_dfs_save_imagelist(cpl_frameset *,
435 const cpl_parameterlist *,
436 const cpl_frameset *,
437 const cpl_imagelist *,
438 cpl_type_bpp,
439 const char *,
440 const char *,
441 const cpl_propertylist *,
442 const char *,
443 const char *,
444 const char *);
445
446cpl_error_code irplib_dfs_save_table(cpl_frameset *,
447 const cpl_parameterlist *,
448 const cpl_frameset *,
449 const cpl_table *,
450 const cpl_propertylist *,
451 const char *,
452 const char *,
453 const cpl_propertylist *,
454 const char *,
455 const char *,
456 const char *);
457
458cpl_error_code irplib_dfs_save_image_(cpl_frameset *,
459 cpl_propertylist *,
460 const cpl_parameterlist *,
461 const cpl_frameset *,
462 const cpl_frame *,
463 const cpl_image *,
464 cpl_type,
465 const char *,
466 const cpl_propertylist *,
467 const char *,
468 const char *,
469 const char *);
470
471void irplib_reset(void);
472int irplib_compare_tags(cpl_frame *, cpl_frame *);
473const char *irplib_frameset_find_file(const cpl_frameset *, const char *);
474const cpl_frame *
475irplib_frameset_get_first_from_group(const cpl_frameset *, cpl_frame_group);
476
477cpl_error_code
478irplib_apertures_find_max_flux(const cpl_apertures *, int *, int);
479
480#if defined HAVE_ISNAN && HAVE_ISNAN != 0
481#if !defined isnan && defined HAVE_DECL_ISNAN && HAVE_DECL_ISNAN == 0
482/* HP-UX and Solaris may have isnan() available at link-time
483 without the prototype */
484int isnan(double);
485#endif
486#endif
487
488cpl_error_code
489irplib_dfs_table_convert(cpl_table *,
490 cpl_frameset *,
491 const cpl_frameset *,
492 int,
493 char,
494 const char *,
495 const char *,
496 const cpl_parameterlist *,
497 const char *,
498 const cpl_propertylist *,
499 const cpl_propertylist *,
500 const char *,
501 const char *,
502 const char *,
503 cpl_boolean (*)(cpl_table *,
504 const char *,
505 int,
506 const cpl_frame *,
507 const cpl_parameterlist *),
508 cpl_error_code (*)(cpl_table *,
509 const cpl_frameset *,
510 const cpl_parameterlist *));
511
512cpl_error_code
514 const cpl_frameset *,
515 int,
516 char,
517 const cpl_parameterlist *,
518 cpl_boolean (*)(cpl_table *,
519 const char *,
520 int,
521 const cpl_frame *,
522 const cpl_parameterlist *));
523
524cpl_error_code irplib_image_split(const cpl_image *,
525 cpl_image *,
526 cpl_image *,
527 cpl_image *,
528 double,
529 cpl_boolean,
530 double,
531 cpl_boolean,
532 double,
533 double,
534 cpl_boolean,
535 cpl_boolean,
536 cpl_boolean);
537
538void irplib_errorstate_dump_warning(unsigned, unsigned, unsigned);
539void irplib_errorstate_dump_info(unsigned, unsigned, unsigned);
540void irplib_errorstate_dump_debug(unsigned, unsigned, unsigned);
541/* wrapper for replace deprecated function cpl_polynomial_fit_1d_create*/
542cpl_polynomial *irplib_polynomial_fit_1d_create(const cpl_vector *x_pos,
543 const cpl_vector *values,
544 int degree,
545 double *mse);
546cpl_polynomial *irplib_polynomial_fit_1d_create_chiq(const cpl_vector *x_pos,
547 const cpl_vector *values,
548 int degree,
549 double *rechiq);
550/*----------------------------------------------------------------------------*/
558cpl_error_code
559irplib_frameset_sort(const cpl_frameset *self, int *iindex, double *exptime);
560
561
562/* FIXME: add alloc_size(2) */
563void *irplib_aligned_malloc(size_t alignment, size_t size) CPL_ATTR_ALLOC;
564void *irplib_aligned_calloc(size_t alignment,
565 size_t nelem,
566 size_t nbytes) CPL_ATTR_ALLOC;
567void irplib_aligned_free(void *aligned_ptr);
568
569const cpl_frame *
570irplib_frameset_get_first_const(cpl_frameset_iterator **iterator,
571 const cpl_frameset *frameset);
572
573const cpl_frame *
574irplib_frameset_get_next_const(cpl_frameset_iterator *iterator);
575
576
577void irplib_vector_get_kth(cpl_vector *, cpl_size);
578
579/*-----------------------------------------------------------------------------
580 Function inlines
581 -----------------------------------------------------------------------------*/
582
583
584/*----------------------------------------------------------------------------*/
588/*----------------------------------------------------------------------------*/
589static __inline__ int
590irplib_isinf(double value)
591{
592/* documented only on 4.4, but available in at least 4.2 */
593#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)
594 return __builtin_isinf(value);
595#elif defined HAVE_ISINF && HAVE_ISINF
596 return isinf(value);
597#else
598 return value != 0 && value == 2 * value;
599#endif
600}
601
602
603/*----------------------------------------------------------------------------*/
607/*----------------------------------------------------------------------------*/
608static __inline__ int
609irplib_isnan(double value)
610{
611/* documented only on 4.4, but available in at least 4.2 */
612#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)
613 return __builtin_isnan(value);
614#elif defined HAVE_ISNAN && HAVE_ISNAN
615 return isnan(value);
616#else
617 return value != value;
618#endif
619}
620
621#endif
cpl_error_code irplib_dfs_save_image_(cpl_frameset *, cpl_propertylist *, const cpl_parameterlist *, const cpl_frameset *, const cpl_frame *, const cpl_image *, cpl_type, const char *, const cpl_propertylist *, const char *, const char *, const char *)
Save an image as a DFS-compliant pipeline product.
void irplib_errorstate_dump_debug(unsigned, unsigned, unsigned)
Dump a single CPL error at the CPL debug level.
cpl_error_code irplib_dfs_save_image(cpl_frameset *, const cpl_parameterlist *, const cpl_frameset *, const cpl_image *, cpl_type_bpp, const char *, const char *, const cpl_propertylist *, const char *, const char *, const char *)
Save an image as a DFS-compliant pipeline product.
cpl_error_code irplib_dfs_table_convert(cpl_table *, cpl_frameset *, const cpl_frameset *, int, char, const char *, const char *, const cpl_parameterlist *, const char *, const cpl_propertylist *, const cpl_propertylist *, const char *, const char *, const char *, cpl_boolean(*)(cpl_table *, const char *, int, const cpl_frame *, const cpl_parameterlist *), cpl_error_code(*)(cpl_table *, const cpl_frameset *, const cpl_parameterlist *))
Create a DFS product with one table from one or more (ASCII) file(s)
cpl_error_code irplib_dfs_save_propertylist(cpl_frameset *, const cpl_parameterlist *, const cpl_frameset *, const char *, const char *, const cpl_propertylist *, const char *, const char *, const char *)
Save a propertylist as a DFS-compliant pipeline product.
cpl_error_code irplib_table_read_from_frameset(cpl_table *, const cpl_frameset *, int, char, const cpl_parameterlist *, cpl_boolean(*)(cpl_table *, const char *, int, const cpl_frame *, const cpl_parameterlist *))
Set the rows of a table with data from one or more (ASCII) files.
cpl_error_code irplib_dfs_save_table(cpl_frameset *, const cpl_parameterlist *, const cpl_frameset *, const cpl_table *, const cpl_propertylist *, const char *, const char *, const cpl_propertylist *, const char *, const char *, const char *)
Save a table as a DFS-compliant pipeline product.
cpl_error_code irplib_dfs_save_imagelist(cpl_frameset *, const cpl_parameterlist *, const cpl_frameset *, const cpl_imagelist *, cpl_type_bpp, const char *, const char *, const cpl_propertylist *, const char *, const char *, const char *)
Save an imagelist as a DFS-compliant pipeline product.
void irplib_errorstate_dump_warning(unsigned, unsigned, unsigned)
Dump a single CPL error at the CPL warning level.
cpl_error_code irplib_image_split(const cpl_image *, cpl_image *, cpl_image *, cpl_image *, double, cpl_boolean, double, cpl_boolean, double, double, cpl_boolean, cpl_boolean, cpl_boolean)
Split the values in an image in three according to two thresholds.
void irplib_errorstate_dump_info(unsigned, unsigned, unsigned)
Dump a single CPL error at the CPL info level.
const cpl_frame * irplib_frameset_get_first_from_group(const cpl_frameset *, cpl_frame_group)
Find the first frame belonging to the given group.
const char * irplib_frameset_find_file(const cpl_frameset *, const char *)
Find the filename with the given tag in a frame set.
cpl_error_code irplib_apertures_find_max_flux(const cpl_apertures *, int *, int)
Find the aperture(s) with the greatest flux.
int irplib_compare_tags(cpl_frame *, cpl_frame *)
Comparison function to identify different input frames.
void irplib_reset(void)
Reset IRPLIB state.