1 /*============================================================================
2   WCSLIB 7.7 - an implementation of the FITS WCS standard.
3   Copyright (C) 1995-2021, Mark Calabretta
4 
5   This file is part of WCSLIB.
6 
7   WCSLIB is free software: you can redistribute it and/or modify it under the
8   terms of the GNU Lesser General Public License as published by the Free
9   Software Foundation, either version 3 of the License, or (at your option)
10   any later version.
11 
12   WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY
13   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
15   more details.
16 
17   You should have received a copy of the GNU Lesser General Public License
18   along with WCSLIB.  If not, see http://www.gnu.org/licenses.
19 
20   Author: Mark Calabretta, Australia Telescope National Facility, CSIRO.
21   http://www.atnf.csiro.au/people/Mark.Calabretta
22   $Id: spc.h,v 7.7 2021/07/12 06:36:49 mcalabre Exp $
23 *=============================================================================
24 *
25 * WCSLIB 7.7 - C routines that implement the FITS World Coordinate System
26 * (WCS) standard.  Refer to the README file provided with WCSLIB for an
27 * overview of the library.
28 *
29 *
30 * Summary of the spc routines
31 * ---------------------------
32 * Routines in this suite implement the part of the FITS World Coordinate
33 * System (WCS) standard that deals with spectral coordinates, as described in
34 *
35 =   "Representations of world coordinates in FITS",
36 =   Greisen, E.W., & Calabretta, M.R. 2002, A&A, 395, 1061 (WCS Paper I)
37 =
38 =   "Representations of spectral coordinates in FITS",
39 =   Greisen, E.W., Calabretta, M.R., Valdes, F.G., & Allen, S.L.
40 =   2006, A&A, 446, 747 (WCS Paper III)
41 *
42 * These routines define methods to be used for computing spectral world
43 * coordinates from intermediate world coordinates (a linear transformation
44 * of image pixel coordinates), and vice versa.  They are based on the spcprm
45 * struct which contains all information needed for the computations.  The
46 * struct contains some members that must be set by the user, and others that
47 * are maintained by these routines, somewhat like a C++ class but with no
48 * encapsulation.
49 *
50 * Routine spcini() is provided to initialize the spcprm struct with default
51 * values, spcfree() reclaims any memory that may have been allocated to store
52 * an error message, spcsize() computes its total size including allocated
53 * memory, and spcprt() prints its contents.
54 *
55 * spcperr() prints the error message(s) (if any) stored in a spcprm struct.
56 *
57 * A setup routine, spcset(), computes intermediate values in the spcprm struct
58 * from parameters in it that were supplied by the user.  The struct always
59 * needs to be set up by spcset() but it need not be called explicitly - refer
60 * to the explanation of spcprm::flag.
61 *
62 * spcx2s() and spcs2x() implement the WCS spectral coordinate transformations.
63 * In fact, they are high level driver routines for the lower level spectral
64 * coordinate transformation routines described in spx.h.
65 *
66 * A number of routines are provided to aid in analysing or synthesising sets
67 * of FITS spectral axis keywords:
68 *
69 *   - spctype() checks a spectral CTYPEia keyword for validity and returns
70 *     information derived from it.
71 *
72 *   - Spectral keyword analysis routine spcspxe() computes the values of the
73 *     X-type spectral variables for the S-type variables supplied.
74 *
75 *   - Spectral keyword synthesis routine, spcxpse(), computes the S-type
76 *     variables for the X-types supplied.
77 *
78 *   - Given a set of spectral keywords, a translation routine, spctrne(),
79 *     produces the corresponding set for the specified spectral CTYPEia.
80 *
81 *   - spcaips() translates AIPS-convention spectral CTYPEia and VELREF
82 *     keyvalues.
83 *
84 * Spectral variable types - S, P, and X:
85 * --------------------------------------
86 * A few words of explanation are necessary regarding spectral variable types
87 * in FITS.
88 *
89 * Every FITS spectral axis has three associated spectral variables:
90 *
91 *   S-type: the spectral variable in which coordinates are to be
92 *     expressed.  Each S-type is encoded as four characters and is
93 *     linearly related to one of four basic types as follows:
94 *
95 *     F (Frequency):
96 *       - 'FREQ':  frequency
97 *       - 'AFRQ':  angular frequency
98 *       - 'ENER':  photon energy
99 *       - 'WAVN':  wave number
100 *       - 'VRAD':  radio velocity
101 *
102 *     W (Wavelength in vacuo):
103 *       - 'WAVE':  wavelength
104 *       - 'VOPT':  optical velocity
105 *       - 'ZOPT':  redshift
106 *
107 *     A (wavelength in Air):
108 *       - 'AWAV':  wavelength in air
109 *
110 *     V (Velocity):
111 *       - 'VELO':  relativistic velocity
112 *       - 'BETA':  relativistic beta factor
113 *
114 *     The S-type forms the first four characters of the CTYPEia keyvalue,
115 *     and CRVALia and CDELTia are expressed as S-type quantities so that
116 *     they provide a first-order approximation to the S-type variable at
117 *     the reference point.
118 *
119 *     Note that 'AFRQ', angular frequency, is additional to the variables
120 *     defined in WCS Paper III.
121 *
122 *   P-type: the basic spectral variable (F, W, A, or V) with which the
123 *     S-type variable is associated (see list above).
124 *
125 *     For non-grism axes, the P-type is encoded as the eighth character of
126 *     CTYPEia.
127 *
128 *   X-type: the basic spectral variable (F, W, A, or V) for which the
129 *     spectral axis is linear, grisms excluded (see below).
130 *
131 *     For non-grism axes, the X-type is encoded as the sixth character of
132 *     CTYPEia.
133 *
134 *   Grisms: Grism axes have normal S-, and P-types but the axis is linear,
135 *     not in any spectral variable, but in a special "grism parameter".
136 *     The X-type spectral variable is either W or A for grisms in vacuo or
137 *     air respectively, but is encoded as 'w' or 'a' to indicate that an
138 *     additional transformation is required to convert to or from the
139 *     grism parameter.  The spectral algorithm code for grisms also has a
140 *     special encoding in CTYPEia, either 'GRI' (in vacuo) or 'GRA' (in air).
141 *
142 * In the algorithm chain, the non-linear transformation occurs between the
143 * X-type and the P-type variables; the transformation between P-type and
144 * S-type variables is always linear.
145 *
146 * When the P-type and X-type variables are the same, the spectral axis is
147 * linear in the S-type variable and the second four characters of CTYPEia
148 * are blank.  This can never happen for grism axes.
149 *
150 * As an example, correlating radio spectrometers always produce spectra that
151 * are regularly gridded in frequency; a redshift scale on such a spectrum is
152 * non-linear.  The required value of CTYPEia would be 'ZOPT-F2W', where the
153 * desired S-type is 'ZOPT' (redshift), the P-type is necessarily 'W'
154 * (wavelength), and the X-type is 'F' (frequency) by the nature of the
155 * instrument.
156 *
157 * Air-to-vacuum wavelength conversion:
158 * ------------------------------------
159 * Please refer to the prologue of spx.h for important comments relating to the
160 * air-to-vacuum wavelength conversion.
161 *
162 * Argument checking:
163 * ------------------
164 * The input spectral values are only checked for values that would result in
165 * floating point exceptions.  In particular, negative frequencies and
166 * wavelengths are allowed, as are velocities greater than the speed of
167 * light.  The same is true for the spectral parameters - rest frequency and
168 * wavelength.
169 *
170 * Accuracy:
171 * ---------
172 * No warranty is given for the accuracy of these routines (refer to the
173 * copyright notice); intending users must satisfy for themselves their
174 * adequacy for the intended purpose.  However, closure effectively to within
175 * double precision rounding error was demonstrated by test routine tspc.c
176 * which accompanies this software.
177 *
178 *
179 * spcini() - Default constructor for the spcprm struct
180 * ----------------------------------------------------
181 * spcini() sets all members of a spcprm struct to default values.  It should
182 * be used to initialize every spcprm struct.
183 *
184 * PLEASE NOTE: If the spcprm struct has already been initialized, then before
185 * reinitializing, it spcfree() should be used to free any memory that may have
186 * been allocated to store an error message.  A memory leak may otherwise
187 * result.
188 *
189 * Given and returned:
190 *   spc       struct spcprm*
191 *                       Spectral transformation parameters.
192 *
193 * Function return value:
194 *             int       Status return value:
195 *                         0: Success.
196 *                         1: Null spcprm pointer passed.
197 *
198 *
199 * spcfree() - Destructor for the spcprm struct
200 * --------------------------------------------
201 * spcfree() frees any memory that may have been allocated to store an error
202 * message in the spcprm struct.
203 *
204 * Given:
205 *   spc       struct spcprm*
206 *                       Spectral transformation parameters.
207 *
208 * Function return value:
209 *             int       Status return value:
210 *                         0: Success.
211 *                         1: Null spcprm pointer passed.
212 *
213 *
214 * spcsize() - Compute the size of a spcprm struct
215 * -----------------------------------------------
216 * spcsize() computes the full size of a spcprm struct, including allocated
217 * memory.
218 *
219 * Given:
220 *   spc       const struct spcprm*
221 *                       Spectral transformation parameters.
222 *
223 *                       If NULL, the base size of the struct and the allocated
224 *                       size are both set to zero.
225 *
226 * Returned:
227 *   sizes     int[2]    The first element is the base size of the struct as
228 *                       returned by sizeof(struct spcprm).  The second element
229 *                       is the total allocated size, in bytes.  This figure
230 *                       includes memory allocated for the constituent struct,
231 *                       spcprm::err.
232 *
233 *                       It is not an error for the struct not to have been set
234 *                       up via spcset().
235 *
236 * Function return value:
237 *             int       Status return value:
238 *                         0: Success.
239 *
240 *
241 * spcprt() - Print routine for the spcprm struct
242 * ----------------------------------------------
243 * spcprt() prints the contents of a spcprm struct using wcsprintf().  Mainly
244 * intended for diagnostic purposes.
245 *
246 * Given:
247 *   spc       const struct spcprm*
248 *                       Spectral transformation parameters.
249 *
250 * Function return value:
251 *             int       Status return value:
252 *                         0: Success.
253 *                         1: Null spcprm pointer passed.
254 *
255 *
256 * spcperr() - Print error messages from a spcprm struct
257 * -----------------------------------------------------
258 * spcperr() prints the error message(s) (if any) stored in a spcprm struct.
259 * If there are no errors then nothing is printed.  It uses wcserr_prt(), q.v.
260 *
261 * Given:
262 *   spc       const struct spcprm*
263 *                       Spectral transformation parameters.
264 *
265 *   prefix    const char *
266 *                       If non-NULL, each output line will be prefixed with
267 *                       this string.
268 *
269 * Function return value:
270 *             int       Status return value:
271 *                         0: Success.
272 *                         1: Null spcprm pointer passed.
273 *
274 *
275 * spcset() - Setup routine for the spcprm struct
276 * ----------------------------------------------
277 * spcset() sets up a spcprm struct according to information supplied within
278 * it.
279 *
280 * Note that this routine need not be called directly; it will be invoked by
281 * spcx2s() and spcs2x() if spcprm::flag is anything other than a predefined
282 * magic value.
283 *
284 * Given and returned:
285 *   spc       struct spcprm*
286 *                       Spectral transformation parameters.
287 *
288 * Function return value:
289 *             int       Status return value:
290 *                         0: Success.
291 *                         1: Null spcprm pointer passed.
292 *                         2: Invalid spectral parameters.
293 *
294 *                       For returns > 1, a detailed error message is set in
295 *                       spcprm::err if enabled, see wcserr_enable().
296 *
297 *
298 * spcx2s() - Transform to spectral coordinates
299 * --------------------------------------------
300 * spcx2s() transforms intermediate world coordinates to spectral coordinates.
301 *
302 * Given and returned:
303 *   spc       struct spcprm*
304 *                       Spectral transformation parameters.
305 *
306 * Given:
307 *   nx        int       Vector length.
308 *
309 *   sx        int       Vector stride.
310 *
311 *   sspec     int       Vector stride.
312 *
313 *   x         const double[]
314 *                       Intermediate world coordinates, in SI units.
315 *
316 * Returned:
317 *   spec      double[]  Spectral coordinates, in SI units.
318 *
319 *   stat      int[]     Status return value status for each vector element:
320 *                         0: Success.
321 *                         1: Invalid value of x.
322 *
323 * Function return value:
324 *             int       Status return value:
325 *                         0: Success.
326 *                         1: Null spcprm pointer passed.
327 *                         2: Invalid spectral parameters.
328 *                         3: One or more of the x coordinates were invalid,
329 *                            as indicated by the stat vector.
330 *
331 *                       For returns > 1, a detailed error message is set in
332 *                       spcprm::err if enabled, see wcserr_enable().
333 *
334 *
335 * spcs2x() - Transform spectral coordinates
336 * -----------------------------------------
337 * spcs2x() transforms spectral world coordinates to intermediate world
338 * coordinates.
339 *
340 * Given and returned:
341 *   spc       struct spcprm*
342 *                       Spectral transformation parameters.
343 *
344 * Given:
345 *   nspec     int       Vector length.
346 *
347 *   sspec     int       Vector stride.
348 *
349 *   sx        int       Vector stride.
350 *
351 *   spec      const double[]
352 *                       Spectral coordinates, in SI units.
353 *
354 * Returned:
355 *   x         double[]  Intermediate world coordinates, in SI units.
356 *
357 *   stat      int[]     Status return value status for each vector element:
358 *                         0: Success.
359 *                         1: Invalid value of spec.
360 *
361 * Function return value:
362 *             int       Status return value:
363 *                         0: Success.
364 *                         1: Null spcprm pointer passed.
365 *                         2: Invalid spectral parameters.
366 *                         4: One or more of the spec coordinates were
367 *                            invalid, as indicated by the stat vector.
368 *
369 *                       For returns > 1, a detailed error message is set in
370 *                       spcprm::err if enabled, see wcserr_enable().
371 *
372 *
373 * spctype() - Spectral CTYPEia keyword analysis
374 * ---------------------------------------------
375 * spctype() checks whether a CTYPEia keyvalue is a valid spectral axis type
376 * and if so returns information derived from it relating to the associated S-,
377 * P-, and X-type spectral variables (see explanation above).
378 *
379 * The return arguments are guaranteed not be modified if CTYPEia is not a
380 * valid spectral type; zero-pointers may be specified for any that are not of
381 * interest.
382 *
383 * A deprecated form of this function, spctyp(), lacks the wcserr** parameter.
384 *
385 * Given:
386 *   ctype     const char[9]
387 *                       The CTYPEia keyvalue, (eight characters with null
388 *                       termination).
389 *
390 * Returned:
391 *   stype     char[]    The four-letter name of the S-type spectral variable
392 *                       copied or translated from ctype.  If a non-zero
393 *                       pointer is given, the array must accomodate a null-
394 *                       terminated string of length 5.
395 *
396 *   scode     char[]    The three-letter spectral algorithm code copied or
397 *                       translated from ctype.  Logarithmic ('LOG') and
398 *                       tabular ('TAB') codes are also recognized.  If a
399 *                       non-zero pointer is given, the array must accomodate a
400 *                       null-terminated string of length 4.
401 *
402 *   sname     char[]    Descriptive name of the S-type spectral variable.
403 *                       If a non-zero pointer is given, the array must
404 *                       accomodate a null-terminated string of length 22.
405 *
406 *   units     char[]    SI units of the S-type spectral variable.  If a
407 *                       non-zero pointer is given, the array must accomodate a
408 *                       null-terminated string of length 8.
409 *
410 *   ptype     char*     Character code for the P-type spectral variable
411 *                       derived from ctype, one of 'F', 'W', 'A', or 'V'.
412 *
413 *   xtype     char*     Character code for the X-type spectral variable
414 *                       derived from ctype, one of 'F', 'W', 'A', or 'V'.
415 *                       Also, 'w' and 'a' are synonymous to 'W' and 'A' for
416 *                       grisms in vacuo and air respectively.  Set to 'L' or
417 *                       'T' for logarithmic ('LOG') and tabular ('TAB') axes.
418 *
419 *   restreq   int*      Multivalued flag that indicates whether rest
420 *                       frequency or wavelength is required to compute
421 *                       spectral variables for this CTYPEia:
422 *                         0: Not required.
423 *                         1: Required for the conversion between S- and
424 *                            P-types (e.g. 'ZOPT-F2W').
425 *                         2: Required for the conversion between P- and
426 *                            X-types (e.g. 'BETA-W2V').
427 *                         3: Required for the conversion between S- and
428 *                            P-types, and between P- and X-types, but not
429 *                            between S- and X-types (this applies only for
430 *                            'VRAD-V2F', 'VOPT-V2W', and 'ZOPT-V2W').
431 *                        Thus the rest frequency or wavelength is required for
432 *                        spectral coordinate computations (i.e. between S- and
433 *                        X-types) only if restreq%3 != 0.
434 *
435 *   err       struct wcserr **
436 *                       If enabled, for function return values > 1, this
437 *                       struct will contain a detailed error message, see
438 *                       wcserr_enable().  May be NULL if an error message is
439 *                       not desired.  Otherwise, the user is responsible for
440 *                       deleting the memory allocated for the wcserr struct.
441 *
442 * Function return value:
443 *             int       Status return value:
444 *                         0: Success.
445 *                         2: Invalid spectral parameters (not a spectral
446 *                            CTYPEia).
447 *
448 *
449 * spcspxe() - Spectral keyword analysis
450 * ------------------------------------
451 * spcspxe() analyses the CTYPEia and CRVALia FITS spectral axis keyword values
452 * and returns information about the associated X-type spectral variable.
453 *
454 * A deprecated form of this function, spcspx(), lacks the wcserr** parameter.
455 *
456 * Given:
457 *   ctypeS    const char[9]
458 *                       Spectral axis type, i.e. the CTYPEia keyvalue, (eight
459 *                       characters with null termination).  For non-grism
460 *                       axes, the character code for the P-type spectral
461 *                       variable in the algorithm code (i.e. the eighth
462 *                       character of CTYPEia) may be set to '?' (it will not
463 *                       be reset).
464 *
465 *   crvalS    double    Value of the S-type spectral variable at the reference
466 *                       point, i.e. the CRVALia keyvalue, SI units.
467 *
468 *   restfrq,
469 *   restwav   double    Rest frequency [Hz] and rest wavelength in vacuo [m],
470 *                       only one of which need be given, the other should be
471 *                       set to zero.
472 *
473 * Returned:
474 *   ptype     char*     Character code for the P-type spectral variable
475 *                       derived from ctypeS, one of 'F', 'W', 'A', or 'V'.
476 *
477 *   xtype     char*     Character code for the X-type spectral variable
478 *                       derived from ctypeS, one of 'F', 'W', 'A', or 'V'.
479 *                       Also, 'w' and 'a' are synonymous to 'W' and 'A' for
480 *                       grisms in vacuo and air respectively; crvalX and dXdS
481 *                       (see below) will conform to these.
482 *
483 *   restreq   int*      Multivalued flag that indicates whether rest frequency
484 *                       or wavelength is required to compute spectral
485 *                       variables for this CTYPEia, as for spctype().
486 *
487 *   crvalX    double*   Value of the X-type spectral variable at the reference
488 *                       point, SI units.
489 *
490 *   dXdS      double*   The derivative, dX/dS, evaluated at the reference
491 *                       point, SI units.  Multiply the CDELTia keyvalue by
492 *                       this to get the pixel spacing in the X-type spectral
493 *                       coordinate.
494 *
495 *   err       struct wcserr **
496 *                       If enabled, for function return values > 1, this
497 *                       struct will contain a detailed error message, see
498 *                       wcserr_enable().  May be NULL if an error message is
499 *                       not desired.  Otherwise, the user is responsible for
500 *                       deleting the memory allocated for the wcserr struct.
501 *
502 * Function return value:
503 *             int       Status return value:
504 *                         0: Success.
505 *                         2: Invalid spectral parameters.
506 *
507 *
508 * spcxpse() - Spectral keyword synthesis
509 * -------------------------------------
510 * spcxpse(), for the spectral axis type specified and the value provided for
511 * the X-type spectral variable at the reference point, deduces the value of
512 * the FITS spectral axis keyword CRVALia and also the derivative dS/dX which
513 * may be used to compute CDELTia.  See above for an explanation of the S-,
514 * P-, and X-type spectral variables.
515 *
516 * A deprecated form of this function, spcxps(), lacks the wcserr** parameter.
517 *
518 * Given:
519 *   ctypeS    const char[9]
520 *                       The required spectral axis type, i.e. the CTYPEia
521 *                       keyvalue, (eight characters with null termination).
522 *                       For non-grism axes, the character code for the P-type
523 *                       spectral variable in the algorithm code (i.e. the
524 *                       eighth character of CTYPEia) may be set to '?' (it
525 *                       will not be reset).
526 *
527 *   crvalX    double    Value of the X-type spectral variable at the reference
528 *                       point (N.B. NOT the CRVALia keyvalue), SI units.
529 *
530 *   restfrq,
531 *   restwav   double    Rest frequency [Hz] and rest wavelength in vacuo [m],
532 *                       only one of which need be given, the other should be
533 *                       set to zero.
534 *
535 * Returned:
536 *   ptype     char*     Character code for the P-type spectral variable
537 *                       derived from ctypeS, one of 'F', 'W', 'A', or 'V'.
538 *
539 *   xtype     char*     Character code for the X-type spectral variable
540 *                       derived from ctypeS, one of 'F', 'W', 'A', or 'V'.
541 *                       Also, 'w' and 'a' are synonymous to 'W' and 'A' for
542 *                       grisms; crvalX and cdeltX must conform to these.
543 *
544 *   restreq   int*      Multivalued flag that indicates whether rest frequency
545 *                       or wavelength is required to compute spectral
546 *                       variables for this CTYPEia, as for spctype().
547 *
548 *   crvalS    double*   Value of the S-type spectral variable at the reference
549 *                       point (i.e. the appropriate CRVALia keyvalue), SI
550 *                       units.
551 *
552 *   dSdX      double*   The derivative, dS/dX, evaluated at the reference
553 *                       point, SI units.  Multiply this by the pixel spacing
554 *                       in the X-type spectral coordinate to get the CDELTia
555 *                       keyvalue.
556 *
557 *   err       struct wcserr **
558 *                       If enabled, for function return values > 1, this
559 *                       struct will contain a detailed error message, see
560 *                       wcserr_enable().  May be NULL if an error message is
561 *                       not desired.  Otherwise, the user is responsible for
562 *                       deleting the memory allocated for the wcserr struct.
563 *
564 * Function return value:
565 *             int       Status return value:
566 *                         0: Success.
567 *                         2: Invalid spectral parameters.
568 *
569 *
570 * spctrne() - Spectral keyword translation
571 * ---------------------------------------
572 * spctrne() translates a set of FITS spectral axis keywords into the
573 * corresponding set for the specified spectral axis type.  For example, a
574 * 'FREQ' axis may be translated into 'ZOPT-F2W' and vice versa.
575 *
576 * A deprecated form of this function, spctrn(), lacks the wcserr** parameter.
577 *
578 * Given:
579 *   ctypeS1   const char[9]
580 *                       Spectral axis type, i.e. the CTYPEia keyvalue, (eight
581 *                       characters with null termination).  For non-grism
582 *                       axes, the character code for the P-type spectral
583 *                       variable in the algorithm code (i.e. the eighth
584 *                       character of CTYPEia) may be set to '?' (it will not
585 *                       be reset).
586 *
587 *   crvalS1   double    Value of the S-type spectral variable at the reference
588 *                       point, i.e. the CRVALia keyvalue, SI units.
589 *
590 *   cdeltS1   double    Increment of the S-type spectral variable at the
591 *                       reference point, SI units.
592 *
593 *   restfrq,
594 *   restwav   double    Rest frequency [Hz] and rest wavelength in vacuo [m],
595 *                       only one of which need be given, the other should be
596 *                       set to zero.  Neither are required if the translation
597 *                       is between wave-characteristic types, or between
598 *                       velocity-characteristic types.  E.g., required for
599 *                       'FREQ'     -> 'ZOPT-F2W', but not required for
600 *                       'VELO-F2V' -> 'ZOPT-F2W'.
601 *
602 * Given and returned:
603 *   ctypeS2   char[9]   Required spectral axis type (eight characters with
604 *                       null termination).  The first four characters are
605 *                       required to be given and are never modified.  The
606 *                       remaining four, the algorithm code, are completely
607 *                       determined by, and must be consistent with, ctypeS1
608 *                       and the first four characters of ctypeS2.  A non-zero
609 *                       status value will be returned if they are inconsistent
610 *                       (see below).  However, if the final three characters
611 *                       are specified as "???", or if just the eighth
612 *                       character is specified as '?', the correct algorithm
613 *                       code will be substituted (applies for grism axes as
614 *                       well as non-grism).
615 *
616 * Returned:
617 *   crvalS2   double*   Value of the new S-type spectral variable at the
618 *                       reference point, i.e. the new CRVALia keyvalue, SI
619 *                       units.
620 *
621 *   cdeltS2   double*   Increment of the new S-type spectral variable at the
622 *                       reference point, i.e. the new CDELTia keyvalue, SI
623 *                       units.
624 *
625 *   err       struct wcserr **
626 *                       If enabled, for function return values > 1, this
627 *                       struct will contain a detailed error message, see
628 *                       wcserr_enable().  May be NULL if an error message is
629 *                       not desired.  Otherwise, the user is responsible for
630 *                       deleting the memory allocated for the wcserr struct.
631 *
632 * Function return value:
633 *             int       Status return value:
634 *                         0: Success.
635 *                         2: Invalid spectral parameters.
636 *
637 *                       A status value of 2 will be returned if restfrq or
638 *                       restwav are not specified when required, or if ctypeS1
639 *                       or ctypeS2 are self-inconsistent, or have different
640 *                       spectral X-type variables.
641 *
642 *
643 * spcaips() - Translate AIPS-convention spectral keywords
644 * -------------------------------------------------------
645 * spcaips() translates AIPS-convention spectral CTYPEia and VELREF keyvalues.
646 *
647 * Given:
648 *   ctypeA    const char[9]
649 *                       CTYPEia keyvalue possibly containing an
650 *                       AIPS-convention spectral code (eight characters, need
651 *                       not be null-terminated).
652 *
653 *   velref    int       AIPS-convention VELREF code.  It has the following
654 *                       integer values:
655 *                         1: LSR kinematic, originally described simply as
656 *                            "LSR" without distinction between the kinematic
657 *                            and dynamic definitions.
658 *                         2: Barycentric, originally described as "HEL"
659 *                            meaning heliocentric.
660 *                         3: Topocentric, originally described as "OBS"
661 *                            meaning geocentric but widely interpreted as
662 *                            topocentric.
663 *                       AIPS++ extensions to VELREF are also recognized:
664 *                         4: LSR dynamic.
665 *                         5: Geocentric.
666 *                         6: Source rest frame.
667 *                         7: Galactocentric.
668 *
669 *                       For an AIPS 'VELO' axis, a radio convention velocity
670 *                       (VRAD) is denoted by adding 256 to VELREF, otherwise
671 *                       an optical velocity (VOPT) is indicated (this is not
672 *                       applicable to 'FREQ' or 'FELO' axes).  Setting velref
673 *                       to 0 or 256 chooses between optical and radio velocity
674 *                       without specifying a Doppler frame, provided that a
675 *                       frame is encoded in ctypeA.  If not, i.e. for
676 *                       ctypeA = 'VELO', ctype will be returned as 'VELO'.
677 *
678 *                       VELREF takes precedence over CTYPEia in defining the
679 *                       Doppler frame, e.g.
680 *
681 =                         ctypeA = 'VELO-HEL'
682 =                         velref = 1
683 *
684 *                       returns ctype = 'VOPT' with specsys set to 'LSRK'.
685 *
686 *                       If omitted from the header, the default value of
687 *                       VELREF is 0.
688 *
689 * Returned:
690 *   ctype     char[9]   Translated CTYPEia keyvalue, or a copy of ctypeA if no
691 *                       translation was performed (in which case any trailing
692 *                       blanks in ctypeA will be replaced with nulls).
693 *
694 *   specsys   char[9]   Doppler reference frame indicated by VELREF or else
695 *                       by CTYPEia with value corresponding to the SPECSYS
696 *                       keyvalue in the FITS WCS standard.  May be returned
697 *                       blank if neither specifies a Doppler frame, e.g.
698 *                       ctypeA = 'FELO' and velref%256 == 0.
699 *
700 * Function return value:
701 *             int       Status return value:
702 *                        -1: No translation required (not an error).
703 *                         0: Success.
704 *                         2: Invalid value of VELREF.
705 *
706 *
707 * spcprm struct - Spectral transformation parameters
708 * --------------------------------------------------
709 * The spcprm struct contains information required to transform spectral
710 * coordinates.  It consists of certain members that must be set by the user
711 * ("given") and others that are set by the WCSLIB routines ("returned").  Some
712 * of the latter are supplied for informational purposes while others are for
713 * internal use only.
714 *
715 *   int flag
716 *     (Given and returned) This flag must be set to zero whenever any of the
717 *     following spcprm structure members are set or changed:
718 *
719 *       - spcprm::type,
720 *       - spcprm::code,
721 *       - spcprm::crval,
722 *       - spcprm::restfrq,
723 *       - spcprm::restwav,
724 *       - spcprm::pv[].
725 *
726 *     This signals the initialization routine, spcset(), to recompute the
727 *     returned members of the spcprm struct.  spcset() will reset flag to
728 *     indicate that this has been done.
729 *
730 *   char type[8]
731 *     (Given) Four-letter spectral variable type, e.g "ZOPT" for
732 *     CTYPEia = 'ZOPT-F2W'.  (Declared as char[8] for alignment reasons.)
733 *
734 *   char code[4]
735 *     (Given) Three-letter spectral algorithm code, e.g "F2W" for
736 *     CTYPEia = 'ZOPT-F2W'.
737 *
738 *   double crval
739 *     (Given) Reference value (CRVALia), SI units.
740 *
741 *   double restfrq
742 *     (Given) The rest frequency [Hz], and ...
743 *
744 *   double restwav
745 *     (Given) ... the rest wavelength in vacuo [m], only one of which need be
746 *     given, the other should be set to zero.  Neither are required if the
747 *     X and S spectral variables are both wave-characteristic, or both
748 *     velocity-characteristic, types.
749 *
750 *   double pv[7]
751 *     (Given) Grism parameters for 'GRI' and 'GRA' algorithm codes:
752 *       - 0: G, grating ruling density.
753 *       - 1: m, interference order.
754 *       - 2: alpha, angle of incidence [deg].
755 *       - 3: n_r, refractive index at the reference wavelength, lambda_r.
756 *       - 4: n'_r, dn/dlambda at the reference wavelength, lambda_r (/m).
757 *       - 5: epsilon, grating tilt angle [deg].
758 *       - 6: theta, detector tilt angle [deg].
759 *
760 * The remaining members of the spcprm struct are maintained by spcset() and
761 * must not be modified elsewhere:
762 *
763 *   double w[6]
764 *     (Returned) Intermediate values:
765 *       - 0: Rest frequency or wavelength (SI).
766 *       - 1: The value of the X-type spectral variable at the reference point
767 *           (SI units).
768 *       - 2: dX/dS at the reference point (SI units).
769 *      The remainder are grism intermediates.
770 *
771 *   int isGrism
772 *     (Returned) Grism coordinates?
773 *       - 0: no,
774 *       - 1: in vacuum,
775 *       - 2: in air.
776 *
777 *   int padding1
778 *     (An unused variable inserted for alignment purposes only.)
779 *
780 *   struct wcserr *err
781 *     (Returned) If enabled, when an error status is returned, this struct
782 *     contains detailed information about the error, see wcserr_enable().
783 *
784 *   void *padding2
785 *     (An unused variable inserted for alignment purposes only.)
786 *   int (*spxX2P)(SPX_ARGS)
787 *     (Returned) The first and ...
788 *   int (*spxP2S)(SPX_ARGS)
789 *     (Returned) ... the second of the pointers to the transformation
790 *     functions in the two-step algorithm chain X -> P -> S in the
791 *     pixel-to-spectral direction where the non-linear transformation is from
792 *     X to P.  The argument list, SPX_ARGS, is defined in spx.h.
793 *
794 *   int (*spxS2P)(SPX_ARGS)
795 *     (Returned) The first and ...
796 *   int (*spxP2X)(SPX_ARGS)
797 *     (Returned) ... the second of the pointers to the transformation
798 *     functions in the two-step algorithm chain S -> P -> X in the
799 *     spectral-to-pixel direction where the non-linear transformation is from
800 *     P to X.  The argument list, SPX_ARGS, is defined in spx.h.
801 *
802 *
803 * Global variable: const char *spc_errmsg[] - Status return messages
804 * ------------------------------------------------------------------
805 * Error messages to match the status value returned from each function.
806 *
807 *===========================================================================*/
808 
809 #ifndef WCSLIB_SPC
810 #define WCSLIB_SPC
811 
812 #include "spx.h"
813 
814 #ifdef __cplusplus
815 extern "C" {
816 #endif
817 
818 
819 extern const char *spc_errmsg[];
820 
821 enum spc_errmsg_enum {
822   SPCERR_NO_CHANGE       = -1,	// No change.
823   SPCERR_SUCCESS         =  0,	// Success.
824   SPCERR_NULL_POINTER    =  1,	// Null spcprm pointer passed.
825   SPCERR_BAD_SPEC_PARAMS =  2,	// Invalid spectral parameters.
826   SPCERR_BAD_X           =  3,	// One or more of x coordinates were
827 				// invalid.
828   SPCERR_BAD_SPEC        =  4 	// One or more of the spec coordinates were
829 				// invalid.
830 };
831 
832 struct spcprm {
833   // Initialization flag (see the prologue above).
834   //--------------------------------------------------------------------------
835   int    flag;			// Set to zero to force initialization.
836 
837   // Parameters to be provided (see the prologue above).
838   //--------------------------------------------------------------------------
839   char   type[8];		// Four-letter spectral variable type.
840   char   code[4];		// Three-letter spectral algorithm code.
841 
842   double crval;			// Reference value (CRVALia), SI units.
843   double restfrq;		// Rest frequency, Hz.
844   double restwav;		// Rest wavelength, m.
845 
846   double pv[7];			// Grism parameters:
847 				//   0: G, grating ruling density.
848 				//   1: m, interference order.
849 				//   2: alpha, angle of incidence.
850 				//   3: n_r, refractive index at lambda_r.
851 				//   4: n'_r, dn/dlambda at lambda_r.
852 				//   5: epsilon, grating tilt angle.
853 				//   6: theta, detector tilt angle.
854 
855   // Information derived from the parameters supplied.
856   //--------------------------------------------------------------------------
857   double w[6];			// Intermediate values.
858 				//   0: Rest frequency or wavelength (SI).
859 				//   1: CRVALX (SI units).
860 				//   2: CDELTX/CDELTia = dX/dS (SI units).
861 				// The remainder are grism intermediates.
862 
863   int    isGrism;		// Grism coordinates?  1: vacuum, 2: air.
864   int    padding1;		// (Dummy inserted for alignment purposes.)
865 
866   // Error handling
867   //--------------------------------------------------------------------------
868   struct wcserr *err;
869 
870   // Private
871   //--------------------------------------------------------------------------
872   void   *padding2;		// (Dummy inserted for alignment purposes.)
873   int (*spxX2P)(SPX_ARGS);	// Pointers to the transformation functions
874   int (*spxP2S)(SPX_ARGS);	// in the two-step algorithm chain in the
875 				// pixel-to-spectral direction.
876 
877   int (*spxS2P)(SPX_ARGS);	// Pointers to the transformation functions
878   int (*spxP2X)(SPX_ARGS);	// in the two-step algorithm chain in the
879 				// spectral-to-pixel direction.
880 };
881 
882 // Size of the spcprm struct in int units, used by the Fortran wrappers.
883 #define SPCLEN (sizeof(struct spcprm)/sizeof(int))
884 
885 
886 int spcini(struct spcprm *spc);
887 
888 int spcfree(struct spcprm *spc);
889 
890 int spcsize(const struct spcprm *spc, int sizes[2]);
891 
892 int spcprt(const struct spcprm *spc);
893 
894 int spcperr(const struct spcprm *spc, const char *prefix);
895 
896 int spcset(struct spcprm *spc);
897 
898 int spcx2s(struct spcprm *spc, int nx, int sx, int sspec,
899            const double x[], double spec[], int stat[]);
900 
901 int spcs2x(struct spcprm *spc, int nspec, int sspec, int sx,
902            const double spec[], double x[], int stat[]);
903 
904 int spctype(const char ctype[9], char stype[], char scode[], char sname[],
905             char units[], char *ptype, char *xtype, int *restreq,
906             struct wcserr **err);
907 
908 int spcspxe(const char ctypeS[9], double crvalS, double restfrq,
909             double restwav, char *ptype, char *xtype, int *restreq,
910             double *crvalX, double *dXdS, struct wcserr **err);
911 
912 int spcxpse(const char ctypeS[9], double crvalX, double restfrq,
913             double restwav, char *ptype, char *xtype, int *restreq,
914             double *crvalS, double *dSdX, struct wcserr **err);
915 
916 int spctrne(const char ctypeS1[9], double crvalS1, double cdeltS1,
917             double restfrq, double restwav, char ctypeS2[9], double *crvalS2,
918             double *cdeltS2, struct wcserr **err);
919 
920 int spcaips(const char ctypeA[9], int velref, char ctype[9], char specsys[9]);
921 
922 
923 // Deprecated.
924 #define spcini_errmsg spc_errmsg
925 #define spcprt_errmsg spc_errmsg
926 #define spcset_errmsg spc_errmsg
927 #define spcx2s_errmsg spc_errmsg
928 #define spcs2x_errmsg spc_errmsg
929 
930 int spctyp(const char ctype[9], char stype[], char scode[], char sname[],
931            char units[], char *ptype, char *xtype, int *restreq);
932 int spcspx(const char ctypeS[9], double crvalS, double restfrq,
933            double restwav, char *ptype, char *xtype, int *restreq,
934            double *crvalX, double *dXdS);
935 int spcxps(const char ctypeS[9], double crvalX, double restfrq,
936            double restwav, char *ptype, char *xtype, int *restreq,
937            double *crvalS, double *dSdX);
938 int spctrn(const char ctypeS1[9], double crvalS1, double cdeltS1,
939            double restfrq, double restwav, char ctypeS2[9], double *crvalS2,
940            double *cdeltS2);
941 
942 #ifdef __cplusplus
943 }
944 #endif
945 
946 #endif // WCSLIB_SPC
947